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 */
70bool creating_extension = false;
71Oid CurrentExtensionObject = InvalidOid;
72
73/*
74 * Internal data structure to hold the results of parsing a control file
75 */
76typedef 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 */
94typedef 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 */
106static List *find_update_path(List *evi_list,
107 ExtensionVersionInfo *evi_start,
108 ExtensionVersionInfo *evi_target,
109 bool reject_indirect,
110 bool reinitialize);
111static Oid get_required_extension(char *reqExtensionName,
112 char *extensionName,
113 char *origSchemaName,
114 bool cascade,
115 List *parents,
116 bool is_create);
117static void get_available_versions_for_extension(ExtensionControlFile *pcontrol,
118 Tuplestorestate *tupstore,
119 TupleDesc tupdesc);
120static Datum convert_requires_to_datum(List *requires);
121static void ApplyExtensionUpdates(Oid extensionOid,
122 ExtensionControlFile *pcontrol,
123 const char *initialVersion,
124 List *updateVersions,
125 char *origSchemaName,
126 bool cascade,
127 bool is_create);
128static 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 */
137Oid
138get_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 */
182char *
183get_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 */
221static Oid
222get_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 */
258static void
259check_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
305static void
306check_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 */
352static bool
353is_extension_control_filename(const char *filename)
354{
355 const char *extension = strrchr(filename, '.');
356
357 return (extension != NULL) && (strcmp(extension, ".control") == 0);
358}
359
360static bool
361is_extension_script_filename(const char *filename)
362{
363 const char *extension = strrchr(filename, '.');
364
365 return (extension != NULL) && (strcmp(extension, ".sql") == 0);
366}
367
368static char *
369get_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
381static char *
382get_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
395static char *
396get_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
418static char *
419get_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
436static char *
437get_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 */
468static void
469parse_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 */
605static ExtensionControlFile *
606read_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 */
633static ExtensionControlFile *
634read_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 */
656static char *
657read_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 */
697static void
698execute_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 */
786static void
787execute_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 * Set up the search path to contain the target schema, then the schemas
843 * of any prerequisite extensions, and nothing else. In particular this
844 * makes the target schema be the default creation target namespace.
845 *
846 * Note: it might look tempting to use PushOverrideSearchPath for this,
847 * but we cannot do that. We have to actually set the search_path GUC in
848 * case the extension script examines or changes it. In any case, the
849 * GUC_ACTION_SAVE method is just as convenient.
850 */
851 initStringInfo(&pathbuf);
852 appendStringInfoString(&pathbuf, quote_identifier(schemaName));
853 foreach(lc, requiredSchemas)
854 {
855 Oid reqschema = lfirst_oid(lc);
856 char *reqname = get_namespace_name(reqschema);
857
858 if (reqname)
859 appendStringInfo(&pathbuf, ", %s", quote_identifier(reqname));
860 }
861
862 (void) set_config_option("search_path", pathbuf.data,
863 PGC_USERSET, PGC_S_SESSION,
864 GUC_ACTION_SAVE, true, 0, false);
865
866 /*
867 * Set creating_extension and related variables so that
868 * recordDependencyOnCurrentExtension and other functions do the right
869 * things. On failure, ensure we reset these variables.
870 */
871 creating_extension = true;
872 CurrentExtensionObject = extensionOid;
873 PG_TRY();
874 {
875 char *c_sql = read_extension_script_file(control, filename);
876 Datum t_sql;
877
878 /* We use various functions that want to operate on text datums */
879 t_sql = CStringGetTextDatum(c_sql);
880
881 /*
882 * Reduce any lines beginning with "\echo" to empty. This allows
883 * scripts to contain messages telling people not to run them via
884 * psql, which has been found to be necessary due to old habits.
885 */
886 t_sql = DirectFunctionCall4Coll(textregexreplace,
887 C_COLLATION_OID,
888 t_sql,
889 CStringGetTextDatum("^\\\\echo.*$"),
890 CStringGetTextDatum(""),
891 CStringGetTextDatum("ng"));
892
893 /*
894 * If it's not relocatable, substitute the target schema name for
895 * occurrences of @extschema@.
896 *
897 * For a relocatable extension, we needn't do this. There cannot be
898 * any need for @extschema@, else it wouldn't be relocatable.
899 */
900 if (!control->relocatable)
901 {
902 const char *qSchemaName = quote_identifier(schemaName);
903
904 t_sql = DirectFunctionCall3Coll(replace_text,
905 C_COLLATION_OID,
906 t_sql,
907 CStringGetTextDatum("@extschema@"),
908 CStringGetTextDatum(qSchemaName));
909 }
910
911 /*
912 * If module_pathname was set in the control file, substitute its
913 * value for occurrences of MODULE_PATHNAME.
914 */
915 if (control->module_pathname)
916 {
917 t_sql = DirectFunctionCall3Coll(replace_text,
918 C_COLLATION_OID,
919 t_sql,
920 CStringGetTextDatum("MODULE_PATHNAME"),
921 CStringGetTextDatum(control->module_pathname));
922 }
923
924 /* And now back to C string */
925 c_sql = text_to_cstring(DatumGetTextPP(t_sql));
926
927 execute_sql_string(c_sql);
928 }
929 PG_CATCH();
930 {
931 creating_extension = false;
932 CurrentExtensionObject = InvalidOid;
933 PG_RE_THROW();
934 }
935 PG_END_TRY();
936
937 creating_extension = false;
938 CurrentExtensionObject = InvalidOid;
939
940 /*
941 * Restore the GUC variables we set above.
942 */
943 AtEOXact_GUC(true, save_nestlevel);
944}
945
946/*
947 * Find or create an ExtensionVersionInfo for the specified version name
948 *
949 * Currently, we just use a List of the ExtensionVersionInfo's. Searching
950 * for them therefore uses about O(N^2) time when there are N versions of
951 * the extension. We could change the data structure to a hash table if
952 * this ever becomes a bottleneck.
953 */
954static ExtensionVersionInfo *
955get_ext_ver_info(const char *versionname, List **evi_list)
956{
957 ExtensionVersionInfo *evi;
958 ListCell *lc;
959
960 foreach(lc, *evi_list)
961 {
962 evi = (ExtensionVersionInfo *) lfirst(lc);
963 if (strcmp(evi->name, versionname) == 0)
964 return evi;
965 }
966
967 evi = (ExtensionVersionInfo *) palloc(sizeof(ExtensionVersionInfo));
968 evi->name = pstrdup(versionname);
969 evi->reachable = NIL;
970 evi->installable = false;
971 /* initialize for later application of Dijkstra's algorithm */
972 evi->distance_known = false;
973 evi->distance = INT_MAX;
974 evi->previous = NULL;
975
976 *evi_list = lappend(*evi_list, evi);
977
978 return evi;
979}
980
981/*
982 * Locate the nearest unprocessed ExtensionVersionInfo
983 *
984 * This part of the algorithm is also about O(N^2). A priority queue would
985 * make it much faster, but for now there's no need.
986 */
987static ExtensionVersionInfo *
988get_nearest_unprocessed_vertex(List *evi_list)
989{
990 ExtensionVersionInfo *evi = NULL;
991 ListCell *lc;
992
993 foreach(lc, evi_list)
994 {
995 ExtensionVersionInfo *evi2 = (ExtensionVersionInfo *) lfirst(lc);
996
997 /* only vertices whose distance is still uncertain are candidates */
998 if (evi2->distance_known)
999 continue;
1000 /* remember the closest such vertex */
1001 if (evi == NULL ||
1002 evi->distance > evi2->distance)
1003 evi = evi2;
1004 }
1005
1006 return evi;
1007}
1008
1009/*
1010 * Obtain information about the set of update scripts available for the
1011 * specified extension. The result is a List of ExtensionVersionInfo
1012 * structs, each with a subsidiary list of the ExtensionVersionInfos for
1013 * the versions that can be reached in one step from that version.
1014 */
1015static List *
1016get_ext_ver_list(ExtensionControlFile *control)
1017{
1018 List *evi_list = NIL;
1019 int extnamelen = strlen(control->name);
1020 char *location;
1021 DIR *dir;
1022 struct dirent *de;
1023
1024 location = get_extension_script_directory(control);
1025 dir = AllocateDir(location);
1026 while ((de = ReadDir(dir, location)) != NULL)
1027 {
1028 char *vername;
1029 char *vername2;
1030 ExtensionVersionInfo *evi;
1031 ExtensionVersionInfo *evi2;
1032
1033 /* must be a .sql file ... */
1034 if (!is_extension_script_filename(de->d_name))
1035 continue;
1036
1037 /* ... matching extension name followed by separator */
1038 if (strncmp(de->d_name, control->name, extnamelen) != 0 ||
1039 de->d_name[extnamelen] != '-' ||
1040 de->d_name[extnamelen + 1] != '-')
1041 continue;
1042
1043 /* extract version name(s) from 'extname--something.sql' filename */
1044 vername = pstrdup(de->d_name + extnamelen + 2);
1045 *strrchr(vername, '.') = '\0';
1046 vername2 = strstr(vername, "--");
1047 if (!vername2)
1048 {
1049 /* It's an install, not update, script; record its version name */
1050 evi = get_ext_ver_info(vername, &evi_list);
1051 evi->installable = true;
1052 continue;
1053 }
1054 *vername2 = '\0'; /* terminate first version */
1055 vername2 += 2; /* and point to second */
1056
1057 /* if there's a third --, it's bogus, ignore it */
1058 if (strstr(vername2, "--"))
1059 continue;
1060
1061 /* Create ExtensionVersionInfos and link them together */
1062 evi = get_ext_ver_info(vername, &evi_list);
1063 evi2 = get_ext_ver_info(vername2, &evi_list);
1064 evi->reachable = lappend(evi->reachable, evi2);
1065 }
1066 FreeDir(dir);
1067
1068 return evi_list;
1069}
1070
1071/*
1072 * Given an initial and final version name, identify the sequence of update
1073 * scripts that have to be applied to perform that update.
1074 *
1075 * Result is a List of names of versions to transition through (the initial
1076 * version is *not* included).
1077 */
1078static List *
1079identify_update_path(ExtensionControlFile *control,
1080 const char *oldVersion, const char *newVersion)
1081{
1082 List *result;
1083 List *evi_list;
1084 ExtensionVersionInfo *evi_start;
1085 ExtensionVersionInfo *evi_target;
1086
1087 /* Extract the version update graph from the script directory */
1088 evi_list = get_ext_ver_list(control);
1089
1090 /* Initialize start and end vertices */
1091 evi_start = get_ext_ver_info(oldVersion, &evi_list);
1092 evi_target = get_ext_ver_info(newVersion, &evi_list);
1093
1094 /* Find shortest path */
1095 result = find_update_path(evi_list, evi_start, evi_target, false, false);
1096
1097 if (result == NIL)
1098 ereport(ERROR,
1099 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1100 errmsg("extension \"%s\" has no update path from version \"%s\" to version \"%s\"",
1101 control->name, oldVersion, newVersion)));
1102
1103 return result;
1104}
1105
1106/*
1107 * Apply Dijkstra's algorithm to find the shortest path from evi_start to
1108 * evi_target.
1109 *
1110 * If reject_indirect is true, ignore paths that go through installable
1111 * versions. This saves work when the caller will consider starting from
1112 * all installable versions anyway.
1113 *
1114 * If reinitialize is false, assume the ExtensionVersionInfo list has not
1115 * been used for this before, and the initialization done by get_ext_ver_info
1116 * is still good. Otherwise, reinitialize all transient fields used here.
1117 *
1118 * Result is a List of names of versions to transition through (the initial
1119 * version is *not* included). Returns NIL if no such path.
1120 */
1121static List *
1122find_update_path(List *evi_list,
1123 ExtensionVersionInfo *evi_start,
1124 ExtensionVersionInfo *evi_target,
1125 bool reject_indirect,
1126 bool reinitialize)
1127{
1128 List *result;
1129 ExtensionVersionInfo *evi;
1130 ListCell *lc;
1131
1132 /* Caller error if start == target */
1133 Assert(evi_start != evi_target);
1134 /* Caller error if reject_indirect and target is installable */
1135 Assert(!(reject_indirect && evi_target->installable));
1136
1137 if (reinitialize)
1138 {
1139 foreach(lc, evi_list)
1140 {
1141 evi = (ExtensionVersionInfo *) lfirst(lc);
1142 evi->distance_known = false;
1143 evi->distance = INT_MAX;
1144 evi->previous = NULL;
1145 }
1146 }
1147
1148 evi_start->distance = 0;
1149
1150 while ((evi = get_nearest_unprocessed_vertex(evi_list)) != NULL)
1151 {
1152 if (evi->distance == INT_MAX)
1153 break; /* all remaining vertices are unreachable */
1154 evi->distance_known = true;
1155 if (evi == evi_target)
1156 break; /* found shortest path to target */
1157 foreach(lc, evi->reachable)
1158 {
1159 ExtensionVersionInfo *evi2 = (ExtensionVersionInfo *) lfirst(lc);
1160 int newdist;
1161
1162 /* if reject_indirect, treat installable versions as unreachable */
1163 if (reject_indirect && evi2->installable)
1164 continue;
1165 newdist = evi->distance + 1;
1166 if (newdist < evi2->distance)
1167 {
1168 evi2->distance = newdist;
1169 evi2->previous = evi;
1170 }
1171 else if (newdist == evi2->distance &&
1172 evi2->previous != NULL &&
1173 strcmp(evi->name, evi2->previous->name) < 0)
1174 {
1175 /*
1176 * Break ties in favor of the version name that comes first
1177 * according to strcmp(). This behavior is undocumented and
1178 * users shouldn't rely on it. We do it just to ensure that
1179 * if there is a tie, the update path that is chosen does not
1180 * depend on random factors like the order in which directory
1181 * entries get visited.
1182 */
1183 evi2->previous = evi;
1184 }
1185 }
1186 }
1187
1188 /* Return NIL if target is not reachable from start */
1189 if (!evi_target->distance_known)
1190 return NIL;
1191
1192 /* Build and return list of version names representing the update path */
1193 result = NIL;
1194 for (evi = evi_target; evi != evi_start; evi = evi->previous)
1195 result = lcons(evi->name, result);
1196
1197 return result;
1198}
1199
1200/*
1201 * Given a target version that is not directly installable, find the
1202 * best installation sequence starting from a directly-installable version.
1203 *
1204 * evi_list: previously-collected version update graph
1205 * evi_target: member of that list that we want to reach
1206 *
1207 * Returns the best starting-point version, or NULL if there is none.
1208 * On success, *best_path is set to the path from the start point.
1209 *
1210 * If there's more than one possible start point, prefer shorter update paths,
1211 * and break any ties arbitrarily on the basis of strcmp'ing the starting
1212 * versions' names.
1213 */
1214static ExtensionVersionInfo *
1215find_install_path(List *evi_list, ExtensionVersionInfo *evi_target,
1216 List **best_path)
1217{
1218 ExtensionVersionInfo *evi_start = NULL;
1219 ListCell *lc;
1220
1221 *best_path = NIL;
1222
1223 /*
1224 * We don't expect to be called for an installable target, but if we are,
1225 * the answer is easy: just start from there, with an empty update path.
1226 */
1227 if (evi_target->installable)
1228 return evi_target;
1229
1230 /* Consider all installable versions as start points */
1231 foreach(lc, evi_list)
1232 {
1233 ExtensionVersionInfo *evi1 = (ExtensionVersionInfo *) lfirst(lc);
1234 List *path;
1235
1236 if (!evi1->installable)
1237 continue;
1238
1239 /*
1240 * Find shortest path from evi1 to evi_target; but no need to consider
1241 * paths going through other installable versions.
1242 */
1243 path = find_update_path(evi_list, evi1, evi_target, true, true);
1244 if (path == NIL)
1245 continue;
1246
1247 /* Remember best path */
1248 if (evi_start == NULL ||
1249 list_length(path) < list_length(*best_path) ||
1250 (list_length(path) == list_length(*best_path) &&
1251 strcmp(evi_start->name, evi1->name) < 0))
1252 {
1253 evi_start = evi1;
1254 *best_path = path;
1255 }
1256 }
1257
1258 return evi_start;
1259}
1260
1261/*
1262 * CREATE EXTENSION worker
1263 *
1264 * When CASCADE is specified, CreateExtensionInternal() recurses if required
1265 * extensions need to be installed. To sanely handle cyclic dependencies,
1266 * the "parents" list contains a list of names of extensions already being
1267 * installed, allowing us to error out if we recurse to one of those.
1268 */
1269static ObjectAddress
1270CreateExtensionInternal(char *extensionName,
1271 char *schemaName,
1272 const char *versionName,
1273 const char *oldVersionName,
1274 bool cascade,
1275 List *parents,
1276 bool is_create)
1277{
1278 char *origSchemaName = schemaName;
1279 Oid schemaOid = InvalidOid;
1280 Oid extowner = GetUserId();
1281 ExtensionControlFile *pcontrol;
1282 ExtensionControlFile *control;
1283 List *updateVersions;
1284 List *requiredExtensions;
1285 List *requiredSchemas;
1286 Oid extensionOid;
1287 ObjectAddress address;
1288 ListCell *lc;
1289
1290 /*
1291 * Read the primary control file. Note we assume that it does not contain
1292 * any non-ASCII data, so there is no need to worry about encoding at this
1293 * point.
1294 */
1295 pcontrol = read_extension_control_file(extensionName);
1296
1297 /*
1298 * Determine the version to install
1299 */
1300 if (versionName == NULL)
1301 {
1302 if (pcontrol->default_version)
1303 versionName = pcontrol->default_version;
1304 else
1305 ereport(ERROR,
1306 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1307 errmsg("version to install must be specified")));
1308 }
1309 check_valid_version_name(versionName);
1310
1311 /*
1312 * Figure out which script(s) we need to run to install the desired
1313 * version of the extension. If we do not have a script that directly
1314 * does what is needed, we try to find a sequence of update scripts that
1315 * will get us there.
1316 */
1317 if (oldVersionName)
1318 {
1319 /*
1320 * "FROM old_version" was specified, indicating that we're trying to
1321 * update from some unpackaged version of the extension. Locate a
1322 * series of update scripts that will do it.
1323 */
1324 check_valid_version_name(oldVersionName);
1325
1326 if (strcmp(oldVersionName, versionName) == 0)
1327 ereport(ERROR,
1328 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1329 errmsg("FROM version must be different from installation target version \"%s\"",
1330 versionName)));
1331
1332 updateVersions = identify_update_path(pcontrol,
1333 oldVersionName,
1334 versionName);
1335
1336 if (list_length(updateVersions) == 1)
1337 {
1338 /*
1339 * Simple case where there's just one update script to run. We
1340 * will not need any follow-on update steps.
1341 */
1342 Assert(strcmp((char *) linitial(updateVersions), versionName) == 0);
1343 updateVersions = NIL;
1344 }
1345 else
1346 {
1347 /*
1348 * Multi-step sequence. We treat this as installing the version
1349 * that is the target of the first script, followed by successive
1350 * updates to the later versions.
1351 */
1352 versionName = (char *) linitial(updateVersions);
1353 updateVersions = list_delete_first(updateVersions);
1354 }
1355 }
1356 else
1357 {
1358 /*
1359 * No FROM, so we're installing from scratch. If there is an install
1360 * script for the desired version, we only need to run that one.
1361 */
1362 char *filename;
1363 struct stat fst;
1364
1365 oldVersionName = NULL;
1366
1367 filename = get_extension_script_filename(pcontrol, NULL, versionName);
1368 if (stat(filename, &fst) == 0)
1369 {
1370 /* Easy, no extra scripts */
1371 updateVersions = NIL;
1372 }
1373 else
1374 {
1375 /* Look for best way to install this version */
1376 List *evi_list;
1377 ExtensionVersionInfo *evi_start;
1378 ExtensionVersionInfo *evi_target;
1379
1380 /* Extract the version update graph from the script directory */
1381 evi_list = get_ext_ver_list(pcontrol);
1382
1383 /* Identify the target version */
1384 evi_target = get_ext_ver_info(versionName, &evi_list);
1385
1386 /* Identify best path to reach target */
1387 evi_start = find_install_path(evi_list, evi_target,
1388 &updateVersions);
1389
1390 /* Fail if no path ... */
1391 if (evi_start == NULL)
1392 ereport(ERROR,
1393 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1394 errmsg("extension \"%s\" has no installation script nor update path for version \"%s\"",
1395 pcontrol->name, versionName)));
1396
1397 /* Otherwise, install best starting point and then upgrade */
1398 versionName = evi_start->name;
1399 }
1400 }
1401
1402 /*
1403 * Fetch control parameters for installation target version
1404 */
1405 control = read_extension_aux_control_file(pcontrol, versionName);
1406
1407 /*
1408 * Determine the target schema to install the extension into
1409 */
1410 if (schemaName)
1411 {
1412 /* If the user is giving us the schema name, it must exist already. */
1413 schemaOid = get_namespace_oid(schemaName, false);
1414 }
1415
1416 if (control->schema != NULL)
1417 {
1418 /*
1419 * The extension is not relocatable and the author gave us a schema
1420 * for it.
1421 *
1422 * Unless CASCADE parameter was given, it's an error to give a schema
1423 * different from control->schema if control->schema is specified.
1424 */
1425 if (schemaName && strcmp(control->schema, schemaName) != 0 &&
1426 !cascade)
1427 ereport(ERROR,
1428 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1429 errmsg("extension \"%s\" must be installed in schema \"%s\"",
1430 control->name,
1431 control->schema)));
1432
1433 /* Always use the schema from control file for current extension. */
1434 schemaName = control->schema;
1435
1436 /* Find or create the schema in case it does not exist. */
1437 schemaOid = get_namespace_oid(schemaName, true);
1438
1439 if (!OidIsValid(schemaOid))
1440 {
1441 CreateSchemaStmt *csstmt = makeNode(CreateSchemaStmt);
1442
1443 csstmt->schemaname = schemaName;
1444 csstmt->authrole = NULL; /* will be created by current user */
1445 csstmt->schemaElts = NIL;
1446 csstmt->if_not_exists = false;
1447 CreateSchemaCommand(csstmt, "(generated CREATE SCHEMA command)",
1448 -1, -1);
1449
1450 /*
1451 * CreateSchemaCommand includes CommandCounterIncrement, so new
1452 * schema is now visible.
1453 */
1454 schemaOid = get_namespace_oid(schemaName, false);
1455 }
1456 }
1457 else if (!OidIsValid(schemaOid))
1458 {
1459 /*
1460 * Neither user nor author of the extension specified schema; use the
1461 * current default creation namespace, which is the first explicit
1462 * entry in the search_path.
1463 */
1464 List *search_path = fetch_search_path(false);
1465
1466 if (search_path == NIL) /* nothing valid in search_path? */
1467 ereport(ERROR,
1468 (errcode(ERRCODE_UNDEFINED_SCHEMA),
1469 errmsg("no schema has been selected to create in")));
1470 schemaOid = linitial_oid(search_path);
1471 schemaName = get_namespace_name(schemaOid);
1472 if (schemaName == NULL) /* recently-deleted namespace? */
1473 ereport(ERROR,
1474 (errcode(ERRCODE_UNDEFINED_SCHEMA),
1475 errmsg("no schema has been selected to create in")));
1476
1477 list_free(search_path);
1478 }
1479
1480 /*
1481 * Make note if a temporary namespace has been accessed in this
1482 * transaction.
1483 */
1484 if (isTempNamespace(schemaOid))
1485 MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPNAMESPACE;
1486
1487 /*
1488 * We don't check creation rights on the target namespace here. If the
1489 * extension script actually creates any objects there, it will fail if
1490 * the user doesn't have such permissions. But there are cases such as
1491 * procedural languages where it's convenient to set schema = pg_catalog
1492 * yet we don't want to restrict the command to users with ACL_CREATE for
1493 * pg_catalog.
1494 */
1495
1496 /*
1497 * Look up the prerequisite extensions, install them if necessary, and
1498 * build lists of their OIDs and the OIDs of their target schemas.
1499 */
1500 requiredExtensions = NIL;
1501 requiredSchemas = NIL;
1502 foreach(lc, control->requires)
1503 {
1504 char *curreq = (char *) lfirst(lc);
1505 Oid reqext;
1506 Oid reqschema;
1507
1508 reqext = get_required_extension(curreq,
1509 extensionName,
1510 origSchemaName,
1511 cascade,
1512 parents,
1513 is_create);
1514 reqschema = get_extension_schema(reqext);
1515 requiredExtensions = lappend_oid(requiredExtensions, reqext);
1516 requiredSchemas = lappend_oid(requiredSchemas, reqschema);
1517 }
1518
1519 /*
1520 * Insert new tuple into pg_extension, and create dependency entries.
1521 */
1522 address = InsertExtensionTuple(control->name, extowner,
1523 schemaOid, control->relocatable,
1524 versionName,
1525 PointerGetDatum(NULL),
1526 PointerGetDatum(NULL),
1527 requiredExtensions);
1528 extensionOid = address.objectId;
1529
1530 /*
1531 * Apply any control-file comment on extension
1532 */
1533 if (control->comment != NULL)
1534 CreateComments(extensionOid, ExtensionRelationId, 0, control->comment);
1535
1536 /*
1537 * Execute the installation script file
1538 */
1539 execute_extension_script(extensionOid, control,
1540 oldVersionName, versionName,
1541 requiredSchemas,
1542 schemaName, schemaOid);
1543
1544 /*
1545 * If additional update scripts have to be executed, apply the updates as
1546 * though a series of ALTER EXTENSION UPDATE commands were given
1547 */
1548 ApplyExtensionUpdates(extensionOid, pcontrol,
1549 versionName, updateVersions,
1550 origSchemaName, cascade, is_create);
1551
1552 return address;
1553}
1554
1555/*
1556 * Get the OID of an extension listed in "requires", possibly creating it.
1557 */
1558static Oid
1559get_required_extension(char *reqExtensionName,
1560 char *extensionName,
1561 char *origSchemaName,
1562 bool cascade,
1563 List *parents,
1564 bool is_create)
1565{
1566 Oid reqExtensionOid;
1567
1568 reqExtensionOid = get_extension_oid(reqExtensionName, true);
1569 if (!OidIsValid(reqExtensionOid))
1570 {
1571 if (cascade)
1572 {
1573 /* Must install it. */
1574 ObjectAddress addr;
1575 List *cascade_parents;
1576 ListCell *lc;
1577
1578 /* Check extension name validity before trying to cascade. */
1579 check_valid_extension_name(reqExtensionName);
1580
1581 /* Check for cyclic dependency between extensions. */
1582 foreach(lc, parents)
1583 {
1584 char *pname = (char *) lfirst(lc);
1585
1586 if (strcmp(pname, reqExtensionName) == 0)
1587 ereport(ERROR,
1588 (errcode(ERRCODE_INVALID_RECURSION),
1589 errmsg("cyclic dependency detected between extensions \"%s\" and \"%s\"",
1590 reqExtensionName, extensionName)));
1591 }
1592
1593 ereport(NOTICE,
1594 (errmsg("installing required extension \"%s\"",
1595 reqExtensionName)));
1596
1597 /* Add current extension to list of parents to pass down. */
1598 cascade_parents = lappend(list_copy(parents), extensionName);
1599
1600 /*
1601 * Create the required extension. We propagate the SCHEMA option
1602 * if any, and CASCADE, but no other options.
1603 */
1604 addr = CreateExtensionInternal(reqExtensionName,
1605 origSchemaName,
1606 NULL,
1607 NULL,
1608 cascade,
1609 cascade_parents,
1610 is_create);
1611
1612 /* Get its newly-assigned OID. */
1613 reqExtensionOid = addr.objectId;
1614 }
1615 else
1616 ereport(ERROR,
1617 (errcode(ERRCODE_UNDEFINED_OBJECT),
1618 errmsg("required extension \"%s\" is not installed",
1619 reqExtensionName),
1620 is_create ?
1621 errhint("Use CREATE EXTENSION ... CASCADE to install required extensions too.") : 0));
1622 }
1623
1624 return reqExtensionOid;
1625}
1626
1627/*
1628 * CREATE EXTENSION
1629 */
1630ObjectAddress
1631CreateExtension(ParseState *pstate, CreateExtensionStmt *stmt)
1632{
1633 DefElem *d_schema = NULL;
1634 DefElem *d_new_version = NULL;
1635 DefElem *d_old_version = NULL;
1636 DefElem *d_cascade = NULL;
1637 char *schemaName = NULL;
1638 char *versionName = NULL;
1639 char *oldVersionName = NULL;
1640 bool cascade = false;
1641 ListCell *lc;
1642
1643 /* Check extension name validity before any filesystem access */
1644 check_valid_extension_name(stmt->extname);
1645
1646 /*
1647 * Check for duplicate extension name. The unique index on
1648 * pg_extension.extname would catch this anyway, and serves as a backstop
1649 * in case of race conditions; but this is a friendlier error message, and
1650 * besides we need a check to support IF NOT EXISTS.
1651 */
1652 if (get_extension_oid(stmt->extname, true) != InvalidOid)
1653 {
1654 if (stmt->if_not_exists)
1655 {
1656 ereport(NOTICE,
1657 (errcode(ERRCODE_DUPLICATE_OBJECT),
1658 errmsg("extension \"%s\" already exists, skipping",
1659 stmt->extname)));
1660 return InvalidObjectAddress;
1661 }
1662 else
1663 ereport(ERROR,
1664 (errcode(ERRCODE_DUPLICATE_OBJECT),
1665 errmsg("extension \"%s\" already exists",
1666 stmt->extname)));
1667 }
1668
1669 /*
1670 * We use global variables to track the extension being created, so we can
1671 * create only one extension at the same time.
1672 */
1673 if (creating_extension)
1674 ereport(ERROR,
1675 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1676 errmsg("nested CREATE EXTENSION is not supported")));
1677
1678 /* Deconstruct the statement option list */
1679 foreach(lc, stmt->options)
1680 {
1681 DefElem *defel = (DefElem *) lfirst(lc);
1682
1683 if (strcmp(defel->defname, "schema") == 0)
1684 {
1685 if (d_schema)
1686 ereport(ERROR,
1687 (errcode(ERRCODE_SYNTAX_ERROR),
1688 errmsg("conflicting or redundant options"),
1689 parser_errposition(pstate, defel->location)));
1690 d_schema = defel;
1691 schemaName = defGetString(d_schema);
1692 }
1693 else if (strcmp(defel->defname, "new_version") == 0)
1694 {
1695 if (d_new_version)
1696 ereport(ERROR,
1697 (errcode(ERRCODE_SYNTAX_ERROR),
1698 errmsg("conflicting or redundant options"),
1699 parser_errposition(pstate, defel->location)));
1700 d_new_version = defel;
1701 versionName = defGetString(d_new_version);
1702 }
1703 else if (strcmp(defel->defname, "old_version") == 0)
1704 {
1705 if (d_old_version)
1706 ereport(ERROR,
1707 (errcode(ERRCODE_SYNTAX_ERROR),
1708 errmsg("conflicting or redundant options"),
1709 parser_errposition(pstate, defel->location)));
1710 d_old_version = defel;
1711 oldVersionName = defGetString(d_old_version);
1712 }
1713 else if (strcmp(defel->defname, "cascade") == 0)
1714 {
1715 if (d_cascade)
1716 ereport(ERROR,
1717 (errcode(ERRCODE_SYNTAX_ERROR),
1718 errmsg("conflicting or redundant options"),
1719 parser_errposition(pstate, defel->location)));
1720 d_cascade = defel;
1721 cascade = defGetBoolean(d_cascade);
1722 }
1723 else
1724 elog(ERROR, "unrecognized option: %s", defel->defname);
1725 }
1726
1727 /* Call CreateExtensionInternal to do the real work. */
1728 return CreateExtensionInternal(stmt->extname,
1729 schemaName,
1730 versionName,
1731 oldVersionName,
1732 cascade,
1733 NIL,
1734 true);
1735}
1736
1737/*
1738 * InsertExtensionTuple
1739 *
1740 * Insert the new pg_extension row, and create extension's dependency entries.
1741 * Return the OID assigned to the new row.
1742 *
1743 * This is exported for the benefit of pg_upgrade, which has to create a
1744 * pg_extension entry (and the extension-level dependencies) without
1745 * actually running the extension's script.
1746 *
1747 * extConfig and extCondition should be arrays or PointerGetDatum(NULL).
1748 * We declare them as plain Datum to avoid needing array.h in extension.h.
1749 */
1750ObjectAddress
1751InsertExtensionTuple(const char *extName, Oid extOwner,
1752 Oid schemaOid, bool relocatable, const char *extVersion,
1753 Datum extConfig, Datum extCondition,
1754 List *requiredExtensions)
1755{
1756 Oid extensionOid;
1757 Relation rel;
1758 Datum values[Natts_pg_extension];
1759 bool nulls[Natts_pg_extension];
1760 HeapTuple tuple;
1761 ObjectAddress myself;
1762 ObjectAddress nsp;
1763 ListCell *lc;
1764
1765 /*
1766 * Build and insert the pg_extension tuple
1767 */
1768 rel = table_open(ExtensionRelationId, RowExclusiveLock);
1769
1770 memset(values, 0, sizeof(values));
1771 memset(nulls, 0, sizeof(nulls));
1772
1773 extensionOid = GetNewOidWithIndex(rel, ExtensionOidIndexId,
1774 Anum_pg_extension_oid);
1775 values[Anum_pg_extension_oid - 1] = ObjectIdGetDatum(extensionOid);
1776 values[Anum_pg_extension_extname - 1] =
1777 DirectFunctionCall1(namein, CStringGetDatum(extName));
1778 values[Anum_pg_extension_extowner - 1] = ObjectIdGetDatum(extOwner);
1779 values[Anum_pg_extension_extnamespace - 1] = ObjectIdGetDatum(schemaOid);
1780 values[Anum_pg_extension_extrelocatable - 1] = BoolGetDatum(relocatable);
1781 values[Anum_pg_extension_extversion - 1] = CStringGetTextDatum(extVersion);
1782
1783 if (extConfig == PointerGetDatum(NULL))
1784 nulls[Anum_pg_extension_extconfig - 1] = true;
1785 else
1786 values[Anum_pg_extension_extconfig - 1] = extConfig;
1787
1788 if (extCondition == PointerGetDatum(NULL))
1789 nulls[Anum_pg_extension_extcondition - 1] = true;
1790 else
1791 values[Anum_pg_extension_extcondition - 1] = extCondition;
1792
1793 tuple = heap_form_tuple(rel->rd_att, values, nulls);
1794
1795 CatalogTupleInsert(rel, tuple);
1796
1797 heap_freetuple(tuple);
1798 table_close(rel, RowExclusiveLock);
1799
1800 /*
1801 * Record dependencies on owner, schema, and prerequisite extensions
1802 */
1803 recordDependencyOnOwner(ExtensionRelationId, extensionOid, extOwner);
1804
1805 myself.classId = ExtensionRelationId;
1806 myself.objectId = extensionOid;
1807 myself.objectSubId = 0;
1808
1809 nsp.classId = NamespaceRelationId;
1810 nsp.objectId = schemaOid;
1811 nsp.objectSubId = 0;
1812
1813 recordDependencyOn(&myself, &nsp, DEPENDENCY_NORMAL);
1814
1815 foreach(lc, requiredExtensions)
1816 {
1817 Oid reqext = lfirst_oid(lc);
1818 ObjectAddress otherext;
1819
1820 otherext.classId = ExtensionRelationId;
1821 otherext.objectId = reqext;
1822 otherext.objectSubId = 0;
1823
1824 recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
1825 }
1826 /* Post creation hook for new extension */
1827 InvokeObjectPostCreateHook(ExtensionRelationId, extensionOid, 0);
1828
1829 return myself;
1830}
1831
1832/*
1833 * Guts of extension deletion.
1834 *
1835 * All we need do here is remove the pg_extension tuple itself. Everything
1836 * else is taken care of by the dependency infrastructure.
1837 */
1838void
1839RemoveExtensionById(Oid extId)
1840{
1841 Relation rel;
1842 SysScanDesc scandesc;
1843 HeapTuple tuple;
1844 ScanKeyData entry[1];
1845
1846 /*
1847 * Disallow deletion of any extension that's currently open for insertion;
1848 * else subsequent executions of recordDependencyOnCurrentExtension()
1849 * could create dangling pg_depend records that refer to a no-longer-valid
1850 * pg_extension OID. This is needed not so much because we think people
1851 * might write "DROP EXTENSION foo" in foo's own script files, as because
1852 * errors in dependency management in extension script files could give
1853 * rise to cases where an extension is dropped as a result of recursing
1854 * from some contained object. Because of that, we must test for the case
1855 * here, not at some higher level of the DROP EXTENSION command.
1856 */
1857 if (extId == CurrentExtensionObject)
1858 ereport(ERROR,
1859 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1860 errmsg("cannot drop extension \"%s\" because it is being modified",
1861 get_extension_name(extId))));
1862
1863 rel = table_open(ExtensionRelationId, RowExclusiveLock);
1864
1865 ScanKeyInit(&entry[0],
1866 Anum_pg_extension_oid,
1867 BTEqualStrategyNumber, F_OIDEQ,
1868 ObjectIdGetDatum(extId));
1869 scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
1870 NULL, 1, entry);
1871
1872 tuple = systable_getnext(scandesc);
1873
1874 /* We assume that there can be at most one matching tuple */
1875 if (HeapTupleIsValid(tuple))
1876 CatalogTupleDelete(rel, &tuple->t_self);
1877
1878 systable_endscan(scandesc);
1879
1880 table_close(rel, RowExclusiveLock);
1881}
1882
1883/*
1884 * This function lists the available extensions (one row per primary control
1885 * file in the control directory). We parse each control file and report the
1886 * interesting fields.
1887 *
1888 * The system view pg_available_extensions provides a user interface to this
1889 * SRF, adding information about whether the extensions are installed in the
1890 * current DB.
1891 */
1892Datum
1893pg_available_extensions(PG_FUNCTION_ARGS)
1894{
1895 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1896 TupleDesc tupdesc;
1897 Tuplestorestate *tupstore;
1898 MemoryContext per_query_ctx;
1899 MemoryContext oldcontext;
1900 char *location;
1901 DIR *dir;
1902 struct dirent *de;
1903
1904 /* check to see if caller supports us returning a tuplestore */
1905 if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
1906 ereport(ERROR,
1907 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1908 errmsg("set-valued function called in context that cannot accept a set")));
1909 if (!(rsinfo->allowedModes & SFRM_Materialize))
1910 ereport(ERROR,
1911 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1912 errmsg("materialize mode required, but it is not " \
1913 "allowed in this context")));
1914
1915 /* Build a tuple descriptor for our result type */
1916 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
1917 elog(ERROR, "return type must be a row type");
1918
1919 /* Build tuplestore to hold the result rows */
1920 per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
1921 oldcontext = MemoryContextSwitchTo(per_query_ctx);
1922
1923 tupstore = tuplestore_begin_heap(true, false, work_mem);
1924 rsinfo->returnMode = SFRM_Materialize;
1925 rsinfo->setResult = tupstore;
1926 rsinfo->setDesc = tupdesc;
1927
1928 MemoryContextSwitchTo(oldcontext);
1929
1930 location = get_extension_control_directory();
1931 dir = AllocateDir(location);
1932
1933 /*
1934 * If the control directory doesn't exist, we want to silently return an
1935 * empty set. Any other error will be reported by ReadDir.
1936 */
1937 if (dir == NULL && errno == ENOENT)
1938 {
1939 /* do nothing */
1940 }
1941 else
1942 {
1943 while ((de = ReadDir(dir, location)) != NULL)
1944 {
1945 ExtensionControlFile *control;
1946 char *extname;
1947 Datum values[3];
1948 bool nulls[3];
1949
1950 if (!is_extension_control_filename(de->d_name))
1951 continue;
1952
1953 /* extract extension name from 'name.control' filename */
1954 extname = pstrdup(de->d_name);
1955 *strrchr(extname, '.') = '\0';
1956
1957 /* ignore it if it's an auxiliary control file */
1958 if (strstr(extname, "--"))
1959 continue;
1960
1961 control = read_extension_control_file(extname);
1962
1963 memset(values, 0, sizeof(values));
1964 memset(nulls, 0, sizeof(nulls));
1965
1966 /* name */
1967 values[0] = DirectFunctionCall1(namein,
1968 CStringGetDatum(control->name));
1969 /* default_version */
1970 if (control->default_version == NULL)
1971 nulls[1] = true;
1972 else
1973 values[1] = CStringGetTextDatum(control->default_version);
1974 /* comment */
1975 if (control->comment == NULL)
1976 nulls[2] = true;
1977 else
1978 values[2] = CStringGetTextDatum(control->comment);
1979
1980 tuplestore_putvalues(tupstore, tupdesc, values, nulls);
1981 }
1982
1983 FreeDir(dir);
1984 }
1985
1986 /* clean up and return the tuplestore */
1987 tuplestore_donestoring(tupstore);
1988
1989 return (Datum) 0;
1990}
1991
1992/*
1993 * This function lists the available extension versions (one row per
1994 * extension installation script). For each version, we parse the related
1995 * control file(s) and report the interesting fields.
1996 *
1997 * The system view pg_available_extension_versions provides a user interface
1998 * to this SRF, adding information about which versions are installed in the
1999 * current DB.
2000 */
2001Datum
2002pg_available_extension_versions(PG_FUNCTION_ARGS)
2003{
2004 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
2005 TupleDesc tupdesc;
2006 Tuplestorestate *tupstore;
2007 MemoryContext per_query_ctx;
2008 MemoryContext oldcontext;
2009 char *location;
2010 DIR *dir;
2011 struct dirent *de;
2012
2013 /* check to see if caller supports us returning a tuplestore */
2014 if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
2015 ereport(ERROR,
2016 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2017 errmsg("set-valued function called in context that cannot accept a set")));
2018 if (!(rsinfo->allowedModes & SFRM_Materialize))
2019 ereport(ERROR,
2020 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2021 errmsg("materialize mode required, but it is not " \
2022 "allowed in this context")));
2023
2024 /* Build a tuple descriptor for our result type */
2025 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
2026 elog(ERROR, "return type must be a row type");
2027
2028 /* Build tuplestore to hold the result rows */
2029 per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
2030 oldcontext = MemoryContextSwitchTo(per_query_ctx);
2031
2032 tupstore = tuplestore_begin_heap(true, false, work_mem);
2033 rsinfo->returnMode = SFRM_Materialize;
2034 rsinfo->setResult = tupstore;
2035 rsinfo->setDesc = tupdesc;
2036
2037 MemoryContextSwitchTo(oldcontext);
2038
2039 location = get_extension_control_directory();
2040 dir = AllocateDir(location);
2041
2042 /*
2043 * If the control directory doesn't exist, we want to silently return an
2044 * empty set. Any other error will be reported by ReadDir.
2045 */
2046 if (dir == NULL && errno == ENOENT)
2047 {
2048 /* do nothing */
2049 }
2050 else
2051 {
2052 while ((de = ReadDir(dir, location)) != NULL)
2053 {
2054 ExtensionControlFile *control;
2055 char *extname;
2056
2057 if (!is_extension_control_filename(de->d_name))
2058 continue;
2059
2060 /* extract extension name from 'name.control' filename */
2061 extname = pstrdup(de->d_name);
2062 *strrchr(extname, '.') = '\0';
2063
2064 /* ignore it if it's an auxiliary control file */
2065 if (strstr(extname, "--"))
2066 continue;
2067
2068 /* read the control file */
2069 control = read_extension_control_file(extname);
2070
2071 /* scan extension's script directory for install scripts */
2072 get_available_versions_for_extension(control, tupstore, tupdesc);
2073 }
2074
2075 FreeDir(dir);
2076 }
2077
2078 /* clean up and return the tuplestore */
2079 tuplestore_donestoring(tupstore);
2080
2081 return (Datum) 0;
2082}
2083
2084/*
2085 * Inner loop for pg_available_extension_versions:
2086 * read versions of one extension, add rows to tupstore
2087 */
2088static void
2089get_available_versions_for_extension(ExtensionControlFile *pcontrol,
2090 Tuplestorestate *tupstore,
2091 TupleDesc tupdesc)
2092{
2093 List *evi_list;
2094 ListCell *lc;
2095
2096 /* Extract the version update graph from the script directory */
2097 evi_list = get_ext_ver_list(pcontrol);
2098
2099 /* For each installable version ... */
2100 foreach(lc, evi_list)
2101 {
2102 ExtensionVersionInfo *evi = (ExtensionVersionInfo *) lfirst(lc);
2103 ExtensionControlFile *control;
2104 Datum values[7];
2105 bool nulls[7];
2106 ListCell *lc2;
2107
2108 if (!evi->installable)
2109 continue;
2110
2111 /*
2112 * Fetch parameters for specific version (pcontrol is not changed)
2113 */
2114 control = read_extension_aux_control_file(pcontrol, evi->name);
2115
2116 memset(values, 0, sizeof(values));
2117 memset(nulls, 0, sizeof(nulls));
2118
2119 /* name */
2120 values[0] = DirectFunctionCall1(namein,
2121 CStringGetDatum(control->name));
2122 /* version */
2123 values[1] = CStringGetTextDatum(evi->name);
2124 /* superuser */
2125 values[2] = BoolGetDatum(control->superuser);
2126 /* relocatable */
2127 values[3] = BoolGetDatum(control->relocatable);
2128 /* schema */
2129 if (control->schema == NULL)
2130 nulls[4] = true;
2131 else
2132 values[4] = DirectFunctionCall1(namein,
2133 CStringGetDatum(control->schema));
2134 /* requires */
2135 if (control->requires == NIL)
2136 nulls[5] = true;
2137 else
2138 values[5] = convert_requires_to_datum(control->requires);
2139 /* comment */
2140 if (control->comment == NULL)
2141 nulls[6] = true;
2142 else
2143 values[6] = CStringGetTextDatum(control->comment);
2144
2145 tuplestore_putvalues(tupstore, tupdesc, values, nulls);
2146
2147 /*
2148 * Find all non-directly-installable versions that would be installed
2149 * starting from this version, and report them, inheriting the
2150 * parameters that aren't changed in updates from this version.
2151 */
2152 foreach(lc2, evi_list)
2153 {
2154 ExtensionVersionInfo *evi2 = (ExtensionVersionInfo *) lfirst(lc2);
2155 List *best_path;
2156
2157 if (evi2->installable)
2158 continue;
2159 if (find_install_path(evi_list, evi2, &best_path) == evi)
2160 {
2161 /*
2162 * Fetch parameters for this version (pcontrol is not changed)
2163 */
2164 control = read_extension_aux_control_file(pcontrol, evi2->name);
2165
2166 /* name stays the same */
2167 /* version */
2168 values[1] = CStringGetTextDatum(evi2->name);
2169 /* superuser */
2170 values[2] = BoolGetDatum(control->superuser);
2171 /* relocatable */
2172 values[3] = BoolGetDatum(control->relocatable);
2173 /* schema stays the same */
2174 /* requires */
2175 if (control->requires == NIL)
2176 nulls[5] = true;
2177 else
2178 {
2179 values[5] = convert_requires_to_datum(control->requires);
2180 nulls[5] = false;
2181 }
2182 /* comment stays the same */
2183
2184 tuplestore_putvalues(tupstore, tupdesc, values, nulls);
2185 }
2186 }
2187 }
2188}
2189
2190/*
2191 * Convert a list of extension names to a name[] Datum
2192 */
2193static Datum
2194convert_requires_to_datum(List *requires)
2195{
2196 Datum *datums;
2197 int ndatums;
2198 ArrayType *a;
2199 ListCell *lc;
2200
2201 ndatums = list_length(requires);
2202 datums = (Datum *) palloc(ndatums * sizeof(Datum));
2203 ndatums = 0;
2204 foreach(lc, requires)
2205 {
2206 char *curreq = (char *) lfirst(lc);
2207
2208 datums[ndatums++] =
2209 DirectFunctionCall1(namein, CStringGetDatum(curreq));
2210 }
2211 a = construct_array(datums, ndatums,
2212 NAMEOID,
2213 NAMEDATALEN, false, 'c');
2214 return PointerGetDatum(a);
2215}
2216
2217/*
2218 * This function reports the version update paths that exist for the
2219 * specified extension.
2220 */
2221Datum
2222pg_extension_update_paths(PG_FUNCTION_ARGS)
2223{
2224 Name extname = PG_GETARG_NAME(0);
2225 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
2226 TupleDesc tupdesc;
2227 Tuplestorestate *tupstore;
2228 MemoryContext per_query_ctx;
2229 MemoryContext oldcontext;
2230 List *evi_list;
2231 ExtensionControlFile *control;
2232 ListCell *lc1;
2233
2234 /* Check extension name validity before any filesystem access */
2235 check_valid_extension_name(NameStr(*extname));
2236
2237 /* check to see if caller supports us returning a tuplestore */
2238 if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
2239 ereport(ERROR,
2240 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2241 errmsg("set-valued function called in context that cannot accept a set")));
2242 if (!(rsinfo->allowedModes & SFRM_Materialize))
2243 ereport(ERROR,
2244 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2245 errmsg("materialize mode required, but it is not " \
2246 "allowed in this context")));
2247
2248 /* Build a tuple descriptor for our result type */
2249 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
2250 elog(ERROR, "return type must be a row type");
2251
2252 /* Build tuplestore to hold the result rows */
2253 per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
2254 oldcontext = MemoryContextSwitchTo(per_query_ctx);
2255
2256 tupstore = tuplestore_begin_heap(true, false, work_mem);
2257 rsinfo->returnMode = SFRM_Materialize;
2258 rsinfo->setResult = tupstore;
2259 rsinfo->setDesc = tupdesc;
2260
2261 MemoryContextSwitchTo(oldcontext);
2262
2263 /* Read the extension's control file */
2264 control = read_extension_control_file(NameStr(*extname));
2265
2266 /* Extract the version update graph from the script directory */
2267 evi_list = get_ext_ver_list(control);
2268
2269 /* Iterate over all pairs of versions */
2270 foreach(lc1, evi_list)
2271 {
2272 ExtensionVersionInfo *evi1 = (ExtensionVersionInfo *) lfirst(lc1);
2273 ListCell *lc2;
2274
2275 foreach(lc2, evi_list)
2276 {
2277 ExtensionVersionInfo *evi2 = (ExtensionVersionInfo *) lfirst(lc2);
2278 List *path;
2279 Datum values[3];
2280 bool nulls[3];
2281
2282 if (evi1 == evi2)
2283 continue;
2284
2285 /* Find shortest path from evi1 to evi2 */
2286 path = find_update_path(evi_list, evi1, evi2, false, true);
2287
2288 /* Emit result row */
2289 memset(values, 0, sizeof(values));
2290 memset(nulls, 0, sizeof(nulls));
2291
2292 /* source */
2293 values[0] = CStringGetTextDatum(evi1->name);
2294 /* target */
2295 values[1] = CStringGetTextDatum(evi2->name);
2296 /* path */
2297 if (path == NIL)
2298 nulls[2] = true;
2299 else
2300 {
2301 StringInfoData pathbuf;
2302 ListCell *lcv;
2303
2304 initStringInfo(&pathbuf);
2305 /* The path doesn't include start vertex, but show it */
2306 appendStringInfoString(&pathbuf, evi1->name);
2307 foreach(lcv, path)
2308 {
2309 char *versionName = (char *) lfirst(lcv);
2310
2311 appendStringInfoString(&pathbuf, "--");
2312 appendStringInfoString(&pathbuf, versionName);
2313 }
2314 values[2] = CStringGetTextDatum(pathbuf.data);
2315 pfree(pathbuf.data);
2316 }
2317
2318 tuplestore_putvalues(tupstore, tupdesc, values, nulls);
2319 }
2320 }
2321
2322 /* clean up and return the tuplestore */
2323 tuplestore_donestoring(tupstore);
2324
2325 return (Datum) 0;
2326}
2327
2328/*
2329 * pg_extension_config_dump
2330 *
2331 * Record information about a configuration table that belongs to an
2332 * extension being created, but whose contents should be dumped in whole
2333 * or in part during pg_dump.
2334 */
2335Datum
2336pg_extension_config_dump(PG_FUNCTION_ARGS)
2337{
2338 Oid tableoid = PG_GETARG_OID(0);
2339 text *wherecond = PG_GETARG_TEXT_PP(1);
2340 char *tablename;
2341 Relation extRel;
2342 ScanKeyData key[1];
2343 SysScanDesc extScan;
2344 HeapTuple extTup;
2345 Datum arrayDatum;
2346 Datum elementDatum;
2347 int arrayLength;
2348 int arrayIndex;
2349 bool isnull;
2350 Datum repl_val[Natts_pg_extension];
2351 bool repl_null[Natts_pg_extension];
2352 bool repl_repl[Natts_pg_extension];
2353 ArrayType *a;
2354
2355 /*
2356 * We only allow this to be called from an extension's SQL script. We
2357 * shouldn't need any permissions check beyond that.
2358 */
2359 if (!creating_extension)
2360 ereport(ERROR,
2361 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2362 errmsg("%s can only be called from an SQL script executed by CREATE EXTENSION",
2363 "pg_extension_config_dump()")));
2364
2365 /*
2366 * Check that the table exists and is a member of the extension being
2367 * created. This ensures that we don't need to register an additional
2368 * dependency to protect the extconfig entry.
2369 */
2370 tablename = get_rel_name(tableoid);
2371 if (tablename == NULL)
2372 ereport(ERROR,
2373 (errcode(ERRCODE_UNDEFINED_TABLE),
2374 errmsg("OID %u does not refer to a table", tableoid)));
2375 if (getExtensionOfObject(RelationRelationId, tableoid) !=
2376 CurrentExtensionObject)
2377 ereport(ERROR,
2378 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2379 errmsg("table \"%s\" is not a member of the extension being created",
2380 tablename)));
2381
2382 /*
2383 * Add the table OID and WHERE condition to the extension's extconfig and
2384 * extcondition arrays.
2385 *
2386 * If the table is already in extconfig, treat this as an update of the
2387 * WHERE condition.
2388 */
2389
2390 /* Find the pg_extension tuple */
2391 extRel = table_open(ExtensionRelationId, RowExclusiveLock);
2392
2393 ScanKeyInit(&key[0],
2394 Anum_pg_extension_oid,
2395 BTEqualStrategyNumber, F_OIDEQ,
2396 ObjectIdGetDatum(CurrentExtensionObject));
2397
2398 extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
2399 NULL, 1, key);
2400
2401 extTup = systable_getnext(extScan);
2402
2403 if (!HeapTupleIsValid(extTup)) /* should not happen */
2404 elog(ERROR, "could not find tuple for extension %u",
2405 CurrentExtensionObject);
2406
2407 memset(repl_val, 0, sizeof(repl_val));
2408 memset(repl_null, false, sizeof(repl_null));
2409 memset(repl_repl, false, sizeof(repl_repl));
2410
2411 /* Build or modify the extconfig value */
2412 elementDatum = ObjectIdGetDatum(tableoid);
2413
2414 arrayDatum = heap_getattr(extTup, Anum_pg_extension_extconfig,
2415 RelationGetDescr(extRel), &isnull);
2416 if (isnull)
2417 {
2418 /* Previously empty extconfig, so build 1-element array */
2419 arrayLength = 0;
2420 arrayIndex = 1;
2421
2422 a = construct_array(&elementDatum, 1,
2423 OIDOID,
2424 sizeof(Oid), true, 'i');
2425 }
2426 else
2427 {
2428 /* Modify or extend existing extconfig array */
2429 Oid *arrayData;
2430 int i;
2431
2432 a = DatumGetArrayTypeP(arrayDatum);
2433
2434 arrayLength = ARR_DIMS(a)[0];
2435 if (ARR_NDIM(a) != 1 ||
2436 ARR_LBOUND(a)[0] != 1 ||
2437 arrayLength < 0 ||
2438 ARR_HASNULL(a) ||
2439 ARR_ELEMTYPE(a) != OIDOID)
2440 elog(ERROR, "extconfig is not a 1-D Oid array");
2441 arrayData = (Oid *) ARR_DATA_PTR(a);
2442
2443 arrayIndex = arrayLength + 1; /* set up to add after end */
2444
2445 for (i = 0; i < arrayLength; i++)
2446 {
2447 if (arrayData[i] == tableoid)
2448 {
2449 arrayIndex = i + 1; /* replace this element instead */
2450 break;
2451 }
2452 }
2453
2454 a = array_set(a, 1, &arrayIndex,
2455 elementDatum,
2456 false,
2457 -1 /* varlena array */ ,
2458 sizeof(Oid) /* OID's typlen */ ,
2459 true /* OID's typbyval */ ,
2460 'i' /* OID's typalign */ );
2461 }
2462 repl_val[Anum_pg_extension_extconfig - 1] = PointerGetDatum(a);
2463 repl_repl[Anum_pg_extension_extconfig - 1] = true;
2464
2465 /* Build or modify the extcondition value */
2466 elementDatum = PointerGetDatum(wherecond);
2467
2468 arrayDatum = heap_getattr(extTup, Anum_pg_extension_extcondition,
2469 RelationGetDescr(extRel), &isnull);
2470 if (isnull)
2471 {
2472 if (arrayLength != 0)
2473 elog(ERROR, "extconfig and extcondition arrays do not match");
2474
2475 a = construct_array(&elementDatum, 1,
2476 TEXTOID,
2477 -1, false, 'i');
2478 }
2479 else
2480 {
2481 a = DatumGetArrayTypeP(arrayDatum);
2482
2483 if (ARR_NDIM(a) != 1 ||
2484 ARR_LBOUND(a)[0] != 1 ||
2485 ARR_HASNULL(a) ||
2486 ARR_ELEMTYPE(a) != TEXTOID)
2487 elog(ERROR, "extcondition is not a 1-D text array");
2488 if (ARR_DIMS(a)[0] != arrayLength)
2489 elog(ERROR, "extconfig and extcondition arrays do not match");
2490
2491 /* Add or replace at same index as in extconfig */
2492 a = array_set(a, 1, &arrayIndex,
2493 elementDatum,
2494 false,
2495 -1 /* varlena array */ ,
2496 -1 /* TEXT's typlen */ ,
2497 false /* TEXT's typbyval */ ,
2498 'i' /* TEXT's typalign */ );
2499 }
2500 repl_val[Anum_pg_extension_extcondition - 1] = PointerGetDatum(a);
2501 repl_repl[Anum_pg_extension_extcondition - 1] = true;
2502
2503 extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
2504 repl_val, repl_null, repl_repl);
2505
2506 CatalogTupleUpdate(extRel, &extTup->t_self, extTup);
2507
2508 systable_endscan(extScan);
2509
2510 table_close(extRel, RowExclusiveLock);
2511
2512 PG_RETURN_VOID();
2513}
2514
2515/*
2516 * extension_config_remove
2517 *
2518 * Remove the specified table OID from extension's extconfig, if present.
2519 * This is not currently exposed as a function, but it could be;
2520 * for now, we just invoke it from ALTER EXTENSION DROP.
2521 */
2522static void
2523extension_config_remove(Oid extensionoid, Oid tableoid)
2524{
2525 Relation extRel;
2526 ScanKeyData key[1];
2527 SysScanDesc extScan;
2528 HeapTuple extTup;
2529 Datum arrayDatum;
2530 int arrayLength;
2531 int arrayIndex;
2532 bool isnull;
2533 Datum repl_val[Natts_pg_extension];
2534 bool repl_null[Natts_pg_extension];
2535 bool repl_repl[Natts_pg_extension];
2536 ArrayType *a;
2537
2538 /* Find the pg_extension tuple */
2539 extRel = table_open(ExtensionRelationId, RowExclusiveLock);
2540
2541 ScanKeyInit(&key[0],
2542 Anum_pg_extension_oid,
2543 BTEqualStrategyNumber, F_OIDEQ,
2544 ObjectIdGetDatum(extensionoid));
2545
2546 extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
2547 NULL, 1, key);
2548
2549 extTup = systable_getnext(extScan);
2550
2551 if (!HeapTupleIsValid(extTup)) /* should not happen */
2552 elog(ERROR, "could not find tuple for extension %u",
2553 extensionoid);
2554
2555 /* Search extconfig for the tableoid */
2556 arrayDatum = heap_getattr(extTup, Anum_pg_extension_extconfig,
2557 RelationGetDescr(extRel), &isnull);
2558 if (isnull)
2559 {
2560 /* nothing to do */
2561 a = NULL;
2562 arrayLength = 0;
2563 arrayIndex = -1;
2564 }
2565 else
2566 {
2567 Oid *arrayData;
2568 int i;
2569
2570 a = DatumGetArrayTypeP(arrayDatum);
2571
2572 arrayLength = ARR_DIMS(a)[0];
2573 if (ARR_NDIM(a) != 1 ||
2574 ARR_LBOUND(a)[0] != 1 ||
2575 arrayLength < 0 ||
2576 ARR_HASNULL(a) ||
2577 ARR_ELEMTYPE(a) != OIDOID)
2578 elog(ERROR, "extconfig is not a 1-D Oid array");
2579 arrayData = (Oid *) ARR_DATA_PTR(a);
2580
2581 arrayIndex = -1; /* flag for no deletion needed */
2582
2583 for (i = 0; i < arrayLength; i++)
2584 {
2585 if (arrayData[i] == tableoid)
2586 {
2587 arrayIndex = i; /* index to remove */
2588 break;
2589 }
2590 }
2591 }
2592
2593 /* If tableoid is not in extconfig, nothing to do */
2594 if (arrayIndex < 0)
2595 {
2596 systable_endscan(extScan);
2597 table_close(extRel, RowExclusiveLock);
2598 return;
2599 }
2600
2601 /* Modify or delete the extconfig value */
2602 memset(repl_val, 0, sizeof(repl_val));
2603 memset(repl_null, false, sizeof(repl_null));
2604 memset(repl_repl, false, sizeof(repl_repl));
2605
2606 if (arrayLength <= 1)
2607 {
2608 /* removing only element, just set array to null */
2609 repl_null[Anum_pg_extension_extconfig - 1] = true;
2610 }
2611 else
2612 {
2613 /* squeeze out the target element */
2614 Datum *dvalues;
2615 int nelems;
2616 int i;
2617
2618 /* We already checked there are no nulls */
2619 deconstruct_array(a, OIDOID, sizeof(Oid), true, 'i',
2620 &dvalues, NULL, &nelems);
2621
2622 for (i = arrayIndex; i < arrayLength - 1; i++)
2623 dvalues[i] = dvalues[i + 1];
2624
2625 a = construct_array(dvalues, arrayLength - 1,
2626 OIDOID, sizeof(Oid), true, 'i');
2627
2628 repl_val[Anum_pg_extension_extconfig - 1] = PointerGetDatum(a);
2629 }
2630 repl_repl[Anum_pg_extension_extconfig - 1] = true;
2631
2632 /* Modify or delete the extcondition value */
2633 arrayDatum = heap_getattr(extTup, Anum_pg_extension_extcondition,
2634 RelationGetDescr(extRel), &isnull);
2635 if (isnull)
2636 {
2637 elog(ERROR, "extconfig and extcondition arrays do not match");
2638 }
2639 else
2640 {
2641 a = DatumGetArrayTypeP(arrayDatum);
2642
2643 if (ARR_NDIM(a) != 1 ||
2644 ARR_LBOUND(a)[0] != 1 ||
2645 ARR_HASNULL(a) ||
2646 ARR_ELEMTYPE(a) != TEXTOID)
2647 elog(ERROR, "extcondition is not a 1-D text array");
2648 if (ARR_DIMS(a)[0] != arrayLength)
2649 elog(ERROR, "extconfig and extcondition arrays do not match");
2650 }
2651
2652 if (arrayLength <= 1)
2653 {
2654 /* removing only element, just set array to null */
2655 repl_null[Anum_pg_extension_extcondition - 1] = true;
2656 }
2657 else
2658 {
2659 /* squeeze out the target element */
2660 Datum *dvalues;
2661 int nelems;
2662 int i;
2663
2664 /* We already checked there are no nulls */
2665 deconstruct_array(a, TEXTOID, -1, false, 'i',
2666 &dvalues, NULL, &nelems);
2667
2668 for (i = arrayIndex; i < arrayLength - 1; i++)
2669 dvalues[i] = dvalues[i + 1];
2670
2671 a = construct_array(dvalues, arrayLength - 1,
2672 TEXTOID, -1, false, 'i');
2673
2674 repl_val[Anum_pg_extension_extcondition - 1] = PointerGetDatum(a);
2675 }
2676 repl_repl[Anum_pg_extension_extcondition - 1] = true;
2677
2678 extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
2679 repl_val, repl_null, repl_repl);
2680
2681 CatalogTupleUpdate(extRel, &extTup->t_self, extTup);
2682
2683 systable_endscan(extScan);
2684
2685 table_close(extRel, RowExclusiveLock);
2686}
2687
2688/*
2689 * Execute ALTER EXTENSION SET SCHEMA
2690 */
2691ObjectAddress
2692AlterExtensionNamespace(const char *extensionName, const char *newschema, Oid *oldschema)
2693{
2694 Oid extensionOid;
2695 Oid nspOid;
2696 Oid oldNspOid = InvalidOid;
2697 AclResult aclresult;
2698 Relation extRel;
2699 ScanKeyData key[2];
2700 SysScanDesc extScan;
2701 HeapTuple extTup;
2702 Form_pg_extension extForm;
2703 Relation depRel;
2704 SysScanDesc depScan;
2705 HeapTuple depTup;
2706 ObjectAddresses *objsMoved;
2707 ObjectAddress extAddr;
2708
2709 extensionOid = get_extension_oid(extensionName, false);
2710
2711 nspOid = LookupCreationNamespace(newschema);
2712
2713 /*
2714 * Permission check: must own extension. Note that we don't bother to
2715 * check ownership of the individual member objects ...
2716 */
2717 if (!pg_extension_ownercheck(extensionOid, GetUserId()))
2718 aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_EXTENSION,
2719 extensionName);
2720
2721 /* Permission check: must have creation rights in target namespace */
2722 aclresult = pg_namespace_aclcheck(nspOid, GetUserId(), ACL_CREATE);
2723 if (aclresult != ACLCHECK_OK)
2724 aclcheck_error(aclresult, OBJECT_SCHEMA, newschema);
2725
2726 /*
2727 * If the schema is currently a member of the extension, disallow moving
2728 * the extension into the schema. That would create a dependency loop.
2729 */
2730 if (getExtensionOfObject(NamespaceRelationId, nspOid) == extensionOid)
2731 ereport(ERROR,
2732 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2733 errmsg("cannot move extension \"%s\" into schema \"%s\" "
2734 "because the extension contains the schema",
2735 extensionName, newschema)));
2736
2737 /* Locate the pg_extension tuple */
2738 extRel = table_open(ExtensionRelationId, RowExclusiveLock);
2739
2740 ScanKeyInit(&key[0],
2741 Anum_pg_extension_oid,
2742 BTEqualStrategyNumber, F_OIDEQ,
2743 ObjectIdGetDatum(extensionOid));
2744
2745 extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
2746 NULL, 1, key);
2747
2748 extTup = systable_getnext(extScan);
2749
2750 if (!HeapTupleIsValid(extTup)) /* should not happen */
2751 elog(ERROR, "could not find tuple for extension %u",
2752 extensionOid);
2753
2754 /* Copy tuple so we can modify it below */
2755 extTup = heap_copytuple(extTup);
2756 extForm = (Form_pg_extension) GETSTRUCT(extTup);
2757
2758 systable_endscan(extScan);
2759
2760 /*
2761 * If the extension is already in the target schema, just silently do
2762 * nothing.
2763 */
2764 if (extForm->extnamespace == nspOid)
2765 {
2766 table_close(extRel, RowExclusiveLock);
2767 return InvalidObjectAddress;
2768 }
2769
2770 /* Check extension is supposed to be relocatable */
2771 if (!extForm->extrelocatable)
2772 ereport(ERROR,
2773 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2774 errmsg("extension \"%s\" does not support SET SCHEMA",
2775 NameStr(extForm->extname))));
2776
2777 objsMoved = new_object_addresses();
2778
2779 /*
2780 * Scan pg_depend to find objects that depend directly on the extension,
2781 * and alter each one's schema.
2782 */
2783 depRel = table_open(DependRelationId, AccessShareLock);
2784
2785 ScanKeyInit(&key[0],
2786 Anum_pg_depend_refclassid,
2787 BTEqualStrategyNumber, F_OIDEQ,
2788 ObjectIdGetDatum(ExtensionRelationId));
2789 ScanKeyInit(&key[1],
2790 Anum_pg_depend_refobjid,
2791 BTEqualStrategyNumber, F_OIDEQ,
2792 ObjectIdGetDatum(extensionOid));
2793
2794 depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
2795 NULL, 2, key);
2796
2797 while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
2798 {
2799 Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
2800 ObjectAddress dep;
2801 Oid dep_oldNspOid;
2802
2803 /*
2804 * Ignore non-membership dependencies. (Currently, the only other
2805 * case we could see here is a normal dependency from another
2806 * extension.)
2807 */
2808 if (pg_depend->deptype != DEPENDENCY_EXTENSION)
2809 continue;
2810
2811 dep.classId = pg_depend->classid;
2812 dep.objectId = pg_depend->objid;
2813 dep.objectSubId = pg_depend->objsubid;
2814
2815 if (dep.objectSubId != 0) /* should not happen */
2816 elog(ERROR, "extension should not have a sub-object dependency");
2817
2818 /* Relocate the object */
2819 dep_oldNspOid = AlterObjectNamespace_oid(dep.classId,
2820 dep.objectId,
2821 nspOid,
2822 objsMoved);
2823
2824 /*
2825 * Remember previous namespace of first object that has one
2826 */
2827 if (oldNspOid == InvalidOid && dep_oldNspOid != InvalidOid)
2828 oldNspOid = dep_oldNspOid;
2829
2830 /*
2831 * If not all the objects had the same old namespace (ignoring any
2832 * that are not in namespaces), complain.
2833 */
2834 if (dep_oldNspOid != InvalidOid && dep_oldNspOid != oldNspOid)
2835 ereport(ERROR,
2836 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2837 errmsg("extension \"%s\" does not support SET SCHEMA",
2838 NameStr(extForm->extname)),
2839 errdetail("%s is not in the extension's schema \"%s\"",
2840 getObjectDescription(&dep),
2841 get_namespace_name(oldNspOid))));
2842 }
2843
2844 /* report old schema, if caller wants it */
2845 if (oldschema)
2846 *oldschema = oldNspOid;
2847
2848 systable_endscan(depScan);
2849
2850 relation_close(depRel, AccessShareLock);
2851
2852 /* Now adjust pg_extension.extnamespace */
2853 extForm->extnamespace = nspOid;
2854
2855 CatalogTupleUpdate(extRel, &extTup->t_self, extTup);
2856
2857 table_close(extRel, RowExclusiveLock);
2858
2859 /* update dependencies to point to the new schema */
2860 changeDependencyFor(ExtensionRelationId, extensionOid,
2861 NamespaceRelationId, oldNspOid, nspOid);
2862
2863 InvokeObjectPostAlterHook(ExtensionRelationId, extensionOid, 0);
2864
2865 ObjectAddressSet(extAddr, ExtensionRelationId, extensionOid);
2866
2867 return extAddr;
2868}
2869
2870/*
2871 * Execute ALTER EXTENSION UPDATE
2872 */
2873ObjectAddress
2874ExecAlterExtensionStmt(ParseState *pstate, AlterExtensionStmt *stmt)
2875{
2876 DefElem *d_new_version = NULL;
2877 char *versionName;
2878 char *oldVersionName;
2879 ExtensionControlFile *control;
2880 Oid extensionOid;
2881 Relation extRel;
2882 ScanKeyData key[1];
2883 SysScanDesc extScan;
2884 HeapTuple extTup;
2885 List *updateVersions;
2886 Datum datum;
2887 bool isnull;
2888 ListCell *lc;
2889 ObjectAddress address;
2890
2891 /*
2892 * We use global variables to track the extension being created, so we can
2893 * create/update only one extension at the same time.
2894 */
2895 if (creating_extension)
2896 ereport(ERROR,
2897 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2898 errmsg("nested ALTER EXTENSION is not supported")));
2899
2900 /*
2901 * Look up the extension --- it must already exist in pg_extension
2902 */
2903 extRel = table_open(ExtensionRelationId, AccessShareLock);
2904
2905 ScanKeyInit(&key[0],
2906 Anum_pg_extension_extname,
2907 BTEqualStrategyNumber, F_NAMEEQ,
2908 CStringGetDatum(stmt->extname));
2909
2910 extScan = systable_beginscan(extRel, ExtensionNameIndexId, true,
2911 NULL, 1, key);
2912
2913 extTup = systable_getnext(extScan);
2914
2915 if (!HeapTupleIsValid(extTup))
2916 ereport(ERROR,
2917 (errcode(ERRCODE_UNDEFINED_OBJECT),
2918 errmsg("extension \"%s\" does not exist",
2919 stmt->extname)));
2920
2921 extensionOid = ((Form_pg_extension) GETSTRUCT(extTup))->oid;
2922
2923 /*
2924 * Determine the existing version we are updating from
2925 */
2926 datum = heap_getattr(extTup, Anum_pg_extension_extversion,
2927 RelationGetDescr(extRel), &isnull);
2928 if (isnull)
2929 elog(ERROR, "extversion is null");
2930 oldVersionName = text_to_cstring(DatumGetTextPP(datum));
2931
2932 systable_endscan(extScan);
2933
2934 table_close(extRel, AccessShareLock);
2935
2936 /* Permission check: must own extension */
2937 if (!pg_extension_ownercheck(extensionOid, GetUserId()))
2938 aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_EXTENSION,
2939 stmt->extname);
2940
2941 /*
2942 * Read the primary control file. Note we assume that it does not contain
2943 * any non-ASCII data, so there is no need to worry about encoding at this
2944 * point.
2945 */
2946 control = read_extension_control_file(stmt->extname);
2947
2948 /*
2949 * Read the statement option list
2950 */
2951 foreach(lc, stmt->options)
2952 {
2953 DefElem *defel = (DefElem *) lfirst(lc);
2954
2955 if (strcmp(defel->defname, "new_version") == 0)
2956 {
2957 if (d_new_version)
2958 ereport(ERROR,
2959 (errcode(ERRCODE_SYNTAX_ERROR),
2960 errmsg("conflicting or redundant options"),
2961 parser_errposition(pstate, defel->location)));
2962 d_new_version = defel;
2963 }
2964 else
2965 elog(ERROR, "unrecognized option: %s", defel->defname);
2966 }
2967
2968 /*
2969 * Determine the version to update to
2970 */
2971 if (d_new_version && d_new_version->arg)
2972 versionName = strVal(d_new_version->arg);
2973 else if (control->default_version)
2974 versionName = control->default_version;
2975 else
2976 {
2977 ereport(ERROR,
2978 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2979 errmsg("version to install must be specified")));
2980 versionName = NULL; /* keep compiler quiet */
2981 }
2982 check_valid_version_name(versionName);
2983
2984 /*
2985 * If we're already at that version, just say so
2986 */
2987 if (strcmp(oldVersionName, versionName) == 0)
2988 {
2989 ereport(NOTICE,
2990 (errmsg("version \"%s\" of extension \"%s\" is already installed",
2991 versionName, stmt->extname)));
2992 return InvalidObjectAddress;
2993 }
2994
2995 /*
2996 * Identify the series of update script files we need to execute
2997 */
2998 updateVersions = identify_update_path(control,
2999 oldVersionName,
3000 versionName);
3001
3002 /*
3003 * Update the pg_extension row and execute the update scripts, one at a
3004 * time
3005 */
3006 ApplyExtensionUpdates(extensionOid, control,
3007 oldVersionName, updateVersions,
3008 NULL, false, false);
3009
3010 ObjectAddressSet(address, ExtensionRelationId, extensionOid);
3011
3012 return address;
3013}
3014
3015/*
3016 * Apply a series of update scripts as though individual ALTER EXTENSION
3017 * UPDATE commands had been given, including altering the pg_extension row
3018 * and dependencies each time.
3019 *
3020 * This might be more work than necessary, but it ensures that old update
3021 * scripts don't break if newer versions have different control parameters.
3022 */
3023static void
3024ApplyExtensionUpdates(Oid extensionOid,
3025 ExtensionControlFile *pcontrol,
3026 const char *initialVersion,
3027 List *updateVersions,
3028 char *origSchemaName,
3029 bool cascade,
3030 bool is_create)
3031{
3032 const char *oldVersionName = initialVersion;
3033 ListCell *lcv;
3034
3035 foreach(lcv, updateVersions)
3036 {
3037 char *versionName = (char *) lfirst(lcv);
3038 ExtensionControlFile *control;
3039 char *schemaName;
3040 Oid schemaOid;
3041 List *requiredExtensions;
3042 List *requiredSchemas;
3043 Relation extRel;
3044 ScanKeyData key[1];
3045 SysScanDesc extScan;
3046 HeapTuple extTup;
3047 Form_pg_extension extForm;
3048 Datum values[Natts_pg_extension];
3049 bool nulls[Natts_pg_extension];
3050 bool repl[Natts_pg_extension];
3051 ObjectAddress myself;
3052 ListCell *lc;
3053
3054 /*
3055 * Fetch parameters for specific version (pcontrol is not changed)
3056 */
3057 control = read_extension_aux_control_file(pcontrol, versionName);
3058
3059 /* Find the pg_extension tuple */
3060 extRel = table_open(ExtensionRelationId, RowExclusiveLock);
3061
3062 ScanKeyInit(&key[0],
3063 Anum_pg_extension_oid,
3064 BTEqualStrategyNumber, F_OIDEQ,
3065 ObjectIdGetDatum(extensionOid));
3066
3067 extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
3068 NULL, 1, key);
3069
3070 extTup = systable_getnext(extScan);
3071
3072 if (!HeapTupleIsValid(extTup)) /* should not happen */
3073 elog(ERROR, "could not find tuple for extension %u",
3074 extensionOid);
3075
3076 extForm = (Form_pg_extension) GETSTRUCT(extTup);
3077
3078 /*
3079 * Determine the target schema (set by original install)
3080 */
3081 schemaOid = extForm->extnamespace;
3082 schemaName = get_namespace_name(schemaOid);
3083
3084 /*
3085 * Modify extrelocatable and extversion in the pg_extension tuple
3086 */
3087 memset(values, 0, sizeof(values));
3088 memset(nulls, 0, sizeof(nulls));
3089 memset(repl, 0, sizeof(repl));
3090
3091 values[Anum_pg_extension_extrelocatable - 1] =
3092 BoolGetDatum(control->relocatable);
3093 repl[Anum_pg_extension_extrelocatable - 1] = true;
3094 values[Anum_pg_extension_extversion - 1] =
3095 CStringGetTextDatum(versionName);
3096 repl[Anum_pg_extension_extversion - 1] = true;
3097
3098 extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
3099 values, nulls, repl);
3100
3101 CatalogTupleUpdate(extRel, &extTup->t_self, extTup);
3102
3103 systable_endscan(extScan);
3104
3105 table_close(extRel, RowExclusiveLock);
3106
3107 /*
3108 * Look up the prerequisite extensions for this version, install them
3109 * if necessary, and build lists of their OIDs and the OIDs of their
3110 * target schemas.
3111 */
3112 requiredExtensions = NIL;
3113 requiredSchemas = NIL;
3114 foreach(lc, control->requires)
3115 {
3116 char *curreq = (char *) lfirst(lc);
3117 Oid reqext;
3118 Oid reqschema;
3119
3120 reqext = get_required_extension(curreq,
3121 control->name,
3122 origSchemaName,
3123 cascade,
3124 NIL,
3125 is_create);
3126 reqschema = get_extension_schema(reqext);
3127 requiredExtensions = lappend_oid(requiredExtensions, reqext);
3128 requiredSchemas = lappend_oid(requiredSchemas, reqschema);
3129 }
3130
3131 /*
3132 * Remove and recreate dependencies on prerequisite extensions
3133 */
3134 deleteDependencyRecordsForClass(ExtensionRelationId, extensionOid,
3135 ExtensionRelationId,
3136 DEPENDENCY_NORMAL);
3137
3138 myself.classId = ExtensionRelationId;
3139 myself.objectId = extensionOid;
3140 myself.objectSubId = 0;
3141
3142 foreach(lc, requiredExtensions)
3143 {
3144 Oid reqext = lfirst_oid(lc);
3145 ObjectAddress otherext;
3146
3147 otherext.classId = ExtensionRelationId;
3148 otherext.objectId = reqext;
3149 otherext.objectSubId = 0;
3150
3151 recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
3152 }
3153
3154 InvokeObjectPostAlterHook(ExtensionRelationId, extensionOid, 0);
3155
3156 /*
3157 * Finally, execute the update script file
3158 */
3159 execute_extension_script(extensionOid, control,
3160 oldVersionName, versionName,
3161 requiredSchemas,
3162 schemaName, schemaOid);
3163
3164 /*
3165 * Update prior-version name and loop around. Since
3166 * execute_sql_string did a final CommandCounterIncrement, we can
3167 * update the pg_extension row again.
3168 */
3169 oldVersionName = versionName;
3170 }
3171}
3172
3173/*
3174 * Execute ALTER EXTENSION ADD/DROP
3175 *
3176 * Return value is the address of the altered extension.
3177 *
3178 * objAddr is an output argument which, if not NULL, is set to the address of
3179 * the added/dropped object.
3180 */
3181ObjectAddress
3182ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt,
3183 ObjectAddress *objAddr)
3184{
3185 ObjectAddress extension;
3186 ObjectAddress object;
3187 Relation relation;
3188 Oid oldExtension;
3189
3190 extension.classId = ExtensionRelationId;
3191 extension.objectId = get_extension_oid(stmt->extname, false);
3192 extension.objectSubId = 0;
3193
3194 /* Permission check: must own extension */
3195 if (!pg_extension_ownercheck(extension.objectId, GetUserId()))
3196 aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_EXTENSION,
3197 stmt->extname);
3198
3199 /*
3200 * Translate the parser representation that identifies the object into an
3201 * ObjectAddress. get_object_address() will throw an error if the object
3202 * does not exist, and will also acquire a lock on the object to guard
3203 * against concurrent DROP and ALTER EXTENSION ADD/DROP operations.
3204 */
3205 object = get_object_address(stmt->objtype, stmt->object,
3206 &relation, ShareUpdateExclusiveLock, false);
3207
3208 Assert(object.objectSubId == 0);
3209 if (objAddr)
3210 *objAddr = object;
3211
3212 /* Permission check: must own target object, too */
3213 check_object_ownership(GetUserId(), stmt->objtype, object,
3214 stmt->object, relation);
3215
3216 /*
3217 * Check existing extension membership.
3218 */
3219 oldExtension = getExtensionOfObject(object.classId, object.objectId);
3220
3221 if (stmt->action > 0)
3222 {
3223 /*
3224 * ADD, so complain if object is already attached to some extension.
3225 */
3226 if (OidIsValid(oldExtension))
3227 ereport(ERROR,
3228 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3229 errmsg("%s is already a member of extension \"%s\"",
3230 getObjectDescription(&object),
3231 get_extension_name(oldExtension))));
3232
3233 /*
3234 * Prevent a schema from being added to an extension if the schema
3235 * contains the extension. That would create a dependency loop.
3236 */
3237 if (object.classId == NamespaceRelationId &&
3238 object.objectId == get_extension_schema(extension.objectId))
3239 ereport(ERROR,
3240 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3241 errmsg("cannot add schema \"%s\" to extension \"%s\" "
3242 "because the schema contains the extension",
3243 get_namespace_name(object.objectId),
3244 stmt->extname)));
3245
3246 /*
3247 * OK, add the dependency.
3248 */
3249 recordDependencyOn(&object, &extension, DEPENDENCY_EXTENSION);
3250
3251 /*
3252 * Also record the initial ACL on the object, if any.
3253 *
3254 * Note that this will handle the object's ACLs, as well as any ACLs
3255 * on object subIds. (In other words, when the object is a table,
3256 * this will record the table's ACL and the ACLs for the columns on
3257 * the table, if any).
3258 */
3259 recordExtObjInitPriv(object.objectId, object.classId);
3260 }
3261 else
3262 {
3263 /*
3264 * DROP, so complain if it's not a member.
3265 */
3266 if (oldExtension != extension.objectId)
3267 ereport(ERROR,
3268 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
3269 errmsg("%s is not a member of extension \"%s\"",
3270 getObjectDescription(&object),
3271 stmt->extname)));
3272
3273 /*
3274 * OK, drop the dependency.
3275 */
3276 if (deleteDependencyRecordsForClass(object.classId, object.objectId,
3277 ExtensionRelationId,
3278 DEPENDENCY_EXTENSION) != 1)
3279 elog(ERROR, "unexpected number of extension dependency records");
3280
3281 /*
3282 * If it's a relation, it might have an entry in the extension's
3283 * extconfig array, which we must remove.
3284 */
3285 if (object.classId == RelationRelationId)
3286 extension_config_remove(extension.objectId, object.objectId);
3287
3288 /*
3289 * Remove all the initial ACLs, if any.
3290 *
3291 * Note that this will remove the object's ACLs, as well as any ACLs
3292 * on object subIds. (In other words, when the object is a table,
3293 * this will remove the table's ACL and the ACLs for the columns on
3294 * the table, if any).
3295 */
3296 removeExtObjInitPriv(object.objectId, object.classId);
3297 }
3298
3299 InvokeObjectPostAlterHook(ExtensionRelationId, extension.objectId, 0);
3300
3301 /*
3302 * If get_object_address() opened the relation for us, we close it to keep
3303 * the reference count correct - but we retain any locks acquired by
3304 * get_object_address() until commit time, to guard against concurrent
3305 * activity.
3306 */
3307 if (relation != NULL)
3308 relation_close(relation, NoLock);
3309
3310 return extension;
3311}
3312
3313/*
3314 * Read the whole of file into memory.
3315 *
3316 * The file contents are returned as a single palloc'd chunk. For convenience
3317 * of the callers, an extra \0 byte is added to the end.
3318 */
3319static char *
3320read_whole_file(const char *filename, int *length)
3321{
3322 char *buf;
3323 FILE *file;
3324 size_t bytes_to_read;
3325 struct stat fst;
3326
3327 if (stat(filename, &fst) < 0)
3328 ereport(ERROR,
3329 (errcode_for_file_access(),
3330 errmsg("could not stat file \"%s\": %m", filename)));
3331
3332 if (fst.st_size > (MaxAllocSize - 1))
3333 ereport(ERROR,
3334 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3335 errmsg("file \"%s\" is too large", filename)));
3336 bytes_to_read = (size_t) fst.st_size;
3337
3338 if ((file = AllocateFile(filename, PG_BINARY_R)) == NULL)
3339 ereport(ERROR,
3340 (errcode_for_file_access(),
3341 errmsg("could not open file \"%s\" for reading: %m",
3342 filename)));
3343
3344 buf = (char *) palloc(bytes_to_read + 1);
3345
3346 *length = fread(buf, 1, bytes_to_read, file);
3347
3348 if (ferror(file))
3349 ereport(ERROR,
3350 (errcode_for_file_access(),
3351 errmsg("could not read file \"%s\": %m", filename)));
3352
3353 FreeFile(file);
3354
3355 buf[*length] = '\0';
3356 return buf;
3357}
3358