PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
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 2883 of file extension.c.

2884{
2885 Oid extensionOid;
2886 Oid nspOid;
2887 Oid oldNspOid;
2888 AclResult aclresult;
2889 Relation extRel;
2890 ScanKeyData key[2];
2891 SysScanDesc extScan;
2892 HeapTuple extTup;
2893 Form_pg_extension extForm;
2894 Relation depRel;
2895 SysScanDesc depScan;
2896 HeapTuple depTup;
2897 ObjectAddresses *objsMoved;
2898 ObjectAddress extAddr;
2899
2900 extensionOid = get_extension_oid(extensionName, false);
2901
2902 nspOid = LookupCreationNamespace(newschema);
2903
2904 /*
2905 * Permission check: must own extension. Note that we don't bother to
2906 * check ownership of the individual member objects ...
2907 */
2908 if (!object_ownercheck(ExtensionRelationId, extensionOid, GetUserId()))
2910 extensionName);
2911
2912 /* Permission check: must have creation rights in target namespace */
2913 aclresult = object_aclcheck(NamespaceRelationId, nspOid, GetUserId(), ACL_CREATE);
2914 if (aclresult != ACLCHECK_OK)
2915 aclcheck_error(aclresult, OBJECT_SCHEMA, newschema);
2916
2917 /*
2918 * If the schema is currently a member of the extension, disallow moving
2919 * the extension into the schema. That would create a dependency loop.
2920 */
2921 if (getExtensionOfObject(NamespaceRelationId, nspOid) == extensionOid)
2922 ereport(ERROR,
2923 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2924 errmsg("cannot move extension \"%s\" into schema \"%s\" "
2925 "because the extension contains the schema",
2926 extensionName, newschema)));
2927
2928 /* Locate the pg_extension tuple */
2929 extRel = table_open(ExtensionRelationId, RowExclusiveLock);
2930
2931 ScanKeyInit(&key[0],
2932 Anum_pg_extension_oid,
2933 BTEqualStrategyNumber, F_OIDEQ,
2934 ObjectIdGetDatum(extensionOid));
2935
2936 extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
2937 NULL, 1, key);
2938
2939 extTup = systable_getnext(extScan);
2940
2941 if (!HeapTupleIsValid(extTup)) /* should not happen */
2942 elog(ERROR, "could not find tuple for extension %u",
2943 extensionOid);
2944
2945 /* Copy tuple so we can modify it below */
2946 extTup = heap_copytuple(extTup);
2947 extForm = (Form_pg_extension) GETSTRUCT(extTup);
2948
2949 systable_endscan(extScan);
2950
2951 /*
2952 * If the extension is already in the target schema, just silently do
2953 * nothing.
2954 */
2955 if (extForm->extnamespace == nspOid)
2956 {
2958 return InvalidObjectAddress;
2959 }
2960
2961 /* Check extension is supposed to be relocatable */
2962 if (!extForm->extrelocatable)
2963 ereport(ERROR,
2964 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2965 errmsg("extension \"%s\" does not support SET SCHEMA",
2966 NameStr(extForm->extname))));
2967
2968 objsMoved = new_object_addresses();
2969
2970 /* store the OID of the namespace to-be-changed */
2971 oldNspOid = extForm->extnamespace;
2972
2973 /*
2974 * Scan pg_depend to find objects that depend directly on the extension,
2975 * and alter each one's schema.
2976 */
2977 depRel = table_open(DependRelationId, AccessShareLock);
2978
2979 ScanKeyInit(&key[0],
2980 Anum_pg_depend_refclassid,
2981 BTEqualStrategyNumber, F_OIDEQ,
2982 ObjectIdGetDatum(ExtensionRelationId));
2983 ScanKeyInit(&key[1],
2984 Anum_pg_depend_refobjid,
2985 BTEqualStrategyNumber, F_OIDEQ,
2986 ObjectIdGetDatum(extensionOid));
2987
2988 depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
2989 NULL, 2, key);
2990
2991 while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
2992 {
2993 Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
2994 ObjectAddress dep;
2995 Oid dep_oldNspOid;
2996
2997 /*
2998 * If a dependent extension has a no_relocate request for this
2999 * extension, disallow SET SCHEMA. (XXX it's a bit ugly to do this in
3000 * the same loop that's actually executing the renames: we may detect
3001 * the error condition only after having expended a fair amount of
3002 * work. However, the alternative is to do two scans of pg_depend,
3003 * which seems like optimizing for failure cases. The rename work
3004 * will all roll back cleanly enough if we do fail here.)
3005 */
3006 if (pg_depend->deptype == DEPENDENCY_NORMAL &&
3007 pg_depend->classid == ExtensionRelationId)
3008 {
3009 char *depextname = get_extension_name(pg_depend->objid);
3010 ExtensionControlFile *dcontrol;
3011 ListCell *lc;
3012
3013 dcontrol = read_extension_control_file(depextname);
3014 foreach(lc, dcontrol->no_relocate)
3015 {
3016 char *nrextname = (char *) lfirst(lc);
3017
3018 if (strcmp(nrextname, NameStr(extForm->extname)) == 0)
3019 {
3020 ereport(ERROR,
3021 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3022 errmsg("cannot SET SCHEMA of extension \"%s\" because other extensions prevent it",
3023 NameStr(extForm->extname)),
3024 errdetail("Extension \"%s\" requests no relocation of extension \"%s\".",
3025 depextname,
3026 NameStr(extForm->extname))));
3027 }
3028 }
3029 }
3030
3031 /*
3032 * Otherwise, ignore non-membership dependencies. (Currently, the
3033 * only other case we could see here is a normal dependency from
3034 * another extension.)
3035 */
3036 if (pg_depend->deptype != DEPENDENCY_EXTENSION)
3037 continue;
3038
3039 dep.classId = pg_depend->classid;
3040 dep.objectId = pg_depend->objid;
3041 dep.objectSubId = pg_depend->objsubid;
3042
3043 if (dep.objectSubId != 0) /* should not happen */
3044 elog(ERROR, "extension should not have a sub-object dependency");
3045
3046 /* Relocate the object */
3047 dep_oldNspOid = AlterObjectNamespace_oid(dep.classId,
3048 dep.objectId,
3049 nspOid,
3050 objsMoved);
3051
3052 /*
3053 * If not all the objects had the same old namespace (ignoring any
3054 * that are not in namespaces or are dependent types), complain.
3055 */
3056 if (dep_oldNspOid != InvalidOid && dep_oldNspOid != oldNspOid)
3057 ereport(ERROR,
3058 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3059 errmsg("extension \"%s\" does not support SET SCHEMA",
3060 NameStr(extForm->extname)),
3061 errdetail("%s is not in the extension's schema \"%s\"",
3062 getObjectDescription(&dep, false),
3063 get_namespace_name(oldNspOid))));
3064 }
3065
3066 /* report old schema, if caller wants it */
3067 if (oldschema)
3068 *oldschema = oldNspOid;
3069
3070 systable_endscan(depScan);
3071
3073
3074 /* Now adjust pg_extension.extnamespace */
3075 extForm->extnamespace = nspOid;
3076
3077 CatalogTupleUpdate(extRel, &extTup->t_self, extTup);
3078
3080
3081 /* update dependency to point to the new schema */
3082 if (changeDependencyFor(ExtensionRelationId, extensionOid,
3083 NamespaceRelationId, oldNspOid, nspOid) != 1)
3084 elog(ERROR, "could not change schema dependency for extension %s",
3085 NameStr(extForm->extname));
3086
3087 InvokeObjectPostAlterHook(ExtensionRelationId, extensionOid, 0);
3088
3089 ObjectAddressSet(extAddr, ExtensionRelationId, extensionOid);
3090
3091 return extAddr;
3092}
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:2622
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3810
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4064
Oid AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: alter.c:609
#define NameStr(name)
Definition: c.h:700
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:604
Oid get_extension_oid(const char *extname, bool missing_ok)
Definition: extension.c:158
char * get_extension_name(Oid ext_oid)
Definition: extension.c:180
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:606
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:513
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:778
#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:517
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:2304
@ OBJECT_EXTENSION
Definition: parsenodes.h:2283
#define ACL_CREATE
Definition: parsenodes.h:85
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:457
Oid getExtensionOfObject(Oid classId, Oid objectId)
Definition: pg_depend.c:732
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
List *List * no_relocate
Definition: extension.c:93
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 1879 of file extension.c.

1880{
1881 DefElem *d_schema = NULL;
1882 DefElem *d_new_version = NULL;
1883 DefElem *d_cascade = NULL;
1884 char *schemaName = NULL;
1885 char *versionName = NULL;
1886 bool cascade = false;
1887 ListCell *lc;
1888
1889 /* Check extension name validity before any filesystem access */
1891
1892 /*
1893 * Check for duplicate extension name. The unique index on
1894 * pg_extension.extname would catch this anyway, and serves as a backstop
1895 * in case of race conditions; but this is a friendlier error message, and
1896 * besides we need a check to support IF NOT EXISTS.
1897 */
1898 if (get_extension_oid(stmt->extname, true) != InvalidOid)
1899 {
1900 if (stmt->if_not_exists)
1901 {
1904 errmsg("extension \"%s\" already exists, skipping",
1905 stmt->extname)));
1906 return InvalidObjectAddress;
1907 }
1908 else
1909 ereport(ERROR,
1911 errmsg("extension \"%s\" already exists",
1912 stmt->extname)));
1913 }
1914
1915 /*
1916 * We use global variables to track the extension being created, so we can
1917 * create only one extension at the same time.
1918 */
1920 ereport(ERROR,
1921 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1922 errmsg("nested CREATE EXTENSION is not supported")));
1923
1924 /* Deconstruct the statement option list */
1925 foreach(lc, stmt->options)
1926 {
1927 DefElem *defel = (DefElem *) lfirst(lc);
1928
1929 if (strcmp(defel->defname, "schema") == 0)
1930 {
1931 if (d_schema)
1932 errorConflictingDefElem(defel, pstate);
1933 d_schema = defel;
1934 schemaName = defGetString(d_schema);
1935 }
1936 else if (strcmp(defel->defname, "new_version") == 0)
1937 {
1938 if (d_new_version)
1939 errorConflictingDefElem(defel, pstate);
1940 d_new_version = defel;
1941 versionName = defGetString(d_new_version);
1942 }
1943 else if (strcmp(defel->defname, "cascade") == 0)
1944 {
1945 if (d_cascade)
1946 errorConflictingDefElem(defel, pstate);
1947 d_cascade = defel;
1948 cascade = defGetBoolean(d_cascade);
1949 }
1950 else
1951 elog(ERROR, "unrecognized option: %s", defel->defname);
1952 }
1953
1954 /* Call CreateExtensionInternal to do the real work. */
1955 return CreateExtensionInternal(stmt->extname,
1956 schemaName,
1957 versionName,
1958 cascade,
1959 NIL,
1960 true);
1961}
char * defGetString(DefElem *def)
Definition: define.c:35
bool defGetBoolean(DefElem *def)
Definition: define.c:94
void errorConflictingDefElem(DefElem *defel, ParseState *pstate)
Definition: define.c:371
#define NOTICE
Definition: elog.h:35
static void check_valid_extension_name(const char *extensionname)
Definition: extension.c:222
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:1569
#define stmt
Definition: indent_codes.h:59
#define NIL
Definition: pg_list.h:68
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:30
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 3403 of file extension.c.

3405{
3406 ObjectAddress extension;
3407 ObjectAddress object;
3408 Relation relation;
3409
3410 switch (stmt->objtype)
3411 {
3412 case OBJECT_DATABASE:
3413 case OBJECT_EXTENSION:
3414 case OBJECT_INDEX:
3415 case OBJECT_PUBLICATION:
3416 case OBJECT_ROLE:
3419 case OBJECT_TABLESPACE:
3420 ereport(ERROR,
3421 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3422 errmsg("cannot add an object of this type to an extension")));
3423 break;
3424 default:
3425 /* OK */
3426 break;
3427 }
3428
3429 /*
3430 * Find the extension and acquire a lock on it, to ensure it doesn't get
3431 * dropped concurrently. A sharable lock seems sufficient: there's no
3432 * reason not to allow other sorts of manipulations, such as add/drop of
3433 * other objects, to occur concurrently. Concurrently adding/dropping the
3434 * *same* object would be bad, but we prevent that by using a non-sharable
3435 * lock on the individual object, below.
3436 */
3438 (Node *) makeString(stmt->extname),
3439 &relation, AccessShareLock, false);
3440
3441 /* Permission check: must own extension */
3442 if (!object_ownercheck(ExtensionRelationId, extension.objectId, GetUserId()))
3444 stmt->extname);
3445
3446 /*
3447 * Translate the parser representation that identifies the object into an
3448 * ObjectAddress. get_object_address() will throw an error if the object
3449 * does not exist, and will also acquire a lock on the object to guard
3450 * against concurrent DROP and ALTER EXTENSION ADD/DROP operations.
3451 */
3452 object = get_object_address(stmt->objtype, stmt->object,
3453 &relation, ShareUpdateExclusiveLock, false);
3454
3455 Assert(object.objectSubId == 0);
3456 if (objAddr)
3457 *objAddr = object;
3458
3459 /* Permission check: must own target object, too */
3460 check_object_ownership(GetUserId(), stmt->objtype, object,
3461 stmt->object, relation);
3462
3463 /* Do the update, recursing to any dependent objects */
3464 ExecAlterExtensionContentsRecurse(stmt, extension, object);
3465
3466 /* Finish up */
3467 InvokeObjectPostAlterHook(ExtensionRelationId, extension.objectId, 0);
3468
3469 /*
3470 * If get_object_address() opened the relation for us, we close it to keep
3471 * the reference count correct - but we retain any locks acquired by
3472 * get_object_address() until commit time, to guard against concurrent
3473 * activity.
3474 */
3475 if (relation != NULL)
3476 relation_close(relation, NoLock);
3477
3478 return extension;
3479}
#define Assert(condition)
Definition: c.h:812
static void ExecAlterExtensionContentsRecurse(AlterExtensionContentsStmt *stmt, ObjectAddress extension, ObjectAddress object)
Definition: extension.c:3489
#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:2310
@ OBJECT_ROLE
Definition: parsenodes.h:2301
@ OBJECT_INDEX
Definition: parsenodes.h:2288
@ OBJECT_DATABASE
Definition: parsenodes.h:2277
@ OBJECT_PUBLICATION
Definition: parsenodes.h:2298
@ OBJECT_SUBSCRIPTION
Definition: parsenodes.h:2306
@ OBJECT_STATISTIC_EXT
Definition: parsenodes.h:2307
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 3098 of file extension.c.

3099{
3100 DefElem *d_new_version = NULL;
3101 char *versionName;
3102 char *oldVersionName;
3103 ExtensionControlFile *control;
3104 Oid extensionOid;
3105 Relation extRel;
3106 ScanKeyData key[1];
3107 SysScanDesc extScan;
3108 HeapTuple extTup;
3109 List *updateVersions;
3110 Datum datum;
3111 bool isnull;
3112 ListCell *lc;
3113 ObjectAddress address;
3114
3115 /*
3116 * We use global variables to track the extension being created, so we can
3117 * create/update only one extension at the same time.
3118 */
3120 ereport(ERROR,
3121 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3122 errmsg("nested ALTER EXTENSION is not supported")));
3123
3124 /*
3125 * Look up the extension --- it must already exist in pg_extension
3126 */
3127 extRel = table_open(ExtensionRelationId, AccessShareLock);
3128
3129 ScanKeyInit(&key[0],
3130 Anum_pg_extension_extname,
3131 BTEqualStrategyNumber, F_NAMEEQ,
3132 CStringGetDatum(stmt->extname));
3133
3134 extScan = systable_beginscan(extRel, ExtensionNameIndexId, true,
3135 NULL, 1, key);
3136
3137 extTup = systable_getnext(extScan);
3138
3139 if (!HeapTupleIsValid(extTup))
3140 ereport(ERROR,
3141 (errcode(ERRCODE_UNDEFINED_OBJECT),
3142 errmsg("extension \"%s\" does not exist",
3143 stmt->extname)));
3144
3145 extensionOid = ((Form_pg_extension) GETSTRUCT(extTup))->oid;
3146
3147 /*
3148 * Determine the existing version we are updating from
3149 */
3150 datum = heap_getattr(extTup, Anum_pg_extension_extversion,
3151 RelationGetDescr(extRel), &isnull);
3152 if (isnull)
3153 elog(ERROR, "extversion is null");
3154 oldVersionName = text_to_cstring(DatumGetTextPP(datum));
3155
3156 systable_endscan(extScan);
3157
3159
3160 /* Permission check: must own extension */
3161 if (!object_ownercheck(ExtensionRelationId, extensionOid, GetUserId()))
3163 stmt->extname);
3164
3165 /*
3166 * Read the primary control file. Note we assume that it does not contain
3167 * any non-ASCII data, so there is no need to worry about encoding at this
3168 * point.
3169 */
3170 control = read_extension_control_file(stmt->extname);
3171
3172 /*
3173 * Read the statement option list
3174 */
3175 foreach(lc, stmt->options)
3176 {
3177 DefElem *defel = (DefElem *) lfirst(lc);
3178
3179 if (strcmp(defel->defname, "new_version") == 0)
3180 {
3181 if (d_new_version)
3182 errorConflictingDefElem(defel, pstate);
3183 d_new_version = defel;
3184 }
3185 else
3186 elog(ERROR, "unrecognized option: %s", defel->defname);
3187 }
3188
3189 /*
3190 * Determine the version to update to
3191 */
3192 if (d_new_version && d_new_version->arg)
3193 versionName = strVal(d_new_version->arg);
3194 else if (control->default_version)
3195 versionName = control->default_version;
3196 else
3197 {
3198 ereport(ERROR,
3199 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3200 errmsg("version to install must be specified")));
3201 versionName = NULL; /* keep compiler quiet */
3202 }
3203 check_valid_version_name(versionName);
3204
3205 /*
3206 * If we're already at that version, just say so
3207 */
3208 if (strcmp(oldVersionName, versionName) == 0)
3209 {
3211 (errmsg("version \"%s\" of extension \"%s\" is already installed",
3212 versionName, stmt->extname)));
3213 return InvalidObjectAddress;
3214 }
3215
3216 /*
3217 * Identify the series of update script files we need to execute
3218 */
3219 updateVersions = identify_update_path(control,
3220 oldVersionName,
3221 versionName);
3222
3223 /*
3224 * Update the pg_extension row and execute the update scripts, one at a
3225 * time
3226 */
3227 ApplyExtensionUpdates(extensionOid, control,
3228 oldVersionName, updateVersions,
3229 NULL, false, false);
3230
3231 ObjectAddressSet(address, ExtensionRelationId, extensionOid);
3232
3233 return address;
3234}
static void check_valid_version_name(const char *versionname)
Definition: extension.c:269
static List * identify_update_path(ExtensionControlFile *control, const char *oldVersion, const char *newVersion)
Definition: extension.c:1378
static void ApplyExtensionUpdates(Oid extensionOid, ExtensionControlFile *pcontrol, const char *initialVersion, List *updateVersions, char *origSchemaName, bool cascade, bool is_create)
Definition: extension.c:3245
#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:83
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 2371 of file extension.c.

2372{
2373 bool result = false;
2374 char *location;
2375 DIR *dir;
2376 struct dirent *de;
2377
2379 dir = AllocateDir(location);
2380
2381 /*
2382 * If the control directory doesn't exist, we want to silently return
2383 * false. Any other error will be reported by ReadDir.
2384 */
2385 if (dir == NULL && errno == ENOENT)
2386 {
2387 /* do nothing */
2388 }
2389 else
2390 {
2391 while ((de = ReadDir(dir, location)) != NULL)
2392 {
2393 char *extname;
2394
2396 continue;
2397
2398 /* extract extension name from 'name.control' filename */
2399 extname = pstrdup(de->d_name);
2400 *strrchr(extname, '.') = '\0';
2401
2402 /* ignore it if it's an auxiliary control file */
2403 if (strstr(extname, "--"))
2404 continue;
2405
2406 /* done if it matches request */
2407 if (strcmp(extname, extensionName) == 0)
2408 {
2409 result = true;
2410 break;
2411 }
2412 }
2413
2414 FreeDir(dir);
2415 }
2416
2417 return result;
2418}
static bool is_extension_control_filename(const char *filename)
Definition: extension.c:316
static char * get_extension_control_directory(void)
Definition: extension.c:332
int FreeDir(DIR *dir)
Definition: fd.c:2983
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2865
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2931
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 180 of file extension.c.

181{
182 char *result;
183 HeapTuple tuple;
184
185 tuple = SearchSysCache1(EXTENSIONOID, ObjectIdGetDatum(ext_oid));
186
187 if (!HeapTupleIsValid(tuple))
188 return NULL;
189
190 result = pstrdup(NameStr(((Form_pg_extension) GETSTRUCT(tuple))->extname));
191 ReleaseSysCache(tuple);
192
193 return result;
194}
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 158 of file extension.c.

159{
160 Oid result;
161
162 result = GetSysCacheOid1(EXTENSIONNAME, Anum_pg_extension_oid,
163 CStringGetDatum(extname));
164
165 if (!OidIsValid(result) && !missing_ok)
167 (errcode(ERRCODE_UNDEFINED_OBJECT),
168 errmsg("extension \"%s\" does not exist",
169 extname)));
170
171 return result;
172}
#define OidIsValid(objectId)
Definition: c.h:729
#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 202 of file extension.c.

203{
204 Oid result;
205 HeapTuple tuple;
206
207 tuple = SearchSysCache1(EXTENSIONOID, ObjectIdGetDatum(ext_oid));
208
209 if (!HeapTupleIsValid(tuple))
210 return InvalidOid;
211
212 result = ((Form_pg_extension) GETSTRUCT(tuple))->extnamespace;
213 ReleaseSysCache(tuple);
214
215 return result;
216}

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

1981{
1982 Oid extensionOid;
1983 Relation rel;
1984 Datum values[Natts_pg_extension];
1985 bool nulls[Natts_pg_extension];
1986 HeapTuple tuple;
1987 ObjectAddress myself;
1988 ObjectAddress nsp;
1989 ObjectAddresses *refobjs;
1990 ListCell *lc;
1991
1992 /*
1993 * Build and insert the pg_extension tuple
1994 */
1995 rel = table_open(ExtensionRelationId, RowExclusiveLock);
1996
1997 memset(values, 0, sizeof(values));
1998 memset(nulls, 0, sizeof(nulls));
1999
2000 extensionOid = GetNewOidWithIndex(rel, ExtensionOidIndexId,
2001 Anum_pg_extension_oid);
2002 values[Anum_pg_extension_oid - 1] = ObjectIdGetDatum(extensionOid);
2003 values[Anum_pg_extension_extname - 1] =
2005 values[Anum_pg_extension_extowner - 1] = ObjectIdGetDatum(extOwner);
2006 values[Anum_pg_extension_extnamespace - 1] = ObjectIdGetDatum(schemaOid);
2007 values[Anum_pg_extension_extrelocatable - 1] = BoolGetDatum(relocatable);
2008 values[Anum_pg_extension_extversion - 1] = CStringGetTextDatum(extVersion);
2009
2010 if (extConfig == PointerGetDatum(NULL))
2011 nulls[Anum_pg_extension_extconfig - 1] = true;
2012 else
2013 values[Anum_pg_extension_extconfig - 1] = extConfig;
2014
2015 if (extCondition == PointerGetDatum(NULL))
2016 nulls[Anum_pg_extension_extcondition - 1] = true;
2017 else
2018 values[Anum_pg_extension_extcondition - 1] = extCondition;
2019
2020 tuple = heap_form_tuple(rel->rd_att, values, nulls);
2021
2022 CatalogTupleInsert(rel, tuple);
2023
2024 heap_freetuple(tuple);
2026
2027 /*
2028 * Record dependencies on owner, schema, and prerequisite extensions
2029 */
2030 recordDependencyOnOwner(ExtensionRelationId, extensionOid, extOwner);
2031
2032 refobjs = new_object_addresses();
2033
2034 ObjectAddressSet(myself, ExtensionRelationId, extensionOid);
2035
2036 ObjectAddressSet(nsp, NamespaceRelationId, schemaOid);
2037 add_exact_object_address(&nsp, refobjs);
2038
2039 foreach(lc, requiredExtensions)
2040 {
2041 Oid reqext = lfirst_oid(lc);
2042 ObjectAddress otherext;
2043
2044 ObjectAddressSet(otherext, ExtensionRelationId, reqext);
2045 add_exact_object_address(&otherext, refobjs);
2046 }
2047
2048 /* Record all of them (this includes duplicate elimination) */
2050 free_object_addresses(refobjs);
2051
2052 /* Post creation hook for new extension */
2053 InvokeObjectPostCreateHook(ExtensionRelationId, extensionOid, 0);
2054
2055 return myself;
2056}
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#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:1117
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1435
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 2065 of file extension.c.

2066{
2067 Relation rel;
2068 SysScanDesc scandesc;
2069 HeapTuple tuple;
2070 ScanKeyData entry[1];
2071
2072 /*
2073 * Disallow deletion of any extension that's currently open for insertion;
2074 * else subsequent executions of recordDependencyOnCurrentExtension()
2075 * could create dangling pg_depend records that refer to a no-longer-valid
2076 * pg_extension OID. This is needed not so much because we think people
2077 * might write "DROP EXTENSION foo" in foo's own script files, as because
2078 * errors in dependency management in extension script files could give
2079 * rise to cases where an extension is dropped as a result of recursing
2080 * from some contained object. Because of that, we must test for the case
2081 * here, not at some higher level of the DROP EXTENSION command.
2082 */
2083 if (extId == CurrentExtensionObject)
2084 ereport(ERROR,
2085 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2086 errmsg("cannot drop extension \"%s\" because it is being modified",
2087 get_extension_name(extId))));
2088
2089 rel = table_open(ExtensionRelationId, RowExclusiveLock);
2090
2091 ScanKeyInit(&entry[0],
2092 Anum_pg_extension_oid,
2093 BTEqualStrategyNumber, F_OIDEQ,
2094 ObjectIdGetDatum(extId));
2095 scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
2096 NULL, 1, entry);
2097
2098 tuple = systable_getnext(scandesc);
2099
2100 /* We assume that there can be at most one matching tuple */
2101 if (HeapTupleIsValid(tuple))
2102 CatalogTupleDelete(rel, &tuple->t_self);
2103
2104 systable_endscan(scandesc);
2105
2107}
Oid CurrentExtensionObject
Definition: extension.c:74
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