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

2676 {
2677  Oid extensionOid;
2678  Oid nspOid;
2679  Oid oldNspOid = InvalidOid;
2680  AclResult aclresult;
2681  Relation extRel;
2682  ScanKeyData key[2];
2683  SysScanDesc extScan;
2684  HeapTuple extTup;
2685  Form_pg_extension extForm;
2686  Relation depRel;
2687  SysScanDesc depScan;
2688  HeapTuple depTup;
2689  ObjectAddresses *objsMoved;
2690  ObjectAddress extAddr;
2691 
2692  extensionOid = get_extension_oid(extensionName, false);
2693 
2694  nspOid = LookupCreationNamespace(newschema);
2695 
2696  /*
2697  * Permission check: must own extension. Note that we don't bother to
2698  * check ownership of the individual member objects ...
2699  */
2700  if (!pg_extension_ownercheck(extensionOid, GetUserId()))
2702  extensionName);
2703 
2704  /* Permission check: must have creation rights in target namespace */
2705  aclresult = pg_namespace_aclcheck(nspOid, GetUserId(), ACL_CREATE);
2706  if (aclresult != ACLCHECK_OK)
2707  aclcheck_error(aclresult, ACL_KIND_NAMESPACE, newschema);
2708 
2709  /*
2710  * If the schema is currently a member of the extension, disallow moving
2711  * the extension into the schema. That would create a dependency loop.
2712  */
2713  if (getExtensionOfObject(NamespaceRelationId, nspOid) == extensionOid)
2714  ereport(ERROR,
2715  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2716  errmsg("cannot move extension \"%s\" into schema \"%s\" "
2717  "because the extension contains the schema",
2718  extensionName, newschema)));
2719 
2720  /* Locate the pg_extension tuple */
2722 
2723  ScanKeyInit(&key[0],
2725  BTEqualStrategyNumber, F_OIDEQ,
2726  ObjectIdGetDatum(extensionOid));
2727 
2728  extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
2729  NULL, 1, key);
2730 
2731  extTup = systable_getnext(extScan);
2732 
2733  if (!HeapTupleIsValid(extTup)) /* should not happen */
2734  elog(ERROR, "extension with oid %u does not exist", extensionOid);
2735 
2736  /* Copy tuple so we can modify it below */
2737  extTup = heap_copytuple(extTup);
2738  extForm = (Form_pg_extension) GETSTRUCT(extTup);
2739 
2740  systable_endscan(extScan);
2741 
2742  /*
2743  * If the extension is already in the target schema, just silently do
2744  * nothing.
2745  */
2746  if (extForm->extnamespace == nspOid)
2747  {
2748  heap_close(extRel, RowExclusiveLock);
2749  return InvalidObjectAddress;
2750  }
2751 
2752  /* Check extension is supposed to be relocatable */
2753  if (!extForm->extrelocatable)
2754  ereport(ERROR,
2755  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2756  errmsg("extension \"%s\" does not support SET SCHEMA",
2757  NameStr(extForm->extname))));
2758 
2759  objsMoved = new_object_addresses();
2760 
2761  /*
2762  * Scan pg_depend to find objects that depend directly on the extension,
2763  * and alter each one's schema.
2764  */
2766 
2767  ScanKeyInit(&key[0],
2769  BTEqualStrategyNumber, F_OIDEQ,
2771  ScanKeyInit(&key[1],
2773  BTEqualStrategyNumber, F_OIDEQ,
2774  ObjectIdGetDatum(extensionOid));
2775 
2776  depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
2777  NULL, 2, key);
2778 
2779  while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
2780  {
2781  Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
2782  ObjectAddress dep;
2783  Oid dep_oldNspOid;
2784 
2785  /*
2786  * Ignore non-membership dependencies. (Currently, the only other
2787  * case we could see here is a normal dependency from another
2788  * extension.)
2789  */
2790  if (pg_depend->deptype != DEPENDENCY_EXTENSION)
2791  continue;
2792 
2793  dep.classId = pg_depend->classid;
2794  dep.objectId = pg_depend->objid;
2795  dep.objectSubId = pg_depend->objsubid;
2796 
2797  if (dep.objectSubId != 0) /* should not happen */
2798  elog(ERROR, "extension should not have a sub-object dependency");
2799 
2800  /* Relocate the object */
2801  dep_oldNspOid = AlterObjectNamespace_oid(dep.classId,
2802  dep.objectId,
2803  nspOid,
2804  objsMoved);
2805 
2806  /*
2807  * Remember previous namespace of first object that has one
2808  */
2809  if (oldNspOid == InvalidOid && dep_oldNspOid != InvalidOid)
2810  oldNspOid = dep_oldNspOid;
2811 
2812  /*
2813  * If not all the objects had the same old namespace (ignoring any
2814  * that are not in namespaces), complain.
2815  */
2816  if (dep_oldNspOid != InvalidOid && dep_oldNspOid != oldNspOid)
2817  ereport(ERROR,
2818  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2819  errmsg("extension \"%s\" does not support SET SCHEMA",
2820  NameStr(extForm->extname)),
2821  errdetail("%s is not in the extension's schema \"%s\"",
2822  getObjectDescription(&dep),
2823  get_namespace_name(oldNspOid))));
2824  }
2825 
2826  /* report old schema, if caller wants it */
2827  if (oldschema)
2828  *oldschema = oldNspOid;
2829 
2830  systable_endscan(depScan);
2831 
2833 
2834  /* Now adjust pg_extension.extnamespace */
2835  extForm->extnamespace = nspOid;
2836 
2837  CatalogTupleUpdate(extRel, &extTup->t_self, extTup);
2838 
2839  heap_close(extRel, RowExclusiveLock);
2840 
2841  /* update dependencies to point to the new schema */
2843  NamespaceRelationId, oldNspOid, nspOid);
2844 
2846 
2847  ObjectAddressSet(extAddr, ExtensionRelationId, extensionOid);
2848 
2849  return extAddr;
2850 }
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:2786
#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:1263
#define heap_close(r, l)
Definition: heapam.h:97
ObjectAddresses * new_object_addresses(void)
Definition: dependency.c:2032
unsigned int Oid
Definition: postgres_ext.h:31
AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode)
Definition: aclchk.c:4467
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:75
ItemPointerData t_self
Definition: htup.h:65
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3006
bool pg_extension_ownercheck(Oid ext_oid, Oid roleid)
Definition: aclchk.c:5025
void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, const char *objectname)
Definition: aclchk.c:3382
#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:1287
#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:552
#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 3006 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().

3013 {
3014  const char *oldVersionName = initialVersion;
3015  ListCell *lcv;
3016 
3017  foreach(lcv, updateVersions)
3018  {
3019  char *versionName = (char *) lfirst(lcv);
3020  ExtensionControlFile *control;
3021  char *schemaName;
3022  Oid schemaOid;
3023  List *requiredExtensions;
3024  List *requiredSchemas;
3025  Relation extRel;
3026  ScanKeyData key[1];
3027  SysScanDesc extScan;
3028  HeapTuple extTup;
3029  Form_pg_extension extForm;
3031  bool nulls[Natts_pg_extension];
3032  bool repl[Natts_pg_extension];
3033  ObjectAddress myself;
3034  ListCell *lc;
3035 
3036  /*
3037  * Fetch parameters for specific version (pcontrol is not changed)
3038  */
3039  control = read_extension_aux_control_file(pcontrol, versionName);
3040 
3041  /* Find the pg_extension tuple */
3043 
3044  ScanKeyInit(&key[0],
3046  BTEqualStrategyNumber, F_OIDEQ,
3047  ObjectIdGetDatum(extensionOid));
3048 
3049  extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
3050  NULL, 1, key);
3051 
3052  extTup = systable_getnext(extScan);
3053 
3054  if (!HeapTupleIsValid(extTup)) /* should not happen */
3055  elog(ERROR, "extension with oid %u does not exist",
3056  extensionOid);
3057 
3058  extForm = (Form_pg_extension) GETSTRUCT(extTup);
3059 
3060  /*
3061  * Determine the target schema (set by original install)
3062  */
3063  schemaOid = extForm->extnamespace;
3064  schemaName = get_namespace_name(schemaOid);
3065 
3066  /*
3067  * Modify extrelocatable and extversion in the pg_extension tuple
3068  */
3069  memset(values, 0, sizeof(values));
3070  memset(nulls, 0, sizeof(nulls));
3071  memset(repl, 0, sizeof(repl));
3072 
3073  values[Anum_pg_extension_extrelocatable - 1] =
3074  BoolGetDatum(control->relocatable);
3075  repl[Anum_pg_extension_extrelocatable - 1] = true;
3076  values[Anum_pg_extension_extversion - 1] =
3077  CStringGetTextDatum(versionName);
3078  repl[Anum_pg_extension_extversion - 1] = true;
3079 
3080  extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
3081  values, nulls, repl);
3082 
3083  CatalogTupleUpdate(extRel, &extTup->t_self, extTup);
3084 
3085  systable_endscan(extScan);
3086 
3087  heap_close(extRel, RowExclusiveLock);
3088 
3089  /*
3090  * Look up the prerequisite extensions for this version, install them
3091  * if necessary, and build lists of their OIDs and the OIDs of their
3092  * target schemas.
3093  */
3094  requiredExtensions = NIL;
3095  requiredSchemas = NIL;
3096  foreach(lc, control->requires)
3097  {
3098  char *curreq = (char *) lfirst(lc);
3099  Oid reqext;
3100  Oid reqschema;
3101 
3102  reqext = get_required_extension(curreq,
3103  control->name,
3104  origSchemaName,
3105  cascade,
3106  NIL,
3107  is_create);
3108  reqschema = get_extension_schema(reqext);
3109  requiredExtensions = lappend_oid(requiredExtensions, reqext);
3110  requiredSchemas = lappend_oid(requiredSchemas, reqschema);
3111  }
3112 
3113  /*
3114  * Remove and recreate dependencies on prerequisite extensions
3115  */
3119 
3120  myself.classId = ExtensionRelationId;
3121  myself.objectId = extensionOid;
3122  myself.objectSubId = 0;
3123 
3124  foreach(lc, requiredExtensions)
3125  {
3126  Oid reqext = lfirst_oid(lc);
3127  ObjectAddress otherext;
3128 
3129  otherext.classId = ExtensionRelationId;
3130  otherext.objectId = reqext;
3131  otherext.objectSubId = 0;
3132 
3133  recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
3134  }
3135 
3137 
3138  /*
3139  * Finally, execute the update script file
3140  */
3141  execute_extension_script(extensionOid, control,
3142  oldVersionName, versionName,
3143  requiredSchemas,
3144  schemaName, schemaOid);
3145 
3146  /*
3147  * Update prior-version name and loop around. Since
3148  * execute_sql_string did a final CommandCounterIncrement, we can
3149  * update the pg_extension row again.
3150  */
3151  oldVersionName = versionName;
3152  }
3153 }
#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:1543
#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:780
#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:3006
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:1287
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:162
#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:793
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 2175 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().

2176 {
2177  Datum *datums;
2178  int ndatums;
2179  ArrayType *a;
2180  ListCell *lc;
2181 
2182  ndatums = list_length(requires);
2183  datums = (Datum *) palloc(ndatums * sizeof(Datum));
2184  ndatums = 0;
2185  foreach(lc, requires)
2186  {
2187  char *curreq = (char *) lfirst(lc);
2188 
2189  datums[ndatums++] =
2191  }
2192  a = construct_array(datums, ndatums,
2193  NAMEOID,
2194  NAMEDATALEN, false, 'c');
2195  return PointerGetDatum(a);
2196 }
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 1615 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().

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

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

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

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

3166 {
3167  ObjectAddress extension;
3168  ObjectAddress object;
3169  Relation relation;
3170  Oid oldExtension;
3171 
3172  extension.classId = ExtensionRelationId;
3173  extension.objectId = get_extension_oid(stmt->extname, false);
3174  extension.objectSubId = 0;
3175 
3176  /* Permission check: must own extension */
3177  if (!pg_extension_ownercheck(extension.objectId, GetUserId()))
3179  stmt->extname);
3180 
3181  /*
3182  * Translate the parser representation that identifies the object into an
3183  * ObjectAddress. get_object_address() will throw an error if the object
3184  * does not exist, and will also acquire a lock on the object to guard
3185  * against concurrent DROP and ALTER EXTENSION ADD/DROP operations.
3186  */
3187  object = get_object_address(stmt->objtype, stmt->object,
3188  &relation, ShareUpdateExclusiveLock, false);
3189 
3190  Assert(object.objectSubId == 0);
3191  if (objAddr)
3192  *objAddr = object;
3193 
3194  /* Permission check: must own target object, too */
3195  check_object_ownership(GetUserId(), stmt->objtype, object,
3196  stmt->object, relation);
3197 
3198  /*
3199  * Check existing extension membership.
3200  */
3201  oldExtension = getExtensionOfObject(object.classId, object.objectId);
3202 
3203  if (stmt->action > 0)
3204  {
3205  /*
3206  * ADD, so complain if object is already attached to some extension.
3207  */
3208  if (OidIsValid(oldExtension))
3209  ereport(ERROR,
3210  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3211  errmsg("%s is already a member of extension \"%s\"",
3212  getObjectDescription(&object),
3213  get_extension_name(oldExtension))));
3214 
3215  /*
3216  * Prevent a schema from being added to an extension if the schema
3217  * contains the extension. That would create a dependency loop.
3218  */
3219  if (object.classId == NamespaceRelationId &&
3220  object.objectId == get_extension_schema(extension.objectId))
3221  ereport(ERROR,
3222  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3223  errmsg("cannot add schema \"%s\" to extension \"%s\" "
3224  "because the schema contains the extension",
3225  get_namespace_name(object.objectId),
3226  stmt->extname)));
3227 
3228  /*
3229  * OK, add the dependency.
3230  */
3231  recordDependencyOn(&object, &extension, DEPENDENCY_EXTENSION);
3232 
3233  /*
3234  * Also record the initial ACL on the object, if any.
3235  *
3236  * Note that this will handle the object's ACLs, as well as any ACLs
3237  * on object subIds. (In other words, when the object is a table,
3238  * this will record the table's ACL and the ACLs for the columns on
3239  * the table, if any).
3240  */
3241  recordExtObjInitPriv(object.objectId, object.classId);
3242  }
3243  else
3244  {
3245  /*
3246  * DROP, so complain if it's not a member.
3247  */
3248  if (oldExtension != extension.objectId)
3249  ereport(ERROR,
3250  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3251  errmsg("%s is not a member of extension \"%s\"",
3252  getObjectDescription(&object),
3253  stmt->extname)));
3254 
3255  /*
3256  * OK, drop the dependency.
3257  */
3258  if (deleteDependencyRecordsForClass(object.classId, object.objectId,
3260  DEPENDENCY_EXTENSION) != 1)
3261  elog(ERROR, "unexpected number of extension dependency records");
3262 
3263  /*
3264  * If it's a relation, it might have an entry in the extension's
3265  * extconfig array, which we must remove.
3266  */
3267  if (object.classId == RelationRelationId)
3268  extension_config_remove(extension.objectId, object.objectId);
3269 
3270  /*
3271  * Remove all the initial ACLs, if any.
3272  *
3273  * Note that this will remove the object's ACLs, as well as any ACLs
3274  * on object subIds. (In other words, when the object is a table,
3275  * this will remove the table's ACL and the ACLs for the columns on
3276  * the table, if any).
3277  */
3278  removeExtObjInitPriv(object.objectId, object.classId);
3279  }
3280 
3282 
3283  /*
3284  * If get_object_address() opened the relation for us, we close it to keep
3285  * the reference count correct - but we retain any locks acquired by
3286  * get_object_address() until commit time, to guard against concurrent
3287  * activity.
3288  */
3289  if (relation != NULL)
3290  relation_close(relation, NoLock);
3291 
3292  return extension;
3293 }
void recordExtObjInitPriv(Oid objoid, Oid classoid)
Definition: aclchk.c:5306
#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:2504
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1263
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:3006
#define NoLock
Definition: lockdefs.h:34
bool pg_extension_ownercheck(Oid ext_oid, Oid roleid)
Definition: aclchk.c:5025
void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, const char *objectname)
Definition: aclchk.c:3382
#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:5595
ObjectAddress ExecAlterExtensionStmt ( ParseState pstate,
AlterExtensionStmt stmt 
)

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

2857 {
2858  DefElem *d_new_version = NULL;
2859  char *versionName;
2860  char *oldVersionName;
2861  ExtensionControlFile *control;
2862  Oid extensionOid;
2863  Relation extRel;
2864  ScanKeyData key[1];
2865  SysScanDesc extScan;
2866  HeapTuple extTup;
2867  List *updateVersions;
2868  Datum datum;
2869  bool isnull;
2870  ListCell *lc;
2871  ObjectAddress address;
2872 
2873  /*
2874  * We use global variables to track the extension being created, so we can
2875  * create/update only one extension at the same time.
2876  */
2877  if (creating_extension)
2878  ereport(ERROR,
2879  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2880  errmsg("nested ALTER EXTENSION is not supported")));
2881 
2882  /*
2883  * Look up the extension --- it must already exist in pg_extension
2884  */
2886 
2887  ScanKeyInit(&key[0],
2889  BTEqualStrategyNumber, F_NAMEEQ,
2890  CStringGetDatum(stmt->extname));
2891 
2892  extScan = systable_beginscan(extRel, ExtensionNameIndexId, true,
2893  NULL, 1, key);
2894 
2895  extTup = systable_getnext(extScan);
2896 
2897  if (!HeapTupleIsValid(extTup))
2898  ereport(ERROR,
2899  (errcode(ERRCODE_UNDEFINED_OBJECT),
2900  errmsg("extension \"%s\" does not exist",
2901  stmt->extname)));
2902 
2903  extensionOid = HeapTupleGetOid(extTup);
2904 
2905  /*
2906  * Determine the existing version we are updating from
2907  */
2909  RelationGetDescr(extRel), &isnull);
2910  if (isnull)
2911  elog(ERROR, "extversion is null");
2912  oldVersionName = text_to_cstring(DatumGetTextPP(datum));
2913 
2914  systable_endscan(extScan);
2915 
2916  heap_close(extRel, AccessShareLock);
2917 
2918  /* Permission check: must own extension */
2919  if (!pg_extension_ownercheck(extensionOid, GetUserId()))
2921  stmt->extname);
2922 
2923  /*
2924  * Read the primary control file. Note we assume that it does not contain
2925  * any non-ASCII data, so there is no need to worry about encoding at this
2926  * point.
2927  */
2928  control = read_extension_control_file(stmt->extname);
2929 
2930  /*
2931  * Read the statement option list
2932  */
2933  foreach(lc, stmt->options)
2934  {
2935  DefElem *defel = (DefElem *) lfirst(lc);
2936 
2937  if (strcmp(defel->defname, "new_version") == 0)
2938  {
2939  if (d_new_version)
2940  ereport(ERROR,
2941  (errcode(ERRCODE_SYNTAX_ERROR),
2942  errmsg("conflicting or redundant options"),
2943  parser_errposition(pstate, defel->location)));
2944  d_new_version = defel;
2945  }
2946  else
2947  elog(ERROR, "unrecognized option: %s", defel->defname);
2948  }
2949 
2950  /*
2951  * Determine the version to update to
2952  */
2953  if (d_new_version && d_new_version->arg)
2954  versionName = strVal(d_new_version->arg);
2955  else if (control->default_version)
2956  versionName = control->default_version;
2957  else
2958  {
2959  ereport(ERROR,
2960  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2961  errmsg("version to install must be specified")));
2962  versionName = NULL; /* keep compiler quiet */
2963  }
2964  check_valid_version_name(versionName);
2965 
2966  /*
2967  * If we're already at that version, just say so
2968  */
2969  if (strcmp(oldVersionName, versionName) == 0)
2970  {
2971  ereport(NOTICE,
2972  (errmsg("version \"%s\" of extension \"%s\" is already installed",
2973  versionName, stmt->extname)));
2974  return InvalidObjectAddress;
2975  }
2976 
2977  /*
2978  * Identify the series of update script files we need to execute
2979  */
2980  updateVersions = identify_update_path(control,
2981  oldVersionName,
2982  versionName);
2983 
2984  /*
2985  * Update the pg_extension row and execute the update scripts, one at a
2986  * time
2987  */
2988  ApplyExtensionUpdates(extensionOid, control,
2989  oldVersionName, updateVersions,
2990  NULL, false, false);
2991 
2992  ObjectAddressSet(address, ExtensionRelationId, extensionOid);
2993 
2994  return address;
2995 }
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:3006
#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:1070
#define Anum_pg_extension_extname
Definition: pg_extension.h:59
bool pg_extension_ownercheck(Oid ext_oid, Oid roleid)
Definition: aclchk.c:5025
void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, const char *objectname)
Definition: aclchk.c:3382
int location
Definition: parsenodes.h:711
#define CStringGetDatum(X)
Definition: postgres.h:584
#define ereport(elevel, rest)
Definition: elog.h:122
Node * arg
Definition: parsenodes.h:709
#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:1287
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:109
#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:708
#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 780 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().

785 {
786  char *filename;
787  int save_nestlevel;
788  StringInfoData pathbuf;
789  ListCell *lc;
790 
791  /*
792  * Enforce superuser-ness if appropriate. We postpone this check until
793  * here so that the flag is correctly associated with the right script(s)
794  * if it's set in secondary control files.
795  */
796  if (control->superuser && !superuser())
797  {
798  if (from_version == NULL)
799  ereport(ERROR,
800  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
801  errmsg("permission denied to create extension \"%s\"",
802  control->name),
803  errhint("Must be superuser to create this extension.")));
804  else
805  ereport(ERROR,
806  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
807  errmsg("permission denied to update extension \"%s\"",
808  control->name),
809  errhint("Must be superuser to update this extension.")));
810  }
811 
812  filename = get_extension_script_filename(control, from_version, version);
813 
814  /*
815  * Force client_min_messages and log_min_messages to be at least WARNING,
816  * so that we won't spam the user with useless NOTICE messages from common
817  * script actions like creating shell types.
818  *
819  * We use the equivalent of a function SET option to allow the setting to
820  * persist for exactly the duration of the script execution. guc.c also
821  * takes care of undoing the setting on error.
822  */
823  save_nestlevel = NewGUCNestLevel();
824 
826  (void) set_config_option("client_min_messages", "warning",
828  GUC_ACTION_SAVE, true, 0, false);
830  (void) set_config_option("log_min_messages", "warning",
832  GUC_ACTION_SAVE, true, 0, false);
833 
834  /*
835  * Set up the search path to contain the target schema, then the schemas
836  * of any prerequisite extensions, and nothing else. In particular this
837  * makes the target schema be the default creation target namespace.
838  *
839  * Note: it might look tempting to use PushOverrideSearchPath for this,
840  * but we cannot do that. We have to actually set the search_path GUC in
841  * case the extension script examines or changes it. In any case, the
842  * GUC_ACTION_SAVE method is just as convenient.
843  */
844  initStringInfo(&pathbuf);
845  appendStringInfoString(&pathbuf, quote_identifier(schemaName));
846  foreach(lc, requiredSchemas)
847  {
848  Oid reqschema = lfirst_oid(lc);
849  char *reqname = get_namespace_name(reqschema);
850 
851  if (reqname)
852  appendStringInfo(&pathbuf, ", %s", quote_identifier(reqname));
853  }
854 
855  (void) set_config_option("search_path", pathbuf.data,
857  GUC_ACTION_SAVE, true, 0, false);
858 
859  /*
860  * Set creating_extension and related variables so that
861  * recordDependencyOnCurrentExtension and other functions do the right
862  * things. On failure, ensure we reset these variables.
863  */
864  creating_extension = true;
865  CurrentExtensionObject = extensionOid;
866  PG_TRY();
867  {
868  char *c_sql = read_extension_script_file(control, filename);
869  Datum t_sql;
870 
871  /* We use various functions that want to operate on text datums */
872  t_sql = CStringGetTextDatum(c_sql);
873 
874  /*
875  * Reduce any lines beginning with "\echo" to empty. This allows
876  * scripts to contain messages telling people not to run them via
877  * psql, which has been found to be necessary due to old habits.
878  */
881  t_sql,
882  CStringGetTextDatum("^\\\\echo.*$"),
884  CStringGetTextDatum("ng"));
885 
886  /*
887  * If it's not relocatable, substitute the target schema name for
888  * occurrences of @extschema@.
889  *
890  * For a relocatable extension, we needn't do this. There cannot be
891  * any need for @extschema@, else it wouldn't be relocatable.
892  */
893  if (!control->relocatable)
894  {
895  const char *qSchemaName = quote_identifier(schemaName);
896 
898  t_sql,
899  CStringGetTextDatum("@extschema@"),
900  CStringGetTextDatum(qSchemaName));
901  }
902 
903  /*
904  * If module_pathname was set in the control file, substitute its
905  * value for occurrences of MODULE_PATHNAME.
906  */
907  if (control->module_pathname)
908  {
910  t_sql,
911  CStringGetTextDatum("MODULE_PATHNAME"),
913  }
914 
915  /* And now back to C string */
916  c_sql = text_to_cstring(DatumGetTextPP(t_sql));
917 
918  execute_sql_string(c_sql, filename);
919  }
920  PG_CATCH();
921  {
922  creating_extension = false;
924  PG_RE_THROW();
925  }
926  PG_END_TRY();
927 
928  creating_extension = false;
930 
931  /*
932  * Restore the GUC variables we set above.
933  */
934  AtEOXact_GUC(true, save_nestlevel);
935 }
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:10185
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:3665
Datum DirectFunctionCall4Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4)
Definition: fmgr.c:1083
#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:110
#define ERROR
Definition: elog.h:43
Definition: guc.h:75
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:189
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3006
void AtEOXact_GUC(bool isCommit, int nestLevel)
Definition: guc.c:5058
#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:65
#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:454
#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:77
char * text_to_cstring(const text *t)
Definition: varlena.c:182
int NewGUCNestLevel(void)
Definition: guc.c:5044
static char * filename
Definition: pg_dumpall.c:87
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define CStringGetTextDatum(s)
Definition: builtins.h:91
int client_min_messages
Definition: guc.c:455
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:5887
#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 castNode, CommandCounterIncrement(), CreateDestReceiver(), CreateQueryDesc(), CURSOR_OPT_PARALLEL_OK, DestNone, ereport, errcode(), errmsg(), ERROR, ExecutorEnd(), ExecutorFinish(), ExecutorRun(), ExecutorStart(), ForwardScanDirection, FreeQueryDesc(), GetActiveSnapshot(), GetTransactionSnapshot(), IsA, lfirst, 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 = castNode(RawStmt, lfirst(lc1));
718  List *stmt_list;
719  ListCell *lc2;
720 
721  stmt_list = pg_analyze_and_rewrite(parsetree,
722  sql,
723  NULL,
724  0);
725  stmt_list = pg_plan_queries(stmt_list, CURSOR_OPT_PARALLEL_OK, NULL);
726 
727  foreach(lc2, stmt_list)
728  {
729  PlannedStmt *stmt = castNode(PlannedStmt, lfirst(lc2));
730 
732 
734 
735  if (stmt->utilityStmt == NULL)
736  {
737  QueryDesc *qdesc;
738 
739  qdesc = CreateQueryDesc(stmt,
740  sql,
742  dest, NULL, 0);
743 
744  ExecutorStart(qdesc, 0);
745  ExecutorRun(qdesc, ForwardScanDirection, 0, true);
746  ExecutorFinish(qdesc);
747  ExecutorEnd(qdesc);
748 
749  FreeQueryDesc(qdesc);
750  }
751  else
752  {
753  if (IsA(stmt->utilityStmt, TransactionStmt))
754  ereport(ERROR,
755  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
756  errmsg("transaction control statements are not allowed within an extension script")));
757 
758  ProcessUtility(stmt,
759  sql,
761  NULL,
762  dest,
763  NULL);
764  }
765 
767  }
768  }
769 
770  /* Be sure to advance the command counter after the last script command */
772 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:557
#define castNode(_type_, nodeptr)
Definition: nodes.h:575
void FreeQueryDesc(QueryDesc *qdesc)
Definition: pquery.c:103
void ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:144
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:834
int errcode(int sqlerrcode)
Definition: elog.c:575
void PopActiveSnapshot(void)
Definition: snapmgr.c:807
QueryDesc * CreateQueryDesc(PlannedStmt *plannedstmt, const char *sourceText, Snapshot snapshot, Snapshot crosscheck_snapshot, DestReceiver *dest, ParamListInfo params, int instrument_options)
Definition: pquery.c:66
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:300
void ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:453
List * pg_analyze_and_rewrite(RawStmt *parsetree, const char *query_string, Oid *paramTypes, int numParams)
Definition: postgres.c:644
#define ERROR
Definition: elog.h:43
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: execMain.c:291
List * pg_parse_query(const char *query_string)
Definition: postgres.c:602
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:83
#define ereport(elevel, rest)
Definition: elog.h:122
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:393
void ProcessUtility(PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, DestReceiver *dest, char *completionTag)
Definition: utility.c:332
void CommandCounterIncrement(void)
Definition: xact.c:922
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2579
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:842
static void extension_config_remove ( Oid  extensionoid,
Oid  tableoid 
)
static

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

2505 {
2506  Relation extRel;
2507  ScanKeyData key[1];
2508  SysScanDesc extScan;
2509  HeapTuple extTup;
2510  Datum arrayDatum;
2511  int arrayLength;
2512  int arrayIndex;
2513  bool isnull;
2514  Datum repl_val[Natts_pg_extension];
2515  bool repl_null[Natts_pg_extension];
2516  bool repl_repl[Natts_pg_extension];
2517  ArrayType *a;
2518 
2519  /* Find the pg_extension tuple */
2521 
2522  ScanKeyInit(&key[0],
2524  BTEqualStrategyNumber, F_OIDEQ,
2525  ObjectIdGetDatum(extensionoid));
2526 
2527  extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
2528  NULL, 1, key);
2529 
2530  extTup = systable_getnext(extScan);
2531 
2532  if (!HeapTupleIsValid(extTup)) /* should not happen */
2533  elog(ERROR, "extension with oid %u does not exist",
2534  extensionoid);
2535 
2536  /* Search extconfig for the tableoid */
2537  arrayDatum = heap_getattr(extTup, Anum_pg_extension_extconfig,
2538  RelationGetDescr(extRel), &isnull);
2539  if (isnull)
2540  {
2541  /* nothing to do */
2542  a = NULL;
2543  arrayLength = 0;
2544  arrayIndex = -1;
2545  }
2546  else
2547  {
2548  Oid *arrayData;
2549  int i;
2550 
2551  a = DatumGetArrayTypeP(arrayDatum);
2552 
2553  arrayLength = ARR_DIMS(a)[0];
2554  if (ARR_NDIM(a) != 1 ||
2555  ARR_LBOUND(a)[0] != 1 ||
2556  arrayLength < 0 ||
2557  ARR_HASNULL(a) ||
2558  ARR_ELEMTYPE(a) != OIDOID)
2559  elog(ERROR, "extconfig is not a 1-D Oid array");
2560  arrayData = (Oid *) ARR_DATA_PTR(a);
2561 
2562  arrayIndex = -1; /* flag for no deletion needed */
2563 
2564  for (i = 0; i < arrayLength; i++)
2565  {
2566  if (arrayData[i] == tableoid)
2567  {
2568  arrayIndex = i; /* index to remove */
2569  break;
2570  }
2571  }
2572  }
2573 
2574  /* If tableoid is not in extconfig, nothing to do */
2575  if (arrayIndex < 0)
2576  {
2577  systable_endscan(extScan);
2578  heap_close(extRel, RowExclusiveLock);
2579  return;
2580  }
2581 
2582  /* Modify or delete the extconfig value */
2583  memset(repl_val, 0, sizeof(repl_val));
2584  memset(repl_null, false, sizeof(repl_null));
2585  memset(repl_repl, false, sizeof(repl_repl));
2586 
2587  if (arrayLength <= 1)
2588  {
2589  /* removing only element, just set array to null */
2590  repl_null[Anum_pg_extension_extconfig - 1] = true;
2591  }
2592  else
2593  {
2594  /* squeeze out the target element */
2595  Datum *dvalues;
2596  bool *dnulls;
2597  int nelems;
2598  int i;
2599 
2600  deconstruct_array(a, OIDOID, sizeof(Oid), true, 'i',
2601  &dvalues, &dnulls, &nelems);
2602 
2603  /* We already checked there are no nulls, so ignore dnulls */
2604  for (i = arrayIndex; i < arrayLength - 1; i++)
2605  dvalues[i] = dvalues[i + 1];
2606 
2607  a = construct_array(dvalues, arrayLength - 1,
2608  OIDOID, sizeof(Oid), true, 'i');
2609 
2610  repl_val[Anum_pg_extension_extconfig - 1] = PointerGetDatum(a);
2611  }
2612  repl_repl[Anum_pg_extension_extconfig - 1] = true;
2613 
2614  /* Modify or delete the extcondition value */
2615  arrayDatum = heap_getattr(extTup, Anum_pg_extension_extcondition,
2616  RelationGetDescr(extRel), &isnull);
2617  if (isnull)
2618  {
2619  elog(ERROR, "extconfig and extcondition arrays do not match");
2620  }
2621  else
2622  {
2623  a = DatumGetArrayTypeP(arrayDatum);
2624 
2625  if (ARR_NDIM(a) != 1 ||
2626  ARR_LBOUND(a)[0] != 1 ||
2627  ARR_HASNULL(a) ||
2628  ARR_ELEMTYPE(a) != TEXTOID)
2629  elog(ERROR, "extcondition is not a 1-D text array");
2630  if (ARR_DIMS(a)[0] != arrayLength)
2631  elog(ERROR, "extconfig and extcondition arrays do not match");
2632  }
2633 
2634  if (arrayLength <= 1)
2635  {
2636  /* removing only element, just set array to null */
2637  repl_null[Anum_pg_extension_extcondition - 1] = true;
2638  }
2639  else
2640  {
2641  /* squeeze out the target element */
2642  Datum *dvalues;
2643  bool *dnulls;
2644  int nelems;
2645  int i;
2646 
2647  deconstruct_array(a, TEXTOID, -1, false, 'i',
2648  &dvalues, &dnulls, &nelems);
2649 
2650  /* We already checked there are no nulls, so ignore dnulls */
2651  for (i = arrayIndex; i < arrayLength - 1; i++)
2652  dvalues[i] = dvalues[i + 1];
2653 
2654  a = construct_array(dvalues, arrayLength - 1,
2655  TEXTOID, -1, false, 'i');
2656 
2658  }
2659  repl_repl[Anum_pg_extension_extcondition - 1] = true;
2660 
2661  extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
2662  repl_val, repl_null, repl_repl);
2663 
2664  CatalogTupleUpdate(extRel, &extTup->t_self, extTup);
2665 
2666  systable_endscan(extScan);
2667 
2668  heap_close(extRel, RowExclusiveLock);
2669 }
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:1287
#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:793
#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 1206 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().

1208 {
1209  ExtensionVersionInfo *evi_start = NULL;
1210  ListCell *lc;
1211 
1212  *best_path = NIL;
1213 
1214  /*
1215  * We don't expect to be called for an installable target, but if we are,
1216  * the answer is easy: just start from there, with an empty update path.
1217  */
1218  if (evi_target->installable)
1219  return evi_target;
1220 
1221  /* Consider all installable versions as start points */
1222  foreach(lc, evi_list)
1223  {
1225  List *path;
1226 
1227  if (!evi1->installable)
1228  continue;
1229 
1230  /*
1231  * Find shortest path from evi1 to evi_target; but no need to consider
1232  * paths going through other installable versions.
1233  */
1234  path = find_update_path(evi_list, evi1, evi_target, true, true);
1235  if (path == NIL)
1236  continue;
1237 
1238  /* Remember best path */
1239  if (evi_start == NULL ||
1240  list_length(path) < list_length(*best_path) ||
1241  (list_length(path) == list_length(*best_path) &&
1242  strcmp(evi_start->name, evi1->name) < 0))
1243  {
1244  evi_start = evi1;
1245  *best_path = path;
1246  }
1247  }
1248 
1249  return evi_start;
1250 }
#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:1113
#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 1113 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().

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

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

947 {
949  ListCell *lc;
950 
951  foreach(lc, *evi_list)
952  {
953  evi = (ExtensionVersionInfo *) lfirst(lc);
954  if (strcmp(evi->name, versionname) == 0)
955  return evi;
956  }
957 
959  evi->name = pstrdup(versionname);
960  evi->reachable = NIL;
961  evi->installable = false;
962  /* initialize for later application of Dijkstra's algorithm */
963  evi->distance_known = false;
964  evi->distance = INT_MAX;
965  evi->previous = NULL;
966 
967  *evi_list = lappend(*evi_list, evi);
968 
969  return evi;
970 }
#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 1007 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().

1008 {
1009  List *evi_list = NIL;
1010  int extnamelen = strlen(control->name);
1011  char *location;
1012  DIR *dir;
1013  struct dirent *de;
1014 
1015  location = get_extension_script_directory(control);
1016  dir = AllocateDir(location);
1017  while ((de = ReadDir(dir, location)) != NULL)
1018  {
1019  char *vername;
1020  char *vername2;
1021  ExtensionVersionInfo *evi;
1022  ExtensionVersionInfo *evi2;
1023 
1024  /* must be a .sql file ... */
1026  continue;
1027 
1028  /* ... matching extension name followed by separator */
1029  if (strncmp(de->d_name, control->name, extnamelen) != 0 ||
1030  de->d_name[extnamelen] != '-' ||
1031  de->d_name[extnamelen + 1] != '-')
1032  continue;
1033 
1034  /* extract version name(s) from 'extname--something.sql' filename */
1035  vername = pstrdup(de->d_name + extnamelen + 2);
1036  *strrchr(vername, '.') = '\0';
1037  vername2 = strstr(vername, "--");
1038  if (!vername2)
1039  {
1040  /* It's an install, not update, script; record its version name */
1041  evi = get_ext_ver_info(vername, &evi_list);
1042  evi->installable = true;
1043  continue;
1044  }
1045  *vername2 = '\0'; /* terminate first version */
1046  vername2 += 2; /* and point to second */
1047 
1048  /* if there's a third --, it's bogus, ignore it */
1049  if (strstr(vername2, "--"))
1050  continue;
1051 
1052  /* Create ExtensionVersionInfos and link them together */
1053  evi = get_ext_ver_info(vername, &evi_list);
1054  evi2 = get_ext_ver_info(vername2, &evi_list);
1055  evi->reachable = lappend(evi->reachable, evi2);
1056  }
1057  FreeDir(dir);
1058 
1059  return evi_list;
1060 }
#define NIL
Definition: pg_list.h:69
static ExtensionVersionInfo * get_ext_ver_info(const char *versionname, List **evi_list)
Definition: extension.c:946
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:1618
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:1618
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:1618
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:1618
#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:1287
#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:1618
#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:1287
#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:1618
#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:1287
#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:1618
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:1618
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 979 of file extension.c.

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

Referenced by find_update_path().

980 {
981  ExtensionVersionInfo *evi = NULL;
982  ListCell *lc;
983 
984  foreach(lc, evi_list)
985  {
987 
988  /* only vertices whose distance is still uncertain are candidates */
989  if (evi2->distance_known)
990  continue;
991  /* remember the closest such vertex */
992  if (evi == NULL ||
993  evi->distance > evi2->distance)
994  evi = evi2;
995  }
996 
997  return evi;
998 }
#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 1543 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().

1549 {
1550  Oid reqExtensionOid;
1551 
1552  reqExtensionOid = get_extension_oid(reqExtensionName, true);
1553  if (!OidIsValid(reqExtensionOid))
1554  {
1555  if (cascade)
1556  {
1557  /* Must install it. */
1558  ObjectAddress addr;
1559  List *cascade_parents;
1560  ListCell *lc;
1561 
1562  /* Check extension name validity before trying to cascade. */
1563  check_valid_extension_name(reqExtensionName);
1564 
1565  /* Check for cyclic dependency between extensions. */
1566  foreach(lc, parents)
1567  {
1568  char *pname = (char *) lfirst(lc);
1569 
1570  if (strcmp(pname, reqExtensionName) == 0)
1571  ereport(ERROR,
1572  (errcode(ERRCODE_INVALID_RECURSION),
1573  errmsg("cyclic dependency detected between extensions \"%s\" and \"%s\"",
1574  reqExtensionName, extensionName)));
1575  }
1576 
1577  ereport(NOTICE,
1578  (errmsg("installing required extension \"%s\"",
1579  reqExtensionName)));
1580 
1581  /* Add current extension to list of parents to pass down. */
1582  cascade_parents = lappend(list_copy(parents), extensionName);
1583 
1584  /*
1585  * Create the required extension. We propagate the SCHEMA option
1586  * if any, and CASCADE, but no other options.
1587  */
1588  addr = CreateExtensionInternal(reqExtensionName,
1589  origSchemaName,
1590  NULL,
1591  NULL,
1592  cascade,
1593  cascade_parents,
1594  is_create);
1595 
1596  /* Get its newly-assigned OID. */
1597  reqExtensionOid = addr.objectId;
1598  }
1599  else
1600  ereport(ERROR,
1601  (errcode(ERRCODE_UNDEFINED_OBJECT),
1602  errmsg("required extension \"%s\" is not installed",
1603  reqExtensionName),
1604  is_create ?
1605  errhint("Use CREATE EXTENSION ... CASCADE to install required extensions too.") : 0));
1606  }
1607 
1608  return reqExtensionOid;
1609 }
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:1261
static List* identify_update_path ( ExtensionControlFile control,
const char *  oldVersion,
const char *  newVersion 
)
static

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

1072 {
1073  List *result;
1074  List *evi_list;
1075  ExtensionVersionInfo *evi_start;
1076  ExtensionVersionInfo *evi_target;
1077 
1078  /* Extract the version update graph from the script directory */
1079  evi_list = get_ext_ver_list(control);
1080 
1081  /* Initialize start and end vertices */
1082  evi_start = get_ext_ver_info(oldVersion, &evi_list);
1083  evi_target = get_ext_ver_info(newVersion, &evi_list);
1084 
1085  /* Find shortest path */
1086  result = find_update_path(evi_list, evi_start, evi_target, false, false);
1087 
1088  if (result == NIL)
1089  ereport(ERROR,
1090  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1091  errmsg("extension \"%s\" has no update path from version \"%s\" to version \"%s\"",
1092  control->name, oldVersion, newVersion)));
1093 
1094  return result;
1095 }
#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:1113
static ExtensionVersionInfo * get_ext_ver_info(const char *versionname, List **evi_list)
Definition: extension.c:946
static List * get_ext_ver_list(ExtensionControlFile *control)
Definition: extension.c:1007
int errcode(int sqlerrcode)
Definition: elog.c:575
return result
Definition: formatting.c:1618
#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 1735 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().

1739 {
1740  Oid extensionOid;
1741  Relation rel;
1743  bool nulls[Natts_pg_extension];
1744  HeapTuple tuple;
1745  ObjectAddress myself;
1746  ObjectAddress nsp;
1747  ListCell *lc;
1748 
1749  /*
1750  * Build and insert the pg_extension tuple
1751  */
1753 
1754  memset(values, 0, sizeof(values));
1755  memset(nulls, 0, sizeof(nulls));
1756 
1757  values[Anum_pg_extension_extname - 1] =
1759  values[Anum_pg_extension_extowner - 1] = ObjectIdGetDatum(extOwner);
1760  values[Anum_pg_extension_extnamespace - 1] = ObjectIdGetDatum(schemaOid);
1761  values[Anum_pg_extension_extrelocatable - 1] = BoolGetDatum(relocatable);
1762  values[Anum_pg_extension_extversion - 1] = CStringGetTextDatum(extVersion);
1763 
1764  if (extConfig == PointerGetDatum(NULL))
1765  nulls[Anum_pg_extension_extconfig - 1] = true;
1766  else
1767  values[Anum_pg_extension_extconfig - 1] = extConfig;
1768 
1769  if (extCondition == PointerGetDatum(NULL))
1770  nulls[Anum_pg_extension_extcondition - 1] = true;
1771  else
1772  values[Anum_pg_extension_extcondition - 1] = extCondition;
1773 
1774  tuple = heap_form_tuple(rel->rd_att, values, nulls);
1775 
1776  extensionOid = CatalogTupleInsert(rel, tuple);
1777 
1778  heap_freetuple(tuple);
1780 
1781  /*
1782  * Record dependencies on owner, schema, and prerequisite extensions
1783  */
1784  recordDependencyOnOwner(ExtensionRelationId, extensionOid, extOwner);
1785 
1786  myself.classId = ExtensionRelationId;
1787  myself.objectId = extensionOid;
1788  myself.objectSubId = 0;
1789 
1791  nsp.objectId = schemaOid;
1792  nsp.objectSubId = 0;
1793 
1794  recordDependencyOn(&myself, &nsp, DEPENDENCY_NORMAL);
1795 
1796  foreach(lc, requiredExtensions)
1797  {
1798  Oid reqext = lfirst_oid(lc);
1799  ObjectAddress otherext;
1800 
1801  otherext.classId = ExtensionRelationId;
1802  otherext.objectId = reqext;
1803  otherext.objectSubId = 0;
1804 
1805  recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
1806  }
1807  /* Post creation hook for new extension */
1809 
1810  return myself;
1811 }
#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:1374
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:1287
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:162
#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:87
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:87
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:3240
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:87
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 1983 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.

1984 {
1985  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1986  TupleDesc tupdesc;
1987  Tuplestorestate *tupstore;
1988  MemoryContext per_query_ctx;
1989  MemoryContext oldcontext;
1990  char *location;
1991  DIR *dir;
1992  struct dirent *de;
1993 
1994  /* check to see if caller supports us returning a tuplestore */
1995  if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
1996  ereport(ERROR,
1997  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1998  errmsg("set-valued function called in context that cannot accept a set")));
1999  if (!(rsinfo->allowedModes & SFRM_Materialize))
2000  ereport(ERROR,
2001  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2002  errmsg("materialize mode required, but it is not " \
2003  "allowed in this context")));
2004 
2005  /* Build a tuple descriptor for our result type */
2006  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
2007  elog(ERROR, "return type must be a row type");
2008 
2009  /* Build tuplestore to hold the result rows */
2010  per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
2011  oldcontext = MemoryContextSwitchTo(per_query_ctx);
2012 
2013  tupstore = tuplestore_begin_heap(true, false, work_mem);
2014  rsinfo->returnMode = SFRM_Materialize;
2015  rsinfo->setResult = tupstore;
2016  rsinfo->setDesc = tupdesc;
2017 
2018  MemoryContextSwitchTo(oldcontext);
2019 
2020  location = get_extension_control_directory();
2021  dir = AllocateDir(location);
2022 
2023  /*
2024  * If the control directory doesn't exist, we want to silently return an
2025  * empty set. Any other error will be reported by ReadDir.
2026  */
2027  if (dir == NULL && errno == ENOENT)
2028  {
2029  /* do nothing */
2030  }
2031  else
2032  {
2033  while ((de = ReadDir(dir, location)) != NULL)
2034  {
2035  ExtensionControlFile *control;
2036  char *extname;
2037 
2038  if (!is_extension_control_filename(de->d_name))
2039  continue;
2040 
2041  /* extract extension name from 'name.control' filename */
2042  extname = pstrdup(de->d_name);
2043  *strrchr(extname, '.') = '\0';
2044 
2045  /* ignore it if it's an auxiliary control file */
2046  if (strstr(extname, "--"))
2047  continue;
2048 
2049  /* read the control file */
2050  control = read_extension_control_file(extname);
2051 
2052  /* scan extension's script directory for install scripts */
2053  get_available_versions_for_extension(control, tupstore, tupdesc);
2054  }
2055 
2056  FreeDir(dir);
2057  }
2058 
2059  /* clean up and return the tuplestore */
2060  tuplestore_donestoring(tupstore);
2061 
2062  return (Datum) 0;
2063 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:557
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:2070
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:316
uintptr_t Datum
Definition: postgres.h:372
int work_mem
Definition: globals.c:112
int allowedModes
Definition: execnodes.h:267
SetFunctionReturnMode returnMode
Definition: execnodes.h:269
#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:201
Tuplestorestate * setResult
Definition: execnodes.h:272
ExprContext * econtext
Definition: execnodes.h:265
TupleDesc setDesc
Definition: execnodes.h:273
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 1874 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.

1875 {
1876  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1877  TupleDesc tupdesc;
1878  Tuplestorestate *tupstore;
1879  MemoryContext per_query_ctx;
1880  MemoryContext oldcontext;
1881  char *location;
1882  DIR *dir;
1883  struct dirent *de;
1884 
1885  /* check to see if caller supports us returning a tuplestore */
1886  if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
1887  ereport(ERROR,
1888  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1889  errmsg("set-valued function called in context that cannot accept a set")));
1890  if (!(rsinfo->allowedModes & SFRM_Materialize))
1891  ereport(ERROR,
1892  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1893  errmsg("materialize mode required, but it is not " \
1894  "allowed in this context")));
1895 
1896  /* Build a tuple descriptor for our result type */
1897  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
1898  elog(ERROR, "return type must be a row type");
1899 
1900  /* Build tuplestore to hold the result rows */
1901  per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
1902  oldcontext = MemoryContextSwitchTo(per_query_ctx);
1903 
1904  tupstore = tuplestore_begin_heap(true, false, work_mem);
1905  rsinfo->returnMode = SFRM_Materialize;
1906  rsinfo->setResult = tupstore;
1907  rsinfo->setDesc = tupdesc;
1908 
1909  MemoryContextSwitchTo(oldcontext);
1910 
1911  location = get_extension_control_directory();
1912  dir = AllocateDir(location);
1913 
1914  /*
1915  * If the control directory doesn't exist, we want to silently return an
1916  * empty set. Any other error will be reported by ReadDir.
1917  */
1918  if (dir == NULL && errno == ENOENT)
1919  {
1920  /* do nothing */
1921  }
1922  else
1923  {
1924  while ((de = ReadDir(dir, location)) != NULL)
1925  {
1926  ExtensionControlFile *control;
1927  char *extname;
1928  Datum values[3];
1929  bool nulls[3];
1930 
1931  if (!is_extension_control_filename(de->d_name))
1932  continue;
1933 
1934  /* extract extension name from 'name.control' filename */
1935  extname = pstrdup(de->d_name);
1936  *strrchr(extname, '.') = '\0';
1937 
1938  /* ignore it if it's an auxiliary control file */
1939  if (strstr(extname, "--"))
1940  continue;
1941 
1942  control = read_extension_control_file(extname);
1943 
1944  memset(values, 0, sizeof(values));
1945  memset(nulls, 0, sizeof(nulls));
1946 
1947  /* name */
1948  values[0] = DirectFunctionCall1(namein,
1949  CStringGetDatum(control->name));
1950  /* default_version */
1951  if (control->default_version == NULL)
1952  nulls[1] = true;
1953  else
1954  values[1] = CStringGetTextDatum(control->default_version);
1955  /* comment */
1956  if (control->comment == NULL)
1957  nulls[2] = true;
1958  else
1959  values[2] = CStringGetTextDatum(control->comment);
1960 
1961  tuplestore_putvalues(tupstore, tupdesc, values, nulls);
1962  }
1963 
1964  FreeDir(dir);
1965  }
1966 
1967  /* clean up and return the tuplestore */
1968  tuplestore_donestoring(tupstore);
1969 
1970  return (Datum) 0;
1971 }
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, Datum *values, bool *isnull)
Definition: tuplestore.c:735
#define IsA(nodeptr, _type_)
Definition: nodes.h:557
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:316
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:267
SetFunctionReturnMode returnMode
Definition: execnodes.h:269
#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:201
Tuplestorestate * setResult
Definition: execnodes.h:272
static Datum values[MAXATTR]
Definition: bootstrap.c:162
ExprContext * econtext
Definition: execnodes.h:265
TupleDesc setDesc
Definition: execnodes.h:273
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 2317 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.

2318 {
2319  Oid tableoid = PG_GETARG_OID(0);
2320  text *wherecond = PG_GETARG_TEXT_PP(1);
2321  char *tablename;
2322  Relation extRel;
2323  ScanKeyData key[1];
2324  SysScanDesc extScan;
2325  HeapTuple extTup;
2326  Datum arrayDatum;
2327  Datum elementDatum;
2328  int arrayLength;
2329  int arrayIndex;
2330  bool isnull;
2331  Datum repl_val[Natts_pg_extension];
2332  bool repl_null[Natts_pg_extension];
2333  bool repl_repl[Natts_pg_extension];
2334  ArrayType *a;
2335 
2336  /*
2337  * We only allow this to be called from an extension's SQL script. We
2338  * shouldn't need any permissions check beyond that.
2339  */
2340  if (!creating_extension)
2341  ereport(ERROR,
2342  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2343  errmsg("pg_extension_config_dump() can only be called "
2344  "from an SQL script executed by CREATE EXTENSION")));
2345 
2346  /*
2347  * Check that the table exists and is a member of the extension being
2348  * created. This ensures that we don't need to register an additional
2349  * dependency to protect the extconfig entry.
2350  */
2351  tablename = get_rel_name(tableoid);
2352  if (tablename == NULL)
2353  ereport(ERROR,
2355  errmsg("OID %u does not refer to a table", tableoid)));
2356  if (getExtensionOfObject(RelationRelationId, tableoid) !=
2358  ereport(ERROR,
2359  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2360  errmsg("table \"%s\" is not a member of the extension being created",
2361  tablename)));
2362 
2363  /*
2364  * Add the table OID and WHERE condition to the extension's extconfig and
2365  * extcondition arrays.
2366  *
2367  * If the table is already in extconfig, treat this as an update of the
2368  * WHERE condition.
2369  */
2370 
2371  /* Find the pg_extension tuple */
2373 
2374  ScanKeyInit(&key[0],
2376  BTEqualStrategyNumber, F_OIDEQ,
2378 
2379  extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
2380  NULL, 1, key);
2381 
2382  extTup = systable_getnext(extScan);
2383 
2384  if (!HeapTupleIsValid(extTup)) /* should not happen */
2385  elog(ERROR, "extension with oid %u does not exist",
2387 
2388  memset(repl_val, 0, sizeof(repl_val));
2389  memset(repl_null, false, sizeof(repl_null));
2390  memset(repl_repl, false, sizeof(repl_repl));
2391 
2392  /* Build or modify the extconfig value */
2393  elementDatum = ObjectIdGetDatum(tableoid);
2394 
2395  arrayDatum = heap_getattr(extTup, Anum_pg_extension_extconfig,
2396  RelationGetDescr(extRel), &isnull);
2397  if (isnull)
2398  {
2399  /* Previously empty extconfig, so build 1-element array */
2400  arrayLength = 0;
2401  arrayIndex = 1;
2402 
2403  a = construct_array(&elementDatum, 1,
2404  OIDOID,
2405  sizeof(Oid), true, 'i');
2406  }
2407  else
2408  {
2409  /* Modify or extend existing extconfig array */
2410  Oid *arrayData;
2411  int i;
2412 
2413  a = DatumGetArrayTypeP(arrayDatum);
2414 
2415  arrayLength = ARR_DIMS(a)[0];
2416  if (ARR_NDIM(a) != 1 ||
2417  ARR_LBOUND(a)[0] != 1 ||
2418  arrayLength < 0 ||
2419  ARR_HASNULL(a) ||
2420  ARR_ELEMTYPE(a) != OIDOID)
2421  elog(ERROR, "extconfig is not a 1-D Oid array");
2422  arrayData = (Oid *) ARR_DATA_PTR(a);
2423 
2424  arrayIndex = arrayLength + 1; /* set up to add after end */
2425 
2426  for (i = 0; i < arrayLength; i++)
2427  {
2428  if (arrayData[i] == tableoid)
2429  {
2430  arrayIndex = i + 1; /* replace this element instead */
2431  break;
2432  }
2433  }
2434 
2435  a = array_set(a, 1, &arrayIndex,
2436  elementDatum,
2437  false,
2438  -1 /* varlena array */ ,
2439  sizeof(Oid) /* OID's typlen */ ,
2440  true /* OID's typbyval */ ,
2441  'i' /* OID's typalign */ );
2442  }
2443  repl_val[Anum_pg_extension_extconfig - 1] = PointerGetDatum(a);
2444  repl_repl[Anum_pg_extension_extconfig - 1] = true;
2445 
2446  /* Build or modify the extcondition value */
2447  elementDatum = PointerGetDatum(wherecond);
2448 
2449  arrayDatum = heap_getattr(extTup, Anum_pg_extension_extcondition,
2450  RelationGetDescr(extRel), &isnull);
2451  if (isnull)
2452  {
2453  if (arrayLength != 0)
2454  elog(ERROR, "extconfig and extcondition arrays do not match");
2455 
2456  a = construct_array(&elementDatum, 1,
2457  TEXTOID,
2458  -1, false, 'i');
2459  }
2460  else
2461  {
2462  a = DatumGetArrayTypeP(arrayDatum);
2463 
2464  if (ARR_NDIM(a) != 1 ||
2465  ARR_LBOUND(a)[0] != 1 ||
2466  ARR_HASNULL(a) ||
2467  ARR_ELEMTYPE(a) != TEXTOID)
2468  elog(ERROR, "extcondition is not a 1-D text array");
2469  if (ARR_DIMS(a)[0] != arrayLength)
2470  elog(ERROR, "extconfig and extcondition arrays do not match");
2471 
2472  /* Add or replace at same index as in extconfig */
2473  a = array_set(a, 1, &arrayIndex,
2474  elementDatum,
2475  false,
2476  -1 /* varlena array */ ,
2477  -1 /* TEXT's typlen */ ,
2478  false /* TEXT's typbyval */ ,
2479  'i' /* TEXT's typalign */ );
2480  }
2482  repl_repl[Anum_pg_extension_extcondition - 1] = true;
2483 
2484  extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
2485  repl_val, repl_null, repl_repl);
2486 
2487  CatalogTupleUpdate(extRel, &extTup->t_self, extTup);
2488 
2489  systable_endscan(extScan);
2490 
2491  heap_close(extRel, RowExclusiveLock);
2492 
2493  PG_RETURN_VOID();
2494 }
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:1287
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:793
char * get_rel_name(Oid relid)
Definition: lsyscache.c:1694
#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 2203 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.

2204 {
2205  Name extname = PG_GETARG_NAME(0);
2206  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
2207  TupleDesc tupdesc;
2208  Tuplestorestate *tupstore;
2209  MemoryContext per_query_ctx;
2210  MemoryContext oldcontext;
2211  List *evi_list;
2212  ExtensionControlFile *control;
2213  ListCell *lc1;
2214 
2215  /* Check extension name validity before any filesystem access */
2217 
2218  /* check to see if caller supports us returning a tuplestore */
2219  if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
2220  ereport(ERROR,
2221  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2222  errmsg("set-valued function called in context that cannot accept a set")));
2223  if (!(rsinfo->allowedModes & SFRM_Materialize))
2224  ereport(ERROR,
2225  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2226  errmsg("materialize mode required, but it is not " \
2227  "allowed in this context")));
2228 
2229  /* Build a tuple descriptor for our result type */
2230  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
2231  elog(ERROR, "return type must be a row type");
2232 
2233  /* Build tuplestore to hold the result rows */
2234  per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
2235  oldcontext = MemoryContextSwitchTo(per_query_ctx);
2236 
2237  tupstore = tuplestore_begin_heap(true, false, work_mem);
2238  rsinfo->returnMode = SFRM_Materialize;
2239  rsinfo->setResult = tupstore;
2240  rsinfo->setDesc = tupdesc;
2241 
2242  MemoryContextSwitchTo(oldcontext);
2243 
2244  /* Read the extension's control file */
2245  control = read_extension_control_file(NameStr(*extname));
2246 
2247  /* Extract the version update graph from the script directory */
2248  evi_list = get_ext_ver_list(control);
2249 
2250  /* Iterate over all pairs of versions */
2251  foreach(lc1, evi_list)
2252  {
2254  ListCell *lc2;
2255 
2256  foreach(lc2, evi_list)
2257  {
2259  List *path;
2260  Datum values[3];
2261  bool nulls[3];
2262 
2263  if (evi1 == evi2)
2264  continue;
2265 
2266  /* Find shortest path from evi1 to evi2 */
2267  path = find_update_path(evi_list, evi1, evi2, false, true);
2268 
2269  /* Emit result row */
2270  memset(values, 0, sizeof(values));
2271  memset(nulls, 0, sizeof(nulls));
2272 
2273  /* source */
2274  values[0] = CStringGetTextDatum(evi1->name);
2275  /* target */
2276  values[1] = CStringGetTextDatum(evi2->name);
2277  /* path */
2278  if (path == NIL)
2279  nulls[2] = true;
2280  else
2281  {
2282  StringInfoData pathbuf;
2283  ListCell *lcv;
2284 
2285  initStringInfo(&pathbuf);
2286  /* The path doesn't include start vertex, but show it */
2287  appendStringInfoString(&pathbuf, evi1->name);
2288  foreach(lcv, path)
2289  {
2290  char *versionName = (char *) lfirst(lcv);
2291 
2292  appendStringInfoString(&pathbuf, "--");
2293  appendStringInfoString(&pathbuf, versionName);
2294  }
2295  values[2] = CStringGetTextDatum(pathbuf.data);
2296  pfree(pathbuf.data);
2297  }
2298 
2299  tuplestore_putvalues(tupstore, tupdesc, values, nulls);
2300  }
2301  }
2302 
2303  /* clean up and return the tuplestore */
2304  tuplestore_donestoring(tupstore);
2305 
2306  return (Datum) 0;
2307 }
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, Datum *values, bool *isnull)
Definition: tuplestore.c:735
#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:1113
#define IsA(nodeptr, _type_)
Definition: nodes.h:557
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:1007
#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:189
#define ereport(elevel, rest)
Definition: elog.h:122
void initStringInfo(StringInfo str)
Definition: stringinfo.c:65
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:316
uintptr_t Datum
Definition: postgres.h:372
int work_mem
Definition: globals.c:112
int allowedModes
Definition: execnodes.h:267
SetFunctionReturnMode returnMode
Definition: execnodes.h:269
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:201
Tuplestorestate * setResult
Definition: execnodes.h:272
static Datum values[MAXATTR]
Definition: bootstrap.c:162
ExprContext * econtext
Definition: execnodes.h:265
TupleDesc setDesc
Definition: execnodes.h:273
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:3302
int GetDatabaseEncoding(void)
Definition: mbutils.c:1015
static char * filename
Definition: pg_dumpall.c:87
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 3302 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().

3303 {
3304  char *buf;
3305  FILE *file;
3306  size_t bytes_to_read;
3307  struct stat fst;
3308 
3309  if (stat(filename, &fst) < 0)
3310  ereport(ERROR,
3312  errmsg("could not stat file \"%s\": %m", filename)));
3313 
3314  if (fst.st_size > (MaxAllocSize - 1))
3315  ereport(ERROR,
3316  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3317  errmsg("file \"%s\" is too large", filename)));
3318  bytes_to_read = (size_t) fst.st_size;
3319 
3320  if ((file = AllocateFile(filename, PG_BINARY_R)) == NULL)
3321  ereport(ERROR,
3323  errmsg("could not open file \"%s\" for reading: %m",
3324  filename)));
3325 
3326  buf = (char *) palloc(bytes_to_read + 1);
3327 
3328  *length = fread(buf, 1, bytes_to_read, file);
3329 
3330  if (ferror(file))
3331  ereport(ERROR,
3333  errmsg("could not read file \"%s\": %m", filename)));
3334 
3335  FreeFile(file);
3336 
3337  buf[*length] = '\0';
3338  return buf;
3339 }
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:65
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:87
void * palloc(Size size)
Definition: mcxt.c:849
int errmsg(const char *fmt,...)
Definition: elog.c:797
void RemoveExtensionById ( Oid  extId)

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

1821 {
1822  Relation rel;
1823  SysScanDesc scandesc;
1824  HeapTuple tuple;
1825  ScanKeyData entry[1];
1826 
1827  /*
1828  * Disallow deletion of any extension that's currently open for insertion;
1829  * else subsequent executions of recordDependencyOnCurrentExtension()
1830  * could create dangling pg_depend records that refer to a no-longer-valid
1831  * pg_extension OID. This is needed not so much because we think people
1832  * might write "DROP EXTENSION foo" in foo's own script files, as because
1833  * errors in dependency management in extension script files could give
1834  * rise to cases where an extension is dropped as a result of recursing
1835  * from some contained object. Because of that, we must test for the case
1836  * here, not at some higher level of the DROP EXTENSION command.
1837  */
1838  if (extId == CurrentExtensionObject)
1839  ereport(ERROR,
1840  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1841  errmsg("cannot drop extension \"%s\" because it is being modified",
1842  get_extension_name(extId))));
1843 
1845 
1846  ScanKeyInit(&entry[0],
1848  BTEqualStrategyNumber, F_OIDEQ,
1849  ObjectIdGetDatum(extId));
1850  scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
1851  NULL, 1, entry);
1852 
1853  tuple = systable_getnext(scandesc);
1854 
1855  /* We assume that there can be at most one matching tuple */
1856  if (HeapTupleIsValid(tuple))
1857  CatalogTupleDelete(rel, &tuple->t_self);
1858 
1859  systable_endscan(scandesc);
1860 
1862 }
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:1287
#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