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