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