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/htup_details.h"
#include "access/sysattr.h"
#include "access/xact.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/objectaccess.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/tqual.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, const char *filename)
 
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, const char *oldVersionName, 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)
 
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 2681 of file extension.c.

References AccessShareLock, ACL_CREATE, ACL_KIND_EXTENSION, ACL_KIND_NAMESPACE, aclcheck_error(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, AlterObjectNamespace_oid(), Anum_pg_depend_refclassid, Anum_pg_depend_refobjid, BTEqualStrategyNumber, CatalogTupleUpdate(), changeDependencyFor(), ObjectAddress::classId, DEPENDENCY_EXTENSION, DependReferenceIndexId, DependRelationId, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, ExtensionOidIndexId, ExtensionRelationId, get_extension_oid(), get_namespace_name(), getExtensionOfObject(), getObjectDescription(), GETSTRUCT, GetUserId(), heap_close, heap_copytuple(), heap_open(), HeapTupleIsValid, InvalidObjectAddress, InvalidOid, InvokeObjectPostAlterHook, LookupCreationNamespace(), NamespaceRelationId, NameStr, new_object_addresses(), ObjectAddressSet, ObjectAddress::objectId, ObjectIdAttributeNumber, ObjectIdGetDatum, ObjectAddress::objectSubId, pg_extension_ownercheck(), pg_namespace_aclcheck(), relation_close(), RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), and HeapTupleData::t_self.

Referenced by ExecAlterObjectSchemaStmt().

2682 {
2683  Oid extensionOid;
2684  Oid nspOid;
2685  Oid oldNspOid = InvalidOid;
2686  AclResult aclresult;
2687  Relation extRel;
2688  ScanKeyData key[2];
2689  SysScanDesc extScan;
2690  HeapTuple extTup;
2691  Form_pg_extension extForm;
2692  Relation depRel;
2693  SysScanDesc depScan;
2694  HeapTuple depTup;
2695  ObjectAddresses *objsMoved;
2696  ObjectAddress extAddr;
2697 
2698  extensionOid = get_extension_oid(extensionName, false);
2699 
2700  nspOid = LookupCreationNamespace(newschema);
2701 
2702  /*
2703  * Permission check: must own extension. Note that we don't bother to
2704  * check ownership of the individual member objects ...
2705  */
2706  if (!pg_extension_ownercheck(extensionOid, GetUserId()))
2708  extensionName);
2709 
2710  /* Permission check: must have creation rights in target namespace */
2711  aclresult = pg_namespace_aclcheck(nspOid, GetUserId(), ACL_CREATE);
2712  if (aclresult != ACLCHECK_OK)
2713  aclcheck_error(aclresult, ACL_KIND_NAMESPACE, newschema);
2714 
2715  /*
2716  * If the schema is currently a member of the extension, disallow moving
2717  * the extension into the schema. That would create a dependency loop.
2718  */
2719  if (getExtensionOfObject(NamespaceRelationId, nspOid) == extensionOid)
2720  ereport(ERROR,
2721  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2722  errmsg("cannot move extension \"%s\" into schema \"%s\" "
2723  "because the extension contains the schema",
2724  extensionName, newschema)));
2725 
2726  /* Locate the pg_extension tuple */
2728 
2729  ScanKeyInit(&key[0],
2731  BTEqualStrategyNumber, F_OIDEQ,
2732  ObjectIdGetDatum(extensionOid));
2733 
2734  extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
2735  NULL, 1, key);
2736 
2737  extTup = systable_getnext(extScan);
2738 
2739  if (!HeapTupleIsValid(extTup)) /* should not happen */
2740  elog(ERROR, "could not find tuple for extension %u",
2741  extensionOid);
2742 
2743  /* Copy tuple so we can modify it below */
2744  extTup = heap_copytuple(extTup);
2745  extForm = (Form_pg_extension) GETSTRUCT(extTup);
2746 
2747  systable_endscan(extScan);
2748 
2749  /*
2750  * If the extension is already in the target schema, just silently do
2751  * nothing.
2752  */
2753  if (extForm->extnamespace == nspOid)
2754  {
2755  heap_close(extRel, RowExclusiveLock);
2756  return InvalidObjectAddress;
2757  }
2758 
2759  /* Check extension is supposed to be relocatable */
2760  if (!extForm->extrelocatable)
2761  ereport(ERROR,
2762  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2763  errmsg("extension \"%s\" does not support SET SCHEMA",
2764  NameStr(extForm->extname))));
2765 
2766  objsMoved = new_object_addresses();
2767 
2768  /*
2769  * Scan pg_depend to find objects that depend directly on the extension,
2770  * and alter each one's schema.
2771  */
2773 
2774  ScanKeyInit(&key[0],
2776  BTEqualStrategyNumber, F_OIDEQ,
2778  ScanKeyInit(&key[1],
2780  BTEqualStrategyNumber, F_OIDEQ,
2781  ObjectIdGetDatum(extensionOid));
2782 
2783  depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
2784  NULL, 2, key);
2785 
2786  while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
2787  {
2788  Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
2789  ObjectAddress dep;
2790  Oid dep_oldNspOid;
2791 
2792  /*
2793  * Ignore non-membership dependencies. (Currently, the only other
2794  * case we could see here is a normal dependency from another
2795  * extension.)
2796  */
2797  if (pg_depend->deptype != DEPENDENCY_EXTENSION)
2798  continue;
2799 
2800  dep.classId = pg_depend->classid;
2801  dep.objectId = pg_depend->objid;
2802  dep.objectSubId = pg_depend->objsubid;
2803 
2804  if (dep.objectSubId != 0) /* should not happen */
2805  elog(ERROR, "extension should not have a sub-object dependency");
2806 
2807  /* Relocate the object */
2808  dep_oldNspOid = AlterObjectNamespace_oid(dep.classId,
2809  dep.objectId,
2810  nspOid,
2811  objsMoved);
2812 
2813  /*
2814  * Remember previous namespace of first object that has one
2815  */
2816  if (oldNspOid == InvalidOid && dep_oldNspOid != InvalidOid)
2817  oldNspOid = dep_oldNspOid;
2818 
2819  /*
2820  * If not all the objects had the same old namespace (ignoring any
2821  * that are not in namespaces), complain.
2822  */
2823  if (dep_oldNspOid != InvalidOid && dep_oldNspOid != oldNspOid)
2824  ereport(ERROR,
2825  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2826  errmsg("extension \"%s\" does not support SET SCHEMA",
2827  NameStr(extForm->extname)),
2828  errdetail("%s is not in the extension's schema \"%s\"",
2829  getObjectDescription(&dep),
2830  get_namespace_name(oldNspOid))));
2831  }
2832 
2833  /* report old schema, if caller wants it */
2834  if (oldschema)
2835  *oldschema = oldNspOid;
2836 
2837  systable_endscan(depScan);
2838 
2840 
2841  /* Now adjust pg_extension.extnamespace */
2842  extForm->extnamespace = nspOid;
2843 
2844  CatalogTupleUpdate(extRel, &extTup->t_self, extTup);
2845 
2846  heap_close(extRel, RowExclusiveLock);
2847 
2848  /* update dependencies to point to the new schema */
2850  NamespaceRelationId, oldNspOid, nspOid);
2851 
2853 
2854  ObjectAddressSet(extAddr, ExtensionRelationId, extensionOid);
2855 
2856  return extAddr;
2857 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:611
#define Anum_pg_depend_refobjid
Definition: pg_depend.h:72
#define NamespaceRelationId
Definition: pg_namespace.h:34
Oid getExtensionOfObject(Oid classId, Oid objectId)
Definition: pg_depend.c:447
#define Anum_pg_depend_refclassid
Definition: pg_depend.h:71
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
Oid GetUserId(void)
Definition: miscinit.c:284
#define ObjectIdAttributeNumber
Definition: sysattr.h:22
Oid LookupCreationNamespace(const char *nspname)
Definition: namespace.c:2896
#define DependReferenceIndexId
Definition: indexing.h:147
#define DependRelationId
Definition: pg_depend.h:29
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:575
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1266
#define heap_close(r, l)
Definition: heapam.h:97
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2105
unsigned int Oid
Definition: postgres_ext.h:31
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4484
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
char * getObjectDescription(const ObjectAddress *object)
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:82
ItemPointerData t_self
Definition: htup.h:65
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3047
bool pg_extension_ownercheck(Oid ext_oid, Oid roleid)
Definition: aclchk.c:5042
void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, const char *objectname)
Definition: aclchk.c:3399
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:873
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:61
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
#define ExtensionOidIndexId
Definition: indexing.h:319
FormData_pg_extension * Form_pg_extension
Definition: pg_extension.h:51
AclResult
Definition: acl.h:178
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
Oid get_extension_oid(const char *extname, bool missing_ok)
Definition: extension.c:135
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:797
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:295
Oid AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: alter.c:553
#define NameStr(name)
Definition: c.h:547
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define elog
Definition: elog.h:219
#define ExtensionRelationId
Definition: pg_extension.h:29
#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 3013 of file extension.c.

References Anum_pg_extension_extrelocatable, Anum_pg_extension_extversion, BoolGetDatum, BTEqualStrategyNumber, CatalogTupleUpdate(), ObjectAddress::classId, CStringGetTextDatum, deleteDependencyRecordsForClass(), DEPENDENCY_NORMAL, elog, ERROR, execute_extension_script(), ExtensionOidIndexId, ExtensionRelationId, get_extension_schema(), get_namespace_name(), get_required_extension(), GETSTRUCT, heap_close, heap_modify_tuple(), heap_open(), HeapTupleIsValid, InvokeObjectPostAlterHook, lappend_oid(), lfirst, lfirst_oid, ExtensionControlFile::name, Natts_pg_extension, NIL, ObjectAddress::objectId, ObjectIdAttributeNumber, 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, and values.

Referenced by CreateExtensionInternal(), and ExecAlterExtensionStmt().

3020 {
3021  const char *oldVersionName = initialVersion;
3022  ListCell *lcv;
3023 
3024  foreach(lcv, updateVersions)
3025  {
3026  char *versionName = (char *) lfirst(lcv);
3027  ExtensionControlFile *control;
3028  char *schemaName;
3029  Oid schemaOid;
3030  List *requiredExtensions;
3031  List *requiredSchemas;
3032  Relation extRel;
3033  ScanKeyData key[1];
3034  SysScanDesc extScan;
3035  HeapTuple extTup;
3036  Form_pg_extension extForm;
3038  bool nulls[Natts_pg_extension];
3039  bool repl[Natts_pg_extension];
3040  ObjectAddress myself;
3041  ListCell *lc;
3042 
3043  /*
3044  * Fetch parameters for specific version (pcontrol is not changed)
3045  */
3046  control = read_extension_aux_control_file(pcontrol, versionName);
3047 
3048  /* Find the pg_extension tuple */
3050 
3051  ScanKeyInit(&key[0],
3053  BTEqualStrategyNumber, F_OIDEQ,
3054  ObjectIdGetDatum(extensionOid));
3055 
3056  extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
3057  NULL, 1, key);
3058 
3059  extTup = systable_getnext(extScan);
3060 
3061  if (!HeapTupleIsValid(extTup)) /* should not happen */
3062  elog(ERROR, "could not find tuple for extension %u",
3063  extensionOid);
3064 
3065  extForm = (Form_pg_extension) GETSTRUCT(extTup);
3066 
3067  /*
3068  * Determine the target schema (set by original install)
3069  */
3070  schemaOid = extForm->extnamespace;
3071  schemaName = get_namespace_name(schemaOid);
3072 
3073  /*
3074  * Modify extrelocatable and extversion in the pg_extension tuple
3075  */
3076  memset(values, 0, sizeof(values));
3077  memset(nulls, 0, sizeof(nulls));
3078  memset(repl, 0, sizeof(repl));
3079 
3080  values[Anum_pg_extension_extrelocatable - 1] =
3081  BoolGetDatum(control->relocatable);
3082  repl[Anum_pg_extension_extrelocatable - 1] = true;
3083  values[Anum_pg_extension_extversion - 1] =
3084  CStringGetTextDatum(versionName);
3085  repl[Anum_pg_extension_extversion - 1] = true;
3086 
3087  extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
3088  values, nulls, repl);
3089 
3090  CatalogTupleUpdate(extRel, &extTup->t_self, extTup);
3091 
3092  systable_endscan(extScan);
3093 
3094  heap_close(extRel, RowExclusiveLock);
3095 
3096  /*
3097  * Look up the prerequisite extensions for this version, install them
3098  * if necessary, and build lists of their OIDs and the OIDs of their
3099  * target schemas.
3100  */
3101  requiredExtensions = NIL;
3102  requiredSchemas = NIL;
3103  foreach(lc, control->requires)
3104  {
3105  char *curreq = (char *) lfirst(lc);
3106  Oid reqext;
3107  Oid reqschema;
3108 
3109  reqext = get_required_extension(curreq,
3110  control->name,
3111  origSchemaName,
3112  cascade,
3113  NIL,
3114  is_create);
3115  reqschema = get_extension_schema(reqext);
3116  requiredExtensions = lappend_oid(requiredExtensions, reqext);
3117  requiredSchemas = lappend_oid(requiredSchemas, reqschema);
3118  }
3119 
3120  /*
3121  * Remove and recreate dependencies on prerequisite extensions
3122  */
3126 
3127  myself.classId = ExtensionRelationId;
3128  myself.objectId = extensionOid;
3129  myself.objectSubId = 0;
3130 
3131  foreach(lc, requiredExtensions)
3132  {
3133  Oid reqext = lfirst_oid(lc);
3134  ObjectAddress otherext;
3135 
3136  otherext.classId = ExtensionRelationId;
3137  otherext.objectId = reqext;
3138  otherext.objectSubId = 0;
3139 
3140  recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
3141  }
3142 
3144 
3145  /*
3146  * Finally, execute the update script file
3147  */
3148  execute_extension_script(extensionOid, control,
3149  oldVersionName, versionName,
3150  requiredSchemas,
3151  schemaName, schemaOid);
3152 
3153  /*
3154  * Update prior-version name and loop around. Since
3155  * execute_sql_string did a final CommandCounterIncrement, we can
3156  * update the pg_extension row again.
3157  */
3158  oldVersionName = versionName;
3159  }
3160 }
#define NIL
Definition: pg_list.h:69
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
static Oid get_extension_schema(Oid ext_oid)
Definition: extension.c:219
#define Anum_pg_extension_extrelocatable
Definition: pg_extension.h:62
static Oid get_required_extension(char *reqExtensionName, char *extensionName, char *origSchemaName, bool cascade, List *parents, bool is_create)
Definition: extension.c:1549
#define RelationGetDescr(relation)
Definition: rel.h:437
#define ObjectIdAttributeNumber
Definition: sysattr.h:22
#define Anum_pg_extension_extversion
Definition: pg_extension.h:63
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
#define heap_close(r, l)
Definition: heapam.h:97
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
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:786
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3047
static ExtensionControlFile * read_extension_aux_control_file(const ExtensionControlFile *pcontrol, const char *version)
Definition: extension.c:631
#define RowExclusiveLock
Definition: lockdefs.h:38
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
#define ExtensionOidIndexId
Definition: indexing.h:319
FormData_pg_extension * Form_pg_extension
Definition: pg_extension.h:51
uintptr_t Datum
Definition: postgres.h:372
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition: pg_depend.c:241
#define BoolGetDatum(X)
Definition: postgres.h:408
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define lfirst(lc)
Definition: pg_list.h:106
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
static Datum values[MAXATTR]
Definition: bootstrap.c:164
#define Natts_pg_extension
Definition: pg_extension.h:58
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define CStringGetTextDatum(s)
Definition: builtins.h:91
#define elog
Definition: elog.h:219
#define ExtensionRelationId
Definition: pg_extension.h:29
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:794
Definition: pg_list.h:45
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define lfirst_oid(lc)
Definition: pg_list.h:108

◆ check_valid_extension_name()

static void check_valid_extension_name ( const char *  extensionname)
static

Definition at line 256 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().

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

◆ check_valid_version_name()

static void check_valid_version_name ( const char *  versionname)
static

Definition at line 303 of file extension.c.

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

Referenced by CreateExtensionInternal(), and ExecAlterExtensionStmt().

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

◆ convert_requires_to_datum()

static Datum convert_requires_to_datum ( List requires)
static

Definition at line 2181 of file extension.c.

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

Referenced by get_available_versions_for_extension().

2182 {
2183  Datum *datums;
2184  int ndatums;
2185  ArrayType *a;
2186  ListCell *lc;
2187 
2188  ndatums = list_length(requires);
2189  datums = (Datum *) palloc(ndatums * sizeof(Datum));
2190  ndatums = 0;
2191  foreach(lc, requires)
2192  {
2193  char *curreq = (char *) lfirst(lc);
2194 
2195  datums[ndatums++] =
2197  }
2198  a = construct_array(datums, ndatums,
2199  NAMEOID,
2200  NAMEDATALEN, false, 'c');
2201  return PointerGetDatum(a);
2202 }
Datum namein(PG_FUNCTION_ARGS)
Definition: name.c:46
#define NAMEOID
Definition: pg_type.h:300
#define PointerGetDatum(X)
Definition: postgres.h:562
ArrayType * construct_array(Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3279
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:585
#define NAMEDATALEN
#define CStringGetDatum(X)
Definition: postgres.h:584
uintptr_t Datum
Definition: postgres.h:372
#define lfirst(lc)
Definition: pg_list.h:106
static int list_length(const List *l)
Definition: pg_list.h:89
void * palloc(Size size)
Definition: mcxt.c:848

◆ CreateExtension()

ObjectAddress CreateExtension ( ParseState pstate,
CreateExtensionStmt stmt 
)

Definition at line 1621 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().

1622 {
1623  DefElem *d_schema = NULL;
1624  DefElem *d_new_version = NULL;
1625  DefElem *d_old_version = NULL;
1626  DefElem *d_cascade = NULL;
1627  char *schemaName = NULL;
1628  char *versionName = NULL;
1629  char *oldVersionName = NULL;
1630  bool cascade = false;
1631  ListCell *lc;
1632 
1633  /* Check extension name validity before any filesystem access */
1635 
1636  /*
1637  * Check for duplicate extension name. The unique index on
1638  * pg_extension.extname would catch this anyway, and serves as a backstop
1639  * in case of race conditions; but this is a friendlier error message, and
1640  * besides we need a check to support IF NOT EXISTS.
1641  */
1642  if (get_extension_oid(stmt->extname, true) != InvalidOid)
1643  {
1644  if (stmt->if_not_exists)
1645  {
1646  ereport(NOTICE,
1648  errmsg("extension \"%s\" already exists, skipping",
1649  stmt->extname)));
1650  return InvalidObjectAddress;
1651  }
1652  else
1653  ereport(ERROR,
1655  errmsg("extension \"%s\" already exists",
1656  stmt->extname)));
1657  }
1658 
1659  /*
1660  * We use global variables to track the extension being created, so we can
1661  * create only one extension at the same time.
1662  */
1663  if (creating_extension)
1664  ereport(ERROR,
1665  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1666  errmsg("nested CREATE EXTENSION is not supported")));
1667 
1668  /* Deconstruct the statement option list */
1669  foreach(lc, stmt->options)
1670  {
1671  DefElem *defel = (DefElem *) lfirst(lc);
1672 
1673  if (strcmp(defel->defname, "schema") == 0)
1674  {
1675  if (d_schema)
1676  ereport(ERROR,
1677  (errcode(ERRCODE_SYNTAX_ERROR),
1678  errmsg("conflicting or redundant options"),
1679  parser_errposition(pstate, defel->location)));
1680  d_schema = defel;
1681  schemaName = defGetString(d_schema);
1682  }
1683  else if (strcmp(defel->defname, "new_version") == 0)
1684  {
1685  if (d_new_version)
1686  ereport(ERROR,
1687  (errcode(ERRCODE_SYNTAX_ERROR),
1688  errmsg("conflicting or redundant options"),
1689  parser_errposition(pstate, defel->location)));
1690  d_new_version = defel;
1691  versionName = defGetString(d_new_version);
1692  }
1693  else if (strcmp(defel->defname, "old_version") == 0)
1694  {
1695  if (d_old_version)
1696  ereport(ERROR,
1697  (errcode(ERRCODE_SYNTAX_ERROR),
1698  errmsg("conflicting or redundant options"),
1699  parser_errposition(pstate, defel->location)));
1700  d_old_version = defel;
1701  oldVersionName = defGetString(d_old_version);
1702  }
1703  else if (strcmp(defel->defname, "cascade") == 0)
1704  {
1705  if (d_cascade)
1706  ereport(ERROR,
1707  (errcode(ERRCODE_SYNTAX_ERROR),
1708  errmsg("conflicting or redundant options"),
1709  parser_errposition(pstate, defel->location)));
1710  d_cascade = defel;
1711  cascade = defGetBoolean(d_cascade);
1712  }
1713  else
1714  elog(ERROR, "unrecognized option: %s", defel->defname);
1715  }
1716 
1717  /* Call CreateExtensionInternal to do the real work. */
1718  return CreateExtensionInternal(stmt->extname,
1719  schemaName,
1720  versionName,
1721  oldVersionName,
1722  cascade,
1723  NIL,
1724  true);
1725 }
#define NIL
Definition: pg_list.h:69
static ObjectAddress CreateExtensionInternal(char *extensionName, char *schemaName, const char *versionName, const char *oldVersionName, bool cascade, List *parents, bool is_create)
Definition: extension.c:1267
static void check_valid_extension_name(const char *extensionname)
Definition: extension.c:256
int errcode(int sqlerrcode)
Definition: elog.c:575
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:722
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvalidOid
Definition: postgres_ext.h:36
bool creating_extension
Definition: extension.c:67
#define NOTICE
Definition: elog.h:37
#define lfirst(lc)
Definition: pg_list.h:106
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
Oid get_extension_oid(const char *extname, bool missing_ok)
Definition: extension.c:135
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:797
char * defname
Definition: parsenodes.h:719
#define elog
Definition: elog.h:219
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:30

◆ CreateExtensionInternal()

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

Definition at line 1267 of file extension.c.

References ApplyExtensionUpdates(), Assert, CreateSchemaStmt::authrole, check_valid_version_name(), ExtensionControlFile::comment, CreateComments(), CreateSchemaCommand(), ExtensionControlFile::default_version, ereport, errcode(), errmsg(), ERROR, execute_extension_script(), ExtensionRelationId, 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(), identify_update_path(), CreateSchemaStmt::if_not_exists, InsertExtensionTuple(), InvalidOid, lappend_oid(), lfirst, linitial, linitial_oid, list_delete_first(), list_free(), list_length(), makeNode, 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, and stat.

Referenced by CreateExtension(), and get_required_extension().

1274 {
1275  char *origSchemaName = schemaName;
1276  Oid schemaOid = InvalidOid;
1277  Oid extowner = GetUserId();
1278  ExtensionControlFile *pcontrol;
1279  ExtensionControlFile *control;
1280  List *updateVersions;
1281  List *requiredExtensions;
1282  List *requiredSchemas;
1283  Oid extensionOid;
1284  ObjectAddress address;
1285  ListCell *lc;
1286 
1287  /*
1288  * Read the primary control file. Note we assume that it does not contain
1289  * any non-ASCII data, so there is no need to worry about encoding at this
1290  * point.
1291  */
1292  pcontrol = read_extension_control_file(extensionName);
1293 
1294  /*
1295  * Determine the version to install
1296  */
1297  if (versionName == NULL)
1298  {
1299  if (pcontrol->default_version)
1300  versionName = pcontrol->default_version;
1301  else
1302  ereport(ERROR,
1303  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1304  errmsg("version to install must be specified")));
1305  }
1306  check_valid_version_name(versionName);
1307 
1308  /*
1309  * Figure out which script(s) we need to run to install the desired
1310  * version of the extension. If we do not have a script that directly
1311  * does what is needed, we try to find a sequence of update scripts that
1312  * will get us there.
1313  */
1314  if (oldVersionName)
1315  {
1316  /*
1317  * "FROM old_version" was specified, indicating that we're trying to
1318  * update from some unpackaged version of the extension. Locate a
1319  * series of update scripts that will do it.
1320  */
1321  check_valid_version_name(oldVersionName);
1322 
1323  if (strcmp(oldVersionName, versionName) == 0)
1324  ereport(ERROR,
1325  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1326  errmsg("FROM version must be different from installation target version \"%s\"",
1327  versionName)));
1328 
1329  updateVersions = identify_update_path(pcontrol,
1330  oldVersionName,
1331  versionName);
1332 
1333  if (list_length(updateVersions) == 1)
1334  {
1335  /*
1336  * Simple case where there's just one update script to run. We
1337  * will not need any follow-on update steps.
1338  */
1339  Assert(strcmp((char *) linitial(updateVersions), versionName) == 0);
1340  updateVersions = NIL;
1341  }
1342  else
1343  {
1344  /*
1345  * Multi-step sequence. We treat this as installing the version
1346  * that is the target of the first script, followed by successive
1347  * updates to the later versions.
1348  */
1349  versionName = (char *) linitial(updateVersions);
1350  updateVersions = list_delete_first(updateVersions);
1351  }
1352  }
1353  else
1354  {
1355  /*
1356  * No FROM, so we're installing from scratch. If there is an install
1357  * script for the desired version, we only need to run that one.
1358  */
1359  char *filename;
1360  struct stat fst;
1361 
1362  oldVersionName = NULL;
1363 
1364  filename = get_extension_script_filename(pcontrol, NULL, versionName);
1365  if (stat(filename, &fst) == 0)
1366  {
1367  /* Easy, no extra scripts */
1368  updateVersions = NIL;
1369  }
1370  else
1371  {
1372  /* Look for best way to install this version */
1373  List *evi_list;
1374  ExtensionVersionInfo *evi_start;
1375  ExtensionVersionInfo *evi_target;
1376 
1377  /* Extract the version update graph from the script directory */
1378  evi_list = get_ext_ver_list(pcontrol);
1379 
1380  /* Identify the target version */
1381  evi_target = get_ext_ver_info(versionName, &evi_list);
1382 
1383  /* Identify best path to reach target */
1384  evi_start = find_install_path(evi_list, evi_target,
1385  &updateVersions);
1386 
1387  /* Fail if no path ... */
1388  if (evi_start == NULL)
1389  ereport(ERROR,
1390  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1391  errmsg("extension \"%s\" has no installation script nor update path for version \"%s\"",
1392  pcontrol->name, versionName)));
1393 
1394  /* Otherwise, install best starting point and then upgrade */
1395  versionName = evi_start->name;
1396  }
1397  }
1398 
1399  /*
1400  * Fetch control parameters for installation target version
1401  */
1402  control = read_extension_aux_control_file(pcontrol, versionName);
1403 
1404  /*
1405  * Determine the target schema to install the extension into
1406  */
1407  if (schemaName)
1408  {
1409  /* If the user is giving us the schema name, it must exist already. */
1410  schemaOid = get_namespace_oid(schemaName, false);
1411  }
1412 
1413  if (control->schema != NULL)
1414  {
1415  /*
1416  * The extension is not relocatable and the author gave us a schema
1417  * for it.
1418  *
1419  * Unless CASCADE parameter was given, it's an error to give a schema
1420  * different from control->schema if control->schema is specified.
1421  */
1422  if (schemaName && strcmp(control->schema, schemaName) != 0 &&
1423  !cascade)
1424  ereport(ERROR,
1425  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1426  errmsg("extension \"%s\" must be installed in schema \"%s\"",
1427  control->name,
1428  control->schema)));
1429 
1430  /* Always use the schema from control file for current extension. */
1431  schemaName = control->schema;
1432 
1433  /* Find or create the schema in case it does not exist. */
1434  schemaOid = get_namespace_oid(schemaName, true);
1435 
1436  if (!OidIsValid(schemaOid))
1437  {
1439 
1440  csstmt->schemaname = schemaName;
1441  csstmt->authrole = NULL; /* will be created by current user */
1442  csstmt->schemaElts = NIL;
1443  csstmt->if_not_exists = false;
1444  CreateSchemaCommand(csstmt, "(generated CREATE SCHEMA command)",
1445  -1, -1);
1446 
1447  /*
1448  * CreateSchemaCommand includes CommandCounterIncrement, so new
1449  * schema is now visible.
1450  */
1451  schemaOid = get_namespace_oid(schemaName, false);
1452  }
1453  }
1454  else if (!OidIsValid(schemaOid))
1455  {
1456  /*
1457  * Neither user nor author of the extension specified schema; use the
1458  * current default creation namespace, which is the first explicit
1459  * entry in the search_path.
1460  */
1461  List *search_path = fetch_search_path(false);
1462 
1463  if (search_path == NIL) /* nothing valid in search_path? */
1464  ereport(ERROR,
1465  (errcode(ERRCODE_UNDEFINED_SCHEMA),
1466  errmsg("no schema has been selected to create in")));
1467  schemaOid = linitial_oid(search_path);
1468  schemaName = get_namespace_name(schemaOid);
1469  if (schemaName == NULL) /* recently-deleted namespace? */
1470  ereport(ERROR,
1471  (errcode(ERRCODE_UNDEFINED_SCHEMA),
1472  errmsg("no schema has been selected to create in")));
1473 
1474  list_free(search_path);
1475  }
1476 
1477  /*
1478  * We don't check creation rights on the target namespace here. If the
1479  * extension script actually creates any objects there, it will fail if
1480  * the user doesn't have such permissions. But there are cases such as
1481  * procedural languages where it's convenient to set schema = pg_catalog
1482  * yet we don't want to restrict the command to users with ACL_CREATE for
1483  * pg_catalog.
1484  */
1485 
1486  /*
1487  * Look up the prerequisite extensions, install them if necessary, and
1488  * build lists of their OIDs and the OIDs of their target schemas.
1489  */
1490  requiredExtensions = NIL;
1491  requiredSchemas = NIL;
1492  foreach(lc, control->requires)
1493  {
1494  char *curreq = (char *) lfirst(lc);
1495  Oid reqext;
1496  Oid reqschema;
1497 
1498  reqext = get_required_extension(curreq,
1499  extensionName,
1500  origSchemaName,
1501  cascade,
1502  parents,
1503  is_create);
1504  reqschema = get_extension_schema(reqext);
1505  requiredExtensions = lappend_oid(requiredExtensions, reqext);
1506  requiredSchemas = lappend_oid(requiredSchemas, reqschema);
1507  }
1508 
1509  /*
1510  * Insert new tuple into pg_extension, and create dependency entries.
1511  */
1512  address = InsertExtensionTuple(control->name, extowner,
1513  schemaOid, control->relocatable,
1514  versionName,
1515  PointerGetDatum(NULL),
1516  PointerGetDatum(NULL),
1517  requiredExtensions);
1518  extensionOid = address.objectId;
1519 
1520  /*
1521  * Apply any control-file comment on extension
1522  */
1523  if (control->comment != NULL)
1524  CreateComments(extensionOid, ExtensionRelationId, 0, control->comment);
1525 
1526  /*
1527  * Execute the installation script file
1528  */
1529  execute_extension_script(extensionOid, control,
1530  oldVersionName, versionName,
1531  requiredSchemas,
1532  schemaName, schemaOid);
1533 
1534  /*
1535  * If additional update scripts have to be executed, apply the updates as
1536  * though a series of ALTER EXTENSION UPDATE commands were given
1537  */
1538  ApplyExtensionUpdates(extensionOid, pcontrol,
1539  versionName, updateVersions,
1540  origSchemaName, cascade, is_create);
1541 
1542  return address;
1543 }
#define NIL
Definition: pg_list.h:69
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:3005
static Oid get_extension_schema(Oid ext_oid)
Definition: extension.c:219
static ExtensionVersionInfo * get_ext_ver_info(const char *versionname, List **evi_list)
Definition: extension.c:952
static char * get_extension_script_filename(ExtensionControlFile *control, const char *from_version, const char *version)
Definition: extension.c:434
static ExtensionControlFile * read_extension_control_file(const char *extname)
Definition: extension.c:603
static Oid get_required_extension(char *reqExtensionName, char *extensionName, char *origSchemaName, bool cascade, List *parents, bool is_create)
Definition: extension.c:1549
Oid GetUserId(void)
Definition: miscinit.c:284
#define PointerGetDatum(X)
Definition: postgres.h:562
static List * get_ext_ver_list(ExtensionControlFile *control)
Definition: extension.c:1013
static void ApplyExtensionUpdates(Oid extensionOid, ExtensionControlFile *pcontrol, const char *initialVersion, List *updateVersions, char *origSchemaName, bool cascade, bool is_create)
Definition: extension.c:3013
int errcode(int sqlerrcode)
Definition: elog.c:575
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
#define OidIsValid(objectId)
Definition: c.h:576
RoleSpec * authrole
Definition: parsenodes.h:1679
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:786
#define linitial(l)
Definition: pg_list.h:111
#define ERROR
Definition: elog.h:43
static List * identify_update_path(ExtensionControlFile *control, const char *oldVersion, const char *newVersion)
Definition: extension.c:1076
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3047
static ExtensionControlFile * read_extension_aux_control_file(const ExtensionControlFile *pcontrol, const char *version)
Definition: extension.c:631
Oid CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString, int stmt_location, int stmt_len)
Definition: schemacmds.c:51
static ExtensionVersionInfo * find_install_path(List *evi_list, ExtensionVersionInfo *evi_target, List **best_path)
Definition: extension.c:1212
#define ereport(elevel, rest)
Definition: elog.h:122
#define stat(a, b)
Definition: win32_port.h:266
char * default_version
Definition: extension.c:77
static void check_valid_version_name(const char *versionname)
Definition: extension.c:303
#define InvalidOid
Definition: postgres_ext.h:36
#define makeNode(_type_)
Definition: nodes.h:559
#define Assert(condition)
Definition: c.h:670
#define lfirst(lc)
Definition: pg_list.h:106
ObjectAddress InsertExtensionTuple(const char *extName, Oid extOwner, Oid schemaOid, bool relocatable, const char *extVersion, Datum extConfig, Datum extCondition, List *requiredExtensions)
Definition: extension.c:1741
#define linitial_oid(l)
Definition: pg_list.h:113
static int list_length(const List *l)
Definition: pg_list.h:89
static char * filename
Definition: pg_dumpall.c:90
int errmsg(const char *fmt,...)
Definition: elog.c:797
void list_free(List *list)
Definition: list.c:1133
#define ExtensionRelationId
Definition: pg_extension.h:29
Definition: pg_list.h:45
List * fetch_search_path(bool includeImplicit)
Definition: namespace.c:4168
List * list_delete_first(List *list)
Definition: list.c:666

◆ ExecAlterExtensionContentsStmt()

ObjectAddress ExecAlterExtensionContentsStmt ( AlterExtensionContentsStmt stmt,
ObjectAddress objAddr 
)

Definition at line 3171 of file extension.c.

References ACL_KIND_EXTENSION, aclcheck_error(), ACLCHECK_NOT_OWNER, AlterExtensionContentsStmt::action, Assert, check_object_ownership(), ObjectAddress::classId, deleteDependencyRecordsForClass(), DEPENDENCY_EXTENSION, elog, ereport, errcode(), errmsg(), ERROR, extension_config_remove(), ExtensionRelationId, AlterExtensionContentsStmt::extname, get_extension_name(), get_extension_oid(), get_extension_schema(), get_namespace_name(), get_object_address(), getExtensionOfObject(), getObjectDescription(), GetUserId(), InvokeObjectPostAlterHook, NamespaceRelationId, NoLock, AlterExtensionContentsStmt::object, ObjectAddress::objectId, ObjectAddress::objectSubId, AlterExtensionContentsStmt::objtype, OidIsValid, pg_extension_ownercheck(), recordDependencyOn(), recordExtObjInitPriv(), relation_close(), RelationRelationId, removeExtObjInitPriv(), and ShareUpdateExclusiveLock.

Referenced by ProcessUtilitySlow().

3173 {
3174  ObjectAddress extension;
3175  ObjectAddress object;
3176  Relation relation;
3177  Oid oldExtension;
3178 
3179  extension.classId = ExtensionRelationId;
3180  extension.objectId = get_extension_oid(stmt->extname, false);
3181  extension.objectSubId = 0;
3182 
3183  /* Permission check: must own extension */
3184  if (!pg_extension_ownercheck(extension.objectId, GetUserId()))
3186  stmt->extname);
3187 
3188  /*
3189  * Translate the parser representation that identifies the object into an
3190  * ObjectAddress. get_object_address() will throw an error if the object
3191  * does not exist, and will also acquire a lock on the object to guard
3192  * against concurrent DROP and ALTER EXTENSION ADD/DROP operations.
3193  */
3194  object = get_object_address(stmt->objtype, stmt->object,
3195  &relation, ShareUpdateExclusiveLock, false);
3196 
3197  Assert(object.objectSubId == 0);
3198  if (objAddr)
3199  *objAddr = object;
3200 
3201  /* Permission check: must own target object, too */
3202  check_object_ownership(GetUserId(), stmt->objtype, object,
3203  stmt->object, relation);
3204 
3205  /*
3206  * Check existing extension membership.
3207  */
3208  oldExtension = getExtensionOfObject(object.classId, object.objectId);
3209 
3210  if (stmt->action > 0)
3211  {
3212  /*
3213  * ADD, so complain if object is already attached to some extension.
3214  */
3215  if (OidIsValid(oldExtension))
3216  ereport(ERROR,
3217  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3218  errmsg("%s is already a member of extension \"%s\"",
3219  getObjectDescription(&object),
3220  get_extension_name(oldExtension))));
3221 
3222  /*
3223  * Prevent a schema from being added to an extension if the schema
3224  * contains the extension. That would create a dependency loop.
3225  */
3226  if (object.classId == NamespaceRelationId &&
3227  object.objectId == get_extension_schema(extension.objectId))
3228  ereport(ERROR,
3229  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3230  errmsg("cannot add schema \"%s\" to extension \"%s\" "
3231  "because the schema contains the extension",
3232  get_namespace_name(object.objectId),
3233  stmt->extname)));
3234 
3235  /*
3236  * OK, add the dependency.
3237  */
3238  recordDependencyOn(&object, &extension, DEPENDENCY_EXTENSION);
3239 
3240  /*
3241  * Also record the initial ACL on the object, if any.
3242  *
3243  * Note that this will handle the object's ACLs, as well as any ACLs
3244  * on object subIds. (In other words, when the object is a table,
3245  * this will record the table's ACL and the ACLs for the columns on
3246  * the table, if any).
3247  */
3248  recordExtObjInitPriv(object.objectId, object.classId);
3249  }
3250  else
3251  {
3252  /*
3253  * DROP, so complain if it's not a member.
3254  */
3255  if (oldExtension != extension.objectId)
3256  ereport(ERROR,
3257  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3258  errmsg("%s is not a member of extension \"%s\"",
3259  getObjectDescription(&object),
3260  stmt->extname)));
3261 
3262  /*
3263  * OK, drop the dependency.
3264  */
3265  if (deleteDependencyRecordsForClass(object.classId, object.objectId,
3267  DEPENDENCY_EXTENSION) != 1)
3268  elog(ERROR, "unexpected number of extension dependency records");
3269 
3270  /*
3271  * If it's a relation, it might have an entry in the extension's
3272  * extconfig array, which we must remove.
3273  */
3274  if (object.classId == RelationRelationId)
3275  extension_config_remove(extension.objectId, object.objectId);
3276 
3277  /*
3278  * Remove all the initial ACLs, if any.
3279  *
3280  * Note that this will remove the object's ACLs, as well as any ACLs
3281  * on object subIds. (In other words, when the object is a table,
3282  * this will remove the table's ACL and the ACLs for the columns on
3283  * the table, if any).
3284  */
3285  removeExtObjInitPriv(object.objectId, object.classId);
3286  }
3287 
3289 
3290  /*
3291  * If get_object_address() opened the relation for us, we close it to keep
3292  * the reference count correct - but we retain any locks acquired by
3293  * get_object_address() until commit time, to guard against concurrent
3294  * activity.
3295  */
3296  if (relation != NULL)
3297  relation_close(relation, NoLock);
3298 
3299  return extension;
3300 }
void recordExtObjInitPriv(Oid objoid, Oid classoid)
Definition: aclchk.c:5328
#define NamespaceRelationId
Definition: pg_namespace.h:34
Oid getExtensionOfObject(Oid classId, Oid objectId)
Definition: pg_depend.c:447
static Oid get_extension_schema(Oid ext_oid)
Definition: extension.c:219
Oid GetUserId(void)
Definition: miscinit.c:284
#define RelationRelationId
Definition: pg_class.h:29
char * get_extension_name(Oid ext_oid)
Definition: extension.c:180
int errcode(int sqlerrcode)
Definition: elog.c:575
static void extension_config_remove(Oid extensionoid, Oid tableoid)
Definition: extension.c:2510
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1266
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:576
char * getObjectDescription(const ObjectAddress *object)
#define ERROR
Definition: elog.h:43
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3047
#define NoLock
Definition: lockdefs.h:34
bool pg_extension_ownercheck(Oid ext_oid, Oid roleid)
Definition: aclchk.c:5042
void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, const char *objectname)
Definition: aclchk.c:3399
#define ereport(elevel, rest)
Definition: elog.h:122
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:163
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition: pg_depend.c:241
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
#define Assert(condition)
Definition: c.h:670
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:135
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define elog
Definition: elog.h:219
#define ExtensionRelationId
Definition: pg_extension.h:29
void removeExtObjInitPriv(Oid objoid, Oid classoid)
Definition: aclchk.c:5617

◆ ExecAlterExtensionStmt()

ObjectAddress ExecAlterExtensionStmt ( ParseState pstate,
AlterExtensionStmt stmt 
)

Definition at line 2863 of file extension.c.

References AccessShareLock, ACL_KIND_EXTENSION, aclcheck_error(), ACLCHECK_NOT_OWNER, Anum_pg_extension_extname, Anum_pg_extension_extversion, ApplyExtensionUpdates(), DefElem::arg, BTEqualStrategyNumber, check_valid_version_name(), creating_extension, CStringGetDatum, DatumGetTextPP, ExtensionControlFile::default_version, DefElem::defname, elog, ereport, errcode(), errmsg(), ERROR, ExtensionNameIndexId, ExtensionRelationId, AlterExtensionStmt::extname, GetUserId(), heap_close, heap_getattr, heap_open(), HeapTupleGetOid, HeapTupleIsValid, identify_update_path(), InvalidObjectAddress, lfirst, DefElem::location, NOTICE, ObjectAddressSet, AlterExtensionStmt::options, parser_errposition(), pg_extension_ownercheck(), read_extension_control_file(), RelationGetDescr, ScanKeyInit(), strVal, systable_beginscan(), systable_endscan(), systable_getnext(), and text_to_cstring().

Referenced by ProcessUtilitySlow().

2864 {
2865  DefElem *d_new_version = NULL;
2866  char *versionName;
2867  char *oldVersionName;
2868  ExtensionControlFile *control;
2869  Oid extensionOid;
2870  Relation extRel;
2871  ScanKeyData key[1];
2872  SysScanDesc extScan;
2873  HeapTuple extTup;
2874  List *updateVersions;
2875  Datum datum;
2876  bool isnull;
2877  ListCell *lc;
2878  ObjectAddress address;
2879 
2880  /*
2881  * We use global variables to track the extension being created, so we can
2882  * create/update only one extension at the same time.
2883  */
2884  if (creating_extension)
2885  ereport(ERROR,
2886  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2887  errmsg("nested ALTER EXTENSION is not supported")));
2888 
2889  /*
2890  * Look up the extension --- it must already exist in pg_extension
2891  */
2893 
2894  ScanKeyInit(&key[0],
2896  BTEqualStrategyNumber, F_NAMEEQ,
2897  CStringGetDatum(stmt->extname));
2898 
2899  extScan = systable_beginscan(extRel, ExtensionNameIndexId, true,
2900  NULL, 1, key);
2901 
2902  extTup = systable_getnext(extScan);
2903 
2904  if (!HeapTupleIsValid(extTup))
2905  ereport(ERROR,
2906  (errcode(ERRCODE_UNDEFINED_OBJECT),
2907  errmsg("extension \"%s\" does not exist",
2908  stmt->extname)));
2909 
2910  extensionOid = HeapTupleGetOid(extTup);
2911 
2912  /*
2913  * Determine the existing version we are updating from
2914  */
2916  RelationGetDescr(extRel), &isnull);
2917  if (isnull)
2918  elog(ERROR, "extversion is null");
2919  oldVersionName = text_to_cstring(DatumGetTextPP(datum));
2920 
2921  systable_endscan(extScan);
2922 
2923  heap_close(extRel, AccessShareLock);
2924 
2925  /* Permission check: must own extension */
2926  if (!pg_extension_ownercheck(extensionOid, GetUserId()))
2928  stmt->extname);
2929 
2930  /*
2931  * Read the primary control file. Note we assume that it does not contain
2932  * any non-ASCII data, so there is no need to worry about encoding at this
2933  * point.
2934  */
2935  control = read_extension_control_file(stmt->extname);
2936 
2937  /*
2938  * Read the statement option list
2939  */
2940  foreach(lc, stmt->options)
2941  {
2942  DefElem *defel = (DefElem *) lfirst(lc);
2943 
2944  if (strcmp(defel->defname, "new_version") == 0)
2945  {
2946  if (d_new_version)
2947  ereport(ERROR,
2948  (errcode(ERRCODE_SYNTAX_ERROR),
2949  errmsg("conflicting or redundant options"),
2950  parser_errposition(pstate, defel->location)));
2951  d_new_version = defel;
2952  }
2953  else
2954  elog(ERROR, "unrecognized option: %s", defel->defname);
2955  }
2956 
2957  /*
2958  * Determine the version to update to
2959  */
2960  if (d_new_version && d_new_version->arg)
2961  versionName = strVal(d_new_version->arg);
2962  else if (control->default_version)
2963  versionName = control->default_version;
2964  else
2965  {
2966  ereport(ERROR,
2967  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2968  errmsg("version to install must be specified")));
2969  versionName = NULL; /* keep compiler quiet */
2970  }
2971  check_valid_version_name(versionName);
2972 
2973  /*
2974  * If we're already at that version, just say so
2975  */
2976  if (strcmp(oldVersionName, versionName) == 0)
2977  {
2978  ereport(NOTICE,
2979  (errmsg("version \"%s\" of extension \"%s\" is already installed",
2980  versionName, stmt->extname)));
2981  return InvalidObjectAddress;
2982  }
2983 
2984  /*
2985  * Identify the series of update script files we need to execute
2986  */
2987  updateVersions = identify_update_path(control,
2988  oldVersionName,
2989  versionName);
2990 
2991  /*
2992  * Update the pg_extension row and execute the update scripts, one at a
2993  * time
2994  */
2995  ApplyExtensionUpdates(extensionOid, control,
2996  oldVersionName, updateVersions,
2997  NULL, false, false);
2998 
2999  ObjectAddressSet(address, ExtensionRelationId, extensionOid);
3000 
3001  return address;
3002 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define ExtensionNameIndexId
Definition: indexing.h:321
static ExtensionControlFile * read_extension_control_file(const char *extname)
Definition: extension.c:603
#define RelationGetDescr(relation)
Definition: rel.h:437
Oid GetUserId(void)
Definition: miscinit.c:284
#define Anum_pg_extension_extversion
Definition: pg_extension.h:63
#define DatumGetTextPP(X)
Definition: fmgr.h:256
static void ApplyExtensionUpdates(Oid extensionOid, ExtensionControlFile *pcontrol, const char *initialVersion, List *updateVersions, char *origSchemaName, bool cascade, bool is_create)
Definition: extension.c:3013
#define AccessShareLock
Definition: lockdefs.h:36
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:575
#define heap_close(r, l)
Definition: heapam.h:97
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:328
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
#define ERROR
Definition: elog.h:43
static List * identify_update_path(ExtensionControlFile *control, const char *oldVersion, const char *newVersion)
Definition: extension.c:1076
#define Anum_pg_extension_extname
Definition: pg_extension.h:59
bool pg_extension_ownercheck(Oid ext_oid, Oid roleid)
Definition: aclchk.c:5042
void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, const char *objectname)
Definition: aclchk.c:3399
int location
Definition: parsenodes.h:722
#define CStringGetDatum(X)
Definition: postgres.h:584
#define ereport(elevel, rest)
Definition: elog.h:122
Node * arg
Definition: parsenodes.h:720
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:774
char * default_version
Definition: extension.c:77
uintptr_t Datum
Definition: postgres.h:372
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
static void check_valid_version_name(const char *versionname)
Definition: extension.c:303
bool creating_extension
Definition: extension.c:67
#define NOTICE
Definition: elog.h:37
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define lfirst(lc)
Definition: pg_list.h:106
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
char * text_to_cstring(const text *t)
Definition: varlena.c:182
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:797
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
char * defname
Definition: parsenodes.h:719
#define elog
Definition: elog.h:219
#define ExtensionRelationId
Definition: pg_extension.h:29
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:700
Definition: pg_list.h:45
#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 786 of file extension.c.

References appendStringInfo(), appendStringInfoString(), AtEOXact_GUC(), C_COLLATION_OID, client_min_messages, creating_extension, CStringGetTextDatum, CurrentExtensionObject, StringInfoData::data, DatumGetTextPP, DirectFunctionCall3, DirectFunctionCall4Coll(), ereport, errcode(), errhint(), errmsg(), ERROR, execute_sql_string(), filename, get_extension_script_filename(), get_namespace_name(), GUC_ACTION_SAVE, initStringInfo(), InvalidOid, lfirst_oid, log_min_messages, ExtensionControlFile::module_pathname, ExtensionControlFile::name, NewGUCNestLevel(), PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PGC_S_SESSION, PGC_SUSET, PGC_USERSET, quote_identifier(), read_extension_script_file(), ExtensionControlFile::relocatable, replace_text(), set_config_option(), ExtensionControlFile::superuser, text_to_cstring(), textregexreplace(), and WARNING.

Referenced by ApplyExtensionUpdates(), and CreateExtensionInternal().

791 {
792  char *filename;
793  int save_nestlevel;
794  StringInfoData pathbuf;
795  ListCell *lc;
796 
797  /*
798  * Enforce superuser-ness if appropriate. We postpone this check until
799  * here so that the flag is correctly associated with the right script(s)
800  * if it's set in secondary control files.
801  */
802  if (control->superuser && !superuser())
803  {
804  if (from_version == NULL)
805  ereport(ERROR,
806  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
807  errmsg("permission denied to create extension \"%s\"",
808  control->name),
809  errhint("Must be superuser to create this extension.")));
810  else
811  ereport(ERROR,
812  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
813  errmsg("permission denied to update extension \"%s\"",
814  control->name),
815  errhint("Must be superuser to update this extension.")));
816  }
817 
818  filename = get_extension_script_filename(control, from_version, version);
819 
820  /*
821  * Force client_min_messages and log_min_messages to be at least WARNING,
822  * so that we won't spam the user with useless NOTICE messages from common
823  * script actions like creating shell types.
824  *
825  * We use the equivalent of a function SET option to allow the setting to
826  * persist for exactly the duration of the script execution. guc.c also
827  * takes care of undoing the setting on error.
828  */
829  save_nestlevel = NewGUCNestLevel();
830 
832  (void) set_config_option("client_min_messages", "warning",
834  GUC_ACTION_SAVE, true, 0, false);
836  (void) set_config_option("log_min_messages", "warning",
838  GUC_ACTION_SAVE, true, 0, false);
839 
840  /*
841  * Set up the search path to contain the target schema, then the schemas
842  * of any prerequisite extensions, and nothing else. In particular this
843  * makes the target schema be the default creation target namespace.
844  *
845  * Note: it might look tempting to use PushOverrideSearchPath for this,
846  * but we cannot do that. We have to actually set the search_path GUC in
847  * case the extension script examines or changes it. In any case, the
848  * GUC_ACTION_SAVE method is just as convenient.
849  */
850  initStringInfo(&pathbuf);
851  appendStringInfoString(&pathbuf, quote_identifier(schemaName));
852  foreach(lc, requiredSchemas)
853  {
854  Oid reqschema = lfirst_oid(lc);
855  char *reqname = get_namespace_name(reqschema);
856 
857  if (reqname)
858  appendStringInfo(&pathbuf, ", %s", quote_identifier(reqname));
859  }
860 
861  (void) set_config_option("search_path", pathbuf.data,
863  GUC_ACTION_SAVE, true, 0, false);
864 
865  /*
866  * Set creating_extension and related variables so that
867  * recordDependencyOnCurrentExtension and other functions do the right
868  * things. On failure, ensure we reset these variables.
869  */
870  creating_extension = true;
871  CurrentExtensionObject = extensionOid;
872  PG_TRY();
873  {
874  char *c_sql = read_extension_script_file(control, filename);
875  Datum t_sql;
876 
877  /* We use various functions that want to operate on text datums */
878  t_sql = CStringGetTextDatum(c_sql);
879 
880  /*
881  * Reduce any lines beginning with "\echo" to empty. This allows
882  * scripts to contain messages telling people not to run them via
883  * psql, which has been found to be necessary due to old habits.
884  */
887  t_sql,
888  CStringGetTextDatum("^\\\\echo.*$"),
890  CStringGetTextDatum("ng"));
891 
892  /*
893  * If it's not relocatable, substitute the target schema name for
894  * occurrences of @extschema@.
895  *
896  * For a relocatable extension, we needn't do this. There cannot be
897  * any need for @extschema@, else it wouldn't be relocatable.
898  */
899  if (!control->relocatable)
900  {
901  const char *qSchemaName = quote_identifier(schemaName);
902 
904  t_sql,
905  CStringGetTextDatum("@extschema@"),
906  CStringGetTextDatum(qSchemaName));
907  }
908 
909  /*
910  * If module_pathname was set in the control file, substitute its
911  * value for occurrences of MODULE_PATHNAME.
912  */
913  if (control->module_pathname)
914  {
916  t_sql,
917  CStringGetTextDatum("MODULE_PATHNAME"),
919  }
920 
921  /* And now back to C string */
922  c_sql = text_to_cstring(DatumGetTextPP(t_sql));
923 
924  execute_sql_string(c_sql, filename);
925  }
926  PG_CATCH();
927  {
928  creating_extension = false;
930  PG_RE_THROW();
931  }
932  PG_END_TRY();
933 
934  creating_extension = false;
936 
937  /*
938  * Restore the GUC variables we set above.
939  */
940  AtEOXact_GUC(true, save_nestlevel);
941 }
Oid CurrentExtensionObject
Definition: extension.c:68
int errhint(const char *fmt,...)
Definition: elog.c:987
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:10406
static char * get_extension_script_filename(ExtensionControlFile *control, const char *from_version, const char *version)
Definition: extension.c:434
static void execute_sql_string(const char *sql, const char *filename)
Definition: extension.c:697
Datum replace_text(PG_FUNCTION_ARGS)
Definition: varlena.c:3691
Datum DirectFunctionCall4Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4)
Definition: fmgr.c:769
#define DatumGetTextPP(X)
Definition: fmgr.h:256
int errcode(int sqlerrcode)
Definition: elog.c:575
bool superuser(void)
Definition: superuser.c:47
unsigned int Oid
Definition: postgres_ext.h:31
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
#define ERROR
Definition: elog.h:43
Definition: guc.h:75
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3047
void AtEOXact_GUC(bool isCommit, int nestLevel)
Definition: guc.c:5098
#define ereport(elevel, rest)
Definition: elog.h:122
static char * read_extension_script_file(const ExtensionControlFile *control, const char *filename)
Definition: extension.c:654
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition: fmgr.h:589
void initStringInfo(StringInfo str)
Definition: stringinfo.c:46
#define WARNING
Definition: elog.h:40
char * module_pathname
Definition: extension.c:78
uintptr_t Datum
Definition: postgres.h:372
int log_min_messages
Definition: guc.c:452
#define InvalidOid
Definition: postgres_ext.h:36
bool creating_extension
Definition: extension.c:67
#define PG_CATCH()
Definition: elog.h:293
#define PG_RE_THROW()
Definition: elog.h:314
#define C_COLLATION_OID
Definition: pg_collation.h:78
char * text_to_cstring(const text *t)
Definition: varlena.c:182
int NewGUCNestLevel(void)
Definition: guc.c:5084
static char * filename
Definition: pg_dumpall.c:90
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define CStringGetTextDatum(s)
Definition: builtins.h:91
int client_min_messages
Definition: guc.c:453
Datum textregexreplace(PG_FUNCTION_ARGS)
Definition: regexp.c:636
#define PG_TRY()
Definition: elog.h:284
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:5927
#define PG_END_TRY()
Definition: elog.h:300
#define lfirst_oid(lc)
Definition: pg_list.h:108

◆ execute_sql_string()

static void execute_sql_string ( const char *  sql,
const char *  filename 
)
static

Definition at line 697 of file extension.c.

References CommandCounterIncrement(), CreateDestReceiver(), CreateQueryDesc(), CURSOR_OPT_PARALLEL_OK, generate_unaccent_rules::dest, DestNone, ereport, errcode(), errmsg(), ERROR, ExecutorEnd(), ExecutorFinish(), ExecutorRun(), ExecutorStart(), ForwardScanDirection, FreeQueryDesc(), GetActiveSnapshot(), GetTransactionSnapshot(), IsA, lfirst_node, pg_analyze_and_rewrite(), pg_parse_query(), pg_plan_queries(), PopActiveSnapshot(), PROCESS_UTILITY_QUERY, ProcessUtility(), PushActiveSnapshot(), and PlannedStmt::utilityStmt.

Referenced by execute_extension_script().

698 {
699  List *raw_parsetree_list;
701  ListCell *lc1;
702 
703  /*
704  * Parse the SQL string into a list of raw parse trees.
705  */
706  raw_parsetree_list = pg_parse_query(sql);
707 
708  /* All output from SELECTs goes to the bit bucket */
710 
711  /*
712  * Do parse analysis, rule rewrite, planning, and execution for each raw
713  * parsetree. We must fully execute each query before beginning parse
714  * analysis on the next one, since there may be interdependencies.
715  */
716  foreach(lc1, raw_parsetree_list)
717  {
718  RawStmt *parsetree = lfirst_node(RawStmt, lc1);
719  List *stmt_list;
720  ListCell *lc2;
721 
722  /* Be sure parser can see any DDL done so far */
724 
725  stmt_list = pg_analyze_and_rewrite(parsetree,
726  sql,
727  NULL,
728  0,
729  NULL);
730  stmt_list = pg_plan_queries(stmt_list, CURSOR_OPT_PARALLEL_OK, NULL);
731 
732  foreach(lc2, stmt_list)
733  {
734  PlannedStmt *stmt = lfirst_node(PlannedStmt, lc2);
735 
737 
739 
740  if (stmt->utilityStmt == NULL)
741  {
742  QueryDesc *qdesc;
743 
744  qdesc = CreateQueryDesc(stmt,
745  sql,
746  GetActiveSnapshot(), NULL,
747  dest, NULL, NULL, 0);
748 
749  ExecutorStart(qdesc, 0);
750  ExecutorRun(qdesc, ForwardScanDirection, 0, true);
751  ExecutorFinish(qdesc);
752  ExecutorEnd(qdesc);
753 
754  FreeQueryDesc(qdesc);
755  }
756  else
757  {
758  if (IsA(stmt->utilityStmt, TransactionStmt))
759  ereport(ERROR,
760  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
761  errmsg("transaction control statements are not allowed within an extension script")));
762 
763  ProcessUtility(stmt,
764  sql,
766  NULL,
767  NULL,
768  dest,
769  NULL);
770  }
771 
773  }
774  }
775 
776  /* Be sure to advance the command counter after the last script command */
778 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:562
void FreeQueryDesc(QueryDesc *qdesc)
Definition: pquery.c:105
void ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:140
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:839
void ProcessUtility(PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, char *completionTag)
Definition: utility.c:335
int errcode(int sqlerrcode)
Definition: elog.c:575
void PopActiveSnapshot(void)
Definition: snapmgr.c:812
List * pg_analyze_and_rewrite(RawStmt *parsetree, const char *query_string, Oid *paramTypes, int numParams, QueryEnvironment *queryEnv)
Definition: postgres.c:649
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:304
void ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:459
#define ERROR
Definition: elog.h:43
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: execMain.c:297
List * pg_parse_query(const char *query_string)
Definition: postgres.c:607
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 lfirst_node(type, lc)
Definition: pg_list.h:109
Definition: dest.h:88
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:733
DestReceiver * CreateDestReceiver(CommandDest dest)
Definition: dest.c:109
Node * utilityStmt
Definition: plannodes.h:94
#define ereport(elevel, rest)
Definition: elog.h:122
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:399
void CommandCounterIncrement(void)
Definition: xact.c:915
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2646
int errmsg(const char *fmt,...)
Definition: elog.c:797
Definition: pg_list.h:45
List * pg_plan_queries(List *querytrees, int cursorOptions, ParamListInfo boundParams)
Definition: postgres.c:851

◆ extension_config_remove()

static void extension_config_remove ( Oid  extensionoid,
Oid  tableoid 
)
static

Definition at line 2510 of file extension.c.

References Anum_pg_extension_extcondition, Anum_pg_extension_extconfig, ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_HASNULL, ARR_LBOUND, ARR_NDIM, BTEqualStrategyNumber, CatalogTupleUpdate(), construct_array(), DatumGetArrayTypeP, deconstruct_array(), elog, ERROR, ExtensionOidIndexId, ExtensionRelationId, heap_close, heap_getattr, heap_modify_tuple(), heap_open(), HeapTupleIsValid, i, Natts_pg_extension, ObjectIdAttributeNumber, ObjectIdGetDatum, OIDOID, PointerGetDatum, RelationGetDescr, RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, and TEXTOID.

Referenced by ExecAlterExtensionContentsStmt().

2511 {
2512  Relation extRel;
2513  ScanKeyData key[1];
2514  SysScanDesc extScan;
2515  HeapTuple extTup;
2516  Datum arrayDatum;
2517  int arrayLength;
2518  int arrayIndex;
2519  bool isnull;
2520  Datum repl_val[Natts_pg_extension];
2521  bool repl_null[Natts_pg_extension];
2522  bool repl_repl[Natts_pg_extension];
2523  ArrayType *a;
2524 
2525  /* Find the pg_extension tuple */
2527 
2528  ScanKeyInit(&key[0],
2530  BTEqualStrategyNumber, F_OIDEQ,
2531  ObjectIdGetDatum(extensionoid));
2532 
2533  extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
2534  NULL, 1, key);
2535 
2536  extTup = systable_getnext(extScan);
2537 
2538  if (!HeapTupleIsValid(extTup)) /* should not happen */
2539  elog(ERROR, "could not find tuple for extension %u",
2540  extensionoid);
2541 
2542  /* Search extconfig for the tableoid */
2543  arrayDatum = heap_getattr(extTup, Anum_pg_extension_extconfig,
2544  RelationGetDescr(extRel), &isnull);
2545  if (isnull)
2546  {
2547  /* nothing to do */
2548  a = NULL;
2549  arrayLength = 0;
2550  arrayIndex = -1;
2551  }
2552  else
2553  {
2554  Oid *arrayData;
2555  int i;
2556 
2557  a = DatumGetArrayTypeP(arrayDatum);
2558 
2559  arrayLength = ARR_DIMS(a)[0];
2560  if (ARR_NDIM(a) != 1 ||
2561  ARR_LBOUND(a)[0] != 1 ||
2562  arrayLength < 0 ||
2563  ARR_HASNULL(a) ||
2564  ARR_ELEMTYPE(a) != OIDOID)
2565  elog(ERROR, "extconfig is not a 1-D Oid array");
2566  arrayData = (Oid *) ARR_DATA_PTR(a);
2567 
2568  arrayIndex = -1; /* flag for no deletion needed */
2569 
2570  for (i = 0; i < arrayLength; i++)
2571  {
2572  if (arrayData[i] == tableoid)
2573  {
2574  arrayIndex = i; /* index to remove */
2575  break;
2576  }
2577  }
2578  }
2579 
2580  /* If tableoid is not in extconfig, nothing to do */
2581  if (arrayIndex < 0)
2582  {
2583  systable_endscan(extScan);
2584  heap_close(extRel, RowExclusiveLock);
2585  return;
2586  }
2587 
2588  /* Modify or delete the extconfig value */
2589  memset(repl_val, 0, sizeof(repl_val));
2590  memset(repl_null, false, sizeof(repl_null));
2591  memset(repl_repl, false, sizeof(repl_repl));
2592 
2593  if (arrayLength <= 1)
2594  {
2595  /* removing only element, just set array to null */
2596  repl_null[Anum_pg_extension_extconfig - 1] = true;
2597  }
2598  else
2599  {
2600  /* squeeze out the target element */
2601  Datum *dvalues;
2602  bool *dnulls;
2603  int nelems;
2604  int i;
2605 
2606  deconstruct_array(a, OIDOID, sizeof(Oid), true, 'i',
2607  &dvalues, &dnulls, &nelems);
2608 
2609  /* We already checked there are no nulls, so ignore dnulls */
2610  for (i = arrayIndex; i < arrayLength - 1; i++)
2611  dvalues[i] = dvalues[i + 1];
2612 
2613  a = construct_array(dvalues, arrayLength - 1,
2614  OIDOID, sizeof(Oid), true, 'i');
2615 
2616  repl_val[Anum_pg_extension_extconfig - 1] = PointerGetDatum(a);
2617  }
2618  repl_repl[Anum_pg_extension_extconfig - 1] = true;
2619 
2620  /* Modify or delete the extcondition value */
2621  arrayDatum = heap_getattr(extTup, Anum_pg_extension_extcondition,
2622  RelationGetDescr(extRel), &isnull);
2623  if (isnull)
2624  {
2625  elog(ERROR, "extconfig and extcondition arrays do not match");
2626  }
2627  else
2628  {
2629  a = DatumGetArrayTypeP(arrayDatum);
2630 
2631  if (ARR_NDIM(a) != 1 ||
2632  ARR_LBOUND(a)[0] != 1 ||
2633  ARR_HASNULL(a) ||
2634  ARR_ELEMTYPE(a) != TEXTOID)
2635  elog(ERROR, "extcondition is not a 1-D text array");
2636  if (ARR_DIMS(a)[0] != arrayLength)
2637  elog(ERROR, "extconfig and extcondition arrays do not match");
2638  }
2639 
2640  if (arrayLength <= 1)
2641  {
2642  /* removing only element, just set array to null */
2643  repl_null[Anum_pg_extension_extcondition - 1] = true;
2644  }
2645  else
2646  {
2647  /* squeeze out the target element */
2648  Datum *dvalues;
2649  bool *dnulls;
2650  int nelems;
2651  int i;
2652 
2653  deconstruct_array(a, TEXTOID, -1, false, 'i',
2654  &dvalues, &dnulls, &nelems);
2655 
2656  /* We already checked there are no nulls, so ignore dnulls */
2657  for (i = arrayIndex; i < arrayLength - 1; i++)
2658  dvalues[i] = dvalues[i + 1];
2659 
2660  a = construct_array(dvalues, arrayLength - 1,
2661  TEXTOID, -1, false, 'i');
2662 
2664  }
2665  repl_repl[Anum_pg_extension_extcondition - 1] = true;
2666 
2667  extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
2668  repl_val, repl_null, repl_repl);
2669 
2670  CatalogTupleUpdate(extRel, &extTup->t_self, extTup);
2671 
2672  systable_endscan(extScan);
2673 
2674  heap_close(extRel, RowExclusiveLock);
2675 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define RelationGetDescr(relation)
Definition: rel.h:437
#define ObjectIdAttributeNumber
Definition: sysattr.h:22
#define OIDOID
Definition: pg_type.h:328
#define TEXTOID
Definition: pg_type.h:324
#define PointerGetDatum(X)
Definition: postgres.h:562
ArrayType * construct_array(Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3279
#define Anum_pg_extension_extconfig
Definition: pg_extension.h:64
#define heap_close(r, l)
Definition: heapam.h:97
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:328
#define ARR_LBOUND(a)
Definition: array.h:281
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
#define ARR_DIMS(a)
Definition: array.h:279
ItemPointerData t_self
Definition: htup.h:65
#define ARR_DATA_PTR(a)
Definition: array.h:307
#define RowExclusiveLock
Definition: lockdefs.h:38
#define ARR_HASNULL(a)
Definition: array.h:276
#define ExtensionOidIndexId
Definition: indexing.h:319
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:774
#define Anum_pg_extension_extcondition
Definition: pg_extension.h:65
uintptr_t Datum
Definition: postgres.h:372
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
#define ARR_NDIM(a)
Definition: array.h:275
void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3449
#define Natts_pg_extension
Definition: pg_extension.h:58
int i
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define elog
Definition: elog.h:219
#define ExtensionRelationId
Definition: pg_extension.h:29
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:794
#define ARR_ELEMTYPE(a)
Definition: array.h:277
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define DatumGetArrayTypeP(X)
Definition: array.h:246

◆ find_install_path()

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

Definition at line 1212 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().

1214 {
1215  ExtensionVersionInfo *evi_start = NULL;
1216  ListCell *lc;
1217 
1218  *best_path = NIL;
1219 
1220  /*
1221  * We don't expect to be called for an installable target, but if we are,
1222  * the answer is easy: just start from there, with an empty update path.
1223  */
1224  if (evi_target->installable)
1225  return evi_target;
1226 
1227  /* Consider all installable versions as start points */
1228  foreach(lc, evi_list)
1229  {
1231  List *path;
1232 
1233  if (!evi1->installable)
1234  continue;
1235 
1236  /*
1237  * Find shortest path from evi1 to evi_target; but no need to consider
1238  * paths going through other installable versions.
1239  */
1240  path = find_update_path(evi_list, evi1, evi_target, true, true);
1241  if (path == NIL)
1242  continue;
1243 
1244  /* Remember best path */
1245  if (evi_start == NULL ||
1246  list_length(path) < list_length(*best_path) ||
1247  (list_length(path) == list_length(*best_path) &&
1248  strcmp(evi_start->name, evi1->name) < 0))
1249  {
1250  evi_start = evi1;
1251  *best_path = path;
1252  }
1253  }
1254 
1255  return evi_start;
1256 }
#define NIL
Definition: pg_list.h:69
static List * find_update_path(List *evi_list, ExtensionVersionInfo *evi_start, ExtensionVersionInfo *evi_target, bool reject_indirect, bool reinitialize)
Definition: extension.c:1119
#define lfirst(lc)
Definition: pg_list.h:106
static int list_length(const List *l)
Definition: pg_list.h:89
Definition: pg_list.h:45

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

1124 {
1125  List *result;
1126  ExtensionVersionInfo *evi;
1127  ListCell *lc;
1128 
1129  /* Caller error if start == target */
1130  Assert(evi_start != evi_target);
1131  /* Caller error if reject_indirect and target is installable */
1132  Assert(!(reject_indirect && evi_target->installable));
1133 
1134  if (reinitialize)
1135  {
1136  foreach(lc, evi_list)
1137  {
1138  evi = (ExtensionVersionInfo *) lfirst(lc);
1139  evi->distance_known = false;
1140  evi->distance = INT_MAX;
1141  evi->previous = NULL;
1142  }
1143  }
1144 
1145  evi_start->distance = 0;
1146 
1147  while ((evi = get_nearest_unprocessed_vertex(evi_list)) != NULL)
1148  {
1149  if (evi->distance == INT_MAX)
1150  break; /* all remaining vertices are unreachable */
1151  evi->distance_known = true;
1152  if (evi == evi_target)
1153  break; /* found shortest path to target */
1154  foreach(lc, evi->reachable)
1155  {
1157  int newdist;
1158 
1159  /* if reject_indirect, treat installable versions as unreachable */
1160  if (reject_indirect && evi2->installable)
1161  continue;
1162  newdist = evi->distance + 1;
1163  if (newdist < evi2->distance)
1164  {
1165  evi2->distance = newdist;
1166  evi2->previous = evi;
1167  }
1168  else if (newdist == evi2->distance &&
1169  evi2->previous != NULL &&
1170  strcmp(evi->name, evi2->previous->name) < 0)
1171  {
1172  /*
1173  * Break ties in favor of the version name that comes first
1174  * according to strcmp(). This behavior is undocumented and
1175  * users shouldn't rely on it. We do it just to ensure that
1176  * if there is a tie, the update path that is chosen does not
1177  * depend on random factors like the order in which directory
1178  * entries get visited.
1179  */
1180  evi2->previous = evi;
1181  }
1182  }
1183  }
1184 
1185  /* Return NIL if target is not reachable from start */
1186  if (!evi_target->distance_known)
1187  return NIL;
1188 
1189  /* Build and return list of version names representing the update path */
1190  result = NIL;
1191  for (evi = evi_target; evi != evi_start; evi = evi->previous)
1192  result = lcons(evi->name, result);
1193 
1194  return result;
1195 }
#define NIL
Definition: pg_list.h:69
struct ExtensionVersionInfo * previous
Definition: extension.c:99
static ExtensionVersionInfo * get_nearest_unprocessed_vertex(List *evi_list)
Definition: extension.c:985
List * lcons(void *datum, List *list)
Definition: list.c:259
#define Assert(condition)
Definition: c.h:670
#define lfirst(lc)
Definition: pg_list.h:106
Definition: pg_list.h:45

◆ get_available_versions_for_extension()

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

Definition at line 2076 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, tuplestore_putvalues(), and values.

Referenced by pg_available_extension_versions().

2079 {
2080  List *evi_list;
2081  ListCell *lc;
2082 
2083  /* Extract the version update graph from the script directory */
2084  evi_list = get_ext_ver_list(pcontrol);
2085 
2086  /* For each installable version ... */
2087  foreach(lc, evi_list)
2088  {
2090  ExtensionControlFile *control;
2091  Datum values[7];
2092  bool nulls[7];
2093  ListCell *lc2;
2094 
2095  if (!evi->installable)
2096  continue;
2097 
2098  /*
2099  * Fetch parameters for specific version (pcontrol is not changed)
2100  */
2101  control = read_extension_aux_control_file(pcontrol, evi->name);
2102 
2103  memset(values, 0, sizeof(values));
2104  memset(nulls, 0, sizeof(nulls));
2105 
2106  /* name */
2107  values[0] = DirectFunctionCall1(namein,
2108  CStringGetDatum(control->name));
2109  /* version */
2110  values[1] = CStringGetTextDatum(evi->name);
2111  /* superuser */
2112  values[2] = BoolGetDatum(control->superuser);
2113  /* relocatable */
2114  values[3] = BoolGetDatum(control->relocatable);
2115  /* schema */
2116  if (control->schema == NULL)
2117  nulls[4] = true;
2118  else
2119  values[4] = DirectFunctionCall1(namein,
2120  CStringGetDatum(control->schema));
2121  /* requires */
2122  if (control->requires == NIL)
2123  nulls[5] = true;
2124  else
2125  values[5] = convert_requires_to_datum(control->requires);
2126  /* comment */
2127  if (control->comment == NULL)
2128  nulls[6] = true;
2129  else
2130  values[6] = CStringGetTextDatum(control->comment);
2131 
2132  tuplestore_putvalues(tupstore, tupdesc, values, nulls);
2133 
2134  /*
2135  * Find all non-directly-installable versions that would be installed
2136  * starting from this version, and report them, inheriting the
2137  * parameters that aren't changed in updates from this version.
2138  */
2139  foreach(lc2, evi_list)
2140  {
2142  List *best_path;
2143 
2144  if (evi2->installable)
2145  continue;
2146  if (find_install_path(evi_list, evi2, &best_path) == evi)
2147  {
2148  /*
2149  * Fetch parameters for this version (pcontrol is not changed)
2150  */
2151  control = read_extension_aux_control_file(pcontrol, evi2->name);
2152 
2153  /* name stays the same */
2154  /* version */
2155  values[1] = CStringGetTextDatum(evi2->name);
2156  /* superuser */
2157  values[2] = BoolGetDatum(control->superuser);
2158  /* relocatable */
2159  values[3] = BoolGetDatum(control->relocatable);
2160  /* schema stays the same */
2161  /* requires */
2162  if (control->requires == NIL)
2163  nulls[5] = true;
2164  else
2165  {
2166  values[5] = convert_requires_to_datum(control->requires);
2167  nulls[5] = false;
2168  }
2169  /* comment stays the same */
2170 
2171  tuplestore_putvalues(tupstore, tupdesc, values, nulls);
2172  }
2173  }
2174  }
2175 }
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, Datum *values, bool *isnull)
Definition: tuplestore.c:750
#define NIL
Definition: pg_list.h:69
Datum namein(PG_FUNCTION_ARGS)
Definition: name.c:46
static Datum convert_requires_to_datum(List *requires)
Definition: extension.c:2181
static List * get_ext_ver_list(ExtensionControlFile *control)
Definition: extension.c:1013
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:585
static ExtensionControlFile * read_extension_aux_control_file(const ExtensionControlFile *pcontrol, const char *version)
Definition: extension.c:631
#define CStringGetDatum(X)
Definition: postgres.h:584
static ExtensionVersionInfo * find_install_path(List *evi_list, ExtensionVersionInfo *evi_target, List **best_path)
Definition: extension.c:1212
uintptr_t Datum
Definition: postgres.h:372
#define BoolGetDatum(X)
Definition: postgres.h:408
#define lfirst(lc)
Definition: pg_list.h:106
static Datum values[MAXATTR]
Definition: bootstrap.c:164
#define CStringGetTextDatum(s)
Definition: builtins.h:91
Definition: pg_list.h:45

◆ get_ext_ver_info()

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

Definition at line 952 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().

953 {
955  ListCell *lc;
956 
957  foreach(lc, *evi_list)
958  {
959  evi = (ExtensionVersionInfo *) lfirst(lc);
960  if (strcmp(evi->name, versionname) == 0)
961  return evi;
962  }
963 
965  evi->name = pstrdup(versionname);
966  evi->reachable = NIL;
967  evi->installable = false;
968  /* initialize for later application of Dijkstra's algorithm */
969  evi->distance_known = false;
970  evi->distance = INT_MAX;
971  evi->previous = NULL;
972 
973  *evi_list = lappend(*evi_list, evi);
974 
975  return evi;
976 }
#define NIL
Definition: pg_list.h:69
char * pstrdup(const char *in)
Definition: mcxt.c:1076
struct ExtensionVersionInfo * previous
Definition: extension.c:99
List * lappend(List *list, void *datum)
Definition: list.c:128
#define lfirst(lc)
Definition: pg_list.h:106
void * palloc(Size size)
Definition: mcxt.c:848

◆ get_ext_ver_list()

static List* get_ext_ver_list ( ExtensionControlFile control)
static

Definition at line 1013 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().

1014 {
1015  List *evi_list = NIL;
1016  int extnamelen = strlen(control->name);
1017  char *location;
1018  DIR *dir;
1019  struct dirent *de;
1020 
1021  location = get_extension_script_directory(control);
1022  dir = AllocateDir(location);
1023  while ((de = ReadDir(dir, location)) != NULL)
1024  {
1025  char *vername;
1026  char *vername2;
1027  ExtensionVersionInfo *evi;
1028  ExtensionVersionInfo *evi2;
1029 
1030  /* must be a .sql file ... */
1032  continue;
1033 
1034  /* ... matching extension name followed by separator */
1035  if (strncmp(de->d_name, control->name, extnamelen) != 0 ||
1036  de->d_name[extnamelen] != '-' ||
1037  de->d_name[extnamelen + 1] != '-')
1038  continue;
1039 
1040  /* extract version name(s) from 'extname--something.sql' filename */
1041  vername = pstrdup(de->d_name + extnamelen + 2);
1042  *strrchr(vername, '.') = '\0';
1043  vername2 = strstr(vername, "--");
1044  if (!vername2)
1045  {
1046  /* It's an install, not update, script; record its version name */
1047  evi = get_ext_ver_info(vername, &evi_list);
1048  evi->installable = true;
1049  continue;
1050  }
1051  *vername2 = '\0'; /* terminate first version */
1052  vername2 += 2; /* and point to second */
1053 
1054  /* if there's a third --, it's bogus, ignore it */
1055  if (strstr(vername2, "--"))
1056  continue;
1057 
1058  /* Create ExtensionVersionInfos and link them together */
1059  evi = get_ext_ver_info(vername, &evi_list);
1060  evi2 = get_ext_ver_info(vername2, &evi_list);
1061  evi->reachable = lappend(evi->reachable, evi2);
1062  }
1063  FreeDir(dir);
1064 
1065  return evi_list;
1066 }
#define NIL
Definition: pg_list.h:69
static ExtensionVersionInfo * get_ext_ver_info(const char *versionname, List **evi_list)
Definition: extension.c:952
char * pstrdup(const char *in)
Definition: mcxt.c:1076
Definition: dirent.h:9
static char * get_extension_script_directory(ExtensionControlFile *control)
Definition: extension.c:393
Definition: dirent.c:25
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2373
List * lappend(List *list, void *datum)
Definition: list.c:128
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2439
static bool is_extension_script_filename(const char *filename)
Definition: extension.c:358
char d_name[MAX_PATH]
Definition: dirent.h:14
Definition: pg_list.h:45
int FreeDir(DIR *dir)
Definition: fd.c:2482

◆ get_extension_aux_control_filename()

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

Definition at line 416 of file extension.c.

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

Referenced by parse_extension_control_file().

418 {
419  char *result;
420  char *scriptdir;
421 
422  scriptdir = get_extension_script_directory(control);
423 
424  result = (char *) palloc(MAXPGPATH);
425  snprintf(result, MAXPGPATH, "%s/%s--%s.control",
426  scriptdir, control->name, version);
427 
428  pfree(scriptdir);
429 
430  return result;
431 }
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
static char * get_extension_script_directory(ExtensionControlFile *control)
Definition: extension.c:393
void pfree(void *pointer)
Definition: mcxt.c:949
#define MAXPGPATH
void * palloc(Size size)
Definition: mcxt.c:848

◆ get_extension_control_directory()

static char* get_extension_control_directory ( void  )
static

Definition at line 366 of file extension.c.

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

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

367 {
368  char sharepath[MAXPGPATH];
369  char *result;
370 
371  get_share_path(my_exec_path, sharepath);
372  result = (char *) palloc(MAXPGPATH);
373  snprintf(result, MAXPGPATH, "%s/extension", sharepath);
374 
375  return result;
376 }
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
#define MAXPGPATH
char my_exec_path[MAXPGPATH]
Definition: globals.c:64
void * palloc(Size size)
Definition: mcxt.c:848
void get_share_path(const char *my_exec_path, char *ret_path)
Definition: path.c:704

◆ get_extension_control_filename()

static char* get_extension_control_filename ( const char *  extname)
static

Definition at line 379 of file extension.c.

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

Referenced by parse_extension_control_file().

380 {
381  char sharepath[MAXPGPATH];
382  char *result;
383 
384  get_share_path(my_exec_path, sharepath);
385  result = (char *) palloc(MAXPGPATH);
386  snprintf(result, MAXPGPATH, "%s/extension/%s.control",
387  sharepath, extname);
388 
389  return result;
390 }
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
#define MAXPGPATH
char my_exec_path[MAXPGPATH]
Definition: globals.c:64
void * palloc(Size size)
Definition: mcxt.c:848
void get_share_path(const char *my_exec_path, char *ret_path)
Definition: path.c:704

◆ get_extension_name()

char* get_extension_name ( Oid  ext_oid)

Definition at line 180 of file extension.c.

References AccessShareLock, BTEqualStrategyNumber, ExtensionOidIndexId, ExtensionRelationId, GETSTRUCT, heap_close, heap_open(), HeapTupleIsValid, NameStr, ObjectIdAttributeNumber, ObjectIdGetDatum, pstrdup(), ScanKeyInit(), systable_beginscan(), systable_endscan(), and systable_getnext().

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

181 {
182  char *result;
183  Relation rel;
184  SysScanDesc scandesc;
185  HeapTuple tuple;
186  ScanKeyData entry[1];
187 
189 
190  ScanKeyInit(&entry[0],
192  BTEqualStrategyNumber, F_OIDEQ,
193  ObjectIdGetDatum(ext_oid));
194 
195  scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
196  NULL, 1, entry);
197 
198  tuple = systable_getnext(scandesc);
199 
200  /* We assume that there can be at most one matching tuple */
201  if (HeapTupleIsValid(tuple))
202  result = pstrdup(NameStr(((Form_pg_extension) GETSTRUCT(tuple))->extname));
203  else
204  result = NULL;
205 
206  systable_endscan(scandesc);
207 
209 
210  return result;
211 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
#define ObjectIdAttributeNumber
Definition: sysattr.h:22
char * pstrdup(const char *in)
Definition: mcxt.c:1076
#define AccessShareLock
Definition: lockdefs.h:36
#define heap_close(r, l)
Definition: heapam.h:97
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ExtensionOidIndexId
Definition: indexing.h:319
FormData_pg_extension * Form_pg_extension
Definition: pg_extension.h:51
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NameStr(name)
Definition: c.h:547
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define ExtensionRelationId
Definition: pg_extension.h:29
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ get_extension_oid()

Oid get_extension_oid ( const char *  extname,
bool  missing_ok 
)

Definition at line 135 of file extension.c.

References AccessShareLock, Anum_pg_extension_extname, BTEqualStrategyNumber, CStringGetDatum, ereport, errcode(), errmsg(), ERROR, ExtensionNameIndexId, ExtensionRelationId, heap_close, heap_open(), HeapTupleGetOid, HeapTupleIsValid, InvalidOid, OidIsValid, ScanKeyInit(), systable_beginscan(), systable_endscan(), and systable_getnext().

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

136 {
137  Oid result;
138  Relation rel;
139  SysScanDesc scandesc;
140  HeapTuple tuple;
141  ScanKeyData entry[1];
142 
144 
145  ScanKeyInit(&entry[0],
147  BTEqualStrategyNumber, F_NAMEEQ,
148  CStringGetDatum(extname));
149 
150  scandesc = systable_beginscan(rel, ExtensionNameIndexId, true,
151  NULL, 1, entry);
152 
153  tuple = systable_getnext(scandesc);
154 
155  /* We assume that there can be at most one matching tuple */
156  if (HeapTupleIsValid(tuple))
157  result = HeapTupleGetOid(tuple);
158  else
159  result = InvalidOid;
160 
161  systable_endscan(scandesc);
162 
164 
165  if (!OidIsValid(result) && !missing_ok)
166  ereport(ERROR,
167  (errcode(ERRCODE_UNDEFINED_OBJECT),
168  errmsg("extension \"%s\" does not exist",
169  extname)));
170 
171  return result;
172 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define ExtensionNameIndexId
Definition: indexing.h:321
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:575
#define heap_close(r, l)
Definition: heapam.h:97
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:576
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
#define ERROR
Definition: elog.h:43
#define Anum_pg_extension_extname
Definition: pg_extension.h:59
#define CStringGetDatum(X)
Definition: postgres.h:584
#define ereport(elevel, rest)
Definition: elog.h:122
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
int errmsg(const char *fmt,...)
Definition: elog.c:797
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define ExtensionRelationId
Definition: pg_extension.h:29
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:700
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ get_extension_schema()

static Oid get_extension_schema ( Oid  ext_oid)
static

Definition at line 219 of file extension.c.

References AccessShareLock, BTEqualStrategyNumber, ExtensionOidIndexId, ExtensionRelationId, GETSTRUCT, heap_close, heap_open(), HeapTupleIsValid, InvalidOid, ObjectIdAttributeNumber, ObjectIdGetDatum, ScanKeyInit(), systable_beginscan(), systable_endscan(), and systable_getnext().

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

220 {
221  Oid result;
222  Relation rel;
223  SysScanDesc scandesc;
224  HeapTuple tuple;
225  ScanKeyData entry[1];
226 
228 
229  ScanKeyInit(&entry[0],
231  BTEqualStrategyNumber, F_OIDEQ,
232  ObjectIdGetDatum(ext_oid));
233 
234  scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
235  NULL, 1, entry);
236 
237  tuple = systable_getnext(scandesc);
238 
239  /* We assume that there can be at most one matching tuple */
240  if (HeapTupleIsValid(tuple))
241  result = ((Form_pg_extension) GETSTRUCT(tuple))->extnamespace;
242  else
243  result = InvalidOid;
244 
245  systable_endscan(scandesc);
246 
248 
249  return result;
250 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define GETSTRUCT(TUP)
Definition: htup_details.h:661
#define ObjectIdAttributeNumber
Definition: sysattr.h:22
#define AccessShareLock
Definition: lockdefs.h:36
#define heap_close(r, l)
Definition: heapam.h:97
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:328
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ExtensionOidIndexId
Definition: indexing.h:319
FormData_pg_extension * Form_pg_extension
Definition: pg_extension.h:51
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define ExtensionRelationId
Definition: pg_extension.h:29
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ get_extension_script_directory()

static char* get_extension_script_directory ( ExtensionControlFile control)
static

Definition at line 393 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().

394 {
395  char sharepath[MAXPGPATH];
396  char *result;
397 
398  /*
399  * The directory parameter can be omitted, absolute, or relative to the
400  * installation's share directory.
401  */
402  if (!control->directory)
404 
405  if (is_absolute_path(control->directory))
406  return pstrdup(control->directory);
407 
408  get_share_path(my_exec_path, sharepath);
409  result = (char *) palloc(MAXPGPATH);
410  snprintf(result, MAXPGPATH, "%s/%s", sharepath, control->directory);
411 
412  return result;
413 }
char * pstrdup(const char *in)
Definition: mcxt.c:1076
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
#define MAXPGPATH
#define is_absolute_path(filename)
Definition: port.h:86
char my_exec_path[MAXPGPATH]
Definition: globals.c:64
void * palloc(Size size)
Definition: mcxt.c:848
void get_share_path(const char *my_exec_path, char *ret_path)
Definition: path.c:704
static char * get_extension_control_directory(void)
Definition: extension.c:366

◆ get_extension_script_filename()

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

Definition at line 434 of file extension.c.

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

Referenced by CreateExtensionInternal(), and execute_extension_script().

436 {
437  char *result;
438  char *scriptdir;
439 
440  scriptdir = get_extension_script_directory(control);
441 
442  result = (char *) palloc(MAXPGPATH);
443  if (from_version)
444  snprintf(result, MAXPGPATH, "%s/%s--%s--%s.sql",
445  scriptdir, control->name, from_version, version);
446  else
447  snprintf(result, MAXPGPATH, "%s/%s--%s.sql",
448  scriptdir, control->name, version);
449 
450  pfree(scriptdir);
451 
452  return result;
453 }
int snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
static char * get_extension_script_directory(ExtensionControlFile *control)
Definition: extension.c:393
void pfree(void *pointer)
Definition: mcxt.c:949
#define MAXPGPATH
void * palloc(Size size)
Definition: mcxt.c:848

◆ get_nearest_unprocessed_vertex()

static ExtensionVersionInfo* get_nearest_unprocessed_vertex ( List evi_list)
static

Definition at line 985 of file extension.c.

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

Referenced by find_update_path().

986 {
987  ExtensionVersionInfo *evi = NULL;
988  ListCell *lc;
989 
990  foreach(lc, evi_list)
991  {
993 
994  /* only vertices whose distance is still uncertain are candidates */
995  if (evi2->distance_known)
996  continue;
997  /* remember the closest such vertex */
998  if (evi == NULL ||
999  evi->distance > evi2->distance)
1000  evi = evi2;
1001  }
1002 
1003  return evi;
1004 }
#define lfirst(lc)
Definition: pg_list.h:106

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

1555 {
1556  Oid reqExtensionOid;
1557 
1558  reqExtensionOid = get_extension_oid(reqExtensionName, true);
1559  if (!OidIsValid(reqExtensionOid))
1560  {
1561  if (cascade)
1562  {
1563  /* Must install it. */
1564  ObjectAddress addr;
1565  List *cascade_parents;
1566  ListCell *lc;
1567 
1568  /* Check extension name validity before trying to cascade. */
1569  check_valid_extension_name(reqExtensionName);
1570 
1571  /* Check for cyclic dependency between extensions. */
1572  foreach(lc, parents)
1573  {
1574  char *pname = (char *) lfirst(lc);
1575 
1576  if (strcmp(pname, reqExtensionName) == 0)
1577  ereport(ERROR,
1578  (errcode(ERRCODE_INVALID_RECURSION),
1579  errmsg("cyclic dependency detected between extensions \"%s\" and \"%s\"",
1580  reqExtensionName, extensionName)));
1581  }
1582 
1583  ereport(NOTICE,
1584  (errmsg("installing required extension \"%s\"",
1585  reqExtensionName)));
1586 
1587  /* Add current extension to list of parents to pass down. */
1588  cascade_parents = lappend(list_copy(parents), extensionName);
1589 
1590  /*
1591  * Create the required extension. We propagate the SCHEMA option
1592  * if any, and CASCADE, but no other options.
1593  */
1594  addr = CreateExtensionInternal(reqExtensionName,
1595  origSchemaName,
1596  NULL,
1597  NULL,
1598  cascade,
1599  cascade_parents,
1600  is_create);
1601 
1602  /* Get its newly-assigned OID. */
1603  reqExtensionOid = addr.objectId;
1604  }
1605  else
1606  ereport(ERROR,
1607  (errcode(ERRCODE_UNDEFINED_OBJECT),
1608  errmsg("required extension \"%s\" is not installed",
1609  reqExtensionName),
1610  is_create ?
1611  errhint("Use CREATE EXTENSION ... CASCADE to install required extensions too.") : 0));
1612  }
1613 
1614  return reqExtensionOid;
1615 }
int errhint(const char *fmt,...)
Definition: elog.c:987
static ObjectAddress CreateExtensionInternal(char *extensionName, char *schemaName, const char *versionName, const char *oldVersionName, bool cascade, List *parents, bool is_create)
Definition: extension.c:1267
static void check_valid_extension_name(const char *extensionname)
Definition: extension.c:256
List * list_copy(const List *oldlist)
Definition: list.c:1160
int errcode(int sqlerrcode)
Definition: elog.c:575
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:576
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
List * lappend(List *list, void *datum)
Definition: list.c:128
#define NOTICE
Definition: elog.h:37
#define lfirst(lc)
Definition: pg_list.h:106
Oid get_extension_oid(const char *extname, bool missing_ok)
Definition: extension.c:135
int errmsg(const char *fmt,...)
Definition: elog.c:797
Definition: pg_list.h:45

◆ identify_update_path()

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

Definition at line 1076 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 CreateExtensionInternal(), and ExecAlterExtensionStmt().

1078 {
1079  List *result;
1080  List *evi_list;
1081  ExtensionVersionInfo *evi_start;
1082  ExtensionVersionInfo *evi_target;
1083 
1084  /* Extract the version update graph from the script directory */
1085  evi_list = get_ext_ver_list(control);
1086 
1087  /* Initialize start and end vertices */
1088  evi_start = get_ext_ver_info(oldVersion, &evi_list);
1089  evi_target = get_ext_ver_info(newVersion, &evi_list);
1090 
1091  /* Find shortest path */
1092  result = find_update_path(evi_list, evi_start, evi_target, false, false);
1093 
1094  if (result == NIL)
1095  ereport(ERROR,
1096  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1097  errmsg("extension \"%s\" has no update path from version \"%s\" to version \"%s\"",
1098  control->name, oldVersion, newVersion)));
1099 
1100  return result;
1101 }
#define NIL
Definition: pg_list.h:69
static List * find_update_path(List *evi_list, ExtensionVersionInfo *evi_start, ExtensionVersionInfo *evi_target, bool reject_indirect, bool reinitialize)
Definition: extension.c:1119
static ExtensionVersionInfo * get_ext_ver_info(const char *versionname, List **evi_list)
Definition: extension.c:952
static List * get_ext_ver_list(ExtensionControlFile *control)
Definition: extension.c:1013
int errcode(int sqlerrcode)
Definition: elog.c:575
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
int errmsg(const char *fmt,...)
Definition: elog.c:797
Definition: pg_list.h:45

◆ InsertExtensionTuple()

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

Definition at line 1741 of file extension.c.

References Anum_pg_extension_extcondition, Anum_pg_extension_extconfig, Anum_pg_extension_extname, Anum_pg_extension_extnamespace, Anum_pg_extension_extowner, Anum_pg_extension_extrelocatable, Anum_pg_extension_extversion, BoolGetDatum, CatalogTupleInsert(), ObjectAddress::classId, CStringGetDatum, CStringGetTextDatum, DEPENDENCY_NORMAL, DirectFunctionCall1, ExtensionRelationId, heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), InvokeObjectPostCreateHook, lfirst_oid, namein(), NamespaceRelationId, Natts_pg_extension, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, PointerGetDatum, RelationData::rd_att, recordDependencyOn(), recordDependencyOnOwner(), RowExclusiveLock, and values.

Referenced by binary_upgrade_create_empty_extension(), and CreateExtensionInternal().

1745 {
1746  Oid extensionOid;
1747  Relation rel;
1749  bool nulls[Natts_pg_extension];
1750  HeapTuple tuple;
1751  ObjectAddress myself;
1752  ObjectAddress nsp;
1753  ListCell *lc;
1754 
1755  /*
1756  * Build and insert the pg_extension tuple
1757  */
1759 
1760  memset(values, 0, sizeof(values));
1761  memset(nulls, 0, sizeof(nulls));
1762 
1763  values[Anum_pg_extension_extname - 1] =
1765  values[Anum_pg_extension_extowner - 1] = ObjectIdGetDatum(extOwner);
1766  values[Anum_pg_extension_extnamespace - 1] = ObjectIdGetDatum(schemaOid);
1767  values[Anum_pg_extension_extrelocatable - 1] = BoolGetDatum(relocatable);
1768  values[Anum_pg_extension_extversion - 1] = CStringGetTextDatum(extVersion);
1769 
1770  if (extConfig == PointerGetDatum(NULL))
1771  nulls[Anum_pg_extension_extconfig - 1] = true;
1772  else
1773  values[Anum_pg_extension_extconfig - 1] = extConfig;
1774 
1775  if (extCondition == PointerGetDatum(NULL))
1776  nulls[Anum_pg_extension_extcondition - 1] = true;
1777  else
1778  values[Anum_pg_extension_extcondition - 1] = extCondition;
1779 
1780  tuple = heap_form_tuple(rel->rd_att, values, nulls);
1781 
1782  extensionOid = CatalogTupleInsert(rel, tuple);
1783 
1784  heap_freetuple(tuple);
1786 
1787  /*
1788  * Record dependencies on owner, schema, and prerequisite extensions
1789  */
1790  recordDependencyOnOwner(ExtensionRelationId, extensionOid, extOwner);
1791 
1792  myself.classId = ExtensionRelationId;
1793  myself.objectId = extensionOid;
1794  myself.objectSubId = 0;
1795 
1797  nsp.objectId = schemaOid;
1798  nsp.objectSubId = 0;
1799 
1800  recordDependencyOn(&myself, &nsp, DEPENDENCY_NORMAL);
1801 
1802  foreach(lc, requiredExtensions)
1803  {
1804  Oid reqext = lfirst_oid(lc);
1805  ObjectAddress otherext;
1806 
1807  otherext.classId = ExtensionRelationId;
1808  otherext.objectId = reqext;
1809  otherext.objectSubId = 0;
1810 
1811  recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
1812  }
1813  /* Post creation hook for new extension */
1815 
1816  return myself;
1817 }
#define NamespaceRelationId
Definition: pg_namespace.h:34
Datum namein(PG_FUNCTION_ARGS)
Definition: name.c:46
#define Anum_pg_extension_extrelocatable
Definition: pg_extension.h:62
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:145
#define PointerGetDatum(X)
Definition: postgres.h:562
#define Anum_pg_extension_extversion
Definition: pg_extension.h:63
#define Anum_pg_extension_extconfig
Definition: pg_extension.h:64
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:695
#define heap_close(r, l)
Definition: heapam.h:97
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:585
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:159
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1373
unsigned int Oid
Definition: postgres_ext.h:31
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
Oid CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:162
#define Anum_pg_extension_extname
Definition: pg_extension.h:59
#define RowExclusiveLock
Definition: lockdefs.h:38
#define CStringGetDatum(X)
Definition: postgres.h:584
#define Anum_pg_extension_extcondition
Definition: pg_extension.h:65
uintptr_t Datum
Definition: postgres.h:372
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
TupleDesc rd_att
Definition: rel.h:115
#define BoolGetDatum(X)
Definition: postgres.h:408
#define Anum_pg_extension_extowner
Definition: pg_extension.h:60
static Datum values[MAXATTR]
Definition: bootstrap.c:164
#define Natts_pg_extension
Definition: pg_extension.h:58
#define CStringGetTextDatum(s)
Definition: builtins.h:91
#define Anum_pg_extension_extnamespace
Definition: pg_extension.h:61
#define ExtensionRelationId
Definition: pg_extension.h:29
#define lfirst_oid(lc)
Definition: pg_list.h:108

◆ is_extension_control_filename()

static bool is_extension_control_filename ( const char *  filename)
static

Definition at line 350 of file extension.c.

Referenced by pg_available_extension_versions(), and pg_available_extensions().

351 {
352  const char *extension = strrchr(filename, '.');
353 
354  return (extension != NULL) && (strcmp(extension, ".control") == 0);
355 }
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 358 of file extension.c.

Referenced by get_ext_ver_list().

359 {
360  const char *extension = strrchr(filename, '.');
361 
362  return (extension != NULL) && (strcmp(extension, ".sql") == 0);
363 }
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 466 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, and ConfigVariable::value.

Referenced by read_extension_aux_control_file(), and read_extension_control_file().

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

1990 {
1991  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1992  TupleDesc tupdesc;
1993  Tuplestorestate *tupstore;
1994  MemoryContext per_query_ctx;
1995  MemoryContext oldcontext;
1996  char *location;
1997  DIR *dir;
1998  struct dirent *de;
1999 
2000  /* check to see if caller supports us returning a tuplestore */
2001  if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
2002  ereport(ERROR,
2003  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2004  errmsg("set-valued function called in context that cannot accept a set")));
2005  if (!(rsinfo->allowedModes & SFRM_Materialize))
2006  ereport(ERROR,
2007  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2008  errmsg("materialize mode required, but it is not " \
2009  "allowed in this context")));
2010 
2011  /* Build a tuple descriptor for our result type */
2012  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
2013  elog(ERROR, "return type must be a row type");
2014 
2015  /* Build tuplestore to hold the result rows */
2016  per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
2017  oldcontext = MemoryContextSwitchTo(per_query_ctx);
2018 
2019  tupstore = tuplestore_begin_heap(true, false, work_mem);
2020  rsinfo->returnMode = SFRM_Materialize;
2021  rsinfo->setResult = tupstore;
2022  rsinfo->setDesc = tupdesc;
2023 
2024  MemoryContextSwitchTo(oldcontext);
2025 
2026  location = get_extension_control_directory();
2027  dir = AllocateDir(location);
2028 
2029  /*
2030  * If the control directory doesn't exist, we want to silently return an
2031  * empty set. Any other error will be reported by ReadDir.
2032  */
2033  if (dir == NULL && errno == ENOENT)
2034  {
2035  /* do nothing */
2036  }
2037  else
2038  {
2039  while ((de = ReadDir(dir, location)) != NULL)
2040  {
2041  ExtensionControlFile *control;
2042  char *extname;
2043 
2044  if (!is_extension_control_filename(de->d_name))
2045  continue;
2046 
2047  /* extract extension name from 'name.control' filename */
2048  extname = pstrdup(de->d_name);
2049  *strrchr(extname, '.') = '\0';
2050 
2051  /* ignore it if it's an auxiliary control file */
2052  if (strstr(extname, "--"))
2053  continue;
2054 
2055  /* read the control file */
2056  control = read_extension_control_file(extname);
2057 
2058  /* scan extension's script directory for install scripts */
2059  get_available_versions_for_extension(control, tupstore, tupdesc);
2060  }
2061 
2062  FreeDir(dir);
2063  }
2064 
2065  /* clean up and return the tuplestore */
2066  tuplestore_donestoring(tupstore);
2067 
2068  return (Datum) 0;
2069 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:562
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:211
static ExtensionControlFile * read_extension_control_file(const char *extname)
Definition: extension.c:603
char * pstrdup(const char *in)
Definition: mcxt.c:1076
#define tuplestore_donestoring(state)
Definition: tuplestore.h:60
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:575
Definition: dirent.h:9
static void get_available_versions_for_extension(ExtensionControlFile *pcontrol, Tuplestorestate *tupstore, TupleDesc tupdesc)
Definition: extension.c:2076
Definition: dirent.c:25
#define ERROR
Definition: elog.h:43
static bool is_extension_control_filename(const char *filename)
Definition: extension.c:350
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2373
#define ereport(elevel, rest)
Definition: elog.h:122
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
uintptr_t Datum
Definition: postgres.h:372
int work_mem
Definition: globals.c:113
int allowedModes
Definition: execnodes.h:268
SetFunctionReturnMode returnMode
Definition: execnodes.h:270
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2439
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:202
Tuplestorestate * setResult
Definition: execnodes.h:273
ExprContext * econtext
Definition: execnodes.h:266
TupleDesc setDesc
Definition: execnodes.h:274
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define elog
Definition: elog.h:219
int FreeDir(DIR *dir)
Definition: fd.c:2482
static char * get_extension_control_directory(void)
Definition: extension.c:366

◆ pg_available_extensions()

Datum pg_available_extensions ( PG_FUNCTION_ARGS  )

Definition at line 1880 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.

1881 {
1882  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1883  TupleDesc tupdesc;
1884  Tuplestorestate *tupstore;
1885  MemoryContext per_query_ctx;
1886  MemoryContext oldcontext;
1887  char *location;
1888  DIR *dir;
1889  struct dirent *de;
1890 
1891  /* check to see if caller supports us returning a tuplestore */
1892  if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
1893  ereport(ERROR,
1894  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1895  errmsg("set-valued function called in context that cannot accept a set")));
1896  if (!(rsinfo->allowedModes & SFRM_Materialize))
1897  ereport(ERROR,
1898  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1899  errmsg("materialize mode required, but it is not " \
1900  "allowed in this context")));
1901 
1902  /* Build a tuple descriptor for our result type */
1903  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
1904  elog(ERROR, "return type must be a row type");
1905 
1906  /* Build tuplestore to hold the result rows */
1907  per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
1908  oldcontext = MemoryContextSwitchTo(per_query_ctx);
1909 
1910  tupstore = tuplestore_begin_heap(true, false, work_mem);
1911  rsinfo->returnMode = SFRM_Materialize;
1912  rsinfo->setResult = tupstore;
1913  rsinfo->setDesc = tupdesc;
1914 
1915  MemoryContextSwitchTo(oldcontext);
1916 
1917  location = get_extension_control_directory();
1918  dir = AllocateDir(location);
1919 
1920  /*
1921  * If the control directory doesn't exist, we want to silently return an
1922  * empty set. Any other error will be reported by ReadDir.
1923  */
1924  if (dir == NULL && errno == ENOENT)
1925  {
1926  /* do nothing */
1927  }
1928  else
1929  {
1930  while ((de = ReadDir(dir, location)) != NULL)
1931  {
1932  ExtensionControlFile *control;
1933  char *extname;
1934  Datum values[3];
1935  bool nulls[3];
1936 
1937  if (!is_extension_control_filename(de->d_name))
1938  continue;
1939 
1940  /* extract extension name from 'name.control' filename */
1941  extname = pstrdup(de->d_name);
1942  *strrchr(extname, '.') = '\0';
1943 
1944  /* ignore it if it's an auxiliary control file */
1945  if (strstr(extname, "--"))
1946  continue;
1947 
1948  control = read_extension_control_file(extname);
1949 
1950  memset(values, 0, sizeof(values));
1951  memset(nulls, 0, sizeof(nulls));
1952 
1953  /* name */
1954  values[0] = DirectFunctionCall1(namein,
1955  CStringGetDatum(control->name));
1956  /* default_version */
1957  if (control->default_version == NULL)
1958  nulls[1] = true;
1959  else
1960  values[1] = CStringGetTextDatum(control->default_version);
1961  /* comment */
1962  if (control->comment == NULL)
1963  nulls[2] = true;
1964  else
1965  values[2] = CStringGetTextDatum(control->comment);
1966 
1967  tuplestore_putvalues(tupstore, tupdesc, values, nulls);
1968  }
1969 
1970  FreeDir(dir);
1971  }
1972 
1973  /* clean up and return the tuplestore */
1974  tuplestore_donestoring(tupstore);
1975 
1976  return (Datum) 0;
1977 }
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, Datum *values, bool *isnull)
Definition: tuplestore.c:750
#define IsA(nodeptr, _type_)
Definition: nodes.h:562
Datum namein(PG_FUNCTION_ARGS)
Definition: name.c:46
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:211
static ExtensionControlFile * read_extension_control_file(const char *extname)
Definition: extension.c:603
char * pstrdup(const char *in)
Definition: mcxt.c:1076
#define tuplestore_donestoring(state)
Definition: tuplestore.h:60
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:575
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:585
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:350
#define CStringGetDatum(X)
Definition: postgres.h:584
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2373
#define ereport(elevel, rest)
Definition: elog.h:122
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
char * default_version
Definition: extension.c:77
uintptr_t Datum
Definition: postgres.h:372
int work_mem
Definition: globals.c:113
int allowedModes
Definition: execnodes.h:268
SetFunctionReturnMode returnMode
Definition: execnodes.h:270
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2439
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:202
Tuplestorestate * setResult
Definition: execnodes.h:273
static Datum values[MAXATTR]
Definition: bootstrap.c:164
ExprContext * econtext
Definition: execnodes.h:266
TupleDesc setDesc
Definition: execnodes.h:274
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define CStringGetTextDatum(s)
Definition: builtins.h:91
#define elog
Definition: elog.h:219
int FreeDir(DIR *dir)
Definition: fd.c:2482
static char * get_extension_control_directory(void)
Definition: extension.c:366

◆ pg_extension_config_dump()

Datum pg_extension_config_dump ( PG_FUNCTION_ARGS  )

Definition at line 2323 of file extension.c.

References Anum_pg_extension_extcondition, Anum_pg_extension_extconfig, 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, ExtensionRelationId, get_rel_name(), getExtensionOfObject(), heap_close, heap_getattr, heap_modify_tuple(), heap_open(), HeapTupleIsValid, i, Natts_pg_extension, ObjectIdAttributeNumber, ObjectIdGetDatum, OIDOID, PG_GETARG_OID, PG_GETARG_TEXT_PP, PG_RETURN_VOID, PointerGetDatum, RelationGetDescr, RelationRelationId, RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, and TEXTOID.

2324 {
2325  Oid tableoid = PG_GETARG_OID(0);
2326  text *wherecond = PG_GETARG_TEXT_PP(1);
2327  char *tablename;
2328  Relation extRel;
2329  ScanKeyData key[1];
2330  SysScanDesc extScan;
2331  HeapTuple extTup;
2332  Datum arrayDatum;
2333  Datum elementDatum;
2334  int arrayLength;
2335  int arrayIndex;
2336  bool isnull;
2337  Datum repl_val[Natts_pg_extension];
2338  bool repl_null[Natts_pg_extension];
2339  bool repl_repl[Natts_pg_extension];
2340  ArrayType *a;
2341 
2342  /*
2343  * We only allow this to be called from an extension's SQL script. We
2344  * shouldn't need any permissions check beyond that.
2345  */
2346  if (!creating_extension)
2347  ereport(ERROR,
2348  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2349  errmsg("pg_extension_config_dump() can only be called "
2350  "from an SQL script executed by CREATE EXTENSION")));
2351 
2352  /*
2353  * Check that the table exists and is a member of the extension being
2354  * created. This ensures that we don't need to register an additional
2355  * dependency to protect the extconfig entry.
2356  */
2357  tablename = get_rel_name(tableoid);
2358  if (tablename == NULL)
2359  ereport(ERROR,
2361  errmsg("OID %u does not refer to a table", tableoid)));
2362  if (getExtensionOfObject(RelationRelationId, tableoid) !=
2364  ereport(ERROR,
2365  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2366  errmsg("table \"%s\" is not a member of the extension being created",
2367  tablename)));
2368 
2369  /*
2370  * Add the table OID and WHERE condition to the extension's extconfig and
2371  * extcondition arrays.
2372  *
2373  * If the table is already in extconfig, treat this as an update of the
2374  * WHERE condition.
2375  */
2376 
2377  /* Find the pg_extension tuple */
2379 
2380  ScanKeyInit(&key[0],
2382  BTEqualStrategyNumber, F_OIDEQ,
2384 
2385  extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
2386  NULL, 1, key);
2387 
2388  extTup = systable_getnext(extScan);
2389 
2390  if (!HeapTupleIsValid(extTup)) /* should not happen */
2391  elog(ERROR, "could not find tuple for extension %u",
2393 
2394  memset(repl_val, 0, sizeof(repl_val));
2395  memset(repl_null, false, sizeof(repl_null));
2396  memset(repl_repl, false, sizeof(repl_repl));
2397 
2398  /* Build or modify the extconfig value */
2399  elementDatum = ObjectIdGetDatum(tableoid);
2400 
2401  arrayDatum = heap_getattr(extTup, Anum_pg_extension_extconfig,
2402  RelationGetDescr(extRel), &isnull);
2403  if (isnull)
2404  {
2405  /* Previously empty extconfig, so build 1-element array */
2406  arrayLength = 0;
2407  arrayIndex = 1;
2408 
2409  a = construct_array(&elementDatum, 1,
2410  OIDOID,
2411  sizeof(Oid), true, 'i');
2412  }
2413  else
2414  {
2415  /* Modify or extend existing extconfig array */
2416  Oid *arrayData;
2417  int i;
2418 
2419  a = DatumGetArrayTypeP(arrayDatum);
2420 
2421  arrayLength = ARR_DIMS(a)[0];
2422  if (ARR_NDIM(a) != 1 ||
2423  ARR_LBOUND(a)[0] != 1 ||
2424  arrayLength < 0 ||
2425  ARR_HASNULL(a) ||
2426  ARR_ELEMTYPE(a) != OIDOID)
2427  elog(ERROR, "extconfig is not a 1-D Oid array");
2428  arrayData = (Oid *) ARR_DATA_PTR(a);
2429 
2430  arrayIndex = arrayLength + 1; /* set up to add after end */
2431 
2432  for (i = 0; i < arrayLength; i++)
2433  {
2434  if (arrayData[i] == tableoid)
2435  {
2436  arrayIndex = i + 1; /* replace this element instead */
2437  break;
2438  }
2439  }
2440 
2441  a = array_set(a, 1, &arrayIndex,
2442  elementDatum,
2443  false,
2444  -1 /* varlena array */ ,
2445  sizeof(Oid) /* OID's typlen */ ,
2446  true /* OID's typbyval */ ,
2447  'i' /* OID's typalign */ );
2448  }
2449  repl_val[Anum_pg_extension_extconfig - 1] = PointerGetDatum(a);
2450  repl_repl[Anum_pg_extension_extconfig - 1] = true;
2451 
2452  /* Build or modify the extcondition value */
2453  elementDatum = PointerGetDatum(wherecond);
2454 
2455  arrayDatum = heap_getattr(extTup, Anum_pg_extension_extcondition,
2456  RelationGetDescr(extRel), &isnull);
2457  if (isnull)
2458  {
2459  if (arrayLength != 0)
2460  elog(ERROR, "extconfig and extcondition arrays do not match");
2461 
2462  a = construct_array(&elementDatum, 1,
2463  TEXTOID,
2464  -1, false, 'i');
2465  }
2466  else
2467  {
2468  a = DatumGetArrayTypeP(arrayDatum);
2469 
2470  if (ARR_NDIM(a) != 1 ||
2471  ARR_LBOUND(a)[0] != 1 ||
2472  ARR_HASNULL(a) ||
2473  ARR_ELEMTYPE(a) != TEXTOID)
2474  elog(ERROR, "extcondition is not a 1-D text array");
2475  if (ARR_DIMS(a)[0] != arrayLength)
2476  elog(ERROR, "extconfig and extcondition arrays do not match");
2477 
2478  /* Add or replace at same index as in extconfig */
2479  a = array_set(a, 1, &arrayIndex,
2480  elementDatum,
2481  false,
2482  -1 /* varlena array */ ,
2483  -1 /* TEXT's typlen */ ,
2484  false /* TEXT's typbyval */ ,
2485  'i' /* TEXT's typalign */ );
2486  }
2488  repl_repl[Anum_pg_extension_extcondition - 1] = true;
2489 
2490  extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
2491  repl_val, repl_null, repl_repl);
2492 
2493  CatalogTupleUpdate(extRel, &extTup->t_self, extTup);
2494 
2495  systable_endscan(extScan);
2496 
2497  heap_close(extRel, RowExclusiveLock);
2498 
2499  PG_RETURN_VOID();
2500 }
Oid CurrentExtensionObject
Definition: extension.c:68
Oid getExtensionOfObject(Oid classId, Oid objectId)
Definition: pg_depend.c:447
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:61
#define RelationGetDescr(relation)
Definition: rel.h:437
#define ObjectIdAttributeNumber
Definition: sysattr.h:22
#define OIDOID
Definition: pg_type.h:328
#define TEXTOID
Definition: pg_type.h:324
#define PointerGetDatum(X)
Definition: postgres.h:562
#define RelationRelationId
Definition: pg_class.h:29
ArrayType * construct_array(Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3279
int errcode(int sqlerrcode)
Definition: elog.c:575
#define Anum_pg_extension_extconfig
Definition: pg_extension.h:64
ArrayType * array_set(ArrayType *array, int nSubscripts, int *indx, Datum dataValue, bool isNull, int arraytyplen, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3081
#define heap_close(r, l)
Definition: heapam.h:97
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:328
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:273
#define ARR_LBOUND(a)
Definition: array.h:281
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
#define ARR_DIMS(a)
Definition: array.h:279
ItemPointerData t_self
Definition: htup.h:65
#define ARR_DATA_PTR(a)
Definition: array.h:307
#define PG_GETARG_OID(n)
Definition: fmgr.h:240
#define RowExclusiveLock
Definition: lockdefs.h:38
#define ARR_HASNULL(a)
Definition: array.h:276
#define ereport(elevel, rest)
Definition: elog.h:122
#define ExtensionOidIndexId
Definition: indexing.h:319
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:774
#define Anum_pg_extension_extcondition
Definition: pg_extension.h:65
uintptr_t Datum
Definition: postgres.h:372
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
bool creating_extension
Definition: extension.c:67
#define PG_RETURN_VOID()
Definition: fmgr.h:309
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:210
#define ARR_NDIM(a)
Definition: array.h:275
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define Natts_pg_extension
Definition: pg_extension.h:58
int i
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Definition: c.h:487
#define elog
Definition: elog.h:219
#define ExtensionRelationId
Definition: pg_extension.h:29
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:794
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1726
#define ARR_ELEMTYPE(a)
Definition: array.h:277
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define DatumGetArrayTypeP(X)
Definition: array.h:246

◆ pg_extension_update_paths()

Datum pg_extension_update_paths ( PG_FUNCTION_ARGS  )

Definition at line 2209 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.

2210 {
2211  Name extname = PG_GETARG_NAME(0);
2212  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
2213  TupleDesc tupdesc;
2214  Tuplestorestate *tupstore;
2215  MemoryContext per_query_ctx;
2216  MemoryContext oldcontext;
2217  List *evi_list;
2218  ExtensionControlFile *control;
2219  ListCell *lc1;
2220 
2221  /* Check extension name validity before any filesystem access */
2223 
2224  /* check to see if caller supports us returning a tuplestore */
2225  if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
2226  ereport(ERROR,
2227  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2228  errmsg("set-valued function called in context that cannot accept a set")));
2229  if (!(rsinfo->allowedModes & SFRM_Materialize))
2230  ereport(ERROR,
2231  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2232  errmsg("materialize mode required, but it is not " \
2233  "allowed in this context")));
2234 
2235  /* Build a tuple descriptor for our result type */
2236  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
2237  elog(ERROR, "return type must be a row type");
2238 
2239  /* Build tuplestore to hold the result rows */
2240  per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
2241  oldcontext = MemoryContextSwitchTo(per_query_ctx);
2242 
2243  tupstore = tuplestore_begin_heap(true, false, work_mem);
2244  rsinfo->returnMode = SFRM_Materialize;
2245  rsinfo->setResult = tupstore;
2246  rsinfo->setDesc = tupdesc;
2247 
2248  MemoryContextSwitchTo(oldcontext);
2249 
2250  /* Read the extension's control file */
2251  control = read_extension_control_file(NameStr(*extname));
2252 
2253  /* Extract the version update graph from the script directory */
2254  evi_list = get_ext_ver_list(control);
2255 
2256  /* Iterate over all pairs of versions */
2257  foreach(lc1, evi_list)
2258  {
2260  ListCell *lc2;
2261 
2262  foreach(lc2, evi_list)
2263  {
2265  List *path;
2266  Datum values[3];
2267  bool nulls[3];
2268 
2269  if (evi1 == evi2)
2270  continue;
2271 
2272  /* Find shortest path from evi1 to evi2 */
2273  path = find_update_path(evi_list, evi1, evi2, false, true);
2274 
2275  /* Emit result row */
2276  memset(values, 0, sizeof(values));
2277  memset(nulls, 0, sizeof(nulls));
2278 
2279  /* source */
2280  values[0] = CStringGetTextDatum(evi1->name);
2281  /* target */
2282  values[1] = CStringGetTextDatum(evi2->name);
2283  /* path */
2284  if (path == NIL)
2285  nulls[2] = true;
2286  else
2287  {
2288  StringInfoData pathbuf;
2289  ListCell *lcv;
2290 
2291  initStringInfo(&pathbuf);
2292  /* The path doesn't include start vertex, but show it */
2293  appendStringInfoString(&pathbuf, evi1->name);
2294  foreach(lcv, path)
2295  {
2296  char *versionName = (char *) lfirst(lcv);
2297 
2298  appendStringInfoString(&pathbuf, "--");
2299  appendStringInfoString(&pathbuf, versionName);
2300  }
2301  values[2] = CStringGetTextDatum(pathbuf.data);
2302  pfree(pathbuf.data);
2303  }
2304 
2305  tuplestore_putvalues(tupstore, tupdesc, values, nulls);
2306  }
2307  }
2308 
2309  /* clean up and return the tuplestore */
2310  tuplestore_donestoring(tupstore);
2311 
2312  return (Datum) 0;
2313 }
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, Datum *values, bool *isnull)
Definition: tuplestore.c:750
#define NIL
Definition: pg_list.h:69
static List * find_update_path(List *evi_list, ExtensionVersionInfo *evi_start, ExtensionVersionInfo *evi_target, bool reject_indirect, bool reinitialize)
Definition: extension.c:1119
#define IsA(nodeptr, _type_)
Definition: nodes.h:562
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:211
static ExtensionControlFile * read_extension_control_file(const char *extname)
Definition: extension.c:603
static void check_valid_extension_name(const char *extensionname)
Definition: extension.c:256
static List * get_ext_ver_list(ExtensionControlFile *control)
Definition: extension.c:1013
#define tuplestore_donestoring(state)
Definition: tuplestore.h:60
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:575
void pfree(void *pointer)
Definition: mcxt.c:949
#define ERROR
Definition: elog.h:43
Definition: c.h:541
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:157
#define ereport(elevel, rest)
Definition: elog.h:122
void initStringInfo(StringInfo str)
Definition: stringinfo.c:46
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
uintptr_t Datum
Definition: postgres.h:372
int work_mem
Definition: globals.c:113
int allowedModes
Definition: execnodes.h:268
SetFunctionReturnMode returnMode
Definition: execnodes.h:270
#define lfirst(lc)
Definition: pg_list.h:106
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:202
Tuplestorestate * setResult
Definition: execnodes.h:273
static Datum values[MAXATTR]
Definition: bootstrap.c:164
ExprContext * econtext
Definition: execnodes.h:266
TupleDesc setDesc
Definition: execnodes.h:274
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define NameStr(name)
Definition: c.h:547
#define CStringGetTextDatum(s)
Definition: builtins.h:91
#define elog
Definition: elog.h:219
Definition: pg_list.h:45
#define PG_GETARG_NAME(n)
Definition: fmgr.h:243

◆ read_extension_aux_control_file()

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

Definition at line 631 of file extension.c.

References palloc(), and parse_extension_control_file().

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

633 {
634  ExtensionControlFile *acontrol;
635 
636  /*
637  * Flat-copy the struct. Pointer fields share values with original.
638  */
639  acontrol = (ExtensionControlFile *) palloc(sizeof(ExtensionControlFile));
640  memcpy(acontrol, pcontrol, sizeof(ExtensionControlFile));
641 
642  /*
643  * Parse the auxiliary control file, overwriting struct fields
644  */
645  parse_extension_control_file(acontrol, version);
646 
647  return acontrol;
648 }
static void parse_extension_control_file(ExtensionControlFile *control, const char *version)
Definition: extension.c:466
void * palloc(Size size)
Definition: mcxt.c:848

◆ read_extension_control_file()

static ExtensionControlFile* read_extension_control_file ( const char *  extname)
static

Definition at line 603 of file extension.c.

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

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

604 {
605  ExtensionControlFile *control;
606 
607  /*
608  * Set up default values. Pointer fields are initially null.
609  */
610  control = (ExtensionControlFile *) palloc0(sizeof(ExtensionControlFile));
611  control->name = pstrdup(extname);
612  control->relocatable = false;
613  control->superuser = true;
614  control->encoding = -1;
615 
616  /*
617  * Parse the primary control file.
618  */
619  parse_extension_control_file(control, NULL);
620 
621  return control;
622 }
char * pstrdup(const char *in)
Definition: mcxt.c:1076
static void parse_extension_control_file(ExtensionControlFile *control, const char *version)
Definition: extension.c:466
void * palloc0(Size size)
Definition: mcxt.c:877

◆ read_extension_script_file()

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

Definition at line 654 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().

656 {
657  int src_encoding;
658  char *src_str;
659  char *dest_str;
660  int len;
661 
662  src_str = read_whole_file(filename, &len);
663 
664  /* use database encoding if not given */
665  if (control->encoding < 0)
666  src_encoding = GetDatabaseEncoding();
667  else
668  src_encoding = control->encoding;
669 
670  /* make sure that source string is valid in the expected encoding */
671  pg_verify_mbstr_len(src_encoding, src_str, len, false);
672 
673  /*
674  * Convert the encoding to the database encoding. read_whole_file
675  * null-terminated the string, so if no conversion happens the string is
676  * valid as is.
677  */
678  dest_str = pg_any_to_server(src_str, len, src_encoding);
679 
680  return dest_str;
681 }
int pg_verify_mbstr_len(int encoding, const char *mbstr, int len, bool noError)
Definition: wchar.c:1894
static char * read_whole_file(const char *filename, int *length)
Definition: extension.c:3309
int GetDatabaseEncoding(void)
Definition: mbutils.c:1004
static char * filename
Definition: pg_dumpall.c:90
char * pg_any_to_server(const char *s, int len, int encoding)
Definition: mbutils.c:561

◆ read_whole_file()

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

Definition at line 3309 of file extension.c.

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

Referenced by read_extension_script_file().

3310 {
3311  char *buf;
3312  FILE *file;
3313  size_t bytes_to_read;
3314  struct stat fst;
3315 
3316  if (stat(filename, &fst) < 0)
3317  ereport(ERROR,
3319  errmsg("could not stat file \"%s\": %m", filename)));
3320 
3321  if (fst.st_size > (MaxAllocSize - 1))
3322  ereport(ERROR,
3323  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3324  errmsg("file \"%s\" is too large", filename)));
3325  bytes_to_read = (size_t) fst.st_size;
3326 
3327  if ((file = AllocateFile(filename, PG_BINARY_R)) == NULL)
3328  ereport(ERROR,
3330  errmsg("could not open file \"%s\" for reading: %m",
3331  filename)));
3332 
3333  buf = (char *) palloc(bytes_to_read + 1);
3334 
3335  *length = fread(buf, 1, bytes_to_read, file);
3336 
3337  if (ferror(file))
3338  ereport(ERROR,
3340  errmsg("could not read file \"%s\": %m", filename)));
3341 
3342  FreeFile(file);
3343 
3344  buf[*length] = '\0';
3345  return buf;
3346 }
int length(const List *list)
Definition: list.c:1271
int errcode(int sqlerrcode)
Definition: elog.c:575
#define PG_BINARY_R
Definition: c.h:1027
#define ERROR
Definition: elog.h:43
static char * buf
Definition: pg_test_fsync.c:67
int errcode_for_file_access(void)
Definition: elog.c:598
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2123
#define ereport(elevel, rest)
Definition: elog.h:122
#define MaxAllocSize
Definition: memutils.h:40
#define stat(a, b)
Definition: win32_port.h:266
int FreeFile(FILE *file)
Definition: fd.c:2315
static char * filename
Definition: pg_dumpall.c:90
void * palloc(Size size)
Definition: mcxt.c:848
int errmsg(const char *fmt,...)
Definition: elog.c:797

◆ RemoveExtensionById()

void RemoveExtensionById ( Oid  extId)

Definition at line 1826 of file extension.c.

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

Referenced by doDeletion().

1827 {
1828  Relation rel;
1829  SysScanDesc scandesc;
1830  HeapTuple tuple;
1831  ScanKeyData entry[1];
1832 
1833  /*
1834  * Disallow deletion of any extension that's currently open for insertion;
1835  * else subsequent executions of recordDependencyOnCurrentExtension()
1836  * could create dangling pg_depend records that refer to a no-longer-valid
1837  * pg_extension OID. This is needed not so much because we think people
1838  * might write "DROP EXTENSION foo" in foo's own script files, as because
1839  * errors in dependency management in extension script files could give
1840  * rise to cases where an extension is dropped as a result of recursing
1841  * from some contained object. Because of that, we must test for the case
1842  * here, not at some higher level of the DROP EXTENSION command.
1843  */
1844  if (extId == CurrentExtensionObject)
1845  ereport(ERROR,
1846  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1847  errmsg("cannot drop extension \"%s\" because it is being modified",
1848  get_extension_name(extId))));
1849 
1851 
1852  ScanKeyInit(&entry[0],
1854  BTEqualStrategyNumber, F_OIDEQ,
1855  ObjectIdGetDatum(extId));
1856  scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
1857  NULL, 1, entry);
1858 
1859  tuple = systable_getnext(scandesc);
1860 
1861  /* We assume that there can be at most one matching tuple */
1862  if (HeapTupleIsValid(tuple))
1863  CatalogTupleDelete(rel, &tuple->t_self);
1864 
1865  systable_endscan(scandesc);
1866 
1868 }
Oid CurrentExtensionObject
Definition: extension.c:68
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:499
#define ObjectIdAttributeNumber
Definition: sysattr.h:22
char * get_extension_name(Oid ext_oid)
Definition: extension.c:180
int errcode(int sqlerrcode)
Definition: elog.c:575
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:255
#define heap_close(r, l)
Definition: heapam.h:97
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:328
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:416
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
#define RowExclusiveLock
Definition: lockdefs.h:38
#define ereport(elevel, rest)
Definition: elog.h:122
#define ExtensionOidIndexId
Definition: indexing.h:319
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1290
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
int errmsg(const char *fmt,...)
Definition: elog.c:797
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define ExtensionRelationId
Definition: pg_extension.h:29
#define BTEqualStrategyNumber
Definition: stratnum.h:31

Variable Documentation

◆ creating_extension

◆ CurrentExtensionObject