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-2016, 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,
104 static void get_available_versions_for_extension(ExtensionControlFile *pcontrol,
105 Tuplestorestate *tupstore,
107 static void ApplyExtensionUpdates(Oid extensionOid,
108 ExtensionControlFile *pcontrol,
109 const char *initialVersion,
110 List *updateVersions);
111 static char *read_whole_file(const char *filename, int *length);
115 * get_extension_oid - given an extension name, look up the OID
117 * If missing_ok is false, throw an error if extension name not found. If
118 * true, just return InvalidOid.
121 get_extension_oid(const char *extname, bool missing_ok)
125 SysScanDesc scandesc;
127 ScanKeyData entry[1];
129 rel = heap_open(ExtensionRelationId, AccessShareLock);
131 ScanKeyInit(&entry[0],
132 Anum_pg_extension_extname,
133 BTEqualStrategyNumber, F_NAMEEQ,
134 CStringGetDatum(extname));
136 scandesc = systable_beginscan(rel, ExtensionNameIndexId, true,
139 tuple = systable_getnext(scandesc);
141 /* We assume that there can be at most one matching tuple */
142 if (HeapTupleIsValid(tuple))
143 result = HeapTupleGetOid(tuple);
147 systable_endscan(scandesc);
149 heap_close(rel, AccessShareLock);
151 if (!OidIsValid(result) && !missing_ok)
153 (errcode(ERRCODE_UNDEFINED_OBJECT),
154 errmsg("extension \"%s\" does not exist",
161 * get_extension_name - given an extension OID, look up the name
163 * Returns a palloc'd string, or NULL if no such extension.
166 get_extension_name(Oid ext_oid)
170 SysScanDesc scandesc;
172 ScanKeyData entry[1];
174 rel = heap_open(ExtensionRelationId, AccessShareLock);
176 ScanKeyInit(&entry[0],
177 ObjectIdAttributeNumber,
178 BTEqualStrategyNumber, F_OIDEQ,
179 ObjectIdGetDatum(ext_oid));
181 scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
184 tuple = systable_getnext(scandesc);
186 /* We assume that there can be at most one matching tuple */
187 if (HeapTupleIsValid(tuple))
188 result = pstrdup(NameStr(((Form_pg_extension) GETSTRUCT(tuple))->extname));
192 systable_endscan(scandesc);
194 heap_close(rel, AccessShareLock);
200 * get_extension_schema - given an extension OID, fetch its extnamespace
202 * Returns InvalidOid if no such extension.
205 get_extension_schema(Oid ext_oid)
209 SysScanDesc scandesc;
211 ScanKeyData entry[1];
213 rel = heap_open(ExtensionRelationId, AccessShareLock);
215 ScanKeyInit(&entry[0],
216 ObjectIdAttributeNumber,
217 BTEqualStrategyNumber, F_OIDEQ,
218 ObjectIdGetDatum(ext_oid));
220 scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
223 tuple = systable_getnext(scandesc);
225 /* We assume that there can be at most one matching tuple */
226 if (HeapTupleIsValid(tuple))
227 result = ((Form_pg_extension) GETSTRUCT(tuple))->extnamespace;
231 systable_endscan(scandesc);
233 heap_close(rel, AccessShareLock);
239 * Utility functions to check validity of extension and version names
242 check_valid_extension_name(const char *extensionname)
244 int namelen = strlen(extensionname);
247 * Disallow empty names (the parser rejects empty identifiers anyway, but
252 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
253 errmsg("invalid extension name: \"%s\"", extensionname),
254 errdetail("Extension names must not be empty.")));
257 * No double dashes, since that would make script filenames ambiguous.
259 if (strstr(extensionname, "--"))
261 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
262 errmsg("invalid extension name: \"%s\"", extensionname),
263 errdetail("Extension names must not contain \"--\".")));
266 * No leading or trailing dash either. (We could probably allow this, but
267 * it would require much care in filename parsing and would make filenames
268 * visually if not formally ambiguous. Since there's no real-world use
269 * case, let's just forbid it.)
271 if (extensionname[0] == '-' || extensionname[namelen - 1] == '-')
273 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
274 errmsg("invalid extension name: \"%s\"", extensionname),
275 errdetail("Extension names must not begin or end with \"-\".")));
278 * No directory separators either (this is sufficient to prevent ".."
281 if (first_dir_separator(extensionname) != NULL)
283 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
284 errmsg("invalid extension name: \"%s\"", extensionname),
285 errdetail("Extension names must not contain directory separator characters.")));
289 check_valid_version_name(const char *versionname)
291 int namelen = strlen(versionname);
294 * Disallow empty names (we could possibly allow this, but there seems
299 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
300 errmsg("invalid extension version name: \"%s\"", versionname),
301 errdetail("Version names must not be empty.")));
304 * No double dashes, since that would make script filenames ambiguous.
306 if (strstr(versionname, "--"))
308 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
309 errmsg("invalid extension version name: \"%s\"", versionname),
310 errdetail("Version names must not contain \"--\".")));
313 * No leading or trailing dash either.
315 if (versionname[0] == '-' || versionname[namelen - 1] == '-')
317 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
318 errmsg("invalid extension version name: \"%s\"", versionname),
319 errdetail("Version names must not begin or end with \"-\".")));
322 * No directory separators either (this is sufficient to prevent ".."
325 if (first_dir_separator(versionname) != NULL)
327 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
328 errmsg("invalid extension version name: \"%s\"", versionname),
329 errdetail("Version names must not contain directory separator characters.")));
333 * Utility functions to handle extension-related path names
336 is_extension_control_filename(const char *filename)
338 const char *extension = strrchr(filename, '.');
340 return (extension != NULL) && (strcmp(extension, ".control") == 0);
344 is_extension_script_filename(const char *filename)
346 const char *extension = strrchr(filename, '.');
348 return (extension != NULL) && (strcmp(extension, ".sql") == 0);
352 get_extension_control_directory(void)
354 char sharepath[MAXPGPATH];
357 get_share_path(my_exec_path, sharepath);
358 result = (char *) palloc(MAXPGPATH);
359 snprintf(result, MAXPGPATH, "%s/extension", sharepath);
365 get_extension_control_filename(const char *extname)
367 char sharepath[MAXPGPATH];
370 get_share_path(my_exec_path, sharepath);
371 result = (char *) palloc(MAXPGPATH);
372 snprintf(result, MAXPGPATH, "%s/extension/%s.control",
379 get_extension_script_directory(ExtensionControlFile *control)
381 char sharepath[MAXPGPATH];
385 * The directory parameter can be omitted, absolute, or relative to the
386 * installation's share directory.
388 if (!control->directory)
389 return get_extension_control_directory();
391 if (is_absolute_path(control->directory))
392 return pstrdup(control->directory);
394 get_share_path(my_exec_path, sharepath);
395 result = (char *) palloc(MAXPGPATH);
396 snprintf(result, MAXPGPATH, "%s/%s", sharepath, control->directory);
402 get_extension_aux_control_filename(ExtensionControlFile *control,
408 scriptdir = get_extension_script_directory(control);
410 result = (char *) palloc(MAXPGPATH);
411 snprintf(result, MAXPGPATH, "%s/%s--%s.control",
412 scriptdir, control->name, version);
420 get_extension_script_filename(ExtensionControlFile *control,
421 const char *from_version, const char *version)
426 scriptdir = get_extension_script_directory(control);
428 result = (char *) palloc(MAXPGPATH);
430 snprintf(result, MAXPGPATH, "%s/%s--%s--%s.sql",
431 scriptdir, control->name, from_version, version);
433 snprintf(result, MAXPGPATH, "%s/%s--%s.sql",
434 scriptdir, control->name, version);
443 * Parse contents of primary or auxiliary control file, and fill in
444 * fields of *control. We parse primary file if version == NULL,
445 * else the optional auxiliary file for that version.
447 * Control files are supposed to be very short, half a dozen lines,
448 * so we don't worry about memory allocation risks here. Also we don't
449 * worry about what encoding it's in; all values are expected to be ASCII.
452 parse_extension_control_file(ExtensionControlFile *control,
457 ConfigVariable *item,
462 * Locate the file to read. Auxiliary files are optional.
465 filename = get_extension_aux_control_filename(control, version);
467 filename = get_extension_control_filename(control->name);
469 if ((file = AllocateFile(filename, "r")) == NULL)
471 if (version && errno == ENOENT)
473 /* no auxiliary file for this version */
478 (errcode_for_file_access(),
479 errmsg("could not open extension control file \"%s\": %m",
484 * Parse the file content, using GUC's file parsing code. We need not
485 * check the return value since any errors will be thrown at ERROR level.
487 (void) ParseConfigFp(file, filename, 0, ERROR, &head, &tail);
492 * Convert the ConfigVariable list into ExtensionControlFile entries.
494 for (item = head; item != NULL; item = item->next)
496 if (strcmp(item->name, "directory") == 0)
500 (errcode(ERRCODE_SYNTAX_ERROR),
501 errmsg("parameter \"%s\" cannot be set in a secondary extension control file",
504 control->directory = pstrdup(item->value);
506 else if (strcmp(item->name, "default_version") == 0)
510 (errcode(ERRCODE_SYNTAX_ERROR),
511 errmsg("parameter \"%s\" cannot be set in a secondary extension control file",
514 control->default_version = pstrdup(item->value);
516 else if (strcmp(item->name, "module_pathname") == 0)
518 control->module_pathname = pstrdup(item->value);
520 else if (strcmp(item->name, "comment") == 0)
522 control->comment = pstrdup(item->value);
524 else if (strcmp(item->name, "schema") == 0)
526 control->schema = pstrdup(item->value);
528 else if (strcmp(item->name, "relocatable") == 0)
530 if (!parse_bool(item->value, &control->relocatable))
532 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
533 errmsg("parameter \"%s\" requires a Boolean value",
536 else if (strcmp(item->name, "superuser") == 0)
538 if (!parse_bool(item->value, &control->superuser))
540 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
541 errmsg("parameter \"%s\" requires a Boolean value",
544 else if (strcmp(item->name, "encoding") == 0)
546 control->encoding = pg_valid_server_encoding(item->value);
547 if (control->encoding < 0)
549 (errcode(ERRCODE_UNDEFINED_OBJECT),
550 errmsg("\"%s\" is not a valid encoding name",
553 else if (strcmp(item->name, "requires") == 0)
555 /* Need a modifiable copy of string */
556 char *rawnames = pstrdup(item->value);
558 /* Parse string into list of identifiers */
559 if (!SplitIdentifierString(rawnames, ',', &control->requires))
561 /* syntax error in name list */
563 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
564 errmsg("parameter \"%s\" must be a list of extension names",
570 (errcode(ERRCODE_SYNTAX_ERROR),
571 errmsg("unrecognized parameter \"%s\" in file \"%s\"",
572 item->name, filename)));
575 FreeConfigVariables(head);
577 if (control->relocatable && control->schema != NULL)
579 (errcode(ERRCODE_SYNTAX_ERROR),
580 errmsg("parameter \"schema\" cannot be specified when \"relocatable\" is true")));
586 * Read the primary control file for the specified extension.
588 static ExtensionControlFile *
589 read_extension_control_file(const char *extname)
591 ExtensionControlFile *control;
594 * Set up default values. Pointer fields are initially null.
596 control = (ExtensionControlFile *) palloc0(sizeof(ExtensionControlFile));
597 control->name = pstrdup(extname);
598 control->relocatable = false;
599 control->superuser = true;
600 control->encoding = -1;
603 * Parse the primary control file.
605 parse_extension_control_file(control, NULL);
611 * Read the auxiliary control file for the specified extension and version.
613 * Returns a new modified ExtensionControlFile struct; the original struct
614 * (reflecting just the primary control file) is not modified.
616 static ExtensionControlFile *
617 read_extension_aux_control_file(const ExtensionControlFile *pcontrol,
620 ExtensionControlFile *acontrol;
623 * Flat-copy the struct. Pointer fields share values with original.
625 acontrol = (ExtensionControlFile *) palloc(sizeof(ExtensionControlFile));
626 memcpy(acontrol, pcontrol, sizeof(ExtensionControlFile));
629 * Parse the auxiliary control file, overwriting struct fields
631 parse_extension_control_file(acontrol, version);
637 * Read an SQL script file into a string, and convert to database encoding
640 read_extension_script_file(const ExtensionControlFile *control,
641 const char *filename)
648 src_str = read_whole_file(filename, &len);
650 /* use database encoding if not given */
651 if (control->encoding < 0)
652 src_encoding = GetDatabaseEncoding();
654 src_encoding = control->encoding;
656 /* make sure that source string is valid in the expected encoding */
657 pg_verify_mbstr_len(src_encoding, src_str, len, false);
660 * Convert the encoding to the database encoding. read_whole_file
661 * null-terminated the string, so if no conversion happens the string is
664 dest_str = pg_any_to_server(src_str, len, src_encoding);
670 * Execute given SQL string.
672 * filename is used only to report errors.
674 * Note: it's tempting to just use SPI to execute the string, but that does
675 * not work very well. The really serious problem is that SPI will parse,
676 * analyze, and plan the whole string before executing any of it; of course
677 * this fails if there are any plannable statements referring to objects
678 * created earlier in the script. A lesser annoyance is that SPI insists
679 * on printing the whole string as errcontext in case of any error, and that
680 * could be very long.
683 execute_sql_string(const char *sql, const char *filename)
685 List *raw_parsetree_list;
690 * Parse the SQL string into a list of raw parse trees.
692 raw_parsetree_list = pg_parse_query(sql);
694 /* All output from SELECTs goes to the bit bucket */
695 dest = CreateDestReceiver(DestNone);
698 * Do parse analysis, rule rewrite, planning, and execution for each raw
699 * parsetree. We must fully execute each query before beginning parse
700 * analysis on the next one, since there may be interdependencies.
702 foreach(lc1, raw_parsetree_list)
704 Node *parsetree = (Node *) lfirst(lc1);
708 stmt_list = pg_analyze_and_rewrite(parsetree,
712 stmt_list = pg_plan_queries(stmt_list, CURSOR_OPT_PARALLEL_OK, NULL);
714 foreach(lc2, stmt_list)
716 Node *stmt = (Node *) lfirst(lc2);
718 if (IsA(stmt, TransactionStmt))
720 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
721 errmsg("transaction control statements are not allowed within an extension script")));
723 CommandCounterIncrement();
725 PushActiveSnapshot(GetTransactionSnapshot());
727 if (IsA(stmt, PlannedStmt) &&
728 ((PlannedStmt *) stmt)->utilityStmt == NULL)
732 qdesc = CreateQueryDesc((PlannedStmt *) stmt,
734 GetActiveSnapshot(), NULL,
737 ExecutorStart(qdesc, 0);
738 ExecutorRun(qdesc, ForwardScanDirection, 0);
739 ExecutorFinish(qdesc);
742 FreeQueryDesc(qdesc);
748 PROCESS_UTILITY_QUERY,
758 /* Be sure to advance the command counter after the last script command */
759 CommandCounterIncrement();
763 * Execute the appropriate script file for installing or updating the extension
765 * If from_version isn't NULL, it's an update
768 execute_extension_script(Oid extensionOid, ExtensionControlFile *control,
769 const char *from_version,
771 List *requiredSchemas,
772 const char *schemaName, Oid schemaOid)
776 StringInfoData pathbuf;
780 * Enforce superuser-ness if appropriate. We postpone this check until
781 * here so that the flag is correctly associated with the right script(s)
782 * if it's set in secondary control files.
784 if (control->superuser && !superuser())
786 if (from_version == NULL)
788 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
789 errmsg("permission denied to create extension \"%s\"",
791 errhint("Must be superuser to create this extension.")));
794 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
795 errmsg("permission denied to update extension \"%s\"",
797 errhint("Must be superuser to update this extension.")));
800 filename = get_extension_script_filename(control, from_version, version);
803 * Force client_min_messages and log_min_messages to be at least WARNING,
804 * so that we won't spam the user with useless NOTICE messages from common
805 * script actions like creating shell types.
807 * We use the equivalent of a function SET option to allow the setting to
808 * persist for exactly the duration of the script execution. guc.c also
809 * takes care of undoing the setting on error.
811 save_nestlevel = NewGUCNestLevel();
813 if (client_min_messages < WARNING)
814 (void) set_config_option("client_min_messages", "warning",
815 PGC_USERSET, PGC_S_SESSION,
816 GUC_ACTION_SAVE, true, 0, false);
817 if (log_min_messages < WARNING)
818 (void) set_config_option("log_min_messages", "warning",
819 PGC_SUSET, PGC_S_SESSION,
820 GUC_ACTION_SAVE, true, 0, false);
823 * Set up the search path to contain the target schema, then the schemas
824 * of any prerequisite extensions, and nothing else. In particular this
825 * makes the target schema be the default creation target namespace.
827 * Note: it might look tempting to use PushOverrideSearchPath for this,
828 * but we cannot do that. We have to actually set the search_path GUC in
829 * case the extension script examines or changes it. In any case, the
830 * GUC_ACTION_SAVE method is just as convenient.
832 initStringInfo(&pathbuf);
833 appendStringInfoString(&pathbuf, quote_identifier(schemaName));
834 foreach(lc, requiredSchemas)
836 Oid reqschema = lfirst_oid(lc);
837 char *reqname = get_namespace_name(reqschema);
840 appendStringInfo(&pathbuf, ", %s", quote_identifier(reqname));
843 (void) set_config_option("search_path", pathbuf.data,
844 PGC_USERSET, PGC_S_SESSION,
845 GUC_ACTION_SAVE, true, 0, false);
848 * Set creating_extension and related variables so that
849 * recordDependencyOnCurrentExtension and other functions do the right
850 * things. On failure, ensure we reset these variables.
852 creating_extension = true;
853 CurrentExtensionObject = extensionOid;
856 char *c_sql = read_extension_script_file(control, filename);
859 /* We use various functions that want to operate on text datums */
860 t_sql = CStringGetTextDatum(c_sql);
863 * Reduce any lines beginning with "\echo" to empty. This allows
864 * scripts to contain messages telling people not to run them via
865 * psql, which has been found to be necessary due to old habits.
867 t_sql = DirectFunctionCall4Coll(textregexreplace,
870 CStringGetTextDatum("^\\\\echo.*$"),
871 CStringGetTextDatum(""),
872 CStringGetTextDatum("ng"));
875 * If it's not relocatable, substitute the target schema name for
876 * occurrences of @extschema@.
878 * For a relocatable extension, we needn't do this. There cannot be
879 * any need for @extschema@, else it wouldn't be relocatable.
881 if (!control->relocatable)
883 const char *qSchemaName = quote_identifier(schemaName);
885 t_sql = DirectFunctionCall3(replace_text,
887 CStringGetTextDatum("@extschema@"),
888 CStringGetTextDatum(qSchemaName));
892 * If module_pathname was set in the control file, substitute its
893 * value for occurrences of MODULE_PATHNAME.
895 if (control->module_pathname)
897 t_sql = DirectFunctionCall3(replace_text,
899 CStringGetTextDatum("MODULE_PATHNAME"),
900 CStringGetTextDatum(control->module_pathname));
903 /* And now back to C string */
904 c_sql = text_to_cstring(DatumGetTextPP(t_sql));
906 execute_sql_string(c_sql, filename);
910 creating_extension = false;
911 CurrentExtensionObject = InvalidOid;
916 creating_extension = false;
917 CurrentExtensionObject = InvalidOid;
920 * Restore the GUC variables we set above.
922 AtEOXact_GUC(true, save_nestlevel);
926 * Find or create an ExtensionVersionInfo for the specified version name
928 * Currently, we just use a List of the ExtensionVersionInfo's. Searching
929 * for them therefore uses about O(N^2) time when there are N versions of
930 * the extension. We could change the data structure to a hash table if
931 * this ever becomes a bottleneck.
933 static ExtensionVersionInfo *
934 get_ext_ver_info(const char *versionname, List **evi_list)
936 ExtensionVersionInfo *evi;
939 foreach(lc, *evi_list)
941 evi = (ExtensionVersionInfo *) lfirst(lc);
942 if (strcmp(evi->name, versionname) == 0)
946 evi = (ExtensionVersionInfo *) palloc(sizeof(ExtensionVersionInfo));
947 evi->name = pstrdup(versionname);
948 evi->reachable = NIL;
949 evi->installable = false;
950 /* initialize for later application of Dijkstra's algorithm */
951 evi->distance_known = false;
952 evi->distance = INT_MAX;
953 evi->previous = NULL;
955 *evi_list = lappend(*evi_list, evi);
961 * Locate the nearest unprocessed ExtensionVersionInfo
963 * This part of the algorithm is also about O(N^2). A priority queue would
964 * make it much faster, but for now there's no need.
966 static ExtensionVersionInfo *
967 get_nearest_unprocessed_vertex(List *evi_list)
969 ExtensionVersionInfo *evi = NULL;
972 foreach(lc, evi_list)
974 ExtensionVersionInfo *evi2 = (ExtensionVersionInfo *) lfirst(lc);
976 /* only vertices whose distance is still uncertain are candidates */
977 if (evi2->distance_known)
979 /* remember the closest such vertex */
981 evi->distance > evi2->distance)
989 * Obtain information about the set of update scripts available for the
990 * specified extension. The result is a List of ExtensionVersionInfo
991 * structs, each with a subsidiary list of the ExtensionVersionInfos for
992 * the versions that can be reached in one step from that version.
995 get_ext_ver_list(ExtensionControlFile *control)
997 List *evi_list = NIL;
998 int extnamelen = strlen(control->name);
1003 location = get_extension_script_directory(control);
1004 dir = AllocateDir(location);
1005 while ((de = ReadDir(dir, location)) != NULL)
1009 ExtensionVersionInfo *evi;
1010 ExtensionVersionInfo *evi2;
1012 /* must be a .sql file ... */
1013 if (!is_extension_script_filename(de->d_name))
1016 /* ... matching extension name followed by separator */
1017 if (strncmp(de->d_name, control->name, extnamelen) != 0 ||
1018 de->d_name[extnamelen] != '-' ||
1019 de->d_name[extnamelen + 1] != '-')
1022 /* extract version name(s) from 'extname--something.sql' filename */
1023 vername = pstrdup(de->d_name + extnamelen + 2);
1024 *strrchr(vername, '.') = '\0';
1025 vername2 = strstr(vername, "--");
1028 /* It's an install, not update, script; record its version name */
1029 evi = get_ext_ver_info(vername, &evi_list);
1030 evi->installable = true;
1033 *vername2 = '\0'; /* terminate first version */
1034 vername2 += 2; /* and point to second */
1036 /* if there's a third --, it's bogus, ignore it */
1037 if (strstr(vername2, "--"))
1040 /* Create ExtensionVersionInfos and link them together */
1041 evi = get_ext_ver_info(vername, &evi_list);
1042 evi2 = get_ext_ver_info(vername2, &evi_list);
1043 evi->reachable = lappend(evi->reachable, evi2);
1051 * Given an initial and final version name, identify the sequence of update
1052 * scripts that have to be applied to perform that update.
1054 * Result is a List of names of versions to transition through (the initial
1055 * version is *not* included).
1058 identify_update_path(ExtensionControlFile *control,
1059 const char *oldVersion, const char *newVersion)
1063 ExtensionVersionInfo *evi_start;
1064 ExtensionVersionInfo *evi_target;
1066 /* Extract the version update graph from the script directory */
1067 evi_list = get_ext_ver_list(control);
1069 /* Initialize start and end vertices */
1070 evi_start = get_ext_ver_info(oldVersion, &evi_list);
1071 evi_target = get_ext_ver_info(newVersion, &evi_list);
1073 /* Find shortest path */
1074 result = find_update_path(evi_list, evi_start, evi_target, false);
1078 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1079 errmsg("extension \"%s\" has no update path from version \"%s\" to version \"%s\"",
1080 control->name, oldVersion, newVersion)));
1086 * Apply Dijkstra's algorithm to find the shortest path from evi_start to
1089 * If reinitialize is false, assume the ExtensionVersionInfo list has not
1090 * been used for this before, and the initialization done by get_ext_ver_info
1093 * Result is a List of names of versions to transition through (the initial
1094 * version is *not* included). Returns NIL if no such path.
1097 find_update_path(List *evi_list,
1098 ExtensionVersionInfo *evi_start,
1099 ExtensionVersionInfo *evi_target,
1103 ExtensionVersionInfo *evi;
1106 /* Caller error if start == target */
1107 Assert(evi_start != evi_target);
1111 foreach(lc, evi_list)
1113 evi = (ExtensionVersionInfo *) lfirst(lc);
1114 evi->distance_known = false;
1115 evi->distance = INT_MAX;
1116 evi->previous = NULL;
1120 evi_start->distance = 0;
1122 while ((evi = get_nearest_unprocessed_vertex(evi_list)) != NULL)
1124 if (evi->distance == INT_MAX)
1125 break; /* all remaining vertices are unreachable */
1126 evi->distance_known = true;
1127 if (evi == evi_target)
1128 break; /* found shortest path to target */
1129 foreach(lc, evi->reachable)
1131 ExtensionVersionInfo *evi2 = (ExtensionVersionInfo *) lfirst(lc);
1134 newdist = evi->distance + 1;
1135 if (newdist < evi2->distance)
1137 evi2->distance = newdist;
1138 evi2->previous = evi;
1140 else if (newdist == evi2->distance &&
1141 evi2->previous != NULL &&
1142 strcmp(evi->name, evi2->previous->name) < 0)
1145 * Break ties in favor of the version name that comes first
1146 * according to strcmp(). This behavior is undocumented and
1147 * users shouldn't rely on it. We do it just to ensure that
1148 * if there is a tie, the update path that is chosen does not
1149 * depend on random factors like the order in which directory
1150 * entries get visited.
1152 evi2->previous = evi;
1157 /* Return NIL if target is not reachable from start */
1158 if (!evi_target->distance_known)
1161 /* Build and return list of version names representing the update path */
1163 for (evi = evi_target; evi != evi_start; evi = evi->previous)
1164 result = lcons(evi->name, result);
1170 * CREATE EXTENSION worker
1172 * When CASCADE is specified CreateExtensionInternal() recurses if required
1173 * extensions need to be installed. To sanely handle cyclic dependencies
1174 * cascade_parent contains the dependency chain leading to the current
1175 * invocation; thus allowing to error out if there's a cyclic dependency.
1177 static ObjectAddress
1178 CreateExtensionInternal(CreateExtensionStmt *stmt, List *parents)
1180 DefElem *d_schema = NULL;
1181 DefElem *d_new_version = NULL;
1182 DefElem *d_old_version = NULL;
1183 DefElem *d_cascade = NULL;
1184 char *schemaName = NULL;
1185 Oid schemaOid = InvalidOid;
1187 char *oldVersionName;
1188 bool cascade = false;
1189 Oid extowner = GetUserId();
1190 ExtensionControlFile *pcontrol;
1191 ExtensionControlFile *control;
1192 List *updateVersions;
1193 List *requiredExtensions;
1194 List *requiredSchemas;
1197 ObjectAddress address;
1200 * Read the primary control file. Note we assume that it does not contain
1201 * any non-ASCII data, so there is no need to worry about encoding at this
1204 pcontrol = read_extension_control_file(stmt->extname);
1207 * Read the statement option list
1209 foreach(lc, stmt->options)
1211 DefElem *defel = (DefElem *) lfirst(lc);
1213 if (strcmp(defel->defname, "schema") == 0)
1217 (errcode(ERRCODE_SYNTAX_ERROR),
1218 errmsg("conflicting or redundant options")));
1221 else if (strcmp(defel->defname, "new_version") == 0)
1225 (errcode(ERRCODE_SYNTAX_ERROR),
1226 errmsg("conflicting or redundant options")));
1227 d_new_version = defel;
1229 else if (strcmp(defel->defname, "old_version") == 0)
1233 (errcode(ERRCODE_SYNTAX_ERROR),
1234 errmsg("conflicting or redundant options")));
1235 d_old_version = defel;
1237 else if (strcmp(defel->defname, "cascade") == 0)
1241 (errcode(ERRCODE_SYNTAX_ERROR),
1242 errmsg("conflicting or redundant options")));
1244 cascade = defGetBoolean(d_cascade);
1247 elog(ERROR, "unrecognized option: %s", defel->defname);
1251 * Determine the version to install
1253 if (d_new_version && d_new_version->arg)
1254 versionName = strVal(d_new_version->arg);
1255 else if (pcontrol->default_version)
1256 versionName = pcontrol->default_version;
1260 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1261 errmsg("version to install must be specified")));
1262 versionName = NULL; /* keep compiler quiet */
1264 check_valid_version_name(versionName);
1267 * Determine the (unpackaged) version to update from, if any, and then
1268 * figure out what sequence of update scripts we need to apply.
1270 if (d_old_version && d_old_version->arg)
1272 oldVersionName = strVal(d_old_version->arg);
1273 check_valid_version_name(oldVersionName);
1275 if (strcmp(oldVersionName, versionName) == 0)
1277 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1278 errmsg("FROM version must be different from installation target version \"%s\"",
1281 updateVersions = identify_update_path(pcontrol,
1285 if (list_length(updateVersions) == 1)
1288 * Simple case where there's just one update script to run. We
1289 * will not need any follow-on update steps.
1291 Assert(strcmp((char *) linitial(updateVersions), versionName) == 0);
1292 updateVersions = NIL;
1297 * Multi-step sequence. We treat this as installing the version
1298 * that is the target of the first script, followed by successive
1299 * updates to the later versions.
1301 versionName = (char *) linitial(updateVersions);
1302 updateVersions = list_delete_first(updateVersions);
1307 oldVersionName = NULL;
1308 updateVersions = NIL;
1312 * Fetch control parameters for installation target version
1314 control = read_extension_aux_control_file(pcontrol, versionName);
1317 * Determine the target schema to install the extension into
1319 if (d_schema && d_schema->arg)
1322 * User given schema, CREATE EXTENSION ... WITH SCHEMA ...
1324 schemaName = strVal(d_schema->arg);
1326 /* If the user is giving us the schema name, it must exist already. */
1327 schemaOid = get_namespace_oid(schemaName, false);
1330 if (control->schema != NULL)
1333 * The extension is not relocatable and the author gave us a schema
1336 * Unless CASCADE parameter was given, it's an error to give a schema
1337 * different from control->schema if control->schema is specified.
1339 if (schemaName && strcmp(control->schema, schemaName) != 0 &&
1342 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1343 errmsg("extension \"%s\" must be installed in schema \"%s\"",
1347 /* Always use the schema from control file for current extension. */
1348 schemaName = control->schema;
1350 /* Find or create the schema in case it does not exist. */
1351 schemaOid = get_namespace_oid(schemaName, true);
1353 if (!OidIsValid(schemaOid))
1355 CreateSchemaStmt *csstmt = makeNode(CreateSchemaStmt);
1357 csstmt->schemaname = schemaName;
1358 csstmt->authrole = NULL; /* will be created by current user */
1359 csstmt->schemaElts = NIL;
1360 csstmt->if_not_exists = false;
1361 CreateSchemaCommand(csstmt, NULL);
1364 * CreateSchemaCommand includes CommandCounterIncrement, so new
1365 * schema is now visible.
1367 schemaOid = get_namespace_oid(schemaName, false);
1370 else if (!OidIsValid(schemaOid))
1373 * Neither user nor author of the extension specified schema, use the
1374 * current default creation namespace, which is the first explicit
1375 * entry in the search_path.
1377 List *search_path = fetch_search_path(false);
1379 if (search_path == NIL) /* nothing valid in search_path? */
1381 (errcode(ERRCODE_UNDEFINED_SCHEMA),
1382 errmsg("no schema has been selected to create in")));
1383 schemaOid = linitial_oid(search_path);
1384 schemaName = get_namespace_name(schemaOid);
1385 if (schemaName == NULL) /* recently-deleted namespace? */
1387 (errcode(ERRCODE_UNDEFINED_SCHEMA),
1388 errmsg("no schema has been selected to create in")));
1390 list_free(search_path);
1394 * We don't check creation rights on the target namespace here. If the
1395 * extension script actually creates any objects there, it will fail if
1396 * the user doesn't have such permissions. But there are cases such as
1397 * procedural languages where it's convenient to set schema = pg_catalog
1398 * yet we don't want to restrict the command to users with ACL_CREATE for
1403 * Look up the prerequisite extensions, and build lists of their OIDs and
1404 * the OIDs of their target schemas.
1406 requiredExtensions = NIL;
1407 requiredSchemas = NIL;
1408 foreach(lc, control->requires)
1410 char *curreq = (char *) lfirst(lc);
1414 reqext = get_extension_oid(curreq, true);
1415 if (!OidIsValid(reqext))
1419 CreateExtensionStmt *ces;
1422 List *cascade_parents;
1424 /* Check extension name validity before trying to cascade */
1425 check_valid_extension_name(curreq);
1427 /* Check for cyclic dependency between extensions. */
1428 foreach(lc, parents)
1430 char *pname = (char *) lfirst(lc);
1432 if (strcmp(pname, curreq) == 0)
1434 (errcode(ERRCODE_INVALID_RECURSION),
1435 errmsg("cyclic dependency detected between extensions \"%s\" and \"%s\"",
1436 curreq, stmt->extname)));
1440 (errmsg("installing required extension \"%s\"",
1443 /* Create and execute new CREATE EXTENSION statement. */
1444 ces = makeNode(CreateExtensionStmt);
1445 ces->extname = curreq;
1447 /* Propagate the CASCADE option */
1448 ces->options = list_make1(d_cascade);
1450 /* Propagate the SCHEMA option if given. */
1451 if (d_schema && d_schema->arg)
1452 ces->options = lappend(ces->options, d_schema);
1455 * Pass the current list of parents + the current extension to
1456 * the "child" CreateExtensionInternal().
1459 lappend(list_copy(parents), stmt->extname);
1461 /* Create the required extension. */
1462 addr = CreateExtensionInternal(ces, cascade_parents);
1463 reqext = addr.objectId;
1467 (errcode(ERRCODE_UNDEFINED_OBJECT),
1468 errmsg("required extension \"%s\" is not installed",
1470 errhint("Use CREATE EXTENSION CASCADE to install required extensions too.")));
1473 reqschema = get_extension_schema(reqext);
1474 requiredExtensions = lappend_oid(requiredExtensions, reqext);
1475 requiredSchemas = lappend_oid(requiredSchemas, reqschema);
1479 * Insert new tuple into pg_extension, and create dependency entries.
1481 address = InsertExtensionTuple(control->name, extowner,
1482 schemaOid, control->relocatable,
1484 PointerGetDatum(NULL),
1485 PointerGetDatum(NULL),
1486 requiredExtensions);
1487 extensionOid = address.objectId;
1490 * Apply any control-file comment on extension
1492 if (control->comment != NULL)
1493 CreateComments(extensionOid, ExtensionRelationId, 0, control->comment);
1496 * Execute the installation script file
1498 execute_extension_script(extensionOid, control,
1499 oldVersionName, versionName,
1501 schemaName, schemaOid);
1504 * If additional update scripts have to be executed, apply the updates as
1505 * though a series of ALTER EXTENSION UPDATE commands were given
1507 ApplyExtensionUpdates(extensionOid, pcontrol,
1508 versionName, updateVersions);
1517 CreateExtension(CreateExtensionStmt *stmt)
1519 /* Check extension name validity before any filesystem access */
1520 check_valid_extension_name(stmt->extname);
1523 * Check for duplicate extension name. The unique index on
1524 * pg_extension.extname would catch this anyway, and serves as a backstop
1525 * in case of race conditions; but this is a friendlier error message, and
1526 * besides we need a check to support IF NOT EXISTS.
1528 if (get_extension_oid(stmt->extname, true) != InvalidOid)
1530 if (stmt->if_not_exists)
1533 (errcode(ERRCODE_DUPLICATE_OBJECT),
1534 errmsg("extension \"%s\" already exists, skipping",
1536 return InvalidObjectAddress;
1540 (errcode(ERRCODE_DUPLICATE_OBJECT),
1541 errmsg("extension \"%s\" already exists",
1546 * We use global variables to track the extension being created, so we can
1547 * create only one extension at the same time.
1549 if (creating_extension)
1551 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1552 errmsg("nested CREATE EXTENSION is not supported")));
1555 /* Finally create the extension. */
1556 return CreateExtensionInternal(stmt, NIL);
1560 * InsertExtensionTuple
1562 * Insert the new pg_extension row, and create extension's dependency entries.
1563 * Return the OID assigned to the new row.
1565 * This is exported for the benefit of pg_upgrade, which has to create a
1566 * pg_extension entry (and the extension-level dependencies) without
1567 * actually running the extension's script.
1569 * extConfig and extCondition should be arrays or PointerGetDatum(NULL).
1570 * We declare them as plain Datum to avoid needing array.h in extension.h.
1573 InsertExtensionTuple(const char *extName, Oid extOwner,
1574 Oid schemaOid, bool relocatable, const char *extVersion,
1575 Datum extConfig, Datum extCondition,
1576 List *requiredExtensions)
1580 Datum values[Natts_pg_extension];
1581 bool nulls[Natts_pg_extension];
1583 ObjectAddress myself;
1588 * Build and insert the pg_extension tuple
1590 rel = heap_open(ExtensionRelationId, RowExclusiveLock);
1592 memset(values, 0, sizeof(values));
1593 memset(nulls, 0, sizeof(nulls));
1595 values[Anum_pg_extension_extname - 1] =
1596 DirectFunctionCall1(namein, CStringGetDatum(extName));
1597 values[Anum_pg_extension_extowner - 1] = ObjectIdGetDatum(extOwner);
1598 values[Anum_pg_extension_extnamespace - 1] = ObjectIdGetDatum(schemaOid);
1599 values[Anum_pg_extension_extrelocatable - 1] = BoolGetDatum(relocatable);
1600 values[Anum_pg_extension_extversion - 1] = CStringGetTextDatum(extVersion);
1602 if (extConfig == PointerGetDatum(NULL))
1603 nulls[Anum_pg_extension_extconfig - 1] = true;
1605 values[Anum_pg_extension_extconfig - 1] = extConfig;
1607 if (extCondition == PointerGetDatum(NULL))
1608 nulls[Anum_pg_extension_extcondition - 1] = true;
1610 values[Anum_pg_extension_extcondition - 1] = extCondition;
1612 tuple = heap_form_tuple(rel->rd_att, values, nulls);
1614 extensionOid = simple_heap_insert(rel, tuple);
1615 CatalogUpdateIndexes(rel, tuple);
1617 heap_freetuple(tuple);
1618 heap_close(rel, RowExclusiveLock);
1621 * Record dependencies on owner, schema, and prerequisite extensions
1623 recordDependencyOnOwner(ExtensionRelationId, extensionOid, extOwner);
1625 myself.classId = ExtensionRelationId;
1626 myself.objectId = extensionOid;
1627 myself.objectSubId = 0;
1629 nsp.classId = NamespaceRelationId;
1630 nsp.objectId = schemaOid;
1631 nsp.objectSubId = 0;
1633 recordDependencyOn(&myself, &nsp, DEPENDENCY_NORMAL);
1635 foreach(lc, requiredExtensions)
1637 Oid reqext = lfirst_oid(lc);
1638 ObjectAddress otherext;
1640 otherext.classId = ExtensionRelationId;
1641 otherext.objectId = reqext;
1642 otherext.objectSubId = 0;
1644 recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
1646 /* Post creation hook for new extension */
1647 InvokeObjectPostCreateHook(ExtensionRelationId, extensionOid, 0);
1653 * Guts of extension deletion.
1655 * All we need do here is remove the pg_extension tuple itself. Everything
1656 * else is taken care of by the dependency infrastructure.
1659 RemoveExtensionById(Oid extId)
1662 SysScanDesc scandesc;
1664 ScanKeyData entry[1];
1667 * Disallow deletion of any extension that's currently open for insertion;
1668 * else subsequent executions of recordDependencyOnCurrentExtension()
1669 * could create dangling pg_depend records that refer to a no-longer-valid
1670 * pg_extension OID. This is needed not so much because we think people
1671 * might write "DROP EXTENSION foo" in foo's own script files, as because
1672 * errors in dependency management in extension script files could give
1673 * rise to cases where an extension is dropped as a result of recursing
1674 * from some contained object. Because of that, we must test for the case
1675 * here, not at some higher level of the DROP EXTENSION command.
1677 if (extId == CurrentExtensionObject)
1679 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1680 errmsg("cannot drop extension \"%s\" because it is being modified",
1681 get_extension_name(extId))));
1683 rel = heap_open(ExtensionRelationId, RowExclusiveLock);
1685 ScanKeyInit(&entry[0],
1686 ObjectIdAttributeNumber,
1687 BTEqualStrategyNumber, F_OIDEQ,
1688 ObjectIdGetDatum(extId));
1689 scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
1692 tuple = systable_getnext(scandesc);
1694 /* We assume that there can be at most one matching tuple */
1695 if (HeapTupleIsValid(tuple))
1696 simple_heap_delete(rel, &tuple->t_self);
1698 systable_endscan(scandesc);
1700 heap_close(rel, RowExclusiveLock);
1704 * This function lists the available extensions (one row per primary control
1705 * file in the control directory). We parse each control file and report the
1706 * interesting fields.
1708 * The system view pg_available_extensions provides a user interface to this
1709 * SRF, adding information about whether the extensions are installed in the
1713 pg_available_extensions(PG_FUNCTION_ARGS)
1715 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1717 Tuplestorestate *tupstore;
1718 MemoryContext per_query_ctx;
1719 MemoryContext oldcontext;
1724 /* check to see if caller supports us returning a tuplestore */
1725 if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
1727 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1728 errmsg("set-valued function called in context that cannot accept a set")));
1729 if (!(rsinfo->allowedModes & SFRM_Materialize))
1731 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1732 errmsg("materialize mode required, but it is not " \
1733 "allowed in this context")));
1735 /* Build a tuple descriptor for our result type */
1736 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
1737 elog(ERROR, "return type must be a row type");
1739 /* Build tuplestore to hold the result rows */
1740 per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
1741 oldcontext = MemoryContextSwitchTo(per_query_ctx);
1743 tupstore = tuplestore_begin_heap(true, false, work_mem);
1744 rsinfo->returnMode = SFRM_Materialize;
1745 rsinfo->setResult = tupstore;
1746 rsinfo->setDesc = tupdesc;
1748 MemoryContextSwitchTo(oldcontext);
1750 location = get_extension_control_directory();
1751 dir = AllocateDir(location);
1754 * If the control directory doesn't exist, we want to silently return an
1755 * empty set. Any other error will be reported by ReadDir.
1757 if (dir == NULL && errno == ENOENT)
1763 while ((de = ReadDir(dir, location)) != NULL)
1765 ExtensionControlFile *control;
1770 if (!is_extension_control_filename(de->d_name))
1773 /* extract extension name from 'name.control' filename */
1774 extname = pstrdup(de->d_name);
1775 *strrchr(extname, '.') = '\0';
1777 /* ignore it if it's an auxiliary control file */
1778 if (strstr(extname, "--"))
1781 control = read_extension_control_file(extname);
1783 memset(values, 0, sizeof(values));
1784 memset(nulls, 0, sizeof(nulls));
1787 values[0] = DirectFunctionCall1(namein,
1788 CStringGetDatum(control->name));
1789 /* default_version */
1790 if (control->default_version == NULL)
1793 values[1] = CStringGetTextDatum(control->default_version);
1795 if (control->comment == NULL)
1798 values[2] = CStringGetTextDatum(control->comment);
1800 tuplestore_putvalues(tupstore, tupdesc, values, nulls);
1806 /* clean up and return the tuplestore */
1807 tuplestore_donestoring(tupstore);
1813 * This function lists the available extension versions (one row per
1814 * extension installation script). For each version, we parse the related
1815 * control file(s) and report the interesting fields.
1817 * The system view pg_available_extension_versions provides a user interface
1818 * to this SRF, adding information about which versions are installed in the
1822 pg_available_extension_versions(PG_FUNCTION_ARGS)
1824 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1826 Tuplestorestate *tupstore;
1827 MemoryContext per_query_ctx;
1828 MemoryContext oldcontext;
1833 /* check to see if caller supports us returning a tuplestore */
1834 if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
1836 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1837 errmsg("set-valued function called in context that cannot accept a set")));
1838 if (!(rsinfo->allowedModes & SFRM_Materialize))
1840 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1841 errmsg("materialize mode required, but it is not " \
1842 "allowed in this context")));
1844 /* Build a tuple descriptor for our result type */
1845 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
1846 elog(ERROR, "return type must be a row type");
1848 /* Build tuplestore to hold the result rows */
1849 per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
1850 oldcontext = MemoryContextSwitchTo(per_query_ctx);
1852 tupstore = tuplestore_begin_heap(true, false, work_mem);
1853 rsinfo->returnMode = SFRM_Materialize;
1854 rsinfo->setResult = tupstore;
1855 rsinfo->setDesc = tupdesc;
1857 MemoryContextSwitchTo(oldcontext);
1859 location = get_extension_control_directory();
1860 dir = AllocateDir(location);
1863 * If the control directory doesn't exist, we want to silently return an
1864 * empty set. Any other error will be reported by ReadDir.
1866 if (dir == NULL && errno == ENOENT)
1872 while ((de = ReadDir(dir, location)) != NULL)
1874 ExtensionControlFile *control;
1877 if (!is_extension_control_filename(de->d_name))
1880 /* extract extension name from 'name.control' filename */
1881 extname = pstrdup(de->d_name);
1882 *strrchr(extname, '.') = '\0';
1884 /* ignore it if it's an auxiliary control file */
1885 if (strstr(extname, "--"))
1888 /* read the control file */
1889 control = read_extension_control_file(extname);
1891 /* scan extension's script directory for install scripts */
1892 get_available_versions_for_extension(control, tupstore, tupdesc);
1898 /* clean up and return the tuplestore */
1899 tuplestore_donestoring(tupstore);
1905 * Inner loop for pg_available_extension_versions:
1906 * read versions of one extension, add rows to tupstore
1909 get_available_versions_for_extension(ExtensionControlFile *pcontrol,
1910 Tuplestorestate *tupstore,
1913 int extnamelen = strlen(pcontrol->name);
1918 location = get_extension_script_directory(pcontrol);
1919 dir = AllocateDir(location);
1920 /* Note this will fail if script directory doesn't exist */
1921 while ((de = ReadDir(dir, location)) != NULL)
1923 ExtensionControlFile *control;
1928 /* must be a .sql file ... */
1929 if (!is_extension_script_filename(de->d_name))
1932 /* ... matching extension name followed by separator */
1933 if (strncmp(de->d_name, pcontrol->name, extnamelen) != 0 ||
1934 de->d_name[extnamelen] != '-' ||
1935 de->d_name[extnamelen + 1] != '-')
1938 /* extract version name from 'extname--something.sql' filename */
1939 vername = pstrdup(de->d_name + extnamelen + 2);
1940 *strrchr(vername, '.') = '\0';
1942 /* ignore it if it's an update script */
1943 if (strstr(vername, "--"))
1947 * Fetch parameters for specific version (pcontrol is not changed)
1949 control = read_extension_aux_control_file(pcontrol, vername);
1951 memset(values, 0, sizeof(values));
1952 memset(nulls, 0, sizeof(nulls));
1955 values[0] = DirectFunctionCall1(namein,
1956 CStringGetDatum(control->name));
1958 values[1] = CStringGetTextDatum(vername);
1960 values[2] = BoolGetDatum(control->superuser);
1962 values[3] = BoolGetDatum(control->relocatable);
1964 if (control->schema == NULL)
1967 values[4] = DirectFunctionCall1(namein,
1968 CStringGetDatum(control->schema));
1970 if (control->requires == NIL)
1979 ndatums = list_length(control->requires);
1980 datums = (Datum *) palloc(ndatums * sizeof(Datum));
1982 foreach(lc, control->requires)
1984 char *curreq = (char *) lfirst(lc);
1987 DirectFunctionCall1(namein, CStringGetDatum(curreq));
1989 a = construct_array(datums, ndatums,
1991 NAMEDATALEN, false, 'c');
1992 values[5] = PointerGetDatum(a);
1995 if (control->comment == NULL)
1998 values[6] = CStringGetTextDatum(control->comment);
2000 tuplestore_putvalues(tupstore, tupdesc, values, nulls);
2007 * This function reports the version update paths that exist for the
2008 * specified extension.
2011 pg_extension_update_paths(PG_FUNCTION_ARGS)
2013 Name extname = PG_GETARG_NAME(0);
2014 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
2016 Tuplestorestate *tupstore;
2017 MemoryContext per_query_ctx;
2018 MemoryContext oldcontext;
2020 ExtensionControlFile *control;
2023 /* Check extension name validity before any filesystem access */
2024 check_valid_extension_name(NameStr(*extname));
2026 /* check to see if caller supports us returning a tuplestore */
2027 if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
2029 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2030 errmsg("set-valued function called in context that cannot accept a set")));
2031 if (!(rsinfo->allowedModes & SFRM_Materialize))
2033 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2034 errmsg("materialize mode required, but it is not " \
2035 "allowed in this context")));
2037 /* Build a tuple descriptor for our result type */
2038 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
2039 elog(ERROR, "return type must be a row type");
2041 /* Build tuplestore to hold the result rows */
2042 per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
2043 oldcontext = MemoryContextSwitchTo(per_query_ctx);
2045 tupstore = tuplestore_begin_heap(true, false, work_mem);
2046 rsinfo->returnMode = SFRM_Materialize;
2047 rsinfo->setResult = tupstore;
2048 rsinfo->setDesc = tupdesc;
2050 MemoryContextSwitchTo(oldcontext);
2052 /* Read the extension's control file */
2053 control = read_extension_control_file(NameStr(*extname));
2055 /* Extract the version update graph from the script directory */
2056 evi_list = get_ext_ver_list(control);
2058 /* Iterate over all pairs of versions */
2059 foreach(lc1, evi_list)
2061 ExtensionVersionInfo *evi1 = (ExtensionVersionInfo *) lfirst(lc1);
2064 foreach(lc2, evi_list)
2066 ExtensionVersionInfo *evi2 = (ExtensionVersionInfo *) lfirst(lc2);
2074 /* Find shortest path from evi1 to evi2 */
2075 path = find_update_path(evi_list, evi1, evi2, true);
2077 /* Emit result row */
2078 memset(values, 0, sizeof(values));
2079 memset(nulls, 0, sizeof(nulls));
2082 values[0] = CStringGetTextDatum(evi1->name);
2084 values[1] = CStringGetTextDatum(evi2->name);
2090 StringInfoData pathbuf;
2093 initStringInfo(&pathbuf);
2094 /* The path doesn't include start vertex, but show it */
2095 appendStringInfoString(&pathbuf, evi1->name);
2098 char *versionName = (char *) lfirst(lcv);
2100 appendStringInfoString(&pathbuf, "--");
2101 appendStringInfoString(&pathbuf, versionName);
2103 values[2] = CStringGetTextDatum(pathbuf.data);
2104 pfree(pathbuf.data);
2107 tuplestore_putvalues(tupstore, tupdesc, values, nulls);
2111 /* clean up and return the tuplestore */
2112 tuplestore_donestoring(tupstore);
2118 * pg_extension_config_dump
2120 * Record information about a configuration table that belongs to an
2121 * extension being created, but whose contents should be dumped in whole
2122 * or in part during pg_dump.
2125 pg_extension_config_dump(PG_FUNCTION_ARGS)
2127 Oid tableoid = PG_GETARG_OID(0);
2128 text *wherecond = PG_GETARG_TEXT_P(1);
2132 SysScanDesc extScan;
2139 Datum repl_val[Natts_pg_extension];
2140 bool repl_null[Natts_pg_extension];
2141 bool repl_repl[Natts_pg_extension];
2145 * We only allow this to be called from an extension's SQL script. We
2146 * shouldn't need any permissions check beyond that.
2148 if (!creating_extension)
2150 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2151 errmsg("pg_extension_config_dump() can only be called "
2152 "from an SQL script executed by CREATE EXTENSION")));
2155 * Check that the table exists and is a member of the extension being
2156 * created. This ensures that we don't need to register an additional
2157 * dependency to protect the extconfig entry.
2159 tablename = get_rel_name(tableoid);
2160 if (tablename == NULL)
2162 (errcode(ERRCODE_UNDEFINED_TABLE),
2163 errmsg("OID %u does not refer to a table", tableoid)));
2164 if (getExtensionOfObject(RelationRelationId, tableoid) !=
2165 CurrentExtensionObject)
2167 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2168 errmsg("table \"%s\" is not a member of the extension being created",
2172 * Add the table OID and WHERE condition to the extension's extconfig and
2173 * extcondition arrays.
2175 * If the table is already in extconfig, treat this as an update of the
2179 /* Find the pg_extension tuple */
2180 extRel = heap_open(ExtensionRelationId, RowExclusiveLock);
2182 ScanKeyInit(&key[0],
2183 ObjectIdAttributeNumber,
2184 BTEqualStrategyNumber, F_OIDEQ,
2185 ObjectIdGetDatum(CurrentExtensionObject));
2187 extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
2190 extTup = systable_getnext(extScan);
2192 if (!HeapTupleIsValid(extTup)) /* should not happen */
2193 elog(ERROR, "extension with oid %u does not exist",
2194 CurrentExtensionObject);
2196 memset(repl_val, 0, sizeof(repl_val));
2197 memset(repl_null, false, sizeof(repl_null));
2198 memset(repl_repl, false, sizeof(repl_repl));
2200 /* Build or modify the extconfig value */
2201 elementDatum = ObjectIdGetDatum(tableoid);
2203 arrayDatum = heap_getattr(extTup, Anum_pg_extension_extconfig,
2204 RelationGetDescr(extRel), &isnull);
2207 /* Previously empty extconfig, so build 1-element array */
2211 a = construct_array(&elementDatum, 1,
2213 sizeof(Oid), true, 'i');
2217 /* Modify or extend existing extconfig array */
2221 a = DatumGetArrayTypeP(arrayDatum);
2223 arrayLength = ARR_DIMS(a)[0];
2224 if (ARR_NDIM(a) != 1 ||
2225 ARR_LBOUND(a)[0] != 1 ||
2228 ARR_ELEMTYPE(a) != OIDOID)
2229 elog(ERROR, "extconfig is not a 1-D Oid array");
2230 arrayData = (Oid *) ARR_DATA_PTR(a);
2232 arrayIndex = arrayLength + 1; /* set up to add after end */
2234 for (i = 0; i < arrayLength; i++)
2236 if (arrayData[i] == tableoid)
2238 arrayIndex = i + 1; /* replace this element instead */
2243 a = array_set(a, 1, &arrayIndex,
2246 -1 /* varlena array */ ,
2247 sizeof(Oid) /* OID's typlen */ ,
2248 true /* OID's typbyval */ ,
2249 'i' /* OID's typalign */ );
2251 repl_val[Anum_pg_extension_extconfig - 1] = PointerGetDatum(a);
2252 repl_repl[Anum_pg_extension_extconfig - 1] = true;
2254 /* Build or modify the extcondition value */
2255 elementDatum = PointerGetDatum(wherecond);
2257 arrayDatum = heap_getattr(extTup, Anum_pg_extension_extcondition,
2258 RelationGetDescr(extRel), &isnull);
2261 if (arrayLength != 0)
2262 elog(ERROR, "extconfig and extcondition arrays do not match");
2264 a = construct_array(&elementDatum, 1,
2270 a = DatumGetArrayTypeP(arrayDatum);
2272 if (ARR_NDIM(a) != 1 ||
2273 ARR_LBOUND(a)[0] != 1 ||
2275 ARR_ELEMTYPE(a) != TEXTOID)
2276 elog(ERROR, "extcondition is not a 1-D text array");
2277 if (ARR_DIMS(a)[0] != arrayLength)
2278 elog(ERROR, "extconfig and extcondition arrays do not match");
2280 /* Add or replace at same index as in extconfig */
2281 a = array_set(a, 1, &arrayIndex,
2284 -1 /* varlena array */ ,
2285 -1 /* TEXT's typlen */ ,
2286 false /* TEXT's typbyval */ ,
2287 'i' /* TEXT's typalign */ );
2289 repl_val[Anum_pg_extension_extcondition - 1] = PointerGetDatum(a);
2290 repl_repl[Anum_pg_extension_extcondition - 1] = true;
2292 extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
2293 repl_val, repl_null, repl_repl);
2295 simple_heap_update(extRel, &extTup->t_self, extTup);
2296 CatalogUpdateIndexes(extRel, extTup);
2298 systable_endscan(extScan);
2300 heap_close(extRel, RowExclusiveLock);
2306 * extension_config_remove
2308 * Remove the specified table OID from extension's extconfig, if present.
2309 * This is not currently exposed as a function, but it could be;
2310 * for now, we just invoke it from ALTER EXTENSION DROP.
2313 extension_config_remove(Oid extensionoid, Oid tableoid)
2317 SysScanDesc extScan;
2323 Datum repl_val[Natts_pg_extension];
2324 bool repl_null[Natts_pg_extension];
2325 bool repl_repl[Natts_pg_extension];
2328 /* Find the pg_extension tuple */
2329 extRel = heap_open(ExtensionRelationId, RowExclusiveLock);
2331 ScanKeyInit(&key[0],
2332 ObjectIdAttributeNumber,
2333 BTEqualStrategyNumber, F_OIDEQ,
2334 ObjectIdGetDatum(extensionoid));
2336 extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
2339 extTup = systable_getnext(extScan);
2341 if (!HeapTupleIsValid(extTup)) /* should not happen */
2342 elog(ERROR, "extension with oid %u does not exist",
2345 /* Search extconfig for the tableoid */
2346 arrayDatum = heap_getattr(extTup, Anum_pg_extension_extconfig,
2347 RelationGetDescr(extRel), &isnull);
2360 a = DatumGetArrayTypeP(arrayDatum);
2362 arrayLength = ARR_DIMS(a)[0];
2363 if (ARR_NDIM(a) != 1 ||
2364 ARR_LBOUND(a)[0] != 1 ||
2367 ARR_ELEMTYPE(a) != OIDOID)
2368 elog(ERROR, "extconfig is not a 1-D Oid array");
2369 arrayData = (Oid *) ARR_DATA_PTR(a);
2371 arrayIndex = -1; /* flag for no deletion needed */
2373 for (i = 0; i < arrayLength; i++)
2375 if (arrayData[i] == tableoid)
2377 arrayIndex = i; /* index to remove */
2383 /* If tableoid is not in extconfig, nothing to do */
2386 systable_endscan(extScan);
2387 heap_close(extRel, RowExclusiveLock);
2391 /* Modify or delete the extconfig value */
2392 memset(repl_val, 0, sizeof(repl_val));
2393 memset(repl_null, false, sizeof(repl_null));
2394 memset(repl_repl, false, sizeof(repl_repl));
2396 if (arrayLength <= 1)
2398 /* removing only element, just set array to null */
2399 repl_null[Anum_pg_extension_extconfig - 1] = true;
2403 /* squeeze out the target element */
2409 deconstruct_array(a, OIDOID, sizeof(Oid), true, 'i',
2410 &dvalues, &dnulls, &nelems);
2412 /* We already checked there are no nulls, so ignore dnulls */
2413 for (i = arrayIndex; i < arrayLength - 1; i++)
2414 dvalues[i] = dvalues[i + 1];
2416 a = construct_array(dvalues, arrayLength - 1,
2417 OIDOID, sizeof(Oid), true, 'i');
2419 repl_val[Anum_pg_extension_extconfig - 1] = PointerGetDatum(a);
2421 repl_repl[Anum_pg_extension_extconfig - 1] = true;
2423 /* Modify or delete the extcondition value */
2424 arrayDatum = heap_getattr(extTup, Anum_pg_extension_extcondition,
2425 RelationGetDescr(extRel), &isnull);
2428 elog(ERROR, "extconfig and extcondition arrays do not match");
2432 a = DatumGetArrayTypeP(arrayDatum);
2434 if (ARR_NDIM(a) != 1 ||
2435 ARR_LBOUND(a)[0] != 1 ||
2437 ARR_ELEMTYPE(a) != TEXTOID)
2438 elog(ERROR, "extcondition is not a 1-D text array");
2439 if (ARR_DIMS(a)[0] != arrayLength)
2440 elog(ERROR, "extconfig and extcondition arrays do not match");
2443 if (arrayLength <= 1)
2445 /* removing only element, just set array to null */
2446 repl_null[Anum_pg_extension_extcondition - 1] = true;
2450 /* squeeze out the target element */
2456 deconstruct_array(a, TEXTOID, -1, false, 'i',
2457 &dvalues, &dnulls, &nelems);
2459 /* We already checked there are no nulls, so ignore dnulls */
2460 for (i = arrayIndex; i < arrayLength - 1; i++)
2461 dvalues[i] = dvalues[i + 1];
2463 a = construct_array(dvalues, arrayLength - 1,
2464 TEXTOID, -1, false, 'i');
2466 repl_val[Anum_pg_extension_extcondition - 1] = PointerGetDatum(a);
2468 repl_repl[Anum_pg_extension_extcondition - 1] = true;
2470 extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
2471 repl_val, repl_null, repl_repl);
2473 simple_heap_update(extRel, &extTup->t_self, extTup);
2474 CatalogUpdateIndexes(extRel, extTup);
2476 systable_endscan(extScan);
2478 heap_close(extRel, RowExclusiveLock);
2482 * Execute ALTER EXTENSION SET SCHEMA
2485 AlterExtensionNamespace(List *names, const char *newschema, Oid *oldschema)
2487 char *extensionName;
2490 Oid oldNspOid = InvalidOid;
2491 AclResult aclresult;
2494 SysScanDesc extScan;
2496 Form_pg_extension extForm;
2498 SysScanDesc depScan;
2500 ObjectAddresses *objsMoved;
2501 ObjectAddress extAddr;
2503 if (list_length(names) != 1)
2505 (errcode(ERRCODE_SYNTAX_ERROR),
2506 errmsg("extension name cannot be qualified")));
2507 extensionName = strVal(linitial(names));
2509 extensionOid = get_extension_oid(extensionName, false);
2511 nspOid = LookupCreationNamespace(newschema);
2514 * Permission check: must own extension. Note that we don't bother to
2515 * check ownership of the individual member objects ...
2517 if (!pg_extension_ownercheck(extensionOid, GetUserId()))
2518 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EXTENSION,
2521 /* Permission check: must have creation rights in target namespace */
2522 aclresult = pg_namespace_aclcheck(nspOid, GetUserId(), ACL_CREATE);
2523 if (aclresult != ACLCHECK_OK)
2524 aclcheck_error(aclresult, ACL_KIND_NAMESPACE, newschema);
2527 * If the schema is currently a member of the extension, disallow moving
2528 * the extension into the schema. That would create a dependency loop.
2530 if (getExtensionOfObject(NamespaceRelationId, nspOid) == extensionOid)
2532 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2533 errmsg("cannot move extension \"%s\" into schema \"%s\" "
2534 "because the extension contains the schema",
2535 extensionName, newschema)));
2537 /* Locate the pg_extension tuple */
2538 extRel = heap_open(ExtensionRelationId, RowExclusiveLock);
2540 ScanKeyInit(&key[0],
2541 ObjectIdAttributeNumber,
2542 BTEqualStrategyNumber, F_OIDEQ,
2543 ObjectIdGetDatum(extensionOid));
2545 extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
2548 extTup = systable_getnext(extScan);
2550 if (!HeapTupleIsValid(extTup)) /* should not happen */
2551 elog(ERROR, "extension with oid %u does not exist", extensionOid);
2553 /* Copy tuple so we can modify it below */
2554 extTup = heap_copytuple(extTup);
2555 extForm = (Form_pg_extension) GETSTRUCT(extTup);
2557 systable_endscan(extScan);
2560 * If the extension is already in the target schema, just silently do
2563 if (extForm->extnamespace == nspOid)
2565 heap_close(extRel, RowExclusiveLock);
2566 return InvalidObjectAddress;
2569 /* Check extension is supposed to be relocatable */
2570 if (!extForm->extrelocatable)
2572 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2573 errmsg("extension \"%s\" does not support SET SCHEMA",
2574 NameStr(extForm->extname))));
2576 objsMoved = new_object_addresses();
2579 * Scan pg_depend to find objects that depend directly on the extension,
2580 * and alter each one's schema.
2582 depRel = heap_open(DependRelationId, AccessShareLock);
2584 ScanKeyInit(&key[0],
2585 Anum_pg_depend_refclassid,
2586 BTEqualStrategyNumber, F_OIDEQ,
2587 ObjectIdGetDatum(ExtensionRelationId));
2588 ScanKeyInit(&key[1],
2589 Anum_pg_depend_refobjid,
2590 BTEqualStrategyNumber, F_OIDEQ,
2591 ObjectIdGetDatum(extensionOid));
2593 depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
2596 while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
2598 Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
2603 * Ignore non-membership dependencies. (Currently, the only other
2604 * case we could see here is a normal dependency from another
2607 if (pg_depend->deptype != DEPENDENCY_EXTENSION)
2610 dep.classId = pg_depend->classid;
2611 dep.objectId = pg_depend->objid;
2612 dep.objectSubId = pg_depend->objsubid;
2614 if (dep.objectSubId != 0) /* should not happen */
2615 elog(ERROR, "extension should not have a sub-object dependency");
2617 /* Relocate the object */
2618 dep_oldNspOid = AlterObjectNamespace_oid(dep.classId,
2624 * Remember previous namespace of first object that has one
2626 if (oldNspOid == InvalidOid && dep_oldNspOid != InvalidOid)
2627 oldNspOid = dep_oldNspOid;
2630 * If not all the objects had the same old namespace (ignoring any
2631 * that are not in namespaces), complain.
2633 if (dep_oldNspOid != InvalidOid && dep_oldNspOid != oldNspOid)
2635 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2636 errmsg("extension \"%s\" does not support SET SCHEMA",
2637 NameStr(extForm->extname)),
2638 errdetail("%s is not in the extension's schema \"%s\"",
2639 getObjectDescription(&dep),
2640 get_namespace_name(oldNspOid))));
2643 /* report old schema, if caller wants it */
2645 *oldschema = oldNspOid;
2647 systable_endscan(depScan);
2649 relation_close(depRel, AccessShareLock);
2651 /* Now adjust pg_extension.extnamespace */
2652 extForm->extnamespace = nspOid;
2654 simple_heap_update(extRel, &extTup->t_self, extTup);
2655 CatalogUpdateIndexes(extRel, extTup);
2657 heap_close(extRel, RowExclusiveLock);
2659 /* update dependencies to point to the new schema */
2660 changeDependencyFor(ExtensionRelationId, extensionOid,
2661 NamespaceRelationId, oldNspOid, nspOid);
2663 InvokeObjectPostAlterHook(ExtensionRelationId, extensionOid, 0);
2665 ObjectAddressSet(extAddr, ExtensionRelationId, extensionOid);
2671 * Execute ALTER EXTENSION UPDATE
2674 ExecAlterExtensionStmt(AlterExtensionStmt *stmt)
2676 DefElem *d_new_version = NULL;
2678 char *oldVersionName;
2679 ExtensionControlFile *control;
2683 SysScanDesc extScan;
2685 List *updateVersions;
2689 ObjectAddress address;
2692 * We use global variables to track the extension being created, so we can
2693 * create/update only one extension at the same time.
2695 if (creating_extension)
2697 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2698 errmsg("nested ALTER EXTENSION is not supported")));
2701 * Look up the extension --- it must already exist in pg_extension
2703 extRel = heap_open(ExtensionRelationId, AccessShareLock);
2705 ScanKeyInit(&key[0],
2706 Anum_pg_extension_extname,
2707 BTEqualStrategyNumber, F_NAMEEQ,
2708 CStringGetDatum(stmt->extname));
2710 extScan = systable_beginscan(extRel, ExtensionNameIndexId, true,
2713 extTup = systable_getnext(extScan);
2715 if (!HeapTupleIsValid(extTup))
2717 (errcode(ERRCODE_UNDEFINED_OBJECT),
2718 errmsg("extension \"%s\" does not exist",
2721 extensionOid = HeapTupleGetOid(extTup);
2724 * Determine the existing version we are updating from
2726 datum = heap_getattr(extTup, Anum_pg_extension_extversion,
2727 RelationGetDescr(extRel), &isnull);
2729 elog(ERROR, "extversion is null");
2730 oldVersionName = text_to_cstring(DatumGetTextPP(datum));
2732 systable_endscan(extScan);
2734 heap_close(extRel, AccessShareLock);
2736 /* Permission check: must own extension */
2737 if (!pg_extension_ownercheck(extensionOid, GetUserId()))
2738 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EXTENSION,
2742 * Read the primary control file. Note we assume that it does not contain
2743 * any non-ASCII data, so there is no need to worry about encoding at this
2746 control = read_extension_control_file(stmt->extname);
2749 * Read the statement option list
2751 foreach(lc, stmt->options)
2753 DefElem *defel = (DefElem *) lfirst(lc);
2755 if (strcmp(defel->defname, "new_version") == 0)
2759 (errcode(ERRCODE_SYNTAX_ERROR),
2760 errmsg("conflicting or redundant options")));
2761 d_new_version = defel;
2764 elog(ERROR, "unrecognized option: %s", defel->defname);
2768 * Determine the version to update to
2770 if (d_new_version && d_new_version->arg)
2771 versionName = strVal(d_new_version->arg);
2772 else if (control->default_version)
2773 versionName = control->default_version;
2777 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2778 errmsg("version to install must be specified")));
2779 versionName = NULL; /* keep compiler quiet */
2781 check_valid_version_name(versionName);
2784 * If we're already at that version, just say so
2786 if (strcmp(oldVersionName, versionName) == 0)
2789 (errmsg("version \"%s\" of extension \"%s\" is already installed",
2790 versionName, stmt->extname)));
2791 return InvalidObjectAddress;
2795 * Identify the series of update script files we need to execute
2797 updateVersions = identify_update_path(control,
2802 * Update the pg_extension row and execute the update scripts, one at a
2805 ApplyExtensionUpdates(extensionOid, control,
2806 oldVersionName, updateVersions);
2808 ObjectAddressSet(address, ExtensionRelationId, extensionOid);
2814 * Apply a series of update scripts as though individual ALTER EXTENSION
2815 * UPDATE commands had been given, including altering the pg_extension row
2816 * and dependencies each time.
2818 * This might be more work than necessary, but it ensures that old update
2819 * scripts don't break if newer versions have different control parameters.
2822 ApplyExtensionUpdates(Oid extensionOid,
2823 ExtensionControlFile *pcontrol,
2824 const char *initialVersion,
2825 List *updateVersions)
2827 const char *oldVersionName = initialVersion;
2830 foreach(lcv, updateVersions)
2832 char *versionName = (char *) lfirst(lcv);
2833 ExtensionControlFile *control;
2836 List *requiredExtensions;
2837 List *requiredSchemas;
2840 SysScanDesc extScan;
2842 Form_pg_extension extForm;
2843 Datum values[Natts_pg_extension];
2844 bool nulls[Natts_pg_extension];
2845 bool repl[Natts_pg_extension];
2846 ObjectAddress myself;
2850 * Fetch parameters for specific version (pcontrol is not changed)
2852 control = read_extension_aux_control_file(pcontrol, versionName);
2854 /* Find the pg_extension tuple */
2855 extRel = heap_open(ExtensionRelationId, RowExclusiveLock);
2857 ScanKeyInit(&key[0],
2858 ObjectIdAttributeNumber,
2859 BTEqualStrategyNumber, F_OIDEQ,
2860 ObjectIdGetDatum(extensionOid));
2862 extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
2865 extTup = systable_getnext(extScan);
2867 if (!HeapTupleIsValid(extTup)) /* should not happen */
2868 elog(ERROR, "extension with oid %u does not exist",
2871 extForm = (Form_pg_extension) GETSTRUCT(extTup);
2874 * Determine the target schema (set by original install)
2876 schemaOid = extForm->extnamespace;
2877 schemaName = get_namespace_name(schemaOid);
2880 * Modify extrelocatable and extversion in the pg_extension tuple
2882 memset(values, 0, sizeof(values));
2883 memset(nulls, 0, sizeof(nulls));
2884 memset(repl, 0, sizeof(repl));
2886 values[Anum_pg_extension_extrelocatable - 1] =
2887 BoolGetDatum(control->relocatable);
2888 repl[Anum_pg_extension_extrelocatable - 1] = true;
2889 values[Anum_pg_extension_extversion - 1] =
2890 CStringGetTextDatum(versionName);
2891 repl[Anum_pg_extension_extversion - 1] = true;
2893 extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
2894 values, nulls, repl);
2896 simple_heap_update(extRel, &extTup->t_self, extTup);
2897 CatalogUpdateIndexes(extRel, extTup);
2899 systable_endscan(extScan);
2901 heap_close(extRel, RowExclusiveLock);
2904 * Look up the prerequisite extensions for this version, and build
2905 * lists of their OIDs and the OIDs of their target schemas.
2907 requiredExtensions = NIL;
2908 requiredSchemas = NIL;
2909 foreach(lc, control->requires)
2911 char *curreq = (char *) lfirst(lc);
2916 * We intentionally don't use get_extension_oid's default error
2917 * message here, because it would be confusing in this context.
2919 reqext = get_extension_oid(curreq, true);
2920 if (!OidIsValid(reqext))
2922 (errcode(ERRCODE_UNDEFINED_OBJECT),
2923 errmsg("required extension \"%s\" is not installed",
2925 reqschema = get_extension_schema(reqext);
2926 requiredExtensions = lappend_oid(requiredExtensions, reqext);
2927 requiredSchemas = lappend_oid(requiredSchemas, reqschema);
2931 * Remove and recreate dependencies on prerequisite extensions
2933 deleteDependencyRecordsForClass(ExtensionRelationId, extensionOid,
2934 ExtensionRelationId,
2937 myself.classId = ExtensionRelationId;
2938 myself.objectId = extensionOid;
2939 myself.objectSubId = 0;
2941 foreach(lc, requiredExtensions)
2943 Oid reqext = lfirst_oid(lc);
2944 ObjectAddress otherext;
2946 otherext.classId = ExtensionRelationId;
2947 otherext.objectId = reqext;
2948 otherext.objectSubId = 0;
2950 recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
2953 InvokeObjectPostAlterHook(ExtensionRelationId, extensionOid, 0);
2956 * Finally, execute the update script file
2958 execute_extension_script(extensionOid, control,
2959 oldVersionName, versionName,
2961 schemaName, schemaOid);
2964 * Update prior-version name and loop around. Since
2965 * execute_sql_string did a final CommandCounterIncrement, we can
2966 * update the pg_extension row again.
2968 oldVersionName = versionName;
2973 * Execute ALTER EXTENSION ADD/DROP
2975 * Return value is the address of the altered extension.
2977 * objAddr is an output argument which, if not NULL, is set to the address of
2978 * the added/dropped object.
2981 ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt,
2982 ObjectAddress *objAddr)
2984 ObjectAddress extension;
2985 ObjectAddress object;
2989 extension.classId = ExtensionRelationId;
2990 extension.objectId = get_extension_oid(stmt->extname, false);
2991 extension.objectSubId = 0;
2993 /* Permission check: must own extension */
2994 if (!pg_extension_ownercheck(extension.objectId, GetUserId()))
2995 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EXTENSION,
2999 * Translate the parser representation that identifies the object into an
3000 * ObjectAddress. get_object_address() will throw an error if the object
3001 * does not exist, and will also acquire a lock on the object to guard
3002 * against concurrent DROP and ALTER EXTENSION ADD/DROP operations.
3004 object = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
3005 &relation, ShareUpdateExclusiveLock, false);
3007 Assert(object.objectSubId == 0);
3011 /* Permission check: must own target object, too */
3012 check_object_ownership(GetUserId(), stmt->objtype, object,
3013 stmt->objname, stmt->objargs, relation);
3016 * Check existing extension membership.
3018 oldExtension = getExtensionOfObject(object.classId, object.objectId);
3020 if (stmt->action > 0)
3023 * ADD, so complain if object is already attached to some extension.
3025 if (OidIsValid(oldExtension))
3027 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3028 errmsg("%s is already a member of extension \"%s\"",
3029 getObjectDescription(&object),
3030 get_extension_name(oldExtension))));
3033 * Prevent a schema from being added to an extension if the schema
3034 * contains the extension. That would create a dependency loop.
3036 if (object.classId == NamespaceRelationId &&
3037 object.objectId == get_extension_schema(extension.objectId))
3039 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3040 errmsg("cannot add schema \"%s\" to extension \"%s\" "
3041 "because the schema contains the extension",
3042 get_namespace_name(object.objectId),
3046 * OK, add the dependency.
3048 recordDependencyOn(&object, &extension, DEPENDENCY_EXTENSION);
3053 * DROP, so complain if it's not a member.
3055 if (oldExtension != extension.objectId)
3057 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3058 errmsg("%s is not a member of extension \"%s\"",
3059 getObjectDescription(&object),
3063 * OK, drop the dependency.
3065 if (deleteDependencyRecordsForClass(object.classId, object.objectId,
3066 ExtensionRelationId,
3067 DEPENDENCY_EXTENSION) != 1)
3068 elog(ERROR, "unexpected number of extension dependency records");
3071 * If it's a relation, it might have an entry in the extension's
3072 * extconfig array, which we must remove.
3074 if (object.classId == RelationRelationId)
3075 extension_config_remove(extension.objectId, object.objectId);
3078 InvokeObjectPostAlterHook(ExtensionRelationId, extension.objectId, 0);
3081 * If get_object_address() opened the relation for us, we close it to keep
3082 * the reference count correct - but we retain any locks acquired by
3083 * get_object_address() until commit time, to guard against concurrent
3086 if (relation != NULL)
3087 relation_close(relation, NoLock);
3093 * Read the whole of file into memory.
3095 * The file contents are returned as a single palloc'd chunk. For convenience
3096 * of the callers, an extra \0 byte is added to the end.
3099 read_whole_file(const char *filename, int *length)
3103 size_t bytes_to_read;
3106 if (stat(filename, &fst) < 0)
3108 (errcode_for_file_access(),
3109 errmsg("could not stat file \"%s\": %m", filename)));
3111 if (fst.st_size > (MaxAllocSize - 1))
3113 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3114 errmsg("file \"%s\" is too large", filename)));
3115 bytes_to_read = (size_t) fst.st_size;
3117 if ((file = AllocateFile(filename, PG_BINARY_R)) == NULL)
3119 (errcode_for_file_access(),
3120 errmsg("could not open file \"%s\" for reading: %m",
3123 buf = (char *) palloc(bytes_to_read + 1);
3125 *length = fread(buf, 1, bytes_to_read, file);
3129 (errcode_for_file_access(),
3130 errmsg("could not read file \"%s\": %m", filename)));
3134 buf[*length] = '\0';