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