OSDN Git Service

08fb3d5d360f00bc0bb919454efc6adfca11ebbd
[pg-rex/syncrep.git] / src / backend / commands / extension.c
1 /*-------------------------------------------------------------------------
2  *
3  * extension.c
4  *        Commands to manipulate extensions
5  *
6  * Extensions in PostgreSQL allow management of collections of SQL objects.
7  *
8  * All we need internally to manage an extension is an OID so that the
9  * dependent objects can be associated with it.  An extension is created by
10  * populating the pg_extension catalog from a "control" file.
11  * The extension control file is parsed with the same parser we use for
12  * postgresql.conf and recovery.conf.  An extension also has an installation
13  * script file, containing SQL commands to create the extension's objects.
14  *
15  * Portions Copyright (c) 1996-2011, 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 <unistd.h>
29
30 #include "access/sysattr.h"
31 #include "access/xact.h"
32 #include "catalog/dependency.h"
33 #include "catalog/indexing.h"
34 #include "catalog/namespace.h"
35 #include "catalog/objectaccess.h"
36 #include "catalog/pg_depend.h"
37 #include "catalog/pg_extension.h"
38 #include "catalog/pg_namespace.h"
39 #include "catalog/pg_type.h"
40 #include "commands/alter.h"
41 #include "commands/comment.h"
42 #include "commands/extension.h"
43 #include "commands/trigger.h"
44 #include "executor/executor.h"
45 #include "funcapi.h"
46 #include "mb/pg_wchar.h"
47 #include "miscadmin.h"
48 #include "tcop/tcopprot.h"
49 #include "tcop/utility.h"
50 #include "utils/builtins.h"
51 #include "utils/fmgroids.h"
52 #include "utils/guc.h"
53 #include "utils/lsyscache.h"
54 #include "utils/snapmgr.h"
55 #include "utils/tqual.h"
56
57
58 /* Globally visible state variables */
59 bool            creating_extension = false;
60 Oid                     CurrentExtensionObject = InvalidOid;
61
62 /*
63  * Internal data structure to hold the results of parsing a control file
64  */
65 typedef struct ExtensionControlFile
66 {
67         char       *name;                       /* name of the extension */
68         char       *directory;          /* directory for script files */
69         char       *default_version;    /* default install target version, if any */
70         char       *module_pathname;    /* string to substitute for MODULE_PATHNAME */
71         char       *comment;            /* comment, if any */
72         char       *schema;                     /* target schema (allowed if !relocatable) */
73         bool            relocatable;    /* is ALTER EXTENSION SET SCHEMA supported? */
74         bool            superuser;              /* must be superuser to install? */
75         int                     encoding;               /* encoding of the script file, or -1 */
76         List       *requires;           /* names of prerequisite extensions */
77 } ExtensionControlFile;
78
79 /*
80  * Internal data structure for update path information
81  */
82 typedef struct ExtensionVersionInfo
83 {
84         char       *name;                       /* name of the starting version */
85         List       *reachable;          /* List of ExtensionVersionInfo's */
86         bool            installable;    /* does this version have an install script? */
87         /* working state for Dijkstra's algorithm: */
88         bool            distance_known; /* is distance from start known yet? */
89         int                     distance;               /* current worst-case distance estimate */
90         struct ExtensionVersionInfo *previous;          /* current best predecessor */
91 } ExtensionVersionInfo;
92
93 /* Local functions */
94 static List *find_update_path(List *evi_list,
95                                  ExtensionVersionInfo *evi_start,
96                                  ExtensionVersionInfo *evi_target,
97                                  bool reinitialize);
98 static void get_available_versions_for_extension(ExtensionControlFile *pcontrol,
99                                                                          Tuplestorestate *tupstore,
100                                                                          TupleDesc tupdesc);
101 static void ApplyExtensionUpdates(Oid extensionOid,
102                                           ExtensionControlFile *pcontrol,
103                                           const char *initialVersion,
104                                           List *updateVersions);
105
106
107 /*
108  * get_extension_oid - given an extension name, look up the OID
109  *
110  * If missing_ok is false, throw an error if extension name not found.  If
111  * true, just return InvalidOid.
112  */
113 Oid
114 get_extension_oid(const char *extname, bool missing_ok)
115 {
116         Oid                     result;
117         Relation        rel;
118         SysScanDesc scandesc;
119         HeapTuple       tuple;
120         ScanKeyData entry[1];
121
122         rel = heap_open(ExtensionRelationId, AccessShareLock);
123
124         ScanKeyInit(&entry[0],
125                                 Anum_pg_extension_extname,
126                                 BTEqualStrategyNumber, F_NAMEEQ,
127                                 CStringGetDatum(extname));
128
129         scandesc = systable_beginscan(rel, ExtensionNameIndexId, true,
130                                                                   SnapshotNow, 1, entry);
131
132         tuple = systable_getnext(scandesc);
133
134         /* We assume that there can be at most one matching tuple */
135         if (HeapTupleIsValid(tuple))
136                 result = HeapTupleGetOid(tuple);
137         else
138                 result = InvalidOid;
139
140         systable_endscan(scandesc);
141
142         heap_close(rel, AccessShareLock);
143
144         if (!OidIsValid(result) && !missing_ok)
145                 ereport(ERROR,
146                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
147                                  errmsg("extension \"%s\" does not exist",
148                                                 extname)));
149
150         return result;
151 }
152
153 /*
154  * get_extension_name - given an extension OID, look up the name
155  *
156  * Returns a palloc'd string, or NULL if no such extension.
157  */
158 char *
159 get_extension_name(Oid ext_oid)
160 {
161         char       *result;
162         Relation        rel;
163         SysScanDesc scandesc;
164         HeapTuple       tuple;
165         ScanKeyData entry[1];
166
167         rel = heap_open(ExtensionRelationId, AccessShareLock);
168
169         ScanKeyInit(&entry[0],
170                                 ObjectIdAttributeNumber,
171                                 BTEqualStrategyNumber, F_OIDEQ,
172                                 ObjectIdGetDatum(ext_oid));
173
174         scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
175                                                                   SnapshotNow, 1, entry);
176
177         tuple = systable_getnext(scandesc);
178
179         /* We assume that there can be at most one matching tuple */
180         if (HeapTupleIsValid(tuple))
181                 result = pstrdup(NameStr(((Form_pg_extension) GETSTRUCT(tuple))->extname));
182         else
183                 result = NULL;
184
185         systable_endscan(scandesc);
186
187         heap_close(rel, AccessShareLock);
188
189         return result;
190 }
191
192 /*
193  * get_extension_schema - given an extension OID, fetch its extnamespace
194  *
195  * Returns InvalidOid if no such extension.
196  */
197 static Oid
198 get_extension_schema(Oid ext_oid)
199 {
200         Oid                     result;
201         Relation        rel;
202         SysScanDesc scandesc;
203         HeapTuple       tuple;
204         ScanKeyData entry[1];
205
206         rel = heap_open(ExtensionRelationId, AccessShareLock);
207
208         ScanKeyInit(&entry[0],
209                                 ObjectIdAttributeNumber,
210                                 BTEqualStrategyNumber, F_OIDEQ,
211                                 ObjectIdGetDatum(ext_oid));
212
213         scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
214                                                                   SnapshotNow, 1, entry);
215
216         tuple = systable_getnext(scandesc);
217
218         /* We assume that there can be at most one matching tuple */
219         if (HeapTupleIsValid(tuple))
220                 result = ((Form_pg_extension) GETSTRUCT(tuple))->extnamespace;
221         else
222                 result = InvalidOid;
223
224         systable_endscan(scandesc);
225
226         heap_close(rel, AccessShareLock);
227
228         return result;
229 }
230
231 /*
232  * Utility functions to check validity of extension and version names
233  */
234 static void
235 check_valid_extension_name(const char *extensionname)
236 {
237         int                     namelen = strlen(extensionname);
238
239         /*
240          * Disallow empty names (the parser rejects empty identifiers anyway, but
241          * let's check).
242          */
243         if (namelen == 0)
244                 ereport(ERROR,
245                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
246                                  errmsg("invalid extension name: \"%s\"", extensionname),
247                                  errdetail("Extension names must not be empty.")));
248
249         /*
250          * No double dashes, since that would make script filenames ambiguous.
251          */
252         if (strstr(extensionname, "--"))
253                 ereport(ERROR,
254                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
255                                  errmsg("invalid extension name: \"%s\"", extensionname),
256                                  errdetail("Extension names must not contain \"--\".")));
257
258         /*
259          * No leading or trailing dash either.  (We could probably allow this, but
260          * it would require much care in filename parsing and would make filenames
261          * visually if not formally ambiguous.  Since there's no real-world use
262          * case, let's just forbid it.)
263          */
264         if (extensionname[0] == '-' || extensionname[namelen - 1] == '-')
265                 ereport(ERROR,
266                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
267                                  errmsg("invalid extension name: \"%s\"", extensionname),
268                         errdetail("Extension names must not begin or end with \"-\".")));
269
270         /*
271          * No directory separators either (this is sufficient to prevent ".."
272          * style attacks).
273          */
274         if (first_dir_separator(extensionname) != NULL)
275                 ereport(ERROR,
276                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
277                                  errmsg("invalid extension name: \"%s\"", extensionname),
278                                  errdetail("Extension names must not contain directory separator characters.")));
279 }
280
281 static void
282 check_valid_version_name(const char *versionname)
283 {
284         int                     namelen = strlen(versionname);
285
286         /*
287          * Disallow empty names (we could possibly allow this, but there seems
288          * little point).
289          */
290         if (namelen == 0)
291                 ereport(ERROR,
292                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
293                            errmsg("invalid extension version name: \"%s\"", versionname),
294                                  errdetail("Version names must not be empty.")));
295
296         /*
297          * No double dashes, since that would make script filenames ambiguous.
298          */
299         if (strstr(versionname, "--"))
300                 ereport(ERROR,
301                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
302                            errmsg("invalid extension version name: \"%s\"", versionname),
303                                  errdetail("Version names must not contain \"--\".")));
304
305         /*
306          * No leading or trailing dash either.
307          */
308         if (versionname[0] == '-' || versionname[namelen - 1] == '-')
309                 ereport(ERROR,
310                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
311                            errmsg("invalid extension version name: \"%s\"", versionname),
312                           errdetail("Version names must not begin or end with \"-\".")));
313
314         /*
315          * No directory separators either (this is sufficient to prevent ".."
316          * style attacks).
317          */
318         if (first_dir_separator(versionname) != NULL)
319                 ereport(ERROR,
320                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
321                            errmsg("invalid extension version name: \"%s\"", versionname),
322                                  errdetail("Version names must not contain directory separator characters.")));
323 }
324
325 /*
326  * Utility functions to handle extension-related path names
327  */
328 static bool
329 is_extension_control_filename(const char *filename)
330 {
331         const char *extension = strrchr(filename, '.');
332
333         return (extension != NULL) && (strcmp(extension, ".control") == 0);
334 }
335
336 static bool
337 is_extension_script_filename(const char *filename)
338 {
339         const char *extension = strrchr(filename, '.');
340
341         return (extension != NULL) && (strcmp(extension, ".sql") == 0);
342 }
343
344 static char *
345 get_extension_control_directory(void)
346 {
347         char            sharepath[MAXPGPATH];
348         char       *result;
349
350         get_share_path(my_exec_path, sharepath);
351         result = (char *) palloc(MAXPGPATH);
352         snprintf(result, MAXPGPATH, "%s/extension", sharepath);
353
354         return result;
355 }
356
357 static char *
358 get_extension_control_filename(const char *extname)
359 {
360         char            sharepath[MAXPGPATH];
361         char       *result;
362
363         get_share_path(my_exec_path, sharepath);
364         result = (char *) palloc(MAXPGPATH);
365         snprintf(result, MAXPGPATH, "%s/extension/%s.control",
366                          sharepath, extname);
367
368         return result;
369 }
370
371 static char *
372 get_extension_script_directory(ExtensionControlFile *control)
373 {
374         char            sharepath[MAXPGPATH];
375         char       *result;
376
377         /*
378          * The directory parameter can be omitted, absolute, or relative to the
379          * installation's share directory.
380          */
381         if (!control->directory)
382                 return get_extension_control_directory();
383
384         if (is_absolute_path(control->directory))
385                 return pstrdup(control->directory);
386
387         get_share_path(my_exec_path, sharepath);
388         result = (char *) palloc(MAXPGPATH);
389         snprintf(result, MAXPGPATH, "%s/%s", sharepath, control->directory);
390
391         return result;
392 }
393
394 static char *
395 get_extension_aux_control_filename(ExtensionControlFile *control,
396                                                                    const char *version)
397 {
398         char       *result;
399         char       *scriptdir;
400
401         scriptdir = get_extension_script_directory(control);
402
403         result = (char *) palloc(MAXPGPATH);
404         snprintf(result, MAXPGPATH, "%s/%s--%s.control",
405                          scriptdir, control->name, version);
406
407         pfree(scriptdir);
408
409         return result;
410 }
411
412 static char *
413 get_extension_script_filename(ExtensionControlFile *control,
414                                                           const char *from_version, const char *version)
415 {
416         char       *result;
417         char       *scriptdir;
418
419         scriptdir = get_extension_script_directory(control);
420
421         result = (char *) palloc(MAXPGPATH);
422         if (from_version)
423                 snprintf(result, MAXPGPATH, "%s/%s--%s--%s.sql",
424                                  scriptdir, control->name, from_version, version);
425         else
426                 snprintf(result, MAXPGPATH, "%s/%s--%s.sql",
427                                  scriptdir, control->name, version);
428
429         pfree(scriptdir);
430
431         return result;
432 }
433
434
435 /*
436  * Parse contents of primary or auxiliary control file, and fill in
437  * fields of *control.  We parse primary file if version == NULL,
438  * else the optional auxiliary file for that version.
439  *
440  * Control files are supposed to be very short, half a dozen lines,
441  * so we don't worry about memory allocation risks here.  Also we don't
442  * worry about what encoding it's in; all values are expected to be ASCII.
443  */
444 static void
445 parse_extension_control_file(ExtensionControlFile *control,
446                                                          const char *version)
447 {
448         char       *filename;
449         FILE       *file;
450         ConfigVariable *item,
451                            *head = NULL,
452                            *tail = NULL;
453
454         /*
455          * Locate the file to read.  Auxiliary files are optional.
456          */
457         if (version)
458                 filename = get_extension_aux_control_filename(control, version);
459         else
460                 filename = get_extension_control_filename(control->name);
461
462         if ((file = AllocateFile(filename, "r")) == NULL)
463         {
464                 if (version && errno == ENOENT)
465                 {
466                         /* no auxiliary file for this version */
467                         pfree(filename);
468                         return;
469                 }
470                 ereport(ERROR,
471                                 (errcode_for_file_access(),
472                                  errmsg("could not open extension control file \"%s\": %m",
473                                                 filename)));
474         }
475
476         /*
477          * Parse the file content, using GUC's file parsing code
478          */
479         ParseConfigFp(file, filename, 0, ERROR, &head, &tail);
480
481         FreeFile(file);
482
483         /*
484          * Convert the ConfigVariable list into ExtensionControlFile entries.
485          */
486         for (item = head; item != NULL; item = item->next)
487         {
488                 if (strcmp(item->name, "directory") == 0)
489                 {
490                         if (version)
491                                 ereport(ERROR,
492                                                 (errcode(ERRCODE_SYNTAX_ERROR),
493                                                  errmsg("parameter \"%s\" cannot be set in a secondary extension control file",
494                                                                 item->name)));
495
496                         control->directory = pstrdup(item->value);
497                 }
498                 else if (strcmp(item->name, "default_version") == 0)
499                 {
500                         if (version)
501                                 ereport(ERROR,
502                                                 (errcode(ERRCODE_SYNTAX_ERROR),
503                                                  errmsg("parameter \"%s\" cannot be set in a secondary extension control file",
504                                                                 item->name)));
505
506                         control->default_version = pstrdup(item->value);
507                 }
508                 else if (strcmp(item->name, "module_pathname") == 0)
509                 {
510                         control->module_pathname = pstrdup(item->value);
511                 }
512                 else if (strcmp(item->name, "comment") == 0)
513                 {
514                         control->comment = pstrdup(item->value);
515                 }
516                 else if (strcmp(item->name, "schema") == 0)
517                 {
518                         control->schema = pstrdup(item->value);
519                 }
520                 else if (strcmp(item->name, "relocatable") == 0)
521                 {
522                         if (!parse_bool(item->value, &control->relocatable))
523                                 ereport(ERROR,
524                                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
525                                                  errmsg("parameter \"%s\" requires a Boolean value",
526                                                                 item->name)));
527                 }
528                 else if (strcmp(item->name, "superuser") == 0)
529                 {
530                         if (!parse_bool(item->value, &control->superuser))
531                                 ereport(ERROR,
532                                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
533                                                  errmsg("parameter \"%s\" requires a Boolean value",
534                                                                 item->name)));
535                 }
536                 else if (strcmp(item->name, "encoding") == 0)
537                 {
538                         control->encoding = pg_valid_server_encoding(item->value);
539                         if (control->encoding < 0)
540                                 ereport(ERROR,
541                                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
542                                                  errmsg("\"%s\" is not a valid encoding name",
543                                                                 item->value)));
544                 }
545                 else if (strcmp(item->name, "requires") == 0)
546                 {
547                         /* Need a modifiable copy of string */
548                         char       *rawnames = pstrdup(item->value);
549
550                         /* Parse string into list of identifiers */
551                         if (!SplitIdentifierString(rawnames, ',', &control->requires))
552                         {
553                                 /* syntax error in name list */
554                                 ereport(ERROR,
555                                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
556                                  errmsg("parameter \"%s\" must be a list of extension names",
557                                                 item->name)));
558                         }
559                 }
560                 else
561                         ereport(ERROR,
562                                         (errcode(ERRCODE_SYNTAX_ERROR),
563                                          errmsg("unrecognized parameter \"%s\" in file \"%s\"",
564                                                         item->name, filename)));
565         }
566
567         FreeConfigVariables(head);
568
569         if (control->relocatable && control->schema != NULL)
570                 ereport(ERROR,
571                                 (errcode(ERRCODE_SYNTAX_ERROR),
572                                  errmsg("parameter \"schema\" cannot be specified when \"relocatable\" is true")));
573
574         pfree(filename);
575 }
576
577 /*
578  * Read the primary control file for the specified extension.
579  */
580 static ExtensionControlFile *
581 read_extension_control_file(const char *extname)
582 {
583         ExtensionControlFile *control;
584
585         /*
586          * Set up default values.  Pointer fields are initially null.
587          */
588         control = (ExtensionControlFile *) palloc0(sizeof(ExtensionControlFile));
589         control->name = pstrdup(extname);
590         control->relocatable = false;
591         control->superuser = true;
592         control->encoding = -1;
593
594         /*
595          * Parse the primary control file.
596          */
597         parse_extension_control_file(control, NULL);
598
599         return control;
600 }
601
602 /*
603  * Read the auxiliary control file for the specified extension and version.
604  *
605  * Returns a new modified ExtensionControlFile struct; the original struct
606  * (reflecting just the primary control file) is not modified.
607  */
608 static ExtensionControlFile *
609 read_extension_aux_control_file(const ExtensionControlFile *pcontrol,
610                                                                 const char *version)
611 {
612         ExtensionControlFile *acontrol;
613
614         /*
615          * Flat-copy the struct.  Pointer fields share values with original.
616          */
617         acontrol = (ExtensionControlFile *) palloc(sizeof(ExtensionControlFile));
618         memcpy(acontrol, pcontrol, sizeof(ExtensionControlFile));
619
620         /*
621          * Parse the auxiliary control file, overwriting struct fields
622          */
623         parse_extension_control_file(acontrol, version);
624
625         return acontrol;
626 }
627
628 /*
629  * Read an SQL script file into a string, and convert to database encoding
630  */
631 static char *
632 read_extension_script_file(const ExtensionControlFile *control,
633                                                    const char *filename)
634 {
635         int                     src_encoding;
636         int                     dest_encoding = GetDatabaseEncoding();
637         bytea      *content;
638         char       *src_str;
639         char       *dest_str;
640         int                     len;
641
642         content = read_binary_file(filename, 0, -1);
643
644         /* use database encoding if not given */
645         if (control->encoding < 0)
646                 src_encoding = dest_encoding;
647         else
648                 src_encoding = control->encoding;
649
650         /* make sure that source string is valid in the expected encoding */
651         len = VARSIZE_ANY_EXHDR(content);
652         src_str = VARDATA_ANY(content);
653         pg_verify_mbstr_len(src_encoding, src_str, len, false);
654
655         /* convert the encoding to the database encoding */
656         dest_str = (char *) pg_do_encoding_conversion((unsigned char *) src_str,
657                                                                                                   len,
658                                                                                                   src_encoding,
659                                                                                                   dest_encoding);
660
661         /* if no conversion happened, we have to arrange for null termination */
662         if (dest_str == src_str)
663         {
664                 dest_str = (char *) palloc(len + 1);
665                 memcpy(dest_str, src_str, len);
666                 dest_str[len] = '\0';
667         }
668
669         return dest_str;
670 }
671
672 /*
673  * Execute given SQL string.
674  *
675  * filename is used only to report errors.
676  *
677  * Note: it's tempting to just use SPI to execute the string, but that does
678  * not work very well.  The really serious problem is that SPI will parse,
679  * analyze, and plan the whole string before executing any of it; of course
680  * this fails if there are any plannable statements referring to objects
681  * created earlier in the script.  A lesser annoyance is that SPI insists
682  * on printing the whole string as errcontext in case of any error, and that
683  * could be very long.
684  */
685 static void
686 execute_sql_string(const char *sql, const char *filename)
687 {
688         List       *raw_parsetree_list;
689         DestReceiver *dest;
690         ListCell   *lc1;
691
692         /*
693          * Parse the SQL string into a list of raw parse trees.
694          */
695         raw_parsetree_list = pg_parse_query(sql);
696
697         /* All output from SELECTs goes to the bit bucket */
698         dest = CreateDestReceiver(DestNone);
699
700         /*
701          * Do parse analysis, rule rewrite, planning, and execution for each raw
702          * parsetree.  We must fully execute each query before beginning parse
703          * analysis on the next one, since there may be interdependencies.
704          */
705         foreach(lc1, raw_parsetree_list)
706         {
707                 Node       *parsetree = (Node *) lfirst(lc1);
708                 List       *stmt_list;
709                 ListCell   *lc2;
710
711                 stmt_list = pg_analyze_and_rewrite(parsetree,
712                                                                                    sql,
713                                                                                    NULL,
714                                                                                    0);
715                 stmt_list = pg_plan_queries(stmt_list, 0, NULL);
716
717                 foreach(lc2, stmt_list)
718                 {
719                         Node       *stmt = (Node *) lfirst(lc2);
720
721                         if (IsA(stmt, TransactionStmt))
722                                 ereport(ERROR,
723                                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
724                                                  errmsg("transaction control statements are not allowed within an extension script")));
725
726                         CommandCounterIncrement();
727
728                         PushActiveSnapshot(GetTransactionSnapshot());
729
730                         if (IsA(stmt, PlannedStmt) &&
731                                 ((PlannedStmt *) stmt)->utilityStmt == NULL)
732                         {
733                                 QueryDesc  *qdesc;
734
735                                 qdesc = CreateQueryDesc((PlannedStmt *) stmt,
736                                                                                 sql,
737                                                                                 GetActiveSnapshot(), NULL,
738                                                                                 dest, NULL, 0);
739
740                                 ExecutorStart(qdesc, 0);
741                                 ExecutorRun(qdesc, ForwardScanDirection, 0);
742                                 ExecutorFinish(qdesc);
743                                 ExecutorEnd(qdesc);
744
745                                 FreeQueryDesc(qdesc);
746                         }
747                         else
748                         {
749                                 ProcessUtility(stmt,
750                                                            sql,
751                                                            NULL,
752                                                            false,       /* not top level */
753                                                            dest,
754                                                            NULL);
755                         }
756
757                         PopActiveSnapshot();
758                 }
759         }
760
761         /* Be sure to advance the command counter after the last script command */
762         CommandCounterIncrement();
763 }
764
765 /*
766  * Execute the appropriate script file for installing or updating the extension
767  *
768  * If from_version isn't NULL, it's an update
769  */
770 static void
771 execute_extension_script(Oid extensionOid, ExtensionControlFile *control,
772                                                  const char *from_version,
773                                                  const char *version,
774                                                  List *requiredSchemas,
775                                                  const char *schemaName, Oid schemaOid)
776 {
777         char       *filename;
778         char       *save_client_min_messages,
779                            *save_log_min_messages,
780                            *save_search_path;
781         StringInfoData pathbuf;
782         ListCell   *lc;
783
784         /*
785          * Enforce superuser-ness if appropriate.  We postpone this check until
786          * here so that the flag is correctly associated with the right script(s)
787          * if it's set in secondary control files.
788          */
789         if (control->superuser && !superuser())
790         {
791                 if (from_version == NULL)
792                         ereport(ERROR,
793                                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
794                                          errmsg("permission denied to create extension \"%s\"",
795                                                         control->name),
796                                          errhint("Must be superuser to create this extension.")));
797                 else
798                         ereport(ERROR,
799                                         (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
800                                          errmsg("permission denied to update extension \"%s\"",
801                                                         control->name),
802                                          errhint("Must be superuser to update this extension.")));
803         }
804
805         filename = get_extension_script_filename(control, from_version, version);
806
807         /*
808          * Force client_min_messages and log_min_messages to be at least WARNING,
809          * so that we won't spam the user with useless NOTICE messages from common
810          * script actions like creating shell types.
811          *
812          * We use the equivalent of SET LOCAL to ensure the setting is undone upon
813          * error.
814          */
815         save_client_min_messages =
816                 pstrdup(GetConfigOption("client_min_messages", false));
817         if (client_min_messages < WARNING)
818                 (void) set_config_option("client_min_messages", "warning",
819                                                                  PGC_USERSET, PGC_S_SESSION,
820                                                                  GUC_ACTION_LOCAL, true);
821
822         save_log_min_messages =
823                 pstrdup(GetConfigOption("log_min_messages", false));
824         if (log_min_messages < WARNING)
825                 (void) set_config_option("log_min_messages", "warning",
826                                                                  PGC_SUSET, PGC_S_SESSION,
827                                                                  GUC_ACTION_LOCAL, true);
828
829         /*
830          * Set up the search path to contain the target schema, then the schemas
831          * of any prerequisite extensions, and nothing else.  In particular this
832          * makes the target schema be the default creation target namespace.
833          *
834          * Note: it might look tempting to use PushOverrideSearchPath for this,
835          * but we cannot do that.  We have to actually set the search_path GUC in
836          * case the extension script examines or changes it.
837          */
838         save_search_path = pstrdup(GetConfigOption("search_path", false));
839
840         initStringInfo(&pathbuf);
841         appendStringInfoString(&pathbuf, quote_identifier(schemaName));
842         foreach(lc, requiredSchemas)
843         {
844                 Oid                     reqschema = lfirst_oid(lc);
845                 char       *reqname = get_namespace_name(reqschema);
846
847                 if (reqname)
848                         appendStringInfo(&pathbuf, ", %s", quote_identifier(reqname));
849         }
850
851         (void) set_config_option("search_path", pathbuf.data,
852                                                          PGC_USERSET, PGC_S_SESSION,
853                                                          GUC_ACTION_LOCAL, true);
854
855         /*
856          * Set creating_extension and related variables so that
857          * recordDependencyOnCurrentExtension and other functions do the right
858          * things.      On failure, ensure we reset these variables.
859          */
860         creating_extension = true;
861         CurrentExtensionObject = extensionOid;
862         PG_TRY();
863         {
864                 char       *sql = read_extension_script_file(control, filename);
865
866                 /*
867                  * If it's not relocatable, substitute the target schema name for
868                  * occcurrences of @extschema@.
869                  *
870                  * For a relocatable extension, we just run the script as-is. There
871                  * cannot be any need for @extschema@, else it wouldn't be
872                  * relocatable.
873                  */
874                 if (!control->relocatable)
875                 {
876                         const char *qSchemaName = quote_identifier(schemaName);
877
878                         sql = text_to_cstring(
879                                                                   DatumGetTextPP(
880                                                                                         DirectFunctionCall3(replace_text,
881                                                                                                         CStringGetTextDatum(sql),
882                                                                                   CStringGetTextDatum("@extschema@"),
883                                                                                  CStringGetTextDatum(qSchemaName))));
884                 }
885
886                 /*
887                  * If module_pathname was set in the control file, substitute its
888                  * value for occurrences of MODULE_PATHNAME.
889                  */
890                 if (control->module_pathname)
891                 {
892                         sql = text_to_cstring(
893                                                                   DatumGetTextPP(
894                                                                                         DirectFunctionCall3(replace_text,
895                                                                                                         CStringGetTextDatum(sql),
896                                                                           CStringGetTextDatum("MODULE_PATHNAME"),
897                                                         CStringGetTextDatum(control->module_pathname))));
898                 }
899
900                 execute_sql_string(sql, filename);
901         }
902         PG_CATCH();
903         {
904                 creating_extension = false;
905                 CurrentExtensionObject = InvalidOid;
906                 PG_RE_THROW();
907         }
908         PG_END_TRY();
909
910         creating_extension = false;
911         CurrentExtensionObject = InvalidOid;
912
913         /*
914          * Restore GUC variables for the remainder of the current transaction.
915          * Again use SET LOCAL, so we won't affect the session value.
916          */
917         (void) set_config_option("search_path", save_search_path,
918                                                          PGC_USERSET, PGC_S_SESSION,
919                                                          GUC_ACTION_LOCAL, true);
920         (void) set_config_option("client_min_messages", save_client_min_messages,
921                                                          PGC_USERSET, PGC_S_SESSION,
922                                                          GUC_ACTION_LOCAL, true);
923         (void) set_config_option("log_min_messages", save_log_min_messages,
924                                                          PGC_SUSET, PGC_S_SESSION,
925                                                          GUC_ACTION_LOCAL, true);
926 }
927
928 /*
929  * Find or create an ExtensionVersionInfo for the specified version name
930  *
931  * Currently, we just use a List of the ExtensionVersionInfo's.  Searching
932  * for them therefore uses about O(N^2) time when there are N versions of
933  * the extension.  We could change the data structure to a hash table if
934  * this ever becomes a bottleneck.
935  */
936 static ExtensionVersionInfo *
937 get_ext_ver_info(const char *versionname, List **evi_list)
938 {
939         ExtensionVersionInfo *evi;
940         ListCell   *lc;
941
942         foreach(lc, *evi_list)
943         {
944                 evi = (ExtensionVersionInfo *) lfirst(lc);
945                 if (strcmp(evi->name, versionname) == 0)
946                         return evi;
947         }
948
949         evi = (ExtensionVersionInfo *) palloc(sizeof(ExtensionVersionInfo));
950         evi->name = pstrdup(versionname);
951         evi->reachable = NIL;
952         evi->installable = false;
953         /* initialize for later application of Dijkstra's algorithm */
954         evi->distance_known = false;
955         evi->distance = INT_MAX;
956         evi->previous = NULL;
957
958         *evi_list = lappend(*evi_list, evi);
959
960         return evi;
961 }
962
963 /*
964  * Locate the nearest unprocessed ExtensionVersionInfo
965  *
966  * This part of the algorithm is also about O(N^2).  A priority queue would
967  * make it much faster, but for now there's no need.
968  */
969 static ExtensionVersionInfo *
970 get_nearest_unprocessed_vertex(List *evi_list)
971 {
972         ExtensionVersionInfo *evi = NULL;
973         ListCell   *lc;
974
975         foreach(lc, evi_list)
976         {
977                 ExtensionVersionInfo *evi2 = (ExtensionVersionInfo *) lfirst(lc);
978
979                 /* only vertices whose distance is still uncertain are candidates */
980                 if (evi2->distance_known)
981                         continue;
982                 /* remember the closest such vertex */
983                 if (evi == NULL ||
984                         evi->distance > evi2->distance)
985                         evi = evi2;
986         }
987
988         return evi;
989 }
990
991 /*
992  * Obtain information about the set of update scripts available for the
993  * specified extension.  The result is a List of ExtensionVersionInfo
994  * structs, each with a subsidiary list of the ExtensionVersionInfos for
995  * the versions that can be reached in one step from that version.
996  */
997 static List *
998 get_ext_ver_list(ExtensionControlFile *control)
999 {
1000         List       *evi_list = NIL;
1001         int                     extnamelen = strlen(control->name);
1002         char       *location;
1003         DIR                *dir;
1004         struct dirent *de;
1005
1006         location = get_extension_script_directory(control);
1007         dir = AllocateDir(location);
1008         while ((de = ReadDir(dir, location)) != NULL)
1009         {
1010                 char       *vername;
1011                 char       *vername2;
1012                 ExtensionVersionInfo *evi;
1013                 ExtensionVersionInfo *evi2;
1014
1015                 /* must be a .sql file ... */
1016                 if (!is_extension_script_filename(de->d_name))
1017                         continue;
1018
1019                 /* ... matching extension name followed by separator */
1020                 if (strncmp(de->d_name, control->name, extnamelen) != 0 ||
1021                         de->d_name[extnamelen] != '-' ||
1022                         de->d_name[extnamelen + 1] != '-')
1023                         continue;
1024
1025                 /* extract version name(s) from 'extname--something.sql' filename */
1026                 vername = pstrdup(de->d_name + extnamelen + 2);
1027                 *strrchr(vername, '.') = '\0';
1028                 vername2 = strstr(vername, "--");
1029                 if (!vername2)
1030                 {
1031                         /* It's an install, not update, script; record its version name */
1032                         evi = get_ext_ver_info(vername, &evi_list);
1033                         evi->installable = true;
1034                         continue;
1035                 }
1036                 *vername2 = '\0';               /* terminate first version */
1037                 vername2 += 2;                  /* and point to second */
1038
1039                 /* if there's a third --, it's bogus, ignore it */
1040                 if (strstr(vername2, "--"))
1041                         continue;
1042
1043                 /* Create ExtensionVersionInfos and link them together */
1044                 evi = get_ext_ver_info(vername, &evi_list);
1045                 evi2 = get_ext_ver_info(vername2, &evi_list);
1046                 evi->reachable = lappend(evi->reachable, evi2);
1047         }
1048         FreeDir(dir);
1049
1050         return evi_list;
1051 }
1052
1053 /*
1054  * Given an initial and final version name, identify the sequence of update
1055  * scripts that have to be applied to perform that update.
1056  *
1057  * Result is a List of names of versions to transition through (the initial
1058  * version is *not* included).
1059  */
1060 static List *
1061 identify_update_path(ExtensionControlFile *control,
1062                                          const char *oldVersion, const char *newVersion)
1063 {
1064         List       *result;
1065         List       *evi_list;
1066         ExtensionVersionInfo *evi_start;
1067         ExtensionVersionInfo *evi_target;
1068
1069         /* Extract the version update graph from the script directory */
1070         evi_list = get_ext_ver_list(control);
1071
1072         /* Initialize start and end vertices */
1073         evi_start = get_ext_ver_info(oldVersion, &evi_list);
1074         evi_target = get_ext_ver_info(newVersion, &evi_list);
1075
1076         /* Find shortest path */
1077         result = find_update_path(evi_list, evi_start, evi_target, false);
1078
1079         if (result == NIL)
1080                 ereport(ERROR,
1081                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1082                                  errmsg("extension \"%s\" has no update path from version \"%s\" to version \"%s\"",
1083                                                 control->name, oldVersion, newVersion)));
1084
1085         return result;
1086 }
1087
1088 /*
1089  * Apply Dijkstra's algorithm to find the shortest path from evi_start to
1090  * evi_target.
1091  *
1092  * If reinitialize is false, assume the ExtensionVersionInfo list has not
1093  * been used for this before, and the initialization done by get_ext_ver_info
1094  * is still good.
1095  *
1096  * Result is a List of names of versions to transition through (the initial
1097  * version is *not* included).  Returns NIL if no such path.
1098  */
1099 static List *
1100 find_update_path(List *evi_list,
1101                                  ExtensionVersionInfo *evi_start,
1102                                  ExtensionVersionInfo *evi_target,
1103                                  bool reinitialize)
1104 {
1105         List       *result;
1106         ExtensionVersionInfo *evi;
1107         ListCell   *lc;
1108
1109         /* Caller error if start == target */
1110         Assert(evi_start != evi_target);
1111
1112         if (reinitialize)
1113         {
1114                 foreach(lc, evi_list)
1115                 {
1116                         evi = (ExtensionVersionInfo *) lfirst(lc);
1117                         evi->distance_known = false;
1118                         evi->distance = INT_MAX;
1119                         evi->previous = NULL;
1120                 }
1121         }
1122
1123         evi_start->distance = 0;
1124
1125         while ((evi = get_nearest_unprocessed_vertex(evi_list)) != NULL)
1126         {
1127                 if (evi->distance == INT_MAX)
1128                         break;                          /* all remaining vertices are unreachable */
1129                 evi->distance_known = true;
1130                 if (evi == evi_target)
1131                         break;                          /* found shortest path to target */
1132                 foreach(lc, evi->reachable)
1133                 {
1134                         ExtensionVersionInfo *evi2 = (ExtensionVersionInfo *) lfirst(lc);
1135                         int                     newdist;
1136
1137                         newdist = evi->distance + 1;
1138                         if (newdist < evi2->distance)
1139                         {
1140                                 evi2->distance = newdist;
1141                                 evi2->previous = evi;
1142                         }
1143                         else if (newdist == evi2->distance &&
1144                                          evi2->previous != NULL &&
1145                                          strcmp(evi->name, evi2->previous->name) < 0)
1146                         {
1147                                 /*
1148                                  * Break ties in favor of the version name that comes first
1149                                  * according to strcmp().  This behavior is undocumented and
1150                                  * users shouldn't rely on it.  We do it just to ensure that
1151                                  * if there is a tie, the update path that is chosen does not
1152                                  * depend on random factors like the order in which directory
1153                                  * entries get visited.
1154                                  */
1155                                 evi2->previous = evi;
1156                         }
1157                 }
1158         }
1159
1160         /* Return NIL if target is not reachable from start */
1161         if (!evi_target->distance_known)
1162                 return NIL;
1163
1164         /* Build and return list of version names representing the update path */
1165         result = NIL;
1166         for (evi = evi_target; evi != evi_start; evi = evi->previous)
1167                 result = lcons(evi->name, result);
1168
1169         return result;
1170 }
1171
1172 /*
1173  * CREATE EXTENSION
1174  */
1175 void
1176 CreateExtension(CreateExtensionStmt *stmt)
1177 {
1178         DefElem    *d_schema = NULL;
1179         DefElem    *d_new_version = NULL;
1180         DefElem    *d_old_version = NULL;
1181         char       *schemaName;
1182         Oid                     schemaOid;
1183         char       *versionName;
1184         char       *oldVersionName;
1185         Oid                     extowner = GetUserId();
1186         ExtensionControlFile *pcontrol;
1187         ExtensionControlFile *control;
1188         List       *updateVersions;
1189         List       *requiredExtensions;
1190         List       *requiredSchemas;
1191         Oid                     extensionOid;
1192         ListCell   *lc;
1193
1194         /* Check extension name validity before any filesystem access */
1195         check_valid_extension_name(stmt->extname);
1196
1197         /*
1198          * Check for duplicate extension name.  The unique index on
1199          * pg_extension.extname would catch this anyway, and serves as a backstop
1200          * in case of race conditions; but this is a friendlier error message, and
1201          * besides we need a check to support IF NOT EXISTS.
1202          */
1203         if (get_extension_oid(stmt->extname, true) != InvalidOid)
1204         {
1205                 if (stmt->if_not_exists)
1206                 {
1207                         ereport(NOTICE,
1208                                         (errcode(ERRCODE_DUPLICATE_OBJECT),
1209                                          errmsg("extension \"%s\" already exists, skipping",
1210                                                         stmt->extname)));
1211                         return;
1212                 }
1213                 else
1214                         ereport(ERROR,
1215                                         (errcode(ERRCODE_DUPLICATE_OBJECT),
1216                                          errmsg("extension \"%s\" already exists",
1217                                                         stmt->extname)));
1218         }
1219
1220         /*
1221          * We use global variables to track the extension being created, so we can
1222          * create only one extension at the same time.
1223          */
1224         if (creating_extension)
1225                 ereport(ERROR,
1226                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1227                                  errmsg("nested CREATE EXTENSION is not supported")));
1228
1229         /*
1230          * Read the primary control file.  Note we assume that it does not contain
1231          * any non-ASCII data, so there is no need to worry about encoding at this
1232          * point.
1233          */
1234         pcontrol = read_extension_control_file(stmt->extname);
1235
1236         /*
1237          * Read the statement option list
1238          */
1239         foreach(lc, stmt->options)
1240         {
1241                 DefElem    *defel = (DefElem *) lfirst(lc);
1242
1243                 if (strcmp(defel->defname, "schema") == 0)
1244                 {
1245                         if (d_schema)
1246                                 ereport(ERROR,
1247                                                 (errcode(ERRCODE_SYNTAX_ERROR),
1248                                                  errmsg("conflicting or redundant options")));
1249                         d_schema = defel;
1250                 }
1251                 else if (strcmp(defel->defname, "new_version") == 0)
1252                 {
1253                         if (d_new_version)
1254                                 ereport(ERROR,
1255                                                 (errcode(ERRCODE_SYNTAX_ERROR),
1256                                                  errmsg("conflicting or redundant options")));
1257                         d_new_version = defel;
1258                 }
1259                 else if (strcmp(defel->defname, "old_version") == 0)
1260                 {
1261                         if (d_old_version)
1262                                 ereport(ERROR,
1263                                                 (errcode(ERRCODE_SYNTAX_ERROR),
1264                                                  errmsg("conflicting or redundant options")));
1265                         d_old_version = defel;
1266                 }
1267                 else
1268                         elog(ERROR, "unrecognized option: %s", defel->defname);
1269         }
1270
1271         /*
1272          * Determine the version to install
1273          */
1274         if (d_new_version && d_new_version->arg)
1275                 versionName = strVal(d_new_version->arg);
1276         else if (pcontrol->default_version)
1277                 versionName = pcontrol->default_version;
1278         else
1279         {
1280                 ereport(ERROR,
1281                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1282                                  errmsg("version to install must be specified")));
1283                 versionName = NULL;             /* keep compiler quiet */
1284         }
1285         check_valid_version_name(versionName);
1286
1287         /*
1288          * Determine the (unpackaged) version to update from, if any, and then
1289          * figure out what sequence of update scripts we need to apply.
1290          */
1291         if (d_old_version && d_old_version->arg)
1292         {
1293                 oldVersionName = strVal(d_old_version->arg);
1294                 check_valid_version_name(oldVersionName);
1295
1296                 if (strcmp(oldVersionName, versionName) == 0)
1297                         ereport(ERROR,
1298                                         (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1299                                          errmsg("FROM version must be different from installation target version \"%s\"",
1300                                                         versionName)));
1301
1302                 updateVersions = identify_update_path(pcontrol,
1303                                                                                           oldVersionName,
1304                                                                                           versionName);
1305
1306                 if (list_length(updateVersions) == 1)
1307                 {
1308                         /*
1309                          * Simple case where there's just one update script to run. We
1310                          * will not need any follow-on update steps.
1311                          */
1312                         Assert(strcmp((char *) linitial(updateVersions), versionName) == 0);
1313                         updateVersions = NIL;
1314                 }
1315                 else
1316                 {
1317                         /*
1318                          * Multi-step sequence.  We treat this as installing the version
1319                          * that is the target of the first script, followed by successive
1320                          * updates to the later versions.
1321                          */
1322                         versionName = (char *) linitial(updateVersions);
1323                         updateVersions = list_delete_first(updateVersions);
1324                 }
1325         }
1326         else
1327         {
1328                 oldVersionName = NULL;
1329                 updateVersions = NIL;
1330         }
1331
1332         /*
1333          * Fetch control parameters for installation target version
1334          */
1335         control = read_extension_aux_control_file(pcontrol, versionName);
1336
1337         /*
1338          * Determine the target schema to install the extension into
1339          */
1340         if (d_schema && d_schema->arg)
1341         {
1342                 /*
1343                  * User given schema, CREATE EXTENSION ... WITH SCHEMA ...
1344                  *
1345                  * It's an error to give a schema different from control->schema if
1346                  * control->schema is specified.
1347                  */
1348                 schemaName = strVal(d_schema->arg);
1349
1350                 if (control->schema != NULL &&
1351                         strcmp(control->schema, schemaName) != 0)
1352                         ereport(ERROR,
1353                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1354                                 errmsg("extension \"%s\" must be installed in schema \"%s\"",
1355                                            control->name,
1356                                            control->schema)));
1357
1358                 /* If the user is giving us the schema name, it must exist already */
1359                 schemaOid = get_namespace_oid(schemaName, false);
1360         }
1361         else if (control->schema != NULL)
1362         {
1363                 /*
1364                  * The extension is not relocatable and the author gave us a schema
1365                  * for it.      We create the schema here if it does not already exist.
1366                  */
1367                 schemaName = control->schema;
1368                 schemaOid = get_namespace_oid(schemaName, true);
1369
1370                 if (schemaOid == InvalidOid)
1371                 {
1372                         schemaOid = NamespaceCreate(schemaName, extowner);
1373                         /* Advance cmd counter to make the namespace visible */
1374                         CommandCounterIncrement();
1375                 }
1376         }
1377         else
1378         {
1379                 /*
1380                  * Else, use the current default creation namespace, which is the
1381                  * first explicit entry in the search_path.
1382                  */
1383                 List       *search_path = fetch_search_path(false);
1384
1385                 if (search_path == NIL) /* probably can't happen */
1386                         elog(ERROR, "there is no default creation target");
1387                 schemaOid = linitial_oid(search_path);
1388                 schemaName = get_namespace_name(schemaOid);
1389                 if (schemaName == NULL) /* recently-deleted namespace? */
1390                         elog(ERROR, "there is no default creation target");
1391
1392                 list_free(search_path);
1393         }
1394
1395         /*
1396          * We don't check creation rights on the target namespace here.  If the
1397          * extension script actually creates any objects there, it will fail if
1398          * the user doesn't have such permissions.  But there are cases such as
1399          * procedural languages where it's convenient to set schema = pg_catalog
1400          * yet we don't want to restrict the command to users with ACL_CREATE for
1401          * pg_catalog.
1402          */
1403
1404         /*
1405          * Look up the prerequisite extensions, and build lists of their OIDs and
1406          * the OIDs of their target schemas.
1407          */
1408         requiredExtensions = NIL;
1409         requiredSchemas = NIL;
1410         foreach(lc, control->requires)
1411         {
1412                 char       *curreq = (char *) lfirst(lc);
1413                 Oid                     reqext;
1414                 Oid                     reqschema;
1415
1416                 /*
1417                  * We intentionally don't use get_extension_oid's default error
1418                  * message here, because it would be confusing in this context.
1419                  */
1420                 reqext = get_extension_oid(curreq, true);
1421                 if (!OidIsValid(reqext))
1422                         ereport(ERROR,
1423                                         (errcode(ERRCODE_UNDEFINED_OBJECT),
1424                                          errmsg("required extension \"%s\" is not installed",
1425                                                         curreq)));
1426                 reqschema = get_extension_schema(reqext);
1427                 requiredExtensions = lappend_oid(requiredExtensions, reqext);
1428                 requiredSchemas = lappend_oid(requiredSchemas, reqschema);
1429         }
1430
1431         /*
1432          * Insert new tuple into pg_extension, and create dependency entries.
1433          */
1434         extensionOid = InsertExtensionTuple(control->name, extowner,
1435                                                                                 schemaOid, control->relocatable,
1436                                                                                 versionName,
1437                                                                                 PointerGetDatum(NULL),
1438                                                                                 PointerGetDatum(NULL),
1439                                                                                 requiredExtensions);
1440
1441         /*
1442          * Apply any control-file comment on extension
1443          */
1444         if (control->comment != NULL)
1445                 CreateComments(extensionOid, ExtensionRelationId, 0, control->comment);
1446
1447         /*
1448          * Execute the installation script file
1449          */
1450         execute_extension_script(extensionOid, control,
1451                                                          oldVersionName, versionName,
1452                                                          requiredSchemas,
1453                                                          schemaName, schemaOid);
1454
1455         /*
1456          * If additional update scripts have to be executed, apply the updates as
1457          * though a series of ALTER EXTENSION UPDATE commands were given
1458          */
1459         ApplyExtensionUpdates(extensionOid, pcontrol,
1460                                                   versionName, updateVersions);
1461 }
1462
1463 /*
1464  * InsertExtensionTuple
1465  *
1466  * Insert the new pg_extension row, and create extension's dependency entries.
1467  * Return the OID assigned to the new row.
1468  *
1469  * This is exported for the benefit of pg_upgrade, which has to create a
1470  * pg_extension entry (and the extension-level dependencies) without
1471  * actually running the extension's script.
1472  *
1473  * extConfig and extCondition should be arrays or PointerGetDatum(NULL).
1474  * We declare them as plain Datum to avoid needing array.h in extension.h.
1475  */
1476 Oid
1477 InsertExtensionTuple(const char *extName, Oid extOwner,
1478                                          Oid schemaOid, bool relocatable, const char *extVersion,
1479                                          Datum extConfig, Datum extCondition,
1480                                          List *requiredExtensions)
1481 {
1482         Oid                     extensionOid;
1483         Relation        rel;
1484         Datum           values[Natts_pg_extension];
1485         bool            nulls[Natts_pg_extension];
1486         HeapTuple       tuple;
1487         ObjectAddress myself;
1488         ObjectAddress nsp;
1489         ListCell   *lc;
1490
1491         /*
1492          * Build and insert the pg_extension tuple
1493          */
1494         rel = heap_open(ExtensionRelationId, RowExclusiveLock);
1495
1496         memset(values, 0, sizeof(values));
1497         memset(nulls, 0, sizeof(nulls));
1498
1499         values[Anum_pg_extension_extname - 1] =
1500                 DirectFunctionCall1(namein, CStringGetDatum(extName));
1501         values[Anum_pg_extension_extowner - 1] = ObjectIdGetDatum(extOwner);
1502         values[Anum_pg_extension_extnamespace - 1] = ObjectIdGetDatum(schemaOid);
1503         values[Anum_pg_extension_extrelocatable - 1] = BoolGetDatum(relocatable);
1504         values[Anum_pg_extension_extversion - 1] = CStringGetTextDatum(extVersion);
1505
1506         if (extConfig == PointerGetDatum(NULL))
1507                 nulls[Anum_pg_extension_extconfig - 1] = true;
1508         else
1509                 values[Anum_pg_extension_extconfig - 1] = extConfig;
1510
1511         if (extCondition == PointerGetDatum(NULL))
1512                 nulls[Anum_pg_extension_extcondition - 1] = true;
1513         else
1514                 values[Anum_pg_extension_extcondition - 1] = extCondition;
1515
1516         tuple = heap_form_tuple(rel->rd_att, values, nulls);
1517
1518         extensionOid = simple_heap_insert(rel, tuple);
1519         CatalogUpdateIndexes(rel, tuple);
1520
1521         heap_freetuple(tuple);
1522         heap_close(rel, RowExclusiveLock);
1523
1524         /*
1525          * Record dependencies on owner, schema, and prerequisite extensions
1526          */
1527         recordDependencyOnOwner(ExtensionRelationId, extensionOid, extOwner);
1528
1529         myself.classId = ExtensionRelationId;
1530         myself.objectId = extensionOid;
1531         myself.objectSubId = 0;
1532
1533         nsp.classId = NamespaceRelationId;
1534         nsp.objectId = schemaOid;
1535         nsp.objectSubId = 0;
1536
1537         recordDependencyOn(&myself, &nsp, DEPENDENCY_NORMAL);
1538
1539         foreach(lc, requiredExtensions)
1540         {
1541                 Oid                     reqext = lfirst_oid(lc);
1542                 ObjectAddress otherext;
1543
1544                 otherext.classId = ExtensionRelationId;
1545                 otherext.objectId = reqext;
1546                 otherext.objectSubId = 0;
1547
1548                 recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
1549         }
1550         /* Post creation hook for new extension */
1551         InvokeObjectAccessHook(OAT_POST_CREATE,
1552                                                    ExtensionRelationId, extensionOid, 0);
1553
1554         return extensionOid;
1555 }
1556
1557
1558 /*
1559  *      RemoveExtensions
1560  *              Implements DROP EXTENSION.
1561  */
1562 void
1563 RemoveExtensions(DropStmt *drop)
1564 {
1565         ObjectAddresses *objects;
1566         ListCell   *cell;
1567
1568         /*
1569          * First we identify all the extensions, then we delete them in a single
1570          * performMultipleDeletions() call.  This is to avoid unwanted DROP
1571          * RESTRICT errors if one of the extensions depends on another.
1572          */
1573         objects = new_object_addresses();
1574
1575         foreach(cell, drop->objects)
1576         {
1577                 List       *names = (List *) lfirst(cell);
1578                 char       *extensionName;
1579                 Oid                     extensionId;
1580                 ObjectAddress object;
1581
1582                 if (list_length(names) != 1)
1583                         ereport(ERROR,
1584                                         (errcode(ERRCODE_SYNTAX_ERROR),
1585                                          errmsg("extension name cannot be qualified")));
1586                 extensionName = strVal(linitial(names));
1587
1588                 extensionId = get_extension_oid(extensionName, drop->missing_ok);
1589
1590                 if (!OidIsValid(extensionId))
1591                 {
1592                         ereport(NOTICE,
1593                                         (errmsg("extension \"%s\" does not exist, skipping",
1594                                                         extensionName)));
1595                         continue;
1596                 }
1597
1598                 /* Permission check: must own extension */
1599                 if (!pg_extension_ownercheck(extensionId, GetUserId()))
1600                         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EXTENSION,
1601                                                    extensionName);
1602
1603                 object.classId = ExtensionRelationId;
1604                 object.objectId = extensionId;
1605                 object.objectSubId = 0;
1606
1607                 add_exact_object_address(&object, objects);
1608         }
1609
1610         /*
1611          * Do the deletions.  Objects contained in the extension(s) are removed by
1612          * means of their dependency links to the extensions.
1613          */
1614         performMultipleDeletions(objects, drop->behavior);
1615
1616         free_object_addresses(objects);
1617 }
1618
1619
1620 /*
1621  * Guts of extension deletion.
1622  *
1623  * All we need do here is remove the pg_extension tuple itself.  Everything
1624  * else is taken care of by the dependency infrastructure.
1625  */
1626 void
1627 RemoveExtensionById(Oid extId)
1628 {
1629         Relation        rel;
1630         SysScanDesc scandesc;
1631         HeapTuple       tuple;
1632         ScanKeyData entry[1];
1633
1634         rel = heap_open(ExtensionRelationId, RowExclusiveLock);
1635
1636         ScanKeyInit(&entry[0],
1637                                 ObjectIdAttributeNumber,
1638                                 BTEqualStrategyNumber, F_OIDEQ,
1639                                 ObjectIdGetDatum(extId));
1640         scandesc = systable_beginscan(rel, ExtensionOidIndexId, true,
1641                                                                   SnapshotNow, 1, entry);
1642
1643         tuple = systable_getnext(scandesc);
1644
1645         /* We assume that there can be at most one matching tuple */
1646         if (HeapTupleIsValid(tuple))
1647                 simple_heap_delete(rel, &tuple->t_self);
1648
1649         systable_endscan(scandesc);
1650
1651         heap_close(rel, RowExclusiveLock);
1652 }
1653
1654 /*
1655  * This function lists the available extensions (one row per primary control
1656  * file in the control directory).      We parse each control file and report the
1657  * interesting fields.
1658  *
1659  * The system view pg_available_extensions provides a user interface to this
1660  * SRF, adding information about whether the extensions are installed in the
1661  * current DB.
1662  */
1663 Datum
1664 pg_available_extensions(PG_FUNCTION_ARGS)
1665 {
1666         ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1667         TupleDesc       tupdesc;
1668         Tuplestorestate *tupstore;
1669         MemoryContext per_query_ctx;
1670         MemoryContext oldcontext;
1671         char       *location;
1672         DIR                *dir;
1673         struct dirent *de;
1674
1675         /* check to see if caller supports us returning a tuplestore */
1676         if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
1677                 ereport(ERROR,
1678                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1679                                  errmsg("set-valued function called in context that cannot accept a set")));
1680         if (!(rsinfo->allowedModes & SFRM_Materialize))
1681                 ereport(ERROR,
1682                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1683                                  errmsg("materialize mode required, but it is not " \
1684                                                 "allowed in this context")));
1685
1686         /* Build a tuple descriptor for our result type */
1687         if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
1688                 elog(ERROR, "return type must be a row type");
1689
1690         /* Build tuplestore to hold the result rows */
1691         per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
1692         oldcontext = MemoryContextSwitchTo(per_query_ctx);
1693
1694         tupstore = tuplestore_begin_heap(true, false, work_mem);
1695         rsinfo->returnMode = SFRM_Materialize;
1696         rsinfo->setResult = tupstore;
1697         rsinfo->setDesc = tupdesc;
1698
1699         MemoryContextSwitchTo(oldcontext);
1700
1701         location = get_extension_control_directory();
1702         dir = AllocateDir(location);
1703
1704         /*
1705          * If the control directory doesn't exist, we want to silently return an
1706          * empty set.  Any other error will be reported by ReadDir.
1707          */
1708         if (dir == NULL && errno == ENOENT)
1709         {
1710                 /* do nothing */
1711         }
1712         else
1713         {
1714                 while ((de = ReadDir(dir, location)) != NULL)
1715                 {
1716                         ExtensionControlFile *control;
1717                         char       *extname;
1718                         Datum           values[3];
1719                         bool            nulls[3];
1720
1721                         if (!is_extension_control_filename(de->d_name))
1722                                 continue;
1723
1724                         /* extract extension name from 'name.control' filename */
1725                         extname = pstrdup(de->d_name);
1726                         *strrchr(extname, '.') = '\0';
1727
1728                         /* ignore it if it's an auxiliary control file */
1729                         if (strstr(extname, "--"))
1730                                 continue;
1731
1732                         control = read_extension_control_file(extname);
1733
1734                         memset(values, 0, sizeof(values));
1735                         memset(nulls, 0, sizeof(nulls));
1736
1737                         /* name */
1738                         values[0] = DirectFunctionCall1(namein,
1739                                                                                         CStringGetDatum(control->name));
1740                         /* default_version */
1741                         if (control->default_version == NULL)
1742                                 nulls[1] = true;
1743                         else
1744                                 values[1] = CStringGetTextDatum(control->default_version);
1745                         /* comment */
1746                         if (control->comment == NULL)
1747                                 nulls[2] = true;
1748                         else
1749                                 values[2] = CStringGetTextDatum(control->comment);
1750
1751                         tuplestore_putvalues(tupstore, tupdesc, values, nulls);
1752                 }
1753
1754                 FreeDir(dir);
1755         }
1756
1757         /* clean up and return the tuplestore */
1758         tuplestore_donestoring(tupstore);
1759
1760         return (Datum) 0;
1761 }
1762
1763 /*
1764  * This function lists the available extension versions (one row per
1765  * extension installation script).      For each version, we parse the related
1766  * control file(s) and report the interesting fields.
1767  *
1768  * The system view pg_available_extension_versions provides a user interface
1769  * to this SRF, adding information about which versions are installed in the
1770  * current DB.
1771  */
1772 Datum
1773 pg_available_extension_versions(PG_FUNCTION_ARGS)
1774 {
1775         ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1776         TupleDesc       tupdesc;
1777         Tuplestorestate *tupstore;
1778         MemoryContext per_query_ctx;
1779         MemoryContext oldcontext;
1780         char       *location;
1781         DIR                *dir;
1782         struct dirent *de;
1783
1784         /* check to see if caller supports us returning a tuplestore */
1785         if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
1786                 ereport(ERROR,
1787                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1788                                  errmsg("set-valued function called in context that cannot accept a set")));
1789         if (!(rsinfo->allowedModes & SFRM_Materialize))
1790                 ereport(ERROR,
1791                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1792                                  errmsg("materialize mode required, but it is not " \
1793                                                 "allowed in this context")));
1794
1795         /* Build a tuple descriptor for our result type */
1796         if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
1797                 elog(ERROR, "return type must be a row type");
1798
1799         /* Build tuplestore to hold the result rows */
1800         per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
1801         oldcontext = MemoryContextSwitchTo(per_query_ctx);
1802
1803         tupstore = tuplestore_begin_heap(true, false, work_mem);
1804         rsinfo->returnMode = SFRM_Materialize;
1805         rsinfo->setResult = tupstore;
1806         rsinfo->setDesc = tupdesc;
1807
1808         MemoryContextSwitchTo(oldcontext);
1809
1810         location = get_extension_control_directory();
1811         dir = AllocateDir(location);
1812
1813         /*
1814          * If the control directory doesn't exist, we want to silently return an
1815          * empty set.  Any other error will be reported by ReadDir.
1816          */
1817         if (dir == NULL && errno == ENOENT)
1818         {
1819                 /* do nothing */
1820         }
1821         else
1822         {
1823                 while ((de = ReadDir(dir, location)) != NULL)
1824                 {
1825                         ExtensionControlFile *control;
1826                         char       *extname;
1827
1828                         if (!is_extension_control_filename(de->d_name))
1829                                 continue;
1830
1831                         /* extract extension name from 'name.control' filename */
1832                         extname = pstrdup(de->d_name);
1833                         *strrchr(extname, '.') = '\0';
1834
1835                         /* ignore it if it's an auxiliary control file */
1836                         if (strstr(extname, "--"))
1837                                 continue;
1838
1839                         /* read the control file */
1840                         control = read_extension_control_file(extname);
1841
1842                         /* scan extension's script directory for install scripts */
1843                         get_available_versions_for_extension(control, tupstore, tupdesc);
1844                 }
1845
1846                 FreeDir(dir);
1847         }
1848
1849         /* clean up and return the tuplestore */
1850         tuplestore_donestoring(tupstore);
1851
1852         return (Datum) 0;
1853 }
1854
1855 /*
1856  * Inner loop for pg_available_extension_versions:
1857  *              read versions of one extension, add rows to tupstore
1858  */
1859 static void
1860 get_available_versions_for_extension(ExtensionControlFile *pcontrol,
1861                                                                          Tuplestorestate *tupstore,
1862                                                                          TupleDesc tupdesc)
1863 {
1864         int                     extnamelen = strlen(pcontrol->name);
1865         char       *location;
1866         DIR                *dir;
1867         struct dirent *de;
1868
1869         location = get_extension_script_directory(pcontrol);
1870         dir = AllocateDir(location);
1871         /* Note this will fail if script directory doesn't exist */
1872         while ((de = ReadDir(dir, location)) != NULL)
1873         {
1874                 ExtensionControlFile *control;
1875                 char       *vername;
1876                 Datum           values[7];
1877                 bool            nulls[7];
1878
1879                 /* must be a .sql file ... */
1880                 if (!is_extension_script_filename(de->d_name))
1881                         continue;
1882
1883                 /* ... matching extension name followed by separator */
1884                 if (strncmp(de->d_name, pcontrol->name, extnamelen) != 0 ||
1885                         de->d_name[extnamelen] != '-' ||
1886                         de->d_name[extnamelen + 1] != '-')
1887                         continue;
1888
1889                 /* extract version name from 'extname--something.sql' filename */
1890                 vername = pstrdup(de->d_name + extnamelen + 2);
1891                 *strrchr(vername, '.') = '\0';
1892
1893                 /* ignore it if it's an update script */
1894                 if (strstr(vername, "--"))
1895                         continue;
1896
1897                 /*
1898                  * Fetch parameters for specific version (pcontrol is not changed)
1899                  */
1900                 control = read_extension_aux_control_file(pcontrol, vername);
1901
1902                 memset(values, 0, sizeof(values));
1903                 memset(nulls, 0, sizeof(nulls));
1904
1905                 /* name */
1906                 values[0] = DirectFunctionCall1(namein,
1907                                                                                 CStringGetDatum(control->name));
1908                 /* version */
1909                 values[1] = CStringGetTextDatum(vername);
1910                 /* superuser */
1911                 values[2] = BoolGetDatum(control->superuser);
1912                 /* relocatable */
1913                 values[3] = BoolGetDatum(control->relocatable);
1914                 /* schema */
1915                 if (control->schema == NULL)
1916                         nulls[4] = true;
1917                 else
1918                         values[4] = DirectFunctionCall1(namein,
1919                                                                                         CStringGetDatum(control->schema));
1920                 /* requires */
1921                 if (control->requires == NIL)
1922                         nulls[5] = true;
1923                 else
1924                 {
1925                         Datum      *datums;
1926                         int                     ndatums;
1927                         ArrayType  *a;
1928                         ListCell   *lc;
1929
1930                         ndatums = list_length(control->requires);
1931                         datums = (Datum *) palloc(ndatums * sizeof(Datum));
1932                         ndatums = 0;
1933                         foreach(lc, control->requires)
1934                         {
1935                                 char       *curreq = (char *) lfirst(lc);
1936
1937                                 datums[ndatums++] =
1938                                         DirectFunctionCall1(namein, CStringGetDatum(curreq));
1939                         }
1940                         a = construct_array(datums, ndatums,
1941                                                                 NAMEOID,
1942                                                                 NAMEDATALEN, false, 'c');
1943                         values[5] = PointerGetDatum(a);
1944                 }
1945                 /* comment */
1946                 if (control->comment == NULL)
1947                         nulls[6] = true;
1948                 else
1949                         values[6] = CStringGetTextDatum(control->comment);
1950
1951                 tuplestore_putvalues(tupstore, tupdesc, values, nulls);
1952         }
1953
1954         FreeDir(dir);
1955 }
1956
1957 /*
1958  * This function reports the version update paths that exist for the
1959  * specified extension.
1960  */
1961 Datum
1962 pg_extension_update_paths(PG_FUNCTION_ARGS)
1963 {
1964         Name            extname = PG_GETARG_NAME(0);
1965         ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1966         TupleDesc       tupdesc;
1967         Tuplestorestate *tupstore;
1968         MemoryContext per_query_ctx;
1969         MemoryContext oldcontext;
1970         List       *evi_list;
1971         ExtensionControlFile *control;
1972         ListCell   *lc1;
1973
1974         /* Check extension name validity before any filesystem access */
1975         check_valid_extension_name(NameStr(*extname));
1976
1977         /* check to see if caller supports us returning a tuplestore */
1978         if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
1979                 ereport(ERROR,
1980                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1981                                  errmsg("set-valued function called in context that cannot accept a set")));
1982         if (!(rsinfo->allowedModes & SFRM_Materialize))
1983                 ereport(ERROR,
1984                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1985                                  errmsg("materialize mode required, but it is not " \
1986                                                 "allowed in this context")));
1987
1988         /* Build a tuple descriptor for our result type */
1989         if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
1990                 elog(ERROR, "return type must be a row type");
1991
1992         /* Build tuplestore to hold the result rows */
1993         per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
1994         oldcontext = MemoryContextSwitchTo(per_query_ctx);
1995
1996         tupstore = tuplestore_begin_heap(true, false, work_mem);
1997         rsinfo->returnMode = SFRM_Materialize;
1998         rsinfo->setResult = tupstore;
1999         rsinfo->setDesc = tupdesc;
2000
2001         MemoryContextSwitchTo(oldcontext);
2002
2003         /* Read the extension's control file */
2004         control = read_extension_control_file(NameStr(*extname));
2005
2006         /* Extract the version update graph from the script directory */
2007         evi_list = get_ext_ver_list(control);
2008
2009         /* Iterate over all pairs of versions */
2010         foreach(lc1, evi_list)
2011         {
2012                 ExtensionVersionInfo *evi1 = (ExtensionVersionInfo *) lfirst(lc1);
2013                 ListCell   *lc2;
2014
2015                 foreach(lc2, evi_list)
2016                 {
2017                         ExtensionVersionInfo *evi2 = (ExtensionVersionInfo *) lfirst(lc2);
2018                         List       *path;
2019                         Datum           values[3];
2020                         bool            nulls[3];
2021
2022                         if (evi1 == evi2)
2023                                 continue;
2024
2025                         /* Find shortest path from evi1 to evi2 */
2026                         path = find_update_path(evi_list, evi1, evi2, true);
2027
2028                         /* Emit result row */
2029                         memset(values, 0, sizeof(values));
2030                         memset(nulls, 0, sizeof(nulls));
2031
2032                         /* source */
2033                         values[0] = CStringGetTextDatum(evi1->name);
2034                         /* target */
2035                         values[1] = CStringGetTextDatum(evi2->name);
2036                         /* path */
2037                         if (path == NIL)
2038                                 nulls[2] = true;
2039                         else
2040                         {
2041                                 StringInfoData pathbuf;
2042                                 ListCell   *lcv;
2043
2044                                 initStringInfo(&pathbuf);
2045                                 /* The path doesn't include start vertex, but show it */
2046                                 appendStringInfoString(&pathbuf, evi1->name);
2047                                 foreach(lcv, path)
2048                                 {
2049                                         char       *versionName = (char *) lfirst(lcv);
2050
2051                                         appendStringInfoString(&pathbuf, "--");
2052                                         appendStringInfoString(&pathbuf, versionName);
2053                                 }
2054                                 values[2] = CStringGetTextDatum(pathbuf.data);
2055                                 pfree(pathbuf.data);
2056                         }
2057
2058                         tuplestore_putvalues(tupstore, tupdesc, values, nulls);
2059                 }
2060         }
2061
2062         /* clean up and return the tuplestore */
2063         tuplestore_donestoring(tupstore);
2064
2065         return (Datum) 0;
2066 }
2067
2068 /*
2069  * pg_extension_config_dump
2070  *
2071  * Record information about a configuration table that belongs to an
2072  * extension being created, but whose contents should be dumped in whole
2073  * or in part during pg_dump.
2074  */
2075 Datum
2076 pg_extension_config_dump(PG_FUNCTION_ARGS)
2077 {
2078         Oid                     tableoid = PG_GETARG_OID(0);
2079         text       *wherecond = PG_GETARG_TEXT_P(1);
2080         char       *tablename;
2081         Relation        extRel;
2082         ScanKeyData key[1];
2083         SysScanDesc extScan;
2084         HeapTuple       extTup;
2085         Datum           arrayDatum;
2086         Datum           elementDatum;
2087         int                     arrayIndex;
2088         bool            isnull;
2089         Datum           repl_val[Natts_pg_extension];
2090         bool            repl_null[Natts_pg_extension];
2091         bool            repl_repl[Natts_pg_extension];
2092         ArrayType  *a;
2093
2094         /*
2095          * We only allow this to be called from an extension's SQL script. We
2096          * shouldn't need any permissions check beyond that.
2097          */
2098         if (!creating_extension)
2099                 ereport(ERROR,
2100                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2101                                  errmsg("pg_extension_config_dump() can only be called "
2102                                                 "from an SQL script executed by CREATE EXTENSION")));
2103
2104         /*
2105          * Check that the table exists and is a member of the extension being
2106          * created.  This ensures that we don't need to register a dependency to
2107          * protect the extconfig entry.
2108          */
2109         tablename = get_rel_name(tableoid);
2110         if (tablename == NULL)
2111                 ereport(ERROR,
2112                                 (errcode(ERRCODE_UNDEFINED_TABLE),
2113                                  errmsg("OID %u does not refer to a table", tableoid)));
2114         if (getExtensionOfObject(RelationRelationId, tableoid) !=
2115                 CurrentExtensionObject)
2116                 ereport(ERROR,
2117                                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2118                 errmsg("table \"%s\" is not a member of the extension being created",
2119                            tablename)));
2120
2121         /*
2122          * Add the table OID and WHERE condition to the extension's extconfig and
2123          * extcondition arrays.
2124          */
2125
2126         /* Find the pg_extension tuple */
2127         extRel = heap_open(ExtensionRelationId, RowExclusiveLock);
2128
2129         ScanKeyInit(&key[0],
2130                                 ObjectIdAttributeNumber,
2131                                 BTEqualStrategyNumber, F_OIDEQ,
2132                                 ObjectIdGetDatum(CurrentExtensionObject));
2133
2134         extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
2135                                                                  SnapshotNow, 1, key);
2136
2137         extTup = systable_getnext(extScan);
2138
2139         if (!HeapTupleIsValid(extTup))          /* should not happen */
2140                 elog(ERROR, "extension with oid %u does not exist",
2141                          CurrentExtensionObject);
2142
2143         memset(repl_val, 0, sizeof(repl_val));
2144         memset(repl_null, false, sizeof(repl_null));
2145         memset(repl_repl, false, sizeof(repl_repl));
2146
2147         /* Build or modify the extconfig value */
2148         elementDatum = ObjectIdGetDatum(tableoid);
2149
2150         arrayDatum = heap_getattr(extTup, Anum_pg_extension_extconfig,
2151                                                           RelationGetDescr(extRel), &isnull);
2152         if (isnull)
2153         {
2154                 a = construct_array(&elementDatum, 1,
2155                                                         OIDOID,
2156                                                         sizeof(Oid), true, 'i');
2157         }
2158         else
2159         {
2160                 a = DatumGetArrayTypeP(arrayDatum);
2161                 Assert(ARR_ELEMTYPE(a) == OIDOID);
2162                 Assert(ARR_NDIM(a) == 1);
2163                 Assert(ARR_LBOUND(a)[0] == 1);
2164
2165                 arrayIndex = ARR_DIMS(a)[0] + 1;                /* add after end */
2166
2167                 a = array_set(a, 1, &arrayIndex,
2168                                           elementDatum,
2169                                           false,
2170                                           -1 /* varlena array */ ,
2171                                           sizeof(Oid) /* OID's typlen */ ,
2172                                           true /* OID's typbyval */ ,
2173                                           'i' /* OID's typalign */ );
2174         }
2175         repl_val[Anum_pg_extension_extconfig - 1] = PointerGetDatum(a);
2176         repl_repl[Anum_pg_extension_extconfig - 1] = true;
2177
2178         /* Build or modify the extcondition value */
2179         elementDatum = PointerGetDatum(wherecond);
2180
2181         arrayDatum = heap_getattr(extTup, Anum_pg_extension_extcondition,
2182                                                           RelationGetDescr(extRel), &isnull);
2183         if (isnull)
2184         {
2185                 a = construct_array(&elementDatum, 1,
2186                                                         TEXTOID,
2187                                                         -1, false, 'i');
2188         }
2189         else
2190         {
2191                 a = DatumGetArrayTypeP(arrayDatum);
2192                 Assert(ARR_ELEMTYPE(a) == TEXTOID);
2193                 Assert(ARR_NDIM(a) == 1);
2194                 Assert(ARR_LBOUND(a)[0] == 1);
2195
2196                 arrayIndex = ARR_DIMS(a)[0] + 1;                /* add after end */
2197
2198                 a = array_set(a, 1, &arrayIndex,
2199                                           elementDatum,
2200                                           false,
2201                                           -1 /* varlena array */ ,
2202                                           -1 /* TEXT's typlen */ ,
2203                                           false /* TEXT's typbyval */ ,
2204                                           'i' /* TEXT's typalign */ );
2205         }
2206         repl_val[Anum_pg_extension_extcondition - 1] = PointerGetDatum(a);
2207         repl_repl[Anum_pg_extension_extcondition - 1] = true;
2208
2209         extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
2210                                                            repl_val, repl_null, repl_repl);
2211
2212         simple_heap_update(extRel, &extTup->t_self, extTup);
2213         CatalogUpdateIndexes(extRel, extTup);
2214
2215         systable_endscan(extScan);
2216
2217         heap_close(extRel, RowExclusiveLock);
2218
2219         PG_RETURN_VOID();
2220 }
2221
2222 /*
2223  * Execute ALTER EXTENSION SET SCHEMA
2224  */
2225 void
2226 AlterExtensionNamespace(List *names, const char *newschema)
2227 {
2228         char       *extensionName;
2229         Oid                     extensionOid;
2230         Oid                     nspOid;
2231         Oid                     oldNspOid = InvalidOid;
2232         AclResult       aclresult;
2233         Relation        extRel;
2234         ScanKeyData key[2];
2235         SysScanDesc extScan;
2236         HeapTuple       extTup;
2237         Form_pg_extension extForm;
2238         Relation        depRel;
2239         SysScanDesc depScan;
2240         HeapTuple       depTup;
2241
2242         if (list_length(names) != 1)
2243                 ereport(ERROR,
2244                                 (errcode(ERRCODE_SYNTAX_ERROR),
2245                                  errmsg("extension name cannot be qualified")));
2246         extensionName = strVal(linitial(names));
2247
2248         extensionOid = get_extension_oid(extensionName, false);
2249
2250         nspOid = LookupCreationNamespace(newschema);
2251
2252         /*
2253          * Permission check: must own extension.  Note that we don't bother to
2254          * check ownership of the individual member objects ...
2255          */
2256         if (!pg_extension_ownercheck(extensionOid, GetUserId()))
2257                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EXTENSION,
2258                                            extensionName);
2259
2260         /* Permission check: must have creation rights in target namespace */
2261         aclresult = pg_namespace_aclcheck(nspOid, GetUserId(), ACL_CREATE);
2262         if (aclresult != ACLCHECK_OK)
2263                 aclcheck_error(aclresult, ACL_KIND_NAMESPACE, newschema);
2264
2265         /* Locate the pg_extension tuple */
2266         extRel = heap_open(ExtensionRelationId, RowExclusiveLock);
2267
2268         ScanKeyInit(&key[0],
2269                                 ObjectIdAttributeNumber,
2270                                 BTEqualStrategyNumber, F_OIDEQ,
2271                                 ObjectIdGetDatum(extensionOid));
2272
2273         extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
2274                                                                  SnapshotNow, 1, key);
2275
2276         extTup = systable_getnext(extScan);
2277
2278         if (!HeapTupleIsValid(extTup))          /* should not happen */
2279                 elog(ERROR, "extension with oid %u does not exist", extensionOid);
2280
2281         /* Copy tuple so we can modify it below */
2282         extTup = heap_copytuple(extTup);
2283         extForm = (Form_pg_extension) GETSTRUCT(extTup);
2284
2285         systable_endscan(extScan);
2286
2287         /*
2288          * If the extension is already in the target schema, just silently do
2289          * nothing.
2290          */
2291         if (extForm->extnamespace == nspOid)
2292         {
2293                 heap_close(extRel, RowExclusiveLock);
2294                 return;
2295         }
2296
2297         /* Check extension is supposed to be relocatable */
2298         if (!extForm->extrelocatable)
2299                 ereport(ERROR,
2300                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2301                                  errmsg("extension \"%s\" does not support SET SCHEMA",
2302                                                 NameStr(extForm->extname))));
2303
2304         /*
2305          * Scan pg_depend to find objects that depend directly on the extension,
2306          * and alter each one's schema.
2307          */
2308         depRel = heap_open(DependRelationId, AccessShareLock);
2309
2310         ScanKeyInit(&key[0],
2311                                 Anum_pg_depend_refclassid,
2312                                 BTEqualStrategyNumber, F_OIDEQ,
2313                                 ObjectIdGetDatum(ExtensionRelationId));
2314         ScanKeyInit(&key[1],
2315                                 Anum_pg_depend_refobjid,
2316                                 BTEqualStrategyNumber, F_OIDEQ,
2317                                 ObjectIdGetDatum(extensionOid));
2318
2319         depScan = systable_beginscan(depRel, DependReferenceIndexId, true,
2320                                                                  SnapshotNow, 2, key);
2321
2322         while (HeapTupleIsValid(depTup = systable_getnext(depScan)))
2323         {
2324                 Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
2325                 ObjectAddress dep;
2326                 Oid                     dep_oldNspOid;
2327
2328                 /*
2329                  * Ignore non-membership dependencies.  (Currently, the only other
2330                  * case we could see here is a normal dependency from another
2331                  * extension.)
2332                  */
2333                 if (pg_depend->deptype != DEPENDENCY_EXTENSION)
2334                         continue;
2335
2336                 dep.classId = pg_depend->classid;
2337                 dep.objectId = pg_depend->objid;
2338                 dep.objectSubId = pg_depend->objsubid;
2339
2340                 if (dep.objectSubId != 0)               /* should not happen */
2341                         elog(ERROR, "extension should not have a sub-object dependency");
2342
2343                 dep_oldNspOid = AlterObjectNamespace_oid(dep.classId,
2344                                                                                                  dep.objectId,
2345                                                                                                  nspOid);
2346
2347                 /*
2348                  * Remember previous namespace of first object that has one
2349                  */
2350                 if (oldNspOid == InvalidOid && dep_oldNspOid != InvalidOid)
2351                         oldNspOid = dep_oldNspOid;
2352
2353                 /*
2354                  * If not all the objects had the same old namespace (ignoring any
2355                  * that are not in namespaces), complain.
2356                  */
2357                 if (dep_oldNspOid != InvalidOid && dep_oldNspOid != oldNspOid)
2358                         ereport(ERROR,
2359                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2360                                          errmsg("extension \"%s\" does not support SET SCHEMA",
2361                                                         NameStr(extForm->extname)),
2362                                          errdetail("%s is not in the extension's schema \"%s\"",
2363                                                            getObjectDescription(&dep),
2364                                                            get_namespace_name(oldNspOid))));
2365         }
2366
2367         systable_endscan(depScan);
2368
2369         relation_close(depRel, AccessShareLock);
2370
2371         /* Now adjust pg_extension.extnamespace */
2372         extForm->extnamespace = nspOid;
2373
2374         simple_heap_update(extRel, &extTup->t_self, extTup);
2375         CatalogUpdateIndexes(extRel, extTup);
2376
2377         heap_close(extRel, RowExclusiveLock);
2378
2379         /* update dependencies to point to the new schema */
2380         changeDependencyFor(ExtensionRelationId, extensionOid,
2381                                                 NamespaceRelationId, oldNspOid, nspOid);
2382 }
2383
2384 /*
2385  * Execute ALTER EXTENSION UPDATE
2386  */
2387 void
2388 ExecAlterExtensionStmt(AlterExtensionStmt *stmt)
2389 {
2390         DefElem    *d_new_version = NULL;
2391         char       *versionName;
2392         char       *oldVersionName;
2393         ExtensionControlFile *control;
2394         Oid                     extensionOid;
2395         Relation        extRel;
2396         ScanKeyData key[1];
2397         SysScanDesc extScan;
2398         HeapTuple       extTup;
2399         List       *updateVersions;
2400         Datum           datum;
2401         bool            isnull;
2402         ListCell   *lc;
2403
2404         /*
2405          * We use global variables to track the extension being created, so we can
2406          * create/update only one extension at the same time.
2407          */
2408         if (creating_extension)
2409                 ereport(ERROR,
2410                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2411                                  errmsg("nested ALTER EXTENSION is not supported")));
2412
2413         /*
2414          * Look up the extension --- it must already exist in pg_extension
2415          */
2416         extRel = heap_open(ExtensionRelationId, AccessShareLock);
2417
2418         ScanKeyInit(&key[0],
2419                                 Anum_pg_extension_extname,
2420                                 BTEqualStrategyNumber, F_NAMEEQ,
2421                                 CStringGetDatum(stmt->extname));
2422
2423         extScan = systable_beginscan(extRel, ExtensionNameIndexId, true,
2424                                                                  SnapshotNow, 1, key);
2425
2426         extTup = systable_getnext(extScan);
2427
2428         if (!HeapTupleIsValid(extTup))
2429                 ereport(ERROR,
2430                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
2431                                  errmsg("extension \"%s\" does not exist",
2432                                                 stmt->extname)));
2433
2434         extensionOid = HeapTupleGetOid(extTup);
2435
2436         /*
2437          * Determine the existing version we are updating from
2438          */
2439         datum = heap_getattr(extTup, Anum_pg_extension_extversion,
2440                                                  RelationGetDescr(extRel), &isnull);
2441         if (isnull)
2442                 elog(ERROR, "extversion is null");
2443         oldVersionName = text_to_cstring(DatumGetTextPP(datum));
2444
2445         systable_endscan(extScan);
2446
2447         heap_close(extRel, AccessShareLock);
2448
2449         /* Permission check: must own extension */
2450         if (!pg_extension_ownercheck(extensionOid, GetUserId()))
2451                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EXTENSION,
2452                                            stmt->extname);
2453
2454         /*
2455          * Read the primary control file.  Note we assume that it does not contain
2456          * any non-ASCII data, so there is no need to worry about encoding at this
2457          * point.
2458          */
2459         control = read_extension_control_file(stmt->extname);
2460
2461         /*
2462          * Read the statement option list
2463          */
2464         foreach(lc, stmt->options)
2465         {
2466                 DefElem    *defel = (DefElem *) lfirst(lc);
2467
2468                 if (strcmp(defel->defname, "new_version") == 0)
2469                 {
2470                         if (d_new_version)
2471                                 ereport(ERROR,
2472                                                 (errcode(ERRCODE_SYNTAX_ERROR),
2473                                                  errmsg("conflicting or redundant options")));
2474                         d_new_version = defel;
2475                 }
2476                 else
2477                         elog(ERROR, "unrecognized option: %s", defel->defname);
2478         }
2479
2480         /*
2481          * Determine the version to update to
2482          */
2483         if (d_new_version && d_new_version->arg)
2484                 versionName = strVal(d_new_version->arg);
2485         else if (control->default_version)
2486                 versionName = control->default_version;
2487         else
2488         {
2489                 ereport(ERROR,
2490                                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2491                                  errmsg("version to install must be specified")));
2492                 versionName = NULL;             /* keep compiler quiet */
2493         }
2494         check_valid_version_name(versionName);
2495
2496         /*
2497          * If we're already at that version, just say so
2498          */
2499         if (strcmp(oldVersionName, versionName) == 0)
2500         {
2501                 ereport(NOTICE,
2502                    (errmsg("version \"%s\" of extension \"%s\" is already installed",
2503                                    versionName, stmt->extname)));
2504                 return;
2505         }
2506
2507         /*
2508          * Identify the series of update script files we need to execute
2509          */
2510         updateVersions = identify_update_path(control,
2511                                                                                   oldVersionName,
2512                                                                                   versionName);
2513
2514         /*
2515          * Update the pg_extension row and execute the update scripts, one at a
2516          * time
2517          */
2518         ApplyExtensionUpdates(extensionOid, control,
2519                                                   oldVersionName, updateVersions);
2520 }
2521
2522 /*
2523  * Apply a series of update scripts as though individual ALTER EXTENSION
2524  * UPDATE commands had been given, including altering the pg_extension row
2525  * and dependencies each time.
2526  *
2527  * This might be more work than necessary, but it ensures that old update
2528  * scripts don't break if newer versions have different control parameters.
2529  */
2530 static void
2531 ApplyExtensionUpdates(Oid extensionOid,
2532                                           ExtensionControlFile *pcontrol,
2533                                           const char *initialVersion,
2534                                           List *updateVersions)
2535 {
2536         const char *oldVersionName = initialVersion;
2537         ListCell   *lcv;
2538
2539         foreach(lcv, updateVersions)
2540         {
2541                 char       *versionName = (char *) lfirst(lcv);
2542                 ExtensionControlFile *control;
2543                 char       *schemaName;
2544                 Oid                     schemaOid;
2545                 List       *requiredExtensions;
2546                 List       *requiredSchemas;
2547                 Relation        extRel;
2548                 ScanKeyData key[1];
2549                 SysScanDesc extScan;
2550                 HeapTuple       extTup;
2551                 Form_pg_extension extForm;
2552                 Datum           values[Natts_pg_extension];
2553                 bool            nulls[Natts_pg_extension];
2554                 bool            repl[Natts_pg_extension];
2555                 ObjectAddress myself;
2556                 ListCell   *lc;
2557
2558                 /*
2559                  * Fetch parameters for specific version (pcontrol is not changed)
2560                  */
2561                 control = read_extension_aux_control_file(pcontrol, versionName);
2562
2563                 /* Find the pg_extension tuple */
2564                 extRel = heap_open(ExtensionRelationId, RowExclusiveLock);
2565
2566                 ScanKeyInit(&key[0],
2567                                         ObjectIdAttributeNumber,
2568                                         BTEqualStrategyNumber, F_OIDEQ,
2569                                         ObjectIdGetDatum(extensionOid));
2570
2571                 extScan = systable_beginscan(extRel, ExtensionOidIndexId, true,
2572                                                                          SnapshotNow, 1, key);
2573
2574                 extTup = systable_getnext(extScan);
2575
2576                 if (!HeapTupleIsValid(extTup))  /* should not happen */
2577                         elog(ERROR, "extension with oid %u does not exist",
2578                                  extensionOid);
2579
2580                 extForm = (Form_pg_extension) GETSTRUCT(extTup);
2581
2582                 /*
2583                  * Determine the target schema (set by original install)
2584                  */
2585                 schemaOid = extForm->extnamespace;
2586                 schemaName = get_namespace_name(schemaOid);
2587
2588                 /*
2589                  * Modify extrelocatable and extversion in the pg_extension tuple
2590                  */
2591                 memset(values, 0, sizeof(values));
2592                 memset(nulls, 0, sizeof(nulls));
2593                 memset(repl, 0, sizeof(repl));
2594
2595                 values[Anum_pg_extension_extrelocatable - 1] =
2596                         BoolGetDatum(control->relocatable);
2597                 repl[Anum_pg_extension_extrelocatable - 1] = true;
2598                 values[Anum_pg_extension_extversion - 1] =
2599                         CStringGetTextDatum(versionName);
2600                 repl[Anum_pg_extension_extversion - 1] = true;
2601
2602                 extTup = heap_modify_tuple(extTup, RelationGetDescr(extRel),
2603                                                                    values, nulls, repl);
2604
2605                 simple_heap_update(extRel, &extTup->t_self, extTup);
2606                 CatalogUpdateIndexes(extRel, extTup);
2607
2608                 systable_endscan(extScan);
2609
2610                 heap_close(extRel, RowExclusiveLock);
2611
2612                 /*
2613                  * Look up the prerequisite extensions for this version, and build
2614                  * lists of their OIDs and the OIDs of their target schemas.
2615                  */
2616                 requiredExtensions = NIL;
2617                 requiredSchemas = NIL;
2618                 foreach(lc, control->requires)
2619                 {
2620                         char       *curreq = (char *) lfirst(lc);
2621                         Oid                     reqext;
2622                         Oid                     reqschema;
2623
2624                         /*
2625                          * We intentionally don't use get_extension_oid's default error
2626                          * message here, because it would be confusing in this context.
2627                          */
2628                         reqext = get_extension_oid(curreq, true);
2629                         if (!OidIsValid(reqext))
2630                                 ereport(ERROR,
2631                                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
2632                                                  errmsg("required extension \"%s\" is not installed",
2633                                                                 curreq)));
2634                         reqschema = get_extension_schema(reqext);
2635                         requiredExtensions = lappend_oid(requiredExtensions, reqext);
2636                         requiredSchemas = lappend_oid(requiredSchemas, reqschema);
2637                 }
2638
2639                 /*
2640                  * Remove and recreate dependencies on prerequisite extensions
2641                  */
2642                 deleteDependencyRecordsForClass(ExtensionRelationId, extensionOid,
2643                                                                                 ExtensionRelationId,
2644                                                                                 DEPENDENCY_NORMAL);
2645
2646                 myself.classId = ExtensionRelationId;
2647                 myself.objectId = extensionOid;
2648                 myself.objectSubId = 0;
2649
2650                 foreach(lc, requiredExtensions)
2651                 {
2652                         Oid                     reqext = lfirst_oid(lc);
2653                         ObjectAddress otherext;
2654
2655                         otherext.classId = ExtensionRelationId;
2656                         otherext.objectId = reqext;
2657                         otherext.objectSubId = 0;
2658
2659                         recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
2660                 }
2661
2662                 /*
2663                  * Finally, execute the update script file
2664                  */
2665                 execute_extension_script(extensionOid, control,
2666                                                                  oldVersionName, versionName,
2667                                                                  requiredSchemas,
2668                                                                  schemaName, schemaOid);
2669
2670                 /*
2671                  * Update prior-version name and loop around.  Since
2672                  * execute_sql_string did a final CommandCounterIncrement, we can
2673                  * update the pg_extension row again.
2674                  */
2675                 oldVersionName = versionName;
2676         }
2677 }
2678
2679 /*
2680  * Execute ALTER EXTENSION ADD/DROP
2681  */
2682 void
2683 ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt)
2684 {
2685         ObjectAddress extension;
2686         ObjectAddress object;
2687         Relation        relation;
2688         Oid                     oldExtension;
2689
2690         extension.classId = ExtensionRelationId;
2691         extension.objectId = get_extension_oid(stmt->extname, false);
2692         extension.objectSubId = 0;
2693
2694         /* Permission check: must own extension */
2695         if (!pg_extension_ownercheck(extension.objectId, GetUserId()))
2696                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EXTENSION,
2697                                            stmt->extname);
2698
2699         /*
2700          * Translate the parser representation that identifies the object into an
2701          * ObjectAddress.  get_object_address() will throw an error if the object
2702          * does not exist, and will also acquire a lock on the object to guard
2703          * against concurrent DROP and ALTER EXTENSION ADD/DROP operations.
2704          */
2705         object = get_object_address(stmt->objtype, stmt->objname, stmt->objargs,
2706                                                                 &relation, ShareUpdateExclusiveLock, false);
2707
2708         /* Permission check: must own target object, too */
2709         check_object_ownership(GetUserId(), stmt->objtype, object,
2710                                                    stmt->objname, stmt->objargs, relation);
2711
2712         /*
2713          * Check existing extension membership.
2714          */
2715         oldExtension = getExtensionOfObject(object.classId, object.objectId);
2716
2717         if (stmt->action > 0)
2718         {
2719                 /*
2720                  * ADD, so complain if object is already attached to some extension.
2721                  */
2722                 if (OidIsValid(oldExtension))
2723                         ereport(ERROR,
2724                                         (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2725                                          errmsg("%s is already a member of extension \"%s\"",
2726                                                         getObjectDescription(&object),
2727                                                         get_extension_name(oldExtension))));
2728
2729                 /*
2730                  * OK, add the dependency.
2731                  */
2732                 recordDependencyOn(&object, &extension, DEPENDENCY_EXTENSION);
2733         }
2734         else
2735         {
2736                 /*
2737                  * DROP, so complain if it's not a member.
2738                  */
2739                 if (oldExtension != extension.objectId)
2740                         ereport(ERROR,
2741                                         (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2742                                          errmsg("%s is not a member of extension \"%s\"",
2743                                                         getObjectDescription(&object),
2744                                                         stmt->extname)));
2745
2746                 /*
2747                  * OK, drop the dependency.
2748                  */
2749                 if (deleteDependencyRecordsForClass(object.classId, object.objectId,
2750                                                                                         ExtensionRelationId,
2751                                                                                         DEPENDENCY_EXTENSION) != 1)
2752                         elog(ERROR, "unexpected number of extension dependency records");
2753         }
2754
2755         /*
2756          * If get_object_address() opened the relation for us, we close it to keep
2757          * the reference count correct - but we retain any locks acquired by
2758          * get_object_address() until commit time, to guard against concurrent
2759          * activity.
2760          */
2761         if (relation != NULL)
2762                 relation_close(relation, NoLock);
2763 }