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