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