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