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