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 (List *names, 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 ( List names,
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, linitial, list_length(), LookupCreationNamespace(), NamespaceRelationId, NameStr, new_object_addresses(), NULL, ObjectAddressSet, ObjectAddress::objectId, ObjectIdAttributeNumber, ObjectIdGetDatum, ObjectAddress::objectSubId, pg_extension_ownercheck(), pg_namespace_aclcheck(), relation_close(), RowExclusiveLock, ScanKeyInit(), strVal, systable_beginscan(), systable_endscan(), systable_getnext(), and HeapTupleData::t_self.

Referenced by ExecAlterObjectSchemaStmt().

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

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

3020 {
3021  const char *oldVersionName = initialVersion;
3022  ListCell *lcv;
3023 
3024  foreach(lcv, updateVersions)
3025  {
3026  char *versionName = (char *) lfirst(lcv);
3027  ExtensionControlFile *control;
3028  char *schemaName;
3029  Oid schemaOid;
3030  List *requiredExtensions;
3031  List *requiredSchemas;
3032  Relation extRel;
3033  ScanKeyData key[1];
3034  SysScanDesc extScan;
3035  HeapTuple extTup;
3036  Form_pg_extension extForm;
3038  bool nulls[Natts_pg_extension];
3039  bool repl[Natts_pg_extension];
3040  ObjectAddress myself;
3041  ListCell *lc;
3042 
3043  /*
3044  * Fetch parameters for specific version (pcontrol is not changed)
3045  */
3046  control = read_extension_aux_control_file(pcontrol, versionName);
3047 
3048  /* Find the pg_extension tuple */
3050 
3051  ScanKeyInit(&key[0],
3053  BTEqualStrategyNumber, F_OIDEQ,
3054  ObjectIdGetDatum(extensionOid));
3055 
3056  extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
3057  NULL, 1, key);
3058 
3059  extTup = systable_getnext(extScan);
3060 
3061  if (!HeapTupleIsValid(extTup)) /* should not happen */
3062  elog(ERROR, "extension with oid %u does not exist",
3063  extensionOid);
3064 
3065  extForm = (Form_pg_extension) GETSTRUCT(extTup);
3066 
3067  /*
3068  * Determine the target schema (set by original install)
3069  */
3070  schemaOid = extForm->extnamespace;
3071  schemaName = get_namespace_name(schemaOid);
3072 
3073  /*
3074  * Modify extrelocatable and extversion in the pg_extension tuple
3075  */
3076  memset(values, 0, sizeof(values));
3077  memset(nulls, 0, sizeof(nulls));
3078  memset(repl, 0, sizeof(repl));
3079 
3080  values[Anum_pg_extension_extrelocatable - 1] =
3081  BoolGetDatum(control->relocatable);
3082  repl[Anum_pg_extension_extrelocatable - 1] = true;
3083  values[Anum_pg_extension_extversion - 1] =
3084  CStringGetTextDatum(versionName);
3085  repl[Anum_pg_extension_extversion - 1] = true;
3086 
3087  extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
3088  values, nulls, repl);
3089 
3090  CatalogTupleUpdate(extRel, &extTup->t_self, extTup);
3091 
3092  systable_endscan(extScan);
3093 
3094  heap_close(extRel, RowExclusiveLock);
3095 
3096  /*
3097  * Look up the prerequisite extensions for this version, install them
3098  * if necessary, and build lists of their OIDs and the OIDs of their
3099  * target schemas.
3100  */
3101  requiredExtensions = NIL;
3102  requiredSchemas = NIL;
3103  foreach(lc, control->requires)
3104  {
3105  char *curreq = (char *) lfirst(lc);
3106  Oid reqext;
3107  Oid reqschema;
3108 
3109  reqext = get_required_extension(curreq,
3110  control->name,
3111  origSchemaName,
3112  cascade,
3113  NIL,
3114  is_create);
3115  reqschema = get_extension_schema(reqext);
3116  requiredExtensions = lappend_oid(requiredExtensions, reqext);
3117  requiredSchemas = lappend_oid(requiredSchemas, reqschema);
3118  }
3119 
3120  /*
3121  * Remove and recreate dependencies on prerequisite extensions
3122  */
3126 
3127  myself.classId = ExtensionRelationId;
3128  myself.objectId = extensionOid;
3129  myself.objectSubId = 0;
3130 
3131  foreach(lc, requiredExtensions)
3132  {
3133  Oid reqext = lfirst_oid(lc);
3134  ObjectAddress otherext;
3135 
3136  otherext.classId = ExtensionRelationId;
3137  otherext.objectId = reqext;
3138  otherext.objectSubId = 0;
3139 
3140  recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
3141  }
3142 
3144 
3145  /*
3146  * Finally, execute the update script file
3147  */
3148  execute_extension_script(extensionOid, control,
3149  oldVersionName, versionName,
3150  requiredSchemas,
3151  schemaName, schemaOid);
3152 
3153  /*
3154  * Update prior-version name and loop around. Since
3155  * execute_sql_string did a final CommandCounterIncrement, we can
3156  * update the pg_extension row again.
3157  */
3158  oldVersionName = versionName;
3159  }
3160 }
#define NIL
Definition: pg_list.h:69
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:493
#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:425
#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:322
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:410
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:515
#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:312
FormData_pg_extension * Form_pg_extension
Definition: pg_extension.h:51
uintptr_t Datum
Definition: postgres.h:374
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:410
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:226
#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:90
#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:226
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:226
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:564
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:555
#define NAMEDATALEN
#define CStringGetDatum(X)
Definition: postgres.h:586
uintptr_t Datum
Definition: postgres.h:374
#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:891
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:678
#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:226
#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:675
#define elog
Definition: elog.h:219
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:34
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:2839
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:564
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:3013
int errcode(int sqlerrcode)
Definition: elog.c:575
void CreateComments(Oid oid, Oid classoid, int32 subid, char *comment)
Definition: comment.c:142
unsigned int Oid
Definition: postgres_ext.h:31
List * lappend_oid(List *list, Oid datum)
Definition: list.c:164
#define OidIsValid(objectId)
Definition: c.h:534
RoleSpec * authrole
Definition: parsenodes.h:1583
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:556
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:671
#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:84
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:4018
List * list_delete_first(List *list)
Definition: list.c:666
ObjectAddress ExecAlterExtensionContentsStmt ( AlterExtensionContentsStmt stmt,
ObjectAddress objAddr 
)

Definition at line 3171 of file extension.c.

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

Referenced by ProcessUtilitySlow().

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

Definition at line 2863 of file extension.c.

References AccessShareLock, ACL_KIND_EXTENSION, aclcheck_error(), ACLCHECK_NOT_OWNER, Anum_pg_extension_extname, Anum_pg_extension_extversion, ApplyExtensionUpdates(), DefElem::arg, BTEqualStrategyNumber, check_valid_version_name(), creating_extension, CStringGetDatum, DatumGetTextPP, ExtensionControlFile::default_version, DefElem::defname, elog, ereport, errcode(), errmsg(), ERROR, ExtensionNameIndexId, ExtensionRelationId, AlterExtensionStmt::extname, GetUserId(), heap_close, heap_getattr, heap_open(), HeapTupleGetOid, HeapTupleIsValid, identify_update_path(), InvalidObjectAddress, lfirst, DefElem::location, NOTICE, 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().

2864 {
2865  DefElem *d_new_version = NULL;
2866  char *versionName;
2867  char *oldVersionName;
2868  ExtensionControlFile *control;
2869  Oid extensionOid;
2870  Relation extRel;
2871  ScanKeyData key[1];
2872  SysScanDesc extScan;
2873  HeapTuple extTup;
2874  List *updateVersions;
2875  Datum datum;
2876  bool isnull;
2877  ListCell *lc;
2878  ObjectAddress address;
2879 
2880  /*
2881  * We use global variables to track the extension being created, so we can
2882  * create/update only one extension at the same time.
2883  */
2884  if (creating_extension)
2885  ereport(ERROR,
2886  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2887  errmsg("nested ALTER EXTENSION is not supported")));
2888 
2889  /*
2890  * Look up the extension --- it must already exist in pg_extension
2891  */
2893 
2894  ScanKeyInit(&key[0],
2896  BTEqualStrategyNumber, F_NAMEEQ,
2897  CStringGetDatum(stmt->extname));
2898 
2899  extScan = systable_beginscan(extRel, ExtensionNameIndexId, true,
2900  NULL, 1, key);
2901 
2902  extTup = systable_getnext(extScan);
2903 
2904  if (!HeapTupleIsValid(extTup))
2905  ereport(ERROR,
2906  (errcode(ERRCODE_UNDEFINED_OBJECT),
2907  errmsg("extension \"%s\" does not exist",
2908  stmt->extname)));
2909 
2910  extensionOid = HeapTupleGetOid(extTup);
2911 
2912  /*
2913  * Determine the existing version we are updating from
2914  */
2916  RelationGetDescr(extRel), &isnull);
2917  if (isnull)
2918  elog(ERROR, "extversion is null");
2919  oldVersionName = text_to_cstring(DatumGetTextPP(datum));
2920 
2921  systable_endscan(extScan);
2922 
2923  heap_close(extRel, AccessShareLock);
2924 
2925  /* Permission check: must own extension */
2926  if (!pg_extension_ownercheck(extensionOid, GetUserId()))
2928  stmt->extname);
2929 
2930  /*
2931  * Read the primary control file. Note we assume that it does not contain
2932  * any non-ASCII data, so there is no need to worry about encoding at this
2933  * point.
2934  */
2935  control = read_extension_control_file(stmt->extname);
2936 
2937  /*
2938  * Read the statement option list
2939  */
2940  foreach(lc, stmt->options)
2941  {
2942  DefElem *defel = (DefElem *) lfirst(lc);
2943 
2944  if (strcmp(defel->defname, "new_version") == 0)
2945  {
2946  if (d_new_version)
2947  ereport(ERROR,
2948  (errcode(ERRCODE_SYNTAX_ERROR),
2949  errmsg("conflicting or redundant options"),
2950  parser_errposition(pstate, defel->location)));
2951  d_new_version = defel;
2952  }
2953  else
2954  elog(ERROR, "unrecognized option: %s", defel->defname);
2955  }
2956 
2957  /*
2958  * Determine the version to update to
2959  */
2960  if (d_new_version && d_new_version->arg)
2961  versionName = strVal(d_new_version->arg);
2962  else if (control->default_version)
2963  versionName = control->default_version;
2964  else
2965  {
2966  ereport(ERROR,
2967  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2968  errmsg("version to install must be specified")));
2969  versionName = NULL; /* keep compiler quiet */
2970  }
2971  check_valid_version_name(versionName);
2972 
2973  /*
2974  * If we're already at that version, just say so
2975  */
2976  if (strcmp(oldVersionName, versionName) == 0)
2977  {
2978  ereport(NOTICE,
2979  (errmsg("version \"%s\" of extension \"%s\" is already installed",
2980  versionName, stmt->extname)));
2981  return InvalidObjectAddress;
2982  }
2983 
2984  /*
2985  * Identify the series of update script files we need to execute
2986  */
2987  updateVersions = identify_update_path(control,
2988  oldVersionName,
2989  versionName);
2990 
2991  /*
2992  * Update the pg_extension row and execute the update scripts, one at a
2993  * time
2994  */
2995  ApplyExtensionUpdates(extensionOid, control,
2996  oldVersionName, updateVersions,
2997  NULL, false, false);
2998 
2999  ObjectAddressSet(address, ExtensionRelationId, extensionOid);
3000 
3001  return address;
3002 }
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:493
#define ExtensionNameIndexId
Definition: indexing.h:314
static ExtensionControlFile * read_extension_control_file(const char *extname)
Definition: extension.c:602
#define RelationGetDescr(relation)
Definition: rel.h:425
Oid GetUserId(void)
Definition: miscinit.c:283
#define Anum_pg_extension_extversion
Definition: pg_extension.h:63
#define DatumGetTextPP(X)
Definition: fmgr.h:249
static void ApplyExtensionUpdates(Oid extensionOid, ExtensionControlFile *pcontrol, const char *initialVersion, List *updateVersions, char *origSchemaName, bool cascade, bool is_create)
Definition: extension.c:3013
#define AccessShareLock
Definition: lockdefs.h:36
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:575
#define heap_close(r, l)
Definition: heapam.h:97
unsigned int Oid
Definition: postgres_ext.h:31
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:322
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:410
#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:5017
void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, const char *objectname)
Definition: aclchk.c:3378
int location
Definition: parsenodes.h:678
#define CStringGetDatum(X)
Definition: postgres.h:586
#define ereport(elevel, rest)
Definition: elog.h:122
Node * arg
Definition: parsenodes.h:676
#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:374
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:226
#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:184
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:675
#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:9968
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:3554
Datum DirectFunctionCall4Coll(PGFunction func, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4)
Definition: fmgr.c:1083
#define DatumGetTextPP(X)
Definition: fmgr.h:249
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:5036
#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:559
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:374
int log_min_messages
Definition: guc.c:453
#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:226
#define PG_RE_THROW()
Definition: elog.h:314
#define C_COLLATION_OID
Definition: pg_collation.h:71
char * text_to_cstring(const text *t)
Definition: varlena.c:184
int NewGUCNestLevel(void)
Definition: guc.c:5022
static char * filename
Definition: pg_dumpall.c:84
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define CStringGetTextDatum(s)
Definition: builtins.h:90
int client_min_messages
Definition: guc.c:454
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:5865
#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);
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:559
#define castNode(_type_, nodeptr)
Definition: nodes.h:577
void FreeQueryDesc(QueryDesc *qdesc)
Definition: pquery.c:100
void ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:138
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:834
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count)
Definition: execMain.c:285
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:439
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
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:80
#define ereport(elevel, rest)
Definition: elog.h:122
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:379
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:921
#define NULL
Definition: c.h:226
#define lfirst(lc)
Definition: pg_list.h:106
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2528
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:493
#define RelationGetDescr(relation)
Definition: rel.h:425
#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:564
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:322
#define ARR_LBOUND(a)
Definition: array.h:277
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:410
#define ObjectIdGetDatum(X)
Definition: postgres.h:515
#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:312
#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:374
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1287
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:226
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:226
#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, and ExtensionVersionInfo::reachable.

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
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:226
#define Assert(condition)
Definition: c.h:671
#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:555
static ExtensionControlFile * read_extension_aux_control_file(const ExtensionControlFile *pcontrol, const char *version)
Definition: extension.c:630
#define CStringGetDatum(X)
Definition: postgres.h:586
static ExtensionVersionInfo * find_install_path(List *evi_list, ExtensionVersionInfo *evi_target, List **best_path)
Definition: extension.c:1206
uintptr_t Datum
Definition: postgres.h:374
#define BoolGetDatum(X)
Definition: postgres.h:410
#define NULL
Definition: c.h:226
#define lfirst(lc)
Definition: pg_list.h:106
static Datum values[MAXATTR]
Definition: bootstrap.c:162
#define CStringGetTextDatum(s)
Definition: builtins.h:90
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:1165
struct ExtensionVersionInfo * previous
Definition: extension.c:98
List * lappend(List *list, void *datum)
Definition: list.c:128
#define NULL
Definition: c.h:226
#define lfirst(lc)
Definition: pg_list.h:106
void * palloc(Size size)
Definition: mcxt.c:891
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:1165
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:2284
List * lappend(List *list, void *datum)
Definition: list.c:128
#define NULL
Definition: c.h:226
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2350
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:2393
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(), 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 }
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:992
#define MAXPGPATH
void * palloc(Size size)
Definition: mcxt.c:891
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(), 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 }
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:891
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(), 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 }
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:891
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(), 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:493
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define ObjectIdAttributeNumber
Definition: sysattr.h:22
char * pstrdup(const char *in)
Definition: mcxt.c:1165
#define AccessShareLock
Definition: lockdefs.h:36
#define heap_close(r, l)
Definition: heapam.h:97
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:322
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:410
#define ObjectIdGetDatum(X)
Definition: postgres.h:515
#define ExtensionOidIndexId
Definition: indexing.h:312
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:226
#define NameStr(name)
Definition: c.h:495
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, 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:493
#define ExtensionNameIndexId
Definition: indexing.h:314
#define AccessShareLock
Definition: lockdefs.h:36
int errcode(int sqlerrcode)
Definition: elog.c:575
#define heap_close(r, l)
Definition: heapam.h:97
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:534
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:322
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:410
#define ERROR
Definition: elog.h:43
#define Anum_pg_extension_extname
Definition: pg_extension.h:59
#define CStringGetDatum(X)
Definition: postgres.h:586
#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:226
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, 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:493
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
#define ObjectIdAttributeNumber
Definition: sysattr.h:22
#define AccessShareLock
Definition: lockdefs.h:36
#define heap_close(r, l)
Definition: heapam.h:97
unsigned int Oid
Definition: postgres_ext.h:31
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:322
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:410
#define ObjectIdGetDatum(X)
Definition: postgres.h:515
#define ExtensionOidIndexId
Definition: indexing.h:312
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:226
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(), 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:1165
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:891
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(), 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 }
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:992
#define MAXPGPATH
void * palloc(Size size)
Definition: mcxt.c:891
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:226
#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:534
#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:226
#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, and NIL.

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
#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:564
#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:555
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:158
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1374
unsigned int Oid
Definition: postgres_ext.h:31
#define ObjectIdGetDatum(X)
Definition: postgres.h:515
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:586
#define Anum_pg_extension_extcondition
Definition: pg_extension.h:65
uintptr_t Datum
Definition: postgres.h:374
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1287
TupleDesc rd_att
Definition: rel.h:114
#define BoolGetDatum(X)
Definition: postgres.h:410
#define Anum_pg_extension_extowner
Definition: pg_extension.h:60
#define NULL
Definition: c.h:226
static Datum values[MAXATTR]
Definition: bootstrap.c:162
#define Natts_pg_extension
Definition: pg_extension.h:58
#define CStringGetTextDatum(s)
Definition: builtins.h:90
#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:226
static char * filename
Definition: pg_dumpall.c:84
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:226
static char * filename
Definition: pg_dumpall.c:84
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:425
char * pstrdup(const char *in)
Definition: mcxt.c:1165
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:992
#define ERROR
Definition: elog.h:43
bool SplitIdentifierString(char *rawstring, char separator, List **namelist)
Definition: varlena.c:3129
int errcode_for_file_access(void)
Definition: elog.c:598
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2043
#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:226
int FreeFile(FILE *file)
Definition: fd.c:2226
static char * filename
Definition: pg_dumpall.c:84
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:559
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:1165
#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:2284
#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:374
int work_mem
Definition: globals.c:112
int allowedModes
Definition: execnodes.h:199
SetFunctionReturnMode returnMode
Definition: execnodes.h:201
#define NULL
Definition: c.h:226
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2350
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:133
Tuplestorestate * setResult
Definition: execnodes.h:204
ExprContext * econtext
Definition: execnodes.h:197
TupleDesc setDesc
Definition: execnodes.h:205
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define elog
Definition: elog.h:219
int FreeDir(DIR *dir)
Definition: fd.c:2393
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:559
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:1165
#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:555
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:586
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2284
#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:374
int work_mem
Definition: globals.c:112
int allowedModes
Definition: execnodes.h:199
SetFunctionReturnMode returnMode
Definition: execnodes.h:201
#define NULL
Definition: c.h:226
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2350
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:133
Tuplestorestate * setResult
Definition: execnodes.h:204
static Datum values[MAXATTR]
Definition: bootstrap.c:162
ExprContext * econtext
Definition: execnodes.h:197
TupleDesc setDesc
Definition: execnodes.h:205
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define CStringGetTextDatum(s)
Definition: builtins.h:90
#define elog
Definition: elog.h:219
int FreeDir(DIR *dir)
Definition: fd.c:2393
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_P, 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_P(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:493
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:61
#define RelationGetDescr(relation)
Definition: rel.h:425
#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:564
#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:322
#define ARR_LBOUND(a)
Definition: array.h:277
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:410
#define ObjectIdGetDatum(X)
Definition: postgres.h:515
#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:231
#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:312
#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:374
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:293
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:226
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 PG_GETARG_TEXT_P(n)
Definition: fmgr.h:269
#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:435
#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:559
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:992
#define ERROR
Definition: elog.h:43
Definition: c.h:489
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:374
int work_mem
Definition: globals.c:112
int allowedModes
Definition: execnodes.h:199
SetFunctionReturnMode returnMode
Definition: execnodes.h:201
#define NULL
Definition: c.h:226
#define lfirst(lc)
Definition: pg_list.h:106
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:133
Tuplestorestate * setResult
Definition: execnodes.h:204
static Datum values[MAXATTR]
Definition: bootstrap.c:162
ExprContext * econtext
Definition: execnodes.h:197
TupleDesc setDesc
Definition: execnodes.h:205
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define NameStr(name)
Definition: c.h:495
#define CStringGetTextDatum(s)
Definition: builtins.h:90
#define elog
Definition: elog.h:219
Definition: pg_list.h:45
#define PG_GETARG_NAME(n)
Definition: fmgr.h:234
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:891
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:1165
static void parse_extension_control_file(ExtensionControlFile *control, const char *version)
Definition: extension.c:465
void * palloc0(Size size)
Definition: mcxt.c:920
#define NULL
Definition: c.h:226
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:3309
int GetDatabaseEncoding(void)
Definition: mbutils.c:1015
static char * filename
Definition: pg_dumpall.c:84
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 3309 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().

3310 {
3311  char *buf;
3312  FILE *file;
3313  size_t bytes_to_read;
3314  struct stat fst;
3315 
3316  if (stat(filename, &fst) < 0)
3317  ereport(ERROR,
3319  errmsg("could not stat file \"%s\": %m", filename)));
3320 
3321  if (fst.st_size > (MaxAllocSize - 1))
3322  ereport(ERROR,
3323  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3324  errmsg("file \"%s\" is too large", filename)));
3325  bytes_to_read = (size_t) fst.st_size;
3326 
3327  if ((file = AllocateFile(filename, PG_BINARY_R)) == NULL)
3328  ereport(ERROR,
3330  errmsg("could not open file \"%s\" for reading: %m",
3331  filename)));
3332 
3333  buf = (char *) palloc(bytes_to_read + 1);
3334 
3335  *length = fread(buf, 1, bytes_to_read, file);
3336 
3337  if (ferror(file))
3338  ereport(ERROR,
3340  errmsg("could not read file \"%s\": %m", filename)));
3341 
3342  FreeFile(file);
3343 
3344  buf[*length] = '\0';
3345  return buf;
3346 }
int length(const List *list)
Definition: list.c:1271
int errcode(int sqlerrcode)
Definition: elog.c:575
#define PG_BINARY_R
Definition: c.h: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:2043
#define ereport(elevel, rest)
Definition: elog.h:122
#define MaxAllocSize
Definition: memutils.h:40
#define NULL
Definition: c.h:226
int FreeFile(FILE *file)
Definition: fd.c:2226
static char * filename
Definition: pg_dumpall.c:84
void * palloc(Size size)
Definition: mcxt.c:891
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:493
#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:322
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:410
#define ObjectIdGetDatum(X)
Definition: postgres.h:515
#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:312
Relation heap_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1287
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:226
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