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)
 
Oid get_extension_schema (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 2716 of file extension.c.

2717 {
2718  Oid extensionOid;
2719  Oid nspOid;
2720  Oid oldNspOid;
2721  AclResult aclresult;
2722  Relation extRel;
2723  ScanKeyData key[2];
2724  SysScanDesc extScan;
2725  HeapTuple extTup;
2726  Form_pg_extension extForm;
2727  Relation depRel;
2728  SysScanDesc depScan;
2729  HeapTuple depTup;
2730  ObjectAddresses *objsMoved;
2731  ObjectAddress extAddr;
2732 
2733  extensionOid = get_extension_oid(extensionName, false);
2734 
2735  nspOid = LookupCreationNamespace(newschema);
2736 
2737  /*
2738  * Permission check: must own extension. Note that we don't bother to
2739  * check ownership of the individual member objects ...
2740  */
2741  if (!object_ownercheck(ExtensionRelationId, extensionOid, GetUserId()))
2743  extensionName);
2744 
2745  /* Permission check: must have creation rights in target namespace */
2746  aclresult = object_aclcheck(NamespaceRelationId, nspOid, GetUserId(), ACL_CREATE);
2747  if (aclresult != ACLCHECK_OK)
2748  aclcheck_error(aclresult, OBJECT_SCHEMA, newschema);
2749 
2750  /*
2751  * If the schema is currently a member of the extension, disallow moving
2752  * the extension into the schema. That would create a dependency loop.
2753  */
2754  if (getExtensionOfObject(NamespaceRelationId, nspOid) == extensionOid)
2755  ereport(ERROR,
2756  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2757  errmsg("cannot move extension \"%s\" into schema \"%s\" "
2758  "because the extension contains the schema",
2759  extensionName, newschema)));
2760 
2761  /* Locate the pg_extension tuple */
2762  extRel = table_open(ExtensionRelationId, RowExclusiveLock);
2763 
2764  ScanKeyInit(&key[0],
2765  Anum_pg_extension_oid,
2766  BTEqualStrategyNumber, F_OIDEQ,
2767  ObjectIdGetDatum(extensionOid));
2768 
2769  extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
2770  NULL, 1, key);
2771 
2772  extTup = systable_getnext(extScan);
2773 
2774  if (!HeapTupleIsValid(extTup)) /* should not happen */
2775  elog(ERROR, "could not find tuple for extension %u",
2776  extensionOid);
2777 
2778  /* Copy tuple so we can modify it below */
2779  extTup = heap_copytuple(extTup);
2780  extForm = (Form_pg_extension) GETSTRUCT(extTup);
2781 
2782  systable_endscan(extScan);
2783 
2784  /*
2785  * If the extension is already in the target schema, just silently do
2786  * nothing.
2787  */
2788  if (extForm->extnamespace == nspOid)
2789  {
2790  table_close(extRel, RowExclusiveLock);
2791  return InvalidObjectAddress;
2792  }
2793 
2794  /* Check extension is supposed to be relocatable */
2795  if (!extForm->extrelocatable)
2796  ereport(ERROR,
2797  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2798  errmsg("extension \"%s\" does not support SET SCHEMA",
2799  NameStr(extForm->extname))));
2800 
2801  objsMoved = new_object_addresses();
2802 
2803  /* store the OID of the namespace to-be-changed */
2804  oldNspOid = extForm->extnamespace;
2805 
2806  /*
2807  * Scan pg_depend to find objects that depend directly on the extension,
2808  * and alter each one's schema.
2809  */
2810  depRel = table_open(DependRelationId, AccessShareLock);
2811 
2812  ScanKeyInit(&key[0],
2813  Anum_pg_depend_refclassid,
2814  BTEqualStrategyNumber, F_OIDEQ,
2815  ObjectIdGetDatum(ExtensionRelationId));
2816  ScanKeyInit(&key[1],
2817  Anum_pg_depend_refobjid,
2818  BTEqualStrategyNumber, F_OIDEQ,
2819  ObjectIdGetDatum(extensionOid));
2820 
2821  depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
2822  NULL, 2, key);
2823 
2824  while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
2825  {
2826  Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
2827  ObjectAddress dep;
2828  Oid dep_oldNspOid;
2829 
2830  /*
2831  * If a dependent extension has a no_relocate request for this
2832  * extension, disallow SET SCHEMA. (XXX it's a bit ugly to do this in
2833  * the same loop that's actually executing the renames: we may detect
2834  * the error condition only after having expended a fair amount of
2835  * work. However, the alternative is to do two scans of pg_depend,
2836  * which seems like optimizing for failure cases. The rename work
2837  * will all roll back cleanly enough if we do fail here.)
2838  */
2839  if (pg_depend->deptype == DEPENDENCY_NORMAL &&
2840  pg_depend->classid == ExtensionRelationId)
2841  {
2842  char *depextname = get_extension_name(pg_depend->objid);
2843  ExtensionControlFile *dcontrol;
2844  ListCell *lc;
2845 
2846  dcontrol = read_extension_control_file(depextname);
2847  foreach(lc, dcontrol->no_relocate)
2848  {
2849  char *nrextname = (char *) lfirst(lc);
2850 
2851  if (strcmp(nrextname, NameStr(extForm->extname)) == 0)
2852  {
2853  ereport(ERROR,
2854  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2855  errmsg("cannot SET SCHEMA of extension \"%s\" because other extensions prevent it",
2856  NameStr(extForm->extname)),
2857  errdetail("Extension \"%s\" requests no relocation of extension \"%s\".",
2858  depextname,
2859  NameStr(extForm->extname))));
2860  }
2861  }
2862  }
2863 
2864  /*
2865  * Otherwise, ignore non-membership dependencies. (Currently, the
2866  * only other case we could see here is a normal dependency from
2867  * another extension.)
2868  */
2869  if (pg_depend->deptype != DEPENDENCY_EXTENSION)
2870  continue;
2871 
2872  dep.classId = pg_depend->classid;
2873  dep.objectId = pg_depend->objid;
2874  dep.objectSubId = pg_depend->objsubid;
2875 
2876  if (dep.objectSubId != 0) /* should not happen */
2877  elog(ERROR, "extension should not have a sub-object dependency");
2878 
2879  /* Relocate the object */
2880  dep_oldNspOid = AlterObjectNamespace_oid(dep.classId,
2881  dep.objectId,
2882  nspOid,
2883  objsMoved);
2884 
2885  /*
2886  * If not all the objects had the same old namespace (ignoring any
2887  * that are not in namespaces or are dependent types), complain.
2888  */
2889  if (dep_oldNspOid != InvalidOid && dep_oldNspOid != oldNspOid)
2890  ereport(ERROR,
2891  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2892  errmsg("extension \"%s\" does not support SET SCHEMA",
2893  NameStr(extForm->extname)),
2894  errdetail("%s is not in the extension's schema \"%s\"",
2895  getObjectDescription(&dep, false),
2896  get_namespace_name(oldNspOid))));
2897  }
2898 
2899  /* report old schema, if caller wants it */
2900  if (oldschema)
2901  *oldschema = oldNspOid;
2902 
2903  systable_endscan(depScan);
2904 
2906 
2907  /* Now adjust pg_extension.extnamespace */
2908  extForm->extnamespace = nspOid;
2909 
2910  CatalogTupleUpdate(extRel, &extTup->t_self, extTup);
2911 
2912  table_close(extRel, RowExclusiveLock);
2913 
2914  /* update dependency to point to the new schema */
2915  if (changeDependencyFor(ExtensionRelationId, extensionOid,
2916  NamespaceRelationId, oldNspOid, nspOid) != 1)
2917  elog(ERROR, "could not change schema dependency for extension %s",
2918  NameStr(extForm->extname));
2919 
2920  InvokeObjectPostAlterHook(ExtensionRelationId, extensionOid, 0);
2921 
2922  ObjectAddressSet(extAddr, ExtensionRelationId, extensionOid);
2923 
2924  return extAddr;
2925 }
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:2703
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3891
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4145
Oid AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: alter.c:613
#define NameStr(name)
Definition: c.h:749
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2487
@ DEPENDENCY_EXTENSION
Definition: dependency.h:38
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
int errdetail(const char *fmt,...)
Definition: elog.c:1203
int errcode(int sqlerrcode)
Definition: elog.c:853
int errmsg(const char *fmt,...)
Definition: elog.c:1070
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define ereport(elevel,...)
Definition: elog.h:149
static ExtensionControlFile * read_extension_control_file(const char *extname)
Definition: extension.c:592
Oid get_extension_oid(const char *extname, bool missing_ok)
Definition: extension.c:146
char * get_extension_name(Oid ext_oid)
Definition: extension.c:168
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:604
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:511
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:776
#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:313
#define AccessShareLock
Definition: lockdefs.h:36
#define RowExclusiveLock
Definition: lockdefs.h:38
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3366
Oid GetUserId(void)
Definition: miscinit.c:514
Oid LookupCreationNamespace(const char *nspname)
Definition: namespace.c:3428
#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:2293
@ OBJECT_EXTENSION
Definition: parsenodes.h:2272
#define ACL_CREATE
Definition: parsenodes.h:85
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:458
Oid getExtensionOfObject(Oid classId, Oid objectId)
Definition: pg_depend.c:733
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:72
FormData_pg_extension * Form_pg_extension
Definition: pg_extension.h:52
#define lfirst(lc)
Definition: pg_list.h:172
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:205
#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, DEPENDENCY_NORMAL, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, get_extension_name(), get_extension_oid(), get_namespace_name(), getExtensionOfObject(), getObjectDescription(), GETSTRUCT, GetUserId(), heap_copytuple(), HeapTupleIsValid, InvalidObjectAddress, InvalidOid, InvokeObjectPostAlterHook, sort-test::key, lfirst, LookupCreationNamespace(), NameStr, new_object_addresses(), ExtensionControlFile::no_relocate, object_aclcheck(), OBJECT_EXTENSION, object_ownercheck(), OBJECT_SCHEMA, ObjectAddressSet, ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, read_extension_control_file(), 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 1712 of file extension.c.

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

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

Referenced by ProcessUtilitySlow().

◆ ExecAlterExtensionContentsStmt()

ObjectAddress ExecAlterExtensionContentsStmt ( AlterExtensionContentsStmt stmt,
ObjectAddress objAddr 
)

Definition at line 3236 of file extension.c.

3238 {
3239  ObjectAddress extension;
3240  ObjectAddress object;
3241  Relation relation;
3242 
3243  switch (stmt->objtype)
3244  {
3245  case OBJECT_DATABASE:
3246  case OBJECT_EXTENSION:
3247  case OBJECT_INDEX:
3248  case OBJECT_PUBLICATION:
3249  case OBJECT_ROLE:
3250  case OBJECT_STATISTIC_EXT:
3251  case OBJECT_SUBSCRIPTION:
3252  case OBJECT_TABLESPACE:
3253  ereport(ERROR,
3254  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3255  errmsg("cannot add an object of this type to an extension")));
3256  break;
3257  default:
3258  /* OK */
3259  break;
3260  }
3261 
3262  /*
3263  * Find the extension and acquire a lock on it, to ensure it doesn't get
3264  * dropped concurrently. A sharable lock seems sufficient: there's no
3265  * reason not to allow other sorts of manipulations, such as add/drop of
3266  * other objects, to occur concurrently. Concurrently adding/dropping the
3267  * *same* object would be bad, but we prevent that by using a non-sharable
3268  * lock on the individual object, below.
3269  */
3271  (Node *) makeString(stmt->extname),
3272  &relation, AccessShareLock, false);
3273 
3274  /* Permission check: must own extension */
3275  if (!object_ownercheck(ExtensionRelationId, extension.objectId, GetUserId()))
3277  stmt->extname);
3278 
3279  /*
3280  * Translate the parser representation that identifies the object into an
3281  * ObjectAddress. get_object_address() will throw an error if the object
3282  * does not exist, and will also acquire a lock on the object to guard
3283  * against concurrent DROP and ALTER EXTENSION ADD/DROP operations.
3284  */
3285  object = get_object_address(stmt->objtype, stmt->object,
3286  &relation, ShareUpdateExclusiveLock, false);
3287 
3288  Assert(object.objectSubId == 0);
3289  if (objAddr)
3290  *objAddr = object;
3291 
3292  /* Permission check: must own target object, too */
3293  check_object_ownership(GetUserId(), stmt->objtype, object,
3294  stmt->object, relation);
3295 
3296  /* Do the update, recursing to any dependent objects */
3297  ExecAlterExtensionContentsRecurse(stmt, extension, object);
3298 
3299  /* Finish up */
3300  InvokeObjectPostAlterHook(ExtensionRelationId, extension.objectId, 0);
3301 
3302  /*
3303  * If get_object_address() opened the relation for us, we close it to keep
3304  * the reference count correct - but we retain any locks acquired by
3305  * get_object_address() until commit time, to guard against concurrent
3306  * activity.
3307  */
3308  if (relation != NULL)
3309  relation_close(relation, NoLock);
3310 
3311  return extension;
3312 }
#define Assert(condition)
Definition: c.h:861
static void ExecAlterExtensionContentsRecurse(AlterExtensionContentsStmt *stmt, ObjectAddress extension, ObjectAddress object)
Definition: extension.c:3322
#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:2299
@ OBJECT_ROLE
Definition: parsenodes.h:2290
@ OBJECT_INDEX
Definition: parsenodes.h:2277
@ OBJECT_DATABASE
Definition: parsenodes.h:2266
@ OBJECT_PUBLICATION
Definition: parsenodes.h:2287
@ OBJECT_SUBSCRIPTION
Definition: parsenodes.h:2295
@ OBJECT_STATISTIC_EXT
Definition: parsenodes.h:2296
Definition: nodes.h:129
String * makeString(char *str)
Definition: value.c:63

References AccessShareLock, aclcheck_error(), ACLCHECK_NOT_OWNER, Assert, check_object_ownership(), ereport, errcode(), errmsg(), ERROR, ExecAlterExtensionContentsRecurse(), get_object_address(), GetUserId(), InvokeObjectPostAlterHook, makeString(), NoLock, OBJECT_DATABASE, OBJECT_EXTENSION, OBJECT_INDEX, object_ownercheck(), OBJECT_PUBLICATION, OBJECT_ROLE, OBJECT_STATISTIC_EXT, OBJECT_SUBSCRIPTION, OBJECT_TABLESPACE, ObjectAddress::objectId, relation_close(), ShareUpdateExclusiveLock, and stmt.

Referenced by ProcessUtilitySlow().

◆ ExecAlterExtensionStmt()

ObjectAddress ExecAlterExtensionStmt ( ParseState pstate,
AlterExtensionStmt stmt 
)

Definition at line 2931 of file extension.c.

2932 {
2933  DefElem *d_new_version = NULL;
2934  char *versionName;
2935  char *oldVersionName;
2936  ExtensionControlFile *control;
2937  Oid extensionOid;
2938  Relation extRel;
2939  ScanKeyData key[1];
2940  SysScanDesc extScan;
2941  HeapTuple extTup;
2942  List *updateVersions;
2943  Datum datum;
2944  bool isnull;
2945  ListCell *lc;
2946  ObjectAddress address;
2947 
2948  /*
2949  * We use global variables to track the extension being created, so we can
2950  * create/update only one extension at the same time.
2951  */
2952  if (creating_extension)
2953  ereport(ERROR,
2954  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2955  errmsg("nested ALTER EXTENSION is not supported")));
2956 
2957  /*
2958  * Look up the extension --- it must already exist in pg_extension
2959  */
2960  extRel = table_open(ExtensionRelationId, AccessShareLock);
2961 
2962  ScanKeyInit(&key[0],
2963  Anum_pg_extension_extname,
2964  BTEqualStrategyNumber, F_NAMEEQ,
2965  CStringGetDatum(stmt->extname));
2966 
2967  extScan = systable_beginscan(extRel, ExtensionNameIndexId, true,
2968  NULL, 1, key);
2969 
2970  extTup = systable_getnext(extScan);
2971 
2972  if (!HeapTupleIsValid(extTup))
2973  ereport(ERROR,
2974  (errcode(ERRCODE_UNDEFINED_OBJECT),
2975  errmsg("extension \"%s\" does not exist",
2976  stmt->extname)));
2977 
2978  extensionOid = ((Form_pg_extension) GETSTRUCT(extTup))->oid;
2979 
2980  /*
2981  * Determine the existing version we are updating from
2982  */
2983  datum = heap_getattr(extTup, Anum_pg_extension_extversion,
2984  RelationGetDescr(extRel), &isnull);
2985  if (isnull)
2986  elog(ERROR, "extversion is null");
2987  oldVersionName = text_to_cstring(DatumGetTextPP(datum));
2988 
2989  systable_endscan(extScan);
2990 
2991  table_close(extRel, AccessShareLock);
2992 
2993  /* Permission check: must own extension */
2994  if (!object_ownercheck(ExtensionRelationId, extensionOid, GetUserId()))
2996  stmt->extname);
2997 
2998  /*
2999  * Read the primary control file. Note we assume that it does not contain
3000  * any non-ASCII data, so there is no need to worry about encoding at this
3001  * point.
3002  */
3003  control = read_extension_control_file(stmt->extname);
3004 
3005  /*
3006  * Read the statement option list
3007  */
3008  foreach(lc, stmt->options)
3009  {
3010  DefElem *defel = (DefElem *) lfirst(lc);
3011 
3012  if (strcmp(defel->defname, "new_version") == 0)
3013  {
3014  if (d_new_version)
3015  errorConflictingDefElem(defel, pstate);
3016  d_new_version = defel;
3017  }
3018  else
3019  elog(ERROR, "unrecognized option: %s", defel->defname);
3020  }
3021 
3022  /*
3023  * Determine the version to update to
3024  */
3025  if (d_new_version && d_new_version->arg)
3026  versionName = strVal(d_new_version->arg);
3027  else if (control->default_version)
3028  versionName = control->default_version;
3029  else
3030  {
3031  ereport(ERROR,
3032  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3033  errmsg("version to install must be specified")));
3034  versionName = NULL; /* keep compiler quiet */
3035  }
3036  check_valid_version_name(versionName);
3037 
3038  /*
3039  * If we're already at that version, just say so
3040  */
3041  if (strcmp(oldVersionName, versionName) == 0)
3042  {
3043  ereport(NOTICE,
3044  (errmsg("version \"%s\" of extension \"%s\" is already installed",
3045  versionName, stmt->extname)));
3046  return InvalidObjectAddress;
3047  }
3048 
3049  /*
3050  * Identify the series of update script files we need to execute
3051  */
3052  updateVersions = identify_update_path(control,
3053  oldVersionName,
3054  versionName);
3055 
3056  /*
3057  * Update the pg_extension row and execute the update scripts, one at a
3058  * time
3059  */
3060  ApplyExtensionUpdates(extensionOid, control,
3061  oldVersionName, updateVersions,
3062  NULL, false, false);
3063 
3064  ObjectAddressSet(address, ExtensionRelationId, extensionOid);
3065 
3066  return address;
3067 }
static List * identify_update_path(ExtensionControlFile *control, const char *oldVersion, const char *newVersion)
Definition: extension.c:1211
static void check_valid_version_name(const char *versionname)
Definition: extension.c:257
static void ApplyExtensionUpdates(Oid extensionOid, ExtensionControlFile *pcontrol, const char *initialVersion, List *updateVersions, char *origSchemaName, bool cascade, bool is_create)
Definition: extension.c:3078
#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:531
Node * arg
Definition: parsenodes.h:818
char * default_version
Definition: extension.c:82
Definition: pg_list.h:54
#define strVal(v)
Definition: value.h:82
char * text_to_cstring(const text *t)
Definition: varlena.c:217

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(), GETSTRUCT, GetUserId(), heap_getattr(), HeapTupleIsValid, identify_update_path(), InvalidObjectAddress, sort-test::key, lfirst, NOTICE, OBJECT_EXTENSION, object_ownercheck(), ObjectAddressSet, read_extension_control_file(), RelationGetDescr, ScanKeyInit(), stmt, 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 2204 of file extension.c.

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

169 {
170  char *result;
171  HeapTuple tuple;
172 
173  tuple = SearchSysCache1(EXTENSIONOID, ObjectIdGetDatum(ext_oid));
174 
175  if (!HeapTupleIsValid(tuple))
176  return NULL;
177 
178  result = pstrdup(NameStr(((Form_pg_extension) GETSTRUCT(tuple))->extname));
179  ReleaseSysCache(tuple);
180 
181  return result;
182 }
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221

References GETSTRUCT, HeapTupleIsValid, NameStr, ObjectIdGetDatum(), pstrdup(), ReleaseSysCache(), and SearchSysCache1().

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

◆ get_extension_oid()

Oid get_extension_oid ( const char *  extname,
bool  missing_ok 
)

Definition at line 146 of file extension.c.

147 {
148  Oid result;
149 
150  result = GetSysCacheOid1(EXTENSIONNAME, Anum_pg_extension_oid,
151  CStringGetDatum(extname));
152 
153  if (!OidIsValid(result) && !missing_ok)
154  ereport(ERROR,
155  (errcode(ERRCODE_UNDEFINED_OBJECT),
156  errmsg("extension \"%s\" does not exist",
157  extname)));
158 
159  return result;
160 }
#define OidIsValid(objectId)
Definition: c.h:778
#define GetSysCacheOid1(cacheId, oidcol, key1)
Definition: syscache.h:109

References CStringGetDatum(), ereport, errcode(), errmsg(), ERROR, GetSysCacheOid1, and OidIsValid.

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

◆ get_extension_schema()

Oid get_extension_schema ( Oid  ext_oid)

Definition at line 190 of file extension.c.

191 {
192  Oid result;
193  HeapTuple tuple;
194 
195  tuple = SearchSysCache1(EXTENSIONOID, ObjectIdGetDatum(ext_oid));
196 
197  if (!HeapTupleIsValid(tuple))
198  return InvalidOid;
199 
200  result = ((Form_pg_extension) GETSTRUCT(tuple))->extnamespace;
201  ReleaseSysCache(tuple);
202 
203  return result;
204 }

References GETSTRUCT, HeapTupleIsValid, InvalidOid, ObjectIdGetDatum(), ReleaseSysCache(), and SearchSysCache1().

Referenced by ApplyExtensionUpdates(), CreateExtensionInternal(), and ExecAlterExtensionContentsRecurse().

◆ InsertExtensionTuple()

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

Definition at line 1810 of file extension.c.

1814 {
1815  Oid extensionOid;
1816  Relation rel;
1817  Datum values[Natts_pg_extension];
1818  bool nulls[Natts_pg_extension];
1819  HeapTuple tuple;
1820  ObjectAddress myself;
1821  ObjectAddress nsp;
1822  ObjectAddresses *refobjs;
1823  ListCell *lc;
1824 
1825  /*
1826  * Build and insert the pg_extension tuple
1827  */
1828  rel = table_open(ExtensionRelationId, RowExclusiveLock);
1829 
1830  memset(values, 0, sizeof(values));
1831  memset(nulls, 0, sizeof(nulls));
1832 
1833  extensionOid = GetNewOidWithIndex(rel, ExtensionOidIndexId,
1834  Anum_pg_extension_oid);
1835  values[Anum_pg_extension_oid - 1] = ObjectIdGetDatum(extensionOid);
1836  values[Anum_pg_extension_extname - 1] =
1838  values[Anum_pg_extension_extowner - 1] = ObjectIdGetDatum(extOwner);
1839  values[Anum_pg_extension_extnamespace - 1] = ObjectIdGetDatum(schemaOid);
1840  values[Anum_pg_extension_extrelocatable - 1] = BoolGetDatum(relocatable);
1841  values[Anum_pg_extension_extversion - 1] = CStringGetTextDatum(extVersion);
1842 
1843  if (extConfig == PointerGetDatum(NULL))
1844  nulls[Anum_pg_extension_extconfig - 1] = true;
1845  else
1846  values[Anum_pg_extension_extconfig - 1] = extConfig;
1847 
1848  if (extCondition == PointerGetDatum(NULL))
1849  nulls[Anum_pg_extension_extcondition - 1] = true;
1850  else
1851  values[Anum_pg_extension_extcondition - 1] = extCondition;
1852 
1853  tuple = heap_form_tuple(rel->rd_att, values, nulls);
1854 
1855  CatalogTupleInsert(rel, tuple);
1856 
1857  heap_freetuple(tuple);
1859 
1860  /*
1861  * Record dependencies on owner, schema, and prerequisite extensions
1862  */
1863  recordDependencyOnOwner(ExtensionRelationId, extensionOid, extOwner);
1864 
1865  refobjs = new_object_addresses();
1866 
1867  ObjectAddressSet(myself, ExtensionRelationId, extensionOid);
1868 
1869  ObjectAddressSet(nsp, NamespaceRelationId, schemaOid);
1870  add_exact_object_address(&nsp, refobjs);
1871 
1872  foreach(lc, requiredExtensions)
1873  {
1874  Oid reqext = lfirst_oid(lc);
1875  ObjectAddress otherext;
1876 
1877  ObjectAddressSet(otherext, ExtensionRelationId, reqext);
1878  add_exact_object_address(&otherext, refobjs);
1879  }
1880 
1881  /* Record all of them (this includes duplicate elimination) */
1883  free_object_addresses(refobjs);
1884 
1885  /* Post creation hook for new extension */
1886  InvokeObjectPostCreateHook(ExtensionRelationId, extensionOid, 0);
1887 
1888  return myself;
1889 }
static Datum values[MAXATTR]
Definition: bootstrap.c:150
#define CStringGetTextDatum(s)
Definition: builtins.h:97
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:419
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
Definition: dependency.c:2742
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2533
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2773
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:641
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1116
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1434
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
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:168
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:112

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

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

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