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