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