#include "nodes/parsenodes.h"
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 |
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; }
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 | ) |
Definition at line 160 of file extension.c.
References AccessShareLock, BTEqualStrategyNumber, ExtensionOidIndexId, ExtensionRelationId, GETSTRUCT, heap_close, heap_open(), HeapTupleIsValid, NameStr, ObjectIdAttributeNumber, ObjectIdGetDatum, pstrdup(), ScanKeyInit(), SnapshotNow, systable_beginscan(), systable_endscan(), and systable_getnext().
Referenced by ExecAlterExtensionContentsStmt(), getObjectDescription(), getObjectIdentity(), recordDependencyOnCurrentExtension(), and RemoveExtensionById().
{ char *result; Relation rel; SysScanDesc scandesc; HeapTuple tuple; ScanKeyData entry[1]; rel = heap_open(ExtensionRelationId, AccessShareLock); ScanKeyInit(&entry[0], ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(ext_oid)); 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)) result = pstrdup(NameStr(((Form_pg_extension) GETSTRUCT(tuple))->extname)); else result = NULL; systable_endscan(scandesc); heap_close(rel, AccessShareLock); return result; }
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); }
Definition at line 60 of file extension.c.
Referenced by CreateExtension(), ExecAlterExtensionStmt(), execute_extension_script(), findDependentObjects(), pg_extension_config_dump(), and recordDependencyOnCurrentExtension().
Definition at line 61 of file extension.c.
Referenced by execute_extension_script(), findDependentObjects(), pg_extension_config_dump(), recordDependencyOnCurrentExtension(), and RemoveExtensionById().