PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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)
 
charget_extension_name (Oid ext_oid)
 
Oid get_extension_schema (Oid ext_oid)
 
bool extension_file_exists (const char *extensionName)
 
Oid get_function_sibling_type (Oid funcoid, const char *typname)
 
ObjectAddress AlterExtensionNamespace (const char *extensionName, const char *newschema, Oid *oldschema)
 

Variables

PGDLLIMPORT charExtension_control_path
 
PGDLLIMPORT bool creating_extension
 
PGDLLIMPORT Oid CurrentExtensionObject
 

Function Documentation

◆ AlterExtensionNamespace()

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

Definition at line 3253 of file extension.c.

3254{
3256 Oid nspOid;
3257 Oid oldNspOid;
3260 ScanKeyData key[2];
3269
3271
3272 nspOid = LookupCreationNamespace(newschema);
3273
3274 /*
3275 * Permission check: must own extension. Note that we don't bother to
3276 * check ownership of the individual member objects ...
3277 */
3281
3282 /* Permission check: must have creation rights in target namespace */
3284 if (aclresult != ACLCHECK_OK)
3286
3287 /*
3288 * If the schema is currently a member of the extension, disallow moving
3289 * the extension into the schema. That would create a dependency loop.
3290 */
3292 ereport(ERROR,
3294 errmsg("cannot move extension \"%s\" into schema \"%s\" "
3295 "because the extension contains the schema",
3296 extensionName, newschema)));
3297
3298 /* Locate the pg_extension tuple */
3300
3301 ScanKeyInit(&key[0],
3305
3307 NULL, 1, key);
3308
3310
3311 if (!HeapTupleIsValid(extTup)) /* should not happen */
3312 elog(ERROR, "could not find tuple for extension %u",
3313 extensionOid);
3314
3315 /* Copy tuple so we can modify it below */
3318
3320
3321 /*
3322 * If the extension is already in the target schema, just silently do
3323 * nothing.
3324 */
3325 if (extForm->extnamespace == nspOid)
3326 {
3328 return InvalidObjectAddress;
3329 }
3330
3331 /* Check extension is supposed to be relocatable */
3332 if (!extForm->extrelocatable)
3333 ereport(ERROR,
3335 errmsg("extension \"%s\" does not support SET SCHEMA",
3336 NameStr(extForm->extname))));
3337
3339
3340 /* store the OID of the namespace to-be-changed */
3341 oldNspOid = extForm->extnamespace;
3342
3343 /*
3344 * Scan pg_depend to find objects that depend directly on the extension,
3345 * and alter each one's schema.
3346 */
3348
3349 ScanKeyInit(&key[0],
3353 ScanKeyInit(&key[1],
3357
3359 NULL, 2, key);
3360
3362 {
3366
3367 /*
3368 * If a dependent extension has a no_relocate request for this
3369 * extension, disallow SET SCHEMA. (XXX it's a bit ugly to do this in
3370 * the same loop that's actually executing the renames: we may detect
3371 * the error condition only after having expended a fair amount of
3372 * work. However, the alternative is to do two scans of pg_depend,
3373 * which seems like optimizing for failure cases. The rename work
3374 * will all roll back cleanly enough if we do fail here.)
3375 */
3376 if (pg_depend->deptype == DEPENDENCY_NORMAL &&
3377 pg_depend->classid == ExtensionRelationId)
3378 {
3379 char *depextname = get_extension_name(pg_depend->objid);
3381 ListCell *lc;
3382
3384 foreach(lc, dcontrol->no_relocate)
3385 {
3386 char *nrextname = (char *) lfirst(lc);
3387
3388 if (strcmp(nrextname, NameStr(extForm->extname)) == 0)
3389 {
3390 ereport(ERROR,
3392 errmsg("cannot SET SCHEMA of extension \"%s\" because other extensions prevent it",
3393 NameStr(extForm->extname)),
3394 errdetail("Extension \"%s\" requests no relocation of extension \"%s\".",
3395 depextname,
3396 NameStr(extForm->extname))));
3397 }
3398 }
3399 }
3400
3401 /*
3402 * Otherwise, ignore non-membership dependencies. (Currently, the
3403 * only other case we could see here is a normal dependency from
3404 * another extension.)
3405 */
3406 if (pg_depend->deptype != DEPENDENCY_EXTENSION)
3407 continue;
3408
3409 dep.classId = pg_depend->classid;
3410 dep.objectId = pg_depend->objid;
3411 dep.objectSubId = pg_depend->objsubid;
3412
3413 if (dep.objectSubId != 0) /* should not happen */
3414 elog(ERROR, "extension should not have a sub-object dependency");
3415
3416 /* Relocate the object */
3418 dep.objectId,
3419 nspOid,
3420 objsMoved);
3421
3422 /*
3423 * If not all the objects had the same old namespace (ignoring any
3424 * that are not in namespaces or are dependent types), complain.
3425 */
3427 ereport(ERROR,
3429 errmsg("extension \"%s\" does not support SET SCHEMA",
3430 NameStr(extForm->extname)),
3431 errdetail("%s is not in the extension's schema \"%s\"",
3432 getObjectDescription(&dep, false),
3434 }
3435
3436 /* report old schema, if caller wants it */
3437 if (oldschema)
3439
3441
3443
3444 /* Now adjust pg_extension.extnamespace */
3445 extForm->extnamespace = nspOid;
3446
3448
3450
3451 /* update dependency to point to the new schema */
3454 elog(ERROR, "could not change schema dependency for extension %s",
3455 NameStr(extForm->extname));
3456
3458
3460
3461 return extAddr;
3462}
AclResult
Definition acl.h:183
@ ACLCHECK_OK
Definition acl.h:184
@ ACLCHECK_NOT_OWNER
Definition acl.h:186
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition aclchk.c:2672
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition aclchk.c:3879
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition aclchk.c:4133
Oid AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid, ObjectAddresses *objsMoved)
Definition alter.c:621
#define NameStr(name)
Definition c.h:835
ObjectAddresses * new_object_addresses(void)
@ DEPENDENCY_EXTENSION
Definition dependency.h:38
@ DEPENDENCY_NORMAL
Definition dependency.h:33
int errcode(int sqlerrcode)
Definition elog.c:874
int errdetail(const char *fmt,...) pg_attribute_printf(1
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:227
#define ereport(elevel,...)
Definition elog.h:151
static ExtensionControlFile * read_extension_control_file(const char *extname)
Definition extension.c:879
Oid get_extension_oid(const char *extname, bool missing_ok)
Definition extension.c:229
char * get_extension_name(Oid ext_oid)
Definition extension.c:251
void systable_endscan(SysScanDesc sysscan)
Definition genam.c:604
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition genam.c:515
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:686
#define HeapTupleIsValid(tuple)
Definition htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
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:3588
Oid GetUserId(void)
Definition miscinit.c:470
Oid LookupCreationNamespace(const char *nspname)
Definition namespace.c:3500
static char * errmsg
#define InvokeObjectPostAlterHook(classId, objectId, subId)
char * getObjectDescription(const ObjectAddress *object, bool missing_ok)
const ObjectAddress InvalidObjectAddress
#define ObjectAddressSet(addr, class_id, object_id)
@ OBJECT_SCHEMA
@ OBJECT_EXTENSION
#define ACL_CREATE
Definition parsenodes.h:85
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition pg_depend.c:459
Oid getExtensionOfObject(Oid classId, Oid objectId)
Definition pg_depend.c:734
END_CATALOG_STRUCT typedef FormData_pg_depend * Form_pg_depend
Definition pg_depend.h:76
END_CATALOG_STRUCT typedef FormData_pg_extension * Form_pg_extension
#define lfirst(lc)
Definition pg_list.h:172
static Datum ObjectIdGetDatum(Oid X)
Definition postgres.h:252
#define InvalidOid
unsigned int Oid
static int fb(int x)
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition scankey.c:76
void relation_close(Relation relation, LOCKMODE lockmode)
Definition relation.c:206
#define BTEqualStrategyNumber
Definition stratnum.h:31
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(), DEPENDENCY_EXTENSION, DEPENDENCY_NORMAL, elog, ereport, errcode(), errdetail(), errmsg, ERROR, fb(), Form_pg_depend, Form_pg_extension, get_extension_name(), get_extension_oid(), get_namespace_name(), getExtensionOfObject(), getObjectDescription(), GETSTRUCT(), GetUserId(), heap_copytuple(), HeapTupleIsValid, InvalidObjectAddress, InvalidOid, InvokeObjectPostAlterHook, lfirst, LookupCreationNamespace(), NameStr, new_object_addresses(), object_aclcheck(), OBJECT_EXTENSION, object_ownercheck(), OBJECT_SCHEMA, ObjectAddressSet, ObjectIdGetDatum(), read_extension_control_file(), relation_close(), RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by ExecAlterObjectSchemaStmt().

◆ CreateExtension()

ObjectAddress CreateExtension ( ParseState pstate,
CreateExtensionStmt stmt 
)
extern

Definition at line 2144 of file extension.c.

2145{
2149 char *schemaName = NULL;
2150 char *versionName = NULL;
2151 bool cascade = false;
2152 ListCell *lc;
2153
2154 /* Check extension name validity before any filesystem access */
2156
2157 /*
2158 * Check for duplicate extension name. The unique index on
2159 * pg_extension.extname would catch this anyway, and serves as a backstop
2160 * in case of race conditions; but this is a friendlier error message, and
2161 * besides we need a check to support IF NOT EXISTS.
2162 */
2163 if (get_extension_oid(stmt->extname, true) != InvalidOid)
2164 {
2165 if (stmt->if_not_exists)
2166 {
2169 errmsg("extension \"%s\" already exists, skipping",
2170 stmt->extname)));
2171 return InvalidObjectAddress;
2172 }
2173 else
2174 ereport(ERROR,
2176 errmsg("extension \"%s\" already exists",
2177 stmt->extname)));
2178 }
2179
2180 /*
2181 * We use global variables to track the extension being created, so we can
2182 * create only one extension at the same time.
2183 */
2185 ereport(ERROR,
2187 errmsg("nested CREATE EXTENSION is not supported")));
2188
2189 /* Deconstruct the statement option list */
2190 foreach(lc, stmt->options)
2191 {
2192 DefElem *defel = (DefElem *) lfirst(lc);
2193
2194 if (strcmp(defel->defname, "schema") == 0)
2195 {
2196 if (d_schema)
2198 d_schema = defel;
2200 }
2201 else if (strcmp(defel->defname, "new_version") == 0)
2202 {
2203 if (d_new_version)
2207 }
2208 else if (strcmp(defel->defname, "cascade") == 0)
2209 {
2210 if (d_cascade)
2212 d_cascade = defel;
2213 cascade = defGetBoolean(d_cascade);
2214 }
2215 else
2216 elog(ERROR, "unrecognized option: %s", defel->defname);
2217 }
2218
2219 /* Call CreateExtensionInternal to do the real work. */
2220 return CreateExtensionInternal(stmt->extname,
2221 schemaName,
2223 cascade,
2224 NIL,
2225 true);
2226}
char * defGetString(DefElem *def)
Definition define.c:34
bool defGetBoolean(DefElem *def)
Definition define.c:93
void errorConflictingDefElem(DefElem *defel, ParseState *pstate)
Definition define.c:370
#define NOTICE
Definition elog.h:35
static void check_valid_extension_name(const char *extensionname)
Definition extension.c:401
bool creating_extension
Definition extension.c:80
static ObjectAddress CreateExtensionInternal(char *extensionName, char *schemaName, const char *versionName, bool cascade, List *parents, bool is_create)
Definition extension.c:1834
#define stmt
#define NIL
Definition pg_list.h:68
#define ERRCODE_DUPLICATE_OBJECT
Definition streamutil.c:30

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

Referenced by ProcessUtilitySlow().

◆ ExecAlterExtensionContentsStmt()

ObjectAddress ExecAlterExtensionContentsStmt ( AlterExtensionContentsStmt stmt,
ObjectAddress objAddr 
)
extern

Definition at line 3773 of file extension.c.

3775{
3777 ObjectAddress object;
3778 Relation relation;
3779
3780 switch (stmt->objtype)
3781 {
3782 case OBJECT_DATABASE:
3783 case OBJECT_EXTENSION:
3784 case OBJECT_INDEX:
3785 case OBJECT_PUBLICATION:
3786 case OBJECT_ROLE:
3789 case OBJECT_TABLESPACE:
3790 ereport(ERROR,
3792 errmsg("cannot add an object of this type to an extension")));
3793 break;
3794 default:
3795 /* OK */
3796 break;
3797 }
3798
3799 /*
3800 * Find the extension and acquire a lock on it, to ensure it doesn't get
3801 * dropped concurrently. A sharable lock seems sufficient: there's no
3802 * reason not to allow other sorts of manipulations, such as add/drop of
3803 * other objects, to occur concurrently. Concurrently adding/dropping the
3804 * *same* object would be bad, but we prevent that by using a non-sharable
3805 * lock on the individual object, below.
3806 */
3808 (Node *) makeString(stmt->extname),
3809 &relation, AccessShareLock, false);
3810
3811 /* Permission check: must own extension */
3814 stmt->extname);
3815
3816 /*
3817 * Translate the parser representation that identifies the object into an
3818 * ObjectAddress. get_object_address() will throw an error if the object
3819 * does not exist, and will also acquire a lock on the object to guard
3820 * against concurrent DROP and ALTER EXTENSION ADD/DROP operations.
3821 */
3822 object = get_object_address(stmt->objtype, stmt->object,
3823 &relation, ShareUpdateExclusiveLock, false);
3824
3825 Assert(object.objectSubId == 0);
3826 if (objAddr)
3827 *objAddr = object;
3828
3829 /* Permission check: must own target object, too */
3830 check_object_ownership(GetUserId(), stmt->objtype, object,
3831 stmt->object, relation);
3832
3833 /* Do the update, recursing to any dependent objects */
3835
3836 /* Finish up */
3838
3839 /*
3840 * If get_object_address() opened the relation for us, we close it to keep
3841 * the reference count correct - but we retain any locks acquired by
3842 * get_object_address() until commit time, to guard against concurrent
3843 * activity.
3844 */
3845 if (relation != NULL)
3846 relation_close(relation, NoLock);
3847
3848 return extension;
3849}
#define Assert(condition)
Definition c.h:943
static void ExecAlterExtensionContentsRecurse(AlterExtensionContentsStmt *stmt, ObjectAddress extension, ObjectAddress object)
Definition extension.c:3859
#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
@ OBJECT_ROLE
@ OBJECT_INDEX
@ OBJECT_DATABASE
@ OBJECT_PUBLICATION
@ OBJECT_SUBSCRIPTION
@ OBJECT_STATISTIC_EXT
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(), fb(), 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, relation_close(), ShareUpdateExclusiveLock, and stmt.

Referenced by ProcessUtilitySlow().

◆ ExecAlterExtensionStmt()

ObjectAddress ExecAlterExtensionStmt ( ParseState pstate,
AlterExtensionStmt stmt 
)
extern

Definition at line 3468 of file extension.c.

3469{
3471 char *versionName;
3472 char *oldVersionName;
3473 ExtensionControlFile *control;
3476 ScanKeyData key[1];
3480 Datum datum;
3481 bool isnull;
3482 ListCell *lc;
3483 ObjectAddress address;
3484
3485 /*
3486 * We use global variables to track the extension being created, so we can
3487 * create/update only one extension at the same time.
3488 */
3490 ereport(ERROR,
3492 errmsg("nested ALTER EXTENSION is not supported")));
3493
3494 /*
3495 * Look up the extension --- it must already exist in pg_extension
3496 */
3498
3499 ScanKeyInit(&key[0],
3502 CStringGetDatum(stmt->extname));
3503
3505 NULL, 1, key);
3506
3508
3510 ereport(ERROR,
3512 errmsg("extension \"%s\" does not exist",
3513 stmt->extname)));
3514
3516
3517 /*
3518 * Determine the existing version we are updating from
3519 */
3521 RelationGetDescr(extRel), &isnull);
3522 if (isnull)
3523 elog(ERROR, "extversion is null");
3525
3527
3529
3530 /* Permission check: must own extension */
3533 stmt->extname);
3534
3535 /*
3536 * Read the primary control file. Note we assume that it does not contain
3537 * any non-ASCII data, so there is no need to worry about encoding at this
3538 * point.
3539 */
3540 control = read_extension_control_file(stmt->extname);
3541
3542 /*
3543 * Read the statement option list
3544 */
3545 foreach(lc, stmt->options)
3546 {
3547 DefElem *defel = (DefElem *) lfirst(lc);
3548
3549 if (strcmp(defel->defname, "new_version") == 0)
3550 {
3551 if (d_new_version)
3554 }
3555 else
3556 elog(ERROR, "unrecognized option: %s", defel->defname);
3557 }
3558
3559 /*
3560 * Determine the version to update to
3561 */
3562 if (d_new_version && d_new_version->arg)
3564 else if (control->default_version)
3565 versionName = control->default_version;
3566 else
3567 {
3568 ereport(ERROR,
3570 errmsg("version to install must be specified")));
3571 versionName = NULL; /* keep compiler quiet */
3572 }
3574
3575 /*
3576 * If we're already at that version, just say so
3577 */
3579 {
3581 (errmsg("version \"%s\" of extension \"%s\" is already installed",
3582 versionName, stmt->extname)));
3583 return InvalidObjectAddress;
3584 }
3585
3586 /*
3587 * Identify the series of update script files we need to execute
3588 */
3591 versionName);
3592
3593 /*
3594 * Update the pg_extension row and execute the update scripts, one at a
3595 * time
3596 */
3599 NULL, false, false);
3600
3602
3603 return address;
3604}
static void check_valid_version_name(const char *versionname)
Definition extension.c:448
static List * identify_update_path(ExtensionControlFile *control, const char *oldVersion, const char *newVersion)
Definition extension.c:1643
static void ApplyExtensionUpdates(Oid extensionOid, ExtensionControlFile *pcontrol, const char *initialVersion, List *updateVersions, char *origSchemaName, bool cascade, bool is_create)
Definition extension.c:3615
#define DatumGetTextPP(X)
Definition fmgr.h:293
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
uint64_t Datum
Definition postgres.h:70
static Datum CStringGetDatum(const char *X)
Definition postgres.h:370
#define RelationGetDescr(relation)
Definition rel.h:540
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(), BTEqualStrategyNumber, check_valid_version_name(), creating_extension, CStringGetDatum(), DatumGetTextPP, ExtensionControlFile::default_version, elog, ereport, errcode(), errmsg, ERROR, errorConflictingDefElem(), fb(), Form_pg_extension, GETSTRUCT(), GetUserId(), heap_getattr(), HeapTupleIsValid, identify_update_path(), InvalidObjectAddress, 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)
extern

Definition at line 2682 of file extension.c.

2683{
2684 bool result = false;
2685 List *locations;
2686 DIR *dir;
2687 struct dirent *de;
2688
2690
2692 {
2693 dir = AllocateDir(location->loc);
2694
2695 /*
2696 * If the control directory doesn't exist, we want to silently return
2697 * false. Any other error will be reported by ReadDir.
2698 */
2699 if (dir == NULL && errno == ENOENT)
2700 {
2701 /* do nothing */
2702 }
2703 else
2704 {
2705 while ((de = ReadDir(dir, location->loc)) != NULL)
2706 {
2707 char *extname;
2708
2709 if (!is_extension_control_filename(de->d_name))
2710 continue;
2711
2712 /* extract extension name from 'name.control' filename */
2713 extname = pstrdup(de->d_name);
2714 *strrchr(extname, '.') = '\0';
2715
2716 /* ignore it if it's an auxiliary control file */
2717 if (strstr(extname, "--"))
2718 continue;
2719
2720 /* done if it matches request */
2721 if (strcmp(extname, extensionName) == 0)
2722 {
2723 result = true;
2724 break;
2725 }
2726 }
2727
2728 FreeDir(dir);
2729 }
2730 if (result)
2731 break;
2732 }
2733
2734 return result;
2735}
static bool is_extension_control_filename(const char *filename)
Definition extension.c:495
static List * get_extension_control_directories(void)
Definition extension.c:514
int FreeDir(DIR *dir)
Definition fd.c:3009
DIR * AllocateDir(const char *dirname)
Definition fd.c:2891
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition fd.c:2957
char * pstrdup(const char *in)
Definition mcxt.c:1781
#define foreach_ptr(type, var, lst)
Definition pg_list.h:501
Definition dirent.c:26

References AllocateDir(), fb(), 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)
extern

Definition at line 251 of file extension.c.

252{
253 char *result;
254 HeapTuple tuple;
255
257
258 if (!HeapTupleIsValid(tuple))
259 return NULL;
260
261 result = pstrdup(NameStr(((Form_pg_extension) GETSTRUCT(tuple))->extname));
262 ReleaseSysCache(tuple);
263
264 return result;
265}
void ReleaseSysCache(HeapTuple tuple)
Definition syscache.c:265
HeapTuple SearchSysCache1(SysCacheIdentifier cacheId, Datum key1)
Definition syscache.c:221

References fb(), Form_pg_extension, 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 
)
extern

Definition at line 229 of file extension.c.

230{
231 Oid result;
232
234 CStringGetDatum(extname));
235
236 if (!OidIsValid(result) && !missing_ok)
239 errmsg("extension \"%s\" does not exist",
240 extname)));
241
242 return result;
243}
#define OidIsValid(objectId)
Definition c.h:858
#define GetSysCacheOid1(cacheId, oidcol, key1)
Definition syscache.h:109

References CStringGetDatum(), ereport, errcode(), errmsg, ERROR, fb(), 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)
extern

Definition at line 273 of file extension.c.

274{
275 Oid result;
276 HeapTuple tuple;
277
279
280 if (!HeapTupleIsValid(tuple))
281 return InvalidOid;
282
283 result = ((Form_pg_extension) GETSTRUCT(tuple))->extnamespace;
284 ReleaseSysCache(tuple);
285
286 return result;
287}

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

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

◆ get_function_sibling_type()

Oid get_function_sibling_type ( Oid  funcoid,
const char typname 
)
extern

Definition at line 313 of file extension.c.

314{
316 Oid extoid;
317 Oid typeoid;
318
319 /*
320 * See if we have the answer cached. Someday there may be enough callers
321 * to justify a hash table, but for now, a simple linked list is fine.
322 */
325 {
326 if (funcoid == cache_entry->reqfuncoid &&
327 strcmp(typname, cache_entry->typname) == 0)
328 break;
329 }
330 if (cache_entry && cache_entry->valid)
331 return cache_entry->typeoid;
332
333 /*
334 * Nope, so do the expensive lookups. We do not expect failures, so we do
335 * not cache negative results.
336 */
338 if (!OidIsValid(extoid))
339 return InvalidOid;
340 typeoid = getExtensionType(extoid, typname);
341 if (!OidIsValid(typeoid))
342 return InvalidOid;
343
344 /*
345 * Build, or revalidate, cache entry.
346 */
347 if (cache_entry == NULL)
348 {
349 /* Register invalidation hook if this is first entry */
350 if (ext_sibling_list == NULL)
353 (Datum) 0);
354
355 /* Momentarily zero the space to ensure valid flag is false */
358 sizeof(ExtensionSiblingCache));
361 }
362
364 cache_entry->typname = typname;
367 cache_entry->typeoid = typeoid;
368 /* Mark it valid only once it's fully populated */
369 cache_entry->valid = true;
370
371 return typeoid;
372}
static ExtensionSiblingCache * ext_sibling_list
Definition extension.c:163
static void ext_sibling_callback(Datum arg, SysCacheIdentifier cacheid, uint32 hashvalue)
Definition extension.c:384
void CacheRegisterSyscacheCallback(SysCacheIdentifier cacheid, SyscacheCallbackFunction func, Datum arg)
Definition inval.c:1816
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition mcxt.c:1266
MemoryContext CacheMemoryContext
Definition mcxt.c:169
Oid getExtensionType(Oid extensionOid, const char *typname)
Definition pg_depend.c:832
NameData typname
Definition pg_type.h:43
struct ExtensionSiblingCache * next
Definition extension.c:153
#define GetSysCacheHashValue1(cacheId, key1)
Definition syscache.h:118

References CacheMemoryContext, CacheRegisterSyscacheCallback(), ext_sibling_callback(), ext_sibling_list, fb(), getExtensionOfObject(), getExtensionType(), GetSysCacheHashValue1, InvalidOid, MemoryContextAllocZero(), ExtensionSiblingCache::next, ObjectIdGetDatum(), OidIsValid, ExtensionSiblingCache::reqfuncoid, ExtensionSiblingCache::typeoid, and typname.

Referenced by _int_matchsel().

◆ InsertExtensionTuple()

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

Definition at line 2242 of file extension.c.

2246{
2248 Relation rel;
2250 bool nulls[Natts_pg_extension];
2251 HeapTuple tuple;
2255 ListCell *lc;
2256
2257 /*
2258 * Build and insert the pg_extension tuple
2259 */
2261
2262 memset(values, 0, sizeof(values));
2263 memset(nulls, 0, sizeof(nulls));
2264
2274
2276 nulls[Anum_pg_extension_extconfig - 1] = true;
2277 else
2279
2281 nulls[Anum_pg_extension_extcondition - 1] = true;
2282 else
2284
2285 tuple = heap_form_tuple(rel->rd_att, values, nulls);
2286
2287 CatalogTupleInsert(rel, tuple);
2288
2289 heap_freetuple(tuple);
2291
2292 /*
2293 * Record dependencies on owner, schema, and prerequisite extensions
2294 */
2296
2298
2300
2303
2304 foreach(lc, requiredExtensions)
2305 {
2308
2311 }
2312
2313 /* Record all of them (this includes duplicate elimination) */
2316
2317 /* Post creation hook for new extension */
2319
2320 return myself;
2321}
static Datum values[MAXATTR]
Definition bootstrap.c:188
#define CStringGetTextDatum(s)
Definition builtins.h:98
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition catalog.c:448
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
void free_object_addresses(ObjectAddresses *addrs)
#define DirectFunctionCall1(func, arg1)
Definition fmgr.h:684
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition heaptuple.c:1025
void heap_freetuple(HeapTuple htup)
Definition heaptuple.c:1372
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition indexing.c:233
Datum namein(PG_FUNCTION_ARGS)
Definition name.c:48
#define InvokeObjectPostCreateHook(classId, objectId, subId)
#define lfirst_oid(lc)
Definition pg_list.h:174
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
static Datum PointerGetDatum(const void *X)
Definition postgres.h:342
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, fb(), 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)
extern

Definition at line 2330 of file extension.c.

2331{
2332 Relation rel;
2333 SysScanDesc scandesc;
2334 HeapTuple tuple;
2335 ScanKeyData entry[1];
2336
2337 /*
2338 * Disallow deletion of any extension that's currently open for insertion;
2339 * else subsequent executions of recordDependencyOnCurrentExtension()
2340 * could create dangling pg_depend records that refer to a no-longer-valid
2341 * pg_extension OID. This is needed not so much because we think people
2342 * might write "DROP EXTENSION foo" in foo's own script files, as because
2343 * errors in dependency management in extension script files could give
2344 * rise to cases where an extension is dropped as a result of recursing
2345 * from some contained object. Because of that, we must test for the case
2346 * here, not at some higher level of the DROP EXTENSION command.
2347 */
2349 ereport(ERROR,
2351 errmsg("cannot drop extension \"%s\" because it is being modified",
2353
2355
2356 ScanKeyInit(&entry[0],
2360 scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
2361 NULL, 1, entry);
2362
2363 tuple = systable_getnext(scandesc);
2364
2365 /* We assume that there can be at most one matching tuple */
2366 if (HeapTupleIsValid(tuple))
2367 CatalogTupleDelete(rel, &tuple->t_self);
2368
2369 systable_endscan(scandesc);
2370
2372}
Oid CurrentExtensionObject
Definition extension.c:81
void CatalogTupleDelete(Relation heapRel, const ItemPointerData *tid)
Definition indexing.c:365
ItemPointerData t_self
Definition htup.h:65

References BTEqualStrategyNumber, CatalogTupleDelete(), CurrentExtensionObject, ereport, errcode(), errmsg, ERROR, fb(), 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 77 of file extension.c.

Referenced by get_extension_control_directories().