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