#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().
1.7.1