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