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

Go to the source code of this file.

Data Structures

struct  ExtensionControlFile
 
struct  ExtensionVersionInfo
 

Typedefs

typedef struct ExtensionControlFile ExtensionControlFile
 
typedef struct ExtensionVersionInfo ExtensionVersionInfo
 

Functions

static Listfind_update_path (List *evi_list, ExtensionVersionInfo *evi_start, ExtensionVersionInfo *evi_target, bool reject_indirect, bool reinitialize)
 
static Oid get_required_extension (char *reqExtensionName, char *extensionName, char *origSchemaName, bool cascade, List *parents, bool is_create)
 
static void get_available_versions_for_extension (ExtensionControlFile *pcontrol, Tuplestorestate *tupstore, TupleDesc tupdesc)
 
static Datum convert_requires_to_datum (List *requires)
 
static void ApplyExtensionUpdates (Oid extensionOid, ExtensionControlFile *pcontrol, const char *initialVersion, List *updateVersions, char *origSchemaName, bool cascade, bool is_create)
 
static char * read_whole_file (const char *filename, int *length)
 
Oid get_extension_oid (const char *extname, bool missing_ok)
 
char * get_extension_name (Oid ext_oid)
 
static Oid get_extension_schema (Oid ext_oid)
 
static void check_valid_extension_name (const char *extensionname)
 
static void check_valid_version_name (const char *versionname)
 
static bool is_extension_control_filename (const char *filename)
 
static bool is_extension_script_filename (const char *filename)
 
static char * get_extension_control_directory (void)
 
static char * get_extension_control_filename (const char *extname)
 
static char * get_extension_script_directory (ExtensionControlFile *control)
 
static char * get_extension_aux_control_filename (ExtensionControlFile *control, const char *version)
 
static char * get_extension_script_filename (ExtensionControlFile *control, const char *from_version, const char *version)
 
static void parse_extension_control_file (ExtensionControlFile *control, const char *version)
 
static ExtensionControlFileread_extension_control_file (const char *extname)
 
static ExtensionControlFileread_extension_aux_control_file (const ExtensionControlFile *pcontrol, const char *version)
 
static char * read_extension_script_file (const ExtensionControlFile *control, const char *filename)
 
static void execute_sql_string (const char *sql)
 
static 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 2704 of file extension.c.

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

Referenced by ExecAlterObjectSchemaStmt().

2705 {
2706  Oid extensionOid;
2707  Oid nspOid;
2708  Oid oldNspOid = InvalidOid;
2709  AclResult aclresult;
2710  Relation extRel;
2711  ScanKeyData key[2];
2712  SysScanDesc extScan;
2713  HeapTuple extTup;
2714  Form_pg_extension extForm;
2715  Relation depRel;
2716  SysScanDesc depScan;
2717  HeapTuple depTup;
2718  ObjectAddresses *objsMoved;
2719  ObjectAddress extAddr;
2720 
2721  extensionOid = get_extension_oid(extensionName, false);
2722 
2723  nspOid = LookupCreationNamespace(newschema);
2724 
2725  /*
2726  * Permission check: must own extension. Note that we don't bother to
2727  * check ownership of the individual member objects ...
2728  */
2729  if (!pg_extension_ownercheck(extensionOid, GetUserId()))
2731  extensionName);
2732 
2733  /* Permission check: must have creation rights in target namespace */
2734  aclresult = pg_namespace_aclcheck(nspOid, GetUserId(), ACL_CREATE);
2735  if (aclresult != ACLCHECK_OK)
2736  aclcheck_error(aclresult, OBJECT_SCHEMA, newschema);
2737 
2738  /*
2739  * If the schema is currently a member of the extension, disallow moving
2740  * the extension into the schema. That would create a dependency loop.
2741  */
2742  if (getExtensionOfObject(NamespaceRelationId, nspOid) == extensionOid)
2743  ereport(ERROR,
2744  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2745  errmsg("cannot move extension \"%s\" into schema \"%s\" "
2746  "because the extension contains the schema",
2747  extensionName, newschema)));
2748 
2749  /* Locate the pg_extension tuple */
2750  extRel = table_open(ExtensionRelationId, RowExclusiveLock);
2751 
2752  ScanKeyInit(&key[0],
2753  Anum_pg_extension_oid,
2754  BTEqualStrategyNumber, F_OIDEQ,
2755  ObjectIdGetDatum(extensionOid));
2756 
2757  extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
2758  NULL, 1, key);
2759 
2760  extTup = systable_getnext(extScan);
2761 
2762  if (!HeapTupleIsValid(extTup)) /* should not happen */
2763  elog(ERROR, "could not find tuple for extension %u",
2764  extensionOid);
2765 
2766  /* Copy tuple so we can modify it below */
2767  extTup = heap_copytuple(extTup);
2768  extForm = (Form_pg_extension) GETSTRUCT(extTup);
2769 
2770  systable_endscan(extScan);
2771 
2772  /*
2773  * If the extension is already in the target schema, just silently do
2774  * nothing.
2775  */
2776  if (extForm->extnamespace == nspOid)
2777  {
2778  table_close(extRel, RowExclusiveLock);
2779  return InvalidObjectAddress;
2780  }
2781 
2782  /* Check extension is supposed to be relocatable */
2783  if (!extForm->extrelocatable)
2784  ereport(ERROR,
2785  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2786  errmsg("extension \"%s\" does not support SET SCHEMA",
2787  NameStr(extForm->extname))));
2788 
2789  objsMoved = new_object_addresses();
2790 
2791  /*
2792  * Scan pg_depend to find objects that depend directly on the extension,
2793  * and alter each one's schema.
2794  */
2795  depRel = table_open(DependRelationId, AccessShareLock);
2796 
2797  ScanKeyInit(&key[0],
2798  Anum_pg_depend_refclassid,
2799  BTEqualStrategyNumber, F_OIDEQ,
2800  ObjectIdGetDatum(ExtensionRelationId));
2801  ScanKeyInit(&key[1],
2802  Anum_pg_depend_refobjid,
2803  BTEqualStrategyNumber, F_OIDEQ,
2804  ObjectIdGetDatum(extensionOid));
2805 
2806  depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
2807  NULL, 2, key);
2808 
2809  while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
2810  {
2811  Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
2812  ObjectAddress dep;
2813  Oid dep_oldNspOid;
2814 
2815  /*
2816  * Ignore non-membership dependencies. (Currently, the only other
2817  * case we could see here is a normal dependency from another
2818  * extension.)
2819  */
2820  if (pg_depend->deptype != DEPENDENCY_EXTENSION)
2821  continue;
2822 
2823  dep.classId = pg_depend->classid;
2824  dep.objectId = pg_depend->objid;
2825  dep.objectSubId = pg_depend->objsubid;
2826 
2827  if (dep.objectSubId != 0) /* should not happen */
2828  elog(ERROR, "extension should not have a sub-object dependency");
2829 
2830  /* Relocate the object */
2831  dep_oldNspOid = AlterObjectNamespace_oid(dep.classId,
2832  dep.objectId,
2833  nspOid,
2834  objsMoved);
2835 
2836  /*
2837  * Remember previous namespace of first object that has one
2838  */
2839  if (oldNspOid == InvalidOid && dep_oldNspOid != InvalidOid)
2840  oldNspOid = dep_oldNspOid;
2841 
2842  /*
2843  * If not all the objects had the same old namespace (ignoring any
2844  * that are not in namespaces), complain.
2845  */
2846  if (dep_oldNspOid != InvalidOid && dep_oldNspOid != oldNspOid)
2847  ereport(ERROR,
2848  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2849  errmsg("extension \"%s\" does not support SET SCHEMA",
2850  NameStr(extForm->extname)),
2851  errdetail("%s is not in the extension's schema \"%s\"",
2852  getObjectDescription(&dep),
2853  get_namespace_name(oldNspOid))));
2854  }
2855 
2856  /* report old schema, if caller wants it */
2857  if (oldschema)
2858  *oldschema = oldNspOid;
2859 
2860  systable_endscan(depScan);
2861 
2863 
2864  /* Now adjust pg_extension.extnamespace */
2865  extForm->extnamespace = nspOid;
2866 
2867  CatalogTupleUpdate(extRel, &extTup->t_self, extTup);
2868 
2869  table_close(extRel, RowExclusiveLock);
2870 
2871  /* update dependencies to point to the new schema */
2872  changeDependencyFor(ExtensionRelationId, extensionOid,
2873  NamespaceRelationId, oldNspOid, nspOid);
2874 
2875  InvokeObjectPostAlterHook(ExtensionRelationId, extensionOid, 0);
2876 
2877  ObjectAddressSet(extAddr, ExtensionRelationId, extensionOid);
2878 
2879  return extAddr;
2880 }
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:680
Oid getExtensionOfObject(Oid classId, Oid objectId)
Definition: pg_depend.c:610
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:525
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
Oid GetUserId(void)
Definition: miscinit.c:380
Oid LookupCreationNamespace(const char *nspname)
Definition: namespace.c:2928
#define DependReferenceIndexId
Definition: indexing.h:151
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:608
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2402
unsigned int Oid
Definition: postgres_ext.h:31
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4691
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:352
char * getObjectDescription(const ObjectAddress *object)
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3352
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:444
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define ACL_CREATE
Definition: parsenodes.h:84
ItemPointerData t_self
Definition: htup.h:65
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3094
bool pg_extension_ownercheck(Oid ext_oid, Oid roleid)
Definition: aclchk.c:5249
#define RowExclusiveLock
Definition: lockdefs.h:38
int errdetail(const char *fmt,...)
Definition: elog.c:955
FormData_pg_depend * Form_pg_depend
Definition: pg_depend.h:71
#define ereport(elevel, rest)
Definition: elog.h:141
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
#define ExtensionOidIndexId
Definition: indexing.h:326
FormData_pg_extension * Form_pg_extension
Definition: pg_extension.h:50
AclResult
Definition: acl.h:177
#define InvalidOid
Definition: postgres_ext.h:36
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
Oid get_extension_oid(const char *extname, bool missing_ok)
Definition: extension.c:138
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:822
long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId)
Definition: pg_depend.c:297
Oid AlterObjectNamespace_oid(Oid classId, Oid objid, Oid nspOid, ObjectAddresses *objsMoved)
Definition: alter.c:563
#define elog(elevel,...)
Definition: elog.h:228
#define NameStr(name)
Definition: c.h:616
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ ApplyExtensionUpdates()

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

Definition at line 3036 of file extension.c.

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

Referenced by CreateExtensionInternal(), and ExecAlterExtensionStmt().

3043 {
3044  const char *oldVersionName = initialVersion;
3045  ListCell *lcv;
3046 
3047  foreach(lcv, updateVersions)
3048  {
3049  char *versionName = (char *) lfirst(lcv);
3050  ExtensionControlFile *control;
3051  char *schemaName;
3052  Oid schemaOid;
3053  List *requiredExtensions;
3054  List *requiredSchemas;
3055  Relation extRel;
3056  ScanKeyData key[1];
3057  SysScanDesc extScan;
3058  HeapTuple extTup;
3059  Form_pg_extension extForm;
3060  Datum values[Natts_pg_extension];
3061  bool nulls[Natts_pg_extension];
3062  bool repl[Natts_pg_extension];
3063  ObjectAddress myself;
3064  ListCell *lc;
3065 
3066  /*
3067  * Fetch parameters for specific version (pcontrol is not changed)
3068  */
3069  control = read_extension_aux_control_file(pcontrol, versionName);
3070 
3071  /* Find the pg_extension tuple */
3072  extRel = table_open(ExtensionRelationId, RowExclusiveLock);
3073 
3074  ScanKeyInit(&key[0],
3075  Anum_pg_extension_oid,
3076  BTEqualStrategyNumber, F_OIDEQ,
3077  ObjectIdGetDatum(extensionOid));
3078 
3079  extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
3080  NULL, 1, key);
3081 
3082  extTup = systable_getnext(extScan);
3083 
3084  if (!HeapTupleIsValid(extTup)) /* should not happen */
3085  elog(ERROR, "could not find tuple for extension %u",
3086  extensionOid);
3087 
3088  extForm = (Form_pg_extension) GETSTRUCT(extTup);
3089 
3090  /*
3091  * Determine the target schema (set by original install)
3092  */
3093  schemaOid = extForm->extnamespace;
3094  schemaName = get_namespace_name(schemaOid);
3095 
3096  /*
3097  * Modify extrelocatable and extversion in the pg_extension tuple
3098  */
3099  memset(values, 0, sizeof(values));
3100  memset(nulls, 0, sizeof(nulls));
3101  memset(repl, 0, sizeof(repl));
3102 
3103  values[Anum_pg_extension_extrelocatable - 1] =
3104  BoolGetDatum(control->relocatable);
3105  repl[Anum_pg_extension_extrelocatable - 1] = true;
3106  values[Anum_pg_extension_extversion - 1] =
3107  CStringGetTextDatum(versionName);
3108  repl[Anum_pg_extension_extversion - 1] = true;
3109 
3110  extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
3111  values, nulls, repl);
3112 
3113  CatalogTupleUpdate(extRel, &extTup->t_self, extTup);
3114 
3115  systable_endscan(extScan);
3116 
3117  table_close(extRel, RowExclusiveLock);
3118 
3119  /*
3120  * Look up the prerequisite extensions for this version, install them
3121  * if necessary, and build lists of their OIDs and the OIDs of their
3122  * target schemas.
3123  */
3124  requiredExtensions = NIL;
3125  requiredSchemas = NIL;
3126  foreach(lc, control->requires)
3127  {
3128  char *curreq = (char *) lfirst(lc);
3129  Oid reqext;
3130  Oid reqschema;
3131 
3132  reqext = get_required_extension(curreq,
3133  control->name,
3134  origSchemaName,
3135  cascade,
3136  NIL,
3137  is_create);
3138  reqschema = get_extension_schema(reqext);
3139  requiredExtensions = lappend_oid(requiredExtensions, reqext);
3140  requiredSchemas = lappend_oid(requiredSchemas, reqschema);
3141  }
3142 
3143  /*
3144  * Remove and recreate dependencies on prerequisite extensions
3145  */
3146  deleteDependencyRecordsForClass(ExtensionRelationId, extensionOid,
3147  ExtensionRelationId,
3149 
3150  myself.classId = ExtensionRelationId;
3151  myself.objectId = extensionOid;
3152  myself.objectSubId = 0;
3153 
3154  foreach(lc, requiredExtensions)
3155  {
3156  Oid reqext = lfirst_oid(lc);
3157  ObjectAddress otherext;
3158 
3159  otherext.classId = ExtensionRelationId;
3160  otherext.objectId = reqext;
3161  otherext.objectSubId = 0;
3162 
3163  recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
3164  }
3165 
3166  InvokeObjectPostAlterHook(ExtensionRelationId, extensionOid, 0);
3167 
3168  /*
3169  * Finally, execute the update script file
3170  */
3171  execute_extension_script(extensionOid, control,
3172  oldVersionName, versionName,
3173  requiredSchemas,
3174  schemaName, schemaOid);
3175 
3176  /*
3177  * Update prior-version name and loop around. Since
3178  * execute_sql_string did a final CommandCounterIncrement, we can
3179  * update the pg_extension row again.
3180  */
3181  oldVersionName = versionName;
3182  }
3183 }
#define NIL
Definition: pg_list.h:65
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:525
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
static Oid get_extension_schema(Oid ext_oid)
Definition: extension.c:222
static Oid get_required_extension(char *reqExtensionName, char *extensionName, char *origSchemaName, bool cascade, List *parents, bool is_create)
Definition: extension.c:1571
#define RelationGetDescr(relation)
Definition: rel.h:448
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:43
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:358
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:352
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:444
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:803
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
ItemPointerData t_self
Definition: htup.h:65
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3094
static ExtensionControlFile * read_extension_aux_control_file(const ExtensionControlFile *pcontrol, const char *version)
Definition: extension.c:634
#define RowExclusiveLock
Definition: lockdefs.h:38
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
#define ExtensionOidIndexId
Definition: indexing.h:326
FormData_pg_extension * Form_pg_extension
Definition: pg_extension.h:50
uintptr_t Datum
Definition: postgres.h:367
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition: pg_depend.c:240
#define BoolGetDatum(X)
Definition: postgres.h:402
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define lfirst(lc)
Definition: pg_list.h:190
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
static Datum values[MAXATTR]
Definition: bootstrap.c:167
#define elog(elevel,...)
Definition: elog.h:228
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define CStringGetTextDatum(s)
Definition: builtins.h:83
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
Definition: pg_list.h:50
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define lfirst_oid(lc)
Definition: pg_list.h:192

◆ check_valid_extension_name()

static void check_valid_extension_name ( const char *  extensionname)
static

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

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

◆ check_valid_version_name()

static void check_valid_version_name ( const char *  versionname)
static

Definition at line 306 of file extension.c.

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

Referenced by CreateExtensionInternal(), and ExecAlterExtensionStmt().

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

◆ convert_requires_to_datum()

static Datum convert_requires_to_datum ( List requires)
static

Definition at line 2206 of file extension.c.

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

Referenced by get_available_versions_for_extension().

2207 {
2208  Datum *datums;
2209  int ndatums;
2210  ArrayType *a;
2211  ListCell *lc;
2212 
2213  ndatums = list_length(requires);
2214  datums = (Datum *) palloc(ndatums * sizeof(Datum));
2215  ndatums = 0;
2216  foreach(lc, requires)
2217  {
2218  char *curreq = (char *) lfirst(lc);
2219 
2220  datums[ndatums++] =
2222  }
2223  a = construct_array(datums, ndatums,
2224  NAMEOID,
2225  NAMEDATALEN, false, 'c');
2226  return PointerGetDatum(a);
2227 }
Datum namein(PG_FUNCTION_ARGS)
Definition: name.c:48
#define PointerGetDatum(X)
Definition: postgres.h:556
ArrayType * construct_array(Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3291
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:615
#define NAMEDATALEN
#define CStringGetDatum(X)
Definition: postgres.h:578
uintptr_t Datum
Definition: postgres.h:367
#define lfirst(lc)
Definition: pg_list.h:190
static int list_length(const List *l)
Definition: pg_list.h:169
void * palloc(Size size)
Definition: mcxt.c:949

◆ CreateExtension()

ObjectAddress CreateExtension ( ParseState pstate,
CreateExtensionStmt stmt 
)

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

1644 {
1645  DefElem *d_schema = NULL;
1646  DefElem *d_new_version = NULL;
1647  DefElem *d_old_version = NULL;
1648  DefElem *d_cascade = NULL;
1649  char *schemaName = NULL;
1650  char *versionName = NULL;
1651  char *oldVersionName = NULL;
1652  bool cascade = false;
1653  ListCell *lc;
1654 
1655  /* Check extension name validity before any filesystem access */
1657 
1658  /*
1659  * Check for duplicate extension name. The unique index on
1660  * pg_extension.extname would catch this anyway, and serves as a backstop
1661  * in case of race conditions; but this is a friendlier error message, and
1662  * besides we need a check to support IF NOT EXISTS.
1663  */
1664  if (get_extension_oid(stmt->extname, true) != InvalidOid)
1665  {
1666  if (stmt->if_not_exists)
1667  {
1668  ereport(NOTICE,
1670  errmsg("extension \"%s\" already exists, skipping",
1671  stmt->extname)));
1672  return InvalidObjectAddress;
1673  }
1674  else
1675  ereport(ERROR,
1677  errmsg("extension \"%s\" already exists",
1678  stmt->extname)));
1679  }
1680 
1681  /*
1682  * We use global variables to track the extension being created, so we can
1683  * create only one extension at the same time.
1684  */
1685  if (creating_extension)
1686  ereport(ERROR,
1687  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1688  errmsg("nested CREATE EXTENSION is not supported")));
1689 
1690  /* Deconstruct the statement option list */
1691  foreach(lc, stmt->options)
1692  {
1693  DefElem *defel = (DefElem *) lfirst(lc);
1694 
1695  if (strcmp(defel->defname, "schema") == 0)
1696  {
1697  if (d_schema)
1698  ereport(ERROR,
1699  (errcode(ERRCODE_SYNTAX_ERROR),
1700  errmsg("conflicting or redundant options"),
1701  parser_errposition(pstate, defel->location)));
1702  d_schema = defel;
1703  schemaName = defGetString(d_schema);
1704  }
1705  else if (strcmp(defel->defname, "new_version") == 0)
1706  {
1707  if (d_new_version)
1708  ereport(ERROR,
1709  (errcode(ERRCODE_SYNTAX_ERROR),
1710  errmsg("conflicting or redundant options"),
1711  parser_errposition(pstate, defel->location)));
1712  d_new_version = defel;
1713  versionName = defGetString(d_new_version);
1714  }
1715  else if (strcmp(defel->defname, "old_version") == 0)
1716  {
1717  if (d_old_version)
1718  ereport(ERROR,
1719  (errcode(ERRCODE_SYNTAX_ERROR),
1720  errmsg("conflicting or redundant options"),
1721  parser_errposition(pstate, defel->location)));
1722  d_old_version = defel;
1723  oldVersionName = defGetString(d_old_version);
1724  }
1725  else if (strcmp(defel->defname, "cascade") == 0)
1726  {
1727  if (d_cascade)
1728  ereport(ERROR,
1729  (errcode(ERRCODE_SYNTAX_ERROR),
1730  errmsg("conflicting or redundant options"),
1731  parser_errposition(pstate, defel->location)));
1732  d_cascade = defel;
1733  cascade = defGetBoolean(d_cascade);
1734  }
1735  else
1736  elog(ERROR, "unrecognized option: %s", defel->defname);
1737  }
1738 
1739  /* Call CreateExtensionInternal to do the real work. */
1740  return CreateExtensionInternal(stmt->extname,
1741  schemaName,
1742  versionName,
1743  oldVersionName,
1744  cascade,
1745  NIL,
1746  true);
1747 }
#define NIL
Definition: pg_list.h:65
static ObjectAddress CreateExtensionInternal(char *extensionName, char *schemaName, const char *versionName, const char *oldVersionName, bool cascade, List *parents, bool is_create)
Definition: extension.c:1282
static void check_valid_extension_name(const char *extensionname)
Definition: extension.c:259
int errcode(int sqlerrcode)
Definition: elog.c:608
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:733
#define ereport(elevel, rest)
Definition: elog.h:141
#define InvalidOid
Definition: postgres_ext.h:36
bool creating_extension
Definition: extension.c:70
#define NOTICE
Definition: elog.h:37
#define lfirst(lc)
Definition: pg_list.h:190
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:110
Oid get_extension_oid(const char *extname, bool missing_ok)
Definition: extension.c:138
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define elog(elevel,...)
Definition: elog.h:228
char * defname
Definition: parsenodes.h:730
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:31

◆ 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 1282 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(), 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, isTempNamespace(), lappend_oid(), lfirst, linitial, linitial_oid, list_delete_first(), list_free(), list_length(), makeNode, MyXactFlags, ExtensionControlFile::name, ExtensionVersionInfo::name, NIL, ObjectAddress::objectId, OidIsValid, PointerGetDatum, read_extension_aux_control_file(), read_extension_control_file(), ExtensionControlFile::relocatable, ExtensionControlFile::requires, ExtensionControlFile::schema, CreateSchemaStmt::schemaElts, CreateSchemaStmt::schemaname, stat, and XACT_FLAGS_ACCESSEDTEMPNAMESPACE.

Referenced by CreateExtension(), and get_required_extension().

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

◆ ExecAlterExtensionContentsStmt()

ObjectAddress ExecAlterExtensionContentsStmt ( AlterExtensionContentsStmt stmt,
ObjectAddress objAddr 
)

Definition at line 3194 of file extension.c.

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

Referenced by ProcessUtilitySlow().

3196 {
3197  ObjectAddress extension;
3198  ObjectAddress object;
3199  Relation relation;
3200  Oid oldExtension;
3201 
3202  extension.classId = ExtensionRelationId;
3203  extension.objectId = get_extension_oid(stmt->extname, false);
3204  extension.objectSubId = 0;
3205 
3206  /* Permission check: must own extension */
3207  if (!pg_extension_ownercheck(extension.objectId, GetUserId()))
3209  stmt->extname);
3210 
3211  /*
3212  * Translate the parser representation that identifies the object into an
3213  * ObjectAddress. get_object_address() will throw an error if the object
3214  * does not exist, and will also acquire a lock on the object to guard
3215  * against concurrent DROP and ALTER EXTENSION ADD/DROP operations.
3216  */
3217  object = get_object_address(stmt->objtype, stmt->object,
3218  &relation, ShareUpdateExclusiveLock, false);
3219 
3220  Assert(object.objectSubId == 0);
3221  if (objAddr)
3222  *objAddr = object;
3223 
3224  /* Permission check: must own target object, too */
3225  check_object_ownership(GetUserId(), stmt->objtype, object,
3226  stmt->object, relation);
3227 
3228  /*
3229  * Check existing extension membership.
3230  */
3231  oldExtension = getExtensionOfObject(object.classId, object.objectId);
3232 
3233  if (stmt->action > 0)
3234  {
3235  /*
3236  * ADD, so complain if object is already attached to some extension.
3237  */
3238  if (OidIsValid(oldExtension))
3239  ereport(ERROR,
3240  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3241  errmsg("%s is already a member of extension \"%s\"",
3242  getObjectDescription(&object),
3243  get_extension_name(oldExtension))));
3244 
3245  /*
3246  * Prevent a schema from being added to an extension if the schema
3247  * contains the extension. That would create a dependency loop.
3248  */
3249  if (object.classId == NamespaceRelationId &&
3250  object.objectId == get_extension_schema(extension.objectId))
3251  ereport(ERROR,
3252  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3253  errmsg("cannot add schema \"%s\" to extension \"%s\" "
3254  "because the schema contains the extension",
3255  get_namespace_name(object.objectId),
3256  stmt->extname)));
3257 
3258  /*
3259  * OK, add the dependency.
3260  */
3261  recordDependencyOn(&object, &extension, DEPENDENCY_EXTENSION);
3262 
3263  /*
3264  * Also record the initial ACL on the object, if any.
3265  *
3266  * Note that this will handle the object's ACLs, as well as any ACLs
3267  * on object subIds. (In other words, when the object is a table,
3268  * this will record the table's ACL and the ACLs for the columns on
3269  * the table, if any).
3270  */
3271  recordExtObjInitPriv(object.objectId, object.classId);
3272  }
3273  else
3274  {
3275  /*
3276  * DROP, so complain if it's not a member.
3277  */
3278  if (oldExtension != extension.objectId)
3279  ereport(ERROR,
3280  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3281  errmsg("%s is not a member of extension \"%s\"",
3282  getObjectDescription(&object),
3283  stmt->extname)));
3284 
3285  /*
3286  * OK, drop the dependency.
3287  */
3288  if (deleteDependencyRecordsForClass(object.classId, object.objectId,
3289  ExtensionRelationId,
3290  DEPENDENCY_EXTENSION) != 1)
3291  elog(ERROR, "unexpected number of extension dependency records");
3292 
3293  /*
3294  * If it's a relation, it might have an entry in the extension's
3295  * extconfig array, which we must remove.
3296  */
3297  if (object.classId == RelationRelationId)
3298  extension_config_remove(extension.objectId, object.objectId);
3299 
3300  /*
3301  * Remove all the initial ACLs, if any.
3302  *
3303  * Note that this will remove the object's ACLs, as well as any ACLs
3304  * on object subIds. (In other words, when the object is a table,
3305  * this will remove the table's ACL and the ACLs for the columns on
3306  * the table, if any).
3307  */
3308  removeExtObjInitPriv(object.objectId, object.classId);
3309  }
3310 
3311  InvokeObjectPostAlterHook(ExtensionRelationId, extension.objectId, 0);
3312 
3313  /*
3314  * If get_object_address() opened the relation for us, we close it to keep
3315  * the reference count correct - but we retain any locks acquired by
3316  * get_object_address() until commit time, to guard against concurrent
3317  * activity.
3318  */
3319  if (relation != NULL)
3320  relation_close(relation, NoLock);
3321 
3322  return extension;
3323 }
void recordExtObjInitPriv(Oid objoid, Oid classoid)
Definition: aclchk.c:5562
Oid getExtensionOfObject(Oid classId, Oid objectId)
Definition: pg_depend.c:610
static Oid get_extension_schema(Oid ext_oid)
Definition: extension.c:222
Oid GetUserId(void)
Definition: miscinit.c:380
char * get_extension_name(Oid ext_oid)
Definition: extension.c:183
int errcode(int sqlerrcode)
Definition: elog.c:608
static void extension_config_remove(Oid extensionoid, Oid tableoid)
Definition: extension.c:2535
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:43
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:645
char * getObjectDescription(const ObjectAddress *object)
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3352
#define ERROR
Definition: elog.h:43
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3094
#define NoLock
Definition: lockdefs.h:34
bool pg_extension_ownercheck(Oid ext_oid, Oid roleid)
Definition: aclchk.c:5249
#define ereport(elevel, rest)
Definition: elog.h:141
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:175
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition: pg_depend.c:240
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: relation.c:206
#define Assert(condition)
Definition: c.h:739
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:138
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define elog(elevel,...)
Definition: elog.h:228
void removeExtObjInitPriv(Oid objoid, Oid classoid)
Definition: aclchk.c:5852

◆ ExecAlterExtensionStmt()

ObjectAddress ExecAlterExtensionStmt ( ParseState pstate,
AlterExtensionStmt stmt 
)

Definition at line 2886 of file extension.c.

References AccessShareLock, aclcheck_error(), ACLCHECK_NOT_OWNER, ApplyExtensionUpdates(), DefElem::arg, BTEqualStrategyNumber, check_valid_version_name(), creating_extension, CStringGetDatum, DatumGetTextPP, ExtensionControlFile::default_version, DefElem::defname, elog, ereport, errcode(), errmsg(), ERROR, ExtensionNameIndexId, AlterExtensionStmt::extname, GETSTRUCT, GetUserId(), heap_getattr, HeapTupleIsValid, identify_update_path(), InvalidObjectAddress, sort-test::key, lfirst, DefElem::location, NOTICE, OBJECT_EXTENSION, ObjectAddressSet, AlterExtensionStmt::options, parser_errposition(), pg_extension_ownercheck(), read_extension_control_file(), RelationGetDescr, ScanKeyInit(), strVal, systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), and text_to_cstring().

Referenced by ProcessUtilitySlow().

2887 {
2888  DefElem *d_new_version = NULL;
2889  char *versionName;
2890  char *oldVersionName;
2891  ExtensionControlFile *control;
2892  Oid extensionOid;
2893  Relation extRel;
2894  ScanKeyData key[1];
2895  SysScanDesc extScan;
2896  HeapTuple extTup;
2897  List *updateVersions;
2898  Datum datum;
2899  bool isnull;
2900  ListCell *lc;
2901  ObjectAddress address;
2902 
2903  /*
2904  * We use global variables to track the extension being created, so we can
2905  * create/update only one extension at the same time.
2906  */
2907  if (creating_extension)
2908  ereport(ERROR,
2909  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2910  errmsg("nested ALTER EXTENSION is not supported")));
2911 
2912  /*
2913  * Look up the extension --- it must already exist in pg_extension
2914  */
2915  extRel = table_open(ExtensionRelationId, AccessShareLock);
2916 
2917  ScanKeyInit(&key[0],
2918  Anum_pg_extension_extname,
2919  BTEqualStrategyNumber, F_NAMEEQ,
2920  CStringGetDatum(stmt->extname));
2921 
2922  extScan = systable_beginscan(extRel, ExtensionNameIndexId, true,
2923  NULL, 1, key);
2924 
2925  extTup = systable_getnext(extScan);
2926 
2927  if (!HeapTupleIsValid(extTup))
2928  ereport(ERROR,
2929  (errcode(ERRCODE_UNDEFINED_OBJECT),
2930  errmsg("extension \"%s\" does not exist",
2931  stmt->extname)));
2932 
2933  extensionOid = ((Form_pg_extension) GETSTRUCT(extTup))->oid;
2934 
2935  /*
2936  * Determine the existing version we are updating from
2937  */
2938  datum = heap_getattr(extTup, Anum_pg_extension_extversion,
2939  RelationGetDescr(extRel), &isnull);
2940  if (isnull)
2941  elog(ERROR, "extversion is null");
2942  oldVersionName = text_to_cstring(DatumGetTextPP(datum));
2943 
2944  systable_endscan(extScan);
2945 
2946  table_close(extRel, AccessShareLock);
2947 
2948  /* Permission check: must own extension */
2949  if (!pg_extension_ownercheck(extensionOid, GetUserId()))
2951  stmt->extname);
2952 
2953  /*
2954  * Read the primary control file. Note we assume that it does not contain
2955  * any non-ASCII data, so there is no need to worry about encoding at this
2956  * point.
2957  */
2958  control = read_extension_control_file(stmt->extname);
2959 
2960  /*
2961  * Read the statement option list
2962  */
2963  foreach(lc, stmt->options)
2964  {
2965  DefElem *defel = (DefElem *) lfirst(lc);
2966 
2967  if (strcmp(defel->defname, "new_version") == 0)
2968  {
2969  if (d_new_version)
2970  ereport(ERROR,
2971  (errcode(ERRCODE_SYNTAX_ERROR),
2972  errmsg("conflicting or redundant options"),
2973  parser_errposition(pstate, defel->location)));
2974  d_new_version = defel;
2975  }
2976  else
2977  elog(ERROR, "unrecognized option: %s", defel->defname);
2978  }
2979 
2980  /*
2981  * Determine the version to update to
2982  */
2983  if (d_new_version && d_new_version->arg)
2984  versionName = strVal(d_new_version->arg);
2985  else if (control->default_version)
2986  versionName = control->default_version;
2987  else
2988  {
2989  ereport(ERROR,
2990  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2991  errmsg("version to install must be specified")));
2992  versionName = NULL; /* keep compiler quiet */
2993  }
2994  check_valid_version_name(versionName);
2995 
2996  /*
2997  * If we're already at that version, just say so
2998  */
2999  if (strcmp(oldVersionName, versionName) == 0)
3000  {
3001  ereport(NOTICE,
3002  (errmsg("version \"%s\" of extension \"%s\" is already installed",
3003  versionName, stmt->extname)));
3004  return InvalidObjectAddress;
3005  }
3006 
3007  /*
3008  * Identify the series of update script files we need to execute
3009  */
3010  updateVersions = identify_update_path(control,
3011  oldVersionName,
3012  versionName);
3013 
3014  /*
3015  * Update the pg_extension row and execute the update scripts, one at a
3016  * time
3017  */
3018  ApplyExtensionUpdates(extensionOid, control,
3019  oldVersionName, updateVersions,
3020  NULL, false, false);
3021 
3022  ObjectAddressSet(address, ExtensionRelationId, extensionOid);
3023 
3024  return address;
3025 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:525
#define GETSTRUCT(TUP)
Definition: htup_details.h:655
#define ExtensionNameIndexId
Definition: indexing.h:328
static ExtensionControlFile * read_extension_control_file(const char *extname)
Definition: extension.c:606
#define RelationGetDescr(relation)
Definition: rel.h:448
Oid GetUserId(void)
Definition: miscinit.c:380
#define DatumGetTextPP(X)
Definition: fmgr.h:286
static void ApplyExtensionUpdates(Oid extensionOid, ExtensionControlFile *pcontrol, const char *initialVersion, List *updateVersions, char *origSchemaName, bool cascade, bool is_create)
Definition: extension.c:3036
#define AccessShareLock
Definition: lockdefs.h:36
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:608
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:352
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3352
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:444
#define ERROR
Definition: elog.h:43
static List * identify_update_path(ExtensionControlFile *control, const char *oldVersion, const char *newVersion)
Definition: extension.c:1091
bool pg_extension_ownercheck(Oid ext_oid, Oid roleid)
Definition: aclchk.c:5249
int location
Definition: parsenodes.h:733
#define CStringGetDatum(X)
Definition: postgres.h:578
#define ereport(elevel, rest)
Definition: elog.h:141
FormData_pg_extension * Form_pg_extension
Definition: pg_extension.h:50
Node * arg
Definition: parsenodes.h:731
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:762
char * default_version
Definition: extension.c:80
uintptr_t Datum
Definition: postgres.h:367
static void check_valid_version_name(const char *versionname)
Definition: extension.c:306
bool creating_extension
Definition: extension.c:70
#define NOTICE
Definition: elog.h:37
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define lfirst(lc)
Definition: pg_list.h:190
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:110
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
char * text_to_cstring(const text *t)
Definition: varlena.c:204
const ObjectAddress InvalidObjectAddress
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define elog(elevel,...)
Definition: elog.h:228
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
char * defname
Definition: parsenodes.h:730
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
#define BTEqualStrategyNumber
Definition: stratnum.h:31

◆ execute_extension_script()

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

Definition at line 803 of file extension.c.

References appendStringInfo(), appendStringInfoString(), AtEOXact_GUC(), client_min_messages, creating_extension, CStringGetTextDatum, CurrentExtensionObject, StringInfoData::data, DatumGetTextPP, DirectFunctionCall3Coll(), DirectFunctionCall4Coll(), ereport, errcode(), errhint(), errmsg(), ERROR, execute_sql_string(), 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_END_TRY, PG_FINALLY, 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().

808 {
809  char *filename;
810  int save_nestlevel;
811  StringInfoData pathbuf;
812  ListCell *lc;
813 
814  /*
815  * Enforce superuser-ness if appropriate. We postpone this check until
816  * here so that the flag is correctly associated with the right script(s)
817  * if it's set in secondary control files.
818  */
819  if (control->superuser && !superuser())
820  {
821  if (from_version == NULL)
822  ereport(ERROR,
823  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
824  errmsg("permission denied to create extension \"%s\"",
825  control->name),
826  errhint("Must be superuser to create this extension.")));
827  else
828  ereport(ERROR,
829  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
830  errmsg("permission denied to update extension \"%s\"",
831  control->name),
832  errhint("Must be superuser to update this extension.")));
833  }
834 
835  filename = get_extension_script_filename(control, from_version, version);
836 
837  /*
838  * Force client_min_messages and log_min_messages to be at least WARNING,
839  * so that we won't spam the user with useless NOTICE messages from common
840  * script actions like creating shell types.
841  *
842  * We use the equivalent of a function SET option to allow the setting to
843  * persist for exactly the duration of the script execution. guc.c also
844  * takes care of undoing the setting on error.
845  */
846  save_nestlevel = NewGUCNestLevel();
847 
849  (void) set_config_option("client_min_messages", "warning",
851  GUC_ACTION_SAVE, true, 0, false);
853  (void) set_config_option("log_min_messages", "warning",
855  GUC_ACTION_SAVE, true, 0, false);
856 
857  /*
858  * Set up the search path to contain the target schema, then the schemas
859  * of any prerequisite extensions, and nothing else. In particular this
860  * makes the target schema be the default creation target namespace.
861  *
862  * Note: it might look tempting to use PushOverrideSearchPath for this,
863  * but we cannot do that. We have to actually set the search_path GUC in
864  * case the extension script examines or changes it. In any case, the
865  * GUC_ACTION_SAVE method is just as convenient.
866  */
867  initStringInfo(&pathbuf);
868  appendStringInfoString(&pathbuf, quote_identifier(schemaName));
869  foreach(lc, requiredSchemas)
870  {
871  Oid reqschema = lfirst_oid(lc);
872  char *reqname = get_namespace_name(reqschema);
873 
874  if (reqname)
875  appendStringInfo(&pathbuf, ", %s", quote_identifier(reqname));
876  }
877 
878  (void) set_config_option("search_path", pathbuf.data,
880  GUC_ACTION_SAVE, true, 0, false);
881 
882  /*
883  * Set creating_extension and related variables so that
884  * recordDependencyOnCurrentExtension and other functions do the right
885  * things. On failure, ensure we reset these variables.
886  */
887  creating_extension = true;
888  CurrentExtensionObject = extensionOid;
889  PG_TRY();
890  {
891  char *c_sql = read_extension_script_file(control, filename);
892  Datum t_sql;
893 
894  /* We use various functions that want to operate on text datums */
895  t_sql = CStringGetTextDatum(c_sql);
896 
897  /*
898  * Reduce any lines beginning with "\echo" to empty. This allows
899  * scripts to contain messages telling people not to run them via
900  * psql, which has been found to be necessary due to old habits.
901  */
903  C_COLLATION_OID,
904  t_sql,
905  CStringGetTextDatum("^\\\\echo.*$"),
907  CStringGetTextDatum("ng"));
908 
909  /*
910  * If it's not relocatable, substitute the target schema name for
911  * occurrences of @extschema@.
912  *
913  * For a relocatable extension, we needn't do this. There cannot be
914  * any need for @extschema@, else it wouldn't be relocatable.
915  */
916  if (!control->relocatable)
917  {
918  const char *qSchemaName = quote_identifier(schemaName);
919 
921  C_COLLATION_OID,
922  t_sql,
923  CStringGetTextDatum("@extschema@"),
924  CStringGetTextDatum(qSchemaName));
925  }
926 
927  /*
928  * If module_pathname was set in the control file, substitute its
929  * value for occurrences of MODULE_PATHNAME.
930  */
931  if (control->module_pathname)
932  {
934  C_COLLATION_OID,
935  t_sql,
936  CStringGetTextDatum("MODULE_PATHNAME"),
938  }
939 
940  /* And now back to C string */
941  c_sql = text_to_cstring(DatumGetTextPP(t_sql));
942 
943  execute_sql_string(c_sql);
944  }
945  PG_FINALLY();
946  {
947  creating_extension = false;
949  }
950  PG_END_TRY();
951 
952  /*
953  * Restore the GUC variables we set above.
954  */
955  AtEOXact_GUC(true, save_nestlevel);
956 }
Oid CurrentExtensionObject
Definition: extension.c:71
int errhint(const char *fmt,...)
Definition: elog.c:1069
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:10640
static char * get_extension_script_filename(ExtensionControlFile *control, const char *from_version, const char *version)
Definition: extension.c:437
Datum replace_text(PG_FUNCTION_ARGS)
Definition: varlena.c:4191
Datum DirectFunctionCall4Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4)
Definition: fmgr.c:860
#define DatumGetTextPP(X)
Definition: fmgr.h:286
int errcode(int sqlerrcode)
Definition: elog.c:608
bool superuser(void)
Definition: superuser.c:46
unsigned int Oid
Definition: postgres_ext.h:31
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
#define ERROR
Definition: elog.h:43
Definition: guc.h:75
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3094
void AtEOXact_GUC(bool isCommit, int nestLevel)
Definition: guc.c:5782
#define ereport(elevel, rest)
Definition: elog.h:141
static char * read_extension_script_file(const ExtensionControlFile *control, const char *filename)
Definition: extension.c:657
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
#define WARNING
Definition: elog.h:40
#define PG_FINALLY()
Definition: elog.h:339
char * module_pathname
Definition: extension.c:81
uintptr_t Datum
Definition: postgres.h:367
int log_min_messages
Definition: guc.c:513
#define InvalidOid
Definition: postgres_ext.h:36
bool creating_extension
Definition: extension.c:70
static void execute_sql_string(const char *sql)
Definition: extension.c:698
Datum DirectFunctionCall3Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2, Datum arg3)
Definition: fmgr.c:835
char * text_to_cstring(const text *t)
Definition: varlena.c:204
int NewGUCNestLevel(void)
Definition: guc.c:5768
static char * filename
Definition: pg_dumpall.c:90
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define CStringGetTextDatum(s)
Definition: builtins.h:83
int client_min_messages
Definition: guc.c:514
Datum textregexreplace(PG_FUNCTION_ARGS)
Definition: regexp.c:640
#define PG_TRY()
Definition: elog.h:322
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:6775
#define PG_END_TRY()
Definition: elog.h:347
#define lfirst_oid(lc)
Definition: pg_list.h:192

◆ execute_sql_string()

static void execute_sql_string ( const char *  sql)
static

Definition at line 698 of file extension.c.

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

Referenced by execute_extension_script().

699 {
700  List *raw_parsetree_list;
702  ListCell *lc1;
703 
704  /*
705  * Parse the SQL string into a list of raw parse trees.
706  */
707  raw_parsetree_list = pg_parse_query(sql);
708 
709  /* All output from SELECTs goes to the bit bucket */
711 
712  /*
713  * Do parse analysis, rule rewrite, planning, and execution for each raw
714  * parsetree. We must fully execute each query before beginning parse
715  * analysis on the next one, since there may be interdependencies.
716  */
717  foreach(lc1, raw_parsetree_list)
718  {
719  RawStmt *parsetree = lfirst_node(RawStmt, lc1);
720  MemoryContext per_parsetree_context,
721  oldcontext;
722  List *stmt_list;
723  ListCell *lc2;
724 
725  /*
726  * We do the work for each parsetree in a short-lived context, to
727  * limit the memory used when there are many commands in the string.
728  */
729  per_parsetree_context =
731  "execute_sql_string per-statement context",
733  oldcontext = MemoryContextSwitchTo(per_parsetree_context);
734 
735  /* Be sure parser can see any DDL done so far */
737 
738  stmt_list = pg_analyze_and_rewrite(parsetree,
739  sql,
740  NULL,
741  0,
742  NULL);
743  stmt_list = pg_plan_queries(stmt_list, CURSOR_OPT_PARALLEL_OK, NULL);
744 
745  foreach(lc2, stmt_list)
746  {
747  PlannedStmt *stmt = lfirst_node(PlannedStmt, lc2);
748 
750 
752 
753  if (stmt->utilityStmt == NULL)
754  {
755  QueryDesc *qdesc;
756 
757  qdesc = CreateQueryDesc(stmt,
758  sql,
759  GetActiveSnapshot(), NULL,
760  dest, NULL, NULL, 0);
761 
762  ExecutorStart(qdesc, 0);
763  ExecutorRun(qdesc, ForwardScanDirection, 0, true);
764  ExecutorFinish(qdesc);
765  ExecutorEnd(qdesc);
766 
767  FreeQueryDesc(qdesc);
768  }
769  else
770  {
771  if (IsA(stmt->utilityStmt, TransactionStmt))
772  ereport(ERROR,
773  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
774  errmsg("transaction control statements are not allowed within an extension script")));
775 
776  ProcessUtility(stmt,
777  sql,
779  NULL,
780  NULL,
781  dest,
782  NULL);
783  }
784 
786  }
787 
788  /* Clean up per-parsetree context. */
789  MemoryContextSwitchTo(oldcontext);
790  MemoryContextDelete(per_parsetree_context);
791  }
792 
793  /* Be sure to advance the command counter after the last script command */
795 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:211
#define AllocSetContextCreate
Definition: memutils.h:170
void FreeQueryDesc(QueryDesc *qdesc)
Definition: pquery.c:105
void ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:143
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:841
void ProcessUtility(PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, char *completionTag)
Definition: utility.c:337
int errcode(int sqlerrcode)
Definition: elog.c:608
void PopActiveSnapshot(void)
Definition: snapmgr.c:814
List * pg_analyze_and_rewrite(RawStmt *parsetree, const char *query_string, Oid *paramTypes, int numParams, QueryEnvironment *queryEnv)
Definition: postgres.c:674
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:306
void ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:462
#define ERROR
Definition: elog.h:43
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: execMain.c:301
List * pg_parse_query(const char *query_string)
Definition: postgres.c:626
QueryDesc * CreateQueryDesc(PlannedStmt *plannedstmt, const char *sourceText, Snapshot snapshot, Snapshot crosscheck_snapshot, DestReceiver *dest, ParamListInfo params, QueryEnvironment *queryEnv, int instrument_options)
Definition: pquery.c:67
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:192
#define lfirst_node(type, lc)
Definition: pg_list.h:193
Definition: dest.h:88
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:735
DestReceiver * CreateDestReceiver(CommandDest dest)
Definition: dest.c:113
Node * utilityStmt
Definition: plannodes.h:90
MemoryContext CurrentMemoryContext
Definition: mcxt.c:38
#define ereport(elevel, rest)
Definition: elog.h:141
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:402
void CommandCounterIncrement(void)
Definition: xact.c:1005
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2692
int errmsg(const char *fmt,...)
Definition: elog.c:822
Definition: pg_list.h:50
List * pg_plan_queries(List *querytrees, int cursorOptions, ParamListInfo boundParams)
Definition: postgres.c:940

◆ extension_config_remove()

static void extension_config_remove ( Oid  extensionoid,
Oid  tableoid 
)
static

Definition at line 2535 of file extension.c.

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

Referenced by ExecAlterExtensionContentsStmt().

2536 {
2537  Relation extRel;
2538  ScanKeyData key[1];
2539  SysScanDesc extScan;
2540  HeapTuple extTup;
2541  Datum arrayDatum;
2542  int arrayLength;
2543  int arrayIndex;
2544  bool isnull;
2545  Datum repl_val[Natts_pg_extension];
2546  bool repl_null[Natts_pg_extension];
2547  bool repl_repl[Natts_pg_extension];
2548  ArrayType *a;
2549 
2550  /* Find the pg_extension tuple */
2551  extRel = table_open(ExtensionRelationId, RowExclusiveLock);
2552 
2553  ScanKeyInit(&key[0],
2554  Anum_pg_extension_oid,
2555  BTEqualStrategyNumber, F_OIDEQ,
2556  ObjectIdGetDatum(extensionoid));
2557 
2558  extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
2559  NULL, 1, key);
2560 
2561  extTup = systable_getnext(extScan);
2562 
2563  if (!HeapTupleIsValid(extTup)) /* should not happen */
2564  elog(ERROR, "could not find tuple for extension %u",
2565  extensionoid);
2566 
2567  /* Search extconfig for the tableoid */
2568  arrayDatum = heap_getattr(extTup, Anum_pg_extension_extconfig,
2569  RelationGetDescr(extRel), &isnull);
2570  if (isnull)
2571  {
2572  /* nothing to do */
2573  a = NULL;
2574  arrayLength = 0;
2575  arrayIndex = -1;
2576  }
2577  else
2578  {
2579  Oid *arrayData;
2580  int i;
2581 
2582  a = DatumGetArrayTypeP(arrayDatum);
2583 
2584  arrayLength = ARR_DIMS(a)[0];
2585  if (ARR_NDIM(a) != 1 ||
2586  ARR_LBOUND(a)[0] != 1 ||
2587  arrayLength < 0 ||
2588  ARR_HASNULL(a) ||
2589  ARR_ELEMTYPE(a) != OIDOID)
2590  elog(ERROR, "extconfig is not a 1-D Oid array");
2591  arrayData = (Oid *) ARR_DATA_PTR(a);
2592 
2593  arrayIndex = -1; /* flag for no deletion needed */
2594 
2595  for (i = 0; i < arrayLength; i++)
2596  {
2597  if (arrayData[i] == tableoid)
2598  {
2599  arrayIndex = i; /* index to remove */
2600  break;
2601  }
2602  }
2603  }
2604 
2605  /* If tableoid is not in extconfig, nothing to do */
2606  if (arrayIndex < 0)
2607  {
2608  systable_endscan(extScan);
2609  table_close(extRel, RowExclusiveLock);
2610  return;
2611  }
2612 
2613  /* Modify or delete the extconfig value */
2614  memset(repl_val, 0, sizeof(repl_val));
2615  memset(repl_null, false, sizeof(repl_null));
2616  memset(repl_repl, false, sizeof(repl_repl));
2617 
2618  if (arrayLength <= 1)
2619  {
2620  /* removing only element, just set array to null */
2621  repl_null[Anum_pg_extension_extconfig - 1] = true;
2622  }
2623  else
2624  {
2625  /* squeeze out the target element */
2626  Datum *dvalues;
2627  int nelems;
2628  int i;
2629 
2630  /* We already checked there are no nulls */
2631  deconstruct_array(a, OIDOID, sizeof(Oid), true, 'i',
2632  &dvalues, NULL, &nelems);
2633 
2634  for (i = arrayIndex; i < arrayLength - 1; i++)
2635  dvalues[i] = dvalues[i + 1];
2636 
2637  a = construct_array(dvalues, arrayLength - 1,
2638  OIDOID, sizeof(Oid), true, 'i');
2639 
2640  repl_val[Anum_pg_extension_extconfig - 1] = PointerGetDatum(a);
2641  }
2642  repl_repl[Anum_pg_extension_extconfig - 1] = true;
2643 
2644  /* Modify or delete the extcondition value */
2645  arrayDatum = heap_getattr(extTup, Anum_pg_extension_extcondition,
2646  RelationGetDescr(extRel), &isnull);
2647  if (isnull)
2648  {
2649  elog(ERROR, "extconfig and extcondition arrays do not match");
2650  }
2651  else
2652  {
2653  a = DatumGetArrayTypeP(arrayDatum);
2654 
2655  if (ARR_NDIM(a) != 1 ||
2656  ARR_LBOUND(a)[0] != 1 ||
2657  ARR_HASNULL(a) ||
2658  ARR_ELEMTYPE(a) != TEXTOID)
2659  elog(ERROR, "extcondition is not a 1-D text array");
2660  if (ARR_DIMS(a)[0] != arrayLength)
2661  elog(ERROR, "extconfig and extcondition arrays do not match");
2662  }
2663 
2664  if (arrayLength <= 1)
2665  {
2666  /* removing only element, just set array to null */
2667  repl_null[Anum_pg_extension_extcondition - 1] = true;
2668  }
2669  else
2670  {
2671  /* squeeze out the target element */
2672  Datum *dvalues;
2673  int nelems;
2674  int i;
2675 
2676  /* We already checked there are no nulls */
2677  deconstruct_array(a, TEXTOID, -1, false, 'i',
2678  &dvalues, NULL, &nelems);
2679 
2680  for (i = arrayIndex; i < arrayLength - 1; i++)
2681  dvalues[i] = dvalues[i + 1];
2682 
2683  a = construct_array(dvalues, arrayLength - 1,
2684  TEXTOID, -1, false, 'i');
2685 
2686  repl_val[Anum_pg_extension_extcondition - 1] = PointerGetDatum(a);
2687  }
2688  repl_repl[Anum_pg_extension_extcondition - 1] = true;
2689 
2690  extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
2691  repl_val, repl_null, repl_repl);
2692 
2693  CatalogTupleUpdate(extRel, &extTup->t_self, extTup);
2694 
2695  systable_endscan(extScan);
2696 
2697  table_close(extRel, RowExclusiveLock);
2698 }
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:525
#define RelationGetDescr(relation)
Definition: rel.h:448
#define PointerGetDatum(X)
Definition: postgres.h:556
ArrayType * construct_array(Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3291
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:352
#define ARR_LBOUND(a)
Definition: array.h:284
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:444
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define ARR_DIMS(a)
Definition: array.h:282
ItemPointerData t_self
Definition: htup.h:65
#define ARR_DATA_PTR(a)
Definition: array.h:310
#define RowExclusiveLock
Definition: lockdefs.h:38
#define ARR_HASNULL(a)
Definition: array.h:279
#define ExtensionOidIndexId
Definition: indexing.h:326
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:762
uintptr_t Datum
Definition: postgres.h:367
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
#define ARR_NDIM(a)
Definition: array.h:278
void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3461
#define elog(elevel,...)
Definition: elog.h:228
int i
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
#define ARR_ELEMTYPE(a)
Definition: array.h:280
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define DatumGetArrayTypeP(X)
Definition: array.h:249

◆ find_install_path()

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

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

1229 {
1230  ExtensionVersionInfo *evi_start = NULL;
1231  ListCell *lc;
1232 
1233  *best_path = NIL;
1234 
1235  /*
1236  * We don't expect to be called for an installable target, but if we are,
1237  * the answer is easy: just start from there, with an empty update path.
1238  */
1239  if (evi_target->installable)
1240  return evi_target;
1241 
1242  /* Consider all installable versions as start points */
1243  foreach(lc, evi_list)
1244  {
1246  List *path;
1247 
1248  if (!evi1->installable)
1249  continue;
1250 
1251  /*
1252  * Find shortest path from evi1 to evi_target; but no need to consider
1253  * paths going through other installable versions.
1254  */
1255  path = find_update_path(evi_list, evi1, evi_target, true, true);
1256  if (path == NIL)
1257  continue;
1258 
1259  /* Remember best path */
1260  if (evi_start == NULL ||
1261  list_length(path) < list_length(*best_path) ||
1262  (list_length(path) == list_length(*best_path) &&
1263  strcmp(evi_start->name, evi1->name) < 0))
1264  {
1265  evi_start = evi1;
1266  *best_path = path;
1267  }
1268  }
1269 
1270  return evi_start;
1271 }
#define NIL
Definition: pg_list.h:65
static List * find_update_path(List *evi_list, ExtensionVersionInfo *evi_start, ExtensionVersionInfo *evi_target, bool reject_indirect, bool reinitialize)
Definition: extension.c:1134
#define lfirst(lc)
Definition: pg_list.h:190
static int list_length(const List *l)
Definition: pg_list.h:169
Definition: pg_list.h:50

◆ find_update_path()

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

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

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

◆ get_available_versions_for_extension()

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

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

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

◆ get_ext_ver_info()

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

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

968 {
970  ListCell *lc;
971 
972  foreach(lc, *evi_list)
973  {
974  evi = (ExtensionVersionInfo *) lfirst(lc);
975  if (strcmp(evi->name, versionname) == 0)
976  return evi;
977  }
978 
980  evi->name = pstrdup(versionname);
981  evi->reachable = NIL;
982  evi->installable = false;
983  /* initialize for later application of Dijkstra's algorithm */
984  evi->distance_known = false;
985  evi->distance = INT_MAX;
986  evi->previous = NULL;
987 
988  *evi_list = lappend(*evi_list, evi);
989 
990  return evi;
991 }
#define NIL
Definition: pg_list.h:65
char * pstrdup(const char *in)
Definition: mcxt.c:1186
struct ExtensionVersionInfo * previous
Definition: extension.c:102
List * lappend(List *list, void *datum)
Definition: list.c:322
#define lfirst(lc)
Definition: pg_list.h:190
void * palloc(Size size)
Definition: mcxt.c:949

◆ get_ext_ver_list()

static List* get_ext_ver_list ( ExtensionControlFile control)
static

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

1029 {
1030  List *evi_list = NIL;
1031  int extnamelen = strlen(control->name);
1032  char *location;
1033  DIR *dir;
1034  struct dirent *de;
1035 
1036  location = get_extension_script_directory(control);
1037  dir = AllocateDir(location);
1038  while ((de = ReadDir(dir, location)) != NULL)
1039  {
1040  char *vername;
1041  char *vername2;
1042  ExtensionVersionInfo *evi;
1043  ExtensionVersionInfo *evi2;
1044 
1045  /* must be a .sql file ... */
1047  continue;
1048 
1049  /* ... matching extension name followed by separator */
1050  if (strncmp(de->d_name, control->name, extnamelen) != 0 ||
1051  de->d_name[extnamelen] != '-' ||
1052  de->d_name[extnamelen + 1] != '-')
1053  continue;
1054 
1055  /* extract version name(s) from 'extname--something.sql' filename */
1056  vername = pstrdup(de->d_name + extnamelen + 2);
1057  *strrchr(vername, '.') = '\0';
1058  vername2 = strstr(vername, "--");
1059  if (!vername2)
1060  {
1061  /* It's an install, not update, script; record its version name */
1062  evi = get_ext_ver_info(vername, &evi_list);
1063  evi->installable = true;
1064  continue;
1065  }
1066  *vername2 = '\0'; /* terminate first version */
1067  vername2 += 2; /* and point to second */
1068 
1069  /* if there's a third --, it's bogus, ignore it */
1070  if (strstr(vername2, "--"))
1071  continue;
1072 
1073  /* Create ExtensionVersionInfos and link them together */
1074  evi = get_ext_ver_info(vername, &evi_list);
1075  evi2 = get_ext_ver_info(vername2, &evi_list);
1076  evi->reachable = lappend(evi->reachable, evi2);
1077  }
1078  FreeDir(dir);
1079 
1080  return evi_list;
1081 }
#define NIL
Definition: pg_list.h:65
static ExtensionVersionInfo * get_ext_ver_info(const char *versionname, List **evi_list)
Definition: extension.c:967
char * pstrdup(const char *in)
Definition: mcxt.c:1186
Definition: dirent.h:9
static char * get_extension_script_directory(ExtensionControlFile *control)
Definition: extension.c:396
Definition: dirent.c:25
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2503
List * lappend(List *list, void *datum)
Definition: list.c:322
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2569
static bool is_extension_script_filename(const char *filename)
Definition: extension.c:361
char d_name[MAX_PATH]
Definition: dirent.h:14
Definition: pg_list.h:50
int FreeDir(DIR *dir)
Definition: fd.c:2621

◆ get_extension_aux_control_filename()

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

Definition at line 419 of file extension.c.

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

Referenced by parse_extension_control_file().

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

◆ get_extension_control_directory()

static char* get_extension_control_directory ( void  )
static

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

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

◆ get_extension_control_filename()

static char* get_extension_control_filename ( const char *  extname)
static

Definition at line 382 of file extension.c.

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

Referenced by parse_extension_control_file().

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

◆ get_extension_name()

char* get_extension_name ( Oid  ext_oid)

Definition at line 183 of file extension.c.

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

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

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

◆ get_extension_oid()

Oid get_extension_oid ( const char *  extname,
bool  missing_ok 
)

Definition at line 138 of file extension.c.

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

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

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

◆ get_extension_schema()

static Oid get_extension_schema ( Oid  ext_oid)
static

Definition at line 222 of file extension.c.

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

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

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

◆ get_extension_script_directory()

static char* get_extension_script_directory ( ExtensionControlFile control)
static

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

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

◆ get_extension_script_filename()

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

Definition at line 437 of file extension.c.

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

Referenced by CreateExtensionInternal(), and execute_extension_script().

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

◆ get_nearest_unprocessed_vertex()

static ExtensionVersionInfo* get_nearest_unprocessed_vertex ( List evi_list)
static

Definition at line 1000 of file extension.c.

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

Referenced by find_update_path().

1001 {
1002  ExtensionVersionInfo *evi = NULL;
1003  ListCell *lc;
1004 
1005  foreach(lc, evi_list)
1006  {
1008 
1009  /* only vertices whose distance is still uncertain are candidates */
1010  if (evi2->distance_known)
1011  continue;
1012  /* remember the closest such vertex */
1013  if (evi == NULL ||
1014  evi->distance > evi2->distance)
1015  evi = evi2;
1016  }
1017 
1018  return evi;
1019 }
#define lfirst(lc)
Definition: pg_list.h:190

◆ get_required_extension()

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

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

1577 {
1578  Oid reqExtensionOid;
1579 
1580  reqExtensionOid = get_extension_oid(reqExtensionName, true);
1581  if (!OidIsValid(reqExtensionOid))
1582  {
1583  if (cascade)
1584  {
1585  /* Must install it. */
1586  ObjectAddress addr;
1587  List *cascade_parents;
1588  ListCell *lc;
1589 
1590  /* Check extension name validity before trying to cascade. */
1591  check_valid_extension_name(reqExtensionName);
1592 
1593  /* Check for cyclic dependency between extensions. */
1594  foreach(lc, parents)
1595  {
1596  char *pname = (char *) lfirst(lc);
1597 
1598  if (strcmp(pname, reqExtensionName) == 0)
1599  ereport(ERROR,
1600  (errcode(ERRCODE_INVALID_RECURSION),
1601  errmsg("cyclic dependency detected between extensions \"%s\" and \"%s\"",
1602  reqExtensionName, extensionName)));
1603  }
1604 
1605  ereport(NOTICE,
1606  (errmsg("installing required extension \"%s\"",
1607  reqExtensionName)));
1608 
1609  /* Add current extension to list of parents to pass down. */
1610  cascade_parents = lappend(list_copy(parents), extensionName);
1611 
1612  /*
1613  * Create the required extension. We propagate the SCHEMA option
1614  * if any, and CASCADE, but no other options.
1615  */
1616  addr = CreateExtensionInternal(reqExtensionName,
1617  origSchemaName,
1618  NULL,
1619  NULL,
1620  cascade,
1621  cascade_parents,
1622  is_create);
1623 
1624  /* Get its newly-assigned OID. */
1625  reqExtensionOid = addr.objectId;
1626  }
1627  else
1628  ereport(ERROR,
1629  (errcode(ERRCODE_UNDEFINED_OBJECT),
1630  errmsg("required extension \"%s\" is not installed",
1631  reqExtensionName),
1632  is_create ?
1633  errhint("Use CREATE EXTENSION ... CASCADE to install required extensions too.") : 0));
1634  }
1635 
1636  return reqExtensionOid;
1637 }
int errhint(const char *fmt,...)
Definition: elog.c:1069
static ObjectAddress CreateExtensionInternal(char *extensionName, char *schemaName, const char *versionName, const char *oldVersionName, bool cascade, List *parents, bool is_create)
Definition: extension.c:1282
static void check_valid_extension_name(const char *extensionname)
Definition: extension.c:259
List * list_copy(const List *oldlist)
Definition: list.c:1404
int errcode(int sqlerrcode)
Definition: elog.c:608
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:645
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:141
List * lappend(List *list, void *datum)
Definition: list.c:322
#define NOTICE
Definition: elog.h:37
#define lfirst(lc)
Definition: pg_list.h:190
Oid get_extension_oid(const char *extname, bool missing_ok)
Definition: extension.c:138
int errmsg(const char *fmt,...)
Definition: elog.c:822
Definition: pg_list.h:50

◆ identify_update_path()

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

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

1093 {
1094  List *result;
1095  List *evi_list;
1096  ExtensionVersionInfo *evi_start;
1097  ExtensionVersionInfo *evi_target;
1098 
1099  /* Extract the version update graph from the script directory */
1100  evi_list = get_ext_ver_list(control);
1101 
1102  /* Initialize start and end vertices */
1103  evi_start = get_ext_ver_info(oldVersion, &evi_list);
1104  evi_target = get_ext_ver_info(newVersion, &evi_list);
1105 
1106  /* Find shortest path */
1107  result = find_update_path(evi_list, evi_start, evi_target, false, false);
1108 
1109  if (result == NIL)
1110  ereport(ERROR,
1111  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1112  errmsg("extension \"%s\" has no update path from version \"%s\" to version \"%s\"",
1113  control->name, oldVersion, newVersion)));
1114 
1115  return result;
1116 }
#define NIL
Definition: pg_list.h:65
static List * find_update_path(List *evi_list, ExtensionVersionInfo *evi_start, ExtensionVersionInfo *evi_target, bool reject_indirect, bool reinitialize)
Definition: extension.c:1134
static ExtensionVersionInfo * get_ext_ver_info(const char *versionname, List **evi_list)
Definition: extension.c:967
static List * get_ext_ver_list(ExtensionControlFile *control)
Definition: extension.c:1028
int errcode(int sqlerrcode)
Definition: elog.c:608
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:141
int errmsg(const char *fmt,...)
Definition: elog.c:822
Definition: pg_list.h:50

◆ InsertExtensionTuple()

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

Definition at line 1763 of file extension.c.

References BoolGetDatum, CatalogTupleInsert(), ObjectAddress::classId, CStringGetDatum, CStringGetTextDatum, DEPENDENCY_NORMAL, DirectFunctionCall1, ExtensionOidIndexId, GetNewOidWithIndex(), heap_form_tuple(), heap_freetuple(), InvokeObjectPostCreateHook, lfirst_oid, namein(), ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, PointerGetDatum, RelationData::rd_att, recordDependencyOn(), recordDependencyOnOwner(), RowExclusiveLock, table_close(), table_open(), and values.

Referenced by binary_upgrade_create_empty_extension(), and CreateExtensionInternal().

1767 {
1768  Oid extensionOid;
1769  Relation rel;
1770  Datum values[Natts_pg_extension];
1771  bool nulls[Natts_pg_extension];
1772  HeapTuple tuple;
1773  ObjectAddress myself;
1774  ObjectAddress nsp;
1775  ListCell *lc;
1776 
1777  /*
1778  * Build and insert the pg_extension tuple
1779  */
1780  rel = table_open(ExtensionRelationId, RowExclusiveLock);
1781 
1782  memset(values, 0, sizeof(values));
1783  memset(nulls, 0, sizeof(nulls));
1784 
1785  extensionOid = GetNewOidWithIndex(rel, ExtensionOidIndexId,
1786  Anum_pg_extension_oid);
1787  values[Anum_pg_extension_oid - 1] = ObjectIdGetDatum(extensionOid);
1788  values[Anum_pg_extension_extname - 1] =
1790  values[Anum_pg_extension_extowner - 1] = ObjectIdGetDatum(extOwner);
1791  values[Anum_pg_extension_extnamespace - 1] = ObjectIdGetDatum(schemaOid);
1792  values[Anum_pg_extension_extrelocatable - 1] = BoolGetDatum(relocatable);
1793  values[Anum_pg_extension_extversion - 1] = CStringGetTextDatum(extVersion);
1794 
1795  if (extConfig == PointerGetDatum(NULL))
1796  nulls[Anum_pg_extension_extconfig - 1] = true;
1797  else
1798  values[Anum_pg_extension_extconfig - 1] = extConfig;
1799 
1800  if (extCondition == PointerGetDatum(NULL))
1801  nulls[Anum_pg_extension_extcondition - 1] = true;
1802  else
1803  values[Anum_pg_extension_extcondition - 1] = extCondition;
1804 
1805  tuple = heap_form_tuple(rel->rd_att, values, nulls);
1806 
1807  CatalogTupleInsert(rel, tuple);
1808 
1809  heap_freetuple(tuple);
1811 
1812  /*
1813  * Record dependencies on owner, schema, and prerequisite extensions
1814  */
1815  recordDependencyOnOwner(ExtensionRelationId, extensionOid, extOwner);
1816 
1817  myself.classId = ExtensionRelationId;
1818  myself.objectId = extensionOid;
1819  myself.objectSubId = 0;
1820 
1821  nsp.classId = NamespaceRelationId;
1822  nsp.objectId = schemaOid;
1823  nsp.objectSubId = 0;
1824 
1825  recordDependencyOn(&myself, &nsp, DEPENDENCY_NORMAL);
1826 
1827  foreach(lc, requiredExtensions)
1828  {
1829  Oid reqext = lfirst_oid(lc);
1830  ObjectAddress otherext;
1831 
1832  otherext.classId = ExtensionRelationId;
1833  otherext.objectId = reqext;
1834  otherext.objectSubId = 0;
1835 
1836  recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
1837  }
1838  /* Post creation hook for new extension */
1839  InvokeObjectPostCreateHook(ExtensionRelationId, extensionOid, 0);
1840 
1841  return myself;
1842 }
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:322
Datum namein(PG_FUNCTION_ARGS)
Definition: name.c:48
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:151
#define PointerGetDatum(X)
Definition: postgres.h:556
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:43
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:615
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:164
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
unsigned int Oid
Definition: postgres_ext.h:31
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define RowExclusiveLock
Definition: lockdefs.h:38
#define CStringGetDatum(X)
Definition: postgres.h:578
#define ExtensionOidIndexId
Definition: indexing.h:326
uintptr_t Datum
Definition: postgres.h:367
TupleDesc rd_att
Definition: rel.h:84
#define BoolGetDatum(X)
Definition: postgres.h:402
static Datum values[MAXATTR]
Definition: bootstrap.c:167
#define CStringGetTextDatum(s)
Definition: builtins.h:83
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:183
#define lfirst_oid(lc)
Definition: pg_list.h:192

◆ is_extension_control_filename()

static bool is_extension_control_filename ( const char *  filename)
static

Definition at line 353 of file extension.c.

Referenced by pg_available_extension_versions(), and pg_available_extensions().

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

Referenced by get_ext_ver_list().

362 {
363  const char *extension = strrchr(filename, '.');
364 
365  return (extension != NULL) && (strcmp(extension, ".sql") == 0);
366 }
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 469 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().

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

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

◆ pg_available_extensions()

Datum pg_available_extensions ( PG_FUNCTION_ARGS  )

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

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

◆ pg_extension_config_dump()

Datum pg_extension_config_dump ( PG_FUNCTION_ARGS  )

Definition at line 2348 of file extension.c.

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

2349 {
2350  Oid tableoid = PG_GETARG_OID(0);
2351  text *wherecond = PG_GETARG_TEXT_PP(1);
2352  char *tablename;
2353  Relation extRel;
2354  ScanKeyData key[1];
2355  SysScanDesc extScan;
2356  HeapTuple extTup;
2357  Datum arrayDatum;
2358  Datum elementDatum;
2359  int arrayLength;
2360  int arrayIndex;
2361  bool isnull;
2362  Datum repl_val[Natts_pg_extension];
2363  bool repl_null[Natts_pg_extension];
2364  bool repl_repl[Natts_pg_extension];
2365  ArrayType *a;
2366 
2367  /*
2368  * We only allow this to be called from an extension's SQL script. We
2369  * shouldn't need any permissions check beyond that.
2370  */
2371  if (!creating_extension)
2372  ereport(ERROR,
2373  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2374  errmsg("%s can only be called from an SQL script executed by CREATE EXTENSION",
2375  "pg_extension_config_dump()")));
2376 
2377  /*
2378  * Check that the table exists and is a member of the extension being
2379  * created. This ensures that we don't need to register an additional
2380  * dependency to protect the extconfig entry.
2381  */
2382  tablename = get_rel_name(tableoid);
2383  if (tablename == NULL)
2384  ereport(ERROR,
2386  errmsg("OID %u does not refer to a table", tableoid)));
2387  if (getExtensionOfObject(RelationRelationId, tableoid) !=
2389  ereport(ERROR,
2390  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2391  errmsg("table \"%s\" is not a member of the extension being created",
2392  tablename)));
2393 
2394  /*
2395  * Add the table OID and WHERE condition to the extension's extconfig and
2396  * extcondition arrays.
2397  *
2398  * If the table is already in extconfig, treat this as an update of the
2399  * WHERE condition.
2400  */
2401 
2402  /* Find the pg_extension tuple */
2403  extRel = table_open(ExtensionRelationId, RowExclusiveLock);
2404 
2405  ScanKeyInit(&key[0],
2406  Anum_pg_extension_oid,
2407  BTEqualStrategyNumber, F_OIDEQ,
2409 
2410  extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
2411  NULL, 1, key);
2412 
2413  extTup = systable_getnext(extScan);
2414 
2415  if (!HeapTupleIsValid(extTup)) /* should not happen */
2416  elog(ERROR, "could not find tuple for extension %u",
2418 
2419  memset(repl_val, 0, sizeof(repl_val));
2420  memset(repl_null, false, sizeof(repl_null));
2421  memset(repl_repl, false, sizeof(repl_repl));
2422 
2423  /* Build or modify the extconfig value */
2424  elementDatum = ObjectIdGetDatum(tableoid);
2425 
2426  arrayDatum = heap_getattr(extTup, Anum_pg_extension_extconfig,
2427  RelationGetDescr(extRel), &isnull);
2428  if (isnull)
2429  {
2430  /* Previously empty extconfig, so build 1-element array */
2431  arrayLength = 0;
2432  arrayIndex = 1;
2433 
2434  a = construct_array(&elementDatum, 1,
2435  OIDOID,
2436  sizeof(Oid), true, 'i');
2437  }
2438  else
2439  {
2440  /* Modify or extend existing extconfig array */
2441  Oid *arrayData;
2442  int i;
2443 
2444  a = DatumGetArrayTypeP(arrayDatum);
2445 
2446  arrayLength = ARR_DIMS(a)[0];
2447  if (ARR_NDIM(a) != 1 ||
2448  ARR_LBOUND(a)[0] != 1 ||
2449  arrayLength < 0 ||
2450  ARR_HASNULL(a) ||
2451  ARR_ELEMTYPE(a) != OIDOID)
2452  elog(ERROR, "extconfig is not a 1-D Oid array");
2453  arrayData = (Oid *) ARR_DATA_PTR(a);
2454 
2455  arrayIndex = arrayLength + 1; /* set up to add after end */
2456 
2457  for (i = 0; i < arrayLength; i++)
2458  {
2459  if (arrayData[i] == tableoid)
2460  {
2461  arrayIndex = i + 1; /* replace this element instead */
2462  break;
2463  }
2464  }
2465 
2466  a = array_set(a, 1, &arrayIndex,
2467  elementDatum,
2468  false,
2469  -1 /* varlena array */ ,
2470  sizeof(Oid) /* OID's typlen */ ,
2471  true /* OID's typbyval */ ,
2472  'i' /* OID's typalign */ );
2473  }
2474  repl_val[Anum_pg_extension_extconfig - 1] = PointerGetDatum(a);
2475  repl_repl[Anum_pg_extension_extconfig - 1] = true;
2476 
2477  /* Build or modify the extcondition value */
2478  elementDatum = PointerGetDatum(wherecond);
2479 
2480  arrayDatum = heap_getattr(extTup, Anum_pg_extension_extcondition,
2481  RelationGetDescr(extRel), &isnull);
2482  if (isnull)
2483  {
2484  if (arrayLength != 0)
2485  elog(ERROR, "extconfig and extcondition arrays do not match");
2486 
2487  a = construct_array(&elementDatum, 1,
2488  TEXTOID,
2489  -1, false, 'i');
2490  }
2491  else
2492  {
2493  a = DatumGetArrayTypeP(arrayDatum);
2494 
2495  if (ARR_NDIM(a) != 1 ||
2496  ARR_LBOUND(a)[0] != 1 ||
2497  ARR_HASNULL(a) ||
2498  ARR_ELEMTYPE(a) != TEXTOID)
2499  elog(ERROR, "extcondition is not a 1-D text array");
2500  if (ARR_DIMS(a)[0] != arrayLength)
2501  elog(ERROR, "extconfig and extcondition arrays do not match");
2502 
2503  /* Add or replace at same index as in extconfig */
2504  a = array_set(a, 1, &arrayIndex,
2505  elementDatum,
2506  false,
2507  -1 /* varlena array */ ,
2508  -1 /* TEXT's typlen */ ,
2509  false /* TEXT's typbyval */ ,
2510  'i' /* TEXT's typalign */ );
2511  }
2512  repl_val[Anum_pg_extension_extcondition - 1] = PointerGetDatum(a);
2513  repl_repl[Anum_pg_extension_extcondition - 1] = true;
2514 
2515  extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
2516  repl_val, repl_null, repl_repl);
2517 
2518  CatalogTupleUpdate(extRel, &extTup->t_self, extTup);
2519 
2520  systable_endscan(extScan);
2521 
2522  table_close(extRel, RowExclusiveLock);
2523 
2524  PG_RETURN_VOID();
2525 }
Oid CurrentExtensionObject
Definition: extension.c:71
Oid getExtensionOfObject(Oid classId, Oid objectId)
Definition: pg_depend.c:610
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:133
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:525
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:74
#define RelationGetDescr(relation)
Definition: rel.h:448
#define PointerGetDatum(X)
Definition: postgres.h:556
ArrayType * construct_array(Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3291
int errcode(int sqlerrcode)
Definition: elog.c:608
ArrayType * array_set(ArrayType *array, int nSubscripts, int *indx, Datum dataValue, bool isNull, int arraytyplen, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3093
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:352
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:303
#define ARR_LBOUND(a)
Definition: array.h:284
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:444
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define ARR_DIMS(a)
Definition: array.h:282
ItemPointerData t_self
Definition: htup.h:65
#define ARR_DATA_PTR(a)
Definition: array.h:310
#define PG_GETARG_OID(n)
Definition: fmgr.h:270
#define RowExclusiveLock
Definition: lockdefs.h:38
#define ARR_HASNULL(a)
Definition: array.h:279
#define ereport(elevel, rest)
Definition: elog.h:141
#define ExtensionOidIndexId
Definition: indexing.h:326
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:762
uintptr_t Datum
Definition: postgres.h:367
bool creating_extension
Definition: extension.c:70
#define PG_RETURN_VOID()
Definition: fmgr.h:339
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:224
#define ARR_NDIM(a)
Definition: array.h:278
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define elog(elevel,...)
Definition: elog.h:228
int i
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Definition: c.h:556
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1730
#define ARR_ELEMTYPE(a)
Definition: array.h:280
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define DatumGetArrayTypeP(X)
Definition: array.h:249

◆ pg_extension_update_paths()

Datum pg_extension_update_paths ( PG_FUNCTION_ARGS  )

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

2235 {
2236  Name extname = PG_GETARG_NAME(0);
2237  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
2238  TupleDesc tupdesc;
2239  Tuplestorestate *tupstore;
2240  MemoryContext per_query_ctx;
2241  MemoryContext oldcontext;
2242  List *evi_list;
2243  ExtensionControlFile *control;
2244  ListCell *lc1;
2245 
2246  /* Check extension name validity before any filesystem access */
2248 
2249  /* check to see if caller supports us returning a tuplestore */
2250  if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
2251  ereport(ERROR,
2252  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2253  errmsg("set-valued function called in context that cannot accept a set")));
2254  if (!(rsinfo->allowedModes & SFRM_Materialize))
2255  ereport(ERROR,
2256  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2257  errmsg("materialize mode required, but it is not " \
2258  "allowed in this context")));
2259 
2260  /* Build a tuple descriptor for our result type */
2261  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
2262  elog(ERROR, "return type must be a row type");
2263 
2264  /* Build tuplestore to hold the result rows */
2265  per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
2266  oldcontext = MemoryContextSwitchTo(per_query_ctx);
2267 
2268  tupstore = tuplestore_begin_heap(true, false, work_mem);
2269  rsinfo->returnMode = SFRM_Materialize;
2270  rsinfo->setResult = tupstore;
2271  rsinfo->setDesc = tupdesc;
2272 
2273  MemoryContextSwitchTo(oldcontext);
2274 
2275  /* Read the extension's control file */
2276  control = read_extension_control_file(NameStr(*extname));
2277 
2278  /* Extract the version update graph from the script directory */
2279  evi_list = get_ext_ver_list(control);
2280 
2281  /* Iterate over all pairs of versions */
2282  foreach(lc1, evi_list)
2283  {
2285  ListCell *lc2;
2286 
2287  foreach(lc2, evi_list)
2288  {
2290  List *path;
2291  Datum values[3];
2292  bool nulls[3];
2293 
2294  if (evi1 == evi2)
2295  continue;
2296 
2297  /* Find shortest path from evi1 to evi2 */
2298  path = find_update_path(evi_list, evi1, evi2, false, true);
2299 
2300  /* Emit result row */
2301  memset(values, 0, sizeof(values));
2302  memset(nulls, 0, sizeof(nulls));
2303 
2304  /* source */
2305  values[0] = CStringGetTextDatum(evi1->name);
2306  /* target */
2307  values[1] = CStringGetTextDatum(evi2->name);
2308  /* path */
2309  if (path == NIL)
2310  nulls[2] = true;
2311  else
2312  {
2313  StringInfoData pathbuf;
2314  ListCell *lcv;
2315 
2316  initStringInfo(&pathbuf);
2317  /* The path doesn't include start vertex, but show it */
2318  appendStringInfoString(&pathbuf, evi1->name);
2319  foreach(lcv, path)
2320  {
2321  char *versionName = (char *) lfirst(lcv);
2322 
2323  appendStringInfoString(&pathbuf, "--");
2324  appendStringInfoString(&pathbuf, versionName);
2325  }
2326  values[2] = CStringGetTextDatum(pathbuf.data);
2327  pfree(pathbuf.data);
2328  }
2329 
2330  tuplestore_putvalues(tupstore, tupdesc, values, nulls);
2331  }
2332  }
2333 
2334  /* clean up and return the tuplestore */
2335  tuplestore_donestoring(tupstore);
2336 
2337  return (Datum) 0;
2338 }
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, Datum *values, bool *isnull)
Definition: tuplestore.c:750
#define NIL
Definition: pg_list.h:65
static List * find_update_path(List *evi_list, ExtensionVersionInfo *evi_start, ExtensionVersionInfo *evi_target, bool reject_indirect, bool reinitialize)
Definition: extension.c:1134
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:196
static ExtensionControlFile * read_extension_control_file(const char *extname)
Definition: extension.c:606
static void check_valid_extension_name(const char *extensionname)
Definition: extension.c:259
static List * get_ext_ver_list(ExtensionControlFile *control)
Definition: extension.c:1028
#define tuplestore_donestoring(state)
Definition: tuplestore.h:60
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:608
void pfree(void *pointer)
Definition: mcxt.c:1056
#define ERROR
Definition: elog.h:43
Definition: c.h:610
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
#define ereport(elevel, rest)
Definition: elog.h:141
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
uintptr_t Datum
Definition: postgres.h:367
int work_mem
Definition: globals.c:121
int allowedModes
Definition: execnodes.h:302
SetFunctionReturnMode returnMode
Definition: execnodes.h:304
#define lfirst(lc)
Definition: pg_list.h:190
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:230
Tuplestorestate * setResult
Definition: execnodes.h:307
static Datum values[MAXATTR]
Definition: bootstrap.c:167
ExprContext * econtext
Definition: execnodes.h:300
TupleDesc setDesc
Definition: execnodes.h:308
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define elog(elevel,...)
Definition: elog.h:228
#define NameStr(name)
Definition: c.h:616
#define CStringGetTextDatum(s)
Definition: builtins.h:83
Definition: pg_list.h:50
#define PG_GETARG_NAME(n)
Definition: fmgr.h:273

◆ read_extension_aux_control_file()

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

Definition at line 634 of file extension.c.

References palloc(), and parse_extension_control_file().

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

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

◆ read_extension_control_file()

static ExtensionControlFile* read_extension_control_file ( const char *  extname)
static

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

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

◆ read_extension_script_file()

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

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

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

◆ read_whole_file()

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

Definition at line 3332 of file extension.c.

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

Referenced by read_extension_script_file().

3333 {
3334  char *buf;
3335  FILE *file;
3336  size_t bytes_to_read;
3337  struct stat fst;
3338 
3339  if (stat(filename, &fst) < 0)
3340  ereport(ERROR,
3342  errmsg("could not stat file \"%s\": %m", filename)));
3343 
3344  if (fst.st_size > (MaxAllocSize - 1))
3345  ereport(ERROR,
3346  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3347  errmsg("file \"%s\" is too large", filename)));
3348  bytes_to_read = (size_t) fst.st_size;
3349 
3350  if ((file = AllocateFile(filename, PG_BINARY_R)) == NULL)
3351  ereport(ERROR,
3353  errmsg("could not open file \"%s\" for reading: %m",
3354  filename)));
3355 
3356  buf = (char *) palloc(bytes_to_read + 1);
3357 
3358  *length = fread(buf, 1, bytes_to_read, file);
3359 
3360  if (ferror(file))
3361  ereport(ERROR,
3363  errmsg("could not read file \"%s\": %m", filename)));
3364 
3365  FreeFile(file);
3366 
3367  buf[*length] = '\0';
3368  return buf;
3369 }
int errcode(int sqlerrcode)
Definition: elog.c:608
#define PG_BINARY_R
Definition: c.h:1224
#define ERROR
Definition: elog.h:43
static char * buf
Definition: pg_test_fsync.c:67
int errcode_for_file_access(void)
Definition: elog.c:631
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2242
#define ereport(elevel, rest)
Definition: elog.h:141
#define MaxAllocSize
Definition: memutils.h:40
#define stat(a, b)
Definition: win32_port.h:255
int FreeFile(FILE *file)
Definition: fd.c:2441
static char * filename
Definition: pg_dumpall.c:90
void * palloc(Size size)
Definition: mcxt.c:949
int errmsg(const char *fmt,...)
Definition: elog.c:822

◆ RemoveExtensionById()

void RemoveExtensionById ( Oid  extId)

Definition at line 1851 of file extension.c.

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

Referenced by doDeletion().

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

Variable Documentation

◆ creating_extension

◆ CurrentExtensionObject