1 /*-------------------------------------------------------------------------
4 * Commands to manipulate extensions
6 * Extensions in PostgreSQL allow management of collections of SQL objects.
8 * All we need internally to manage an extension is an OID so that the
9 * dependent objects can be associated with it. An extension is created by
10 * populating the pg_extension catalog from a "control" file.
11 * The extension control file is parsed with the same parser we use for
12 * postgresql.conf and recovery.conf. An extension also has an installation
13 * script file, containing SQL commands to create the extension's objects.
15 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
16 * Portions Copyright (c) 1994, Regents of the University of California
20 * src/backend/commands/extension.c
22 *-------------------------------------------------------------------------
32 #include "access/htup_details.h"
33 #include "access/sysattr.h"
34 #include "access/xact.h"
35 #include "catalog/dependency.h"
36 #include "catalog/indexing.h"
37 #include "catalog/namespace.h"
38 #include "catalog/objectaccess.h"
39 #include "catalog/pg_collation.h"
40 #include "catalog/pg_depend.h"
41 #include "catalog/pg_extension.h"
42 #include "catalog/pg_namespace.h"
43 #include "catalog/pg_type.h"
44 #include "commands/alter.h"
45 #include "commands/comment.h"
46 #include "commands/defrem.h"
47 #include "commands/extension.h"
48 #include "commands/schemacmds.h"
50 #include "mb/pg_wchar.h"
51 #include "miscadmin.h"
52 #include "nodes/makefuncs.h"
53 #include "storage/fd.h"
54 #include "tcop/utility.h"
55 #include "utils/builtins.h"
56 #include "utils/fmgroids.h"
57 #include "utils/lsyscache.h"
58 #include "utils/memutils.h"
59 #include "utils/rel.h"
60 #include "utils/snapmgr.h"
61 #include "utils/tqual.h"
64 /* Globally visible state variables */
65 bool creating_extension = false;
66 Oid CurrentExtensionObject = InvalidOid;
69 * Internal data structure to hold the results of parsing a control file
71 typedef struct ExtensionControlFile
73 char *name; /* name of the extension */
74 char *directory; /* directory for script files */
75 char *default_version; /* default install target version, if any */
76 char *module_pathname; /* string to substitute for MODULE_PATHNAME */
77 char *comment; /* comment, if any */
78 char *schema; /* target schema (allowed if !relocatable) */
79 bool relocatable; /* is ALTER EXTENSION SET SCHEMA supported? */
80 bool superuser; /* must be superuser to install? */
81 int encoding; /* encoding of the script file, or -1 */
82 List *requires; /* names of prerequisite extensions */
83 } ExtensionControlFile;
86 * Internal data structure for update path information
88 typedef struct ExtensionVersionInfo
90 char *name; /* name of the starting version */
91 List *reachable; /* List of ExtensionVersionInfo's */
92 bool installable; /* does this version have an install script? */
93 /* working state for Dijkstra's algorithm: */
94 bool distance_known; /* is distance from start known yet? */
95 int distance; /* current worst-case distance estimate */
96 struct ExtensionVersionInfo *previous; /* current best predecessor */
97 } ExtensionVersionInfo;
100 static List *find_update_path(List *evi_list,
101 ExtensionVersionInfo *evi_start,
102 ExtensionVersionInfo *evi_target,
103 bool reject_indirect,
105 static Oid get_required_extension(char *reqExtensionName,
107 char *origSchemaName,
111 static void get_available_versions_for_extension(ExtensionControlFile *pcontrol,
112 Tuplestorestate *tupstore,
114 static Datum convert_requires_to_datum(List *requires);
115 static void ApplyExtensionUpdates(Oid extensionOid,
116 ExtensionControlFile *pcontrol,
117 const char *initialVersion,
118 List *updateVersions,
119 char *origSchemaName,
122 static char *read_whole_file(const char *filename, int *length);
126 * get_extension_oid - given an extension name, look up the OID
128 * If missing_ok is false, throw an error if extension name not found. If
129 * true, just return InvalidOid.
132 get_extension_oid(const char *extname, bool missing_ok)
136 SysScanDesc scandesc;
138 ScanKeyData entry[1];
140 rel = heap_open(ExtensionRelationId, AccessShareLock);
142 ScanKeyInit(&entry[0],
143 Anum_pg_extension_extname,
144 BTEqualStrategyNumber, F_NAMEEQ,
145 CStringGetDatum(extname));
147 scandesc = systable_beginscan(rel, ExtensionNameIndexId, true,
150 tuple = systable_getnext(scandesc);
152 /* We assume that there can be at most one matching tuple */
153 if (HeapTupleIsValid(tuple))
154 result = HeapTupleGetOid(tuple);
158 systable_endscan(scandesc);
160 heap_close(rel, AccessShareLock);
162 if (!OidIsValid(result) && !missing_ok)
164 (errcode(ERRCODE_UNDEFINED_OBJECT),
165 errmsg("extension \"%s\" does not exist",
172 * get_extension_name - given an extension OID, look up the name
174 * Returns a palloc'd string, or NULL if no such extension.
177 get_extension_name(Oid ext_oid)
181 SysScanDesc scandesc;
183 ScanKeyData entry[1];
185 rel = heap_open(ExtensionRelationId, AccessShareLock);
187 ScanKeyInit(&entry[0],
188 ObjectIdAttributeNumber,
189 BTEqualStrategyNumber, F_OIDEQ,
190 ObjectIdGetDatum(ext_oid));
192 scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
195 tuple = systable_getnext(scandesc);
197 /* We assume that there can be at most one matching tuple */
198 if (HeapTupleIsValid(tuple))
199 result = pstrdup(NameStr(((Form_pg_extension) GETSTRUCT(tuple))->extname));
203 systable_endscan(scandesc);
205 heap_close(rel, AccessShareLock);
211 * get_extension_schema - given an extension OID, fetch its extnamespace
213 * Returns InvalidOid if no such extension.
216 get_extension_schema(Oid ext_oid)
220 SysScanDesc scandesc;
222 ScanKeyData entry[1];
224 rel = heap_open(ExtensionRelationId, AccessShareLock);
226 ScanKeyInit(&entry[0],
227 ObjectIdAttributeNumber,
228 BTEqualStrategyNumber, F_OIDEQ,
229 ObjectIdGetDatum(ext_oid));
231 scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
234 tuple = systable_getnext(scandesc);
236 /* We assume that there can be at most one matching tuple */
237 if (HeapTupleIsValid(tuple))
238 result = ((Form_pg_extension) GETSTRUCT(tuple))->extnamespace;
242 systable_endscan(scandesc);
244 heap_close(rel, AccessShareLock);
250 * Utility functions to check validity of extension and version names
253 check_valid_extension_name(const char *extensionname)
255 int namelen = strlen(extensionname);
258 * Disallow empty names (the parser rejects empty identifiers anyway, but
263 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
264 errmsg("invalid extension name: \"%s\"", extensionname),
265 errdetail("Extension names must not be empty.")));
268 * No double dashes, since that would make script filenames ambiguous.
270 if (strstr(extensionname, "--"))
272 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
273 errmsg("invalid extension name: \"%s\"", extensionname),
274 errdetail("Extension names must not contain \"--\".")));
277 * No leading or trailing dash either. (We could probably allow this, but
278 * it would require much care in filename parsing and would make filenames
279 * visually if not formally ambiguous. Since there's no real-world use
280 * case, let's just forbid it.)
282 if (extensionname[0] == '-' || extensionname[namelen - 1] == '-')
284 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
285 errmsg("invalid extension name: \"%s\"", extensionname),
286 errdetail("Extension names must not begin or end with \"-\".")));
289 * No directory separators either (this is sufficient to prevent ".."
292 if (first_dir_separator(extensionname) != NULL)
294 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
295 errmsg("invalid extension name: \"%s\"", extensionname),
296 errdetail("Extension names must not contain directory separator characters.")));
300 check_valid_version_name(const char *versionname)
302 int namelen = strlen(versionname);
305 * Disallow empty names (we could possibly allow this, but there seems
310 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
311 errmsg("invalid extension version name: \"%s\"", versionname),
312 errdetail("Version names must not be empty.")));
315 * No double dashes, since that would make script filenames ambiguous.
317 if (strstr(versionname, "--"))
319 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
320 errmsg("invalid extension version name: \"%s\"", versionname),
321 errdetail("Version names must not contain \"--\".")));
324 * No leading or trailing dash either.
326 if (versionname[0] == '-' || versionname[namelen - 1] == '-')
328 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
329 errmsg("invalid extension version name: \"%s\"", versionname),
330 errdetail("Version names must not begin or end with \"-\".")));
333 * No directory separators either (this is sufficient to prevent ".."
336 if (first_dir_separator(versionname) != NULL)
338 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
339 errmsg("invalid extension version name: \"%s\"", versionname),
340 errdetail("Version names must not contain directory separator characters.")));
344 * Utility functions to handle extension-related path names
347 is_extension_control_filename(const char *filename)
349 const char *extension = strrchr(filename, '.');
351 return (extension != NULL) && (strcmp(extension, ".control") == 0);
355 is_extension_script_filename(const char *filename)
357 const char *extension = strrchr(filename, '.');
359 return (extension != NULL) && (strcmp(extension, ".sql") == 0);
363 get_extension_control_directory(void)
365 char sharepath[MAXPGPATH];
368 get_share_path(my_exec_path, sharepath);
369 result = (char *) palloc(MAXPGPATH);
370 snprintf(result, MAXPGPATH, "%s/extension", sharepath);
376 get_extension_control_filename(const char *extname)
378 char sharepath[MAXPGPATH];
381 get_share_path(my_exec_path, sharepath);
382 result = (char *) palloc(MAXPGPATH);
383 snprintf(result, MAXPGPATH, "%s/extension/%s.control",
390 get_extension_script_directory(ExtensionControlFile *control)
392 char sharepath[MAXPGPATH];
396 * The directory parameter can be omitted, absolute, or relative to the
397 * installation's share directory.
399 if (!control->directory)
400 return get_extension_control_directory();
402 if (is_absolute_path(control->directory))
403 return pstrdup(control->directory);
405 get_share_path(my_exec_path, sharepath);
406 result = (char *) palloc(MAXPGPATH);
407 snprintf(result, MAXPGPATH, "%s/%s", sharepath, control->directory);
413 get_extension_aux_control_filename(ExtensionControlFile *control,
419 scriptdir = get_extension_script_directory(control);
421 result = (char *) palloc(MAXPGPATH);
422 snprintf(result, MAXPGPATH, "%s/%s--%s.control",
423 scriptdir, control->name, version);
431 get_extension_script_filename(ExtensionControlFile *control,
432 const char *from_version, const char *version)
437 scriptdir = get_extension_script_directory(control);
439 result = (char *) palloc(MAXPGPATH);
441 snprintf(result, MAXPGPATH, "%s/%s--%s--%s.sql",
442 scriptdir, control->name, from_version, version);
444 snprintf(result, MAXPGPATH, "%s/%s--%s.sql",
445 scriptdir, control->name, version);
454 * Parse contents of primary or auxiliary control file, and fill in
455 * fields of *control. We parse primary file if version == NULL,
456 * else the optional auxiliary file for that version.
458 * Control files are supposed to be very short, half a dozen lines,
459 * so we don't worry about memory allocation risks here. Also we don't
460 * worry about what encoding it's in; all values are expected to be ASCII.
463 parse_extension_control_file(ExtensionControlFile *control,
468 ConfigVariable *item,
473 * Locate the file to read. Auxiliary files are optional.
476 filename = get_extension_aux_control_filename(control, version);
478 filename = get_extension_control_filename(control->name);
480 if ((file = AllocateFile(filename, "r")) == NULL)
482 if (version && errno == ENOENT)
484 /* no auxiliary file for this version */
489 (errcode_for_file_access(),
490 errmsg("could not open extension control file \"%s\": %m",
495 * Parse the file content, using GUC's file parsing code. We need not
496 * check the return value since any errors will be thrown at ERROR level.
498 (void) ParseConfigFp(file, filename, 0, ERROR, &head, &tail);
503 * Convert the ConfigVariable list into ExtensionControlFile entries.
505 for (item = head; item != NULL; item = item->next)
507 if (strcmp(item->name, "directory") == 0)
511 (errcode(ERRCODE_SYNTAX_ERROR),
512 errmsg("parameter \"%s\" cannot be set in a secondary extension control file",
515 control->directory = pstrdup(item->value);
517 else if (strcmp(item->name, "default_version") == 0)
521 (errcode(ERRCODE_SYNTAX_ERROR),
522 errmsg("parameter \"%s\" cannot be set in a secondary extension control file",
525 control->default_version = pstrdup(item->value);
527 else if (strcmp(item->name, "module_pathname") == 0)
529 control->module_pathname = pstrdup(item->value);
531 else if (strcmp(item->name, "comment") == 0)
533 control->comment = pstrdup(item->value);
535 else if (strcmp(item->name, "schema") == 0)
537 control->schema = pstrdup(item->value);
539 else if (strcmp(item->name, "relocatable") == 0)
541 if (!parse_bool(item->value, &control->relocatable))
543 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
544 errmsg("parameter \"%s\" requires a Boolean value",
547 else if (strcmp(item->name, "superuser") == 0)
549 if (!parse_bool(item->value, &control->superuser))
551 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
552 errmsg("parameter \"%s\" requires a Boolean value",
555 else if (strcmp(item->name, "encoding") == 0)
557 control->encoding = pg_valid_server_encoding(item->value);
558 if (control->encoding < 0)
560 (errcode(ERRCODE_UNDEFINED_OBJECT),
561 errmsg("\"%s\" is not a valid encoding name",
564 else if (strcmp(item->name, "requires") == 0)
566 /* Need a modifiable copy of string */
567 char *rawnames = pstrdup(item->value);
569 /* Parse string into list of identifiers */
570 if (!SplitIdentifierString(rawnames, ',', &control->requires))
572 /* syntax error in name list */
574 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
575 errmsg("parameter \"%s\" must be a list of extension names",
581 (errcode(ERRCODE_SYNTAX_ERROR),
582 errmsg("unrecognized parameter \"%s\" in file \"%s\"",
583 item->name, filename)));
586 FreeConfigVariables(head);
588 if (control->relocatable && control->schema != NULL)
590 (errcode(ERRCODE_SYNTAX_ERROR),
591 errmsg("parameter \"schema\" cannot be specified when \"relocatable\" is true")));
597 * Read the primary control file for the specified extension.
599 static ExtensionControlFile *
600 read_extension_control_file(const char *extname)
602 ExtensionControlFile *control;
605 * Set up default values. Pointer fields are initially null.
607 control = (ExtensionControlFile *) palloc0(sizeof(ExtensionControlFile));
608 control->name = pstrdup(extname);
609 control->relocatable = false;
610 control->superuser = true;
611 control->encoding = -1;
614 * Parse the primary control file.
616 parse_extension_control_file(control, NULL);
622 * Read the auxiliary control file for the specified extension and version.
624 * Returns a new modified ExtensionControlFile struct; the original struct
625 * (reflecting just the primary control file) is not modified.
627 static ExtensionControlFile *
628 read_extension_aux_control_file(const ExtensionControlFile *pcontrol,
631 ExtensionControlFile *acontrol;
634 * Flat-copy the struct. Pointer fields share values with original.
636 acontrol = (ExtensionControlFile *) palloc(sizeof(ExtensionControlFile));
637 memcpy(acontrol, pcontrol, sizeof(ExtensionControlFile));
640 * Parse the auxiliary control file, overwriting struct fields
642 parse_extension_control_file(acontrol, version);
648 * Read an SQL script file into a string, and convert to database encoding
651 read_extension_script_file(const ExtensionControlFile *control,
652 const char *filename)
659 src_str = read_whole_file(filename, &len);
661 /* use database encoding if not given */
662 if (control->encoding < 0)
663 src_encoding = GetDatabaseEncoding();
665 src_encoding = control->encoding;
667 /* make sure that source string is valid in the expected encoding */
668 pg_verify_mbstr_len(src_encoding, src_str, len, false);
671 * Convert the encoding to the database encoding. read_whole_file
672 * null-terminated the string, so if no conversion happens the string is
675 dest_str = pg_any_to_server(src_str, len, src_encoding);
681 * Execute given SQL string.
683 * filename is used only to report errors.
685 * Note: it's tempting to just use SPI to execute the string, but that does
686 * not work very well. The really serious problem is that SPI will parse,
687 * analyze, and plan the whole string before executing any of it; of course
688 * this fails if there are any plannable statements referring to objects
689 * created earlier in the script. A lesser annoyance is that SPI insists
690 * on printing the whole string as errcontext in case of any error, and that
691 * could be very long.
694 execute_sql_string(const char *sql, const char *filename)
696 List *raw_parsetree_list;
701 * Parse the SQL string into a list of raw parse trees.
703 raw_parsetree_list = pg_parse_query(sql);
705 /* All output from SELECTs goes to the bit bucket */
706 dest = CreateDestReceiver(DestNone);
709 * Do parse analysis, rule rewrite, planning, and execution for each raw
710 * parsetree. We must fully execute each query before beginning parse
711 * analysis on the next one, since there may be interdependencies.
713 foreach(lc1, raw_parsetree_list)
715 RawStmt *parsetree = (RawStmt *) lfirst(lc1);
719 stmt_list = pg_analyze_and_rewrite(parsetree,
723 stmt_list = pg_plan_queries(stmt_list, CURSOR_OPT_PARALLEL_OK, NULL);
725 foreach(lc2, stmt_list)
727 PlannedStmt *stmt = (PlannedStmt *) lfirst(lc2);
729 CommandCounterIncrement();
731 PushActiveSnapshot(GetTransactionSnapshot());
733 if (stmt->utilityStmt == NULL)
737 qdesc = CreateQueryDesc(stmt,
739 GetActiveSnapshot(), NULL,
742 ExecutorStart(qdesc, 0);
743 ExecutorRun(qdesc, ForwardScanDirection, 0);
744 ExecutorFinish(qdesc);
747 FreeQueryDesc(qdesc);
751 if (IsA(stmt->utilityStmt, TransactionStmt))
753 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
754 errmsg("transaction control statements are not allowed within an extension script")));
758 PROCESS_UTILITY_QUERY,
768 /* Be sure to advance the command counter after the last script command */
769 CommandCounterIncrement();
773 * Execute the appropriate script file for installing or updating the extension
775 * If from_version isn't NULL, it's an update
778 execute_extension_script(Oid extensionOid, ExtensionControlFile *control,
779 const char *from_version,
781 List *requiredSchemas,
782 const char *schemaName, Oid schemaOid)
786 StringInfoData pathbuf;
790 * Enforce superuser-ness if appropriate. We postpone this check until
791 * here so that the flag is correctly associated with the right script(s)
792 * if it's set in secondary control files.
794 if (control->superuser && !superuser())
796 if (from_version == NULL)
798 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
799 errmsg("permission denied to create extension \"%s\"",
801 errhint("Must be superuser to create this extension.")));
804 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
805 errmsg("permission denied to update extension \"%s\"",
807 errhint("Must be superuser to update this extension.")));
810 filename = get_extension_script_filename(control, from_version, version);
813 * Force client_min_messages and log_min_messages to be at least WARNING,
814 * so that we won't spam the user with useless NOTICE messages from common
815 * script actions like creating shell types.
817 * We use the equivalent of a function SET option to allow the setting to
818 * persist for exactly the duration of the script execution. guc.c also
819 * takes care of undoing the setting on error.
821 save_nestlevel = NewGUCNestLevel();
823 if (client_min_messages < WARNING)
824 (void) set_config_option("client_min_messages", "warning",
825 PGC_USERSET, PGC_S_SESSION,
826 GUC_ACTION_SAVE, true, 0, false);
827 if (log_min_messages < WARNING)
828 (void) set_config_option("log_min_messages", "warning",
829 PGC_SUSET, PGC_S_SESSION,
830 GUC_ACTION_SAVE, true, 0, false);
833 * Set up the search path to contain the target schema, then the schemas
834 * of any prerequisite extensions, and nothing else. In particular this
835 * makes the target schema be the default creation target namespace.
837 * Note: it might look tempting to use PushOverrideSearchPath for this,
838 * but we cannot do that. We have to actually set the search_path GUC in
839 * case the extension script examines or changes it. In any case, the
840 * GUC_ACTION_SAVE method is just as convenient.
842 initStringInfo(&pathbuf);
843 appendStringInfoString(&pathbuf, quote_identifier(schemaName));
844 foreach(lc, requiredSchemas)
846 Oid reqschema = lfirst_oid(lc);
847 char *reqname = get_namespace_name(reqschema);
850 appendStringInfo(&pathbuf, ", %s", quote_identifier(reqname));
853 (void) set_config_option("search_path", pathbuf.data,
854 PGC_USERSET, PGC_S_SESSION,
855 GUC_ACTION_SAVE, true, 0, false);
858 * Set creating_extension and related variables so that
859 * recordDependencyOnCurrentExtension and other functions do the right
860 * things. On failure, ensure we reset these variables.
862 creating_extension = true;
863 CurrentExtensionObject = extensionOid;
866 char *c_sql = read_extension_script_file(control, filename);
869 /* We use various functions that want to operate on text datums */
870 t_sql = CStringGetTextDatum(c_sql);
873 * Reduce any lines beginning with "\echo" to empty. This allows
874 * scripts to contain messages telling people not to run them via
875 * psql, which has been found to be necessary due to old habits.
877 t_sql = DirectFunctionCall4Coll(textregexreplace,
880 CStringGetTextDatum("^\\\\echo.*$"),
881 CStringGetTextDatum(""),
882 CStringGetTextDatum("ng"));
885 * If it's not relocatable, substitute the target schema name for
886 * occurrences of @extschema@.
888 * For a relocatable extension, we needn't do this. There cannot be
889 * any need for @extschema@, else it wouldn't be relocatable.
891 if (!control->relocatable)
893 const char *qSchemaName = quote_identifier(schemaName);
895 t_sql = DirectFunctionCall3(replace_text,
897 CStringGetTextDatum("@extschema@"),
898 CStringGetTextDatum(qSchemaName));
902 * If module_pathname was set in the control file, substitute its
903 * value for occurrences of MODULE_PATHNAME.
905 if (control->module_pathname)
907 t_sql = DirectFunctionCall3(replace_text,
909 CStringGetTextDatum("MODULE_PATHNAME"),
910 CStringGetTextDatum(control->module_pathname));
913 /* And now back to C string */
914 c_sql = text_to_cstring(DatumGetTextPP(t_sql));
916 execute_sql_string(c_sql, filename);
920 creating_extension = false;
921 CurrentExtensionObject = InvalidOid;
926 creating_extension = false;
927 CurrentExtensionObject = InvalidOid;
930 * Restore the GUC variables we set above.
932 AtEOXact_GUC(true, save_nestlevel);
936 * Find or create an ExtensionVersionInfo for the specified version name
938 * Currently, we just use a List of the ExtensionVersionInfo's. Searching
939 * for them therefore uses about O(N^2) time when there are N versions of
940 * the extension. We could change the data structure to a hash table if
941 * this ever becomes a bottleneck.
943 static ExtensionVersionInfo *
944 get_ext_ver_info(const char *versionname, List **evi_list)
946 ExtensionVersionInfo *evi;
949 foreach(lc, *evi_list)
951 evi = (ExtensionVersionInfo *) lfirst(lc);
952 if (strcmp(evi->name, versionname) == 0)
956 evi = (ExtensionVersionInfo *) palloc(sizeof(ExtensionVersionInfo));
957 evi->name = pstrdup(versionname);
958 evi->reachable = NIL;
959 evi->installable = false;
960 /* initialize for later application of Dijkstra's algorithm */
961 evi->distance_known = false;
962 evi->distance = INT_MAX;
963 evi->previous = NULL;
965 *evi_list = lappend(*evi_list, evi);
971 * Locate the nearest unprocessed ExtensionVersionInfo
973 * This part of the algorithm is also about O(N^2). A priority queue would
974 * make it much faster, but for now there's no need.
976 static ExtensionVersionInfo *
977 get_nearest_unprocessed_vertex(List *evi_list)
979 ExtensionVersionInfo *evi = NULL;
982 foreach(lc, evi_list)
984 ExtensionVersionInfo *evi2 = (ExtensionVersionInfo *) lfirst(lc);
986 /* only vertices whose distance is still uncertain are candidates */
987 if (evi2->distance_known)
989 /* remember the closest such vertex */
991 evi->distance > evi2->distance)
999 * Obtain information about the set of update scripts available for the
1000 * specified extension. The result is a List of ExtensionVersionInfo
1001 * structs, each with a subsidiary list of the ExtensionVersionInfos for
1002 * the versions that can be reached in one step from that version.
1005 get_ext_ver_list(ExtensionControlFile *control)
1007 List *evi_list = NIL;
1008 int extnamelen = strlen(control->name);
1013 location = get_extension_script_directory(control);
1014 dir = AllocateDir(location);
1015 while ((de = ReadDir(dir, location)) != NULL)
1019 ExtensionVersionInfo *evi;
1020 ExtensionVersionInfo *evi2;
1022 /* must be a .sql file ... */
1023 if (!is_extension_script_filename(de->d_name))
1026 /* ... matching extension name followed by separator */
1027 if (strncmp(de->d_name, control->name, extnamelen) != 0 ||
1028 de->d_name[extnamelen] != '-' ||
1029 de->d_name[extnamelen + 1] != '-')
1032 /* extract version name(s) from 'extname--something.sql' filename */
1033 vername = pstrdup(de->d_name + extnamelen + 2);
1034 *strrchr(vername, '.') = '\0';
1035 vername2 = strstr(vername, "--");
1038 /* It's an install, not update, script; record its version name */
1039 evi = get_ext_ver_info(vername, &evi_list);
1040 evi->installable = true;
1043 *vername2 = '\0'; /* terminate first version */
1044 vername2 += 2; /* and point to second */
1046 /* if there's a third --, it's bogus, ignore it */
1047 if (strstr(vername2, "--"))
1050 /* Create ExtensionVersionInfos and link them together */
1051 evi = get_ext_ver_info(vername, &evi_list);
1052 evi2 = get_ext_ver_info(vername2, &evi_list);
1053 evi->reachable = lappend(evi->reachable, evi2);
1061 * Given an initial and final version name, identify the sequence of update
1062 * scripts that have to be applied to perform that update.
1064 * Result is a List of names of versions to transition through (the initial
1065 * version is *not* included).
1068 identify_update_path(ExtensionControlFile *control,
1069 const char *oldVersion, const char *newVersion)
1073 ExtensionVersionInfo *evi_start;
1074 ExtensionVersionInfo *evi_target;
1076 /* Extract the version update graph from the script directory */
1077 evi_list = get_ext_ver_list(control);
1079 /* Initialize start and end vertices */
1080 evi_start = get_ext_ver_info(oldVersion, &evi_list);
1081 evi_target = get_ext_ver_info(newVersion, &evi_list);
1083 /* Find shortest path */
1084 result = find_update_path(evi_list, evi_start, evi_target, false, false);
1088 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1089 errmsg("extension \"%s\" has no update path from version \"%s\" to version \"%s\"",
1090 control->name, oldVersion, newVersion)));
1096 * Apply Dijkstra's algorithm to find the shortest path from evi_start to
1099 * If reject_indirect is true, ignore paths that go through installable
1100 * versions. This saves work when the caller will consider starting from
1101 * all installable versions anyway.
1103 * If reinitialize is false, assume the ExtensionVersionInfo list has not
1104 * been used for this before, and the initialization done by get_ext_ver_info
1105 * is still good. Otherwise, reinitialize all transient fields used here.
1107 * Result is a List of names of versions to transition through (the initial
1108 * version is *not* included). Returns NIL if no such path.
1111 find_update_path(List *evi_list,
1112 ExtensionVersionInfo *evi_start,
1113 ExtensionVersionInfo *evi_target,
1114 bool reject_indirect,
1118 ExtensionVersionInfo *evi;
1121 /* Caller error if start == target */
1122 Assert(evi_start != evi_target);
1123 /* Caller error if reject_indirect and target is installable */
1124 Assert(!(reject_indirect && evi_target->installable));
1128 foreach(lc, evi_list)
1130 evi = (ExtensionVersionInfo *) lfirst(lc);
1131 evi->distance_known = false;
1132 evi->distance = INT_MAX;
1133 evi->previous = NULL;
1137 evi_start->distance = 0;
1139 while ((evi = get_nearest_unprocessed_vertex(evi_list)) != NULL)
1141 if (evi->distance == INT_MAX)
1142 break; /* all remaining vertices are unreachable */
1143 evi->distance_known = true;
1144 if (evi == evi_target)
1145 break; /* found shortest path to target */
1146 foreach(lc, evi->reachable)
1148 ExtensionVersionInfo *evi2 = (ExtensionVersionInfo *) lfirst(lc);
1151 /* if reject_indirect, treat installable versions as unreachable */
1152 if (reject_indirect && evi2->installable)
1154 newdist = evi->distance + 1;
1155 if (newdist < evi2->distance)
1157 evi2->distance = newdist;
1158 evi2->previous = evi;
1160 else if (newdist == evi2->distance &&
1161 evi2->previous != NULL &&
1162 strcmp(evi->name, evi2->previous->name) < 0)
1165 * Break ties in favor of the version name that comes first
1166 * according to strcmp(). This behavior is undocumented and
1167 * users shouldn't rely on it. We do it just to ensure that
1168 * if there is a tie, the update path that is chosen does not
1169 * depend on random factors like the order in which directory
1170 * entries get visited.
1172 evi2->previous = evi;
1177 /* Return NIL if target is not reachable from start */
1178 if (!evi_target->distance_known)
1181 /* Build and return list of version names representing the update path */
1183 for (evi = evi_target; evi != evi_start; evi = evi->previous)
1184 result = lcons(evi->name, result);
1190 * Given a target version that is not directly installable, find the
1191 * best installation sequence starting from a directly-installable version.
1193 * evi_list: previously-collected version update graph
1194 * evi_target: member of that list that we want to reach
1196 * Returns the best starting-point version, or NULL if there is none.
1197 * On success, *best_path is set to the path from the start point.
1199 * If there's more than one possible start point, prefer shorter update paths,
1200 * and break any ties arbitrarily on the basis of strcmp'ing the starting
1203 static ExtensionVersionInfo *
1204 find_install_path(List *evi_list, ExtensionVersionInfo *evi_target,
1207 ExtensionVersionInfo *evi_start = NULL;
1213 * We don't expect to be called for an installable target, but if we are,
1214 * the answer is easy: just start from there, with an empty update path.
1216 if (evi_target->installable)
1219 /* Consider all installable versions as start points */
1220 foreach(lc, evi_list)
1222 ExtensionVersionInfo *evi1 = (ExtensionVersionInfo *) lfirst(lc);
1225 if (!evi1->installable)
1229 * Find shortest path from evi1 to evi_target; but no need to consider
1230 * paths going through other installable versions.
1232 path = find_update_path(evi_list, evi1, evi_target, true, true);
1236 /* Remember best path */
1237 if (evi_start == NULL ||
1238 list_length(path) < list_length(*best_path) ||
1239 (list_length(path) == list_length(*best_path) &&
1240 strcmp(evi_start->name, evi1->name) < 0))
1251 * CREATE EXTENSION worker
1253 * When CASCADE is specified, CreateExtensionInternal() recurses if required
1254 * extensions need to be installed. To sanely handle cyclic dependencies,
1255 * the "parents" list contains a list of names of extensions already being
1256 * installed, allowing us to error out if we recurse to one of those.
1258 static ObjectAddress
1259 CreateExtensionInternal(char *extensionName,
1262 char *oldVersionName,
1267 char *origSchemaName = schemaName;
1268 Oid schemaOid = InvalidOid;
1269 Oid extowner = GetUserId();
1270 ExtensionControlFile *pcontrol;
1271 ExtensionControlFile *control;
1272 List *updateVersions;
1273 List *requiredExtensions;
1274 List *requiredSchemas;
1276 ObjectAddress address;
1280 * Read the primary control file. Note we assume that it does not contain
1281 * any non-ASCII data, so there is no need to worry about encoding at this
1284 pcontrol = read_extension_control_file(extensionName);
1287 * Determine the version to install
1289 if (versionName == NULL)
1291 if (pcontrol->default_version)
1292 versionName = pcontrol->default_version;
1295 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1296 errmsg("version to install must be specified")));
1298 check_valid_version_name(versionName);
1301 * Figure out which script(s) we need to run to install the desired
1302 * version of the extension. If we do not have a script that directly
1303 * does what is needed, we try to find a sequence of update scripts that
1304 * will get us there.
1309 * "FROM old_version" was specified, indicating that we're trying to
1310 * update from some unpackaged version of the extension. Locate a
1311 * series of update scripts that will do it.
1313 check_valid_version_name(oldVersionName);
1315 if (strcmp(oldVersionName, versionName) == 0)
1317 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1318 errmsg("FROM version must be different from installation target version \"%s\"",
1321 updateVersions = identify_update_path(pcontrol,
1325 if (list_length(updateVersions) == 1)
1328 * Simple case where there's just one update script to run. We
1329 * will not need any follow-on update steps.
1331 Assert(strcmp((char *) linitial(updateVersions), versionName) == 0);
1332 updateVersions = NIL;
1337 * Multi-step sequence. We treat this as installing the version
1338 * that is the target of the first script, followed by successive
1339 * updates to the later versions.
1341 versionName = (char *) linitial(updateVersions);
1342 updateVersions = list_delete_first(updateVersions);
1348 * No FROM, so we're installing from scratch. If there is an install
1349 * script for the desired version, we only need to run that one.
1354 oldVersionName = NULL;
1356 filename = get_extension_script_filename(pcontrol, NULL, versionName);
1357 if (stat(filename, &fst) == 0)
1359 /* Easy, no extra scripts */
1360 updateVersions = NIL;
1364 /* Look for best way to install this version */
1366 ExtensionVersionInfo *evi_start;
1367 ExtensionVersionInfo *evi_target;
1369 /* Extract the version update graph from the script directory */
1370 evi_list = get_ext_ver_list(pcontrol);
1372 /* Identify the target version */
1373 evi_target = get_ext_ver_info(versionName, &evi_list);
1375 /* Identify best path to reach target */
1376 evi_start = find_install_path(evi_list, evi_target,
1379 /* Fail if no path ... */
1380 if (evi_start == NULL)
1382 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1383 errmsg("extension \"%s\" has no installation script nor update path for version \"%s\"",
1384 pcontrol->name, versionName)));
1386 /* Otherwise, install best starting point and then upgrade */
1387 versionName = evi_start->name;
1392 * Fetch control parameters for installation target version
1394 control = read_extension_aux_control_file(pcontrol, versionName);
1397 * Determine the target schema to install the extension into
1401 /* If the user is giving us the schema name, it must exist already. */
1402 schemaOid = get_namespace_oid(schemaName, false);
1405 if (control->schema != NULL)
1408 * The extension is not relocatable and the author gave us a schema
1411 * Unless CASCADE parameter was given, it's an error to give a schema
1412 * different from control->schema if control->schema is specified.
1414 if (schemaName && strcmp(control->schema, schemaName) != 0 &&
1417 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1418 errmsg("extension \"%s\" must be installed in schema \"%s\"",
1422 /* Always use the schema from control file for current extension. */
1423 schemaName = control->schema;
1425 /* Find or create the schema in case it does not exist. */
1426 schemaOid = get_namespace_oid(schemaName, true);
1428 if (!OidIsValid(schemaOid))
1430 CreateSchemaStmt *csstmt = makeNode(CreateSchemaStmt);
1432 csstmt->schemaname = schemaName;
1433 csstmt->authrole = NULL; /* will be created by current user */
1434 csstmt->schemaElts = NIL;
1435 csstmt->if_not_exists = false;
1436 CreateSchemaCommand(csstmt, "(generated CREATE SCHEMA command)",
1440 * CreateSchemaCommand includes CommandCounterIncrement, so new
1441 * schema is now visible.
1443 schemaOid = get_namespace_oid(schemaName, false);
1446 else if (!OidIsValid(schemaOid))
1449 * Neither user nor author of the extension specified schema; use the
1450 * current default creation namespace, which is the first explicit
1451 * entry in the search_path.
1453 List *search_path = fetch_search_path(false);
1455 if (search_path == NIL) /* nothing valid in search_path? */
1457 (errcode(ERRCODE_UNDEFINED_SCHEMA),
1458 errmsg("no schema has been selected to create in")));
1459 schemaOid = linitial_oid(search_path);
1460 schemaName = get_namespace_name(schemaOid);
1461 if (schemaName == NULL) /* recently-deleted namespace? */
1463 (errcode(ERRCODE_UNDEFINED_SCHEMA),
1464 errmsg("no schema has been selected to create in")));
1466 list_free(search_path);
1470 * We don't check creation rights on the target namespace here. If the
1471 * extension script actually creates any objects there, it will fail if
1472 * the user doesn't have such permissions. But there are cases such as
1473 * procedural languages where it's convenient to set schema = pg_catalog
1474 * yet we don't want to restrict the command to users with ACL_CREATE for
1479 * Look up the prerequisite extensions, install them if necessary, and
1480 * build lists of their OIDs and the OIDs of their target schemas.
1482 requiredExtensions = NIL;
1483 requiredSchemas = NIL;
1484 foreach(lc, control->requires)
1486 char *curreq = (char *) lfirst(lc);
1490 reqext = get_required_extension(curreq,
1496 reqschema = get_extension_schema(reqext);
1497 requiredExtensions = lappend_oid(requiredExtensions, reqext);
1498 requiredSchemas = lappend_oid(requiredSchemas, reqschema);
1502 * Insert new tuple into pg_extension, and create dependency entries.
1504 address = InsertExtensionTuple(control->name, extowner,
1505 schemaOid, control->relocatable,
1507 PointerGetDatum(NULL),
1508 PointerGetDatum(NULL),
1509 requiredExtensions);
1510 extensionOid = address.objectId;
1513 * Apply any control-file comment on extension
1515 if (control->comment != NULL)
1516 CreateComments(extensionOid, ExtensionRelationId, 0, control->comment);
1519 * Execute the installation script file
1521 execute_extension_script(extensionOid, control,
1522 oldVersionName, versionName,
1524 schemaName, schemaOid);
1527 * If additional update scripts have to be executed, apply the updates as
1528 * though a series of ALTER EXTENSION UPDATE commands were given
1530 ApplyExtensionUpdates(extensionOid, pcontrol,
1531 versionName, updateVersions,
1532 origSchemaName, cascade, is_create);
1538 * Get the OID of an extension listed in "requires", possibly creating it.
1541 get_required_extension(char *reqExtensionName,
1542 char *extensionName,
1543 char *origSchemaName,
1548 Oid reqExtensionOid;
1550 reqExtensionOid = get_extension_oid(reqExtensionName, true);
1551 if (!OidIsValid(reqExtensionOid))
1555 /* Must install it. */
1557 List *cascade_parents;
1560 /* Check extension name validity before trying to cascade. */
1561 check_valid_extension_name(reqExtensionName);
1563 /* Check for cyclic dependency between extensions. */
1564 foreach(lc, parents)
1566 char *pname = (char *) lfirst(lc);
1568 if (strcmp(pname, reqExtensionName) == 0)
1570 (errcode(ERRCODE_INVALID_RECURSION),
1571 errmsg("cyclic dependency detected between extensions \"%s\" and \"%s\"",
1572 reqExtensionName, extensionName)));
1576 (errmsg("installing required extension \"%s\"",
1577 reqExtensionName)));
1579 /* Add current extension to list of parents to pass down. */
1580 cascade_parents = lappend(list_copy(parents), extensionName);
1583 * Create the required extension. We propagate the SCHEMA option
1584 * if any, and CASCADE, but no other options.
1586 addr = CreateExtensionInternal(reqExtensionName,
1594 /* Get its newly-assigned OID. */
1595 reqExtensionOid = addr.objectId;
1599 (errcode(ERRCODE_UNDEFINED_OBJECT),
1600 errmsg("required extension \"%s\" is not installed",
1603 errhint("Use CREATE EXTENSION ... CASCADE to install required extensions too.") : 0));
1606 return reqExtensionOid;
1613 CreateExtension(ParseState *pstate, CreateExtensionStmt *stmt)
1615 DefElem *d_schema = NULL;
1616 DefElem *d_new_version = NULL;
1617 DefElem *d_old_version = NULL;
1618 DefElem *d_cascade = NULL;
1619 char *schemaName = NULL;
1620 char *versionName = NULL;
1621 char *oldVersionName = NULL;
1622 bool cascade = false;
1625 /* Check extension name validity before any filesystem access */
1626 check_valid_extension_name(stmt->extname);
1629 * Check for duplicate extension name. The unique index on
1630 * pg_extension.extname would catch this anyway, and serves as a backstop
1631 * in case of race conditions; but this is a friendlier error message, and
1632 * besides we need a check to support IF NOT EXISTS.
1634 if (get_extension_oid(stmt->extname, true) != InvalidOid)
1636 if (stmt->if_not_exists)
1639 (errcode(ERRCODE_DUPLICATE_OBJECT),
1640 errmsg("extension \"%s\" already exists, skipping",
1642 return InvalidObjectAddress;
1646 (errcode(ERRCODE_DUPLICATE_OBJECT),
1647 errmsg("extension \"%s\" already exists",
1652 * We use global variables to track the extension being created, so we can
1653 * create only one extension at the same time.
1655 if (creating_extension)
1657 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1658 errmsg("nested CREATE EXTENSION is not supported")));
1660 /* Deconstruct the statement option list */
1661 foreach(lc, stmt->options)
1663 DefElem *defel = (DefElem *) lfirst(lc);
1665 if (strcmp(defel->defname, "schema") == 0)
1669 (errcode(ERRCODE_SYNTAX_ERROR),
1670 errmsg("conflicting or redundant options"),
1671 parser_errposition(pstate, defel->location)));
1673 schemaName = defGetString(d_schema);
1675 else if (strcmp(defel->defname, "new_version") == 0)
1679 (errcode(ERRCODE_SYNTAX_ERROR),
1680 errmsg("conflicting or redundant options"),
1681 parser_errposition(pstate, defel->location)));
1682 d_new_version = defel;
1683 versionName = defGetString(d_new_version);
1685 else if (strcmp(defel->defname, "old_version") == 0)
1689 (errcode(ERRCODE_SYNTAX_ERROR),
1690 errmsg("conflicting or redundant options"),
1691 parser_errposition(pstate, defel->location)));
1692 d_old_version = defel;
1693 oldVersionName = defGetString(d_old_version);
1695 else if (strcmp(defel->defname, "cascade") == 0)
1699 (errcode(ERRCODE_SYNTAX_ERROR),
1700 errmsg("conflicting or redundant options"),
1701 parser_errposition(pstate, defel->location)));
1703 cascade = defGetBoolean(d_cascade);
1706 elog(ERROR, "unrecognized option: %s", defel->defname);
1709 /* Call CreateExtensionInternal to do the real work. */
1710 return CreateExtensionInternal(stmt->extname,
1720 * InsertExtensionTuple
1722 * Insert the new pg_extension row, and create extension's dependency entries.
1723 * Return the OID assigned to the new row.
1725 * This is exported for the benefit of pg_upgrade, which has to create a
1726 * pg_extension entry (and the extension-level dependencies) without
1727 * actually running the extension's script.
1729 * extConfig and extCondition should be arrays or PointerGetDatum(NULL).
1730 * We declare them as plain Datum to avoid needing array.h in extension.h.
1733 InsertExtensionTuple(const char *extName, Oid extOwner,
1734 Oid schemaOid, bool relocatable, const char *extVersion,
1735 Datum extConfig, Datum extCondition,
1736 List *requiredExtensions)
1740 Datum values[Natts_pg_extension];
1741 bool nulls[Natts_pg_extension];
1743 ObjectAddress myself;
1748 * Build and insert the pg_extension tuple
1750 rel = heap_open(ExtensionRelationId, RowExclusiveLock);
1752 memset(values, 0, sizeof(values));
1753 memset(nulls, 0, sizeof(nulls));
1755 values[Anum_pg_extension_extname - 1] =
1756 DirectFunctionCall1(namein, CStringGetDatum(extName));
1757 values[Anum_pg_extension_extowner - 1] = ObjectIdGetDatum(extOwner);
1758 values[Anum_pg_extension_extnamespace - 1] = ObjectIdGetDatum(schemaOid);
1759 values[Anum_pg_extension_extrelocatable - 1] = BoolGetDatum(relocatable);
1760 values[Anum_pg_extension_extversion - 1] = CStringGetTextDatum(extVersion);
1762 if (extConfig == PointerGetDatum(NULL))
1763 nulls[Anum_pg_extension_extconfig - 1] = true;
1765 values[Anum_pg_extension_extconfig - 1] = extConfig;
1767 if (extCondition == PointerGetDatum(NULL))
1768 nulls[Anum_pg_extension_extcondition - 1] = true;
1770 values[Anum_pg_extension_extcondition - 1] = extCondition;
1772 tuple = heap_form_tuple(rel->rd_att, values, nulls);
1774 extensionOid = simple_heap_insert(rel, tuple);
1775 CatalogUpdateIndexes(rel, tuple);
1777 heap_freetuple(tuple);
1778 heap_close(rel, RowExclusiveLock);
1781 * Record dependencies on owner, schema, and prerequisite extensions
1783 recordDependencyOnOwner(ExtensionRelationId, extensionOid, extOwner);
1785 myself.classId = ExtensionRelationId;
1786 myself.objectId = extensionOid;
1787 myself.objectSubId = 0;
1789 nsp.classId = NamespaceRelationId;
1790 nsp.objectId = schemaOid;
1791 nsp.objectSubId = 0;
1793 recordDependencyOn(&myself, &nsp, DEPENDENCY_NORMAL);
1795 foreach(lc, requiredExtensions)
1797 Oid reqext = lfirst_oid(lc);
1798 ObjectAddress otherext;
1800 otherext.classId = ExtensionRelationId;
1801 otherext.objectId = reqext;
1802 otherext.objectSubId = 0;
1804 recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
1806 /* Post creation hook for new extension */
1807 InvokeObjectPostCreateHook(ExtensionRelationId, extensionOid, 0);
1813 * Guts of extension deletion.
1815 * All we need do here is remove the pg_extension tuple itself. Everything
1816 * else is taken care of by the dependency infrastructure.
1819 RemoveExtensionById(Oid extId)
1822 SysScanDesc scandesc;
1824 ScanKeyData entry[1];
1827 * Disallow deletion of any extension that's currently open for insertion;
1828 * else subsequent executions of recordDependencyOnCurrentExtension()
1829 * could create dangling pg_depend records that refer to a no-longer-valid
1830 * pg_extension OID. This is needed not so much because we think people
1831 * might write "DROP EXTENSION foo" in foo's own script files, as because
1832 * errors in dependency management in extension script files could give
1833 * rise to cases where an extension is dropped as a result of recursing
1834 * from some contained object. Because of that, we must test for the case
1835 * here, not at some higher level of the DROP EXTENSION command.
1837 if (extId == CurrentExtensionObject)
1839 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1840 errmsg("cannot drop extension \"%s\" because it is being modified",
1841 get_extension_name(extId))));
1843 rel = heap_open(ExtensionRelationId, RowExclusiveLock);
1845 ScanKeyInit(&entry[0],
1846 ObjectIdAttributeNumber,
1847 BTEqualStrategyNumber, F_OIDEQ,
1848 ObjectIdGetDatum(extId));
1849 scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
1852 tuple = systable_getnext(scandesc);
1854 /* We assume that there can be at most one matching tuple */
1855 if (HeapTupleIsValid(tuple))
1856 simple_heap_delete(rel, &tuple->t_self);
1858 systable_endscan(scandesc);
1860 heap_close(rel, RowExclusiveLock);
1864 * This function lists the available extensions (one row per primary control
1865 * file in the control directory). We parse each control file and report the
1866 * interesting fields.
1868 * The system view pg_available_extensions provides a user interface to this
1869 * SRF, adding information about whether the extensions are installed in the
1873 pg_available_extensions(PG_FUNCTION_ARGS)
1875 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1877 Tuplestorestate *tupstore;
1878 MemoryContext per_query_ctx;
1879 MemoryContext oldcontext;
1884 /* check to see if caller supports us returning a tuplestore */
1885 if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
1887 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1888 errmsg("set-valued function called in context that cannot accept a set")));
1889 if (!(rsinfo->allowedModes & SFRM_Materialize))
1891 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1892 errmsg("materialize mode required, but it is not " \
1893 "allowed in this context")));
1895 /* Build a tuple descriptor for our result type */
1896 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
1897 elog(ERROR, "return type must be a row type");
1899 /* Build tuplestore to hold the result rows */
1900 per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
1901 oldcontext = MemoryContextSwitchTo(per_query_ctx);
1903 tupstore = tuplestore_begin_heap(true, false, work_mem);
1904 rsinfo->returnMode = SFRM_Materialize;
1905 rsinfo->setResult = tupstore;
1906 rsinfo->setDesc = tupdesc;
1908 MemoryContextSwitchTo(oldcontext);
1910 location = get_extension_control_directory();
1911 dir = AllocateDir(location);
1914 * If the control directory doesn't exist, we want to silently return an
1915 * empty set. Any other error will be reported by ReadDir.
1917 if (dir == NULL && errno == ENOENT)
1923 while ((de = ReadDir(dir, location)) != NULL)
1925 ExtensionControlFile *control;
1930 if (!is_extension_control_filename(de->d_name))
1933 /* extract extension name from 'name.control' filename */
1934 extname = pstrdup(de->d_name);
1935 *strrchr(extname, '.') = '\0';
1937 /* ignore it if it's an auxiliary control file */
1938 if (strstr(extname, "--"))
1941 control = read_extension_control_file(extname);
1943 memset(values, 0, sizeof(values));
1944 memset(nulls, 0, sizeof(nulls));
1947 values[0] = DirectFunctionCall1(namein,
1948 CStringGetDatum(control->name));
1949 /* default_version */
1950 if (control->default_version == NULL)
1953 values[1] = CStringGetTextDatum(control->default_version);
1955 if (control->comment == NULL)
1958 values[2] = CStringGetTextDatum(control->comment);
1960 tuplestore_putvalues(tupstore, tupdesc, values, nulls);
1966 /* clean up and return the tuplestore */
1967 tuplestore_donestoring(tupstore);
1973 * This function lists the available extension versions (one row per
1974 * extension installation script). For each version, we parse the related
1975 * control file(s) and report the interesting fields.
1977 * The system view pg_available_extension_versions provides a user interface
1978 * to this SRF, adding information about which versions are installed in the
1982 pg_available_extension_versions(PG_FUNCTION_ARGS)
1984 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1986 Tuplestorestate *tupstore;
1987 MemoryContext per_query_ctx;
1988 MemoryContext oldcontext;
1993 /* check to see if caller supports us returning a tuplestore */
1994 if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
1996 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1997 errmsg("set-valued function called in context that cannot accept a set")));
1998 if (!(rsinfo->allowedModes & SFRM_Materialize))
2000 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2001 errmsg("materialize mode required, but it is not " \
2002 "allowed in this context")));
2004 /* Build a tuple descriptor for our result type */
2005 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
2006 elog(ERROR, "return type must be a row type");
2008 /* Build tuplestore to hold the result rows */
2009 per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
2010 oldcontext = MemoryContextSwitchTo(per_query_ctx);
2012 tupstore = tuplestore_begin_heap(true, false, work_mem);
2013 rsinfo->returnMode = SFRM_Materialize;
2014 rsinfo->setResult = tupstore;
2015 rsinfo->setDesc = tupdesc;
2017 MemoryContextSwitchTo(oldcontext);
2019 location = get_extension_control_directory();
2020 dir = AllocateDir(location);
2023 * If the control directory doesn't exist, we want to silently return an
2024 * empty set. Any other error will be reported by ReadDir.
2026 if (dir == NULL && errno == ENOENT)
2032 while ((de = ReadDir(dir, location)) != NULL)
2034 ExtensionControlFile *control;
2037 if (!is_extension_control_filename(de->d_name))
2040 /* extract extension name from 'name.control' filename */
2041 extname = pstrdup(de->d_name);
2042 *strrchr(extname, '.') = '\0';
2044 /* ignore it if it's an auxiliary control file */
2045 if (strstr(extname, "--"))
2048 /* read the control file */
2049 control = read_extension_control_file(extname);
2051 /* scan extension's script directory for install scripts */
2052 get_available_versions_for_extension(control, tupstore, tupdesc);
2058 /* clean up and return the tuplestore */
2059 tuplestore_donestoring(tupstore);
2065 * Inner loop for pg_available_extension_versions:
2066 * read versions of one extension, add rows to tupstore
2069 get_available_versions_for_extension(ExtensionControlFile *pcontrol,
2070 Tuplestorestate *tupstore,
2076 /* Extract the version update graph from the script directory */
2077 evi_list = get_ext_ver_list(pcontrol);
2079 /* For each installable version ... */
2080 foreach(lc, evi_list)
2082 ExtensionVersionInfo *evi = (ExtensionVersionInfo *) lfirst(lc);
2083 ExtensionControlFile *control;
2088 if (!evi->installable)
2092 * Fetch parameters for specific version (pcontrol is not changed)
2094 control = read_extension_aux_control_file(pcontrol, evi->name);
2096 memset(values, 0, sizeof(values));
2097 memset(nulls, 0, sizeof(nulls));
2100 values[0] = DirectFunctionCall1(namein,
2101 CStringGetDatum(control->name));
2103 values[1] = CStringGetTextDatum(evi->name);
2105 values[2] = BoolGetDatum(control->superuser);
2107 values[3] = BoolGetDatum(control->relocatable);
2109 if (control->schema == NULL)
2112 values[4] = DirectFunctionCall1(namein,
2113 CStringGetDatum(control->schema));
2115 if (control->requires == NIL)
2118 values[5] = convert_requires_to_datum(control->requires);
2120 if (control->comment == NULL)
2123 values[6] = CStringGetTextDatum(control->comment);
2125 tuplestore_putvalues(tupstore, tupdesc, values, nulls);
2128 * Find all non-directly-installable versions that would be installed
2129 * starting from this version, and report them, inheriting the
2130 * parameters that aren't changed in updates from this version.
2132 foreach(lc2, evi_list)
2134 ExtensionVersionInfo *evi2 = (ExtensionVersionInfo *) lfirst(lc2);
2137 if (evi2->installable)
2139 if (find_install_path(evi_list, evi2, &best_path) == evi)
2142 * Fetch parameters for this version (pcontrol is not changed)
2144 control = read_extension_aux_control_file(pcontrol, evi2->name);
2146 /* name stays the same */
2148 values[1] = CStringGetTextDatum(evi2->name);
2150 values[2] = BoolGetDatum(control->superuser);
2152 values[3] = BoolGetDatum(control->relocatable);
2153 /* schema stays the same */
2155 if (control->requires == NIL)
2159 values[5] = convert_requires_to_datum(control->requires);
2162 /* comment stays the same */
2164 tuplestore_putvalues(tupstore, tupdesc, values, nulls);
2171 * Convert a list of extension names to a name[] Datum
2174 convert_requires_to_datum(List *requires)
2181 ndatums = list_length(requires);
2182 datums = (Datum *) palloc(ndatums * sizeof(Datum));
2184 foreach(lc, requires)
2186 char *curreq = (char *) lfirst(lc);
2189 DirectFunctionCall1(namein, CStringGetDatum(curreq));
2191 a = construct_array(datums, ndatums,
2193 NAMEDATALEN, false, 'c');
2194 return PointerGetDatum(a);
2198 * This function reports the version update paths that exist for the
2199 * specified extension.
2202 pg_extension_update_paths(PG_FUNCTION_ARGS)
2204 Name extname = PG_GETARG_NAME(0);
2205 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
2207 Tuplestorestate *tupstore;
2208 MemoryContext per_query_ctx;
2209 MemoryContext oldcontext;
2211 ExtensionControlFile *control;
2214 /* Check extension name validity before any filesystem access */
2215 check_valid_extension_name(NameStr(*extname));
2217 /* check to see if caller supports us returning a tuplestore */
2218 if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
2220 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2221 errmsg("set-valued function called in context that cannot accept a set")));
2222 if (!(rsinfo->allowedModes & SFRM_Materialize))
2224 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2225 errmsg("materialize mode required, but it is not " \
2226 "allowed in this context")));
2228 /* Build a tuple descriptor for our result type */
2229 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
2230 elog(ERROR, "return type must be a row type");
2232 /* Build tuplestore to hold the result rows */
2233 per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
2234 oldcontext = MemoryContextSwitchTo(per_query_ctx);
2236 tupstore = tuplestore_begin_heap(true, false, work_mem);
2237 rsinfo->returnMode = SFRM_Materialize;
2238 rsinfo->setResult = tupstore;
2239 rsinfo->setDesc = tupdesc;
2241 MemoryContextSwitchTo(oldcontext);
2243 /* Read the extension's control file */
2244 control = read_extension_control_file(NameStr(*extname));
2246 /* Extract the version update graph from the script directory */
2247 evi_list = get_ext_ver_list(control);
2249 /* Iterate over all pairs of versions */
2250 foreach(lc1, evi_list)
2252 ExtensionVersionInfo *evi1 = (ExtensionVersionInfo *) lfirst(lc1);
2255 foreach(lc2, evi_list)
2257 ExtensionVersionInfo *evi2 = (ExtensionVersionInfo *) lfirst(lc2);
2265 /* Find shortest path from evi1 to evi2 */
2266 path = find_update_path(evi_list, evi1, evi2, false, true);
2268 /* Emit result row */
2269 memset(values, 0, sizeof(values));
2270 memset(nulls, 0, sizeof(nulls));
2273 values[0] = CStringGetTextDatum(evi1->name);
2275 values[1] = CStringGetTextDatum(evi2->name);
2281 StringInfoData pathbuf;
2284 initStringInfo(&pathbuf);
2285 /* The path doesn't include start vertex, but show it */
2286 appendStringInfoString(&pathbuf, evi1->name);
2289 char *versionName = (char *) lfirst(lcv);
2291 appendStringInfoString(&pathbuf, "--");
2292 appendStringInfoString(&pathbuf, versionName);
2294 values[2] = CStringGetTextDatum(pathbuf.data);
2295 pfree(pathbuf.data);
2298 tuplestore_putvalues(tupstore, tupdesc, values, nulls);
2302 /* clean up and return the tuplestore */
2303 tuplestore_donestoring(tupstore);
2309 * pg_extension_config_dump
2311 * Record information about a configuration table that belongs to an
2312 * extension being created, but whose contents should be dumped in whole
2313 * or in part during pg_dump.
2316 pg_extension_config_dump(PG_FUNCTION_ARGS)
2318 Oid tableoid = PG_GETARG_OID(0);
2319 text *wherecond = PG_GETARG_TEXT_P(1);
2323 SysScanDesc extScan;
2330 Datum repl_val[Natts_pg_extension];
2331 bool repl_null[Natts_pg_extension];
2332 bool repl_repl[Natts_pg_extension];
2336 * We only allow this to be called from an extension's SQL script. We
2337 * shouldn't need any permissions check beyond that.
2339 if (!creating_extension)
2341 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2342 errmsg("pg_extension_config_dump() can only be called "
2343 "from an SQL script executed by CREATE EXTENSION")));
2346 * Check that the table exists and is a member of the extension being
2347 * created. This ensures that we don't need to register an additional
2348 * dependency to protect the extconfig entry.
2350 tablename = get_rel_name(tableoid);
2351 if (tablename == NULL)
2353 (errcode(ERRCODE_UNDEFINED_TABLE),
2354 errmsg("OID %u does not refer to a table", tableoid)));
2355 if (getExtensionOfObject(RelationRelationId, tableoid) !=
2356 CurrentExtensionObject)
2358 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2359 errmsg("table \"%s\" is not a member of the extension being created",
2363 * Add the table OID and WHERE condition to the extension's extconfig and
2364 * extcondition arrays.
2366 * If the table is already in extconfig, treat this as an update of the
2370 /* Find the pg_extension tuple */
2371 extRel = heap_open(ExtensionRelationId, RowExclusiveLock);
2373 ScanKeyInit(&key[0],
2374 ObjectIdAttributeNumber,
2375 BTEqualStrategyNumber, F_OIDEQ,
2376 ObjectIdGetDatum(CurrentExtensionObject));
2378 extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
2381 extTup = systable_getnext(extScan);
2383 if (!HeapTupleIsValid(extTup)) /* should not happen */
2384 elog(ERROR, "extension with oid %u does not exist",
2385 CurrentExtensionObject);
2387 memset(repl_val, 0, sizeof(repl_val));
2388 memset(repl_null, false, sizeof(repl_null));
2389 memset(repl_repl, false, sizeof(repl_repl));
2391 /* Build or modify the extconfig value */
2392 elementDatum = ObjectIdGetDatum(tableoid);
2394 arrayDatum = heap_getattr(extTup, Anum_pg_extension_extconfig,
2395 RelationGetDescr(extRel), &isnull);
2398 /* Previously empty extconfig, so build 1-element array */
2402 a = construct_array(&elementDatum, 1,
2404 sizeof(Oid), true, 'i');
2408 /* Modify or extend existing extconfig array */
2412 a = DatumGetArrayTypeP(arrayDatum);
2414 arrayLength = ARR_DIMS(a)[0];
2415 if (ARR_NDIM(a) != 1 ||
2416 ARR_LBOUND(a)[0] != 1 ||
2419 ARR_ELEMTYPE(a) != OIDOID)
2420 elog(ERROR, "extconfig is not a 1-D Oid array");
2421 arrayData = (Oid *) ARR_DATA_PTR(a);
2423 arrayIndex = arrayLength + 1; /* set up to add after end */
2425 for (i = 0; i < arrayLength; i++)
2427 if (arrayData[i] == tableoid)
2429 arrayIndex = i + 1; /* replace this element instead */
2434 a = array_set(a, 1, &arrayIndex,
2437 -1 /* varlena array */ ,
2438 sizeof(Oid) /* OID's typlen */ ,
2439 true /* OID's typbyval */ ,
2440 'i' /* OID's typalign */ );
2442 repl_val[Anum_pg_extension_extconfig - 1] = PointerGetDatum(a);
2443 repl_repl[Anum_pg_extension_extconfig - 1] = true;
2445 /* Build or modify the extcondition value */
2446 elementDatum = PointerGetDatum(wherecond);
2448 arrayDatum = heap_getattr(extTup, Anum_pg_extension_extcondition,
2449 RelationGetDescr(extRel), &isnull);
2452 if (arrayLength != 0)
2453 elog(ERROR, "extconfig and extcondition arrays do not match");
2455 a = construct_array(&elementDatum, 1,
2461 a = DatumGetArrayTypeP(arrayDatum);
2463 if (ARR_NDIM(a) != 1 ||
2464 ARR_LBOUND(a)[0] != 1 ||
2466 ARR_ELEMTYPE(a) != TEXTOID)
2467 elog(ERROR, "extcondition is not a 1-D text array");
2468 if (ARR_DIMS(a)[0] != arrayLength)
2469 elog(ERROR, "extconfig and extcondition arrays do not match");
2471 /* Add or replace at same index as in extconfig */
2472 a = array_set(a, 1, &arrayIndex,
2475 -1 /* varlena array */ ,
2476 -1 /* TEXT's typlen */ ,
2477 false /* TEXT's typbyval */ ,
2478 'i' /* TEXT's typalign */ );
2480 repl_val[Anum_pg_extension_extcondition - 1] = PointerGetDatum(a);
2481 repl_repl[Anum_pg_extension_extcondition - 1] = true;
2483 extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
2484 repl_val, repl_null, repl_repl);
2486 simple_heap_update(extRel, &extTup->t_self, extTup);
2487 CatalogUpdateIndexes(extRel, extTup);
2489 systable_endscan(extScan);
2491 heap_close(extRel, RowExclusiveLock);
2497 * extension_config_remove
2499 * Remove the specified table OID from extension's extconfig, if present.
2500 * This is not currently exposed as a function, but it could be;
2501 * for now, we just invoke it from ALTER EXTENSION DROP.
2504 extension_config_remove(Oid extensionoid, Oid tableoid)
2508 SysScanDesc extScan;
2514 Datum repl_val[Natts_pg_extension];
2515 bool repl_null[Natts_pg_extension];
2516 bool repl_repl[Natts_pg_extension];
2519 /* Find the pg_extension tuple */
2520 extRel = heap_open(ExtensionRelationId, RowExclusiveLock);
2522 ScanKeyInit(&key[0],
2523 ObjectIdAttributeNumber,
2524 BTEqualStrategyNumber, F_OIDEQ,
2525 ObjectIdGetDatum(extensionoid));
2527 extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
2530 extTup = systable_getnext(extScan);
2532 if (!HeapTupleIsValid(extTup)) /* should not happen */
2533 elog(ERROR, "extension with oid %u does not exist",
2536 /* Search extconfig for the tableoid */
2537 arrayDatum = heap_getattr(extTup, Anum_pg_extension_extconfig,
2538 RelationGetDescr(extRel), &isnull);
2551 a = DatumGetArrayTypeP(arrayDatum);
2553 arrayLength = ARR_DIMS(a)[0];
2554 if (ARR_NDIM(a) != 1 ||
2555 ARR_LBOUND(a)[0] != 1 ||
2558 ARR_ELEMTYPE(a) != OIDOID)
2559 elog(ERROR, "extconfig is not a 1-D Oid array");
2560 arrayData = (Oid *) ARR_DATA_PTR(a);
2562 arrayIndex = -1; /* flag for no deletion needed */
2564 for (i = 0; i < arrayLength; i++)
2566 if (arrayData[i] == tableoid)
2568 arrayIndex = i; /* index to remove */
2574 /* If tableoid is not in extconfig, nothing to do */
2577 systable_endscan(extScan);
2578 heap_close(extRel, RowExclusiveLock);
2582 /* Modify or delete the extconfig value */
2583 memset(repl_val, 0, sizeof(repl_val));
2584 memset(repl_null, false, sizeof(repl_null));
2585 memset(repl_repl, false, sizeof(repl_repl));
2587 if (arrayLength <= 1)
2589 /* removing only element, just set array to null */
2590 repl_null[Anum_pg_extension_extconfig - 1] = true;
2594 /* squeeze out the target element */
2600 deconstruct_array(a, OIDOID, sizeof(Oid), true, 'i',
2601 &dvalues, &dnulls, &nelems);
2603 /* We already checked there are no nulls, so ignore dnulls */
2604 for (i = arrayIndex; i < arrayLength - 1; i++)
2605 dvalues[i] = dvalues[i + 1];
2607 a = construct_array(dvalues, arrayLength - 1,
2608 OIDOID, sizeof(Oid), true, 'i');
2610 repl_val[Anum_pg_extension_extconfig - 1] = PointerGetDatum(a);
2612 repl_repl[Anum_pg_extension_extconfig - 1] = true;
2614 /* Modify or delete the extcondition value */
2615 arrayDatum = heap_getattr(extTup, Anum_pg_extension_extcondition,
2616 RelationGetDescr(extRel), &isnull);
2619 elog(ERROR, "extconfig and extcondition arrays do not match");
2623 a = DatumGetArrayTypeP(arrayDatum);
2625 if (ARR_NDIM(a) != 1 ||
2626 ARR_LBOUND(a)[0] != 1 ||
2628 ARR_ELEMTYPE(a) != TEXTOID)
2629 elog(ERROR, "extcondition is not a 1-D text array");
2630 if (ARR_DIMS(a)[0] != arrayLength)
2631 elog(ERROR, "extconfig and extcondition arrays do not match");
2634 if (arrayLength <= 1)
2636 /* removing only element, just set array to null */
2637 repl_null[Anum_pg_extension_extcondition - 1] = true;
2641 /* squeeze out the target element */
2647 deconstruct_array(a, TEXTOID, -1, false, 'i',
2648 &dvalues, &dnulls, &nelems);
2650 /* We already checked there are no nulls, so ignore dnulls */
2651 for (i = arrayIndex; i < arrayLength - 1; i++)
2652 dvalues[i] = dvalues[i + 1];
2654 a = construct_array(dvalues, arrayLength - 1,
2655 TEXTOID, -1, false, 'i');
2657 repl_val[Anum_pg_extension_extcondition - 1] = PointerGetDatum(a);
2659 repl_repl[Anum_pg_extension_extcondition - 1] = true;
2661 extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
2662 repl_val, repl_null, repl_repl);
2664 simple_heap_update(extRel, &extTup->t_self, extTup);
2665 CatalogUpdateIndexes(extRel, extTup);
2667 systable_endscan(extScan);
2669 heap_close(extRel, RowExclusiveLock);
2673 * Execute ALTER EXTENSION SET SCHEMA
2676 AlterExtensionNamespace(List *names, const char *newschema, Oid *oldschema)
2678 char *extensionName;
2681 Oid oldNspOid = InvalidOid;
2682 AclResult aclresult;
2685 SysScanDesc extScan;
2687 Form_pg_extension extForm;
2689 SysScanDesc depScan;
2691 ObjectAddresses *objsMoved;
2692 ObjectAddress extAddr;
2694 if (list_length(names) != 1)
2696 (errcode(ERRCODE_SYNTAX_ERROR),
2697 errmsg("extension name cannot be qualified")));
2698 extensionName = strVal(linitial(names));
2700 extensionOid = get_extension_oid(extensionName, false);
2702 nspOid = LookupCreationNamespace(newschema);
2705 * Permission check: must own extension. Note that we don't bother to
2706 * check ownership of the individual member objects ...
2708 if (!pg_extension_ownercheck(extensionOid, GetUserId()))
2709 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EXTENSION,
2712 /* Permission check: must have creation rights in target namespace */
2713 aclresult = pg_namespace_aclcheck(nspOid, GetUserId(), ACL_CREATE);
2714 if (aclresult != ACLCHECK_OK)
2715 aclcheck_error(aclresult, ACL_KIND_NAMESPACE, newschema);
2718 * If the schema is currently a member of the extension, disallow moving
2719 * the extension into the schema. That would create a dependency loop.
2721 if (getExtensionOfObject(NamespaceRelationId, nspOid) == extensionOid)
2723 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2724 errmsg("cannot move extension \"%s\" into schema \"%s\" "
2725 "because the extension contains the schema",
2726 extensionName, newschema)));
2728 /* Locate the pg_extension tuple */
2729 extRel = heap_open(ExtensionRelationId, RowExclusiveLock);
2731 ScanKeyInit(&key[0],
2732 ObjectIdAttributeNumber,
2733 BTEqualStrategyNumber, F_OIDEQ,
2734 ObjectIdGetDatum(extensionOid));
2736 extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
2739 extTup = systable_getnext(extScan);
2741 if (!HeapTupleIsValid(extTup)) /* should not happen */
2742 elog(ERROR, "extension with oid %u does not exist", extensionOid);
2744 /* Copy tuple so we can modify it below */
2745 extTup = heap_copytuple(extTup);
2746 extForm = (Form_pg_extension) GETSTRUCT(extTup);
2748 systable_endscan(extScan);
2751 * If the extension is already in the target schema, just silently do
2754 if (extForm->extnamespace == nspOid)
2756 heap_close(extRel, RowExclusiveLock);
2757 return InvalidObjectAddress;
2760 /* Check extension is supposed to be relocatable */
2761 if (!extForm->extrelocatable)
2763 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2764 errmsg("extension \"%s\" does not support SET SCHEMA",
2765 NameStr(extForm->extname))));
2767 objsMoved = new_object_addresses();
2770 * Scan pg_depend to find objects that depend directly on the extension,
2771 * and alter each one's schema.
2773 depRel = heap_open(DependRelationId, AccessShareLock);
2775 ScanKeyInit(&key[0],
2776 Anum_pg_depend_refclassid,
2777 BTEqualStrategyNumber, F_OIDEQ,
2778 ObjectIdGetDatum(ExtensionRelationId));
2779 ScanKeyInit(&key[1],
2780 Anum_pg_depend_refobjid,
2781 BTEqualStrategyNumber, F_OIDEQ,
2782 ObjectIdGetDatum(extensionOid));
2784 depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
2787 while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
2789 Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
2794 * Ignore non-membership dependencies. (Currently, the only other
2795 * case we could see here is a normal dependency from another
2798 if (pg_depend->deptype != DEPENDENCY_EXTENSION)
2801 dep.classId = pg_depend->classid;
2802 dep.objectId = pg_depend->objid;
2803 dep.objectSubId = pg_depend->objsubid;
2805 if (dep.objectSubId != 0) /* should not happen */
2806 elog(ERROR, "extension should not have a sub-object dependency");
2808 /* Relocate the object */
2809 dep_oldNspOid = AlterObjectNamespace_oid(dep.classId,
2815 * Remember previous namespace of first object that has one
2817 if (oldNspOid == InvalidOid && dep_oldNspOid != InvalidOid)
2818 oldNspOid = dep_oldNspOid;
2821 * If not all the objects had the same old namespace (ignoring any
2822 * that are not in namespaces), complain.
2824 if (dep_oldNspOid != InvalidOid && dep_oldNspOid != oldNspOid)
2826 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2827 errmsg("extension \"%s\" does not support SET SCHEMA",
2828 NameStr(extForm->extname)),
2829 errdetail("%s is not in the extension's schema \"%s\"",
2830 getObjectDescription(&dep),
2831 get_namespace_name(oldNspOid))));
2834 /* report old schema, if caller wants it */
2836 *oldschema = oldNspOid;
2838 systable_endscan(depScan);
2840 relation_close(depRel, AccessShareLock);
2842 /* Now adjust pg_extension.extnamespace */
2843 extForm->extnamespace = nspOid;
2845 simple_heap_update(extRel, &extTup->t_self, extTup);
2846 CatalogUpdateIndexes(extRel, extTup);
2848 heap_close(extRel, RowExclusiveLock);
2850 /* update dependencies to point to the new schema */
2851 changeDependencyFor(ExtensionRelationId, extensionOid,
2852 NamespaceRelationId, oldNspOid, nspOid);
2854 InvokeObjectPostAlterHook(ExtensionRelationId, extensionOid, 0);
2856 ObjectAddressSet(extAddr, ExtensionRelationId, extensionOid);
2862 * Execute ALTER EXTENSION UPDATE
2865 ExecAlterExtensionStmt(ParseState *pstate, AlterExtensionStmt *stmt)
2867 DefElem *d_new_version = NULL;
2869 char *oldVersionName;
2870 ExtensionControlFile *control;
2874 SysScanDesc extScan;
2876 List *updateVersions;
2880 ObjectAddress address;
2883 * We use global variables to track the extension being created, so we can
2884 * create/update only one extension at the same time.
2886 if (creating_extension)
2888 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2889 errmsg("nested ALTER EXTENSION is not supported")));
2892 * Look up the extension --- it must already exist in pg_extension
2894 extRel = heap_open(ExtensionRelationId, AccessShareLock);
2896 ScanKeyInit(&key[0],
2897 Anum_pg_extension_extname,
2898 BTEqualStrategyNumber, F_NAMEEQ,
2899 CStringGetDatum(stmt->extname));
2901 extScan = systable_beginscan(extRel, ExtensionNameIndexId, true,
2904 extTup = systable_getnext(extScan);
2906 if (!HeapTupleIsValid(extTup))
2908 (errcode(ERRCODE_UNDEFINED_OBJECT),
2909 errmsg("extension \"%s\" does not exist",
2912 extensionOid = HeapTupleGetOid(extTup);
2915 * Determine the existing version we are updating from
2917 datum = heap_getattr(extTup, Anum_pg_extension_extversion,
2918 RelationGetDescr(extRel), &isnull);
2920 elog(ERROR, "extversion is null");
2921 oldVersionName = text_to_cstring(DatumGetTextPP(datum));
2923 systable_endscan(extScan);
2925 heap_close(extRel, AccessShareLock);
2927 /* Permission check: must own extension */
2928 if (!pg_extension_ownercheck(extensionOid, GetUserId()))
2929 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EXTENSION,
2933 * Read the primary control file. Note we assume that it does not contain
2934 * any non-ASCII data, so there is no need to worry about encoding at this
2937 control = read_extension_control_file(stmt->extname);
2940 * Read the statement option list
2942 foreach(lc, stmt->options)
2944 DefElem *defel = (DefElem *) lfirst(lc);
2946 if (strcmp(defel->defname, "new_version") == 0)
2950 (errcode(ERRCODE_SYNTAX_ERROR),
2951 errmsg("conflicting or redundant options"),
2952 parser_errposition(pstate, defel->location)));
2953 d_new_version = defel;
2956 elog(ERROR, "unrecognized option: %s", defel->defname);
2960 * Determine the version to update to
2962 if (d_new_version && d_new_version->arg)
2963 versionName = strVal(d_new_version->arg);
2964 else if (control->default_version)
2965 versionName = control->default_version;
2969 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2970 errmsg("version to install must be specified")));
2971 versionName = NULL; /* keep compiler quiet */
2973 check_valid_version_name(versionName);
2976 * If we're already at that version, just say so
2978 if (strcmp(oldVersionName, versionName) == 0)
2981 (errmsg("version \"%s\" of extension \"%s\" is already installed",
2982 versionName, stmt->extname)));
2983 return InvalidObjectAddress;
2987 * Identify the series of update script files we need to execute
2989 updateVersions = identify_update_path(control,
2994 * Update the pg_extension row and execute the update scripts, one at a
2997 ApplyExtensionUpdates(extensionOid, control,
2998 oldVersionName, updateVersions,
2999 NULL, false, false);
3001 ObjectAddressSet(address, ExtensionRelationId, extensionOid);
3007 * Apply a series of update scripts as though individual ALTER EXTENSION
3008 * UPDATE commands had been given, including altering the pg_extension row
3009 * and dependencies each time.
3011 * This might be more work than necessary, but it ensures that old update
3012 * scripts don't break if newer versions have different control parameters.
3015 ApplyExtensionUpdates(Oid extensionOid,
3016 ExtensionControlFile *pcontrol,
3017 const char *initialVersion,
3018 List *updateVersions,
3019 char *origSchemaName,
3023 const char *oldVersionName = initialVersion;
3026 foreach(lcv, updateVersions)
3028 char *versionName = (char *) lfirst(lcv);
3029 ExtensionControlFile *control;
3032 List *requiredExtensions;
3033 List *requiredSchemas;
3036 SysScanDesc extScan;
3038 Form_pg_extension extForm;
3039 Datum values[Natts_pg_extension];
3040 bool nulls[Natts_pg_extension];
3041 bool repl[Natts_pg_extension];
3042 ObjectAddress myself;
3046 * Fetch parameters for specific version (pcontrol is not changed)
3048 control = read_extension_aux_control_file(pcontrol, versionName);
3050 /* Find the pg_extension tuple */
3051 extRel = heap_open(ExtensionRelationId, RowExclusiveLock);
3053 ScanKeyInit(&key[0],
3054 ObjectIdAttributeNumber,
3055 BTEqualStrategyNumber, F_OIDEQ,
3056 ObjectIdGetDatum(extensionOid));
3058 extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
3061 extTup = systable_getnext(extScan);
3063 if (!HeapTupleIsValid(extTup)) /* should not happen */
3064 elog(ERROR, "extension with oid %u does not exist",
3067 extForm = (Form_pg_extension) GETSTRUCT(extTup);
3070 * Determine the target schema (set by original install)
3072 schemaOid = extForm->extnamespace;
3073 schemaName = get_namespace_name(schemaOid);
3076 * Modify extrelocatable and extversion in the pg_extension tuple
3078 memset(values, 0, sizeof(values));
3079 memset(nulls, 0, sizeof(nulls));
3080 memset(repl, 0, sizeof(repl));
3082 values[Anum_pg_extension_extrelocatable - 1] =
3083 BoolGetDatum(control->relocatable);
3084 repl[Anum_pg_extension_extrelocatable - 1] = true;
3085 values[Anum_pg_extension_extversion - 1] =
3086 CStringGetTextDatum(versionName);
3087 repl[Anum_pg_extension_extversion - 1] = true;
3089 extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
3090 values, nulls, repl);
3092 simple_heap_update(extRel, &extTup->t_self, extTup);
3093 CatalogUpdateIndexes(extRel, extTup);
3095 systable_endscan(extScan);
3097 heap_close(extRel, RowExclusiveLock);
3100 * Look up the prerequisite extensions for this version, install them
3101 * if necessary, and build lists of their OIDs and the OIDs of their
3104 requiredExtensions = NIL;
3105 requiredSchemas = NIL;
3106 foreach(lc, control->requires)
3108 char *curreq = (char *) lfirst(lc);
3112 reqext = get_required_extension(curreq,
3118 reqschema = get_extension_schema(reqext);
3119 requiredExtensions = lappend_oid(requiredExtensions, reqext);
3120 requiredSchemas = lappend_oid(requiredSchemas, reqschema);
3124 * Remove and recreate dependencies on prerequisite extensions
3126 deleteDependencyRecordsForClass(ExtensionRelationId, extensionOid,
3127 ExtensionRelationId,
3130 myself.classId = ExtensionRelationId;
3131 myself.objectId = extensionOid;
3132 myself.objectSubId = 0;
3134 foreach(lc, requiredExtensions)
3136 Oid reqext = lfirst_oid(lc);
3137 ObjectAddress otherext;
3139 otherext.classId = ExtensionRelationId;
3140 otherext.objectId = reqext;
3141 otherext.objectSubId = 0;
3143 recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
3146 InvokeObjectPostAlterHook(ExtensionRelationId, extensionOid, 0);
3149 * Finally, execute the update script file
3151 execute_extension_script(extensionOid, control,
3152 oldVersionName, versionName,
3154 schemaName, schemaOid);
3157 * Update prior-version name and loop around. Since
3158 * execute_sql_string did a final CommandCounterIncrement, we can
3159 * update the pg_extension row again.
3161 oldVersionName = versionName;
3166 * Execute ALTER EXTENSION ADD/DROP
3168 * Return value is the address of the altered extension.
3170 * objAddr is an output argument which, if not NULL, is set to the address of
3171 * the added/dropped object.
3174 ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt,
3175 ObjectAddress *objAddr)
3177 ObjectAddress extension;
3178 ObjectAddress object;
3182 extension.classId = ExtensionRelationId;
3183 extension.objectId = get_extension_oid(stmt->extname, false);
3184 extension.objectSubId = 0;
3186 /* Permission check: must own extension */
3187 if (!pg_extension_ownercheck(extension.objectId, GetUserId()))
3188 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EXTENSION,
3192 * Translate the parser representation that identifies the object into an
3193 * ObjectAddress. get_object_address() will throw an error if the object
3194 * does not exist, and will also acquire a lock on the object to guard
3195 * against concurrent DROP and ALTER EXTENSION ADD/DROP operations.
3197 object = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
3198 &relation, ShareUpdateExclusiveLock, false);
3200 Assert(object.objectSubId == 0);
3204 /* Permission check: must own target object, too */
3205 check_object_ownership(GetUserId(), stmt->objtype, object,
3206 stmt->objname, stmt->objargs, relation);
3209 * Check existing extension membership.
3211 oldExtension = getExtensionOfObject(object.classId, object.objectId);
3213 if (stmt->action > 0)
3216 * ADD, so complain if object is already attached to some extension.
3218 if (OidIsValid(oldExtension))
3220 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3221 errmsg("%s is already a member of extension \"%s\"",
3222 getObjectDescription(&object),
3223 get_extension_name(oldExtension))));
3226 * Prevent a schema from being added to an extension if the schema
3227 * contains the extension. That would create a dependency loop.
3229 if (object.classId == NamespaceRelationId &&
3230 object.objectId == get_extension_schema(extension.objectId))
3232 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3233 errmsg("cannot add schema \"%s\" to extension \"%s\" "
3234 "because the schema contains the extension",
3235 get_namespace_name(object.objectId),
3239 * OK, add the dependency.
3241 recordDependencyOn(&object, &extension, DEPENDENCY_EXTENSION);
3246 * DROP, so complain if it's not a member.
3248 if (oldExtension != extension.objectId)
3250 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3251 errmsg("%s is not a member of extension \"%s\"",
3252 getObjectDescription(&object),
3256 * OK, drop the dependency.
3258 if (deleteDependencyRecordsForClass(object.classId, object.objectId,
3259 ExtensionRelationId,
3260 DEPENDENCY_EXTENSION) != 1)
3261 elog(ERROR, "unexpected number of extension dependency records");
3264 * If it's a relation, it might have an entry in the extension's
3265 * extconfig array, which we must remove.
3267 if (object.classId == RelationRelationId)
3268 extension_config_remove(extension.objectId, object.objectId);
3271 InvokeObjectPostAlterHook(ExtensionRelationId, extension.objectId, 0);
3274 * If get_object_address() opened the relation for us, we close it to keep
3275 * the reference count correct - but we retain any locks acquired by
3276 * get_object_address() until commit time, to guard against concurrent
3279 if (relation != NULL)
3280 relation_close(relation, NoLock);
3286 * Read the whole of file into memory.
3288 * The file contents are returned as a single palloc'd chunk. For convenience
3289 * of the callers, an extra \0 byte is added to the end.
3292 read_whole_file(const char *filename, int *length)
3296 size_t bytes_to_read;
3299 if (stat(filename, &fst) < 0)
3301 (errcode_for_file_access(),
3302 errmsg("could not stat file \"%s\": %m", filename)));
3304 if (fst.st_size > (MaxAllocSize - 1))
3306 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3307 errmsg("file \"%s\" is too large", filename)));
3308 bytes_to_read = (size_t) fst.st_size;
3310 if ((file = AllocateFile(filename, PG_BINARY_R)) == NULL)
3312 (errcode_for_file_access(),
3313 errmsg("could not open file \"%s\" for reading: %m",
3316 buf = (char *) palloc(bytes_to_read + 1);
3318 *length = fread(buf, 1, bytes_to_read, file);
3322 (errcode_for_file_access(),
3323 errmsg("could not read file \"%s\": %m", filename)));
3327 buf[*length] = '\0';