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