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