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