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

Go to the source code of this file.

Data Structures

struct  ExtensionControlFile
 
struct  ExtensionVersionInfo
 

Typedefs

typedef struct ExtensionControlFile ExtensionControlFile
 
typedef struct ExtensionVersionInfo ExtensionVersionInfo
 

Functions

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

Variables

bool creating_extension = false
 
Oid CurrentExtensionObject = InvalidOid
 

Typedef Documentation

◆ ExtensionControlFile

◆ ExtensionVersionInfo

Function Documentation

◆ AlterExtensionNamespace()

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

Definition at line 2706 of file extension.c.

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

References AccessShareLock, ACL_CREATE, aclcheck_error(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, AlterObjectNamespace_oid(), BTEqualStrategyNumber, CatalogTupleUpdate(), changeDependencyFor(), ObjectAddress::classId, DEPENDENCY_EXTENSION, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, 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().

◆ ApplyExtensionUpdates()

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

Definition at line 3035 of file extension.c.

3042 {
3043  const char *oldVersionName = initialVersion;
3044  ListCell *lcv;
3045 
3046  foreach(lcv, updateVersions)
3047  {
3048  char *versionName = (char *) lfirst(lcv);
3049  ExtensionControlFile *control;
3050  char *schemaName;
3051  Oid schemaOid;
3052  List *requiredExtensions;
3053  List *requiredSchemas;
3054  Relation extRel;
3055  ScanKeyData key[1];
3056  SysScanDesc extScan;
3057  HeapTuple extTup;
3058  Form_pg_extension extForm;
3059  Datum values[Natts_pg_extension];
3060  bool nulls[Natts_pg_extension];
3061  bool repl[Natts_pg_extension];
3062  ObjectAddress myself;
3063  ListCell *lc;
3064 
3065  /*
3066  * Fetch parameters for specific version (pcontrol is not changed)
3067  */
3068  control = read_extension_aux_control_file(pcontrol, versionName);
3069 
3070  /* Find the pg_extension tuple */
3071  extRel = table_open(ExtensionRelationId, RowExclusiveLock);
3072 
3073  ScanKeyInit(&key[0],
3074  Anum_pg_extension_oid,
3075  BTEqualStrategyNumber, F_OIDEQ,
3076  ObjectIdGetDatum(extensionOid));
3077 
3078  extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
3079  NULL, 1, key);
3080 
3081  extTup = systable_getnext(extScan);
3082 
3083  if (!HeapTupleIsValid(extTup)) /* should not happen */
3084  elog(ERROR, "could not find tuple for extension %u",
3085  extensionOid);
3086 
3087  extForm = (Form_pg_extension) GETSTRUCT(extTup);
3088 
3089  /*
3090  * Determine the target schema (set by original install)
3091  */
3092  schemaOid = extForm->extnamespace;
3093  schemaName = get_namespace_name(schemaOid);
3094 
3095  /*
3096  * Modify extrelocatable and extversion in the pg_extension tuple
3097  */
3098  memset(values, 0, sizeof(values));
3099  memset(nulls, 0, sizeof(nulls));
3100  memset(repl, 0, sizeof(repl));
3101 
3102  values[Anum_pg_extension_extrelocatable - 1] =
3103  BoolGetDatum(control->relocatable);
3104  repl[Anum_pg_extension_extrelocatable - 1] = true;
3105  values[Anum_pg_extension_extversion - 1] =
3106  CStringGetTextDatum(versionName);
3107  repl[Anum_pg_extension_extversion - 1] = true;
3108 
3109  extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
3110  values, nulls, repl);
3111 
3112  CatalogTupleUpdate(extRel, &extTup->t_self, extTup);
3113 
3114  systable_endscan(extScan);
3115 
3116  table_close(extRel, RowExclusiveLock);
3117 
3118  /*
3119  * Look up the prerequisite extensions for this version, install them
3120  * if necessary, and build lists of their OIDs and the OIDs of their
3121  * target schemas.
3122  */
3123  requiredExtensions = NIL;
3124  requiredSchemas = NIL;
3125  foreach(lc, control->requires)
3126  {
3127  char *curreq = (char *) lfirst(lc);
3128  Oid reqext;
3129  Oid reqschema;
3130 
3131  reqext = get_required_extension(curreq,
3132  control->name,
3133  origSchemaName,
3134  cascade,
3135  NIL,
3136  is_create);
3137  reqschema = get_extension_schema(reqext);
3138  requiredExtensions = lappend_oid(requiredExtensions, reqext);
3139  requiredSchemas = lappend_oid(requiredSchemas, reqschema);
3140  }
3141 
3142  /*
3143  * Remove and recreate dependencies on prerequisite extensions
3144  */
3145  deleteDependencyRecordsForClass(ExtensionRelationId, extensionOid,
3146  ExtensionRelationId,
3148 
3149  myself.classId = ExtensionRelationId;
3150  myself.objectId = extensionOid;
3151  myself.objectSubId = 0;
3152 
3153  foreach(lc, requiredExtensions)
3154  {
3155  Oid reqext = lfirst_oid(lc);
3156  ObjectAddress otherext;
3157 
3158  otherext.classId = ExtensionRelationId;
3159  otherext.objectId = reqext;
3160  otherext.objectSubId = 0;
3161 
3162  recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
3163  }
3164 
3165  InvokeObjectPostAlterHook(ExtensionRelationId, extensionOid, 0);
3166 
3167  /*
3168  * Finally, execute the update script file
3169  */
3170  execute_extension_script(extensionOid, control,
3171  oldVersionName, versionName,
3172  requiredSchemas,
3173  schemaName, schemaOid);
3174 
3175  /*
3176  * Update prior-version name and loop around. Since
3177  * execute_sql_string did a final CommandCounterIncrement, we can
3178  * update the pg_extension row again.
3179  */
3180  oldVersionName = versionName;
3181  }
3182 }
static Datum values[MAXATTR]
Definition: bootstrap.c:156
#define CStringGetTextDatum(s)
Definition: builtins.h:85
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
static Oid get_required_extension(char *reqExtensionName, char *extensionName, char *origSchemaName, bool cascade, List *parents, bool is_create)
Definition: extension.c:1621
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:847
static Oid get_extension_schema(Oid ext_oid)
Definition: extension.c:224
static ExtensionControlFile * read_extension_aux_control_file(const ExtensionControlFile *pcontrol, const char *version)
Definition: extension.c:656
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
List * lappend_oid(List *list, Oid datum)
Definition: list.c:372
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition: pg_depend.c:293
#define lfirst(lc)
Definition: pg_list.h:169
#define NIL
Definition: pg_list.h:65
#define lfirst_oid(lc)
Definition: pg_list.h:171
uintptr_t Datum
Definition: postgres.h:411
#define BoolGetDatum(X)
Definition: postgres.h:446
#define RelationGetDescr(relation)
Definition: rel.h:515
Definition: pg_list.h:51

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

Referenced by CreateExtensionInternal(), and ExecAlterExtensionStmt().

◆ check_valid_extension_name()

static void check_valid_extension_name ( const char *  extensionname)
static

Definition at line 261 of file extension.c.

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

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

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

◆ check_valid_version_name()

static void check_valid_version_name ( const char *  versionname)
static

Definition at line 308 of file extension.c.

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

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

Referenced by CreateExtensionInternal(), and ExecAlterExtensionStmt().

◆ convert_requires_to_datum()

static Datum convert_requires_to_datum ( List requires)
static

Definition at line 2237 of file extension.c.

2238 {
2239  Datum *datums;
2240  int ndatums;
2241  ArrayType *a;
2242  ListCell *lc;
2243 
2244  ndatums = list_length(requires);
2245  datums = (Datum *) palloc(ndatums * sizeof(Datum));
2246  ndatums = 0;
2247  foreach(lc, requires)
2248  {
2249  char *curreq = (char *) lfirst(lc);
2250 
2251  datums[ndatums++] =
2253  }
2254  a = construct_array(datums, ndatums,
2255  NAMEOID,
2256  NAMEDATALEN, false, TYPALIGN_CHAR);
2257  return PointerGetDatum(a);
2258 }
ArrayType * construct_array(Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3319
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:631
int a
Definition: isn.c:69
void * palloc(Size size)
Definition: mcxt.c:1068
Datum namein(PG_FUNCTION_ARGS)
Definition: name.c:48
#define NAMEDATALEN
static int list_length(const List *l)
Definition: pg_list.h:149
#define CStringGetDatum(X)
Definition: postgres.h:622
#define PointerGetDatum(X)
Definition: postgres.h:600

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

Referenced by get_available_versions_for_extension().

◆ CreateExtension()

ObjectAddress CreateExtension ( ParseState pstate,
CreateExtensionStmt stmt 
)

Definition at line 1692 of file extension.c.

1693 {
1694  DefElem *d_schema = NULL;
1695  DefElem *d_new_version = NULL;
1696  DefElem *d_cascade = NULL;
1697  char *schemaName = NULL;
1698  char *versionName = NULL;
1699  bool cascade = false;
1700  ListCell *lc;
1701 
1702  /* Check extension name validity before any filesystem access */
1704 
1705  /*
1706  * Check for duplicate extension name. The unique index on
1707  * pg_extension.extname would catch this anyway, and serves as a backstop
1708  * in case of race conditions; but this is a friendlier error message, and
1709  * besides we need a check to support IF NOT EXISTS.
1710  */
1711  if (get_extension_oid(stmt->extname, true) != InvalidOid)
1712  {
1713  if (stmt->if_not_exists)
1714  {
1715  ereport(NOTICE,
1717  errmsg("extension \"%s\" already exists, skipping",
1718  stmt->extname)));
1719  return InvalidObjectAddress;
1720  }
1721  else
1722  ereport(ERROR,
1724  errmsg("extension \"%s\" already exists",
1725  stmt->extname)));
1726  }
1727 
1728  /*
1729  * We use global variables to track the extension being created, so we can
1730  * create only one extension at the same time.
1731  */
1732  if (creating_extension)
1733  ereport(ERROR,
1734  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1735  errmsg("nested CREATE EXTENSION is not supported")));
1736 
1737  /* Deconstruct the statement option list */
1738  foreach(lc, stmt->options)
1739  {
1740  DefElem *defel = (DefElem *) lfirst(lc);
1741 
1742  if (strcmp(defel->defname, "schema") == 0)
1743  {
1744  if (d_schema)
1745  errorConflictingDefElem(defel, pstate);
1746  d_schema = defel;
1747  schemaName = defGetString(d_schema);
1748  }
1749  else if (strcmp(defel->defname, "new_version") == 0)
1750  {
1751  if (d_new_version)
1752  errorConflictingDefElem(defel, pstate);
1753  d_new_version = defel;
1754  versionName = defGetString(d_new_version);
1755  }
1756  else if (strcmp(defel->defname, "cascade") == 0)
1757  {
1758  if (d_cascade)
1759  errorConflictingDefElem(defel, pstate);
1760  d_cascade = defel;
1761  cascade = defGetBoolean(d_cascade);
1762  }
1763  else
1764  elog(ERROR, "unrecognized option: %s", defel->defname);
1765  }
1766 
1767  /* Call CreateExtensionInternal to do the real work. */
1768  return CreateExtensionInternal(stmt->extname,
1769  schemaName,
1770  versionName,
1771  cascade,
1772  NIL,
1773  true);
1774 }
bool defGetBoolean(DefElem *def)
Definition: define.c:108
char * defGetString(DefElem *def)
Definition: define.c:49
void errorConflictingDefElem(DefElem *defel, ParseState *pstate)
Definition: define.c:352
#define NOTICE
Definition: elog.h:29
static void check_valid_extension_name(const char *extensionname)
Definition: extension.c:261
bool creating_extension
Definition: extension.c:71
static ObjectAddress CreateExtensionInternal(char *extensionName, char *schemaName, const char *versionName, bool cascade, List *parents, bool is_create)
Definition: extension.c:1382
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
char * defname
Definition: parsenodes.h:765

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

Referenced by ProcessUtilitySlow().

◆ CreateExtensionInternal()

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

Definition at line 1382 of file extension.c.

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

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

Referenced by CreateExtension(), and get_required_extension().

◆ ExecAlterExtensionContentsStmt()

ObjectAddress ExecAlterExtensionContentsStmt ( AlterExtensionContentsStmt stmt,
ObjectAddress objAddr 
)

Definition at line 3193 of file extension.c.

3195 {
3196  ObjectAddress extension;
3197  ObjectAddress object;
3198  Relation relation;
3199  Oid oldExtension;
3200 
3201  switch (stmt->objtype)
3202  {
3203  case OBJECT_DATABASE:
3204  case OBJECT_EXTENSION:
3205  case OBJECT_INDEX:
3206  case OBJECT_PUBLICATION:
3207  case OBJECT_ROLE:
3208  case OBJECT_STATISTIC_EXT:
3209  case OBJECT_SUBSCRIPTION:
3210  case OBJECT_TABLESPACE:
3211  ereport(ERROR,
3212  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3213  errmsg("cannot add an object of this type to an extension")));
3214  break;
3215  default:
3216  /* OK */
3217  break;
3218  }
3219 
3220  /*
3221  * Find the extension and acquire a lock on it, to ensure it doesn't get
3222  * dropped concurrently. A sharable lock seems sufficient: there's no
3223  * reason not to allow other sorts of manipulations, such as add/drop of
3224  * other objects, to occur concurrently. Concurrently adding/dropping the
3225  * *same* object would be bad, but we prevent that by using a non-sharable
3226  * lock on the individual object, below.
3227  */
3229  (Node *) makeString(stmt->extname),
3230  &relation, AccessShareLock, false);
3231 
3232  /* Permission check: must own extension */
3233  if (!pg_extension_ownercheck(extension.objectId, GetUserId()))
3235  stmt->extname);
3236 
3237  /*
3238  * Translate the parser representation that identifies the object into an
3239  * ObjectAddress. get_object_address() will throw an error if the object
3240  * does not exist, and will also acquire a lock on the object to guard
3241  * against concurrent DROP and ALTER EXTENSION ADD/DROP operations.
3242  */
3243  object = get_object_address(stmt->objtype, stmt->object,
3244  &relation, ShareUpdateExclusiveLock, false);
3245 
3246  Assert(object.objectSubId == 0);
3247  if (objAddr)
3248  *objAddr = object;
3249 
3250  /* Permission check: must own target object, too */
3251  check_object_ownership(GetUserId(), stmt->objtype, object,
3252  stmt->object, relation);
3253 
3254  /*
3255  * Check existing extension membership.
3256  */
3257  oldExtension = getExtensionOfObject(object.classId, object.objectId);
3258 
3259  if (stmt->action > 0)
3260  {
3261  /*
3262  * ADD, so complain if object is already attached to some extension.
3263  */
3264  if (OidIsValid(oldExtension))
3265  ereport(ERROR,
3266  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3267  errmsg("%s is already a member of extension \"%s\"",
3268  getObjectDescription(&object, false),
3269  get_extension_name(oldExtension))));
3270 
3271  /*
3272  * Prevent a schema from being added to an extension if the schema
3273  * contains the extension. That would create a dependency loop.
3274  */
3275  if (object.classId == NamespaceRelationId &&
3276  object.objectId == get_extension_schema(extension.objectId))
3277  ereport(ERROR,
3278  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3279  errmsg("cannot add schema \"%s\" to extension \"%s\" "
3280  "because the schema contains the extension",
3281  get_namespace_name(object.objectId),
3282  stmt->extname)));
3283 
3284  /*
3285  * OK, add the dependency.
3286  */
3287  recordDependencyOn(&object, &extension, DEPENDENCY_EXTENSION);
3288 
3289  /*
3290  * Also record the initial ACL on the object, if any.
3291  *
3292  * Note that this will handle the object's ACLs, as well as any ACLs
3293  * on object subIds. (In other words, when the object is a table,
3294  * this will record the table's ACL and the ACLs for the columns on
3295  * the table, if any).
3296  */
3297  recordExtObjInitPriv(object.objectId, object.classId);
3298  }
3299  else
3300  {
3301  /*
3302  * DROP, so complain if it's not a member.
3303  */
3304  if (oldExtension != extension.objectId)
3305  ereport(ERROR,
3306  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3307  errmsg("%s is not a member of extension \"%s\"",
3308  getObjectDescription(&object, false),
3309  stmt->extname)));
3310 
3311  /*
3312  * OK, drop the dependency.
3313  */
3314  if (deleteDependencyRecordsForClass(object.classId, object.objectId,
3315  ExtensionRelationId,
3316  DEPENDENCY_EXTENSION) != 1)
3317  elog(ERROR, "unexpected number of extension dependency records");
3318 
3319  /*
3320  * If it's a relation, it might have an entry in the extension's
3321  * extconfig array, which we must remove.
3322  */
3323  if (object.classId == RelationRelationId)
3324  extension_config_remove(extension.objectId, object.objectId);
3325 
3326  /*
3327  * Remove all the initial ACLs, if any.
3328  *
3329  * Note that this will remove the object's ACLs, as well as any ACLs
3330  * on object subIds. (In other words, when the object is a table,
3331  * this will remove the table's ACL and the ACLs for the columns on
3332  * the table, if any).
3333  */
3334  removeExtObjInitPriv(object.objectId, object.classId);
3335  }
3336 
3337  InvokeObjectPostAlterHook(ExtensionRelationId, extension.objectId, 0);
3338 
3339  /*
3340  * If get_object_address() opened the relation for us, we close it to keep
3341  * the reference count correct - but we retain any locks acquired by
3342  * get_object_address() until commit time, to guard against concurrent
3343  * activity.
3344  */
3345  if (relation != NULL)
3346  relation_close(relation, NoLock);
3347 
3348  return extension;
3349 }
void recordExtObjInitPriv(Oid objoid, Oid classoid)
Definition: aclchk.c:5980
void removeExtObjInitPriv(Oid objoid, Oid classoid)
Definition: aclchk.c:6278
static void extension_config_remove(Oid extensionoid, Oid tableoid)
Definition: extension.c:2537
char * get_extension_name(Oid ext_oid)
Definition: extension.c:185
Assert(fmt[strlen(fmt) - 1] !='\n')
#define NoLock
Definition: lockdefs.h:34
#define ShareUpdateExclusiveLock
Definition: lockdefs.h:39
void check_object_ownership(Oid roleid, ObjectType objtype, ObjectAddress address, Node *object, Relation relation)
ObjectAddress get_object_address(ObjectType objtype, Node *object, Relation *relp, LOCKMODE lockmode, bool missing_ok)
@ OBJECT_TABLESPACE
Definition: parsenodes.h:2176
@ OBJECT_ROLE
Definition: parsenodes.h:2167
@ OBJECT_INDEX
Definition: parsenodes.h:2154
@ OBJECT_DATABASE
Definition: parsenodes.h:2143
@ OBJECT_PUBLICATION
Definition: parsenodes.h:2164
@ OBJECT_SUBSCRIPTION
Definition: parsenodes.h:2172
@ OBJECT_STATISTIC_EXT
Definition: parsenodes.h:2173
Definition: nodes.h:574
String * makeString(char *str)
Definition: value.c:63

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

Referenced by ProcessUtilitySlow().

◆ ExecAlterExtensionStmt()

ObjectAddress ExecAlterExtensionStmt ( ParseState pstate,
AlterExtensionStmt stmt 
)

Definition at line 2888 of file extension.c.

2889 {
2890  DefElem *d_new_version = NULL;
2891  char *versionName;
2892  char *oldVersionName;
2893  ExtensionControlFile *control;
2894  Oid extensionOid;
2895  Relation extRel;
2896  ScanKeyData key[1];
2897  SysScanDesc extScan;
2898  HeapTuple extTup;
2899  List *updateVersions;
2900  Datum datum;
2901  bool isnull;
2902  ListCell *lc;
2903  ObjectAddress address;
2904 
2905  /*
2906  * We use global variables to track the extension being created, so we can
2907  * create/update only one extension at the same time.
2908  */
2909  if (creating_extension)
2910  ereport(ERROR,
2911  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2912  errmsg("nested ALTER EXTENSION is not supported")));
2913 
2914  /*
2915  * Look up the extension --- it must already exist in pg_extension
2916  */
2917  extRel = table_open(ExtensionRelationId, AccessShareLock);
2918 
2919  ScanKeyInit(&key[0],
2920  Anum_pg_extension_extname,
2921  BTEqualStrategyNumber, F_NAMEEQ,
2922  CStringGetDatum(stmt->extname));
2923 
2924  extScan = systable_beginscan(extRel, ExtensionNameIndexId, true,
2925  NULL, 1, key);
2926 
2927  extTup = systable_getnext(extScan);
2928 
2929  if (!HeapTupleIsValid(extTup))
2930  ereport(ERROR,
2931  (errcode(ERRCODE_UNDEFINED_OBJECT),
2932  errmsg("extension \"%s\" does not exist",
2933  stmt->extname)));
2934 
2935  extensionOid = ((Form_pg_extension) GETSTRUCT(extTup))->oid;
2936 
2937  /*
2938  * Determine the existing version we are updating from
2939  */
2940  datum = heap_getattr(extTup, Anum_pg_extension_extversion,
2941  RelationGetDescr(extRel), &isnull);
2942  if (isnull)
2943  elog(ERROR, "extversion is null");
2944  oldVersionName = text_to_cstring(DatumGetTextPP(datum));
2945 
2946  systable_endscan(extScan);
2947 
2948  table_close(extRel, AccessShareLock);
2949 
2950  /* Permission check: must own extension */
2951  if (!pg_extension_ownercheck(extensionOid, GetUserId()))
2953  stmt->extname);
2954 
2955  /*
2956  * Read the primary control file. Note we assume that it does not contain
2957  * any non-ASCII data, so there is no need to worry about encoding at this
2958  * point.
2959  */
2960  control = read_extension_control_file(stmt->extname);
2961 
2962  /*
2963  * Read the statement option list
2964  */
2965  foreach(lc, stmt->options)
2966  {
2967  DefElem *defel = (DefElem *) lfirst(lc);
2968 
2969  if (strcmp(defel->defname, "new_version") == 0)
2970  {
2971  if (d_new_version)
2972  errorConflictingDefElem(defel, pstate);
2973  d_new_version = defel;
2974  }
2975  else
2976  elog(ERROR, "unrecognized option: %s", defel->defname);
2977  }
2978 
2979  /*
2980  * Determine the version to update to
2981  */
2982  if (d_new_version && d_new_version->arg)
2983  versionName = strVal(d_new_version->arg);
2984  else if (control->default_version)
2985  versionName = control->default_version;
2986  else
2987  {
2988  ereport(ERROR,
2989  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2990  errmsg("version to install must be specified")));
2991  versionName = NULL; /* keep compiler quiet */
2992  }
2993  check_valid_version_name(versionName);
2994 
2995  /*
2996  * If we're already at that version, just say so
2997  */
2998  if (strcmp(oldVersionName, versionName) == 0)
2999  {
3000  ereport(NOTICE,
3001  (errmsg("version \"%s\" of extension \"%s\" is already installed",
3002  versionName, stmt->extname)));
3003  return InvalidObjectAddress;
3004  }
3005 
3006  /*
3007  * Identify the series of update script files we need to execute
3008  */
3009  updateVersions = identify_update_path(control,
3010  oldVersionName,
3011  versionName);
3012 
3013  /*
3014  * Update the pg_extension row and execute the update scripts, one at a
3015  * time
3016  */
3017  ApplyExtensionUpdates(extensionOid, control,
3018  oldVersionName, updateVersions,
3019  NULL, false, false);
3020 
3021  ObjectAddressSet(address, ExtensionRelationId, extensionOid);
3022 
3023  return address;
3024 }
static List * identify_update_path(ExtensionControlFile *control, const char *oldVersion, const char *newVersion)
Definition: extension.c:1191
#define DatumGetTextPP(X)
Definition: fmgr.h:292
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:788
Node * arg
Definition: parsenodes.h:766
#define strVal(v)
Definition: value.h:72
char * text_to_cstring(const text *t)
Definition: varlena.c:221

References AccessShareLock, aclcheck_error(), ACLCHECK_NOT_OWNER, ApplyExtensionUpdates(), DefElem::arg, BTEqualStrategyNumber, check_valid_version_name(), creating_extension, CStringGetDatum, DatumGetTextPP, ExtensionControlFile::default_version, DefElem::defname, elog, ereport, errcode(), errmsg(), ERROR, errorConflictingDefElem(), AlterExtensionStmt::extname, GETSTRUCT, GetUserId(), heap_getattr(), HeapTupleIsValid, identify_update_path(), InvalidObjectAddress, sort-test::key, lfirst, NOTICE, OBJECT_EXTENSION, ObjectAddressSet, AlterExtensionStmt::options, 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().

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

852 {
853  bool switch_to_superuser = false;
854  char *filename;
855  Oid save_userid = 0;
856  int save_sec_context = 0;
857  int save_nestlevel;
858  StringInfoData pathbuf;
859  ListCell *lc;
860 
861  /*
862  * Enforce superuser-ness if appropriate. We postpone these checks until
863  * here so that the control flags are correctly associated with the right
864  * script(s) if they happen to be set in secondary control files.
865  */
866  if (control->superuser && !superuser())
867  {
868  if (extension_is_trusted(control))
869  switch_to_superuser = true;
870  else if (from_version == NULL)
871  ereport(ERROR,
872  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
873  errmsg("permission denied to create extension \"%s\"",
874  control->name),
875  control->trusted
876  ? errhint("Must have CREATE privilege on current database to create this extension.")
877  : errhint("Must be superuser to create this extension.")));
878  else
879  ereport(ERROR,
880  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
881  errmsg("permission denied to update extension \"%s\"",
882  control->name),
883  control->trusted
884  ? errhint("Must have CREATE privilege on current database to update this extension.")
885  : errhint("Must be superuser to update this extension.")));
886  }
887 
888  filename = get_extension_script_filename(control, from_version, version);
889 
890  /*
891  * If installing a trusted extension on behalf of a non-superuser, become
892  * the bootstrap superuser. (This switch will be cleaned up automatically
893  * if the transaction aborts, as will the GUC changes below.)
894  */
895  if (switch_to_superuser)
896  {
897  GetUserIdAndSecContext(&save_userid, &save_sec_context);
898  SetUserIdAndSecContext(BOOTSTRAP_SUPERUSERID,
899  save_sec_context | SECURITY_LOCAL_USERID_CHANGE);
900  }
901 
902  /*
903  * Force client_min_messages and log_min_messages to be at least WARNING,
904  * so that we won't spam the user with useless NOTICE messages from common
905  * script actions like creating shell types.
906  *
907  * We use the equivalent of a function SET option to allow the setting to
908  * persist for exactly the duration of the script execution. guc.c also
909  * takes care of undoing the setting on error.
910  */
911  save_nestlevel = NewGUCNestLevel();
912 
914  (void) set_config_option("client_min_messages", "warning",
916  GUC_ACTION_SAVE, true, 0, false);
918  (void) set_config_option("log_min_messages", "warning",
920  GUC_ACTION_SAVE, true, 0, false);
921 
922  /*
923  * Similarly disable check_function_bodies, to ensure that SQL functions
924  * won't be parsed during creation.
925  */
927  (void) set_config_option("check_function_bodies", "off",
929  GUC_ACTION_SAVE, true, 0, false);
930 
931  /*
932  * Set up the search path to have the target schema first, making it be
933  * the default creation target namespace. Then add the schemas of any
934  * prerequisite extensions, unless they are in pg_catalog which would be
935  * searched anyway. (Listing pg_catalog explicitly in a non-first
936  * position would be bad for security.) Finally add pg_temp to ensure
937  * that temp objects can't take precedence over others.
938  *
939  * Note: it might look tempting to use PushOverrideSearchPath for this,
940  * but we cannot do that. We have to actually set the search_path GUC in
941  * case the extension script examines or changes it. In any case, the
942  * GUC_ACTION_SAVE method is just as convenient.
943  */
944  initStringInfo(&pathbuf);
945  appendStringInfoString(&pathbuf, quote_identifier(schemaName));
946  foreach(lc, requiredSchemas)
947  {
948  Oid reqschema = lfirst_oid(lc);
949  char *reqname = get_namespace_name(reqschema);
950 
951  if (reqname && strcmp(reqname, "pg_catalog") != 0)
952  appendStringInfo(&pathbuf, ", %s", quote_identifier(reqname));
953  }
954  appendStringInfoString(&pathbuf, ", pg_temp");
955 
956  (void) set_config_option("search_path", pathbuf.data,
958  GUC_ACTION_SAVE, true, 0, false);
959 
960  /*
961  * Set creating_extension and related variables so that
962  * recordDependencyOnCurrentExtension and other functions do the right
963  * things. On failure, ensure we reset these variables.
964  */
965  creating_extension = true;
966  CurrentExtensionObject = extensionOid;
967  PG_TRY();
968  {
969  char *c_sql = read_extension_script_file(control, filename);
970  Datum t_sql;
971 
972  /* We use various functions that want to operate on text datums */
973  t_sql = CStringGetTextDatum(c_sql);
974 
975  /*
976  * Reduce any lines beginning with "\echo" to empty. This allows
977  * scripts to contain messages telling people not to run them via
978  * psql, which has been found to be necessary due to old habits.
979  */
981  C_COLLATION_OID,
982  t_sql,
983  CStringGetTextDatum("^\\\\echo.*$"),
985  CStringGetTextDatum("ng"));
986 
987  /*
988  * If the script uses @extowner@, substitute the calling username.
989  */
990  if (strstr(c_sql, "@extowner@"))
991  {
992  Oid uid = switch_to_superuser ? save_userid : GetUserId();
993  const char *userName = GetUserNameFromId(uid, false);
994  const char *qUserName = quote_identifier(userName);
995 
997  C_COLLATION_OID,
998  t_sql,
999  CStringGetTextDatum("@extowner@"),
1000  CStringGetTextDatum(qUserName));
1001  }
1002 
1003  /*
1004  * If it's not relocatable, substitute the target schema name for
1005  * occurrences of @extschema@.
1006  *
1007  * For a relocatable extension, we needn't do this. There cannot be
1008  * any need for @extschema@, else it wouldn't be relocatable.
1009  */
1010  if (!control->relocatable)
1011  {
1012  const char *qSchemaName = quote_identifier(schemaName);
1013 
1015  C_COLLATION_OID,
1016  t_sql,
1017  CStringGetTextDatum("@extschema@"),
1018  CStringGetTextDatum(qSchemaName));
1019  }
1020 
1021  /*
1022  * If module_pathname was set in the control file, substitute its
1023  * value for occurrences of MODULE_PATHNAME.
1024  */
1025  if (control->module_pathname)
1026  {
1028  C_COLLATION_OID,
1029  t_sql,
1030  CStringGetTextDatum("MODULE_PATHNAME"),
1032  }
1033 
1034  /* And now back to C string */
1035  c_sql = text_to_cstring(DatumGetTextPP(t_sql));
1036 
1037  execute_sql_string(c_sql);
1038  }
1039  PG_FINALLY();
1040  {
1041  creating_extension = false;
1043  }
1044  PG_END_TRY();
1045 
1046  /*
1047  * Restore the GUC variables we set above.
1048  */
1049  AtEOXact_GUC(true, save_nestlevel);
1050 
1051  /*
1052  * Restore authentication state if needed.
1053  */
1054  if (switch_to_superuser)
1055  SetUserIdAndSecContext(save_userid, save_sec_context);
1056 }
int errhint(const char *fmt,...)
Definition: elog.c:1151
#define PG_END_TRY()
Definition: elog.h:324
#define PG_TRY()
Definition: elog.h:299
#define WARNING
Definition: elog.h:30
#define PG_FINALLY()
Definition: elog.h:316
static char * read_extension_script_file(const ExtensionControlFile *control, const char *filename)
Definition: extension.c:679
static void execute_sql_string(const char *sql)
Definition: extension.c:720
Oid CurrentExtensionObject
Definition: extension.c:72
static bool extension_is_trusted(ExtensionControlFile *control)
Definition: extension.c:827
Datum DirectFunctionCall4Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4)
Definition: fmgr.c:844
Datum DirectFunctionCall3Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2, Datum arg3)
Definition: fmgr.c:819
bool check_function_bodies
Definition: guc.c:626
int client_min_messages
Definition: guc.c:637
int NewGUCNestLevel(void)
Definition: guc.c:6467
void AtEOXact_GUC(bool isCommit, int nestLevel)
Definition: guc.c:6481
int log_min_messages
Definition: guc.c:636
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:7558
@ GUC_ACTION_SAVE
Definition: guc.h:196
@ PGC_S_SESSION
Definition: guc.h:119
@ PGC_SUSET
Definition: guc.h:75
@ PGC_USERSET
Definition: guc.h:76
#define SECURITY_LOCAL_USERID_CHANGE
Definition: miscadmin.h:312
char * GetUserNameFromId(Oid roleid, bool noerr)
Definition: miscinit.c:913
void GetUserIdAndSecContext(Oid *userid, int *sec_context)
Definition: miscinit.c:603
void SetUserIdAndSecContext(Oid userid, int sec_context)
Definition: miscinit.c:610
Datum textregexreplace(PG_FUNCTION_ARGS)
Definition: regexp.c:644
const char * quote_identifier(const char *ident)
Definition: ruleutils.c:12163
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:176
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
char * module_pathname
Definition: extension.c:82
bool superuser(void)
Definition: superuser.c:46
Datum replace_text(PG_FUNCTION_ARGS)
Definition: varlena.c:4254

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

Referenced by ApplyExtensionUpdates(), and CreateExtensionInternal().

◆ execute_sql_string()

static void execute_sql_string ( const char *  sql)
static

Definition at line 720 of file extension.c.

721 {
722  List *raw_parsetree_list;
724  ListCell *lc1;
725 
726  /*
727  * Parse the SQL string into a list of raw parse trees.
728  */
729  raw_parsetree_list = pg_parse_query(sql);
730 
731  /* All output from SELECTs goes to the bit bucket */
733 
734  /*
735  * Do parse analysis, rule rewrite, planning, and execution for each raw
736  * parsetree. We must fully execute each query before beginning parse
737  * analysis on the next one, since there may be interdependencies.
738  */
739  foreach(lc1, raw_parsetree_list)
740  {
741  RawStmt *parsetree = lfirst_node(RawStmt, lc1);
742  MemoryContext per_parsetree_context,
743  oldcontext;
744  List *stmt_list;
745  ListCell *lc2;
746 
747  /*
748  * We do the work for each parsetree in a short-lived context, to
749  * limit the memory used when there are many commands in the string.
750  */
751  per_parsetree_context =
753  "execute_sql_string per-statement context",
755  oldcontext = MemoryContextSwitchTo(per_parsetree_context);
756 
757  /* Be sure parser can see any DDL done so far */
759 
760  stmt_list = pg_analyze_and_rewrite_fixedparams(parsetree,
761  sql,
762  NULL,
763  0,
764  NULL);
765  stmt_list = pg_plan_queries(stmt_list, sql, CURSOR_OPT_PARALLEL_OK, NULL);
766 
767  foreach(lc2, stmt_list)
768  {
769  PlannedStmt *stmt = lfirst_node(PlannedStmt, lc2);
770 
772 
774 
775  if (stmt->utilityStmt == NULL)
776  {
777  QueryDesc *qdesc;
778 
779  qdesc = CreateQueryDesc(stmt,
780  sql,
781  GetActiveSnapshot(), NULL,
782  dest, NULL, NULL, 0);
783 
784  ExecutorStart(qdesc, 0);
785  ExecutorRun(qdesc, ForwardScanDirection, 0, true);
786  ExecutorFinish(qdesc);
787  ExecutorEnd(qdesc);
788 
789  FreeQueryDesc(qdesc);
790  }
791  else
792  {
793  if (IsA(stmt->utilityStmt, TransactionStmt))
794  ereport(ERROR,
795  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
796  errmsg("transaction control statements are not allowed within an extension script")));
797 
798  ProcessUtility(stmt,
799  sql,
800  false,
802  NULL,
803  NULL,
804  dest,
805  NULL);
806  }
807 
809  }
810 
811  /* Clean up per-parsetree context. */
812  MemoryContextSwitchTo(oldcontext);
813  MemoryContextDelete(per_parsetree_context);
814  }
815 
816  /* Be sure to advance the command counter after the last script command */
818 }
DestReceiver * CreateDestReceiver(CommandDest dest)
Definition: dest.c:113
@ DestNone
Definition: dest.h:89
void ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:461
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:401
void ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:131
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: execMain.c:300
MemoryContext CurrentMemoryContext
Definition: mcxt.c:42
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:218
#define AllocSetContextCreate
Definition: memutils.h:173
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:197
#define IsA(nodeptr, _type_)
Definition: nodes.h:624
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:3177
#define lfirst_node(type, lc)
Definition: pg_list.h:172
List * pg_parse_query(const char *query_string)
Definition: postgres.c:592
List * pg_analyze_and_rewrite_fixedparams(RawStmt *parsetree, const char *query_string, const Oid *paramTypes, int numParams, QueryEnvironment *queryEnv)
Definition: postgres.c:640
List * pg_plan_queries(List *querytrees, const char *query_string, int cursorOptions, ParamListInfo boundParams)
Definition: postgres.c:951
void FreeQueryDesc(QueryDesc *qdesc)
Definition: pquery.c:105
QueryDesc * CreateQueryDesc(PlannedStmt *plannedstmt, const char *sourceText, Snapshot snapshot, Snapshot crosscheck_snapshot, DestReceiver *dest, ParamListInfo params, QueryEnvironment *queryEnv, int instrument_options)
Definition: pquery.c:67
@ ForwardScanDirection
Definition: sdir.h:26
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:250
void PopActiveSnapshot(void)
Definition: snapmgr.c:776
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:682
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:803
Node * utilityStmt
Definition: plannodes.h:87
void ProcessUtility(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc)
Definition: utility.c:506
@ PROCESS_UTILITY_QUERY
Definition: utility.h:23
void CommandCounterIncrement(void)
Definition: xact.c:1074

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

Referenced by execute_extension_script().

◆ extension_config_remove()

static void extension_config_remove ( Oid  extensionoid,
Oid  tableoid 
)
static

Definition at line 2537 of file extension.c.

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

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

Referenced by ExecAlterExtensionContentsStmt().

◆ extension_file_exists()

bool extension_file_exists ( const char *  extensionName)

Definition at line 2184 of file extension.c.

2185 {
2186  bool result = false;
2187  char *location;
2188  DIR *dir;
2189  struct dirent *de;
2190 
2191  location = get_extension_control_directory();
2192  dir = AllocateDir(location);
2193 
2194  /*
2195  * If the control directory doesn't exist, we want to silently return
2196  * false. Any other error will be reported by ReadDir.
2197  */
2198  if (dir == NULL && errno == ENOENT)
2199  {
2200  /* do nothing */
2201  }
2202  else
2203  {
2204  while ((de = ReadDir(dir, location)) != NULL)
2205  {
2206  char *extname;
2207 
2209  continue;
2210 
2211  /* extract extension name from 'name.control' filename */
2212  extname = pstrdup(de->d_name);
2213  *strrchr(extname, '.') = '\0';
2214 
2215  /* ignore it if it's an auxiliary control file */
2216  if (strstr(extname, "--"))
2217  continue;
2218 
2219  /* done if it matches request */
2220  if (strcmp(extname, extensionName) == 0)
2221  {
2222  result = true;
2223  break;
2224  }
2225  }
2226 
2227  FreeDir(dir);
2228  }
2229 
2230  return result;
2231 }
static bool is_extension_control_filename(const char *filename)
Definition: extension.c:355
static char * get_extension_control_directory(void)
Definition: extension.c:371
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2788
int FreeDir(DIR *dir)
Definition: fd.c:2840
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2722
char * pstrdup(const char *in)
Definition: mcxt.c:1305
Definition: dirent.c:26
Definition: dirent.h:10
char d_name[MAX_PATH]
Definition: dirent.h:15

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

Referenced by CreateFunction(), and ExecuteDoStmt().

◆ extension_is_trusted()

static bool extension_is_trusted ( ExtensionControlFile control)
static

Definition at line 827 of file extension.c.

828 {
829  AclResult aclresult;
830 
831  /* Never trust unless extension's control file says it's okay */
832  if (!control->trusted)
833  return false;
834  /* Allow if user has CREATE privilege on current database */
836  if (aclresult == ACLCHECK_OK)
837  return true;
838  return false;
839 }
AclResult pg_database_aclcheck(Oid db_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:5033
Oid MyDatabaseId
Definition: globals.c:89

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

Referenced by execute_extension_script().

◆ find_install_path()

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

Definition at line 1327 of file extension.c.

1329 {
1330  ExtensionVersionInfo *evi_start = NULL;
1331  ListCell *lc;
1332 
1333  *best_path = NIL;
1334 
1335  /*
1336  * We don't expect to be called for an installable target, but if we are,
1337  * the answer is easy: just start from there, with an empty update path.
1338  */
1339  if (evi_target->installable)
1340  return evi_target;
1341 
1342  /* Consider all installable versions as start points */
1343  foreach(lc, evi_list)
1344  {
1346  List *path;
1347 
1348  if (!evi1->installable)
1349  continue;
1350 
1351  /*
1352  * Find shortest path from evi1 to evi_target; but no need to consider
1353  * paths going through other installable versions.
1354  */
1355  path = find_update_path(evi_list, evi1, evi_target, true, true);
1356  if (path == NIL)
1357  continue;
1358 
1359  /* Remember best path */
1360  if (evi_start == NULL ||
1361  list_length(path) < list_length(*best_path) ||
1362  (list_length(path) == list_length(*best_path) &&
1363  strcmp(evi_start->name, evi1->name) < 0))
1364  {
1365  evi_start = evi1;
1366  *best_path = path;
1367  }
1368  }
1369 
1370  return evi_start;
1371 }
static List * find_update_path(List *evi_list, ExtensionVersionInfo *evi_start, ExtensionVersionInfo *evi_target, bool reject_indirect, bool reinitialize)
Definition: extension.c:1234

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

Referenced by CreateExtensionInternal(), and get_available_versions_for_extension().

◆ find_update_path()

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

Definition at line 1234 of file extension.c.

1239 {
1240  List *result;
1241  ExtensionVersionInfo *evi;
1242  ListCell *lc;
1243 
1244  /* Caller error if start == target */
1245  Assert(evi_start != evi_target);
1246  /* Caller error if reject_indirect and target is installable */
1247  Assert(!(reject_indirect && evi_target->installable));
1248 
1249  if (reinitialize)
1250  {
1251  foreach(lc, evi_list)
1252  {
1253  evi = (ExtensionVersionInfo *) lfirst(lc);
1254  evi->distance_known = false;
1255  evi->distance = INT_MAX;
1256  evi->previous = NULL;
1257  }
1258  }
1259 
1260  evi_start->distance = 0;
1261 
1262  while ((evi = get_nearest_unprocessed_vertex(evi_list)) != NULL)
1263  {
1264  if (evi->distance == INT_MAX)
1265  break; /* all remaining vertices are unreachable */
1266  evi->distance_known = true;
1267  if (evi == evi_target)
1268  break; /* found shortest path to target */
1269  foreach(lc, evi->reachable)
1270  {
1272  int newdist;
1273 
1274  /* if reject_indirect, treat installable versions as unreachable */
1275  if (reject_indirect && evi2->installable)
1276  continue;
1277  newdist = evi->distance + 1;
1278  if (newdist < evi2->distance)
1279  {
1280  evi2->distance = newdist;
1281  evi2->previous = evi;
1282  }
1283  else if (newdist == evi2->distance &&
1284  evi2->previous != NULL &&
1285  strcmp(evi->name, evi2->previous->name) < 0)
1286  {
1287  /*
1288  * Break ties in favor of the version name that comes first
1289  * according to strcmp(). This behavior is undocumented and
1290  * users shouldn't rely on it. We do it just to ensure that
1291  * if there is a tie, the update path that is chosen does not
1292  * depend on random factors like the order in which directory
1293  * entries get visited.
1294  */
1295  evi2->previous = evi;
1296  }
1297  }
1298  }
1299 
1300  /* Return NIL if target is not reachable from start */
1301  if (!evi_target->distance_known)
1302  return NIL;
1303 
1304  /* Build and return list of version names representing the update path */
1305  result = NIL;
1306  for (evi = evi_target; evi != evi_start; evi = evi->previous)
1307  result = lcons(evi->name, result);
1308 
1309  return result;
1310 }
static ExtensionVersionInfo * get_nearest_unprocessed_vertex(List *evi_list)
Definition: extension.c:1100
List * lcons(void *datum, List *list)
Definition: list.c:474
struct ExtensionVersionInfo * previous
Definition: extension.c:104

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

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

◆ get_available_versions_for_extension()

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

Definition at line 2070 of file extension.c.

2073 {
2074  List *evi_list;
2075  ListCell *lc;
2076 
2077  /* Extract the version update graph from the script directory */
2078  evi_list = get_ext_ver_list(pcontrol);
2079 
2080  /* For each installable version ... */
2081  foreach(lc, evi_list)
2082  {
2084  ExtensionControlFile *control;
2085  Datum values[8];
2086  bool nulls[8];
2087  ListCell *lc2;
2088 
2089  if (!evi->installable)
2090  continue;
2091 
2092  /*
2093  * Fetch parameters for specific version (pcontrol is not changed)
2094  */
2095  control = read_extension_aux_control_file(pcontrol, evi->name);
2096 
2097  memset(values, 0, sizeof(values));
2098  memset(nulls, 0, sizeof(nulls));
2099 
2100  /* name */
2102  CStringGetDatum(control->name));
2103  /* version */
2104  values[1] = CStringGetTextDatum(evi->name);
2105  /* superuser */
2106  values[2] = BoolGetDatum(control->superuser);
2107  /* trusted */
2108  values[3] = BoolGetDatum(control->trusted);
2109  /* relocatable */
2110  values[4] = BoolGetDatum(control->relocatable);
2111  /* schema */
2112  if (control->schema == NULL)
2113  nulls[5] = true;
2114  else
2116  CStringGetDatum(control->schema));
2117  /* requires */
2118  if (control->requires == NIL)
2119  nulls[6] = true;
2120  else
2121  values[6] = convert_requires_to_datum(control->requires);
2122  /* comment */
2123  if (control->comment == NULL)
2124  nulls[7] = true;
2125  else
2126  values[7] = CStringGetTextDatum(control->comment);
2127 
2128  tuplestore_putvalues(tupstore, tupdesc, values, nulls);
2129 
2130  /*
2131  * Find all non-directly-installable versions that would be installed
2132  * starting from this version, and report them, inheriting the
2133  * parameters that aren't changed in updates from this version.
2134  */
2135  foreach(lc2, evi_list)
2136  {
2138  List *best_path;
2139 
2140  if (evi2->installable)
2141  continue;
2142  if (find_install_path(evi_list, evi2, &best_path) == evi)
2143  {
2144  /*
2145  * Fetch parameters for this version (pcontrol is not changed)
2146  */
2147  control = read_extension_aux_control_file(pcontrol, evi2->name);
2148 
2149  /* name stays the same */
2150  /* version */
2151  values[1] = CStringGetTextDatum(evi2->name);
2152  /* superuser */
2153  values[2] = BoolGetDatum(control->superuser);
2154  /* trusted */
2155  values[3] = BoolGetDatum(control->trusted);
2156  /* relocatable */
2157  values[4] = BoolGetDatum(control->relocatable);
2158  /* schema stays the same */
2159  /* requires */
2160  if (control->requires == NIL)
2161  nulls[6] = true;
2162  else
2163  {
2164  values[6] = convert_requires_to_datum(control->requires);
2165  nulls[6] = false;
2166  }
2167  /* comment stays the same */
2168 
2169  tuplestore_putvalues(tupstore, tupdesc, values, nulls);
2170  }
2171  }
2172  }
2173 }
static Datum convert_requires_to_datum(List *requires)
Definition: extension.c:2237
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, Datum *values, bool *isnull)
Definition: tuplestore.c:750

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

Referenced by pg_available_extension_versions().

◆ get_ext_ver_info()

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

Definition at line 1067 of file extension.c.

1068 {
1069  ExtensionVersionInfo *evi;
1070  ListCell *lc;
1071 
1072  foreach(lc, *evi_list)
1073  {
1074  evi = (ExtensionVersionInfo *) lfirst(lc);
1075  if (strcmp(evi->name, versionname) == 0)
1076  return evi;
1077  }
1078 
1080  evi->name = pstrdup(versionname);
1081  evi->reachable = NIL;
1082  evi->installable = false;
1083  /* initialize for later application of Dijkstra's algorithm */
1084  evi->distance_known = false;
1085  evi->distance = INT_MAX;
1086  evi->previous = NULL;
1087 
1088  *evi_list = lappend(*evi_list, evi);
1089 
1090  return evi;
1091 }
List * lappend(List *list, void *datum)
Definition: list.c:336

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

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

◆ get_ext_ver_list()

static List* get_ext_ver_list ( ExtensionControlFile control)
static

Definition at line 1128 of file extension.c.

1129 {
1130  List *evi_list = NIL;
1131  int extnamelen = strlen(control->name);
1132  char *location;
1133  DIR *dir;
1134  struct dirent *de;
1135 
1136  location = get_extension_script_directory(control);
1137  dir = AllocateDir(location);
1138  while ((de = ReadDir(dir, location)) != NULL)
1139  {
1140  char *vername;
1141  char *vername2;
1142  ExtensionVersionInfo *evi;
1143  ExtensionVersionInfo *evi2;
1144 
1145  /* must be a .sql file ... */
1147  continue;
1148 
1149  /* ... matching extension name followed by separator */
1150  if (strncmp(de->d_name, control->name, extnamelen) != 0 ||
1151  de->d_name[extnamelen] != '-' ||
1152  de->d_name[extnamelen + 1] != '-')
1153  continue;
1154 
1155  /* extract version name(s) from 'extname--something.sql' filename */
1156  vername = pstrdup(de->d_name + extnamelen + 2);
1157  *strrchr(vername, '.') = '\0';
1158  vername2 = strstr(vername, "--");
1159  if (!vername2)
1160  {
1161  /* It's an install, not update, script; record its version name */
1162  evi = get_ext_ver_info(vername, &evi_list);
1163  evi->installable = true;
1164  continue;
1165  }
1166  *vername2 = '\0'; /* terminate first version */
1167  vername2 += 2; /* and point to second */
1168 
1169  /* if there's a third --, it's bogus, ignore it */
1170  if (strstr(vername2, "--"))
1171  continue;
1172 
1173  /* Create ExtensionVersionInfos and link them together */
1174  evi = get_ext_ver_info(vername, &evi_list);
1175  evi2 = get_ext_ver_info(vername2, &evi_list);
1176  evi->reachable = lappend(evi->reachable, evi2);
1177  }
1178  FreeDir(dir);
1179 
1180  return evi_list;
1181 }
static bool is_extension_script_filename(const char *filename)
Definition: extension.c:363
static char * get_extension_script_directory(ExtensionControlFile *control)
Definition: extension.c:398

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

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

◆ get_extension_aux_control_filename()

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

Definition at line 421 of file extension.c.

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

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

Referenced by parse_extension_control_file().

◆ get_extension_control_directory()

static char* get_extension_control_directory ( void  )
static

Definition at line 371 of file extension.c.

372 {
373  char sharepath[MAXPGPATH];
374  char *result;
375 
376  get_share_path(my_exec_path, sharepath);
377  result = (char *) palloc(MAXPGPATH);
378  snprintf(result, MAXPGPATH, "%s/extension", sharepath);
379 
380  return result;
381 }
char my_exec_path[MAXPGPATH]
Definition: globals.c:76
void get_share_path(const char *my_exec_path, char *ret_path)
Definition: path.c:825

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

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

◆ get_extension_control_filename()

static char* get_extension_control_filename ( const char *  extname)
static

Definition at line 384 of file extension.c.

385 {
386  char sharepath[MAXPGPATH];
387  char *result;
388 
389  get_share_path(my_exec_path, sharepath);
390  result = (char *) palloc(MAXPGPATH);
391  snprintf(result, MAXPGPATH, "%s/extension/%s.control",
392  sharepath, extname);
393 
394  return result;
395 }

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

Referenced by parse_extension_control_file().

◆ get_extension_name()

char* get_extension_name ( Oid  ext_oid)

Definition at line 185 of file extension.c.

186 {
187  char *result;
188  Relation rel;
189  SysScanDesc scandesc;
190  HeapTuple tuple;
191  ScanKeyData entry[1];
192 
193  rel = table_open(ExtensionRelationId, AccessShareLock);
194 
195  ScanKeyInit(&entry[0],
196  Anum_pg_extension_oid,
197  BTEqualStrategyNumber, F_OIDEQ,
198  ObjectIdGetDatum(ext_oid));
199 
200  scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
201  NULL, 1, entry);
202 
203  tuple = systable_getnext(scandesc);
204 
205  /* We assume that there can be at most one matching tuple */
206  if (HeapTupleIsValid(tuple))
207  result = pstrdup(NameStr(((Form_pg_extension) GETSTRUCT(tuple))->extname));
208  else
209  result = NULL;
210 
211  systable_endscan(scandesc);
212 
214 
215  return result;
216 }

References AccessShareLock, BTEqualStrategyNumber, 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().

◆ get_extension_oid()

Oid get_extension_oid ( const char *  extname,
bool  missing_ok 
)

Definition at line 140 of file extension.c.

141 {
142  Oid result;
143  Relation rel;
144  SysScanDesc scandesc;
145  HeapTuple tuple;
146  ScanKeyData entry[1];
147 
148  rel = table_open(ExtensionRelationId, AccessShareLock);
149 
150  ScanKeyInit(&entry[0],
151  Anum_pg_extension_extname,
152  BTEqualStrategyNumber, F_NAMEEQ,
153  CStringGetDatum(extname));
154 
155  scandesc = systable_beginscan(rel, ExtensionNameIndexId, true,
156  NULL, 1, entry);
157 
158  tuple = systable_getnext(scandesc);
159 
160  /* We assume that there can be at most one matching tuple */
161  if (HeapTupleIsValid(tuple))
162  result = ((Form_pg_extension) GETSTRUCT(tuple))->oid;
163  else
164  result = InvalidOid;
165 
166  systable_endscan(scandesc);
167 
169 
170  if (!OidIsValid(result) && !missing_ok)
171  ereport(ERROR,
172  (errcode(ERRCODE_UNDEFINED_OBJECT),
173  errmsg("extension \"%s\" does not exist",
174  extname)));
175 
176  return result;
177 }

References AccessShareLock, BTEqualStrategyNumber, CStringGetDatum, ereport, errcode(), errmsg(), ERROR, 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(), ExtractExtensionList(), get_object_address_unqualified(), and get_required_extension().

◆ get_extension_schema()

static Oid get_extension_schema ( Oid  ext_oid)
static

Definition at line 224 of file extension.c.

225 {
226  Oid result;
227  Relation rel;
228  SysScanDesc scandesc;
229  HeapTuple tuple;
230  ScanKeyData entry[1];
231 
232  rel = table_open(ExtensionRelationId, AccessShareLock);
233 
234  ScanKeyInit(&entry[0],
235  Anum_pg_extension_oid,
236  BTEqualStrategyNumber, F_OIDEQ,
237  ObjectIdGetDatum(ext_oid));
238 
239  scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
240  NULL, 1, entry);
241 
242  tuple = systable_getnext(scandesc);
243 
244  /* We assume that there can be at most one matching tuple */
245  if (HeapTupleIsValid(tuple))
246  result = ((Form_pg_extension) GETSTRUCT(tuple))->extnamespace;
247  else
248  result = InvalidOid;
249 
250  systable_endscan(scandesc);
251 
253 
254  return result;
255 }

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

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

◆ get_extension_script_directory()

static char* get_extension_script_directory ( ExtensionControlFile control)
static

Definition at line 398 of file extension.c.

399 {
400  char sharepath[MAXPGPATH];
401  char *result;
402 
403  /*
404  * The directory parameter can be omitted, absolute, or relative to the
405  * installation's share directory.
406  */
407  if (!control->directory)
409 
410  if (is_absolute_path(control->directory))
411  return pstrdup(control->directory);
412 
413  get_share_path(my_exec_path, sharepath);
414  result = (char *) palloc(MAXPGPATH);
415  snprintf(result, MAXPGPATH, "%s/%s", sharepath, control->directory);
416 
417  return result;
418 }
#define is_absolute_path(filename)
Definition: port.h:89

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

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

◆ get_extension_script_filename()

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

Definition at line 439 of file extension.c.

441 {
442  char *result;
443  char *scriptdir;
444 
445  scriptdir = get_extension_script_directory(control);
446 
447  result = (char *) palloc(MAXPGPATH);
448  if (from_version)
449  snprintf(result, MAXPGPATH, "%s/%s--%s--%s.sql",
450  scriptdir, control->name, from_version, version);
451  else
452  snprintf(result, MAXPGPATH, "%s/%s--%s.sql",
453  scriptdir, control->name, version);
454 
455  pfree(scriptdir);
456 
457  return result;
458 }

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

Referenced by CreateExtensionInternal(), and execute_extension_script().

◆ get_nearest_unprocessed_vertex()

static ExtensionVersionInfo* get_nearest_unprocessed_vertex ( List evi_list)
static

Definition at line 1100 of file extension.c.

1101 {
1102  ExtensionVersionInfo *evi = NULL;
1103  ListCell *lc;
1104 
1105  foreach(lc, evi_list)
1106  {
1108 
1109  /* only vertices whose distance is still uncertain are candidates */
1110  if (evi2->distance_known)
1111  continue;
1112  /* remember the closest such vertex */
1113  if (evi == NULL ||
1114  evi->distance > evi2->distance)
1115  evi = evi2;
1116  }
1117 
1118  return evi;
1119 }

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

Referenced by find_update_path().

◆ get_required_extension()

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

Definition at line 1621 of file extension.c.

1627 {
1628  Oid reqExtensionOid;
1629 
1630  reqExtensionOid = get_extension_oid(reqExtensionName, true);
1631  if (!OidIsValid(reqExtensionOid))
1632  {
1633  if (cascade)
1634  {
1635  /* Must install it. */
1636  ObjectAddress addr;
1637  List *cascade_parents;
1638  ListCell *lc;
1639 
1640  /* Check extension name validity before trying to cascade. */
1641  check_valid_extension_name(reqExtensionName);
1642 
1643  /* Check for cyclic dependency between extensions. */
1644  foreach(lc, parents)
1645  {
1646  char *pname = (char *) lfirst(lc);
1647 
1648  if (strcmp(pname, reqExtensionName) == 0)
1649  ereport(ERROR,
1650  (errcode(ERRCODE_INVALID_RECURSION),
1651  errmsg("cyclic dependency detected between extensions \"%s\" and \"%s\"",
1652  reqExtensionName, extensionName)));
1653  }
1654 
1655  ereport(NOTICE,
1656  (errmsg("installing required extension \"%s\"",
1657  reqExtensionName)));
1658 
1659  /* Add current extension to list of parents to pass down. */
1660  cascade_parents = lappend(list_copy(parents), extensionName);
1661 
1662  /*
1663  * Create the required extension. We propagate the SCHEMA option
1664  * if any, and CASCADE, but no other options.
1665  */
1666  addr = CreateExtensionInternal(reqExtensionName,
1667  origSchemaName,
1668  NULL,
1669  cascade,
1670  cascade_parents,
1671  is_create);
1672 
1673  /* Get its newly-assigned OID. */
1674  reqExtensionOid = addr.objectId;
1675  }
1676  else
1677  ereport(ERROR,
1678  (errcode(ERRCODE_UNDEFINED_OBJECT),
1679  errmsg("required extension \"%s\" is not installed",
1680  reqExtensionName),
1681  is_create ?
1682  errhint("Use CREATE EXTENSION ... CASCADE to install required extensions too.") : 0));
1683  }
1684 
1685  return reqExtensionOid;
1686 }
List * list_copy(const List *oldlist)
Definition: list.c:1532

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

Referenced by ApplyExtensionUpdates(), and CreateExtensionInternal().

◆ identify_update_path()

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

Definition at line 1191 of file extension.c.

1193 {
1194  List *result;
1195  List *evi_list;
1196  ExtensionVersionInfo *evi_start;
1197  ExtensionVersionInfo *evi_target;
1198 
1199  /* Extract the version update graph from the script directory */
1200  evi_list = get_ext_ver_list(control);
1201 
1202  /* Initialize start and end vertices */
1203  evi_start = get_ext_ver_info(oldVersion, &evi_list);
1204  evi_target = get_ext_ver_info(newVersion, &evi_list);
1205 
1206  /* Find shortest path */
1207  result = find_update_path(evi_list, evi_start, evi_target, false, false);
1208 
1209  if (result == NIL)
1210  ereport(ERROR,
1211  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1212  errmsg("extension \"%s\" has no update path from version \"%s\" to version \"%s\"",
1213  control->name, oldVersion, newVersion)));
1214 
1215  return result;
1216 }

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

Referenced by ExecAlterExtensionStmt().

◆ InsertExtensionTuple()

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

Definition at line 1790 of file extension.c.

1794 {
1795  Oid extensionOid;
1796  Relation rel;
1797  Datum values[Natts_pg_extension];
1798  bool nulls[Natts_pg_extension];
1799  HeapTuple tuple;
1800  ObjectAddress myself;
1801  ObjectAddress nsp;
1802  ObjectAddresses *refobjs;
1803  ListCell *lc;
1804 
1805  /*
1806  * Build and insert the pg_extension tuple
1807  */
1808  rel = table_open(ExtensionRelationId, RowExclusiveLock);
1809 
1810  memset(values, 0, sizeof(values));
1811  memset(nulls, 0, sizeof(nulls));
1812 
1813  extensionOid = GetNewOidWithIndex(rel, ExtensionOidIndexId,
1814  Anum_pg_extension_oid);
1815  values[Anum_pg_extension_oid - 1] = ObjectIdGetDatum(extensionOid);
1816  values[Anum_pg_extension_extname - 1] =
1818  values[Anum_pg_extension_extowner - 1] = ObjectIdGetDatum(extOwner);
1819  values[Anum_pg_extension_extnamespace - 1] = ObjectIdGetDatum(schemaOid);
1820  values[Anum_pg_extension_extrelocatable - 1] = BoolGetDatum(relocatable);
1821  values[Anum_pg_extension_extversion - 1] = CStringGetTextDatum(extVersion);
1822 
1823  if (extConfig == PointerGetDatum(NULL))
1824  nulls[Anum_pg_extension_extconfig - 1] = true;
1825  else
1826  values[Anum_pg_extension_extconfig - 1] = extConfig;
1827 
1828  if (extCondition == PointerGetDatum(NULL))
1829  nulls[Anum_pg_extension_extcondition - 1] = true;
1830  else
1831  values[Anum_pg_extension_extcondition - 1] = extCondition;
1832 
1833  tuple = heap_form_tuple(rel->rd_att, values, nulls);
1834 
1835  CatalogTupleInsert(rel, tuple);
1836 
1837  heap_freetuple(tuple);
1839 
1840  /*
1841  * Record dependencies on owner, schema, and prerequisite extensions
1842  */
1843  recordDependencyOnOwner(ExtensionRelationId, extensionOid, extOwner);
1844 
1845  refobjs = new_object_addresses();
1846 
1847  ObjectAddressSet(myself, ExtensionRelationId, extensionOid);
1848 
1849  ObjectAddressSet(nsp, NamespaceRelationId, schemaOid);
1850  add_exact_object_address(&nsp, refobjs);
1851 
1852  foreach(lc, requiredExtensions)
1853  {
1854  Oid reqext = lfirst_oid(lc);
1855  ObjectAddress otherext;
1856 
1857  ObjectAddressSet(otherext, ExtensionRelationId, reqext);
1858  add_exact_object_address(&otherext, refobjs);
1859  }
1860 
1861  /* Record all of them (this includes duplicate elimination) */
1863  free_object_addresses(refobjs);
1864 
1865  /* Post creation hook for new extension */
1866  InvokeObjectPostCreateHook(ExtensionRelationId, extensionOid, 0);
1867 
1868  return myself;
1869 }
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:391
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
Definition: dependency.c:2711
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
Definition: dependency.c:2502
void free_object_addresses(ObjectAddresses *addrs)
Definition: dependency.c:2742
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:221
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:171
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:164
TupleDesc rd_att
Definition: rel.h:110

References add_exact_object_address(), BoolGetDatum, CatalogTupleInsert(), CStringGetDatum, CStringGetTextDatum, DEPENDENCY_NORMAL, DirectFunctionCall1, free_object_addresses(), GetNewOidWithIndex(), heap_form_tuple(), heap_freetuple(), InvokeObjectPostCreateHook, lfirst_oid, namein(), new_object_addresses(), ObjectAddressSet, ObjectIdGetDatum, PointerGetDatum, RelationData::rd_att, record_object_address_dependencies(), recordDependencyOnOwner(), RowExclusiveLock, table_close(), table_open(), and values.

Referenced by binary_upgrade_create_empty_extension(), and CreateExtensionInternal().

◆ is_extension_control_filename()

static bool is_extension_control_filename ( const char *  filename)
static

Definition at line 355 of file extension.c.

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

References filename.

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

◆ is_extension_script_filename()

static bool is_extension_script_filename ( const char *  filename)
static

Definition at line 363 of file extension.c.

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

References filename.

Referenced by get_ext_ver_list().

◆ parse_extension_control_file()

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

Definition at line 471 of file extension.c.

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

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

Referenced by read_extension_aux_control_file(), and read_extension_control_file().

◆ pg_available_extension_versions()

Datum pg_available_extension_versions ( PG_FUNCTION_ARGS  )

Definition at line 2012 of file extension.c.

2013 {
2014  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
2015  char *location;
2016  DIR *dir;
2017  struct dirent *de;
2018 
2019  /* Build tuplestore to hold the result rows */
2020  SetSingleFuncCall(fcinfo, 0);
2021 
2022  location = get_extension_control_directory();
2023  dir = AllocateDir(location);
2024 
2025  /*
2026  * If the control directory doesn't exist, we want to silently return an
2027  * empty set. Any other error will be reported by ReadDir.
2028  */
2029  if (dir == NULL && errno == ENOENT)
2030  {
2031  /* do nothing */
2032  }
2033  else
2034  {
2035  while ((de = ReadDir(dir, location)) != NULL)
2036  {
2037  ExtensionControlFile *control;
2038  char *extname;
2039 
2040  if (!is_extension_control_filename(de->d_name))
2041  continue;
2042 
2043  /* extract extension name from 'name.control' filename */
2044  extname = pstrdup(de->d_name);
2045  *strrchr(extname, '.') = '\0';
2046 
2047  /* ignore it if it's an auxiliary control file */
2048  if (strstr(extname, "--"))
2049  continue;
2050 
2051  /* read the control file */
2052  control = read_extension_control_file(extname);
2053 
2054  /* scan extension's script directory for install scripts */
2056  rsinfo->setDesc);
2057  }
2058 
2059  FreeDir(dir);
2060  }
2061 
2062  return (Datum) 0;
2063 }
static void get_available_versions_for_extension(ExtensionControlFile *pcontrol, Tuplestorestate *tupstore, TupleDesc tupdesc)
Definition: extension.c:2070
void SetSingleFuncCall(FunctionCallInfo fcinfo, bits32 flags)
Definition: funcapi.c:76
TupleDesc setDesc
Definition: execnodes.h:317
Tuplestorestate * setResult
Definition: execnodes.h:316

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

◆ pg_available_extensions()

Datum pg_available_extensions ( PG_FUNCTION_ARGS  )

Definition at line 1932 of file extension.c.

1933 {
1934  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1935  char *location;
1936  DIR *dir;
1937  struct dirent *de;
1938 
1939  /* Build tuplestore to hold the result rows */
1940  SetSingleFuncCall(fcinfo, 0);
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 */
1980  CStringGetDatum(control->name));
1981  /* default_version */
1982  if (control->default_version == NULL)
1983  nulls[1] = true;
1984  else
1986  /* comment */
1987  if (control->comment == NULL)
1988  nulls[2] = true;
1989  else
1990  values[2] = CStringGetTextDatum(control->comment);
1991 
1992  tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
1993  values, nulls);
1994  }
1995 
1996  FreeDir(dir);
1997  }
1998 
1999  return (Datum) 0;
2000 }

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

◆ pg_extension_config_dump()

Datum pg_extension_config_dump ( PG_FUNCTION_ARGS  )

Definition at line 2350 of file extension.c.

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

References a, 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, get_rel_name(), getExtensionOfObject(), heap_getattr(), heap_modify_tuple(), HeapTupleIsValid, i, sort-test::key, ObjectIdGetDatum, PG_GETARG_OID, PG_GETARG_TEXT_PP, PG_RETURN_VOID, PointerGetDatum, RelationGetDescr, RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, table_close(), and table_open().

◆ pg_extension_update_paths()

Datum pg_extension_update_paths ( PG_FUNCTION_ARGS  )

Definition at line 2265 of file extension.c.

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

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

◆ read_extension_aux_control_file()

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

Definition at line 656 of file extension.c.

658 {
659  ExtensionControlFile *acontrol;
660 
661  /*
662  * Flat-copy the struct. Pointer fields share values with original.
663  */
664  acontrol = (ExtensionControlFile *) palloc(sizeof(ExtensionControlFile));
665  memcpy(acontrol, pcontrol, sizeof(ExtensionControlFile));
666 
667  /*
668  * Parse the auxiliary control file, overwriting struct fields
669  */
670  parse_extension_control_file(acontrol, version);
671 
672  return acontrol;
673 }
static void parse_extension_control_file(ExtensionControlFile *control, const char *version)
Definition: extension.c:471

References palloc(), and parse_extension_control_file().

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

◆ read_extension_control_file()

static ExtensionControlFile* read_extension_control_file ( const char *  extname)
static

Definition at line 627 of file extension.c.

628 {
629  ExtensionControlFile *control;
630 
631  /*
632  * Set up default values. Pointer fields are initially null.
633  */
634  control = (ExtensionControlFile *) palloc0(sizeof(ExtensionControlFile));
635  control->name = pstrdup(extname);
636  control->relocatable = false;
637  control->superuser = true;
638  control->trusted = false;
639  control->encoding = -1;
640 
641  /*
642  * Parse the primary control file.
643  */
644  parse_extension_control_file(control, NULL);
645 
646  return control;
647 }
void * palloc0(Size size)
Definition: mcxt.c:1099

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

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

◆ read_extension_script_file()

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

Definition at line 679 of file extension.c.

681 {
682  int src_encoding;
683  char *src_str;
684  char *dest_str;
685  int len;
686 
687  src_str = read_whole_file(filename, &len);
688 
689  /* use database encoding if not given */
690  if (control->encoding < 0)
691  src_encoding = GetDatabaseEncoding();
692  else
693  src_encoding = control->encoding;
694 
695  /* make sure that source string is valid in the expected encoding */
696  (void) pg_verify_mbstr(src_encoding, src_str, len, false);
697 
698  /*
699  * Convert the encoding to the database encoding. read_whole_file
700  * null-terminated the string, so if no conversion happens the string is
701  * valid as is.
702  */
703  dest_str = pg_any_to_server(src_str, len, src_encoding);
704 
705  return dest_str;
706 }
static char * read_whole_file(const char *filename, int *length)
Definition: extension.c:3358
char * pg_any_to_server(const char *s, int len, int encoding)
Definition: mbutils.c:676
int GetDatabaseEncoding(void)
Definition: mbutils.c:1210
bool pg_verify_mbstr(int encoding, const char *mbstr, int len, bool noError)
Definition: mbutils.c:1515
const void size_t len

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

Referenced by execute_extension_script().

◆ read_whole_file()

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

Definition at line 3358 of file extension.c.

3359 {
3360  char *buf;
3361  FILE *file;
3362  size_t bytes_to_read;
3363  struct stat fst;
3364 
3365  if (stat(filename, &fst) < 0)
3366  ereport(ERROR,
3368  errmsg("could not stat file \"%s\": %m", filename)));
3369 
3370  if (fst.st_size > (MaxAllocSize - 1))
3371  ereport(ERROR,
3372  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3373  errmsg("file \"%s\" is too large", filename)));
3374  bytes_to_read = (size_t) fst.st_size;
3375 
3376  if ((file = AllocateFile(filename, PG_BINARY_R)) == NULL)
3377  ereport(ERROR,
3379  errmsg("could not open file \"%s\" for reading: %m",
3380  filename)));
3381 
3382  buf = (char *) palloc(bytes_to_read + 1);
3383 
3384  *length = fread(buf, 1, bytes_to_read, file);
3385 
3386  if (ferror(file))
3387  ereport(ERROR,
3389  errmsg("could not read file \"%s\": %m", filename)));
3390 
3391  FreeFile(file);
3392 
3393  buf[*length] = '\0';
3394  return buf;
3395 }
#define PG_BINARY_R
Definition: c.h:1270
#define MaxAllocSize
Definition: memutils.h:40
static char * buf
Definition: pg_test_fsync.c:67

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

Referenced by read_extension_script_file().

◆ RemoveExtensionById()

void RemoveExtensionById ( Oid  extId)

Definition at line 1878 of file extension.c.

1879 {
1880  Relation rel;
1881  SysScanDesc scandesc;
1882  HeapTuple tuple;
1883  ScanKeyData entry[1];
1884 
1885  /*
1886  * Disallow deletion of any extension that's currently open for insertion;
1887  * else subsequent executions of recordDependencyOnCurrentExtension()
1888  * could create dangling pg_depend records that refer to a no-longer-valid
1889  * pg_extension OID. This is needed not so much because we think people
1890  * might write "DROP EXTENSION foo" in foo's own script files, as because
1891  * errors in dependency management in extension script files could give
1892  * rise to cases where an extension is dropped as a result of recursing
1893  * from some contained object. Because of that, we must test for the case
1894  * here, not at some higher level of the DROP EXTENSION command.
1895  */
1896  if (extId == CurrentExtensionObject)
1897  ereport(ERROR,
1898  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1899  errmsg("cannot drop extension \"%s\" because it is being modified",
1900  get_extension_name(extId))));
1901 
1902  rel = table_open(ExtensionRelationId, RowExclusiveLock);
1903 
1904  ScanKeyInit(&entry[0],
1905  Anum_pg_extension_oid,
1906  BTEqualStrategyNumber, F_OIDEQ,
1907  ObjectIdGetDatum(extId));
1908  scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
1909  NULL, 1, entry);
1910 
1911  tuple = systable_getnext(scandesc);
1912 
1913  /* We assume that there can be at most one matching tuple */
1914  if (HeapTupleIsValid(tuple))
1915  CatalogTupleDelete(rel, &tuple->t_self);
1916 
1917  systable_endscan(scandesc);
1918 
1920 }
void CatalogTupleDelete(Relation heapRel, ItemPointer tid)
Definition: indexing.c:350

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

Referenced by doDeletion().

Variable Documentation

◆ creating_extension

◆ CurrentExtensionObject