PostgreSQL Source Code  git master
extension.c File Reference
#include "postgres.h"
#include <dirent.h>
#include <limits.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <unistd.h>
#include "access/genam.h"
#include "access/htup_details.h"
#include "access/relation.h"
#include "access/table.h"
#include "access/xact.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_database.h"
#include "catalog/pg_depend.h"
#include "catalog/pg_extension.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_type.h"
#include "commands/alter.h"
#include "commands/comment.h"
#include "commands/defrem.h"
#include "commands/extension.h"
#include "commands/schemacmds.h"
#include "funcapi.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "storage/fd.h"
#include "tcop/utility.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/conffiles.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
#include "utils/varlena.h"
Include dependency graph for extension.c:

Go to the source code of this file.

Data Structures

struct  ExtensionControlFile
 
struct  ExtensionVersionInfo
 

Typedefs

typedef struct ExtensionControlFile ExtensionControlFile
 
typedef struct ExtensionVersionInfo ExtensionVersionInfo
 

Functions

static Listfind_update_path (List *evi_list, ExtensionVersionInfo *evi_start, ExtensionVersionInfo *evi_target, bool reject_indirect, bool reinitialize)
 
static Oid get_required_extension (char *reqExtensionName, char *extensionName, char *origSchemaName, bool cascade, List *parents, bool is_create)
 
static void get_available_versions_for_extension (ExtensionControlFile *pcontrol, Tuplestorestate *tupstore, TupleDesc tupdesc)
 
static Datum convert_requires_to_datum (List *requires)
 
static void ApplyExtensionUpdates (Oid extensionOid, ExtensionControlFile *pcontrol, const char *initialVersion, List *updateVersions, char *origSchemaName, bool cascade, bool is_create)
 
static void ExecAlterExtensionContentsRecurse (AlterExtensionContentsStmt *stmt, ObjectAddress extension, ObjectAddress object)
 
static char * read_whole_file (const char *filename, int *length)
 
Oid get_extension_oid (const char *extname, bool missing_ok)
 
char * get_extension_name (Oid ext_oid)
 
Oid get_extension_schema (Oid ext_oid)
 
static void check_valid_extension_name (const char *extensionname)
 
static void check_valid_version_name (const char *versionname)
 
static bool is_extension_control_filename (const char *filename)
 
static bool is_extension_script_filename (const char *filename)
 
static char * get_extension_control_directory (void)
 
static char * get_extension_control_filename (const char *extname)
 
static char * get_extension_script_directory (ExtensionControlFile *control)
 
static char * get_extension_aux_control_filename (ExtensionControlFile *control, const char *version)
 
static char * get_extension_script_filename (ExtensionControlFile *control, const char *from_version, const char *version)
 
static void parse_extension_control_file (ExtensionControlFile *control, const char *version)
 
static ExtensionControlFileread_extension_control_file (const char *extname)
 
static ExtensionControlFileread_extension_aux_control_file (const ExtensionControlFile *pcontrol, const char *version)
 
static char * read_extension_script_file (const ExtensionControlFile *control, const char *filename)
 
static void execute_sql_string (const char *sql)
 
static bool extension_is_trusted (ExtensionControlFile *control)
 
static void execute_extension_script (Oid extensionOid, ExtensionControlFile *control, const char *from_version, const char *version, List *requiredSchemas, const char *schemaName, Oid schemaOid)
 
static ExtensionVersionInfoget_ext_ver_info (const char *versionname, List **evi_list)
 
static ExtensionVersionInfoget_nearest_unprocessed_vertex (List *evi_list)
 
static Listget_ext_ver_list (ExtensionControlFile *control)
 
static Listidentify_update_path (ExtensionControlFile *control, const char *oldVersion, const char *newVersion)
 
static ExtensionVersionInfofind_install_path (List *evi_list, ExtensionVersionInfo *evi_target, List **best_path)
 
static ObjectAddress CreateExtensionInternal (char *extensionName, char *schemaName, const char *versionName, bool cascade, List *parents, bool is_create)
 
ObjectAddress CreateExtension (ParseState *pstate, CreateExtensionStmt *stmt)
 
ObjectAddress InsertExtensionTuple (const char *extName, Oid extOwner, Oid schemaOid, bool relocatable, const char *extVersion, Datum extConfig, Datum extCondition, List *requiredExtensions)
 
void RemoveExtensionById (Oid extId)
 
Datum pg_available_extensions (PG_FUNCTION_ARGS)
 
Datum pg_available_extension_versions (PG_FUNCTION_ARGS)
 
bool extension_file_exists (const char *extensionName)
 
Datum pg_extension_update_paths (PG_FUNCTION_ARGS)
 
Datum pg_extension_config_dump (PG_FUNCTION_ARGS)
 
static void extension_config_remove (Oid extensionoid, Oid tableoid)
 
ObjectAddress AlterExtensionNamespace (const char *extensionName, const char *newschema, Oid *oldschema)
 
ObjectAddress ExecAlterExtensionStmt (ParseState *pstate, AlterExtensionStmt *stmt)
 
ObjectAddress ExecAlterExtensionContentsStmt (AlterExtensionContentsStmt *stmt, ObjectAddress *objAddr)
 

Variables

bool creating_extension = false
 
Oid CurrentExtensionObject = InvalidOid
 

Typedef Documentation

◆ ExtensionControlFile

◆ ExtensionVersionInfo

Function Documentation

◆ AlterExtensionNamespace()

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

Definition at line 2716 of file extension.c.

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

References AccessShareLock, ACL_CREATE, aclcheck_error(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, AlterObjectNamespace_oid(), BTEqualStrategyNumber, CatalogTupleUpdate(), changeDependencyFor(), ObjectAddress::classId, DEPENDENCY_EXTENSION, DEPENDENCY_NORMAL, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, get_extension_name(), get_extension_oid(), get_namespace_name(), getExtensionOfObject(), getObjectDescription(), GETSTRUCT, GetUserId(), heap_copytuple(), HeapTupleIsValid, InvalidObjectAddress, InvalidOid, InvokeObjectPostAlterHook, sort-test::key, lfirst, LookupCreationNamespace(), NameStr, new_object_addresses(), ExtensionControlFile::no_relocate, object_aclcheck(), OBJECT_EXTENSION, object_ownercheck(), OBJECT_SCHEMA, ObjectAddressSet, ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, read_extension_control_file(), relation_close(), RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by ExecAlterObjectSchemaStmt().

◆ ApplyExtensionUpdates()

static void ApplyExtensionUpdates ( Oid  extensionOid,
ExtensionControlFile pcontrol,
const char *  initialVersion,
List updateVersions,
char *  origSchemaName,
bool  cascade,
bool  is_create 
)
static

Definition at line 3078 of file extension.c.

3085 {
3086  const char *oldVersionName = initialVersion;
3087  ListCell *lcv;
3088 
3089  foreach(lcv, updateVersions)
3090  {
3091  char *versionName = (char *) lfirst(lcv);
3092  ExtensionControlFile *control;
3093  char *schemaName;
3094  Oid schemaOid;
3095  List *requiredExtensions;
3096  List *requiredSchemas;
3097  Relation extRel;
3098  ScanKeyData key[1];
3099  SysScanDesc extScan;
3100  HeapTuple extTup;
3101  Form_pg_extension extForm;
3102  Datum values[Natts_pg_extension];
3103  bool nulls[Natts_pg_extension];
3104  bool repl[Natts_pg_extension];
3105  ObjectAddress myself;
3106  ListCell *lc;
3107 
3108  /*
3109  * Fetch parameters for specific version (pcontrol is not changed)
3110  */
3111  control = read_extension_aux_control_file(pcontrol, versionName);
3112 
3113  /* Find the pg_extension tuple */
3114  extRel = table_open(ExtensionRelationId, RowExclusiveLock);
3115 
3116  ScanKeyInit(&key[0],
3117  Anum_pg_extension_oid,
3118  BTEqualStrategyNumber, F_OIDEQ,
3119  ObjectIdGetDatum(extensionOid));
3120 
3121  extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
3122  NULL, 1, key);
3123 
3124  extTup = systable_getnext(extScan);
3125 
3126  if (!HeapTupleIsValid(extTup)) /* should not happen */
3127  elog(ERROR, "could not find tuple for extension %u",
3128  extensionOid);
3129 
3130  extForm = (Form_pg_extension) GETSTRUCT(extTup);
3131 
3132  /*
3133  * Determine the target schema (set by original install)
3134  */
3135  schemaOid = extForm->extnamespace;
3136  schemaName = get_namespace_name(schemaOid);
3137 
3138  /*
3139  * Modify extrelocatable and extversion in the pg_extension tuple
3140  */
3141  memset(values, 0, sizeof(values));
3142  memset(nulls, 0, sizeof(nulls));
3143  memset(repl, 0, sizeof(repl));
3144 
3145  values[Anum_pg_extension_extrelocatable - 1] =
3146  BoolGetDatum(control->relocatable);
3147  repl[Anum_pg_extension_extrelocatable - 1] = true;
3148  values[Anum_pg_extension_extversion - 1] =
3149  CStringGetTextDatum(versionName);
3150  repl[Anum_pg_extension_extversion - 1] = true;
3151 
3152  extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
3153  values, nulls, repl);
3154 
3155  CatalogTupleUpdate(extRel, &extTup->t_self, extTup);
3156 
3157  systable_endscan(extScan);
3158 
3159  table_close(extRel, RowExclusiveLock);
3160 
3161  /*
3162  * Look up the prerequisite extensions for this version, install them
3163  * if necessary, and build lists of their OIDs and the OIDs of their
3164  * target schemas.
3165  */
3166  requiredExtensions = NIL;
3167  requiredSchemas = NIL;
3168  foreach(lc, control->requires)
3169  {
3170  char *curreq = (char *) lfirst(lc);
3171  Oid reqext;
3172  Oid reqschema;
3173 
3174  reqext = get_required_extension(curreq,
3175  control->name,
3176  origSchemaName,
3177  cascade,
3178  NIL,
3179  is_create);
3180  reqschema = get_extension_schema(reqext);
3181  requiredExtensions = lappend_oid(requiredExtensions, reqext);
3182  requiredSchemas = lappend_oid(requiredSchemas, reqschema);
3183  }
3184 
3185  /*
3186  * Remove and recreate dependencies on prerequisite extensions
3187  */
3188  deleteDependencyRecordsForClass(ExtensionRelationId, extensionOid,
3189  ExtensionRelationId,
3191 
3192  myself.classId = ExtensionRelationId;
3193  myself.objectId = extensionOid;
3194  myself.objectSubId = 0;
3195 
3196  foreach(lc, requiredExtensions)
3197  {
3198  Oid reqext = lfirst_oid(lc);
3199  ObjectAddress otherext;
3200 
3201  otherext.classId = ExtensionRelationId;
3202  otherext.objectId = reqext;
3203  otherext.objectSubId = 0;
3204 
3205  recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
3206  }
3207 
3208  InvokeObjectPostAlterHook(ExtensionRelationId, extensionOid, 0);
3209 
3210  /*
3211  * Finally, execute the update script file
3212  */
3213  execute_extension_script(extensionOid, control,
3214  oldVersionName, versionName,
3215  requiredSchemas,
3216  schemaName, schemaOid);
3217 
3218  /*
3219  * Update prior-version name and loop around. Since
3220  * execute_sql_string did a final CommandCounterIncrement, we can
3221  * update the pg_extension row again.
3222  */
3223  oldVersionName = versionName;
3224  }
3225 }
static Datum values[MAXATTR]
Definition: bootstrap.c:150
#define CStringGetTextDatum(s)
Definition: builtins.h:97
Oid get_extension_schema(Oid ext_oid)
Definition: extension.c:190
static Oid get_required_extension(char *reqExtensionName, char *extensionName, char *origSchemaName, bool cascade, List *parents, bool is_create)
Definition: extension.c:1641
static void execute_extension_script(Oid extensionOid, ExtensionControlFile *control, const char *from_version, const char *version, List *requiredSchemas, const char *schemaName, Oid schemaOid)
Definition: extension.c:814
static ExtensionControlFile * read_extension_aux_control_file(const ExtensionControlFile *pcontrol, const char *version)
Definition: extension.c:621
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition: heaptuple.c:1209
List * lappend_oid(List *list, Oid datum)
Definition: list.c:375
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:46
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition: pg_depend.c:352
#define NIL
Definition: pg_list.h:68
#define lfirst_oid(lc)
Definition: pg_list.h:174
uintptr_t Datum
Definition: postgres.h:64
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102
#define RelationGetDescr(relation)
Definition: rel.h:531
Definition: pg_list.h:54

References BoolGetDatum(), BTEqualStrategyNumber, CatalogTupleUpdate(), ObjectAddress::classId, CStringGetTextDatum, deleteDependencyRecordsForClass(), DEPENDENCY_NORMAL, elog, ERROR, execute_extension_script(), get_extension_schema(), get_namespace_name(), get_required_extension(), GETSTRUCT, heap_modify_tuple(), HeapTupleIsValid, InvokeObjectPostAlterHook, sort-test::key, lappend_oid(), lfirst, lfirst_oid, ExtensionControlFile::name, NIL, ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, read_extension_aux_control_file(), recordDependencyOn(), RelationGetDescr, ExtensionControlFile::relocatable, ExtensionControlFile::requires, RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), table_open(), and values.

Referenced by CreateExtensionInternal(), and ExecAlterExtensionStmt().

◆ check_valid_extension_name()

static void check_valid_extension_name ( const char *  extensionname)
static

Definition at line 210 of file extension.c.

211 {
212  int namelen = strlen(extensionname);
213 
214  /*
215  * Disallow empty names (the parser rejects empty identifiers anyway, but
216  * let's check).
217  */
218  if (namelen == 0)
219  ereport(ERROR,
220  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
221  errmsg("invalid extension name: \"%s\"", extensionname),
222  errdetail("Extension names must not be empty.")));
223 
224  /*
225  * No double dashes, since that would make script filenames ambiguous.
226  */
227  if (strstr(extensionname, "--"))
228  ereport(ERROR,
229  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
230  errmsg("invalid extension name: \"%s\"", extensionname),
231  errdetail("Extension names must not contain \"--\".")));
232 
233  /*
234  * No leading or trailing dash either. (We could probably allow this, but
235  * it would require much care in filename parsing and would make filenames
236  * visually if not formally ambiguous. Since there's no real-world use
237  * case, let's just forbid it.)
238  */
239  if (extensionname[0] == '-' || extensionname[namelen - 1] == '-')
240  ereport(ERROR,
241  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
242  errmsg("invalid extension name: \"%s\"", extensionname),
243  errdetail("Extension names must not begin or end with \"-\".")));
244 
245  /*
246  * No directory separators either (this is sufficient to prevent ".."
247  * style attacks).
248  */
249  if (first_dir_separator(extensionname) != NULL)
250  ereport(ERROR,
251  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
252  errmsg("invalid extension name: \"%s\"", extensionname),
253  errdetail("Extension names must not contain directory separator characters.")));
254 }
char * first_dir_separator(const char *filename)
Definition: path.c:105

References ereport, errcode(), errdetail(), errmsg(), ERROR, and first_dir_separator().

Referenced by CreateExtension(), get_required_extension(), and pg_extension_update_paths().

◆ check_valid_version_name()

static void check_valid_version_name ( const char *  versionname)
static

Definition at line 257 of file extension.c.

258 {
259  int namelen = strlen(versionname);
260 
261  /*
262  * Disallow empty names (we could possibly allow this, but there seems
263  * little point).
264  */
265  if (namelen == 0)
266  ereport(ERROR,
267  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
268  errmsg("invalid extension version name: \"%s\"", versionname),
269  errdetail("Version names must not be empty.")));
270 
271  /*
272  * No double dashes, since that would make script filenames ambiguous.
273  */
274  if (strstr(versionname, "--"))
275  ereport(ERROR,
276  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
277  errmsg("invalid extension version name: \"%s\"", versionname),
278  errdetail("Version names must not contain \"--\".")));
279 
280  /*
281  * No leading or trailing dash either.
282  */
283  if (versionname[0] == '-' || versionname[namelen - 1] == '-')
284  ereport(ERROR,
285  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
286  errmsg("invalid extension version name: \"%s\"", versionname),
287  errdetail("Version names must not begin or end with \"-\".")));
288 
289  /*
290  * No directory separators either (this is sufficient to prevent ".."
291  * style attacks).
292  */
293  if (first_dir_separator(versionname) != NULL)
294  ereport(ERROR,
295  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
296  errmsg("invalid extension version name: \"%s\"", versionname),
297  errdetail("Version names must not contain directory separator characters.")));
298 }

References ereport, errcode(), errdetail(), errmsg(), ERROR, and first_dir_separator().

Referenced by CreateExtensionInternal(), and ExecAlterExtensionStmt().

◆ convert_requires_to_datum()

static Datum convert_requires_to_datum ( List requires)
static

Definition at line 2257 of file extension.c.

2258 {
2259  Datum *datums;
2260  int ndatums;
2261  ArrayType *a;
2262  ListCell *lc;
2263 
2264  ndatums = list_length(requires);
2265  datums = (Datum *) palloc(ndatums * sizeof(Datum));
2266  ndatums = 0;
2267  foreach(lc, requires)
2268  {
2269  char *curreq = (char *) lfirst(lc);
2270 
2271  datums[ndatums++] =
2273  }
2274  a = construct_array_builtin(datums, ndatums, NAMEOID);
2275  return PointerGetDatum(a);
2276 }
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
Definition: arrayfuncs.c:3381
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:641
int a
Definition: isn.c:69
void * palloc(Size size)
Definition: mcxt.c:1317
Datum namein(PG_FUNCTION_ARGS)
Definition: name.c:48
static int list_length(const List *l)
Definition: pg_list.h:152
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:350

References a, construct_array_builtin(), CStringGetDatum(), DirectFunctionCall1, lfirst, list_length(), namein(), palloc(), and PointerGetDatum().

Referenced by get_available_versions_for_extension().

◆ CreateExtension()

ObjectAddress CreateExtension ( ParseState pstate,
CreateExtensionStmt stmt 
)

Definition at line 1712 of file extension.c.

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

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

Referenced by ProcessUtilitySlow().

◆ CreateExtensionInternal()

static ObjectAddress CreateExtensionInternal ( char *  extensionName,
char *  schemaName,
const char *  versionName,
bool  cascade,
List parents,
bool  is_create 
)
static

Definition at line 1402 of file extension.c.

1408 {
1409  char *origSchemaName = schemaName;
1410  Oid schemaOid = InvalidOid;
1411  Oid extowner = GetUserId();
1412  ExtensionControlFile *pcontrol;
1413  ExtensionControlFile *control;
1414  char *filename;
1415  struct stat fst;
1416  List *updateVersions;
1417  List *requiredExtensions;
1418  List *requiredSchemas;
1419  Oid extensionOid;
1420  ObjectAddress address;
1421  ListCell *lc;
1422 
1423  /*
1424  * Read the primary control file. Note we assume that it does not contain
1425  * any non-ASCII data, so there is no need to worry about encoding at this
1426  * point.
1427  */
1428  pcontrol = read_extension_control_file(extensionName);
1429 
1430  /*
1431  * Determine the version to install
1432  */
1433  if (versionName == NULL)
1434  {
1435  if (pcontrol->default_version)
1436  versionName = pcontrol->default_version;
1437  else
1438  ereport(ERROR,
1439  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1440  errmsg("version to install must be specified")));
1441  }
1442  check_valid_version_name(versionName);
1443 
1444  /*
1445  * Figure out which script(s) we need to run to install the desired
1446  * version of the extension. If we do not have a script that directly
1447  * does what is needed, we try to find a sequence of update scripts that
1448  * will get us there.
1449  */
1450  filename = get_extension_script_filename(pcontrol, NULL, versionName);
1451  if (stat(filename, &fst) == 0)
1452  {
1453  /* Easy, no extra scripts */
1454  updateVersions = NIL;
1455  }
1456  else
1457  {
1458  /* Look for best way to install this version */
1459  List *evi_list;
1460  ExtensionVersionInfo *evi_start;
1461  ExtensionVersionInfo *evi_target;
1462 
1463  /* Extract the version update graph from the script directory */
1464  evi_list = get_ext_ver_list(pcontrol);
1465 
1466  /* Identify the target version */
1467  evi_target = get_ext_ver_info(versionName, &evi_list);
1468 
1469  /* Identify best path to reach target */
1470  evi_start = find_install_path(evi_list, evi_target,
1471  &updateVersions);
1472 
1473  /* Fail if no path ... */
1474  if (evi_start == NULL)
1475  ereport(ERROR,
1476  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1477  errmsg("extension \"%s\" has no installation script nor update path for version \"%s\"",
1478  pcontrol->name, versionName)));
1479 
1480  /* Otherwise, install best starting point and then upgrade */
1481  versionName = evi_start->name;
1482  }
1483 
1484  /*
1485  * Fetch control parameters for installation target version
1486  */
1487  control = read_extension_aux_control_file(pcontrol, versionName);
1488 
1489  /*
1490  * Determine the target schema to install the extension into
1491  */
1492  if (schemaName)
1493  {
1494  /* If the user is giving us the schema name, it must exist already. */
1495  schemaOid = get_namespace_oid(schemaName, false);
1496  }
1497 
1498  if (control->schema != NULL)
1499  {
1500  /*
1501  * The extension is not relocatable and the author gave us a schema
1502  * for it.
1503  *
1504  * Unless CASCADE parameter was given, it's an error to give a schema
1505  * different from control->schema if control->schema is specified.
1506  */
1507  if (schemaName && strcmp(control->schema, schemaName) != 0 &&
1508  !cascade)
1509  ereport(ERROR,
1510  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1511  errmsg("extension \"%s\" must be installed in schema \"%s\"",
1512  control->name,
1513  control->schema)));
1514 
1515  /* Always use the schema from control file for current extension. */
1516  schemaName = control->schema;
1517 
1518  /* Find or create the schema in case it does not exist. */
1519  schemaOid = get_namespace_oid(schemaName, true);
1520 
1521  if (!OidIsValid(schemaOid))
1522  {
1524 
1525  csstmt->schemaname = schemaName;
1526  csstmt->authrole = NULL; /* will be created by current user */
1527  csstmt->schemaElts = NIL;
1528  csstmt->if_not_exists = false;
1529  CreateSchemaCommand(csstmt, "(generated CREATE SCHEMA command)",
1530  -1, -1);
1531 
1532  /*
1533  * CreateSchemaCommand includes CommandCounterIncrement, so new
1534  * schema is now visible.
1535  */
1536  schemaOid = get_namespace_oid(schemaName, false);
1537  }
1538  }
1539  else if (!OidIsValid(schemaOid))
1540  {
1541  /*
1542  * Neither user nor author of the extension specified schema; use the
1543  * current default creation namespace, which is the first explicit
1544  * entry in the search_path.
1545  */
1546  List *search_path = fetch_search_path(false);
1547 
1548  if (search_path == NIL) /* nothing valid in search_path? */
1549  ereport(ERROR,
1550  (errcode(ERRCODE_UNDEFINED_SCHEMA),
1551  errmsg("no schema has been selected to create in")));
1552  schemaOid = linitial_oid(search_path);
1553  schemaName = get_namespace_name(schemaOid);
1554  if (schemaName == NULL) /* recently-deleted namespace? */
1555  ereport(ERROR,
1556  (errcode(ERRCODE_UNDEFINED_SCHEMA),
1557  errmsg("no schema has been selected to create in")));
1558 
1559  list_free(search_path);
1560  }
1561 
1562  /*
1563  * Make note if a temporary namespace has been accessed in this
1564  * transaction.
1565  */
1566  if (isTempNamespace(schemaOid))
1568 
1569  /*
1570  * We don't check creation rights on the target namespace here. If the
1571  * extension script actually creates any objects there, it will fail if
1572  * the user doesn't have such permissions. But there are cases such as
1573  * procedural languages where it's convenient to set schema = pg_catalog
1574  * yet we don't want to restrict the command to users with ACL_CREATE for
1575  * pg_catalog.
1576  */
1577 
1578  /*
1579  * Look up the prerequisite extensions, install them if necessary, and
1580  * build lists of their OIDs and the OIDs of their target schemas.
1581  */
1582  requiredExtensions = NIL;
1583  requiredSchemas = NIL;
1584  foreach(lc, control->requires)
1585  {
1586  char *curreq = (char *) lfirst(lc);
1587  Oid reqext;
1588  Oid reqschema;
1589 
1590  reqext = get_required_extension(curreq,
1591  extensionName,
1592  origSchemaName,
1593  cascade,
1594  parents,
1595  is_create);
1596  reqschema = get_extension_schema(reqext);
1597  requiredExtensions = lappend_oid(requiredExtensions, reqext);
1598  requiredSchemas = lappend_oid(requiredSchemas, reqschema);
1599  }
1600 
1601  /*
1602  * Insert new tuple into pg_extension, and create dependency entries.
1603  */
1604  address = InsertExtensionTuple(control->name, extowner,
1605  schemaOid, control->relocatable,
1606  versionName,
1607  PointerGetDatum(NULL),
1608  PointerGetDatum(NULL),
1609  requiredExtensions);
1610  extensionOid = address.objectId;
1611 
1612  /*
1613  * Apply any control-file comment on extension
1614  */
1615  if (control->comment != NULL)
1616  CreateComments(extensionOid, ExtensionRelationId, 0, control->comment);
1617 
1618  /*
1619  * Execute the installation script file
1620  */
1621  execute_extension_script(extensionOid, control,
1622  NULL, versionName,
1623  requiredSchemas,
1624  schemaName, schemaOid);
1625 
1626  /*
1627  * If additional update scripts have to be executed, apply the updates as
1628  * though a series of ALTER EXTENSION UPDATE commands were given
1629  */
1630  ApplyExtensionUpdates(extensionOid, pcontrol,
1631  versionName, updateVersions,
1632  origSchemaName, cascade, is_create);
1633 
1634  return address;
1635 }
#define OidIsValid(objectId)
Definition: c.h:778
void CreateComments(Oid oid, Oid classoid, int32 subid, const char *comment)
Definition: comment.c:143
static ExtensionVersionInfo * get_ext_ver_info(const char *versionname, List **evi_list)
Definition: extension.c:1087
ObjectAddress InsertExtensionTuple(const char *extName, Oid extOwner, Oid schemaOid, bool relocatable, const char *extVersion, Datum extConfig, Datum extCondition, List *requiredExtensions)
Definition: extension.c:1810
static void check_valid_version_name(const char *versionname)
Definition: extension.c:257
static char * get_extension_script_filename(ExtensionControlFile *control, const char *from_version, const char *version)
Definition: extension.c:388
static List * get_ext_ver_list(ExtensionControlFile *control)
Definition: extension.c:1148
static ExtensionVersionInfo * find_install_path(List *evi_list, ExtensionVersionInfo *evi_target, List **best_path)
Definition: extension.c:1347
static void ApplyExtensionUpdates(Oid extensionOid, ExtensionControlFile *pcontrol, const char *initialVersion, List *updateVersions, char *origSchemaName, bool cascade, bool is_create)
Definition: extension.c:3078
void list_free(List *list)
Definition: list.c:1546
bool isTempNamespace(Oid namespaceId)
Definition: namespace.c:3634
List * fetch_search_path(bool includeImplicit)
Definition: namespace.c:4809
Oid get_namespace_oid(const char *nspname, bool missing_ok)
Definition: namespace.c:3520
#define makeNode(_type_)
Definition: nodes.h:155
static char * filename
Definition: pg_dumpall.c:119
#define linitial_oid(l)
Definition: pg_list.h:180
Oid CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString, int stmt_location, int stmt_len)
Definition: schemacmds.c:52
RoleSpec * authrole
Definition: parsenodes.h:2323
char * default_version
Definition: extension.c:82
#define stat
Definition: win32_port.h:284
int MyXactFlags
Definition: xact.c:135
#define XACT_FLAGS_ACCESSEDTEMPNAMESPACE
Definition: xact.h:102

References ApplyExtensionUpdates(), CreateSchemaStmt::authrole, check_valid_version_name(), ExtensionControlFile::comment, CreateComments(), CreateSchemaCommand(), ExtensionControlFile::default_version, ereport, errcode(), errmsg(), ERROR, execute_extension_script(), fetch_search_path(), filename, find_install_path(), get_ext_ver_info(), get_ext_ver_list(), get_extension_schema(), get_extension_script_filename(), get_namespace_name(), get_namespace_oid(), get_required_extension(), GetUserId(), CreateSchemaStmt::if_not_exists, InsertExtensionTuple(), InvalidOid, isTempNamespace(), lappend_oid(), lfirst, linitial_oid, list_free(), makeNode, MyXactFlags, ExtensionControlFile::name, ExtensionVersionInfo::name, NIL, ObjectAddress::objectId, OidIsValid, PointerGetDatum(), read_extension_aux_control_file(), read_extension_control_file(), ExtensionControlFile::relocatable, ExtensionControlFile::requires, ExtensionControlFile::schema, CreateSchemaStmt::schemaElts, CreateSchemaStmt::schemaname, stat, and XACT_FLAGS_ACCESSEDTEMPNAMESPACE.

Referenced by CreateExtension(), and get_required_extension().

◆ ExecAlterExtensionContentsRecurse()

static void ExecAlterExtensionContentsRecurse ( AlterExtensionContentsStmt stmt,
ObjectAddress  extension,
ObjectAddress  object 
)
static

Definition at line 3322 of file extension.c.

3325 {
3326  Oid oldExtension;
3327 
3328  /*
3329  * Check existing extension membership.
3330  */
3331  oldExtension = getExtensionOfObject(object.classId, object.objectId);
3332 
3333  if (stmt->action > 0)
3334  {
3335  /*
3336  * ADD, so complain if object is already attached to some extension.
3337  */
3338  if (OidIsValid(oldExtension))
3339  ereport(ERROR,
3340  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3341  errmsg("%s is already a member of extension \"%s\"",
3342  getObjectDescription(&object, false),
3343  get_extension_name(oldExtension))));
3344 
3345  /*
3346  * Prevent a schema from being added to an extension if the schema
3347  * contains the extension. That would create a dependency loop.
3348  */
3349  if (object.classId == NamespaceRelationId &&
3350  object.objectId == get_extension_schema(extension.objectId))
3351  ereport(ERROR,
3352  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3353  errmsg("cannot add schema \"%s\" to extension \"%s\" "
3354  "because the schema contains the extension",
3355  get_namespace_name(object.objectId),
3356  stmt->extname)));
3357 
3358  /*
3359  * OK, add the dependency.
3360  */
3361  recordDependencyOn(&object, &extension, DEPENDENCY_EXTENSION);
3362 
3363  /*
3364  * Also record the initial ACL on the object, if any.
3365  *
3366  * Note that this will handle the object's ACLs, as well as any ACLs
3367  * on object subIds. (In other words, when the object is a table,
3368  * this will record the table's ACL and the ACLs for the columns on
3369  * the table, if any).
3370  */
3371  recordExtObjInitPriv(object.objectId, object.classId);
3372  }
3373  else
3374  {
3375  /*
3376  * DROP, so complain if it's not a member.
3377  */
3378  if (oldExtension != extension.objectId)
3379  ereport(ERROR,
3380  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3381  errmsg("%s is not a member of extension \"%s\"",
3382  getObjectDescription(&object, false),
3383  stmt->extname)));
3384 
3385  /*
3386  * OK, drop the dependency.
3387  */
3388  if (deleteDependencyRecordsForClass(object.classId, object.objectId,
3389  ExtensionRelationId,
3390  DEPENDENCY_EXTENSION) != 1)
3391  elog(ERROR, "unexpected number of extension dependency records");
3392 
3393  /*
3394  * If it's a relation, it might have an entry in the extension's
3395  * extconfig array, which we must remove.
3396  */
3397  if (object.classId == RelationRelationId)
3398  extension_config_remove(extension.objectId, object.objectId);
3399 
3400  /*
3401  * Remove all the initial ACLs, if any.
3402  *
3403  * Note that this will remove the object's ACLs, as well as any ACLs
3404  * on object subIds. (In other words, when the object is a table,
3405  * this will remove the table's ACL and the ACLs for the columns on
3406  * the table, if any).
3407  */
3408  removeExtObjInitPriv(object.objectId, object.classId);
3409  }
3410 
3411  /*
3412  * Recurse to any dependent objects; currently, this includes the array
3413  * type of a base type, the multirange type associated with a range type,
3414  * and the rowtype of a table.
3415  */
3416  if (object.classId == TypeRelationId)
3417  {
3418  ObjectAddress depobject;
3419 
3420  depobject.classId = TypeRelationId;
3421  depobject.objectSubId = 0;
3422 
3423  /* If it has an array type, update that too */
3424  depobject.objectId = get_array_type(object.objectId);
3425  if (OidIsValid(depobject.objectId))
3426  ExecAlterExtensionContentsRecurse(stmt, extension, depobject);
3427 
3428  /* If it is a range type, update the associated multirange too */
3429  if (type_is_range(object.objectId))
3430  {
3431  depobject.objectId = get_range_multirange(object.objectId);
3432  if (!OidIsValid(depobject.objectId))
3433  ereport(ERROR,
3434  (errcode(ERRCODE_UNDEFINED_OBJECT),
3435  errmsg("could not find multirange type for data type %s",
3436  format_type_be(object.objectId))));
3437  ExecAlterExtensionContentsRecurse(stmt, extension, depobject);
3438  }
3439  }
3440  if (object.classId == RelationRelationId)
3441  {
3442  ObjectAddress depobject;
3443 
3444  depobject.classId = TypeRelationId;
3445  depobject.objectSubId = 0;
3446 
3447  /* It might not have a rowtype, but if it does, update that */
3448  depobject.objectId = get_rel_type_id(object.objectId);
3449  if (OidIsValid(depobject.objectId))
3450  ExecAlterExtensionContentsRecurse(stmt, extension, depobject);
3451  }
3452 }
void recordExtObjInitPriv(Oid objoid, Oid classoid)
Definition: aclchk.c:4407
void removeExtObjInitPriv(Oid objoid, Oid classoid)
Definition: aclchk.c:4571
static void extension_config_remove(Oid extensionoid, Oid tableoid)
Definition: extension.c:2551
static void ExecAlterExtensionContentsRecurse(AlterExtensionContentsStmt *stmt, ObjectAddress extension, ObjectAddress object)
Definition: extension.c:3322
char * format_type_be(Oid type_oid)
Definition: format_type.c:343
bool type_is_range(Oid typid)
Definition: lsyscache.c:2688
Oid get_rel_type_id(Oid relid)
Definition: lsyscache.c:1979
Oid get_range_multirange(Oid rangeOid)
Definition: lsyscache.c:3458
Oid get_array_type(Oid typid)
Definition: lsyscache.c:2787

References ObjectAddress::classId, deleteDependencyRecordsForClass(), DEPENDENCY_EXTENSION, elog, ereport, errcode(), errmsg(), ERROR, extension_config_remove(), format_type_be(), get_array_type(), get_extension_name(), get_extension_schema(), get_namespace_name(), get_range_multirange(), get_rel_type_id(), getExtensionOfObject(), getObjectDescription(), ObjectAddress::objectId, ObjectAddress::objectSubId, OidIsValid, recordDependencyOn(), recordExtObjInitPriv(), removeExtObjInitPriv(), stmt, and type_is_range().

Referenced by ExecAlterExtensionContentsStmt().

◆ ExecAlterExtensionContentsStmt()

ObjectAddress ExecAlterExtensionContentsStmt ( AlterExtensionContentsStmt stmt,
ObjectAddress objAddr 
)

Definition at line 3236 of file extension.c.

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

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

Referenced by ProcessUtilitySlow().

◆ ExecAlterExtensionStmt()

ObjectAddress ExecAlterExtensionStmt ( ParseState pstate,
AlterExtensionStmt stmt 
)

Definition at line 2931 of file extension.c.

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

◆ execute_extension_script()

static void execute_extension_script ( Oid  extensionOid,
ExtensionControlFile control,
const char *  from_version,
const char *  version,
List requiredSchemas,
const char *  schemaName,
Oid  schemaOid 
)
static

Definition at line 814 of file extension.c.

819 {
820  bool switch_to_superuser = false;
821  char *filename;
822  Oid save_userid = 0;
823  int save_sec_context = 0;
824  int save_nestlevel;
825  StringInfoData pathbuf;
826  ListCell *lc;
827  ListCell *lc2;
828 
829  /*
830  * Enforce superuser-ness if appropriate. We postpone these checks until
831  * here so that the control flags are correctly associated with the right
832  * script(s) if they happen to be set in secondary control files.
833  */
834  if (control->superuser && !superuser())
835  {
836  if (extension_is_trusted(control))
837  switch_to_superuser = true;
838  else if (from_version == NULL)
839  ereport(ERROR,
840  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
841  errmsg("permission denied to create extension \"%s\"",
842  control->name),
843  control->trusted
844  ? errhint("Must have CREATE privilege on current database to create this extension.")
845  : errhint("Must be superuser to create this extension.")));
846  else
847  ereport(ERROR,
848  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
849  errmsg("permission denied to update extension \"%s\"",
850  control->name),
851  control->trusted
852  ? errhint("Must have CREATE privilege on current database to update this extension.")
853  : errhint("Must be superuser to update this extension.")));
854  }
855 
856  filename = get_extension_script_filename(control, from_version, version);
857 
858  if (from_version == NULL)
859  elog(DEBUG1, "executing extension script for \"%s\" version '%s'", control->name, version);
860  else
861  elog(DEBUG1, "executing extension script for \"%s\" update from version '%s' to '%s'", control->name, from_version, version);
862 
863  /*
864  * If installing a trusted extension on behalf of a non-superuser, become
865  * the bootstrap superuser. (This switch will be cleaned up automatically
866  * if the transaction aborts, as will the GUC changes below.)
867  */
868  if (switch_to_superuser)
869  {
870  GetUserIdAndSecContext(&save_userid, &save_sec_context);
871  SetUserIdAndSecContext(BOOTSTRAP_SUPERUSERID,
872  save_sec_context | SECURITY_LOCAL_USERID_CHANGE);
873  }
874 
875  /*
876  * Force client_min_messages and log_min_messages to be at least WARNING,
877  * so that we won't spam the user with useless NOTICE messages from common
878  * script actions like creating shell types.
879  *
880  * We use the equivalent of a function SET option to allow the setting to
881  * persist for exactly the duration of the script execution. guc.c also
882  * takes care of undoing the setting on error.
883  *
884  * log_min_messages can't be set by ordinary users, so for that one we
885  * pretend to be superuser.
886  */
887  save_nestlevel = NewGUCNestLevel();
888 
890  (void) set_config_option("client_min_messages", "warning",
892  GUC_ACTION_SAVE, true, 0, false);
894  (void) set_config_option_ext("log_min_messages", "warning",
896  BOOTSTRAP_SUPERUSERID,
897  GUC_ACTION_SAVE, true, 0, false);
898 
899  /*
900  * Similarly disable check_function_bodies, to ensure that SQL functions
901  * won't be parsed during creation.
902  */
904  (void) set_config_option("check_function_bodies", "off",
906  GUC_ACTION_SAVE, true, 0, false);
907 
908  /*
909  * Set up the search path to have the target schema first, making it be
910  * the default creation target namespace. Then add the schemas of any
911  * prerequisite extensions, unless they are in pg_catalog which would be
912  * searched anyway. (Listing pg_catalog explicitly in a non-first
913  * position would be bad for security.) Finally add pg_temp to ensure
914  * that temp objects can't take precedence over others.
915  */
916  initStringInfo(&pathbuf);
917  appendStringInfoString(&pathbuf, quote_identifier(schemaName));
918  foreach(lc, requiredSchemas)
919  {
920  Oid reqschema = lfirst_oid(lc);
921  char *reqname = get_namespace_name(reqschema);
922 
923  if (reqname && strcmp(reqname, "pg_catalog") != 0)
924  appendStringInfo(&pathbuf, ", %s", quote_identifier(reqname));
925  }
926  appendStringInfoString(&pathbuf, ", pg_temp");
927 
928  (void) set_config_option("search_path", pathbuf.data,
930  GUC_ACTION_SAVE, true, 0, false);
931 
932  /*
933  * Set creating_extension and related variables so that
934  * recordDependencyOnCurrentExtension and other functions do the right
935  * things. On failure, ensure we reset these variables.
936  */
937  creating_extension = true;
938  CurrentExtensionObject = extensionOid;
939  PG_TRY();
940  {
941  char *c_sql = read_extension_script_file(control, filename);
942  Datum t_sql;
943 
944  /*
945  * We filter each substitution through quote_identifier(). When the
946  * arg contains one of the following characters, no one collection of
947  * quoting can work inside $$dollar-quoted string literals$$,
948  * 'single-quoted string literals', and outside of any literal. To
949  * avoid a security snare for extension authors, error on substitution
950  * for arguments containing these.
951  */
952  const char *quoting_relevant_chars = "\"$'\\";
953 
954  /* We use various functions that want to operate on text datums */
955  t_sql = CStringGetTextDatum(c_sql);
956 
957  /*
958  * Reduce any lines beginning with "\echo" to empty. This allows
959  * scripts to contain messages telling people not to run them via
960  * psql, which has been found to be necessary due to old habits.
961  */
963  C_COLLATION_OID,
964  t_sql,
965  CStringGetTextDatum("^\\\\echo.*$"),
967  CStringGetTextDatum("ng"));
968 
969  /*
970  * If the script uses @extowner@, substitute the calling username.
971  */
972  if (strstr(c_sql, "@extowner@"))
973  {
974  Oid uid = switch_to_superuser ? save_userid : GetUserId();
975  const char *userName = GetUserNameFromId(uid, false);
976  const char *qUserName = quote_identifier(userName);
977 
979  C_COLLATION_OID,
980  t_sql,
981  CStringGetTextDatum("@extowner@"),
982  CStringGetTextDatum(qUserName));
983  if (strpbrk(userName, quoting_relevant_chars))
984  ereport(ERROR,
985  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
986  errmsg("invalid character in extension owner: must not contain any of \"%s\"",
987  quoting_relevant_chars)));
988  }
989 
990  /*
991  * If it's not relocatable, substitute the target schema name for
992  * occurrences of @extschema@.
993  *
994  * For a relocatable extension, we needn't do this. There cannot be
995  * any need for @extschema@, else it wouldn't be relocatable.
996  */
997  if (!control->relocatable)
998  {
999  Datum old = t_sql;
1000  const char *qSchemaName = quote_identifier(schemaName);
1001 
1003  C_COLLATION_OID,
1004  t_sql,
1005  CStringGetTextDatum("@extschema@"),
1006  CStringGetTextDatum(qSchemaName));
1007  if (t_sql != old && strpbrk(schemaName, quoting_relevant_chars))
1008  ereport(ERROR,
1009  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1010  errmsg("invalid character in extension \"%s\" schema: must not contain any of \"%s\"",
1011  control->name, quoting_relevant_chars)));
1012  }
1013 
1014  /*
1015  * Likewise, substitute required extensions' schema names for
1016  * occurrences of @extschema:extension_name@.
1017  */
1018  Assert(list_length(control->requires) == list_length(requiredSchemas));
1019  forboth(lc, control->requires, lc2, requiredSchemas)
1020  {
1021  Datum old = t_sql;
1022  char *reqextname = (char *) lfirst(lc);
1023  Oid reqschema = lfirst_oid(lc2);
1024  char *schemaName = get_namespace_name(reqschema);
1025  const char *qSchemaName = quote_identifier(schemaName);
1026  char *repltoken;
1027 
1028  repltoken = psprintf("@extschema:%s@", reqextname);
1030  C_COLLATION_OID,
1031  t_sql,
1032  CStringGetTextDatum(repltoken),
1033  CStringGetTextDatum(qSchemaName));
1034  if (t_sql != old && strpbrk(schemaName, quoting_relevant_chars))
1035  ereport(ERROR,
1036  (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1037  errmsg("invalid character in extension \"%s\" schema: must not contain any of \"%s\"",
1038  reqextname, quoting_relevant_chars)));
1039  }
1040 
1041  /*
1042  * If module_pathname was set in the control file, substitute its
1043  * value for occurrences of MODULE_PATHNAME.
1044  */
1045  if (control->module_pathname)
1046  {
1048  C_COLLATION_OID,
1049  t_sql,
1050  CStringGetTextDatum("MODULE_PATHNAME"),
1052  }
1053 
1054  /* And now back to C string */
1055  c_sql = text_to_cstring(DatumGetTextPP(t_sql));
1056 
1057  execute_sql_string(c_sql);
1058  }
1059  PG_FINALLY();
1060  {
1061  creating_extension = false;
1063  }
1064  PG_END_TRY();
1065 
1066  /*
1067  * Restore the GUC variables we set above.
1068  */
1069  AtEOXact_GUC(true, save_nestlevel);
1070 
1071  /*
1072  * Restore authentication state if needed.
1073  */
1074  if (switch_to_superuser)
1075  SetUserIdAndSecContext(save_userid, save_sec_context);
1076 }
int errhint(const char *fmt,...)
Definition: elog.c:1317
#define PG_TRY(...)
Definition: elog.h:371
#define WARNING
Definition: elog.h:36
#define PG_END_TRY(...)
Definition: elog.h:396
#define DEBUG1
Definition: elog.h:30
#define PG_FINALLY(...)
Definition: elog.h:388
static char * read_extension_script_file(const ExtensionControlFile *control, const char *filename)
Definition: extension.c:644
static void execute_sql_string(const char *sql)
Definition: extension.c:685
Oid CurrentExtensionObject
Definition: extension.c:73
static bool extension_is_trusted(ExtensionControlFile *control)
Definition: extension.c:792
Datum DirectFunctionCall4Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4)
Definition: fmgr.c:859
Datum DirectFunctionCall3Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2, Datum arg3)
Definition: fmgr.c:834
int set_config_option_ext(const char *name, const char *value, GucContext context, GucSource source, Oid srole, GucAction action, bool changeVal, int elevel, bool is_reload)
Definition: guc.c:3382
int NewGUCNestLevel(void)
Definition: guc.c:2234
void AtEOXact_GUC(bool isCommit, int nestLevel)
Definition: guc.c:2261
int set_config_option(const char *name, const char *value, GucContext context, GucSource source, GucAction action, bool changeVal, int elevel, bool is_reload)
Definition: guc.c:3342
@ GUC_ACTION_SAVE
Definition: guc.h:201
@ PGC_S_SESSION
Definition: guc.h:122
@ PGC_SUSET
Definition: guc.h:74
@ PGC_USERSET
Definition: guc.h:75
bool check_function_bodies
Definition: guc_tables.c:511
int client_min_messages
Definition: guc_tables.c:523
int log_min_messages
Definition: guc_tables.c:522
#define SECURITY_LOCAL_USERID_CHANGE
Definition: miscadmin.h:311
char * GetUserNameFromId(Oid roleid, bool noerr)
Definition: miscinit.c:980
void GetUserIdAndSecContext(Oid *userid, int *sec_context)
Definition: miscinit.c:635
void SetUserIdAndSecContext(Oid userid, int sec_context)
Definition: miscinit.c:642
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:518
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
Datum textregexreplace(PG_FUNCTION_ARGS)
Definition: regexp.c:658
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:12840
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:97
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:182
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
char * module_pathname
Definition: extension.c:83
bool superuser(void)
Definition: superuser.c:46
Datum replace_text(PG_FUNCTION_ARGS)
Definition: varlena.c:3971

References appendStringInfo(), appendStringInfoString(), Assert, AtEOXact_GUC(), check_function_bodies, client_min_messages, creating_extension, CStringGetTextDatum, CurrentExtensionObject, StringInfoData::data, DatumGetTextPP, DEBUG1, DirectFunctionCall3Coll(), DirectFunctionCall4Coll(), elog, ereport, errcode(), errhint(), errmsg(), ERROR, execute_sql_string(), extension_is_trusted(), filename, forboth, get_extension_script_filename(), get_namespace_name(), GetUserId(), GetUserIdAndSecContext(), GetUserNameFromId(), GUC_ACTION_SAVE, initStringInfo(), InvalidOid, lfirst, lfirst_oid, list_length(), log_min_messages, ExtensionControlFile::module_pathname, ExtensionControlFile::name, NewGUCNestLevel(), PG_END_TRY, PG_FINALLY, PG_TRY, PGC_S_SESSION, PGC_SUSET, PGC_USERSET, psprintf(), quote_identifier(), read_extension_script_file(), ExtensionControlFile::relocatable, replace_text(), ExtensionControlFile::requires, SECURITY_LOCAL_USERID_CHANGE, set_config_option(), set_config_option_ext(), SetUserIdAndSecContext(), ExtensionControlFile::superuser, superuser(), text_to_cstring(), textregexreplace(), ExtensionControlFile::trusted, and WARNING.

Referenced by ApplyExtensionUpdates(), and CreateExtensionInternal().

◆ execute_sql_string()

static void execute_sql_string ( const char *  sql)
static

Definition at line 685 of file extension.c.

686 {
687  List *raw_parsetree_list;
689  ListCell *lc1;
690 
691  /*
692  * Parse the SQL string into a list of raw parse trees.
693  */
694  raw_parsetree_list = pg_parse_query(sql);
695 
696  /* All output from SELECTs goes to the bit bucket */
698 
699  /*
700  * Do parse analysis, rule rewrite, planning, and execution for each raw
701  * parsetree. We must fully execute each query before beginning parse
702  * analysis on the next one, since there may be interdependencies.
703  */
704  foreach(lc1, raw_parsetree_list)
705  {
706  RawStmt *parsetree = lfirst_node(RawStmt, lc1);
707  MemoryContext per_parsetree_context,
708  oldcontext;
709  List *stmt_list;
710  ListCell *lc2;
711 
712  /*
713  * We do the work for each parsetree in a short-lived context, to
714  * limit the memory used when there are many commands in the string.
715  */
716  per_parsetree_context =
718  "execute_sql_string per-statement context",
720  oldcontext = MemoryContextSwitchTo(per_parsetree_context);
721 
722  /* Be sure parser can see any DDL done so far */
724 
725  stmt_list = pg_analyze_and_rewrite_fixedparams(parsetree,
726  sql,
727  NULL,
728  0,
729  NULL);
730  stmt_list = pg_plan_queries(stmt_list, sql, CURSOR_OPT_PARALLEL_OK, NULL);
731 
732  foreach(lc2, stmt_list)
733  {
735 
737 
739 
740  if (stmt->utilityStmt == NULL)
741  {
742  QueryDesc *qdesc;
743 
744  qdesc = CreateQueryDesc(stmt,
745  sql,
746  GetActiveSnapshot(), NULL,
747  dest, NULL, NULL, 0);
748 
749  ExecutorStart(qdesc, 0);
750  ExecutorRun(qdesc, ForwardScanDirection, 0, true);
751  ExecutorFinish(qdesc);
752  ExecutorEnd(qdesc);
753 
754  FreeQueryDesc(qdesc);
755  }
756  else
757  {
758  if (IsA(stmt->utilityStmt, TransactionStmt))
759  ereport(ERROR,
760  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
761  errmsg("transaction control statements are not allowed within an extension script")));
762 
764  sql,
765  false,
767  NULL,
768  NULL,
769  dest,
770  NULL);
771  }
772 
774  }
775 
776  /* Clean up per-parsetree context. */
777  MemoryContextSwitchTo(oldcontext);
778  MemoryContextDelete(per_parsetree_context);
779  }
780 
781  /* Be sure to advance the command counter after the last script command */
783 }
DestReceiver * CreateDestReceiver(CommandDest dest)
Definition: dest.c:113
@ DestNone
Definition: dest.h:87
void ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:465
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:405
void ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:120
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: execMain.c:295
MemoryContext CurrentMemoryContext
Definition: mcxt.c:143
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:454
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
#define IsA(nodeptr, _type_)
Definition: nodes.h:158
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:3308
#define lfirst_node(type, lc)
Definition: pg_list.h:176
List * pg_parse_query(const char *query_string)
Definition: postgres.c:615
List * pg_analyze_and_rewrite_fixedparams(RawStmt *parsetree, const char *query_string, const Oid *paramTypes, int numParams, QueryEnvironment *queryEnv)
Definition: postgres.c:677
List * pg_plan_queries(List *querytrees, const char *query_string, int cursorOptions, ParamListInfo boundParams)
Definition: postgres.c:982
void FreeQueryDesc(QueryDesc *qdesc)
Definition: pquery.c:105
QueryDesc * CreateQueryDesc(PlannedStmt *plannedstmt, const char *sourceText, Snapshot snapshot, Snapshot crosscheck_snapshot, DestReceiver *dest, ParamListInfo params, QueryEnvironment *queryEnv, int instrument_options)
Definition: pquery.c:67
MemoryContextSwitchTo(old_ctx)
@ ForwardScanDirection
Definition: sdir.h:28
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:216
void PushActiveSnapshot(Snapshot snapshot)
Definition: snapmgr.c:648
void PopActiveSnapshot(void)
Definition: snapmgr.c:743
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:770
void ProcessUtility(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc)
Definition: utility.c:499
@ PROCESS_UTILITY_QUERY
Definition: utility.h:23
void CommandCounterIncrement(void)
Definition: xact.c:1099

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, CommandCounterIncrement(), CreateDestReceiver(), CreateQueryDesc(), CurrentMemoryContext, CURSOR_OPT_PARALLEL_OK, generate_unaccent_rules::dest, DestNone, ereport, errcode(), errmsg(), ERROR, ExecutorEnd(), ExecutorFinish(), ExecutorRun(), ExecutorStart(), ForwardScanDirection, FreeQueryDesc(), GetActiveSnapshot(), GetTransactionSnapshot(), IsA, lfirst_node, MemoryContextDelete(), MemoryContextSwitchTo(), pg_analyze_and_rewrite_fixedparams(), pg_parse_query(), pg_plan_queries(), PopActiveSnapshot(), PROCESS_UTILITY_QUERY, ProcessUtility(), PushActiveSnapshot(), and stmt.

Referenced by execute_extension_script().

◆ extension_config_remove()

static void extension_config_remove ( Oid  extensionoid,
Oid  tableoid 
)
static

Definition at line 2551 of file extension.c.

2552 {
2553  Relation extRel;
2554  ScanKeyData key[1];
2555  SysScanDesc extScan;
2556  HeapTuple extTup;
2557  Datum arrayDatum;
2558  int arrayLength;
2559  int arrayIndex;
2560  bool isnull;
2561  Datum repl_val[Natts_pg_extension];
2562  bool repl_null[Natts_pg_extension];
2563  bool repl_repl[Natts_pg_extension];
2564  ArrayType *a;
2565 
2566  /* Find the pg_extension tuple */
2567  extRel = table_open(ExtensionRelationId, RowExclusiveLock);
2568 
2569  ScanKeyInit(&key[0],
2570  Anum_pg_extension_oid,
2571  BTEqualStrategyNumber, F_OIDEQ,
2572  ObjectIdGetDatum(extensionoid));
2573 
2574  extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
2575  NULL, 1, key);
2576 
2577  extTup = systable_getnext(extScan);
2578 
2579  if (!HeapTupleIsValid(extTup)) /* should not happen */
2580  elog(ERROR, "could not find tuple for extension %u",
2581  extensionoid);
2582 
2583  /* Search extconfig for the tableoid */
2584  arrayDatum = heap_getattr(extTup, Anum_pg_extension_extconfig,
2585  RelationGetDescr(extRel), &isnull);
2586  if (isnull)
2587  {
2588  /* nothing to do */
2589  a = NULL;
2590  arrayLength = 0;
2591  arrayIndex = -1;
2592  }
2593  else
2594  {
2595  Oid *arrayData;
2596  int i;
2597 
2598  a = DatumGetArrayTypeP(arrayDatum);
2599 
2600  arrayLength = ARR_DIMS(a)[0];
2601  if (ARR_NDIM(a) != 1 ||
2602  ARR_LBOUND(a)[0] != 1 ||
2603  arrayLength < 0 ||
2604  ARR_HASNULL(a) ||
2605  ARR_ELEMTYPE(a) != OIDOID)
2606  elog(ERROR, "extconfig is not a 1-D Oid array");
2607  arrayData = (Oid *) ARR_DATA_PTR(a);
2608 
2609  arrayIndex = -1; /* flag for no deletion needed */
2610 
2611  for (i = 0; i < arrayLength; i++)
2612  {
2613  if (arrayData[i] == tableoid)
2614  {
2615  arrayIndex = i; /* index to remove */
2616  break;
2617  }
2618  }
2619  }
2620 
2621  /* If tableoid is not in extconfig, nothing to do */
2622  if (arrayIndex < 0)
2623  {
2624  systable_endscan(extScan);
2625  table_close(extRel, RowExclusiveLock);
2626  return;
2627  }
2628 
2629  /* Modify or delete the extconfig value */
2630  memset(repl_val, 0, sizeof(repl_val));
2631  memset(repl_null, false, sizeof(repl_null));
2632  memset(repl_repl, false, sizeof(repl_repl));
2633 
2634  if (arrayLength <= 1)
2635  {
2636  /* removing only element, just set array to null */
2637  repl_null[Anum_pg_extension_extconfig - 1] = true;
2638  }
2639  else
2640  {
2641  /* squeeze out the target element */
2642  Datum *dvalues;
2643  int nelems;
2644  int i;
2645 
2646  /* We already checked there are no nulls */
2647  deconstruct_array_builtin(a, OIDOID, &dvalues, NULL, &nelems);
2648 
2649  for (i = arrayIndex; i < arrayLength - 1; i++)
2650  dvalues[i] = dvalues[i + 1];
2651 
2652  a = construct_array_builtin(dvalues, arrayLength - 1, OIDOID);
2653 
2654  repl_val[Anum_pg_extension_extconfig - 1] = PointerGetDatum(a);
2655  }
2656  repl_repl[Anum_pg_extension_extconfig - 1] = true;
2657 
2658  /* Modify or delete the extcondition value */
2659  arrayDatum = heap_getattr(extTup, Anum_pg_extension_extcondition,
2660  RelationGetDescr(extRel), &isnull);
2661  if (isnull)
2662  {
2663  elog(ERROR, "extconfig and extcondition arrays do not match");
2664  }
2665  else
2666  {
2667  a = DatumGetArrayTypeP(arrayDatum);
2668 
2669  if (ARR_NDIM(a) != 1 ||
2670  ARR_LBOUND(a)[0] != 1 ||
2671  ARR_HASNULL(a) ||
2672  ARR_ELEMTYPE(a) != TEXTOID)
2673  elog(ERROR, "extcondition is not a 1-D text array");
2674  if (ARR_DIMS(a)[0] != arrayLength)
2675  elog(ERROR, "extconfig and extcondition arrays do not match");
2676  }
2677 
2678  if (arrayLength <= 1)
2679  {
2680  /* removing only element, just set array to null */
2681  repl_null[Anum_pg_extension_extcondition - 1] = true;
2682  }
2683  else
2684  {
2685  /* squeeze out the target element */
2686  Datum *dvalues;
2687  int nelems;
2688  int i;
2689 
2690  /* We already checked there are no nulls */
2691  deconstruct_array_builtin(a, TEXTOID, &dvalues, NULL, &nelems);
2692 
2693  for (i = arrayIndex; i < arrayLength - 1; i++)
2694  dvalues[i] = dvalues[i + 1];
2695 
2696  a = construct_array_builtin(dvalues, arrayLength - 1, TEXTOID);
2697 
2698  repl_val[Anum_pg_extension_extcondition - 1] = PointerGetDatum(a);
2699  }
2700  repl_repl[Anum_pg_extension_extcondition - 1] = true;
2701 
2702  extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
2703  repl_val, repl_null, repl_repl);
2704 
2705  CatalogTupleUpdate(extRel, &extTup->t_self, extTup);
2706 
2707  systable_endscan(extScan);
2708 
2709  table_close(extRel, RowExclusiveLock);
2710 }
#define ARR_NDIM(a)
Definition: array.h:290
#define ARR_DATA_PTR(a)
Definition: array.h:322
#define DatumGetArrayTypeP(X)
Definition: array.h:261
#define ARR_ELEMTYPE(a)
Definition: array.h:292
#define ARR_DIMS(a)
Definition: array.h:294
#define ARR_HASNULL(a)
Definition: array.h:291
#define ARR_LBOUND(a)
Definition: array.h:296
void deconstruct_array_builtin(ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3685
int i
Definition: isn.c:73

References a, ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_HASNULL, ARR_LBOUND, ARR_NDIM, BTEqualStrategyNumber, CatalogTupleUpdate(), construct_array_builtin(), DatumGetArrayTypeP, deconstruct_array_builtin(), elog, ERROR, heap_getattr(), heap_modify_tuple(), HeapTupleIsValid, i, sort-test::key, ObjectIdGetDatum(), PointerGetDatum(), RelationGetDescr, RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by ExecAlterExtensionContentsRecurse().

◆ extension_file_exists()

bool extension_file_exists ( const char *  extensionName)

Definition at line 2204 of file extension.c.

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

References AllocateDir(), dirent::d_name, FreeDir(), get_extension_control_directory(), is_extension_control_filename(), pstrdup(), and ReadDir().

Referenced by CreateFunction(), and ExecuteDoStmt().

◆ extension_is_trusted()

static bool extension_is_trusted ( ExtensionControlFile control)
static

Definition at line 792 of file extension.c.

793 {
794  AclResult aclresult;
795 
796  /* Never trust unless extension's control file says it's okay */
797  if (!control->trusted)
798  return false;
799  /* Allow if user has CREATE privilege on current database */
800  aclresult = object_aclcheck(DatabaseRelationId, MyDatabaseId, GetUserId(), ACL_CREATE);
801  if (aclresult == ACLCHECK_OK)
802  return true;
803  return false;
804 }
Oid MyDatabaseId
Definition: globals.c:93

References ACL_CREATE, ACLCHECK_OK, GetUserId(), MyDatabaseId, object_aclcheck(), and ExtensionControlFile::trusted.

Referenced by execute_extension_script().

◆ find_install_path()

static ExtensionVersionInfo* find_install_path ( List evi_list,
ExtensionVersionInfo evi_target,
List **  best_path 
)
static

Definition at line 1347 of file extension.c.

1349 {
1350  ExtensionVersionInfo *evi_start = NULL;
1351  ListCell *lc;
1352 
1353  *best_path = NIL;
1354 
1355  /*
1356  * We don't expect to be called for an installable target, but if we are,
1357  * the answer is easy: just start from there, with an empty update path.
1358  */
1359  if (evi_target->installable)
1360  return evi_target;
1361 
1362  /* Consider all installable versions as start points */
1363  foreach(lc, evi_list)
1364  {
1366  List *path;
1367 
1368  if (!evi1->installable)
1369  continue;
1370 
1371  /*
1372  * Find shortest path from evi1 to evi_target; but no need to consider
1373  * paths going through other installable versions.
1374  */
1375  path = find_update_path(evi_list, evi1, evi_target, true, true);
1376  if (path == NIL)
1377  continue;
1378 
1379  /* Remember best path */
1380  if (evi_start == NULL ||
1381  list_length(path) < list_length(*best_path) ||
1382  (list_length(path) == list_length(*best_path) &&
1383  strcmp(evi_start->name, evi1->name) < 0))
1384  {
1385  evi_start = evi1;
1386  *best_path = path;
1387  }
1388  }
1389 
1390  return evi_start;
1391 }
static List * find_update_path(List *evi_list, ExtensionVersionInfo *evi_start, ExtensionVersionInfo *evi_target, bool reject_indirect, bool reinitialize)
Definition: extension.c:1254

References find_update_path(), ExtensionVersionInfo::installable, lfirst, list_length(), ExtensionVersionInfo::name, and NIL.

Referenced by CreateExtensionInternal(), and get_available_versions_for_extension().

◆ find_update_path()

static List * find_update_path ( List evi_list,
ExtensionVersionInfo evi_start,
ExtensionVersionInfo evi_target,
bool  reject_indirect,
bool  reinitialize 
)
static

Definition at line 1254 of file extension.c.

1259 {
1260  List *result;
1261  ExtensionVersionInfo *evi;
1262  ListCell *lc;
1263 
1264  /* Caller error if start == target */
1265  Assert(evi_start != evi_target);
1266  /* Caller error if reject_indirect and target is installable */
1267  Assert(!(reject_indirect && evi_target->installable));
1268 
1269  if (reinitialize)
1270  {
1271  foreach(lc, evi_list)
1272  {
1273  evi = (ExtensionVersionInfo *) lfirst(lc);
1274  evi->distance_known = false;
1275  evi->distance = INT_MAX;
1276  evi->previous = NULL;
1277  }
1278  }
1279 
1280  evi_start->distance = 0;
1281 
1282  while ((evi = get_nearest_unprocessed_vertex(evi_list)) != NULL)
1283  {
1284  if (evi->distance == INT_MAX)
1285  break; /* all remaining vertices are unreachable */
1286  evi->distance_known = true;
1287  if (evi == evi_target)
1288  break; /* found shortest path to target */
1289  foreach(lc, evi->reachable)
1290  {
1292  int newdist;
1293 
1294  /* if reject_indirect, treat installable versions as unreachable */
1295  if (reject_indirect && evi2->installable)
1296  continue;
1297  newdist = evi->distance + 1;
1298  if (newdist < evi2->distance)
1299  {
1300  evi2->distance = newdist;
1301  evi2->previous = evi;
1302  }
1303  else if (newdist == evi2->distance &&
1304  evi2->previous != NULL &&
1305  strcmp(evi->name, evi2->previous->name) < 0)
1306  {
1307  /*
1308  * Break ties in favor of the version name that comes first
1309  * according to strcmp(). This behavior is undocumented and
1310  * users shouldn't rely on it. We do it just to ensure that
1311  * if there is a tie, the update path that is chosen does not
1312  * depend on random factors like the order in which directory
1313  * entries get visited.
1314  */
1315  evi2->previous = evi;
1316  }
1317  }
1318  }
1319 
1320  /* Return NIL if target is not reachable from start */
1321  if (!evi_target->distance_known)
1322  return NIL;
1323 
1324  /* Build and return list of version names representing the update path */
1325  result = NIL;
1326  for (evi = evi_target; evi != evi_start; evi = evi->previous)
1327  result = lcons(evi->name, result);
1328 
1329  return result;
1330 }
static ExtensionVersionInfo * get_nearest_unprocessed_vertex(List *evi_list)
Definition: extension.c:1120
List * lcons(void *datum, List *list)
Definition: list.c:495
struct ExtensionVersionInfo * previous
Definition: extension.c:107

References Assert, ExtensionVersionInfo::distance, ExtensionVersionInfo::distance_known, get_nearest_unprocessed_vertex(), ExtensionVersionInfo::installable, lcons(), lfirst, ExtensionVersionInfo::name, NIL, ExtensionVersionInfo::previous, and ExtensionVersionInfo::reachable.

Referenced by find_install_path(), identify_update_path(), and pg_extension_update_paths().

◆ get_available_versions_for_extension()

static void get_available_versions_for_extension ( ExtensionControlFile pcontrol,
Tuplestorestate tupstore,
TupleDesc  tupdesc 
)
static

Definition at line 2090 of file extension.c.

2093 {
2094  List *evi_list;
2095  ListCell *lc;
2096 
2097  /* Extract the version update graph from the script directory */
2098  evi_list = get_ext_ver_list(pcontrol);
2099 
2100  /* For each installable version ... */
2101  foreach(lc, evi_list)
2102  {
2104  ExtensionControlFile *control;
2105  Datum values[8];
2106  bool nulls[8];
2107  ListCell *lc2;
2108 
2109  if (!evi->installable)
2110  continue;
2111 
2112  /*
2113  * Fetch parameters for specific version (pcontrol is not changed)
2114  */
2115  control = read_extension_aux_control_file(pcontrol, evi->name);
2116 
2117  memset(values, 0, sizeof(values));
2118  memset(nulls, 0, sizeof(nulls));
2119 
2120  /* name */
2122  CStringGetDatum(control->name));
2123  /* version */
2124  values[1] = CStringGetTextDatum(evi->name);
2125  /* superuser */
2126  values[2] = BoolGetDatum(control->superuser);
2127  /* trusted */
2128  values[3] = BoolGetDatum(control->trusted);
2129  /* relocatable */
2130  values[4] = BoolGetDatum(control->relocatable);
2131  /* schema */
2132  if (control->schema == NULL)
2133  nulls[5] = true;
2134  else
2136  CStringGetDatum(control->schema));
2137  /* requires */
2138  if (control->requires == NIL)
2139  nulls[6] = true;
2140  else
2141  values[6] = convert_requires_to_datum(control->requires);
2142  /* comment */
2143  if (control->comment == NULL)
2144  nulls[7] = true;
2145  else
2146  values[7] = CStringGetTextDatum(control->comment);
2147 
2148  tuplestore_putvalues(tupstore, tupdesc, values, nulls);
2149 
2150  /*
2151  * Find all non-directly-installable versions that would be installed
2152  * starting from this version, and report them, inheriting the
2153  * parameters that aren't changed in updates from this version.
2154  */
2155  foreach(lc2, evi_list)
2156  {
2158  List *best_path;
2159 
2160  if (evi2->installable)
2161  continue;
2162  if (find_install_path(evi_list, evi2, &best_path) == evi)
2163  {
2164  /*
2165  * Fetch parameters for this version (pcontrol is not changed)
2166  */
2167  control = read_extension_aux_control_file(pcontrol, evi2->name);
2168 
2169  /* name stays the same */
2170  /* version */
2171  values[1] = CStringGetTextDatum(evi2->name);
2172  /* superuser */
2173  values[2] = BoolGetDatum(control->superuser);
2174  /* trusted */
2175  values[3] = BoolGetDatum(control->trusted);
2176  /* relocatable */
2177  values[4] = BoolGetDatum(control->relocatable);
2178  /* schema stays the same */
2179  /* requires */
2180  if (control->requires == NIL)
2181  nulls[6] = true;
2182  else
2183  {
2184  values[6] = convert_requires_to_datum(control->requires);
2185  nulls[6] = false;
2186  }
2187  /* comment stays the same */
2188 
2189  tuplestore_putvalues(tupstore, tupdesc, values, nulls);
2190  }
2191  }
2192  }
2193 }
static Datum convert_requires_to_datum(List *requires)
Definition: extension.c:2257
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
Definition: tuplestore.c:784

References BoolGetDatum(), ExtensionControlFile::comment, convert_requires_to_datum(), CStringGetDatum(), CStringGetTextDatum, DirectFunctionCall1, find_install_path(), get_ext_ver_list(), ExtensionVersionInfo::installable, lfirst, ExtensionControlFile::name, ExtensionVersionInfo::name, namein(), NIL, read_extension_aux_control_file(), ExtensionControlFile::relocatable, ExtensionControlFile::requires, ExtensionControlFile::schema, ExtensionControlFile::superuser, ExtensionControlFile::trusted, tuplestore_putvalues(), and values.

Referenced by pg_available_extension_versions().

◆ get_ext_ver_info()

static ExtensionVersionInfo* get_ext_ver_info ( const char *  versionname,
List **  evi_list 
)
static

Definition at line 1087 of file extension.c.

1088 {
1089  ExtensionVersionInfo *evi;
1090  ListCell *lc;
1091 
1092  foreach(lc, *evi_list)
1093  {
1094  evi = (ExtensionVersionInfo *) lfirst(lc);
1095  if (strcmp(evi->name, versionname) == 0)
1096  return evi;
1097  }
1098 
1100  evi->name = pstrdup(versionname);
1101  evi->reachable = NIL;
1102  evi->installable = false;
1103  /* initialize for later application of Dijkstra's algorithm */
1104  evi->distance_known = false;
1105  evi->distance = INT_MAX;
1106  evi->previous = NULL;
1107 
1108  *evi_list = lappend(*evi_list, evi);
1109 
1110  return evi;
1111 }
List * lappend(List *list, void *datum)
Definition: list.c:339

References ExtensionVersionInfo::distance, ExtensionVersionInfo::distance_known, ExtensionVersionInfo::installable, lappend(), lfirst, ExtensionVersionInfo::name, NIL, palloc(), ExtensionVersionInfo::previous, pstrdup(), and ExtensionVersionInfo::reachable.

Referenced by CreateExtensionInternal(), get_ext_ver_list(), and identify_update_path().

◆ get_ext_ver_list()

static List* get_ext_ver_list ( ExtensionControlFile control)
static

Definition at line 1148 of file extension.c.

1149 {
1150  List *evi_list = NIL;
1151  int extnamelen = strlen(control->name);
1152  char *location;
1153  DIR *dir;
1154  struct dirent *de;
1155 
1156  location = get_extension_script_directory(control);
1157  dir = AllocateDir(location);
1158  while ((de = ReadDir(dir, location)) != NULL)
1159  {
1160  char *vername;
1161  char *vername2;
1162  ExtensionVersionInfo *evi;
1163  ExtensionVersionInfo *evi2;
1164 
1165  /* must be a .sql file ... */
1167  continue;
1168 
1169  /* ... matching extension name followed by separator */
1170  if (strncmp(de->d_name, control->name, extnamelen) != 0 ||
1171  de->d_name[extnamelen] != '-' ||
1172  de->d_name[extnamelen + 1] != '-')
1173  continue;
1174 
1175  /* extract version name(s) from 'extname--something.sql' filename */
1176  vername = pstrdup(de->d_name + extnamelen + 2);
1177  *strrchr(vername, '.') = '\0';
1178  vername2 = strstr(vername, "--");
1179  if (!vername2)
1180  {
1181  /* It's an install, not update, script; record its version name */
1182  evi = get_ext_ver_info(vername, &evi_list);
1183  evi->installable = true;
1184  continue;
1185  }
1186  *vername2 = '\0'; /* terminate first version */
1187  vername2 += 2; /* and point to second */
1188 
1189  /* if there's a third --, it's bogus, ignore it */
1190  if (strstr(vername2, "--"))
1191  continue;
1192 
1193  /* Create ExtensionVersionInfos and link them together */
1194  evi = get_ext_ver_info(vername, &evi_list);
1195  evi2 = get_ext_ver_info(vername2, &evi_list);
1196  evi->reachable = lappend(evi->reachable, evi2);
1197  }
1198  FreeDir(dir);
1199 
1200  return evi_list;
1201 }
static bool is_extension_script_filename(const char *filename)
Definition: extension.c:312
static char * get_extension_script_directory(ExtensionControlFile *control)
Definition: extension.c:347

References AllocateDir(), dirent::d_name, FreeDir(), get_ext_ver_info(), get_extension_script_directory(), ExtensionVersionInfo::installable, is_extension_script_filename(), lappend(), ExtensionControlFile::name, NIL, pstrdup(), ExtensionVersionInfo::reachable, and ReadDir().

Referenced by CreateExtensionInternal(), get_available_versions_for_extension(), identify_update_path(), and pg_extension_update_paths().

◆ get_extension_aux_control_filename()

static char* get_extension_aux_control_filename ( ExtensionControlFile control,
const char *  version 
)
static

Definition at line 370 of file extension.c.

372 {
373  char *result;
374  char *scriptdir;
375 
376  scriptdir = get_extension_script_directory(control);
377 
378  result = (char *) palloc(MAXPGPATH);
379  snprintf(result, MAXPGPATH, "%s/%s--%s.control",
380  scriptdir, control->name, version);
381 
382  pfree(scriptdir);
383 
384  return result;
385 }
void pfree(void *pointer)
Definition: mcxt.c:1521
#define MAXPGPATH
#define snprintf
Definition: port.h:238

References get_extension_script_directory(), MAXPGPATH, ExtensionControlFile::name, palloc(), pfree(), and snprintf.

Referenced by parse_extension_control_file().

◆ get_extension_control_directory()

static char* get_extension_control_directory ( void  )
static

Definition at line 320 of file extension.c.

321 {
322  char sharepath[MAXPGPATH];
323  char *result;
324 
325  get_share_path(my_exec_path, sharepath);
326  result = (char *) palloc(MAXPGPATH);
327  snprintf(result, MAXPGPATH, "%s/extension", sharepath);
328 
329  return result;
330 }
char my_exec_path[MAXPGPATH]
Definition: globals.c:80
void get_share_path(const char *my_exec_path, char *ret_path)
Definition: path.c:825

References get_share_path(), MAXPGPATH, my_exec_path, palloc(), and snprintf.

Referenced by extension_file_exists(), get_extension_script_directory(), pg_available_extension_versions(), and pg_available_extensions().

◆ get_extension_control_filename()

static char* get_extension_control_filename ( const char *  extname)
static

Definition at line 333 of file extension.c.

334 {
335  char sharepath[MAXPGPATH];
336  char *result;
337 
338  get_share_path(my_exec_path, sharepath);
339  result = (char *) palloc(MAXPGPATH);
340  snprintf(result, MAXPGPATH, "%s/extension/%s.control",
341  sharepath, extname);
342 
343  return result;
344 }

References get_share_path(), MAXPGPATH, my_exec_path, palloc(), and snprintf.

Referenced by parse_extension_control_file().

◆ get_extension_name()

char* get_extension_name ( Oid  ext_oid)

Definition at line 168 of file extension.c.

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

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

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

◆ get_extension_oid()

Oid get_extension_oid ( const char *  extname,
bool  missing_ok 
)

Definition at line 146 of file extension.c.

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

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

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

◆ get_extension_schema()

Oid get_extension_schema ( Oid  ext_oid)

Definition at line 190 of file extension.c.

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

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

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

◆ get_extension_script_directory()

static char* get_extension_script_directory ( ExtensionControlFile control)
static

Definition at line 347 of file extension.c.

348 {
349  char sharepath[MAXPGPATH];
350  char *result;
351 
352  /*
353  * The directory parameter can be omitted, absolute, or relative to the
354  * installation's share directory.
355  */
356  if (!control->directory)
358 
359  if (is_absolute_path(control->directory))
360  return pstrdup(control->directory);
361 
362  get_share_path(my_exec_path, sharepath);
363  result = (char *) palloc(MAXPGPATH);
364  snprintf(result, MAXPGPATH, "%s/%s", sharepath, control->directory);
365 
366  return result;
367 }
#define is_absolute_path(filename)
Definition: port.h:103

References ExtensionControlFile::directory, get_extension_control_directory(), get_share_path(), is_absolute_path, MAXPGPATH, my_exec_path, palloc(), pstrdup(), and snprintf.

Referenced by get_ext_ver_list(), get_extension_aux_control_filename(), and get_extension_script_filename().

◆ get_extension_script_filename()

static char* get_extension_script_filename ( ExtensionControlFile control,
const char *  from_version,
const char *  version 
)
static

Definition at line 388 of file extension.c.

390 {
391  char *result;
392  char *scriptdir;
393 
394  scriptdir = get_extension_script_directory(control);
395 
396  result = (char *) palloc(MAXPGPATH);
397  if (from_version)
398  snprintf(result, MAXPGPATH, "%s/%s--%s--%s.sql",
399  scriptdir, control->name, from_version, version);
400  else
401  snprintf(result, MAXPGPATH, "%s/%s--%s.sql",
402  scriptdir, control->name, version);
403 
404  pfree(scriptdir);
405 
406  return result;
407 }

References get_extension_script_directory(), MAXPGPATH, ExtensionControlFile::name, palloc(), pfree(), and snprintf.

Referenced by CreateExtensionInternal(), and execute_extension_script().

◆ get_nearest_unprocessed_vertex()

static ExtensionVersionInfo* get_nearest_unprocessed_vertex ( List evi_list)
static

Definition at line 1120 of file extension.c.

1121 {
1122  ExtensionVersionInfo *evi = NULL;
1123  ListCell *lc;
1124 
1125  foreach(lc, evi_list)
1126  {
1128 
1129  /* only vertices whose distance is still uncertain are candidates */
1130  if (evi2->distance_known)
1131  continue;
1132  /* remember the closest such vertex */
1133  if (evi == NULL ||
1134  evi->distance > evi2->distance)
1135  evi = evi2;
1136  }
1137 
1138  return evi;
1139 }

References ExtensionVersionInfo::distance, ExtensionVersionInfo::distance_known, and lfirst.

Referenced by find_update_path().

◆ get_required_extension()

static Oid get_required_extension ( char *  reqExtensionName,
char *  extensionName,
char *  origSchemaName,
bool  cascade,
List parents,
bool  is_create 
)
static

Definition at line 1641 of file extension.c.

1647 {
1648  Oid reqExtensionOid;
1649 
1650  reqExtensionOid = get_extension_oid(reqExtensionName, true);
1651  if (!OidIsValid(reqExtensionOid))
1652  {
1653  if (cascade)
1654  {
1655  /* Must install it. */
1656  ObjectAddress addr;
1657  List *cascade_parents;
1658  ListCell *lc;
1659 
1660  /* Check extension name validity before trying to cascade. */
1661  check_valid_extension_name(reqExtensionName);
1662 
1663  /* Check for cyclic dependency between extensions. */
1664  foreach(lc, parents)
1665  {
1666  char *pname = (char *) lfirst(lc);
1667 
1668  if (strcmp(pname, reqExtensionName) == 0)
1669  ereport(ERROR,
1670  (errcode(ERRCODE_INVALID_RECURSION),
1671  errmsg("cyclic dependency detected between extensions \"%s\" and \"%s\"",
1672  reqExtensionName, extensionName)));
1673  }
1674 
1675  ereport(NOTICE,
1676  (errmsg("installing required extension \"%s\"",
1677  reqExtensionName)));
1678 
1679  /* Add current extension to list of parents to pass down. */
1680  cascade_parents = lappend(list_copy(parents), extensionName);
1681 
1682  /*
1683  * Create the required extension. We propagate the SCHEMA option
1684  * if any, and CASCADE, but no other options.
1685  */
1686  addr = CreateExtensionInternal(reqExtensionName,
1687  origSchemaName,
1688  NULL,
1689  cascade,
1690  cascade_parents,
1691  is_create);
1692 
1693  /* Get its newly-assigned OID. */
1694  reqExtensionOid = addr.objectId;
1695  }
1696  else
1697  ereport(ERROR,
1698  (errcode(ERRCODE_UNDEFINED_OBJECT),
1699  errmsg("required extension \"%s\" is not installed",
1700  reqExtensionName),
1701  is_create ?
1702  errhint("Use CREATE EXTENSION ... CASCADE to install required extensions too.") : 0));
1703  }
1704 
1705  return reqExtensionOid;
1706 }
List * list_copy(const List *oldlist)
Definition: list.c:1573

References check_valid_extension_name(), CreateExtensionInternal(), ereport, errcode(), errhint(), errmsg(), ERROR, get_extension_oid(), lappend(), lfirst, list_copy(), NOTICE, ObjectAddress::objectId, and OidIsValid.

Referenced by ApplyExtensionUpdates(), and CreateExtensionInternal().

◆ identify_update_path()

static List* identify_update_path ( ExtensionControlFile control,
const char *  oldVersion,
const char *  newVersion 
)
static

Definition at line 1211 of file extension.c.

1213 {
1214  List *result;
1215  List *evi_list;
1216  ExtensionVersionInfo *evi_start;
1217  ExtensionVersionInfo *evi_target;
1218 
1219  /* Extract the version update graph from the script directory */
1220  evi_list = get_ext_ver_list(control);
1221 
1222  /* Initialize start and end vertices */
1223  evi_start = get_ext_ver_info(oldVersion, &evi_list);
1224  evi_target = get_ext_ver_info(newVersion, &evi_list);
1225 
1226  /* Find shortest path */
1227  result = find_update_path(evi_list, evi_start, evi_target, false, false);
1228 
1229  if (result == NIL)
1230  ereport(ERROR,
1231  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1232  errmsg("extension \"%s\" has no update path from version \"%s\" to version \"%s\"",
1233  control->name, oldVersion, newVersion)));
1234 
1235  return result;
1236 }

References ereport, errcode(), errmsg(), ERROR, find_update_path(), get_ext_ver_info(), get_ext_ver_list(), ExtensionControlFile::name, and NIL.

Referenced by ExecAlterExtensionStmt().

◆ InsertExtensionTuple()

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

Definition at line 1810 of file extension.c.

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

◆ is_extension_control_filename()

static bool is_extension_control_filename ( const char *  filename)
static

Definition at line 304 of file extension.c.

305 {
306  const char *extension = strrchr(filename, '.');
307 
308  return (extension != NULL) && (strcmp(extension, ".control") == 0);
309 }

References filename.

Referenced by extension_file_exists(), pg_available_extension_versions(), and pg_available_extensions().

◆ is_extension_script_filename()

static bool is_extension_script_filename ( const char *  filename)
static

Definition at line 312 of file extension.c.

313 {
314  const char *extension = strrchr(filename, '.');
315 
316  return (extension != NULL) && (strcmp(extension, ".sql") == 0);
317 }

References filename.

Referenced by get_ext_ver_list().

◆ parse_extension_control_file()

static void parse_extension_control_file ( ExtensionControlFile control,
const char *  version 
)
static

Definition at line 420 of file extension.c.

422 {
423  char *filename;
424  FILE *file;
425  ConfigVariable *item,
426  *head = NULL,
427  *tail = NULL;
428 
429  /*
430  * Locate the file to read. Auxiliary files are optional.
431  */
432  if (version)
433  filename = get_extension_aux_control_filename(control, version);
434  else
436 
437  if ((file = AllocateFile(filename, "r")) == NULL)
438  {
439  if (errno == ENOENT)
440  {
441  /* no complaint for missing auxiliary file */
442  if (version)
443  {
444  pfree(filename);
445  return;
446  }
447 
448  /* missing control file indicates extension is not installed */
449  ereport(ERROR,
450  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
451  errmsg("extension \"%s\" is not available", control->name),
452  errdetail("Could not open extension control file \"%s\": %m.",
453  filename),
454  errhint("The extension must first be installed on the system where PostgreSQL is running.")));
455  }
456  ereport(ERROR,
458  errmsg("could not open extension control file \"%s\": %m",
459  filename)));
460  }
461 
462  /*
463  * Parse the file content, using GUC's file parsing code. We need not
464  * check the return value since any errors will be thrown at ERROR level.
465  */
467  &head, &tail);
468 
469  FreeFile(file);
470 
471  /*
472  * Convert the ConfigVariable list into ExtensionControlFile entries.
473  */
474  for (item = head; item != NULL; item = item->next)
475  {
476  if (strcmp(item->name, "directory") == 0)
477  {
478  if (version)
479  ereport(ERROR,
480  (errcode(ERRCODE_SYNTAX_ERROR),
481  errmsg("parameter \"%s\" cannot be set in a secondary extension control file",
482  item->name)));
483 
484  control->directory = pstrdup(item->value);
485  }
486  else if (strcmp(item->name, "default_version") == 0)
487  {
488  if (version)
489  ereport(ERROR,
490  (errcode(ERRCODE_SYNTAX_ERROR),
491  errmsg("parameter \"%s\" cannot be set in a secondary extension control file",
492  item->name)));
493 
494  control->default_version = pstrdup(item->value);
495  }
496  else if (strcmp(item->name, "module_pathname") == 0)
497  {
498  control->module_pathname = pstrdup(item->value);
499  }
500  else if (strcmp(item->name, "comment") == 0)
501  {
502  control->comment = pstrdup(item->value);
503  }
504  else if (strcmp(item->name, "schema") == 0)
505  {
506  control->schema = pstrdup(item->value);
507  }
508  else if (strcmp(item->name, "relocatable") == 0)
509  {
510  if (!parse_bool(item->value, &control->relocatable))
511  ereport(ERROR,
512  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
513  errmsg("parameter \"%s\" requires a Boolean value",
514  item->name)));
515  }
516  else if (strcmp(item->name, "superuser") == 0)
517  {
518  if (!parse_bool(item->value, &control->superuser))
519  ereport(ERROR,
520  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
521  errmsg("parameter \"%s\" requires a Boolean value",
522  item->name)));
523  }
524  else if (strcmp(item->name, "trusted") == 0)
525  {
526  if (!parse_bool(item->value, &control->trusted))
527  ereport(ERROR,
528  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
529  errmsg("parameter \"%s\" requires a Boolean value",
530  item->name)));
531  }
532  else if (strcmp(item->name, "encoding") == 0)
533  {
534  control->encoding = pg_valid_server_encoding(item->value);
535  if (control->encoding < 0)
536  ereport(ERROR,
537  (errcode(ERRCODE_UNDEFINED_OBJECT),
538  errmsg("\"%s\" is not a valid encoding name",
539  item->value)));
540  }
541  else if (strcmp(item->name, "requires") == 0)
542  {
543  /* Need a modifiable copy of string */
544  char *rawnames = pstrdup(item->value);
545 
546  /* Parse string into list of identifiers */
547  if (!SplitIdentifierString(rawnames, ',', &control->requires))
548  {
549  /* syntax error in name list */
550  ereport(ERROR,
551  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
552  errmsg("parameter \"%s\" must be a list of extension names",
553  item->name)));
554  }
555  }
556  else if (strcmp(item->name, "no_relocate") == 0)
557  {
558  /* Need a modifiable copy of string */
559  char *rawnames = pstrdup(item->value);
560 
561  /* Parse string into list of identifiers */
562  if (!SplitIdentifierString(rawnames, ',', &control->no_relocate))
563  {
564  /* syntax error in name list */
565  ereport(ERROR,
566  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
567  errmsg("parameter \"%s\" must be a list of extension names",
568  item->name)));
569  }
570  }
571  else
572  ereport(ERROR,
573  (errcode(ERRCODE_SYNTAX_ERROR),
574  errmsg("unrecognized parameter \"%s\" in file \"%s\"",
575  item->name, filename)));
576  }
577 
578  FreeConfigVariables(head);
579 
580  if (control->relocatable && control->schema != NULL)
581  ereport(ERROR,
582  (errcode(ERRCODE_SYNTAX_ERROR),
583  errmsg("parameter \"schema\" cannot be specified when \"relocatable\" is true")));
584 
585  pfree(filename);
586 }
bool parse_bool(const char *value, bool *result)
Definition: bool.c:31
#define CONF_FILE_START_DEPTH
Definition: conffiles.h:17
int errcode_for_file_access(void)
Definition: elog.c:876
static char * get_extension_control_filename(const char *extname)
Definition: extension.c:333
static char * get_extension_aux_control_filename(ExtensionControlFile *control, const char *version)
Definition: extension.c:370
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2606
int FreeFile(FILE *file)
Definition: fd.c:2804
void FreeConfigVariables(ConfigVariable *list)
bool ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel, ConfigVariable **head_p, ConfigVariable **tail_p)
#define pg_valid_server_encoding
Definition: pg_wchar.h:631
char * name
Definition: guc.h:137
struct ConfigVariable * next
Definition: guc.h:144
char * value
Definition: guc.h:138
bool SplitIdentifierString(char *rawstring, char separator, List **namelist)
Definition: varlena.c:3432

References AllocateFile(), ExtensionControlFile::comment, CONF_FILE_START_DEPTH, ExtensionControlFile::default_version, ExtensionControlFile::directory, ExtensionControlFile::encoding, ereport, errcode(), errcode_for_file_access(), errdetail(), errhint(), errmsg(), ERROR, filename, FreeConfigVariables(), FreeFile(), get_extension_aux_control_filename(), get_extension_control_filename(), ExtensionControlFile::module_pathname, ExtensionControlFile::name, ConfigVariable::name, ConfigVariable::next, ExtensionControlFile::no_relocate, parse_bool(), ParseConfigFp(), pfree(), pg_valid_server_encoding, pstrdup(), ExtensionControlFile::relocatable, ExtensionControlFile::requires, ExtensionControlFile::schema, SplitIdentifierString(), ExtensionControlFile::superuser, ExtensionControlFile::trusted, and ConfigVariable::value.

Referenced by read_extension_aux_control_file(), and read_extension_control_file().

◆ pg_available_extension_versions()

Datum pg_available_extension_versions ( PG_FUNCTION_ARGS  )

Definition at line 2032 of file extension.c.

2033 {
2034  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
2035  char *location;
2036  DIR *dir;
2037  struct dirent *de;
2038 
2039  /* Build tuplestore to hold the result rows */
2040  InitMaterializedSRF(fcinfo, 0);
2041 
2042  location = get_extension_control_directory();
2043  dir = AllocateDir(location);
2044 
2045  /*
2046  * If the control directory doesn't exist, we want to silently return an
2047  * empty set. Any other error will be reported by ReadDir.
2048  */
2049  if (dir == NULL && errno == ENOENT)
2050  {
2051  /* do nothing */
2052  }
2053  else
2054  {
2055  while ((de = ReadDir(dir, location)) != NULL)
2056  {
2057  ExtensionControlFile *control;
2058  char *extname;
2059 
2060  if (!is_extension_control_filename(de->d_name))
2061  continue;
2062 
2063  /* extract extension name from 'name.control' filename */
2064  extname = pstrdup(de->d_name);
2065  *strrchr(extname, '.') = '\0';
2066 
2067  /* ignore it if it's an auxiliary control file */
2068  if (strstr(extname, "--"))
2069  continue;
2070 
2071  /* read the control file */
2072  control = read_extension_control_file(extname);
2073 
2074  /* scan extension's script directory for install scripts */
2076  rsinfo->setDesc);
2077  }
2078 
2079  FreeDir(dir);
2080  }
2081 
2082  return (Datum) 0;
2083 }
static void get_available_versions_for_extension(ExtensionControlFile *pcontrol, Tuplestorestate *tupstore, TupleDesc tupdesc)
Definition: extension.c:2090
void InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags)
Definition: funcapi.c:76
TupleDesc setDesc
Definition: execnodes.h:343
Tuplestorestate * setResult
Definition: execnodes.h:342

References AllocateDir(), FreeDir(), get_available_versions_for_extension(), get_extension_control_directory(), InitMaterializedSRF(), is_extension_control_filename(), pstrdup(), read_extension_control_file(), ReadDir(), ReturnSetInfo::setDesc, and ReturnSetInfo::setResult.

◆ pg_available_extensions()

Datum pg_available_extensions ( PG_FUNCTION_ARGS  )

Definition at line 1952 of file extension.c.

1953 {
1954  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1955  char *location;
1956  DIR *dir;
1957  struct dirent *de;
1958 
1959  /* Build tuplestore to hold the result rows */
1960  InitMaterializedSRF(fcinfo, 0);
1961 
1962  location = get_extension_control_directory();
1963  dir = AllocateDir(location);
1964 
1965  /*
1966  * If the control directory doesn't exist, we want to silently return an
1967  * empty set. Any other error will be reported by ReadDir.
1968  */
1969  if (dir == NULL && errno == ENOENT)
1970  {
1971  /* do nothing */
1972  }
1973  else
1974  {
1975  while ((de = ReadDir(dir, location)) != NULL)
1976  {
1977  ExtensionControlFile *control;
1978  char *extname;
1979  Datum values[3];
1980  bool nulls[3];
1981 
1982  if (!is_extension_control_filename(de->d_name))
1983  continue;
1984 
1985  /* extract extension name from 'name.control' filename */
1986  extname = pstrdup(de->d_name);
1987  *strrchr(extname, '.') = '\0';
1988 
1989  /* ignore it if it's an auxiliary control file */
1990  if (strstr(extname, "--"))
1991  continue;
1992 
1993  control = read_extension_control_file(extname);
1994 
1995  memset(values, 0, sizeof(values));
1996  memset(nulls, 0, sizeof(nulls));
1997 
1998  /* name */
2000  CStringGetDatum(control->name));
2001  /* default_version */
2002  if (control->default_version == NULL)
2003  nulls[1] = true;
2004  else
2006  /* comment */
2007  if (control->comment == NULL)
2008  nulls[2] = true;
2009  else
2010  values[2] = CStringGetTextDatum(control->comment);
2011 
2012  tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
2013  values, nulls);
2014  }
2015 
2016  FreeDir(dir);
2017  }
2018 
2019  return (Datum) 0;
2020 }

References AllocateDir(), ExtensionControlFile::comment, CStringGetDatum(), CStringGetTextDatum, ExtensionControlFile::default_version, DirectFunctionCall1, FreeDir(), get_extension_control_directory(), InitMaterializedSRF(), is_extension_control_filename(), ExtensionControlFile::name, namein(), pstrdup(), read_extension_control_file(), ReadDir(), ReturnSetInfo::setDesc, ReturnSetInfo::setResult, tuplestore_putvalues(), and values.

◆ pg_extension_config_dump()

Datum pg_extension_config_dump ( PG_FUNCTION_ARGS  )

Definition at line 2368 of file extension.c.

2369 {
2370  Oid tableoid = PG_GETARG_OID(0);
2371  text *wherecond = PG_GETARG_TEXT_PP(1);
2372  char *tablename;
2373  Relation extRel;
2374  ScanKeyData key[1];
2375  SysScanDesc extScan;
2376  HeapTuple extTup;
2377  Datum arrayDatum;
2378  Datum elementDatum;
2379  int arrayLength;
2380  int arrayIndex;
2381  bool isnull;
2382  Datum repl_val[Natts_pg_extension];
2383  bool repl_null[Natts_pg_extension];
2384  bool repl_repl[Natts_pg_extension];
2385  ArrayType *a;
2386 
2387  /*
2388  * We only allow this to be called from an extension's SQL script. We
2389  * shouldn't need any permissions check beyond that.
2390  */
2391  if (!creating_extension)
2392  ereport(ERROR,
2393  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2394  errmsg("%s can only be called from an SQL script executed by CREATE EXTENSION",
2395  "pg_extension_config_dump()")));
2396 
2397  /*
2398  * Check that the table exists and is a member of the extension being
2399  * created. This ensures that we don't need to register an additional
2400  * dependency to protect the extconfig entry.
2401  */
2402  tablename = get_rel_name(tableoid);
2403  if (tablename == NULL)
2404  ereport(ERROR,
2406  errmsg("OID %u does not refer to a table", tableoid)));
2407  if (getExtensionOfObject(RelationRelationId, tableoid) !=
2409  ereport(ERROR,
2410  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2411  errmsg("table \"%s\" is not a member of the extension being created",
2412  tablename)));
2413 
2414  /*
2415  * Add the table OID and WHERE condition to the extension's extconfig and
2416  * extcondition arrays.
2417  *
2418  * If the table is already in extconfig, treat this as an update of the
2419  * WHERE condition.
2420  */
2421 
2422  /* Find the pg_extension tuple */
2423  extRel = table_open(ExtensionRelationId, RowExclusiveLock);
2424 
2425  ScanKeyInit(&key[0],
2426  Anum_pg_extension_oid,
2427  BTEqualStrategyNumber, F_OIDEQ,
2429 
2430  extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
2431  NULL, 1, key);
2432 
2433  extTup = systable_getnext(extScan);
2434 
2435  if (!HeapTupleIsValid(extTup)) /* should not happen */
2436  elog(ERROR, "could not find tuple for extension %u",
2438 
2439  memset(repl_val, 0, sizeof(repl_val));
2440  memset(repl_null, false, sizeof(repl_null));
2441  memset(repl_repl, false, sizeof(repl_repl));
2442 
2443  /* Build or modify the extconfig value */
2444  elementDatum = ObjectIdGetDatum(tableoid);
2445 
2446  arrayDatum = heap_getattr(extTup, Anum_pg_extension_extconfig,
2447  RelationGetDescr(extRel), &isnull);
2448  if (isnull)
2449  {
2450  /* Previously empty extconfig, so build 1-element array */
2451  arrayLength = 0;
2452  arrayIndex = 1;
2453 
2454  a = construct_array_builtin(&elementDatum, 1, OIDOID);
2455  }
2456  else
2457  {
2458  /* Modify or extend existing extconfig array */
2459  Oid *arrayData;
2460  int i;
2461 
2462  a = DatumGetArrayTypeP(arrayDatum);
2463 
2464  arrayLength = ARR_DIMS(a)[0];
2465  if (ARR_NDIM(a) != 1 ||
2466  ARR_LBOUND(a)[0] != 1 ||
2467  arrayLength < 0 ||
2468  ARR_HASNULL(a) ||
2469  ARR_ELEMTYPE(a) != OIDOID)
2470  elog(ERROR, "extconfig is not a 1-D Oid array");
2471  arrayData = (Oid *) ARR_DATA_PTR(a);
2472 
2473  arrayIndex = arrayLength + 1; /* set up to add after end */
2474 
2475  for (i = 0; i < arrayLength; i++)
2476  {
2477  if (arrayData[i] == tableoid)
2478  {
2479  arrayIndex = i + 1; /* replace this element instead */
2480  break;
2481  }
2482  }
2483 
2484  a = array_set(a, 1, &arrayIndex,
2485  elementDatum,
2486  false,
2487  -1 /* varlena array */ ,
2488  sizeof(Oid) /* OID's typlen */ ,
2489  true /* OID's typbyval */ ,
2490  TYPALIGN_INT /* OID's typalign */ );
2491  }
2492  repl_val[Anum_pg_extension_extconfig - 1] = PointerGetDatum(a);
2493  repl_repl[Anum_pg_extension_extconfig - 1] = true;
2494 
2495  /* Build or modify the extcondition value */
2496  elementDatum = PointerGetDatum(wherecond);
2497 
2498  arrayDatum = heap_getattr(extTup, Anum_pg_extension_extcondition,
2499  RelationGetDescr(extRel), &isnull);
2500  if (isnull)
2501  {
2502  if (arrayLength != 0)
2503  elog(ERROR, "extconfig and extcondition arrays do not match");
2504 
2505  a = construct_array_builtin(&elementDatum, 1, TEXTOID);
2506  }
2507  else
2508  {
2509  a = DatumGetArrayTypeP(arrayDatum);
2510 
2511  if (ARR_NDIM(a) != 1 ||
2512  ARR_LBOUND(a)[0] != 1 ||
2513  ARR_HASNULL(a) ||
2514  ARR_ELEMTYPE(a) != TEXTOID)
2515  elog(ERROR, "extcondition is not a 1-D text array");
2516  if (ARR_DIMS(a)[0] != arrayLength)
2517  elog(ERROR, "extconfig and extcondition arrays do not match");
2518 
2519  /* Add or replace at same index as in extconfig */
2520  a = array_set(a, 1, &arrayIndex,
2521  elementDatum,
2522  false,
2523  -1 /* varlena array */ ,
2524  -1 /* TEXT's typlen */ ,
2525  false /* TEXT's typbyval */ ,
2526  TYPALIGN_INT /* TEXT's typalign */ );
2527  }
2528  repl_val[Anum_pg_extension_extcondition - 1] = PointerGetDatum(a);
2529  repl_repl[Anum_pg_extension_extcondition - 1] = true;
2530 
2531  extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
2532  repl_val, repl_null, repl_repl);
2533 
2534  CatalogTupleUpdate(extRel, &extTup->t_self, extTup);
2535 
2536  systable_endscan(extScan);
2537 
2538  table_close(extRel, RowExclusiveLock);
2539 
2540  PG_RETURN_VOID();
2541 }
ArrayType * array_set(ArrayType *array, int nSubscripts, int *indx, Datum dataValue, bool isNull, int arraytyplen, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3163
#define PG_RETURN_VOID()
Definition: fmgr.h:349
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1928
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:78
Definition: c.h:690

References a, ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_HASNULL, ARR_LBOUND, ARR_NDIM, array_set(), BTEqualStrategyNumber, CatalogTupleUpdate(), construct_array_builtin(), creating_extension, CurrentExtensionObject, DatumGetArrayTypeP, elog, ereport, errcode(), ERRCODE_UNDEFINED_TABLE, errmsg(), ERROR, get_rel_name(), getExtensionOfObject(), heap_getattr(), heap_modify_tuple(), HeapTupleIsValid, i, sort-test::key, ObjectIdGetDatum(), PG_GETARG_OID, PG_GETARG_TEXT_PP, PG_RETURN_VOID, PointerGetDatum(), RelationGetDescr, RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), and table_open().

◆ pg_extension_update_paths()

Datum pg_extension_update_paths ( PG_FUNCTION_ARGS  )

Definition at line 2283 of file extension.c.

2284 {
2285  Name extname = PG_GETARG_NAME(0);
2286  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
2287  List *evi_list;
2288  ExtensionControlFile *control;
2289  ListCell *lc1;
2290 
2291  /* Check extension name validity before any filesystem access */
2293 
2294  /* Build tuplestore to hold the result rows */
2295  InitMaterializedSRF(fcinfo, 0);
2296 
2297  /* Read the extension's control file */
2298  control = read_extension_control_file(NameStr(*extname));
2299 
2300  /* Extract the version update graph from the script directory */
2301  evi_list = get_ext_ver_list(control);
2302 
2303  /* Iterate over all pairs of versions */
2304  foreach(lc1, evi_list)
2305  {
2307  ListCell *lc2;
2308 
2309  foreach(lc2, evi_list)
2310  {
2312  List *path;
2313  Datum values[3];
2314  bool nulls[3];
2315 
2316  if (evi1 == evi2)
2317  continue;
2318 
2319  /* Find shortest path from evi1 to evi2 */
2320  path = find_update_path(evi_list, evi1, evi2, false, true);
2321 
2322  /* Emit result row */
2323  memset(values, 0, sizeof(values));
2324  memset(nulls, 0, sizeof(nulls));
2325 
2326  /* source */
2327  values[0] = CStringGetTextDatum(evi1->name);
2328  /* target */
2329  values[1] = CStringGetTextDatum(evi2->name);
2330  /* path */
2331  if (path == NIL)
2332  nulls[2] = true;
2333  else
2334  {
2335  StringInfoData pathbuf;
2336  ListCell *lcv;
2337 
2338  initStringInfo(&pathbuf);
2339  /* The path doesn't include start vertex, but show it */
2340  appendStringInfoString(&pathbuf, evi1->name);
2341  foreach(lcv, path)
2342  {
2343  char *versionName = (char *) lfirst(lcv);
2344 
2345  appendStringInfoString(&pathbuf, "--");
2346  appendStringInfoString(&pathbuf, versionName);
2347  }
2348  values[2] = CStringGetTextDatum(pathbuf.data);
2349  pfree(pathbuf.data);
2350  }
2351 
2352  tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
2353  values, nulls);
2354  }
2355  }
2356 
2357  return (Datum) 0;
2358 }
#define PG_GETARG_NAME(n)
Definition: fmgr.h:278
Definition: c.h:744

References appendStringInfoString(), check_valid_extension_name(), CStringGetTextDatum, StringInfoData::data, find_update_path(), get_ext_ver_list(), InitMaterializedSRF(), initStringInfo(), lfirst, ExtensionVersionInfo::name, NameStr, NIL, pfree(), PG_GETARG_NAME, read_extension_control_file(), ReturnSetInfo::setDesc, ReturnSetInfo::setResult, tuplestore_putvalues(), and values.

◆ read_extension_aux_control_file()

static ExtensionControlFile* read_extension_aux_control_file ( const ExtensionControlFile pcontrol,
const char *  version 
)
static

Definition at line 621 of file extension.c.

623 {
624  ExtensionControlFile *acontrol;
625 
626  /*
627  * Flat-copy the struct. Pointer fields share values with original.
628  */
629  acontrol = (ExtensionControlFile *) palloc(sizeof(ExtensionControlFile));
630  memcpy(acontrol, pcontrol, sizeof(ExtensionControlFile));
631 
632  /*
633  * Parse the auxiliary control file, overwriting struct fields
634  */
635  parse_extension_control_file(acontrol, version);
636 
637  return acontrol;
638 }
static void parse_extension_control_file(ExtensionControlFile *control, const char *version)
Definition: extension.c:420

References palloc(), and parse_extension_control_file().

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

◆ read_extension_control_file()

static ExtensionControlFile* read_extension_control_file ( const char *  extname)
static

Definition at line 592 of file extension.c.

593 {
594  ExtensionControlFile *control;
595 
596  /*
597  * Set up default values. Pointer fields are initially null.
598  */
599  control = (ExtensionControlFile *) palloc0(sizeof(ExtensionControlFile));
600  control->name = pstrdup(extname);
601  control->relocatable = false;
602  control->superuser = true;
603  control->trusted = false;
604  control->encoding = -1;
605 
606  /*
607  * Parse the primary control file.
608  */
609  parse_extension_control_file(control, NULL);
610 
611  return control;
612 }
void * palloc0(Size size)
Definition: mcxt.c:1347

References ExtensionControlFile::encoding, ExtensionControlFile::name, palloc0(), parse_extension_control_file(), pstrdup(), ExtensionControlFile::relocatable, ExtensionControlFile::superuser, and ExtensionControlFile::trusted.

Referenced by AlterExtensionNamespace(), CreateExtensionInternal(), ExecAlterExtensionStmt(), pg_available_extension_versions(), pg_available_extensions(), and pg_extension_update_paths().

◆ read_extension_script_file()

static char* read_extension_script_file ( const ExtensionControlFile control,
const char *  filename 
)
static

Definition at line 644 of file extension.c.

646 {
647  int src_encoding;
648  char *src_str;
649  char *dest_str;
650  int len;
651 
652  src_str = read_whole_file(filename, &len);
653 
654  /* use database encoding if not given */
655  if (control->encoding < 0)
656  src_encoding = GetDatabaseEncoding();
657  else
658  src_encoding = control->encoding;
659 
660  /* make sure that source string is valid in the expected encoding */
661  (void) pg_verify_mbstr(src_encoding, src_str, len, false);
662 
663  /*
664  * Convert the encoding to the database encoding. read_whole_file
665  * null-terminated the string, so if no conversion happens the string is
666  * valid as is.
667  */
668  dest_str = pg_any_to_server(src_str, len, src_encoding);
669 
670  return dest_str;
671 }
static char * read_whole_file(const char *filename, int *length)
Definition: extension.c:3461
char * pg_any_to_server(const char *s, int len, int encoding)
Definition: mbutils.c:676
int GetDatabaseEncoding(void)
Definition: mbutils.c:1261
bool pg_verify_mbstr(int encoding, const char *mbstr, int len, bool noError)
Definition: mbutils.c:1566
const void size_t len

References ExtensionControlFile::encoding, filename, GetDatabaseEncoding(), len, pg_any_to_server(), pg_verify_mbstr(), and read_whole_file().

Referenced by execute_extension_script().

◆ read_whole_file()

static char * read_whole_file ( const char *  filename,
int *  length 
)
static

Definition at line 3461 of file extension.c.

3462 {
3463  char *buf;
3464  FILE *file;
3465  size_t bytes_to_read;
3466  struct stat fst;
3467 
3468  if (stat(filename, &fst) < 0)
3469  ereport(ERROR,
3471  errmsg("could not stat file \"%s\": %m", filename)));
3472 
3473  if (fst.st_size > (MaxAllocSize - 1))
3474  ereport(ERROR,
3475  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3476  errmsg("file \"%s\" is too large", filename)));
3477  bytes_to_read = (size_t) fst.st_size;
3478 
3479  if ((file = AllocateFile(filename, PG_BINARY_R)) == NULL)
3480  ereport(ERROR,
3482  errmsg("could not open file \"%s\" for reading: %m",
3483  filename)));
3484 
3485  buf = (char *) palloc(bytes_to_read + 1);
3486 
3487  *length = fread(buf, 1, bytes_to_read, file);
3488 
3489  if (ferror(file))
3490  ereport(ERROR,
3492  errmsg("could not read file \"%s\": %m", filename)));
3493 
3494  FreeFile(file);
3495 
3496  buf[*length] = '\0';
3497  return buf;
3498 }
#define PG_BINARY_R
Definition: c.h:1278
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
#define MaxAllocSize
Definition: memutils.h:40
static char * buf
Definition: pg_test_fsync.c:73

References AllocateFile(), buf, ereport, errcode(), errcode_for_file_access(), errmsg(), ERROR, filename, FreeFile(), if(), MaxAllocSize, palloc(), PG_BINARY_R, stat::st_size, and stat.

Referenced by read_extension_script_file().

◆ RemoveExtensionById()

void RemoveExtensionById ( Oid  extId)

Definition at line 1898 of file extension.c.

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