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