LCOV - differential code coverage report
Current view: top level - src/backend/commands - extension.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DUB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 80.4 % 1033 831 5 34 137 26 38 562 33 198 130 594 8 5
Current Date: 2023-04-08 17:13:01 Functions: 95.3 % 43 41 2 41 2 41
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 [..60] days: 95.5 % 22 21 1 21
Legend: Lines: hit not hit (120,180] days: 88.9 % 9 8 1 1 1 6
(240..) days: 80.0 % 1002 802 4 34 136 26 37 561 6 198 126 576
Function coverage date bins:
(240..) days: 48.2 % 85 41 2 41 2 40

 Age         Owner                  TLA  Line data    Source code
                                  1                 : /*-------------------------------------------------------------------------
                                  2                 :  *
                                  3                 :  * extension.c
                                  4                 :  *    Commands to manipulate extensions
                                  5                 :  *
                                  6                 :  * Extensions in PostgreSQL allow management of collections of SQL objects.
                                  7                 :  *
                                  8                 :  * All we need internally to manage an extension is an OID so that the
                                  9                 :  * dependent objects can be associated with it.  An extension is created by
                                 10                 :  * populating the pg_extension catalog from a "control" file.
                                 11                 :  * The extension control file is parsed with the same parser we use for
                                 12                 :  * postgresql.conf.  An extension also has an installation script file,
                                 13                 :  * containing SQL commands to create the extension's objects.
                                 14                 :  *
                                 15                 :  * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
                                 16                 :  * Portions Copyright (c) 1994, Regents of the University of California
                                 17                 :  *
                                 18                 :  *
                                 19                 :  * IDENTIFICATION
                                 20                 :  *    src/backend/commands/extension.c
                                 21                 :  *
                                 22                 :  *-------------------------------------------------------------------------
                                 23                 :  */
                                 24                 : #include "postgres.h"
                                 25                 : 
                                 26                 : #include <dirent.h>
                                 27                 : #include <limits.h>
                                 28                 : #include <sys/file.h>
                                 29                 : #include <sys/stat.h>
                                 30                 : #include <unistd.h>
                                 31                 : 
                                 32                 : #include "access/genam.h"
                                 33                 : #include "access/htup_details.h"
                                 34                 : #include "access/relation.h"
                                 35                 : #include "access/sysattr.h"
                                 36                 : #include "access/table.h"
                                 37                 : #include "access/xact.h"
                                 38                 : #include "catalog/catalog.h"
                                 39                 : #include "catalog/dependency.h"
                                 40                 : #include "catalog/indexing.h"
                                 41                 : #include "catalog/namespace.h"
                                 42                 : #include "catalog/objectaccess.h"
                                 43                 : #include "catalog/pg_authid.h"
                                 44                 : #include "catalog/pg_collation.h"
                                 45                 : #include "catalog/pg_database.h"
                                 46                 : #include "catalog/pg_depend.h"
                                 47                 : #include "catalog/pg_extension.h"
                                 48                 : #include "catalog/pg_namespace.h"
                                 49                 : #include "catalog/pg_type.h"
                                 50                 : #include "commands/alter.h"
                                 51                 : #include "commands/comment.h"
                                 52                 : #include "commands/defrem.h"
                                 53                 : #include "commands/extension.h"
                                 54                 : #include "commands/schemacmds.h"
                                 55                 : #include "funcapi.h"
                                 56                 : #include "mb/pg_wchar.h"
                                 57                 : #include "miscadmin.h"
                                 58                 : #include "nodes/makefuncs.h"
                                 59                 : #include "storage/fd.h"
                                 60                 : #include "tcop/utility.h"
                                 61                 : #include "utils/acl.h"
                                 62                 : #include "utils/builtins.h"
                                 63                 : #include "utils/conffiles.h"
                                 64                 : #include "utils/fmgroids.h"
                                 65                 : #include "utils/lsyscache.h"
                                 66                 : #include "utils/memutils.h"
                                 67                 : #include "utils/rel.h"
                                 68                 : #include "utils/snapmgr.h"
                                 69                 : #include "utils/varlena.h"
                                 70                 : 
                                 71                 : 
                                 72                 : /* Globally visible state variables */
                                 73                 : bool        creating_extension = false;
                                 74                 : Oid         CurrentExtensionObject = InvalidOid;
                                 75                 : 
                                 76                 : /*
                                 77                 :  * Internal data structure to hold the results of parsing a control file
                                 78                 :  */
                                 79                 : typedef struct ExtensionControlFile
                                 80                 : {
                                 81                 :     char       *name;           /* name of the extension */
                                 82                 :     char       *directory;      /* directory for script files */
                                 83                 :     char       *default_version;    /* default install target version, if any */
                                 84                 :     char       *module_pathname;    /* string to substitute for
                                 85                 :                                      * MODULE_PATHNAME */
                                 86                 :     char       *comment;        /* comment, if any */
                                 87                 :     char       *schema;         /* target schema (allowed if !relocatable) */
                                 88                 :     bool        relocatable;    /* is ALTER EXTENSION SET SCHEMA supported? */
                                 89                 :     bool        superuser;      /* must be superuser to install? */
                                 90                 :     bool        trusted;        /* allow becoming superuser on the fly? */
                                 91                 :     int         encoding;       /* encoding of the script file, or -1 */
                                 92                 :     List       *requires;       /* names of prerequisite extensions */
                                 93                 :     List       *no_relocate;    /* names of prerequisite extensions that
                                 94                 :                                  * should not be relocated */
                                 95                 : } ExtensionControlFile;
                                 96                 : 
                                 97                 : /*
                                 98                 :  * Internal data structure for update path information
                                 99                 :  */
                                100                 : typedef struct ExtensionVersionInfo
                                101                 : {
                                102                 :     char       *name;           /* name of the starting version */
                                103                 :     List       *reachable;      /* List of ExtensionVersionInfo's */
                                104                 :     bool        installable;    /* does this version have an install script? */
                                105                 :     /* working state for Dijkstra's algorithm: */
                                106                 :     bool        distance_known; /* is distance from start known yet? */
                                107                 :     int         distance;       /* current worst-case distance estimate */
                                108                 :     struct ExtensionVersionInfo *previous;  /* current best predecessor */
                                109                 : } ExtensionVersionInfo;
                                110                 : 
                                111                 : /* Local functions */
                                112                 : static List *find_update_path(List *evi_list,
                                113                 :                               ExtensionVersionInfo *evi_start,
                                114                 :                               ExtensionVersionInfo *evi_target,
                                115                 :                               bool reject_indirect,
                                116                 :                               bool reinitialize);
                                117                 : static Oid  get_required_extension(char *reqExtensionName,
                                118                 :                                    char *extensionName,
                                119                 :                                    char *origSchemaName,
                                120                 :                                    bool cascade,
                                121                 :                                    List *parents,
                                122                 :                                    bool is_create);
                                123                 : static void get_available_versions_for_extension(ExtensionControlFile *pcontrol,
                                124                 :                                                  Tuplestorestate *tupstore,
                                125                 :                                                  TupleDesc tupdesc);
                                126                 : static Datum convert_requires_to_datum(List *requires);
                                127                 : static void ApplyExtensionUpdates(Oid extensionOid,
                                128                 :                                   ExtensionControlFile *pcontrol,
                                129                 :                                   const char *initialVersion,
                                130                 :                                   List *updateVersions,
                                131                 :                                   char *origSchemaName,
                                132                 :                                   bool cascade,
                                133                 :                                   bool is_create);
                                134                 : static char *read_whole_file(const char *filename, int *length);
                                135                 : 
                                136                 : 
                                137                 : /*
                                138                 :  * get_extension_oid - given an extension name, look up the OID
                                139                 :  *
                                140                 :  * If missing_ok is false, throw an error if extension name not found.  If
                                141                 :  * true, just return InvalidOid.
                                142                 :  */
                                143                 : Oid
 4443 tgl                       144 GIC        1501 : get_extension_oid(const char *extname, bool missing_ok)
                                145                 : {
                                146                 :     Oid         result;
                                147                 :     Relation    rel;
 4443 tgl                       148 ECB             :     SysScanDesc scandesc;
                                149                 :     HeapTuple   tuple;
                                150                 :     ScanKeyData entry[1];
                                151                 : 
 1539 andres                    152 GIC        1501 :     rel = table_open(ExtensionRelationId, AccessShareLock);
                                153                 : 
 4443 tgl                       154            1501 :     ScanKeyInit(&entry[0],
                                155                 :                 Anum_pg_extension_extname,
 4443 tgl                       156 ECB             :                 BTEqualStrategyNumber, F_NAMEEQ,
                                157                 :                 CStringGetDatum(extname));
                                158                 : 
 4443 tgl                       159 GIC        1501 :     scandesc = systable_beginscan(rel, ExtensionNameIndexId, true,
                                160                 :                                   NULL, 1, entry);
                                161                 : 
                                162            1501 :     tuple = systable_getnext(scandesc);
 4443 tgl                       163 ECB             : 
                                164                 :     /* We assume that there can be at most one matching tuple */
 4443 tgl                       165 GIC        1501 :     if (HeapTupleIsValid(tuple))
 1601 andres                    166 CBC        1015 :         result = ((Form_pg_extension) GETSTRUCT(tuple))->oid;
                                167                 :     else
 4443 tgl                       168 GIC         486 :         result = InvalidOid;
 4443 tgl                       169 ECB             : 
 4443 tgl                       170 CBC        1501 :     systable_endscan(scandesc);
                                171                 : 
 1539 andres                    172            1501 :     table_close(rel, AccessShareLock);
                                173                 : 
 4443 tgl                       174            1501 :     if (!OidIsValid(result) && !missing_ok)
 4382 bruce                     175 GIC           6 :         ereport(ERROR,
 4382 bruce                     176 ECB             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
                                177                 :                  errmsg("extension \"%s\" does not exist",
                                178                 :                         extname)));
 4443 tgl                       179                 : 
 4443 tgl                       180 GIC        1495 :     return result;
                                181                 : }
                                182                 : 
                                183                 : /*
 4443 tgl                       184 ECB             :  * get_extension_name - given an extension OID, look up the name
                                185                 :  *
                                186                 :  * Returns a palloc'd string, or NULL if no such extension.
                                187                 :  */
                                188                 : char *
 4443 tgl                       189 GIC          54 : get_extension_name(Oid ext_oid)
                                190                 : {
                                191                 :     char       *result;
                                192                 :     Relation    rel;
 4443 tgl                       193 ECB             :     SysScanDesc scandesc;
                                194                 :     HeapTuple   tuple;
                                195                 :     ScanKeyData entry[1];
                                196                 : 
 1539 andres                    197 GIC          54 :     rel = table_open(ExtensionRelationId, AccessShareLock);
                                198                 : 
 4443 tgl                       199              54 :     ScanKeyInit(&entry[0],
                                200                 :                 Anum_pg_extension_oid,
 4443 tgl                       201 ECB             :                 BTEqualStrategyNumber, F_OIDEQ,
                                202                 :                 ObjectIdGetDatum(ext_oid));
                                203                 : 
 4443 tgl                       204 GIC          54 :     scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
                                205                 :                                   NULL, 1, entry);
                                206                 : 
                                207              54 :     tuple = systable_getnext(scandesc);
 4443 tgl                       208 ECB             : 
                                209                 :     /* We assume that there can be at most one matching tuple */
 4443 tgl                       210 GIC          54 :     if (HeapTupleIsValid(tuple))
 4443 tgl                       211 CBC          45 :         result = pstrdup(NameStr(((Form_pg_extension) GETSTRUCT(tuple))->extname));
                                212                 :     else
 4443 tgl                       213 GIC           9 :         result = NULL;
 4443 tgl                       214 ECB             : 
 4443 tgl                       215 CBC          54 :     systable_endscan(scandesc);
                                216                 : 
 1539 andres                    217              54 :     table_close(rel, AccessShareLock);
                                218                 : 
 4443 tgl                       219              54 :     return result;
                                220                 : }
 4443 tgl                       221 ECB             : 
                                222                 : /*
                                223                 :  * get_extension_schema - given an extension OID, fetch its extnamespace
                                224                 :  *
                                225                 :  * Returns InvalidOid if no such extension.
                                226                 :  */
                                227                 : Oid
 4443 tgl                       228 GIC          26 : get_extension_schema(Oid ext_oid)
                                229                 : {
                                230                 :     Oid         result;
                                231                 :     Relation    rel;
 4443 tgl                       232 ECB             :     SysScanDesc scandesc;
                                233                 :     HeapTuple   tuple;
                                234                 :     ScanKeyData entry[1];
                                235                 : 
 1539 andres                    236 GIC          26 :     rel = table_open(ExtensionRelationId, AccessShareLock);
                                237                 : 
 4443 tgl                       238              26 :     ScanKeyInit(&entry[0],
                                239                 :                 Anum_pg_extension_oid,
 4443 tgl                       240 ECB             :                 BTEqualStrategyNumber, F_OIDEQ,
                                241                 :                 ObjectIdGetDatum(ext_oid));
                                242                 : 
 4443 tgl                       243 GIC          26 :     scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
                                244                 :                                   NULL, 1, entry);
                                245                 : 
                                246              26 :     tuple = systable_getnext(scandesc);
 4443 tgl                       247 ECB             : 
                                248                 :     /* We assume that there can be at most one matching tuple */
 4443 tgl                       249 GIC          26 :     if (HeapTupleIsValid(tuple))
 4443 tgl                       250 CBC          26 :         result = ((Form_pg_extension) GETSTRUCT(tuple))->extnamespace;
                                251                 :     else
 4443 tgl                       252 UIC           0 :         result = InvalidOid;
 4443 tgl                       253 ECB             : 
 4443 tgl                       254 CBC          26 :     systable_endscan(scandesc);
                                255                 : 
 1539 andres                    256 GBC          26 :     table_close(rel, AccessShareLock);
                                257                 : 
 4443 tgl                       258 CBC          26 :     return result;
                                259                 : }
 4443 tgl                       260 ECB             : 
                                261                 : /*
 4440                           262                 :  * Utility functions to check validity of extension and version names
                                263                 :  */
                                264                 : static void
 4440 tgl                       265 GIC         471 : check_valid_extension_name(const char *extensionname)
                                266                 : {
 4438                           267             471 :     int         namelen = strlen(extensionname);
                                268                 : 
 4440 tgl                       269 ECB             :     /*
                                270                 :      * Disallow empty names (the parser rejects empty identifiers anyway, but
 4382 bruce                     271                 :      * let's check).
                                272                 :      */
 4438 tgl                       273 GIC         471 :     if (namelen == 0)
 4438 tgl                       274 UIC           0 :         ereport(ERROR,
                                275                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                276                 :                  errmsg("invalid extension name: \"%s\"", extensionname),
 4438 tgl                       277 ECB             :                  errdetail("Extension names must not be empty.")));
 4438 tgl                       278 EUB             : 
                                279                 :     /*
                                280                 :      * No double dashes, since that would make script filenames ambiguous.
                                281                 :      */
 4438 tgl                       282 GIC         471 :     if (strstr(extensionname, "--"))
 4438 tgl                       283 UIC           0 :         ereport(ERROR,
                                284                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                285                 :                  errmsg("invalid extension name: \"%s\"", extensionname),
 4438 tgl                       286 ECB             :                  errdetail("Extension names must not contain \"--\".")));
 4438 tgl                       287 EUB             : 
                                288                 :     /*
                                289                 :      * No leading or trailing dash either.  (We could probably allow this, but
                                290                 :      * it would require much care in filename parsing and would make filenames
                                291                 :      * visually if not formally ambiguous.  Since there's no real-world use
                                292                 :      * case, let's just forbid it.)
                                293                 :      */
 4438 tgl                       294 GIC         471 :     if (extensionname[0] == '-' || extensionname[namelen - 1] == '-')
 4438 tgl                       295 UIC           0 :         ereport(ERROR,
                                296                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                297                 :                  errmsg("invalid extension name: \"%s\"", extensionname),
 2118 tgl                       298 ECB             :                  errdetail("Extension names must not begin or end with \"-\".")));
 4438 tgl                       299 EUB             : 
                                300                 :     /*
                                301                 :      * No directory separators either (this is sufficient to prevent ".."
                                302                 :      * style attacks).
                                303                 :      */
 4440 tgl                       304 GIC         471 :     if (first_dir_separator(extensionname) != NULL)
 4440 tgl                       305 UIC           0 :         ereport(ERROR,
                                306                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                307                 :                  errmsg("invalid extension name: \"%s\"", extensionname),
 4440 tgl                       308 ECB             :                  errdetail("Extension names must not contain directory separator characters.")));
 4440 tgl                       309 GBC         471 : }
                                310                 : 
                                311                 : static void
 4440 tgl                       312 GIC         480 : check_valid_version_name(const char *versionname)
 4440 tgl                       313 ECB             : {
 4438 tgl                       314 GIC         480 :     int         namelen = strlen(versionname);
                                315                 : 
 4438 tgl                       316 ECB             :     /*
                                317                 :      * Disallow empty names (we could possibly allow this, but there seems
                                318                 :      * little point).
                                319                 :      */
 4438 tgl                       320 GIC         480 :     if (namelen == 0)
 4438 tgl                       321 UIC           0 :         ereport(ERROR,
                                322                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                323                 :                  errmsg("invalid extension version name: \"%s\"", versionname),
 4438 tgl                       324 ECB             :                  errdetail("Version names must not be empty.")));
 4438 tgl                       325 EUB             : 
                                326                 :     /*
                                327                 :      * No double dashes, since that would make script filenames ambiguous.
                                328                 :      */
 4438 tgl                       329 GIC         480 :     if (strstr(versionname, "--"))
 4438 tgl                       330 UIC           0 :         ereport(ERROR,
                                331                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                332                 :                  errmsg("invalid extension version name: \"%s\"", versionname),
 4438 tgl                       333 ECB             :                  errdetail("Version names must not contain \"--\".")));
 4438 tgl                       334 EUB             : 
                                335                 :     /*
                                336                 :      * No leading or trailing dash either.
                                337                 :      */
 4438 tgl                       338 GIC         480 :     if (versionname[0] == '-' || versionname[namelen - 1] == '-')
 4440 tgl                       339 UIC           0 :         ereport(ERROR,
                                340                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                341                 :                  errmsg("invalid extension version name: \"%s\"", versionname),
 2118 tgl                       342 ECB             :                  errdetail("Version names must not begin or end with \"-\".")));
 4438 tgl                       343 EUB             : 
                                344                 :     /*
                                345                 :      * No directory separators either (this is sufficient to prevent ".."
                                346                 :      * style attacks).
                                347                 :      */
 4440 tgl                       348 GIC         480 :     if (first_dir_separator(versionname) != NULL)
 4440 tgl                       349 UIC           0 :         ereport(ERROR,
                                350                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                351                 :                  errmsg("invalid extension version name: \"%s\"", versionname),
 4440 tgl                       352 ECB             :                  errdetail("Version names must not contain directory separator characters.")));
 4440 tgl                       353 GBC         480 : }
                                354                 : 
                                355                 : /*
                                356                 :  * Utility functions to handle extension-related path names
 4443 tgl                       357 ECB             :  */
                                358                 : static bool
 4443 tgl                       359 GIC        3696 : is_extension_control_filename(const char *filename)
                                360                 : {
                                361            3696 :     const char *extension = strrchr(filename, '.');
                                362                 : 
 4443 tgl                       363 CBC        3696 :     return (extension != NULL) && (strcmp(extension, ".control") == 0);
                                364                 : }
 4443 tgl                       365 ECB             : 
                                366                 : static bool
 4440 tgl                       367 CBC      108724 : is_extension_script_filename(const char *filename)
                                368                 : {
 4440 tgl                       369 GIC      108724 :     const char *extension = strrchr(filename, '.');
                                370                 : 
 4440 tgl                       371 CBC      108724 :     return (extension != NULL) && (strcmp(extension, ".sql") == 0);
                                372                 : }
 4440 tgl                       373 ECB             : 
                                374                 : static char *
 4443 tgl                       375 CBC        2576 : get_extension_control_directory(void)
                                376                 : {
                                377                 :     char        sharepath[MAXPGPATH];
                                378                 :     char       *result;
 4443 tgl                       379 ECB             : 
 4443 tgl                       380 GIC        2576 :     get_share_path(my_exec_path, sharepath);
                                381            2576 :     result = (char *) palloc(MAXPGPATH);
 4440                           382            2576 :     snprintf(result, MAXPGPATH, "%s/extension", sharepath);
                                383                 : 
 4443 tgl                       384 CBC        2576 :     return result;
 4443 tgl                       385 ECB             : }
                                386                 : 
                                387                 : static char *
 4443 tgl                       388 CBC        1648 : get_extension_control_filename(const char *extname)
                                389                 : {
                                390                 :     char        sharepath[MAXPGPATH];
                                391                 :     char       *result;
 4443 tgl                       392 ECB             : 
 4443 tgl                       393 GIC        1648 :     get_share_path(my_exec_path, sharepath);
                                394            1648 :     result = (char *) palloc(MAXPGPATH);
 4440                           395            1648 :     snprintf(result, MAXPGPATH, "%s/extension/%s.control",
                                396                 :              sharepath, extname);
 4443 tgl                       397 ECB             : 
 4443 tgl                       398 CBC        1648 :     return result;
 4443 tgl                       399 ECB             : }
                                400                 : 
                                401                 : static char *
 4440 tgl                       402 CBC        2564 : get_extension_script_directory(ExtensionControlFile *control)
                                403                 : {
                                404                 :     char        sharepath[MAXPGPATH];
                                405                 :     char       *result;
 4443 tgl                       406 ECB             : 
                                407                 :     /*
                                408                 :      * The directory parameter can be omitted, absolute, or relative to the
                                409                 :      * installation's share directory.
                                410                 :      */
 4440 tgl                       411 GIC        2564 :     if (!control->directory)
                                412            2564 :         return get_extension_control_directory();
                                413                 : 
 4440 tgl                       414 UIC           0 :     if (is_absolute_path(control->directory))
 4440 tgl                       415 LBC           0 :         return pstrdup(control->directory);
 4443 tgl                       416 ECB             : 
 4443 tgl                       417 UIC           0 :     get_share_path(my_exec_path, sharepath);
 4443 tgl                       418 UBC           0 :     result = (char *) palloc(MAXPGPATH);
 4382 bruce                     419               0 :     snprintf(result, MAXPGPATH, "%s/%s", sharepath, control->directory);
                                420                 : 
 4440 tgl                       421               0 :     return result;
 4440 tgl                       422 EUB             : }
                                423                 : 
                                424                 : static char *
 4440 tgl                       425 GBC        1110 : get_extension_aux_control_filename(ExtensionControlFile *control,
                                426                 :                                    const char *version)
                                427                 : {
                                428                 :     char       *result;
 4440 tgl                       429 ECB             :     char       *scriptdir;
                                430                 : 
 4440 tgl                       431 GIC        1110 :     scriptdir = get_extension_script_directory(control);
                                432                 : 
                                433            1110 :     result = (char *) palloc(MAXPGPATH);
 4438                           434            1110 :     snprintf(result, MAXPGPATH, "%s/%s--%s.control",
 4438 tgl                       435 ECB             :              scriptdir, control->name, version);
                                436                 : 
 4440 tgl                       437 CBC        1110 :     pfree(scriptdir);
 4440 tgl                       438 ECB             : 
 4440 tgl                       439 GIC        1110 :     return result;
                                440                 : }
 4440 tgl                       441 ECB             : 
                                442                 : static char *
 4440 tgl                       443 CBC        1101 : get_extension_script_filename(ExtensionControlFile *control,
                                444                 :                               const char *from_version, const char *version)
                                445                 : {
                                446                 :     char       *result;
 4440 tgl                       447 ECB             :     char       *scriptdir;
                                448                 : 
 4440 tgl                       449 GIC        1101 :     scriptdir = get_extension_script_directory(control);
                                450                 : 
                                451            1101 :     result = (char *) palloc(MAXPGPATH);
                                452            1101 :     if (from_version)
 4438 tgl                       453 CBC         173 :         snprintf(result, MAXPGPATH, "%s/%s--%s--%s.sql",
                                454                 :                  scriptdir, control->name, from_version, version);
 4440 tgl                       455 ECB             :     else
 4438 tgl                       456 CBC         928 :         snprintf(result, MAXPGPATH, "%s/%s--%s.sql",
 4438 tgl                       457 ECB             :                  scriptdir, control->name, version);
                                458                 : 
 4440 tgl                       459 GIC        1101 :     pfree(scriptdir);
 4443 tgl                       460 ECB             : 
 4443 tgl                       461 GIC        1101 :     return result;
                                462                 : }
 4443 tgl                       463 ECB             : 
                                464                 : 
                                465                 : /*
                                466                 :  * Parse contents of primary or auxiliary control file, and fill in
                                467                 :  * fields of *control.  We parse primary file if version == NULL,
                                468                 :  * else the optional auxiliary file for that version.
                                469                 :  *
                                470                 :  * Control files are supposed to be very short, half a dozen lines,
                                471                 :  * so we don't worry about memory allocation risks here.  Also we don't
                                472                 :  * worry about what encoding it's in; all values are expected to be ASCII.
                                473                 :  */
                                474                 : static void
 4440 tgl                       475 GIC        2758 : parse_extension_control_file(ExtensionControlFile *control,
                                476                 :                              const char *version)
                                477                 : {
                                478                 :     char       *filename;
 4443 tgl                       479 ECB             :     FILE       *file;
                                480                 :     ConfigVariable *item,
 4382 bruce                     481 GIC        2758 :                *head = NULL,
                                482            2758 :                *tail = NULL;
                                483                 : 
                                484                 :     /*
 4440 tgl                       485 ECB             :      * Locate the file to read.  Auxiliary files are optional.
 4443                           486                 :      */
 4440 tgl                       487 GIC        2758 :     if (version)
                                488            1110 :         filename = get_extension_aux_control_filename(control, version);
                                489                 :     else
                                490            1648 :         filename = get_extension_control_filename(control->name);
 4440 tgl                       491 ECB             : 
 4443 tgl                       492 CBC        2758 :     if ((file = AllocateFile(filename, "r")) == NULL)
                                493                 :     {
  453                           494            1110 :         if (errno == ENOENT)
                                495                 :         {
  453 tgl                       496 ECB             :             /* no complaint for missing auxiliary file */
  453 tgl                       497 GIC        1110 :             if (version)
  453 tgl                       498 ECB             :             {
  453 tgl                       499 GIC        1110 :                 pfree(filename);
                                500            1110 :                 return;
  453 tgl                       501 ECB             :             }
                                502                 : 
                                503                 :             /* missing control file indicates extension is not installed */
  453 tgl                       504 LBC           0 :             ereport(ERROR,
                                505                 :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                506                 :                      errmsg("extension \"%s\" is not available", control->name),
                                507                 :                      errdetail("Could not open extension control file \"%s\": %m.",
  453 tgl                       508 EUB             :                                filename),
                                509                 :                      errhint("The extension must first be installed on the system where PostgreSQL is running.")));
                                510                 :         }
 4443 tgl                       511 UIC           0 :         ereport(ERROR,
                                512                 :                 (errcode_for_file_access(),
                                513                 :                  errmsg("could not open extension control file \"%s\": %m",
                                514                 :                         filename)));
 4440 tgl                       515 EUB             :     }
                                516                 : 
                                517                 :     /*
                                518                 :      * Parse the file content, using GUC's file parsing code.  We need not
                                519                 :      * check the return value since any errors will be thrown at ERROR level.
                                520                 :      */
  135 michael                   521 GNC        1648 :     (void) ParseConfigFp(file, filename, CONF_FILE_START_DEPTH, ERROR,
                                522                 :                          &head, &tail);
                                523                 : 
 4443 tgl                       524 GIC        1648 :     FreeFile(file);
                                525                 : 
 4443 tgl                       526 ECB             :     /*
                                527                 :      * Convert the ConfigVariable list into ExtensionControlFile entries.
                                528                 :      */
 4443 tgl                       529 CBC        9803 :     for (item = head; item != NULL; item = item->next)
                                530                 :     {
 4440 tgl                       531 GIC        8155 :         if (strcmp(item->name, "directory") == 0)
                                532                 :         {
 4440 tgl                       533 UIC           0 :             if (version)
 4440 tgl                       534 LBC           0 :                 ereport(ERROR,
                                535                 :                         (errcode(ERRCODE_SYNTAX_ERROR),
 4438 tgl                       536 ECB             :                          errmsg("parameter \"%s\" cannot be set in a secondary extension control file",
                                537                 :                                 item->name)));
 4440 tgl                       538 EUB             : 
 4440 tgl                       539 UBC           0 :             control->directory = pstrdup(item->value);
                                540                 :         }
 4440 tgl                       541 GIC        8155 :         else if (strcmp(item->name, "default_version") == 0)
                                542                 :         {
                                543            1648 :             if (version)
 4440 tgl                       544 UBC           0 :                 ereport(ERROR,
                                545                 :                         (errcode(ERRCODE_SYNTAX_ERROR),
 4438 tgl                       546 ECB             :                          errmsg("parameter \"%s\" cannot be set in a secondary extension control file",
                                547                 :                                 item->name)));
 4440                           548                 : 
 4440 tgl                       549 GBC        1648 :             control->default_version = pstrdup(item->value);
                                550                 :         }
 4438 tgl                       551 GIC        6507 :         else if (strcmp(item->name, "module_pathname") == 0)
                                552                 :         {
                                553            1384 :             control->module_pathname = pstrdup(item->value);
 4438 tgl                       554 ECB             :         }
 4443 tgl                       555 GIC        5123 :         else if (strcmp(item->name, "comment") == 0)
 4443 tgl                       556 ECB             :         {
 4443 tgl                       557 GIC        1648 :             control->comment = pstrdup(item->value);
 4443 tgl                       558 ECB             :         }
 4443 tgl                       559 GIC        3475 :         else if (strcmp(item->name, "schema") == 0)
 4443 tgl                       560 ECB             :         {
 4443 tgl                       561 GIC         478 :             control->schema = pstrdup(item->value);
 4443 tgl                       562 ECB             :         }
 4443 tgl                       563 GIC        2997 :         else if (strcmp(item->name, "relocatable") == 0)
 4443 tgl                       564 ECB             :         {
 4443 tgl                       565 GIC        1648 :             if (!parse_bool(item->value, &control->relocatable))
 4443 tgl                       566 LBC           0 :                 ereport(ERROR,
                                567                 :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 4443 tgl                       568 ECB             :                          errmsg("parameter \"%s\" requires a Boolean value",
                                569                 :                                 item->name)));
                                570                 :         }
 4419 tgl                       571 GBC        1349 :         else if (strcmp(item->name, "superuser") == 0)
                                572                 :         {
 4419 tgl                       573 GIC         433 :             if (!parse_bool(item->value, &control->superuser))
 4419 tgl                       574 UIC           0 :                 ereport(ERROR,
                                575                 :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 4419 tgl                       576 ECB             :                          errmsg("parameter \"%s\" requires a Boolean value",
                                577                 :                                 item->name)));
                                578                 :         }
 1166 tgl                       579 GBC         916 :         else if (strcmp(item->name, "trusted") == 0)
                                580                 :         {
 1166 tgl                       581 GIC         669 :             if (!parse_bool(item->value, &control->trusted))
 1166 tgl                       582 UIC           0 :                 ereport(ERROR,
                                583                 :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 1166 tgl                       584 ECB             :                          errmsg("parameter \"%s\" requires a Boolean value",
                                585                 :                                 item->name)));
                                586                 :         }
 4443 tgl                       587 GBC         247 :         else if (strcmp(item->name, "encoding") == 0)
                                588                 :         {
 4443 tgl                       589 UIC           0 :             control->encoding = pg_valid_server_encoding(item->value);
                                590               0 :             if (control->encoding < 0)
                                591               0 :                 ereport(ERROR,
 4443 tgl                       592 ECB             :                         (errcode(ERRCODE_UNDEFINED_OBJECT),
                                593                 :                          errmsg("\"%s\" is not a valid encoding name",
 4443 tgl                       594 EUB             :                                 item->value)));
                                595                 :         }
 4443 tgl                       596 GBC         247 :         else if (strcmp(item->name, "requires") == 0)
                                597                 :         {
                                598                 :             /* Need a modifiable copy of string */
 4443 tgl                       599 GIC         232 :             char       *rawnames = pstrdup(item->value);
                                600                 : 
 4443 tgl                       601 ECB             :             /* Parse string into list of identifiers */
 4443 tgl                       602 GIC         232 :             if (!SplitIdentifierString(rawnames, ',', &control->requires))
                                603                 :             {
 4443 tgl                       604 ECB             :                 /* syntax error in name list */
 4443 tgl                       605 UIC           0 :                 ereport(ERROR,
                                606                 :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 2118 tgl                       607 ECB             :                          errmsg("parameter \"%s\" must be a list of extension names",
                                608                 :                                 item->name)));
                                609                 :             }
 4443 tgl                       610 EUB             :         }
   20 tgl                       611 GNC          15 :         else if (strcmp(item->name, "no_relocate") == 0)
                                612                 :         {
                                613                 :             /* Need a modifiable copy of string */
                                614              15 :             char       *rawnames = pstrdup(item->value);
                                615                 : 
                                616                 :             /* Parse string into list of identifiers */
                                617              15 :             if (!SplitIdentifierString(rawnames, ',', &control->no_relocate))
                                618                 :             {
                                619                 :                 /* syntax error in name list */
   20 tgl                       620 UNC           0 :                 ereport(ERROR,
                                621                 :                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                                622                 :                          errmsg("parameter \"%s\" must be a list of extension names",
                                623                 :                                 item->name)));
                                624                 :             }
                                625                 :         }
                                626                 :         else
 4443 tgl                       627 UIC           0 :             ereport(ERROR,
                                628                 :                     (errcode(ERRCODE_SYNTAX_ERROR),
                                629                 :                      errmsg("unrecognized parameter \"%s\" in file \"%s\"",
                                630                 :                             item->name, filename)));
 4443 tgl                       631 ECB             :     }
                                632                 : 
 4443 tgl                       633 GIC        1648 :     FreeConfigVariables(head);
 4443 tgl                       634 ECB             : 
 4443 tgl                       635 GIC        1648 :     if (control->relocatable && control->schema != NULL)
 4443 tgl                       636 UIC           0 :         ereport(ERROR,
 4443 tgl                       637 ECB             :                 (errcode(ERRCODE_SYNTAX_ERROR),
                                638                 :                  errmsg("parameter \"schema\" cannot be specified when \"relocatable\" is true")));
                                639                 : 
 4440 tgl                       640 GBC        1648 :     pfree(filename);
                                641                 : }
                                642                 : 
                                643                 : /*
                                644                 :  * Read the primary control file for the specified extension.
                                645                 :  */
                                646                 : static ExtensionControlFile *
                                647            1648 : read_extension_control_file(const char *extname)
                                648                 : {
                                649                 :     ExtensionControlFile *control;
                                650                 : 
                                651                 :     /*
                                652                 :      * Set up default values.  Pointer fields are initially null.
 4443 tgl                       653 ECB             :      */
 4440 tgl                       654 GIC        1648 :     control = (ExtensionControlFile *) palloc0(sizeof(ExtensionControlFile));
 4440 tgl                       655 CBC        1648 :     control->name = pstrdup(extname);
 4440 tgl                       656 GBC        1648 :     control->relocatable = false;
 4419 tgl                       657 GIC        1648 :     control->superuser = true;
 1166                           658            1648 :     control->trusted = false;
 4440                           659            1648 :     control->encoding = -1;
 4443 tgl                       660 ECB             : 
                                661                 :     /*
                                662                 :      * Parse the primary control file.
                                663                 :      */
 4440 tgl                       664 GIC        1648 :     parse_extension_control_file(control, NULL);
                                665                 : 
 4443                           666            1648 :     return control;
 4443 tgl                       667 ECB             : }
                                668                 : 
                                669                 : /*
                                670                 :  * Read the auxiliary control file for the specified extension and version.
                                671                 :  *
                                672                 :  * Returns a new modified ExtensionControlFile struct; the original struct
                                673                 :  * (reflecting just the primary control file) is not modified.
 4439                           674                 :  */
                                675                 : static ExtensionControlFile *
 4439 tgl                       676 CBC        1110 : read_extension_aux_control_file(const ExtensionControlFile *pcontrol,
 4439 tgl                       677 ECB             :                                 const char *version)
                                678                 : {
                                679                 :     ExtensionControlFile *acontrol;
                                680                 : 
                                681                 :     /*
                                682                 :      * Flat-copy the struct.  Pointer fields share values with original.
                                683                 :      */
 4439 tgl                       684 CBC        1110 :     acontrol = (ExtensionControlFile *) palloc(sizeof(ExtensionControlFile));
 4439 tgl                       685 GIC        1110 :     memcpy(acontrol, pcontrol, sizeof(ExtensionControlFile));
 4439 tgl                       686 ECB             : 
                                687                 :     /*
                                688                 :      * Parse the auxiliary control file, overwriting struct fields
                                689                 :      */
 4439 tgl                       690 GIC        1110 :     parse_extension_control_file(acontrol, version);
                                691                 : 
                                692            1110 :     return acontrol;
                                693                 : }
                                694                 : 
                                695                 : /*
 4309 peter_e                   696 ECB             :  * Read an SQL script file into a string, and convert to database encoding
                                697                 :  */
                                698                 : static char *
 4443 tgl                       699 GIC         632 : read_extension_script_file(const ExtensionControlFile *control,
                                700                 :                            const char *filename)
                                701                 : {
                                702                 :     int         src_encoding;
                                703                 :     char       *src_str;
 4382 bruce                     704 ECB             :     char       *dest_str;
                                705                 :     int         len;
                                706                 : 
 2842 heikki.linnakangas        707 GIC         632 :     src_str = read_whole_file(filename, &len);
                                708                 : 
                                709                 :     /* use database encoding if not given */
 4443 tgl                       710 CBC         632 :     if (control->encoding < 0)
 3332 tgl                       711 GIC         632 :         src_encoding = GetDatabaseEncoding();
 4443 tgl                       712 ECB             :     else
 4443 tgl                       713 UIC           0 :         src_encoding = control->encoding;
                                714                 : 
                                715                 :     /* make sure that source string is valid in the expected encoding */
  801 heikki.linnakangas        716 GIC         632 :     (void) pg_verify_mbstr(src_encoding, src_str, len, false);
                                717                 : 
                                718                 :     /*
 2842 heikki.linnakangas        719 ECB             :      * Convert the encoding to the database encoding. read_whole_file
                                720                 :      * null-terminated the string, so if no conversion happens the string is
                                721                 :      * valid as is.
                                722                 :      */
 3332 tgl                       723 GIC         632 :     dest_str = pg_any_to_server(src_str, len, src_encoding);
                                724                 : 
 4443                           725             632 :     return dest_str;
                                726                 : }
 4443 tgl                       727 ECB             : 
                                728                 : /*
                                729                 :  * Execute given SQL string.
                                730                 :  *
                                731                 :  * Note: it's tempting to just use SPI to execute the string, but that does
                                732                 :  * not work very well.  The really serious problem is that SPI will parse,
 4443 tgl                       733 EUB             :  * analyze, and plan the whole string before executing any of it; of course
                                734                 :  * this fails if there are any plannable statements referring to objects
                                735                 :  * created earlier in the script.  A lesser annoyance is that SPI insists
 4443 tgl                       736 ECB             :  * on printing the whole string as errcontext in case of any error, and that
                                737                 :  * could be very long.
                                738                 :  */
                                739                 : static void
 1669 michael                   740 GIC         632 : execute_sql_string(const char *sql)
                                741                 : {
                                742                 :     List       *raw_parsetree_list;
 4443 tgl                       743 ECB             :     DestReceiver *dest;
                                744                 :     ListCell   *lc1;
                                745                 : 
                                746                 :     /*
                                747                 :      * Parse the SQL string into a list of raw parse trees.
                                748                 :      */
 4443 tgl                       749 GIC         632 :     raw_parsetree_list = pg_parse_query(sql);
                                750                 : 
                                751                 :     /* All output from SELECTs goes to the bit bucket */
                                752             632 :     dest = CreateDestReceiver(DestNone);
                                753                 : 
                                754                 :     /*
                                755                 :      * Do parse analysis, rule rewrite, planning, and execution for each raw
                                756                 :      * parsetree.  We must fully execute each query before beginning parse
                                757                 :      * analysis on the next one, since there may be interdependencies.
                                758                 :      */
                                759            6680 :     foreach(lc1, raw_parsetree_list)
 4443 tgl                       760 ECB             :     {
 2190 tgl                       761 GIC        6059 :         RawStmt    *parsetree = lfirst_node(RawStmt, lc1);
                                762                 :         MemoryContext per_parsetree_context,
                                763                 :                     oldcontext;
                                764                 :         List       *stmt_list;
                                765                 :         ListCell   *lc2;
                                766                 : 
                                767                 :         /*
                                768                 :          * We do the work for each parsetree in a short-lived context, to
 1369 tgl                       769 ECB             :          * limit the memory used when there are many commands in the string.
                                770                 :          */
                                771                 :         per_parsetree_context =
 1369 tgl                       772 CBC        6059 :             AllocSetContextCreate(CurrentMemoryContext,
                                773                 :                                   "execute_sql_string per-statement context",
                                774                 :                                   ALLOCSET_DEFAULT_SIZES);
 1369 tgl                       775 GIC        6059 :         oldcontext = MemoryContextSwitchTo(per_parsetree_context);
                                776                 : 
                                777                 :         /* Be sure parser can see any DDL done so far */
 2168                           778            6059 :         CommandCounterIncrement();
 2168 tgl                       779 ECB             : 
  401 peter                     780 GIC        6059 :         stmt_list = pg_analyze_and_rewrite_fixedparams(parsetree,
  332 tgl                       781 ECB             :                                                        sql,
                                782                 :                                                        NULL,
                                783                 :                                                        0,
                                784                 :                                                        NULL);
 1105 fujii                     785 GIC        6059 :         stmt_list = pg_plan_queries(stmt_list, sql, CURSOR_OPT_PARALLEL_OK, NULL);
                                786                 : 
 4443 tgl                       787           12107 :         foreach(lc2, stmt_list)
                                788                 :         {
 2190                           789            6059 :             PlannedStmt *stmt = lfirst_node(PlannedStmt, lc2);
                                790                 : 
 4443                           791            6059 :             CommandCounterIncrement();
 4443 tgl                       792 ECB             : 
 4443 tgl                       793 GIC        6059 :             PushActiveSnapshot(GetTransactionSnapshot());
                                794                 : 
 2276 tgl                       795 CBC        6059 :             if (stmt->utilityStmt == NULL)
                                796                 :             {
                                797                 :                 QueryDesc  *qdesc;
 4443 tgl                       798 ECB             : 
 2276 tgl                       799 GIC           5 :                 qdesc = CreateQueryDesc(stmt,
 4443 tgl                       800 ECB             :                                         sql,
                                801                 :                                         GetActiveSnapshot(), NULL,
                                802                 :                                         dest, NULL, NULL, 0);
                                803                 : 
 4443 tgl                       804 GIC           5 :                 ExecutorStart(qdesc, 0);
 2208 rhaas                     805 CBC           5 :                 ExecutorRun(qdesc, ForwardScanDirection, 0, true);
 4424 tgl                       806 GIC           5 :                 ExecutorFinish(qdesc);
 4443 tgl                       807 CBC           5 :                 ExecutorEnd(qdesc);
                                808                 : 
                                809               5 :                 FreeQueryDesc(qdesc);
                                810                 :             }
 4443 tgl                       811 ECB             :             else
                                812                 :             {
 2276 tgl                       813 CBC        6054 :                 if (IsA(stmt->utilityStmt, TransactionStmt))
 2276 tgl                       814 UIC           0 :                     ereport(ERROR,
 2276 tgl                       815 ECB             :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                816                 :                              errmsg("transaction control statements are not allowed within an extension script")));
                                817                 : 
 4443 tgl                       818 GIC        6054 :                 ProcessUtility(stmt,
 4443 tgl                       819 ECB             :                                sql,
                                820                 :                                false,
                                821                 :                                PROCESS_UTILITY_QUERY,
                                822                 :                                NULL,
                                823                 :                                NULL,
                                824                 :                                dest,
 3633                           825                 :                                NULL);
 4443                           826                 :             }
                                827                 : 
 4443 tgl                       828 GIC        6048 :             PopActiveSnapshot();
 4443 tgl                       829 ECB             :         }
                                830                 : 
                                831                 :         /* Clean up per-parsetree context. */
 1369 tgl                       832 GIC        6048 :         MemoryContextSwitchTo(oldcontext);
 1369 tgl                       833 CBC        6048 :         MemoryContextDelete(per_parsetree_context);
 4443 tgl                       834 EUB             :     }
                                835                 : 
                                836                 :     /* Be sure to advance the command counter after the last script command */
 4443 tgl                       837 GIC         621 :     CommandCounterIncrement();
 4443 tgl                       838 CBC         621 : }
                                839                 : 
                                840                 : /*
                                841                 :  * Policy function: is the given extension trusted for installation by a
                                842                 :  * non-superuser?
                                843                 :  *
                                844                 :  * (Update the errhint logic below if you change this.)
                                845                 :  */
                                846                 : static bool
 1166 tgl                       847 GIC           4 : extension_is_trusted(ExtensionControlFile *control)
 1166 tgl                       848 ECB             : {
                                849                 :     AclResult   aclresult;
                                850                 : 
                                851                 :     /* Never trust unless extension's control file says it's okay */
 1166 tgl                       852 CBC           4 :     if (!control->trusted)
                                853               2 :         return false;
                                854                 :     /* Allow if user has CREATE privilege on current database */
  147 peter                     855 GNC           2 :     aclresult = object_aclcheck(DatabaseRelationId, MyDatabaseId, GetUserId(), ACL_CREATE);
 1166 tgl                       856 GIC           2 :     if (aclresult == ACLCHECK_OK)
 1166 tgl                       857 CBC           1 :         return true;
                                858               1 :     return false;
                                859                 : }
                                860                 : 
                                861                 : /*
                                862                 :  * Execute the appropriate script file for installing or updating the extension
                                863                 :  *
                                864                 :  * If from_version isn't NULL, it's an update
                                865                 :  *
                                866                 :  * Note: requiredSchemas must be one-for-one with the control->requires list
                                867                 :  */
                                868                 : static void
 4443                           869             635 : execute_extension_script(Oid extensionOid, ExtensionControlFile *control,
                                870                 :                          const char *from_version,
                                871                 :                          const char *version,
                                872                 :                          List *requiredSchemas,
                                873                 :                          const char *schemaName, Oid schemaOid)
 4443 tgl                       874 ECB             : {
 1166 tgl                       875 CBC         635 :     bool        switch_to_superuser = false;
                                876                 :     char       *filename;
                                877             635 :     Oid         save_userid = 0;
                                878             635 :     int         save_sec_context = 0;
 4204 tgl                       879 ECB             :     int         save_nestlevel;
 4443                           880                 :     StringInfoData pathbuf;
                                881                 :     ListCell   *lc;
                                882                 :     ListCell   *lc2;
                                883                 : 
                                884                 :     /*
                                885                 :      * Enforce superuser-ness if appropriate.  We postpone these checks until
                                886                 :      * here so that the control flags are correctly associated with the right
                                887                 :      * script(s) if they happen to be set in secondary control files.
                                888                 :      */
 4419 tgl                       889 GIC         635 :     if (control->superuser && !superuser())
                                890                 :     {
 1166                           891               4 :         if (extension_is_trusted(control))
 1166 tgl                       892 CBC           1 :             switch_to_superuser = true;
 1166 tgl                       893 GIC           3 :         else if (from_version == NULL)
 4419                           894               3 :             ereport(ERROR,
                                895                 :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                896                 :                      errmsg("permission denied to create extension \"%s\"",
                                897                 :                             control->name),
 1166 tgl                       898 ECB             :                      control->trusted
                                899                 :                      ? errhint("Must have CREATE privilege on current database to create this extension.")
                                900                 :                      : errhint("Must be superuser to create this extension.")));
 4419                           901                 :         else
 4419 tgl                       902 UIC           0 :             ereport(ERROR,
                                903                 :                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                                904                 :                      errmsg("permission denied to update extension \"%s\"",
                                905                 :                             control->name),
                                906                 :                      control->trusted
                                907                 :                      ? errhint("Must have CREATE privilege on current database to update this extension.")
                                908                 :                      : errhint("Must be superuser to update this extension.")));
                                909                 :     }
                                910                 : 
 4440 tgl                       911 GIC         632 :     filename = get_extension_script_filename(control, from_version, version);
 4440 tgl                       912 ECB             : 
  281 jdavis                    913 GNC         632 :     if (from_version == NULL)
                                914             459 :         elog(DEBUG1, "executing extension script for \"%s\" version '%s'", control->name, version);
                                915                 :     else
                                916             173 :         elog(DEBUG1, "executing extension script for \"%s\" update from version '%s' to '%s'", control->name, from_version, version);
                                917                 : 
                                918                 :     /*
 1166 tgl                       919 ECB             :      * If installing a trusted extension on behalf of a non-superuser, become
                                920                 :      * the bootstrap superuser.  (This switch will be cleaned up automatically
                                921                 :      * if the transaction aborts, as will the GUC changes below.)
                                922                 :      */
 1166 tgl                       923 GIC         632 :     if (switch_to_superuser)
                                924                 :     {
                                925               1 :         GetUserIdAndSecContext(&save_userid, &save_sec_context);
                                926               1 :         SetUserIdAndSecContext(BOOTSTRAP_SUPERUSERID,
                                927                 :                                save_sec_context | SECURITY_LOCAL_USERID_CHANGE);
                                928                 :     }
                                929                 : 
 4443 tgl                       930 EUB             :     /*
                                931                 :      * Force client_min_messages and log_min_messages to be at least WARNING,
                                932                 :      * so that we won't spam the user with useless NOTICE messages from common
                                933                 :      * script actions like creating shell types.
                                934                 :      *
                                935                 :      * We use the equivalent of a function SET option to allow the setting to
                                936                 :      * persist for exactly the duration of the script execution.  guc.c also
                                937                 :      * takes care of undoing the setting on error.
                                938                 :      *
  264 tgl                       939 ECB             :      * log_min_messages can't be set by ordinary users, so for that one we
                                940                 :      * pretend to be superuser.
 4443                           941                 :      */
 4204 tgl                       942 CBC         632 :     save_nestlevel = NewGUCNestLevel();
                                943                 : 
 4443                           944             632 :     if (client_min_messages < WARNING)
 4443 tgl                       945 GIC         630 :         (void) set_config_option("client_min_messages", "warning",
                                946                 :                                  PGC_USERSET, PGC_S_SESSION,
                                947                 :                                  GUC_ACTION_SAVE, true, 0, false);
                                948             632 :     if (log_min_messages < WARNING)
  264                           949               2 :         (void) set_config_option_ext("log_min_messages", "warning",
                                950                 :                                      PGC_SUSET, PGC_S_SESSION,
  264 tgl                       951 ECB             :                                      BOOTSTRAP_SUPERUSERID,
                                952                 :                                      GUC_ACTION_SAVE, true, 0, false);
 4443                           953                 : 
                                954                 :     /*
                                955                 :      * Similarly disable check_function_bodies, to ensure that SQL functions
                                956                 :      * won't be parsed during creation.
                                957                 :      */
  972 tgl                       958 GIC         632 :     if (check_function_bodies)
                                959             632 :         (void) set_config_option("check_function_bodies", "off",
                                960                 :                                  PGC_USERSET, PGC_S_SESSION,
                                961                 :                                  GUC_ACTION_SAVE, true, 0, false);
                                962                 : 
                                963                 :     /*
                                964                 :      * Set up the search path to have the target schema first, making it be
                                965                 :      * the default creation target namespace.  Then add the schemas of any
                                966                 :      * prerequisite extensions, unless they are in pg_catalog which would be
                                967                 :      * searched anyway.  (Listing pg_catalog explicitly in a non-first
                                968                 :      * position would be bad for security.)  Finally add pg_temp to ensure
                                969                 :      * that temp objects can't take precedence over others.
 4443 tgl                       970 ECB             :      *
                                971                 :      * Note: it might look tempting to use PushOverrideSearchPath for this,
 4382 bruce                     972                 :      * but we cannot do that.  We have to actually set the search_path GUC in
 4204 tgl                       973                 :      * case the extension script examines or changes it.  In any case, the
                                974                 :      * GUC_ACTION_SAVE method is just as convenient.
                                975                 :      */
 4443 tgl                       976 CBC         632 :     initStringInfo(&pathbuf);
                                977             632 :     appendStringInfoString(&pathbuf, quote_identifier(schemaName));
 4443 tgl                       978 GIC         657 :     foreach(lc, requiredSchemas)
                                979                 :     {
                                980              25 :         Oid         reqschema = lfirst_oid(lc);
                                981              25 :         char       *reqname = get_namespace_name(reqschema);
                                982                 : 
  972                           983              25 :         if (reqname && strcmp(reqname, "pg_catalog") != 0)
 4443                           984              15 :             appendStringInfo(&pathbuf, ", %s", quote_identifier(reqname));
                                985                 :     }
  972 tgl                       986 CBC         632 :     appendStringInfoString(&pathbuf, ", pg_temp");
 4443 tgl                       987 ECB             : 
 4443 tgl                       988 GIC         632 :     (void) set_config_option("search_path", pathbuf.data,
                                989                 :                              PGC_USERSET, PGC_S_SESSION,
                                990                 :                              GUC_ACTION_SAVE, true, 0, false);
                                991                 : 
                                992                 :     /*
                                993                 :      * Set creating_extension and related variables so that
                                994                 :      * recordDependencyOnCurrentExtension and other functions do the right
                                995                 :      * things.  On failure, ensure we reset these variables.
                                996                 :      */
                                997             632 :     creating_extension = true;
                                998             632 :     CurrentExtensionObject = extensionOid;
                                999             632 :     PG_TRY();
                               1000                 :     {
 4197                          1001             632 :         char       *c_sql = read_extension_script_file(control, filename);
                               1002                 :         Datum       t_sql;
                               1003                 : 
 4197 tgl                      1004 ECB             :         /* We use various functions that want to operate on text datums */
 4197 tgl                      1005 CBC         632 :         t_sql = CStringGetTextDatum(c_sql);
 4197 tgl                      1006 ECB             : 
                               1007                 :         /*
                               1008                 :          * Reduce any lines beginning with "\echo" to empty.  This allows
                               1009                 :          * scripts to contain messages telling people not to run them via
                               1010                 :          * psql, which has been found to be necessary due to old habits.
                               1011                 :          */
 4197 tgl                      1012 CBC         632 :         t_sql = DirectFunctionCall4Coll(textregexreplace,
                               1013                 :                                         C_COLLATION_OID,
 4197 tgl                      1014 ECB             :                                         t_sql,
 4197 tgl                      1015 GIC         632 :                                         CStringGetTextDatum("^\\\\echo.*$"),
 4197 tgl                      1016 CBC         632 :                                         CStringGetTextDatum(""),
 4197 tgl                      1017 GIC         632 :                                         CStringGetTextDatum("ng"));
                               1018                 : 
                               1019                 :         /*
                               1020                 :          * If the script uses @extowner@, substitute the calling username.
                               1021                 :          */
 1166                          1022             632 :         if (strstr(c_sql, "@extowner@"))
                               1023                 :         {
                               1024             311 :             Oid         uid = switch_to_superuser ? save_userid : GetUserId();
 1166 tgl                      1025 CBC         311 :             const char *userName = GetUserNameFromId(uid, false);
                               1026             311 :             const char *qUserName = quote_identifier(userName);
 1166 tgl                      1027 ECB             : 
 1166 tgl                      1028 GIC         311 :             t_sql = DirectFunctionCall3Coll(replace_text,
 1166 tgl                      1029 ECB             :                                             C_COLLATION_OID,
                               1030                 :                                             t_sql,
 1166 tgl                      1031 GIC         311 :                                             CStringGetTextDatum("@extowner@"),
                               1032             311 :                                             CStringGetTextDatum(qUserName));
 1166 tgl                      1033 ECB             :         }
                               1034                 : 
                               1035                 :         /*
                               1036                 :          * If it's not relocatable, substitute the target schema name for
                               1037                 :          * occurrences of @extschema@.
                               1038                 :          *
                               1039                 :          * For a relocatable extension, we needn't do this.  There cannot be
 4197                          1040                 :          * any need for @extschema@, else it wouldn't be relocatable.
                               1041                 :          */
 4443 tgl                      1042 GIC         632 :         if (!control->relocatable)
 4443 tgl                      1043 ECB             :         {
 4382 bruce                    1044 CBC         332 :             const char *qSchemaName = quote_identifier(schemaName);
 4443 tgl                      1045 ECB             : 
 1479 peter                    1046 GIC         332 :             t_sql = DirectFunctionCall3Coll(replace_text,
                               1047                 :                                             C_COLLATION_OID,
                               1048                 :                                             t_sql,
 1418 tgl                      1049             332 :                                             CStringGetTextDatum("@extschema@"),
 1418 tgl                      1050 CBC         332 :                                             CStringGetTextDatum(qSchemaName));
                               1051                 :         }
 4443 tgl                      1052 ECB             : 
                               1053                 :         /*
                               1054                 :          * Likewise, substitute required extensions' schema names for
                               1055                 :          * occurrences of @extschema:extension_name@.
                               1056                 :          */
   20 tgl                      1057 GNC         632 :         Assert(list_length(control->requires) == list_length(requiredSchemas));
                               1058             657 :         forboth(lc, control->requires, lc2, requiredSchemas)
                               1059                 :         {
                               1060              25 :             char       *reqextname = (char *) lfirst(lc);
                               1061              25 :             Oid         reqschema = lfirst_oid(lc2);
                               1062              25 :             char       *schemaName = get_namespace_name(reqschema);
                               1063              25 :             const char *qSchemaName = quote_identifier(schemaName);
                               1064                 :             char       *repltoken;
                               1065                 : 
                               1066              25 :             repltoken = psprintf("@extschema:%s@", reqextname);
                               1067              25 :             t_sql = DirectFunctionCall3Coll(replace_text,
                               1068                 :                                             C_COLLATION_OID,
                               1069                 :                                             t_sql,
                               1070              25 :                                             CStringGetTextDatum(repltoken),
                               1071              25 :                                             CStringGetTextDatum(qSchemaName));
                               1072                 :         }
                               1073                 : 
 4438 tgl                      1074 ECB             :         /*
                               1075                 :          * If module_pathname was set in the control file, substitute its
                               1076                 :          * value for occurrences of MODULE_PATHNAME.
                               1077                 :          */
 4438 tgl                      1078 GIC         632 :         if (control->module_pathname)
                               1079                 :         {
 1479 peter                    1080 CBC         594 :             t_sql = DirectFunctionCall3Coll(replace_text,
 1479 peter                    1081 ECB             :                                             C_COLLATION_OID,
                               1082                 :                                             t_sql,
 1418 tgl                      1083 GIC         594 :                                             CStringGetTextDatum("MODULE_PATHNAME"),
                               1084             594 :                                             CStringGetTextDatum(control->module_pathname));
                               1085                 :         }
                               1086                 : 
                               1087                 :         /* And now back to C string */
 4197                          1088             632 :         c_sql = text_to_cstring(DatumGetTextPP(t_sql));
                               1089                 : 
 1669 michael                  1090             632 :         execute_sql_string(c_sql);
 4443 tgl                      1091 ECB             :     }
 1255 peter                    1092 GIC          11 :     PG_FINALLY();
 4443 tgl                      1093 ECB             :     {
 4443 tgl                      1094 GIC         632 :         creating_extension = false;
 4443 tgl                      1095 CBC         632 :         CurrentExtensionObject = InvalidOid;
                               1096                 :     }
 4443 tgl                      1097 GIC         632 :     PG_END_TRY();
 4443 tgl                      1098 ECB             : 
                               1099                 :     /*
                               1100                 :      * Restore the GUC variables we set above.
                               1101                 :      */
 4204 tgl                      1102 GIC         621 :     AtEOXact_GUC(true, save_nestlevel);
                               1103                 : 
                               1104                 :     /*
                               1105                 :      * Restore authentication state if needed.
 1166 tgl                      1106 ECB             :      */
 1166 tgl                      1107 CBC         621 :     if (switch_to_superuser)
 1166 tgl                      1108 GIC           1 :         SetUserIdAndSecContext(save_userid, save_sec_context);
 4443 tgl                      1109 CBC         621 : }
 4443 tgl                      1110 ECB             : 
 4440                          1111                 : /*
                               1112                 :  * Find or create an ExtensionVersionInfo for the specified version name
                               1113                 :  *
                               1114                 :  * Currently, we just use a List of the ExtensionVersionInfo's.  Searching
                               1115                 :  * for them therefore uses about O(N^2) time when there are N versions of
                               1116                 :  * the extension.  We could change the data structure to a hash table if
                               1117                 :  * this ever becomes a bottleneck.
                               1118                 :  */
                               1119                 : static ExtensionVersionInfo *
 4440 tgl                      1120 CBC        1780 : get_ext_ver_info(const char *versionname, List **evi_list)
                               1121                 : {
                               1122                 :     ExtensionVersionInfo *evi;
                               1123                 :     ListCell   *lc;
                               1124                 : 
 4440 tgl                      1125 GIC        6657 :     foreach(lc, *evi_list)
                               1126                 :     {
 4440 tgl                      1127 CBC        5627 :         evi = (ExtensionVersionInfo *) lfirst(lc);
 4440 tgl                      1128 GIC        5627 :         if (strcmp(evi->name, versionname) == 0)
 4440 tgl                      1129 CBC         750 :             return evi;
                               1130                 :     }
                               1131                 : 
                               1132            1030 :     evi = (ExtensionVersionInfo *) palloc(sizeof(ExtensionVersionInfo));
                               1133            1030 :     evi->name = pstrdup(versionname);
 4440 tgl                      1134 GIC        1030 :     evi->reachable = NIL;
 4437                          1135            1030 :     evi->installable = false;
                               1136                 :     /* initialize for later application of Dijkstra's algorithm */
 4440 tgl                      1137 CBC        1030 :     evi->distance_known = false;
 4440 tgl                      1138 GIC        1030 :     evi->distance = INT_MAX;
 4440 tgl                      1139 CBC        1030 :     evi->previous = NULL;
                               1140                 : 
                               1141            1030 :     *evi_list = lappend(*evi_list, evi);
                               1142                 : 
                               1143            1030 :     return evi;
 4440 tgl                      1144 ECB             : }
                               1145                 : 
                               1146                 : /*
                               1147                 :  * Locate the nearest unprocessed ExtensionVersionInfo
                               1148                 :  *
                               1149                 :  * This part of the algorithm is also about O(N^2).  A priority queue would
                               1150                 :  * make it much faster, but for now there's no need.
                               1151                 :  */
                               1152                 : static ExtensionVersionInfo *
 4440 tgl                      1153 GIC        1513 : get_nearest_unprocessed_vertex(List *evi_list)
                               1154                 : {
                               1155            1513 :     ExtensionVersionInfo *evi = NULL;
 4440 tgl                      1156 ECB             :     ListCell   *lc;
                               1157                 : 
 4440 tgl                      1158 CBC       13130 :     foreach(lc, evi_list)
                               1159                 :     {
 4440 tgl                      1160 GIC       11617 :         ExtensionVersionInfo *evi2 = (ExtensionVersionInfo *) lfirst(lc);
                               1161                 : 
                               1162                 :         /* only vertices whose distance is still uncertain are candidates */
                               1163           11617 :         if (evi2->distance_known)
                               1164            2910 :             continue;
                               1165                 :         /* remember the closest such vertex */
                               1166            8707 :         if (evi == NULL ||
                               1167            7194 :             evi->distance > evi2->distance)
                               1168            2422 :             evi = evi2;
 4440 tgl                      1169 ECB             :     }
                               1170                 : 
 4440 tgl                      1171 GIC        1513 :     return evi;
                               1172                 : }
                               1173                 : 
 4440 tgl                      1174 ECB             : /*
                               1175                 :  * Obtain information about the set of update scripts available for the
                               1176                 :  * specified extension.  The result is a List of ExtensionVersionInfo
                               1177                 :  * structs, each with a subsidiary list of the ExtensionVersionInfos for
                               1178                 :  * the versions that can be reached in one step from that version.
                               1179                 :  */
                               1180                 : static List *
 4440 tgl                      1181 CBC         353 : get_ext_ver_list(ExtensionControlFile *control)
 4440 tgl                      1182 ECB             : {
 4440 tgl                      1183 CBC         353 :     List       *evi_list = NIL;
                               1184             353 :     int         extnamelen = strlen(control->name);
                               1185                 :     char       *location;
 4440 tgl                      1186 ECB             :     DIR        *dir;
                               1187                 :     struct dirent *de;
                               1188                 : 
 4440 tgl                      1189 GIC         353 :     location = get_extension_script_directory(control);
 4382 bruce                    1190 CBC         353 :     dir = AllocateDir(location);
 4440 tgl                      1191 GIC      109077 :     while ((de = ReadDir(dir, location)) != NULL)
 4440 tgl                      1192 ECB             :     {
                               1193                 :         char       *vername;
                               1194                 :         char       *vername2;
                               1195                 :         ExtensionVersionInfo *evi;
                               1196                 :         ExtensionVersionInfo *evi2;
                               1197                 : 
                               1198                 :         /* must be a .sql file ... */
 4440 tgl                      1199 GIC      108724 :         if (!is_extension_script_filename(de->d_name))
                               1200           34947 :             continue;
                               1201                 : 
 4440 tgl                      1202 ECB             :         /* ... matching extension name followed by separator */
 4440 tgl                      1203 GIC       73777 :         if (strncmp(de->d_name, control->name, extnamelen) != 0 ||
 4438 tgl                      1204 CBC        1080 :             de->d_name[extnamelen] != '-' ||
 4438 tgl                      1205 GIC        1030 :             de->d_name[extnamelen + 1] != '-')
 4440                          1206           72747 :             continue;
 4440 tgl                      1207 ECB             : 
                               1208                 :         /* extract version name(s) from 'extname--something.sql' filename */
 4438 tgl                      1209 CBC        1030 :         vername = pstrdup(de->d_name + extnamelen + 2);
 4440 tgl                      1210 GIC        1030 :         *strrchr(vername, '.') = '\0';
 4438                          1211            1030 :         vername2 = strstr(vername, "--");
 4440 tgl                      1212 CBC        1030 :         if (!vername2)
 4437 tgl                      1213 ECB             :         {
                               1214                 :             /* It's an install, not update, script; record its version name */
 4437 tgl                      1215 CBC         353 :             evi = get_ext_ver_info(vername, &evi_list);
                               1216             353 :             evi->installable = true;
                               1217             353 :             continue;
                               1218                 :         }
 4438 tgl                      1219 GIC         677 :         *vername2 = '\0';       /* terminate first version */
 4438 tgl                      1220 CBC         677 :         vername2 += 2;          /* and point to second */
                               1221                 : 
                               1222                 :         /* if there's a third --, it's bogus, ignore it */
 4437 tgl                      1223 GIC         677 :         if (strstr(vername2, "--"))
 4437 tgl                      1224 UIC           0 :             continue;
                               1225                 : 
                               1226                 :         /* Create ExtensionVersionInfos and link them together */
 4440 tgl                      1227 GIC         677 :         evi = get_ext_ver_info(vername, &evi_list);
                               1228             677 :         evi2 = get_ext_ver_info(vername2, &evi_list);
                               1229             677 :         evi->reachable = lappend(evi->reachable, evi2);
 4440 tgl                      1230 ECB             :     }
 4440 tgl                      1231 GIC         353 :     FreeDir(dir);
 4440 tgl                      1232 ECB             : 
 4440 tgl                      1233 CBC         353 :     return evi_list;
                               1234                 : }
                               1235                 : 
                               1236                 : /*
                               1237                 :  * Given an initial and final version name, identify the sequence of update
 4440 tgl                      1238 ECB             :  * scripts that have to be applied to perform that update.
                               1239                 :  *
 4439                          1240                 :  * Result is a List of names of versions to transition through (the initial
                               1241                 :  * version is *not* included).
                               1242                 :  */
                               1243                 : static List *
 4440 tgl                      1244 GIC          11 : identify_update_path(ExtensionControlFile *control,
                               1245                 :                      const char *oldVersion, const char *newVersion)
                               1246                 : {
                               1247                 :     List       *result;
 4440 tgl                      1248 ECB             :     List       *evi_list;
                               1249                 :     ExtensionVersionInfo *evi_start;
                               1250                 :     ExtensionVersionInfo *evi_target;
                               1251                 : 
                               1252                 :     /* Extract the version update graph from the script directory */
 4440 tgl                      1253 CBC          11 :     evi_list = get_ext_ver_list(control);
 4440 tgl                      1254 ECB             : 
                               1255                 :     /* Initialize start and end vertices */
 4440 tgl                      1256 GIC          11 :     evi_start = get_ext_ver_info(oldVersion, &evi_list);
                               1257              11 :     evi_target = get_ext_ver_info(newVersion, &evi_list);
 4440 tgl                      1258 ECB             : 
 4437                          1259                 :     /* Find shortest path */
 2401 tgl                      1260 CBC          11 :     result = find_update_path(evi_list, evi_start, evi_target, false, false);
 4437 tgl                      1261 ECB             : 
 4437 tgl                      1262 GIC          11 :     if (result == NIL)
 4437 tgl                      1263 UIC           0 :         ereport(ERROR,
 4437 tgl                      1264 ECB             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                               1265                 :                  errmsg("extension \"%s\" has no update path from version \"%s\" to version \"%s\"",
                               1266                 :                         control->name, oldVersion, newVersion)));
                               1267                 : 
 4437 tgl                      1268 CBC          11 :     return result;
 4437 tgl                      1269 ECB             : }
                               1270                 : 
                               1271                 : /*
                               1272                 :  * Apply Dijkstra's algorithm to find the shortest path from evi_start to
 4437 tgl                      1273 EUB             :  * evi_target.
                               1274                 :  *
                               1275                 :  * If reject_indirect is true, ignore paths that go through installable
 2401 tgl                      1276 ECB             :  * versions.  This saves work when the caller will consider starting from
                               1277                 :  * all installable versions anyway.
                               1278                 :  *
                               1279                 :  * If reinitialize is false, assume the ExtensionVersionInfo list has not
 4437                          1280                 :  * been used for this before, and the initialization done by get_ext_ver_info
                               1281                 :  * is still good.  Otherwise, reinitialize all transient fields used here.
                               1282                 :  *
                               1283                 :  * Result is a List of names of versions to transition through (the initial
                               1284                 :  * version is *not* included).  Returns NIL if no such path.
                               1285                 :  */
                               1286                 : static List *
 4437 tgl                      1287 GIC         398 : find_update_path(List *evi_list,
                               1288                 :                  ExtensionVersionInfo *evi_start,
                               1289                 :                  ExtensionVersionInfo *evi_target,
                               1290                 :                  bool reject_indirect,
                               1291                 :                  bool reinitialize)
                               1292                 : {
 4437 tgl                      1293 ECB             :     List       *result;
                               1294                 :     ExtensionVersionInfo *evi;
                               1295                 :     ListCell   *lc;
                               1296                 : 
                               1297                 :     /* Caller error if start == target */
 4437 tgl                      1298 GIC         398 :     Assert(evi_start != evi_target);
                               1299                 :     /* Caller error if reject_indirect and target is installable */
 2401                          1300             398 :     Assert(!(reject_indirect && evi_target->installable));
                               1301                 : 
 4437 tgl                      1302 CBC         398 :     if (reinitialize)
                               1303                 :     {
 4437 tgl                      1304 GIC        2851 :         foreach(lc, evi_list)
 4437 tgl                      1305 ECB             :         {
 4437 tgl                      1306 CBC        2464 :             evi = (ExtensionVersionInfo *) lfirst(lc);
 4437 tgl                      1307 GIC        2464 :             evi->distance_known = false;
                               1308            2464 :             evi->distance = INT_MAX;
 4437 tgl                      1309 CBC        2464 :             evi->previous = NULL;
                               1310                 :         }
 4437 tgl                      1311 ECB             :     }
 4437 tgl                      1312 EUB             : 
 4440 tgl                      1313 GIC         398 :     evi_start->distance = 0;
                               1314                 : 
                               1315            1513 :     while ((evi = get_nearest_unprocessed_vertex(evi_list)) != NULL)
                               1316                 :     {
 4440 tgl                      1317 CBC        1513 :         if (evi->distance == INT_MAX)
 4440 tgl                      1318 GIC         159 :             break;              /* all remaining vertices are unreachable */
                               1319            1354 :         evi->distance_known = true;
                               1320            1354 :         if (evi == evi_target)
                               1321             239 :             break;              /* found shortest path to target */
                               1322            2071 :         foreach(lc, evi->reachable)
                               1323                 :         {
                               1324             956 :             ExtensionVersionInfo *evi2 = (ExtensionVersionInfo *) lfirst(lc);
                               1325                 :             int         newdist;
                               1326                 : 
                               1327                 :             /* if reject_indirect, treat installable versions as unreachable */
 2401                          1328             956 :             if (reject_indirect && evi2->installable)
 2401 tgl                      1329 UIC           0 :                 continue;
 4440 tgl                      1330 GIC         956 :             newdist = evi->distance + 1;
                               1331             956 :             if (newdist < evi2->distance)
                               1332                 :             {
                               1333             956 :                 evi2->distance = newdist;
                               1334             956 :                 evi2->previous = evi;
                               1335                 :             }
 4438 tgl                      1336 LBC           0 :             else if (newdist == evi2->distance &&
 4438 tgl                      1337 UIC           0 :                      evi2->previous != NULL &&
                               1338               0 :                      strcmp(evi->name, evi2->previous->name) < 0)
                               1339                 :             {
                               1340                 :                 /*
                               1341                 :                  * Break ties in favor of the version name that comes first
                               1342                 :                  * according to strcmp().  This behavior is undocumented and
                               1343                 :                  * users shouldn't rely on it.  We do it just to ensure that
                               1344                 :                  * if there is a tie, the update path that is chosen does not
                               1345                 :                  * depend on random factors like the order in which directory
                               1346                 :                  * entries get visited.
 4438 tgl                      1347 ECB             :                  */
 4438 tgl                      1348 UIC           0 :                 evi2->previous = evi;
 4438 tgl                      1349 ECB             :             }
                               1350                 :         }
 4440                          1351                 :     }
                               1352                 : 
 4437                          1353                 :     /* Return NIL if target is not reachable from start */
 4440 tgl                      1354 GIC         398 :     if (!evi_target->distance_known)
 4437 tgl                      1355 CBC         159 :         return NIL;
 4440 tgl                      1356 ECB             : 
                               1357                 :     /* Build and return list of version names representing the update path */
 4440 tgl                      1358 CBC         239 :     result = NIL;
 4440 tgl                      1359 GIC         814 :     for (evi = evi_target; evi != evi_start; evi = evi->previous)
                               1360             575 :         result = lcons(evi->name, result);
                               1361                 : 
 4440 tgl                      1362 CBC         239 :     return result;
                               1363                 : }
 4440 tgl                      1364 ECB             : 
                               1365                 : /*
 2401                          1366                 :  * Given a target version that is not directly installable, find the
                               1367                 :  * best installation sequence starting from a directly-installable version.
                               1368                 :  *
                               1369                 :  * evi_list: previously-collected version update graph
                               1370                 :  * evi_target: member of that list that we want to reach
                               1371                 :  *
                               1372                 :  * Returns the best starting-point version, or NULL if there is none.
                               1373                 :  * On success, *best_path is set to the path from the start point.
                               1374                 :  *
                               1375                 :  * If there's more than one possible start point, prefer shorter update paths,
                               1376                 :  * and break any ties arbitrarily on the basis of strcmp'ing the starting
                               1377                 :  * versions' names.
 2401 tgl                      1378 EUB             :  */
 2401 tgl                      1379 ECB             : static ExtensionVersionInfo *
 2401 tgl                      1380 CBC         387 : find_install_path(List *evi_list, ExtensionVersionInfo *evi_target,
                               1381                 :                   List **best_path)
 2401 tgl                      1382 ECB             : {
 2401 tgl                      1383 CBC         387 :     ExtensionVersionInfo *evi_start = NULL;
                               1384                 :     ListCell   *lc;
 2401 tgl                      1385 EUB             : 
 2401 tgl                      1386 GBC         387 :     *best_path = NIL;
 2401 tgl                      1387 EUB             : 
                               1388                 :     /*
                               1389                 :      * We don't expect to be called for an installable target, but if we are,
                               1390                 :      * the answer is easy: just start from there, with an empty update path.
                               1391                 :      */
 2401 tgl                      1392 GIC         387 :     if (evi_target->installable)
 2401 tgl                      1393 UIC           0 :         return evi_target;
                               1394                 : 
                               1395                 :     /* Consider all installable versions as start points */
 2401 tgl                      1396 GIC        2851 :     foreach(lc, evi_list)
 2401 tgl                      1397 EUB             :     {
 2401 tgl                      1398 GIC        2464 :         ExtensionVersionInfo *evi1 = (ExtensionVersionInfo *) lfirst(lc);
                               1399                 :         List       *path;
                               1400                 : 
                               1401            2464 :         if (!evi1->installable)
                               1402            2077 :             continue;
 2401 tgl                      1403 ECB             : 
                               1404                 :         /*
                               1405                 :          * Find shortest path from evi1 to evi_target; but no need to consider
                               1406                 :          * paths going through other installable versions.
                               1407                 :          */
 2401 tgl                      1408 CBC         387 :         path = find_update_path(evi_list, evi1, evi_target, true, true);
                               1409             387 :         if (path == NIL)
 2401 tgl                      1410 GIC         159 :             continue;
 2401 tgl                      1411 ECB             : 
                               1412                 :         /* Remember best path */
 2401 tgl                      1413 GIC         228 :         if (evi_start == NULL ||
 2401 tgl                      1414 UIC           0 :             list_length(path) < list_length(*best_path) ||
                               1415               0 :             (list_length(path) == list_length(*best_path) &&
                               1416               0 :              strcmp(evi_start->name, evi1->name) < 0))
                               1417                 :         {
 2401 tgl                      1418 GIC         228 :             evi_start = evi1;
                               1419             228 :             *best_path = path;
                               1420                 :         }
                               1421                 :     }
                               1422                 : 
                               1423             387 :     return evi_start;
                               1424                 : }
                               1425                 : 
                               1426                 : /*
                               1427                 :  * CREATE EXTENSION worker
                               1428                 :  *
 2407 tgl                      1429 ECB             :  * When CASCADE is specified, CreateExtensionInternal() recurses if required
                               1430                 :  * extensions need to be installed.  To sanely handle cyclic dependencies,
                               1431                 :  * the "parents" list contains a list of names of extensions already being
                               1432                 :  * installed, allowing us to error out if we recurse to one of those.
                               1433                 :  */
                               1434                 : static ObjectAddress
 2401 tgl                      1435 CBC         469 : CreateExtensionInternal(char *extensionName,
                               1436                 :                         char *schemaName,
                               1437                 :                         const char *versionName,
                               1438                 :                         bool cascade,
                               1439                 :                         List *parents,
                               1440                 :                         bool is_create)
 4443 tgl                      1441 ECB             : {
 2401 tgl                      1442 GBC         469 :     char       *origSchemaName = schemaName;
 2745 andres                   1443 GIC         469 :     Oid         schemaOid = InvalidOid;
 4443 tgl                      1444             469 :     Oid         extowner = GetUserId();
 4439 tgl                      1445 ECB             :     ExtensionControlFile *pcontrol;
                               1446                 :     ExtensionControlFile *control;
 1145                          1447                 :     char       *filename;
                               1448                 :     struct stat fst;
                               1449                 :     List       *updateVersions;
 4443                          1450                 :     List       *requiredExtensions;
                               1451                 :     List       *requiredSchemas;
                               1452                 :     Oid         extensionOid;
                               1453                 :     ObjectAddress address;
                               1454                 :     ListCell   *lc;
                               1455                 : 
                               1456                 :     /*
 4440                          1457                 :      * Read the primary control file.  Note we assume that it does not contain
                               1458                 :      * any non-ASCII data, so there is no need to worry about encoding at this
                               1459                 :      * point.
                               1460                 :      */
 2401 tgl                      1461 GIC         469 :     pcontrol = read_extension_control_file(extensionName);
 4443 tgl                      1462 ECB             : 
 4440 tgl                      1463 EUB             :     /*
                               1464                 :      * Determine the version to install
                               1465                 :      */
 2401 tgl                      1466 GIC         469 :     if (versionName == NULL)
 4440 tgl                      1467 ECB             :     {
 2401 tgl                      1468 CBC         466 :         if (pcontrol->default_version)
 2401 tgl                      1469 GIC         466 :             versionName = pcontrol->default_version;
                               1470                 :         else
 2401 tgl                      1471 UIC           0 :             ereport(ERROR,
 2401 tgl                      1472 ECB             :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                               1473                 :                      errmsg("version to install must be specified")));
                               1474                 :     }
 4440 tgl                      1475 GIC         469 :     check_valid_version_name(versionName);
                               1476                 : 
                               1477                 :     /*
                               1478                 :      * Figure out which script(s) we need to run to install the desired
                               1479                 :      * version of the extension.  If we do not have a script that directly
                               1480                 :      * does what is needed, we try to find a sequence of update scripts that
                               1481                 :      * will get us there.
                               1482                 :      */
 1060                          1483             469 :     filename = get_extension_script_filename(pcontrol, NULL, versionName);
 1060 tgl                      1484 CBC         469 :     if (stat(filename, &fst) == 0)
                               1485                 :     {
                               1486                 :         /* Easy, no extra scripts */
 1060 tgl                      1487 GIC         418 :         updateVersions = NIL;
                               1488                 :     }
                               1489                 :     else
                               1490                 :     {
 1060 tgl                      1491 ECB             :         /* Look for best way to install this version */
                               1492                 :         List       *evi_list;
                               1493                 :         ExtensionVersionInfo *evi_start;
                               1494                 :         ExtensionVersionInfo *evi_target;
                               1495                 : 
                               1496                 :         /* Extract the version update graph from the script directory */
 1060 tgl                      1497 GIC          51 :         evi_list = get_ext_ver_list(pcontrol);
                               1498                 : 
                               1499                 :         /* Identify the target version */
                               1500              51 :         evi_target = get_ext_ver_info(versionName, &evi_list);
                               1501                 : 
                               1502                 :         /* Identify best path to reach target */
                               1503              51 :         evi_start = find_install_path(evi_list, evi_target,
                               1504                 :                                       &updateVersions);
                               1505                 : 
                               1506                 :         /* Fail if no path ... */
                               1507              51 :         if (evi_start == NULL)
 1060 tgl                      1508 UIC           0 :             ereport(ERROR,
                               1509                 :                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 1060 tgl                      1510 ECB             :                      errmsg("extension \"%s\" has no installation script nor update path for version \"%s\"",
                               1511                 :                             pcontrol->name, versionName)));
                               1512                 : 
                               1513                 :         /* Otherwise, install best starting point and then upgrade */
 1060 tgl                      1514 GIC          51 :         versionName = evi_start->name;
 1060 tgl                      1515 ECB             :     }
                               1516                 : 
 4439                          1517                 :     /*
                               1518                 :      * Fetch control parameters for installation target version
                               1519                 :      */
 4439 tgl                      1520 GBC         469 :     control = read_extension_aux_control_file(pcontrol, versionName);
                               1521                 : 
                               1522                 :     /*
                               1523                 :      * Determine the target schema to install the extension into
 4443 tgl                      1524 ECB             :      */
 2401 tgl                      1525 GIC         469 :     if (schemaName)
                               1526                 :     {
                               1527                 :         /* If the user is giving us the schema name, it must exist already. */
 4443                          1528              22 :         schemaOid = get_namespace_oid(schemaName, false);
                               1529                 :     }
                               1530                 : 
 2745 andres                   1531             467 :     if (control->schema != NULL)
 4443 tgl                      1532 ECB             :     {
                               1533                 :         /*
                               1534                 :          * The extension is not relocatable and the author gave us a schema
                               1535                 :          * for it.
 2745 andres                   1536                 :          *
                               1537                 :          * Unless CASCADE parameter was given, it's an error to give a schema
                               1538                 :          * different from control->schema if control->schema is specified.
                               1539                 :          */
 2745 andres                   1540 GIC         331 :         if (schemaName && strcmp(control->schema, schemaName) != 0 &&
                               1541               2 :             !cascade)
                               1542               1 :             ereport(ERROR,
                               1543                 :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               1544                 :                      errmsg("extension \"%s\" must be installed in schema \"%s\"",
                               1545                 :                             control->name,
 2118 tgl                      1546 ECB             :                             control->schema)));
                               1547                 : 
                               1548                 :         /* Always use the schema from control file for current extension. */
 4443 tgl                      1549 CBC         330 :         schemaName = control->schema;
                               1550                 : 
                               1551                 :         /* Find or create the schema in case it does not exist. */
                               1552             330 :         schemaOid = get_namespace_oid(schemaName, true);
                               1553                 : 
 2745 andres                   1554 GIC         330 :         if (!OidIsValid(schemaOid))
                               1555                 :         {
 4247 tgl                      1556 CBC           3 :             CreateSchemaStmt *csstmt = makeNode(CreateSchemaStmt);
 4247 tgl                      1557 EUB             : 
 4247 tgl                      1558 GIC           3 :             csstmt->schemaname = schemaName;
 2953 alvherre                 1559               3 :             csstmt->authrole = NULL; /* will be created by current user */
 4247 tgl                      1560               3 :             csstmt->schemaElts = NIL;
 3840                          1561               3 :             csstmt->if_not_exists = false;
 2276                          1562               3 :             CreateSchemaCommand(csstmt, "(generated CREATE SCHEMA command)",
 2276 tgl                      1563 ECB             :                                 -1, -1);
                               1564                 : 
                               1565                 :             /*
                               1566                 :              * CreateSchemaCommand includes CommandCounterIncrement, so new
                               1567                 :              * schema is now visible.
                               1568                 :              */
 4247 tgl                      1569 CBC           3 :             schemaOid = get_namespace_oid(schemaName, false);
                               1570                 :         }
                               1571                 :     }
 2745 andres                   1572 GIC         136 :     else if (!OidIsValid(schemaOid))
                               1573                 :     {
 4443 tgl                      1574 ECB             :         /*
                               1575                 :          * Neither user nor author of the extension specified schema; use the
                               1576                 :          * current default creation namespace, which is the first explicit
 2745 andres                   1577                 :          * entry in the search_path.
                               1578                 :          */
 4382 bruce                    1579 GIC         118 :         List       *search_path = fetch_search_path(false);
 4443 tgl                      1580 ECB             : 
 3260 bruce                    1581 GIC         118 :         if (search_path == NIL) /* nothing valid in search_path? */
 3596 tgl                      1582 UIC           0 :             ereport(ERROR,
                               1583                 :                     (errcode(ERRCODE_UNDEFINED_SCHEMA),
                               1584                 :                      errmsg("no schema has been selected to create in")));
 4443 tgl                      1585 GIC         118 :         schemaOid = linitial_oid(search_path);
                               1586             118 :         schemaName = get_namespace_name(schemaOid);
 4382 bruce                    1587             118 :         if (schemaName == NULL) /* recently-deleted namespace? */
 3596 tgl                      1588 UIC           0 :             ereport(ERROR,
 3596 tgl                      1589 ECB             :                     (errcode(ERRCODE_UNDEFINED_SCHEMA),
                               1590                 :                      errmsg("no schema has been selected to create in")));
 4443                          1591                 : 
 4443 tgl                      1592 GIC         118 :         list_free(search_path);
                               1593                 :     }
                               1594                 : 
                               1595                 :     /*
                               1596                 :      * Make note if a temporary namespace has been accessed in this
                               1597                 :      * transaction.
 1542 michael                  1598 ECB             :      */
 1542 michael                  1599 GIC         466 :     if (isTempNamespace(schemaOid))
                               1600               2 :         MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPNAMESPACE;
 1542 michael                  1601 ECB             : 
                               1602                 :     /*
 4419 tgl                      1603                 :      * We don't check creation rights on the target namespace here.  If the
                               1604                 :      * extension script actually creates any objects there, it will fail if
                               1605                 :      * the user doesn't have such permissions.  But there are cases such as
                               1606                 :      * procedural languages where it's convenient to set schema = pg_catalog
 4382 bruce                    1607                 :      * yet we don't want to restrict the command to users with ACL_CREATE for
                               1608                 :      * pg_catalog.
 4443 tgl                      1609                 :      */
                               1610                 : 
                               1611                 :     /*
                               1612                 :      * Look up the prerequisite extensions, install them if necessary, and
                               1613                 :      * build lists of their OIDs and the OIDs of their target schemas.
                               1614                 :      */
 4443 tgl                      1615 GIC         466 :     requiredExtensions = NIL;
                               1616             466 :     requiredSchemas = NIL;
                               1617             491 :     foreach(lc, control->requires)
 4443 tgl                      1618 ECB             :     {
 4443 tgl                      1619 GIC          29 :         char       *curreq = (char *) lfirst(lc);
                               1620                 :         Oid         reqext;
 4443 tgl                      1621 ECB             :         Oid         reqschema;
                               1622                 : 
 2401 tgl                      1623 GIC          29 :         reqext = get_required_extension(curreq,
                               1624                 :                                         extensionName,
                               1625                 :                                         origSchemaName,
                               1626                 :                                         cascade,
                               1627                 :                                         parents,
 2401 tgl                      1628 ECB             :                                         is_create);
 4443 tgl                      1629 GIC          25 :         reqschema = get_extension_schema(reqext);
 4443 tgl                      1630 CBC          25 :         requiredExtensions = lappend_oid(requiredExtensions, reqext);
 4443 tgl                      1631 GBC          25 :         requiredSchemas = lappend_oid(requiredSchemas, reqschema);
                               1632                 :     }
                               1633                 : 
 4443 tgl                      1634 ECB             :     /*
 4442                          1635                 :      * Insert new tuple into pg_extension, and create dependency entries.
                               1636                 :      */
 2959 alvherre                 1637 GBC         462 :     address = InsertExtensionTuple(control->name, extowner,
 2959 alvherre                 1638 GIC         462 :                                    schemaOid, control->relocatable,
                               1639                 :                                    versionName,
                               1640                 :                                    PointerGetDatum(NULL),
 2959 alvherre                 1641 ECB             :                                    PointerGetDatum(NULL),
                               1642                 :                                    requiredExtensions);
 2959 alvherre                 1643 GIC         462 :     extensionOid = address.objectId;
                               1644                 : 
                               1645                 :     /*
                               1646                 :      * Apply any control-file comment on extension
                               1647                 :      */
 4442 tgl                      1648 CBC         462 :     if (control->comment != NULL)
                               1649             462 :         CreateComments(extensionOid, ExtensionRelationId, 0, control->comment);
                               1650                 : 
                               1651                 :     /*
                               1652                 :      * Execute the installation script file
                               1653                 :      */
 4439 tgl                      1654 GIC         462 :     execute_extension_script(extensionOid, control,
                               1655                 :                              NULL, versionName,
                               1656                 :                              requiredSchemas,
                               1657                 :                              schemaName, schemaOid);
                               1658                 : 
                               1659                 :     /*
                               1660                 :      * If additional update scripts have to be executed, apply the updates as
                               1661                 :      * though a series of ALTER EXTENSION UPDATE commands were given
                               1662                 :      */
                               1663             448 :     ApplyExtensionUpdates(extensionOid, pcontrol,
 2401 tgl                      1664 ECB             :                           versionName, updateVersions,
                               1665                 :                           origSchemaName, cascade, is_create);
 3759 rhaas                    1666                 : 
 2959 alvherre                 1667 GIC         448 :     return address;
 4442 tgl                      1668 ECB             : }
                               1669                 : 
                               1670                 : /*
                               1671                 :  * Get the OID of an extension listed in "requires", possibly creating it.
 2401                          1672                 :  */
                               1673                 : static Oid
 2401 tgl                      1674 GIC          29 : get_required_extension(char *reqExtensionName,
                               1675                 :                        char *extensionName,
                               1676                 :                        char *origSchemaName,
                               1677                 :                        bool cascade,
 2401 tgl                      1678 ECB             :                        List *parents,
                               1679                 :                        bool is_create)
                               1680                 : {
                               1681                 :     Oid         reqExtensionOid;
                               1682                 : 
 2401 tgl                      1683 GIC          29 :     reqExtensionOid = get_extension_oid(reqExtensionName, true);
                               1684              29 :     if (!OidIsValid(reqExtensionOid))
                               1685                 :     {
 2401 tgl                      1686 CBC          21 :         if (cascade)
 2401 tgl                      1687 ECB             :         {
                               1688                 :             /* Must install it. */
                               1689                 :             ObjectAddress addr;
                               1690                 :             List       *cascade_parents;
                               1691                 :             ListCell   *lc;
                               1692                 : 
                               1693                 :             /* Check extension name validity before trying to cascade. */
 2401 tgl                      1694 GIC          19 :             check_valid_extension_name(reqExtensionName);
                               1695                 : 
                               1696                 :             /* Check for cyclic dependency between extensions. */
 2401 tgl                      1697 CBC          21 :             foreach(lc, parents)
 2401 tgl                      1698 ECB             :             {
 2401 tgl                      1699 GIC           3 :                 char       *pname = (char *) lfirst(lc);
                               1700                 : 
                               1701               3 :                 if (strcmp(pname, reqExtensionName) == 0)
                               1702               1 :                     ereport(ERROR,
 2401 tgl                      1703 ECB             :                             (errcode(ERRCODE_INVALID_RECURSION),
                               1704                 :                              errmsg("cyclic dependency detected between extensions \"%s\" and \"%s\"",
                               1705                 :                                     reqExtensionName, extensionName)));
                               1706                 :             }
                               1707                 : 
 2401 tgl                      1708 GIC          18 :             ereport(NOTICE,
                               1709                 :                     (errmsg("installing required extension \"%s\"",
                               1710                 :                             reqExtensionName)));
                               1711                 : 
 2401 tgl                      1712 ECB             :             /* Add current extension to list of parents to pass down. */
 2401 tgl                      1713 GIC          18 :             cascade_parents = lappend(list_copy(parents), extensionName);
                               1714                 : 
                               1715                 :             /*
 2401 tgl                      1716 ECB             :              * Create the required extension.  We propagate the SCHEMA option
                               1717                 :              * if any, and CASCADE, but no other options.
                               1718                 :              */
 2401 tgl                      1719 GIC          18 :             addr = CreateExtensionInternal(reqExtensionName,
                               1720                 :                                            origSchemaName,
                               1721                 :                                            NULL,
                               1722                 :                                            cascade,
 2401 tgl                      1723 ECB             :                                            cascade_parents,
                               1724                 :                                            is_create);
                               1725                 : 
                               1726                 :             /* Get its newly-assigned OID. */
 2401 tgl                      1727 GIC          17 :             reqExtensionOid = addr.objectId;
                               1728                 :         }
                               1729                 :         else
                               1730               2 :             ereport(ERROR,
                               1731                 :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
 2401 tgl                      1732 ECB             :                      errmsg("required extension \"%s\" is not installed",
                               1733                 :                             reqExtensionName),
                               1734                 :                      is_create ?
                               1735                 :                      errhint("Use CREATE EXTENSION ... CASCADE to install required extensions too.") : 0));
                               1736                 :     }
                               1737                 : 
 2401 tgl                      1738 GIC          25 :     return reqExtensionOid;
                               1739                 : }
                               1740                 : 
                               1741                 : /*
                               1742                 :  * CREATE EXTENSION
 2745 andres                   1743 ECB             :  */
                               1744                 : ObjectAddress
 2406 peter_e                  1745 GIC         452 : CreateExtension(ParseState *pstate, CreateExtensionStmt *stmt)
 2745 andres                   1746 ECB             : {
 2401 tgl                      1747 GIC         452 :     DefElem    *d_schema = NULL;
 2401 tgl                      1748 CBC         452 :     DefElem    *d_new_version = NULL;
 2401 tgl                      1749 GIC         452 :     DefElem    *d_cascade = NULL;
 2401 tgl                      1750 CBC         452 :     char       *schemaName = NULL;
                               1751             452 :     char       *versionName = NULL;
 2401 tgl                      1752 GIC         452 :     bool        cascade = false;
                               1753                 :     ListCell   *lc;
                               1754                 : 
                               1755                 :     /* Check extension name validity before any filesystem access */
 2745 andres                   1756             452 :     check_valid_extension_name(stmt->extname);
 2745 andres                   1757 ECB             : 
                               1758                 :     /*
                               1759                 :      * Check for duplicate extension name.  The unique index on
                               1760                 :      * pg_extension.extname would catch this anyway, and serves as a backstop
                               1761                 :      * in case of race conditions; but this is a friendlier error message, and
                               1762                 :      * besides we need a check to support IF NOT EXISTS.
                               1763                 :      */
 2745 andres                   1764 GIC         452 :     if (get_extension_oid(stmt->extname, true) != InvalidOid)
                               1765                 :     {
                               1766               1 :         if (stmt->if_not_exists)
                               1767                 :         {
 2745 andres                   1768 CBC           1 :             ereport(NOTICE,
                               1769                 :                     (errcode(ERRCODE_DUPLICATE_OBJECT),
                               1770                 :                      errmsg("extension \"%s\" already exists, skipping",
                               1771                 :                             stmt->extname)));
 2745 andres                   1772 GIC           1 :             return InvalidObjectAddress;
                               1773                 :         }
                               1774                 :         else
 2745 andres                   1775 UIC           0 :             ereport(ERROR,
 2745 andres                   1776 ECB             :                     (errcode(ERRCODE_DUPLICATE_OBJECT),
                               1777                 :                      errmsg("extension \"%s\" already exists",
                               1778                 :                             stmt->extname)));
                               1779                 :     }
                               1780                 : 
                               1781                 :     /*
                               1782                 :      * We use global variables to track the extension being created, so we can
                               1783                 :      * create only one extension at the same time.
                               1784                 :      */
 2745 andres                   1785 GIC         451 :     if (creating_extension)
 2745 andres                   1786 UIC           0 :         ereport(ERROR,
 2745 andres                   1787 ECB             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               1788                 :                  errmsg("nested CREATE EXTENSION is not supported")));
                               1789                 : 
                               1790                 :     /* Deconstruct the statement option list */
 2401 tgl                      1791 GIC         490 :     foreach(lc, stmt->options)
                               1792                 :     {
                               1793              39 :         DefElem    *defel = (DefElem *) lfirst(lc);
 2401 tgl                      1794 ECB             : 
 2401 tgl                      1795 GIC          39 :         if (strcmp(defel->defname, "schema") == 0)
 2401 tgl                      1796 ECB             :         {
 2401 tgl                      1797 CBC          17 :             if (d_schema)
  633 dean.a.rasheed           1798 LBC           0 :                 errorConflictingDefElem(defel, pstate);
 2401 tgl                      1799 CBC          17 :             d_schema = defel;
                               1800              17 :             schemaName = defGetString(d_schema);
 2401 tgl                      1801 ECB             :         }
 2401 tgl                      1802 GIC          22 :         else if (strcmp(defel->defname, "new_version") == 0)
                               1803                 :         {
                               1804               3 :             if (d_new_version)
  633 dean.a.rasheed           1805 LBC           0 :                 errorConflictingDefElem(defel, pstate);
 2401 tgl                      1806 GIC           3 :             d_new_version = defel;
                               1807               3 :             versionName = defGetString(d_new_version);
                               1808                 :         }
                               1809              19 :         else if (strcmp(defel->defname, "cascade") == 0)
                               1810                 :         {
                               1811              19 :             if (d_cascade)
  633 dean.a.rasheed           1812 UIC           0 :                 errorConflictingDefElem(defel, pstate);
 2401 tgl                      1813 CBC          19 :             d_cascade = defel;
 2401 tgl                      1814 GIC          19 :             cascade = defGetBoolean(d_cascade);
 2401 tgl                      1815 ECB             :         }
                               1816                 :         else
 2401 tgl                      1817 LBC           0 :             elog(ERROR, "unrecognized option: %s", defel->defname);
                               1818                 :     }
                               1819                 : 
                               1820                 :     /* Call CreateExtensionInternal to do the real work. */
 2401 tgl                      1821 CBC         451 :     return CreateExtensionInternal(stmt->extname,
                               1822                 :                                    schemaName,
                               1823                 :                                    versionName,
 2401 tgl                      1824 EUB             :                                    cascade,
                               1825                 :                                    NIL,
                               1826                 :                                    true);
                               1827                 : }
                               1828                 : 
                               1829                 : /*
                               1830                 :  * InsertExtensionTuple
                               1831                 :  *
                               1832                 :  * Insert the new pg_extension row, and create extension's dependency entries.
                               1833                 :  * Return the OID assigned to the new row.
 4442 tgl                      1834 ECB             :  *
 4442 tgl                      1835 EUB             :  * This is exported for the benefit of pg_upgrade, which has to create a
                               1836                 :  * pg_extension entry (and the extension-level dependencies) without
                               1837                 :  * actually running the extension's script.
                               1838                 :  *
                               1839                 :  * extConfig and extCondition should be arrays or PointerGetDatum(NULL).
 4442 tgl                      1840 ECB             :  * We declare them as plain Datum to avoid needing array.h in extension.h.
                               1841                 :  */
 2959 alvherre                 1842                 : ObjectAddress
 4442 tgl                      1843 GIC         462 : InsertExtensionTuple(const char *extName, Oid extOwner,
 4442 tgl                      1844 ECB             :                      Oid schemaOid, bool relocatable, const char *extVersion,
                               1845                 :                      Datum extConfig, Datum extCondition,
                               1846                 :                      List *requiredExtensions)
 4442 tgl                      1847 EUB             : {
 4442 tgl                      1848 ECB             :     Oid         extensionOid;
                               1849                 :     Relation    rel;
                               1850                 :     Datum       values[Natts_pg_extension];
                               1851                 :     bool        nulls[Natts_pg_extension];
                               1852                 :     HeapTuple   tuple;
                               1853                 :     ObjectAddress myself;
 4442 tgl                      1854 EUB             :     ObjectAddress nsp;
 1012 michael                  1855 ECB             :     ObjectAddresses *refobjs;
 4442 tgl                      1856                 :     ListCell   *lc;
                               1857                 : 
                               1858                 :     /*
                               1859                 :      * Build and insert the pg_extension tuple
 4443                          1860                 :      */
 1539 andres                   1861 GBC         462 :     rel = table_open(ExtensionRelationId, RowExclusiveLock);
 4443 tgl                      1862 ECB             : 
 4443 tgl                      1863 CBC         462 :     memset(values, 0, sizeof(values));
 4443 tgl                      1864 GIC         462 :     memset(nulls, 0, sizeof(nulls));
                               1865                 : 
 1601 andres                   1866 GBC         462 :     extensionOid = GetNewOidWithIndex(rel, ExtensionOidIndexId,
                               1867                 :                                       Anum_pg_extension_oid);
 1601 andres                   1868 GIC         462 :     values[Anum_pg_extension_oid - 1] = ObjectIdGetDatum(extensionOid);
 4443 tgl                      1869             462 :     values[Anum_pg_extension_extname - 1] =
 4442 tgl                      1870 CBC         462 :         DirectFunctionCall1(namein, CStringGetDatum(extName));
 4442 tgl                      1871 GIC         462 :     values[Anum_pg_extension_extowner - 1] = ObjectIdGetDatum(extOwner);
 4443                          1872             462 :     values[Anum_pg_extension_extnamespace - 1] = ObjectIdGetDatum(schemaOid);
 4442                          1873             462 :     values[Anum_pg_extension_extrelocatable - 1] = BoolGetDatum(relocatable);
 4440                          1874             462 :     values[Anum_pg_extension_extversion - 1] = CStringGetTextDatum(extVersion);
                               1875                 : 
 4442                          1876             462 :     if (extConfig == PointerGetDatum(NULL))
                               1877             462 :         nulls[Anum_pg_extension_extconfig - 1] = true;
                               1878                 :     else
 4442 tgl                      1879 UIC           0 :         values[Anum_pg_extension_extconfig - 1] = extConfig;
                               1880                 : 
 4442 tgl                      1881 GIC         462 :     if (extCondition == PointerGetDatum(NULL))
                               1882             462 :         nulls[Anum_pg_extension_extcondition - 1] = true;
                               1883                 :     else
 4442 tgl                      1884 UIC           0 :         values[Anum_pg_extension_extcondition - 1] = extCondition;
                               1885                 : 
 4443 tgl                      1886 GIC         462 :     tuple = heap_form_tuple(rel->rd_att, values, nulls);
                               1887                 : 
 1601 andres                   1888             462 :     CatalogTupleInsert(rel, tuple);
                               1889                 : 
 4443 tgl                      1890             462 :     heap_freetuple(tuple);
 1539 andres                   1891             462 :     table_close(rel, RowExclusiveLock);
 4443 tgl                      1892 ECB             : 
                               1893                 :     /*
                               1894                 :      * Record dependencies on owner, schema, and prerequisite extensions
                               1895                 :      */
 4442 tgl                      1896 GIC         462 :     recordDependencyOnOwner(ExtensionRelationId, extensionOid, extOwner);
                               1897                 : 
 1012 michael                  1898             462 :     refobjs = new_object_addresses();
                               1899                 : 
                               1900             462 :     ObjectAddressSet(myself, ExtensionRelationId, extensionOid);
                               1901                 : 
                               1902             462 :     ObjectAddressSet(nsp, NamespaceRelationId, schemaOid);
                               1903             462 :     add_exact_object_address(&nsp, refobjs);
                               1904                 : 
 4443 tgl                      1905             487 :     foreach(lc, requiredExtensions)
                               1906                 :     {
                               1907              25 :         Oid         reqext = lfirst_oid(lc);
                               1908                 :         ObjectAddress otherext;
                               1909                 : 
 1012 michael                  1910 CBC          25 :         ObjectAddressSet(otherext, ExtensionRelationId, reqext);
 1012 michael                  1911 GIC          25 :         add_exact_object_address(&otherext, refobjs);
 4443 tgl                      1912 ECB             :     }
 1012 michael                  1913                 : 
                               1914                 :     /* Record all of them (this includes duplicate elimination) */
 1012 michael                  1915 CBC         462 :     record_object_address_dependencies(&myself, refobjs, DEPENDENCY_NORMAL);
 1012 michael                  1916 GIC         462 :     free_object_addresses(refobjs);
 1012 michael                  1917 ECB             : 
 4399 rhaas                    1918                 :     /* Post creation hook for new extension */
 3686 rhaas                    1919 CBC         462 :     InvokeObjectPostCreateHook(ExtensionRelationId, extensionOid, 0);
 4443 tgl                      1920 ECB             : 
 2959 alvherre                 1921 CBC         462 :     return myself;
 4443 tgl                      1922 ECB             : }
                               1923                 : 
                               1924                 : /*
                               1925                 :  * Guts of extension deletion.
                               1926                 :  *
                               1927                 :  * All we need do here is remove the pg_extension tuple itself.  Everything
 4443 tgl                      1928 EUB             :  * else is taken care of by the dependency infrastructure.
                               1929                 :  */
 4443 tgl                      1930 ECB             : void
 4443 tgl                      1931 CBC          48 : RemoveExtensionById(Oid extId)
                               1932                 : {
 4443 tgl                      1933 EUB             :     Relation    rel;
                               1934                 :     SysScanDesc scandesc;
 4443 tgl                      1935 ECB             :     HeapTuple   tuple;
                               1936                 :     ScanKeyData entry[1];
                               1937                 : 
                               1938                 :     /*
 4150                          1939                 :      * Disallow deletion of any extension that's currently open for insertion;
                               1940                 :      * else subsequent executions of recordDependencyOnCurrentExtension()
                               1941                 :      * could create dangling pg_depend records that refer to a no-longer-valid
                               1942                 :      * pg_extension OID.  This is needed not so much because we think people
                               1943                 :      * might write "DROP EXTENSION foo" in foo's own script files, as because
                               1944                 :      * errors in dependency management in extension script files could give
                               1945                 :      * rise to cases where an extension is dropped as a result of recursing
                               1946                 :      * from some contained object.  Because of that, we must test for the case
                               1947                 :      * here, not at some higher level of the DROP EXTENSION command.
                               1948                 :      */
 4150 tgl                      1949 CBC          48 :     if (extId == CurrentExtensionObject)
 4150 tgl                      1950 UIC           0 :         ereport(ERROR,
 4150 tgl                      1951 ECB             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 2118                          1952                 :                  errmsg("cannot drop extension \"%s\" because it is being modified",
                               1953                 :                         get_extension_name(extId))));
 4150                          1954                 : 
 1539 andres                   1955 GIC          48 :     rel = table_open(ExtensionRelationId, RowExclusiveLock);
 4443 tgl                      1956 ECB             : 
 4443 tgl                      1957 GIC          48 :     ScanKeyInit(&entry[0],
                               1958                 :                 Anum_pg_extension_oid,
 4443 tgl                      1959 ECB             :                 BTEqualStrategyNumber, F_OIDEQ,
                               1960                 :                 ObjectIdGetDatum(extId));
 4443 tgl                      1961 GIC          48 :     scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
                               1962                 :                                   NULL, 1, entry);
                               1963                 : 
 4443 tgl                      1964 CBC          48 :     tuple = systable_getnext(scandesc);
 4443 tgl                      1965 ECB             : 
                               1966                 :     /* We assume that there can be at most one matching tuple */
 4443 tgl                      1967 GIC          48 :     if (HeapTupleIsValid(tuple))
 2258 tgl                      1968 CBC          48 :         CatalogTupleDelete(rel, &tuple->t_self);
                               1969                 : 
 4443                          1970              48 :     systable_endscan(scandesc);
                               1971                 : 
 1539 andres                   1972 GIC          48 :     table_close(rel, RowExclusiveLock);
 4443 tgl                      1973              48 : }
                               1974                 : 
                               1975                 : /*
                               1976                 :  * This function lists the available extensions (one row per primary control
                               1977                 :  * file in the control directory).  We parse each control file and report the
                               1978                 :  * interesting fields.
                               1979                 :  *
 4443 tgl                      1980 ECB             :  * The system view pg_available_extensions provides a user interface to this
                               1981                 :  * SRF, adding information about whether the extensions are installed in the
                               1982                 :  * current DB.
                               1983                 :  */
                               1984                 : Datum
 4443 tgl                      1985 GIC           9 : pg_available_extensions(PG_FUNCTION_ARGS)
                               1986                 : {
 4382 bruce                    1987               9 :     ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
                               1988                 :     char       *location;
                               1989                 :     DIR        *dir;
                               1990                 :     struct dirent *de;
                               1991                 : 
                               1992                 :     /* Build tuplestore to hold the result rows */
  173 michael                  1993               9 :     InitMaterializedSRF(fcinfo, 0);
                               1994                 : 
 4443 tgl                      1995               9 :     location = get_extension_control_directory();
 4382 bruce                    1996               9 :     dir = AllocateDir(location);
                               1997                 : 
 4443 tgl                      1998 ECB             :     /*
 4382 bruce                    1999 EUB             :      * If the control directory doesn't exist, we want to silently return an
                               2000                 :      * empty set.  Any other error will be reported by ReadDir.
                               2001                 :      */
 4443 tgl                      2002 GIC           9 :     if (dir == NULL && errno == ENOENT)
                               2003                 :     {
 4443 tgl                      2004 ECB             :         /* do nothing */
                               2005                 :     }
                               2006                 :     else
                               2007                 :     {
 4443 tgl                      2008 GIC        2781 :         while ((de = ReadDir(dir, location)) != NULL)
                               2009                 :         {
 4443 tgl                      2010 ECB             :             ExtensionControlFile *control;
                               2011                 :             char       *extname;
                               2012                 :             Datum       values[3];
 4437                          2013                 :             bool        nulls[3];
                               2014                 : 
 4443 tgl                      2015 GIC        2772 :             if (!is_extension_control_filename(de->d_name))
 4443 tgl                      2016 CBC        1899 :                 continue;
 4443 tgl                      2017 ECB             : 
                               2018                 :             /* extract extension name from 'name.control' filename */
 4443 tgl                      2019 CBC         873 :             extname = pstrdup(de->d_name);
 4443 tgl                      2020 GIC         873 :             *strrchr(extname, '.') = '\0';
 4443 tgl                      2021 ECB             : 
 4438                          2022                 :             /* ignore it if it's an auxiliary control file */
 4438 tgl                      2023 GIC         873 :             if (strstr(extname, "--"))
 4438 tgl                      2024 UIC           0 :                 continue;
                               2025                 : 
 4443 tgl                      2026 GIC         873 :             control = read_extension_control_file(extname);
                               2027                 : 
                               2028             873 :             memset(values, 0, sizeof(values));
                               2029             873 :             memset(nulls, 0, sizeof(nulls));
                               2030                 : 
                               2031                 :             /* name */
                               2032             873 :             values[0] = DirectFunctionCall1(namein,
                               2033                 :                                             CStringGetDatum(control->name));
 4440 tgl                      2034 ECB             :             /* default_version */
 4440 tgl                      2035 GIC         873 :             if (control->default_version == NULL)
 4443 tgl                      2036 LBC           0 :                 nulls[1] = true;
                               2037                 :             else
 4440 tgl                      2038 GIC         873 :                 values[1] = CStringGetTextDatum(control->default_version);
                               2039                 :             /* comment */
 4443                          2040             873 :             if (control->comment == NULL)
 4437 tgl                      2041 UIC           0 :                 nulls[2] = true;
 4443 tgl                      2042 ECB             :             else
 4437 tgl                      2043 GIC         873 :                 values[2] = CStringGetTextDatum(control->comment);
 4443 tgl                      2044 ECB             : 
  398 michael                  2045 CBC         873 :             tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
                               2046                 :                                  values, nulls);
                               2047                 :         }
                               2048                 : 
 4443 tgl                      2049 GIC           9 :         FreeDir(dir);
                               2050                 :     }
 4443 tgl                      2051 ECB             : 
 4443 tgl                      2052 GIC           9 :     return (Datum) 0;
                               2053                 : }
                               2054                 : 
                               2055                 : /*
                               2056                 :  * This function lists the available extension versions (one row per
 3260 bruce                    2057 ECB             :  * extension installation script).  For each version, we parse the related
                               2058                 :  * control file(s) and report the interesting fields.
                               2059                 :  *
                               2060                 :  * The system view pg_available_extension_versions provides a user interface
                               2061                 :  * to this SRF, adding information about which versions are installed in the
                               2062                 :  * current DB.
                               2063                 :  */
 4437 tgl                      2064                 : Datum
 4437 tgl                      2065 CBC           3 : pg_available_extension_versions(PG_FUNCTION_ARGS)
                               2066                 : {
 4382 bruce                    2067 GIC           3 :     ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
 4382 bruce                    2068 ECB             :     char       *location;
                               2069                 :     DIR        *dir;
                               2070                 :     struct dirent *de;
                               2071                 : 
 4437 tgl                      2072                 :     /* Build tuplestore to hold the result rows */
  173 michael                  2073 GBC           3 :     InitMaterializedSRF(fcinfo, 0);
                               2074                 : 
 4437 tgl                      2075 CBC           3 :     location = get_extension_control_directory();
 4382 bruce                    2076 GIC           3 :     dir = AllocateDir(location);
 4437 tgl                      2077 ECB             : 
                               2078                 :     /*
                               2079                 :      * If the control directory doesn't exist, we want to silently return an
                               2080                 :      * empty set.  Any other error will be reported by ReadDir.
                               2081                 :      */
 4437 tgl                      2082 GIC           3 :     if (dir == NULL && errno == ENOENT)
                               2083                 :     {
 4437 tgl                      2084 ECB             :         /* do nothing */
 4437 tgl                      2085 EUB             :     }
                               2086                 :     else
 4437 tgl                      2087 ECB             :     {
 4437 tgl                      2088 GIC         927 :         while ((de = ReadDir(dir, location)) != NULL)
 4437 tgl                      2089 ECB             :         {
 4437 tgl                      2090 EUB             :             ExtensionControlFile *control;
                               2091                 :             char       *extname;
 4437 tgl                      2092 ECB             : 
 4437 tgl                      2093 GIC         924 :             if (!is_extension_control_filename(de->d_name))
 4437 tgl                      2094 CBC         633 :                 continue;
                               2095                 : 
                               2096                 :             /* extract extension name from 'name.control' filename */
 4437 tgl                      2097 GIC         291 :             extname = pstrdup(de->d_name);
 4437 tgl                      2098 CBC         291 :             *strrchr(extname, '.') = '\0';
                               2099                 : 
                               2100                 :             /* ignore it if it's an auxiliary control file */
                               2101             291 :             if (strstr(extname, "--"))
 4437 tgl                      2102 UIC           0 :                 continue;
                               2103                 : 
                               2104                 :             /* read the control file */
 4437 tgl                      2105 GIC         291 :             control = read_extension_control_file(extname);
                               2106                 : 
                               2107                 :             /* scan extension's script directory for install scripts */
  398 michael                  2108             291 :             get_available_versions_for_extension(control, rsinfo->setResult,
                               2109                 :                                                  rsinfo->setDesc);
                               2110                 :         }
                               2111                 : 
 4437 tgl                      2112               3 :         FreeDir(dir);
                               2113                 :     }
 4437 tgl                      2114 ECB             : 
 4437 tgl                      2115 GIC           3 :     return (Datum) 0;
 4437 tgl                      2116 ECB             : }
                               2117                 : 
                               2118                 : /*
                               2119                 :  * Inner loop for pg_available_extension_versions:
                               2120                 :  *      read versions of one extension, add rows to tupstore
                               2121                 :  */
                               2122                 : static void
 4437 tgl                      2123 GIC         291 : get_available_versions_for_extension(ExtensionControlFile *pcontrol,
 4437 tgl                      2124 ECB             :                                      Tuplestorestate *tupstore,
                               2125                 :                                      TupleDesc tupdesc)
                               2126                 : {
                               2127                 :     List       *evi_list;
                               2128                 :     ListCell   *lc;
                               2129                 : 
                               2130                 :     /* Extract the version update graph from the script directory */
 2401 tgl                      2131 CBC         291 :     evi_list = get_ext_ver_list(pcontrol);
                               2132                 : 
                               2133                 :     /* For each installable version ... */
 2401 tgl                      2134 GIC         918 :     foreach(lc, evi_list)
                               2135                 :     {
                               2136             627 :         ExtensionVersionInfo *evi = (ExtensionVersionInfo *) lfirst(lc);
 4437 tgl                      2137 ECB             :         ExtensionControlFile *control;
                               2138                 :         Datum       values[8];
                               2139                 :         bool        nulls[8];
                               2140                 :         ListCell   *lc2;
                               2141                 : 
 2401 tgl                      2142 CBC         627 :         if (!evi->installable)
 4437                          2143             336 :             continue;
                               2144                 : 
                               2145                 :         /*
 4437 tgl                      2146 ECB             :          * Fetch parameters for specific version (pcontrol is not changed)
                               2147                 :          */
 2401 tgl                      2148 GIC         291 :         control = read_extension_aux_control_file(pcontrol, evi->name);
                               2149                 : 
 4437 tgl                      2150 CBC         291 :         memset(values, 0, sizeof(values));
 4437 tgl                      2151 GBC         291 :         memset(nulls, 0, sizeof(nulls));
                               2152                 : 
                               2153                 :         /* name */
 4437 tgl                      2154 CBC         291 :         values[0] = DirectFunctionCall1(namein,
                               2155                 :                                         CStringGetDatum(control->name));
                               2156                 :         /* version */
 2401                          2157             291 :         values[1] = CStringGetTextDatum(evi->name);
                               2158                 :         /* superuser */
 4419 tgl                      2159 GIC         291 :         values[2] = BoolGetDatum(control->superuser);
                               2160                 :         /* trusted */
 1166 tgl                      2161 CBC         291 :         values[3] = BoolGetDatum(control->trusted);
                               2162                 :         /* relocatable */
 1166 tgl                      2163 GIC         291 :         values[4] = BoolGetDatum(control->relocatable);
 4437 tgl                      2164 ECB             :         /* schema */
 4437 tgl                      2165 GIC         291 :         if (control->schema == NULL)
 1166                          2166             255 :             nulls[5] = true;
                               2167                 :         else
                               2168              36 :             values[5] = DirectFunctionCall1(namein,
                               2169                 :                                             CStringGetDatum(control->schema));
                               2170                 :         /* requires */
 4437                          2171             291 :         if (control->requires == NIL)
 1166 tgl                      2172 CBC         240 :             nulls[6] = true;
                               2173                 :         else
 1166 tgl                      2174 GIC          51 :             values[6] = convert_requires_to_datum(control->requires);
                               2175                 :         /* comment */
 4437                          2176             291 :         if (control->comment == NULL)
 1166 tgl                      2177 UIC           0 :             nulls[7] = true;
                               2178                 :         else
 1166 tgl                      2179 GIC         291 :             values[7] = CStringGetTextDatum(control->comment);
 4437 tgl                      2180 ECB             : 
 4437 tgl                      2181 GIC         291 :         tuplestore_putvalues(tupstore, tupdesc, values, nulls);
                               2182                 : 
 2401 tgl                      2183 ECB             :         /*
                               2184                 :          * Find all non-directly-installable versions that would be installed
                               2185                 :          * starting from this version, and report them, inheriting the
                               2186                 :          * parameters that aren't changed in updates from this version.
                               2187                 :          */
 2401 tgl                      2188 GIC         918 :         foreach(lc2, evi_list)
                               2189                 :         {
                               2190             627 :             ExtensionVersionInfo *evi2 = (ExtensionVersionInfo *) lfirst(lc2);
 2401 tgl                      2191 ECB             :             List       *best_path;
                               2192                 : 
 2401 tgl                      2193 GIC         627 :             if (evi2->installable)
                               2194             291 :                 continue;
                               2195             336 :             if (find_install_path(evi_list, evi2, &best_path) == evi)
                               2196                 :             {
 2401 tgl                      2197 ECB             :                 /*
                               2198                 :                  * Fetch parameters for this version (pcontrol is not changed)
                               2199                 :                  */
 2401 tgl                      2200 CBC         177 :                 control = read_extension_aux_control_file(pcontrol, evi2->name);
                               2201                 : 
                               2202                 :                 /* name stays the same */
 2401 tgl                      2203 ECB             :                 /* version */
 2401 tgl                      2204 GIC         177 :                 values[1] = CStringGetTextDatum(evi2->name);
                               2205                 :                 /* superuser */
 2401 tgl                      2206 CBC         177 :                 values[2] = BoolGetDatum(control->superuser);
                               2207                 :                 /* trusted */
 1166                          2208             177 :                 values[3] = BoolGetDatum(control->trusted);
                               2209                 :                 /* relocatable */
                               2210             177 :                 values[4] = BoolGetDatum(control->relocatable);
                               2211                 :                 /* schema stays the same */
 2401 tgl                      2212 ECB             :                 /* requires */
 2401 tgl                      2213 GIC         177 :                 if (control->requires == NIL)
 1166 tgl                      2214 CBC         177 :                     nulls[6] = true;
 2401 tgl                      2215 ECB             :                 else
                               2216                 :                 {
 1166 tgl                      2217 LBC           0 :                     values[6] = convert_requires_to_datum(control->requires);
 1166 tgl                      2218 UIC           0 :                     nulls[6] = false;
                               2219                 :                 }
 2401 tgl                      2220 ECB             :                 /* comment stays the same */
                               2221                 : 
 2401 tgl                      2222 GIC         177 :                 tuplestore_putvalues(tupstore, tupdesc, values, nulls);
 2401 tgl                      2223 ECB             :             }
                               2224                 :         }
 4437                          2225                 :     }
 2401 tgl                      2226 GBC         291 : }
                               2227                 : 
 1166 tgl                      2228 ECB             : /*
                               2229                 :  * Test whether the given extension exists (not whether it's installed)
                               2230                 :  *
                               2231                 :  * This checks for the existence of a matching control file in the extension
                               2232                 :  * directory.  That's not a bulletproof check, since the file might be
                               2233                 :  * invalid, but this is only used for hints so it doesn't have to be 100%
                               2234                 :  * right.
                               2235                 :  */
                               2236                 : bool
 1166 tgl                      2237 LBC           0 : extension_file_exists(const char *extensionName)
                               2238                 : {
                               2239               0 :     bool        result = false;
                               2240                 :     char       *location;
                               2241                 :     DIR        *dir;
 1166 tgl                      2242 ECB             :     struct dirent *de;
                               2243                 : 
 1166 tgl                      2244 LBC           0 :     location = get_extension_control_directory();
 1166 tgl                      2245 UIC           0 :     dir = AllocateDir(location);
                               2246                 : 
                               2247                 :     /*
                               2248                 :      * If the control directory doesn't exist, we want to silently return
 1166 tgl                      2249 ECB             :      * false.  Any other error will be reported by ReadDir.
                               2250                 :      */
 1166 tgl                      2251 UIC           0 :     if (dir == NULL && errno == ENOENT)
                               2252                 :     {
 1166 tgl                      2253 ECB             :         /* do nothing */
                               2254                 :     }
                               2255                 :     else
                               2256                 :     {
 1166 tgl                      2257 LBC           0 :         while ((de = ReadDir(dir, location)) != NULL)
                               2258                 :         {
 1166 tgl                      2259 ECB             :             char       *extname;
                               2260                 : 
 1166 tgl                      2261 UIC           0 :             if (!is_extension_control_filename(de->d_name))
 1166 tgl                      2262 LBC           0 :                 continue;
 1166 tgl                      2263 ECB             : 
                               2264                 :             /* extract extension name from 'name.control' filename */
 1166 tgl                      2265 UIC           0 :             extname = pstrdup(de->d_name);
 1166 tgl                      2266 UBC           0 :             *strrchr(extname, '.') = '\0';
 1166 tgl                      2267 EUB             : 
                               2268                 :             /* ignore it if it's an auxiliary control file */
 1166 tgl                      2269 UIC           0 :             if (strstr(extname, "--"))
                               2270               0 :                 continue;
 1166 tgl                      2271 ECB             : 
                               2272                 :             /* done if it matches request */
 1166 tgl                      2273 UIC           0 :             if (strcmp(extname, extensionName) == 0)
                               2274                 :             {
 1166 tgl                      2275 LBC           0 :                 result = true;
 1166 tgl                      2276 UIC           0 :                 break;
                               2277                 :             }
                               2278                 :         }
                               2279                 : 
                               2280               0 :         FreeDir(dir);
                               2281                 :     }
                               2282                 : 
                               2283               0 :     return result;
                               2284                 : }
                               2285                 : 
 2401 tgl                      2286 EUB             : /*
                               2287                 :  * Convert a list of extension names to a name[] Datum
                               2288                 :  */
                               2289                 : static Datum
 2401 tgl                      2290 GIC          51 : convert_requires_to_datum(List *requires)
                               2291                 : {
                               2292                 :     Datum      *datums;
 2401 tgl                      2293 EUB             :     int         ndatums;
                               2294                 :     ArrayType  *a;
                               2295                 :     ListCell   *lc;
                               2296                 : 
 2401 tgl                      2297 GIC          51 :     ndatums = list_length(requires);
                               2298              51 :     datums = (Datum *) palloc(ndatums * sizeof(Datum));
                               2299              51 :     ndatums = 0;
 2401 tgl                      2300 GBC         123 :     foreach(lc, requires)
                               2301                 :     {
 2401 tgl                      2302 GIC          72 :         char       *curreq = (char *) lfirst(lc);
                               2303                 : 
                               2304              72 :         datums[ndatums++] =
                               2305              72 :             DirectFunctionCall1(namein, CStringGetDatum(curreq));
 2401 tgl                      2306 EUB             :     }
  282 peter                    2307 GNC          51 :     a = construct_array_builtin(datums, ndatums, NAMEOID);
 2401 tgl                      2308 GBC          51 :     return PointerGetDatum(a);
 4437 tgl                      2309 EUB             : }
                               2310                 : 
                               2311                 : /*
                               2312                 :  * This function reports the version update paths that exist for the
                               2313                 :  * specified extension.
                               2314                 :  */
                               2315                 : Datum
 4437 tgl                      2316 UBC           0 : pg_extension_update_paths(PG_FUNCTION_ARGS)
 4437 tgl                      2317 EUB             : {
 4437 tgl                      2318 UIC           0 :     Name        extname = PG_GETARG_NAME(0);
 4382 bruce                    2319               0 :     ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
 4437 tgl                      2320 EUB             :     List       *evi_list;
                               2321                 :     ExtensionControlFile *control;
                               2322                 :     ListCell   *lc1;
                               2323                 : 
                               2324                 :     /* Check extension name validity before any filesystem access */
 4437 tgl                      2325 UIC           0 :     check_valid_extension_name(NameStr(*extname));
                               2326                 : 
 4437 tgl                      2327 EUB             :     /* Build tuplestore to hold the result rows */
  173 michael                  2328 UIC           0 :     InitMaterializedSRF(fcinfo, 0);
                               2329                 : 
 4437 tgl                      2330 EUB             :     /* Read the extension's control file */
 4437 tgl                      2331 UIC           0 :     control = read_extension_control_file(NameStr(*extname));
                               2332                 : 
                               2333                 :     /* Extract the version update graph from the script directory */
                               2334               0 :     evi_list = get_ext_ver_list(control);
                               2335                 : 
                               2336                 :     /* Iterate over all pairs of versions */
 4437 tgl                      2337 LBC           0 :     foreach(lc1, evi_list)
                               2338                 :     {
 4437 tgl                      2339 UIC           0 :         ExtensionVersionInfo *evi1 = (ExtensionVersionInfo *) lfirst(lc1);
                               2340                 :         ListCell   *lc2;
                               2341                 : 
                               2342               0 :         foreach(lc2, evi_list)
                               2343                 :         {
 4437 tgl                      2344 LBC           0 :             ExtensionVersionInfo *evi2 = (ExtensionVersionInfo *) lfirst(lc2);
 4437 tgl                      2345 ECB             :             List       *path;
                               2346                 :             Datum       values[3];
                               2347                 :             bool        nulls[3];
                               2348                 : 
 4437 tgl                      2349 LBC           0 :             if (evi1 == evi2)
 4437 tgl                      2350 UIC           0 :                 continue;
 4437 tgl                      2351 ECB             : 
                               2352                 :             /* Find shortest path from evi1 to evi2 */
 2401 tgl                      2353 UIC           0 :             path = find_update_path(evi_list, evi1, evi2, false, true);
 4437 tgl                      2354 ECB             : 
                               2355                 :             /* Emit result row */
 4437 tgl                      2356 UIC           0 :             memset(values, 0, sizeof(values));
                               2357               0 :             memset(nulls, 0, sizeof(nulls));
                               2358                 : 
                               2359                 :             /* source */
                               2360               0 :             values[0] = CStringGetTextDatum(evi1->name);
                               2361                 :             /* target */
                               2362               0 :             values[1] = CStringGetTextDatum(evi2->name);
 4437 tgl                      2363 EUB             :             /* path */
 4437 tgl                      2364 UIC           0 :             if (path == NIL)
 4437 tgl                      2365 UBC           0 :                 nulls[2] = true;
 4437 tgl                      2366 EUB             :             else
                               2367                 :             {
                               2368                 :                 StringInfoData pathbuf;
                               2369                 :                 ListCell   *lcv;
                               2370                 : 
 4437 tgl                      2371 UIC           0 :                 initStringInfo(&pathbuf);
 4437 tgl                      2372 EUB             :                 /* The path doesn't include start vertex, but show it */
 4437 tgl                      2373 UIC           0 :                 appendStringInfoString(&pathbuf, evi1->name);
                               2374               0 :                 foreach(lcv, path)
 4437 tgl                      2375 EUB             :                 {
 4437 tgl                      2376 UIC           0 :                     char       *versionName = (char *) lfirst(lcv);
                               2377                 : 
 4437 tgl                      2378 UBC           0 :                     appendStringInfoString(&pathbuf, "--");
 4437 tgl                      2379 UIC           0 :                     appendStringInfoString(&pathbuf, versionName);
                               2380                 :                 }
 4437 tgl                      2381 UBC           0 :                 values[2] = CStringGetTextDatum(pathbuf.data);
 4437 tgl                      2382 UIC           0 :                 pfree(pathbuf.data);
                               2383                 :             }
 4437 tgl                      2384 EUB             : 
  398 michael                  2385 UIC           0 :             tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
  398 michael                  2386 EUB             :                                  values, nulls);
                               2387                 :         }
                               2388                 :     }
 4437 tgl                      2389                 : 
 4437 tgl                      2390 UIC           0 :     return (Datum) 0;
 4437 tgl                      2391 EUB             : }
                               2392                 : 
                               2393                 : /*
                               2394                 :  * pg_extension_config_dump
                               2395                 :  *
 4443                          2396                 :  * Record information about a configuration table that belongs to an
                               2397                 :  * extension being created, but whose contents should be dumped in whole
                               2398                 :  * or in part during pg_dump.
                               2399                 :  */
                               2400                 : Datum
 4443 tgl                      2401 GIC           4 : pg_extension_config_dump(PG_FUNCTION_ARGS)
                               2402                 : {
 4443 tgl                      2403 GBC           4 :     Oid         tableoid = PG_GETARG_OID(0);
 2219 noah                     2404               4 :     text       *wherecond = PG_GETARG_TEXT_PP(1);
                               2405                 :     char       *tablename;
                               2406                 :     Relation    extRel;
 4382 bruce                    2407 EUB             :     ScanKeyData key[1];
                               2408                 :     SysScanDesc extScan;
 4443 tgl                      2409                 :     HeapTuple   extTup;
                               2410                 :     Datum       arrayDatum;
                               2411                 :     Datum       elementDatum;
 3762                          2412                 :     int         arrayLength;
                               2413                 :     int         arrayIndex;
                               2414                 :     bool        isnull;
                               2415                 :     Datum       repl_val[Natts_pg_extension];
                               2416                 :     bool        repl_null[Natts_pg_extension];
                               2417                 :     bool        repl_repl[Natts_pg_extension];
 4443                          2418                 :     ArrayType  *a;
                               2419                 : 
                               2420                 :     /*
 4382 bruce                    2421                 :      * We only allow this to be called from an extension's SQL script. We
                               2422                 :      * shouldn't need any permissions check beyond that.
 4443 tgl                      2423                 :      */
 4443 tgl                      2424 GIC           4 :     if (!creating_extension)
 4443 tgl                      2425 UBC           0 :         ereport(ERROR,
 4443 tgl                      2426 EUB             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               2427                 :                  errmsg("%s can only be called from an SQL script executed by CREATE EXTENSION",
 1572 alvherre                 2428                 :                         "pg_extension_config_dump()")));
 4443 tgl                      2429                 : 
                               2430                 :     /*
                               2431                 :      * Check that the table exists and is a member of the extension being
 3762                          2432                 :      * created.  This ensures that we don't need to register an additional
                               2433                 :      * dependency to protect the extconfig entry.
                               2434                 :      */
 4443 tgl                      2435 GIC           4 :     tablename = get_rel_name(tableoid);
                               2436               4 :     if (tablename == NULL)
 4443 tgl                      2437 UBC           0 :         ereport(ERROR,
                               2438                 :                 (errcode(ERRCODE_UNDEFINED_TABLE),
                               2439                 :                  errmsg("OID %u does not refer to a table", tableoid)));
 4443 tgl                      2440 GIC           4 :     if (getExtensionOfObject(RelationRelationId, tableoid) !=
                               2441                 :         CurrentExtensionObject)
 4443 tgl                      2442 UIC           0 :         ereport(ERROR,
                               2443                 :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                               2444                 :                  errmsg("table \"%s\" is not a member of the extension being created",
                               2445                 :                         tablename)));
                               2446                 : 
                               2447                 :     /*
 4382 bruce                    2448 ECB             :      * Add the table OID and WHERE condition to the extension's extconfig and
                               2449                 :      * extcondition arrays.
 3762 tgl                      2450                 :      *
                               2451                 :      * If the table is already in extconfig, treat this as an update of the
                               2452                 :      * WHERE condition.
                               2453                 :      */
                               2454                 : 
                               2455                 :     /* Find the pg_extension tuple */
 1539 andres                   2456 GIC           4 :     extRel = table_open(ExtensionRelationId, RowExclusiveLock);
                               2457                 : 
 4443 tgl                      2458               4 :     ScanKeyInit(&key[0],
                               2459                 :                 Anum_pg_extension_oid,
                               2460                 :                 BTEqualStrategyNumber, F_OIDEQ,
                               2461                 :                 ObjectIdGetDatum(CurrentExtensionObject));
                               2462                 : 
                               2463               4 :     extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
                               2464                 :                                  NULL, 1, key);
                               2465                 : 
                               2466               4 :     extTup = systable_getnext(extScan);
                               2467                 : 
 2118                          2468               4 :     if (!HeapTupleIsValid(extTup))  /* should not happen */
 2135 tgl                      2469 UIC           0 :         elog(ERROR, "could not find tuple for extension %u",
                               2470                 :              CurrentExtensionObject);
 4443 tgl                      2471 ECB             : 
 4443 tgl                      2472 GBC           4 :     memset(repl_val, 0, sizeof(repl_val));
 4443 tgl                      2473 GIC           4 :     memset(repl_null, false, sizeof(repl_null));
                               2474               4 :     memset(repl_repl, false, sizeof(repl_repl));
                               2475                 : 
                               2476                 :     /* Build or modify the extconfig value */
                               2477               4 :     elementDatum = ObjectIdGetDatum(tableoid);
                               2478                 : 
                               2479               4 :     arrayDatum = heap_getattr(extTup, Anum_pg_extension_extconfig,
                               2480                 :                               RelationGetDescr(extRel), &isnull);
                               2481               4 :     if (isnull)
 4443 tgl                      2482 ECB             :     {
 3762                          2483                 :         /* Previously empty extconfig, so build 1-element array */
 3762 tgl                      2484 GBC           2 :         arrayLength = 0;
 3762 tgl                      2485 GIC           2 :         arrayIndex = 1;
                               2486                 : 
  282 peter                    2487 GNC           2 :         a = construct_array_builtin(&elementDatum, 1, OIDOID);
                               2488                 :     }
                               2489                 :     else
                               2490                 :     {
                               2491                 :         /* Modify or extend existing extconfig array */
                               2492                 :         Oid        *arrayData;
                               2493                 :         int         i;
                               2494                 : 
 4443 tgl                      2495 GIC           2 :         a = DatumGetArrayTypeP(arrayDatum);
                               2496                 : 
 3762                          2497               2 :         arrayLength = ARR_DIMS(a)[0];
                               2498               2 :         if (ARR_NDIM(a) != 1 ||
                               2499               2 :             ARR_LBOUND(a)[0] != 1 ||
                               2500               2 :             arrayLength < 0 ||
 3762 tgl                      2501 CBC           2 :             ARR_HASNULL(a) ||
 3762 tgl                      2502 GIC           2 :             ARR_ELEMTYPE(a) != OIDOID)
 3762 tgl                      2503 LBC           0 :             elog(ERROR, "extconfig is not a 1-D Oid array");
 3762 tgl                      2504 GIC           2 :         arrayData = (Oid *) ARR_DATA_PTR(a);
                               2505                 : 
                               2506               2 :         arrayIndex = arrayLength + 1;   /* set up to add after end */
                               2507                 : 
 3762 tgl                      2508 CBC           4 :         for (i = 0; i < arrayLength; i++)
                               2509                 :         {
 3762 tgl                      2510 GIC           2 :             if (arrayData[i] == tableoid)
 3762 tgl                      2511 ECB             :             {
 2118 tgl                      2512 UIC           0 :                 arrayIndex = i + 1; /* replace this element instead */
 3762 tgl                      2513 LBC           0 :                 break;
 3762 tgl                      2514 EUB             :             }
                               2515                 :         }
                               2516                 : 
 4443 tgl                      2517 CBC           2 :         a = array_set(a, 1, &arrayIndex,
 4443 tgl                      2518 ECB             :                       elementDatum,
                               2519                 :                       false,
                               2520                 :                       -1 /* varlena array */ ,
                               2521                 :                       sizeof(Oid) /* OID's typlen */ ,
                               2522                 :                       true /* OID's typbyval */ ,
                               2523                 :                       TYPALIGN_INT /* OID's typalign */ );
                               2524                 :     }
 4443 tgl                      2525 GIC           4 :     repl_val[Anum_pg_extension_extconfig - 1] = PointerGetDatum(a);
 4443 tgl                      2526 CBC           4 :     repl_repl[Anum_pg_extension_extconfig - 1] = true;
                               2527                 : 
                               2528                 :     /* Build or modify the extcondition value */
                               2529               4 :     elementDatum = PointerGetDatum(wherecond);
 4443 tgl                      2530 ECB             : 
 4443 tgl                      2531 GIC           4 :     arrayDatum = heap_getattr(extTup, Anum_pg_extension_extcondition,
 4443 tgl                      2532 ECB             :                               RelationGetDescr(extRel), &isnull);
 4443 tgl                      2533 GIC           4 :     if (isnull)
                               2534                 :     {
 3762                          2535               2 :         if (arrayLength != 0)
 3762 tgl                      2536 UIC           0 :             elog(ERROR, "extconfig and extcondition arrays do not match");
                               2537                 : 
  282 peter                    2538 GNC           2 :         a = construct_array_builtin(&elementDatum, 1, TEXTOID);
                               2539                 :     }
 4443 tgl                      2540 ECB             :     else
                               2541                 :     {
 4443 tgl                      2542 CBC           2 :         a = DatumGetArrayTypeP(arrayDatum);
 4443 tgl                      2543 ECB             : 
 3762 tgl                      2544 CBC           2 :         if (ARR_NDIM(a) != 1 ||
                               2545               2 :             ARR_LBOUND(a)[0] != 1 ||
 3762 tgl                      2546 GBC           2 :             ARR_HASNULL(a) ||
 3762 tgl                      2547 CBC           2 :             ARR_ELEMTYPE(a) != TEXTOID)
 3762 tgl                      2548 UIC           0 :             elog(ERROR, "extcondition is not a 1-D text array");
 3762 tgl                      2549 CBC           2 :         if (ARR_DIMS(a)[0] != arrayLength)
 3762 tgl                      2550 UIC           0 :             elog(ERROR, "extconfig and extcondition arrays do not match");
 4443 tgl                      2551 ECB             : 
                               2552                 :         /* Add or replace at same index as in extconfig */
 4443 tgl                      2553 CBC           2 :         a = array_set(a, 1, &arrayIndex,
                               2554                 :                       elementDatum,
 4443 tgl                      2555 EUB             :                       false,
                               2556                 :                       -1 /* varlena array */ ,
                               2557                 :                       -1 /* TEXT's typlen */ ,
                               2558                 :                       false /* TEXT's typbyval */ ,
                               2559                 :                       TYPALIGN_INT /* TEXT's typalign */ );
 4443 tgl                      2560 ECB             :     }
 4443 tgl                      2561 GIC           4 :     repl_val[Anum_pg_extension_extcondition - 1] = PointerGetDatum(a);
                               2562               4 :     repl_repl[Anum_pg_extension_extcondition - 1] = true;
                               2563                 : 
                               2564               4 :     extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
                               2565                 :                                repl_val, repl_null, repl_repl);
                               2566                 : 
 2259 alvherre                 2567               4 :     CatalogTupleUpdate(extRel, &extTup->t_self, extTup);
 4443 tgl                      2568 ECB             : 
 4443 tgl                      2569 CBC           4 :     systable_endscan(extScan);
                               2570                 : 
 1539 andres                   2571 GIC           4 :     table_close(extRel, RowExclusiveLock);
 4443 tgl                      2572 ECB             : 
 4443 tgl                      2573 GIC           4 :     PG_RETURN_VOID();
 4443 tgl                      2574 ECB             : }
                               2575                 : 
 3762                          2576                 : /*
                               2577                 :  * extension_config_remove
                               2578                 :  *
 3762 tgl                      2579 EUB             :  * Remove the specified table OID from extension's extconfig, if present.
                               2580                 :  * This is not currently exposed as a function, but it could be;
 3762 tgl                      2581 ECB             :  * for now, we just invoke it from ALTER EXTENSION DROP.
                               2582                 :  */
                               2583                 : static void
 3762 tgl                      2584 GIC          16 : extension_config_remove(Oid extensionoid, Oid tableoid)
 3762 tgl                      2585 ECB             : {
                               2586                 :     Relation    extRel;
                               2587                 :     ScanKeyData key[1];
                               2588                 :     SysScanDesc extScan;
                               2589                 :     HeapTuple   extTup;
                               2590                 :     Datum       arrayDatum;
 3762 tgl                      2591 EUB             :     int         arrayLength;
 3762 tgl                      2592 ECB             :     int         arrayIndex;
 3762 tgl                      2593 EUB             :     bool        isnull;
                               2594                 :     Datum       repl_val[Natts_pg_extension];
                               2595                 :     bool        repl_null[Natts_pg_extension];
 3762 tgl                      2596 ECB             :     bool        repl_repl[Natts_pg_extension];
                               2597                 :     ArrayType  *a;
                               2598                 : 
                               2599                 :     /* Find the pg_extension tuple */
 1539 andres                   2600 GIC          16 :     extRel = table_open(ExtensionRelationId, RowExclusiveLock);
                               2601                 : 
 3762 tgl                      2602              16 :     ScanKeyInit(&key[0],
                               2603                 :                 Anum_pg_extension_oid,
 3762 tgl                      2604 ECB             :                 BTEqualStrategyNumber, F_OIDEQ,
                               2605                 :                 ObjectIdGetDatum(extensionoid));
                               2606                 : 
 3762 tgl                      2607 CBC          16 :     extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
                               2608                 :                                  NULL, 1, key);
                               2609                 : 
                               2610              16 :     extTup = systable_getnext(extScan);
                               2611                 : 
 2118                          2612              16 :     if (!HeapTupleIsValid(extTup))  /* should not happen */
 2135 tgl                      2613 UIC           0 :         elog(ERROR, "could not find tuple for extension %u",
 3762 tgl                      2614 ECB             :              extensionoid);
                               2615                 : 
                               2616                 :     /* Search extconfig for the tableoid */
 3762 tgl                      2617 GIC          16 :     arrayDatum = heap_getattr(extTup, Anum_pg_extension_extconfig,
                               2618                 :                               RelationGetDescr(extRel), &isnull);
                               2619              16 :     if (isnull)
                               2620                 :     {
                               2621                 :         /* nothing to do */
                               2622              12 :         a = NULL;
                               2623              12 :         arrayLength = 0;
                               2624              12 :         arrayIndex = -1;
                               2625                 :     }
                               2626                 :     else
 3762 tgl                      2627 ECB             :     {
                               2628                 :         Oid        *arrayData;
                               2629                 :         int         i;
                               2630                 : 
 3762 tgl                      2631 GIC           4 :         a = DatumGetArrayTypeP(arrayDatum);
                               2632                 : 
                               2633               4 :         arrayLength = ARR_DIMS(a)[0];
                               2634               4 :         if (ARR_NDIM(a) != 1 ||
                               2635               4 :             ARR_LBOUND(a)[0] != 1 ||
                               2636               4 :             arrayLength < 0 ||
                               2637               4 :             ARR_HASNULL(a) ||
                               2638               4 :             ARR_ELEMTYPE(a) != OIDOID)
 3762 tgl                      2639 UIC           0 :             elog(ERROR, "extconfig is not a 1-D Oid array");
 3762 tgl                      2640 GIC           4 :         arrayData = (Oid *) ARR_DATA_PTR(a);
                               2641                 : 
                               2642               4 :         arrayIndex = -1;        /* flag for no deletion needed */
 3762 tgl                      2643 ECB             : 
 3762 tgl                      2644 GIC          12 :         for (i = 0; i < arrayLength; i++)
 3762 tgl                      2645 ECB             :         {
 3762 tgl                      2646 GIC           8 :             if (arrayData[i] == tableoid)
                               2647                 :             {
 3762 tgl                      2648 UIC           0 :                 arrayIndex = i; /* index to remove */
                               2649               0 :                 break;
 3762 tgl                      2650 ECB             :             }
                               2651                 :         }
                               2652                 :     }
                               2653                 : 
                               2654                 :     /* If tableoid is not in extconfig, nothing to do */
 3762 tgl                      2655 CBC          16 :     if (arrayIndex < 0)
 3762 tgl                      2656 EUB             :     {
 3762 tgl                      2657 GIC          16 :         systable_endscan(extScan);
 1539 andres                   2658              16 :         table_close(extRel, RowExclusiveLock);
 3762 tgl                      2659              16 :         return;
 3762 tgl                      2660 ECB             :     }
                               2661                 : 
                               2662                 :     /* Modify or delete the extconfig value */
 3762 tgl                      2663 UIC           0 :     memset(repl_val, 0, sizeof(repl_val));
                               2664               0 :     memset(repl_null, false, sizeof(repl_null));
 3762 tgl                      2665 LBC           0 :     memset(repl_repl, false, sizeof(repl_repl));
 3762 tgl                      2666 ECB             : 
 3762 tgl                      2667 LBC           0 :     if (arrayLength <= 1)
                               2668                 :     {
                               2669                 :         /* removing only element, just set array to null */
 3762 tgl                      2670 UIC           0 :         repl_null[Anum_pg_extension_extconfig - 1] = true;
                               2671                 :     }
                               2672                 :     else
                               2673                 :     {
 3762 tgl                      2674 ECB             :         /* squeeze out the target element */
                               2675                 :         Datum      *dvalues;
                               2676                 :         int         nelems;
                               2677                 :         int         i;
                               2678                 : 
 1609                          2679                 :         /* We already checked there are no nulls */
  282 peter                    2680 UNC           0 :         deconstruct_array_builtin(a, OIDOID, &dvalues, NULL, &nelems);
 3762 tgl                      2681 EUB             : 
 3762 tgl                      2682 LBC           0 :         for (i = arrayIndex; i < arrayLength - 1; i++)
 3762 tgl                      2683 UIC           0 :             dvalues[i] = dvalues[i + 1];
 3762 tgl                      2684 ECB             : 
  282 peter                    2685 UNC           0 :         a = construct_array_builtin(dvalues, arrayLength - 1, OIDOID);
                               2686                 : 
 3762 tgl                      2687 LBC           0 :         repl_val[Anum_pg_extension_extconfig - 1] = PointerGetDatum(a);
                               2688                 :     }
 3762 tgl                      2689 UBC           0 :     repl_repl[Anum_pg_extension_extconfig - 1] = true;
 3762 tgl                      2690 EUB             : 
                               2691                 :     /* Modify or delete the extcondition value */
 3762 tgl                      2692 UIC           0 :     arrayDatum = heap_getattr(extTup, Anum_pg_extension_extcondition,
                               2693                 :                               RelationGetDescr(extRel), &isnull);
                               2694               0 :     if (isnull)
                               2695                 :     {
 3762 tgl                      2696 LBC           0 :         elog(ERROR, "extconfig and extcondition arrays do not match");
                               2697                 :     }
 3762 tgl                      2698 ECB             :     else
                               2699                 :     {
 3762 tgl                      2700 LBC           0 :         a = DatumGetArrayTypeP(arrayDatum);
                               2701                 : 
 3762 tgl                      2702 UIC           0 :         if (ARR_NDIM(a) != 1 ||
                               2703               0 :             ARR_LBOUND(a)[0] != 1 ||
 3762 tgl                      2704 UBC           0 :             ARR_HASNULL(a) ||
                               2705               0 :             ARR_ELEMTYPE(a) != TEXTOID)
                               2706               0 :             elog(ERROR, "extcondition is not a 1-D text array");
 3762 tgl                      2707 UIC           0 :         if (ARR_DIMS(a)[0] != arrayLength)
 3762 tgl                      2708 UBC           0 :             elog(ERROR, "extconfig and extcondition arrays do not match");
                               2709                 :     }
                               2710                 : 
                               2711               0 :     if (arrayLength <= 1)
                               2712                 :     {
                               2713                 :         /* removing only element, just set array to null */
 3762 tgl                      2714 UIC           0 :         repl_null[Anum_pg_extension_extcondition - 1] = true;
                               2715                 :     }
                               2716                 :     else
                               2717                 :     {
                               2718                 :         /* squeeze out the target element */
                               2719                 :         Datum      *dvalues;
                               2720                 :         int         nelems;
 3762 tgl                      2721 EUB             :         int         i;
                               2722                 : 
 1609                          2723                 :         /* We already checked there are no nulls */
  282 peter                    2724 UNC           0 :         deconstruct_array_builtin(a, TEXTOID, &dvalues, NULL, &nelems);
 3762 tgl                      2725 EUB             : 
 3762 tgl                      2726 UIC           0 :         for (i = arrayIndex; i < arrayLength - 1; i++)
 3762 tgl                      2727 UBC           0 :             dvalues[i] = dvalues[i + 1];
                               2728                 : 
  282 peter                    2729 UNC           0 :         a = construct_array_builtin(dvalues, arrayLength - 1, TEXTOID);
                               2730                 : 
 3762 tgl                      2731 UBC           0 :         repl_val[Anum_pg_extension_extcondition - 1] = PointerGetDatum(a);
                               2732                 :     }
                               2733               0 :     repl_repl[Anum_pg_extension_extcondition - 1] = true;
                               2734                 : 
                               2735               0 :     extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
                               2736                 :                                repl_val, repl_null, repl_repl);
                               2737                 : 
 2259 alvherre                 2738 UIC           0 :     CatalogTupleUpdate(extRel, &extTup->t_self, extTup);
 3762 tgl                      2739 EUB             : 
 3762 tgl                      2740 UIC           0 :     systable_endscan(extScan);
 3762 tgl                      2741 EUB             : 
 1539 andres                   2742 UBC           0 :     table_close(extRel, RowExclusiveLock);
 3762 tgl                      2743 EUB             : }
                               2744                 : 
 4443                          2745                 : /*
                               2746                 :  * Execute ALTER EXTENSION SET SCHEMA
                               2747                 :  */
                               2748                 : ObjectAddress
 2339 peter_e                  2749 GIC           3 : AlterExtensionNamespace(const char *extensionName, const char *newschema, Oid *oldschema)
 4443 tgl                      2750 EUB             : {
                               2751                 :     Oid         extensionOid;
                               2752                 :     Oid         nspOid;
 4443 tgl                      2753 GBC           3 :     Oid         oldNspOid = InvalidOid;
                               2754                 :     AclResult   aclresult;
                               2755                 :     Relation    extRel;
                               2756                 :     ScanKeyData key[2];
                               2757                 :     SysScanDesc extScan;
                               2758                 :     HeapTuple   extTup;
                               2759                 :     Form_pg_extension extForm;
                               2760                 :     Relation    depRel;
                               2761                 :     SysScanDesc depScan;
                               2762                 :     HeapTuple   depTup;
 3812 alvherre                 2763 EUB             :     ObjectAddresses *objsMoved;
                               2764                 :     ObjectAddress extAddr;
 4443 tgl                      2765                 : 
 4443 tgl                      2766 GBC           3 :     extensionOid = get_extension_oid(extensionName, false);
                               2767                 : 
                               2768               3 :     nspOid = LookupCreationNamespace(newschema);
                               2769                 : 
 4419 tgl                      2770 EUB             :     /*
                               2771                 :      * Permission check: must own extension.  Note that we don't bother to
                               2772                 :      * check ownership of the individual member objects ...
                               2773                 :      */
  147 peter                    2774 GNC           3 :     if (!object_ownercheck(ExtensionRelationId, extensionOid, GetUserId()))
 1954 peter_e                  2775 UIC           0 :         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_EXTENSION,
                               2776                 :                        extensionName);
 4419 tgl                      2777 EUB             : 
                               2778                 :     /* Permission check: must have creation rights in target namespace */
  147 peter                    2779 GNC           3 :     aclresult = object_aclcheck(NamespaceRelationId, nspOid, GetUserId(), ACL_CREATE);
 4419 tgl                      2780 GIC           3 :     if (aclresult != ACLCHECK_OK)
 1954 peter_e                  2781 UBC           0 :         aclcheck_error(aclresult, OBJECT_SCHEMA, newschema);
                               2782                 : 
                               2783                 :     /*
                               2784                 :      * If the schema is currently a member of the extension, disallow moving
                               2785                 :      * the extension into the schema.  That would create a dependency loop.
                               2786                 :      */
 3889 tgl                      2787 GIC           3 :     if (getExtensionOfObject(NamespaceRelationId, nspOid) == extensionOid)
 3889 tgl                      2788 LBC           0 :         ereport(ERROR,
                               2789                 :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                               2790                 :                  errmsg("cannot move extension \"%s\" into schema \"%s\" "
                               2791                 :                         "because the extension contains the schema",
 3889 tgl                      2792 ECB             :                         extensionName, newschema)));
                               2793                 : 
                               2794                 :     /* Locate the pg_extension tuple */
 1539 andres                   2795 GIC           3 :     extRel = table_open(ExtensionRelationId, RowExclusiveLock);
                               2796                 : 
 4443 tgl                      2797               3 :     ScanKeyInit(&key[0],
                               2798                 :                 Anum_pg_extension_oid,
                               2799                 :                 BTEqualStrategyNumber, F_OIDEQ,
                               2800                 :                 ObjectIdGetDatum(extensionOid));
                               2801                 : 
                               2802               3 :     extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
                               2803                 :                                  NULL, 1, key);
                               2804                 : 
 4443 tgl                      2805 CBC           3 :     extTup = systable_getnext(extScan);
                               2806                 : 
 2118                          2807               3 :     if (!HeapTupleIsValid(extTup))  /* should not happen */
 2135 tgl                      2808 UIC           0 :         elog(ERROR, "could not find tuple for extension %u",
                               2809                 :              extensionOid);
                               2810                 : 
                               2811                 :     /* Copy tuple so we can modify it below */
 4443 tgl                      2812 GIC           3 :     extTup = heap_copytuple(extTup);
 4443 tgl                      2813 CBC           3 :     extForm = (Form_pg_extension) GETSTRUCT(extTup);
 4443 tgl                      2814 EUB             : 
 4443 tgl                      2815 GIC           3 :     systable_endscan(extScan);
                               2816                 : 
                               2817                 :     /*
 4382 bruce                    2818 ECB             :      * If the extension is already in the target schema, just silently do
                               2819                 :      * nothing.
 4443 tgl                      2820 EUB             :      */
 4443 tgl                      2821 GIC           3 :     if (extForm->extnamespace == nspOid)
                               2822                 :     {
 1539 andres                   2823 UIC           0 :         table_close(extRel, RowExclusiveLock);
 2959 alvherre                 2824               0 :         return InvalidObjectAddress;
                               2825                 :     }
 4443 tgl                      2826 ECB             : 
 4443 tgl                      2827 EUB             :     /* Check extension is supposed to be relocatable */
 4443 tgl                      2828 GIC           3 :     if (!extForm->extrelocatable)
 4443 tgl                      2829 UIC           0 :         ereport(ERROR,
                               2830                 :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               2831                 :                  errmsg("extension \"%s\" does not support SET SCHEMA",
                               2832                 :                         NameStr(extForm->extname))));
                               2833                 : 
 3812 alvherre                 2834 CBC           3 :     objsMoved = new_object_addresses();
                               2835                 : 
 4443 tgl                      2836 ECB             :     /*
                               2837                 :      * Scan pg_depend to find objects that depend directly on the extension,
                               2838                 :      * and alter each one's schema.
                               2839                 :      */
 1539 andres                   2840 GIC           3 :     depRel = table_open(DependRelationId, AccessShareLock);
 4443 tgl                      2841 ECB             : 
 4443 tgl                      2842 GIC           3 :     ScanKeyInit(&key[0],
                               2843                 :                 Anum_pg_depend_refclassid,
 4443 tgl                      2844 ECB             :                 BTEqualStrategyNumber, F_OIDEQ,
                               2845                 :                 ObjectIdGetDatum(ExtensionRelationId));
 4443 tgl                      2846 CBC           3 :     ScanKeyInit(&key[1],
 4443 tgl                      2847 EUB             :                 Anum_pg_depend_refobjid,
                               2848                 :                 BTEqualStrategyNumber, F_OIDEQ,
                               2849                 :                 ObjectIdGetDatum(extensionOid));
                               2850                 : 
 4443 tgl                      2851 CBC           3 :     depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
 3568 rhaas                    2852 ECB             :                                  NULL, 2, key);
                               2853                 : 
 4443 tgl                      2854 CBC           9 :     while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
                               2855                 :     {
 4443 tgl                      2856 GIC           7 :         Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
                               2857                 :         ObjectAddress dep;
                               2858                 :         Oid         dep_oldNspOid;
                               2859                 : 
 4443 tgl                      2860 ECB             :         /*
                               2861                 :          * If a dependent extension has a no_relocate request for this
                               2862                 :          * extension, disallow SET SCHEMA.  (XXX it's a bit ugly to do this in
                               2863                 :          * the same loop that's actually executing the renames: we may detect
                               2864                 :          * the error condition only after having expended a fair amount of
                               2865                 :          * work.  However, the alternative is to do two scans of pg_depend,
                               2866                 :          * which seems like optimizing for failure cases.  The rename work
                               2867                 :          * will all roll back cleanly enough if we do fail here.)
                               2868                 :          */
   20 tgl                      2869 GNC           7 :         if (pg_depend->deptype == DEPENDENCY_NORMAL &&
                               2870               4 :             pg_depend->classid == ExtensionRelationId)
                               2871                 :         {
                               2872               4 :             char       *depextname = get_extension_name(pg_depend->objid);
                               2873                 :             ExtensionControlFile *dcontrol;
                               2874                 :             ListCell   *lc;
                               2875                 : 
                               2876               4 :             dcontrol = read_extension_control_file(depextname);
                               2877               5 :             foreach(lc, dcontrol->no_relocate)
                               2878                 :             {
                               2879               2 :                 char       *nrextname = (char *) lfirst(lc);
                               2880                 : 
                               2881               2 :                 if (strcmp(nrextname, NameStr(extForm->extname)) == 0)
                               2882                 :                 {
                               2883               1 :                     ereport(ERROR,
                               2884                 :                             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               2885                 :                              errmsg("cannot SET SCHEMA of extension \"%s\" because other extensions prevent it",
                               2886                 :                                     NameStr(extForm->extname)),
                               2887                 :                              errdetail("Extension \"%s\" requests no relocation of extension \"%s\".",
                               2888                 :                                        depextname,
                               2889                 :                                        NameStr(extForm->extname))));
                               2890                 :                 }
                               2891                 :             }
                               2892                 :         }
                               2893                 : 
                               2894                 :         /*
                               2895                 :          * Otherwise, ignore non-membership dependencies.  (Currently, the
                               2896                 :          * only other case we could see here is a normal dependency from
                               2897                 :          * another extension.)
                               2898                 :          */
 4443 tgl                      2899 GIC           6 :         if (pg_depend->deptype != DEPENDENCY_EXTENSION)
                               2900               3 :             continue;
 4443 tgl                      2901 ECB             : 
 4443 tgl                      2902 GBC           3 :         dep.classId = pg_depend->classid;
 4443 tgl                      2903 GIC           3 :         dep.objectId = pg_depend->objid;
                               2904               3 :         dep.objectSubId = pg_depend->objsubid;
                               2905                 : 
 2118                          2906               3 :         if (dep.objectSubId != 0)   /* should not happen */
 4443 tgl                      2907 LBC           0 :             elog(ERROR, "extension should not have a sub-object dependency");
                               2908                 : 
                               2909                 :         /* Relocate the object */
 4443 tgl                      2910 GIC           3 :         dep_oldNspOid = AlterObjectNamespace_oid(dep.classId,
                               2911                 :                                                  dep.objectId,
                               2912                 :                                                  nspOid,
 3812 alvherre                 2913 ECB             :                                                  objsMoved);
                               2914                 : 
 4443 tgl                      2915                 :         /*
                               2916                 :          * Remember previous namespace of first object that has one
                               2917                 :          */
 4443 tgl                      2918 GIC           3 :         if (oldNspOid == InvalidOid && dep_oldNspOid != InvalidOid)
 4443 tgl                      2919 CBC           3 :             oldNspOid = dep_oldNspOid;
                               2920                 : 
                               2921                 :         /*
                               2922                 :          * If not all the objects had the same old namespace (ignoring any
                               2923                 :          * that are not in namespaces), complain.
 4443 tgl                      2924 ECB             :          */
 4443 tgl                      2925 GIC           3 :         if (dep_oldNspOid != InvalidOid && dep_oldNspOid != oldNspOid)
 4443 tgl                      2926 UIC           0 :             ereport(ERROR,
 4443 tgl                      2927 ECB             :                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               2928                 :                      errmsg("extension \"%s\" does not support SET SCHEMA",
                               2929                 :                             NameStr(extForm->extname)),
                               2930                 :                      errdetail("%s is not in the extension's schema \"%s\"",
                               2931                 :                                getObjectDescription(&dep, false),
                               2932                 :                                get_namespace_name(oldNspOid))));
                               2933                 :     }
                               2934                 : 
                               2935                 :     /* report old schema, if caller wants it */
 2959 alvherre                 2936 GIC           2 :     if (oldschema)
                               2937               2 :         *oldschema = oldNspOid;
                               2938                 : 
 4443 tgl                      2939               2 :     systable_endscan(depScan);
                               2940                 : 
                               2941               2 :     relation_close(depRel, AccessShareLock);
 4443 tgl                      2942 ECB             : 
                               2943                 :     /* Now adjust pg_extension.extnamespace */
 4443 tgl                      2944 GIC           2 :     extForm->extnamespace = nspOid;
 4443 tgl                      2945 ECB             : 
 2259 alvherre                 2946 GIC           2 :     CatalogTupleUpdate(extRel, &extTup->t_self, extTup);
                               2947                 : 
 1539 andres                   2948               2 :     table_close(extRel, RowExclusiveLock);
 4443 tgl                      2949 ECB             : 
                               2950                 :     /* update dependencies to point to the new schema */
 4443 tgl                      2951 GIC           2 :     changeDependencyFor(ExtensionRelationId, extensionOid,
 4443 tgl                      2952 ECB             :                         NamespaceRelationId, oldNspOid, nspOid);
                               2953                 : 
 3675 rhaas                    2954 CBC           2 :     InvokeObjectPostAlterHook(ExtensionRelationId, extensionOid, 0);
                               2955                 : 
 2959 alvherre                 2956               2 :     ObjectAddressSet(extAddr, ExtensionRelationId, extensionOid);
                               2957                 : 
 2959 alvherre                 2958 GIC           2 :     return extAddr;
                               2959                 : }
                               2960                 : 
                               2961                 : /*
                               2962                 :  * Execute ALTER EXTENSION UPDATE
                               2963                 :  */
                               2964                 : ObjectAddress
 2406 peter_e                  2965              11 : ExecAlterExtensionStmt(ParseState *pstate, AlterExtensionStmt *stmt)
                               2966                 : {
 4440 tgl                      2967              11 :     DefElem    *d_new_version = NULL;
                               2968                 :     char       *versionName;
                               2969                 :     char       *oldVersionName;
                               2970                 :     ExtensionControlFile *control;
                               2971                 :     Oid         extensionOid;
 4440 tgl                      2972 ECB             :     Relation    extRel;
 4382 bruce                    2973                 :     ScanKeyData key[1];
                               2974                 :     SysScanDesc extScan;
 4440 tgl                      2975                 :     HeapTuple   extTup;
                               2976                 :     List       *updateVersions;
                               2977                 :     Datum       datum;
                               2978                 :     bool        isnull;
                               2979                 :     ListCell   *lc;
 2959 alvherre                 2980 EUB             :     ObjectAddress address;
                               2981                 : 
                               2982                 :     /*
 4382 bruce                    2983 ECB             :      * We use global variables to track the extension being created, so we can
                               2984                 :      * create/update only one extension at the same time.
                               2985                 :      */
 4440 tgl                      2986 GIC          11 :     if (creating_extension)
 4440 tgl                      2987 UIC           0 :         ereport(ERROR,
                               2988                 :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                               2989                 :                  errmsg("nested ALTER EXTENSION is not supported")));
                               2990                 : 
 4439 tgl                      2991 ECB             :     /*
                               2992                 :      * Look up the extension --- it must already exist in pg_extension
                               2993                 :      */
 1539 andres                   2994 GIC          11 :     extRel = table_open(ExtensionRelationId, AccessShareLock);
                               2995                 : 
 4440 tgl                      2996              11 :     ScanKeyInit(&key[0],
                               2997                 :                 Anum_pg_extension_extname,
 4440 tgl                      2998 ECB             :                 BTEqualStrategyNumber, F_NAMEEQ,
 4440 tgl                      2999 GBC          11 :                 CStringGetDatum(stmt->extname));
                               3000                 : 
 4440 tgl                      3001 GIC          11 :     extScan = systable_beginscan(extRel, ExtensionNameIndexId, true,
                               3002                 :                                  NULL, 1, key);
                               3003                 : 
                               3004              11 :     extTup = systable_getnext(extScan);
                               3005                 : 
                               3006              11 :     if (!HeapTupleIsValid(extTup))
 4382 bruce                    3007 UIC           0 :         ereport(ERROR,
                               3008                 :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
 4382 bruce                    3009 ECB             :                  errmsg("extension \"%s\" does not exist",
                               3010                 :                         stmt->extname)));
                               3011                 : 
 1601 andres                   3012 CBC          11 :     extensionOid = ((Form_pg_extension) GETSTRUCT(extTup))->oid;
                               3013                 : 
 4439 tgl                      3014 ECB             :     /*
                               3015                 :      * Determine the existing version we are updating from
                               3016                 :      */
 4439 tgl                      3017 CBC          11 :     datum = heap_getattr(extTup, Anum_pg_extension_extversion,
                               3018                 :                          RelationGetDescr(extRel), &isnull);
                               3019              11 :     if (isnull)
 4439 tgl                      3020 UIC           0 :         elog(ERROR, "extversion is null");
 4439 tgl                      3021 CBC          11 :     oldVersionName = text_to_cstring(DatumGetTextPP(datum));
                               3022                 : 
 4440 tgl                      3023 GIC          11 :     systable_endscan(extScan);
 4440 tgl                      3024 ECB             : 
 1539 andres                   3025 GIC          11 :     table_close(extRel, AccessShareLock);
                               3026                 : 
 4419 tgl                      3027 ECB             :     /* Permission check: must own extension */
  147 peter                    3028 GNC          11 :     if (!object_ownercheck(ExtensionRelationId, extensionOid, GetUserId()))
 1954 peter_e                  3029 LBC           0 :         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_EXTENSION,
 4419 tgl                      3030 UIC           0 :                        stmt->extname);
 4419 tgl                      3031 ECB             : 
                               3032                 :     /*
                               3033                 :      * Read the primary control file.  Note we assume that it does not contain
                               3034                 :      * any non-ASCII data, so there is no need to worry about encoding at this
                               3035                 :      * point.
                               3036                 :      */
 4440 tgl                      3037 GIC          11 :     control = read_extension_control_file(stmt->extname);
 4440 tgl                      3038 ECB             : 
                               3039                 :     /*
                               3040                 :      * Read the statement option list
                               3041                 :      */
 4440 tgl                      3042 GIC          22 :     foreach(lc, stmt->options)
                               3043                 :     {
                               3044              11 :         DefElem    *defel = (DefElem *) lfirst(lc);
                               3045                 : 
                               3046              11 :         if (strcmp(defel->defname, "new_version") == 0)
                               3047                 :         {
                               3048              11 :             if (d_new_version)
  633 dean.a.rasheed           3049 UIC           0 :                 errorConflictingDefElem(defel, pstate);
 4440 tgl                      3050 GIC          11 :             d_new_version = defel;
                               3051                 :         }
                               3052                 :         else
 4440 tgl                      3053 UIC           0 :             elog(ERROR, "unrecognized option: %s", defel->defname);
                               3054                 :     }
                               3055                 : 
                               3056                 :     /*
                               3057                 :      * Determine the version to update to
                               3058                 :      */
 4440 tgl                      3059 CBC          11 :     if (d_new_version && d_new_version->arg)
 4440 tgl                      3060 GBC          11 :         versionName = strVal(d_new_version->arg);
 4440 tgl                      3061 UIC           0 :     else if (control->default_version)
                               3062               0 :         versionName = control->default_version;
                               3063                 :     else
                               3064                 :     {
                               3065               0 :         ereport(ERROR,
                               3066                 :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 4440 tgl                      3067 ECB             :                  errmsg("version to install must be specified")));
                               3068                 :         versionName = NULL;     /* keep compiler quiet */
                               3069                 :     }
 4440 tgl                      3070 GIC          11 :     check_valid_version_name(versionName);
                               3071                 : 
 4435 tgl                      3072 ECB             :     /*
                               3073                 :      * If we're already at that version, just say so
                               3074                 :      */
 4435 tgl                      3075 GIC          11 :     if (strcmp(oldVersionName, versionName) == 0)
                               3076                 :     {
 4435 tgl                      3077 LBC           0 :         ereport(NOTICE,
                               3078                 :                 (errmsg("version \"%s\" of extension \"%s\" is already installed",
 2118 tgl                      3079 ECB             :                         versionName, stmt->extname)));
 2959 alvherre                 3080 UBC           0 :         return InvalidObjectAddress;
                               3081                 :     }
                               3082                 : 
                               3083                 :     /*
                               3084                 :      * Identify the series of update script files we need to execute
 4440 tgl                      3085 ECB             :      */
 4439 tgl                      3086 GIC          11 :     updateVersions = identify_update_path(control,
                               3087                 :                                           oldVersionName,
                               3088                 :                                           versionName);
                               3089                 : 
 4440 tgl                      3090 ECB             :     /*
                               3091                 :      * Update the pg_extension row and execute the update scripts, one at a
 4439                          3092                 :      * time
 4440 tgl                      3093 EUB             :      */
 4439 tgl                      3094 CBC          11 :     ApplyExtensionUpdates(extensionOid, control,
                               3095                 :                           oldVersionName, updateVersions,
 2401 tgl                      3096 ECB             :                           NULL, false, false);
                               3097                 : 
 2959 alvherre                 3098 CBC          11 :     ObjectAddressSet(address, ExtensionRelationId, extensionOid);
                               3099                 : 
 2959 alvherre                 3100 GIC          11 :     return address;
 4439 tgl                      3101 ECB             : }
 4440 tgl                      3102 EUB             : 
 4439                          3103                 : /*
                               3104                 :  * Apply a series of update scripts as though individual ALTER EXTENSION
                               3105                 :  * UPDATE commands had been given, including altering the pg_extension row
                               3106                 :  * and dependencies each time.
                               3107                 :  *
                               3108                 :  * This might be more work than necessary, but it ensures that old update
                               3109                 :  * scripts don't break if newer versions have different control parameters.
 4439 tgl                      3110 ECB             :  */
                               3111                 : static void
 4439 tgl                      3112 GIC         459 : ApplyExtensionUpdates(Oid extensionOid,
                               3113                 :                       ExtensionControlFile *pcontrol,
                               3114                 :                       const char *initialVersion,
 2401 tgl                      3115 ECB             :                       List *updateVersions,
                               3116                 :                       char *origSchemaName,
                               3117                 :                       bool cascade,
                               3118                 :                       bool is_create)
 4439                          3119                 : {
 4439 tgl                      3120 GIC         459 :     const char *oldVersionName = initialVersion;
 4439 tgl                      3121 ECB             :     ListCell   *lcv;
 4440 tgl                      3122 EUB             : 
 4439 tgl                      3123 CBC         632 :     foreach(lcv, updateVersions)
                               3124                 :     {
 4439 tgl                      3125 GIC         173 :         char       *versionName = (char *) lfirst(lcv);
 4439 tgl                      3126 EUB             :         ExtensionControlFile *control;
                               3127                 :         char       *schemaName;
                               3128                 :         Oid         schemaOid;
                               3129                 :         List       *requiredExtensions;
                               3130                 :         List       *requiredSchemas;
                               3131                 :         Relation    extRel;
 4382 bruce                    3132 ECB             :         ScanKeyData key[1];
                               3133                 :         SysScanDesc extScan;
 4439 tgl                      3134 EUB             :         HeapTuple   extTup;
                               3135                 :         Form_pg_extension extForm;
                               3136                 :         Datum       values[Natts_pg_extension];
                               3137                 :         bool        nulls[Natts_pg_extension];
                               3138                 :         bool        repl[Natts_pg_extension];
                               3139                 :         ObjectAddress myself;
                               3140                 :         ListCell   *lc;
                               3141                 : 
                               3142                 :         /*
 4439 tgl                      3143 ECB             :          * Fetch parameters for specific version (pcontrol is not changed)
                               3144                 :          */
 4439 tgl                      3145 GIC         173 :         control = read_extension_aux_control_file(pcontrol, versionName);
                               3146                 : 
                               3147                 :         /* Find the pg_extension tuple */
 1539 andres                   3148 CBC         173 :         extRel = table_open(ExtensionRelationId, RowExclusiveLock);
                               3149                 : 
 4439 tgl                      3150 GBC         173 :         ScanKeyInit(&key[0],
                               3151                 :                     Anum_pg_extension_oid,
                               3152                 :                     BTEqualStrategyNumber, F_OIDEQ,
 4439 tgl                      3153 EUB             :                     ObjectIdGetDatum(extensionOid));
                               3154                 : 
 4439 tgl                      3155 GIC         173 :         extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
                               3156                 :                                      NULL, 1, key);
                               3157                 : 
                               3158             173 :         extTup = systable_getnext(extScan);
 4440 tgl                      3159 ECB             : 
 4382 bruce                    3160 GIC         173 :         if (!HeapTupleIsValid(extTup))  /* should not happen */
 2135 tgl                      3161 UIC           0 :             elog(ERROR, "could not find tuple for extension %u",
                               3162                 :                  extensionOid);
                               3163                 : 
 4439 tgl                      3164 GIC         173 :         extForm = (Form_pg_extension) GETSTRUCT(extTup);
                               3165                 : 
                               3166                 :         /*
 4439 tgl                      3167 ECB             :          * Determine the target schema (set by original install)
                               3168                 :          */
 4439 tgl                      3169 GIC         173 :         schemaOid = extForm->extnamespace;
                               3170             173 :         schemaName = get_namespace_name(schemaOid);
 4440 tgl                      3171 ECB             : 
                               3172                 :         /*
 4439                          3173                 :          * Modify extrelocatable and extversion in the pg_extension tuple
                               3174                 :          */
 4439 tgl                      3175 GIC         173 :         memset(values, 0, sizeof(values));
                               3176             173 :         memset(nulls, 0, sizeof(nulls));
                               3177             173 :         memset(repl, 0, sizeof(repl));
                               3178                 : 
                               3179             173 :         values[Anum_pg_extension_extrelocatable - 1] =
                               3180             173 :             BoolGetDatum(control->relocatable);
                               3181             173 :         repl[Anum_pg_extension_extrelocatable - 1] = true;
                               3182             173 :         values[Anum_pg_extension_extversion - 1] =
                               3183             173 :             CStringGetTextDatum(versionName);
                               3184             173 :         repl[Anum_pg_extension_extversion - 1] = true;
 4440 tgl                      3185 ECB             : 
 4439 tgl                      3186 GIC         173 :         extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
                               3187                 :                                    values, nulls, repl);
                               3188                 : 
 2259 alvherre                 3189             173 :         CatalogTupleUpdate(extRel, &extTup->t_self, extTup);
                               3190                 : 
 4439 tgl                      3191             173 :         systable_endscan(extScan);
                               3192                 : 
 1539 andres                   3193 CBC         173 :         table_close(extRel, RowExclusiveLock);
                               3194                 : 
                               3195                 :         /*
 2401 tgl                      3196 ECB             :          * Look up the prerequisite extensions for this version, install them
                               3197                 :          * if necessary, and build lists of their OIDs and the OIDs of their
                               3198                 :          * target schemas.
                               3199                 :          */
 4439 tgl                      3200 GIC         173 :         requiredExtensions = NIL;
                               3201             173 :         requiredSchemas = NIL;
                               3202             173 :         foreach(lc, control->requires)
                               3203                 :         {
 4439 tgl                      3204 UIC           0 :             char       *curreq = (char *) lfirst(lc);
                               3205                 :             Oid         reqext;
                               3206                 :             Oid         reqschema;
                               3207                 : 
 2401                          3208               0 :             reqext = get_required_extension(curreq,
                               3209                 :                                             control->name,
                               3210                 :                                             origSchemaName,
                               3211                 :                                             cascade,
                               3212                 :                                             NIL,
                               3213                 :                                             is_create);
 4439                          3214               0 :             reqschema = get_extension_schema(reqext);
                               3215               0 :             requiredExtensions = lappend_oid(requiredExtensions, reqext);
                               3216               0 :             requiredSchemas = lappend_oid(requiredSchemas, reqschema);
                               3217                 :         }
 4439 tgl                      3218 ECB             : 
                               3219                 :         /*
                               3220                 :          * Remove and recreate dependencies on prerequisite extensions
                               3221                 :          */
 4439 tgl                      3222 GIC         173 :         deleteDependencyRecordsForClass(ExtensionRelationId, extensionOid,
 4439 tgl                      3223 ECB             :                                         ExtensionRelationId,
                               3224                 :                                         DEPENDENCY_NORMAL);
                               3225                 : 
 4439 tgl                      3226 GIC         173 :         myself.classId = ExtensionRelationId;
                               3227             173 :         myself.objectId = extensionOid;
 4439 tgl                      3228 CBC         173 :         myself.objectSubId = 0;
                               3229                 : 
 4439 tgl                      3230 GIC         173 :         foreach(lc, requiredExtensions)
 4439 tgl                      3231 ECB             :         {
 4439 tgl                      3232 UIC           0 :             Oid         reqext = lfirst_oid(lc);
 4439 tgl                      3233 ECB             :             ObjectAddress otherext;
 4439 tgl                      3234 EUB             : 
 4439 tgl                      3235 UIC           0 :             otherext.classId = ExtensionRelationId;
                               3236               0 :             otherext.objectId = reqext;
 4439 tgl                      3237 LBC           0 :             otherext.objectSubId = 0;
                               3238                 : 
 4439 tgl                      3239 UIC           0 :             recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
                               3240                 :         }
                               3241                 : 
 3675 rhaas                    3242 CBC         173 :         InvokeObjectPostAlterHook(ExtensionRelationId, extensionOid, 0);
 3675 rhaas                    3243 ECB             : 
                               3244                 :         /*
                               3245                 :          * Finally, execute the update script file
                               3246                 :          */
 4440 tgl                      3247 GIC         173 :         execute_extension_script(extensionOid, control,
 4439 tgl                      3248 ECB             :                                  oldVersionName, versionName,
 4440                          3249                 :                                  requiredSchemas,
                               3250                 :                                  schemaName, schemaOid);
                               3251                 : 
 4439                          3252                 :         /*
 4382 bruce                    3253                 :          * Update prior-version name and loop around.  Since
                               3254                 :          * execute_sql_string did a final CommandCounterIncrement, we can
                               3255                 :          * update the pg_extension row again.
 4439 tgl                      3256                 :          */
 4439 tgl                      3257 CBC         173 :         oldVersionName = versionName;
                               3258                 :     }
 4440                          3259             459 : }
                               3260                 : 
                               3261                 : /*
 4441 tgl                      3262 ECB             :  * Execute ALTER EXTENSION ADD/DROP
                               3263                 :  *
 2959 alvherre                 3264                 :  * Return value is the address of the altered extension.
                               3265                 :  *
                               3266                 :  * objAddr is an output argument which, if not NULL, is set to the address of
                               3267                 :  * the added/dropped object.
                               3268                 :  */
                               3269                 : ObjectAddress
 2959 alvherre                 3270 GIC          87 : ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt,
                               3271                 :                                ObjectAddress *objAddr)
                               3272                 : {
 4382 bruce                    3273 ECB             :     ObjectAddress extension;
                               3274                 :     ObjectAddress object;
                               3275                 :     Relation    relation;
                               3276                 :     Oid         oldExtension;
 4442 tgl                      3277 EUB             : 
 1030 peter                    3278 GIC          87 :     switch (stmt->objtype)
                               3279                 :     {
                               3280               1 :         case OBJECT_DATABASE:
 1030 peter                    3281 EUB             :         case OBJECT_EXTENSION:
                               3282                 :         case OBJECT_INDEX:
                               3283                 :         case OBJECT_PUBLICATION:
                               3284                 :         case OBJECT_ROLE:
                               3285                 :         case OBJECT_STATISTIC_EXT:
                               3286                 :         case OBJECT_SUBSCRIPTION:
                               3287                 :         case OBJECT_TABLESPACE:
 1030 peter                    3288 GBC           1 :             ereport(ERROR,
  697 tgl                      3289 EUB             :                     (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                               3290                 :                      errmsg("cannot add an object of this type to an extension")));
                               3291                 :             break;
 1030 peter                    3292 GIC          86 :         default:
                               3293                 :             /* OK */
                               3294              86 :             break;
 1030 peter                    3295 ECB             :     }
                               3296                 : 
                               3297                 :     /*
                               3298                 :      * Find the extension and acquire a lock on it, to ensure it doesn't get
  637 tgl                      3299                 :      * dropped concurrently.  A sharable lock seems sufficient: there's no
                               3300                 :      * reason not to allow other sorts of manipulations, such as add/drop of
                               3301                 :      * other objects, to occur concurrently.  Concurrently adding/dropping the
                               3302                 :      * *same* object would be bad, but we prevent that by using a non-sharable
                               3303                 :      * lock on the individual object, below.
                               3304                 :      */
  637 tgl                      3305 GBC          86 :     extension = get_object_address(OBJECT_EXTENSION,
  637 tgl                      3306 GIC          86 :                                    (Node *) makeString(stmt->extname),
                               3307                 :                                    &relation, AccessShareLock, false);
 4442 tgl                      3308 EUB             : 
 4419                          3309                 :     /* Permission check: must own extension */
  147 peter                    3310 GNC          86 :     if (!object_ownercheck(ExtensionRelationId, extension.objectId, GetUserId()))
 1954 peter_e                  3311 UIC           0 :         aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_EXTENSION,
 4419 tgl                      3312 UBC           0 :                        stmt->extname);
                               3313                 : 
                               3314                 :     /*
 4382 bruce                    3315 ECB             :      * Translate the parser representation that identifies the object into an
                               3316                 :      * ObjectAddress.  get_object_address() will throw an error if the object
                               3317                 :      * does not exist, and will also acquire a lock on the object to guard
                               3318                 :      * against concurrent DROP and ALTER EXTENSION ADD/DROP operations.
                               3319                 :      */
 2339 peter_e                  3320 CBC          86 :     object = get_object_address(stmt->objtype, stmt->object,
                               3321                 :                                 &relation, ShareUpdateExclusiveLock, false);
                               3322                 : 
 2959 alvherre                 3323 GIC          86 :     Assert(object.objectSubId == 0);
                               3324              86 :     if (objAddr)
                               3325              86 :         *objAddr = object;
                               3326                 : 
                               3327                 :     /* Permission check: must own target object, too */
 4419 tgl                      3328              86 :     check_object_ownership(GetUserId(), stmt->objtype, object,
                               3329                 :                            stmt->object, relation);
 4419 tgl                      3330 ECB             : 
                               3331                 :     /*
 4441                          3332                 :      * Check existing extension membership.
                               3333                 :      */
 4441 tgl                      3334 GIC          86 :     oldExtension = getExtensionOfObject(object.classId, object.objectId);
                               3335                 : 
                               3336              86 :     if (stmt->action > 0)
                               3337                 :     {
                               3338                 :         /*
                               3339                 :          * ADD, so complain if object is already attached to some extension.
                               3340                 :          */
                               3341              28 :         if (OidIsValid(oldExtension))
 4441 tgl                      3342 UIC           0 :             ereport(ERROR,
 4441 tgl                      3343 ECB             :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                               3344                 :                      errmsg("%s is already a member of extension \"%s\"",
                               3345                 :                             getObjectDescription(&object, false),
                               3346                 :                             get_extension_name(oldExtension))));
                               3347                 : 
                               3348                 :         /*
                               3349                 :          * Prevent a schema from being added to an extension if the schema
                               3350                 :          * contains the extension.  That would create a dependency loop.
 3889                          3351                 :          */
 3889 tgl                      3352 GIC          29 :         if (object.classId == NamespaceRelationId &&
 3889 tgl                      3353 CBC           1 :             object.objectId == get_extension_schema(extension.objectId))
 3889 tgl                      3354 UIC           0 :             ereport(ERROR,
                               3355                 :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                               3356                 :                      errmsg("cannot add schema \"%s\" to extension \"%s\" "
                               3357                 :                             "because the schema contains the extension",
                               3358                 :                             get_namespace_name(object.objectId),
                               3359                 :                             stmt->extname)));
                               3360                 : 
 4441 tgl                      3361 ECB             :         /*
                               3362                 :          * OK, add the dependency.
                               3363                 :          */
 4441 tgl                      3364 GIC          28 :         recordDependencyOn(&object, &extension, DEPENDENCY_EXTENSION);
 2261 sfrost                   3365 ECB             : 
                               3366                 :         /*
                               3367                 :          * Also record the initial ACL on the object, if any.
                               3368                 :          *
                               3369                 :          * Note that this will handle the object's ACLs, as well as any ACLs
                               3370                 :          * on object subIds.  (In other words, when the object is a table,
                               3371                 :          * this will record the table's ACL and the ACLs for the columns on
                               3372                 :          * the table, if any).
                               3373                 :          */
 2261 sfrost                   3374 GIC          28 :         recordExtObjInitPriv(object.objectId, object.classId);
                               3375                 :     }
                               3376                 :     else
                               3377                 :     {
 4441 tgl                      3378 ECB             :         /*
                               3379                 :          * DROP, so complain if it's not a member.
                               3380                 :          */
 4441 tgl                      3381 GIC          58 :         if (oldExtension != extension.objectId)
 4441 tgl                      3382 UIC           0 :             ereport(ERROR,
 4441 tgl                      3383 ECB             :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 4441 tgl                      3384 EUB             :                      errmsg("%s is not a member of extension \"%s\"",
  998 michael                  3385                 :                             getObjectDescription(&object, false),
                               3386                 :                             stmt->extname)));
                               3387                 : 
                               3388                 :         /*
                               3389                 :          * OK, drop the dependency.
                               3390                 :          */
 4441 tgl                      3391 GIC          58 :         if (deleteDependencyRecordsForClass(object.classId, object.objectId,
                               3392                 :                                             ExtensionRelationId,
 4441 tgl                      3393 ECB             :                                             DEPENDENCY_EXTENSION) != 1)
 4441 tgl                      3394 UIC           0 :             elog(ERROR, "unexpected number of extension dependency records");
                               3395                 : 
 3762 tgl                      3396 ECB             :         /*
                               3397                 :          * If it's a relation, it might have an entry in the extension's
                               3398                 :          * extconfig array, which we must remove.
                               3399                 :          */
 3762 tgl                      3400 GIC          58 :         if (object.classId == RelationRelationId)
 3762 tgl                      3401 CBC          16 :             extension_config_remove(extension.objectId, object.objectId);
                               3402                 : 
                               3403                 :         /*
                               3404                 :          * Remove all the initial ACLs, if any.
                               3405                 :          *
                               3406                 :          * Note that this will remove the object's ACLs, as well as any ACLs
 2261 sfrost                   3407 ECB             :          * on object subIds.  (In other words, when the object is a table,
                               3408                 :          * this will remove the table's ACL and the ACLs for the columns on
                               3409                 :          * the table, if any).
                               3410                 :          */
 2261 sfrost                   3411 GIC          58 :         removeExtObjInitPriv(object.objectId, object.classId);
                               3412                 :     }
                               3413                 : 
 3675 rhaas                    3414 CBC          86 :     InvokeObjectPostAlterHook(ExtensionRelationId, extension.objectId, 0);
 3675 rhaas                    3415 EUB             : 
                               3416                 :     /*
                               3417                 :      * If get_object_address() opened the relation for us, we close it to keep
                               3418                 :      * the reference count correct - but we retain any locks acquired by
                               3419                 :      * get_object_address() until commit time, to guard against concurrent
                               3420                 :      * activity.
                               3421                 :      */
 4442 tgl                      3422 GIC          86 :     if (relation != NULL)
                               3423              23 :         relation_close(relation, NoLock);
                               3424                 : 
 2959 alvherre                 3425 CBC          86 :     return extension;
 4442 tgl                      3426 ECB             : }
 2842 heikki.linnakangas       3427 EUB             : 
                               3428                 : /*
                               3429                 :  * Read the whole of file into memory.
                               3430                 :  *
                               3431                 :  * The file contents are returned as a single palloc'd chunk. For convenience
                               3432                 :  * of the callers, an extra \0 byte is added to the end.
                               3433                 :  */
                               3434                 : static char *
 2842 heikki.linnakangas       3435 GIC         632 : read_whole_file(const char *filename, int *length)
                               3436                 : {
 2842 heikki.linnakangas       3437 ECB             :     char       *buf;
                               3438                 :     FILE       *file;
                               3439                 :     size_t      bytes_to_read;
                               3440                 :     struct stat fst;
                               3441                 : 
 2842 heikki.linnakangas       3442 GIC         632 :     if (stat(filename, &fst) < 0)
 2842 heikki.linnakangas       3443 UIC           0 :         ereport(ERROR,
                               3444                 :                 (errcode_for_file_access(),
                               3445                 :                  errmsg("could not stat file \"%s\": %m", filename)));
                               3446                 : 
 2842 heikki.linnakangas       3447 CBC         632 :     if (fst.st_size > (MaxAllocSize - 1))
 2842 heikki.linnakangas       3448 UIC           0 :         ereport(ERROR,
                               3449                 :                 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
                               3450                 :                  errmsg("file \"%s\" is too large", filename)));
 2842 heikki.linnakangas       3451 GIC         632 :     bytes_to_read = (size_t) fst.st_size;
                               3452                 : 
                               3453             632 :     if ((file = AllocateFile(filename, PG_BINARY_R)) == NULL)
 2842 heikki.linnakangas       3454 LBC           0 :         ereport(ERROR,
 2842 heikki.linnakangas       3455 EUB             :                 (errcode_for_file_access(),
                               3456                 :                  errmsg("could not open file \"%s\" for reading: %m",
                               3457                 :                         filename)));
                               3458                 : 
 2842 heikki.linnakangas       3459 GIC         632 :     buf = (char *) palloc(bytes_to_read + 1);
                               3460                 : 
                               3461             632 :     *length = fread(buf, 1, bytes_to_read, file);
                               3462                 : 
                               3463             632 :     if (ferror(file))
 2842 heikki.linnakangas       3464 LBC           0 :         ereport(ERROR,
                               3465                 :                 (errcode_for_file_access(),
                               3466                 :                  errmsg("could not read file \"%s\": %m", filename)));
 2842 heikki.linnakangas       3467 EUB             : 
 2842 heikki.linnakangas       3468 GIC         632 :     FreeFile(file);
                               3469                 : 
                               3470             632 :     buf[*length] = '\0';
                               3471             632 :     return buf;
                               3472                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a