PostgreSQL Source Code  git master
extension.h File Reference
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

ObjectAddress CreateExtension (ParseState *pstate, CreateExtensionStmt *stmt)
 
void RemoveExtensionById (Oid extId)
 
ObjectAddress InsertExtensionTuple (const char *extName, Oid extOwner, Oid schemaOid, bool relocatable, const char *extVersion, Datum extConfig, Datum extCondition, List *requiredExtensions)
 
ObjectAddress ExecAlterExtensionStmt (ParseState *pstate, AlterExtensionStmt *stmt)
 
ObjectAddress ExecAlterExtensionContentsStmt (AlterExtensionContentsStmt *stmt, ObjectAddress *objAddr)
 
Oid get_extension_oid (const char *extname, bool missing_ok)
 
char * get_extension_name (Oid ext_oid)
 
bool extension_file_exists (const char *extensionName)
 
ObjectAddress AlterExtensionNamespace (const char *extensionName, const char *newschema, Oid *oldschema)
 

Variables

PGDLLIMPORT bool creating_extension
 
PGDLLIMPORT Oid CurrentExtensionObject
 

Function Documentation

◆ AlterExtensionNamespace()

ObjectAddress AlterExtensionNamespace ( const char *  extensionName,
const char *  newschema,
Oid oldschema 
)

Definition at line 2706 of file extension.c.

2707 {
2708  Oid extensionOid;
2709  Oid nspOid;
2710  Oid oldNspOid = InvalidOid;
2711  AclResult aclresult;
2712  Relation extRel;
2713  ScanKeyData key[2];
2714  SysScanDesc extScan;
2715  HeapTuple extTup;
2716  Form_pg_extension extForm;
2717  Relation depRel;
2718  SysScanDesc depScan;
2719  HeapTuple depTup;
2720  ObjectAddresses *objsMoved;
2721  ObjectAddress extAddr;
2722 
2723  extensionOid = get_extension_oid(extensionName, false);
2724 
2725  nspOid = LookupCreationNamespace(newschema);
2726 
2727  /*
2728  * Permission check: must own extension. Note that we don't bother to
2729  * check ownership of the individual member objects ...
2730  */
2731  if (!pg_extension_ownercheck(extensionOid, GetUserId()))
2733  extensionName);
2734 
2735  /* Permission check: must have creation rights in target namespace */
2736  aclresult = pg_namespace_aclcheck(nspOid, GetUserId(), ACL_CREATE);
2737  if (aclresult != ACLCHECK_OK)
2738  aclcheck_error(aclresult, OBJECT_SCHEMA, newschema);
2739 
2740  /*
2741  * If the schema is currently a member of the extension, disallow moving
2742  * the extension into the schema. That would create a dependency loop.
2743  */
2744  if (getExtensionOfObject(NamespaceRelationId, nspOid) == extensionOid)
2745  ereport(ERROR,
2746  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2747  errmsg("cannot move extension \"%s\" into schema \"%s\" "
2748  "because the extension contains the schema",
2749  extensionName, newschema)));
2750 
2751  /* Locate the pg_extension tuple */
2752  extRel = table_open(ExtensionRelationId, RowExclusiveLock);
2753 
2754  ScanKeyInit(&key[0],
2755  Anum_pg_extension_oid,
2756  BTEqualStrategyNumber, F_OIDEQ,
2757  ObjectIdGetDatum(extensionOid));
2758 
2759  extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
2760  NULL, 1, key);
2761 
2762  extTup = systable_getnext(extScan);
2763 
2764  if (!HeapTupleIsValid(extTup)) /* should not happen */
2765  elog(ERROR, "could not find tuple for extension %u",
2766  extensionOid);
2767 
2768  /* Copy tuple so we can modify it below */
2769  extTup = heap_copytuple(extTup);
2770  extForm = (Form_pg_extension) GETSTRUCT(extTup);
2771 
2772  systable_endscan(extScan);
2773 
2774  /*
2775  * If the extension is already in the target schema, just silently do
2776  * nothing.
2777  */
2778  if (extForm->extnamespace == nspOid)
2779  {
2780  table_close(extRel, RowExclusiveLock);
2781  return InvalidObjectAddress;
2782  }
2783 
2784  /* Check extension is supposed to be relocatable */
2785  if (!extForm->extrelocatable)
2786  ereport(ERROR,
2787  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2788  errmsg("extension \"%s\" does not support SET SCHEMA",
2789  NameStr(extForm->extname))));
2790 
2791  objsMoved = new_object_addresses();
2792 
2793  /*
2794  * Scan pg_depend to find objects that depend directly on the extension,
2795  * and alter each one's schema.
2796  */
2797  depRel = table_open(DependRelationId, AccessShareLock);
2798 
2799  ScanKeyInit(&key[0],
2800  Anum_pg_depend_refclassid,
2801  BTEqualStrategyNumber, F_OIDEQ,
2802  ObjectIdGetDatum(ExtensionRelationId));
2803  ScanKeyInit(&key[1],
2804  Anum_pg_depend_refobjid,
2805  BTEqualStrategyNumber, F_OIDEQ,
2806  ObjectIdGetDatum(extensionOid));
2807 
2808  depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
2809  NULL, 2, key);
2810 
2811  while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
2812  {
2813  Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
2814  ObjectAddress dep;
2815  Oid dep_oldNspOid;
2816 
2817  /*
2818  * Ignore non-membership dependencies. (Currently, the only other
2819  * case we could see here is a normal dependency from another
2820  * extension.)
2821  */
2822  if (pg_depend->deptype != DEPENDENCY_EXTENSION)
2823  continue;
2824 
2825  dep.classId = pg_depend->classid;
2826  dep.objectId = pg_depend->objid;
2827  dep.objectSubId = pg_depend->objsubid;
2828 
2829  if (dep.objectSubId != 0) /* should not happen */
2830  elog(ERROR, "extension should not have a sub-object dependency");
2831 
2832  /* Relocate the object */
2833  dep_oldNspOid = AlterObjectNamespace_oid(dep.classId,
2834  dep.objectId,
2835  nspOid,
2836  objsMoved);
2837 
2838  /*
2839  * Remember previous namespace of first object that has one
2840  */
2841  if (oldNspOid == InvalidOid && dep_oldNspOid != InvalidOid)
2842  oldNspOid = dep_oldNspOid;
2843 
2844  /*
2845  * If not all the objects had the same old namespace (ignoring any
2846  * that are not in namespaces), complain.
2847  */
2848  if (dep_oldNspOid != InvalidOid && dep_oldNspOid != oldNspOid)
2849  ereport(ERROR,
2850  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2851  errmsg("extension \"%s\" does not support SET SCHEMA",
2852  NameStr(extForm->extname)),
2853  errdetail("%s is not in the extension's schema \"%s\"",
2854  getObjectDescription(&dep, false),
2855  get_namespace_name(oldNspOid))));
2856  }
2857 
2858  /* report old schema, if caller wants it */
2859  if (oldschema)
2860  *oldschema = oldNspOid;
2861 
2862  systable_endscan(depScan);
2863 
2865 
2866  /* Now adjust pg_extension.extnamespace */
2867  extForm->extnamespace = nspOid;
2868 
2869  CatalogTupleUpdate(extRel, &extTup->t_self, extTup);
2870 
2871  table_close(extRel, RowExclusiveLock);
2872 
2873  /* update dependencies to point to the new schema */
2874  changeDependencyFor(ExtensionRelationId, extensionOid,
2875  NamespaceRelationId, oldNspOid, nspOid);
2876 
2877  InvokeObjectPostAlterHook(ExtensionRelationId, extensionOid, 0);
2878 
2879  ObjectAddressSet(extAddr, ExtensionRelationId, extensionOid);
2880 
2881  return extAddr;
2882 }
AclResult
Definition: acl.h:181
@ ACLCHECK_OK
Definition: acl.h:182
@ ACLCHECK_NOT_OWNER
Definition: acl.h:184
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:5109
bool pg_extension_ownercheck(Oid ext_oid, Oid roleid)
Definition: aclchk.c:5667
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3512
Oid AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: alter.c:589
#define NameStr(name)
Definition: c.h:681
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2447
@ DEPENDENCY_EXTENSION
Definition: dependency.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:1037
int errcode(int sqlerrcode)
Definition: elog.c:693
int errmsg(const char *fmt,...)
Definition: elog.c:904
#define ERROR
Definition: elog.h:33
#define elog(elevel,...)
Definition: elog.h:218
#define ereport(elevel,...)
Definition: elog.h:143
Oid get_extension_oid(const char *extname, bool missing_ok)
Definition: extension.c:140
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:598
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:505
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:386
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:680
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:649
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
#define AccessShareLock
Definition: lockdefs.h:36
#define RowExclusiveLock
Definition: lockdefs.h:38
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3326
Oid GetUserId(void)
Definition: miscinit.c:492
Oid LookupCreationNamespace(const char *nspname)
Definition: namespace.c:2982
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:195
char * getObjectDescription(const ObjectAddress *object, bool missing_ok)
const ObjectAddress InvalidObjectAddress
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
@ OBJECT_SCHEMA
Definition: parsenodes.h:2170
@ OBJECT_EXTENSION
Definition: parsenodes.h:2149
#define ACL_CREATE
Definition: parsenodes.h:91
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:399
Oid getExtensionOfObject(Oid classId, Oid objectId)
Definition: pg_depend.c:674
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:72
FormData_pg_extension * Form_pg_extension
Definition: pg_extension.h:52
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define BTEqualStrategyNumber
Definition: stratnum.h:31
ItemPointerData t_self
Definition: htup.h:65
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39

References AccessShareLock, ACL_CREATE, aclcheck_error(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, AlterObjectNamespace_oid(), BTEqualStrategyNumber, CatalogTupleUpdate(), changeDependencyFor(), ObjectAddress::classId, DEPENDENCY_EXTENSION, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, get_extension_oid(), get_namespace_name(), getExtensionOfObject(), getObjectDescription(), GETSTRUCT, GetUserId(), heap_copytuple(), HeapTupleIsValid, InvalidObjectAddress, InvalidOid, InvokeObjectPostAlterHook, sort-test::key, LookupCreationNamespace(), NameStr, new_object_addresses(), OBJECT_EXTENSION, OBJECT_SCHEMA, ObjectAddressSet, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, pg_extension_ownercheck(), pg_namespace_aclcheck(), relation_close(), RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by ExecAlterObjectSchemaStmt().

◆ CreateExtension()

ObjectAddress CreateExtension ( ParseState pstate,
CreateExtensionStmt stmt 
)

Definition at line 1692 of file extension.c.

1693 {
1694  DefElem *d_schema = NULL;
1695  DefElem *d_new_version = NULL;
1696  DefElem *d_cascade = NULL;
1697  char *schemaName = NULL;
1698  char *versionName = NULL;
1699  bool cascade = false;
1700  ListCell *lc;
1701 
1702  /* Check extension name validity before any filesystem access */
1704 
1705  /*
1706  * Check for duplicate extension name. The unique index on
1707  * pg_extension.extname would catch this anyway, and serves as a backstop
1708  * in case of race conditions; but this is a friendlier error message, and
1709  * besides we need a check to support IF NOT EXISTS.
1710  */
1711  if (get_extension_oid(stmt->extname, true) != InvalidOid)
1712  {
1713  if (stmt->if_not_exists)
1714  {
1715  ereport(NOTICE,
1717  errmsg("extension \"%s\" already exists, skipping",
1718  stmt->extname)));
1719  return InvalidObjectAddress;
1720  }
1721  else
1722  ereport(ERROR,
1724  errmsg("extension \"%s\" already exists",
1725  stmt->extname)));
1726  }
1727 
1728  /*
1729  * We use global variables to track the extension being created, so we can
1730  * create only one extension at the same time.
1731  */
1732  if (creating_extension)
1733  ereport(ERROR,
1734  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1735  errmsg("nested CREATE EXTENSION is not supported")));
1736 
1737  /* Deconstruct the statement option list */
1738  foreach(lc, stmt->options)
1739  {
1740  DefElem *defel = (DefElem *) lfirst(lc);
1741 
1742  if (strcmp(defel->defname, "schema") == 0)
1743  {
1744  if (d_schema)
1745  errorConflictingDefElem(defel, pstate);
1746  d_schema = defel;
1747  schemaName = defGetString(d_schema);
1748  }
1749  else if (strcmp(defel->defname, "new_version") == 0)
1750  {
1751  if (d_new_version)
1752  errorConflictingDefElem(defel, pstate);
1753  d_new_version = defel;
1754  versionName = defGetString(d_new_version);
1755  }
1756  else if (strcmp(defel->defname, "cascade") == 0)
1757  {
1758  if (d_cascade)
1759  errorConflictingDefElem(defel, pstate);
1760  d_cascade = defel;
1761  cascade = defGetBoolean(d_cascade);
1762  }
1763  else
1764  elog(ERROR, "unrecognized option: %s", defel->defname);
1765  }
1766 
1767  /* Call CreateExtensionInternal to do the real work. */
1768  return CreateExtensionInternal(stmt->extname,
1769  schemaName,
1770  versionName,
1771  cascade,
1772  NIL,
1773  true);
1774 }
bool defGetBoolean(DefElem *def)
Definition: define.c:108
char * defGetString(DefElem *def)
Definition: define.c:49
void errorConflictingDefElem(DefElem *defel, ParseState *pstate)
Definition: define.c:352
#define NOTICE
Definition: elog.h:29
static void check_valid_extension_name(const char *extensionname)
Definition: extension.c:261
bool creating_extension
Definition: extension.c:71
static ObjectAddress CreateExtensionInternal(char *extensionName, char *schemaName, const char *versionName, bool cascade, List *parents, bool is_create)
Definition: extension.c:1382
#define lfirst(lc)
Definition: pg_list.h:169
#define NIL
Definition: pg_list.h:65
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
char * defname
Definition: parsenodes.h:765

References check_valid_extension_name(), CreateExtensionInternal(), creating_extension, defGetBoolean(), defGetString(), DefElem::defname, elog, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, errorConflictingDefElem(), CreateExtensionStmt::extname, get_extension_oid(), CreateExtensionStmt::if_not_exists, InvalidObjectAddress, InvalidOid, lfirst, NIL, NOTICE, and CreateExtensionStmt::options.

Referenced by ProcessUtilitySlow().

◆ ExecAlterExtensionContentsStmt()

ObjectAddress ExecAlterExtensionContentsStmt ( AlterExtensionContentsStmt stmt,
ObjectAddress objAddr 
)

Definition at line 3193 of file extension.c.

3195 {
3196  ObjectAddress extension;
3197  ObjectAddress object;
3198  Relation relation;
3199  Oid oldExtension;
3200 
3201  switch (stmt->objtype)
3202  {
3203  case OBJECT_DATABASE:
3204  case OBJECT_EXTENSION:
3205  case OBJECT_INDEX:
3206  case OBJECT_PUBLICATION:
3207  case OBJECT_ROLE:
3208  case OBJECT_STATISTIC_EXT:
3209  case OBJECT_SUBSCRIPTION:
3210  case OBJECT_TABLESPACE:
3211  ereport(ERROR,
3212  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3213  errmsg("cannot add an object of this type to an extension")));
3214  break;
3215  default:
3216  /* OK */
3217  break;
3218  }
3219 
3220  /*
3221  * Find the extension and acquire a lock on it, to ensure it doesn't get
3222  * dropped concurrently. A sharable lock seems sufficient: there's no
3223  * reason not to allow other sorts of manipulations, such as add/drop of
3224  * other objects, to occur concurrently. Concurrently adding/dropping the
3225  * *same* object would be bad, but we prevent that by using a non-sharable
3226  * lock on the individual object, below.
3227  */
3229  (Node *) makeString(stmt->extname),
3230  &relation, AccessShareLock, false);
3231 
3232  /* Permission check: must own extension */
3233  if (!pg_extension_ownercheck(extension.objectId, GetUserId()))
3235  stmt->extname);
3236 
3237  /*
3238  * Translate the parser representation that identifies the object into an
3239  * ObjectAddress. get_object_address() will throw an error if the object
3240  * does not exist, and will also acquire a lock on the object to guard
3241  * against concurrent DROP and ALTER EXTENSION ADD/DROP operations.
3242  */
3243  object = get_object_address(stmt->objtype, stmt->object,
3244  &relation, ShareUpdateExclusiveLock, false);
3245 
3246  Assert(object.objectSubId == 0);
3247  if (objAddr)
3248  *objAddr = object;
3249 
3250  /* Permission check: must own target object, too */
3251  check_object_ownership(GetUserId(), stmt->objtype, object,
3252  stmt->object, relation);
3253 
3254  /*
3255  * Check existing extension membership.
3256  */
3257  oldExtension = getExtensionOfObject(object.classId, object.objectId);
3258 
3259  if (stmt->action > 0)
3260  {
3261  /*
3262  * ADD, so complain if object is already attached to some extension.
3263  */
3264  if (OidIsValid(oldExtension))
3265  ereport(ERROR,
3266  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3267  errmsg("%s is already a member of extension \"%s\"",
3268  getObjectDescription(&object, false),
3269  get_extension_name(oldExtension))));
3270 
3271  /*
3272  * Prevent a schema from being added to an extension if the schema
3273  * contains the extension. That would create a dependency loop.
3274  */
3275  if (object.classId == NamespaceRelationId &&
3276  object.objectId == get_extension_schema(extension.objectId))
3277  ereport(ERROR,
3278  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3279  errmsg("cannot add schema \"%s\" to extension \"%s\" "
3280  "because the schema contains the extension",
3281  get_namespace_name(object.objectId),
3282  stmt->extname)));
3283 
3284  /*
3285  * OK, add the dependency.
3286  */
3287  recordDependencyOn(&object, &extension, DEPENDENCY_EXTENSION);
3288 
3289  /*
3290  * Also record the initial ACL on the object, if any.
3291  *
3292  * Note that this will handle the object's ACLs, as well as any ACLs
3293  * on object subIds. (In other words, when the object is a table,
3294  * this will record the table's ACL and the ACLs for the columns on
3295  * the table, if any).
3296  */
3297  recordExtObjInitPriv(object.objectId, object.classId);
3298  }
3299  else
3300  {
3301  /*
3302  * DROP, so complain if it's not a member.
3303  */
3304  if (oldExtension != extension.objectId)
3305  ereport(ERROR,
3306  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3307  errmsg("%s is not a member of extension \"%s\"",
3308  getObjectDescription(&object, false),
3309  stmt->extname)));
3310 
3311  /*
3312  * OK, drop the dependency.
3313  */
3314  if (deleteDependencyRecordsForClass(object.classId, object.objectId,
3315  ExtensionRelationId,
3316  DEPENDENCY_EXTENSION) != 1)
3317  elog(ERROR, "unexpected number of extension dependency records");
3318 
3319  /*
3320  * If it's a relation, it might have an entry in the extension's
3321  * extconfig array, which we must remove.
3322  */
3323  if (object.classId == RelationRelationId)
3324  extension_config_remove(extension.objectId, object.objectId);
3325 
3326  /*
3327  * Remove all the initial ACLs, if any.
3328  *
3329  * Note that this will remove the object's ACLs, as well as any ACLs
3330  * on object subIds. (In other words, when the object is a table,
3331  * this will remove the table's ACL and the ACLs for the columns on
3332  * the table, if any).
3333  */
3334  removeExtObjInitPriv(object.objectId, object.classId);
3335  }
3336 
3337  InvokeObjectPostAlterHook(ExtensionRelationId, extension.objectId, 0);
3338 
3339  /*
3340  * If get_object_address() opened the relation for us, we close it to keep
3341  * the reference count correct - but we retain any locks acquired by
3342  * get_object_address() until commit time, to guard against concurrent
3343  * activity.
3344  */
3345  if (relation != NULL)
3346  relation_close(relation, NoLock);
3347 
3348  return extension;
3349 }
void recordExtObjInitPriv(Oid objoid, Oid classoid)
Definition: aclchk.c:5980
void removeExtObjInitPriv(Oid objoid, Oid classoid)
Definition: aclchk.c:6278
#define OidIsValid(objectId)
Definition: c.h:710
static void extension_config_remove(Oid extensionoid, Oid tableoid)
Definition: extension.c:2537
static Oid get_extension_schema(Oid ext_oid)
Definition: extension.c:224
char * get_extension_name(Oid ext_oid)
Definition: extension.c:185
Assert(fmt[strlen(fmt) - 1] !='\n')
#define NoLock
Definition: lockdefs.h:34
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
void check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address, Node *object, Relation relation)
ObjectAddress get_object_address(ObjectType objtype, Node *object, Relation *relp, LOCKMODE lockmode, bool missing_ok)
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2176
@ OBJECT_ROLE
Definition: parsenodes.h:2167
@ OBJECT_INDEX
Definition: parsenodes.h:2154
@ OBJECT_DATABASE
Definition: parsenodes.h:2143
@ OBJECT_PUBLICATION
Definition: parsenodes.h:2164
@ OBJECT_SUBSCRIPTION
Definition: parsenodes.h:2172
@ OBJECT_STATISTIC_EXT
Definition: parsenodes.h:2173
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition: pg_depend.c:293
Definition: nodes.h:574
String * makeString(char *str)
Definition: value.c:63

References AccessShareLock, aclcheck_error(), ACLCHECK_NOT_OWNER, AlterExtensionContentsStmt::action, Assert(), check_object_ownership(), deleteDependencyRecordsForClass(), DEPENDENCY_EXTENSION, elog, ereport, errcode(), errmsg(), ERROR, extension_config_remove(), AlterExtensionContentsStmt::extname, get_extension_name(), get_extension_schema(), get_namespace_name(), get_object_address(), getExtensionOfObject(), getObjectDescription(), GetUserId(), InvokeObjectPostAlterHook, makeString(), NoLock, AlterExtensionContentsStmt::object, OBJECT_DATABASE, OBJECT_EXTENSION, OBJECT_INDEX, OBJECT_PUBLICATION, OBJECT_ROLE, OBJECT_STATISTIC_EXT, OBJECT_SUBSCRIPTION, OBJECT_TABLESPACE, ObjectAddress::objectId, AlterExtensionContentsStmt::objtype, OidIsValid, pg_extension_ownercheck(), recordDependencyOn(), recordExtObjInitPriv(), relation_close(), removeExtObjInitPriv(), and ShareUpdateExclusiveLock.

Referenced by ProcessUtilitySlow().

◆ ExecAlterExtensionStmt()

ObjectAddress ExecAlterExtensionStmt ( ParseState pstate,
AlterExtensionStmt stmt 
)

Definition at line 2888 of file extension.c.

2889 {
2890  DefElem *d_new_version = NULL;
2891  char *versionName;
2892  char *oldVersionName;
2893  ExtensionControlFile *control;
2894  Oid extensionOid;
2895  Relation extRel;
2896  ScanKeyData key[1];
2897  SysScanDesc extScan;
2898  HeapTuple extTup;
2899  List *updateVersions;
2900  Datum datum;
2901  bool isnull;
2902  ListCell *lc;
2903  ObjectAddress address;
2904 
2905  /*
2906  * We use global variables to track the extension being created, so we can
2907  * create/update only one extension at the same time.
2908  */
2909  if (creating_extension)
2910  ereport(ERROR,
2911  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2912  errmsg("nested ALTER EXTENSION is not supported")));
2913 
2914  /*
2915  * Look up the extension --- it must already exist in pg_extension
2916  */
2917  extRel = table_open(ExtensionRelationId, AccessShareLock);
2918 
2919  ScanKeyInit(&key[0],
2920  Anum_pg_extension_extname,
2921  BTEqualStrategyNumber, F_NAMEEQ,
2922  CStringGetDatum(stmt->extname));
2923 
2924  extScan = systable_beginscan(extRel, ExtensionNameIndexId, true,
2925  NULL, 1, key);
2926 
2927  extTup = systable_getnext(extScan);
2928 
2929  if (!HeapTupleIsValid(extTup))
2930  ereport(ERROR,
2931  (errcode(ERRCODE_UNDEFINED_OBJECT),
2932  errmsg("extension \"%s\" does not exist",
2933  stmt->extname)));
2934 
2935  extensionOid = ((Form_pg_extension) GETSTRUCT(extTup))->oid;
2936 
2937  /*
2938  * Determine the existing version we are updating from
2939  */
2940  datum = heap_getattr(extTup, Anum_pg_extension_extversion,
2941  RelationGetDescr(extRel), &isnull);
2942  if (isnull)
2943  elog(ERROR, "extversion is null");
2944  oldVersionName = text_to_cstring(DatumGetTextPP(datum));
2945 
2946  systable_endscan(extScan);
2947 
2948  table_close(extRel, AccessShareLock);
2949 
2950  /* Permission check: must own extension */
2951  if (!pg_extension_ownercheck(extensionOid, GetUserId()))
2953  stmt->extname);
2954 
2955  /*
2956  * Read the primary control file. Note we assume that it does not contain
2957  * any non-ASCII data, so there is no need to worry about encoding at this
2958  * point.
2959  */
2960  control = read_extension_control_file(stmt->extname);
2961 
2962  /*
2963  * Read the statement option list
2964  */
2965  foreach(lc, stmt->options)
2966  {
2967  DefElem *defel = (DefElem *) lfirst(lc);
2968 
2969  if (strcmp(defel->defname, "new_version") == 0)
2970  {
2971  if (d_new_version)
2972  errorConflictingDefElem(defel, pstate);
2973  d_new_version = defel;
2974  }
2975  else
2976  elog(ERROR, "unrecognized option: %s", defel->defname);
2977  }
2978 
2979  /*
2980  * Determine the version to update to
2981  */
2982  if (d_new_version && d_new_version->arg)
2983  versionName = strVal(d_new_version->arg);
2984  else if (control->default_version)
2985  versionName = control->default_version;
2986  else
2987  {
2988  ereport(ERROR,
2989  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2990  errmsg("version to install must be specified")));
2991  versionName = NULL; /* keep compiler quiet */
2992  }
2993  check_valid_version_name(versionName);
2994 
2995  /*
2996  * If we're already at that version, just say so
2997  */
2998  if (strcmp(oldVersionName, versionName) == 0)
2999  {
3000  ereport(NOTICE,
3001  (errmsg("version \"%s\" of extension \"%s\" is already installed",
3002  versionName, stmt->extname)));
3003  return InvalidObjectAddress;
3004  }
3005 
3006  /*
3007  * Identify the series of update script files we need to execute
3008  */
3009  updateVersions = identify_update_path(control,
3010  oldVersionName,
3011  versionName);
3012 
3013  /*
3014  * Update the pg_extension row and execute the update scripts, one at a
3015  * time
3016  */
3017  ApplyExtensionUpdates(extensionOid, control,
3018  oldVersionName, updateVersions,
3019  NULL, false, false);
3020 
3021  ObjectAddressSet(address, ExtensionRelationId, extensionOid);
3022 
3023  return address;
3024 }
static List * identify_update_path(ExtensionControlFile *control, const char *oldVersion, const char *newVersion)
Definition: extension.c:1191
static void check_valid_version_name(const char *versionname)
Definition: extension.c:308
static ExtensionControlFile * read_extension_control_file(const char *extname)
Definition: extension.c:627
static void ApplyExtensionUpdates(Oid extensionOid, ExtensionControlFile *pcontrol, const char *initialVersion, List *updateVersions, char *origSchemaName, bool cascade, bool is_create)
Definition: extension.c:3035
#define DatumGetTextPP(X)
Definition: fmgr.h:292
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:788
#define CStringGetDatum(X)
Definition: postgres.h:622
uintptr_t Datum
Definition: postgres.h:411
#define RelationGetDescr(relation)
Definition: rel.h:515
Node * arg
Definition: parsenodes.h:766
char * default_version
Definition: extension.c:81
Definition: pg_list.h:51
#define strVal(v)
Definition: value.h:72
char * text_to_cstring(const text *t)
Definition: varlena.c:221

References AccessShareLock, aclcheck_error(), ACLCHECK_NOT_OWNER, ApplyExtensionUpdates(), DefElem::arg, BTEqualStrategyNumber, check_valid_version_name(), creating_extension, CStringGetDatum, DatumGetTextPP, ExtensionControlFile::default_version, DefElem::defname, elog, ereport, errcode(), errmsg(), ERROR, errorConflictingDefElem(), AlterExtensionStmt::extname, GETSTRUCT, GetUserId(), heap_getattr(), HeapTupleIsValid, identify_update_path(), InvalidObjectAddress, sort-test::key, lfirst, NOTICE, OBJECT_EXTENSION, ObjectAddressSet, AlterExtensionStmt::options, pg_extension_ownercheck(), read_extension_control_file(), RelationGetDescr, ScanKeyInit(), strVal, systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), and text_to_cstring().

Referenced by ProcessUtilitySlow().

◆ extension_file_exists()

bool extension_file_exists ( const char *  extensionName)

Definition at line 2184 of file extension.c.

2185 {
2186  bool result = false;
2187  char *location;
2188  DIR *dir;
2189  struct dirent *de;
2190 
2191  location = get_extension_control_directory();
2192  dir = AllocateDir(location);
2193 
2194  /*
2195  * If the control directory doesn't exist, we want to silently return
2196  * false. Any other error will be reported by ReadDir.
2197  */
2198  if (dir == NULL && errno == ENOENT)
2199  {
2200  /* do nothing */
2201  }
2202  else
2203  {
2204  while ((de = ReadDir(dir, location)) != NULL)
2205  {
2206  char *extname;
2207 
2209  continue;
2210 
2211  /* extract extension name from 'name.control' filename */
2212  extname = pstrdup(de->d_name);
2213  *strrchr(extname, '.') = '\0';
2214 
2215  /* ignore it if it's an auxiliary control file */
2216  if (strstr(extname, "--"))
2217  continue;
2218 
2219  /* done if it matches request */
2220  if (strcmp(extname, extensionName) == 0)
2221  {
2222  result = true;
2223  break;
2224  }
2225  }
2226 
2227  FreeDir(dir);
2228  }
2229 
2230  return result;
2231 }
static bool is_extension_control_filename(const char *filename)
Definition: extension.c:355
static char * get_extension_control_directory(void)
Definition: extension.c:371
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2788
int FreeDir(DIR *dir)
Definition: fd.c:2840
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2722
char * pstrdup(const char *in)
Definition: mcxt.c:1305
Definition: dirent.c:26
Definition: dirent.h:10
char d_name[MAX_PATH]
Definition: dirent.h:15

References AllocateDir(), dirent::d_name, FreeDir(), get_extension_control_directory(), is_extension_control_filename(), pstrdup(), and ReadDir().

Referenced by CreateFunction(), and ExecuteDoStmt().

◆ get_extension_name()

char* get_extension_name ( Oid  ext_oid)

Definition at line 185 of file extension.c.

186 {
187  char *result;
188  Relation rel;
189  SysScanDesc scandesc;
190  HeapTuple tuple;
191  ScanKeyData entry[1];
192 
193  rel = table_open(ExtensionRelationId, AccessShareLock);
194 
195  ScanKeyInit(&entry[0],
196  Anum_pg_extension_oid,
197  BTEqualStrategyNumber, F_OIDEQ,
198  ObjectIdGetDatum(ext_oid));
199 
200  scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
201  NULL, 1, entry);
202 
203  tuple = systable_getnext(scandesc);
204 
205  /* We assume that there can be at most one matching tuple */
206  if (HeapTupleIsValid(tuple))
207  result = pstrdup(NameStr(((Form_pg_extension) GETSTRUCT(tuple))->extname));
208  else
209  result = NULL;
210 
211  systable_endscan(scandesc);
212 
214 
215  return result;
216 }

References AccessShareLock, BTEqualStrategyNumber, GETSTRUCT, HeapTupleIsValid, NameStr, ObjectIdGetDatum, pstrdup(), ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by ExecAlterExtensionContentsStmt(), getObjectDescription(), getObjectIdentityParts(), recordDependencyOnCurrentExtension(), and RemoveExtensionById().

◆ get_extension_oid()

Oid get_extension_oid ( const char *  extname,
bool  missing_ok 
)

Definition at line 140 of file extension.c.

141 {
142  Oid result;
143  Relation rel;
144  SysScanDesc scandesc;
145  HeapTuple tuple;
146  ScanKeyData entry[1];
147 
148  rel = table_open(ExtensionRelationId, AccessShareLock);
149 
150  ScanKeyInit(&entry[0],
151  Anum_pg_extension_extname,
152  BTEqualStrategyNumber, F_NAMEEQ,
153  CStringGetDatum(extname));
154 
155  scandesc = systable_beginscan(rel, ExtensionNameIndexId, true,
156  NULL, 1, entry);
157 
158  tuple = systable_getnext(scandesc);
159 
160  /* We assume that there can be at most one matching tuple */
161  if (HeapTupleIsValid(tuple))
162  result = ((Form_pg_extension) GETSTRUCT(tuple))->oid;
163  else
164  result = InvalidOid;
165 
166  systable_endscan(scandesc);
167 
169 
170  if (!OidIsValid(result) && !missing_ok)
171  ereport(ERROR,
172  (errcode(ERRCODE_UNDEFINED_OBJECT),
173  errmsg("extension \"%s\" does not exist",
174  extname)));
175 
176  return result;
177 }

References AccessShareLock, BTEqualStrategyNumber, CStringGetDatum, ereport, errcode(), errmsg(), ERROR, GETSTRUCT, HeapTupleIsValid, InvalidOid, OidIsValid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by AlterExtensionNamespace(), binary_upgrade_create_empty_extension(), CreateExtension(), ExtractExtensionList(), get_object_address_unqualified(), and get_required_extension().

◆ InsertExtensionTuple()

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

Definition at line 1790 of file extension.c.

1794 {
1795  Oid extensionOid;
1796  Relation rel;
1797  Datum values[Natts_pg_extension];
1798  bool nulls[Natts_pg_extension];
1799  HeapTuple tuple;
1800  ObjectAddress myself;
1801  ObjectAddress nsp;
1802  ObjectAddresses *refobjs;
1803  ListCell *lc;
1804 
1805  /*
1806  * Build and insert the pg_extension tuple
1807  */
1808  rel = table_open(ExtensionRelationId, RowExclusiveLock);
1809 
1810  memset(values, 0, sizeof(values));
1811  memset(nulls, 0, sizeof(nulls));
1812 
1813  extensionOid = GetNewOidWithIndex(rel, ExtensionOidIndexId,
1814  Anum_pg_extension_oid);
1815  values[Anum_pg_extension_oid - 1] = ObjectIdGetDatum(extensionOid);
1816  values[Anum_pg_extension_extname - 1] =
1818  values[Anum_pg_extension_extowner - 1] = ObjectIdGetDatum(extOwner);
1819  values[Anum_pg_extension_extnamespace - 1] = ObjectIdGetDatum(schemaOid);
1820  values[Anum_pg_extension_extrelocatable - 1] = BoolGetDatum(relocatable);
1821  values[Anum_pg_extension_extversion - 1] = CStringGetTextDatum(extVersion);
1822 
1823  if (extConfig == PointerGetDatum(NULL))
1824  nulls[Anum_pg_extension_extconfig - 1] = true;
1825  else
1826  values[Anum_pg_extension_extconfig - 1] = extConfig;
1827 
1828  if (extCondition == PointerGetDatum(NULL))
1829  nulls[Anum_pg_extension_extcondition - 1] = true;
1830  else
1831  values[Anum_pg_extension_extcondition - 1] = extCondition;
1832 
1833  tuple = heap_form_tuple(rel->rd_att, values, nulls);
1834 
1835  CatalogTupleInsert(rel, tuple);
1836 
1837  heap_freetuple(tuple);
1839 
1840  /*
1841  * Record dependencies on owner, schema, and prerequisite extensions
1842  */
1843  recordDependencyOnOwner(ExtensionRelationId, extensionOid, extOwner);
1844 
1845  refobjs = new_object_addresses();
1846 
1847  ObjectAddressSet(myself, ExtensionRelationId, extensionOid);
1848 
1849  ObjectAddressSet(nsp, NamespaceRelationId, schemaOid);
1850  add_exact_object_address(&nsp, refobjs);
1851 
1852  foreach(lc, requiredExtensions)
1853  {
1854  Oid reqext = lfirst_oid(lc);
1855  ObjectAddress otherext;
1856 
1857  ObjectAddressSet(otherext, ExtensionRelationId, reqext);
1858  add_exact_object_address(&otherext, refobjs);
1859  }
1860 
1861  /* Record all of them (this includes duplicate elimination) */
1863  free_object_addresses(refobjs);
1864 
1865  /* Post creation hook for new extension */
1866  InvokeObjectPostCreateHook(ExtensionRelationId, extensionOid, 0);
1867 
1868  return myself;
1869 }
static Datum values[MAXATTR]
Definition: bootstrap.c:156
#define CStringGetTextDatum(s)
Definition: builtins.h:85
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:391
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
Definition: dependency.c:2711
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2502
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2742
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:631
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:221
Datum namein(PG_FUNCTION_ARGS)
Definition: name.c:48
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:171
#define lfirst_oid(lc)
Definition: pg_list.h:171
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:164
#define BoolGetDatum(X)
Definition: postgres.h:446
#define PointerGetDatum(X)
Definition: postgres.h:600
TupleDesc rd_att
Definition: rel.h:110

References add_exact_object_address(), BoolGetDatum, CatalogTupleInsert(), CStringGetDatum, CStringGetTextDatum, DEPENDENCY_NORMAL, DirectFunctionCall1, free_object_addresses(), GetNewOidWithIndex(), heap_form_tuple(), heap_freetuple(), InvokeObjectPostCreateHook, lfirst_oid, namein(), new_object_addresses(), ObjectAddressSet, ObjectIdGetDatum, PointerGetDatum, RelationData::rd_att, record_object_address_dependencies(), recordDependencyOnOwner(), RowExclusiveLock, table_close(), table_open(), and values.

Referenced by binary_upgrade_create_empty_extension(), and CreateExtensionInternal().

◆ RemoveExtensionById()

void RemoveExtensionById ( Oid  extId)

Definition at line 1878 of file extension.c.

1879 {
1880  Relation rel;
1881  SysScanDesc scandesc;
1882  HeapTuple tuple;
1883  ScanKeyData entry[1];
1884 
1885  /*
1886  * Disallow deletion of any extension that's currently open for insertion;
1887  * else subsequent executions of recordDependencyOnCurrentExtension()
1888  * could create dangling pg_depend records that refer to a no-longer-valid
1889  * pg_extension OID. This is needed not so much because we think people
1890  * might write "DROP EXTENSION foo" in foo's own script files, as because
1891  * errors in dependency management in extension script files could give
1892  * rise to cases where an extension is dropped as a result of recursing
1893  * from some contained object. Because of that, we must test for the case
1894  * here, not at some higher level of the DROP EXTENSION command.
1895  */
1896  if (extId == CurrentExtensionObject)
1897  ereport(ERROR,
1898  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1899  errmsg("cannot drop extension \"%s\" because it is being modified",
1900  get_extension_name(extId))));
1901 
1902  rel = table_open(ExtensionRelationId, RowExclusiveLock);
1903 
1904  ScanKeyInit(&entry[0],
1905  Anum_pg_extension_oid,
1906  BTEqualStrategyNumber, F_OIDEQ,
1907  ObjectIdGetDatum(extId));
1908  scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
1909  NULL, 1, entry);
1910 
1911  tuple = systable_getnext(scandesc);
1912 
1913  /* We assume that there can be at most one matching tuple */
1914  if (HeapTupleIsValid(tuple))
1915  CatalogTupleDelete(rel, &tuple->t_self);
1916 
1917  systable_endscan(scandesc);
1918 
1920 }
Oid CurrentExtensionObject
Definition: extension.c:72
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:350

References BTEqualStrategyNumber, CatalogTupleDelete(), CurrentExtensionObject, ereport, errcode(), errmsg(), ERROR, get_extension_name(), HeapTupleIsValid, ObjectIdGetDatum, RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by doDeletion().

Variable Documentation

◆ creating_extension

◆ CurrentExtensionObject