Header And Logo

PostgreSQL
| The world's most advanced open source database.

Functions | Variables

extension.h File Reference

#include "nodes/parsenodes.h"
Include dependency graph for extension.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

Oid CreateExtension (CreateExtensionStmt *stmt)
void RemoveExtensionById (Oid extId)
Oid InsertExtensionTuple (const char *extName, Oid extOwner, Oid schemaOid, bool relocatable, const char *extVersion, Datum extConfig, Datum extCondition, List *requiredExtensions)
Oid ExecAlterExtensionStmt (AlterExtensionStmt *stmt)
Oid ExecAlterExtensionContentsStmt (AlterExtensionContentsStmt *stmt)
Oid get_extension_oid (const char *extname, bool missing_ok)
char * get_extension_name (Oid ext_oid)
Oid AlterExtensionNamespace (List *names, const char *newschema)
void AlterExtensionOwner_oid (Oid extensionOid, Oid newOwnerId)

Variables

bool creating_extension
Oid CurrentExtensionObject

Function Documentation

Oid AlterExtensionNamespace ( List names,
const char *  newschema 
)

Definition at line 2403 of file extension.c.

References AccessShareLock, ACL_CREATE, ACL_KIND_EXTENSION, ACL_KIND_NAMESPACE, aclcheck_error(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, AlterObjectNamespace_oid(), Anum_pg_depend_refclassid, Anum_pg_depend_refobjid, BTEqualStrategyNumber, CatalogUpdateIndexes(), changeDependencyFor(), ObjectAddress::classId, DEPENDENCY_EXTENSION, DependReferenceIndexId, DependRelationId, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, ExtensionOidIndexId, ExtensionRelationId, get_extension_oid(), get_namespace_name(), getExtensionOfObject(), getObjectDescription(), GETSTRUCT, GetUserId(), heap_close, heap_copytuple(), heap_open(), HeapTupleIsValid, InvalidOid, InvokeObjectPostAlterHook, linitial, list_length(), LookupCreationNamespace(), NamespaceRelationId, NameStr, new_object_addresses(), ObjectAddress::objectId, ObjectIdAttributeNumber, ObjectIdGetDatum, ObjectAddress::objectSubId, pg_extension_ownercheck(), pg_namespace_aclcheck(), relation_close(), RowExclusiveLock, ScanKeyInit(), simple_heap_update(), SnapshotNow, strVal, systable_beginscan(), systable_endscan(), systable_getnext(), and HeapTupleData::t_self.

Referenced by ExecAlterObjectSchemaStmt().

{
    char       *extensionName;
    Oid         extensionOid;
    Oid         nspOid;
    Oid         oldNspOid = InvalidOid;
    AclResult   aclresult;
    Relation    extRel;
    ScanKeyData key[2];
    SysScanDesc extScan;
    HeapTuple   extTup;
    Form_pg_extension extForm;
    Relation    depRel;
    SysScanDesc depScan;
    HeapTuple   depTup;
    ObjectAddresses *objsMoved;

    if (list_length(names) != 1)
        ereport(ERROR,
                (errcode(ERRCODE_SYNTAX_ERROR),
                 errmsg("extension name cannot be qualified")));
    extensionName = strVal(linitial(names));

    extensionOid = get_extension_oid(extensionName, false);

    nspOid = LookupCreationNamespace(newschema);

    /*
     * Permission check: must own extension.  Note that we don't bother to
     * check ownership of the individual member objects ...
     */
    if (!pg_extension_ownercheck(extensionOid, GetUserId()))
        aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EXTENSION,
                       extensionName);

    /* Permission check: must have creation rights in target namespace */
    aclresult = pg_namespace_aclcheck(nspOid, GetUserId(), ACL_CREATE);
    if (aclresult != ACLCHECK_OK)
        aclcheck_error(aclresult, ACL_KIND_NAMESPACE, newschema);

    /*
     * If the schema is currently a member of the extension, disallow moving
     * the extension into the schema.  That would create a dependency loop.
     */
    if (getExtensionOfObject(NamespaceRelationId, nspOid) == extensionOid)
        ereport(ERROR,
                (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                 errmsg("cannot move extension \"%s\" into schema \"%s\" "
                        "because the extension contains the schema",
                        extensionName, newschema)));

    /* Locate the pg_extension tuple */
    extRel = heap_open(ExtensionRelationId, RowExclusiveLock);

    ScanKeyInit(&key[0],
                ObjectIdAttributeNumber,
                BTEqualStrategyNumber, F_OIDEQ,
                ObjectIdGetDatum(extensionOid));

    extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
                                 SnapshotNow, 1, key);

    extTup = systable_getnext(extScan);

    if (!HeapTupleIsValid(extTup))      /* should not happen */
        elog(ERROR, "extension with oid %u does not exist", extensionOid);

    /* Copy tuple so we can modify it below */
    extTup = heap_copytuple(extTup);
    extForm = (Form_pg_extension) GETSTRUCT(extTup);

    systable_endscan(extScan);

    /*
     * If the extension is already in the target schema, just silently do
     * nothing.
     */
    if (extForm->extnamespace == nspOid)
    {
        heap_close(extRel, RowExclusiveLock);
        return InvalidOid;
    }

    /* Check extension is supposed to be relocatable */
    if (!extForm->extrelocatable)
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("extension \"%s\" does not support SET SCHEMA",
                        NameStr(extForm->extname))));

    objsMoved = new_object_addresses();

    /*
     * Scan pg_depend to find objects that depend directly on the extension,
     * and alter each one's schema.
     */
    depRel = heap_open(DependRelationId, AccessShareLock);

    ScanKeyInit(&key[0],
                Anum_pg_depend_refclassid,
                BTEqualStrategyNumber, F_OIDEQ,
                ObjectIdGetDatum(ExtensionRelationId));
    ScanKeyInit(&key[1],
                Anum_pg_depend_refobjid,
                BTEqualStrategyNumber, F_OIDEQ,
                ObjectIdGetDatum(extensionOid));

    depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
                                 SnapshotNow, 2, key);

    while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
    {
        Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
        ObjectAddress dep;
        Oid         dep_oldNspOid;

        /*
         * Ignore non-membership dependencies.  (Currently, the only other
         * case we could see here is a normal dependency from another
         * extension.)
         */
        if (pg_depend->deptype != DEPENDENCY_EXTENSION)
            continue;

        dep.classId = pg_depend->classid;
        dep.objectId = pg_depend->objid;
        dep.objectSubId = pg_depend->objsubid;

        if (dep.objectSubId != 0)       /* should not happen */
            elog(ERROR, "extension should not have a sub-object dependency");

        /* Relocate the object */
        dep_oldNspOid = AlterObjectNamespace_oid(dep.classId,
                                                 dep.objectId,
                                                 nspOid,
                                                 objsMoved);

        /*
         * Remember previous namespace of first object that has one
         */
        if (oldNspOid == InvalidOid && dep_oldNspOid != InvalidOid)
            oldNspOid = dep_oldNspOid;

        /*
         * If not all the objects had the same old namespace (ignoring any
         * that are not in namespaces), complain.
         */
        if (dep_oldNspOid != InvalidOid && dep_oldNspOid != oldNspOid)
            ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                     errmsg("extension \"%s\" does not support SET SCHEMA",
                            NameStr(extForm->extname)),
                     errdetail("%s is not in the extension's schema \"%s\"",
                               getObjectDescription(&dep),
                               get_namespace_name(oldNspOid))));
    }

    systable_endscan(depScan);

    relation_close(depRel, AccessShareLock);

    /* Now adjust pg_extension.extnamespace */
    extForm->extnamespace = nspOid;

    simple_heap_update(extRel, &extTup->t_self, extTup);
    CatalogUpdateIndexes(extRel, extTup);

    heap_close(extRel, RowExclusiveLock);

    /* update dependencies to point to the new schema */
    changeDependencyFor(ExtensionRelationId, extensionOid,
                        NamespaceRelationId, oldNspOid, nspOid);

    InvokeObjectPostAlterHook(ExtensionRelationId, extensionOid, 0);

    return extensionOid;
}

void AlterExtensionOwner_oid ( Oid  extensionOid,
Oid  newOwnerId 
)
Oid CreateExtension ( CreateExtensionStmt stmt  ) 

Definition at line 1178 of file extension.c.

References ApplyExtensionUpdates(), DefElem::arg, Assert, CreateSchemaStmt::authid, check_valid_extension_name(), check_valid_version_name(), ExtensionControlFile::comment, CreateComments(), CreateSchemaCommand(), creating_extension, ExtensionControlFile::default_version, DefElem::defname, elog, ereport, errcode(), errmsg(), ERROR, execute_extension_script(), ExtensionRelationId, CreateExtensionStmt::extname, fetch_search_path(), get_extension_oid(), get_extension_schema(), get_namespace_name(), get_namespace_oid(), GetUserId(), identify_update_path(), CreateSchemaStmt::if_not_exists, CreateExtensionStmt::if_not_exists, InsertExtensionTuple(), InvalidOid, lappend_oid(), lfirst, linitial, linitial_oid, list_delete_first(), list_free(), list_length(), makeNode, ExtensionControlFile::name, NIL, NOTICE, NULL, OidIsValid, CreateExtensionStmt::options, PointerGetDatum, read_extension_aux_control_file(), read_extension_control_file(), ExtensionControlFile::relocatable, ExtensionControlFile::requires, ExtensionControlFile::schema, CreateSchemaStmt::schemaElts, CreateSchemaStmt::schemaname, and strVal.

Referenced by ProcessUtilitySlow().

{
    DefElem    *d_schema = NULL;
    DefElem    *d_new_version = NULL;
    DefElem    *d_old_version = NULL;
    char       *schemaName;
    Oid         schemaOid;
    char       *versionName;
    char       *oldVersionName;
    Oid         extowner = GetUserId();
    ExtensionControlFile *pcontrol;
    ExtensionControlFile *control;
    List       *updateVersions;
    List       *requiredExtensions;
    List       *requiredSchemas;
    Oid         extensionOid;
    ListCell   *lc;

    /* Check extension name validity before any filesystem access */
    check_valid_extension_name(stmt->extname);

    /*
     * Check for duplicate extension name.  The unique index on
     * pg_extension.extname would catch this anyway, and serves as a backstop
     * in case of race conditions; but this is a friendlier error message, and
     * besides we need a check to support IF NOT EXISTS.
     */
    if (get_extension_oid(stmt->extname, true) != InvalidOid)
    {
        if (stmt->if_not_exists)
        {
            ereport(NOTICE,
                    (errcode(ERRCODE_DUPLICATE_OBJECT),
                     errmsg("extension \"%s\" already exists, skipping",
                            stmt->extname)));
            return InvalidOid;
        }
        else
            ereport(ERROR,
                    (errcode(ERRCODE_DUPLICATE_OBJECT),
                     errmsg("extension \"%s\" already exists",
                            stmt->extname)));
    }

    /*
     * We use global variables to track the extension being created, so we can
     * create only one extension at the same time.
     */
    if (creating_extension)
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("nested CREATE EXTENSION is not supported")));

    /*
     * Read the primary control file.  Note we assume that it does not contain
     * any non-ASCII data, so there is no need to worry about encoding at this
     * point.
     */
    pcontrol = read_extension_control_file(stmt->extname);

    /*
     * Read the statement option list
     */
    foreach(lc, stmt->options)
    {
        DefElem    *defel = (DefElem *) lfirst(lc);

        if (strcmp(defel->defname, "schema") == 0)
        {
            if (d_schema)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            d_schema = defel;
        }
        else if (strcmp(defel->defname, "new_version") == 0)
        {
            if (d_new_version)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            d_new_version = defel;
        }
        else if (strcmp(defel->defname, "old_version") == 0)
        {
            if (d_old_version)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            d_old_version = defel;
        }
        else
            elog(ERROR, "unrecognized option: %s", defel->defname);
    }

    /*
     * Determine the version to install
     */
    if (d_new_version && d_new_version->arg)
        versionName = strVal(d_new_version->arg);
    else if (pcontrol->default_version)
        versionName = pcontrol->default_version;
    else
    {
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("version to install must be specified")));
        versionName = NULL;     /* keep compiler quiet */
    }
    check_valid_version_name(versionName);

    /*
     * Determine the (unpackaged) version to update from, if any, and then
     * figure out what sequence of update scripts we need to apply.
     */
    if (d_old_version && d_old_version->arg)
    {
        oldVersionName = strVal(d_old_version->arg);
        check_valid_version_name(oldVersionName);

        if (strcmp(oldVersionName, versionName) == 0)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                     errmsg("FROM version must be different from installation target version \"%s\"",
                            versionName)));

        updateVersions = identify_update_path(pcontrol,
                                              oldVersionName,
                                              versionName);

        if (list_length(updateVersions) == 1)
        {
            /*
             * Simple case where there's just one update script to run. We
             * will not need any follow-on update steps.
             */
            Assert(strcmp((char *) linitial(updateVersions), versionName) == 0);
            updateVersions = NIL;
        }
        else
        {
            /*
             * Multi-step sequence.  We treat this as installing the version
             * that is the target of the first script, followed by successive
             * updates to the later versions.
             */
            versionName = (char *) linitial(updateVersions);
            updateVersions = list_delete_first(updateVersions);
        }
    }
    else
    {
        oldVersionName = NULL;
        updateVersions = NIL;
    }

    /*
     * Fetch control parameters for installation target version
     */
    control = read_extension_aux_control_file(pcontrol, versionName);

    /*
     * Determine the target schema to install the extension into
     */
    if (d_schema && d_schema->arg)
    {
        /*
         * User given schema, CREATE EXTENSION ... WITH SCHEMA ...
         *
         * It's an error to give a schema different from control->schema if
         * control->schema is specified.
         */
        schemaName = strVal(d_schema->arg);

        if (control->schema != NULL &&
            strcmp(control->schema, schemaName) != 0)
            ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                errmsg("extension \"%s\" must be installed in schema \"%s\"",
                       control->name,
                       control->schema)));

        /* If the user is giving us the schema name, it must exist already */
        schemaOid = get_namespace_oid(schemaName, false);
    }
    else if (control->schema != NULL)
    {
        /*
         * The extension is not relocatable and the author gave us a schema
         * for it.  We create the schema here if it does not already exist.
         */
        schemaName = control->schema;
        schemaOid = get_namespace_oid(schemaName, true);

        if (schemaOid == InvalidOid)
        {
            CreateSchemaStmt *csstmt = makeNode(CreateSchemaStmt);

            csstmt->schemaname = schemaName;
            csstmt->authid = NULL;      /* will be created by current user */
            csstmt->schemaElts = NIL;
            csstmt->if_not_exists = false;
            CreateSchemaCommand(csstmt, NULL);

            /*
             * CreateSchemaCommand includes CommandCounterIncrement, so new
             * schema is now visible
             */
            schemaOid = get_namespace_oid(schemaName, false);
        }
    }
    else
    {
        /*
         * Else, use the current default creation namespace, which is the
         * first explicit entry in the search_path.
         */
        List       *search_path = fetch_search_path(false);

        if (search_path == NIL) /* probably can't happen */
            elog(ERROR, "there is no default creation target");
        schemaOid = linitial_oid(search_path);
        schemaName = get_namespace_name(schemaOid);
        if (schemaName == NULL) /* recently-deleted namespace? */
            elog(ERROR, "there is no default creation target");

        list_free(search_path);
    }

    /*
     * We don't check creation rights on the target namespace here.  If the
     * extension script actually creates any objects there, it will fail if
     * the user doesn't have such permissions.  But there are cases such as
     * procedural languages where it's convenient to set schema = pg_catalog
     * yet we don't want to restrict the command to users with ACL_CREATE for
     * pg_catalog.
     */

    /*
     * Look up the prerequisite extensions, and build lists of their OIDs and
     * the OIDs of their target schemas.
     */
    requiredExtensions = NIL;
    requiredSchemas = NIL;
    foreach(lc, control->requires)
    {
        char       *curreq = (char *) lfirst(lc);
        Oid         reqext;
        Oid         reqschema;

        /*
         * We intentionally don't use get_extension_oid's default error
         * message here, because it would be confusing in this context.
         */
        reqext = get_extension_oid(curreq, true);
        if (!OidIsValid(reqext))
            ereport(ERROR,
                    (errcode(ERRCODE_UNDEFINED_OBJECT),
                     errmsg("required extension \"%s\" is not installed",
                            curreq)));
        reqschema = get_extension_schema(reqext);
        requiredExtensions = lappend_oid(requiredExtensions, reqext);
        requiredSchemas = lappend_oid(requiredSchemas, reqschema);
    }

    /*
     * Insert new tuple into pg_extension, and create dependency entries.
     */
    extensionOid = InsertExtensionTuple(control->name, extowner,
                                        schemaOid, control->relocatable,
                                        versionName,
                                        PointerGetDatum(NULL),
                                        PointerGetDatum(NULL),
                                        requiredExtensions);

    /*
     * Apply any control-file comment on extension
     */
    if (control->comment != NULL)
        CreateComments(extensionOid, ExtensionRelationId, 0, control->comment);

    /*
     * Execute the installation script file
     */
    execute_extension_script(extensionOid, control,
                             oldVersionName, versionName,
                             requiredSchemas,
                             schemaName, schemaOid);

    /*
     * If additional update scripts have to be executed, apply the updates as
     * though a series of ALTER EXTENSION UPDATE commands were given
     */
    ApplyExtensionUpdates(extensionOid, pcontrol,
                          versionName, updateVersions);

    return extensionOid;
}

Oid ExecAlterExtensionContentsStmt ( AlterExtensionContentsStmt stmt  ) 

Definition at line 2884 of file extension.c.

References ACL_KIND_EXTENSION, aclcheck_error(), ACLCHECK_NOT_OWNER, AlterExtensionContentsStmt::action, check_object_ownership(), ObjectAddress::classId, deleteDependencyRecordsForClass(), DEPENDENCY_EXTENSION, elog, ereport, errcode(), errmsg(), ERROR, extension_config_remove(), ExtensionRelationId, AlterExtensionContentsStmt::extname, get_extension_name(), get_extension_oid(), get_extension_schema(), get_namespace_name(), get_object_address(), getExtensionOfObject(), getObjectDescription(), GetUserId(), InvokeObjectPostAlterHook, NamespaceRelationId, NoLock, NULL, AlterExtensionContentsStmt::objargs, ObjectAddress::objectId, ObjectAddress::objectSubId, AlterExtensionContentsStmt::objname, AlterExtensionContentsStmt::objtype, OidIsValid, pg_extension_ownercheck(), recordDependencyOn(), relation_close(), RelationRelationId, and ShareUpdateExclusiveLock.

Referenced by ProcessUtilitySlow().

{
    ObjectAddress extension;
    ObjectAddress object;
    Relation    relation;
    Oid         oldExtension;

    extension.classId = ExtensionRelationId;
    extension.objectId = get_extension_oid(stmt->extname, false);
    extension.objectSubId = 0;

    /* Permission check: must own extension */
    if (!pg_extension_ownercheck(extension.objectId, GetUserId()))
        aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EXTENSION,
                       stmt->extname);

    /*
     * Translate the parser representation that identifies the object into an
     * ObjectAddress.  get_object_address() will throw an error if the object
     * does not exist, and will also acquire a lock on the object to guard
     * against concurrent DROP and ALTER EXTENSION ADD/DROP operations.
     */
    object = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
                                &relation, ShareUpdateExclusiveLock, false);

    /* Permission check: must own target object, too */
    check_object_ownership(GetUserId(), stmt->objtype, object,
                           stmt->objname, stmt->objargs, relation);

    /*
     * Check existing extension membership.
     */
    oldExtension = getExtensionOfObject(object.classId, object.objectId);

    if (stmt->action > 0)
    {
        /*
         * ADD, so complain if object is already attached to some extension.
         */
        if (OidIsValid(oldExtension))
            ereport(ERROR,
                    (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                     errmsg("%s is already a member of extension \"%s\"",
                            getObjectDescription(&object),
                            get_extension_name(oldExtension))));

        /*
         * Prevent a schema from being added to an extension if the schema
         * contains the extension.  That would create a dependency loop.
         */
        if (object.classId == NamespaceRelationId &&
            object.objectId == get_extension_schema(extension.objectId))
            ereport(ERROR,
                    (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                     errmsg("cannot add schema \"%s\" to extension \"%s\" "
                            "because the schema contains the extension",
                            get_namespace_name(object.objectId),
                            stmt->extname)));

        /*
         * OK, add the dependency.
         */
        recordDependencyOn(&object, &extension, DEPENDENCY_EXTENSION);
    }
    else
    {
        /*
         * DROP, so complain if it's not a member.
         */
        if (oldExtension != extension.objectId)
            ereport(ERROR,
                    (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                     errmsg("%s is not a member of extension \"%s\"",
                            getObjectDescription(&object),
                            stmt->extname)));

        /*
         * OK, drop the dependency.
         */
        if (deleteDependencyRecordsForClass(object.classId, object.objectId,
                                            ExtensionRelationId,
                                            DEPENDENCY_EXTENSION) != 1)
            elog(ERROR, "unexpected number of extension dependency records");

        /*
         * If it's a relation, it might have an entry in the extension's
         * extconfig array, which we must remove.
         */
        if (object.classId == RelationRelationId)
            extension_config_remove(extension.objectId, object.objectId);
    }

    InvokeObjectPostAlterHook(ExtensionRelationId, extension.objectId, 0);

    /*
     * If get_object_address() opened the relation for us, we close it to keep
     * the reference count correct - but we retain any locks acquired by
     * get_object_address() until commit time, to guard against concurrent
     * activity.
     */
    if (relation != NULL)
        relation_close(relation, NoLock);

    return extension.objectId;
}

Oid ExecAlterExtensionStmt ( AlterExtensionStmt stmt  ) 

Definition at line 2585 of file extension.c.

References AccessShareLock, ACL_KIND_EXTENSION, aclcheck_error(), ACLCHECK_NOT_OWNER, Anum_pg_extension_extname, Anum_pg_extension_extversion, ApplyExtensionUpdates(), DefElem::arg, BTEqualStrategyNumber, check_valid_version_name(), creating_extension, CStringGetDatum, DatumGetTextPP, ExtensionControlFile::default_version, DefElem::defname, elog, ereport, errcode(), errmsg(), ERROR, ExtensionNameIndexId, ExtensionRelationId, AlterExtensionStmt::extname, GetUserId(), heap_close, heap_getattr, heap_open(), HeapTupleGetOid, HeapTupleIsValid, identify_update_path(), lfirst, NOTICE, AlterExtensionStmt::options, pg_extension_ownercheck(), read_extension_control_file(), RelationGetDescr, ScanKeyInit(), SnapshotNow, strVal, systable_beginscan(), systable_endscan(), systable_getnext(), and text_to_cstring().

Referenced by ProcessUtilitySlow().

{
    DefElem    *d_new_version = NULL;
    char       *versionName;
    char       *oldVersionName;
    ExtensionControlFile *control;
    Oid         extensionOid;
    Relation    extRel;
    ScanKeyData key[1];
    SysScanDesc extScan;
    HeapTuple   extTup;
    List       *updateVersions;
    Datum       datum;
    bool        isnull;
    ListCell   *lc;

    /*
     * We use global variables to track the extension being created, so we can
     * create/update only one extension at the same time.
     */
    if (creating_extension)
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("nested ALTER EXTENSION is not supported")));

    /*
     * Look up the extension --- it must already exist in pg_extension
     */
    extRel = heap_open(ExtensionRelationId, AccessShareLock);

    ScanKeyInit(&key[0],
                Anum_pg_extension_extname,
                BTEqualStrategyNumber, F_NAMEEQ,
                CStringGetDatum(stmt->extname));

    extScan = systable_beginscan(extRel, ExtensionNameIndexId, true,
                                 SnapshotNow, 1, key);

    extTup = systable_getnext(extScan);

    if (!HeapTupleIsValid(extTup))
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_OBJECT),
                 errmsg("extension \"%s\" does not exist",
                        stmt->extname)));

    extensionOid = HeapTupleGetOid(extTup);

    /*
     * Determine the existing version we are updating from
     */
    datum = heap_getattr(extTup, Anum_pg_extension_extversion,
                         RelationGetDescr(extRel), &isnull);
    if (isnull)
        elog(ERROR, "extversion is null");
    oldVersionName = text_to_cstring(DatumGetTextPP(datum));

    systable_endscan(extScan);

    heap_close(extRel, AccessShareLock);

    /* Permission check: must own extension */
    if (!pg_extension_ownercheck(extensionOid, GetUserId()))
        aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EXTENSION,
                       stmt->extname);

    /*
     * Read the primary control file.  Note we assume that it does not contain
     * any non-ASCII data, so there is no need to worry about encoding at this
     * point.
     */
    control = read_extension_control_file(stmt->extname);

    /*
     * Read the statement option list
     */
    foreach(lc, stmt->options)
    {
        DefElem    *defel = (DefElem *) lfirst(lc);

        if (strcmp(defel->defname, "new_version") == 0)
        {
            if (d_new_version)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            d_new_version = defel;
        }
        else
            elog(ERROR, "unrecognized option: %s", defel->defname);
    }

    /*
     * Determine the version to update to
     */
    if (d_new_version && d_new_version->arg)
        versionName = strVal(d_new_version->arg);
    else if (control->default_version)
        versionName = control->default_version;
    else
    {
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("version to install must be specified")));
        versionName = NULL;     /* keep compiler quiet */
    }
    check_valid_version_name(versionName);

    /*
     * If we're already at that version, just say so
     */
    if (strcmp(oldVersionName, versionName) == 0)
    {
        ereport(NOTICE,
           (errmsg("version \"%s\" of extension \"%s\" is already installed",
                   versionName, stmt->extname)));
        return InvalidOid;
    }

    /*
     * Identify the series of update script files we need to execute
     */
    updateVersions = identify_update_path(control,
                                          oldVersionName,
                                          versionName);

    /*
     * Update the pg_extension row and execute the update scripts, one at a
     * time
     */
    ApplyExtensionUpdates(extensionOid, control,
                          oldVersionName, updateVersions);

    return extensionOid;
}

char* get_extension_name ( Oid  ext_oid  ) 
Oid get_extension_oid ( const char *  extname,
bool  missing_ok 
)

Definition at line 115 of file extension.c.

References AccessShareLock, Anum_pg_extension_extname, BTEqualStrategyNumber, CStringGetDatum, ereport, errcode(), errmsg(), ERROR, ExtensionNameIndexId, ExtensionRelationId, heap_close, heap_open(), HeapTupleGetOid, HeapTupleIsValid, OidIsValid, ScanKeyInit(), SnapshotNow, systable_beginscan(), systable_endscan(), and systable_getnext().

Referenced by AlterExtensionNamespace(), ApplyExtensionUpdates(), create_empty_extension(), CreateExtension(), ExecAlterExtensionContentsStmt(), and get_object_address_unqualified().

{
    Oid         result;
    Relation    rel;
    SysScanDesc scandesc;
    HeapTuple   tuple;
    ScanKeyData entry[1];

    rel = heap_open(ExtensionRelationId, AccessShareLock);

    ScanKeyInit(&entry[0],
                Anum_pg_extension_extname,
                BTEqualStrategyNumber, F_NAMEEQ,
                CStringGetDatum(extname));

    scandesc = systable_beginscan(rel, ExtensionNameIndexId, true,
                                  SnapshotNow, 1, entry);

    tuple = systable_getnext(scandesc);

    /* We assume that there can be at most one matching tuple */
    if (HeapTupleIsValid(tuple))
        result = HeapTupleGetOid(tuple);
    else
        result = InvalidOid;

    systable_endscan(scandesc);

    heap_close(rel, AccessShareLock);

    if (!OidIsValid(result) && !missing_ok)
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_OBJECT),
                 errmsg("extension \"%s\" does not exist",
                        extname)));

    return result;
}

Oid InsertExtensionTuple ( const char *  extName,
Oid  extOwner,
Oid  schemaOid,
bool  relocatable,
const char *  extVersion,
Datum  extConfig,
Datum  extCondition,
List requiredExtensions 
)

Definition at line 1491 of file extension.c.

References Anum_pg_extension_extcondition, Anum_pg_extension_extconfig, Anum_pg_extension_extname, Anum_pg_extension_extnamespace, Anum_pg_extension_extowner, Anum_pg_extension_extrelocatable, Anum_pg_extension_extversion, BoolGetDatum, CatalogUpdateIndexes(), ObjectAddress::classId, CStringGetDatum, CStringGetTextDatum, DEPENDENCY_NORMAL, DirectFunctionCall1, ExtensionRelationId, heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), InvokeObjectPostCreateHook, lfirst_oid, namein(), NULL, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, PointerGetDatum, RelationData::rd_att, recordDependencyOn(), recordDependencyOnOwner(), RowExclusiveLock, simple_heap_insert(), and values.

Referenced by create_empty_extension(), and CreateExtension().

{
    Oid         extensionOid;
    Relation    rel;
    Datum       values[Natts_pg_extension];
    bool        nulls[Natts_pg_extension];
    HeapTuple   tuple;
    ObjectAddress myself;
    ObjectAddress nsp;
    ListCell   *lc;

    /*
     * Build and insert the pg_extension tuple
     */
    rel = heap_open(ExtensionRelationId, RowExclusiveLock);

    memset(values, 0, sizeof(values));
    memset(nulls, 0, sizeof(nulls));

    values[Anum_pg_extension_extname - 1] =
        DirectFunctionCall1(namein, CStringGetDatum(extName));
    values[Anum_pg_extension_extowner - 1] = ObjectIdGetDatum(extOwner);
    values[Anum_pg_extension_extnamespace - 1] = ObjectIdGetDatum(schemaOid);
    values[Anum_pg_extension_extrelocatable - 1] = BoolGetDatum(relocatable);
    values[Anum_pg_extension_extversion - 1] = CStringGetTextDatum(extVersion);

    if (extConfig == PointerGetDatum(NULL))
        nulls[Anum_pg_extension_extconfig - 1] = true;
    else
        values[Anum_pg_extension_extconfig - 1] = extConfig;

    if (extCondition == PointerGetDatum(NULL))
        nulls[Anum_pg_extension_extcondition - 1] = true;
    else
        values[Anum_pg_extension_extcondition - 1] = extCondition;

    tuple = heap_form_tuple(rel->rd_att, values, nulls);

    extensionOid = simple_heap_insert(rel, tuple);
    CatalogUpdateIndexes(rel, tuple);

    heap_freetuple(tuple);
    heap_close(rel, RowExclusiveLock);

    /*
     * Record dependencies on owner, schema, and prerequisite extensions
     */
    recordDependencyOnOwner(ExtensionRelationId, extensionOid, extOwner);

    myself.classId = ExtensionRelationId;
    myself.objectId = extensionOid;
    myself.objectSubId = 0;

    nsp.classId = NamespaceRelationId;
    nsp.objectId = schemaOid;
    nsp.objectSubId = 0;

    recordDependencyOn(&myself, &nsp, DEPENDENCY_NORMAL);

    foreach(lc, requiredExtensions)
    {
        Oid         reqext = lfirst_oid(lc);
        ObjectAddress otherext;

        otherext.classId = ExtensionRelationId;
        otherext.objectId = reqext;
        otherext.objectSubId = 0;

        recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
    }
    /* Post creation hook for new extension */
    InvokeObjectPostCreateHook(ExtensionRelationId, extensionOid, 0);

    return extensionOid;
}

void RemoveExtensionById ( Oid  extId  ) 

Definition at line 1577 of file extension.c.

References BTEqualStrategyNumber, CurrentExtensionObject, ereport, errcode(), errmsg(), ERROR, ExtensionOidIndexId, ExtensionRelationId, get_extension_name(), heap_close, heap_open(), HeapTupleIsValid, ObjectIdAttributeNumber, ObjectIdGetDatum, RowExclusiveLock, ScanKeyInit(), simple_heap_delete(), SnapshotNow, systable_beginscan(), systable_endscan(), systable_getnext(), and HeapTupleData::t_self.

Referenced by doDeletion().

{
    Relation    rel;
    SysScanDesc scandesc;
    HeapTuple   tuple;
    ScanKeyData entry[1];

    /*
     * Disallow deletion of any extension that's currently open for insertion;
     * else subsequent executions of recordDependencyOnCurrentExtension()
     * could create dangling pg_depend records that refer to a no-longer-valid
     * pg_extension OID.  This is needed not so much because we think people
     * might write "DROP EXTENSION foo" in foo's own script files, as because
     * errors in dependency management in extension script files could give
     * rise to cases where an extension is dropped as a result of recursing
     * from some contained object.  Because of that, we must test for the case
     * here, not at some higher level of the DROP EXTENSION command.
     */
    if (extId == CurrentExtensionObject)
        ereport(ERROR,
                (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
          errmsg("cannot drop extension \"%s\" because it is being modified",
                 get_extension_name(extId))));

    rel = heap_open(ExtensionRelationId, RowExclusiveLock);

    ScanKeyInit(&entry[0],
                ObjectIdAttributeNumber,
                BTEqualStrategyNumber, F_OIDEQ,
                ObjectIdGetDatum(extId));
    scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
                                  SnapshotNow, 1, entry);

    tuple = systable_getnext(scandesc);

    /* We assume that there can be at most one matching tuple */
    if (HeapTupleIsValid(tuple))
        simple_heap_delete(rel, &tuple->t_self);

    systable_endscan(scandesc);

    heap_close(rel, RowExclusiveLock);
}


Variable Documentation