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