Header And Logo

PostgreSQL
| The world's most advanced open source database.

extension.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * extension.c
00004  *    Commands to manipulate extensions
00005  *
00006  * Extensions in PostgreSQL allow management of collections of SQL objects.
00007  *
00008  * All we need internally to manage an extension is an OID so that the
00009  * dependent objects can be associated with it.  An extension is created by
00010  * populating the pg_extension catalog from a "control" file.
00011  * The extension control file is parsed with the same parser we use for
00012  * postgresql.conf and recovery.conf.  An extension also has an installation
00013  * script file, containing SQL commands to create the extension's objects.
00014  *
00015  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00016  * Portions Copyright (c) 1994, Regents of the University of California
00017  *
00018  *
00019  * IDENTIFICATION
00020  *    src/backend/commands/extension.c
00021  *
00022  *-------------------------------------------------------------------------
00023  */
00024 #include "postgres.h"
00025 
00026 #include <dirent.h>
00027 #include <limits.h>
00028 #include <unistd.h>
00029 
00030 #include "access/htup_details.h"
00031 #include "access/sysattr.h"
00032 #include "access/xact.h"
00033 #include "catalog/dependency.h"
00034 #include "catalog/indexing.h"
00035 #include "catalog/namespace.h"
00036 #include "catalog/objectaccess.h"
00037 #include "catalog/pg_collation.h"
00038 #include "catalog/pg_depend.h"
00039 #include "catalog/pg_extension.h"
00040 #include "catalog/pg_namespace.h"
00041 #include "catalog/pg_type.h"
00042 #include "commands/alter.h"
00043 #include "commands/comment.h"
00044 #include "commands/extension.h"
00045 #include "commands/schemacmds.h"
00046 #include "funcapi.h"
00047 #include "mb/pg_wchar.h"
00048 #include "miscadmin.h"
00049 #include "storage/fd.h"
00050 #include "tcop/utility.h"
00051 #include "utils/builtins.h"
00052 #include "utils/fmgroids.h"
00053 #include "utils/lsyscache.h"
00054 #include "utils/rel.h"
00055 #include "utils/snapmgr.h"
00056 #include "utils/tqual.h"
00057 
00058 
00059 /* Globally visible state variables */
00060 bool        creating_extension = false;
00061 Oid         CurrentExtensionObject = InvalidOid;
00062 
00063 /*
00064  * Internal data structure to hold the results of parsing a control file
00065  */
00066 typedef struct ExtensionControlFile
00067 {
00068     char       *name;           /* name of the extension */
00069     char       *directory;      /* directory for script files */
00070     char       *default_version;    /* default install target version, if any */
00071     char       *module_pathname;    /* string to substitute for MODULE_PATHNAME */
00072     char       *comment;        /* comment, if any */
00073     char       *schema;         /* target schema (allowed if !relocatable) */
00074     bool        relocatable;    /* is ALTER EXTENSION SET SCHEMA supported? */
00075     bool        superuser;      /* must be superuser to install? */
00076     int         encoding;       /* encoding of the script file, or -1 */
00077     List       *requires;       /* names of prerequisite extensions */
00078 } ExtensionControlFile;
00079 
00080 /*
00081  * Internal data structure for update path information
00082  */
00083 typedef struct ExtensionVersionInfo
00084 {
00085     char       *name;           /* name of the starting version */
00086     List       *reachable;      /* List of ExtensionVersionInfo's */
00087     bool        installable;    /* does this version have an install script? */
00088     /* working state for Dijkstra's algorithm: */
00089     bool        distance_known; /* is distance from start known yet? */
00090     int         distance;       /* current worst-case distance estimate */
00091     struct ExtensionVersionInfo *previous;      /* current best predecessor */
00092 } ExtensionVersionInfo;
00093 
00094 /* Local functions */
00095 static List *find_update_path(List *evi_list,
00096                  ExtensionVersionInfo *evi_start,
00097                  ExtensionVersionInfo *evi_target,
00098                  bool reinitialize);
00099 static void get_available_versions_for_extension(ExtensionControlFile *pcontrol,
00100                                      Tuplestorestate *tupstore,
00101                                      TupleDesc tupdesc);
00102 static void ApplyExtensionUpdates(Oid extensionOid,
00103                       ExtensionControlFile *pcontrol,
00104                       const char *initialVersion,
00105                       List *updateVersions);
00106 
00107 
00108 /*
00109  * get_extension_oid - given an extension name, look up the OID
00110  *
00111  * If missing_ok is false, throw an error if extension name not found.  If
00112  * true, just return InvalidOid.
00113  */
00114 Oid
00115 get_extension_oid(const char *extname, bool missing_ok)
00116 {
00117     Oid         result;
00118     Relation    rel;
00119     SysScanDesc scandesc;
00120     HeapTuple   tuple;
00121     ScanKeyData entry[1];
00122 
00123     rel = heap_open(ExtensionRelationId, AccessShareLock);
00124 
00125     ScanKeyInit(&entry[0],
00126                 Anum_pg_extension_extname,
00127                 BTEqualStrategyNumber, F_NAMEEQ,
00128                 CStringGetDatum(extname));
00129 
00130     scandesc = systable_beginscan(rel, ExtensionNameIndexId, true,
00131                                   SnapshotNow, 1, entry);
00132 
00133     tuple = systable_getnext(scandesc);
00134 
00135     /* We assume that there can be at most one matching tuple */
00136     if (HeapTupleIsValid(tuple))
00137         result = HeapTupleGetOid(tuple);
00138     else
00139         result = InvalidOid;
00140 
00141     systable_endscan(scandesc);
00142 
00143     heap_close(rel, AccessShareLock);
00144 
00145     if (!OidIsValid(result) && !missing_ok)
00146         ereport(ERROR,
00147                 (errcode(ERRCODE_UNDEFINED_OBJECT),
00148                  errmsg("extension \"%s\" does not exist",
00149                         extname)));
00150 
00151     return result;
00152 }
00153 
00154 /*
00155  * get_extension_name - given an extension OID, look up the name
00156  *
00157  * Returns a palloc'd string, or NULL if no such extension.
00158  */
00159 char *
00160 get_extension_name(Oid ext_oid)
00161 {
00162     char       *result;
00163     Relation    rel;
00164     SysScanDesc scandesc;
00165     HeapTuple   tuple;
00166     ScanKeyData entry[1];
00167 
00168     rel = heap_open(ExtensionRelationId, AccessShareLock);
00169 
00170     ScanKeyInit(&entry[0],
00171                 ObjectIdAttributeNumber,
00172                 BTEqualStrategyNumber, F_OIDEQ,
00173                 ObjectIdGetDatum(ext_oid));
00174 
00175     scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
00176                                   SnapshotNow, 1, entry);
00177 
00178     tuple = systable_getnext(scandesc);
00179 
00180     /* We assume that there can be at most one matching tuple */
00181     if (HeapTupleIsValid(tuple))
00182         result = pstrdup(NameStr(((Form_pg_extension) GETSTRUCT(tuple))->extname));
00183     else
00184         result = NULL;
00185 
00186     systable_endscan(scandesc);
00187 
00188     heap_close(rel, AccessShareLock);
00189 
00190     return result;
00191 }
00192 
00193 /*
00194  * get_extension_schema - given an extension OID, fetch its extnamespace
00195  *
00196  * Returns InvalidOid if no such extension.
00197  */
00198 static Oid
00199 get_extension_schema(Oid ext_oid)
00200 {
00201     Oid         result;
00202     Relation    rel;
00203     SysScanDesc scandesc;
00204     HeapTuple   tuple;
00205     ScanKeyData entry[1];
00206 
00207     rel = heap_open(ExtensionRelationId, AccessShareLock);
00208 
00209     ScanKeyInit(&entry[0],
00210                 ObjectIdAttributeNumber,
00211                 BTEqualStrategyNumber, F_OIDEQ,
00212                 ObjectIdGetDatum(ext_oid));
00213 
00214     scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
00215                                   SnapshotNow, 1, entry);
00216 
00217     tuple = systable_getnext(scandesc);
00218 
00219     /* We assume that there can be at most one matching tuple */
00220     if (HeapTupleIsValid(tuple))
00221         result = ((Form_pg_extension) GETSTRUCT(tuple))->extnamespace;
00222     else
00223         result = InvalidOid;
00224 
00225     systable_endscan(scandesc);
00226 
00227     heap_close(rel, AccessShareLock);
00228 
00229     return result;
00230 }
00231 
00232 /*
00233  * Utility functions to check validity of extension and version names
00234  */
00235 static void
00236 check_valid_extension_name(const char *extensionname)
00237 {
00238     int         namelen = strlen(extensionname);
00239 
00240     /*
00241      * Disallow empty names (the parser rejects empty identifiers anyway, but
00242      * let's check).
00243      */
00244     if (namelen == 0)
00245         ereport(ERROR,
00246                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00247                  errmsg("invalid extension name: \"%s\"", extensionname),
00248                  errdetail("Extension names must not be empty.")));
00249 
00250     /*
00251      * No double dashes, since that would make script filenames ambiguous.
00252      */
00253     if (strstr(extensionname, "--"))
00254         ereport(ERROR,
00255                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00256                  errmsg("invalid extension name: \"%s\"", extensionname),
00257                  errdetail("Extension names must not contain \"--\".")));
00258 
00259     /*
00260      * No leading or trailing dash either.  (We could probably allow this, but
00261      * it would require much care in filename parsing and would make filenames
00262      * visually if not formally ambiguous.  Since there's no real-world use
00263      * case, let's just forbid it.)
00264      */
00265     if (extensionname[0] == '-' || extensionname[namelen - 1] == '-')
00266         ereport(ERROR,
00267                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00268                  errmsg("invalid extension name: \"%s\"", extensionname),
00269             errdetail("Extension names must not begin or end with \"-\".")));
00270 
00271     /*
00272      * No directory separators either (this is sufficient to prevent ".."
00273      * style attacks).
00274      */
00275     if (first_dir_separator(extensionname) != NULL)
00276         ereport(ERROR,
00277                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00278                  errmsg("invalid extension name: \"%s\"", extensionname),
00279                  errdetail("Extension names must not contain directory separator characters.")));
00280 }
00281 
00282 static void
00283 check_valid_version_name(const char *versionname)
00284 {
00285     int         namelen = strlen(versionname);
00286 
00287     /*
00288      * Disallow empty names (we could possibly allow this, but there seems
00289      * little point).
00290      */
00291     if (namelen == 0)
00292         ereport(ERROR,
00293                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00294                errmsg("invalid extension version name: \"%s\"", versionname),
00295                  errdetail("Version names must not be empty.")));
00296 
00297     /*
00298      * No double dashes, since that would make script filenames ambiguous.
00299      */
00300     if (strstr(versionname, "--"))
00301         ereport(ERROR,
00302                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00303                errmsg("invalid extension version name: \"%s\"", versionname),
00304                  errdetail("Version names must not contain \"--\".")));
00305 
00306     /*
00307      * No leading or trailing dash either.
00308      */
00309     if (versionname[0] == '-' || versionname[namelen - 1] == '-')
00310         ereport(ERROR,
00311                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00312                errmsg("invalid extension version name: \"%s\"", versionname),
00313               errdetail("Version names must not begin or end with \"-\".")));
00314 
00315     /*
00316      * No directory separators either (this is sufficient to prevent ".."
00317      * style attacks).
00318      */
00319     if (first_dir_separator(versionname) != NULL)
00320         ereport(ERROR,
00321                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00322                errmsg("invalid extension version name: \"%s\"", versionname),
00323                  errdetail("Version names must not contain directory separator characters.")));
00324 }
00325 
00326 /*
00327  * Utility functions to handle extension-related path names
00328  */
00329 static bool
00330 is_extension_control_filename(const char *filename)
00331 {
00332     const char *extension = strrchr(filename, '.');
00333 
00334     return (extension != NULL) && (strcmp(extension, ".control") == 0);
00335 }
00336 
00337 static bool
00338 is_extension_script_filename(const char *filename)
00339 {
00340     const char *extension = strrchr(filename, '.');
00341 
00342     return (extension != NULL) && (strcmp(extension, ".sql") == 0);
00343 }
00344 
00345 static char *
00346 get_extension_control_directory(void)
00347 {
00348     char        sharepath[MAXPGPATH];
00349     char       *result;
00350 
00351     get_share_path(my_exec_path, sharepath);
00352     result = (char *) palloc(MAXPGPATH);
00353     snprintf(result, MAXPGPATH, "%s/extension", sharepath);
00354 
00355     return result;
00356 }
00357 
00358 static char *
00359 get_extension_control_filename(const char *extname)
00360 {
00361     char        sharepath[MAXPGPATH];
00362     char       *result;
00363 
00364     get_share_path(my_exec_path, sharepath);
00365     result = (char *) palloc(MAXPGPATH);
00366     snprintf(result, MAXPGPATH, "%s/extension/%s.control",
00367              sharepath, extname);
00368 
00369     return result;
00370 }
00371 
00372 static char *
00373 get_extension_script_directory(ExtensionControlFile *control)
00374 {
00375     char        sharepath[MAXPGPATH];
00376     char       *result;
00377 
00378     /*
00379      * The directory parameter can be omitted, absolute, or relative to the
00380      * installation's share directory.
00381      */
00382     if (!control->directory)
00383         return get_extension_control_directory();
00384 
00385     if (is_absolute_path(control->directory))
00386         return pstrdup(control->directory);
00387 
00388     get_share_path(my_exec_path, sharepath);
00389     result = (char *) palloc(MAXPGPATH);
00390     snprintf(result, MAXPGPATH, "%s/%s", sharepath, control->directory);
00391 
00392     return result;
00393 }
00394 
00395 static char *
00396 get_extension_aux_control_filename(ExtensionControlFile *control,
00397                                    const char *version)
00398 {
00399     char       *result;
00400     char       *scriptdir;
00401 
00402     scriptdir = get_extension_script_directory(control);
00403 
00404     result = (char *) palloc(MAXPGPATH);
00405     snprintf(result, MAXPGPATH, "%s/%s--%s.control",
00406              scriptdir, control->name, version);
00407 
00408     pfree(scriptdir);
00409 
00410     return result;
00411 }
00412 
00413 static char *
00414 get_extension_script_filename(ExtensionControlFile *control,
00415                               const char *from_version, const char *version)
00416 {
00417     char       *result;
00418     char       *scriptdir;
00419 
00420     scriptdir = get_extension_script_directory(control);
00421 
00422     result = (char *) palloc(MAXPGPATH);
00423     if (from_version)
00424         snprintf(result, MAXPGPATH, "%s/%s--%s--%s.sql",
00425                  scriptdir, control->name, from_version, version);
00426     else
00427         snprintf(result, MAXPGPATH, "%s/%s--%s.sql",
00428                  scriptdir, control->name, version);
00429 
00430     pfree(scriptdir);
00431 
00432     return result;
00433 }
00434 
00435 
00436 /*
00437  * Parse contents of primary or auxiliary control file, and fill in
00438  * fields of *control.  We parse primary file if version == NULL,
00439  * else the optional auxiliary file for that version.
00440  *
00441  * Control files are supposed to be very short, half a dozen lines,
00442  * so we don't worry about memory allocation risks here.  Also we don't
00443  * worry about what encoding it's in; all values are expected to be ASCII.
00444  */
00445 static void
00446 parse_extension_control_file(ExtensionControlFile *control,
00447                              const char *version)
00448 {
00449     char       *filename;
00450     FILE       *file;
00451     ConfigVariable *item,
00452                *head = NULL,
00453                *tail = NULL;
00454 
00455     /*
00456      * Locate the file to read.  Auxiliary files are optional.
00457      */
00458     if (version)
00459         filename = get_extension_aux_control_filename(control, version);
00460     else
00461         filename = get_extension_control_filename(control->name);
00462 
00463     if ((file = AllocateFile(filename, "r")) == NULL)
00464     {
00465         if (version && errno == ENOENT)
00466         {
00467             /* no auxiliary file for this version */
00468             pfree(filename);
00469             return;
00470         }
00471         ereport(ERROR,
00472                 (errcode_for_file_access(),
00473                  errmsg("could not open extension control file \"%s\": %m",
00474                         filename)));
00475     }
00476 
00477     /*
00478      * Parse the file content, using GUC's file parsing code.  We need not
00479      * check the return value since any errors will be thrown at ERROR level.
00480      */
00481     (void) ParseConfigFp(file, filename, 0, ERROR, &head, &tail);
00482 
00483     FreeFile(file);
00484 
00485     /*
00486      * Convert the ConfigVariable list into ExtensionControlFile entries.
00487      */
00488     for (item = head; item != NULL; item = item->next)
00489     {
00490         if (strcmp(item->name, "directory") == 0)
00491         {
00492             if (version)
00493                 ereport(ERROR,
00494                         (errcode(ERRCODE_SYNTAX_ERROR),
00495                          errmsg("parameter \"%s\" cannot be set in a secondary extension control file",
00496                                 item->name)));
00497 
00498             control->directory = pstrdup(item->value);
00499         }
00500         else if (strcmp(item->name, "default_version") == 0)
00501         {
00502             if (version)
00503                 ereport(ERROR,
00504                         (errcode(ERRCODE_SYNTAX_ERROR),
00505                          errmsg("parameter \"%s\" cannot be set in a secondary extension control file",
00506                                 item->name)));
00507 
00508             control->default_version = pstrdup(item->value);
00509         }
00510         else if (strcmp(item->name, "module_pathname") == 0)
00511         {
00512             control->module_pathname = pstrdup(item->value);
00513         }
00514         else if (strcmp(item->name, "comment") == 0)
00515         {
00516             control->comment = pstrdup(item->value);
00517         }
00518         else if (strcmp(item->name, "schema") == 0)
00519         {
00520             control->schema = pstrdup(item->value);
00521         }
00522         else if (strcmp(item->name, "relocatable") == 0)
00523         {
00524             if (!parse_bool(item->value, &control->relocatable))
00525                 ereport(ERROR,
00526                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00527                          errmsg("parameter \"%s\" requires a Boolean value",
00528                                 item->name)));
00529         }
00530         else if (strcmp(item->name, "superuser") == 0)
00531         {
00532             if (!parse_bool(item->value, &control->superuser))
00533                 ereport(ERROR,
00534                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00535                          errmsg("parameter \"%s\" requires a Boolean value",
00536                                 item->name)));
00537         }
00538         else if (strcmp(item->name, "encoding") == 0)
00539         {
00540             control->encoding = pg_valid_server_encoding(item->value);
00541             if (control->encoding < 0)
00542                 ereport(ERROR,
00543                         (errcode(ERRCODE_UNDEFINED_OBJECT),
00544                          errmsg("\"%s\" is not a valid encoding name",
00545                                 item->value)));
00546         }
00547         else if (strcmp(item->name, "requires") == 0)
00548         {
00549             /* Need a modifiable copy of string */
00550             char       *rawnames = pstrdup(item->value);
00551 
00552             /* Parse string into list of identifiers */
00553             if (!SplitIdentifierString(rawnames, ',', &control->requires))
00554             {
00555                 /* syntax error in name list */
00556                 ereport(ERROR,
00557                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00558                  errmsg("parameter \"%s\" must be a list of extension names",
00559                         item->name)));
00560             }
00561         }
00562         else
00563             ereport(ERROR,
00564                     (errcode(ERRCODE_SYNTAX_ERROR),
00565                      errmsg("unrecognized parameter \"%s\" in file \"%s\"",
00566                             item->name, filename)));
00567     }
00568 
00569     FreeConfigVariables(head);
00570 
00571     if (control->relocatable && control->schema != NULL)
00572         ereport(ERROR,
00573                 (errcode(ERRCODE_SYNTAX_ERROR),
00574                  errmsg("parameter \"schema\" cannot be specified when \"relocatable\" is true")));
00575 
00576     pfree(filename);
00577 }
00578 
00579 /*
00580  * Read the primary control file for the specified extension.
00581  */
00582 static ExtensionControlFile *
00583 read_extension_control_file(const char *extname)
00584 {
00585     ExtensionControlFile *control;
00586 
00587     /*
00588      * Set up default values.  Pointer fields are initially null.
00589      */
00590     control = (ExtensionControlFile *) palloc0(sizeof(ExtensionControlFile));
00591     control->name = pstrdup(extname);
00592     control->relocatable = false;
00593     control->superuser = true;
00594     control->encoding = -1;
00595 
00596     /*
00597      * Parse the primary control file.
00598      */
00599     parse_extension_control_file(control, NULL);
00600 
00601     return control;
00602 }
00603 
00604 /*
00605  * Read the auxiliary control file for the specified extension and version.
00606  *
00607  * Returns a new modified ExtensionControlFile struct; the original struct
00608  * (reflecting just the primary control file) is not modified.
00609  */
00610 static ExtensionControlFile *
00611 read_extension_aux_control_file(const ExtensionControlFile *pcontrol,
00612                                 const char *version)
00613 {
00614     ExtensionControlFile *acontrol;
00615 
00616     /*
00617      * Flat-copy the struct.  Pointer fields share values with original.
00618      */
00619     acontrol = (ExtensionControlFile *) palloc(sizeof(ExtensionControlFile));
00620     memcpy(acontrol, pcontrol, sizeof(ExtensionControlFile));
00621 
00622     /*
00623      * Parse the auxiliary control file, overwriting struct fields
00624      */
00625     parse_extension_control_file(acontrol, version);
00626 
00627     return acontrol;
00628 }
00629 
00630 /*
00631  * Read an SQL script file into a string, and convert to database encoding
00632  */
00633 static char *
00634 read_extension_script_file(const ExtensionControlFile *control,
00635                            const char *filename)
00636 {
00637     int         src_encoding;
00638     int         dest_encoding = GetDatabaseEncoding();
00639     bytea      *content;
00640     char       *src_str;
00641     char       *dest_str;
00642     int         len;
00643 
00644     content = read_binary_file(filename, 0, -1);
00645 
00646     /* use database encoding if not given */
00647     if (control->encoding < 0)
00648         src_encoding = dest_encoding;
00649     else
00650         src_encoding = control->encoding;
00651 
00652     /* make sure that source string is valid in the expected encoding */
00653     len = VARSIZE_ANY_EXHDR(content);
00654     src_str = VARDATA_ANY(content);
00655     pg_verify_mbstr_len(src_encoding, src_str, len, false);
00656 
00657     /* convert the encoding to the database encoding */
00658     dest_str = (char *) pg_do_encoding_conversion((unsigned char *) src_str,
00659                                                   len,
00660                                                   src_encoding,
00661                                                   dest_encoding);
00662 
00663     /* if no conversion happened, we have to arrange for null termination */
00664     if (dest_str == src_str)
00665     {
00666         dest_str = (char *) palloc(len + 1);
00667         memcpy(dest_str, src_str, len);
00668         dest_str[len] = '\0';
00669     }
00670 
00671     return dest_str;
00672 }
00673 
00674 /*
00675  * Execute given SQL string.
00676  *
00677  * filename is used only to report errors.
00678  *
00679  * Note: it's tempting to just use SPI to execute the string, but that does
00680  * not work very well.  The really serious problem is that SPI will parse,
00681  * analyze, and plan the whole string before executing any of it; of course
00682  * this fails if there are any plannable statements referring to objects
00683  * created earlier in the script.  A lesser annoyance is that SPI insists
00684  * on printing the whole string as errcontext in case of any error, and that
00685  * could be very long.
00686  */
00687 static void
00688 execute_sql_string(const char *sql, const char *filename)
00689 {
00690     List       *raw_parsetree_list;
00691     DestReceiver *dest;
00692     ListCell   *lc1;
00693 
00694     /*
00695      * Parse the SQL string into a list of raw parse trees.
00696      */
00697     raw_parsetree_list = pg_parse_query(sql);
00698 
00699     /* All output from SELECTs goes to the bit bucket */
00700     dest = CreateDestReceiver(DestNone);
00701 
00702     /*
00703      * Do parse analysis, rule rewrite, planning, and execution for each raw
00704      * parsetree.  We must fully execute each query before beginning parse
00705      * analysis on the next one, since there may be interdependencies.
00706      */
00707     foreach(lc1, raw_parsetree_list)
00708     {
00709         Node       *parsetree = (Node *) lfirst(lc1);
00710         List       *stmt_list;
00711         ListCell   *lc2;
00712 
00713         stmt_list = pg_analyze_and_rewrite(parsetree,
00714                                            sql,
00715                                            NULL,
00716                                            0);
00717         stmt_list = pg_plan_queries(stmt_list, 0, NULL);
00718 
00719         foreach(lc2, stmt_list)
00720         {
00721             Node       *stmt = (Node *) lfirst(lc2);
00722 
00723             if (IsA(stmt, TransactionStmt))
00724                 ereport(ERROR,
00725                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00726                          errmsg("transaction control statements are not allowed within an extension script")));
00727 
00728             CommandCounterIncrement();
00729 
00730             PushActiveSnapshot(GetTransactionSnapshot());
00731 
00732             if (IsA(stmt, PlannedStmt) &&
00733                 ((PlannedStmt *) stmt)->utilityStmt == NULL)
00734             {
00735                 QueryDesc  *qdesc;
00736 
00737                 qdesc = CreateQueryDesc((PlannedStmt *) stmt,
00738                                         sql,
00739                                         GetActiveSnapshot(), NULL,
00740                                         dest, NULL, 0);
00741 
00742                 ExecutorStart(qdesc, 0);
00743                 ExecutorRun(qdesc, ForwardScanDirection, 0);
00744                 ExecutorFinish(qdesc);
00745                 ExecutorEnd(qdesc);
00746 
00747                 FreeQueryDesc(qdesc);
00748             }
00749             else
00750             {
00751                 ProcessUtility(stmt,
00752                                sql,
00753                                PROCESS_UTILITY_QUERY,
00754                                NULL,
00755                                dest,
00756                                NULL);
00757             }
00758 
00759             PopActiveSnapshot();
00760         }
00761     }
00762 
00763     /* Be sure to advance the command counter after the last script command */
00764     CommandCounterIncrement();
00765 }
00766 
00767 /*
00768  * Execute the appropriate script file for installing or updating the extension
00769  *
00770  * If from_version isn't NULL, it's an update
00771  */
00772 static void
00773 execute_extension_script(Oid extensionOid, ExtensionControlFile *control,
00774                          const char *from_version,
00775                          const char *version,
00776                          List *requiredSchemas,
00777                          const char *schemaName, Oid schemaOid)
00778 {
00779     char       *filename;
00780     int         save_nestlevel;
00781     StringInfoData pathbuf;
00782     ListCell   *lc;
00783 
00784     /*
00785      * Enforce superuser-ness if appropriate.  We postpone this check until
00786      * here so that the flag is correctly associated with the right script(s)
00787      * if it's set in secondary control files.
00788      */
00789     if (control->superuser && !superuser())
00790     {
00791         if (from_version == NULL)
00792             ereport(ERROR,
00793                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00794                      errmsg("permission denied to create extension \"%s\"",
00795                             control->name),
00796                      errhint("Must be superuser to create this extension.")));
00797         else
00798             ereport(ERROR,
00799                     (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00800                      errmsg("permission denied to update extension \"%s\"",
00801                             control->name),
00802                      errhint("Must be superuser to update this extension.")));
00803     }
00804 
00805     filename = get_extension_script_filename(control, from_version, version);
00806 
00807     /*
00808      * Force client_min_messages and log_min_messages to be at least WARNING,
00809      * so that we won't spam the user with useless NOTICE messages from common
00810      * script actions like creating shell types.
00811      *
00812      * We use the equivalent of a function SET option to allow the setting to
00813      * persist for exactly the duration of the script execution.  guc.c also
00814      * takes care of undoing the setting on error.
00815      */
00816     save_nestlevel = NewGUCNestLevel();
00817 
00818     if (client_min_messages < WARNING)
00819         (void) set_config_option("client_min_messages", "warning",
00820                                  PGC_USERSET, PGC_S_SESSION,
00821                                  GUC_ACTION_SAVE, true, 0);
00822     if (log_min_messages < WARNING)
00823         (void) set_config_option("log_min_messages", "warning",
00824                                  PGC_SUSET, PGC_S_SESSION,
00825                                  GUC_ACTION_SAVE, true, 0);
00826 
00827     /*
00828      * Set up the search path to contain the target schema, then the schemas
00829      * of any prerequisite extensions, and nothing else.  In particular this
00830      * makes the target schema be the default creation target namespace.
00831      *
00832      * Note: it might look tempting to use PushOverrideSearchPath for this,
00833      * but we cannot do that.  We have to actually set the search_path GUC in
00834      * case the extension script examines or changes it.  In any case, the
00835      * GUC_ACTION_SAVE method is just as convenient.
00836      */
00837     initStringInfo(&pathbuf);
00838     appendStringInfoString(&pathbuf, quote_identifier(schemaName));
00839     foreach(lc, requiredSchemas)
00840     {
00841         Oid         reqschema = lfirst_oid(lc);
00842         char       *reqname = get_namespace_name(reqschema);
00843 
00844         if (reqname)
00845             appendStringInfo(&pathbuf, ", %s", quote_identifier(reqname));
00846     }
00847 
00848     (void) set_config_option("search_path", pathbuf.data,
00849                              PGC_USERSET, PGC_S_SESSION,
00850                              GUC_ACTION_SAVE, true, 0);
00851 
00852     /*
00853      * Set creating_extension and related variables so that
00854      * recordDependencyOnCurrentExtension and other functions do the right
00855      * things.  On failure, ensure we reset these variables.
00856      */
00857     creating_extension = true;
00858     CurrentExtensionObject = extensionOid;
00859     PG_TRY();
00860     {
00861         char       *c_sql = read_extension_script_file(control, filename);
00862         Datum       t_sql;
00863 
00864         /* We use various functions that want to operate on text datums */
00865         t_sql = CStringGetTextDatum(c_sql);
00866 
00867         /*
00868          * Reduce any lines beginning with "\echo" to empty.  This allows
00869          * scripts to contain messages telling people not to run them via
00870          * psql, which has been found to be necessary due to old habits.
00871          */
00872         t_sql = DirectFunctionCall4Coll(textregexreplace,
00873                                         C_COLLATION_OID,
00874                                         t_sql,
00875                                         CStringGetTextDatum("^\\\\echo.*$"),
00876                                         CStringGetTextDatum(""),
00877                                         CStringGetTextDatum("ng"));
00878 
00879         /*
00880          * If it's not relocatable, substitute the target schema name for
00881          * occurrences of @extschema@.
00882          *
00883          * For a relocatable extension, we needn't do this.  There cannot be
00884          * any need for @extschema@, else it wouldn't be relocatable.
00885          */
00886         if (!control->relocatable)
00887         {
00888             const char *qSchemaName = quote_identifier(schemaName);
00889 
00890             t_sql = DirectFunctionCall3(replace_text,
00891                                         t_sql,
00892                                         CStringGetTextDatum("@extschema@"),
00893                                         CStringGetTextDatum(qSchemaName));
00894         }
00895 
00896         /*
00897          * If module_pathname was set in the control file, substitute its
00898          * value for occurrences of MODULE_PATHNAME.
00899          */
00900         if (control->module_pathname)
00901         {
00902             t_sql = DirectFunctionCall3(replace_text,
00903                                         t_sql,
00904                                       CStringGetTextDatum("MODULE_PATHNAME"),
00905                               CStringGetTextDatum(control->module_pathname));
00906         }
00907 
00908         /* And now back to C string */
00909         c_sql = text_to_cstring(DatumGetTextPP(t_sql));
00910 
00911         execute_sql_string(c_sql, filename);
00912     }
00913     PG_CATCH();
00914     {
00915         creating_extension = false;
00916         CurrentExtensionObject = InvalidOid;
00917         PG_RE_THROW();
00918     }
00919     PG_END_TRY();
00920 
00921     creating_extension = false;
00922     CurrentExtensionObject = InvalidOid;
00923 
00924     /*
00925      * Restore the GUC variables we set above.
00926      */
00927     AtEOXact_GUC(true, save_nestlevel);
00928 }
00929 
00930 /*
00931  * Find or create an ExtensionVersionInfo for the specified version name
00932  *
00933  * Currently, we just use a List of the ExtensionVersionInfo's.  Searching
00934  * for them therefore uses about O(N^2) time when there are N versions of
00935  * the extension.  We could change the data structure to a hash table if
00936  * this ever becomes a bottleneck.
00937  */
00938 static ExtensionVersionInfo *
00939 get_ext_ver_info(const char *versionname, List **evi_list)
00940 {
00941     ExtensionVersionInfo *evi;
00942     ListCell   *lc;
00943 
00944     foreach(lc, *evi_list)
00945     {
00946         evi = (ExtensionVersionInfo *) lfirst(lc);
00947         if (strcmp(evi->name, versionname) == 0)
00948             return evi;
00949     }
00950 
00951     evi = (ExtensionVersionInfo *) palloc(sizeof(ExtensionVersionInfo));
00952     evi->name = pstrdup(versionname);
00953     evi->reachable = NIL;
00954     evi->installable = false;
00955     /* initialize for later application of Dijkstra's algorithm */
00956     evi->distance_known = false;
00957     evi->distance = INT_MAX;
00958     evi->previous = NULL;
00959 
00960     *evi_list = lappend(*evi_list, evi);
00961 
00962     return evi;
00963 }
00964 
00965 /*
00966  * Locate the nearest unprocessed ExtensionVersionInfo
00967  *
00968  * This part of the algorithm is also about O(N^2).  A priority queue would
00969  * make it much faster, but for now there's no need.
00970  */
00971 static ExtensionVersionInfo *
00972 get_nearest_unprocessed_vertex(List *evi_list)
00973 {
00974     ExtensionVersionInfo *evi = NULL;
00975     ListCell   *lc;
00976 
00977     foreach(lc, evi_list)
00978     {
00979         ExtensionVersionInfo *evi2 = (ExtensionVersionInfo *) lfirst(lc);
00980 
00981         /* only vertices whose distance is still uncertain are candidates */
00982         if (evi2->distance_known)
00983             continue;
00984         /* remember the closest such vertex */
00985         if (evi == NULL ||
00986             evi->distance > evi2->distance)
00987             evi = evi2;
00988     }
00989 
00990     return evi;
00991 }
00992 
00993 /*
00994  * Obtain information about the set of update scripts available for the
00995  * specified extension.  The result is a List of ExtensionVersionInfo
00996  * structs, each with a subsidiary list of the ExtensionVersionInfos for
00997  * the versions that can be reached in one step from that version.
00998  */
00999 static List *
01000 get_ext_ver_list(ExtensionControlFile *control)
01001 {
01002     List       *evi_list = NIL;
01003     int         extnamelen = strlen(control->name);
01004     char       *location;
01005     DIR        *dir;
01006     struct dirent *de;
01007 
01008     location = get_extension_script_directory(control);
01009     dir = AllocateDir(location);
01010     while ((de = ReadDir(dir, location)) != NULL)
01011     {
01012         char       *vername;
01013         char       *vername2;
01014         ExtensionVersionInfo *evi;
01015         ExtensionVersionInfo *evi2;
01016 
01017         /* must be a .sql file ... */
01018         if (!is_extension_script_filename(de->d_name))
01019             continue;
01020 
01021         /* ... matching extension name followed by separator */
01022         if (strncmp(de->d_name, control->name, extnamelen) != 0 ||
01023             de->d_name[extnamelen] != '-' ||
01024             de->d_name[extnamelen + 1] != '-')
01025             continue;
01026 
01027         /* extract version name(s) from 'extname--something.sql' filename */
01028         vername = pstrdup(de->d_name + extnamelen + 2);
01029         *strrchr(vername, '.') = '\0';
01030         vername2 = strstr(vername, "--");
01031         if (!vername2)
01032         {
01033             /* It's an install, not update, script; record its version name */
01034             evi = get_ext_ver_info(vername, &evi_list);
01035             evi->installable = true;
01036             continue;
01037         }
01038         *vername2 = '\0';       /* terminate first version */
01039         vername2 += 2;          /* and point to second */
01040 
01041         /* if there's a third --, it's bogus, ignore it */
01042         if (strstr(vername2, "--"))
01043             continue;
01044 
01045         /* Create ExtensionVersionInfos and link them together */
01046         evi = get_ext_ver_info(vername, &evi_list);
01047         evi2 = get_ext_ver_info(vername2, &evi_list);
01048         evi->reachable = lappend(evi->reachable, evi2);
01049     }
01050     FreeDir(dir);
01051 
01052     return evi_list;
01053 }
01054 
01055 /*
01056  * Given an initial and final version name, identify the sequence of update
01057  * scripts that have to be applied to perform that update.
01058  *
01059  * Result is a List of names of versions to transition through (the initial
01060  * version is *not* included).
01061  */
01062 static List *
01063 identify_update_path(ExtensionControlFile *control,
01064                      const char *oldVersion, const char *newVersion)
01065 {
01066     List       *result;
01067     List       *evi_list;
01068     ExtensionVersionInfo *evi_start;
01069     ExtensionVersionInfo *evi_target;
01070 
01071     /* Extract the version update graph from the script directory */
01072     evi_list = get_ext_ver_list(control);
01073 
01074     /* Initialize start and end vertices */
01075     evi_start = get_ext_ver_info(oldVersion, &evi_list);
01076     evi_target = get_ext_ver_info(newVersion, &evi_list);
01077 
01078     /* Find shortest path */
01079     result = find_update_path(evi_list, evi_start, evi_target, false);
01080 
01081     if (result == NIL)
01082         ereport(ERROR,
01083                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
01084                  errmsg("extension \"%s\" has no update path from version \"%s\" to version \"%s\"",
01085                         control->name, oldVersion, newVersion)));
01086 
01087     return result;
01088 }
01089 
01090 /*
01091  * Apply Dijkstra's algorithm to find the shortest path from evi_start to
01092  * evi_target.
01093  *
01094  * If reinitialize is false, assume the ExtensionVersionInfo list has not
01095  * been used for this before, and the initialization done by get_ext_ver_info
01096  * is still good.
01097  *
01098  * Result is a List of names of versions to transition through (the initial
01099  * version is *not* included).  Returns NIL if no such path.
01100  */
01101 static List *
01102 find_update_path(List *evi_list,
01103                  ExtensionVersionInfo *evi_start,
01104                  ExtensionVersionInfo *evi_target,
01105                  bool reinitialize)
01106 {
01107     List       *result;
01108     ExtensionVersionInfo *evi;
01109     ListCell   *lc;
01110 
01111     /* Caller error if start == target */
01112     Assert(evi_start != evi_target);
01113 
01114     if (reinitialize)
01115     {
01116         foreach(lc, evi_list)
01117         {
01118             evi = (ExtensionVersionInfo *) lfirst(lc);
01119             evi->distance_known = false;
01120             evi->distance = INT_MAX;
01121             evi->previous = NULL;
01122         }
01123     }
01124 
01125     evi_start->distance = 0;
01126 
01127     while ((evi = get_nearest_unprocessed_vertex(evi_list)) != NULL)
01128     {
01129         if (evi->distance == INT_MAX)
01130             break;              /* all remaining vertices are unreachable */
01131         evi->distance_known = true;
01132         if (evi == evi_target)
01133             break;              /* found shortest path to target */
01134         foreach(lc, evi->reachable)
01135         {
01136             ExtensionVersionInfo *evi2 = (ExtensionVersionInfo *) lfirst(lc);
01137             int         newdist;
01138 
01139             newdist = evi->distance + 1;
01140             if (newdist < evi2->distance)
01141             {
01142                 evi2->distance = newdist;
01143                 evi2->previous = evi;
01144             }
01145             else if (newdist == evi2->distance &&
01146                      evi2->previous != NULL &&
01147                      strcmp(evi->name, evi2->previous->name) < 0)
01148             {
01149                 /*
01150                  * Break ties in favor of the version name that comes first
01151                  * according to strcmp().  This behavior is undocumented and
01152                  * users shouldn't rely on it.  We do it just to ensure that
01153                  * if there is a tie, the update path that is chosen does not
01154                  * depend on random factors like the order in which directory
01155                  * entries get visited.
01156                  */
01157                 evi2->previous = evi;
01158             }
01159         }
01160     }
01161 
01162     /* Return NIL if target is not reachable from start */
01163     if (!evi_target->distance_known)
01164         return NIL;
01165 
01166     /* Build and return list of version names representing the update path */
01167     result = NIL;
01168     for (evi = evi_target; evi != evi_start; evi = evi->previous)
01169         result = lcons(evi->name, result);
01170 
01171     return result;
01172 }
01173 
01174 /*
01175  * CREATE EXTENSION
01176  */
01177 Oid
01178 CreateExtension(CreateExtensionStmt *stmt)
01179 {
01180     DefElem    *d_schema = NULL;
01181     DefElem    *d_new_version = NULL;
01182     DefElem    *d_old_version = NULL;
01183     char       *schemaName;
01184     Oid         schemaOid;
01185     char       *versionName;
01186     char       *oldVersionName;
01187     Oid         extowner = GetUserId();
01188     ExtensionControlFile *pcontrol;
01189     ExtensionControlFile *control;
01190     List       *updateVersions;
01191     List       *requiredExtensions;
01192     List       *requiredSchemas;
01193     Oid         extensionOid;
01194     ListCell   *lc;
01195 
01196     /* Check extension name validity before any filesystem access */
01197     check_valid_extension_name(stmt->extname);
01198 
01199     /*
01200      * Check for duplicate extension name.  The unique index on
01201      * pg_extension.extname would catch this anyway, and serves as a backstop
01202      * in case of race conditions; but this is a friendlier error message, and
01203      * besides we need a check to support IF NOT EXISTS.
01204      */
01205     if (get_extension_oid(stmt->extname, true) != InvalidOid)
01206     {
01207         if (stmt->if_not_exists)
01208         {
01209             ereport(NOTICE,
01210                     (errcode(ERRCODE_DUPLICATE_OBJECT),
01211                      errmsg("extension \"%s\" already exists, skipping",
01212                             stmt->extname)));
01213             return InvalidOid;
01214         }
01215         else
01216             ereport(ERROR,
01217                     (errcode(ERRCODE_DUPLICATE_OBJECT),
01218                      errmsg("extension \"%s\" already exists",
01219                             stmt->extname)));
01220     }
01221 
01222     /*
01223      * We use global variables to track the extension being created, so we can
01224      * create only one extension at the same time.
01225      */
01226     if (creating_extension)
01227         ereport(ERROR,
01228                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01229                  errmsg("nested CREATE EXTENSION is not supported")));
01230 
01231     /*
01232      * Read the primary control file.  Note we assume that it does not contain
01233      * any non-ASCII data, so there is no need to worry about encoding at this
01234      * point.
01235      */
01236     pcontrol = read_extension_control_file(stmt->extname);
01237 
01238     /*
01239      * Read the statement option list
01240      */
01241     foreach(lc, stmt->options)
01242     {
01243         DefElem    *defel = (DefElem *) lfirst(lc);
01244 
01245         if (strcmp(defel->defname, "schema") == 0)
01246         {
01247             if (d_schema)
01248                 ereport(ERROR,
01249                         (errcode(ERRCODE_SYNTAX_ERROR),
01250                          errmsg("conflicting or redundant options")));
01251             d_schema = defel;
01252         }
01253         else if (strcmp(defel->defname, "new_version") == 0)
01254         {
01255             if (d_new_version)
01256                 ereport(ERROR,
01257                         (errcode(ERRCODE_SYNTAX_ERROR),
01258                          errmsg("conflicting or redundant options")));
01259             d_new_version = defel;
01260         }
01261         else if (strcmp(defel->defname, "old_version") == 0)
01262         {
01263             if (d_old_version)
01264                 ereport(ERROR,
01265                         (errcode(ERRCODE_SYNTAX_ERROR),
01266                          errmsg("conflicting or redundant options")));
01267             d_old_version = defel;
01268         }
01269         else
01270             elog(ERROR, "unrecognized option: %s", defel->defname);
01271     }
01272 
01273     /*
01274      * Determine the version to install
01275      */
01276     if (d_new_version && d_new_version->arg)
01277         versionName = strVal(d_new_version->arg);
01278     else if (pcontrol->default_version)
01279         versionName = pcontrol->default_version;
01280     else
01281     {
01282         ereport(ERROR,
01283                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
01284                  errmsg("version to install must be specified")));
01285         versionName = NULL;     /* keep compiler quiet */
01286     }
01287     check_valid_version_name(versionName);
01288 
01289     /*
01290      * Determine the (unpackaged) version to update from, if any, and then
01291      * figure out what sequence of update scripts we need to apply.
01292      */
01293     if (d_old_version && d_old_version->arg)
01294     {
01295         oldVersionName = strVal(d_old_version->arg);
01296         check_valid_version_name(oldVersionName);
01297 
01298         if (strcmp(oldVersionName, versionName) == 0)
01299             ereport(ERROR,
01300                     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
01301                      errmsg("FROM version must be different from installation target version \"%s\"",
01302                             versionName)));
01303 
01304         updateVersions = identify_update_path(pcontrol,
01305                                               oldVersionName,
01306                                               versionName);
01307 
01308         if (list_length(updateVersions) == 1)
01309         {
01310             /*
01311              * Simple case where there's just one update script to run. We
01312              * will not need any follow-on update steps.
01313              */
01314             Assert(strcmp((char *) linitial(updateVersions), versionName) == 0);
01315             updateVersions = NIL;
01316         }
01317         else
01318         {
01319             /*
01320              * Multi-step sequence.  We treat this as installing the version
01321              * that is the target of the first script, followed by successive
01322              * updates to the later versions.
01323              */
01324             versionName = (char *) linitial(updateVersions);
01325             updateVersions = list_delete_first(updateVersions);
01326         }
01327     }
01328     else
01329     {
01330         oldVersionName = NULL;
01331         updateVersions = NIL;
01332     }
01333 
01334     /*
01335      * Fetch control parameters for installation target version
01336      */
01337     control = read_extension_aux_control_file(pcontrol, versionName);
01338 
01339     /*
01340      * Determine the target schema to install the extension into
01341      */
01342     if (d_schema && d_schema->arg)
01343     {
01344         /*
01345          * User given schema, CREATE EXTENSION ... WITH SCHEMA ...
01346          *
01347          * It's an error to give a schema different from control->schema if
01348          * control->schema is specified.
01349          */
01350         schemaName = strVal(d_schema->arg);
01351 
01352         if (control->schema != NULL &&
01353             strcmp(control->schema, schemaName) != 0)
01354             ereport(ERROR,
01355                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01356                 errmsg("extension \"%s\" must be installed in schema \"%s\"",
01357                        control->name,
01358                        control->schema)));
01359 
01360         /* If the user is giving us the schema name, it must exist already */
01361         schemaOid = get_namespace_oid(schemaName, false);
01362     }
01363     else if (control->schema != NULL)
01364     {
01365         /*
01366          * The extension is not relocatable and the author gave us a schema
01367          * for it.  We create the schema here if it does not already exist.
01368          */
01369         schemaName = control->schema;
01370         schemaOid = get_namespace_oid(schemaName, true);
01371 
01372         if (schemaOid == InvalidOid)
01373         {
01374             CreateSchemaStmt *csstmt = makeNode(CreateSchemaStmt);
01375 
01376             csstmt->schemaname = schemaName;
01377             csstmt->authid = NULL;      /* will be created by current user */
01378             csstmt->schemaElts = NIL;
01379             csstmt->if_not_exists = false;
01380             CreateSchemaCommand(csstmt, NULL);
01381 
01382             /*
01383              * CreateSchemaCommand includes CommandCounterIncrement, so new
01384              * schema is now visible
01385              */
01386             schemaOid = get_namespace_oid(schemaName, false);
01387         }
01388     }
01389     else
01390     {
01391         /*
01392          * Else, use the current default creation namespace, which is the
01393          * first explicit entry in the search_path.
01394          */
01395         List       *search_path = fetch_search_path(false);
01396 
01397         if (search_path == NIL) /* probably can't happen */
01398             elog(ERROR, "there is no default creation target");
01399         schemaOid = linitial_oid(search_path);
01400         schemaName = get_namespace_name(schemaOid);
01401         if (schemaName == NULL) /* recently-deleted namespace? */
01402             elog(ERROR, "there is no default creation target");
01403 
01404         list_free(search_path);
01405     }
01406 
01407     /*
01408      * We don't check creation rights on the target namespace here.  If the
01409      * extension script actually creates any objects there, it will fail if
01410      * the user doesn't have such permissions.  But there are cases such as
01411      * procedural languages where it's convenient to set schema = pg_catalog
01412      * yet we don't want to restrict the command to users with ACL_CREATE for
01413      * pg_catalog.
01414      */
01415 
01416     /*
01417      * Look up the prerequisite extensions, and build lists of their OIDs and
01418      * the OIDs of their target schemas.
01419      */
01420     requiredExtensions = NIL;
01421     requiredSchemas = NIL;
01422     foreach(lc, control->requires)
01423     {
01424         char       *curreq = (char *) lfirst(lc);
01425         Oid         reqext;
01426         Oid         reqschema;
01427 
01428         /*
01429          * We intentionally don't use get_extension_oid's default error
01430          * message here, because it would be confusing in this context.
01431          */
01432         reqext = get_extension_oid(curreq, true);
01433         if (!OidIsValid(reqext))
01434             ereport(ERROR,
01435                     (errcode(ERRCODE_UNDEFINED_OBJECT),
01436                      errmsg("required extension \"%s\" is not installed",
01437                             curreq)));
01438         reqschema = get_extension_schema(reqext);
01439         requiredExtensions = lappend_oid(requiredExtensions, reqext);
01440         requiredSchemas = lappend_oid(requiredSchemas, reqschema);
01441     }
01442 
01443     /*
01444      * Insert new tuple into pg_extension, and create dependency entries.
01445      */
01446     extensionOid = InsertExtensionTuple(control->name, extowner,
01447                                         schemaOid, control->relocatable,
01448                                         versionName,
01449                                         PointerGetDatum(NULL),
01450                                         PointerGetDatum(NULL),
01451                                         requiredExtensions);
01452 
01453     /*
01454      * Apply any control-file comment on extension
01455      */
01456     if (control->comment != NULL)
01457         CreateComments(extensionOid, ExtensionRelationId, 0, control->comment);
01458 
01459     /*
01460      * Execute the installation script file
01461      */
01462     execute_extension_script(extensionOid, control,
01463                              oldVersionName, versionName,
01464                              requiredSchemas,
01465                              schemaName, schemaOid);
01466 
01467     /*
01468      * If additional update scripts have to be executed, apply the updates as
01469      * though a series of ALTER EXTENSION UPDATE commands were given
01470      */
01471     ApplyExtensionUpdates(extensionOid, pcontrol,
01472                           versionName, updateVersions);
01473 
01474     return extensionOid;
01475 }
01476 
01477 /*
01478  * InsertExtensionTuple
01479  *
01480  * Insert the new pg_extension row, and create extension's dependency entries.
01481  * Return the OID assigned to the new row.
01482  *
01483  * This is exported for the benefit of pg_upgrade, which has to create a
01484  * pg_extension entry (and the extension-level dependencies) without
01485  * actually running the extension's script.
01486  *
01487  * extConfig and extCondition should be arrays or PointerGetDatum(NULL).
01488  * We declare them as plain Datum to avoid needing array.h in extension.h.
01489  */
01490 Oid
01491 InsertExtensionTuple(const char *extName, Oid extOwner,
01492                      Oid schemaOid, bool relocatable, const char *extVersion,
01493                      Datum extConfig, Datum extCondition,
01494                      List *requiredExtensions)
01495 {
01496     Oid         extensionOid;
01497     Relation    rel;
01498     Datum       values[Natts_pg_extension];
01499     bool        nulls[Natts_pg_extension];
01500     HeapTuple   tuple;
01501     ObjectAddress myself;
01502     ObjectAddress nsp;
01503     ListCell   *lc;
01504 
01505     /*
01506      * Build and insert the pg_extension tuple
01507      */
01508     rel = heap_open(ExtensionRelationId, RowExclusiveLock);
01509 
01510     memset(values, 0, sizeof(values));
01511     memset(nulls, 0, sizeof(nulls));
01512 
01513     values[Anum_pg_extension_extname - 1] =
01514         DirectFunctionCall1(namein, CStringGetDatum(extName));
01515     values[Anum_pg_extension_extowner - 1] = ObjectIdGetDatum(extOwner);
01516     values[Anum_pg_extension_extnamespace - 1] = ObjectIdGetDatum(schemaOid);
01517     values[Anum_pg_extension_extrelocatable - 1] = BoolGetDatum(relocatable);
01518     values[Anum_pg_extension_extversion - 1] = CStringGetTextDatum(extVersion);
01519 
01520     if (extConfig == PointerGetDatum(NULL))
01521         nulls[Anum_pg_extension_extconfig - 1] = true;
01522     else
01523         values[Anum_pg_extension_extconfig - 1] = extConfig;
01524 
01525     if (extCondition == PointerGetDatum(NULL))
01526         nulls[Anum_pg_extension_extcondition - 1] = true;
01527     else
01528         values[Anum_pg_extension_extcondition - 1] = extCondition;
01529 
01530     tuple = heap_form_tuple(rel->rd_att, values, nulls);
01531 
01532     extensionOid = simple_heap_insert(rel, tuple);
01533     CatalogUpdateIndexes(rel, tuple);
01534 
01535     heap_freetuple(tuple);
01536     heap_close(rel, RowExclusiveLock);
01537 
01538     /*
01539      * Record dependencies on owner, schema, and prerequisite extensions
01540      */
01541     recordDependencyOnOwner(ExtensionRelationId, extensionOid, extOwner);
01542 
01543     myself.classId = ExtensionRelationId;
01544     myself.objectId = extensionOid;
01545     myself.objectSubId = 0;
01546 
01547     nsp.classId = NamespaceRelationId;
01548     nsp.objectId = schemaOid;
01549     nsp.objectSubId = 0;
01550 
01551     recordDependencyOn(&myself, &nsp, DEPENDENCY_NORMAL);
01552 
01553     foreach(lc, requiredExtensions)
01554     {
01555         Oid         reqext = lfirst_oid(lc);
01556         ObjectAddress otherext;
01557 
01558         otherext.classId = ExtensionRelationId;
01559         otherext.objectId = reqext;
01560         otherext.objectSubId = 0;
01561 
01562         recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
01563     }
01564     /* Post creation hook for new extension */
01565     InvokeObjectPostCreateHook(ExtensionRelationId, extensionOid, 0);
01566 
01567     return extensionOid;
01568 }
01569 
01570 /*
01571  * Guts of extension deletion.
01572  *
01573  * All we need do here is remove the pg_extension tuple itself.  Everything
01574  * else is taken care of by the dependency infrastructure.
01575  */
01576 void
01577 RemoveExtensionById(Oid extId)
01578 {
01579     Relation    rel;
01580     SysScanDesc scandesc;
01581     HeapTuple   tuple;
01582     ScanKeyData entry[1];
01583 
01584     /*
01585      * Disallow deletion of any extension that's currently open for insertion;
01586      * else subsequent executions of recordDependencyOnCurrentExtension()
01587      * could create dangling pg_depend records that refer to a no-longer-valid
01588      * pg_extension OID.  This is needed not so much because we think people
01589      * might write "DROP EXTENSION foo" in foo's own script files, as because
01590      * errors in dependency management in extension script files could give
01591      * rise to cases where an extension is dropped as a result of recursing
01592      * from some contained object.  Because of that, we must test for the case
01593      * here, not at some higher level of the DROP EXTENSION command.
01594      */
01595     if (extId == CurrentExtensionObject)
01596         ereport(ERROR,
01597                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
01598           errmsg("cannot drop extension \"%s\" because it is being modified",
01599                  get_extension_name(extId))));
01600 
01601     rel = heap_open(ExtensionRelationId, RowExclusiveLock);
01602 
01603     ScanKeyInit(&entry[0],
01604                 ObjectIdAttributeNumber,
01605                 BTEqualStrategyNumber, F_OIDEQ,
01606                 ObjectIdGetDatum(extId));
01607     scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
01608                                   SnapshotNow, 1, entry);
01609 
01610     tuple = systable_getnext(scandesc);
01611 
01612     /* We assume that there can be at most one matching tuple */
01613     if (HeapTupleIsValid(tuple))
01614         simple_heap_delete(rel, &tuple->t_self);
01615 
01616     systable_endscan(scandesc);
01617 
01618     heap_close(rel, RowExclusiveLock);
01619 }
01620 
01621 /*
01622  * This function lists the available extensions (one row per primary control
01623  * file in the control directory).  We parse each control file and report the
01624  * interesting fields.
01625  *
01626  * The system view pg_available_extensions provides a user interface to this
01627  * SRF, adding information about whether the extensions are installed in the
01628  * current DB.
01629  */
01630 Datum
01631 pg_available_extensions(PG_FUNCTION_ARGS)
01632 {
01633     ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
01634     TupleDesc   tupdesc;
01635     Tuplestorestate *tupstore;
01636     MemoryContext per_query_ctx;
01637     MemoryContext oldcontext;
01638     char       *location;
01639     DIR        *dir;
01640     struct dirent *de;
01641 
01642     /* check to see if caller supports us returning a tuplestore */
01643     if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
01644         ereport(ERROR,
01645                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01646                  errmsg("set-valued function called in context that cannot accept a set")));
01647     if (!(rsinfo->allowedModes & SFRM_Materialize))
01648         ereport(ERROR,
01649                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01650                  errmsg("materialize mode required, but it is not " \
01651                         "allowed in this context")));
01652 
01653     /* Build a tuple descriptor for our result type */
01654     if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
01655         elog(ERROR, "return type must be a row type");
01656 
01657     /* Build tuplestore to hold the result rows */
01658     per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
01659     oldcontext = MemoryContextSwitchTo(per_query_ctx);
01660 
01661     tupstore = tuplestore_begin_heap(true, false, work_mem);
01662     rsinfo->returnMode = SFRM_Materialize;
01663     rsinfo->setResult = tupstore;
01664     rsinfo->setDesc = tupdesc;
01665 
01666     MemoryContextSwitchTo(oldcontext);
01667 
01668     location = get_extension_control_directory();
01669     dir = AllocateDir(location);
01670 
01671     /*
01672      * If the control directory doesn't exist, we want to silently return an
01673      * empty set.  Any other error will be reported by ReadDir.
01674      */
01675     if (dir == NULL && errno == ENOENT)
01676     {
01677         /* do nothing */
01678     }
01679     else
01680     {
01681         while ((de = ReadDir(dir, location)) != NULL)
01682         {
01683             ExtensionControlFile *control;
01684             char       *extname;
01685             Datum       values[3];
01686             bool        nulls[3];
01687 
01688             if (!is_extension_control_filename(de->d_name))
01689                 continue;
01690 
01691             /* extract extension name from 'name.control' filename */
01692             extname = pstrdup(de->d_name);
01693             *strrchr(extname, '.') = '\0';
01694 
01695             /* ignore it if it's an auxiliary control file */
01696             if (strstr(extname, "--"))
01697                 continue;
01698 
01699             control = read_extension_control_file(extname);
01700 
01701             memset(values, 0, sizeof(values));
01702             memset(nulls, 0, sizeof(nulls));
01703 
01704             /* name */
01705             values[0] = DirectFunctionCall1(namein,
01706                                             CStringGetDatum(control->name));
01707             /* default_version */
01708             if (control->default_version == NULL)
01709                 nulls[1] = true;
01710             else
01711                 values[1] = CStringGetTextDatum(control->default_version);
01712             /* comment */
01713             if (control->comment == NULL)
01714                 nulls[2] = true;
01715             else
01716                 values[2] = CStringGetTextDatum(control->comment);
01717 
01718             tuplestore_putvalues(tupstore, tupdesc, values, nulls);
01719         }
01720 
01721         FreeDir(dir);
01722     }
01723 
01724     /* clean up and return the tuplestore */
01725     tuplestore_donestoring(tupstore);
01726 
01727     return (Datum) 0;
01728 }
01729 
01730 /*
01731  * This function lists the available extension versions (one row per
01732  * extension installation script).  For each version, we parse the related
01733  * control file(s) and report the interesting fields.
01734  *
01735  * The system view pg_available_extension_versions provides a user interface
01736  * to this SRF, adding information about which versions are installed in the
01737  * current DB.
01738  */
01739 Datum
01740 pg_available_extension_versions(PG_FUNCTION_ARGS)
01741 {
01742     ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
01743     TupleDesc   tupdesc;
01744     Tuplestorestate *tupstore;
01745     MemoryContext per_query_ctx;
01746     MemoryContext oldcontext;
01747     char       *location;
01748     DIR        *dir;
01749     struct dirent *de;
01750 
01751     /* check to see if caller supports us returning a tuplestore */
01752     if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
01753         ereport(ERROR,
01754                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01755                  errmsg("set-valued function called in context that cannot accept a set")));
01756     if (!(rsinfo->allowedModes & SFRM_Materialize))
01757         ereport(ERROR,
01758                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01759                  errmsg("materialize mode required, but it is not " \
01760                         "allowed in this context")));
01761 
01762     /* Build a tuple descriptor for our result type */
01763     if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
01764         elog(ERROR, "return type must be a row type");
01765 
01766     /* Build tuplestore to hold the result rows */
01767     per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
01768     oldcontext = MemoryContextSwitchTo(per_query_ctx);
01769 
01770     tupstore = tuplestore_begin_heap(true, false, work_mem);
01771     rsinfo->returnMode = SFRM_Materialize;
01772     rsinfo->setResult = tupstore;
01773     rsinfo->setDesc = tupdesc;
01774 
01775     MemoryContextSwitchTo(oldcontext);
01776 
01777     location = get_extension_control_directory();
01778     dir = AllocateDir(location);
01779 
01780     /*
01781      * If the control directory doesn't exist, we want to silently return an
01782      * empty set.  Any other error will be reported by ReadDir.
01783      */
01784     if (dir == NULL && errno == ENOENT)
01785     {
01786         /* do nothing */
01787     }
01788     else
01789     {
01790         while ((de = ReadDir(dir, location)) != NULL)
01791         {
01792             ExtensionControlFile *control;
01793             char       *extname;
01794 
01795             if (!is_extension_control_filename(de->d_name))
01796                 continue;
01797 
01798             /* extract extension name from 'name.control' filename */
01799             extname = pstrdup(de->d_name);
01800             *strrchr(extname, '.') = '\0';
01801 
01802             /* ignore it if it's an auxiliary control file */
01803             if (strstr(extname, "--"))
01804                 continue;
01805 
01806             /* read the control file */
01807             control = read_extension_control_file(extname);
01808 
01809             /* scan extension's script directory for install scripts */
01810             get_available_versions_for_extension(control, tupstore, tupdesc);
01811         }
01812 
01813         FreeDir(dir);
01814     }
01815 
01816     /* clean up and return the tuplestore */
01817     tuplestore_donestoring(tupstore);
01818 
01819     return (Datum) 0;
01820 }
01821 
01822 /*
01823  * Inner loop for pg_available_extension_versions:
01824  *      read versions of one extension, add rows to tupstore
01825  */
01826 static void
01827 get_available_versions_for_extension(ExtensionControlFile *pcontrol,
01828                                      Tuplestorestate *tupstore,
01829                                      TupleDesc tupdesc)
01830 {
01831     int         extnamelen = strlen(pcontrol->name);
01832     char       *location;
01833     DIR        *dir;
01834     struct dirent *de;
01835 
01836     location = get_extension_script_directory(pcontrol);
01837     dir = AllocateDir(location);
01838     /* Note this will fail if script directory doesn't exist */
01839     while ((de = ReadDir(dir, location)) != NULL)
01840     {
01841         ExtensionControlFile *control;
01842         char       *vername;
01843         Datum       values[7];
01844         bool        nulls[7];
01845 
01846         /* must be a .sql file ... */
01847         if (!is_extension_script_filename(de->d_name))
01848             continue;
01849 
01850         /* ... matching extension name followed by separator */
01851         if (strncmp(de->d_name, pcontrol->name, extnamelen) != 0 ||
01852             de->d_name[extnamelen] != '-' ||
01853             de->d_name[extnamelen + 1] != '-')
01854             continue;
01855 
01856         /* extract version name from 'extname--something.sql' filename */
01857         vername = pstrdup(de->d_name + extnamelen + 2);
01858         *strrchr(vername, '.') = '\0';
01859 
01860         /* ignore it if it's an update script */
01861         if (strstr(vername, "--"))
01862             continue;
01863 
01864         /*
01865          * Fetch parameters for specific version (pcontrol is not changed)
01866          */
01867         control = read_extension_aux_control_file(pcontrol, vername);
01868 
01869         memset(values, 0, sizeof(values));
01870         memset(nulls, 0, sizeof(nulls));
01871 
01872         /* name */
01873         values[0] = DirectFunctionCall1(namein,
01874                                         CStringGetDatum(control->name));
01875         /* version */
01876         values[1] = CStringGetTextDatum(vername);
01877         /* superuser */
01878         values[2] = BoolGetDatum(control->superuser);
01879         /* relocatable */
01880         values[3] = BoolGetDatum(control->relocatable);
01881         /* schema */
01882         if (control->schema == NULL)
01883             nulls[4] = true;
01884         else
01885             values[4] = DirectFunctionCall1(namein,
01886                                             CStringGetDatum(control->schema));
01887         /* requires */
01888         if (control->requires == NIL)
01889             nulls[5] = true;
01890         else
01891         {
01892             Datum      *datums;
01893             int         ndatums;
01894             ArrayType  *a;
01895             ListCell   *lc;
01896 
01897             ndatums = list_length(control->requires);
01898             datums = (Datum *) palloc(ndatums * sizeof(Datum));
01899             ndatums = 0;
01900             foreach(lc, control->requires)
01901             {
01902                 char       *curreq = (char *) lfirst(lc);
01903 
01904                 datums[ndatums++] =
01905                     DirectFunctionCall1(namein, CStringGetDatum(curreq));
01906             }
01907             a = construct_array(datums, ndatums,
01908                                 NAMEOID,
01909                                 NAMEDATALEN, false, 'c');
01910             values[5] = PointerGetDatum(a);
01911         }
01912         /* comment */
01913         if (control->comment == NULL)
01914             nulls[6] = true;
01915         else
01916             values[6] = CStringGetTextDatum(control->comment);
01917 
01918         tuplestore_putvalues(tupstore, tupdesc, values, nulls);
01919     }
01920 
01921     FreeDir(dir);
01922 }
01923 
01924 /*
01925  * This function reports the version update paths that exist for the
01926  * specified extension.
01927  */
01928 Datum
01929 pg_extension_update_paths(PG_FUNCTION_ARGS)
01930 {
01931     Name        extname = PG_GETARG_NAME(0);
01932     ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
01933     TupleDesc   tupdesc;
01934     Tuplestorestate *tupstore;
01935     MemoryContext per_query_ctx;
01936     MemoryContext oldcontext;
01937     List       *evi_list;
01938     ExtensionControlFile *control;
01939     ListCell   *lc1;
01940 
01941     /* Check extension name validity before any filesystem access */
01942     check_valid_extension_name(NameStr(*extname));
01943 
01944     /* check to see if caller supports us returning a tuplestore */
01945     if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
01946         ereport(ERROR,
01947                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01948                  errmsg("set-valued function called in context that cannot accept a set")));
01949     if (!(rsinfo->allowedModes & SFRM_Materialize))
01950         ereport(ERROR,
01951                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01952                  errmsg("materialize mode required, but it is not " \
01953                         "allowed in this context")));
01954 
01955     /* Build a tuple descriptor for our result type */
01956     if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
01957         elog(ERROR, "return type must be a row type");
01958 
01959     /* Build tuplestore to hold the result rows */
01960     per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
01961     oldcontext = MemoryContextSwitchTo(per_query_ctx);
01962 
01963     tupstore = tuplestore_begin_heap(true, false, work_mem);
01964     rsinfo->returnMode = SFRM_Materialize;
01965     rsinfo->setResult = tupstore;
01966     rsinfo->setDesc = tupdesc;
01967 
01968     MemoryContextSwitchTo(oldcontext);
01969 
01970     /* Read the extension's control file */
01971     control = read_extension_control_file(NameStr(*extname));
01972 
01973     /* Extract the version update graph from the script directory */
01974     evi_list = get_ext_ver_list(control);
01975 
01976     /* Iterate over all pairs of versions */
01977     foreach(lc1, evi_list)
01978     {
01979         ExtensionVersionInfo *evi1 = (ExtensionVersionInfo *) lfirst(lc1);
01980         ListCell   *lc2;
01981 
01982         foreach(lc2, evi_list)
01983         {
01984             ExtensionVersionInfo *evi2 = (ExtensionVersionInfo *) lfirst(lc2);
01985             List       *path;
01986             Datum       values[3];
01987             bool        nulls[3];
01988 
01989             if (evi1 == evi2)
01990                 continue;
01991 
01992             /* Find shortest path from evi1 to evi2 */
01993             path = find_update_path(evi_list, evi1, evi2, true);
01994 
01995             /* Emit result row */
01996             memset(values, 0, sizeof(values));
01997             memset(nulls, 0, sizeof(nulls));
01998 
01999             /* source */
02000             values[0] = CStringGetTextDatum(evi1->name);
02001             /* target */
02002             values[1] = CStringGetTextDatum(evi2->name);
02003             /* path */
02004             if (path == NIL)
02005                 nulls[2] = true;
02006             else
02007             {
02008                 StringInfoData pathbuf;
02009                 ListCell   *lcv;
02010 
02011                 initStringInfo(&pathbuf);
02012                 /* The path doesn't include start vertex, but show it */
02013                 appendStringInfoString(&pathbuf, evi1->name);
02014                 foreach(lcv, path)
02015                 {
02016                     char       *versionName = (char *) lfirst(lcv);
02017 
02018                     appendStringInfoString(&pathbuf, "--");
02019                     appendStringInfoString(&pathbuf, versionName);
02020                 }
02021                 values[2] = CStringGetTextDatum(pathbuf.data);
02022                 pfree(pathbuf.data);
02023             }
02024 
02025             tuplestore_putvalues(tupstore, tupdesc, values, nulls);
02026         }
02027     }
02028 
02029     /* clean up and return the tuplestore */
02030     tuplestore_donestoring(tupstore);
02031 
02032     return (Datum) 0;
02033 }
02034 
02035 /*
02036  * pg_extension_config_dump
02037  *
02038  * Record information about a configuration table that belongs to an
02039  * extension being created, but whose contents should be dumped in whole
02040  * or in part during pg_dump.
02041  */
02042 Datum
02043 pg_extension_config_dump(PG_FUNCTION_ARGS)
02044 {
02045     Oid         tableoid = PG_GETARG_OID(0);
02046     text       *wherecond = PG_GETARG_TEXT_P(1);
02047     char       *tablename;
02048     Relation    extRel;
02049     ScanKeyData key[1];
02050     SysScanDesc extScan;
02051     HeapTuple   extTup;
02052     Datum       arrayDatum;
02053     Datum       elementDatum;
02054     int         arrayLength;
02055     int         arrayIndex;
02056     bool        isnull;
02057     Datum       repl_val[Natts_pg_extension];
02058     bool        repl_null[Natts_pg_extension];
02059     bool        repl_repl[Natts_pg_extension];
02060     ArrayType  *a;
02061 
02062     /*
02063      * We only allow this to be called from an extension's SQL script. We
02064      * shouldn't need any permissions check beyond that.
02065      */
02066     if (!creating_extension)
02067         ereport(ERROR,
02068                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
02069                  errmsg("pg_extension_config_dump() can only be called "
02070                         "from an SQL script executed by CREATE EXTENSION")));
02071 
02072     /*
02073      * Check that the table exists and is a member of the extension being
02074      * created.  This ensures that we don't need to register an additional
02075      * dependency to protect the extconfig entry.
02076      */
02077     tablename = get_rel_name(tableoid);
02078     if (tablename == NULL)
02079         ereport(ERROR,
02080                 (errcode(ERRCODE_UNDEFINED_TABLE),
02081                  errmsg("OID %u does not refer to a table", tableoid)));
02082     if (getExtensionOfObject(RelationRelationId, tableoid) !=
02083         CurrentExtensionObject)
02084         ereport(ERROR,
02085                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
02086         errmsg("table \"%s\" is not a member of the extension being created",
02087                tablename)));
02088 
02089     /*
02090      * Add the table OID and WHERE condition to the extension's extconfig and
02091      * extcondition arrays.
02092      *
02093      * If the table is already in extconfig, treat this as an update of the
02094      * WHERE condition.
02095      */
02096 
02097     /* Find the pg_extension tuple */
02098     extRel = heap_open(ExtensionRelationId, RowExclusiveLock);
02099 
02100     ScanKeyInit(&key[0],
02101                 ObjectIdAttributeNumber,
02102                 BTEqualStrategyNumber, F_OIDEQ,
02103                 ObjectIdGetDatum(CurrentExtensionObject));
02104 
02105     extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
02106                                  SnapshotNow, 1, key);
02107 
02108     extTup = systable_getnext(extScan);
02109 
02110     if (!HeapTupleIsValid(extTup))      /* should not happen */
02111         elog(ERROR, "extension with oid %u does not exist",
02112              CurrentExtensionObject);
02113 
02114     memset(repl_val, 0, sizeof(repl_val));
02115     memset(repl_null, false, sizeof(repl_null));
02116     memset(repl_repl, false, sizeof(repl_repl));
02117 
02118     /* Build or modify the extconfig value */
02119     elementDatum = ObjectIdGetDatum(tableoid);
02120 
02121     arrayDatum = heap_getattr(extTup, Anum_pg_extension_extconfig,
02122                               RelationGetDescr(extRel), &isnull);
02123     if (isnull)
02124     {
02125         /* Previously empty extconfig, so build 1-element array */
02126         arrayLength = 0;
02127         arrayIndex = 1;
02128 
02129         a = construct_array(&elementDatum, 1,
02130                             OIDOID,
02131                             sizeof(Oid), true, 'i');
02132     }
02133     else
02134     {
02135         /* Modify or extend existing extconfig array */
02136         Oid        *arrayData;
02137         int         i;
02138 
02139         a = DatumGetArrayTypeP(arrayDatum);
02140 
02141         arrayLength = ARR_DIMS(a)[0];
02142         if (ARR_NDIM(a) != 1 ||
02143             ARR_LBOUND(a)[0] != 1 ||
02144             arrayLength < 0 ||
02145             ARR_HASNULL(a) ||
02146             ARR_ELEMTYPE(a) != OIDOID)
02147             elog(ERROR, "extconfig is not a 1-D Oid array");
02148         arrayData = (Oid *) ARR_DATA_PTR(a);
02149 
02150         arrayIndex = arrayLength + 1;   /* set up to add after end */
02151 
02152         for (i = 0; i < arrayLength; i++)
02153         {
02154             if (arrayData[i] == tableoid)
02155             {
02156                 arrayIndex = i + 1;     /* replace this element instead */
02157                 break;
02158             }
02159         }
02160 
02161         a = array_set(a, 1, &arrayIndex,
02162                       elementDatum,
02163                       false,
02164                       -1 /* varlena array */ ,
02165                       sizeof(Oid) /* OID's typlen */ ,
02166                       true /* OID's typbyval */ ,
02167                       'i' /* OID's typalign */ );
02168     }
02169     repl_val[Anum_pg_extension_extconfig - 1] = PointerGetDatum(a);
02170     repl_repl[Anum_pg_extension_extconfig - 1] = true;
02171 
02172     /* Build or modify the extcondition value */
02173     elementDatum = PointerGetDatum(wherecond);
02174 
02175     arrayDatum = heap_getattr(extTup, Anum_pg_extension_extcondition,
02176                               RelationGetDescr(extRel), &isnull);
02177     if (isnull)
02178     {
02179         if (arrayLength != 0)
02180             elog(ERROR, "extconfig and extcondition arrays do not match");
02181 
02182         a = construct_array(&elementDatum, 1,
02183                             TEXTOID,
02184                             -1, false, 'i');
02185     }
02186     else
02187     {
02188         a = DatumGetArrayTypeP(arrayDatum);
02189 
02190         if (ARR_NDIM(a) != 1 ||
02191             ARR_LBOUND(a)[0] != 1 ||
02192             ARR_HASNULL(a) ||
02193             ARR_ELEMTYPE(a) != TEXTOID)
02194             elog(ERROR, "extcondition is not a 1-D text array");
02195         if (ARR_DIMS(a)[0] != arrayLength)
02196             elog(ERROR, "extconfig and extcondition arrays do not match");
02197 
02198         /* Add or replace at same index as in extconfig */
02199         a = array_set(a, 1, &arrayIndex,
02200                       elementDatum,
02201                       false,
02202                       -1 /* varlena array */ ,
02203                       -1 /* TEXT's typlen */ ,
02204                       false /* TEXT's typbyval */ ,
02205                       'i' /* TEXT's typalign */ );
02206     }
02207     repl_val[Anum_pg_extension_extcondition - 1] = PointerGetDatum(a);
02208     repl_repl[Anum_pg_extension_extcondition - 1] = true;
02209 
02210     extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
02211                                repl_val, repl_null, repl_repl);
02212 
02213     simple_heap_update(extRel, &extTup->t_self, extTup);
02214     CatalogUpdateIndexes(extRel, extTup);
02215 
02216     systable_endscan(extScan);
02217 
02218     heap_close(extRel, RowExclusiveLock);
02219 
02220     PG_RETURN_VOID();
02221 }
02222 
02223 /*
02224  * extension_config_remove
02225  *
02226  * Remove the specified table OID from extension's extconfig, if present.
02227  * This is not currently exposed as a function, but it could be;
02228  * for now, we just invoke it from ALTER EXTENSION DROP.
02229  */
02230 static void
02231 extension_config_remove(Oid extensionoid, Oid tableoid)
02232 {
02233     Relation    extRel;
02234     ScanKeyData key[1];
02235     SysScanDesc extScan;
02236     HeapTuple   extTup;
02237     Datum       arrayDatum;
02238     int         arrayLength;
02239     int         arrayIndex;
02240     bool        isnull;
02241     Datum       repl_val[Natts_pg_extension];
02242     bool        repl_null[Natts_pg_extension];
02243     bool        repl_repl[Natts_pg_extension];
02244     ArrayType  *a;
02245 
02246     /* Find the pg_extension tuple */
02247     extRel = heap_open(ExtensionRelationId, RowExclusiveLock);
02248 
02249     ScanKeyInit(&key[0],
02250                 ObjectIdAttributeNumber,
02251                 BTEqualStrategyNumber, F_OIDEQ,
02252                 ObjectIdGetDatum(extensionoid));
02253 
02254     extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
02255                                  SnapshotNow, 1, key);
02256 
02257     extTup = systable_getnext(extScan);
02258 
02259     if (!HeapTupleIsValid(extTup))      /* should not happen */
02260         elog(ERROR, "extension with oid %u does not exist",
02261              extensionoid);
02262 
02263     /* Search extconfig for the tableoid */
02264     arrayDatum = heap_getattr(extTup, Anum_pg_extension_extconfig,
02265                               RelationGetDescr(extRel), &isnull);
02266     if (isnull)
02267     {
02268         /* nothing to do */
02269         a = NULL;
02270         arrayLength = 0;
02271         arrayIndex = -1;
02272     }
02273     else
02274     {
02275         Oid        *arrayData;
02276         int         i;
02277 
02278         a = DatumGetArrayTypeP(arrayDatum);
02279 
02280         arrayLength = ARR_DIMS(a)[0];
02281         if (ARR_NDIM(a) != 1 ||
02282             ARR_LBOUND(a)[0] != 1 ||
02283             arrayLength < 0 ||
02284             ARR_HASNULL(a) ||
02285             ARR_ELEMTYPE(a) != OIDOID)
02286             elog(ERROR, "extconfig is not a 1-D Oid array");
02287         arrayData = (Oid *) ARR_DATA_PTR(a);
02288 
02289         arrayIndex = -1;        /* flag for no deletion needed */
02290 
02291         for (i = 0; i < arrayLength; i++)
02292         {
02293             if (arrayData[i] == tableoid)
02294             {
02295                 arrayIndex = i; /* index to remove */
02296                 break;
02297             }
02298         }
02299     }
02300 
02301     /* If tableoid is not in extconfig, nothing to do */
02302     if (arrayIndex < 0)
02303     {
02304         systable_endscan(extScan);
02305         heap_close(extRel, RowExclusiveLock);
02306         return;
02307     }
02308 
02309     /* Modify or delete the extconfig value */
02310     memset(repl_val, 0, sizeof(repl_val));
02311     memset(repl_null, false, sizeof(repl_null));
02312     memset(repl_repl, false, sizeof(repl_repl));
02313 
02314     if (arrayLength <= 1)
02315     {
02316         /* removing only element, just set array to null */
02317         repl_null[Anum_pg_extension_extconfig - 1] = true;
02318     }
02319     else
02320     {
02321         /* squeeze out the target element */
02322         Datum      *dvalues;
02323         bool       *dnulls;
02324         int         nelems;
02325         int         i;
02326 
02327         deconstruct_array(a, OIDOID, sizeof(Oid), true, 'i',
02328                           &dvalues, &dnulls, &nelems);
02329 
02330         /* We already checked there are no nulls, so ignore dnulls */
02331         for (i = arrayIndex; i < arrayLength - 1; i++)
02332             dvalues[i] = dvalues[i + 1];
02333 
02334         a = construct_array(dvalues, arrayLength - 1,
02335                             OIDOID, sizeof(Oid), true, 'i');
02336 
02337         repl_val[Anum_pg_extension_extconfig - 1] = PointerGetDatum(a);
02338     }
02339     repl_repl[Anum_pg_extension_extconfig - 1] = true;
02340 
02341     /* Modify or delete the extcondition value */
02342     arrayDatum = heap_getattr(extTup, Anum_pg_extension_extcondition,
02343                               RelationGetDescr(extRel), &isnull);
02344     if (isnull)
02345     {
02346         elog(ERROR, "extconfig and extcondition arrays do not match");
02347     }
02348     else
02349     {
02350         a = DatumGetArrayTypeP(arrayDatum);
02351 
02352         if (ARR_NDIM(a) != 1 ||
02353             ARR_LBOUND(a)[0] != 1 ||
02354             ARR_HASNULL(a) ||
02355             ARR_ELEMTYPE(a) != TEXTOID)
02356             elog(ERROR, "extcondition is not a 1-D text array");
02357         if (ARR_DIMS(a)[0] != arrayLength)
02358             elog(ERROR, "extconfig and extcondition arrays do not match");
02359     }
02360 
02361     if (arrayLength <= 1)
02362     {
02363         /* removing only element, just set array to null */
02364         repl_null[Anum_pg_extension_extcondition - 1] = true;
02365     }
02366     else
02367     {
02368         /* squeeze out the target element */
02369         Datum      *dvalues;
02370         bool       *dnulls;
02371         int         nelems;
02372         int         i;
02373 
02374         deconstruct_array(a, TEXTOID, -1, false, 'i',
02375                           &dvalues, &dnulls, &nelems);
02376 
02377         /* We already checked there are no nulls, so ignore dnulls */
02378         for (i = arrayIndex; i < arrayLength - 1; i++)
02379             dvalues[i] = dvalues[i + 1];
02380 
02381         a = construct_array(dvalues, arrayLength - 1,
02382                             TEXTOID, -1, false, 'i');
02383 
02384         repl_val[Anum_pg_extension_extcondition - 1] = PointerGetDatum(a);
02385     }
02386     repl_repl[Anum_pg_extension_extcondition - 1] = true;
02387 
02388     extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
02389                                repl_val, repl_null, repl_repl);
02390 
02391     simple_heap_update(extRel, &extTup->t_self, extTup);
02392     CatalogUpdateIndexes(extRel, extTup);
02393 
02394     systable_endscan(extScan);
02395 
02396     heap_close(extRel, RowExclusiveLock);
02397 }
02398 
02399 /*
02400  * Execute ALTER EXTENSION SET SCHEMA
02401  */
02402 Oid
02403 AlterExtensionNamespace(List *names, const char *newschema)
02404 {
02405     char       *extensionName;
02406     Oid         extensionOid;
02407     Oid         nspOid;
02408     Oid         oldNspOid = InvalidOid;
02409     AclResult   aclresult;
02410     Relation    extRel;
02411     ScanKeyData key[2];
02412     SysScanDesc extScan;
02413     HeapTuple   extTup;
02414     Form_pg_extension extForm;
02415     Relation    depRel;
02416     SysScanDesc depScan;
02417     HeapTuple   depTup;
02418     ObjectAddresses *objsMoved;
02419 
02420     if (list_length(names) != 1)
02421         ereport(ERROR,
02422                 (errcode(ERRCODE_SYNTAX_ERROR),
02423                  errmsg("extension name cannot be qualified")));
02424     extensionName = strVal(linitial(names));
02425 
02426     extensionOid = get_extension_oid(extensionName, false);
02427 
02428     nspOid = LookupCreationNamespace(newschema);
02429 
02430     /*
02431      * Permission check: must own extension.  Note that we don't bother to
02432      * check ownership of the individual member objects ...
02433      */
02434     if (!pg_extension_ownercheck(extensionOid, GetUserId()))
02435         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EXTENSION,
02436                        extensionName);
02437 
02438     /* Permission check: must have creation rights in target namespace */
02439     aclresult = pg_namespace_aclcheck(nspOid, GetUserId(), ACL_CREATE);
02440     if (aclresult != ACLCHECK_OK)
02441         aclcheck_error(aclresult, ACL_KIND_NAMESPACE, newschema);
02442 
02443     /*
02444      * If the schema is currently a member of the extension, disallow moving
02445      * the extension into the schema.  That would create a dependency loop.
02446      */
02447     if (getExtensionOfObject(NamespaceRelationId, nspOid) == extensionOid)
02448         ereport(ERROR,
02449                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
02450                  errmsg("cannot move extension \"%s\" into schema \"%s\" "
02451                         "because the extension contains the schema",
02452                         extensionName, newschema)));
02453 
02454     /* Locate the pg_extension tuple */
02455     extRel = heap_open(ExtensionRelationId, RowExclusiveLock);
02456 
02457     ScanKeyInit(&key[0],
02458                 ObjectIdAttributeNumber,
02459                 BTEqualStrategyNumber, F_OIDEQ,
02460                 ObjectIdGetDatum(extensionOid));
02461 
02462     extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
02463                                  SnapshotNow, 1, key);
02464 
02465     extTup = systable_getnext(extScan);
02466 
02467     if (!HeapTupleIsValid(extTup))      /* should not happen */
02468         elog(ERROR, "extension with oid %u does not exist", extensionOid);
02469 
02470     /* Copy tuple so we can modify it below */
02471     extTup = heap_copytuple(extTup);
02472     extForm = (Form_pg_extension) GETSTRUCT(extTup);
02473 
02474     systable_endscan(extScan);
02475 
02476     /*
02477      * If the extension is already in the target schema, just silently do
02478      * nothing.
02479      */
02480     if (extForm->extnamespace == nspOid)
02481     {
02482         heap_close(extRel, RowExclusiveLock);
02483         return InvalidOid;
02484     }
02485 
02486     /* Check extension is supposed to be relocatable */
02487     if (!extForm->extrelocatable)
02488         ereport(ERROR,
02489                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
02490                  errmsg("extension \"%s\" does not support SET SCHEMA",
02491                         NameStr(extForm->extname))));
02492 
02493     objsMoved = new_object_addresses();
02494 
02495     /*
02496      * Scan pg_depend to find objects that depend directly on the extension,
02497      * and alter each one's schema.
02498      */
02499     depRel = heap_open(DependRelationId, AccessShareLock);
02500 
02501     ScanKeyInit(&key[0],
02502                 Anum_pg_depend_refclassid,
02503                 BTEqualStrategyNumber, F_OIDEQ,
02504                 ObjectIdGetDatum(ExtensionRelationId));
02505     ScanKeyInit(&key[1],
02506                 Anum_pg_depend_refobjid,
02507                 BTEqualStrategyNumber, F_OIDEQ,
02508                 ObjectIdGetDatum(extensionOid));
02509 
02510     depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
02511                                  SnapshotNow, 2, key);
02512 
02513     while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
02514     {
02515         Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
02516         ObjectAddress dep;
02517         Oid         dep_oldNspOid;
02518 
02519         /*
02520          * Ignore non-membership dependencies.  (Currently, the only other
02521          * case we could see here is a normal dependency from another
02522          * extension.)
02523          */
02524         if (pg_depend->deptype != DEPENDENCY_EXTENSION)
02525             continue;
02526 
02527         dep.classId = pg_depend->classid;
02528         dep.objectId = pg_depend->objid;
02529         dep.objectSubId = pg_depend->objsubid;
02530 
02531         if (dep.objectSubId != 0)       /* should not happen */
02532             elog(ERROR, "extension should not have a sub-object dependency");
02533 
02534         /* Relocate the object */
02535         dep_oldNspOid = AlterObjectNamespace_oid(dep.classId,
02536                                                  dep.objectId,
02537                                                  nspOid,
02538                                                  objsMoved);
02539 
02540         /*
02541          * Remember previous namespace of first object that has one
02542          */
02543         if (oldNspOid == InvalidOid && dep_oldNspOid != InvalidOid)
02544             oldNspOid = dep_oldNspOid;
02545 
02546         /*
02547          * If not all the objects had the same old namespace (ignoring any
02548          * that are not in namespaces), complain.
02549          */
02550         if (dep_oldNspOid != InvalidOid && dep_oldNspOid != oldNspOid)
02551             ereport(ERROR,
02552                     (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
02553                      errmsg("extension \"%s\" does not support SET SCHEMA",
02554                             NameStr(extForm->extname)),
02555                      errdetail("%s is not in the extension's schema \"%s\"",
02556                                getObjectDescription(&dep),
02557                                get_namespace_name(oldNspOid))));
02558     }
02559 
02560     systable_endscan(depScan);
02561 
02562     relation_close(depRel, AccessShareLock);
02563 
02564     /* Now adjust pg_extension.extnamespace */
02565     extForm->extnamespace = nspOid;
02566 
02567     simple_heap_update(extRel, &extTup->t_self, extTup);
02568     CatalogUpdateIndexes(extRel, extTup);
02569 
02570     heap_close(extRel, RowExclusiveLock);
02571 
02572     /* update dependencies to point to the new schema */
02573     changeDependencyFor(ExtensionRelationId, extensionOid,
02574                         NamespaceRelationId, oldNspOid, nspOid);
02575 
02576     InvokeObjectPostAlterHook(ExtensionRelationId, extensionOid, 0);
02577 
02578     return extensionOid;
02579 }
02580 
02581 /*
02582  * Execute ALTER EXTENSION UPDATE
02583  */
02584 Oid
02585 ExecAlterExtensionStmt(AlterExtensionStmt *stmt)
02586 {
02587     DefElem    *d_new_version = NULL;
02588     char       *versionName;
02589     char       *oldVersionName;
02590     ExtensionControlFile *control;
02591     Oid         extensionOid;
02592     Relation    extRel;
02593     ScanKeyData key[1];
02594     SysScanDesc extScan;
02595     HeapTuple   extTup;
02596     List       *updateVersions;
02597     Datum       datum;
02598     bool        isnull;
02599     ListCell   *lc;
02600 
02601     /*
02602      * We use global variables to track the extension being created, so we can
02603      * create/update only one extension at the same time.
02604      */
02605     if (creating_extension)
02606         ereport(ERROR,
02607                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
02608                  errmsg("nested ALTER EXTENSION is not supported")));
02609 
02610     /*
02611      * Look up the extension --- it must already exist in pg_extension
02612      */
02613     extRel = heap_open(ExtensionRelationId, AccessShareLock);
02614 
02615     ScanKeyInit(&key[0],
02616                 Anum_pg_extension_extname,
02617                 BTEqualStrategyNumber, F_NAMEEQ,
02618                 CStringGetDatum(stmt->extname));
02619 
02620     extScan = systable_beginscan(extRel, ExtensionNameIndexId, true,
02621                                  SnapshotNow, 1, key);
02622 
02623     extTup = systable_getnext(extScan);
02624 
02625     if (!HeapTupleIsValid(extTup))
02626         ereport(ERROR,
02627                 (errcode(ERRCODE_UNDEFINED_OBJECT),
02628                  errmsg("extension \"%s\" does not exist",
02629                         stmt->extname)));
02630 
02631     extensionOid = HeapTupleGetOid(extTup);
02632 
02633     /*
02634      * Determine the existing version we are updating from
02635      */
02636     datum = heap_getattr(extTup, Anum_pg_extension_extversion,
02637                          RelationGetDescr(extRel), &isnull);
02638     if (isnull)
02639         elog(ERROR, "extversion is null");
02640     oldVersionName = text_to_cstring(DatumGetTextPP(datum));
02641 
02642     systable_endscan(extScan);
02643 
02644     heap_close(extRel, AccessShareLock);
02645 
02646     /* Permission check: must own extension */
02647     if (!pg_extension_ownercheck(extensionOid, GetUserId()))
02648         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EXTENSION,
02649                        stmt->extname);
02650 
02651     /*
02652      * Read the primary control file.  Note we assume that it does not contain
02653      * any non-ASCII data, so there is no need to worry about encoding at this
02654      * point.
02655      */
02656     control = read_extension_control_file(stmt->extname);
02657 
02658     /*
02659      * Read the statement option list
02660      */
02661     foreach(lc, stmt->options)
02662     {
02663         DefElem    *defel = (DefElem *) lfirst(lc);
02664 
02665         if (strcmp(defel->defname, "new_version") == 0)
02666         {
02667             if (d_new_version)
02668                 ereport(ERROR,
02669                         (errcode(ERRCODE_SYNTAX_ERROR),
02670                          errmsg("conflicting or redundant options")));
02671             d_new_version = defel;
02672         }
02673         else
02674             elog(ERROR, "unrecognized option: %s", defel->defname);
02675     }
02676 
02677     /*
02678      * Determine the version to update to
02679      */
02680     if (d_new_version && d_new_version->arg)
02681         versionName = strVal(d_new_version->arg);
02682     else if (control->default_version)
02683         versionName = control->default_version;
02684     else
02685     {
02686         ereport(ERROR,
02687                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
02688                  errmsg("version to install must be specified")));
02689         versionName = NULL;     /* keep compiler quiet */
02690     }
02691     check_valid_version_name(versionName);
02692 
02693     /*
02694      * If we're already at that version, just say so
02695      */
02696     if (strcmp(oldVersionName, versionName) == 0)
02697     {
02698         ereport(NOTICE,
02699            (errmsg("version \"%s\" of extension \"%s\" is already installed",
02700                    versionName, stmt->extname)));
02701         return InvalidOid;
02702     }
02703 
02704     /*
02705      * Identify the series of update script files we need to execute
02706      */
02707     updateVersions = identify_update_path(control,
02708                                           oldVersionName,
02709                                           versionName);
02710 
02711     /*
02712      * Update the pg_extension row and execute the update scripts, one at a
02713      * time
02714      */
02715     ApplyExtensionUpdates(extensionOid, control,
02716                           oldVersionName, updateVersions);
02717 
02718     return extensionOid;
02719 }
02720 
02721 /*
02722  * Apply a series of update scripts as though individual ALTER EXTENSION
02723  * UPDATE commands had been given, including altering the pg_extension row
02724  * and dependencies each time.
02725  *
02726  * This might be more work than necessary, but it ensures that old update
02727  * scripts don't break if newer versions have different control parameters.
02728  */
02729 static void
02730 ApplyExtensionUpdates(Oid extensionOid,
02731                       ExtensionControlFile *pcontrol,
02732                       const char *initialVersion,
02733                       List *updateVersions)
02734 {
02735     const char *oldVersionName = initialVersion;
02736     ListCell   *lcv;
02737 
02738     foreach(lcv, updateVersions)
02739     {
02740         char       *versionName = (char *) lfirst(lcv);
02741         ExtensionControlFile *control;
02742         char       *schemaName;
02743         Oid         schemaOid;
02744         List       *requiredExtensions;
02745         List       *requiredSchemas;
02746         Relation    extRel;
02747         ScanKeyData key[1];
02748         SysScanDesc extScan;
02749         HeapTuple   extTup;
02750         Form_pg_extension extForm;
02751         Datum       values[Natts_pg_extension];
02752         bool        nulls[Natts_pg_extension];
02753         bool        repl[Natts_pg_extension];
02754         ObjectAddress myself;
02755         ListCell   *lc;
02756 
02757         /*
02758          * Fetch parameters for specific version (pcontrol is not changed)
02759          */
02760         control = read_extension_aux_control_file(pcontrol, versionName);
02761 
02762         /* Find the pg_extension tuple */
02763         extRel = heap_open(ExtensionRelationId, RowExclusiveLock);
02764 
02765         ScanKeyInit(&key[0],
02766                     ObjectIdAttributeNumber,
02767                     BTEqualStrategyNumber, F_OIDEQ,
02768                     ObjectIdGetDatum(extensionOid));
02769 
02770         extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
02771                                      SnapshotNow, 1, key);
02772 
02773         extTup = systable_getnext(extScan);
02774 
02775         if (!HeapTupleIsValid(extTup))  /* should not happen */
02776             elog(ERROR, "extension with oid %u does not exist",
02777                  extensionOid);
02778 
02779         extForm = (Form_pg_extension) GETSTRUCT(extTup);
02780 
02781         /*
02782          * Determine the target schema (set by original install)
02783          */
02784         schemaOid = extForm->extnamespace;
02785         schemaName = get_namespace_name(schemaOid);
02786 
02787         /*
02788          * Modify extrelocatable and extversion in the pg_extension tuple
02789          */
02790         memset(values, 0, sizeof(values));
02791         memset(nulls, 0, sizeof(nulls));
02792         memset(repl, 0, sizeof(repl));
02793 
02794         values[Anum_pg_extension_extrelocatable - 1] =
02795             BoolGetDatum(control->relocatable);
02796         repl[Anum_pg_extension_extrelocatable - 1] = true;
02797         values[Anum_pg_extension_extversion - 1] =
02798             CStringGetTextDatum(versionName);
02799         repl[Anum_pg_extension_extversion - 1] = true;
02800 
02801         extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
02802                                    values, nulls, repl);
02803 
02804         simple_heap_update(extRel, &extTup->t_self, extTup);
02805         CatalogUpdateIndexes(extRel, extTup);
02806 
02807         systable_endscan(extScan);
02808 
02809         heap_close(extRel, RowExclusiveLock);
02810 
02811         /*
02812          * Look up the prerequisite extensions for this version, and build
02813          * lists of their OIDs and the OIDs of their target schemas.
02814          */
02815         requiredExtensions = NIL;
02816         requiredSchemas = NIL;
02817         foreach(lc, control->requires)
02818         {
02819             char       *curreq = (char *) lfirst(lc);
02820             Oid         reqext;
02821             Oid         reqschema;
02822 
02823             /*
02824              * We intentionally don't use get_extension_oid's default error
02825              * message here, because it would be confusing in this context.
02826              */
02827             reqext = get_extension_oid(curreq, true);
02828             if (!OidIsValid(reqext))
02829                 ereport(ERROR,
02830                         (errcode(ERRCODE_UNDEFINED_OBJECT),
02831                          errmsg("required extension \"%s\" is not installed",
02832                                 curreq)));
02833             reqschema = get_extension_schema(reqext);
02834             requiredExtensions = lappend_oid(requiredExtensions, reqext);
02835             requiredSchemas = lappend_oid(requiredSchemas, reqschema);
02836         }
02837 
02838         /*
02839          * Remove and recreate dependencies on prerequisite extensions
02840          */
02841         deleteDependencyRecordsForClass(ExtensionRelationId, extensionOid,
02842                                         ExtensionRelationId,
02843                                         DEPENDENCY_NORMAL);
02844 
02845         myself.classId = ExtensionRelationId;
02846         myself.objectId = extensionOid;
02847         myself.objectSubId = 0;
02848 
02849         foreach(lc, requiredExtensions)
02850         {
02851             Oid         reqext = lfirst_oid(lc);
02852             ObjectAddress otherext;
02853 
02854             otherext.classId = ExtensionRelationId;
02855             otherext.objectId = reqext;
02856             otherext.objectSubId = 0;
02857 
02858             recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
02859         }
02860 
02861         InvokeObjectPostAlterHook(ExtensionRelationId, extensionOid, 0);
02862 
02863         /*
02864          * Finally, execute the update script file
02865          */
02866         execute_extension_script(extensionOid, control,
02867                                  oldVersionName, versionName,
02868                                  requiredSchemas,
02869                                  schemaName, schemaOid);
02870 
02871         /*
02872          * Update prior-version name and loop around.  Since
02873          * execute_sql_string did a final CommandCounterIncrement, we can
02874          * update the pg_extension row again.
02875          */
02876         oldVersionName = versionName;
02877     }
02878 }
02879 
02880 /*
02881  * Execute ALTER EXTENSION ADD/DROP
02882  */
02883 Oid
02884 ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt)
02885 {
02886     ObjectAddress extension;
02887     ObjectAddress object;
02888     Relation    relation;
02889     Oid         oldExtension;
02890 
02891     extension.classId = ExtensionRelationId;
02892     extension.objectId = get_extension_oid(stmt->extname, false);
02893     extension.objectSubId = 0;
02894 
02895     /* Permission check: must own extension */
02896     if (!pg_extension_ownercheck(extension.objectId, GetUserId()))
02897         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EXTENSION,
02898                        stmt->extname);
02899 
02900     /*
02901      * Translate the parser representation that identifies the object into an
02902      * ObjectAddress.  get_object_address() will throw an error if the object
02903      * does not exist, and will also acquire a lock on the object to guard
02904      * against concurrent DROP and ALTER EXTENSION ADD/DROP operations.
02905      */
02906     object = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
02907                                 &relation, ShareUpdateExclusiveLock, false);
02908 
02909     /* Permission check: must own target object, too */
02910     check_object_ownership(GetUserId(), stmt->objtype, object,
02911                            stmt->objname, stmt->objargs, relation);
02912 
02913     /*
02914      * Check existing extension membership.
02915      */
02916     oldExtension = getExtensionOfObject(object.classId, object.objectId);
02917 
02918     if (stmt->action > 0)
02919     {
02920         /*
02921          * ADD, so complain if object is already attached to some extension.
02922          */
02923         if (OidIsValid(oldExtension))
02924             ereport(ERROR,
02925                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
02926                      errmsg("%s is already a member of extension \"%s\"",
02927                             getObjectDescription(&object),
02928                             get_extension_name(oldExtension))));
02929 
02930         /*
02931          * Prevent a schema from being added to an extension if the schema
02932          * contains the extension.  That would create a dependency loop.
02933          */
02934         if (object.classId == NamespaceRelationId &&
02935             object.objectId == get_extension_schema(extension.objectId))
02936             ereport(ERROR,
02937                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
02938                      errmsg("cannot add schema \"%s\" to extension \"%s\" "
02939                             "because the schema contains the extension",
02940                             get_namespace_name(object.objectId),
02941                             stmt->extname)));
02942 
02943         /*
02944          * OK, add the dependency.
02945          */
02946         recordDependencyOn(&object, &extension, DEPENDENCY_EXTENSION);
02947     }
02948     else
02949     {
02950         /*
02951          * DROP, so complain if it's not a member.
02952          */
02953         if (oldExtension != extension.objectId)
02954             ereport(ERROR,
02955                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
02956                      errmsg("%s is not a member of extension \"%s\"",
02957                             getObjectDescription(&object),
02958                             stmt->extname)));
02959 
02960         /*
02961          * OK, drop the dependency.
02962          */
02963         if (deleteDependencyRecordsForClass(object.classId, object.objectId,
02964                                             ExtensionRelationId,
02965                                             DEPENDENCY_EXTENSION) != 1)
02966             elog(ERROR, "unexpected number of extension dependency records");
02967 
02968         /*
02969          * If it's a relation, it might have an entry in the extension's
02970          * extconfig array, which we must remove.
02971          */
02972         if (object.classId == RelationRelationId)
02973             extension_config_remove(extension.objectId, object.objectId);
02974     }
02975 
02976     InvokeObjectPostAlterHook(ExtensionRelationId, extension.objectId, 0);
02977 
02978     /*
02979      * If get_object_address() opened the relation for us, we close it to keep
02980      * the reference count correct - but we retain any locks acquired by
02981      * get_object_address() until commit time, to guard against concurrent
02982      * activity.
02983      */
02984     if (relation != NULL)
02985         relation_close(relation, NoLock);
02986 
02987     return extension.objectId;
02988 }