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 2708 of file extension.c.

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

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_aclcheck(), OBJECT_EXTENSION, object_ownercheck(), OBJECT_SCHEMA, ObjectAddressSet, ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, 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 1704 of file extension.c.

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

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 3195 of file extension.c.

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

Referenced by ProcessUtilitySlow().

◆ ExecAlterExtensionStmt()

ObjectAddress ExecAlterExtensionStmt ( ParseState pstate,
AlterExtensionStmt stmt 
)

Definition at line 2890 of file extension.c.

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

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, object_ownercheck(), ObjectAddressSet, AlterExtensionStmt::options, 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 2196 of file extension.c.

2197 {
2198  bool result = false;
2199  char *location;
2200  DIR *dir;
2201  struct dirent *de;
2202 
2203  location = get_extension_control_directory();
2204  dir = AllocateDir(location);
2205 
2206  /*
2207  * If the control directory doesn't exist, we want to silently return
2208  * false. Any other error will be reported by ReadDir.
2209  */
2210  if (dir == NULL && errno == ENOENT)
2211  {
2212  /* do nothing */
2213  }
2214  else
2215  {
2216  while ((de = ReadDir(dir, location)) != NULL)
2217  {
2218  char *extname;
2219 
2221  continue;
2222 
2223  /* extract extension name from 'name.control' filename */
2224  extname = pstrdup(de->d_name);
2225  *strrchr(extname, '.') = '\0';
2226 
2227  /* ignore it if it's an auxiliary control file */
2228  if (strstr(extname, "--"))
2229  continue;
2230 
2231  /* done if it matches request */
2232  if (strcmp(extname, extensionName) == 0)
2233  {
2234  result = true;
2235  break;
2236  }
2237  }
2238 
2239  FreeDir(dir);
2240  }
2241 
2242  return result;
2243 }
static bool is_extension_control_filename(const char *filename)
Definition: extension.c:357
static char * get_extension_control_directory(void)
Definition: extension.c:373
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2709
int FreeDir(DIR *dir)
Definition: fd.c:2761
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2643
char * pstrdup(const char *in)
Definition: mcxt.c:1624
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 187 of file extension.c.

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

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

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

◆ get_extension_oid()

Oid get_extension_oid ( const char *  extname,
bool  missing_ok 
)

Definition at line 142 of file extension.c.

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

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 1802 of file extension.c.

1806 {
1807  Oid extensionOid;
1808  Relation rel;
1809  Datum values[Natts_pg_extension];
1810  bool nulls[Natts_pg_extension];
1811  HeapTuple tuple;
1812  ObjectAddress myself;
1813  ObjectAddress nsp;
1814  ObjectAddresses *refobjs;
1815  ListCell *lc;
1816 
1817  /*
1818  * Build and insert the pg_extension tuple
1819  */
1820  rel = table_open(ExtensionRelationId, RowExclusiveLock);
1821 
1822  memset(values, 0, sizeof(values));
1823  memset(nulls, 0, sizeof(nulls));
1824 
1825  extensionOid = GetNewOidWithIndex(rel, ExtensionOidIndexId,
1826  Anum_pg_extension_oid);
1827  values[Anum_pg_extension_oid - 1] = ObjectIdGetDatum(extensionOid);
1828  values[Anum_pg_extension_extname - 1] =
1830  values[Anum_pg_extension_extowner - 1] = ObjectIdGetDatum(extOwner);
1831  values[Anum_pg_extension_extnamespace - 1] = ObjectIdGetDatum(schemaOid);
1832  values[Anum_pg_extension_extrelocatable - 1] = BoolGetDatum(relocatable);
1833  values[Anum_pg_extension_extversion - 1] = CStringGetTextDatum(extVersion);
1834 
1835  if (extConfig == PointerGetDatum(NULL))
1836  nulls[Anum_pg_extension_extconfig - 1] = true;
1837  else
1838  values[Anum_pg_extension_extconfig - 1] = extConfig;
1839 
1840  if (extCondition == PointerGetDatum(NULL))
1841  nulls[Anum_pg_extension_extcondition - 1] = true;
1842  else
1843  values[Anum_pg_extension_extcondition - 1] = extCondition;
1844 
1845  tuple = heap_form_tuple(rel->rd_att, values, nulls);
1846 
1847  CatalogTupleInsert(rel, tuple);
1848 
1849  heap_freetuple(tuple);
1851 
1852  /*
1853  * Record dependencies on owner, schema, and prerequisite extensions
1854  */
1855  recordDependencyOnOwner(ExtensionRelationId, extensionOid, extOwner);
1856 
1857  refobjs = new_object_addresses();
1858 
1859  ObjectAddressSet(myself, ExtensionRelationId, extensionOid);
1860 
1861  ObjectAddressSet(nsp, NamespaceRelationId, schemaOid);
1862  add_exact_object_address(&nsp, refobjs);
1863 
1864  foreach(lc, requiredExtensions)
1865  {
1866  Oid reqext = lfirst_oid(lc);
1867  ObjectAddress otherext;
1868 
1869  ObjectAddressSet(otherext, ExtensionRelationId, reqext);
1870  add_exact_object_address(&otherext, refobjs);
1871  }
1872 
1873  /* Record all of them (this includes duplicate elimination) */
1875  free_object_addresses(refobjs);
1876 
1877  /* Post creation hook for new extension */
1878  InvokeObjectPostCreateHook(ExtensionRelationId, extensionOid, 0);
1879 
1880  return myself;
1881 }
static Datum values[MAXATTR]
Definition: bootstrap.c:156
#define CStringGetTextDatum(s)
Definition: builtins.h:94
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:393
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
Definition: dependency.c:2790
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2581
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2821
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:642
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:173
#define lfirst_oid(lc)
Definition: pg_list.h:174
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:165
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102
TupleDesc rd_att
Definition: rel.h:111

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 1890 of file extension.c.

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