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