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

Go to the source code of this file.

Data Structures

struct  ExtensionControlFile
 
struct  ExtensionVersionInfo
 

Typedefs

typedef struct ExtensionControlFile ExtensionControlFile
 
typedef struct ExtensionVersionInfo ExtensionVersionInfo
 

Functions

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

Variables

bool creating_extension = false
 
Oid CurrentExtensionObject = InvalidOid
 

Typedef Documentation

Function Documentation

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

Definition at line 2680 of file extension.c.

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

Referenced by ExecAlterObjectSchemaStmt().

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

Definition at line 3011 of file extension.c.

References Anum_pg_extension_extrelocatable, Anum_pg_extension_extversion, BoolGetDatum, BTEqualStrategyNumber, CatalogTupleUpdate(), ObjectAddress::classId, CStringGetTextDatum, deleteDependencyRecordsForClass(), DEPENDENCY_NORMAL, elog, ERROR, execute_extension_script(), ExtensionOidIndexId, ExtensionRelationId, get_extension_schema(), get_namespace_name(), get_required_extension(), GETSTRUCT, heap_close, heap_modify_tuple(), heap_open(), HeapTupleIsValid, InvokeObjectPostAlterHook, lappend_oid(), lfirst, lfirst_oid, ExtensionControlFile::name, Natts_pg_extension, NIL, NULL, ObjectAddress::objectId, ObjectIdAttributeNumber, ObjectIdGetDatum, ObjectAddress::objectSubId, read_extension_aux_control_file(), recordDependencyOn(), RelationGetDescr, ExtensionControlFile::relocatable, ExtensionControlFile::requires, RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, and values.

Referenced by CreateExtensionInternal(), and ExecAlterExtensionStmt().

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

Definition at line 255 of file extension.c.

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

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

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

Definition at line 302 of file extension.c.

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

Referenced by CreateExtensionInternal(), and ExecAlterExtensionStmt().

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

Definition at line 2180 of file extension.c.

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

Referenced by get_available_versions_for_extension().

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

Definition at line 1620 of file extension.c.

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

Referenced by ProcessUtilitySlow().

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

Definition at line 1266 of file extension.c.

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

Referenced by CreateExtension(), and get_required_extension().

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

Definition at line 3169 of file extension.c.

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

Referenced by ProcessUtilitySlow().

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

Definition at line 2861 of file extension.c.

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

Referenced by ProcessUtilitySlow().

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

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

Referenced by ApplyExtensionUpdates(), and CreateExtensionInternal().

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

Definition at line 696 of file extension.c.

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

Referenced by execute_extension_script().

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

Definition at line 2509 of file extension.c.

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

Referenced by ExecAlterExtensionContentsStmt().

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

Definition at line 1211 of file extension.c.

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

Referenced by CreateExtensionInternal(), and get_available_versions_for_extension().

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

Definition at line 1118 of file extension.c.

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

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

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

Definition at line 2075 of file extension.c.

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

Referenced by pg_available_extension_versions().

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

Definition at line 951 of file extension.c.

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

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

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

Definition at line 1012 of file extension.c.

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

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

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

Definition at line 415 of file extension.c.

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

Referenced by parse_extension_control_file().

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

Definition at line 365 of file extension.c.

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

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

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

Definition at line 378 of file extension.c.

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

Referenced by parse_extension_control_file().

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

Definition at line 179 of file extension.c.

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

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

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

Definition at line 134 of file extension.c.

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

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

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

Definition at line 218 of file extension.c.

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

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

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

Definition at line 392 of file extension.c.

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

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

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

Definition at line 433 of file extension.c.

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

Referenced by CreateExtensionInternal(), and execute_extension_script().

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

Definition at line 984 of file extension.c.

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

Referenced by find_update_path().

985 {
986  ExtensionVersionInfo *evi = NULL;
987  ListCell *lc;
988 
989  foreach(lc, evi_list)
990  {
992 
993  /* only vertices whose distance is still uncertain are candidates */
994  if (evi2->distance_known)
995  continue;
996  /* remember the closest such vertex */
997  if (evi == NULL ||
998  evi->distance > evi2->distance)
999  evi = evi2;
1000  }
1001 
1002  return evi;
1003 }
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
static Oid get_required_extension ( char *  reqExtensionName,
char *  extensionName,
char *  origSchemaName,
bool  cascade,
List parents,
bool  is_create 
)
static

Definition at line 1548 of file extension.c.

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

Referenced by ApplyExtensionUpdates(), and CreateExtensionInternal().

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

Definition at line 1075 of file extension.c.

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

Referenced by CreateExtensionInternal(), and ExecAlterExtensionStmt().

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

Definition at line 1740 of file extension.c.

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

Referenced by binary_upgrade_create_empty_extension(), and CreateExtensionInternal().

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

Definition at line 349 of file extension.c.

References NULL.

Referenced by pg_available_extension_versions(), and pg_available_extensions().

350 {
351  const char *extension = strrchr(filename, '.');
352 
353  return (extension != NULL) && (strcmp(extension, ".control") == 0);
354 }
#define NULL
Definition: c.h:229
static char * filename
Definition: pg_dumpall.c:89
static bool is_extension_script_filename ( const char *  filename)
static

Definition at line 357 of file extension.c.

References NULL.

Referenced by get_ext_ver_list().

358 {
359  const char *extension = strrchr(filename, '.');
360 
361  return (extension != NULL) && (strcmp(extension, ".sql") == 0);
362 }
#define NULL
Definition: c.h:229
static char * filename
Definition: pg_dumpall.c:89
static void parse_extension_control_file ( ExtensionControlFile control,
const char *  version 
)
static

Definition at line 465 of file extension.c.

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

Referenced by read_extension_aux_control_file(), and read_extension_control_file().

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

Definition at line 1988 of file extension.c.

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

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

Definition at line 1879 of file extension.c.

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

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

Definition at line 2322 of file extension.c.

References Anum_pg_extension_extcondition, Anum_pg_extension_extconfig, ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_HASNULL, ARR_LBOUND, ARR_NDIM, array_set(), BTEqualStrategyNumber, CatalogTupleUpdate(), construct_array(), creating_extension, CurrentExtensionObject, DatumGetArrayTypeP, elog, ereport, errcode(), ERRCODE_UNDEFINED_TABLE, errmsg(), ERROR, ExtensionOidIndexId, ExtensionRelationId, get_rel_name(), getExtensionOfObject(), heap_close, heap_getattr, heap_modify_tuple(), heap_open(), HeapTupleIsValid, i, Natts_pg_extension, NULL, ObjectIdAttributeNumber, ObjectIdGetDatum, OIDOID, PG_GETARG_OID, PG_GETARG_TEXT_PP, PG_RETURN_VOID, PointerGetDatum, RelationGetDescr, RelationRelationId, RowExclusiveLock, ScanKeyInit(), systable_beginscan(), systable_endscan(), systable_getnext(), HeapTupleData::t_self, and TEXTOID.

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

Definition at line 2208 of file extension.c.

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

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

Definition at line 630 of file extension.c.

References palloc(), and parse_extension_control_file().

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

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

Definition at line 602 of file extension.c.

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

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

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

Definition at line 653 of file extension.c.

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

Referenced by execute_extension_script().

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

Definition at line 3307 of file extension.c.

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

Referenced by read_extension_script_file().

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

Definition at line 1825 of file extension.c.

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

Referenced by doDeletion().

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

Variable Documentation