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-2011, PostgreSQL Global Development Group
16 * Portions Copyright (c) 1994, Regents of the University of California
20 * src/backend/commands/extension.c
22 *-------------------------------------------------------------------------
30 #include "access/sysattr.h"
31 #include "access/xact.h"
32 #include "catalog/dependency.h"
33 #include "catalog/indexing.h"
34 #include "catalog/namespace.h"
35 #include "catalog/objectaccess.h"
36 #include "catalog/pg_depend.h"
37 #include "catalog/pg_extension.h"
38 #include "catalog/pg_namespace.h"
39 #include "catalog/pg_type.h"
40 #include "commands/alter.h"
41 #include "commands/comment.h"
42 #include "commands/extension.h"
43 #include "commands/trigger.h"
44 #include "executor/executor.h"
46 #include "mb/pg_wchar.h"
47 #include "miscadmin.h"
48 #include "tcop/tcopprot.h"
49 #include "tcop/utility.h"
50 #include "utils/builtins.h"
51 #include "utils/fmgroids.h"
52 #include "utils/guc.h"
53 #include "utils/lsyscache.h"
54 #include "utils/snapmgr.h"
55 #include "utils/tqual.h"
58 /* Globally visible state variables */
59 bool creating_extension = false;
60 Oid CurrentExtensionObject = InvalidOid;
63 * Internal data structure to hold the results of parsing a control file
65 typedef struct ExtensionControlFile
67 char *name; /* name of the extension */
68 char *directory; /* directory for script files */
69 char *default_version; /* default install target version, if any */
70 char *module_pathname; /* string to substitute for MODULE_PATHNAME */
71 char *comment; /* comment, if any */
72 char *schema; /* target schema (allowed if !relocatable) */
73 bool relocatable; /* is ALTER EXTENSION SET SCHEMA supported? */
74 bool superuser; /* must be superuser to install? */
75 int encoding; /* encoding of the script file, or -1 */
76 List *requires; /* names of prerequisite extensions */
77 } ExtensionControlFile;
80 * Internal data structure for update path information
82 typedef struct ExtensionVersionInfo
84 char *name; /* name of the starting version */
85 List *reachable; /* List of ExtensionVersionInfo's */
86 bool installable; /* does this version have an install script? */
87 /* working state for Dijkstra's algorithm: */
88 bool distance_known; /* is distance from start known yet? */
89 int distance; /* current worst-case distance estimate */
90 struct ExtensionVersionInfo *previous; /* current best predecessor */
91 } ExtensionVersionInfo;
94 static List *find_update_path(List *evi_list,
95 ExtensionVersionInfo *evi_start,
96 ExtensionVersionInfo *evi_target,
98 static void get_available_versions_for_extension(ExtensionControlFile *pcontrol,
99 Tuplestorestate *tupstore,
101 static void ApplyExtensionUpdates(Oid extensionOid,
102 ExtensionControlFile *pcontrol,
103 const char *initialVersion,
104 List *updateVersions);
108 * get_extension_oid - given an extension name, look up the OID
110 * If missing_ok is false, throw an error if extension name not found. If
111 * true, just return InvalidOid.
114 get_extension_oid(const char *extname, bool missing_ok)
118 SysScanDesc scandesc;
120 ScanKeyData entry[1];
122 rel = heap_open(ExtensionRelationId, AccessShareLock);
124 ScanKeyInit(&entry[0],
125 Anum_pg_extension_extname,
126 BTEqualStrategyNumber, F_NAMEEQ,
127 CStringGetDatum(extname));
129 scandesc = systable_beginscan(rel, ExtensionNameIndexId, true,
130 SnapshotNow, 1, entry);
132 tuple = systable_getnext(scandesc);
134 /* We assume that there can be at most one matching tuple */
135 if (HeapTupleIsValid(tuple))
136 result = HeapTupleGetOid(tuple);
140 systable_endscan(scandesc);
142 heap_close(rel, AccessShareLock);
144 if (!OidIsValid(result) && !missing_ok)
146 (errcode(ERRCODE_UNDEFINED_OBJECT),
147 errmsg("extension \"%s\" does not exist",
154 * get_extension_name - given an extension OID, look up the name
156 * Returns a palloc'd string, or NULL if no such extension.
159 get_extension_name(Oid ext_oid)
163 SysScanDesc scandesc;
165 ScanKeyData entry[1];
167 rel = heap_open(ExtensionRelationId, AccessShareLock);
169 ScanKeyInit(&entry[0],
170 ObjectIdAttributeNumber,
171 BTEqualStrategyNumber, F_OIDEQ,
172 ObjectIdGetDatum(ext_oid));
174 scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
175 SnapshotNow, 1, entry);
177 tuple = systable_getnext(scandesc);
179 /* We assume that there can be at most one matching tuple */
180 if (HeapTupleIsValid(tuple))
181 result = pstrdup(NameStr(((Form_pg_extension) GETSTRUCT(tuple))->extname));
185 systable_endscan(scandesc);
187 heap_close(rel, AccessShareLock);
193 * get_extension_schema - given an extension OID, fetch its extnamespace
195 * Returns InvalidOid if no such extension.
198 get_extension_schema(Oid ext_oid)
202 SysScanDesc scandesc;
204 ScanKeyData entry[1];
206 rel = heap_open(ExtensionRelationId, AccessShareLock);
208 ScanKeyInit(&entry[0],
209 ObjectIdAttributeNumber,
210 BTEqualStrategyNumber, F_OIDEQ,
211 ObjectIdGetDatum(ext_oid));
213 scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
214 SnapshotNow, 1, entry);
216 tuple = systable_getnext(scandesc);
218 /* We assume that there can be at most one matching tuple */
219 if (HeapTupleIsValid(tuple))
220 result = ((Form_pg_extension) GETSTRUCT(tuple))->extnamespace;
224 systable_endscan(scandesc);
226 heap_close(rel, AccessShareLock);
232 * Utility functions to check validity of extension and version names
235 check_valid_extension_name(const char *extensionname)
237 int namelen = strlen(extensionname);
240 * Disallow empty names (the parser rejects empty identifiers anyway, but
245 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
246 errmsg("invalid extension name: \"%s\"", extensionname),
247 errdetail("Extension names must not be empty.")));
250 * No double dashes, since that would make script filenames ambiguous.
252 if (strstr(extensionname, "--"))
254 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
255 errmsg("invalid extension name: \"%s\"", extensionname),
256 errdetail("Extension names must not contain \"--\".")));
259 * No leading or trailing dash either. (We could probably allow this, but
260 * it would require much care in filename parsing and would make filenames
261 * visually if not formally ambiguous. Since there's no real-world use
262 * case, let's just forbid it.)
264 if (extensionname[0] == '-' || extensionname[namelen - 1] == '-')
266 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
267 errmsg("invalid extension name: \"%s\"", extensionname),
268 errdetail("Extension names must not begin or end with \"-\".")));
271 * No directory separators either (this is sufficient to prevent ".."
274 if (first_dir_separator(extensionname) != NULL)
276 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
277 errmsg("invalid extension name: \"%s\"", extensionname),
278 errdetail("Extension names must not contain directory separator characters.")));
282 check_valid_version_name(const char *versionname)
284 int namelen = strlen(versionname);
287 * Disallow empty names (we could possibly allow this, but there seems
292 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
293 errmsg("invalid extension version name: \"%s\"", versionname),
294 errdetail("Version names must not be empty.")));
297 * No double dashes, since that would make script filenames ambiguous.
299 if (strstr(versionname, "--"))
301 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
302 errmsg("invalid extension version name: \"%s\"", versionname),
303 errdetail("Version names must not contain \"--\".")));
306 * No leading or trailing dash either.
308 if (versionname[0] == '-' || versionname[namelen - 1] == '-')
310 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
311 errmsg("invalid extension version name: \"%s\"", versionname),
312 errdetail("Version names must not begin or end with \"-\".")));
315 * No directory separators either (this is sufficient to prevent ".."
318 if (first_dir_separator(versionname) != NULL)
320 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
321 errmsg("invalid extension version name: \"%s\"", versionname),
322 errdetail("Version names must not contain directory separator characters.")));
326 * Utility functions to handle extension-related path names
329 is_extension_control_filename(const char *filename)
331 const char *extension = strrchr(filename, '.');
333 return (extension != NULL) && (strcmp(extension, ".control") == 0);
337 is_extension_script_filename(const char *filename)
339 const char *extension = strrchr(filename, '.');
341 return (extension != NULL) && (strcmp(extension, ".sql") == 0);
345 get_extension_control_directory(void)
347 char sharepath[MAXPGPATH];
350 get_share_path(my_exec_path, sharepath);
351 result = (char *) palloc(MAXPGPATH);
352 snprintf(result, MAXPGPATH, "%s/extension", sharepath);
358 get_extension_control_filename(const char *extname)
360 char sharepath[MAXPGPATH];
363 get_share_path(my_exec_path, sharepath);
364 result = (char *) palloc(MAXPGPATH);
365 snprintf(result, MAXPGPATH, "%s/extension/%s.control",
372 get_extension_script_directory(ExtensionControlFile *control)
374 char sharepath[MAXPGPATH];
378 * The directory parameter can be omitted, absolute, or relative to the
379 * installation's share directory.
381 if (!control->directory)
382 return get_extension_control_directory();
384 if (is_absolute_path(control->directory))
385 return pstrdup(control->directory);
387 get_share_path(my_exec_path, sharepath);
388 result = (char *) palloc(MAXPGPATH);
389 snprintf(result, MAXPGPATH, "%s/%s", sharepath, control->directory);
395 get_extension_aux_control_filename(ExtensionControlFile *control,
401 scriptdir = get_extension_script_directory(control);
403 result = (char *) palloc(MAXPGPATH);
404 snprintf(result, MAXPGPATH, "%s/%s--%s.control",
405 scriptdir, control->name, version);
413 get_extension_script_filename(ExtensionControlFile *control,
414 const char *from_version, const char *version)
419 scriptdir = get_extension_script_directory(control);
421 result = (char *) palloc(MAXPGPATH);
423 snprintf(result, MAXPGPATH, "%s/%s--%s--%s.sql",
424 scriptdir, control->name, from_version, version);
426 snprintf(result, MAXPGPATH, "%s/%s--%s.sql",
427 scriptdir, control->name, version);
436 * Parse contents of primary or auxiliary control file, and fill in
437 * fields of *control. We parse primary file if version == NULL,
438 * else the optional auxiliary file for that version.
440 * Control files are supposed to be very short, half a dozen lines,
441 * so we don't worry about memory allocation risks here. Also we don't
442 * worry about what encoding it's in; all values are expected to be ASCII.
445 parse_extension_control_file(ExtensionControlFile *control,
450 ConfigVariable *item,
455 * Locate the file to read. Auxiliary files are optional.
458 filename = get_extension_aux_control_filename(control, version);
460 filename = get_extension_control_filename(control->name);
462 if ((file = AllocateFile(filename, "r")) == NULL)
464 if (version && errno == ENOENT)
466 /* no auxiliary file for this version */
471 (errcode_for_file_access(),
472 errmsg("could not open extension control file \"%s\": %m",
477 * Parse the file content, using GUC's file parsing code
479 ParseConfigFp(file, filename, 0, ERROR, &head, &tail);
484 * Convert the ConfigVariable list into ExtensionControlFile entries.
486 for (item = head; item != NULL; item = item->next)
488 if (strcmp(item->name, "directory") == 0)
492 (errcode(ERRCODE_SYNTAX_ERROR),
493 errmsg("parameter \"%s\" cannot be set in a secondary extension control file",
496 control->directory = pstrdup(item->value);
498 else if (strcmp(item->name, "default_version") == 0)
502 (errcode(ERRCODE_SYNTAX_ERROR),
503 errmsg("parameter \"%s\" cannot be set in a secondary extension control file",
506 control->default_version = pstrdup(item->value);
508 else if (strcmp(item->name, "module_pathname") == 0)
510 control->module_pathname = pstrdup(item->value);
512 else if (strcmp(item->name, "comment") == 0)
514 control->comment = pstrdup(item->value);
516 else if (strcmp(item->name, "schema") == 0)
518 control->schema = pstrdup(item->value);
520 else if (strcmp(item->name, "relocatable") == 0)
522 if (!parse_bool(item->value, &control->relocatable))
524 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
525 errmsg("parameter \"%s\" requires a Boolean value",
528 else if (strcmp(item->name, "superuser") == 0)
530 if (!parse_bool(item->value, &control->superuser))
532 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
533 errmsg("parameter \"%s\" requires a Boolean value",
536 else if (strcmp(item->name, "encoding") == 0)
538 control->encoding = pg_valid_server_encoding(item->value);
539 if (control->encoding < 0)
541 (errcode(ERRCODE_UNDEFINED_OBJECT),
542 errmsg("\"%s\" is not a valid encoding name",
545 else if (strcmp(item->name, "requires") == 0)
547 /* Need a modifiable copy of string */
548 char *rawnames = pstrdup(item->value);
550 /* Parse string into list of identifiers */
551 if (!SplitIdentifierString(rawnames, ',', &control->requires))
553 /* syntax error in name list */
555 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
556 errmsg("parameter \"%s\" must be a list of extension names",
562 (errcode(ERRCODE_SYNTAX_ERROR),
563 errmsg("unrecognized parameter \"%s\" in file \"%s\"",
564 item->name, filename)));
567 FreeConfigVariables(head);
569 if (control->relocatable && control->schema != NULL)
571 (errcode(ERRCODE_SYNTAX_ERROR),
572 errmsg("parameter \"schema\" cannot be specified when \"relocatable\" is true")));
578 * Read the primary control file for the specified extension.
580 static ExtensionControlFile *
581 read_extension_control_file(const char *extname)
583 ExtensionControlFile *control;
586 * Set up default values. Pointer fields are initially null.
588 control = (ExtensionControlFile *) palloc0(sizeof(ExtensionControlFile));
589 control->name = pstrdup(extname);
590 control->relocatable = false;
591 control->superuser = true;
592 control->encoding = -1;
595 * Parse the primary control file.
597 parse_extension_control_file(control, NULL);
603 * Read the auxiliary control file for the specified extension and version.
605 * Returns a new modified ExtensionControlFile struct; the original struct
606 * (reflecting just the primary control file) is not modified.
608 static ExtensionControlFile *
609 read_extension_aux_control_file(const ExtensionControlFile *pcontrol,
612 ExtensionControlFile *acontrol;
615 * Flat-copy the struct. Pointer fields share values with original.
617 acontrol = (ExtensionControlFile *) palloc(sizeof(ExtensionControlFile));
618 memcpy(acontrol, pcontrol, sizeof(ExtensionControlFile));
621 * Parse the auxiliary control file, overwriting struct fields
623 parse_extension_control_file(acontrol, version);
629 * Read an SQL script file into a string, and convert to database encoding
632 read_extension_script_file(const ExtensionControlFile *control,
633 const char *filename)
636 int dest_encoding = GetDatabaseEncoding();
642 content = read_binary_file(filename, 0, -1);
644 /* use database encoding if not given */
645 if (control->encoding < 0)
646 src_encoding = dest_encoding;
648 src_encoding = control->encoding;
650 /* make sure that source string is valid in the expected encoding */
651 len = VARSIZE_ANY_EXHDR(content);
652 src_str = VARDATA_ANY(content);
653 pg_verify_mbstr_len(src_encoding, src_str, len, false);
655 /* convert the encoding to the database encoding */
656 dest_str = (char *) pg_do_encoding_conversion((unsigned char *) src_str,
661 /* if no conversion happened, we have to arrange for null termination */
662 if (dest_str == src_str)
664 dest_str = (char *) palloc(len + 1);
665 memcpy(dest_str, src_str, len);
666 dest_str[len] = '\0';
673 * Execute given SQL string.
675 * filename is used only to report errors.
677 * Note: it's tempting to just use SPI to execute the string, but that does
678 * not work very well. The really serious problem is that SPI will parse,
679 * analyze, and plan the whole string before executing any of it; of course
680 * this fails if there are any plannable statements referring to objects
681 * created earlier in the script. A lesser annoyance is that SPI insists
682 * on printing the whole string as errcontext in case of any error, and that
683 * could be very long.
686 execute_sql_string(const char *sql, const char *filename)
688 List *raw_parsetree_list;
693 * Parse the SQL string into a list of raw parse trees.
695 raw_parsetree_list = pg_parse_query(sql);
697 /* All output from SELECTs goes to the bit bucket */
698 dest = CreateDestReceiver(DestNone);
701 * Do parse analysis, rule rewrite, planning, and execution for each raw
702 * parsetree. We must fully execute each query before beginning parse
703 * analysis on the next one, since there may be interdependencies.
705 foreach(lc1, raw_parsetree_list)
707 Node *parsetree = (Node *) lfirst(lc1);
711 stmt_list = pg_analyze_and_rewrite(parsetree,
715 stmt_list = pg_plan_queries(stmt_list, 0, NULL);
717 foreach(lc2, stmt_list)
719 Node *stmt = (Node *) lfirst(lc2);
721 if (IsA(stmt, TransactionStmt))
723 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
724 errmsg("transaction control statements are not allowed within an extension script")));
726 CommandCounterIncrement();
728 PushActiveSnapshot(GetTransactionSnapshot());
730 if (IsA(stmt, PlannedStmt) &&
731 ((PlannedStmt *) stmt)->utilityStmt == NULL)
735 qdesc = CreateQueryDesc((PlannedStmt *) stmt,
737 GetActiveSnapshot(), NULL,
740 ExecutorStart(qdesc, 0);
741 ExecutorRun(qdesc, ForwardScanDirection, 0);
742 ExecutorFinish(qdesc);
745 FreeQueryDesc(qdesc);
752 false, /* not top level */
761 /* Be sure to advance the command counter after the last script command */
762 CommandCounterIncrement();
766 * Execute the appropriate script file for installing or updating the extension
768 * If from_version isn't NULL, it's an update
771 execute_extension_script(Oid extensionOid, ExtensionControlFile *control,
772 const char *from_version,
774 List *requiredSchemas,
775 const char *schemaName, Oid schemaOid)
778 char *save_client_min_messages,
779 *save_log_min_messages,
781 StringInfoData pathbuf;
785 * Enforce superuser-ness if appropriate. We postpone this check until
786 * here so that the flag is correctly associated with the right script(s)
787 * if it's set in secondary control files.
789 if (control->superuser && !superuser())
791 if (from_version == NULL)
793 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
794 errmsg("permission denied to create extension \"%s\"",
796 errhint("Must be superuser to create this extension.")));
799 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
800 errmsg("permission denied to update extension \"%s\"",
802 errhint("Must be superuser to update this extension.")));
805 filename = get_extension_script_filename(control, from_version, version);
808 * Force client_min_messages and log_min_messages to be at least WARNING,
809 * so that we won't spam the user with useless NOTICE messages from common
810 * script actions like creating shell types.
812 * We use the equivalent of SET LOCAL to ensure the setting is undone upon
815 save_client_min_messages =
816 pstrdup(GetConfigOption("client_min_messages", false));
817 if (client_min_messages < WARNING)
818 (void) set_config_option("client_min_messages", "warning",
819 PGC_USERSET, PGC_S_SESSION,
820 GUC_ACTION_LOCAL, true);
822 save_log_min_messages =
823 pstrdup(GetConfigOption("log_min_messages", false));
824 if (log_min_messages < WARNING)
825 (void) set_config_option("log_min_messages", "warning",
826 PGC_SUSET, PGC_S_SESSION,
827 GUC_ACTION_LOCAL, true);
830 * Set up the search path to contain the target schema, then the schemas
831 * of any prerequisite extensions, and nothing else. In particular this
832 * makes the target schema be the default creation target namespace.
834 * Note: it might look tempting to use PushOverrideSearchPath for this,
835 * but we cannot do that. We have to actually set the search_path GUC in
836 * case the extension script examines or changes it.
838 save_search_path = pstrdup(GetConfigOption("search_path", false));
840 initStringInfo(&pathbuf);
841 appendStringInfoString(&pathbuf, quote_identifier(schemaName));
842 foreach(lc, requiredSchemas)
844 Oid reqschema = lfirst_oid(lc);
845 char *reqname = get_namespace_name(reqschema);
848 appendStringInfo(&pathbuf, ", %s", quote_identifier(reqname));
851 (void) set_config_option("search_path", pathbuf.data,
852 PGC_USERSET, PGC_S_SESSION,
853 GUC_ACTION_LOCAL, true);
856 * Set creating_extension and related variables so that
857 * recordDependencyOnCurrentExtension and other functions do the right
858 * things. On failure, ensure we reset these variables.
860 creating_extension = true;
861 CurrentExtensionObject = extensionOid;
864 char *sql = read_extension_script_file(control, filename);
867 * If it's not relocatable, substitute the target schema name for
868 * occcurrences of @extschema@.
870 * For a relocatable extension, we just run the script as-is. There
871 * cannot be any need for @extschema@, else it wouldn't be
874 if (!control->relocatable)
876 const char *qSchemaName = quote_identifier(schemaName);
878 sql = text_to_cstring(
880 DirectFunctionCall3(replace_text,
881 CStringGetTextDatum(sql),
882 CStringGetTextDatum("@extschema@"),
883 CStringGetTextDatum(qSchemaName))));
887 * If module_pathname was set in the control file, substitute its
888 * value for occurrences of MODULE_PATHNAME.
890 if (control->module_pathname)
892 sql = text_to_cstring(
894 DirectFunctionCall3(replace_text,
895 CStringGetTextDatum(sql),
896 CStringGetTextDatum("MODULE_PATHNAME"),
897 CStringGetTextDatum(control->module_pathname))));
900 execute_sql_string(sql, filename);
904 creating_extension = false;
905 CurrentExtensionObject = InvalidOid;
910 creating_extension = false;
911 CurrentExtensionObject = InvalidOid;
914 * Restore GUC variables for the remainder of the current transaction.
915 * Again use SET LOCAL, so we won't affect the session value.
917 (void) set_config_option("search_path", save_search_path,
918 PGC_USERSET, PGC_S_SESSION,
919 GUC_ACTION_LOCAL, true);
920 (void) set_config_option("client_min_messages", save_client_min_messages,
921 PGC_USERSET, PGC_S_SESSION,
922 GUC_ACTION_LOCAL, true);
923 (void) set_config_option("log_min_messages", save_log_min_messages,
924 PGC_SUSET, PGC_S_SESSION,
925 GUC_ACTION_LOCAL, true);
929 * Find or create an ExtensionVersionInfo for the specified version name
931 * Currently, we just use a List of the ExtensionVersionInfo's. Searching
932 * for them therefore uses about O(N^2) time when there are N versions of
933 * the extension. We could change the data structure to a hash table if
934 * this ever becomes a bottleneck.
936 static ExtensionVersionInfo *
937 get_ext_ver_info(const char *versionname, List **evi_list)
939 ExtensionVersionInfo *evi;
942 foreach(lc, *evi_list)
944 evi = (ExtensionVersionInfo *) lfirst(lc);
945 if (strcmp(evi->name, versionname) == 0)
949 evi = (ExtensionVersionInfo *) palloc(sizeof(ExtensionVersionInfo));
950 evi->name = pstrdup(versionname);
951 evi->reachable = NIL;
952 evi->installable = false;
953 /* initialize for later application of Dijkstra's algorithm */
954 evi->distance_known = false;
955 evi->distance = INT_MAX;
956 evi->previous = NULL;
958 *evi_list = lappend(*evi_list, evi);
964 * Locate the nearest unprocessed ExtensionVersionInfo
966 * This part of the algorithm is also about O(N^2). A priority queue would
967 * make it much faster, but for now there's no need.
969 static ExtensionVersionInfo *
970 get_nearest_unprocessed_vertex(List *evi_list)
972 ExtensionVersionInfo *evi = NULL;
975 foreach(lc, evi_list)
977 ExtensionVersionInfo *evi2 = (ExtensionVersionInfo *) lfirst(lc);
979 /* only vertices whose distance is still uncertain are candidates */
980 if (evi2->distance_known)
982 /* remember the closest such vertex */
984 evi->distance > evi2->distance)
992 * Obtain information about the set of update scripts available for the
993 * specified extension. The result is a List of ExtensionVersionInfo
994 * structs, each with a subsidiary list of the ExtensionVersionInfos for
995 * the versions that can be reached in one step from that version.
998 get_ext_ver_list(ExtensionControlFile *control)
1000 List *evi_list = NIL;
1001 int extnamelen = strlen(control->name);
1006 location = get_extension_script_directory(control);
1007 dir = AllocateDir(location);
1008 while ((de = ReadDir(dir, location)) != NULL)
1012 ExtensionVersionInfo *evi;
1013 ExtensionVersionInfo *evi2;
1015 /* must be a .sql file ... */
1016 if (!is_extension_script_filename(de->d_name))
1019 /* ... matching extension name followed by separator */
1020 if (strncmp(de->d_name, control->name, extnamelen) != 0 ||
1021 de->d_name[extnamelen] != '-' ||
1022 de->d_name[extnamelen + 1] != '-')
1025 /* extract version name(s) from 'extname--something.sql' filename */
1026 vername = pstrdup(de->d_name + extnamelen + 2);
1027 *strrchr(vername, '.') = '\0';
1028 vername2 = strstr(vername, "--");
1031 /* It's an install, not update, script; record its version name */
1032 evi = get_ext_ver_info(vername, &evi_list);
1033 evi->installable = true;
1036 *vername2 = '\0'; /* terminate first version */
1037 vername2 += 2; /* and point to second */
1039 /* if there's a third --, it's bogus, ignore it */
1040 if (strstr(vername2, "--"))
1043 /* Create ExtensionVersionInfos and link them together */
1044 evi = get_ext_ver_info(vername, &evi_list);
1045 evi2 = get_ext_ver_info(vername2, &evi_list);
1046 evi->reachable = lappend(evi->reachable, evi2);
1054 * Given an initial and final version name, identify the sequence of update
1055 * scripts that have to be applied to perform that update.
1057 * Result is a List of names of versions to transition through (the initial
1058 * version is *not* included).
1061 identify_update_path(ExtensionControlFile *control,
1062 const char *oldVersion, const char *newVersion)
1066 ExtensionVersionInfo *evi_start;
1067 ExtensionVersionInfo *evi_target;
1069 /* Extract the version update graph from the script directory */
1070 evi_list = get_ext_ver_list(control);
1072 /* Initialize start and end vertices */
1073 evi_start = get_ext_ver_info(oldVersion, &evi_list);
1074 evi_target = get_ext_ver_info(newVersion, &evi_list);
1076 /* Find shortest path */
1077 result = find_update_path(evi_list, evi_start, evi_target, false);
1081 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1082 errmsg("extension \"%s\" has no update path from version \"%s\" to version \"%s\"",
1083 control->name, oldVersion, newVersion)));
1089 * Apply Dijkstra's algorithm to find the shortest path from evi_start to
1092 * If reinitialize is false, assume the ExtensionVersionInfo list has not
1093 * been used for this before, and the initialization done by get_ext_ver_info
1096 * Result is a List of names of versions to transition through (the initial
1097 * version is *not* included). Returns NIL if no such path.
1100 find_update_path(List *evi_list,
1101 ExtensionVersionInfo *evi_start,
1102 ExtensionVersionInfo *evi_target,
1106 ExtensionVersionInfo *evi;
1109 /* Caller error if start == target */
1110 Assert(evi_start != evi_target);
1114 foreach(lc, evi_list)
1116 evi = (ExtensionVersionInfo *) lfirst(lc);
1117 evi->distance_known = false;
1118 evi->distance = INT_MAX;
1119 evi->previous = NULL;
1123 evi_start->distance = 0;
1125 while ((evi = get_nearest_unprocessed_vertex(evi_list)) != NULL)
1127 if (evi->distance == INT_MAX)
1128 break; /* all remaining vertices are unreachable */
1129 evi->distance_known = true;
1130 if (evi == evi_target)
1131 break; /* found shortest path to target */
1132 foreach(lc, evi->reachable)
1134 ExtensionVersionInfo *evi2 = (ExtensionVersionInfo *) lfirst(lc);
1137 newdist = evi->distance + 1;
1138 if (newdist < evi2->distance)
1140 evi2->distance = newdist;
1141 evi2->previous = evi;
1143 else if (newdist == evi2->distance &&
1144 evi2->previous != NULL &&
1145 strcmp(evi->name, evi2->previous->name) < 0)
1148 * Break ties in favor of the version name that comes first
1149 * according to strcmp(). This behavior is undocumented and
1150 * users shouldn't rely on it. We do it just to ensure that
1151 * if there is a tie, the update path that is chosen does not
1152 * depend on random factors like the order in which directory
1153 * entries get visited.
1155 evi2->previous = evi;
1160 /* Return NIL if target is not reachable from start */
1161 if (!evi_target->distance_known)
1164 /* Build and return list of version names representing the update path */
1166 for (evi = evi_target; evi != evi_start; evi = evi->previous)
1167 result = lcons(evi->name, result);
1176 CreateExtension(CreateExtensionStmt *stmt)
1178 DefElem *d_schema = NULL;
1179 DefElem *d_new_version = NULL;
1180 DefElem *d_old_version = NULL;
1184 char *oldVersionName;
1185 Oid extowner = GetUserId();
1186 ExtensionControlFile *pcontrol;
1187 ExtensionControlFile *control;
1188 List *updateVersions;
1189 List *requiredExtensions;
1190 List *requiredSchemas;
1194 /* Check extension name validity before any filesystem access */
1195 check_valid_extension_name(stmt->extname);
1198 * Check for duplicate extension name. The unique index on
1199 * pg_extension.extname would catch this anyway, and serves as a backstop
1200 * in case of race conditions; but this is a friendlier error message, and
1201 * besides we need a check to support IF NOT EXISTS.
1203 if (get_extension_oid(stmt->extname, true) != InvalidOid)
1205 if (stmt->if_not_exists)
1208 (errcode(ERRCODE_DUPLICATE_OBJECT),
1209 errmsg("extension \"%s\" already exists, skipping",
1215 (errcode(ERRCODE_DUPLICATE_OBJECT),
1216 errmsg("extension \"%s\" already exists",
1221 * We use global variables to track the extension being created, so we can
1222 * create only one extension at the same time.
1224 if (creating_extension)
1226 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1227 errmsg("nested CREATE EXTENSION is not supported")));
1230 * Read the primary control file. Note we assume that it does not contain
1231 * any non-ASCII data, so there is no need to worry about encoding at this
1234 pcontrol = read_extension_control_file(stmt->extname);
1237 * Read the statement option list
1239 foreach(lc, stmt->options)
1241 DefElem *defel = (DefElem *) lfirst(lc);
1243 if (strcmp(defel->defname, "schema") == 0)
1247 (errcode(ERRCODE_SYNTAX_ERROR),
1248 errmsg("conflicting or redundant options")));
1251 else if (strcmp(defel->defname, "new_version") == 0)
1255 (errcode(ERRCODE_SYNTAX_ERROR),
1256 errmsg("conflicting or redundant options")));
1257 d_new_version = defel;
1259 else if (strcmp(defel->defname, "old_version") == 0)
1263 (errcode(ERRCODE_SYNTAX_ERROR),
1264 errmsg("conflicting or redundant options")));
1265 d_old_version = defel;
1268 elog(ERROR, "unrecognized option: %s", defel->defname);
1272 * Determine the version to install
1274 if (d_new_version && d_new_version->arg)
1275 versionName = strVal(d_new_version->arg);
1276 else if (pcontrol->default_version)
1277 versionName = pcontrol->default_version;
1281 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1282 errmsg("version to install must be specified")));
1283 versionName = NULL; /* keep compiler quiet */
1285 check_valid_version_name(versionName);
1288 * Determine the (unpackaged) version to update from, if any, and then
1289 * figure out what sequence of update scripts we need to apply.
1291 if (d_old_version && d_old_version->arg)
1293 oldVersionName = strVal(d_old_version->arg);
1294 check_valid_version_name(oldVersionName);
1296 if (strcmp(oldVersionName, versionName) == 0)
1298 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1299 errmsg("FROM version must be different from installation target version \"%s\"",
1302 updateVersions = identify_update_path(pcontrol,
1306 if (list_length(updateVersions) == 1)
1309 * Simple case where there's just one update script to run. We
1310 * will not need any follow-on update steps.
1312 Assert(strcmp((char *) linitial(updateVersions), versionName) == 0);
1313 updateVersions = NIL;
1318 * Multi-step sequence. We treat this as installing the version
1319 * that is the target of the first script, followed by successive
1320 * updates to the later versions.
1322 versionName = (char *) linitial(updateVersions);
1323 updateVersions = list_delete_first(updateVersions);
1328 oldVersionName = NULL;
1329 updateVersions = NIL;
1333 * Fetch control parameters for installation target version
1335 control = read_extension_aux_control_file(pcontrol, versionName);
1338 * Determine the target schema to install the extension into
1340 if (d_schema && d_schema->arg)
1343 * User given schema, CREATE EXTENSION ... WITH SCHEMA ...
1345 * It's an error to give a schema different from control->schema if
1346 * control->schema is specified.
1348 schemaName = strVal(d_schema->arg);
1350 if (control->schema != NULL &&
1351 strcmp(control->schema, schemaName) != 0)
1353 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1354 errmsg("extension \"%s\" must be installed in schema \"%s\"",
1358 /* If the user is giving us the schema name, it must exist already */
1359 schemaOid = get_namespace_oid(schemaName, false);
1361 else if (control->schema != NULL)
1364 * The extension is not relocatable and the author gave us a schema
1365 * for it. We create the schema here if it does not already exist.
1367 schemaName = control->schema;
1368 schemaOid = get_namespace_oid(schemaName, true);
1370 if (schemaOid == InvalidOid)
1372 schemaOid = NamespaceCreate(schemaName, extowner);
1373 /* Advance cmd counter to make the namespace visible */
1374 CommandCounterIncrement();
1380 * Else, use the current default creation namespace, which is the
1381 * first explicit entry in the search_path.
1383 List *search_path = fetch_search_path(false);
1385 if (search_path == NIL) /* probably can't happen */
1386 elog(ERROR, "there is no default creation target");
1387 schemaOid = linitial_oid(search_path);
1388 schemaName = get_namespace_name(schemaOid);
1389 if (schemaName == NULL) /* recently-deleted namespace? */
1390 elog(ERROR, "there is no default creation target");
1392 list_free(search_path);
1396 * We don't check creation rights on the target namespace here. If the
1397 * extension script actually creates any objects there, it will fail if
1398 * the user doesn't have such permissions. But there are cases such as
1399 * procedural languages where it's convenient to set schema = pg_catalog
1400 * yet we don't want to restrict the command to users with ACL_CREATE for
1405 * Look up the prerequisite extensions, and build lists of their OIDs and
1406 * the OIDs of their target schemas.
1408 requiredExtensions = NIL;
1409 requiredSchemas = NIL;
1410 foreach(lc, control->requires)
1412 char *curreq = (char *) lfirst(lc);
1417 * We intentionally don't use get_extension_oid's default error
1418 * message here, because it would be confusing in this context.
1420 reqext = get_extension_oid(curreq, true);
1421 if (!OidIsValid(reqext))
1423 (errcode(ERRCODE_UNDEFINED_OBJECT),
1424 errmsg("required extension \"%s\" is not installed",
1426 reqschema = get_extension_schema(reqext);
1427 requiredExtensions = lappend_oid(requiredExtensions, reqext);
1428 requiredSchemas = lappend_oid(requiredSchemas, reqschema);
1432 * Insert new tuple into pg_extension, and create dependency entries.
1434 extensionOid = InsertExtensionTuple(control->name, extowner,
1435 schemaOid, control->relocatable,
1437 PointerGetDatum(NULL),
1438 PointerGetDatum(NULL),
1439 requiredExtensions);
1442 * Apply any control-file comment on extension
1444 if (control->comment != NULL)
1445 CreateComments(extensionOid, ExtensionRelationId, 0, control->comment);
1448 * Execute the installation script file
1450 execute_extension_script(extensionOid, control,
1451 oldVersionName, versionName,
1453 schemaName, schemaOid);
1456 * If additional update scripts have to be executed, apply the updates as
1457 * though a series of ALTER EXTENSION UPDATE commands were given
1459 ApplyExtensionUpdates(extensionOid, pcontrol,
1460 versionName, updateVersions);
1464 * InsertExtensionTuple
1466 * Insert the new pg_extension row, and create extension's dependency entries.
1467 * Return the OID assigned to the new row.
1469 * This is exported for the benefit of pg_upgrade, which has to create a
1470 * pg_extension entry (and the extension-level dependencies) without
1471 * actually running the extension's script.
1473 * extConfig and extCondition should be arrays or PointerGetDatum(NULL).
1474 * We declare them as plain Datum to avoid needing array.h in extension.h.
1477 InsertExtensionTuple(const char *extName, Oid extOwner,
1478 Oid schemaOid, bool relocatable, const char *extVersion,
1479 Datum extConfig, Datum extCondition,
1480 List *requiredExtensions)
1484 Datum values[Natts_pg_extension];
1485 bool nulls[Natts_pg_extension];
1487 ObjectAddress myself;
1492 * Build and insert the pg_extension tuple
1494 rel = heap_open(ExtensionRelationId, RowExclusiveLock);
1496 memset(values, 0, sizeof(values));
1497 memset(nulls, 0, sizeof(nulls));
1499 values[Anum_pg_extension_extname - 1] =
1500 DirectFunctionCall1(namein, CStringGetDatum(extName));
1501 values[Anum_pg_extension_extowner - 1] = ObjectIdGetDatum(extOwner);
1502 values[Anum_pg_extension_extnamespace - 1] = ObjectIdGetDatum(schemaOid);
1503 values[Anum_pg_extension_extrelocatable - 1] = BoolGetDatum(relocatable);
1504 values[Anum_pg_extension_extversion - 1] = CStringGetTextDatum(extVersion);
1506 if (extConfig == PointerGetDatum(NULL))
1507 nulls[Anum_pg_extension_extconfig - 1] = true;
1509 values[Anum_pg_extension_extconfig - 1] = extConfig;
1511 if (extCondition == PointerGetDatum(NULL))
1512 nulls[Anum_pg_extension_extcondition - 1] = true;
1514 values[Anum_pg_extension_extcondition - 1] = extCondition;
1516 tuple = heap_form_tuple(rel->rd_att, values, nulls);
1518 extensionOid = simple_heap_insert(rel, tuple);
1519 CatalogUpdateIndexes(rel, tuple);
1521 heap_freetuple(tuple);
1522 heap_close(rel, RowExclusiveLock);
1525 * Record dependencies on owner, schema, and prerequisite extensions
1527 recordDependencyOnOwner(ExtensionRelationId, extensionOid, extOwner);
1529 myself.classId = ExtensionRelationId;
1530 myself.objectId = extensionOid;
1531 myself.objectSubId = 0;
1533 nsp.classId = NamespaceRelationId;
1534 nsp.objectId = schemaOid;
1535 nsp.objectSubId = 0;
1537 recordDependencyOn(&myself, &nsp, DEPENDENCY_NORMAL);
1539 foreach(lc, requiredExtensions)
1541 Oid reqext = lfirst_oid(lc);
1542 ObjectAddress otherext;
1544 otherext.classId = ExtensionRelationId;
1545 otherext.objectId = reqext;
1546 otherext.objectSubId = 0;
1548 recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
1550 /* Post creation hook for new extension */
1551 InvokeObjectAccessHook(OAT_POST_CREATE,
1552 ExtensionRelationId, extensionOid, 0);
1554 return extensionOid;
1560 * Implements DROP EXTENSION.
1563 RemoveExtensions(DropStmt *drop)
1565 ObjectAddresses *objects;
1569 * First we identify all the extensions, then we delete them in a single
1570 * performMultipleDeletions() call. This is to avoid unwanted DROP
1571 * RESTRICT errors if one of the extensions depends on another.
1573 objects = new_object_addresses();
1575 foreach(cell, drop->objects)
1577 List *names = (List *) lfirst(cell);
1578 char *extensionName;
1580 ObjectAddress object;
1582 if (list_length(names) != 1)
1584 (errcode(ERRCODE_SYNTAX_ERROR),
1585 errmsg("extension name cannot be qualified")));
1586 extensionName = strVal(linitial(names));
1588 extensionId = get_extension_oid(extensionName, drop->missing_ok);
1590 if (!OidIsValid(extensionId))
1593 (errmsg("extension \"%s\" does not exist, skipping",
1598 /* Permission check: must own extension */
1599 if (!pg_extension_ownercheck(extensionId, GetUserId()))
1600 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EXTENSION,
1603 object.classId = ExtensionRelationId;
1604 object.objectId = extensionId;
1605 object.objectSubId = 0;
1607 add_exact_object_address(&object, objects);
1611 * Do the deletions. Objects contained in the extension(s) are removed by
1612 * means of their dependency links to the extensions.
1614 performMultipleDeletions(objects, drop->behavior);
1616 free_object_addresses(objects);
1621 * Guts of extension deletion.
1623 * All we need do here is remove the pg_extension tuple itself. Everything
1624 * else is taken care of by the dependency infrastructure.
1627 RemoveExtensionById(Oid extId)
1630 SysScanDesc scandesc;
1632 ScanKeyData entry[1];
1634 rel = heap_open(ExtensionRelationId, RowExclusiveLock);
1636 ScanKeyInit(&entry[0],
1637 ObjectIdAttributeNumber,
1638 BTEqualStrategyNumber, F_OIDEQ,
1639 ObjectIdGetDatum(extId));
1640 scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
1641 SnapshotNow, 1, entry);
1643 tuple = systable_getnext(scandesc);
1645 /* We assume that there can be at most one matching tuple */
1646 if (HeapTupleIsValid(tuple))
1647 simple_heap_delete(rel, &tuple->t_self);
1649 systable_endscan(scandesc);
1651 heap_close(rel, RowExclusiveLock);
1655 * This function lists the available extensions (one row per primary control
1656 * file in the control directory). We parse each control file and report the
1657 * interesting fields.
1659 * The system view pg_available_extensions provides a user interface to this
1660 * SRF, adding information about whether the extensions are installed in the
1664 pg_available_extensions(PG_FUNCTION_ARGS)
1666 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1668 Tuplestorestate *tupstore;
1669 MemoryContext per_query_ctx;
1670 MemoryContext oldcontext;
1675 /* check to see if caller supports us returning a tuplestore */
1676 if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
1678 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1679 errmsg("set-valued function called in context that cannot accept a set")));
1680 if (!(rsinfo->allowedModes & SFRM_Materialize))
1682 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1683 errmsg("materialize mode required, but it is not " \
1684 "allowed in this context")));
1686 /* Build a tuple descriptor for our result type */
1687 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
1688 elog(ERROR, "return type must be a row type");
1690 /* Build tuplestore to hold the result rows */
1691 per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
1692 oldcontext = MemoryContextSwitchTo(per_query_ctx);
1694 tupstore = tuplestore_begin_heap(true, false, work_mem);
1695 rsinfo->returnMode = SFRM_Materialize;
1696 rsinfo->setResult = tupstore;
1697 rsinfo->setDesc = tupdesc;
1699 MemoryContextSwitchTo(oldcontext);
1701 location = get_extension_control_directory();
1702 dir = AllocateDir(location);
1705 * If the control directory doesn't exist, we want to silently return an
1706 * empty set. Any other error will be reported by ReadDir.
1708 if (dir == NULL && errno == ENOENT)
1714 while ((de = ReadDir(dir, location)) != NULL)
1716 ExtensionControlFile *control;
1721 if (!is_extension_control_filename(de->d_name))
1724 /* extract extension name from 'name.control' filename */
1725 extname = pstrdup(de->d_name);
1726 *strrchr(extname, '.') = '\0';
1728 /* ignore it if it's an auxiliary control file */
1729 if (strstr(extname, "--"))
1732 control = read_extension_control_file(extname);
1734 memset(values, 0, sizeof(values));
1735 memset(nulls, 0, sizeof(nulls));
1738 values[0] = DirectFunctionCall1(namein,
1739 CStringGetDatum(control->name));
1740 /* default_version */
1741 if (control->default_version == NULL)
1744 values[1] = CStringGetTextDatum(control->default_version);
1746 if (control->comment == NULL)
1749 values[2] = CStringGetTextDatum(control->comment);
1751 tuplestore_putvalues(tupstore, tupdesc, values, nulls);
1757 /* clean up and return the tuplestore */
1758 tuplestore_donestoring(tupstore);
1764 * This function lists the available extension versions (one row per
1765 * extension installation script). For each version, we parse the related
1766 * control file(s) and report the interesting fields.
1768 * The system view pg_available_extension_versions provides a user interface
1769 * to this SRF, adding information about which versions are installed in the
1773 pg_available_extension_versions(PG_FUNCTION_ARGS)
1775 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1777 Tuplestorestate *tupstore;
1778 MemoryContext per_query_ctx;
1779 MemoryContext oldcontext;
1784 /* check to see if caller supports us returning a tuplestore */
1785 if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
1787 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1788 errmsg("set-valued function called in context that cannot accept a set")));
1789 if (!(rsinfo->allowedModes & SFRM_Materialize))
1791 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1792 errmsg("materialize mode required, but it is not " \
1793 "allowed in this context")));
1795 /* Build a tuple descriptor for our result type */
1796 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
1797 elog(ERROR, "return type must be a row type");
1799 /* Build tuplestore to hold the result rows */
1800 per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
1801 oldcontext = MemoryContextSwitchTo(per_query_ctx);
1803 tupstore = tuplestore_begin_heap(true, false, work_mem);
1804 rsinfo->returnMode = SFRM_Materialize;
1805 rsinfo->setResult = tupstore;
1806 rsinfo->setDesc = tupdesc;
1808 MemoryContextSwitchTo(oldcontext);
1810 location = get_extension_control_directory();
1811 dir = AllocateDir(location);
1814 * If the control directory doesn't exist, we want to silently return an
1815 * empty set. Any other error will be reported by ReadDir.
1817 if (dir == NULL && errno == ENOENT)
1823 while ((de = ReadDir(dir, location)) != NULL)
1825 ExtensionControlFile *control;
1828 if (!is_extension_control_filename(de->d_name))
1831 /* extract extension name from 'name.control' filename */
1832 extname = pstrdup(de->d_name);
1833 *strrchr(extname, '.') = '\0';
1835 /* ignore it if it's an auxiliary control file */
1836 if (strstr(extname, "--"))
1839 /* read the control file */
1840 control = read_extension_control_file(extname);
1842 /* scan extension's script directory for install scripts */
1843 get_available_versions_for_extension(control, tupstore, tupdesc);
1849 /* clean up and return the tuplestore */
1850 tuplestore_donestoring(tupstore);
1856 * Inner loop for pg_available_extension_versions:
1857 * read versions of one extension, add rows to tupstore
1860 get_available_versions_for_extension(ExtensionControlFile *pcontrol,
1861 Tuplestorestate *tupstore,
1864 int extnamelen = strlen(pcontrol->name);
1869 location = get_extension_script_directory(pcontrol);
1870 dir = AllocateDir(location);
1871 /* Note this will fail if script directory doesn't exist */
1872 while ((de = ReadDir(dir, location)) != NULL)
1874 ExtensionControlFile *control;
1879 /* must be a .sql file ... */
1880 if (!is_extension_script_filename(de->d_name))
1883 /* ... matching extension name followed by separator */
1884 if (strncmp(de->d_name, pcontrol->name, extnamelen) != 0 ||
1885 de->d_name[extnamelen] != '-' ||
1886 de->d_name[extnamelen + 1] != '-')
1889 /* extract version name from 'extname--something.sql' filename */
1890 vername = pstrdup(de->d_name + extnamelen + 2);
1891 *strrchr(vername, '.') = '\0';
1893 /* ignore it if it's an update script */
1894 if (strstr(vername, "--"))
1898 * Fetch parameters for specific version (pcontrol is not changed)
1900 control = read_extension_aux_control_file(pcontrol, vername);
1902 memset(values, 0, sizeof(values));
1903 memset(nulls, 0, sizeof(nulls));
1906 values[0] = DirectFunctionCall1(namein,
1907 CStringGetDatum(control->name));
1909 values[1] = CStringGetTextDatum(vername);
1911 values[2] = BoolGetDatum(control->superuser);
1913 values[3] = BoolGetDatum(control->relocatable);
1915 if (control->schema == NULL)
1918 values[4] = DirectFunctionCall1(namein,
1919 CStringGetDatum(control->schema));
1921 if (control->requires == NIL)
1930 ndatums = list_length(control->requires);
1931 datums = (Datum *) palloc(ndatums * sizeof(Datum));
1933 foreach(lc, control->requires)
1935 char *curreq = (char *) lfirst(lc);
1938 DirectFunctionCall1(namein, CStringGetDatum(curreq));
1940 a = construct_array(datums, ndatums,
1942 NAMEDATALEN, false, 'c');
1943 values[5] = PointerGetDatum(a);
1946 if (control->comment == NULL)
1949 values[6] = CStringGetTextDatum(control->comment);
1951 tuplestore_putvalues(tupstore, tupdesc, values, nulls);
1958 * This function reports the version update paths that exist for the
1959 * specified extension.
1962 pg_extension_update_paths(PG_FUNCTION_ARGS)
1964 Name extname = PG_GETARG_NAME(0);
1965 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1967 Tuplestorestate *tupstore;
1968 MemoryContext per_query_ctx;
1969 MemoryContext oldcontext;
1971 ExtensionControlFile *control;
1974 /* Check extension name validity before any filesystem access */
1975 check_valid_extension_name(NameStr(*extname));
1977 /* check to see if caller supports us returning a tuplestore */
1978 if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
1980 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1981 errmsg("set-valued function called in context that cannot accept a set")));
1982 if (!(rsinfo->allowedModes & SFRM_Materialize))
1984 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1985 errmsg("materialize mode required, but it is not " \
1986 "allowed in this context")));
1988 /* Build a tuple descriptor for our result type */
1989 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
1990 elog(ERROR, "return type must be a row type");
1992 /* Build tuplestore to hold the result rows */
1993 per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
1994 oldcontext = MemoryContextSwitchTo(per_query_ctx);
1996 tupstore = tuplestore_begin_heap(true, false, work_mem);
1997 rsinfo->returnMode = SFRM_Materialize;
1998 rsinfo->setResult = tupstore;
1999 rsinfo->setDesc = tupdesc;
2001 MemoryContextSwitchTo(oldcontext);
2003 /* Read the extension's control file */
2004 control = read_extension_control_file(NameStr(*extname));
2006 /* Extract the version update graph from the script directory */
2007 evi_list = get_ext_ver_list(control);
2009 /* Iterate over all pairs of versions */
2010 foreach(lc1, evi_list)
2012 ExtensionVersionInfo *evi1 = (ExtensionVersionInfo *) lfirst(lc1);
2015 foreach(lc2, evi_list)
2017 ExtensionVersionInfo *evi2 = (ExtensionVersionInfo *) lfirst(lc2);
2025 /* Find shortest path from evi1 to evi2 */
2026 path = find_update_path(evi_list, evi1, evi2, true);
2028 /* Emit result row */
2029 memset(values, 0, sizeof(values));
2030 memset(nulls, 0, sizeof(nulls));
2033 values[0] = CStringGetTextDatum(evi1->name);
2035 values[1] = CStringGetTextDatum(evi2->name);
2041 StringInfoData pathbuf;
2044 initStringInfo(&pathbuf);
2045 /* The path doesn't include start vertex, but show it */
2046 appendStringInfoString(&pathbuf, evi1->name);
2049 char *versionName = (char *) lfirst(lcv);
2051 appendStringInfoString(&pathbuf, "--");
2052 appendStringInfoString(&pathbuf, versionName);
2054 values[2] = CStringGetTextDatum(pathbuf.data);
2055 pfree(pathbuf.data);
2058 tuplestore_putvalues(tupstore, tupdesc, values, nulls);
2062 /* clean up and return the tuplestore */
2063 tuplestore_donestoring(tupstore);
2069 * pg_extension_config_dump
2071 * Record information about a configuration table that belongs to an
2072 * extension being created, but whose contents should be dumped in whole
2073 * or in part during pg_dump.
2076 pg_extension_config_dump(PG_FUNCTION_ARGS)
2078 Oid tableoid = PG_GETARG_OID(0);
2079 text *wherecond = PG_GETARG_TEXT_P(1);
2083 SysScanDesc extScan;
2089 Datum repl_val[Natts_pg_extension];
2090 bool repl_null[Natts_pg_extension];
2091 bool repl_repl[Natts_pg_extension];
2095 * We only allow this to be called from an extension's SQL script. We
2096 * shouldn't need any permissions check beyond that.
2098 if (!creating_extension)
2100 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2101 errmsg("pg_extension_config_dump() can only be called "
2102 "from an SQL script executed by CREATE EXTENSION")));
2105 * Check that the table exists and is a member of the extension being
2106 * created. This ensures that we don't need to register a dependency to
2107 * protect the extconfig entry.
2109 tablename = get_rel_name(tableoid);
2110 if (tablename == NULL)
2112 (errcode(ERRCODE_UNDEFINED_TABLE),
2113 errmsg("OID %u does not refer to a table", tableoid)));
2114 if (getExtensionOfObject(RelationRelationId, tableoid) !=
2115 CurrentExtensionObject)
2117 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2118 errmsg("table \"%s\" is not a member of the extension being created",
2122 * Add the table OID and WHERE condition to the extension's extconfig and
2123 * extcondition arrays.
2126 /* Find the pg_extension tuple */
2127 extRel = heap_open(ExtensionRelationId, RowExclusiveLock);
2129 ScanKeyInit(&key[0],
2130 ObjectIdAttributeNumber,
2131 BTEqualStrategyNumber, F_OIDEQ,
2132 ObjectIdGetDatum(CurrentExtensionObject));
2134 extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
2135 SnapshotNow, 1, key);
2137 extTup = systable_getnext(extScan);
2139 if (!HeapTupleIsValid(extTup)) /* should not happen */
2140 elog(ERROR, "extension with oid %u does not exist",
2141 CurrentExtensionObject);
2143 memset(repl_val, 0, sizeof(repl_val));
2144 memset(repl_null, false, sizeof(repl_null));
2145 memset(repl_repl, false, sizeof(repl_repl));
2147 /* Build or modify the extconfig value */
2148 elementDatum = ObjectIdGetDatum(tableoid);
2150 arrayDatum = heap_getattr(extTup, Anum_pg_extension_extconfig,
2151 RelationGetDescr(extRel), &isnull);
2154 a = construct_array(&elementDatum, 1,
2156 sizeof(Oid), true, 'i');
2160 a = DatumGetArrayTypeP(arrayDatum);
2161 Assert(ARR_ELEMTYPE(a) == OIDOID);
2162 Assert(ARR_NDIM(a) == 1);
2163 Assert(ARR_LBOUND(a)[0] == 1);
2165 arrayIndex = ARR_DIMS(a)[0] + 1; /* add after end */
2167 a = array_set(a, 1, &arrayIndex,
2170 -1 /* varlena array */ ,
2171 sizeof(Oid) /* OID's typlen */ ,
2172 true /* OID's typbyval */ ,
2173 'i' /* OID's typalign */ );
2175 repl_val[Anum_pg_extension_extconfig - 1] = PointerGetDatum(a);
2176 repl_repl[Anum_pg_extension_extconfig - 1] = true;
2178 /* Build or modify the extcondition value */
2179 elementDatum = PointerGetDatum(wherecond);
2181 arrayDatum = heap_getattr(extTup, Anum_pg_extension_extcondition,
2182 RelationGetDescr(extRel), &isnull);
2185 a = construct_array(&elementDatum, 1,
2191 a = DatumGetArrayTypeP(arrayDatum);
2192 Assert(ARR_ELEMTYPE(a) == TEXTOID);
2193 Assert(ARR_NDIM(a) == 1);
2194 Assert(ARR_LBOUND(a)[0] == 1);
2196 arrayIndex = ARR_DIMS(a)[0] + 1; /* add after end */
2198 a = array_set(a, 1, &arrayIndex,
2201 -1 /* varlena array */ ,
2202 -1 /* TEXT's typlen */ ,
2203 false /* TEXT's typbyval */ ,
2204 'i' /* TEXT's typalign */ );
2206 repl_val[Anum_pg_extension_extcondition - 1] = PointerGetDatum(a);
2207 repl_repl[Anum_pg_extension_extcondition - 1] = true;
2209 extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
2210 repl_val, repl_null, repl_repl);
2212 simple_heap_update(extRel, &extTup->t_self, extTup);
2213 CatalogUpdateIndexes(extRel, extTup);
2215 systable_endscan(extScan);
2217 heap_close(extRel, RowExclusiveLock);
2223 * Execute ALTER EXTENSION SET SCHEMA
2226 AlterExtensionNamespace(List *names, const char *newschema)
2228 char *extensionName;
2231 Oid oldNspOid = InvalidOid;
2232 AclResult aclresult;
2235 SysScanDesc extScan;
2237 Form_pg_extension extForm;
2239 SysScanDesc depScan;
2242 if (list_length(names) != 1)
2244 (errcode(ERRCODE_SYNTAX_ERROR),
2245 errmsg("extension name cannot be qualified")));
2246 extensionName = strVal(linitial(names));
2248 extensionOid = get_extension_oid(extensionName, false);
2250 nspOid = LookupCreationNamespace(newschema);
2253 * Permission check: must own extension. Note that we don't bother to
2254 * check ownership of the individual member objects ...
2256 if (!pg_extension_ownercheck(extensionOid, GetUserId()))
2257 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EXTENSION,
2260 /* Permission check: must have creation rights in target namespace */
2261 aclresult = pg_namespace_aclcheck(nspOid, GetUserId(), ACL_CREATE);
2262 if (aclresult != ACLCHECK_OK)
2263 aclcheck_error(aclresult, ACL_KIND_NAMESPACE, newschema);
2265 /* Locate the pg_extension tuple */
2266 extRel = heap_open(ExtensionRelationId, RowExclusiveLock);
2268 ScanKeyInit(&key[0],
2269 ObjectIdAttributeNumber,
2270 BTEqualStrategyNumber, F_OIDEQ,
2271 ObjectIdGetDatum(extensionOid));
2273 extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
2274 SnapshotNow, 1, key);
2276 extTup = systable_getnext(extScan);
2278 if (!HeapTupleIsValid(extTup)) /* should not happen */
2279 elog(ERROR, "extension with oid %u does not exist", extensionOid);
2281 /* Copy tuple so we can modify it below */
2282 extTup = heap_copytuple(extTup);
2283 extForm = (Form_pg_extension) GETSTRUCT(extTup);
2285 systable_endscan(extScan);
2288 * If the extension is already in the target schema, just silently do
2291 if (extForm->extnamespace == nspOid)
2293 heap_close(extRel, RowExclusiveLock);
2297 /* Check extension is supposed to be relocatable */
2298 if (!extForm->extrelocatable)
2300 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2301 errmsg("extension \"%s\" does not support SET SCHEMA",
2302 NameStr(extForm->extname))));
2305 * Scan pg_depend to find objects that depend directly on the extension,
2306 * and alter each one's schema.
2308 depRel = heap_open(DependRelationId, AccessShareLock);
2310 ScanKeyInit(&key[0],
2311 Anum_pg_depend_refclassid,
2312 BTEqualStrategyNumber, F_OIDEQ,
2313 ObjectIdGetDatum(ExtensionRelationId));
2314 ScanKeyInit(&key[1],
2315 Anum_pg_depend_refobjid,
2316 BTEqualStrategyNumber, F_OIDEQ,
2317 ObjectIdGetDatum(extensionOid));
2319 depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
2320 SnapshotNow, 2, key);
2322 while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
2324 Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
2329 * Ignore non-membership dependencies. (Currently, the only other
2330 * case we could see here is a normal dependency from another
2333 if (pg_depend->deptype != DEPENDENCY_EXTENSION)
2336 dep.classId = pg_depend->classid;
2337 dep.objectId = pg_depend->objid;
2338 dep.objectSubId = pg_depend->objsubid;
2340 if (dep.objectSubId != 0) /* should not happen */
2341 elog(ERROR, "extension should not have a sub-object dependency");
2343 dep_oldNspOid = AlterObjectNamespace_oid(dep.classId,
2348 * Remember previous namespace of first object that has one
2350 if (oldNspOid == InvalidOid && dep_oldNspOid != InvalidOid)
2351 oldNspOid = dep_oldNspOid;
2354 * If not all the objects had the same old namespace (ignoring any
2355 * that are not in namespaces), complain.
2357 if (dep_oldNspOid != InvalidOid && dep_oldNspOid != oldNspOid)
2359 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2360 errmsg("extension \"%s\" does not support SET SCHEMA",
2361 NameStr(extForm->extname)),
2362 errdetail("%s is not in the extension's schema \"%s\"",
2363 getObjectDescription(&dep),
2364 get_namespace_name(oldNspOid))));
2367 systable_endscan(depScan);
2369 relation_close(depRel, AccessShareLock);
2371 /* Now adjust pg_extension.extnamespace */
2372 extForm->extnamespace = nspOid;
2374 simple_heap_update(extRel, &extTup->t_self, extTup);
2375 CatalogUpdateIndexes(extRel, extTup);
2377 heap_close(extRel, RowExclusiveLock);
2379 /* update dependencies to point to the new schema */
2380 changeDependencyFor(ExtensionRelationId, extensionOid,
2381 NamespaceRelationId, oldNspOid, nspOid);
2385 * Execute ALTER EXTENSION UPDATE
2388 ExecAlterExtensionStmt(AlterExtensionStmt *stmt)
2390 DefElem *d_new_version = NULL;
2392 char *oldVersionName;
2393 ExtensionControlFile *control;
2397 SysScanDesc extScan;
2399 List *updateVersions;
2405 * We use global variables to track the extension being created, so we can
2406 * create/update only one extension at the same time.
2408 if (creating_extension)
2410 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2411 errmsg("nested ALTER EXTENSION is not supported")));
2414 * Look up the extension --- it must already exist in pg_extension
2416 extRel = heap_open(ExtensionRelationId, AccessShareLock);
2418 ScanKeyInit(&key[0],
2419 Anum_pg_extension_extname,
2420 BTEqualStrategyNumber, F_NAMEEQ,
2421 CStringGetDatum(stmt->extname));
2423 extScan = systable_beginscan(extRel, ExtensionNameIndexId, true,
2424 SnapshotNow, 1, key);
2426 extTup = systable_getnext(extScan);
2428 if (!HeapTupleIsValid(extTup))
2430 (errcode(ERRCODE_UNDEFINED_OBJECT),
2431 errmsg("extension \"%s\" does not exist",
2434 extensionOid = HeapTupleGetOid(extTup);
2437 * Determine the existing version we are updating from
2439 datum = heap_getattr(extTup, Anum_pg_extension_extversion,
2440 RelationGetDescr(extRel), &isnull);
2442 elog(ERROR, "extversion is null");
2443 oldVersionName = text_to_cstring(DatumGetTextPP(datum));
2445 systable_endscan(extScan);
2447 heap_close(extRel, AccessShareLock);
2449 /* Permission check: must own extension */
2450 if (!pg_extension_ownercheck(extensionOid, GetUserId()))
2451 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EXTENSION,
2455 * Read the primary control file. Note we assume that it does not contain
2456 * any non-ASCII data, so there is no need to worry about encoding at this
2459 control = read_extension_control_file(stmt->extname);
2462 * Read the statement option list
2464 foreach(lc, stmt->options)
2466 DefElem *defel = (DefElem *) lfirst(lc);
2468 if (strcmp(defel->defname, "new_version") == 0)
2472 (errcode(ERRCODE_SYNTAX_ERROR),
2473 errmsg("conflicting or redundant options")));
2474 d_new_version = defel;
2477 elog(ERROR, "unrecognized option: %s", defel->defname);
2481 * Determine the version to update to
2483 if (d_new_version && d_new_version->arg)
2484 versionName = strVal(d_new_version->arg);
2485 else if (control->default_version)
2486 versionName = control->default_version;
2490 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2491 errmsg("version to install must be specified")));
2492 versionName = NULL; /* keep compiler quiet */
2494 check_valid_version_name(versionName);
2497 * If we're already at that version, just say so
2499 if (strcmp(oldVersionName, versionName) == 0)
2502 (errmsg("version \"%s\" of extension \"%s\" is already installed",
2503 versionName, stmt->extname)));
2508 * Identify the series of update script files we need to execute
2510 updateVersions = identify_update_path(control,
2515 * Update the pg_extension row and execute the update scripts, one at a
2518 ApplyExtensionUpdates(extensionOid, control,
2519 oldVersionName, updateVersions);
2523 * Apply a series of update scripts as though individual ALTER EXTENSION
2524 * UPDATE commands had been given, including altering the pg_extension row
2525 * and dependencies each time.
2527 * This might be more work than necessary, but it ensures that old update
2528 * scripts don't break if newer versions have different control parameters.
2531 ApplyExtensionUpdates(Oid extensionOid,
2532 ExtensionControlFile *pcontrol,
2533 const char *initialVersion,
2534 List *updateVersions)
2536 const char *oldVersionName = initialVersion;
2539 foreach(lcv, updateVersions)
2541 char *versionName = (char *) lfirst(lcv);
2542 ExtensionControlFile *control;
2545 List *requiredExtensions;
2546 List *requiredSchemas;
2549 SysScanDesc extScan;
2551 Form_pg_extension extForm;
2552 Datum values[Natts_pg_extension];
2553 bool nulls[Natts_pg_extension];
2554 bool repl[Natts_pg_extension];
2555 ObjectAddress myself;
2559 * Fetch parameters for specific version (pcontrol is not changed)
2561 control = read_extension_aux_control_file(pcontrol, versionName);
2563 /* Find the pg_extension tuple */
2564 extRel = heap_open(ExtensionRelationId, RowExclusiveLock);
2566 ScanKeyInit(&key[0],
2567 ObjectIdAttributeNumber,
2568 BTEqualStrategyNumber, F_OIDEQ,
2569 ObjectIdGetDatum(extensionOid));
2571 extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
2572 SnapshotNow, 1, key);
2574 extTup = systable_getnext(extScan);
2576 if (!HeapTupleIsValid(extTup)) /* should not happen */
2577 elog(ERROR, "extension with oid %u does not exist",
2580 extForm = (Form_pg_extension) GETSTRUCT(extTup);
2583 * Determine the target schema (set by original install)
2585 schemaOid = extForm->extnamespace;
2586 schemaName = get_namespace_name(schemaOid);
2589 * Modify extrelocatable and extversion in the pg_extension tuple
2591 memset(values, 0, sizeof(values));
2592 memset(nulls, 0, sizeof(nulls));
2593 memset(repl, 0, sizeof(repl));
2595 values[Anum_pg_extension_extrelocatable - 1] =
2596 BoolGetDatum(control->relocatable);
2597 repl[Anum_pg_extension_extrelocatable - 1] = true;
2598 values[Anum_pg_extension_extversion - 1] =
2599 CStringGetTextDatum(versionName);
2600 repl[Anum_pg_extension_extversion - 1] = true;
2602 extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
2603 values, nulls, repl);
2605 simple_heap_update(extRel, &extTup->t_self, extTup);
2606 CatalogUpdateIndexes(extRel, extTup);
2608 systable_endscan(extScan);
2610 heap_close(extRel, RowExclusiveLock);
2613 * Look up the prerequisite extensions for this version, and build
2614 * lists of their OIDs and the OIDs of their target schemas.
2616 requiredExtensions = NIL;
2617 requiredSchemas = NIL;
2618 foreach(lc, control->requires)
2620 char *curreq = (char *) lfirst(lc);
2625 * We intentionally don't use get_extension_oid's default error
2626 * message here, because it would be confusing in this context.
2628 reqext = get_extension_oid(curreq, true);
2629 if (!OidIsValid(reqext))
2631 (errcode(ERRCODE_UNDEFINED_OBJECT),
2632 errmsg("required extension \"%s\" is not installed",
2634 reqschema = get_extension_schema(reqext);
2635 requiredExtensions = lappend_oid(requiredExtensions, reqext);
2636 requiredSchemas = lappend_oid(requiredSchemas, reqschema);
2640 * Remove and recreate dependencies on prerequisite extensions
2642 deleteDependencyRecordsForClass(ExtensionRelationId, extensionOid,
2643 ExtensionRelationId,
2646 myself.classId = ExtensionRelationId;
2647 myself.objectId = extensionOid;
2648 myself.objectSubId = 0;
2650 foreach(lc, requiredExtensions)
2652 Oid reqext = lfirst_oid(lc);
2653 ObjectAddress otherext;
2655 otherext.classId = ExtensionRelationId;
2656 otherext.objectId = reqext;
2657 otherext.objectSubId = 0;
2659 recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
2663 * Finally, execute the update script file
2665 execute_extension_script(extensionOid, control,
2666 oldVersionName, versionName,
2668 schemaName, schemaOid);
2671 * Update prior-version name and loop around. Since
2672 * execute_sql_string did a final CommandCounterIncrement, we can
2673 * update the pg_extension row again.
2675 oldVersionName = versionName;
2680 * Execute ALTER EXTENSION ADD/DROP
2683 ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt)
2685 ObjectAddress extension;
2686 ObjectAddress object;
2690 extension.classId = ExtensionRelationId;
2691 extension.objectId = get_extension_oid(stmt->extname, false);
2692 extension.objectSubId = 0;
2694 /* Permission check: must own extension */
2695 if (!pg_extension_ownercheck(extension.objectId, GetUserId()))
2696 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EXTENSION,
2700 * Translate the parser representation that identifies the object into an
2701 * ObjectAddress. get_object_address() will throw an error if the object
2702 * does not exist, and will also acquire a lock on the object to guard
2703 * against concurrent DROP and ALTER EXTENSION ADD/DROP operations.
2705 object = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
2706 &relation, ShareUpdateExclusiveLock, false);
2708 /* Permission check: must own target object, too */
2709 check_object_ownership(GetUserId(), stmt->objtype, object,
2710 stmt->objname, stmt->objargs, relation);
2713 * Check existing extension membership.
2715 oldExtension = getExtensionOfObject(object.classId, object.objectId);
2717 if (stmt->action > 0)
2720 * ADD, so complain if object is already attached to some extension.
2722 if (OidIsValid(oldExtension))
2724 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2725 errmsg("%s is already a member of extension \"%s\"",
2726 getObjectDescription(&object),
2727 get_extension_name(oldExtension))));
2730 * OK, add the dependency.
2732 recordDependencyOn(&object, &extension, DEPENDENCY_EXTENSION);
2737 * DROP, so complain if it's not a member.
2739 if (oldExtension != extension.objectId)
2741 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2742 errmsg("%s is not a member of extension \"%s\"",
2743 getObjectDescription(&object),
2747 * OK, drop the dependency.
2749 if (deleteDependencyRecordsForClass(object.classId, object.objectId,
2750 ExtensionRelationId,
2751 DEPENDENCY_EXTENSION) != 1)
2752 elog(ERROR, "unexpected number of extension dependency records");
2756 * If get_object_address() opened the relation for us, we close it to keep
2757 * the reference count correct - but we retain any locks acquired by
2758 * get_object_address() until commit time, to guard against concurrent
2761 if (relation != NULL)
2762 relation_close(relation, NoLock);