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/sysattr.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_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 "nodes/makefuncs.h"
#include "storage/fd.h"
#include "tcop/utility.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
#include "utils/snapmgr.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 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)
 
static 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 2774 of file extension.c.

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

Referenced by ExecAlterObjectSchemaStmt().

2775 {
2776  Oid extensionOid;
2777  Oid nspOid;
2778  Oid oldNspOid = InvalidOid;
2779  AclResult aclresult;
2780  Relation extRel;
2781  ScanKeyData key[2];
2782  SysScanDesc extScan;
2783  HeapTuple extTup;
2784  Form_pg_extension extForm;
2785  Relation depRel;
2786  SysScanDesc depScan;
2787  HeapTuple depTup;
2788  ObjectAddresses *objsMoved;
2789  ObjectAddress extAddr;
2790 
2791  extensionOid = get_extension_oid(extensionName, false);
2792 
2793  nspOid = LookupCreationNamespace(newschema);
2794 
2795  /*
2796  * Permission check: must own extension. Note that we don't bother to
2797  * check ownership of the individual member objects ...
2798  */
2799  if (!pg_extension_ownercheck(extensionOid, GetUserId()))
2801  extensionName);
2802 
2803  /* Permission check: must have creation rights in target namespace */
2804  aclresult = pg_namespace_aclcheck(nspOid, GetUserId(), ACL_CREATE);
2805  if (aclresult != ACLCHECK_OK)
2806  aclcheck_error(aclresult, OBJECT_SCHEMA, newschema);
2807 
2808  /*
2809  * If the schema is currently a member of the extension, disallow moving
2810  * the extension into the schema. That would create a dependency loop.
2811  */
2812  if (getExtensionOfObject(NamespaceRelationId, nspOid) == extensionOid)
2813  ereport(ERROR,
2814  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2815  errmsg("cannot move extension \"%s\" into schema \"%s\" "
2816  "because the extension contains the schema",
2817  extensionName, newschema)));
2818 
2819  /* Locate the pg_extension tuple */
2820  extRel = table_open(ExtensionRelationId, RowExclusiveLock);
2821 
2822  ScanKeyInit(&key[0],
2823  Anum_pg_extension_oid,
2824  BTEqualStrategyNumber, F_OIDEQ,
2825  ObjectIdGetDatum(extensionOid));
2826 
2827  extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
2828  NULL, 1, key);
2829 
2830  extTup = systable_getnext(extScan);
2831 
2832  if (!HeapTupleIsValid(extTup)) /* should not happen */
2833  elog(ERROR, "could not find tuple for extension %u",
2834  extensionOid);
2835 
2836  /* Copy tuple so we can modify it below */
2837  extTup = heap_copytuple(extTup);
2838  extForm = (Form_pg_extension) GETSTRUCT(extTup);
2839 
2840  systable_endscan(extScan);
2841 
2842  /*
2843  * If the extension is already in the target schema, just silently do
2844  * nothing.
2845  */
2846  if (extForm->extnamespace == nspOid)
2847  {
2848  table_close(extRel, RowExclusiveLock);
2849  return InvalidObjectAddress;
2850  }
2851 
2852  /* Check extension is supposed to be relocatable */
2853  if (!extForm->extrelocatable)
2854  ereport(ERROR,
2855  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2856  errmsg("extension \"%s\" does not support SET SCHEMA",
2857  NameStr(extForm->extname))));
2858 
2859  objsMoved = new_object_addresses();
2860 
2861  /*
2862  * Scan pg_depend to find objects that depend directly on the extension,
2863  * and alter each one's schema.
2864  */
2865  depRel = table_open(DependRelationId, AccessShareLock);
2866 
2867  ScanKeyInit(&key[0],
2868  Anum_pg_depend_refclassid,
2869  BTEqualStrategyNumber, F_OIDEQ,
2870  ObjectIdGetDatum(ExtensionRelationId));
2871  ScanKeyInit(&key[1],
2872  Anum_pg_depend_refobjid,
2873  BTEqualStrategyNumber, F_OIDEQ,
2874  ObjectIdGetDatum(extensionOid));
2875 
2876  depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
2877  NULL, 2, key);
2878 
2879  while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
2880  {
2881  Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
2882  ObjectAddress dep;
2883  Oid dep_oldNspOid;
2884 
2885  /*
2886  * Ignore non-membership dependencies. (Currently, the only other
2887  * case we could see here is a normal dependency from another
2888  * extension.)
2889  */
2890  if (pg_depend->deptype != DEPENDENCY_EXTENSION)
2891  continue;
2892 
2893  dep.classId = pg_depend->classid;
2894  dep.objectId = pg_depend->objid;
2895  dep.objectSubId = pg_depend->objsubid;
2896 
2897  if (dep.objectSubId != 0) /* should not happen */
2898  elog(ERROR, "extension should not have a sub-object dependency");
2899 
2900  /* Relocate the object */
2901  dep_oldNspOid = AlterObjectNamespace_oid(dep.classId,
2902  dep.objectId,
2903  nspOid,
2904  objsMoved);
2905 
2906  /*
2907  * Remember previous namespace of first object that has one
2908  */
2909  if (oldNspOid == InvalidOid && dep_oldNspOid != InvalidOid)
2910  oldNspOid = dep_oldNspOid;
2911 
2912  /*
2913  * If not all the objects had the same old namespace (ignoring any
2914  * that are not in namespaces), complain.
2915  */
2916  if (dep_oldNspOid != InvalidOid && dep_oldNspOid != oldNspOid)
2917  ereport(ERROR,
2918  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2919  errmsg("extension \"%s\" does not support SET SCHEMA",
2920  NameStr(extForm->extname)),
2921  errdetail("%s is not in the extension's schema \"%s\"",
2922  getObjectDescription(&dep),
2923  get_namespace_name(oldNspOid))));
2924  }
2925 
2926  /* report old schema, if caller wants it */
2927  if (oldschema)
2928  *oldschema = oldNspOid;
2929 
2930  systable_endscan(depScan);
2931 
2933 
2934  /* Now adjust pg_extension.extnamespace */
2935  extForm->extnamespace = nspOid;
2936 
2937  CatalogTupleUpdate(extRel, &extTup->t_self, extTup);
2938 
2939  table_close(extRel, RowExclusiveLock);
2940 
2941  /* update dependencies to point to the new schema */
2942  changeDependencyFor(ExtensionRelationId, extensionOid,
2943  NamespaceRelationId, oldNspOid, nspOid);
2944 
2945  InvokeObjectPostAlterHook(ExtensionRelationId, extensionOid, 0);
2946 
2947  ObjectAddressSet(extAddr, ExtensionRelationId, extensionOid);
2948 
2949  return extAddr;
2950 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:680
Oid getExtensionOfObject(Oid classId, Oid objectId)
Definition: pg_depend.c:659
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:529
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
Oid GetUserId(void)
Definition: miscinit.c:448
Oid LookupCreationNamespace(const char *nspname)
Definition: namespace.c:2936
#define DependReferenceIndexId
Definition: indexing.h:151
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:610
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2410
unsigned int Oid
Definition: postgres_ext.h:31
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4625
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:356
char * getObjectDescription(const ObjectAddress *object)
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:448
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:84
ItemPointerData t_self
Definition: htup.h:65
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3191
bool pg_extension_ownercheck(Oid ext_oid, Oid roleid)
Definition: aclchk.c:5183
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:957
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:71
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
#define ExtensionOidIndexId
Definition: indexing.h:323
FormData_pg_extension * Form_pg_extension
Definition: pg_extension.h:50
AclResult
Definition: acl.h:177
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:144
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
Oid get_extension_oid(const char *extname, bool missing_ok)
Definition: extension.c:140
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:824
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:346
Oid AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: alter.c:589
#define elog(elevel,...)
Definition: elog.h:214
#define NameStr(name)
Definition: c.h:615
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ ApplyExtensionUpdates()

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

Definition at line 3106 of file extension.c.

References BoolGetDatum, BTEqualStrategyNumber, CatalogTupleUpdate(), ObjectAddress::classId, CStringGetTextDatum, deleteDependencyRecordsForClass(), DEPENDENCY_NORMAL, elog, ERROR, execute_extension_script(), ExtensionOidIndexId, 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().

3113 {
3114  const char *oldVersionName = initialVersion;
3115  ListCell *lcv;
3116 
3117  foreach(lcv, updateVersions)
3118  {
3119  char *versionName = (char *) lfirst(lcv);
3120  ExtensionControlFile *control;
3121  char *schemaName;
3122  Oid schemaOid;
3123  List *requiredExtensions;
3124  List *requiredSchemas;
3125  Relation extRel;
3126  ScanKeyData key[1];
3127  SysScanDesc extScan;
3128  HeapTuple extTup;
3129  Form_pg_extension extForm;
3130  Datum values[Natts_pg_extension];
3131  bool nulls[Natts_pg_extension];
3132  bool repl[Natts_pg_extension];
3133  ObjectAddress myself;
3134  ListCell *lc;
3135 
3136  /*
3137  * Fetch parameters for specific version (pcontrol is not changed)
3138  */
3139  control = read_extension_aux_control_file(pcontrol, versionName);
3140 
3141  /* Find the pg_extension tuple */
3142  extRel = table_open(ExtensionRelationId, RowExclusiveLock);
3143 
3144  ScanKeyInit(&key[0],
3145  Anum_pg_extension_oid,
3146  BTEqualStrategyNumber, F_OIDEQ,
3147  ObjectIdGetDatum(extensionOid));
3148 
3149  extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
3150  NULL, 1, key);
3151 
3152  extTup = systable_getnext(extScan);
3153 
3154  if (!HeapTupleIsValid(extTup)) /* should not happen */
3155  elog(ERROR, "could not find tuple for extension %u",
3156  extensionOid);
3157 
3158  extForm = (Form_pg_extension) GETSTRUCT(extTup);
3159 
3160  /*
3161  * Determine the target schema (set by original install)
3162  */
3163  schemaOid = extForm->extnamespace;
3164  schemaName = get_namespace_name(schemaOid);
3165 
3166  /*
3167  * Modify extrelocatable and extversion in the pg_extension tuple
3168  */
3169  memset(values, 0, sizeof(values));
3170  memset(nulls, 0, sizeof(nulls));
3171  memset(repl, 0, sizeof(repl));
3172 
3173  values[Anum_pg_extension_extrelocatable - 1] =
3174  BoolGetDatum(control->relocatable);
3175  repl[Anum_pg_extension_extrelocatable - 1] = true;
3176  values[Anum_pg_extension_extversion - 1] =
3177  CStringGetTextDatum(versionName);
3178  repl[Anum_pg_extension_extversion - 1] = true;
3179 
3180  extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
3181  values, nulls, repl);
3182 
3183  CatalogTupleUpdate(extRel, &extTup->t_self, extTup);
3184 
3185  systable_endscan(extScan);
3186 
3187  table_close(extRel, RowExclusiveLock);
3188 
3189  /*
3190  * Look up the prerequisite extensions for this version, install them
3191  * if necessary, and build lists of their OIDs and the OIDs of their
3192  * target schemas.
3193  */
3194  requiredExtensions = NIL;
3195  requiredSchemas = NIL;
3196  foreach(lc, control->requires)
3197  {
3198  char *curreq = (char *) lfirst(lc);
3199  Oid reqext;
3200  Oid reqschema;
3201 
3202  reqext = get_required_extension(curreq,
3203  control->name,
3204  origSchemaName,
3205  cascade,
3206  NIL,
3207  is_create);
3208  reqschema = get_extension_schema(reqext);
3209  requiredExtensions = lappend_oid(requiredExtensions, reqext);
3210  requiredSchemas = lappend_oid(requiredSchemas, reqschema);
3211  }
3212 
3213  /*
3214  * Remove and recreate dependencies on prerequisite extensions
3215  */
3216  deleteDependencyRecordsForClass(ExtensionRelationId, extensionOid,
3217  ExtensionRelationId,
3219 
3220  myself.classId = ExtensionRelationId;
3221  myself.objectId = extensionOid;
3222  myself.objectSubId = 0;
3223 
3224  foreach(lc, requiredExtensions)
3225  {
3226  Oid reqext = lfirst_oid(lc);
3227  ObjectAddress otherext;
3228 
3229  otherext.classId = ExtensionRelationId;
3230  otherext.objectId = reqext;
3231  otherext.objectSubId = 0;
3232 
3233  recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
3234  }
3235 
3236  InvokeObjectPostAlterHook(ExtensionRelationId, extensionOid, 0);
3237 
3238  /*
3239  * Finally, execute the update script file
3240  */
3241  execute_extension_script(extensionOid, control,
3242  oldVersionName, versionName,
3243  requiredSchemas,
3244  schemaName, schemaOid);
3245 
3246  /*
3247  * Update prior-version name and loop around. Since
3248  * execute_sql_string did a final CommandCounterIncrement, we can
3249  * update the pg_extension row again.
3250  */
3251  oldVersionName = versionName;
3252  }
3253 }
#define NIL
Definition: pg_list.h:65
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:529
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
static Oid get_extension_schema(Oid ext_oid)
Definition: extension.c:224
static Oid get_required_extension(char *reqExtensionName, char *extensionName, char *origSchemaName, bool cascade, List *parents, bool is_create)
Definition: extension.c:1596
#define RelationGetDescr(relation)
Definition: rel.h:482
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:43
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:357
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:356
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:448
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:835
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3191
static ExtensionControlFile * read_extension_aux_control_file(const ExtensionControlFile *pcontrol, const char *version)
Definition: extension.c:645
#define RowExclusiveLock
Definition: lockdefs.h:38
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
#define ExtensionOidIndexId
Definition: indexing.h:323
FormData_pg_extension * Form_pg_extension
Definition: pg_extension.h:50
uintptr_t Datum
Definition: postgres.h:367
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition: pg_depend.c:240
#define BoolGetDatum(X)
Definition: postgres.h:402
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define lfirst(lc)
Definition: pg_list.h:190
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
static Datum values[MAXATTR]
Definition: bootstrap.c:167
#define elog(elevel,...)
Definition: elog.h:214
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define CStringGetTextDatum(s)
Definition: builtins.h:87
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
Definition: pg_list.h:50
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define lfirst_oid(lc)
Definition: pg_list.h:192

◆ check_valid_extension_name()

static void check_valid_extension_name ( const char *  extensionname)
static

Definition at line 261 of file extension.c.

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

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

262 {
263  int namelen = strlen(extensionname);
264 
265  /*
266  * Disallow empty names (the parser rejects empty identifiers anyway, but
267  * let's check).
268  */
269  if (namelen == 0)
270  ereport(ERROR,
271  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
272  errmsg("invalid extension name: \"%s\"", extensionname),
273  errdetail("Extension names must not be empty.")));
274 
275  /*
276  * No double dashes, since that would make script filenames ambiguous.
277  */
278  if (strstr(extensionname, "--"))
279  ereport(ERROR,
280  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
281  errmsg("invalid extension name: \"%s\"", extensionname),
282  errdetail("Extension names must not contain \"--\".")));
283 
284  /*
285  * No leading or trailing dash either. (We could probably allow this, but
286  * it would require much care in filename parsing and would make filenames
287  * visually if not formally ambiguous. Since there's no real-world use
288  * case, let's just forbid it.)
289  */
290  if (extensionname[0] == '-' || extensionname[namelen - 1] == '-')
291  ereport(ERROR,
292  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
293  errmsg("invalid extension name: \"%s\"", extensionname),
294  errdetail("Extension names must not begin or end with \"-\".")));
295 
296  /*
297  * No directory separators either (this is sufficient to prevent ".."
298  * style attacks).
299  */
300  if (first_dir_separator(extensionname) != NULL)
301  ereport(ERROR,
302  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
303  errmsg("invalid extension name: \"%s\"", extensionname),
304  errdetail("Extension names must not contain directory separator characters.")));
305 }
int errcode(int sqlerrcode)
Definition: elog.c:610
#define ERROR
Definition: elog.h:43
int errdetail(const char *fmt,...)
Definition: elog.c:957
char * first_dir_separator(const char *filename)
Definition: path.c:103
#define ereport(elevel,...)
Definition: elog.h:144
int errmsg(const char *fmt,...)
Definition: elog.c:824

◆ check_valid_version_name()

static void check_valid_version_name ( const char *  versionname)
static

Definition at line 308 of file extension.c.

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

Referenced by CreateExtensionInternal(), and ExecAlterExtensionStmt().

309 {
310  int namelen = strlen(versionname);
311 
312  /*
313  * Disallow empty names (we could possibly allow this, but there seems
314  * little point).
315  */
316  if (namelen == 0)
317  ereport(ERROR,
318  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
319  errmsg("invalid extension version name: \"%s\"", versionname),
320  errdetail("Version names must not be empty.")));
321 
322  /*
323  * No double dashes, since that would make script filenames ambiguous.
324  */
325  if (strstr(versionname, "--"))
326  ereport(ERROR,
327  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
328  errmsg("invalid extension version name: \"%s\"", versionname),
329  errdetail("Version names must not contain \"--\".")));
330 
331  /*
332  * No leading or trailing dash either.
333  */
334  if (versionname[0] == '-' || versionname[namelen - 1] == '-')
335  ereport(ERROR,
336  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
337  errmsg("invalid extension version name: \"%s\"", versionname),
338  errdetail("Version names must not begin or end with \"-\".")));
339 
340  /*
341  * No directory separators either (this is sufficient to prevent ".."
342  * style attacks).
343  */
344  if (first_dir_separator(versionname) != NULL)
345  ereport(ERROR,
346  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
347  errmsg("invalid extension version name: \"%s\"", versionname),
348  errdetail("Version names must not contain directory separator characters.")));
349 }
int errcode(int sqlerrcode)
Definition: elog.c:610
#define ERROR
Definition: elog.h:43
int errdetail(const char *fmt,...)
Definition: elog.c:957
char * first_dir_separator(const char *filename)
Definition: path.c:103
#define ereport(elevel,...)
Definition: elog.h:144
int errmsg(const char *fmt,...)
Definition: elog.c:824

◆ convert_requires_to_datum()

static Datum convert_requires_to_datum ( List requires)
static

Definition at line 2277 of file extension.c.

References construct_array(), CStringGetDatum, DirectFunctionCall1, lfirst, list_length(), NAMEDATALEN, namein(), palloc(), and PointerGetDatum.

Referenced by get_available_versions_for_extension().

2278 {
2279  Datum *datums;
2280  int ndatums;
2281  ArrayType *a;
2282  ListCell *lc;
2283 
2284  ndatums = list_length(requires);
2285  datums = (Datum *) palloc(ndatums * sizeof(Datum));
2286  ndatums = 0;
2287  foreach(lc, requires)
2288  {
2289  char *curreq = (char *) lfirst(lc);
2290 
2291  datums[ndatums++] =
2293  }
2294  a = construct_array(datums, ndatums,
2295  NAMEOID,
2296  NAMEDATALEN, false, TYPALIGN_CHAR);
2297  return PointerGetDatum(a);
2298 }
Datum namein(PG_FUNCTION_ARGS)
Definition: name.c:48
#define PointerGetDatum(X)
Definition: postgres.h:556
ArrayType * construct_array(Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3292
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:624
#define NAMEDATALEN
#define CStringGetDatum(X)
Definition: postgres.h:578
uintptr_t Datum
Definition: postgres.h:367
#define lfirst(lc)
Definition: pg_list.h:190
static int list_length(const List *l)
Definition: pg_list.h:169
void * palloc(Size size)
Definition: mcxt.c:949

◆ CreateExtension()

ObjectAddress CreateExtension ( ParseState pstate,
CreateExtensionStmt stmt 
)

Definition at line 1667 of file extension.c.

References check_valid_extension_name(), CreateExtensionInternal(), creating_extension, defGetBoolean(), defGetString(), DefElem::defname, elog, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, CreateExtensionStmt::extname, get_extension_oid(), CreateExtensionStmt::if_not_exists, InvalidObjectAddress, InvalidOid, lfirst, DefElem::location, NIL, NOTICE, CreateExtensionStmt::options, and parser_errposition().

Referenced by ProcessUtilitySlow().

1668 {
1669  DefElem *d_schema = NULL;
1670  DefElem *d_new_version = NULL;
1671  DefElem *d_cascade = NULL;
1672  char *schemaName = NULL;
1673  char *versionName = NULL;
1674  bool cascade = false;
1675  ListCell *lc;
1676 
1677  /* Check extension name validity before any filesystem access */
1679 
1680  /*
1681  * Check for duplicate extension name. The unique index on
1682  * pg_extension.extname would catch this anyway, and serves as a backstop
1683  * in case of race conditions; but this is a friendlier error message, and
1684  * besides we need a check to support IF NOT EXISTS.
1685  */
1686  if (get_extension_oid(stmt->extname, true) != InvalidOid)
1687  {
1688  if (stmt->if_not_exists)
1689  {
1690  ereport(NOTICE,
1692  errmsg("extension \"%s\" already exists, skipping",
1693  stmt->extname)));
1694  return InvalidObjectAddress;
1695  }
1696  else
1697  ereport(ERROR,
1699  errmsg("extension \"%s\" already exists",
1700  stmt->extname)));
1701  }
1702 
1703  /*
1704  * We use global variables to track the extension being created, so we can
1705  * create only one extension at the same time.
1706  */
1707  if (creating_extension)
1708  ereport(ERROR,
1709  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1710  errmsg("nested CREATE EXTENSION is not supported")));
1711 
1712  /* Deconstruct the statement option list */
1713  foreach(lc, stmt->options)
1714  {
1715  DefElem *defel = (DefElem *) lfirst(lc);
1716 
1717  if (strcmp(defel->defname, "schema") == 0)
1718  {
1719  if (d_schema)
1720  ereport(ERROR,
1721  (errcode(ERRCODE_SYNTAX_ERROR),
1722  errmsg("conflicting or redundant options"),
1723  parser_errposition(pstate, defel->location)));
1724  d_schema = defel;
1725  schemaName = defGetString(d_schema);
1726  }
1727  else if (strcmp(defel->defname, "new_version") == 0)
1728  {
1729  if (d_new_version)
1730  ereport(ERROR,
1731  (errcode(ERRCODE_SYNTAX_ERROR),
1732  errmsg("conflicting or redundant options"),
1733  parser_errposition(pstate, defel->location)));
1734  d_new_version = defel;
1735  versionName = defGetString(d_new_version);
1736  }
1737  else if (strcmp(defel->defname, "cascade") == 0)
1738  {
1739  if (d_cascade)
1740  ereport(ERROR,
1741  (errcode(ERRCODE_SYNTAX_ERROR),
1742  errmsg("conflicting or redundant options"),
1743  parser_errposition(pstate, defel->location)));
1744  d_cascade = defel;
1745  cascade = defGetBoolean(d_cascade);
1746  }
1747  else
1748  elog(ERROR, "unrecognized option: %s", defel->defname);
1749  }
1750 
1751  /* Call CreateExtensionInternal to do the real work. */
1752  return CreateExtensionInternal(stmt->extname,
1753  schemaName,
1754  versionName,
1755  cascade,
1756  NIL,
1757  true);
1758 }
#define NIL
Definition: pg_list.h:65
static void check_valid_extension_name(const char *extensionname)
Definition: extension.c:261
int errcode(int sqlerrcode)
Definition: elog.c:610
bool defGetBoolean(DefElem *def)
Definition: define.c:111
#define ERROR
Definition: elog.h:43
char * defGetString(DefElem *def)
Definition: define.c:49
int location
Definition: parsenodes.h:735
static ObjectAddress CreateExtensionInternal(char *extensionName, char *schemaName, const char *versionName, bool cascade, List *parents, bool is_create)
Definition: extension.c:1357
#define InvalidOid
Definition: postgres_ext.h:36
bool creating_extension
Definition: extension.c:71
#define ereport(elevel,...)
Definition: elog.h:144
#define NOTICE
Definition: elog.h:37
#define lfirst(lc)
Definition: pg_list.h:190
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:110
Oid get_extension_oid(const char *extname, bool missing_ok)
Definition: extension.c:140
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
char * defname
Definition: parsenodes.h:732
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:31

◆ CreateExtensionInternal()

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

Definition at line 1357 of file extension.c.

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().

1363 {
1364  char *origSchemaName = schemaName;
1365  Oid schemaOid = InvalidOid;
1366  Oid extowner = GetUserId();
1367  ExtensionControlFile *pcontrol;
1368  ExtensionControlFile *control;
1369  char *filename;
1370  struct stat fst;
1371  List *updateVersions;
1372  List *requiredExtensions;
1373  List *requiredSchemas;
1374  Oid extensionOid;
1375  ObjectAddress address;
1376  ListCell *lc;
1377 
1378  /*
1379  * Read the primary control file. Note we assume that it does not contain
1380  * any non-ASCII data, so there is no need to worry about encoding at this
1381  * point.
1382  */
1383  pcontrol = read_extension_control_file(extensionName);
1384 
1385  /*
1386  * Determine the version to install
1387  */
1388  if (versionName == NULL)
1389  {
1390  if (pcontrol->default_version)
1391  versionName = pcontrol->default_version;
1392  else
1393  ereport(ERROR,
1394  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1395  errmsg("version to install must be specified")));
1396  }
1397  check_valid_version_name(versionName);
1398 
1399  /*
1400  * Figure out which script(s) we need to run to install the desired
1401  * version of the extension. If we do not have a script that directly
1402  * does what is needed, we try to find a sequence of update scripts that
1403  * will get us there.
1404  */
1405  filename = get_extension_script_filename(pcontrol, NULL, versionName);
1406  if (stat(filename, &fst) == 0)
1407  {
1408  /* Easy, no extra scripts */
1409  updateVersions = NIL;
1410  }
1411  else
1412  {
1413  /* Look for best way to install this version */
1414  List *evi_list;
1415  ExtensionVersionInfo *evi_start;
1416  ExtensionVersionInfo *evi_target;
1417 
1418  /* Extract the version update graph from the script directory */
1419  evi_list = get_ext_ver_list(pcontrol);
1420 
1421  /* Identify the target version */
1422  evi_target = get_ext_ver_info(versionName, &evi_list);
1423 
1424  /* Identify best path to reach target */
1425  evi_start = find_install_path(evi_list, evi_target,
1426  &updateVersions);
1427 
1428  /* Fail if no path ... */
1429  if (evi_start == NULL)
1430  ereport(ERROR,
1431  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1432  errmsg("extension \"%s\" has no installation script nor update path for version \"%s\"",
1433  pcontrol->name, versionName)));
1434 
1435  /* Otherwise, install best starting point and then upgrade */
1436  versionName = evi_start->name;
1437  }
1438 
1439  /*
1440  * Fetch control parameters for installation target version
1441  */
1442  control = read_extension_aux_control_file(pcontrol, versionName);
1443 
1444  /*
1445  * Determine the target schema to install the extension into
1446  */
1447  if (schemaName)
1448  {
1449  /* If the user is giving us the schema name, it must exist already. */
1450  schemaOid = get_namespace_oid(schemaName, false);
1451  }
1452 
1453  if (control->schema != NULL)
1454  {
1455  /*
1456  * The extension is not relocatable and the author gave us a schema
1457  * for it.
1458  *
1459  * Unless CASCADE parameter was given, it's an error to give a schema
1460  * different from control->schema if control->schema is specified.
1461  */
1462  if (schemaName && strcmp(control->schema, schemaName) != 0 &&
1463  !cascade)
1464  ereport(ERROR,
1465  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1466  errmsg("extension \"%s\" must be installed in schema \"%s\"",
1467  control->name,
1468  control->schema)));
1469 
1470  /* Always use the schema from control file for current extension. */
1471  schemaName = control->schema;
1472 
1473  /* Find or create the schema in case it does not exist. */
1474  schemaOid = get_namespace_oid(schemaName, true);
1475 
1476  if (!OidIsValid(schemaOid))
1477  {
1479 
1480  csstmt->schemaname = schemaName;
1481  csstmt->authrole = NULL; /* will be created by current user */
1482  csstmt->schemaElts = NIL;
1483  csstmt->if_not_exists = false;
1484  CreateSchemaCommand(csstmt, "(generated CREATE SCHEMA command)",
1485  -1, -1);
1486 
1487  /*
1488  * CreateSchemaCommand includes CommandCounterIncrement, so new
1489  * schema is now visible.
1490  */
1491  schemaOid = get_namespace_oid(schemaName, false);
1492  }
1493  }
1494  else if (!OidIsValid(schemaOid))
1495  {
1496  /*
1497  * Neither user nor author of the extension specified schema; use the
1498  * current default creation namespace, which is the first explicit
1499  * entry in the search_path.
1500  */
1501  List *search_path = fetch_search_path(false);
1502 
1503  if (search_path == NIL) /* nothing valid in search_path? */
1504  ereport(ERROR,
1505  (errcode(ERRCODE_UNDEFINED_SCHEMA),
1506  errmsg("no schema has been selected to create in")));
1507  schemaOid = linitial_oid(search_path);
1508  schemaName = get_namespace_name(schemaOid);
1509  if (schemaName == NULL) /* recently-deleted namespace? */
1510  ereport(ERROR,
1511  (errcode(ERRCODE_UNDEFINED_SCHEMA),
1512  errmsg("no schema has been selected to create in")));
1513 
1514  list_free(search_path);
1515  }
1516 
1517  /*
1518  * Make note if a temporary namespace has been accessed in this
1519  * transaction.
1520  */
1521  if (isTempNamespace(schemaOid))
1523 
1524  /*
1525  * We don't check creation rights on the target namespace here. If the
1526  * extension script actually creates any objects there, it will fail if
1527  * the user doesn't have such permissions. But there are cases such as
1528  * procedural languages where it's convenient to set schema = pg_catalog
1529  * yet we don't want to restrict the command to users with ACL_CREATE for
1530  * pg_catalog.
1531  */
1532 
1533  /*
1534  * Look up the prerequisite extensions, install them if necessary, and
1535  * build lists of their OIDs and the OIDs of their target schemas.
1536  */
1537  requiredExtensions = NIL;
1538  requiredSchemas = NIL;
1539  foreach(lc, control->requires)
1540  {
1541  char *curreq = (char *) lfirst(lc);
1542  Oid reqext;
1543  Oid reqschema;
1544 
1545  reqext = get_required_extension(curreq,
1546  extensionName,
1547  origSchemaName,
1548  cascade,
1549  parents,
1550  is_create);
1551  reqschema = get_extension_schema(reqext);
1552  requiredExtensions = lappend_oid(requiredExtensions, reqext);
1553  requiredSchemas = lappend_oid(requiredSchemas, reqschema);
1554  }
1555 
1556  /*
1557  * Insert new tuple into pg_extension, and create dependency entries.
1558  */
1559  address = InsertExtensionTuple(control->name, extowner,
1560  schemaOid, control->relocatable,
1561  versionName,
1562  PointerGetDatum(NULL),
1563  PointerGetDatum(NULL),
1564  requiredExtensions);
1565  extensionOid = address.objectId;
1566 
1567  /*
1568  * Apply any control-file comment on extension
1569  */
1570  if (control->comment != NULL)
1571  CreateComments(extensionOid, ExtensionRelationId, 0, control->comment);
1572 
1573  /*
1574  * Execute the installation script file
1575  */
1576  execute_extension_script(extensionOid, control,
1577  NULL, versionName,
1578  requiredSchemas,
1579  schemaName, schemaOid);
1580 
1581  /*
1582  * If additional update scripts have to be executed, apply the updates as
1583  * though a series of ALTER EXTENSION UPDATE commands were given
1584  */
1585  ApplyExtensionUpdates(extensionOid, pcontrol,
1586  versionName, updateVersions,
1587  origSchemaName, cascade, is_create);
1588 
1589  return address;
1590 }
#define NIL
Definition: pg_list.h:65
void CreateComments(Oid oid, Oid classoid, int32 subid, const char *comment)
Definition: comment.c:142
Oid get_namespace_oid(const char *nspname, bool missing_ok)
Definition: namespace.c:3043
static Oid get_extension_schema(Oid ext_oid)
Definition: extension.c:224
static ExtensionVersionInfo * get_ext_ver_info(const char *versionname, List **evi_list)
Definition: extension.c:1042
static char * get_extension_script_filename(ExtensionControlFile *control, const char *from_version, const char *version)
Definition: extension.c:439
static ExtensionControlFile * read_extension_control_file(const char *extname)
Definition: extension.c:616
static Oid get_required_extension(char *reqExtensionName, char *extensionName, char *origSchemaName, bool cascade, List *parents, bool is_create)
Definition: extension.c:1596
Oid GetUserId(void)
Definition: miscinit.c:448
#define PointerGetDatum(X)
Definition: postgres.h:556
static List * get_ext_ver_list(ExtensionControlFile *control)
Definition: extension.c:1103
static void ApplyExtensionUpdates(Oid extensionOid, ExtensionControlFile *pcontrol, const char *initialVersion, List *updateVersions, char *origSchemaName, bool cascade, bool is_create)
Definition: extension.c:3106
int errcode(int sqlerrcode)
Definition: elog.c:610
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:357
#define OidIsValid(objectId)
Definition: c.h:644
RoleSpec * authrole
Definition: parsenodes.h:1759
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:835
#define ERROR
Definition: elog.h:43
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3191
static ExtensionControlFile * read_extension_aux_control_file(const ExtensionControlFile *pcontrol, const char *version)
Definition: extension.c:645
bool isTempNamespace(Oid namespaceId)
Definition: namespace.c:3157
Oid CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString, int stmt_location, int stmt_len)
Definition: schemacmds.c:50
static ExtensionVersionInfo * find_install_path(List *evi_list, ExtensionVersionInfo *evi_target, List **best_path)
Definition: extension.c:1302
int MyXactFlags
Definition: xact.c:119
#define XACT_FLAGS_ACCESSEDTEMPNAMESPACE
Definition: xact.h:97
#define stat(a, b)
Definition: win32_port.h:255
char * default_version
Definition: extension.c:81
static void check_valid_version_name(const char *versionname)
Definition: extension.c:308
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:144
#define makeNode(_type_)
Definition: nodes.h:577
#define lfirst(lc)
Definition: pg_list.h:190
ObjectAddress InsertExtensionTuple(const char *extName, Oid extOwner, Oid schemaOid, bool relocatable, const char *extVersion, Datum extConfig, Datum extCondition, List *requiredExtensions)
Definition: extension.c:1774
#define linitial_oid(l)
Definition: pg_list.h:197
static char * filename
Definition: pg_dumpall.c:90
int errmsg(const char *fmt,...)
Definition: elog.c:824
void list_free(List *list)
Definition: list.c:1376
Definition: pg_list.h:50
List * fetch_search_path(bool includeImplicit)
Definition: namespace.c:4383

◆ ExecAlterExtensionContentsStmt()

ObjectAddress ExecAlterExtensionContentsStmt ( AlterExtensionContentsStmt stmt,
ObjectAddress objAddr 
)

Definition at line 3264 of file extension.c.

References aclcheck_error(), ACLCHECK_NOT_OWNER, AlterExtensionContentsStmt::action, Assert, check_object_ownership(), ObjectAddress::classId, deleteDependencyRecordsForClass(), DEPENDENCY_EXTENSION, elog, ereport, errcode(), errmsg(), ERROR, extension_config_remove(), AlterExtensionContentsStmt::extname, get_extension_name(), get_extension_oid(), get_extension_schema(), get_namespace_name(), get_object_address(), getExtensionOfObject(), getObjectDescription(), GetUserId(), InvokeObjectPostAlterHook, NoLock, AlterExtensionContentsStmt::object, OBJECT_DATABASE, OBJECT_EXTENSION, OBJECT_INDEX, OBJECT_PUBLICATION, OBJECT_ROLE, OBJECT_STATISTIC_EXT, OBJECT_SUBSCRIPTION, OBJECT_TABLESPACE, ObjectAddress::objectId, ObjectAddress::objectSubId, AlterExtensionContentsStmt::objtype, OidIsValid, pg_extension_ownercheck(), recordDependencyOn(), recordExtObjInitPriv(), relation_close(), removeExtObjInitPriv(), and ShareUpdateExclusiveLock.

Referenced by ProcessUtilitySlow().

3266 {
3267  ObjectAddress extension;
3268  ObjectAddress object;
3269  Relation relation;
3270  Oid oldExtension;
3271 
3272  switch (stmt->objtype)
3273  {
3274  case OBJECT_DATABASE:
3275  case OBJECT_EXTENSION:
3276  case OBJECT_INDEX:
3277  case OBJECT_PUBLICATION:
3278  case OBJECT_ROLE:
3279  case OBJECT_STATISTIC_EXT:
3280  case OBJECT_SUBSCRIPTION:
3281  case OBJECT_TABLESPACE:
3282  ereport(ERROR,
3283  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3284  errmsg("cannot add an object of this type to an extension")));
3285  break;
3286  default:
3287  /* OK */
3288  break;
3289  }
3290 
3291  extension.classId = ExtensionRelationId;
3292  extension.objectId = get_extension_oid(stmt->extname, false);
3293  extension.objectSubId = 0;
3294 
3295  /* Permission check: must own extension */
3296  if (!pg_extension_ownercheck(extension.objectId, GetUserId()))
3298  stmt->extname);
3299 
3300  /*
3301  * Translate the parser representation that identifies the object into an
3302  * ObjectAddress. get_object_address() will throw an error if the object
3303  * does not exist, and will also acquire a lock on the object to guard
3304  * against concurrent DROP and ALTER EXTENSION ADD/DROP operations.
3305  */
3306  object = get_object_address(stmt->objtype, stmt->object,
3307  &relation, ShareUpdateExclusiveLock, false);
3308 
3309  Assert(object.objectSubId == 0);
3310  if (objAddr)
3311  *objAddr = object;
3312 
3313  /* Permission check: must own target object, too */
3314  check_object_ownership(GetUserId(), stmt->objtype, object,
3315  stmt->object, relation);
3316 
3317  /*
3318  * Check existing extension membership.
3319  */
3320  oldExtension = getExtensionOfObject(object.classId, object.objectId);
3321 
3322  if (stmt->action > 0)
3323  {
3324  /*
3325  * ADD, so complain if object is already attached to some extension.
3326  */
3327  if (OidIsValid(oldExtension))
3328  ereport(ERROR,
3329  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3330  errmsg("%s is already a member of extension \"%s\"",
3331  getObjectDescription(&object),
3332  get_extension_name(oldExtension))));
3333 
3334  /*
3335  * Prevent a schema from being added to an extension if the schema
3336  * contains the extension. That would create a dependency loop.
3337  */
3338  if (object.classId == NamespaceRelationId &&
3339  object.objectId == get_extension_schema(extension.objectId))
3340  ereport(ERROR,
3341  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3342  errmsg("cannot add schema \"%s\" to extension \"%s\" "
3343  "because the schema contains the extension",
3344  get_namespace_name(object.objectId),
3345  stmt->extname)));
3346 
3347  /*
3348  * OK, add the dependency.
3349  */
3350  recordDependencyOn(&object, &extension, DEPENDENCY_EXTENSION);
3351 
3352  /*
3353  * Also record the initial ACL on the object, if any.
3354  *
3355  * Note that this will handle the object's ACLs, as well as any ACLs
3356  * on object subIds. (In other words, when the object is a table,
3357  * this will record the table's ACL and the ACLs for the columns on
3358  * the table, if any).
3359  */
3360  recordExtObjInitPriv(object.objectId, object.classId);
3361  }
3362  else
3363  {
3364  /*
3365  * DROP, so complain if it's not a member.
3366  */
3367  if (oldExtension != extension.objectId)
3368  ereport(ERROR,
3369  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3370  errmsg("%s is not a member of extension \"%s\"",
3371  getObjectDescription(&object),
3372  stmt->extname)));
3373 
3374  /*
3375  * OK, drop the dependency.
3376  */
3377  if (deleteDependencyRecordsForClass(object.classId, object.objectId,
3378  ExtensionRelationId,
3379  DEPENDENCY_EXTENSION) != 1)
3380  elog(ERROR, "unexpected number of extension dependency records");
3381 
3382  /*
3383  * If it's a relation, it might have an entry in the extension's
3384  * extconfig array, which we must remove.
3385  */
3386  if (object.classId == RelationRelationId)
3387  extension_config_remove(extension.objectId, object.objectId);
3388 
3389  /*
3390  * Remove all the initial ACLs, if any.
3391  *
3392  * Note that this will remove the object's ACLs, as well as any ACLs
3393  * on object subIds. (In other words, when the object is a table,
3394  * this will remove the table's ACL and the ACLs for the columns on
3395  * the table, if any).
3396  */
3397  removeExtObjInitPriv(object.objectId, object.classId);
3398  }
3399 
3400  InvokeObjectPostAlterHook(ExtensionRelationId, extension.objectId, 0);
3401 
3402  /*
3403  * If get_object_address() opened the relation for us, we close it to keep
3404  * the reference count correct - but we retain any locks acquired by
3405  * get_object_address() until commit time, to guard against concurrent
3406  * activity.
3407  */
3408  if (relation != NULL)
3409  relation_close(relation, NoLock);
3410 
3411  return extension;
3412 }
void recordExtObjInitPriv(Oid objoid, Oid classoid)
Definition: aclchk.c:5496
Oid getExtensionOfObject(Oid classId, Oid objectId)
Definition: pg_depend.c:659
static Oid get_extension_schema(Oid ext_oid)
Definition: extension.c:224
Oid GetUserId(void)
Definition: miscinit.c:448
char * get_extension_name(Oid ext_oid)
Definition: extension.c:185
int errcode(int sqlerrcode)
Definition: elog.c:610
static void extension_config_remove(Oid extensionoid, Oid tableoid)
Definition: extension.c:2605
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:43
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:644
char * getObjectDescription(const ObjectAddress *object)
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
#define ERROR
Definition: elog.h:43
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3191
#define NoLock
Definition: lockdefs.h:34
bool pg_extension_ownercheck(Oid ext_oid, Oid roleid)
Definition: aclchk.c:5183
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition: pg_depend.c:240
#define ereport(elevel,...)
Definition: elog.h:144
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define Assert(condition)
Definition: c.h:738
ObjectAddress get_object_address(ObjectType objtype, Node *object, Relation *relp, LOCKMODE lockmode, bool missing_ok)
void check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address, Node *object, Relation relation)
Oid get_extension_oid(const char *extname, bool missing_ok)
Definition: extension.c:140
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
void removeExtObjInitPriv(Oid objoid, Oid classoid)
Definition: aclchk.c:5794

◆ ExecAlterExtensionStmt()

ObjectAddress ExecAlterExtensionStmt ( ParseState pstate,
AlterExtensionStmt stmt 
)

Definition at line 2956 of file extension.c.

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, ExtensionNameIndexId, AlterExtensionStmt::extname, GETSTRUCT, GetUserId(), heap_getattr, HeapTupleIsValid, identify_update_path(), InvalidObjectAddress, sort-test::key, lfirst, DefElem::location, NOTICE, OBJECT_EXTENSION, ObjectAddressSet, AlterExtensionStmt::options, parser_errposition(), pg_extension_ownercheck(), read_extension_control_file(), RelationGetDescr, ScanKeyInit(), strVal, systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), and text_to_cstring().

Referenced by ProcessUtilitySlow().

2957 {
2958  DefElem *d_new_version = NULL;
2959  char *versionName;
2960  char *oldVersionName;
2961  ExtensionControlFile *control;
2962  Oid extensionOid;
2963  Relation extRel;
2964  ScanKeyData key[1];
2965  SysScanDesc extScan;
2966  HeapTuple extTup;
2967  List *updateVersions;
2968  Datum datum;
2969  bool isnull;
2970  ListCell *lc;
2971  ObjectAddress address;
2972 
2973  /*
2974  * We use global variables to track the extension being created, so we can
2975  * create/update only one extension at the same time.
2976  */
2977  if (creating_extension)
2978  ereport(ERROR,
2979  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2980  errmsg("nested ALTER EXTENSION is not supported")));
2981 
2982  /*
2983  * Look up the extension --- it must already exist in pg_extension
2984  */
2985  extRel = table_open(ExtensionRelationId, AccessShareLock);
2986 
2987  ScanKeyInit(&key[0],
2988  Anum_pg_extension_extname,
2989  BTEqualStrategyNumber, F_NAMEEQ,
2990  CStringGetDatum(stmt->extname));
2991 
2992  extScan = systable_beginscan(extRel, ExtensionNameIndexId, true,
2993  NULL, 1, key);
2994 
2995  extTup = systable_getnext(extScan);
2996 
2997  if (!HeapTupleIsValid(extTup))
2998  ereport(ERROR,
2999  (errcode(ERRCODE_UNDEFINED_OBJECT),
3000  errmsg("extension \"%s\" does not exist",
3001  stmt->extname)));
3002 
3003  extensionOid = ((Form_pg_extension) GETSTRUCT(extTup))->oid;
3004 
3005  /*
3006  * Determine the existing version we are updating from
3007  */
3008  datum = heap_getattr(extTup, Anum_pg_extension_extversion,
3009  RelationGetDescr(extRel), &isnull);
3010  if (isnull)
3011  elog(ERROR, "extversion is null");
3012  oldVersionName = text_to_cstring(DatumGetTextPP(datum));
3013 
3014  systable_endscan(extScan);
3015 
3016  table_close(extRel, AccessShareLock);
3017 
3018  /* Permission check: must own extension */
3019  if (!pg_extension_ownercheck(extensionOid, GetUserId()))
3021  stmt->extname);
3022 
3023  /*
3024  * Read the primary control file. Note we assume that it does not contain
3025  * any non-ASCII data, so there is no need to worry about encoding at this
3026  * point.
3027  */
3028  control = read_extension_control_file(stmt->extname);
3029 
3030  /*
3031  * Read the statement option list
3032  */
3033  foreach(lc, stmt->options)
3034  {
3035  DefElem *defel = (DefElem *) lfirst(lc);
3036 
3037  if (strcmp(defel->defname, "new_version") == 0)
3038  {
3039  if (d_new_version)
3040  ereport(ERROR,
3041  (errcode(ERRCODE_SYNTAX_ERROR),
3042  errmsg("conflicting or redundant options"),
3043  parser_errposition(pstate, defel->location)));
3044  d_new_version = defel;
3045  }
3046  else
3047  elog(ERROR, "unrecognized option: %s", defel->defname);
3048  }
3049 
3050  /*
3051  * Determine the version to update to
3052  */
3053  if (d_new_version && d_new_version->arg)
3054  versionName = strVal(d_new_version->arg);
3055  else if (control->default_version)
3056  versionName = control->default_version;
3057  else
3058  {
3059  ereport(ERROR,
3060  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3061  errmsg("version to install must be specified")));
3062  versionName = NULL; /* keep compiler quiet */
3063  }
3064  check_valid_version_name(versionName);
3065 
3066  /*
3067  * If we're already at that version, just say so
3068  */
3069  if (strcmp(oldVersionName, versionName) == 0)
3070  {
3071  ereport(NOTICE,
3072  (errmsg("version \"%s\" of extension \"%s\" is already installed",
3073  versionName, stmt->extname)));
3074  return InvalidObjectAddress;
3075  }
3076 
3077  /*
3078  * Identify the series of update script files we need to execute
3079  */
3080  updateVersions = identify_update_path(control,
3081  oldVersionName,
3082  versionName);
3083 
3084  /*
3085  * Update the pg_extension row and execute the update scripts, one at a
3086  * time
3087  */
3088  ApplyExtensionUpdates(extensionOid, control,
3089  oldVersionName, updateVersions,
3090  NULL, false, false);
3091 
3092  ObjectAddressSet(address, ExtensionRelationId, extensionOid);
3093 
3094  return address;
3095 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:529
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define ExtensionNameIndexId
Definition: indexing.h:325
static ExtensionControlFile * read_extension_control_file(const char *extname)
Definition: extension.c:616
#define RelationGetDescr(relation)
Definition: rel.h:482
Oid GetUserId(void)
Definition: miscinit.c:448
#define DatumGetTextPP(X)
Definition: fmgr.h:291
static void ApplyExtensionUpdates(Oid extensionOid, ExtensionControlFile *pcontrol, const char *initialVersion, List *updateVersions, char *origSchemaName, bool cascade, bool is_create)
Definition: extension.c:3106
#define AccessShareLock
Definition: lockdefs.h:36
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:610
unsigned int Oid
Definition: postgres_ext.h:31
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:356
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3294
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:448
#define ERROR
Definition: elog.h:43
static List * identify_update_path(ExtensionControlFile *control, const char *oldVersion, const char *newVersion)
Definition: extension.c:1166
bool pg_extension_ownercheck(Oid ext_oid, Oid roleid)
Definition: aclchk.c:5183
int location
Definition: parsenodes.h:735
#define CStringGetDatum(X)
Definition: postgres.h:578
FormData_pg_extension * Form_pg_extension
Definition: pg_extension.h:50
Node * arg
Definition: parsenodes.h:733
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:762
char * default_version
Definition: extension.c:81
uintptr_t Datum
Definition: postgres.h:367
static void check_valid_version_name(const char *versionname)
Definition: extension.c:308
bool creating_extension
Definition: extension.c:71
#define ereport(elevel,...)
Definition: elog.h:144
#define NOTICE
Definition: elog.h:37
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define lfirst(lc)
Definition: pg_list.h:190
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:110
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
char * text_to_cstring(const text *t)
Definition: varlena.c:205
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
char * defname
Definition: parsenodes.h:732
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
#define BTEqualStrategyNumber
Definition: stratnum.h:31

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

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

Referenced by ApplyExtensionUpdates(), and CreateExtensionInternal().

840 {
841  bool switch_to_superuser = false;
842  char *filename;
843  Oid save_userid = 0;
844  int save_sec_context = 0;
845  int save_nestlevel;
846  StringInfoData pathbuf;
847  ListCell *lc;
848 
849  /*
850  * Enforce superuser-ness if appropriate. We postpone these checks until
851  * here so that the control flags are correctly associated with the right
852  * script(s) if they happen to be set in secondary control files.
853  */
854  if (control->superuser && !superuser())
855  {
856  if (extension_is_trusted(control))
857  switch_to_superuser = true;
858  else if (from_version == NULL)
859  ereport(ERROR,
860  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
861  errmsg("permission denied to create extension \"%s\"",
862  control->name),
863  control->trusted
864  ? errhint("Must have CREATE privilege on current database to create this extension.")
865  : errhint("Must be superuser to create this extension.")));
866  else
867  ereport(ERROR,
868  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
869  errmsg("permission denied to update extension \"%s\"",
870  control->name),
871  control->trusted
872  ? errhint("Must have CREATE privilege on current database to update this extension.")
873  : errhint("Must be superuser to update this extension.")));
874  }
875 
876  filename = get_extension_script_filename(control, from_version, version);
877 
878  /*
879  * If installing a trusted extension on behalf of a non-superuser, become
880  * the bootstrap superuser. (This switch will be cleaned up automatically
881  * if the transaction aborts, as will the GUC changes below.)
882  */
883  if (switch_to_superuser)
884  {
885  GetUserIdAndSecContext(&save_userid, &save_sec_context);
886  SetUserIdAndSecContext(BOOTSTRAP_SUPERUSERID,
887  save_sec_context | SECURITY_LOCAL_USERID_CHANGE);
888  }
889 
890  /*
891  * Force client_min_messages and log_min_messages to be at least WARNING,
892  * so that we won't spam the user with useless NOTICE messages from common
893  * script actions like creating shell types.
894  *
895  * We use the equivalent of a function SET option to allow the setting to
896  * persist for exactly the duration of the script execution. guc.c also
897  * takes care of undoing the setting on error.
898  */
899  save_nestlevel = NewGUCNestLevel();
900 
902  (void) set_config_option("client_min_messages", "warning",
904  GUC_ACTION_SAVE, true, 0, false);
906  (void) set_config_option("log_min_messages", "warning",
908  GUC_ACTION_SAVE, true, 0, false);
909 
910  /*
911  * Set up the search path to contain the target schema, then the schemas
912  * of any prerequisite extensions, and nothing else. In particular this
913  * makes the target schema be the default creation target namespace.
914  *
915  * Note: it might look tempting to use PushOverrideSearchPath for this,
916  * but we cannot do that. We have to actually set the search_path GUC in
917  * case the extension script examines or changes it. In any case, the
918  * GUC_ACTION_SAVE method is just as convenient.
919  */
920  initStringInfo(&pathbuf);
921  appendStringInfoString(&pathbuf, quote_identifier(schemaName));
922  foreach(lc, requiredSchemas)
923  {
924  Oid reqschema = lfirst_oid(lc);
925  char *reqname = get_namespace_name(reqschema);
926 
927  if (reqname)
928  appendStringInfo(&pathbuf, ", %s", quote_identifier(reqname));
929  }
930 
931  (void) set_config_option("search_path", pathbuf.data,
933  GUC_ACTION_SAVE, true, 0, false);
934 
935  /*
936  * Set creating_extension and related variables so that
937  * recordDependencyOnCurrentExtension and other functions do the right
938  * things. On failure, ensure we reset these variables.
939  */
940  creating_extension = true;
941  CurrentExtensionObject = extensionOid;
942  PG_TRY();
943  {
944  char *c_sql = read_extension_script_file(control, filename);
945  Datum t_sql;
946 
947  /* We use various functions that want to operate on text datums */
948  t_sql = CStringGetTextDatum(c_sql);
949 
950  /*
951  * Reduce any lines beginning with "\echo" to empty. This allows
952  * scripts to contain messages telling people not to run them via
953  * psql, which has been found to be necessary due to old habits.
954  */
956  C_COLLATION_OID,
957  t_sql,
958  CStringGetTextDatum("^\\\\echo.*$"),
960  CStringGetTextDatum("ng"));
961 
962  /*
963  * If the script uses @extowner@, substitute the calling username.
964  */
965  if (strstr(c_sql, "@extowner@"))
966  {
967  Oid uid = switch_to_superuser ? save_userid : GetUserId();
968  const char *userName = GetUserNameFromId(uid, false);
969  const char *qUserName = quote_identifier(userName);
970 
972  C_COLLATION_OID,
973  t_sql,
974  CStringGetTextDatum("@extowner@"),
975  CStringGetTextDatum(qUserName));
976  }
977 
978  /*
979  * If it's not relocatable, substitute the target schema name for
980  * occurrences of @extschema@.
981  *
982  * For a relocatable extension, we needn't do this. There cannot be
983  * any need for @extschema@, else it wouldn't be relocatable.
984  */
985  if (!control->relocatable)
986  {
987  const char *qSchemaName = quote_identifier(schemaName);
988 
990  C_COLLATION_OID,
991  t_sql,
992  CStringGetTextDatum("@extschema@"),
993  CStringGetTextDatum(qSchemaName));
994  }
995 
996  /*
997  * If module_pathname was set in the control file, substitute its
998  * value for occurrences of MODULE_PATHNAME.
999  */
1000  if (control->module_pathname)
1001  {
1003  C_COLLATION_OID,
1004  t_sql,
1005  CStringGetTextDatum("MODULE_PATHNAME"),
1007  }
1008 
1009  /* And now back to C string */
1010  c_sql = text_to_cstring(DatumGetTextPP(t_sql));
1011 
1012  execute_sql_string(c_sql);
1013  }
1014  PG_FINALLY();
1015  {
1016  creating_extension = false;
1018  }
1019  PG_END_TRY();
1020 
1021  /*
1022  * Restore the GUC variables we set above.
1023  */
1024  AtEOXact_GUC(true, save_nestlevel);
1025 
1026  /*
1027  * Restore authentication state if needed.
1028  */
1029  if (switch_to_superuser)
1030  SetUserIdAndSecContext(save_userid, save_sec_context);
1031 }
Oid CurrentExtensionObject
Definition: extension.c:72
int errhint(const char *fmt,...)
Definition: elog.c:1071
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:10727
static char * get_extension_script_filename(ExtensionControlFile *control, const char *from_version, const char *version)
Definition: extension.c:439
void SetUserIdAndSecContext(Oid userid, int sec_context)
Definition: miscinit.c:560
Oid GetUserId(void)
Definition: miscinit.c:448
Datum replace_text(PG_FUNCTION_ARGS)
Definition: varlena.c:4225
Datum DirectFunctionCall4Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4)
Definition: fmgr.c:862
#define DatumGetTextPP(X)
Definition: fmgr.h:291
int errcode(int sqlerrcode)
Definition: elog.c:610
bool superuser(void)
Definition: superuser.c:46
unsigned int Oid
Definition: postgres_ext.h:31
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
#define ERROR
Definition: elog.h:43
Definition: guc.h:75
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3191
void GetUserIdAndSecContext(Oid *userid, int *sec_context)
Definition: miscinit.c:553
void AtEOXact_GUC(bool isCommit, int nestLevel)
Definition: guc.c:5927
static char * read_extension_script_file(const ExtensionControlFile *control, const char *filename)
Definition: extension.c:668
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
#define WARNING
Definition: elog.h:40
#define PG_FINALLY()
Definition: elog.h:312
char * module_pathname
Definition: extension.c:82
uintptr_t Datum
Definition: postgres.h:367
#define SECURITY_LOCAL_USERID_CHANGE
Definition: miscadmin.h:297
int log_min_messages
Definition: guc.c:534
#define InvalidOid
Definition: postgres_ext.h:36
bool creating_extension
Definition: extension.c:71
#define ereport(elevel,...)
Definition: elog.h:144
char * GetUserNameFromId(Oid roleid, bool noerr)
Definition: miscinit.c:863
static void execute_sql_string(const char *sql)
Definition: extension.c:709
Datum DirectFunctionCall3Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2, Datum arg3)
Definition: fmgr.c:837
static bool extension_is_trusted(ExtensionControlFile *control)
Definition: extension.c:815
char * text_to_cstring(const text *t)
Definition: varlena.c:205
int NewGUCNestLevel(void)
Definition: guc.c:5913
static char * filename
Definition: pg_dumpall.c:90
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define CStringGetTextDatum(s)
Definition: builtins.h:87
int client_min_messages
Definition: guc.c:535
Datum textregexreplace(PG_FUNCTION_ARGS)
Definition: regexp.c:640
#define PG_TRY()
Definition: elog.h:295
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:6920
#define PG_END_TRY()
Definition: elog.h:320
#define lfirst_oid(lc)
Definition: pg_list.h:192

◆ execute_sql_string()

static void execute_sql_string ( const char *  sql)
static

Definition at line 709 of file extension.c.

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(), pg_parse_query(), pg_plan_queries(), PopActiveSnapshot(), PROCESS_UTILITY_QUERY, ProcessUtility(), PushActiveSnapshot(), and PlannedStmt::utilityStmt.

Referenced by execute_extension_script().

710 {
711  List *raw_parsetree_list;
713  ListCell *lc1;
714 
715  /*
716  * Parse the SQL string into a list of raw parse trees.
717  */
718  raw_parsetree_list = pg_parse_query(sql);
719 
720  /* All output from SELECTs goes to the bit bucket */
722 
723  /*
724  * Do parse analysis, rule rewrite, planning, and execution for each raw
725  * parsetree. We must fully execute each query before beginning parse
726  * analysis on the next one, since there may be interdependencies.
727  */
728  foreach(lc1, raw_parsetree_list)
729  {
730  RawStmt *parsetree = lfirst_node(RawStmt, lc1);
731  MemoryContext per_parsetree_context,
732  oldcontext;
733  List *stmt_list;
734  ListCell *lc2;
735 
736  /*
737  * We do the work for each parsetree in a short-lived context, to
738  * limit the memory used when there are many commands in the string.
739  */
740  per_parsetree_context =
742  "execute_sql_string per-statement context",
744  oldcontext = MemoryContextSwitchTo(per_parsetree_context);
745 
746  /* Be sure parser can see any DDL done so far */
748 
749  stmt_list = pg_analyze_and_rewrite(parsetree,
750  sql,
751  NULL,
752  0,
753  NULL);
754  stmt_list = pg_plan_queries(stmt_list, sql, CURSOR_OPT_PARALLEL_OK, NULL);
755 
756  foreach(lc2, stmt_list)
757  {
758  PlannedStmt *stmt = lfirst_node(PlannedStmt, lc2);
759 
761 
763 
764  if (stmt->utilityStmt == NULL)
765  {
766  QueryDesc *qdesc;
767 
768  qdesc = CreateQueryDesc(stmt,
769  sql,
770  GetActiveSnapshot(), NULL,
771  dest, NULL, NULL, 0);
772 
773  ExecutorStart(qdesc, 0);
774  ExecutorRun(qdesc, ForwardScanDirection, 0, true);
775  ExecutorFinish(qdesc);
776  ExecutorEnd(qdesc);
777 
778  FreeQueryDesc(qdesc);
779  }
780  else
781  {
782  if (IsA(stmt->utilityStmt, TransactionStmt))
783  ereport(ERROR,
784  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
785  errmsg("transaction control statements are not allowed within an extension script")));
786 
787  ProcessUtility(stmt,
788  sql,
790  NULL,
791  NULL,
792  dest,
793  NULL);
794  }
795 
797  }
798 
799  /* Clean up per-parsetree context. */
800  MemoryContextSwitchTo(oldcontext);
801  MemoryContextDelete(per_parsetree_context);
802  }
803 
804  /* Be sure to advance the command counter after the last script command */
806 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
#define AllocSetContextCreate
Definition: memutils.h:170
void FreeQueryDesc(QueryDesc *qdesc)
Definition: pquery.c:105
List * pg_plan_queries(List *querytrees, const char *query_string, int cursorOptions, ParamListInfo boundParams)
Definition: postgres.c:943
void ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:143
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:841
int errcode(int sqlerrcode)
Definition: elog.c:610
void PopActiveSnapshot(void)
Definition: snapmgr.c:814
List * pg_analyze_and_rewrite(RawStmt *parsetree, const char *query_string, Oid *paramTypes, int numParams, QueryEnvironment *queryEnv)
Definition: postgres.c:676
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:306
void ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:462
#define ERROR
Definition: elog.h:43
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: execMain.c:301
List * pg_parse_query(const char *query_string)
Definition: postgres.c:628
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
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
#define lfirst_node(type, lc)
Definition: pg_list.h:193
Definition: dest.h:89
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:735
DestReceiver * CreateDestReceiver(CommandDest dest)
Definition: dest.c:113
Node * utilityStmt
Definition: plannodes.h:92
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:402
void CommandCounterIncrement(void)
Definition: xact.c:1006
#define ereport(elevel,...)
Definition: elog.h:144
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2715
int errmsg(const char *fmt,...)
Definition: elog.c:824
Definition: pg_list.h:50
void ProcessUtility(PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc)
Definition: utility.c:501

◆ extension_config_remove()

static void extension_config_remove ( Oid  extensionoid,
Oid  tableoid 
)
static

Definition at line 2605 of file extension.c.

References ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_HASNULL, ARR_LBOUND, ARR_NDIM, BTEqualStrategyNumber, CatalogTupleUpdate(), construct_array(), DatumGetArrayTypeP, deconstruct_array(), elog, ERROR, ExtensionOidIndexId, 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 ExecAlterExtensionContentsStmt().

2606 {
2607  Relation extRel;
2608  ScanKeyData key[1];
2609  SysScanDesc extScan;
2610  HeapTuple extTup;
2611  Datum arrayDatum;
2612  int arrayLength;
2613  int arrayIndex;
2614  bool isnull;
2615  Datum repl_val[Natts_pg_extension];
2616  bool repl_null[Natts_pg_extension];
2617  bool repl_repl[Natts_pg_extension];
2618  ArrayType *a;
2619 
2620  /* Find the pg_extension tuple */
2621  extRel = table_open(ExtensionRelationId, RowExclusiveLock);
2622 
2623  ScanKeyInit(&key[0],
2624  Anum_pg_extension_oid,
2625  BTEqualStrategyNumber, F_OIDEQ,
2626  ObjectIdGetDatum(extensionoid));
2627 
2628  extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
2629  NULL, 1, key);
2630 
2631  extTup = systable_getnext(extScan);
2632 
2633  if (!HeapTupleIsValid(extTup)) /* should not happen */
2634  elog(ERROR, "could not find tuple for extension %u",
2635  extensionoid);
2636 
2637  /* Search extconfig for the tableoid */
2638  arrayDatum = heap_getattr(extTup, Anum_pg_extension_extconfig,
2639  RelationGetDescr(extRel), &isnull);
2640  if (isnull)
2641  {
2642  /* nothing to do */
2643  a = NULL;
2644  arrayLength = 0;
2645  arrayIndex = -1;
2646  }
2647  else
2648  {
2649  Oid *arrayData;
2650  int i;
2651 
2652  a = DatumGetArrayTypeP(arrayDatum);
2653 
2654  arrayLength = ARR_DIMS(a)[0];
2655  if (ARR_NDIM(a) != 1 ||
2656  ARR_LBOUND(a)[0] != 1 ||
2657  arrayLength < 0 ||
2658  ARR_HASNULL(a) ||
2659  ARR_ELEMTYPE(a) != OIDOID)
2660  elog(ERROR, "extconfig is not a 1-D Oid array");
2661  arrayData = (Oid *) ARR_DATA_PTR(a);
2662 
2663  arrayIndex = -1; /* flag for no deletion needed */
2664 
2665  for (i = 0; i < arrayLength; i++)
2666  {
2667  if (arrayData[i] == tableoid)
2668  {
2669  arrayIndex = i; /* index to remove */
2670  break;
2671  }
2672  }
2673  }
2674 
2675  /* If tableoid is not in extconfig, nothing to do */
2676  if (arrayIndex < 0)
2677  {
2678  systable_endscan(extScan);
2679  table_close(extRel, RowExclusiveLock);
2680  return;
2681  }
2682 
2683  /* Modify or delete the extconfig value */
2684  memset(repl_val, 0, sizeof(repl_val));
2685  memset(repl_null, false, sizeof(repl_null));
2686  memset(repl_repl, false, sizeof(repl_repl));
2687 
2688  if (arrayLength <= 1)
2689  {
2690  /* removing only element, just set array to null */
2691  repl_null[Anum_pg_extension_extconfig - 1] = true;
2692  }
2693  else
2694  {
2695  /* squeeze out the target element */
2696  Datum *dvalues;
2697  int nelems;
2698  int i;
2699 
2700  /* We already checked there are no nulls */
2701  deconstruct_array(a, OIDOID, sizeof(Oid), true, TYPALIGN_INT,
2702  &dvalues, NULL, &nelems);
2703 
2704  for (i = arrayIndex; i < arrayLength - 1; i++)
2705  dvalues[i] = dvalues[i + 1];
2706 
2707  a = construct_array(dvalues, arrayLength - 1,
2708  OIDOID, sizeof(Oid), true, TYPALIGN_INT);
2709 
2710  repl_val[Anum_pg_extension_extconfig - 1] = PointerGetDatum(a);
2711  }
2712  repl_repl[Anum_pg_extension_extconfig - 1] = true;
2713 
2714  /* Modify or delete the extcondition value */
2715  arrayDatum = heap_getattr(extTup, Anum_pg_extension_extcondition,
2716  RelationGetDescr(extRel), &isnull);
2717  if (isnull)
2718  {
2719  elog(ERROR, "extconfig and extcondition arrays do not match");
2720  }
2721  else
2722  {
2723  a = DatumGetArrayTypeP(arrayDatum);
2724 
2725  if (ARR_NDIM(a) != 1 ||
2726  ARR_LBOUND(a)[0] != 1 ||
2727  ARR_HASNULL(a) ||
2728  ARR_ELEMTYPE(a) != TEXTOID)
2729  elog(ERROR, "extcondition is not a 1-D text array");
2730  if (ARR_DIMS(a)[0] != arrayLength)
2731  elog(ERROR, "extconfig and extcondition arrays do not match");
2732  }
2733 
2734  if (arrayLength <= 1)
2735  {
2736  /* removing only element, just set array to null */
2737  repl_null[Anum_pg_extension_extcondition - 1] = true;
2738  }
2739  else
2740  {
2741  /* squeeze out the target element */
2742  Datum *dvalues;
2743  int nelems;
2744  int i;
2745 
2746  /* We already checked there are no nulls */
2747  deconstruct_array(a, TEXTOID, -1, false, TYPALIGN_INT,
2748  &dvalues, NULL, &nelems);
2749 
2750  for (i = arrayIndex; i < arrayLength - 1; i++)
2751  dvalues[i] = dvalues[i + 1];
2752 
2753  a = construct_array(dvalues, arrayLength - 1,
2754  TEXTOID, -1, false, TYPALIGN_INT);
2755 
2756  repl_val[Anum_pg_extension_extcondition - 1] = PointerGetDatum(a);
2757  }
2758  repl_repl[Anum_pg_extension_extcondition - 1] = true;
2759 
2760  extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
2761  repl_val, repl_null, repl_repl);
2762 
2763  CatalogTupleUpdate(extRel, &extTup->t_self, extTup);
2764 
2765  systable_endscan(extScan);
2766 
2767  table_close(extRel, RowExclusiveLock);
2768 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:529
#define RelationGetDescr(relation)
Definition: rel.h:482
#define PointerGetDatum(X)
Definition: postgres.h:556
ArrayType * construct_array(Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3292
unsigned int Oid
Definition: postgres_ext.h:31
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:356
#define ARR_LBOUND(a)
Definition: array.h:284
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:448
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define ARR_DIMS(a)
Definition: array.h:282
ItemPointerData t_self
Definition: htup.h:65
#define ARR_DATA_PTR(a)
Definition: array.h:310
#define RowExclusiveLock
Definition: lockdefs.h:38
#define ARR_HASNULL(a)
Definition: array.h:279
#define ExtensionOidIndexId
Definition: indexing.h:323
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:762
uintptr_t Datum
Definition: postgres.h:367
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
#define ARR_NDIM(a)
Definition: array.h:278
void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3462
#define elog(elevel,...)
Definition: elog.h:214
int i
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
#define ARR_ELEMTYPE(a)
Definition: array.h:280
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define DatumGetArrayTypeP(X)
Definition: array.h:249

◆ extension_file_exists()

bool extension_file_exists ( const char *  extensionName)

Definition at line 2224 of file extension.c.

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

Referenced by CreateFunction(), and ExecuteDoStmt().

2225 {
2226  bool result = false;
2227  char *location;
2228  DIR *dir;
2229  struct dirent *de;
2230 
2231  location = get_extension_control_directory();
2232  dir = AllocateDir(location);
2233 
2234  /*
2235  * If the control directory doesn't exist, we want to silently return
2236  * false. Any other error will be reported by ReadDir.
2237  */
2238  if (dir == NULL && errno == ENOENT)
2239  {
2240  /* do nothing */
2241  }
2242  else
2243  {
2244  while ((de = ReadDir(dir, location)) != NULL)
2245  {
2246  char *extname;
2247 
2249  continue;
2250 
2251  /* extract extension name from 'name.control' filename */
2252  extname = pstrdup(de->d_name);
2253  *strrchr(extname, '.') = '\0';
2254 
2255  /* ignore it if it's an auxiliary control file */
2256  if (strstr(extname, "--"))
2257  continue;
2258 
2259  /* done if it matches request */
2260  if (strcmp(extname, extensionName) == 0)
2261  {
2262  result = true;
2263  break;
2264  }
2265  }
2266 
2267  FreeDir(dir);
2268  }
2269 
2270  return result;
2271 }
char * pstrdup(const char *in)
Definition: mcxt.c:1186
Definition: dirent.h:9
Definition: dirent.c:25
static bool is_extension_control_filename(const char *filename)
Definition: extension.c:355
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2583
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2649
char d_name[MAX_PATH]
Definition: dirent.h:14
int FreeDir(DIR *dir)
Definition: fd.c:2701
static char * get_extension_control_directory(void)
Definition: extension.c:371

◆ extension_is_trusted()

static bool extension_is_trusted ( ExtensionControlFile control)
static

Definition at line 815 of file extension.c.

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

Referenced by execute_extension_script().

816 {
817  AclResult aclresult;
818 
819  /* Never trust unless extension's control file says it's okay */
820  if (!control->trusted)
821  return false;
822  /* Allow if user has CREATE privilege on current database */
824  if (aclresult == ACLCHECK_OK)
825  return true;
826  return false;
827 }
Oid GetUserId(void)
Definition: miscinit.c:448
#define ACL_CREATE
Definition: parsenodes.h:84
AclResult
Definition: acl.h:177
Oid MyDatabaseId
Definition: globals.c:85
AclResult pg_database_aclcheck(Oid db_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4575

◆ find_install_path()

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

Definition at line 1302 of file extension.c.

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

Referenced by CreateExtensionInternal(), and get_available_versions_for_extension().

1304 {
1305  ExtensionVersionInfo *evi_start = NULL;
1306  ListCell *lc;
1307 
1308  *best_path = NIL;
1309 
1310  /*
1311  * We don't expect to be called for an installable target, but if we are,
1312  * the answer is easy: just start from there, with an empty update path.
1313  */
1314  if (evi_target->installable)
1315  return evi_target;
1316 
1317  /* Consider all installable versions as start points */
1318  foreach(lc, evi_list)
1319  {
1321  List *path;
1322 
1323  if (!evi1->installable)
1324  continue;
1325 
1326  /*
1327  * Find shortest path from evi1 to evi_target; but no need to consider
1328  * paths going through other installable versions.
1329  */
1330  path = find_update_path(evi_list, evi1, evi_target, true, true);
1331  if (path == NIL)
1332  continue;
1333 
1334  /* Remember best path */
1335  if (evi_start == NULL ||
1336  list_length(path) < list_length(*best_path) ||
1337  (list_length(path) == list_length(*best_path) &&
1338  strcmp(evi_start->name, evi1->name) < 0))
1339  {
1340  evi_start = evi1;
1341  *best_path = path;
1342  }
1343  }
1344 
1345  return evi_start;
1346 }
#define NIL
Definition: pg_list.h:65
static List * find_update_path(List *evi_list, ExtensionVersionInfo *evi_start, ExtensionVersionInfo *evi_target, bool reject_indirect, bool reinitialize)
Definition: extension.c:1209
#define lfirst(lc)
Definition: pg_list.h:190
static int list_length(const List *l)
Definition: pg_list.h:169
Definition: pg_list.h:50

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

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().

1214 {
1215  List *result;
1216  ExtensionVersionInfo *evi;
1217  ListCell *lc;
1218 
1219  /* Caller error if start == target */
1220  Assert(evi_start != evi_target);
1221  /* Caller error if reject_indirect and target is installable */
1222  Assert(!(reject_indirect && evi_target->installable));
1223 
1224  if (reinitialize)
1225  {
1226  foreach(lc, evi_list)
1227  {
1228  evi = (ExtensionVersionInfo *) lfirst(lc);
1229  evi->distance_known = false;
1230  evi->distance = INT_MAX;
1231  evi->previous = NULL;
1232  }
1233  }
1234 
1235  evi_start->distance = 0;
1236 
1237  while ((evi = get_nearest_unprocessed_vertex(evi_list)) != NULL)
1238  {
1239  if (evi->distance == INT_MAX)
1240  break; /* all remaining vertices are unreachable */
1241  evi->distance_known = true;
1242  if (evi == evi_target)
1243  break; /* found shortest path to target */
1244  foreach(lc, evi->reachable)
1245  {
1247  int newdist;
1248 
1249  /* if reject_indirect, treat installable versions as unreachable */
1250  if (reject_indirect && evi2->installable)
1251  continue;
1252  newdist = evi->distance + 1;
1253  if (newdist < evi2->distance)
1254  {
1255  evi2->distance = newdist;
1256  evi2->previous = evi;
1257  }
1258  else if (newdist == evi2->distance &&
1259  evi2->previous != NULL &&
1260  strcmp(evi->name, evi2->previous->name) < 0)
1261  {
1262  /*
1263  * Break ties in favor of the version name that comes first
1264  * according to strcmp(). This behavior is undocumented and
1265  * users shouldn't rely on it. We do it just to ensure that
1266  * if there is a tie, the update path that is chosen does not
1267  * depend on random factors like the order in which directory
1268  * entries get visited.
1269  */
1270  evi2->previous = evi;
1271  }
1272  }
1273  }
1274 
1275  /* Return NIL if target is not reachable from start */
1276  if (!evi_target->distance_known)
1277  return NIL;
1278 
1279  /* Build and return list of version names representing the update path */
1280  result = NIL;
1281  for (evi = evi_target; evi != evi_start; evi = evi->previous)
1282  result = lcons(evi->name, result);
1283 
1284  return result;
1285 }
#define NIL
Definition: pg_list.h:65
struct ExtensionVersionInfo * previous
Definition: extension.c:104
static ExtensionVersionInfo * get_nearest_unprocessed_vertex(List *evi_list)
Definition: extension.c:1075
List * lcons(void *datum, List *list)
Definition: list.c:453
#define Assert(condition)
Definition: c.h:738
#define lfirst(lc)
Definition: pg_list.h:190
Definition: pg_list.h:50

◆ get_available_versions_for_extension()

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

Definition at line 2110 of file extension.c.

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().

2113 {
2114  List *evi_list;
2115  ListCell *lc;
2116 
2117  /* Extract the version update graph from the script directory */
2118  evi_list = get_ext_ver_list(pcontrol);
2119 
2120  /* For each installable version ... */
2121  foreach(lc, evi_list)
2122  {
2124  ExtensionControlFile *control;
2125  Datum values[8];
2126  bool nulls[8];
2127  ListCell *lc2;
2128 
2129  if (!evi->installable)
2130  continue;
2131 
2132  /*
2133  * Fetch parameters for specific version (pcontrol is not changed)
2134  */
2135  control = read_extension_aux_control_file(pcontrol, evi->name);
2136 
2137  memset(values, 0, sizeof(values));
2138  memset(nulls, 0, sizeof(nulls));
2139 
2140  /* name */
2141  values[0] = DirectFunctionCall1(namein,
2142  CStringGetDatum(control->name));
2143  /* version */
2144  values[1] = CStringGetTextDatum(evi->name);
2145  /* superuser */
2146  values[2] = BoolGetDatum(control->superuser);
2147  /* trusted */
2148  values[3] = BoolGetDatum(control->trusted);
2149  /* relocatable */
2150  values[4] = BoolGetDatum(control->relocatable);
2151  /* schema */
2152  if (control->schema == NULL)
2153  nulls[5] = true;
2154  else
2155  values[5] = DirectFunctionCall1(namein,
2156  CStringGetDatum(control->schema));
2157  /* requires */
2158  if (control->requires == NIL)
2159  nulls[6] = true;
2160  else
2161  values[6] = convert_requires_to_datum(control->requires);
2162  /* comment */
2163  if (control->comment == NULL)
2164  nulls[7] = true;
2165  else
2166  values[7] = CStringGetTextDatum(control->comment);
2167 
2168  tuplestore_putvalues(tupstore, tupdesc, values, nulls);
2169 
2170  /*
2171  * Find all non-directly-installable versions that would be installed
2172  * starting from this version, and report them, inheriting the
2173  * parameters that aren't changed in updates from this version.
2174  */
2175  foreach(lc2, evi_list)
2176  {
2178  List *best_path;
2179 
2180  if (evi2->installable)
2181  continue;
2182  if (find_install_path(evi_list, evi2, &best_path) == evi)
2183  {
2184  /*
2185  * Fetch parameters for this version (pcontrol is not changed)
2186  */
2187  control = read_extension_aux_control_file(pcontrol, evi2->name);
2188 
2189  /* name stays the same */
2190  /* version */
2191  values[1] = CStringGetTextDatum(evi2->name);
2192  /* superuser */
2193  values[2] = BoolGetDatum(control->superuser);
2194  /* trusted */
2195  values[3] = BoolGetDatum(control->trusted);
2196  /* relocatable */
2197  values[4] = BoolGetDatum(control->relocatable);
2198  /* schema stays the same */
2199  /* requires */
2200  if (control->requires == NIL)
2201  nulls[6] = true;
2202  else
2203  {
2204  values[6] = convert_requires_to_datum(control->requires);
2205  nulls[6] = false;
2206  }
2207  /* comment stays the same */
2208 
2209  tuplestore_putvalues(tupstore, tupdesc, values, nulls);
2210  }
2211  }
2212  }
2213 }
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, Datum *values, bool *isnull)
Definition: tuplestore.c:750
#define NIL
Definition: pg_list.h:65
Datum namein(PG_FUNCTION_ARGS)
Definition: name.c:48
static Datum convert_requires_to_datum(List *requires)
Definition: extension.c:2277
static List * get_ext_ver_list(ExtensionControlFile *control)
Definition: extension.c:1103
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:624
static ExtensionControlFile * read_extension_aux_control_file(const ExtensionControlFile *pcontrol, const char *version)
Definition: extension.c:645
#define CStringGetDatum(X)
Definition: postgres.h:578
static ExtensionVersionInfo * find_install_path(List *evi_list, ExtensionVersionInfo *evi_target, List **best_path)
Definition: extension.c:1302
uintptr_t Datum
Definition: postgres.h:367
#define BoolGetDatum(X)
Definition: postgres.h:402
#define lfirst(lc)
Definition: pg_list.h:190
static Datum values[MAXATTR]
Definition: bootstrap.c:167
#define CStringGetTextDatum(s)
Definition: builtins.h:87
Definition: pg_list.h:50

◆ get_ext_ver_info()

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

Definition at line 1042 of file extension.c.

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().

1043 {
1044  ExtensionVersionInfo *evi;
1045  ListCell *lc;
1046 
1047  foreach(lc, *evi_list)
1048  {
1049  evi = (ExtensionVersionInfo *) lfirst(lc);
1050  if (strcmp(evi->name, versionname) == 0)
1051  return evi;
1052  }
1053 
1055  evi->name = pstrdup(versionname);
1056  evi->reachable = NIL;
1057  evi->installable = false;
1058  /* initialize for later application of Dijkstra's algorithm */
1059  evi->distance_known = false;
1060  evi->distance = INT_MAX;
1061  evi->previous = NULL;
1062 
1063  *evi_list = lappend(*evi_list, evi);
1064 
1065  return evi;
1066 }
#define NIL
Definition: pg_list.h:65
char * pstrdup(const char *in)
Definition: mcxt.c:1186
struct ExtensionVersionInfo * previous
Definition: extension.c:104
List * lappend(List *list, void *datum)
Definition: list.c:321
#define lfirst(lc)
Definition: pg_list.h:190
void * palloc(Size size)
Definition: mcxt.c:949

◆ get_ext_ver_list()

static List* get_ext_ver_list ( ExtensionControlFile control)
static

Definition at line 1103 of file extension.c.

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().

1104 {
1105  List *evi_list = NIL;
1106  int extnamelen = strlen(control->name);
1107  char *location;
1108  DIR *dir;
1109  struct dirent *de;
1110 
1111  location = get_extension_script_directory(control);
1112  dir = AllocateDir(location);
1113  while ((de = ReadDir(dir, location)) != NULL)
1114  {
1115  char *vername;
1116  char *vername2;
1117  ExtensionVersionInfo *evi;
1118  ExtensionVersionInfo *evi2;
1119 
1120  /* must be a .sql file ... */
1122  continue;
1123 
1124  /* ... matching extension name followed by separator */
1125  if (strncmp(de->d_name, control->name, extnamelen) != 0 ||
1126  de->d_name[extnamelen] != '-' ||
1127  de->d_name[extnamelen + 1] != '-')
1128  continue;
1129 
1130  /* extract version name(s) from 'extname--something.sql' filename */
1131  vername = pstrdup(de->d_name + extnamelen + 2);
1132  *strrchr(vername, '.') = '\0';
1133  vername2 = strstr(vername, "--");
1134  if (!vername2)
1135  {
1136  /* It's an install, not update, script; record its version name */
1137  evi = get_ext_ver_info(vername, &evi_list);
1138  evi->installable = true;
1139  continue;
1140  }
1141  *vername2 = '\0'; /* terminate first version */
1142  vername2 += 2; /* and point to second */
1143 
1144  /* if there's a third --, it's bogus, ignore it */
1145  if (strstr(vername2, "--"))
1146  continue;
1147 
1148  /* Create ExtensionVersionInfos and link them together */
1149  evi = get_ext_ver_info(vername, &evi_list);
1150  evi2 = get_ext_ver_info(vername2, &evi_list);
1151  evi->reachable = lappend(evi->reachable, evi2);
1152  }
1153  FreeDir(dir);
1154 
1155  return evi_list;
1156 }
#define NIL
Definition: pg_list.h:65
static ExtensionVersionInfo * get_ext_ver_info(const char *versionname, List **evi_list)
Definition: extension.c:1042
char * pstrdup(const char *in)
Definition: mcxt.c:1186
Definition: dirent.h:9
static char * get_extension_script_directory(ExtensionControlFile *control)
Definition: extension.c:398
Definition: dirent.c:25
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2583
List * lappend(List *list, void *datum)
Definition: list.c:321
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2649
static bool is_extension_script_filename(const char *filename)
Definition: extension.c:363
char d_name[MAX_PATH]
Definition: dirent.h:14
Definition: pg_list.h:50
int FreeDir(DIR *dir)
Definition: fd.c:2701

◆ get_extension_aux_control_filename()

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

Definition at line 421 of file extension.c.

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

Referenced by parse_extension_control_file().

423 {
424  char *result;
425  char *scriptdir;
426 
427  scriptdir = get_extension_script_directory(control);
428 
429  result = (char *) palloc(MAXPGPATH);
430  snprintf(result, MAXPGPATH, "%s/%s--%s.control",
431  scriptdir, control->name, version);
432 
433  pfree(scriptdir);
434 
435  return result;
436 }
static char * get_extension_script_directory(ExtensionControlFile *control)
Definition: extension.c:398
void pfree(void *pointer)
Definition: mcxt.c:1056
#define MAXPGPATH
void * palloc(Size size)
Definition: mcxt.c:949
#define snprintf
Definition: port.h:193

◆ get_extension_control_directory()

static char* get_extension_control_directory ( void  )
static

Definition at line 371 of file extension.c.

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().

372 {
373  char sharepath[MAXPGPATH];
374  char *result;
375 
376  get_share_path(my_exec_path, sharepath);
377  result = (char *) palloc(MAXPGPATH);
378  snprintf(result, MAXPGPATH, "%s/extension", sharepath);
379 
380  return result;
381 }
#define MAXPGPATH
char my_exec_path[MAXPGPATH]
Definition: globals.c:72
void * palloc(Size size)
Definition: mcxt.c:949
void get_share_path(const char *my_exec_path, char *ret_path)
Definition: path.c:704
#define snprintf
Definition: port.h:193

◆ get_extension_control_filename()

static char* get_extension_control_filename ( const char *  extname)
static

Definition at line 384 of file extension.c.

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

Referenced by parse_extension_control_file().

385 {
386  char sharepath[MAXPGPATH];
387  char *result;
388 
389  get_share_path(my_exec_path, sharepath);
390  result = (char *) palloc(MAXPGPATH);
391  snprintf(result, MAXPGPATH, "%s/extension/%s.control",
392  sharepath, extname);
393 
394  return result;
395 }
#define MAXPGPATH
char my_exec_path[MAXPGPATH]
Definition: globals.c:72
void * palloc(Size size)
Definition: mcxt.c:949
void get_share_path(const char *my_exec_path, char *ret_path)
Definition: path.c:704
#define snprintf
Definition: port.h:193

◆ get_extension_name()

char* get_extension_name ( Oid  ext_oid)

Definition at line 185 of file extension.c.

References AccessShareLock, BTEqualStrategyNumber, ExtensionOidIndexId, GETSTRUCT, HeapTupleIsValid, NameStr, ObjectIdGetDatum, pstrdup(), ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

Referenced by ExecAlterExtensionContentsStmt(), getObjectDescription(), getObjectIdentityParts(), recordDependencyOnCurrentExtension(), and RemoveExtensionById().

186 {
187  char *result;
188  Relation rel;
189  SysScanDesc scandesc;
190  HeapTuple tuple;
191  ScanKeyData entry[1];
192 
193  rel = table_open(ExtensionRelationId, AccessShareLock);
194 
195  ScanKeyInit(&entry[0],
196  Anum_pg_extension_oid,
197  BTEqualStrategyNumber, F_OIDEQ,
198  ObjectIdGetDatum(ext_oid));
199 
200  scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
201  NULL, 1, entry);
202 
203  tuple = systable_getnext(scandesc);
204 
205  /* We assume that there can be at most one matching tuple */
206  if (HeapTupleIsValid(tuple))
207  result = pstrdup(NameStr(((Form_pg_extension) GETSTRUCT(tuple))->extname));
208  else
209  result = NULL;
210 
211  systable_endscan(scandesc);
212 
214 
215  return result;
216 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:529
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
char * pstrdup(const char *in)
Definition: mcxt.c:1186
#define AccessShareLock
Definition: lockdefs.h:36
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:356
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:448
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ExtensionOidIndexId
Definition: indexing.h:323
FormData_pg_extension * Form_pg_extension
Definition: pg_extension.h:50
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define NameStr(name)
Definition: c.h:615
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ get_extension_oid()

Oid get_extension_oid ( const char *  extname,
bool  missing_ok 
)

Definition at line 140 of file extension.c.

References AccessShareLock, BTEqualStrategyNumber, CStringGetDatum, ereport, errcode(), errmsg(), ERROR, ExtensionNameIndexId, GETSTRUCT, HeapTupleIsValid, InvalidOid, OidIsValid, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

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

141 {
142  Oid result;
143  Relation rel;
144  SysScanDesc scandesc;
145  HeapTuple tuple;
146  ScanKeyData entry[1];
147 
148  rel = table_open(ExtensionRelationId, AccessShareLock);
149 
150  ScanKeyInit(&entry[0],
151  Anum_pg_extension_extname,
152  BTEqualStrategyNumber, F_NAMEEQ,
153  CStringGetDatum(extname));
154 
155  scandesc = systable_beginscan(rel, ExtensionNameIndexId, true,
156  NULL, 1, entry);
157 
158  tuple = systable_getnext(scandesc);
159 
160  /* We assume that there can be at most one matching tuple */
161  if (HeapTupleIsValid(tuple))
162  result = ((Form_pg_extension) GETSTRUCT(tuple))->oid;
163  else
164  result = InvalidOid;
165 
166  systable_endscan(scandesc);
167 
169 
170  if (!OidIsValid(result) && !missing_ok)
171  ereport(ERROR,
172  (errcode(ERRCODE_UNDEFINED_OBJECT),
173  errmsg("extension \"%s\" does not exist",
174  extname)));
175 
176  return result;
177 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:529
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define ExtensionNameIndexId
Definition: indexing.h:325
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:610
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:644
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:356
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:448
#define ERROR
Definition: elog.h:43
#define CStringGetDatum(X)
Definition: postgres.h:578
FormData_pg_extension * Form_pg_extension
Definition: pg_extension.h:50
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:144
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
int errmsg(const char *fmt,...)
Definition: elog.c:824
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ get_extension_schema()

static Oid get_extension_schema ( Oid  ext_oid)
static

Definition at line 224 of file extension.c.

References AccessShareLock, BTEqualStrategyNumber, ExtensionOidIndexId, GETSTRUCT, HeapTupleIsValid, InvalidOid, ObjectIdGetDatum, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), and table_open().

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

225 {
226  Oid result;
227  Relation rel;
228  SysScanDesc scandesc;
229  HeapTuple tuple;
230  ScanKeyData entry[1];
231 
232  rel = table_open(ExtensionRelationId, AccessShareLock);
233 
234  ScanKeyInit(&entry[0],
235  Anum_pg_extension_oid,
236  BTEqualStrategyNumber, F_OIDEQ,
237  ObjectIdGetDatum(ext_oid));
238 
239  scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
240  NULL, 1, entry);
241 
242  tuple = systable_getnext(scandesc);
243 
244  /* We assume that there can be at most one matching tuple */
245  if (HeapTupleIsValid(tuple))
246  result = ((Form_pg_extension) GETSTRUCT(tuple))->extnamespace;
247  else
248  result = InvalidOid;
249 
250  systable_endscan(scandesc);
251 
253 
254  return result;
255 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:529
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define AccessShareLock
Definition: lockdefs.h:36
unsigned int Oid
Definition: postgres_ext.h:31
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:356
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:448
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ExtensionOidIndexId
Definition: indexing.h:323
FormData_pg_extension * Form_pg_extension
Definition: pg_extension.h:50
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ get_extension_script_directory()

static char* get_extension_script_directory ( ExtensionControlFile control)
static

Definition at line 398 of file extension.c.

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().

399 {
400  char sharepath[MAXPGPATH];
401  char *result;
402 
403  /*
404  * The directory parameter can be omitted, absolute, or relative to the
405  * installation's share directory.
406  */
407  if (!control->directory)
409 
410  if (is_absolute_path(control->directory))
411  return pstrdup(control->directory);
412 
413  get_share_path(my_exec_path, sharepath);
414  result = (char *) palloc(MAXPGPATH);
415  snprintf(result, MAXPGPATH, "%s/%s", sharepath, control->directory);
416 
417  return result;
418 }
char * pstrdup(const char *in)
Definition: mcxt.c:1186
#define MAXPGPATH
#define is_absolute_path(filename)
Definition: port.h:86
char my_exec_path[MAXPGPATH]
Definition: globals.c:72
void * palloc(Size size)
Definition: mcxt.c:949
void get_share_path(const char *my_exec_path, char *ret_path)
Definition: path.c:704
#define snprintf
Definition: port.h:193
static char * get_extension_control_directory(void)
Definition: extension.c:371

◆ get_extension_script_filename()

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

Definition at line 439 of file extension.c.

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

Referenced by CreateExtensionInternal(), and execute_extension_script().

441 {
442  char *result;
443  char *scriptdir;
444 
445  scriptdir = get_extension_script_directory(control);
446 
447  result = (char *) palloc(MAXPGPATH);
448  if (from_version)
449  snprintf(result, MAXPGPATH, "%s/%s--%s--%s.sql",
450  scriptdir, control->name, from_version, version);
451  else
452  snprintf(result, MAXPGPATH, "%s/%s--%s.sql",
453  scriptdir, control->name, version);
454 
455  pfree(scriptdir);
456 
457  return result;
458 }
static char * get_extension_script_directory(ExtensionControlFile *control)
Definition: extension.c:398
void pfree(void *pointer)
Definition: mcxt.c:1056
#define MAXPGPATH
void * palloc(Size size)
Definition: mcxt.c:949
#define snprintf
Definition: port.h:193

◆ get_nearest_unprocessed_vertex()

static ExtensionVersionInfo* get_nearest_unprocessed_vertex ( List evi_list)
static

Definition at line 1075 of file extension.c.

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

Referenced by find_update_path().

1076 {
1077  ExtensionVersionInfo *evi = NULL;
1078  ListCell *lc;
1079 
1080  foreach(lc, evi_list)
1081  {
1083 
1084  /* only vertices whose distance is still uncertain are candidates */
1085  if (evi2->distance_known)
1086  continue;
1087  /* remember the closest such vertex */
1088  if (evi == NULL ||
1089  evi->distance > evi2->distance)
1090  evi = evi2;
1091  }
1092 
1093  return evi;
1094 }
#define lfirst(lc)
Definition: pg_list.h:190

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

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().

1602 {
1603  Oid reqExtensionOid;
1604 
1605  reqExtensionOid = get_extension_oid(reqExtensionName, true);
1606  if (!OidIsValid(reqExtensionOid))
1607  {
1608  if (cascade)
1609  {
1610  /* Must install it. */
1611  ObjectAddress addr;
1612  List *cascade_parents;
1613  ListCell *lc;
1614 
1615  /* Check extension name validity before trying to cascade. */
1616  check_valid_extension_name(reqExtensionName);
1617 
1618  /* Check for cyclic dependency between extensions. */
1619  foreach(lc, parents)
1620  {
1621  char *pname = (char *) lfirst(lc);
1622 
1623  if (strcmp(pname, reqExtensionName) == 0)
1624  ereport(ERROR,
1625  (errcode(ERRCODE_INVALID_RECURSION),
1626  errmsg("cyclic dependency detected between extensions \"%s\" and \"%s\"",
1627  reqExtensionName, extensionName)));
1628  }
1629 
1630  ereport(NOTICE,
1631  (errmsg("installing required extension \"%s\"",
1632  reqExtensionName)));
1633 
1634  /* Add current extension to list of parents to pass down. */
1635  cascade_parents = lappend(list_copy(parents), extensionName);
1636 
1637  /*
1638  * Create the required extension. We propagate the SCHEMA option
1639  * if any, and CASCADE, but no other options.
1640  */
1641  addr = CreateExtensionInternal(reqExtensionName,
1642  origSchemaName,
1643  NULL,
1644  cascade,
1645  cascade_parents,
1646  is_create);
1647 
1648  /* Get its newly-assigned OID. */
1649  reqExtensionOid = addr.objectId;
1650  }
1651  else
1652  ereport(ERROR,
1653  (errcode(ERRCODE_UNDEFINED_OBJECT),
1654  errmsg("required extension \"%s\" is not installed",
1655  reqExtensionName),
1656  is_create ?
1657  errhint("Use CREATE EXTENSION ... CASCADE to install required extensions too.") : 0));
1658  }
1659 
1660  return reqExtensionOid;
1661 }
int errhint(const char *fmt,...)
Definition: elog.c:1071
static void check_valid_extension_name(const char *extensionname)
Definition: extension.c:261
List * list_copy(const List *oldlist)
Definition: list.c:1403
int errcode(int sqlerrcode)
Definition: elog.c:610
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:644
#define ERROR
Definition: elog.h:43
List * lappend(List *list, void *datum)
Definition: list.c:321
static ObjectAddress CreateExtensionInternal(char *extensionName, char *schemaName, const char *versionName, bool cascade, List *parents, bool is_create)
Definition: extension.c:1357
#define ereport(elevel,...)
Definition: elog.h:144
#define NOTICE
Definition: elog.h:37
#define lfirst(lc)
Definition: pg_list.h:190
Oid get_extension_oid(const char *extname, bool missing_ok)
Definition: extension.c:140
int errmsg(const char *fmt,...)
Definition: elog.c:824
Definition: pg_list.h:50

◆ identify_update_path()

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

Definition at line 1166 of file extension.c.

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

Referenced by ExecAlterExtensionStmt().

1168 {
1169  List *result;
1170  List *evi_list;
1171  ExtensionVersionInfo *evi_start;
1172  ExtensionVersionInfo *evi_target;
1173 
1174  /* Extract the version update graph from the script directory */
1175  evi_list = get_ext_ver_list(control);
1176 
1177  /* Initialize start and end vertices */
1178  evi_start = get_ext_ver_info(oldVersion, &evi_list);
1179  evi_target = get_ext_ver_info(newVersion, &evi_list);
1180 
1181  /* Find shortest path */
1182  result = find_update_path(evi_list, evi_start, evi_target, false, false);
1183 
1184  if (result == NIL)
1185  ereport(ERROR,
1186  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1187  errmsg("extension \"%s\" has no update path from version \"%s\" to version \"%s\"",
1188  control->name, oldVersion, newVersion)));
1189 
1190  return result;
1191 }
#define NIL
Definition: pg_list.h:65
static List * find_update_path(List *evi_list, ExtensionVersionInfo *evi_start, ExtensionVersionInfo *evi_target, bool reject_indirect, bool reinitialize)
Definition: extension.c:1209
static ExtensionVersionInfo * get_ext_ver_info(const char *versionname, List **evi_list)
Definition: extension.c:1042
static List * get_ext_ver_list(ExtensionControlFile *control)
Definition: extension.c:1103
int errcode(int sqlerrcode)
Definition: elog.c:610
#define ERROR
Definition: elog.h:43
#define ereport(elevel,...)
Definition: elog.h:144
int errmsg(const char *fmt,...)
Definition: elog.c:824
Definition: pg_list.h:50

◆ InsertExtensionTuple()

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

Definition at line 1774 of file extension.c.

References add_exact_object_address(), BoolGetDatum, CatalogTupleInsert(), CStringGetDatum, CStringGetTextDatum, DEPENDENCY_NORMAL, DirectFunctionCall1, ExtensionOidIndexId, 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().

1778 {
1779  Oid extensionOid;
1780  Relation rel;
1781  Datum values[Natts_pg_extension];
1782  bool nulls[Natts_pg_extension];
1783  HeapTuple tuple;
1784  ObjectAddress myself;
1785  ObjectAddress nsp;
1786  ObjectAddresses *refobjs;
1787  ListCell *lc;
1788 
1789  /*
1790  * Build and insert the pg_extension tuple
1791  */
1792  rel = table_open(ExtensionRelationId, RowExclusiveLock);
1793 
1794  memset(values, 0, sizeof(values));
1795  memset(nulls, 0, sizeof(nulls));
1796 
1797  extensionOid = GetNewOidWithIndex(rel, ExtensionOidIndexId,
1798  Anum_pg_extension_oid);
1799  values[Anum_pg_extension_oid - 1] = ObjectIdGetDatum(extensionOid);
1800  values[Anum_pg_extension_extname - 1] =
1802  values[Anum_pg_extension_extowner - 1] = ObjectIdGetDatum(extOwner);
1803  values[Anum_pg_extension_extnamespace - 1] = ObjectIdGetDatum(schemaOid);
1804  values[Anum_pg_extension_extrelocatable - 1] = BoolGetDatum(relocatable);
1805  values[Anum_pg_extension_extversion - 1] = CStringGetTextDatum(extVersion);
1806 
1807  if (extConfig == PointerGetDatum(NULL))
1808  nulls[Anum_pg_extension_extconfig - 1] = true;
1809  else
1810  values[Anum_pg_extension_extconfig - 1] = extConfig;
1811 
1812  if (extCondition == PointerGetDatum(NULL))
1813  nulls[Anum_pg_extension_extcondition - 1] = true;
1814  else
1815  values[Anum_pg_extension_extcondition - 1] = extCondition;
1816 
1817  tuple = heap_form_tuple(rel->rd_att, values, nulls);
1818 
1819  CatalogTupleInsert(rel, tuple);
1820 
1821  heap_freetuple(tuple);
1823 
1824  /*
1825  * Record dependencies on owner, schema, and prerequisite extensions
1826  */
1827  recordDependencyOnOwner(ExtensionRelationId, extensionOid, extOwner);
1828 
1829  refobjs = new_object_addresses();
1830 
1831  ObjectAddressSet(myself, ExtensionRelationId, extensionOid);
1832 
1833  ObjectAddressSet(nsp, NamespaceRelationId, schemaOid);
1834  add_exact_object_address(&nsp, refobjs);
1835 
1836  foreach(lc, requiredExtensions)
1837  {
1838  Oid reqext = lfirst_oid(lc);
1839  ObjectAddress otherext;
1840 
1841  ObjectAddressSet(otherext, ExtensionRelationId, reqext);
1842  add_exact_object_address(&otherext, refobjs);
1843  }
1844 
1845  /* Record all of them (this includes duplicate elimination) */
1847  free_object_addresses(refobjs);
1848 
1849  /* Post creation hook for new extension */
1850  InvokeObjectPostCreateHook(ExtensionRelationId, extensionOid, 0);
1851 
1852  return myself;
1853 }
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:317
Datum namein(PG_FUNCTION_ARGS)
Definition: name.c:48
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:151
#define PointerGetDatum(X)
Definition: postgres.h:556
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
Definition: dependency.c:2674
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2465
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:624
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:164
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2410
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2705
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define RowExclusiveLock
Definition: lockdefs.h:38
#define CStringGetDatum(X)
Definition: postgres.h:578
#define ExtensionOidIndexId
Definition: indexing.h:323
uintptr_t Datum
Definition: postgres.h:367
TupleDesc rd_att
Definition: rel.h:110
#define BoolGetDatum(X)
Definition: postgres.h:402
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
static Datum values[MAXATTR]
Definition: bootstrap.c:167
#define CStringGetTextDatum(s)
Definition: builtins.h:87
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:183
#define lfirst_oid(lc)
Definition: pg_list.h:192

◆ is_extension_control_filename()

static bool is_extension_control_filename ( const char *  filename)
static

Definition at line 355 of file extension.c.

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

356 {
357  const char *extension = strrchr(filename, '.');
358 
359  return (extension != NULL) && (strcmp(extension, ".control") == 0);
360 }
static char * filename
Definition: pg_dumpall.c:90

◆ is_extension_script_filename()

static bool is_extension_script_filename ( const char *  filename)
static

Definition at line 363 of file extension.c.

Referenced by get_ext_ver_list().

364 {
365  const char *extension = strrchr(filename, '.');
366 
367  return (extension != NULL) && (strcmp(extension, ".sql") == 0);
368 }
static char * filename
Definition: pg_dumpall.c:90

◆ parse_extension_control_file()

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

Definition at line 471 of file extension.c.

References AllocateFile(), ExtensionControlFile::comment, ExtensionControlFile::default_version, ExtensionControlFile::directory, ExtensionControlFile::encoding, ereport, errcode(), errcode_for_file_access(), errmsg(), ERROR, filename, FreeConfigVariables(), FreeFile(), get_extension_aux_control_filename(), get_extension_control_filename(), ExtensionControlFile::module_pathname, ExtensionControlFile::name, ConfigVariable::name, ConfigVariable::next, 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().

473 {
474  char *filename;
475  FILE *file;
476  ConfigVariable *item,
477  *head = NULL,
478  *tail = NULL;
479 
480  /*
481  * Locate the file to read. Auxiliary files are optional.
482  */
483  if (version)
484  filename = get_extension_aux_control_filename(control, version);
485  else
486  filename = get_extension_control_filename(control->name);
487 
488  if ((file = AllocateFile(filename, "r")) == NULL)
489  {
490  if (version && errno == ENOENT)
491  {
492  /* no auxiliary file for this version */
493  pfree(filename);
494  return;
495  }
496  ereport(ERROR,
498  errmsg("could not open extension control file \"%s\": %m",
499  filename)));
500  }
501 
502  /*
503  * Parse the file content, using GUC's file parsing code. We need not
504  * check the return value since any errors will be thrown at ERROR level.
505  */
506  (void) ParseConfigFp(file, filename, 0, ERROR, &head, &tail);
507 
508  FreeFile(file);
509 
510  /*
511  * Convert the ConfigVariable list into ExtensionControlFile entries.
512  */
513  for (item = head; item != NULL; item = item->next)
514  {
515  if (strcmp(item->name, "directory") == 0)
516  {
517  if (version)
518  ereport(ERROR,
519  (errcode(ERRCODE_SYNTAX_ERROR),
520  errmsg("parameter \"%s\" cannot be set in a secondary extension control file",
521  item->name)));
522 
523  control->directory = pstrdup(item->value);
524  }
525  else if (strcmp(item->name, "default_version") == 0)
526  {
527  if (version)
528  ereport(ERROR,
529  (errcode(ERRCODE_SYNTAX_ERROR),
530  errmsg("parameter \"%s\" cannot be set in a secondary extension control file",
531  item->name)));
532 
533  control->default_version = pstrdup(item->value);
534  }
535  else if (strcmp(item->name, "module_pathname") == 0)
536  {
537  control->module_pathname = pstrdup(item->value);
538  }
539  else if (strcmp(item->name, "comment") == 0)
540  {
541  control->comment = pstrdup(item->value);
542  }
543  else if (strcmp(item->name, "schema") == 0)
544  {
545  control->schema = pstrdup(item->value);
546  }
547  else if (strcmp(item->name, "relocatable") == 0)
548  {
549  if (!parse_bool(item->value, &control->relocatable))
550  ereport(ERROR,
551  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
552  errmsg("parameter \"%s\" requires a Boolean value",
553  item->name)));
554  }
555  else if (strcmp(item->name, "superuser") == 0)
556  {
557  if (!parse_bool(item->value, &control->superuser))
558  ereport(ERROR,
559  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
560  errmsg("parameter \"%s\" requires a Boolean value",
561  item->name)));
562  }
563  else if (strcmp(item->name, "trusted") == 0)
564  {
565  if (!parse_bool(item->value, &control->trusted))
566  ereport(ERROR,
567  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
568  errmsg("parameter \"%s\" requires a Boolean value",
569  item->name)));
570  }
571  else if (strcmp(item->name, "encoding") == 0)
572  {
573  control->encoding = pg_valid_server_encoding(item->value);
574  if (control->encoding < 0)
575  ereport(ERROR,
576  (errcode(ERRCODE_UNDEFINED_OBJECT),
577  errmsg("\"%s\" is not a valid encoding name",
578  item->value)));
579  }
580  else if (strcmp(item->name, "requires") == 0)
581  {
582  /* Need a modifiable copy of string */
583  char *rawnames = pstrdup(item->value);
584 
585  /* Parse string into list of identifiers */
586  if (!SplitIdentifierString(rawnames, ',', &control->requires))
587  {
588  /* syntax error in name list */
589  ereport(ERROR,
590  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
591  errmsg("parameter \"%s\" must be a list of extension names",
592  item->name)));
593  }
594  }
595  else
596  ereport(ERROR,
597  (errcode(ERRCODE_SYNTAX_ERROR),
598  errmsg("unrecognized parameter \"%s\" in file \"%s\"",
599  item->name, filename)));
600  }
601 
602  FreeConfigVariables(head);
603 
604  if (control->relocatable && control->schema != NULL)
605  ereport(ERROR,
606  (errcode(ERRCODE_SYNTAX_ERROR),
607  errmsg("parameter \"schema\" cannot be specified when \"relocatable\" is true")));
608 
609  pfree(filename);
610 }
int pg_valid_server_encoding(const char *name)
Definition: encnames.c:500
char * pstrdup(const char *in)
Definition: mcxt.c:1186
int errcode(int sqlerrcode)
Definition: elog.c:610
bool parse_bool(const char *value, bool *result)
Definition: bool.c:30
void pfree(void *pointer)
Definition: mcxt.c:1056
#define ERROR
Definition: elog.h:43
bool SplitIdentifierString(char *rawstring, char separator, List **namelist)
Definition: varlena.c:3686
int errcode_for_file_access(void)
Definition: elog.c:633
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2322
char * value
Definition: guc.h:136
char * name
Definition: guc.h:135
char * default_version
Definition: extension.c:81
char * module_pathname
Definition: extension.c:82
static char * get_extension_aux_control_filename(ExtensionControlFile *control, const char *version)
Definition: extension.c:421
#define ereport(elevel,...)
Definition: elog.h:144
static char * get_extension_control_filename(const char *extname)
Definition: extension.c:384
int FreeFile(FILE *file)
Definition: fd.c:2521
static char * filename
Definition: pg_dumpall.c:90
int errmsg(const char *fmt,...)
Definition: elog.c:824
bool ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel, ConfigVariable **head_p, ConfigVariable **tail_p)
void FreeConfigVariables(ConfigVariable *list)
struct ConfigVariable * next
Definition: guc.h:142

◆ pg_available_extension_versions()

Datum pg_available_extension_versions ( PG_FUNCTION_ARGS  )

Definition at line 2024 of file extension.c.

References AllocateDir(), ReturnSetInfo::allowedModes, ReturnSetInfo::econtext, ExprContext::ecxt_per_query_memory, elog, ereport, errcode(), errmsg(), ERROR, FreeDir(), get_available_versions_for_extension(), get_call_result_type(), get_extension_control_directory(), is_extension_control_filename(), IsA, MemoryContextSwitchTo(), pstrdup(), read_extension_control_file(), ReadDir(), ReturnSetInfo::returnMode, ReturnSetInfo::setDesc, ReturnSetInfo::setResult, SFRM_Materialize, tuplestore_begin_heap(), tuplestore_donestoring, TYPEFUNC_COMPOSITE, and work_mem.

2025 {
2026  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
2027  TupleDesc tupdesc;
2028  Tuplestorestate *tupstore;
2029  MemoryContext per_query_ctx;
2030  MemoryContext oldcontext;
2031  char *location;
2032  DIR *dir;
2033  struct dirent *de;
2034 
2035  /* check to see if caller supports us returning a tuplestore */
2036  if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
2037  ereport(ERROR,
2038  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2039  errmsg("set-valued function called in context that cannot accept a set")));
2040  if (!(rsinfo->allowedModes & SFRM_Materialize))
2041  ereport(ERROR,
2042  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2043  errmsg("materialize mode required, but it is not allowed in this context")));
2044 
2045  /* Build a tuple descriptor for our result type */
2046  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
2047  elog(ERROR, "return type must be a row type");
2048 
2049  /* Build tuplestore to hold the result rows */
2050  per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
2051  oldcontext = MemoryContextSwitchTo(per_query_ctx);
2052 
2053  tupstore = tuplestore_begin_heap(true, false, work_mem);
2054  rsinfo->returnMode = SFRM_Materialize;
2055  rsinfo->setResult = tupstore;
2056  rsinfo->setDesc = tupdesc;
2057 
2058  MemoryContextSwitchTo(oldcontext);
2059 
2060  location = get_extension_control_directory();
2061  dir = AllocateDir(location);
2062 
2063  /*
2064  * If the control directory doesn't exist, we want to silently return an
2065  * empty set. Any other error will be reported by ReadDir.
2066  */
2067  if (dir == NULL && errno == ENOENT)
2068  {
2069  /* do nothing */
2070  }
2071  else
2072  {
2073  while ((de = ReadDir(dir, location)) != NULL)
2074  {
2075  ExtensionControlFile *control;
2076  char *extname;
2077 
2078  if (!is_extension_control_filename(de->d_name))
2079  continue;
2080 
2081  /* extract extension name from 'name.control' filename */
2082  extname = pstrdup(de->d_name);
2083  *strrchr(extname, '.') = '\0';
2084 
2085  /* ignore it if it's an auxiliary control file */
2086  if (strstr(extname, "--"))
2087  continue;
2088 
2089  /* read the control file */
2090  control = read_extension_control_file(extname);
2091 
2092  /* scan extension's script directory for install scripts */
2093  get_available_versions_for_extension(control, tupstore, tupdesc);
2094  }
2095 
2096  FreeDir(dir);
2097  }
2098 
2099  /* clean up and return the tuplestore */
2100  tuplestore_donestoring(tupstore);
2101 
2102  return (Datum) 0;
2103 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:205
static ExtensionControlFile * read_extension_control_file(const char *extname)
Definition: extension.c:616
char * pstrdup(const char *in)
Definition: mcxt.c:1186
#define tuplestore_donestoring(state)
Definition: tuplestore.h:60
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:610
Definition: dirent.h:9
static void get_available_versions_for_extension(ExtensionControlFile *pcontrol, Tuplestorestate *tupstore, TupleDesc tupdesc)
Definition: extension.c:2110
Definition: dirent.c:25
#define ERROR
Definition: elog.h:43
static bool is_extension_control_filename(const char *filename)
Definition: extension.c:355
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2583
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
uintptr_t Datum
Definition: postgres.h:367
int work_mem
Definition: globals.c:121
#define ereport(elevel,...)
Definition: elog.h:144
int allowedModes
Definition: execnodes.h:305
SetFunctionReturnMode returnMode
Definition: execnodes.h:307
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2649
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:233
Tuplestorestate * setResult
Definition: execnodes.h:310
ExprContext * econtext
Definition: execnodes.h:303
TupleDesc setDesc
Definition: execnodes.h:311
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
int FreeDir(DIR *dir)
Definition: fd.c:2701
static char * get_extension_control_directory(void)
Definition: extension.c:371

◆ pg_available_extensions()

Datum pg_available_extensions ( PG_FUNCTION_ARGS  )

Definition at line 1916 of file extension.c.

References AllocateDir(), ReturnSetInfo::allowedModes, ExtensionControlFile::comment, CStringGetDatum, CStringGetTextDatum, ExtensionControlFile::default_version, DirectFunctionCall1, ReturnSetInfo::econtext, ExprContext::ecxt_per_query_memory, elog, ereport, errcode(), errmsg(), ERROR, FreeDir(), get_call_result_type(), get_extension_control_directory(), is_extension_control_filename(), IsA, MemoryContextSwitchTo(), ExtensionControlFile::name, namein(), pstrdup(), read_extension_control_file(), ReadDir(), ReturnSetInfo::returnMode, ReturnSetInfo::setDesc, ReturnSetInfo::setResult, SFRM_Materialize, tuplestore_begin_heap(), tuplestore_donestoring, tuplestore_putvalues(), TYPEFUNC_COMPOSITE, values, and work_mem.

1917 {
1918  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1919  TupleDesc tupdesc;
1920  Tuplestorestate *tupstore;
1921  MemoryContext per_query_ctx;
1922  MemoryContext oldcontext;
1923  char *location;
1924  DIR *dir;
1925  struct dirent *de;
1926 
1927  /* check to see if caller supports us returning a tuplestore */
1928  if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
1929  ereport(ERROR,
1930  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1931  errmsg("set-valued function called in context that cannot accept a set")));
1932  if (!(rsinfo->allowedModes & SFRM_Materialize))
1933  ereport(ERROR,
1934  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1935  errmsg("materialize mode required, but it is not allowed in this context")));
1936 
1937  /* Build a tuple descriptor for our result type */
1938  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
1939  elog(ERROR, "return type must be a row type");
1940 
1941  /* Build tuplestore to hold the result rows */
1942  per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
1943  oldcontext = MemoryContextSwitchTo(per_query_ctx);
1944 
1945  tupstore = tuplestore_begin_heap(true, false, work_mem);
1946  rsinfo->returnMode = SFRM_Materialize;
1947  rsinfo->setResult = tupstore;
1948  rsinfo->setDesc = tupdesc;
1949 
1950  MemoryContextSwitchTo(oldcontext);
1951 
1952  location = get_extension_control_directory();
1953  dir = AllocateDir(location);
1954 
1955  /*
1956  * If the control directory doesn't exist, we want to silently return an
1957  * empty set. Any other error will be reported by ReadDir.
1958  */
1959  if (dir == NULL && errno == ENOENT)
1960  {
1961  /* do nothing */
1962  }
1963  else
1964  {
1965  while ((de = ReadDir(dir, location)) != NULL)
1966  {
1967  ExtensionControlFile *control;
1968  char *extname;
1969  Datum values[3];
1970  bool nulls[3];
1971 
1972  if (!is_extension_control_filename(de->d_name))
1973  continue;
1974 
1975  /* extract extension name from 'name.control' filename */
1976  extname = pstrdup(de->d_name);
1977  *strrchr(extname, '.') = '\0';
1978 
1979  /* ignore it if it's an auxiliary control file */
1980  if (strstr(extname, "--"))
1981  continue;
1982 
1983  control = read_extension_control_file(extname);
1984 
1985  memset(values, 0, sizeof(values));
1986  memset(nulls, 0, sizeof(nulls));
1987 
1988  /* name */
1989  values[0] = DirectFunctionCall1(namein,
1990  CStringGetDatum(control->name));
1991  /* default_version */
1992  if (control->default_version == NULL)
1993  nulls[1] = true;
1994  else
1995  values[1] = CStringGetTextDatum(control->default_version);
1996  /* comment */
1997  if (control->comment == NULL)
1998  nulls[2] = true;
1999  else
2000  values[2] = CStringGetTextDatum(control->comment);
2001 
2002  tuplestore_putvalues(tupstore, tupdesc, values, nulls);
2003  }
2004 
2005  FreeDir(dir);
2006  }
2007 
2008  /* clean up and return the tuplestore */
2009  tuplestore_donestoring(tupstore);
2010 
2011  return (Datum) 0;
2012 }
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, Datum *values, bool *isnull)
Definition: tuplestore.c:750
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
Datum namein(PG_FUNCTION_ARGS)
Definition: name.c:48
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:205
static ExtensionControlFile * read_extension_control_file(const char *extname)
Definition: extension.c:616
char * pstrdup(const char *in)
Definition: mcxt.c:1186
#define tuplestore_donestoring(state)
Definition: tuplestore.h:60
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:610
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:624
Definition: dirent.h:9
Definition: dirent.c:25
#define ERROR
Definition: elog.h:43
static bool is_extension_control_filename(const char *filename)
Definition: extension.c:355
#define CStringGetDatum(X)
Definition: postgres.h:578
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2583
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
char * default_version
Definition: extension.c:81
uintptr_t Datum
Definition: postgres.h:367
int work_mem
Definition: globals.c:121
#define ereport(elevel,...)
Definition: elog.h:144
int allowedModes
Definition: execnodes.h:305
SetFunctionReturnMode returnMode
Definition: execnodes.h:307
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2649
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:233
Tuplestorestate * setResult
Definition: execnodes.h:310
static Datum values[MAXATTR]
Definition: bootstrap.c:167
ExprContext * econtext
Definition: execnodes.h:303
TupleDesc setDesc
Definition: execnodes.h:311
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
#define CStringGetTextDatum(s)
Definition: builtins.h:87
int FreeDir(DIR *dir)
Definition: fd.c:2701
static char * get_extension_control_directory(void)
Definition: extension.c:371

◆ pg_extension_config_dump()

Datum pg_extension_config_dump ( PG_FUNCTION_ARGS  )

Definition at line 2418 of file extension.c.

References ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_HASNULL, ARR_LBOUND, ARR_NDIM, array_set(), BTEqualStrategyNumber, CatalogTupleUpdate(), construct_array(), creating_extension, CurrentExtensionObject, DatumGetArrayTypeP, elog, ereport, errcode(), ERRCODE_UNDEFINED_TABLE, errmsg(), ERROR, ExtensionOidIndexId, 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().

2419 {
2420  Oid tableoid = PG_GETARG_OID(0);
2421  text *wherecond = PG_GETARG_TEXT_PP(1);
2422  char *tablename;
2423  Relation extRel;
2424  ScanKeyData key[1];
2425  SysScanDesc extScan;
2426  HeapTuple extTup;
2427  Datum arrayDatum;
2428  Datum elementDatum;
2429  int arrayLength;
2430  int arrayIndex;
2431  bool isnull;
2432  Datum repl_val[Natts_pg_extension];
2433  bool repl_null[Natts_pg_extension];
2434  bool repl_repl[Natts_pg_extension];
2435  ArrayType *a;
2436 
2437  /*
2438  * We only allow this to be called from an extension's SQL script. We
2439  * shouldn't need any permissions check beyond that.
2440  */
2441  if (!creating_extension)
2442  ereport(ERROR,
2443  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2444  errmsg("%s can only be called from an SQL script executed by CREATE EXTENSION",
2445  "pg_extension_config_dump()")));
2446 
2447  /*
2448  * Check that the table exists and is a member of the extension being
2449  * created. This ensures that we don't need to register an additional
2450  * dependency to protect the extconfig entry.
2451  */
2452  tablename = get_rel_name(tableoid);
2453  if (tablename == NULL)
2454  ereport(ERROR,
2456  errmsg("OID %u does not refer to a table", tableoid)));
2457  if (getExtensionOfObject(RelationRelationId, tableoid) !=
2459  ereport(ERROR,
2460  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2461  errmsg("table \"%s\" is not a member of the extension being created",
2462  tablename)));
2463 
2464  /*
2465  * Add the table OID and WHERE condition to the extension's extconfig and
2466  * extcondition arrays.
2467  *
2468  * If the table is already in extconfig, treat this as an update of the
2469  * WHERE condition.
2470  */
2471 
2472  /* Find the pg_extension tuple */
2473  extRel = table_open(ExtensionRelationId, RowExclusiveLock);
2474 
2475  ScanKeyInit(&key[0],
2476  Anum_pg_extension_oid,
2477  BTEqualStrategyNumber, F_OIDEQ,
2479 
2480  extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
2481  NULL, 1, key);
2482 
2483  extTup = systable_getnext(extScan);
2484 
2485  if (!HeapTupleIsValid(extTup)) /* should not happen */
2486  elog(ERROR, "could not find tuple for extension %u",
2488 
2489  memset(repl_val, 0, sizeof(repl_val));
2490  memset(repl_null, false, sizeof(repl_null));
2491  memset(repl_repl, false, sizeof(repl_repl));
2492 
2493  /* Build or modify the extconfig value */
2494  elementDatum = ObjectIdGetDatum(tableoid);
2495 
2496  arrayDatum = heap_getattr(extTup, Anum_pg_extension_extconfig,
2497  RelationGetDescr(extRel), &isnull);
2498  if (isnull)
2499  {
2500  /* Previously empty extconfig, so build 1-element array */
2501  arrayLength = 0;
2502  arrayIndex = 1;
2503 
2504  a = construct_array(&elementDatum, 1,
2505  OIDOID,
2506  sizeof(Oid), true, TYPALIGN_INT);
2507  }
2508  else
2509  {
2510  /* Modify or extend existing extconfig array */
2511  Oid *arrayData;
2512  int i;
2513 
2514  a = DatumGetArrayTypeP(arrayDatum);
2515 
2516  arrayLength = ARR_DIMS(a)[0];
2517  if (ARR_NDIM(a) != 1 ||
2518  ARR_LBOUND(a)[0] != 1 ||
2519  arrayLength < 0 ||
2520  ARR_HASNULL(a) ||
2521  ARR_ELEMTYPE(a) != OIDOID)
2522  elog(ERROR, "extconfig is not a 1-D Oid array");
2523  arrayData = (Oid *) ARR_DATA_PTR(a);
2524 
2525  arrayIndex = arrayLength + 1; /* set up to add after end */
2526 
2527  for (i = 0; i < arrayLength; i++)
2528  {
2529  if (arrayData[i] == tableoid)
2530  {
2531  arrayIndex = i + 1; /* replace this element instead */
2532  break;
2533  }
2534  }
2535 
2536  a = array_set(a, 1, &arrayIndex,
2537  elementDatum,
2538  false,
2539  -1 /* varlena array */ ,
2540  sizeof(Oid) /* OID's typlen */ ,
2541  true /* OID's typbyval */ ,
2542  TYPALIGN_INT /* OID's typalign */ );
2543  }
2544  repl_val[Anum_pg_extension_extconfig - 1] = PointerGetDatum(a);
2545  repl_repl[Anum_pg_extension_extconfig - 1] = true;
2546 
2547  /* Build or modify the extcondition value */
2548  elementDatum = PointerGetDatum(wherecond);
2549 
2550  arrayDatum = heap_getattr(extTup, Anum_pg_extension_extcondition,
2551  RelationGetDescr(extRel), &isnull);
2552  if (isnull)
2553  {
2554  if (arrayLength != 0)
2555  elog(ERROR, "extconfig and extcondition arrays do not match");
2556 
2557  a = construct_array(&elementDatum, 1,
2558  TEXTOID,
2559  -1, false, TYPALIGN_INT);
2560  }
2561  else
2562  {
2563  a = DatumGetArrayTypeP(arrayDatum);
2564 
2565  if (ARR_NDIM(a) != 1 ||
2566  ARR_LBOUND(a)[0] != 1 ||
2567  ARR_HASNULL(a) ||
2568  ARR_ELEMTYPE(a) != TEXTOID)
2569  elog(ERROR, "extcondition is not a 1-D text array");
2570  if (ARR_DIMS(a)[0] != arrayLength)
2571  elog(ERROR, "extconfig and extcondition arrays do not match");
2572 
2573  /* Add or replace at same index as in extconfig */
2574  a = array_set(a, 1, &arrayIndex,
2575  elementDatum,
2576  false,
2577  -1 /* varlena array */ ,
2578  -1 /* TEXT's typlen */ ,
2579  false /* TEXT's typbyval */ ,
2580  TYPALIGN_INT /* TEXT's typalign */ );
2581  }
2582  repl_val[Anum_pg_extension_extcondition - 1] = PointerGetDatum(a);
2583  repl_repl[Anum_pg_extension_extcondition - 1] = true;
2584 
2585  extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
2586  repl_val, repl_null, repl_repl);
2587 
2588  CatalogTupleUpdate(extRel, &extTup->t_self, extTup);
2589 
2590  systable_endscan(extScan);
2591 
2592  table_close(extRel, RowExclusiveLock);
2593 
2594  PG_RETURN_VOID();
2595 }
Oid CurrentExtensionObject
Definition: extension.c:72
Oid getExtensionOfObject(Oid classId, Oid objectId)
Definition: pg_depend.c:659
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:529
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:73
#define RelationGetDescr(relation)
Definition: rel.h:482
#define PointerGetDatum(X)
Definition: postgres.h:556
ArrayType * construct_array(Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3292
int errcode(int sqlerrcode)
Definition: elog.c:610
ArrayType * array_set(ArrayType *array, int nSubscripts, int *indx, Datum dataValue, bool isNull, int arraytyplen, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3094
unsigned int Oid
Definition: postgres_ext.h:31
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:356
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:308
#define ARR_LBOUND(a)
Definition: array.h:284
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:448
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define ARR_DIMS(a)
Definition: array.h:282
ItemPointerData t_self
Definition: htup.h:65
#define ARR_DATA_PTR(a)
Definition: array.h:310
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
#define RowExclusiveLock
Definition: lockdefs.h:38
#define ARR_HASNULL(a)
Definition: array.h:279
#define ExtensionOidIndexId
Definition: indexing.h:323
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:762
uintptr_t Datum
Definition: postgres.h:367
bool creating_extension
Definition: extension.c:71
#define ereport(elevel,...)
Definition: elog.h:144
#define PG_RETURN_VOID()
Definition: fmgr.h:348
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
#define ARR_NDIM(a)
Definition: array.h:278
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
int i
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Definition: c.h:555
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1840
#define ARR_ELEMTYPE(a)
Definition: array.h:280
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define DatumGetArrayTypeP(X)
Definition: array.h:249

◆ pg_extension_update_paths()

Datum pg_extension_update_paths ( PG_FUNCTION_ARGS  )

Definition at line 2305 of file extension.c.

References ReturnSetInfo::allowedModes, appendStringInfoString(), check_valid_extension_name(), CStringGetTextDatum, StringInfoData::data, ReturnSetInfo::econtext, ExprContext::ecxt_per_query_memory, elog, ereport, errcode(), errmsg(), ERROR, find_update_path(), get_call_result_type(), get_ext_ver_list(), initStringInfo(), IsA, lfirst, MemoryContextSwitchTo(), ExtensionVersionInfo::name, NameStr, NIL, pfree(), PG_GETARG_NAME, read_extension_control_file(), ReturnSetInfo::returnMode, ReturnSetInfo::setDesc, ReturnSetInfo::setResult, SFRM_Materialize, tuplestore_begin_heap(), tuplestore_donestoring, tuplestore_putvalues(), TYPEFUNC_COMPOSITE, values, and work_mem.

2306 {
2307  Name extname = PG_GETARG_NAME(0);
2308  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
2309  TupleDesc tupdesc;
2310  Tuplestorestate *tupstore;
2311  MemoryContext per_query_ctx;
2312  MemoryContext oldcontext;
2313  List *evi_list;
2314  ExtensionControlFile *control;
2315  ListCell *lc1;
2316 
2317  /* Check extension name validity before any filesystem access */
2319 
2320  /* check to see if caller supports us returning a tuplestore */
2321  if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
2322  ereport(ERROR,
2323  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2324  errmsg("set-valued function called in context that cannot accept a set")));
2325  if (!(rsinfo->allowedModes & SFRM_Materialize))
2326  ereport(ERROR,
2327  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2328  errmsg("materialize mode required, but it is not allowed in this context")));
2329 
2330  /* Build a tuple descriptor for our result type */
2331  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
2332  elog(ERROR, "return type must be a row type");
2333 
2334  /* Build tuplestore to hold the result rows */
2335  per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
2336  oldcontext = MemoryContextSwitchTo(per_query_ctx);
2337 
2338  tupstore = tuplestore_begin_heap(true, false, work_mem);
2339  rsinfo->returnMode = SFRM_Materialize;
2340  rsinfo->setResult = tupstore;
2341  rsinfo->setDesc = tupdesc;
2342 
2343  MemoryContextSwitchTo(oldcontext);
2344 
2345  /* Read the extension's control file */
2346  control = read_extension_control_file(NameStr(*extname));
2347 
2348  /* Extract the version update graph from the script directory */
2349  evi_list = get_ext_ver_list(control);
2350 
2351  /* Iterate over all pairs of versions */
2352  foreach(lc1, evi_list)
2353  {
2355  ListCell *lc2;
2356 
2357  foreach(lc2, evi_list)
2358  {
2360  List *path;
2361  Datum values[3];
2362  bool nulls[3];
2363 
2364  if (evi1 == evi2)
2365  continue;
2366 
2367  /* Find shortest path from evi1 to evi2 */
2368  path = find_update_path(evi_list, evi1, evi2, false, true);
2369 
2370  /* Emit result row */
2371  memset(values, 0, sizeof(values));
2372  memset(nulls, 0, sizeof(nulls));
2373 
2374  /* source */
2375  values[0] = CStringGetTextDatum(evi1->name);
2376  /* target */
2377  values[1] = CStringGetTextDatum(evi2->name);
2378  /* path */
2379  if (path == NIL)
2380  nulls[2] = true;
2381  else
2382  {
2383  StringInfoData pathbuf;
2384  ListCell *lcv;
2385 
2386  initStringInfo(&pathbuf);
2387  /* The path doesn't include start vertex, but show it */
2388  appendStringInfoString(&pathbuf, evi1->name);
2389  foreach(lcv, path)
2390  {
2391  char *versionName = (char *) lfirst(lcv);
2392 
2393  appendStringInfoString(&pathbuf, "--");
2394  appendStringInfoString(&pathbuf, versionName);
2395  }
2396  values[2] = CStringGetTextDatum(pathbuf.data);
2397  pfree(pathbuf.data);
2398  }
2399 
2400  tuplestore_putvalues(tupstore, tupdesc, values, nulls);
2401  }
2402  }
2403 
2404  /* clean up and return the tuplestore */
2405  tuplestore_donestoring(tupstore);
2406 
2407  return (Datum) 0;
2408 }
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, Datum *values, bool *isnull)
Definition: tuplestore.c:750
#define NIL
Definition: pg_list.h:65
static List * find_update_path(List *evi_list, ExtensionVersionInfo *evi_start, ExtensionVersionInfo *evi_target, bool reject_indirect, bool reinitialize)
Definition: extension.c:1209
#define IsA(nodeptr, _type_)
Definition: nodes.h:580
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:205
static ExtensionControlFile * read_extension_control_file(const char *extname)
Definition: extension.c:616
static void check_valid_extension_name(const char *extensionname)
Definition: extension.c:261
static List * get_ext_ver_list(ExtensionControlFile *control)
Definition: extension.c:1103
#define tuplestore_donestoring(state)
Definition: tuplestore.h:60
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:610
void pfree(void *pointer)
Definition: mcxt.c:1056
#define ERROR
Definition: elog.h:43
Definition: c.h:609
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
uintptr_t Datum
Definition: postgres.h:367
int work_mem
Definition: globals.c:121
#define ereport(elevel,...)
Definition: elog.h:144
int allowedModes
Definition: execnodes.h:305
SetFunctionReturnMode returnMode
Definition: execnodes.h:307
#define lfirst(lc)
Definition: pg_list.h:190
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:233
Tuplestorestate * setResult
Definition: execnodes.h:310
static Datum values[MAXATTR]
Definition: bootstrap.c:167
ExprContext * econtext
Definition: execnodes.h:303
TupleDesc setDesc
Definition: execnodes.h:311
int errmsg(const char *fmt,...)
Definition: elog.c:824
#define elog(elevel,...)
Definition: elog.h:214
#define NameStr(name)
Definition: c.h:615
#define CStringGetTextDatum(s)
Definition: builtins.h:87
Definition: pg_list.h:50
#define PG_GETARG_NAME(n)
Definition: fmgr.h:278

◆ read_extension_aux_control_file()

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

Definition at line 645 of file extension.c.

References palloc(), and parse_extension_control_file().

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

647 {
648  ExtensionControlFile *acontrol;
649 
650  /*
651  * Flat-copy the struct. Pointer fields share values with original.
652  */
653  acontrol = (ExtensionControlFile *) palloc(sizeof(ExtensionControlFile));
654  memcpy(acontrol, pcontrol, sizeof(ExtensionControlFile));
655 
656  /*
657  * Parse the auxiliary control file, overwriting struct fields
658  */
659  parse_extension_control_file(acontrol, version);
660 
661  return acontrol;
662 }
static void parse_extension_control_file(ExtensionControlFile *control, const char *version)
Definition: extension.c:471
void * palloc(Size size)
Definition: mcxt.c:949

◆ read_extension_control_file()

static ExtensionControlFile* read_extension_control_file ( const char *  extname)
static

Definition at line 616 of file extension.c.

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

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

617 {
618  ExtensionControlFile *control;
619 
620  /*
621  * Set up default values. Pointer fields are initially null.
622  */
623  control = (ExtensionControlFile *) palloc0(sizeof(ExtensionControlFile));
624  control->name = pstrdup(extname);
625  control->relocatable = false;
626  control->superuser = true;
627  control->trusted = false;
628  control->encoding = -1;
629 
630  /*
631  * Parse the primary control file.
632  */
633  parse_extension_control_file(control, NULL);
634 
635  return control;
636 }
char * pstrdup(const char *in)
Definition: mcxt.c:1186
static void parse_extension_control_file(ExtensionControlFile *control, const char *version)
Definition: extension.c:471
void * palloc0(Size size)
Definition: mcxt.c:980

◆ read_extension_script_file()

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

Definition at line 668 of file extension.c.

References ExtensionControlFile::encoding, GetDatabaseEncoding(), pg_any_to_server(), pg_verify_mbstr_len(), and read_whole_file().

Referenced by execute_extension_script().

670 {
671  int src_encoding;
672  char *src_str;
673  char *dest_str;
674  int len;
675 
676  src_str = read_whole_file(filename, &len);
677 
678  /* use database encoding if not given */
679  if (control->encoding < 0)
680  src_encoding = GetDatabaseEncoding();
681  else
682  src_encoding = control->encoding;
683 
684  /* make sure that source string is valid in the expected encoding */
685  pg_verify_mbstr_len(src_encoding, src_str, len, false);
686 
687  /*
688  * Convert the encoding to the database encoding. read_whole_file
689  * null-terminated the string, so if no conversion happens the string is
690  * valid as is.
691  */
692  dest_str = pg_any_to_server(src_str, len, src_encoding);
693 
694  return dest_str;
695 }
static char * read_whole_file(const char *filename, int *length)
Definition: extension.c:3421
int GetDatabaseEncoding(void)
Definition: mbutils.c:1151
static char * filename
Definition: pg_dumpall.c:90
char * pg_any_to_server(const char *s, int len, int encoding)
Definition: mbutils.c:619
int pg_verify_mbstr_len(int encoding, const char *mbstr, int len, bool noError)
Definition: mbutils.c:1474

◆ read_whole_file()

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

Definition at line 3421 of file extension.c.

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

Referenced by read_extension_script_file().

3422 {
3423  char *buf;
3424  FILE *file;
3425  size_t bytes_to_read;
3426  struct stat fst;
3427 
3428  if (stat(filename, &fst) < 0)
3429  ereport(ERROR,
3431  errmsg("could not stat file \"%s\": %m", filename)));
3432 
3433  if (fst.st_size > (MaxAllocSize - 1))
3434  ereport(ERROR,
3435  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3436  errmsg("file \"%s\" is too large", filename)));
3437  bytes_to_read = (size_t) fst.st_size;
3438 
3439  if ((file = AllocateFile(filename, PG_BINARY_R)) == NULL)
3440  ereport(ERROR,
3442  errmsg("could not open file \"%s\" for reading: %m",
3443  filename)));
3444 
3445  buf = (char *) palloc(bytes_to_read + 1);
3446 
3447  *length = fread(buf, 1, bytes_to_read, file);
3448 
3449  if (ferror(file))
3450  ereport(ERROR,
3452  errmsg("could not read file \"%s\": %m", filename)));
3453 
3454  FreeFile(file);
3455 
3456  buf[*length] = '\0';
3457  return buf;
3458 }
int errcode(int sqlerrcode)
Definition: elog.c:610
#define PG_BINARY_R
Definition: c.h:1235
#define ERROR
Definition: elog.h:43
static char * buf
Definition: pg_test_fsync.c:67
int errcode_for_file_access(void)
Definition: elog.c:633
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2322
#define MaxAllocSize
Definition: memutils.h:40
#define stat(a, b)
Definition: win32_port.h:255
#define ereport(elevel,...)
Definition: elog.h:144
int FreeFile(FILE *file)
Definition: fd.c:2521
static char * filename
Definition: pg_dumpall.c:90
void * palloc(Size size)
Definition: mcxt.c:949
int errmsg(const char *fmt,...)
Definition: elog.c:824

◆ RemoveExtensionById()

void RemoveExtensionById ( Oid  extId)

Definition at line 1862 of file extension.c.

References BTEqualStrategyNumber, CatalogTupleDelete(), CurrentExtensionObject, ereport, errcode(), errmsg(), ERROR, ExtensionOidIndexId, get_extension_name(), HeapTupleIsValid, ObjectIdGetDatum, RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), and table_open().

Referenced by doDeletion().

1863 {
1864  Relation rel;
1865  SysScanDesc scandesc;
1866  HeapTuple tuple;
1867  ScanKeyData entry[1];
1868 
1869  /*
1870  * Disallow deletion of any extension that's currently open for insertion;
1871  * else subsequent executions of recordDependencyOnCurrentExtension()
1872  * could create dangling pg_depend records that refer to a no-longer-valid
1873  * pg_extension OID. This is needed not so much because we think people
1874  * might write "DROP EXTENSION foo" in foo's own script files, as because
1875  * errors in dependency management in extension script files could give
1876  * rise to cases where an extension is dropped as a result of recursing
1877  * from some contained object. Because of that, we must test for the case
1878  * here, not at some higher level of the DROP EXTENSION command.
1879  */
1880  if (extId == CurrentExtensionObject)
1881  ereport(ERROR,
1882  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1883  errmsg("cannot drop extension \"%s\" because it is being modified",
1884  get_extension_name(extId))));
1885 
1886  rel = table_open(ExtensionRelationId, RowExclusiveLock);
1887 
1888  ScanKeyInit(&entry[0],
1889  Anum_pg_extension_oid,
1890  BTEqualStrategyNumber, F_OIDEQ,
1891  ObjectIdGetDatum(extId));
1892  scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
1893  NULL, 1, entry);
1894 
1895  tuple = systable_getnext(scandesc);
1896 
1897  /* We assume that there can be at most one matching tuple */
1898  if (HeapTupleIsValid(tuple))
1899  CatalogTupleDelete(rel, &tuple->t_self);
1900 
1901  systable_endscan(scandesc);
1902 
1904 }
Oid CurrentExtensionObject
Definition: extension.c:72
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:529
char * get_extension_name(Oid ext_oid)
Definition: extension.c:185
int errcode(int sqlerrcode)
Definition: elog.c:610
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:269
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:356
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:448
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
#define ExtensionOidIndexId
Definition: indexing.h:323
#define ereport(elevel,...)
Definition: elog.h:144
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
int errmsg(const char *fmt,...)
Definition: elog.c:824
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define BTEqualStrategyNumber
Definition: stratnum.h:31

Variable Documentation

◆ creating_extension

◆ CurrentExtensionObject