PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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 */
148 bool reject_indirect,
149 bool reinitialize);
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);
163 const char *initialVersion,
165 char *origSchemaName,
166 bool cascade,
167 bool is_create);
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
211 CStringGetDatum(extname));
212
213 if (!OidIsValid(result) && !missing_ok)
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
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
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
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)
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, "--"))
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] == '-')
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 */
312 errmsg("invalid extension name: \"%s\"", extensionname),
313 errdetail("Extension names must not contain directory separator characters.")));
314}
315
316static void
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)
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, "--"))
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] == '-')
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 */
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 in the extension_control_path GUC.
381 */
382static List *
384{
385 char sharepath[MAXPGPATH];
386 char *system_dir;
387 char *ecp;
388 List *paths = NIL;
389
391
392 system_dir = psprintf("%s/extension", sharepath);
393
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;
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);
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 */
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
458 * available paths. Return the full file name, or NULL if not found.
459 * If found, the 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 was set via extension_control_path. It depends on 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
514
515 result = (char *) palloc(MAXPGPATH);
516 snprintf(result, MAXPGPATH, "%s/%s--%s.control",
517 scriptdir, control->name, version);
518
520
521 return result;
522}
523
524static char *
526 const char *from_version, const char *version)
527{
528 char *result;
529 char *scriptdir;
530
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
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 * If control->control_dir is not NULL, use that to read and parse the
553 * control file, otherwise search for the file in extension_control_path.
554 *
555 * Control files are supposed to be very short, half a dozen lines,
556 * so we don't worry about memory allocation risks here. Also we don't
557 * worry about what encoding it's in; all values are expected to be ASCII.
558 */
559static void
561 const char *version)
562{
563 char *filename;
564 FILE *file;
565 ConfigVariable *item,
566 *head = NULL,
567 *tail = NULL;
568
569 /*
570 * Locate the file to read. Auxiliary files are optional.
571 */
572 if (version)
574 else
575 {
576 /*
577 * If control_dir is already set, use it, else do a path search.
578 */
579 if (control->control_dir)
580 {
581 filename = psprintf("%s/%s.control", control->control_dir, control->name);
582 }
583 else
585 }
586
587 if (!filename)
588 {
591 errmsg("extension \"%s\" is not available", control->name),
592 errhint("The extension must first be installed on the system where PostgreSQL is running.")));
593 }
594
595 /* Assert that the control_dir ends with /extension */
596 Assert(control->control_dir != NULL);
597 Assert(strcmp(control->control_dir + strlen(control->control_dir) - strlen("/extension"), "/extension") == 0);
598
599 control->basedir = pnstrdup(
600 control->control_dir,
601 strlen(control->control_dir) - strlen("/extension"));
602
603 if ((file = AllocateFile(filename, "r")) == NULL)
604 {
605 /* no complaint for missing auxiliary file */
606 if (errno == ENOENT && version)
607 {
609 return;
610 }
611
614 errmsg("could not open extension control file \"%s\": %m",
615 filename)));
616 }
617
618 /*
619 * Parse the file content, using GUC's file parsing code. We need not
620 * check the return value since any errors will be thrown at ERROR level.
621 */
623 &head, &tail);
624
625 FreeFile(file);
626
627 /*
628 * Convert the ConfigVariable list into ExtensionControlFile entries.
629 */
630 for (item = head; item != NULL; item = item->next)
631 {
632 if (strcmp(item->name, "directory") == 0)
633 {
634 if (version)
637 errmsg("parameter \"%s\" cannot be set in a secondary extension control file",
638 item->name)));
639
640 control->directory = pstrdup(item->value);
641 }
642 else if (strcmp(item->name, "default_version") == 0)
643 {
644 if (version)
647 errmsg("parameter \"%s\" cannot be set in a secondary extension control file",
648 item->name)));
649
650 control->default_version = pstrdup(item->value);
651 }
652 else if (strcmp(item->name, "module_pathname") == 0)
653 {
654 control->module_pathname = pstrdup(item->value);
655 }
656 else if (strcmp(item->name, "comment") == 0)
657 {
658 control->comment = pstrdup(item->value);
659 }
660 else if (strcmp(item->name, "schema") == 0)
661 {
662 control->schema = pstrdup(item->value);
663 }
664 else if (strcmp(item->name, "relocatable") == 0)
665 {
666 if (!parse_bool(item->value, &control->relocatable))
669 errmsg("parameter \"%s\" requires a Boolean value",
670 item->name)));
671 }
672 else if (strcmp(item->name, "superuser") == 0)
673 {
674 if (!parse_bool(item->value, &control->superuser))
677 errmsg("parameter \"%s\" requires a Boolean value",
678 item->name)));
679 }
680 else if (strcmp(item->name, "trusted") == 0)
681 {
682 if (!parse_bool(item->value, &control->trusted))
685 errmsg("parameter \"%s\" requires a Boolean value",
686 item->name)));
687 }
688 else if (strcmp(item->name, "encoding") == 0)
689 {
690 control->encoding = pg_valid_server_encoding(item->value);
691 if (control->encoding < 0)
694 errmsg("\"%s\" is not a valid encoding name",
695 item->value)));
696 }
697 else if (strcmp(item->name, "requires") == 0)
698 {
699 /* Need a modifiable copy of string */
700 char *rawnames = pstrdup(item->value);
701
702 /* Parse string into list of identifiers */
703 if (!SplitIdentifierString(rawnames, ',', &control->requires))
704 {
705 /* syntax error in name list */
708 errmsg("parameter \"%s\" must be a list of extension names",
709 item->name)));
710 }
711 }
712 else if (strcmp(item->name, "no_relocate") == 0)
713 {
714 /* Need a modifiable copy of string */
715 char *rawnames = pstrdup(item->value);
716
717 /* Parse string into list of identifiers */
718 if (!SplitIdentifierString(rawnames, ',', &control->no_relocate))
719 {
720 /* syntax error in name list */
723 errmsg("parameter \"%s\" must be a list of extension names",
724 item->name)));
725 }
726 }
727 else
730 errmsg("unrecognized parameter \"%s\" in file \"%s\"",
731 item->name, filename)));
732 }
733
735
736 if (control->relocatable && control->schema != NULL)
739 errmsg("parameter \"schema\" cannot be specified when \"relocatable\" is true")));
740
742}
743
744/*
745 * Read the primary control file for the specified extension.
746 */
748read_extension_control_file(const char *extname)
749{
751
752 /*
753 * Parse the primary control file.
754 */
756
757 return control;
758}
759
760/*
761 * Read the auxiliary control file for the specified extension and version.
762 *
763 * Returns a new modified ExtensionControlFile struct; the original struct
764 * (reflecting just the primary control file) is not modified.
765 */
768 const char *version)
769{
771
772 /*
773 * Flat-copy the struct. Pointer fields share values with original.
774 */
777
778 /*
779 * Parse the auxiliary control file, overwriting struct fields
780 */
782
783 return acontrol;
784}
785
786/*
787 * Read an SQL script file into a string, and convert to database encoding
788 */
789static char *
791 const char *filename)
792{
793 int src_encoding;
794 char *src_str;
795 char *dest_str;
796 int len;
797
799
800 /* use database encoding if not given */
801 if (control->encoding < 0)
803 else
804 src_encoding = control->encoding;
805
806 /* make sure that source string is valid in the expected encoding */
808
809 /*
810 * Convert the encoding to the database encoding. read_whole_file
811 * null-terminated the string, so if no conversion happens the string is
812 * valid as is.
813 */
815
816 return dest_str;
817}
818
819/*
820 * error context callback for failures in script-file execution
821 */
822static void
824{
826 const char *query = callback_arg->sql;
827 int location = callback_arg->stmt_location;
828 int len = callback_arg->stmt_len;
830 const char *lastslash;
831
832 /*
833 * If there is a syntax error position, convert to internal syntax error;
834 * otherwise report the current query as an item of context stack.
835 *
836 * Note: we'll provide no context except the filename if there's neither
837 * an error position nor any known current query. That shouldn't happen
838 * though: all errors reported during raw parsing should come with an
839 * error position.
840 */
842 if (syntaxerrposition > 0)
843 {
844 /*
845 * If we do not know the bounds of the current statement (as would
846 * happen for an error occurring during initial raw parsing), we have
847 * to use a heuristic to decide how much of the script to show. We'll
848 * also use the heuristic in the unlikely case that syntaxerrposition
849 * is outside what we think the statement bounds are.
850 */
851 if (location < 0 || syntaxerrposition < location ||
852 (len > 0 && syntaxerrposition > location + len))
853 {
854 /*
855 * Our heuristic is pretty simple: look for semicolon-newline
856 * sequences, and break at the last one strictly before
857 * syntaxerrposition and the first one strictly after. It's
858 * certainly possible to fool this with semicolon-newline embedded
859 * in a string literal, but it seems better to do this than to
860 * show the entire extension script.
861 *
862 * Notice we cope with Windows-style newlines (\r\n) regardless of
863 * platform. This is because there might be such newlines in
864 * script files on other platforms.
865 */
866 int slen = strlen(query);
867
868 location = len = 0;
869 for (int loc = 0; loc < slen; loc++)
870 {
871 if (query[loc] != ';')
872 continue;
873 if (query[loc + 1] == '\r')
874 loc++;
875 if (query[loc + 1] == '\n')
876 {
877 int bkpt = loc + 2;
878
880 location = bkpt;
881 else if (bkpt > syntaxerrposition)
882 {
883 len = bkpt - location;
884 break; /* no need to keep searching */
885 }
886 }
887 }
888 }
889
890 /* Trim leading/trailing whitespace, for consistency */
891 query = CleanQuerytext(query, &location, &len);
892
893 /*
894 * Adjust syntaxerrposition. It shouldn't be pointing into the
895 * whitespace we just trimmed, but cope if it is.
896 */
897 syntaxerrposition -= location;
898 if (syntaxerrposition < 0)
900 else if (syntaxerrposition > len)
902
903 /* And report. */
904 errposition(0);
907 }
908 else if (location >= 0)
909 {
910 /*
911 * Since no syntax cursor will be shown, it's okay and helpful to trim
912 * the reported query string to just the current statement.
913 */
914 query = CleanQuerytext(query, &location, &len);
915 errcontext("SQL statement \"%.*s\"", len, query);
916 }
917
918 /*
919 * Trim the reported file name to remove the path. We know that
920 * get_extension_script_filename() inserted a '/', regardless of whether
921 * we're on Windows.
922 */
923 lastslash = strrchr(callback_arg->filename, '/');
924 if (lastslash)
925 lastslash++;
926 else
927 lastslash = callback_arg->filename; /* shouldn't happen, but cope */
928
929 /*
930 * If we have a location (which, as said above, we really always should)
931 * then report a line number to aid in localizing problems in big scripts.
932 */
933 if (location >= 0)
934 {
935 int linenumber = 1;
936
937 for (query = callback_arg->sql; *query; query++)
938 {
939 if (--location < 0)
940 break;
941 if (*query == '\n')
942 linenumber++;
943 }
944 errcontext("extension script file \"%s\", near line %d",
945 lastslash, linenumber);
946 }
947 else
948 errcontext("extension script file \"%s\"", lastslash);
949}
950
951/*
952 * Execute given SQL string.
953 *
954 * The filename the string came from is also provided, for error reporting.
955 *
956 * Note: it's tempting to just use SPI to execute the string, but that does
957 * not work very well. The really serious problem is that SPI will parse,
958 * analyze, and plan the whole string before executing any of it; of course
959 * this fails if there are any plannable statements referring to objects
960 * created earlier in the script. A lesser annoyance is that SPI insists
961 * on printing the whole string as errcontext in case of any error, and that
962 * could be very long.
963 */
964static void
965execute_sql_string(const char *sql, const char *filename)
966{
967 script_error_callback_arg callback_arg;
970 DestReceiver *dest;
971 ListCell *lc1;
972
973 /*
974 * Setup error traceback support for ereport().
975 */
976 callback_arg.sql = sql;
977 callback_arg.filename = filename;
978 callback_arg.stmt_location = -1;
979 callback_arg.stmt_len = -1;
980
982 scripterrcontext.arg = &callback_arg;
985
986 /*
987 * Parse the SQL string into a list of raw parse trees.
988 */
990
991 /* All output from SELECTs goes to the bit bucket */
993
994 /*
995 * Do parse analysis, rule rewrite, planning, and execution for each raw
996 * parsetree. We must fully execute each query before beginning parse
997 * analysis on the next one, since there may be interdependencies.
998 */
999 foreach(lc1, raw_parsetree_list)
1000 {
1001 RawStmt *parsetree = lfirst_node(RawStmt, lc1);
1003 oldcontext;
1004 List *stmt_list;
1005 ListCell *lc2;
1006
1007 /* Report location of this query for error context callback */
1008 callback_arg.stmt_location = parsetree->stmt_location;
1009 callback_arg.stmt_len = parsetree->stmt_len;
1010
1011 /*
1012 * We do the work for each parsetree in a short-lived context, to
1013 * limit the memory used when there are many commands in the string.
1014 */
1017 "execute_sql_string per-statement context",
1020
1021 /* Be sure parser can see any DDL done so far */
1023
1024 stmt_list = pg_analyze_and_rewrite_fixedparams(parsetree,
1025 sql,
1026 NULL,
1027 0,
1028 NULL);
1029 stmt_list = pg_plan_queries(stmt_list, sql, CURSOR_OPT_PARALLEL_OK, NULL);
1030
1031 foreach(lc2, stmt_list)
1032 {
1034
1036
1038
1039 if (stmt->utilityStmt == NULL)
1040 {
1042
1044 sql,
1046 dest, NULL, NULL, 0);
1047
1048 ExecutorStart(qdesc, 0);
1052
1054 }
1055 else
1056 {
1057 if (IsA(stmt->utilityStmt, TransactionStmt))
1058 ereport(ERROR,
1060 errmsg("transaction control statements are not allowed within an extension script")));
1061
1063 sql,
1064 false,
1066 NULL,
1067 NULL,
1068 dest,
1069 NULL);
1070 }
1071
1073 }
1074
1075 /* Clean up per-parsetree context. */
1076 MemoryContextSwitchTo(oldcontext);
1078 }
1079
1081
1082 /* Be sure to advance the command counter after the last script command */
1084}
1085
1086/*
1087 * Policy function: is the given extension trusted for installation by a
1088 * non-superuser?
1089 *
1090 * (Update the errhint logic below if you change this.)
1091 */
1092static bool
1094{
1096
1097 /* Never trust unless extension's control file says it's okay */
1098 if (!control->trusted)
1099 return false;
1100 /* Allow if user has CREATE privilege on current database */
1102 if (aclresult == ACLCHECK_OK)
1103 return true;
1104 return false;
1105}
1106
1107/*
1108 * Execute the appropriate script file for installing or updating the extension
1109 *
1110 * If from_version isn't NULL, it's an update
1111 *
1112 * Note: requiredSchemas must be one-for-one with the control->requires list
1113 */
1114static void
1116 const char *from_version,
1117 const char *version,
1119 const char *schemaName)
1120{
1121 bool switch_to_superuser = false;
1122 char *filename;
1123 Oid save_userid = 0;
1124 int save_sec_context = 0;
1125 int save_nestlevel;
1127 ListCell *lc;
1128 ListCell *lc2;
1129
1130 /*
1131 * Enforce superuser-ness if appropriate. We postpone these checks until
1132 * here so that the control flags are correctly associated with the right
1133 * script(s) if they happen to be set in secondary control files.
1134 */
1135 if (control->superuser && !superuser())
1136 {
1137 if (extension_is_trusted(control))
1138 switch_to_superuser = true;
1139 else if (from_version == NULL)
1140 ereport(ERROR,
1142 errmsg("permission denied to create extension \"%s\"",
1143 control->name),
1144 control->trusted
1145 ? errhint("Must have CREATE privilege on current database to create this extension.")
1146 : errhint("Must be superuser to create this extension.")));
1147 else
1148 ereport(ERROR,
1150 errmsg("permission denied to update extension \"%s\"",
1151 control->name),
1152 control->trusted
1153 ? errhint("Must have CREATE privilege on current database to update this extension.")
1154 : errhint("Must be superuser to update this extension.")));
1155 }
1156
1158
1159 if (from_version == NULL)
1160 elog(DEBUG1, "executing extension script for \"%s\" version '%s'", control->name, version);
1161 else
1162 elog(DEBUG1, "executing extension script for \"%s\" update from version '%s' to '%s'", control->name, from_version, version);
1163
1164 /*
1165 * If installing a trusted extension on behalf of a non-superuser, become
1166 * the bootstrap superuser. (This switch will be cleaned up automatically
1167 * if the transaction aborts, as will the GUC changes below.)
1168 */
1170 {
1171 GetUserIdAndSecContext(&save_userid, &save_sec_context);
1173 save_sec_context | SECURITY_LOCAL_USERID_CHANGE);
1174 }
1175
1176 /*
1177 * Force client_min_messages and log_min_messages to be at least WARNING,
1178 * so that we won't spam the user with useless NOTICE messages from common
1179 * script actions like creating shell types.
1180 *
1181 * We use the equivalent of a function SET option to allow the setting to
1182 * persist for exactly the duration of the script execution. guc.c also
1183 * takes care of undoing the setting on error.
1184 *
1185 * log_min_messages can't be set by ordinary users, so for that one we
1186 * pretend to be superuser.
1187 */
1188 save_nestlevel = NewGUCNestLevel();
1189
1191 (void) set_config_option("client_min_messages", "warning",
1193 GUC_ACTION_SAVE, true, 0, false);
1195 (void) set_config_option_ext("log_min_messages", "warning",
1198 GUC_ACTION_SAVE, true, 0, false);
1199
1200 /*
1201 * Similarly disable check_function_bodies, to ensure that SQL functions
1202 * won't be parsed during creation.
1203 */
1205 (void) set_config_option("check_function_bodies", "off",
1207 GUC_ACTION_SAVE, true, 0, false);
1208
1209 /*
1210 * Set up the search path to have the target schema first, making it be
1211 * the default creation target namespace. Then add the schemas of any
1212 * prerequisite extensions, unless they are in pg_catalog which would be
1213 * searched anyway. (Listing pg_catalog explicitly in a non-first
1214 * position would be bad for security.) Finally add pg_temp to ensure
1215 * that temp objects can't take precedence over others.
1216 */
1219 foreach(lc, requiredSchemas)
1220 {
1223
1224 if (reqname && strcmp(reqname, "pg_catalog") != 0)
1226 }
1227 appendStringInfoString(&pathbuf, ", pg_temp");
1228
1229 (void) set_config_option("search_path", pathbuf.data,
1231 GUC_ACTION_SAVE, true, 0, false);
1232
1233 /*
1234 * Set creating_extension and related variables so that
1235 * recordDependencyOnCurrentExtension and other functions do the right
1236 * things. On failure, ensure we reset these variables.
1237 */
1238 creating_extension = true;
1240 PG_TRY();
1241 {
1242 char *c_sql = read_extension_script_file(control, filename);
1243 Datum t_sql;
1244
1245 /*
1246 * We filter each substitution through quote_identifier(). When the
1247 * arg contains one of the following characters, no one collection of
1248 * quoting can work inside $$dollar-quoted string literals$$,
1249 * 'single-quoted string literals', and outside of any literal. To
1250 * avoid a security snare for extension authors, error on substitution
1251 * for arguments containing these.
1252 */
1253 const char *quoting_relevant_chars = "\"$'\\";
1254
1255 /* We use various functions that want to operate on text datums */
1257
1258 /*
1259 * Reduce any lines beginning with "\echo" to empty. This allows
1260 * scripts to contain messages telling people not to run them via
1261 * psql, which has been found to be necessary due to old habits.
1262 */
1265 t_sql,
1266 CStringGetTextDatum("^\\\\echo.*$"),
1268 CStringGetTextDatum("ng"));
1269
1270 /*
1271 * If the script uses @extowner@, substitute the calling username.
1272 */
1273 if (strstr(c_sql, "@extowner@"))
1274 {
1275 Oid uid = switch_to_superuser ? save_userid : GetUserId();
1276 const char *userName = GetUserNameFromId(uid, false);
1277 const char *qUserName = quote_identifier(userName);
1278
1281 t_sql,
1282 CStringGetTextDatum("@extowner@"),
1285 ereport(ERROR,
1287 errmsg("invalid character in extension owner: must not contain any of \"%s\"",
1289 }
1290
1291 /*
1292 * If it's not relocatable, substitute the target schema name for
1293 * occurrences of @extschema@.
1294 *
1295 * For a relocatable extension, we needn't do this. There cannot be
1296 * any need for @extschema@, else it wouldn't be relocatable.
1297 */
1298 if (!control->relocatable)
1299 {
1300 Datum old = t_sql;
1302
1305 t_sql,
1306 CStringGetTextDatum("@extschema@"),
1309 ereport(ERROR,
1311 errmsg("invalid character in extension \"%s\" schema: must not contain any of \"%s\"",
1312 control->name, quoting_relevant_chars)));
1313 }
1314
1315 /*
1316 * Likewise, substitute required extensions' schema names for
1317 * occurrences of @extschema:extension_name@.
1318 */
1319 Assert(list_length(control->requires) == list_length(requiredSchemas));
1320 forboth(lc, control->requires, lc2, requiredSchemas)
1321 {
1322 Datum old = t_sql;
1323 char *reqextname = (char *) lfirst(lc);
1327 char *repltoken;
1328
1329 repltoken = psprintf("@extschema:%s@", reqextname);
1332 t_sql,
1336 ereport(ERROR,
1338 errmsg("invalid character in extension \"%s\" schema: must not contain any of \"%s\"",
1340 }
1341
1342 /*
1343 * If module_pathname was set in the control file, substitute its
1344 * value for occurrences of MODULE_PATHNAME.
1345 */
1346 if (control->module_pathname)
1347 {
1350 t_sql,
1351 CStringGetTextDatum("MODULE_PATHNAME"),
1353 }
1354
1355 /* And now back to C string */
1357
1359 }
1360 PG_FINALLY();
1361 {
1362 creating_extension = false;
1364 }
1365 PG_END_TRY();
1366
1367 /*
1368 * Restore the GUC variables we set above.
1369 */
1370 AtEOXact_GUC(true, save_nestlevel);
1371
1372 /*
1373 * Restore authentication state if needed.
1374 */
1376 SetUserIdAndSecContext(save_userid, save_sec_context);
1377}
1378
1379/*
1380 * Find or create an ExtensionVersionInfo for the specified version name
1381 *
1382 * Currently, we just use a List of the ExtensionVersionInfo's. Searching
1383 * for them therefore uses about O(N^2) time when there are N versions of
1384 * the extension. We could change the data structure to a hash table if
1385 * this ever becomes a bottleneck.
1386 */
1387static ExtensionVersionInfo *
1389{
1391 ListCell *lc;
1392
1393 foreach(lc, *evi_list)
1394 {
1396 if (strcmp(evi->name, versionname) == 0)
1397 return evi;
1398 }
1399
1401 evi->name = pstrdup(versionname);
1402 evi->reachable = NIL;
1403 evi->installable = false;
1404 /* initialize for later application of Dijkstra's algorithm */
1405 evi->distance_known = false;
1406 evi->distance = INT_MAX;
1407 evi->previous = NULL;
1408
1410
1411 return evi;
1412}
1413
1414/*
1415 * Locate the nearest unprocessed ExtensionVersionInfo
1416 *
1417 * This part of the algorithm is also about O(N^2). A priority queue would
1418 * make it much faster, but for now there's no need.
1419 */
1420static ExtensionVersionInfo *
1422{
1424 ListCell *lc;
1425
1426 foreach(lc, evi_list)
1427 {
1429
1430 /* only vertices whose distance is still uncertain are candidates */
1431 if (evi2->distance_known)
1432 continue;
1433 /* remember the closest such vertex */
1434 if (evi == NULL ||
1435 evi->distance > evi2->distance)
1436 evi = evi2;
1437 }
1438
1439 return evi;
1440}
1441
1442/*
1443 * Obtain information about the set of update scripts available for the
1444 * specified extension. The result is a List of ExtensionVersionInfo
1445 * structs, each with a subsidiary list of the ExtensionVersionInfos for
1446 * the versions that can be reached in one step from that version.
1447 */
1448static List *
1450{
1451 List *evi_list = NIL;
1452 int extnamelen = strlen(control->name);
1453 char *location;
1454 DIR *dir;
1455 struct dirent *de;
1456
1457 location = get_extension_script_directory(control);
1458 dir = AllocateDir(location);
1459 while ((de = ReadDir(dir, location)) != NULL)
1460 {
1461 char *vername;
1462 char *vername2;
1465
1466 /* must be a .sql file ... */
1467 if (!is_extension_script_filename(de->d_name))
1468 continue;
1469
1470 /* ... matching extension name followed by separator */
1471 if (strncmp(de->d_name, control->name, extnamelen) != 0 ||
1472 de->d_name[extnamelen] != '-' ||
1473 de->d_name[extnamelen + 1] != '-')
1474 continue;
1475
1476 /* extract version name(s) from 'extname--something.sql' filename */
1477 vername = pstrdup(de->d_name + extnamelen + 2);
1478 *strrchr(vername, '.') = '\0';
1479 vername2 = strstr(vername, "--");
1480 if (!vername2)
1481 {
1482 /* It's an install, not update, script; record its version name */
1484 evi->installable = true;
1485 continue;
1486 }
1487 *vername2 = '\0'; /* terminate first version */
1488 vername2 += 2; /* and point to second */
1489
1490 /* if there's a third --, it's bogus, ignore it */
1491 if (strstr(vername2, "--"))
1492 continue;
1493
1494 /* Create ExtensionVersionInfos and link them together */
1497 evi->reachable = lappend(evi->reachable, evi2);
1498 }
1499 FreeDir(dir);
1500
1501 return evi_list;
1502}
1503
1504/*
1505 * Given an initial and final version name, identify the sequence of update
1506 * scripts that have to be applied to perform that update.
1507 *
1508 * Result is a List of names of versions to transition through (the initial
1509 * version is *not* included).
1510 */
1511static List *
1513 const char *oldVersion, const char *newVersion)
1514{
1515 List *result;
1516 List *evi_list;
1519
1520 /* Extract the version update graph from the script directory */
1521 evi_list = get_ext_ver_list(control);
1522
1523 /* Initialize start and end vertices */
1526
1527 /* Find shortest path */
1528 result = find_update_path(evi_list, evi_start, evi_target, false, false);
1529
1530 if (result == NIL)
1531 ereport(ERROR,
1533 errmsg("extension \"%s\" has no update path from version \"%s\" to version \"%s\"",
1534 control->name, oldVersion, newVersion)));
1535
1536 return result;
1537}
1538
1539/*
1540 * Apply Dijkstra's algorithm to find the shortest path from evi_start to
1541 * evi_target.
1542 *
1543 * If reject_indirect is true, ignore paths that go through installable
1544 * versions. This saves work when the caller will consider starting from
1545 * all installable versions anyway.
1546 *
1547 * If reinitialize is false, assume the ExtensionVersionInfo list has not
1548 * been used for this before, and the initialization done by get_ext_ver_info
1549 * is still good. Otherwise, reinitialize all transient fields used here.
1550 *
1551 * Result is a List of names of versions to transition through (the initial
1552 * version is *not* included). Returns NIL if no such path.
1553 */
1554static List *
1558 bool reject_indirect,
1559 bool reinitialize)
1560{
1561 List *result;
1563 ListCell *lc;
1564
1565 /* Caller error if start == target */
1567 /* Caller error if reject_indirect and target is installable */
1568 Assert(!(reject_indirect && evi_target->installable));
1569
1570 if (reinitialize)
1571 {
1572 foreach(lc, evi_list)
1573 {
1575 evi->distance_known = false;
1576 evi->distance = INT_MAX;
1577 evi->previous = NULL;
1578 }
1579 }
1580
1581 evi_start->distance = 0;
1582
1584 {
1585 if (evi->distance == INT_MAX)
1586 break; /* all remaining vertices are unreachable */
1587 evi->distance_known = true;
1588 if (evi == evi_target)
1589 break; /* found shortest path to target */
1590 foreach(lc, evi->reachable)
1591 {
1593 int newdist;
1594
1595 /* if reject_indirect, treat installable versions as unreachable */
1596 if (reject_indirect && evi2->installable)
1597 continue;
1598 newdist = evi->distance + 1;
1599 if (newdist < evi2->distance)
1600 {
1601 evi2->distance = newdist;
1602 evi2->previous = evi;
1603 }
1604 else if (newdist == evi2->distance &&
1605 evi2->previous != NULL &&
1606 strcmp(evi->name, evi2->previous->name) < 0)
1607 {
1608 /*
1609 * Break ties in favor of the version name that comes first
1610 * according to strcmp(). This behavior is undocumented and
1611 * users shouldn't rely on it. We do it just to ensure that
1612 * if there is a tie, the update path that is chosen does not
1613 * depend on random factors like the order in which directory
1614 * entries get visited.
1615 */
1616 evi2->previous = evi;
1617 }
1618 }
1619 }
1620
1621 /* Return NIL if target is not reachable from start */
1622 if (!evi_target->distance_known)
1623 return NIL;
1624
1625 /* Build and return list of version names representing the update path */
1626 result = NIL;
1627 for (evi = evi_target; evi != evi_start; evi = evi->previous)
1628 result = lcons(evi->name, result);
1629
1630 return result;
1631}
1632
1633/*
1634 * Given a target version that is not directly installable, find the
1635 * best installation sequence starting from a directly-installable version.
1636 *
1637 * evi_list: previously-collected version update graph
1638 * evi_target: member of that list that we want to reach
1639 *
1640 * Returns the best starting-point version, or NULL if there is none.
1641 * On success, *best_path is set to the path from the start point.
1642 *
1643 * If there's more than one possible start point, prefer shorter update paths,
1644 * and break any ties arbitrarily on the basis of strcmp'ing the starting
1645 * versions' names.
1646 */
1647static ExtensionVersionInfo *
1649 List **best_path)
1650{
1652 ListCell *lc;
1653
1654 *best_path = NIL;
1655
1656 /*
1657 * We don't expect to be called for an installable target, but if we are,
1658 * the answer is easy: just start from there, with an empty update path.
1659 */
1660 if (evi_target->installable)
1661 return evi_target;
1662
1663 /* Consider all installable versions as start points */
1664 foreach(lc, evi_list)
1665 {
1667 List *path;
1668
1669 if (!evi1->installable)
1670 continue;
1671
1672 /*
1673 * Find shortest path from evi1 to evi_target; but no need to consider
1674 * paths going through other installable versions.
1675 */
1676 path = find_update_path(evi_list, evi1, evi_target, true, true);
1677 if (path == NIL)
1678 continue;
1679
1680 /* Remember best path */
1681 if (evi_start == NULL ||
1682 list_length(path) < list_length(*best_path) ||
1683 (list_length(path) == list_length(*best_path) &&
1684 strcmp(evi_start->name, evi1->name) < 0))
1685 {
1686 evi_start = evi1;
1687 *best_path = path;
1688 }
1689 }
1690
1691 return evi_start;
1692}
1693
1694/*
1695 * CREATE EXTENSION worker
1696 *
1697 * When CASCADE is specified, CreateExtensionInternal() recurses if required
1698 * extensions need to be installed. To sanely handle cyclic dependencies,
1699 * the "parents" list contains a list of names of extensions already being
1700 * installed, allowing us to error out if we recurse to one of those.
1701 */
1702static ObjectAddress
1704 char *schemaName,
1705 const char *versionName,
1706 bool cascade,
1707 List *parents,
1708 bool is_create)
1709{
1710 char *origSchemaName = schemaName;
1714 ExtensionControlFile *control;
1715 char *filename;
1716 struct stat fst;
1721 ObjectAddress address;
1722 ListCell *lc;
1723
1724 /*
1725 * Read the primary control file. Note we assume that it does not contain
1726 * any non-ASCII data, so there is no need to worry about encoding at this
1727 * point.
1728 */
1730
1731 /*
1732 * Determine the version to install
1733 */
1734 if (versionName == NULL)
1735 {
1736 if (pcontrol->default_version)
1737 versionName = pcontrol->default_version;
1738 else
1739 ereport(ERROR,
1741 errmsg("version to install must be specified")));
1742 }
1744
1745 /*
1746 * Figure out which script(s) we need to run to install the desired
1747 * version of the extension. If we do not have a script that directly
1748 * does what is needed, we try to find a sequence of update scripts that
1749 * will get us there.
1750 */
1752 if (stat(filename, &fst) == 0)
1753 {
1754 /* Easy, no extra scripts */
1756 }
1757 else
1758 {
1759 /* Look for best way to install this version */
1760 List *evi_list;
1763
1764 /* Extract the version update graph from the script directory */
1766
1767 /* Identify the target version */
1769
1770 /* Identify best path to reach target */
1773
1774 /* Fail if no path ... */
1775 if (evi_start == NULL)
1776 ereport(ERROR,
1778 errmsg("extension \"%s\" has no installation script nor update path for version \"%s\"",
1779 pcontrol->name, versionName)));
1780
1781 /* Otherwise, install best starting point and then upgrade */
1782 versionName = evi_start->name;
1783 }
1784
1785 /*
1786 * Fetch control parameters for installation target version
1787 */
1789
1790 /*
1791 * Determine the target schema to install the extension into
1792 */
1793 if (schemaName)
1794 {
1795 /* If the user is giving us the schema name, it must exist already. */
1797 }
1798
1799 if (control->schema != NULL)
1800 {
1801 /*
1802 * The extension is not relocatable and the author gave us a schema
1803 * for it.
1804 *
1805 * Unless CASCADE parameter was given, it's an error to give a schema
1806 * different from control->schema if control->schema is specified.
1807 */
1808 if (schemaName && strcmp(control->schema, schemaName) != 0 &&
1809 !cascade)
1810 ereport(ERROR,
1812 errmsg("extension \"%s\" must be installed in schema \"%s\"",
1813 control->name,
1814 control->schema)));
1815
1816 /* Always use the schema from control file for current extension. */
1817 schemaName = control->schema;
1818
1819 /* Find or create the schema in case it does not exist. */
1821
1822 if (!OidIsValid(schemaOid))
1823 {
1825
1826 csstmt->schemaname = schemaName;
1827 csstmt->authrole = NULL; /* will be created by current user */
1828 csstmt->schemaElts = NIL;
1829 csstmt->if_not_exists = false;
1830 CreateSchemaCommand(csstmt, "(generated CREATE SCHEMA command)",
1831 -1, -1);
1832
1833 /*
1834 * CreateSchemaCommand includes CommandCounterIncrement, so new
1835 * schema is now visible.
1836 */
1838 }
1839 }
1840 else if (!OidIsValid(schemaOid))
1841 {
1842 /*
1843 * Neither user nor author of the extension specified schema; use the
1844 * current default creation namespace, which is the first explicit
1845 * entry in the search_path.
1846 */
1847 List *search_path = fetch_search_path(false);
1848
1849 if (search_path == NIL) /* nothing valid in search_path? */
1850 ereport(ERROR,
1852 errmsg("no schema has been selected to create in")));
1853 schemaOid = linitial_oid(search_path);
1855 if (schemaName == NULL) /* recently-deleted namespace? */
1856 ereport(ERROR,
1858 errmsg("no schema has been selected to create in")));
1859
1860 list_free(search_path);
1861 }
1862
1863 /*
1864 * Make note if a temporary namespace has been accessed in this
1865 * transaction.
1866 */
1869
1870 /*
1871 * We don't check creation rights on the target namespace here. If the
1872 * extension script actually creates any objects there, it will fail if
1873 * the user doesn't have such permissions. But there are cases such as
1874 * procedural languages where it's convenient to set schema = pg_catalog
1875 * yet we don't want to restrict the command to users with ACL_CREATE for
1876 * pg_catalog.
1877 */
1878
1879 /*
1880 * Look up the prerequisite extensions, install them if necessary, and
1881 * build lists of their OIDs and the OIDs of their target schemas.
1882 */
1885 foreach(lc, control->requires)
1886 {
1887 char *curreq = (char *) lfirst(lc);
1888 Oid reqext;
1889 Oid reqschema;
1890
1894 cascade,
1895 parents,
1896 is_create);
1900 }
1901
1902 /*
1903 * Insert new tuple into pg_extension, and create dependency entries.
1904 */
1905 address = InsertExtensionTuple(control->name, extowner,
1906 schemaOid, control->relocatable,
1911 extensionOid = address.objectId;
1912
1913 /*
1914 * Apply any control-file comment on extension
1915 */
1916 if (control->comment != NULL)
1918
1919 /*
1920 * Execute the installation script file
1921 */
1925 schemaName);
1926
1927 /*
1928 * If additional update scripts have to be executed, apply the updates as
1929 * though a series of ALTER EXTENSION UPDATE commands were given
1930 */
1933 origSchemaName, cascade, is_create);
1934
1935 return address;
1936}
1937
1938/*
1939 * Get the OID of an extension listed in "requires", possibly creating it.
1940 */
1941static Oid
1943 char *extensionName,
1944 char *origSchemaName,
1945 bool cascade,
1946 List *parents,
1947 bool is_create)
1948{
1950
1953 {
1954 if (cascade)
1955 {
1956 /* Must install it. */
1957 ObjectAddress addr;
1959 ListCell *lc;
1960
1961 /* Check extension name validity before trying to cascade. */
1963
1964 /* Check for cyclic dependency between extensions. */
1965 foreach(lc, parents)
1966 {
1967 char *pname = (char *) lfirst(lc);
1968
1969 if (strcmp(pname, reqExtensionName) == 0)
1970 ereport(ERROR,
1972 errmsg("cyclic dependency detected between extensions \"%s\" and \"%s\"",
1974 }
1975
1977 (errmsg("installing required extension \"%s\"",
1979
1980 /* Add current extension to list of parents to pass down. */
1982
1983 /*
1984 * Create the required extension. We propagate the SCHEMA option
1985 * if any, and CASCADE, but no other options.
1986 */
1989 NULL,
1990 cascade,
1992 is_create);
1993
1994 /* Get its newly-assigned OID. */
1996 }
1997 else
1998 ereport(ERROR,
2000 errmsg("required extension \"%s\" is not installed",
2002 is_create ?
2003 errhint("Use CREATE EXTENSION ... CASCADE to install required extensions too.") : 0));
2004 }
2005
2006 return reqExtensionOid;
2007}
2008
2009/*
2010 * CREATE EXTENSION
2011 */
2014{
2018 char *schemaName = NULL;
2019 char *versionName = NULL;
2020 bool cascade = false;
2021 ListCell *lc;
2022
2023 /* Check extension name validity before any filesystem access */
2025
2026 /*
2027 * Check for duplicate extension name. The unique index on
2028 * pg_extension.extname would catch this anyway, and serves as a backstop
2029 * in case of race conditions; but this is a friendlier error message, and
2030 * besides we need a check to support IF NOT EXISTS.
2031 */
2032 if (get_extension_oid(stmt->extname, true) != InvalidOid)
2033 {
2034 if (stmt->if_not_exists)
2035 {
2038 errmsg("extension \"%s\" already exists, skipping",
2039 stmt->extname)));
2040 return InvalidObjectAddress;
2041 }
2042 else
2043 ereport(ERROR,
2045 errmsg("extension \"%s\" already exists",
2046 stmt->extname)));
2047 }
2048
2049 /*
2050 * We use global variables to track the extension being created, so we can
2051 * create only one extension at the same time.
2052 */
2054 ereport(ERROR,
2056 errmsg("nested CREATE EXTENSION is not supported")));
2057
2058 /* Deconstruct the statement option list */
2059 foreach(lc, stmt->options)
2060 {
2061 DefElem *defel = (DefElem *) lfirst(lc);
2062
2063 if (strcmp(defel->defname, "schema") == 0)
2064 {
2065 if (d_schema)
2067 d_schema = defel;
2069 }
2070 else if (strcmp(defel->defname, "new_version") == 0)
2071 {
2072 if (d_new_version)
2076 }
2077 else if (strcmp(defel->defname, "cascade") == 0)
2078 {
2079 if (d_cascade)
2081 d_cascade = defel;
2082 cascade = defGetBoolean(d_cascade);
2083 }
2084 else
2085 elog(ERROR, "unrecognized option: %s", defel->defname);
2086 }
2087
2088 /* Call CreateExtensionInternal to do the real work. */
2089 return CreateExtensionInternal(stmt->extname,
2090 schemaName,
2092 cascade,
2093 NIL,
2094 true);
2095}
2096
2097/*
2098 * InsertExtensionTuple
2099 *
2100 * Insert the new pg_extension row, and create extension's dependency entries.
2101 * Return the OID assigned to the new row.
2102 *
2103 * This is exported for the benefit of pg_upgrade, which has to create a
2104 * pg_extension entry (and the extension-level dependencies) without
2105 * actually running the extension's script.
2106 *
2107 * extConfig and extCondition should be arrays or PointerGetDatum(NULL).
2108 * We declare them as plain Datum to avoid needing array.h in extension.h.
2109 */
2112 Oid schemaOid, bool relocatable, const char *extVersion,
2115{
2117 Relation rel;
2119 bool nulls[Natts_pg_extension];
2120 HeapTuple tuple;
2124 ListCell *lc;
2125
2126 /*
2127 * Build and insert the pg_extension tuple
2128 */
2130
2131 memset(values, 0, sizeof(values));
2132 memset(nulls, 0, sizeof(nulls));
2133
2143
2145 nulls[Anum_pg_extension_extconfig - 1] = true;
2146 else
2148
2150 nulls[Anum_pg_extension_extcondition - 1] = true;
2151 else
2153
2154 tuple = heap_form_tuple(rel->rd_att, values, nulls);
2155
2156 CatalogTupleInsert(rel, tuple);
2157
2158 heap_freetuple(tuple);
2160
2161 /*
2162 * Record dependencies on owner, schema, and prerequisite extensions
2163 */
2165
2167
2169
2172
2173 foreach(lc, requiredExtensions)
2174 {
2177
2180 }
2181
2182 /* Record all of them (this includes duplicate elimination) */
2185
2186 /* Post creation hook for new extension */
2188
2189 return myself;
2190}
2191
2192/*
2193 * Guts of extension deletion.
2194 *
2195 * All we need do here is remove the pg_extension tuple itself. Everything
2196 * else is taken care of by the dependency infrastructure.
2197 */
2198void
2200{
2201 Relation rel;
2202 SysScanDesc scandesc;
2203 HeapTuple tuple;
2204 ScanKeyData entry[1];
2205
2206 /*
2207 * Disallow deletion of any extension that's currently open for insertion;
2208 * else subsequent executions of recordDependencyOnCurrentExtension()
2209 * could create dangling pg_depend records that refer to a no-longer-valid
2210 * pg_extension OID. This is needed not so much because we think people
2211 * might write "DROP EXTENSION foo" in foo's own script files, as because
2212 * errors in dependency management in extension script files could give
2213 * rise to cases where an extension is dropped as a result of recursing
2214 * from some contained object. Because of that, we must test for the case
2215 * here, not at some higher level of the DROP EXTENSION command.
2216 */
2218 ereport(ERROR,
2220 errmsg("cannot drop extension \"%s\" because it is being modified",
2222
2224
2225 ScanKeyInit(&entry[0],
2229 scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
2230 NULL, 1, entry);
2231
2232 tuple = systable_getnext(scandesc);
2233
2234 /* We assume that there can be at most one matching tuple */
2235 if (HeapTupleIsValid(tuple))
2236 CatalogTupleDelete(rel, &tuple->t_self);
2237
2238 systable_endscan(scandesc);
2239
2241}
2242
2243/*
2244 * This function lists the available extensions (one row per primary control
2245 * file in the control directory). We parse each control file and report the
2246 * interesting fields.
2247 *
2248 * The system view pg_available_extensions provides a user interface to this
2249 * SRF, adding information about whether the extensions are installed in the
2250 * current DB.
2251 */
2252Datum
2254{
2255 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
2256 List *locations;
2257 DIR *dir;
2258 struct dirent *de;
2259 List *found_ext = NIL;
2260
2261 /* Build tuplestore to hold the result rows */
2262 InitMaterializedSRF(fcinfo, 0);
2263
2265
2267 {
2268 dir = AllocateDir(location->loc);
2269
2270 /*
2271 * If the control directory doesn't exist, we want to silently return
2272 * an empty set. Any other error will be reported by ReadDir.
2273 */
2274 if (dir == NULL && errno == ENOENT)
2275 {
2276 /* do nothing */
2277 }
2278 else
2279 {
2280 while ((de = ReadDir(dir, location->loc)) != NULL)
2281 {
2282 ExtensionControlFile *control;
2283 char *extname;
2285 Datum values[4];
2286 bool nulls[4];
2287
2288 if (!is_extension_control_filename(de->d_name))
2289 continue;
2290
2291 /* extract extension name from 'name.control' filename */
2292 extname = pstrdup(de->d_name);
2293 *strrchr(extname, '.') = '\0';
2294
2295 /* ignore it if it's an auxiliary control file */
2296 if (strstr(extname, "--"))
2297 continue;
2298
2299 /*
2300 * Ignore already-found names. They are not reachable by the
2301 * path search, so don't show them.
2302 */
2303 extname_str = makeString(extname);
2305 continue;
2306 else
2308
2309 control = new_ExtensionControlFile(extname);
2310 control->control_dir = pstrdup(location->loc);
2312
2313 memset(values, 0, sizeof(values));
2314 memset(nulls, 0, sizeof(nulls));
2315
2316 /* name */
2318 CStringGetDatum(control->name));
2319 /* default_version */
2320 if (control->default_version == NULL)
2321 nulls[1] = true;
2322 else
2324
2325 /* location */
2327
2328 /* comment */
2329 if (control->comment == NULL)
2330 nulls[3] = true;
2331 else
2332 values[3] = CStringGetTextDatum(control->comment);
2333
2334 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
2335 values, nulls);
2336 }
2337
2338 FreeDir(dir);
2339 }
2340 }
2341
2342 return (Datum) 0;
2343}
2344
2345/*
2346 * This function lists the available extension versions (one row per
2347 * extension installation script). For each version, we parse the related
2348 * control file(s) and report the interesting fields.
2349 *
2350 * The system view pg_available_extension_versions provides a user interface
2351 * to this SRF, adding information about which versions are installed in the
2352 * current DB.
2353 */
2354Datum
2356{
2357 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
2358 List *locations;
2359 DIR *dir;
2360 struct dirent *de;
2361 List *found_ext = NIL;
2362
2363 /* Build tuplestore to hold the result rows */
2364 InitMaterializedSRF(fcinfo, 0);
2365
2367
2369 {
2370 dir = AllocateDir(location->loc);
2371
2372 /*
2373 * If the control directory doesn't exist, we want to silently return
2374 * an empty set. Any other error will be reported by ReadDir.
2375 */
2376 if (dir == NULL && errno == ENOENT)
2377 {
2378 /* do nothing */
2379 }
2380 else
2381 {
2382 while ((de = ReadDir(dir, location->loc)) != NULL)
2383 {
2384 ExtensionControlFile *control;
2385 char *extname;
2387
2388 if (!is_extension_control_filename(de->d_name))
2389 continue;
2390
2391 /* extract extension name from 'name.control' filename */
2392 extname = pstrdup(de->d_name);
2393 *strrchr(extname, '.') = '\0';
2394
2395 /* ignore it if it's an auxiliary control file */
2396 if (strstr(extname, "--"))
2397 continue;
2398
2399 /*
2400 * Ignore already-found names. They are not reachable by the
2401 * path search, so don't shown them.
2402 */
2403 extname_str = makeString(extname);
2405 continue;
2406 else
2408
2409 /* read the control file */
2410 control = new_ExtensionControlFile(extname);
2411 control->control_dir = pstrdup(location->loc);
2413
2414 /* scan extension's script directory for install scripts */
2415 get_available_versions_for_extension(control, rsinfo->setResult,
2416 rsinfo->setDesc,
2417 location);
2418 }
2419
2420 FreeDir(dir);
2421 }
2422 }
2423
2424 return (Datum) 0;
2425}
2426
2427/*
2428 * Inner loop for pg_available_extension_versions:
2429 * read versions of one extension, add rows to tupstore
2430 */
2431static void
2433 Tuplestorestate *tupstore,
2434 TupleDesc tupdesc,
2435 ExtensionLocation *location)
2436{
2437 List *evi_list;
2438 ListCell *lc;
2439
2440 /* Extract the version update graph from the script directory */
2442
2443 /* For each installable version ... */
2444 foreach(lc, evi_list)
2445 {
2447 ExtensionControlFile *control;
2448 Datum values[9];
2449 bool nulls[9];
2450 ListCell *lc2;
2451
2452 if (!evi->installable)
2453 continue;
2454
2455 /*
2456 * Fetch parameters for specific version (pcontrol is not changed)
2457 */
2459
2460 memset(values, 0, sizeof(values));
2461 memset(nulls, 0, sizeof(nulls));
2462
2463 /* name */
2465 CStringGetDatum(control->name));
2466 /* version */
2467 values[1] = CStringGetTextDatum(evi->name);
2468 /* superuser */
2469 values[2] = BoolGetDatum(control->superuser);
2470 /* trusted */
2471 values[3] = BoolGetDatum(control->trusted);
2472 /* relocatable */
2473 values[4] = BoolGetDatum(control->relocatable);
2474 /* schema */
2475 if (control->schema == NULL)
2476 nulls[5] = true;
2477 else
2479 CStringGetDatum(control->schema));
2480 /* requires */
2481 if (control->requires == NIL)
2482 nulls[6] = true;
2483 else
2484 values[6] = convert_requires_to_datum(control->requires);
2485
2486 /* location */
2488
2489 /* comment */
2490 if (control->comment == NULL)
2491 nulls[8] = true;
2492 else
2493 values[8] = CStringGetTextDatum(control->comment);
2494
2495 tuplestore_putvalues(tupstore, tupdesc, values, nulls);
2496
2497 /*
2498 * Find all non-directly-installable versions that would be installed
2499 * starting from this version, and report them, inheriting the
2500 * parameters that aren't changed in updates from this version.
2501 */
2502 foreach(lc2, evi_list)
2503 {
2505 List *best_path;
2506
2507 if (evi2->installable)
2508 continue;
2510 {
2511 /*
2512 * Fetch parameters for this version (pcontrol is not changed)
2513 */
2515
2516 /* name stays the same */
2517 /* version */
2518 values[1] = CStringGetTextDatum(evi2->name);
2519 /* superuser */
2520 values[2] = BoolGetDatum(control->superuser);
2521 /* trusted */
2522 values[3] = BoolGetDatum(control->trusted);
2523 /* relocatable */
2524 values[4] = BoolGetDatum(control->relocatable);
2525 /* schema stays the same */
2526 /* requires */
2527 if (control->requires == NIL)
2528 nulls[6] = true;
2529 else
2530 {
2531 values[6] = convert_requires_to_datum(control->requires);
2532 nulls[6] = false;
2533 }
2534 /* comment and location stay the same */
2535
2536 tuplestore_putvalues(tupstore, tupdesc, values, nulls);
2537 }
2538 }
2539 }
2540}
2541
2542/*
2543 * Test whether the given extension exists (not whether it's installed)
2544 *
2545 * This checks for the existence of a matching control file in the extension
2546 * directory. That's not a bulletproof check, since the file might be
2547 * invalid, but this is only used for hints so it doesn't have to be 100%
2548 * right.
2549 */
2550bool
2552{
2553 bool result = false;
2554 List *locations;
2555 DIR *dir;
2556 struct dirent *de;
2557
2559
2560 foreach_ptr(char, location, locations)
2561 {
2562 dir = AllocateDir(location);
2563
2564 /*
2565 * If the control directory doesn't exist, we want to silently return
2566 * false. Any other error will be reported by ReadDir.
2567 */
2568 if (dir == NULL && errno == ENOENT)
2569 {
2570 /* do nothing */
2571 }
2572 else
2573 {
2574 while ((de = ReadDir(dir, location)) != NULL)
2575 {
2576 char *extname;
2577
2578 if (!is_extension_control_filename(de->d_name))
2579 continue;
2580
2581 /* extract extension name from 'name.control' filename */
2582 extname = pstrdup(de->d_name);
2583 *strrchr(extname, '.') = '\0';
2584
2585 /* ignore it if it's an auxiliary control file */
2586 if (strstr(extname, "--"))
2587 continue;
2588
2589 /* done if it matches request */
2590 if (strcmp(extname, extensionName) == 0)
2591 {
2592 result = true;
2593 break;
2594 }
2595 }
2596
2597 FreeDir(dir);
2598 }
2599 if (result)
2600 break;
2601 }
2602
2603 return result;
2604}
2605
2606/*
2607 * Convert a list of extension names to a name[] Datum
2608 */
2609static Datum
2611{
2612 Datum *datums;
2613 int ndatums;
2614 ArrayType *a;
2615 ListCell *lc;
2616
2617 ndatums = list_length(requires);
2618 datums = (Datum *) palloc(ndatums * sizeof(Datum));
2619 ndatums = 0;
2620 foreach(lc, requires)
2621 {
2622 char *curreq = (char *) lfirst(lc);
2623
2624 datums[ndatums++] =
2626 }
2627 a = construct_array_builtin(datums, ndatums, NAMEOID);
2628 return PointerGetDatum(a);
2629}
2630
2631/*
2632 * This function reports the version update paths that exist for the
2633 * specified extension.
2634 */
2635Datum
2637{
2638 Name extname = PG_GETARG_NAME(0);
2639 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
2640 List *evi_list;
2641 ExtensionControlFile *control;
2642 ListCell *lc1;
2643
2644 /* Check extension name validity before any filesystem access */
2646
2647 /* Build tuplestore to hold the result rows */
2648 InitMaterializedSRF(fcinfo, 0);
2649
2650 /* Read the extension's control file */
2651 control = read_extension_control_file(NameStr(*extname));
2652
2653 /* Extract the version update graph from the script directory */
2654 evi_list = get_ext_ver_list(control);
2655
2656 /* Iterate over all pairs of versions */
2657 foreach(lc1, evi_list)
2658 {
2660 ListCell *lc2;
2661
2662 foreach(lc2, evi_list)
2663 {
2665 List *path;
2666 Datum values[3];
2667 bool nulls[3];
2668
2669 if (evi1 == evi2)
2670 continue;
2671
2672 /* Find shortest path from evi1 to evi2 */
2673 path = find_update_path(evi_list, evi1, evi2, false, true);
2674
2675 /* Emit result row */
2676 memset(values, 0, sizeof(values));
2677 memset(nulls, 0, sizeof(nulls));
2678
2679 /* source */
2680 values[0] = CStringGetTextDatum(evi1->name);
2681 /* target */
2682 values[1] = CStringGetTextDatum(evi2->name);
2683 /* path */
2684 if (path == NIL)
2685 nulls[2] = true;
2686 else
2687 {
2689 ListCell *lcv;
2690
2692 /* The path doesn't include start vertex, but show it */
2694 foreach(lcv, path)
2695 {
2696 char *versionName = (char *) lfirst(lcv);
2697
2700 }
2702 pfree(pathbuf.data);
2703 }
2704
2705 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
2706 values, nulls);
2707 }
2708 }
2709
2710 return (Datum) 0;
2711}
2712
2713/*
2714 * pg_extension_config_dump
2715 *
2716 * Record information about a configuration table that belongs to an
2717 * extension being created, but whose contents should be dumped in whole
2718 * or in part during pg_dump.
2719 */
2720Datum
2722{
2723 Oid tableoid = PG_GETARG_OID(0);
2725 char *tablename;
2727 ScanKeyData key[1];
2732 int arrayLength;
2733 int arrayIndex;
2734 bool isnull;
2738 ArrayType *a;
2739
2740 /*
2741 * We only allow this to be called from an extension's SQL script. We
2742 * shouldn't need any permissions check beyond that.
2743 */
2744 if (!creating_extension)
2745 ereport(ERROR,
2747 errmsg("%s can only be called from an SQL script executed by CREATE EXTENSION",
2748 "pg_extension_config_dump()")));
2749
2750 /*
2751 * Check that the table exists and is a member of the extension being
2752 * created. This ensures that we don't need to register an additional
2753 * dependency to protect the extconfig entry.
2754 */
2755 tablename = get_rel_name(tableoid);
2756 if (tablename == NULL)
2757 ereport(ERROR,
2759 errmsg("OID %u does not refer to a table", tableoid)));
2762 ereport(ERROR,
2764 errmsg("table \"%s\" is not a member of the extension being created",
2765 tablename)));
2766
2767 /*
2768 * Add the table OID and WHERE condition to the extension's extconfig and
2769 * extcondition arrays.
2770 *
2771 * If the table is already in extconfig, treat this as an update of the
2772 * WHERE condition.
2773 */
2774
2775 /* Find the pg_extension tuple */
2777
2778 ScanKeyInit(&key[0],
2782
2784 NULL, 1, key);
2785
2787
2788 if (!HeapTupleIsValid(extTup)) /* should not happen */
2789 elog(ERROR, "could not find tuple for extension %u",
2791
2792 memset(repl_val, 0, sizeof(repl_val));
2793 memset(repl_null, false, sizeof(repl_null));
2794 memset(repl_repl, false, sizeof(repl_repl));
2795
2796 /* Build or modify the extconfig value */
2797 elementDatum = ObjectIdGetDatum(tableoid);
2798
2800 RelationGetDescr(extRel), &isnull);
2801 if (isnull)
2802 {
2803 /* Previously empty extconfig, so build 1-element array */
2804 arrayLength = 0;
2805 arrayIndex = 1;
2806
2808 }
2809 else
2810 {
2811 /* Modify or extend existing extconfig array */
2812 Oid *arrayData;
2813 int i;
2814
2816
2817 arrayLength = ARR_DIMS(a)[0];
2818 if (ARR_NDIM(a) != 1 ||
2819 ARR_LBOUND(a)[0] != 1 ||
2820 arrayLength < 0 ||
2821 ARR_HASNULL(a) ||
2822 ARR_ELEMTYPE(a) != OIDOID)
2823 elog(ERROR, "extconfig is not a 1-D Oid array");
2824 arrayData = (Oid *) ARR_DATA_PTR(a);
2825
2826 arrayIndex = arrayLength + 1; /* set up to add after end */
2827
2828 for (i = 0; i < arrayLength; i++)
2829 {
2830 if (arrayData[i] == tableoid)
2831 {
2832 arrayIndex = i + 1; /* replace this element instead */
2833 break;
2834 }
2835 }
2836
2837 a = array_set(a, 1, &arrayIndex,
2839 false,
2840 -1 /* varlena array */ ,
2841 sizeof(Oid) /* OID's typlen */ ,
2842 true /* OID's typbyval */ ,
2843 TYPALIGN_INT /* OID's typalign */ );
2844 }
2847
2848 /* Build or modify the extcondition value */
2850
2852 RelationGetDescr(extRel), &isnull);
2853 if (isnull)
2854 {
2855 if (arrayLength != 0)
2856 elog(ERROR, "extconfig and extcondition arrays do not match");
2857
2859 }
2860 else
2861 {
2863
2864 if (ARR_NDIM(a) != 1 ||
2865 ARR_LBOUND(a)[0] != 1 ||
2866 ARR_HASNULL(a) ||
2868 elog(ERROR, "extcondition is not a 1-D text array");
2869 if (ARR_DIMS(a)[0] != arrayLength)
2870 elog(ERROR, "extconfig and extcondition arrays do not match");
2871
2872 /* Add or replace at same index as in extconfig */
2873 a = array_set(a, 1, &arrayIndex,
2875 false,
2876 -1 /* varlena array */ ,
2877 -1 /* TEXT's typlen */ ,
2878 false /* TEXT's typbyval */ ,
2879 TYPALIGN_INT /* TEXT's typalign */ );
2880 }
2883
2886
2888
2890
2892
2894}
2895
2896/*
2897 * pg_get_loaded_modules
2898 *
2899 * SQL-callable function to get per-loaded-module information. Modules
2900 * (shared libraries) aren't necessarily one-to-one with extensions, but
2901 * they're sufficiently closely related to make this file a good home.
2902 */
2903Datum
2905{
2906 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
2908
2909 /* Build tuplestore to hold the result rows */
2910 InitMaterializedSRF(fcinfo, 0);
2911
2914 {
2915 const char *library_path,
2916 *module_name,
2918 const char *sep;
2919 Datum values[3] = {0};
2920 bool nulls[3] = {0};
2921
2923 &library_path,
2924 &module_name,
2926
2927 if (module_name == NULL)
2928 nulls[0] = true;
2929 else
2931 if (module_version == NULL)
2932 nulls[1] = true;
2933 else
2935
2936 /* For security reasons, we don't show the directory path */
2938 if (sep)
2939 library_path = sep + 1;
2941
2942 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
2943 values, nulls);
2944 }
2945
2946 return (Datum) 0;
2947}
2948
2949/*
2950 * extension_config_remove
2951 *
2952 * Remove the specified table OID from extension's extconfig, if present.
2953 * This is not currently exposed as a function, but it could be;
2954 * for now, we just invoke it from ALTER EXTENSION DROP.
2955 */
2956static void
2958{
2960 ScanKeyData key[1];
2964 int arrayLength;
2965 int arrayIndex;
2966 bool isnull;
2970 ArrayType *a;
2971
2972 /* Find the pg_extension tuple */
2974
2975 ScanKeyInit(&key[0],
2979
2981 NULL, 1, key);
2982
2984
2985 if (!HeapTupleIsValid(extTup)) /* should not happen */
2986 elog(ERROR, "could not find tuple for extension %u",
2987 extensionoid);
2988
2989 /* Search extconfig for the tableoid */
2991 RelationGetDescr(extRel), &isnull);
2992 if (isnull)
2993 {
2994 /* nothing to do */
2995 a = NULL;
2996 arrayLength = 0;
2997 arrayIndex = -1;
2998 }
2999 else
3000 {
3001 Oid *arrayData;
3002 int i;
3003
3005
3006 arrayLength = ARR_DIMS(a)[0];
3007 if (ARR_NDIM(a) != 1 ||
3008 ARR_LBOUND(a)[0] != 1 ||
3009 arrayLength < 0 ||
3010 ARR_HASNULL(a) ||
3011 ARR_ELEMTYPE(a) != OIDOID)
3012 elog(ERROR, "extconfig is not a 1-D Oid array");
3013 arrayData = (Oid *) ARR_DATA_PTR(a);
3014
3015 arrayIndex = -1; /* flag for no deletion needed */
3016
3017 for (i = 0; i < arrayLength; i++)
3018 {
3019 if (arrayData[i] == tableoid)
3020 {
3021 arrayIndex = i; /* index to remove */
3022 break;
3023 }
3024 }
3025 }
3026
3027 /* If tableoid is not in extconfig, nothing to do */
3028 if (arrayIndex < 0)
3029 {
3032 return;
3033 }
3034
3035 /* Modify or delete the extconfig value */
3036 memset(repl_val, 0, sizeof(repl_val));
3037 memset(repl_null, false, sizeof(repl_null));
3038 memset(repl_repl, false, sizeof(repl_repl));
3039
3040 if (arrayLength <= 1)
3041 {
3042 /* removing only element, just set array to null */
3044 }
3045 else
3046 {
3047 /* squeeze out the target element */
3048 Datum *dvalues;
3049 int nelems;
3050 int i;
3051
3052 /* We already checked there are no nulls */
3053 deconstruct_array_builtin(a, OIDOID, &dvalues, NULL, &nelems);
3054
3055 for (i = arrayIndex; i < arrayLength - 1; i++)
3056 dvalues[i] = dvalues[i + 1];
3057
3059
3061 }
3063
3064 /* Modify or delete the extcondition value */
3066 RelationGetDescr(extRel), &isnull);
3067 if (isnull)
3068 {
3069 elog(ERROR, "extconfig and extcondition arrays do not match");
3070 }
3071 else
3072 {
3074
3075 if (ARR_NDIM(a) != 1 ||
3076 ARR_LBOUND(a)[0] != 1 ||
3077 ARR_HASNULL(a) ||
3079 elog(ERROR, "extcondition is not a 1-D text array");
3080 if (ARR_DIMS(a)[0] != arrayLength)
3081 elog(ERROR, "extconfig and extcondition arrays do not match");
3082 }
3083
3084 if (arrayLength <= 1)
3085 {
3086 /* removing only element, just set array to null */
3088 }
3089 else
3090 {
3091 /* squeeze out the target element */
3092 Datum *dvalues;
3093 int nelems;
3094 int i;
3095
3096 /* We already checked there are no nulls */
3097 deconstruct_array_builtin(a, TEXTOID, &dvalues, NULL, &nelems);
3098
3099 for (i = arrayIndex; i < arrayLength - 1; i++)
3100 dvalues[i] = dvalues[i + 1];
3101
3103
3105 }
3107
3110
3112
3114
3116}
3117
3118/*
3119 * Execute ALTER EXTENSION SET SCHEMA
3120 */
3122AlterExtensionNamespace(const char *extensionName, const char *newschema, Oid *oldschema)
3123{
3125 Oid nspOid;
3126 Oid oldNspOid;
3129 ScanKeyData key[2];
3138
3140
3141 nspOid = LookupCreationNamespace(newschema);
3142
3143 /*
3144 * Permission check: must own extension. Note that we don't bother to
3145 * check ownership of the individual member objects ...
3146 */
3150
3151 /* Permission check: must have creation rights in target namespace */
3153 if (aclresult != ACLCHECK_OK)
3155
3156 /*
3157 * If the schema is currently a member of the extension, disallow moving
3158 * the extension into the schema. That would create a dependency loop.
3159 */
3161 ereport(ERROR,
3163 errmsg("cannot move extension \"%s\" into schema \"%s\" "
3164 "because the extension contains the schema",
3165 extensionName, newschema)));
3166
3167 /* Locate the pg_extension tuple */
3169
3170 ScanKeyInit(&key[0],
3174
3176 NULL, 1, key);
3177
3179
3180 if (!HeapTupleIsValid(extTup)) /* should not happen */
3181 elog(ERROR, "could not find tuple for extension %u",
3182 extensionOid);
3183
3184 /* Copy tuple so we can modify it below */
3187
3189
3190 /*
3191 * If the extension is already in the target schema, just silently do
3192 * nothing.
3193 */
3194 if (extForm->extnamespace == nspOid)
3195 {
3197 return InvalidObjectAddress;
3198 }
3199
3200 /* Check extension is supposed to be relocatable */
3201 if (!extForm->extrelocatable)
3202 ereport(ERROR,
3204 errmsg("extension \"%s\" does not support SET SCHEMA",
3205 NameStr(extForm->extname))));
3206
3208
3209 /* store the OID of the namespace to-be-changed */
3210 oldNspOid = extForm->extnamespace;
3211
3212 /*
3213 * Scan pg_depend to find objects that depend directly on the extension,
3214 * and alter each one's schema.
3215 */
3217
3218 ScanKeyInit(&key[0],
3222 ScanKeyInit(&key[1],
3226
3228 NULL, 2, key);
3229
3231 {
3235
3236 /*
3237 * If a dependent extension has a no_relocate request for this
3238 * extension, disallow SET SCHEMA. (XXX it's a bit ugly to do this in
3239 * the same loop that's actually executing the renames: we may detect
3240 * the error condition only after having expended a fair amount of
3241 * work. However, the alternative is to do two scans of pg_depend,
3242 * which seems like optimizing for failure cases. The rename work
3243 * will all roll back cleanly enough if we do fail here.)
3244 */
3245 if (pg_depend->deptype == DEPENDENCY_NORMAL &&
3246 pg_depend->classid == ExtensionRelationId)
3247 {
3248 char *depextname = get_extension_name(pg_depend->objid);
3250 ListCell *lc;
3251
3253 foreach(lc, dcontrol->no_relocate)
3254 {
3255 char *nrextname = (char *) lfirst(lc);
3256
3257 if (strcmp(nrextname, NameStr(extForm->extname)) == 0)
3258 {
3259 ereport(ERROR,
3261 errmsg("cannot SET SCHEMA of extension \"%s\" because other extensions prevent it",
3262 NameStr(extForm->extname)),
3263 errdetail("Extension \"%s\" requests no relocation of extension \"%s\".",
3264 depextname,
3265 NameStr(extForm->extname))));
3266 }
3267 }
3268 }
3269
3270 /*
3271 * Otherwise, ignore non-membership dependencies. (Currently, the
3272 * only other case we could see here is a normal dependency from
3273 * another extension.)
3274 */
3275 if (pg_depend->deptype != DEPENDENCY_EXTENSION)
3276 continue;
3277
3278 dep.classId = pg_depend->classid;
3279 dep.objectId = pg_depend->objid;
3280 dep.objectSubId = pg_depend->objsubid;
3281
3282 if (dep.objectSubId != 0) /* should not happen */
3283 elog(ERROR, "extension should not have a sub-object dependency");
3284
3285 /* Relocate the object */
3287 dep.objectId,
3288 nspOid,
3289 objsMoved);
3290
3291 /*
3292 * If not all the objects had the same old namespace (ignoring any
3293 * that are not in namespaces or are dependent types), complain.
3294 */
3296 ereport(ERROR,
3298 errmsg("extension \"%s\" does not support SET SCHEMA",
3299 NameStr(extForm->extname)),
3300 errdetail("%s is not in the extension's schema \"%s\"",
3301 getObjectDescription(&dep, false),
3303 }
3304
3305 /* report old schema, if caller wants it */
3306 if (oldschema)
3308
3310
3312
3313 /* Now adjust pg_extension.extnamespace */
3314 extForm->extnamespace = nspOid;
3315
3317
3319
3320 /* update dependency to point to the new schema */
3323 elog(ERROR, "could not change schema dependency for extension %s",
3324 NameStr(extForm->extname));
3325
3327
3329
3330 return extAddr;
3331}
3332
3333/*
3334 * Execute ALTER EXTENSION UPDATE
3335 */
3338{
3340 char *versionName;
3341 char *oldVersionName;
3342 ExtensionControlFile *control;
3345 ScanKeyData key[1];
3349 Datum datum;
3350 bool isnull;
3351 ListCell *lc;
3352 ObjectAddress address;
3353
3354 /*
3355 * We use global variables to track the extension being created, so we can
3356 * create/update only one extension at the same time.
3357 */
3359 ereport(ERROR,
3361 errmsg("nested ALTER EXTENSION is not supported")));
3362
3363 /*
3364 * Look up the extension --- it must already exist in pg_extension
3365 */
3367
3368 ScanKeyInit(&key[0],
3371 CStringGetDatum(stmt->extname));
3372
3374 NULL, 1, key);
3375
3377
3379 ereport(ERROR,
3381 errmsg("extension \"%s\" does not exist",
3382 stmt->extname)));
3383
3385
3386 /*
3387 * Determine the existing version we are updating from
3388 */
3390 RelationGetDescr(extRel), &isnull);
3391 if (isnull)
3392 elog(ERROR, "extversion is null");
3394
3396
3398
3399 /* Permission check: must own extension */
3402 stmt->extname);
3403
3404 /*
3405 * Read the primary control file. Note we assume that it does not contain
3406 * any non-ASCII data, so there is no need to worry about encoding at this
3407 * point.
3408 */
3409 control = read_extension_control_file(stmt->extname);
3410
3411 /*
3412 * Read the statement option list
3413 */
3414 foreach(lc, stmt->options)
3415 {
3416 DefElem *defel = (DefElem *) lfirst(lc);
3417
3418 if (strcmp(defel->defname, "new_version") == 0)
3419 {
3420 if (d_new_version)
3423 }
3424 else
3425 elog(ERROR, "unrecognized option: %s", defel->defname);
3426 }
3427
3428 /*
3429 * Determine the version to update to
3430 */
3431 if (d_new_version && d_new_version->arg)
3433 else if (control->default_version)
3434 versionName = control->default_version;
3435 else
3436 {
3437 ereport(ERROR,
3439 errmsg("version to install must be specified")));
3440 versionName = NULL; /* keep compiler quiet */
3441 }
3443
3444 /*
3445 * If we're already at that version, just say so
3446 */
3448 {
3450 (errmsg("version \"%s\" of extension \"%s\" is already installed",
3451 versionName, stmt->extname)));
3452 return InvalidObjectAddress;
3453 }
3454
3455 /*
3456 * Identify the series of update script files we need to execute
3457 */
3460 versionName);
3461
3462 /*
3463 * Update the pg_extension row and execute the update scripts, one at a
3464 * time
3465 */
3468 NULL, false, false);
3469
3471
3472 return address;
3473}
3474
3475/*
3476 * Apply a series of update scripts as though individual ALTER EXTENSION
3477 * UPDATE commands had been given, including altering the pg_extension row
3478 * and dependencies each time.
3479 *
3480 * This might be more work than necessary, but it ensures that old update
3481 * scripts don't break if newer versions have different control parameters.
3482 */
3483static void
3486 const char *initialVersion,
3488 char *origSchemaName,
3489 bool cascade,
3490 bool is_create)
3491{
3492 const char *oldVersionName = initialVersion;
3493 ListCell *lcv;
3494
3495 foreach(lcv, updateVersions)
3496 {
3497 char *versionName = (char *) lfirst(lcv);
3498 ExtensionControlFile *control;
3499 char *schemaName;
3500 Oid schemaOid;
3504 ScanKeyData key[1];
3509 bool nulls[Natts_pg_extension];
3510 bool repl[Natts_pg_extension];
3512 ListCell *lc;
3513
3514 /*
3515 * Fetch parameters for specific version (pcontrol is not changed)
3516 */
3518
3519 /* Find the pg_extension tuple */
3521
3522 ScanKeyInit(&key[0],
3526
3528 NULL, 1, key);
3529
3531
3532 if (!HeapTupleIsValid(extTup)) /* should not happen */
3533 elog(ERROR, "could not find tuple for extension %u",
3534 extensionOid);
3535
3537
3538 /*
3539 * Determine the target schema (set by original install)
3540 */
3541 schemaOid = extForm->extnamespace;
3543
3544 /*
3545 * Modify extrelocatable and extversion in the pg_extension tuple
3546 */
3547 memset(values, 0, sizeof(values));
3548 memset(nulls, 0, sizeof(nulls));
3549 memset(repl, 0, sizeof(repl));
3550
3552 BoolGetDatum(control->relocatable);
3553 repl[Anum_pg_extension_extrelocatable - 1] = true;
3556 repl[Anum_pg_extension_extversion - 1] = true;
3557
3559 values, nulls, repl);
3560
3562
3564
3566
3567 /*
3568 * Look up the prerequisite extensions for this version, install them
3569 * if necessary, and build lists of their OIDs and the OIDs of their
3570 * target schemas.
3571 */
3574 foreach(lc, control->requires)
3575 {
3576 char *curreq = (char *) lfirst(lc);
3577 Oid reqext;
3578 Oid reqschema;
3579
3581 control->name,
3583 cascade,
3584 NIL,
3585 is_create);
3589 }
3590
3591 /*
3592 * Remove and recreate dependencies on prerequisite extensions
3593 */
3597
3598 myself.classId = ExtensionRelationId;
3599 myself.objectId = extensionOid;
3600 myself.objectSubId = 0;
3601
3602 foreach(lc, requiredExtensions)
3603 {
3606
3608 otherext.objectId = reqext;
3609 otherext.objectSubId = 0;
3610
3612 }
3613
3615
3616 /*
3617 * Finally, execute the update script file
3618 */
3622 schemaName);
3623
3624 /*
3625 * Update prior-version name and loop around. Since
3626 * execute_sql_string did a final CommandCounterIncrement, we can
3627 * update the pg_extension row again.
3628 */
3630 }
3631}
3632
3633/*
3634 * Execute ALTER EXTENSION ADD/DROP
3635 *
3636 * Return value is the address of the altered extension.
3637 *
3638 * objAddr is an output argument which, if not NULL, is set to the address of
3639 * the added/dropped object.
3640 */
3644{
3646 ObjectAddress object;
3647 Relation relation;
3648
3649 switch (stmt->objtype)
3650 {
3651 case OBJECT_DATABASE:
3652 case OBJECT_EXTENSION:
3653 case OBJECT_INDEX:
3654 case OBJECT_PUBLICATION:
3655 case OBJECT_ROLE:
3658 case OBJECT_TABLESPACE:
3659 ereport(ERROR,
3661 errmsg("cannot add an object of this type to an extension")));
3662 break;
3663 default:
3664 /* OK */
3665 break;
3666 }
3667
3668 /*
3669 * Find the extension and acquire a lock on it, to ensure it doesn't get
3670 * dropped concurrently. A sharable lock seems sufficient: there's no
3671 * reason not to allow other sorts of manipulations, such as add/drop of
3672 * other objects, to occur concurrently. Concurrently adding/dropping the
3673 * *same* object would be bad, but we prevent that by using a non-sharable
3674 * lock on the individual object, below.
3675 */
3677 (Node *) makeString(stmt->extname),
3678 &relation, AccessShareLock, false);
3679
3680 /* Permission check: must own extension */
3683 stmt->extname);
3684
3685 /*
3686 * Translate the parser representation that identifies the object into an
3687 * ObjectAddress. get_object_address() will throw an error if the object
3688 * does not exist, and will also acquire a lock on the object to guard
3689 * against concurrent DROP and ALTER EXTENSION ADD/DROP operations.
3690 */
3691 object = get_object_address(stmt->objtype, stmt->object,
3692 &relation, ShareUpdateExclusiveLock, false);
3693
3694 Assert(object.objectSubId == 0);
3695 if (objAddr)
3696 *objAddr = object;
3697
3698 /* Permission check: must own target object, too */
3699 check_object_ownership(GetUserId(), stmt->objtype, object,
3700 stmt->object, relation);
3701
3702 /* Do the update, recursing to any dependent objects */
3704
3705 /* Finish up */
3707
3708 /*
3709 * If get_object_address() opened the relation for us, we close it to keep
3710 * the reference count correct - but we retain any locks acquired by
3711 * get_object_address() until commit time, to guard against concurrent
3712 * activity.
3713 */
3714 if (relation != NULL)
3715 relation_close(relation, NoLock);
3716
3717 return extension;
3718}
3719
3720/*
3721 * ExecAlterExtensionContentsRecurse
3722 * Subroutine for ExecAlterExtensionContentsStmt
3723 *
3724 * Do the bare alteration of object's membership in extension,
3725 * without permission checks. Recurse to dependent objects, if any.
3726 */
3727static void
3730 ObjectAddress object)
3731{
3733
3734 /*
3735 * Check existing extension membership.
3736 */
3737 oldExtension = getExtensionOfObject(object.classId, object.objectId);
3738
3739 if (stmt->action > 0)
3740 {
3741 /*
3742 * ADD, so complain if object is already attached to some extension.
3743 */
3745 ereport(ERROR,
3747 errmsg("%s is already a member of extension \"%s\"",
3748 getObjectDescription(&object, false),
3750
3751 /*
3752 * Prevent a schema from being added to an extension if the schema
3753 * contains the extension. That would create a dependency loop.
3754 */
3755 if (object.classId == NamespaceRelationId &&
3756 object.objectId == get_extension_schema(extension.objectId))
3757 ereport(ERROR,
3759 errmsg("cannot add schema \"%s\" to extension \"%s\" "
3760 "because the schema contains the extension",
3761 get_namespace_name(object.objectId),
3762 stmt->extname)));
3763
3764 /*
3765 * OK, add the dependency.
3766 */
3768
3769 /*
3770 * Also record the initial ACL on the object, if any.
3771 *
3772 * Note that this will handle the object's ACLs, as well as any ACLs
3773 * on object subIds. (In other words, when the object is a table,
3774 * this will record the table's ACL and the ACLs for the columns on
3775 * the table, if any).
3776 */
3777 recordExtObjInitPriv(object.objectId, object.classId);
3778 }
3779 else
3780 {
3781 /*
3782 * DROP, so complain if it's not a member.
3783 */
3784 if (oldExtension != extension.objectId)
3785 ereport(ERROR,
3787 errmsg("%s is not a member of extension \"%s\"",
3788 getObjectDescription(&object, false),
3789 stmt->extname)));
3790
3791 /*
3792 * OK, drop the dependency.
3793 */
3794 if (deleteDependencyRecordsForClass(object.classId, object.objectId,
3797 elog(ERROR, "unexpected number of extension dependency records");
3798
3799 /*
3800 * If it's a relation, it might have an entry in the extension's
3801 * extconfig array, which we must remove.
3802 */
3803 if (object.classId == RelationRelationId)
3804 extension_config_remove(extension.objectId, object.objectId);
3805
3806 /*
3807 * Remove all the initial ACLs, if any.
3808 *
3809 * Note that this will remove the object's ACLs, as well as any ACLs
3810 * on object subIds. (In other words, when the object is a table,
3811 * this will remove the table's ACL and the ACLs for the columns on
3812 * the table, if any).
3813 */
3814 removeExtObjInitPriv(object.objectId, object.classId);
3815 }
3816
3817 /*
3818 * Recurse to any dependent objects; currently, this includes the array
3819 * type of a base type, the multirange type associated with a range type,
3820 * and the rowtype of a table.
3821 */
3822 if (object.classId == TypeRelationId)
3823 {
3825
3827 depobject.objectSubId = 0;
3828
3829 /* If it has an array type, update that too */
3830 depobject.objectId = get_array_type(object.objectId);
3831 if (OidIsValid(depobject.objectId))
3833
3834 /* If it is a range type, update the associated multirange too */
3835 if (type_is_range(object.objectId))
3836 {
3837 depobject.objectId = get_range_multirange(object.objectId);
3838 if (!OidIsValid(depobject.objectId))
3839 ereport(ERROR,
3841 errmsg("could not find multirange type for data type %s",
3842 format_type_be(object.objectId))));
3844 }
3845 }
3846 if (object.classId == RelationRelationId)
3847 {
3849
3851 depobject.objectSubId = 0;
3852
3853 /* It might not have a rowtype, but if it does, update that */
3854 depobject.objectId = get_rel_type_id(object.objectId);
3855 if (OidIsValid(depobject.objectId))
3857 }
3858}
3859
3860/*
3861 * Read the whole of file into memory.
3862 *
3863 * The file contents are returned as a single palloc'd chunk. For convenience
3864 * of the callers, an extra \0 byte is added to the end. That is not counted
3865 * in the length returned into *length.
3866 */
3867static char *
3868read_whole_file(const char *filename, int *length)
3869{
3870 char *buf;
3871 FILE *file;
3872 size_t bytes_to_read;
3873 struct stat fst;
3874
3875 if (stat(filename, &fst) < 0)
3876 ereport(ERROR,
3878 errmsg("could not stat file \"%s\": %m", filename)));
3879
3880 if (fst.st_size > (MaxAllocSize - 1))
3881 ereport(ERROR,
3883 errmsg("file \"%s\" is too large", filename)));
3884 bytes_to_read = (size_t) fst.st_size;
3885
3886 if ((file = AllocateFile(filename, PG_BINARY_R)) == NULL)
3887 ereport(ERROR,
3889 errmsg("could not open file \"%s\" for reading: %m",
3890 filename)));
3891
3892 buf = (char *) palloc(bytes_to_read + 1);
3893
3894 bytes_to_read = fread(buf, 1, bytes_to_read, file);
3895
3896 if (ferror(file))
3897 ereport(ERROR,
3899 errmsg("could not read file \"%s\": %m", filename)));
3900
3901 FreeFile(file);
3902
3903 buf[bytes_to_read] = '\0';
3904
3905 /*
3906 * On Windows, manually convert Windows-style newlines (\r\n) to the Unix
3907 * convention of \n only. This avoids gotchas due to script files
3908 * possibly getting converted when being transferred between platforms.
3909 * Ideally we'd do this by using text mode to read the file, but that also
3910 * causes control-Z to be treated as end-of-file. Historically we've
3911 * allowed control-Z in script files, so breaking that seems unwise.
3912 */
3913#ifdef WIN32
3914 {
3915 char *s,
3916 *d;
3917
3918 for (s = d = buf; *s; s++)
3919 {
3920 if (!(*s == '\r' && s[1] == '\n'))
3921 *d++ = *s;
3922 }
3923 *d = '\0';
3924 bytes_to_read = d - buf;
3925 }
3926#endif
3927
3928 *length = bytes_to_read;
3929 return buf;
3930}
3931
3932static ExtensionControlFile *
3933new_ExtensionControlFile(const char *extname)
3934{
3935 /*
3936 * Set up default values. Pointer fields are initially null.
3937 */
3939
3940 control->name = pstrdup(extname);
3941 control->relocatable = false;
3942 control->superuser = true;
3943 control->trusted = false;
3944 control->encoding = -1;
3945
3946 return control;
3947}
3948
3949/*
3950 * Search for the basename in the list of paths.
3951 *
3952 * Similar to find_in_path but for simplicity does not support custom error
3953 * messages and expects that paths already have all macros replaced.
3954 */
3955char *
3956find_in_paths(const char *basename, List *paths)
3957{
3958 ListCell *cell;
3959
3960 foreach(cell, paths)
3961 {
3962 ExtensionLocation *location = lfirst(cell);
3963 char *path = location->loc;
3964 char *full;
3965
3966 Assert(path != NULL);
3967
3968 path = pstrdup(path);
3969 canonicalize_path(path);
3970
3971 /* only absolute paths */
3972 if (!is_absolute_path(path))
3973 ereport(ERROR,
3975 errmsg("component in parameter \"%s\" is not an absolute path", "extension_control_path"));
3976
3977 full = psprintf("%s/%s", path, basename);
3978
3979 if (pg_file_exists(full))
3980 return full;
3981
3982 pfree(path);
3983 pfree(full);
3984 }
3985
3986 return NULL;
3987}
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:619
#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)
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
void deconstruct_array_builtin(const ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
bool parse_bool(const char *value, bool *result)
Definition bool.c:31
static Datum values[MAXATTR]
Definition bootstrap.c:155
#define CStringGetTextDatum(s)
Definition builtins.h:97
#define NameStr(name)
Definition c.h:765
#define PG_BINARY_R
Definition c.h:1283
#define Assert(condition)
Definition c.h:873
#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:34
bool defGetBoolean(DefElem *def)
Definition define.c:93
void errorConflictingDefElem(DefElem *defel, ParseState *pstate)
Definition define.c:370
void record_object_address_dependencies(const ObjectAddress *depender, ObjectAddresses *referenced, DependencyType behavior)
void add_exact_object_address(const ObjectAddress *object, ObjectAddresses *addrs)
ObjectAddresses * new_object_addresses(void)
void free_object_addresses(ObjectAddresses *addrs)
@ 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:3868
ObjectAddress InsertExtensionTuple(const char *extName, Oid extOwner, Oid schemaOid, bool relocatable, const char *extVersion, Datum extConfig, Datum extCondition, List *requiredExtensions)
Definition extension.c:2111
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:1421
ObjectAddress CreateExtension(ParseState *pstate, CreateExtensionStmt *stmt)
Definition extension.c:2013
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:2432
static bool is_extension_control_filename(const char *filename)
Definition extension.c:364
Datum pg_get_loaded_modules(PG_FUNCTION_ARGS)
Definition extension.c:2904
static Oid get_required_extension(char *reqExtensionName, char *extensionName, char *origSchemaName, bool cascade, List *parents, bool is_create)
Definition extension.c:1942
static void script_error_callback(void *arg)
Definition extension.c:823
static ExtensionControlFile * read_extension_aux_control_file(const ExtensionControlFile *pcontrol, const char *version)
Definition extension.c:767
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:560
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:2355
static void extension_config_remove(Oid extensionoid, Oid tableoid)
Definition extension.c:2957
static void execute_sql_string(const char *sql, const char *filename)
Definition extension.c:965
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:3122
static ExtensionVersionInfo * find_install_path(List *evi_list, ExtensionVersionInfo *evi_target, List **best_path)
Definition extension.c:1648
static ExtensionControlFile * read_extension_control_file(const char *extname)
Definition extension.c:748
ObjectAddress ExecAlterExtensionStmt(ParseState *pstate, AlterExtensionStmt *stmt)
Definition extension.c:3337
Oid CurrentExtensionObject
Definition extension.c:78
ObjectAddress ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt, ObjectAddress *objAddr)
Definition extension.c:3642
Datum pg_extension_update_paths(PG_FUNCTION_ARGS)
Definition extension.c:2636
static char * read_extension_script_file(const ExtensionControlFile *control, const char *filename)
Definition extension.c:790
static void ExecAlterExtensionContentsRecurse(AlterExtensionContentsStmt *stmt, ObjectAddress extension, ObjectAddress object)
Definition extension.c:3728
Oid get_extension_oid(const char *extname, bool missing_ok)
Definition extension.c:206
Datum pg_available_extensions(PG_FUNCTION_ARGS)
Definition extension.c:2253
static ExtensionControlFile * new_ExtensionControlFile(const char *extname)
Definition extension.c:3933
Datum pg_extension_config_dump(PG_FUNCTION_ARGS)
Definition extension.c:2721
char * find_in_paths(const char *basename, List *paths)
Definition extension.c:3956
static Datum convert_requires_to_datum(List *requires)
Definition extension.c:2610
static List * identify_update_path(ExtensionControlFile *control, const char *oldVersion, const char *newVersion)
Definition extension.c:1512
static ExtensionVersionInfo * get_ext_ver_info(const char *versionname, List **evi_list)
Definition extension.c:1388
char * get_extension_name(Oid ext_oid)
Definition extension.c:228
void RemoveExtensionById(Oid extId)
Definition extension.c:2199
static List * get_ext_ver_list(ExtensionControlFile *control)
Definition extension.c:1449
static List * find_update_path(List *evi_list, ExtensionVersionInfo *evi_start, ExtensionVersionInfo *evi_target, bool reject_indirect, bool reinitialize)
Definition extension.c:1555
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:1115
bool extension_file_exists(const char *extensionName)
Definition extension.c:2551
static bool extension_is_trusted(ExtensionControlFile *control)
Definition extension.c:1093
static void ApplyExtensionUpdates(Oid extensionOid, ExtensionControlFile *pcontrol, const char *initialVersion, List *updateVersions, char *origSchemaName, bool cascade, bool is_create)
Definition extension.c:3484
static ObjectAddress CreateExtensionInternal(char *extensionName, char *schemaName, const char *versionName, bool cascade, List *parents, bool is_create)
Definition extension.c:1703
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:350
#define PG_GETARG_OID(n)
Definition fmgr.h:275
#define PG_GETARG_TEXT_PP(n)
Definition fmgr.h:310
#define DatumGetTextPP(X)
Definition fmgr.h:293
#define DirectFunctionCall1(func, arg1)
Definition fmgr.h:684
#define PG_GETARG_NAME(n)
Definition fmgr.h:279
#define PG_FUNCTION_ARGS
Definition fmgr.h:193
char * format_type_be(Oid type_oid)
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
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)
static void * GETSTRUCT(const HeapTupleData *tuple)
#define stmt
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
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)
#define InvokeObjectPostAlterHook(classId, objectId, subId)
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)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition palloc.h:124
@ OBJECT_SCHEMA
@ OBJECT_TABLESPACE
@ OBJECT_ROLE
@ OBJECT_EXTENSION
@ OBJECT_INDEX
@ OBJECT_DATABASE
@ OBJECT_PUBLICATION
@ OBJECT_SUBSCRIPTION
@ OBJECT_STATISTIC_EXT
#define CURSOR_OPT_PARALLEL_OK
#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
#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)
static char buf[DEFAULT_XLOG_SEG_SIZE]
#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:352
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:380
#define InvalidOid
unsigned int Oid
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
static int fb(int x)
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:540
const char * quote_identifier(const char *ident)
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
Definition dirent.c:26
struct ErrorContextCallback * previous
Definition elog.h:297
List *List * no_relocate
Definition extension.c:100
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
ParseLoc stmt_len
TupleDesc rd_att
Definition rel.h:112
Definition value.h:64
Definition c.h:760
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:2730
char * text_to_cstring(const text *t)
Definition varlena.c:214
Datum replace_text(PG_FUNCTION_ARGS)
Definition varlena.c:3078
#define stat
Definition win32_port.h:74
void CommandCounterIncrement(void)
Definition xact.c:1101
int MyXactFlags
Definition xact.c:137
#define XACT_FLAGS_ACCESSEDTEMPNAMESPACE
Definition xact.h:103