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