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 char * Extension_control_path
 
PGDLLIMPORT bool creating_extension
 
PGDLLIMPORT Oid CurrentExtensionObject
 

Function Documentation

◆ AlterExtensionNamespace()

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

Definition at line 3124 of file extension.c.

3125{
3126 Oid extensionOid;
3127 Oid nspOid;
3128 Oid oldNspOid;
3129 AclResult aclresult;
3130 Relation extRel;
3131 ScanKeyData key[2];
3132 SysScanDesc extScan;
3133 HeapTuple extTup;
3134 Form_pg_extension extForm;
3135 Relation depRel;
3136 SysScanDesc depScan;
3137 HeapTuple depTup;
3138 ObjectAddresses *objsMoved;
3139 ObjectAddress extAddr;
3140
3141 extensionOid = get_extension_oid(extensionName, false);
3142
3143 nspOid = LookupCreationNamespace(newschema);
3144
3145 /*
3146 * Permission check: must own extension. Note that we don't bother to
3147 * check ownership of the individual member objects ...
3148 */
3149 if (!object_ownercheck(ExtensionRelationId, extensionOid, GetUserId()))
3151 extensionName);
3152
3153 /* Permission check: must have creation rights in target namespace */
3154 aclresult = object_aclcheck(NamespaceRelationId, nspOid, GetUserId(), ACL_CREATE);
3155 if (aclresult != ACLCHECK_OK)
3156 aclcheck_error(aclresult, OBJECT_SCHEMA, newschema);
3157
3158 /*
3159 * If the schema is currently a member of the extension, disallow moving
3160 * the extension into the schema. That would create a dependency loop.
3161 */
3162 if (getExtensionOfObject(NamespaceRelationId, nspOid) == extensionOid)
3163 ereport(ERROR,
3164 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3165 errmsg("cannot move extension \"%s\" into schema \"%s\" "
3166 "because the extension contains the schema",
3167 extensionName, newschema)));
3168
3169 /* Locate the pg_extension tuple */
3170 extRel = table_open(ExtensionRelationId, RowExclusiveLock);
3171
3172 ScanKeyInit(&key[0],
3173 Anum_pg_extension_oid,
3174 BTEqualStrategyNumber, F_OIDEQ,
3175 ObjectIdGetDatum(extensionOid));
3176
3177 extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
3178 NULL, 1, key);
3179
3180 extTup = systable_getnext(extScan);
3181
3182 if (!HeapTupleIsValid(extTup)) /* should not happen */
3183 elog(ERROR, "could not find tuple for extension %u",
3184 extensionOid);
3185
3186 /* Copy tuple so we can modify it below */
3187 extTup = heap_copytuple(extTup);
3188 extForm = (Form_pg_extension) GETSTRUCT(extTup);
3189
3190 systable_endscan(extScan);
3191
3192 /*
3193 * If the extension is already in the target schema, just silently do
3194 * nothing.
3195 */
3196 if (extForm->extnamespace == nspOid)
3197 {
3199 return InvalidObjectAddress;
3200 }
3201
3202 /* Check extension is supposed to be relocatable */
3203 if (!extForm->extrelocatable)
3204 ereport(ERROR,
3205 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3206 errmsg("extension \"%s\" does not support SET SCHEMA",
3207 NameStr(extForm->extname))));
3208
3209 objsMoved = new_object_addresses();
3210
3211 /* store the OID of the namespace to-be-changed */
3212 oldNspOid = extForm->extnamespace;
3213
3214 /*
3215 * Scan pg_depend to find objects that depend directly on the extension,
3216 * and alter each one's schema.
3217 */
3218 depRel = table_open(DependRelationId, AccessShareLock);
3219
3220 ScanKeyInit(&key[0],
3221 Anum_pg_depend_refclassid,
3222 BTEqualStrategyNumber, F_OIDEQ,
3223 ObjectIdGetDatum(ExtensionRelationId));
3224 ScanKeyInit(&key[1],
3225 Anum_pg_depend_refobjid,
3226 BTEqualStrategyNumber, F_OIDEQ,
3227 ObjectIdGetDatum(extensionOid));
3228
3229 depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
3230 NULL, 2, key);
3231
3232 while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
3233 {
3234 Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
3235 ObjectAddress dep;
3236 Oid dep_oldNspOid;
3237
3238 /*
3239 * If a dependent extension has a no_relocate request for this
3240 * extension, disallow SET SCHEMA. (XXX it's a bit ugly to do this in
3241 * the same loop that's actually executing the renames: we may detect
3242 * the error condition only after having expended a fair amount of
3243 * work. However, the alternative is to do two scans of pg_depend,
3244 * which seems like optimizing for failure cases. The rename work
3245 * will all roll back cleanly enough if we do fail here.)
3246 */
3247 if (pg_depend->deptype == DEPENDENCY_NORMAL &&
3248 pg_depend->classid == ExtensionRelationId)
3249 {
3250 char *depextname = get_extension_name(pg_depend->objid);
3251 ExtensionControlFile *dcontrol;
3252 ListCell *lc;
3253
3254 dcontrol = read_extension_control_file(depextname);
3255 foreach(lc, dcontrol->no_relocate)
3256 {
3257 char *nrextname = (char *) lfirst(lc);
3258
3259 if (strcmp(nrextname, NameStr(extForm->extname)) == 0)
3260 {
3261 ereport(ERROR,
3262 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3263 errmsg("cannot SET SCHEMA of extension \"%s\" because other extensions prevent it",
3264 NameStr(extForm->extname)),
3265 errdetail("Extension \"%s\" requests no relocation of extension \"%s\".",
3266 depextname,
3267 NameStr(extForm->extname))));
3268 }
3269 }
3270 }
3271
3272 /*
3273 * Otherwise, ignore non-membership dependencies. (Currently, the
3274 * only other case we could see here is a normal dependency from
3275 * another extension.)
3276 */
3277 if (pg_depend->deptype != DEPENDENCY_EXTENSION)
3278 continue;
3279
3280 dep.classId = pg_depend->classid;
3281 dep.objectId = pg_depend->objid;
3282 dep.objectSubId = pg_depend->objsubid;
3283
3284 if (dep.objectSubId != 0) /* should not happen */
3285 elog(ERROR, "extension should not have a sub-object dependency");
3286
3287 /* Relocate the object */
3288 dep_oldNspOid = AlterObjectNamespace_oid(dep.classId,
3289 dep.objectId,
3290 nspOid,
3291 objsMoved);
3292
3293 /*
3294 * If not all the objects had the same old namespace (ignoring any
3295 * that are not in namespaces or are dependent types), complain.
3296 */
3297 if (dep_oldNspOid != InvalidOid && dep_oldNspOid != oldNspOid)
3298 ereport(ERROR,
3299 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3300 errmsg("extension \"%s\" does not support SET SCHEMA",
3301 NameStr(extForm->extname)),
3302 errdetail("%s is not in the extension's schema \"%s\"",
3303 getObjectDescription(&dep, false),
3304 get_namespace_name(oldNspOid))));
3305 }
3306
3307 /* report old schema, if caller wants it */
3308 if (oldschema)
3309 *oldschema = oldNspOid;
3310
3311 systable_endscan(depScan);
3312
3314
3315 /* Now adjust pg_extension.extnamespace */
3316 extForm->extnamespace = nspOid;
3317
3318 CatalogTupleUpdate(extRel, &extTup->t_self, extTup);
3319
3321
3322 /* update dependency to point to the new schema */
3323 if (changeDependencyFor(ExtensionRelationId, extensionOid,
3324 NamespaceRelationId, oldNspOid, nspOid) != 1)
3325 elog(ERROR, "could not change schema dependency for extension %s",
3326 NameStr(extForm->extname));
3327
3328 InvokeObjectPostAlterHook(ExtensionRelationId, extensionOid, 0);
3329
3330 ObjectAddressSet(extAddr, ExtensionRelationId, extensionOid);
3331
3332 return extAddr;
3333}
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:2654
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3836
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4090
Oid AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: alter.c:625
#define NameStr(name)
Definition: c.h:771
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2664
@ DEPENDENCY_EXTENSION
Definition: dependency.h:38
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
int errdetail(const char *fmt,...)
Definition: elog.c:1216
int errcode(int sqlerrcode)
Definition: elog.c:863
int errmsg(const char *fmt,...)
Definition: elog.c:1080
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
#define ereport(elevel,...)
Definition: elog.h:150
static ExtensionControlFile * read_extension_control_file(const char *extname)
Definition: extension.c:750
Oid get_extension_oid(const char *extname, bool missing_ok)
Definition: extension.c:206
char * get_extension_name(Oid ext_oid)
Definition: extension.c:228
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:603
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:514
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:388
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:778
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
void CatalogTupleUpdate(Relation heapRel, const ItemPointerData *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:3516
Oid GetUserId(void)
Definition: miscinit.c:469
Oid LookupCreationNamespace(const char *nspname)
Definition: namespace.c:3498
#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:2388
@ OBJECT_EXTENSION
Definition: parsenodes.h:2367
#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:262
#define InvalidOid
Definition: postgres_ext.h:37
unsigned int Oid
Definition: postgres_ext.h:32
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:100
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 2015 of file extension.c.

2016{
2017 DefElem *d_schema = NULL;
2018 DefElem *d_new_version = NULL;
2019 DefElem *d_cascade = NULL;
2020 char *schemaName = NULL;
2021 char *versionName = NULL;
2022 bool cascade = false;
2023 ListCell *lc;
2024
2025 /* Check extension name validity before any filesystem access */
2027
2028 /*
2029 * Check for duplicate extension name. The unique index on
2030 * pg_extension.extname would catch this anyway, and serves as a backstop
2031 * in case of race conditions; but this is a friendlier error message, and
2032 * besides we need a check to support IF NOT EXISTS.
2033 */
2034 if (get_extension_oid(stmt->extname, true) != InvalidOid)
2035 {
2036 if (stmt->if_not_exists)
2037 {
2040 errmsg("extension \"%s\" already exists, skipping",
2041 stmt->extname)));
2042 return InvalidObjectAddress;
2043 }
2044 else
2045 ereport(ERROR,
2047 errmsg("extension \"%s\" already exists",
2048 stmt->extname)));
2049 }
2050
2051 /*
2052 * We use global variables to track the extension being created, so we can
2053 * create only one extension at the same time.
2054 */
2056 ereport(ERROR,
2057 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2058 errmsg("nested CREATE EXTENSION is not supported")));
2059
2060 /* Deconstruct the statement option list */
2061 foreach(lc, stmt->options)
2062 {
2063 DefElem *defel = (DefElem *) lfirst(lc);
2064
2065 if (strcmp(defel->defname, "schema") == 0)
2066 {
2067 if (d_schema)
2068 errorConflictingDefElem(defel, pstate);
2069 d_schema = defel;
2070 schemaName = defGetString(d_schema);
2071 }
2072 else if (strcmp(defel->defname, "new_version") == 0)
2073 {
2074 if (d_new_version)
2075 errorConflictingDefElem(defel, pstate);
2076 d_new_version = defel;
2077 versionName = defGetString(d_new_version);
2078 }
2079 else if (strcmp(defel->defname, "cascade") == 0)
2080 {
2081 if (d_cascade)
2082 errorConflictingDefElem(defel, pstate);
2083 d_cascade = defel;
2084 cascade = defGetBoolean(d_cascade);
2085 }
2086 else
2087 elog(ERROR, "unrecognized option: %s", defel->defname);
2088 }
2089
2090 /* Call CreateExtensionInternal to do the real work. */
2091 return CreateExtensionInternal(stmt->extname,
2092 schemaName,
2093 versionName,
2094 cascade,
2095 NIL,
2096 true);
2097}
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:270
bool creating_extension
Definition: extension.c:77
static ObjectAddress CreateExtensionInternal(char *extensionName, char *schemaName, const char *versionName, bool cascade, List *parents, bool is_create)
Definition: extension.c:1705
#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:844

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

3646{
3647 ObjectAddress extension;
3648 ObjectAddress object;
3649 Relation relation;
3650
3651 switch (stmt->objtype)
3652 {
3653 case OBJECT_DATABASE:
3654 case OBJECT_EXTENSION:
3655 case OBJECT_INDEX:
3656 case OBJECT_PUBLICATION:
3657 case OBJECT_ROLE:
3660 case OBJECT_TABLESPACE:
3661 ereport(ERROR,
3662 (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3663 errmsg("cannot add an object of this type to an extension")));
3664 break;
3665 default:
3666 /* OK */
3667 break;
3668 }
3669
3670 /*
3671 * Find the extension and acquire a lock on it, to ensure it doesn't get
3672 * dropped concurrently. A sharable lock seems sufficient: there's no
3673 * reason not to allow other sorts of manipulations, such as add/drop of
3674 * other objects, to occur concurrently. Concurrently adding/dropping the
3675 * *same* object would be bad, but we prevent that by using a non-sharable
3676 * lock on the individual object, below.
3677 */
3679 (Node *) makeString(stmt->extname),
3680 &relation, AccessShareLock, false);
3681
3682 /* Permission check: must own extension */
3683 if (!object_ownercheck(ExtensionRelationId, extension.objectId, GetUserId()))
3685 stmt->extname);
3686
3687 /*
3688 * Translate the parser representation that identifies the object into an
3689 * ObjectAddress. get_object_address() will throw an error if the object
3690 * does not exist, and will also acquire a lock on the object to guard
3691 * against concurrent DROP and ALTER EXTENSION ADD/DROP operations.
3692 */
3693 object = get_object_address(stmt->objtype, stmt->object,
3694 &relation, ShareUpdateExclusiveLock, false);
3695
3696 Assert(object.objectSubId == 0);
3697 if (objAddr)
3698 *objAddr = object;
3699
3700 /* Permission check: must own target object, too */
3701 check_object_ownership(GetUserId(), stmt->objtype, object,
3702 stmt->object, relation);
3703
3704 /* Do the update, recursing to any dependent objects */
3705 ExecAlterExtensionContentsRecurse(stmt, extension, object);
3706
3707 /* Finish up */
3708 InvokeObjectPostAlterHook(ExtensionRelationId, extension.objectId, 0);
3709
3710 /*
3711 * If get_object_address() opened the relation for us, we close it to keep
3712 * the reference count correct - but we retain any locks acquired by
3713 * get_object_address() until commit time, to guard against concurrent
3714 * activity.
3715 */
3716 if (relation != NULL)
3717 relation_close(relation, NoLock);
3718
3719 return extension;
3720}
static void ExecAlterExtensionContentsRecurse(AlterExtensionContentsStmt *stmt, ObjectAddress extension, ObjectAddress object)
Definition: extension.c:3730
Assert(PointerIsAligned(start, uint64))
#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:2394
@ OBJECT_ROLE
Definition: parsenodes.h:2385
@ OBJECT_INDEX
Definition: parsenodes.h:2372
@ OBJECT_DATABASE
Definition: parsenodes.h:2361
@ OBJECT_PUBLICATION
Definition: parsenodes.h:2382
@ OBJECT_SUBSCRIPTION
Definition: parsenodes.h:2390
@ OBJECT_STATISTIC_EXT
Definition: parsenodes.h:2391
Definition: nodes.h:135
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 3339 of file extension.c.

3340{
3341 DefElem *d_new_version = NULL;
3342 char *versionName;
3343 char *oldVersionName;
3344 ExtensionControlFile *control;
3345 Oid extensionOid;
3346 Relation extRel;
3347 ScanKeyData key[1];
3348 SysScanDesc extScan;
3349 HeapTuple extTup;
3350 List *updateVersions;
3351 Datum datum;
3352 bool isnull;
3353 ListCell *lc;
3354 ObjectAddress address;
3355
3356 /*
3357 * We use global variables to track the extension being created, so we can
3358 * create/update only one extension at the same time.
3359 */
3361 ereport(ERROR,
3362 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3363 errmsg("nested ALTER EXTENSION is not supported")));
3364
3365 /*
3366 * Look up the extension --- it must already exist in pg_extension
3367 */
3368 extRel = table_open(ExtensionRelationId, AccessShareLock);
3369
3370 ScanKeyInit(&key[0],
3371 Anum_pg_extension_extname,
3372 BTEqualStrategyNumber, F_NAMEEQ,
3373 CStringGetDatum(stmt->extname));
3374
3375 extScan = systable_beginscan(extRel, ExtensionNameIndexId, true,
3376 NULL, 1, key);
3377
3378 extTup = systable_getnext(extScan);
3379
3380 if (!HeapTupleIsValid(extTup))
3381 ereport(ERROR,
3382 (errcode(ERRCODE_UNDEFINED_OBJECT),
3383 errmsg("extension \"%s\" does not exist",
3384 stmt->extname)));
3385
3386 extensionOid = ((Form_pg_extension) GETSTRUCT(extTup))->oid;
3387
3388 /*
3389 * Determine the existing version we are updating from
3390 */
3391 datum = heap_getattr(extTup, Anum_pg_extension_extversion,
3392 RelationGetDescr(extRel), &isnull);
3393 if (isnull)
3394 elog(ERROR, "extversion is null");
3395 oldVersionName = text_to_cstring(DatumGetTextPP(datum));
3396
3397 systable_endscan(extScan);
3398
3400
3401 /* Permission check: must own extension */
3402 if (!object_ownercheck(ExtensionRelationId, extensionOid, GetUserId()))
3404 stmt->extname);
3405
3406 /*
3407 * Read the primary control file. Note we assume that it does not contain
3408 * any non-ASCII data, so there is no need to worry about encoding at this
3409 * point.
3410 */
3411 control = read_extension_control_file(stmt->extname);
3412
3413 /*
3414 * Read the statement option list
3415 */
3416 foreach(lc, stmt->options)
3417 {
3418 DefElem *defel = (DefElem *) lfirst(lc);
3419
3420 if (strcmp(defel->defname, "new_version") == 0)
3421 {
3422 if (d_new_version)
3423 errorConflictingDefElem(defel, pstate);
3424 d_new_version = defel;
3425 }
3426 else
3427 elog(ERROR, "unrecognized option: %s", defel->defname);
3428 }
3429
3430 /*
3431 * Determine the version to update to
3432 */
3433 if (d_new_version && d_new_version->arg)
3434 versionName = strVal(d_new_version->arg);
3435 else if (control->default_version)
3436 versionName = control->default_version;
3437 else
3438 {
3439 ereport(ERROR,
3440 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3441 errmsg("version to install must be specified")));
3442 versionName = NULL; /* keep compiler quiet */
3443 }
3444 check_valid_version_name(versionName);
3445
3446 /*
3447 * If we're already at that version, just say so
3448 */
3449 if (strcmp(oldVersionName, versionName) == 0)
3450 {
3452 (errmsg("version \"%s\" of extension \"%s\" is already installed",
3453 versionName, stmt->extname)));
3454 return InvalidObjectAddress;
3455 }
3456
3457 /*
3458 * Identify the series of update script files we need to execute
3459 */
3460 updateVersions = identify_update_path(control,
3461 oldVersionName,
3462 versionName);
3463
3464 /*
3465 * Update the pg_extension row and execute the update scripts, one at a
3466 * time
3467 */
3468 ApplyExtensionUpdates(extensionOid, control,
3469 oldVersionName, updateVersions,
3470 NULL, false, false);
3471
3472 ObjectAddressSet(address, ExtensionRelationId, extensionOid);
3473
3474 return address;
3475}
static void check_valid_version_name(const char *versionname)
Definition: extension.c:317
static List * identify_update_path(ExtensionControlFile *control, const char *oldVersion, const char *newVersion)
Definition: extension.c:1514
static void ApplyExtensionUpdates(Oid extensionOid, ExtensionControlFile *pcontrol, const char *initialVersion, List *updateVersions, char *origSchemaName, bool cascade, bool is_create)
Definition: extension.c:3486
#define DatumGetTextPP(X)
Definition: fmgr.h:293
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:904
uint64_t Datum
Definition: postgres.h:70
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:380
#define RelationGetDescr(relation)
Definition: rel.h:541
Node * arg
Definition: parsenodes.h:845
char * default_version
Definition: extension.c:90
Definition: pg_list.h:54
#define strVal(v)
Definition: value.h:82
char * text_to_cstring(const text *t)
Definition: varlena.c:214

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

2554{
2555 bool result = false;
2556 List *locations;
2557 DIR *dir;
2558 struct dirent *de;
2559
2561
2562 foreach_ptr(char, location, locations)
2563 {
2564 dir = AllocateDir(location);
2565
2566 /*
2567 * If the control directory doesn't exist, we want to silently return
2568 * false. Any other error will be reported by ReadDir.
2569 */
2570 if (dir == NULL && errno == ENOENT)
2571 {
2572 /* do nothing */
2573 }
2574 else
2575 {
2576 while ((de = ReadDir(dir, location)) != NULL)
2577 {
2578 char *extname;
2579
2581 continue;
2582
2583 /* extract extension name from 'name.control' filename */
2584 extname = pstrdup(de->d_name);
2585 *strrchr(extname, '.') = '\0';
2586
2587 /* ignore it if it's an auxiliary control file */
2588 if (strstr(extname, "--"))
2589 continue;
2590
2591 /* done if it matches request */
2592 if (strcmp(extname, extensionName) == 0)
2593 {
2594 result = true;
2595 break;
2596 }
2597 }
2598
2599 FreeDir(dir);
2600 }
2601 if (result)
2602 break;
2603 }
2604
2605 return result;
2606}
static bool is_extension_control_filename(const char *filename)
Definition: extension.c:364
static List * get_extension_control_directories(void)
Definition: extension.c:383
int FreeDir(DIR *dir)
Definition: fd.c:3005
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2887
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2953
char * pstrdup(const char *in)
Definition: mcxt.c:1781
#define foreach_ptr(type, var, lst)
Definition: pg_list.h:469
Definition: dirent.c:26
Definition: dirent.h:10
char d_name[MAX_PATH]
Definition: dirent.h:15

References AllocateDir(), dirent::d_name, foreach_ptr, FreeDir(), get_extension_control_directories(), 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 228 of file extension.c.

229{
230 char *result;
231 HeapTuple tuple;
232
233 tuple = SearchSysCache1(EXTENSIONOID, ObjectIdGetDatum(ext_oid));
234
235 if (!HeapTupleIsValid(tuple))
236 return NULL;
237
238 result = pstrdup(NameStr(((Form_pg_extension) GETSTRUCT(tuple))->extname));
239 ReleaseSysCache(tuple);
240
241 return result;
242}
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:264
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:220

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

207{
208 Oid result;
209
210 result = GetSysCacheOid1(EXTENSIONNAME, Anum_pg_extension_oid,
211 CStringGetDatum(extname));
212
213 if (!OidIsValid(result) && !missing_ok)
215 (errcode(ERRCODE_UNDEFINED_OBJECT),
216 errmsg("extension \"%s\" does not exist",
217 extname)));
218
219 return result;
220}
#define OidIsValid(objectId)
Definition: c.h:794
#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 250 of file extension.c.

251{
252 Oid result;
253 HeapTuple tuple;
254
255 tuple = SearchSysCache1(EXTENSIONOID, ObjectIdGetDatum(ext_oid));
256
257 if (!HeapTupleIsValid(tuple))
258 return InvalidOid;
259
260 result = ((Form_pg_extension) GETSTRUCT(tuple))->extnamespace;
261 ReleaseSysCache(tuple);
262
263 return result;
264}

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

2117{
2118 Oid extensionOid;
2119 Relation rel;
2120 Datum values[Natts_pg_extension];
2121 bool nulls[Natts_pg_extension];
2122 HeapTuple tuple;
2123 ObjectAddress myself;
2124 ObjectAddress nsp;
2125 ObjectAddresses *refobjs;
2126 ListCell *lc;
2127
2128 /*
2129 * Build and insert the pg_extension tuple
2130 */
2131 rel = table_open(ExtensionRelationId, RowExclusiveLock);
2132
2133 memset(values, 0, sizeof(values));
2134 memset(nulls, 0, sizeof(nulls));
2135
2136 extensionOid = GetNewOidWithIndex(rel, ExtensionOidIndexId,
2137 Anum_pg_extension_oid);
2138 values[Anum_pg_extension_oid - 1] = ObjectIdGetDatum(extensionOid);
2139 values[Anum_pg_extension_extname - 1] =
2141 values[Anum_pg_extension_extowner - 1] = ObjectIdGetDatum(extOwner);
2142 values[Anum_pg_extension_extnamespace - 1] = ObjectIdGetDatum(schemaOid);
2143 values[Anum_pg_extension_extrelocatable - 1] = BoolGetDatum(relocatable);
2144 values[Anum_pg_extension_extversion - 1] = CStringGetTextDatum(extVersion);
2145
2146 if (extConfig == PointerGetDatum(NULL))
2147 nulls[Anum_pg_extension_extconfig - 1] = true;
2148 else
2149 values[Anum_pg_extension_extconfig - 1] = extConfig;
2150
2151 if (extCondition == PointerGetDatum(NULL))
2152 nulls[Anum_pg_extension_extcondition - 1] = true;
2153 else
2154 values[Anum_pg_extension_extcondition - 1] = extCondition;
2155
2156 tuple = heap_form_tuple(rel->rd_att, values, nulls);
2157
2158 CatalogTupleInsert(rel, tuple);
2159
2160 heap_freetuple(tuple);
2162
2163 /*
2164 * Record dependencies on owner, schema, and prerequisite extensions
2165 */
2166 recordDependencyOnOwner(ExtensionRelationId, extensionOid, extOwner);
2167
2168 refobjs = new_object_addresses();
2169
2170 ObjectAddressSet(myself, ExtensionRelationId, extensionOid);
2171
2172 ObjectAddressSet(nsp, NamespaceRelationId, schemaOid);
2173 add_exact_object_address(&nsp, refobjs);
2174
2175 foreach(lc, requiredExtensions)
2176 {
2177 Oid reqext = lfirst_oid(lc);
2178 ObjectAddress otherext;
2179
2180 ObjectAddressSet(otherext, ExtensionRelationId, reqext);
2181 add_exact_object_address(&otherext, refobjs);
2182 }
2183
2184 /* Record all of them (this includes duplicate elimination) */
2186 free_object_addresses(refobjs);
2187
2188 /* Post creation hook for new extension */
2189 InvokeObjectPostCreateHook(ExtensionRelationId, extensionOid, 0);
2190
2191 return myself;
2192}
static Datum values[MAXATTR]
Definition: bootstrap.c:155
#define CStringGetTextDatum(s)
Definition: builtins.h:97
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:448
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
Definition: dependency.c:2918
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2709
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2949
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:684
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:352
static Datum BoolGetDatum(bool X)
Definition: postgres.h:112
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 2201 of file extension.c.

2202{
2203 Relation rel;
2204 SysScanDesc scandesc;
2205 HeapTuple tuple;
2206 ScanKeyData entry[1];
2207
2208 /*
2209 * Disallow deletion of any extension that's currently open for insertion;
2210 * else subsequent executions of recordDependencyOnCurrentExtension()
2211 * could create dangling pg_depend records that refer to a no-longer-valid
2212 * pg_extension OID. This is needed not so much because we think people
2213 * might write "DROP EXTENSION foo" in foo's own script files, as because
2214 * errors in dependency management in extension script files could give
2215 * rise to cases where an extension is dropped as a result of recursing
2216 * from some contained object. Because of that, we must test for the case
2217 * here, not at some higher level of the DROP EXTENSION command.
2218 */
2219 if (extId == CurrentExtensionObject)
2220 ereport(ERROR,
2221 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2222 errmsg("cannot drop extension \"%s\" because it is being modified",
2223 get_extension_name(extId))));
2224
2225 rel = table_open(ExtensionRelationId, RowExclusiveLock);
2226
2227 ScanKeyInit(&entry[0],
2228 Anum_pg_extension_oid,
2229 BTEqualStrategyNumber, F_OIDEQ,
2230 ObjectIdGetDatum(extId));
2231 scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
2232 NULL, 1, entry);
2233
2234 tuple = systable_getnext(scandesc);
2235
2236 /* We assume that there can be at most one matching tuple */
2237 if (HeapTupleIsValid(tuple))
2238 CatalogTupleDelete(rel, &tuple->t_self);
2239
2240 systable_endscan(scandesc);
2241
2243}
Oid CurrentExtensionObject
Definition: extension.c:78
void CatalogTupleDelete(Relation heapRel, const ItemPointerData *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

◆ Extension_control_path

PGDLLIMPORT char* Extension_control_path
extern

Definition at line 74 of file extension.c.

Referenced by get_extension_control_directories().