Thanks to visit codestin.com
Credit goes to doxygen.postgresql.org

PostgreSQL Source Code git master
foreigncmds.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * foreigncmds.c
4 * foreign-data wrapper/server creation/manipulation commands
5 *
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 *
8 *
9 * IDENTIFICATION
10 * src/backend/commands/foreigncmds.c
11 *
12 *-------------------------------------------------------------------------
13 */
14#include "postgres.h"
15
16#include "access/htup_details.h"
17#include "access/reloptions.h"
18#include "access/table.h"
19#include "access/xact.h"
20#include "catalog/catalog.h"
21#include "catalog/dependency.h"
22#include "catalog/indexing.h"
27#include "catalog/pg_proc.h"
28#include "catalog/pg_type.h"
30#include "commands/defrem.h"
31#include "foreign/fdwapi.h"
32#include "foreign/foreign.h"
33#include "miscadmin.h"
34#include "parser/parse_func.h"
35#include "tcop/utility.h"
36#include "utils/acl.h"
37#include "utils/builtins.h"
38#include "utils/lsyscache.h"
39#include "utils/rel.h"
40#include "utils/syscache.h"
41
42
43typedef struct
44{
45 char *tablename;
46 char *cmd;
48
49/* Internal functions */
50static void import_error_callback(void *arg);
51
52
53/*
54 * Convert a DefElem list to the text array format that is used in
55 * pg_foreign_data_wrapper, pg_foreign_server, pg_user_mapping, and
56 * pg_foreign_table.
57 *
58 * Returns the array in the form of a Datum, or PointerGetDatum(NULL)
59 * if the list is empty.
60 *
61 * Note: The array is usually stored to database without further
62 * processing, hence any validation should be done before this
63 * conversion.
64 */
65static Datum
67{
68 ArrayBuildState *astate = NULL;
69 ListCell *cell;
70
71 foreach(cell, options)
72 {
73 DefElem *def = lfirst(cell);
74 const char *name;
75 const char *value;
76 Size len;
77 text *t;
78
79 name = def->defname;
80 value = defGetString(def);
81
82 /* Insist that name not contain "=", else "a=b=c" is ambiguous */
83 if (strchr(name, '=') != NULL)
85 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
86 errmsg("invalid option name \"%s\": must not contain \"=\"",
87 name)));
88
89 len = VARHDRSZ + strlen(name) + 1 + strlen(value);
90 /* +1 leaves room for sprintf's trailing null */
91 t = palloc(len + 1);
92 SET_VARSIZE(t, len);
93 sprintf(VARDATA(t), "%s=%s", name, value);
94
95 astate = accumArrayResult(astate, PointerGetDatum(t),
96 false, TEXTOID,
98 }
99
100 if (astate)
102
103 return PointerGetDatum(NULL);
104}
105
106
107/*
108 * Transform a list of DefElem into text array format. This is substantially
109 * the same thing as optionListToArray(), except we recognize SET/ADD/DROP
110 * actions for modifying an existing list of options, which is passed in
111 * Datum form as oldOptions. Also, if fdwvalidator isn't InvalidOid
112 * it specifies a validator function to call on the result.
113 *
114 * Returns the array in the form of a Datum, or PointerGetDatum(NULL)
115 * if the list is empty.
116 *
117 * This is used by CREATE/ALTER of FOREIGN DATA WRAPPER/SERVER/USER MAPPING/
118 * FOREIGN TABLE.
119 */
120Datum
122 Datum oldOptions,
123 List *options,
124 Oid fdwvalidator)
125{
126 List *resultOptions = untransformRelOptions(oldOptions);
127 ListCell *optcell;
128 Datum result;
129
130 foreach(optcell, options)
131 {
132 DefElem *od = lfirst(optcell);
133 ListCell *cell;
134
135 /*
136 * Find the element in resultOptions. We need this for validation in
137 * all cases.
138 */
139 foreach(cell, resultOptions)
140 {
141 DefElem *def = lfirst(cell);
142
143 if (strcmp(def->defname, od->defname) == 0)
144 break;
145 }
146
147 /*
148 * It is possible to perform multiple SET/DROP actions on the same
149 * option. The standard permits this, as long as the options to be
150 * added are unique. Note that an unspecified action is taken to be
151 * ADD.
152 */
153 switch (od->defaction)
154 {
155 case DEFELEM_DROP:
156 if (!cell)
158 (errcode(ERRCODE_UNDEFINED_OBJECT),
159 errmsg("option \"%s\" not found",
160 od->defname)));
161 resultOptions = list_delete_cell(resultOptions, cell);
162 break;
163
164 case DEFELEM_SET:
165 if (!cell)
167 (errcode(ERRCODE_UNDEFINED_OBJECT),
168 errmsg("option \"%s\" not found",
169 od->defname)));
170 lfirst(cell) = od;
171 break;
172
173 case DEFELEM_ADD:
174 case DEFELEM_UNSPEC:
175 if (cell)
178 errmsg("option \"%s\" provided more than once",
179 od->defname)));
180 resultOptions = lappend(resultOptions, od);
181 break;
182
183 default:
184 elog(ERROR, "unrecognized action %d on option \"%s\"",
185 (int) od->defaction, od->defname);
186 break;
187 }
188 }
189
190 result = optionListToArray(resultOptions);
191
192 if (OidIsValid(fdwvalidator))
193 {
194 Datum valarg = result;
195
196 /*
197 * Pass a null options list as an empty array, so that validators
198 * don't have to be declared non-strict to handle the case.
199 */
200 if (DatumGetPointer(valarg) == NULL)
201 valarg = PointerGetDatum(construct_empty_array(TEXTOID));
202 OidFunctionCall2(fdwvalidator, valarg, ObjectIdGetDatum(catalogId));
203 }
204
205 return result;
206}
207
208
209/*
210 * Internal workhorse for changing a data wrapper's owner.
211 *
212 * Allow this only for superusers; also the new owner must be a
213 * superuser.
214 */
215static void
217{
219 Datum repl_val[Natts_pg_foreign_data_wrapper];
220 bool repl_null[Natts_pg_foreign_data_wrapper];
221 bool repl_repl[Natts_pg_foreign_data_wrapper];
222 Acl *newAcl;
223 Datum aclDatum;
224 bool isNull;
225
227
228 /* Must be a superuser to change a FDW owner */
229 if (!superuser())
231 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
232 errmsg("permission denied to change owner of foreign-data wrapper \"%s\"",
233 NameStr(form->fdwname)),
234 errhint("Must be superuser to change owner of a foreign-data wrapper.")));
235
236 /* New owner must also be a superuser */
237 if (!superuser_arg(newOwnerId))
239 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
240 errmsg("permission denied to change owner of foreign-data wrapper \"%s\"",
241 NameStr(form->fdwname)),
242 errhint("The owner of a foreign-data wrapper must be a superuser.")));
243
244 if (form->fdwowner != newOwnerId)
245 {
246 memset(repl_null, false, sizeof(repl_null));
247 memset(repl_repl, false, sizeof(repl_repl));
248
249 repl_repl[Anum_pg_foreign_data_wrapper_fdwowner - 1] = true;
250 repl_val[Anum_pg_foreign_data_wrapper_fdwowner - 1] = ObjectIdGetDatum(newOwnerId);
251
252 aclDatum = heap_getattr(tup,
253 Anum_pg_foreign_data_wrapper_fdwacl,
254 RelationGetDescr(rel),
255 &isNull);
256 /* Null ACLs do not require changes */
257 if (!isNull)
258 {
259 newAcl = aclnewowner(DatumGetAclP(aclDatum),
260 form->fdwowner, newOwnerId);
261 repl_repl[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true;
262 repl_val[Anum_pg_foreign_data_wrapper_fdwacl - 1] = PointerGetDatum(newAcl);
263 }
264
265 tup = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null,
266 repl_repl);
267
268 CatalogTupleUpdate(rel, &tup->t_self, tup);
269
270 /* Update owner dependency reference */
271 changeDependencyOnOwner(ForeignDataWrapperRelationId,
272 form->oid,
273 newOwnerId);
274 }
275
276 InvokeObjectPostAlterHook(ForeignDataWrapperRelationId,
277 form->oid, 0);
278}
279
280/*
281 * Change foreign-data wrapper owner -- by name
282 *
283 * Note restrictions in the "_internal" function, above.
284 */
286AlterForeignDataWrapperOwner(const char *name, Oid newOwnerId)
287{
288 Oid fdwId;
289 HeapTuple tup;
290 Relation rel;
291 ObjectAddress address;
293
294
295 rel = table_open(ForeignDataWrapperRelationId, RowExclusiveLock);
296
297 tup = SearchSysCacheCopy1(FOREIGNDATAWRAPPERNAME, CStringGetDatum(name));
298
299 if (!HeapTupleIsValid(tup))
301 (errcode(ERRCODE_UNDEFINED_OBJECT),
302 errmsg("foreign-data wrapper \"%s\" does not exist", name)));
303
305 fdwId = form->oid;
306
307 AlterForeignDataWrapperOwner_internal(rel, tup, newOwnerId);
308
309 ObjectAddressSet(address, ForeignDataWrapperRelationId, fdwId);
310
311 heap_freetuple(tup);
312
314
315 return address;
316}
317
318/*
319 * Change foreign-data wrapper owner -- by OID
320 *
321 * Note restrictions in the "_internal" function, above.
322 */
323void
325{
326 HeapTuple tup;
327 Relation rel;
328
329 rel = table_open(ForeignDataWrapperRelationId, RowExclusiveLock);
330
331 tup = SearchSysCacheCopy1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fwdId));
332
333 if (!HeapTupleIsValid(tup))
335 (errcode(ERRCODE_UNDEFINED_OBJECT),
336 errmsg("foreign-data wrapper with OID %u does not exist", fwdId)));
337
338 AlterForeignDataWrapperOwner_internal(rel, tup, newOwnerId);
339
340 heap_freetuple(tup);
341
343}
344
345/*
346 * Internal workhorse for changing a foreign server's owner
347 */
348static void
350{
352 Datum repl_val[Natts_pg_foreign_server];
353 bool repl_null[Natts_pg_foreign_server];
354 bool repl_repl[Natts_pg_foreign_server];
355 Acl *newAcl;
356 Datum aclDatum;
357 bool isNull;
358
359 form = (Form_pg_foreign_server) GETSTRUCT(tup);
360
361 if (form->srvowner != newOwnerId)
362 {
363 /* Superusers can always do it */
364 if (!superuser())
365 {
366 Oid srvId;
367 AclResult aclresult;
368
369 srvId = form->oid;
370
371 /* Must be owner */
372 if (!object_ownercheck(ForeignServerRelationId, srvId, GetUserId()))
374 NameStr(form->srvname));
375
376 /* Must be able to become new owner */
377 check_can_set_role(GetUserId(), newOwnerId);
378
379 /* New owner must have USAGE privilege on foreign-data wrapper */
380 aclresult = object_aclcheck(ForeignDataWrapperRelationId, form->srvfdw, newOwnerId, ACL_USAGE);
381 if (aclresult != ACLCHECK_OK)
382 {
383 ForeignDataWrapper *fdw = GetForeignDataWrapper(form->srvfdw);
384
385 aclcheck_error(aclresult, OBJECT_FDW, fdw->fdwname);
386 }
387 }
388
389 memset(repl_null, false, sizeof(repl_null));
390 memset(repl_repl, false, sizeof(repl_repl));
391
392 repl_repl[Anum_pg_foreign_server_srvowner - 1] = true;
393 repl_val[Anum_pg_foreign_server_srvowner - 1] = ObjectIdGetDatum(newOwnerId);
394
395 aclDatum = heap_getattr(tup,
396 Anum_pg_foreign_server_srvacl,
397 RelationGetDescr(rel),
398 &isNull);
399 /* Null ACLs do not require changes */
400 if (!isNull)
401 {
402 newAcl = aclnewowner(DatumGetAclP(aclDatum),
403 form->srvowner, newOwnerId);
404 repl_repl[Anum_pg_foreign_server_srvacl - 1] = true;
405 repl_val[Anum_pg_foreign_server_srvacl - 1] = PointerGetDatum(newAcl);
406 }
407
408 tup = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null,
409 repl_repl);
410
411 CatalogTupleUpdate(rel, &tup->t_self, tup);
412
413 /* Update owner dependency reference */
414 changeDependencyOnOwner(ForeignServerRelationId, form->oid,
415 newOwnerId);
416 }
417
418 InvokeObjectPostAlterHook(ForeignServerRelationId,
419 form->oid, 0);
420}
421
422/*
423 * Change foreign server owner -- by name
424 */
426AlterForeignServerOwner(const char *name, Oid newOwnerId)
427{
428 Oid servOid;
429 HeapTuple tup;
430 Relation rel;
431 ObjectAddress address;
433
434 rel = table_open(ForeignServerRelationId, RowExclusiveLock);
435
436 tup = SearchSysCacheCopy1(FOREIGNSERVERNAME, CStringGetDatum(name));
437
438 if (!HeapTupleIsValid(tup))
440 (errcode(ERRCODE_UNDEFINED_OBJECT),
441 errmsg("server \"%s\" does not exist", name)));
442
443 form = (Form_pg_foreign_server) GETSTRUCT(tup);
444 servOid = form->oid;
445
446 AlterForeignServerOwner_internal(rel, tup, newOwnerId);
447
448 ObjectAddressSet(address, ForeignServerRelationId, servOid);
449
450 heap_freetuple(tup);
451
453
454 return address;
455}
456
457/*
458 * Change foreign server owner -- by OID
459 */
460void
462{
463 HeapTuple tup;
464 Relation rel;
465
466 rel = table_open(ForeignServerRelationId, RowExclusiveLock);
467
468 tup = SearchSysCacheCopy1(FOREIGNSERVEROID, ObjectIdGetDatum(srvId));
469
470 if (!HeapTupleIsValid(tup))
472 (errcode(ERRCODE_UNDEFINED_OBJECT),
473 errmsg("foreign server with OID %u does not exist", srvId)));
474
475 AlterForeignServerOwner_internal(rel, tup, newOwnerId);
476
477 heap_freetuple(tup);
478
480}
481
482/*
483 * Convert a handler function name passed from the parser to an Oid.
484 */
485static Oid
487{
488 Oid handlerOid;
489
490 if (handler == NULL || handler->arg == NULL)
491 return InvalidOid;
492
493 /* handlers have no arguments */
494 handlerOid = LookupFuncName((List *) handler->arg, 0, NULL, false);
495
496 /* check that handler has correct return type */
497 if (get_func_rettype(handlerOid) != FDW_HANDLEROID)
499 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
500 errmsg("function %s must return type %s",
501 NameListToString((List *) handler->arg), "fdw_handler")));
502
503 return handlerOid;
504}
505
506/*
507 * Convert a validator function name passed from the parser to an Oid.
508 */
509static Oid
511{
512 Oid funcargtypes[2];
513
514 if (validator == NULL || validator->arg == NULL)
515 return InvalidOid;
516
517 /* validators take text[], oid */
518 funcargtypes[0] = TEXTARRAYOID;
519 funcargtypes[1] = OIDOID;
520
521 return LookupFuncName((List *) validator->arg, 2, funcargtypes, false);
522 /* validator's return value is ignored, so we don't check the type */
523}
524
525/*
526 * Process function options of CREATE/ALTER FDW
527 */
528static void
529parse_func_options(ParseState *pstate, List *func_options,
530 bool *handler_given, Oid *fdwhandler,
531 bool *validator_given, Oid *fdwvalidator)
532{
533 ListCell *cell;
534
535 *handler_given = false;
536 *validator_given = false;
537 /* return InvalidOid if not given */
538 *fdwhandler = InvalidOid;
539 *fdwvalidator = InvalidOid;
540
541 foreach(cell, func_options)
542 {
543 DefElem *def = (DefElem *) lfirst(cell);
544
545 if (strcmp(def->defname, "handler") == 0)
546 {
547 if (*handler_given)
548 errorConflictingDefElem(def, pstate);
549 *handler_given = true;
550 *fdwhandler = lookup_fdw_handler_func(def);
551 }
552 else if (strcmp(def->defname, "validator") == 0)
553 {
554 if (*validator_given)
555 errorConflictingDefElem(def, pstate);
556 *validator_given = true;
557 *fdwvalidator = lookup_fdw_validator_func(def);
558 }
559 else
560 elog(ERROR, "option \"%s\" not recognized",
561 def->defname);
562 }
563}
564
565/*
566 * Create a foreign-data wrapper
567 */
570{
571 Relation rel;
572 Datum values[Natts_pg_foreign_data_wrapper];
573 bool nulls[Natts_pg_foreign_data_wrapper];
574 HeapTuple tuple;
575 Oid fdwId;
576 bool handler_given;
577 bool validator_given;
578 Oid fdwhandler;
579 Oid fdwvalidator;
580 Datum fdwoptions;
581 Oid ownerId;
582 ObjectAddress myself;
583 ObjectAddress referenced;
584
585 rel = table_open(ForeignDataWrapperRelationId, RowExclusiveLock);
586
587 /* Must be superuser */
588 if (!superuser())
590 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
591 errmsg("permission denied to create foreign-data wrapper \"%s\"",
592 stmt->fdwname),
593 errhint("Must be superuser to create a foreign-data wrapper.")));
594
595 /* For now the owner cannot be specified on create. Use effective user ID. */
596 ownerId = GetUserId();
597
598 /*
599 * Check that there is no other foreign-data wrapper by this name.
600 */
601 if (GetForeignDataWrapperByName(stmt->fdwname, true) != NULL)
604 errmsg("foreign-data wrapper \"%s\" already exists",
605 stmt->fdwname)));
606
607 /*
608 * Insert tuple into pg_foreign_data_wrapper.
609 */
610 memset(values, 0, sizeof(values));
611 memset(nulls, false, sizeof(nulls));
612
613 fdwId = GetNewOidWithIndex(rel, ForeignDataWrapperOidIndexId,
614 Anum_pg_foreign_data_wrapper_oid);
615 values[Anum_pg_foreign_data_wrapper_oid - 1] = ObjectIdGetDatum(fdwId);
616 values[Anum_pg_foreign_data_wrapper_fdwname - 1] =
618 values[Anum_pg_foreign_data_wrapper_fdwowner - 1] = ObjectIdGetDatum(ownerId);
619
620 /* Lookup handler and validator functions, if given */
621 parse_func_options(pstate, stmt->func_options,
622 &handler_given, &fdwhandler,
623 &validator_given, &fdwvalidator);
624
625 values[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = ObjectIdGetDatum(fdwhandler);
626 values[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = ObjectIdGetDatum(fdwvalidator);
627
628 nulls[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true;
629
630 fdwoptions = transformGenericOptions(ForeignDataWrapperRelationId,
631 PointerGetDatum(NULL),
632 stmt->options,
633 fdwvalidator);
634
635 if (DatumGetPointer(fdwoptions) != NULL)
636 values[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = fdwoptions;
637 else
638 nulls[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true;
639
640 tuple = heap_form_tuple(rel->rd_att, values, nulls);
641
642 CatalogTupleInsert(rel, tuple);
643
644 heap_freetuple(tuple);
645
646 /* record dependencies */
647 myself.classId = ForeignDataWrapperRelationId;
648 myself.objectId = fdwId;
649 myself.objectSubId = 0;
650
651 if (OidIsValid(fdwhandler))
652 {
653 referenced.classId = ProcedureRelationId;
654 referenced.objectId = fdwhandler;
655 referenced.objectSubId = 0;
656 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
657 }
658
659 if (OidIsValid(fdwvalidator))
660 {
661 referenced.classId = ProcedureRelationId;
662 referenced.objectId = fdwvalidator;
663 referenced.objectSubId = 0;
664 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
665 }
666
667 recordDependencyOnOwner(ForeignDataWrapperRelationId, fdwId, ownerId);
668
669 /* dependency on extension */
671
672 /* Post creation hook for new foreign data wrapper */
673 InvokeObjectPostCreateHook(ForeignDataWrapperRelationId, fdwId, 0);
674
676
677 return myself;
678}
679
680
681/*
682 * Alter foreign-data wrapper
683 */
686{
687 Relation rel;
688 HeapTuple tp;
690 Datum repl_val[Natts_pg_foreign_data_wrapper];
691 bool repl_null[Natts_pg_foreign_data_wrapper];
692 bool repl_repl[Natts_pg_foreign_data_wrapper];
693 Oid fdwId;
694 bool isnull;
695 Datum datum;
696 bool handler_given;
697 bool validator_given;
698 Oid fdwhandler;
699 Oid fdwvalidator;
700 ObjectAddress myself;
701
702 rel = table_open(ForeignDataWrapperRelationId, RowExclusiveLock);
703
704 /* Must be superuser */
705 if (!superuser())
707 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
708 errmsg("permission denied to alter foreign-data wrapper \"%s\"",
709 stmt->fdwname),
710 errhint("Must be superuser to alter a foreign-data wrapper.")));
711
712 tp = SearchSysCacheCopy1(FOREIGNDATAWRAPPERNAME,
713 CStringGetDatum(stmt->fdwname));
714
715 if (!HeapTupleIsValid(tp))
717 (errcode(ERRCODE_UNDEFINED_OBJECT),
718 errmsg("foreign-data wrapper \"%s\" does not exist", stmt->fdwname)));
719
721 fdwId = fdwForm->oid;
722
723 memset(repl_val, 0, sizeof(repl_val));
724 memset(repl_null, false, sizeof(repl_null));
725 memset(repl_repl, false, sizeof(repl_repl));
726
727 parse_func_options(pstate, stmt->func_options,
728 &handler_given, &fdwhandler,
729 &validator_given, &fdwvalidator);
730
731 if (handler_given)
732 {
733 repl_val[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = ObjectIdGetDatum(fdwhandler);
734 repl_repl[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = true;
735
736 /*
737 * It could be that the behavior of accessing foreign table changes
738 * with the new handler. Warn about this.
739 */
741 (errmsg("changing the foreign-data wrapper handler can change behavior of existing foreign tables")));
742 }
743
744 if (validator_given)
745 {
746 repl_val[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = ObjectIdGetDatum(fdwvalidator);
747 repl_repl[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = true;
748
749 /*
750 * It could be that existing options for the FDW or dependent SERVER,
751 * USER MAPPING or FOREIGN TABLE objects are no longer valid according
752 * to the new validator. Warn about this.
753 */
754 if (OidIsValid(fdwvalidator))
756 (errmsg("changing the foreign-data wrapper validator can cause "
757 "the options for dependent objects to become invalid")));
758 }
759 else
760 {
761 /*
762 * Validator is not changed, but we need it for validating options.
763 */
764 fdwvalidator = fdwForm->fdwvalidator;
765 }
766
767 /*
768 * If options specified, validate and update.
769 */
770 if (stmt->options)
771 {
772 /* Extract the current options */
773 datum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID,
774 tp,
775 Anum_pg_foreign_data_wrapper_fdwoptions,
776 &isnull);
777 if (isnull)
778 datum = PointerGetDatum(NULL);
779
780 /* Transform the options */
781 datum = transformGenericOptions(ForeignDataWrapperRelationId,
782 datum,
783 stmt->options,
784 fdwvalidator);
785
786 if (DatumGetPointer(datum) != NULL)
787 repl_val[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = datum;
788 else
789 repl_null[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true;
790
791 repl_repl[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true;
792 }
793
794 /* Everything looks good - update the tuple */
796 repl_val, repl_null, repl_repl);
797
798 CatalogTupleUpdate(rel, &tp->t_self, tp);
799
800 heap_freetuple(tp);
801
802 ObjectAddressSet(myself, ForeignDataWrapperRelationId, fdwId);
803
804 /* Update function dependencies if we changed them */
805 if (handler_given || validator_given)
806 {
807 ObjectAddress referenced;
808
809 /*
810 * Flush all existing dependency records of this FDW on functions; we
811 * assume there can be none other than the ones we are fixing.
812 */
813 deleteDependencyRecordsForClass(ForeignDataWrapperRelationId,
814 fdwId,
815 ProcedureRelationId,
817
818 /* And build new ones. */
819
820 if (OidIsValid(fdwhandler))
821 {
822 referenced.classId = ProcedureRelationId;
823 referenced.objectId = fdwhandler;
824 referenced.objectSubId = 0;
825 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
826 }
827
828 if (OidIsValid(fdwvalidator))
829 {
830 referenced.classId = ProcedureRelationId;
831 referenced.objectId = fdwvalidator;
832 referenced.objectSubId = 0;
833 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
834 }
835 }
836
837 InvokeObjectPostAlterHook(ForeignDataWrapperRelationId, fdwId, 0);
838
840
841 return myself;
842}
843
844
845/*
846 * Create a foreign server
847 */
850{
851 Relation rel;
852 Datum srvoptions;
853 Datum values[Natts_pg_foreign_server];
854 bool nulls[Natts_pg_foreign_server];
855 HeapTuple tuple;
856 Oid srvId;
857 Oid ownerId;
858 AclResult aclresult;
859 ObjectAddress myself;
860 ObjectAddress referenced;
862
863 rel = table_open(ForeignServerRelationId, RowExclusiveLock);
864
865 /* For now the owner cannot be specified on create. Use effective user ID. */
866 ownerId = GetUserId();
867
868 /*
869 * Check that there is no other foreign server by this name. If there is
870 * one, do nothing if IF NOT EXISTS was specified.
871 */
872 srvId = get_foreign_server_oid(stmt->servername, true);
873 if (OidIsValid(srvId))
874 {
875 if (stmt->if_not_exists)
876 {
877 /*
878 * If we are in an extension script, insist that the pre-existing
879 * object be a member of the extension, to avoid security risks.
880 */
881 ObjectAddressSet(myself, ForeignServerRelationId, srvId);
883
884 /* OK to skip */
887 errmsg("server \"%s\" already exists, skipping",
888 stmt->servername)));
891 }
892 else
895 errmsg("server \"%s\" already exists",
896 stmt->servername)));
897 }
898
899 /*
900 * Check that the FDW exists and that we have USAGE on it. Also get the
901 * actual FDW for option validation etc.
902 */
903 fdw = GetForeignDataWrapperByName(stmt->fdwname, false);
904
905 aclresult = object_aclcheck(ForeignDataWrapperRelationId, fdw->fdwid, ownerId, ACL_USAGE);
906 if (aclresult != ACLCHECK_OK)
907 aclcheck_error(aclresult, OBJECT_FDW, fdw->fdwname);
908
909 /*
910 * Insert tuple into pg_foreign_server.
911 */
912 memset(values, 0, sizeof(values));
913 memset(nulls, false, sizeof(nulls));
914
915 srvId = GetNewOidWithIndex(rel, ForeignServerOidIndexId,
916 Anum_pg_foreign_server_oid);
917 values[Anum_pg_foreign_server_oid - 1] = ObjectIdGetDatum(srvId);
918 values[Anum_pg_foreign_server_srvname - 1] =
920 values[Anum_pg_foreign_server_srvowner - 1] = ObjectIdGetDatum(ownerId);
921 values[Anum_pg_foreign_server_srvfdw - 1] = ObjectIdGetDatum(fdw->fdwid);
922
923 /* Add server type if supplied */
924 if (stmt->servertype)
925 values[Anum_pg_foreign_server_srvtype - 1] =
926 CStringGetTextDatum(stmt->servertype);
927 else
928 nulls[Anum_pg_foreign_server_srvtype - 1] = true;
929
930 /* Add server version if supplied */
931 if (stmt->version)
932 values[Anum_pg_foreign_server_srvversion - 1] =
933 CStringGetTextDatum(stmt->version);
934 else
935 nulls[Anum_pg_foreign_server_srvversion - 1] = true;
936
937 /* Start with a blank acl */
938 nulls[Anum_pg_foreign_server_srvacl - 1] = true;
939
940 /* Add server options */
941 srvoptions = transformGenericOptions(ForeignServerRelationId,
942 PointerGetDatum(NULL),
943 stmt->options,
944 fdw->fdwvalidator);
945
946 if (DatumGetPointer(srvoptions) != NULL)
947 values[Anum_pg_foreign_server_srvoptions - 1] = srvoptions;
948 else
949 nulls[Anum_pg_foreign_server_srvoptions - 1] = true;
950
951 tuple = heap_form_tuple(rel->rd_att, values, nulls);
952
953 CatalogTupleInsert(rel, tuple);
954
955 heap_freetuple(tuple);
956
957 /* record dependencies */
958 myself.classId = ForeignServerRelationId;
959 myself.objectId = srvId;
960 myself.objectSubId = 0;
961
962 referenced.classId = ForeignDataWrapperRelationId;
963 referenced.objectId = fdw->fdwid;
964 referenced.objectSubId = 0;
965 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
966
967 recordDependencyOnOwner(ForeignServerRelationId, srvId, ownerId);
968
969 /* dependency on extension */
971
972 /* Post creation hook for new foreign server */
973 InvokeObjectPostCreateHook(ForeignServerRelationId, srvId, 0);
974
976
977 return myself;
978}
979
980
981/*
982 * Alter foreign server
983 */
986{
987 Relation rel;
988 HeapTuple tp;
989 Datum repl_val[Natts_pg_foreign_server];
990 bool repl_null[Natts_pg_foreign_server];
991 bool repl_repl[Natts_pg_foreign_server];
992 Oid srvId;
994 ObjectAddress address;
995
996 rel = table_open(ForeignServerRelationId, RowExclusiveLock);
997
998 tp = SearchSysCacheCopy1(FOREIGNSERVERNAME,
999 CStringGetDatum(stmt->servername));
1000
1001 if (!HeapTupleIsValid(tp))
1002 ereport(ERROR,
1003 (errcode(ERRCODE_UNDEFINED_OBJECT),
1004 errmsg("server \"%s\" does not exist", stmt->servername)));
1005
1006 srvForm = (Form_pg_foreign_server) GETSTRUCT(tp);
1007 srvId = srvForm->oid;
1008
1009 /*
1010 * Only owner or a superuser can ALTER a SERVER.
1011 */
1012 if (!object_ownercheck(ForeignServerRelationId, srvId, GetUserId()))
1014 stmt->servername);
1015
1016 memset(repl_val, 0, sizeof(repl_val));
1017 memset(repl_null, false, sizeof(repl_null));
1018 memset(repl_repl, false, sizeof(repl_repl));
1019
1020 if (stmt->has_version)
1021 {
1022 /*
1023 * Change the server VERSION string.
1024 */
1025 if (stmt->version)
1026 repl_val[Anum_pg_foreign_server_srvversion - 1] =
1027 CStringGetTextDatum(stmt->version);
1028 else
1029 repl_null[Anum_pg_foreign_server_srvversion - 1] = true;
1030
1031 repl_repl[Anum_pg_foreign_server_srvversion - 1] = true;
1032 }
1033
1034 if (stmt->options)
1035 {
1036 ForeignDataWrapper *fdw = GetForeignDataWrapper(srvForm->srvfdw);
1037 Datum datum;
1038 bool isnull;
1039
1040 /* Extract the current srvoptions */
1041 datum = SysCacheGetAttr(FOREIGNSERVEROID,
1042 tp,
1043 Anum_pg_foreign_server_srvoptions,
1044 &isnull);
1045 if (isnull)
1046 datum = PointerGetDatum(NULL);
1047
1048 /* Prepare the options array */
1049 datum = transformGenericOptions(ForeignServerRelationId,
1050 datum,
1051 stmt->options,
1052 fdw->fdwvalidator);
1053
1054 if (DatumGetPointer(datum) != NULL)
1055 repl_val[Anum_pg_foreign_server_srvoptions - 1] = datum;
1056 else
1057 repl_null[Anum_pg_foreign_server_srvoptions - 1] = true;
1058
1059 repl_repl[Anum_pg_foreign_server_srvoptions - 1] = true;
1060 }
1061
1062 /* Everything looks good - update the tuple */
1063 tp = heap_modify_tuple(tp, RelationGetDescr(rel),
1064 repl_val, repl_null, repl_repl);
1065
1066 CatalogTupleUpdate(rel, &tp->t_self, tp);
1067
1068 InvokeObjectPostAlterHook(ForeignServerRelationId, srvId, 0);
1069
1070 ObjectAddressSet(address, ForeignServerRelationId, srvId);
1071
1072 heap_freetuple(tp);
1073
1075
1076 return address;
1077}
1078
1079
1080/*
1081 * Common routine to check permission for user-mapping-related DDL
1082 * commands. We allow server owners to operate on any mapping, and
1083 * users to operate on their own mapping.
1084 */
1085static void
1086user_mapping_ddl_aclcheck(Oid umuserid, Oid serverid, const char *servername)
1087{
1088 Oid curuserid = GetUserId();
1089
1090 if (!object_ownercheck(ForeignServerRelationId, serverid, curuserid))
1091 {
1092 if (umuserid == curuserid)
1093 {
1094 AclResult aclresult;
1095
1096 aclresult = object_aclcheck(ForeignServerRelationId, serverid, curuserid, ACL_USAGE);
1097 if (aclresult != ACLCHECK_OK)
1098 aclcheck_error(aclresult, OBJECT_FOREIGN_SERVER, servername);
1099 }
1100 else
1102 servername);
1103 }
1104}
1105
1106
1107/*
1108 * Create user mapping
1109 */
1112{
1113 Relation rel;
1114 Datum useoptions;
1115 Datum values[Natts_pg_user_mapping];
1116 bool nulls[Natts_pg_user_mapping];
1117 HeapTuple tuple;
1118 Oid useId;
1119 Oid umId;
1120 ObjectAddress myself;
1121 ObjectAddress referenced;
1122 ForeignServer *srv;
1123 ForeignDataWrapper *fdw;
1124 RoleSpec *role = (RoleSpec *) stmt->user;
1125
1126 rel = table_open(UserMappingRelationId, RowExclusiveLock);
1127
1128 if (role->roletype == ROLESPEC_PUBLIC)
1129 useId = ACL_ID_PUBLIC;
1130 else
1131 useId = get_rolespec_oid(stmt->user, false);
1132
1133 /* Check that the server exists. */
1134 srv = GetForeignServerByName(stmt->servername, false);
1135
1136 user_mapping_ddl_aclcheck(useId, srv->serverid, stmt->servername);
1137
1138 /*
1139 * Check that the user mapping is unique within server.
1140 */
1141 umId = GetSysCacheOid2(USERMAPPINGUSERSERVER, Anum_pg_user_mapping_oid,
1142 ObjectIdGetDatum(useId),
1144
1145 if (OidIsValid(umId))
1146 {
1147 if (stmt->if_not_exists)
1148 {
1149 /*
1150 * Since user mappings aren't members of extensions (see comments
1151 * below), no need for checkMembershipInCurrentExtension here.
1152 */
1155 errmsg("user mapping for \"%s\" already exists for server \"%s\", skipping",
1156 MappingUserName(useId),
1157 stmt->servername)));
1158
1160 return InvalidObjectAddress;
1161 }
1162 else
1163 ereport(ERROR,
1165 errmsg("user mapping for \"%s\" already exists for server \"%s\"",
1166 MappingUserName(useId),
1167 stmt->servername)));
1168 }
1169
1170 fdw = GetForeignDataWrapper(srv->fdwid);
1171
1172 /*
1173 * Insert tuple into pg_user_mapping.
1174 */
1175 memset(values, 0, sizeof(values));
1176 memset(nulls, false, sizeof(nulls));
1177
1178 umId = GetNewOidWithIndex(rel, UserMappingOidIndexId,
1179 Anum_pg_user_mapping_oid);
1180 values[Anum_pg_user_mapping_oid - 1] = ObjectIdGetDatum(umId);
1181 values[Anum_pg_user_mapping_umuser - 1] = ObjectIdGetDatum(useId);
1182 values[Anum_pg_user_mapping_umserver - 1] = ObjectIdGetDatum(srv->serverid);
1183
1184 /* Add user options */
1185 useoptions = transformGenericOptions(UserMappingRelationId,
1186 PointerGetDatum(NULL),
1187 stmt->options,
1188 fdw->fdwvalidator);
1189
1190 if (DatumGetPointer(useoptions) != NULL)
1191 values[Anum_pg_user_mapping_umoptions - 1] = useoptions;
1192 else
1193 nulls[Anum_pg_user_mapping_umoptions - 1] = true;
1194
1195 tuple = heap_form_tuple(rel->rd_att, values, nulls);
1196
1197 CatalogTupleInsert(rel, tuple);
1198
1199 heap_freetuple(tuple);
1200
1201 /* Add dependency on the server */
1202 myself.classId = UserMappingRelationId;
1203 myself.objectId = umId;
1204 myself.objectSubId = 0;
1205
1206 referenced.classId = ForeignServerRelationId;
1207 referenced.objectId = srv->serverid;
1208 referenced.objectSubId = 0;
1209 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1210
1211 if (OidIsValid(useId))
1212 {
1213 /* Record the mapped user dependency */
1214 recordDependencyOnOwner(UserMappingRelationId, umId, useId);
1215 }
1216
1217 /*
1218 * Perhaps someday there should be a recordDependencyOnCurrentExtension
1219 * call here; but since roles aren't members of extensions, it seems like
1220 * user mappings shouldn't be either. Note that the grammar and pg_dump
1221 * would need to be extended too if we change this.
1222 */
1223
1224 /* Post creation hook for new user mapping */
1225 InvokeObjectPostCreateHook(UserMappingRelationId, umId, 0);
1226
1228
1229 return myself;
1230}
1231
1232
1233/*
1234 * Alter user mapping
1235 */
1238{
1239 Relation rel;
1240 HeapTuple tp;
1241 Datum repl_val[Natts_pg_user_mapping];
1242 bool repl_null[Natts_pg_user_mapping];
1243 bool repl_repl[Natts_pg_user_mapping];
1244 Oid useId;
1245 Oid umId;
1246 ForeignServer *srv;
1247 ObjectAddress address;
1248 RoleSpec *role = (RoleSpec *) stmt->user;
1249
1250 rel = table_open(UserMappingRelationId, RowExclusiveLock);
1251
1252 if (role->roletype == ROLESPEC_PUBLIC)
1253 useId = ACL_ID_PUBLIC;
1254 else
1255 useId = get_rolespec_oid(stmt->user, false);
1256
1257 srv = GetForeignServerByName(stmt->servername, false);
1258
1259 umId = GetSysCacheOid2(USERMAPPINGUSERSERVER, Anum_pg_user_mapping_oid,
1260 ObjectIdGetDatum(useId),
1262 if (!OidIsValid(umId))
1263 ereport(ERROR,
1264 (errcode(ERRCODE_UNDEFINED_OBJECT),
1265 errmsg("user mapping for \"%s\" does not exist for server \"%s\"",
1266 MappingUserName(useId), stmt->servername)));
1267
1268 user_mapping_ddl_aclcheck(useId, srv->serverid, stmt->servername);
1269
1270 tp = SearchSysCacheCopy1(USERMAPPINGOID, ObjectIdGetDatum(umId));
1271
1272 if (!HeapTupleIsValid(tp))
1273 elog(ERROR, "cache lookup failed for user mapping %u", umId);
1274
1275 memset(repl_val, 0, sizeof(repl_val));
1276 memset(repl_null, false, sizeof(repl_null));
1277 memset(repl_repl, false, sizeof(repl_repl));
1278
1279 if (stmt->options)
1280 {
1281 ForeignDataWrapper *fdw;
1282 Datum datum;
1283 bool isnull;
1284
1285 /*
1286 * Process the options.
1287 */
1288
1289 fdw = GetForeignDataWrapper(srv->fdwid);
1290
1291 datum = SysCacheGetAttr(USERMAPPINGUSERSERVER,
1292 tp,
1293 Anum_pg_user_mapping_umoptions,
1294 &isnull);
1295 if (isnull)
1296 datum = PointerGetDatum(NULL);
1297
1298 /* Prepare the options array */
1299 datum = transformGenericOptions(UserMappingRelationId,
1300 datum,
1301 stmt->options,
1302 fdw->fdwvalidator);
1303
1304 if (DatumGetPointer(datum) != NULL)
1305 repl_val[Anum_pg_user_mapping_umoptions - 1] = datum;
1306 else
1307 repl_null[Anum_pg_user_mapping_umoptions - 1] = true;
1308
1309 repl_repl[Anum_pg_user_mapping_umoptions - 1] = true;
1310 }
1311
1312 /* Everything looks good - update the tuple */
1313 tp = heap_modify_tuple(tp, RelationGetDescr(rel),
1314 repl_val, repl_null, repl_repl);
1315
1316 CatalogTupleUpdate(rel, &tp->t_self, tp);
1317
1318 InvokeObjectPostAlterHook(UserMappingRelationId,
1319 umId, 0);
1320
1321 ObjectAddressSet(address, UserMappingRelationId, umId);
1322
1323 heap_freetuple(tp);
1324
1326
1327 return address;
1328}
1329
1330
1331/*
1332 * Drop user mapping
1333 */
1334Oid
1336{
1337 ObjectAddress object;
1338 Oid useId;
1339 Oid umId;
1340 ForeignServer *srv;
1341 RoleSpec *role = (RoleSpec *) stmt->user;
1342
1343 if (role->roletype == ROLESPEC_PUBLIC)
1344 useId = ACL_ID_PUBLIC;
1345 else
1346 {
1347 useId = get_rolespec_oid(stmt->user, stmt->missing_ok);
1348 if (!OidIsValid(useId))
1349 {
1350 /*
1351 * IF EXISTS specified, role not found and not public. Notice this
1352 * and leave.
1353 */
1354 elog(NOTICE, "role \"%s\" does not exist, skipping",
1355 role->rolename);
1356 return InvalidOid;
1357 }
1358 }
1359
1360 srv = GetForeignServerByName(stmt->servername, true);
1361
1362 if (!srv)
1363 {
1364 if (!stmt->missing_ok)
1365 ereport(ERROR,
1366 (errcode(ERRCODE_UNDEFINED_OBJECT),
1367 errmsg("server \"%s\" does not exist",
1368 stmt->servername)));
1369 /* IF EXISTS, just note it */
1371 (errmsg("server \"%s\" does not exist, skipping",
1372 stmt->servername)));
1373 return InvalidOid;
1374 }
1375
1376 umId = GetSysCacheOid2(USERMAPPINGUSERSERVER, Anum_pg_user_mapping_oid,
1377 ObjectIdGetDatum(useId),
1379
1380 if (!OidIsValid(umId))
1381 {
1382 if (!stmt->missing_ok)
1383 ereport(ERROR,
1384 (errcode(ERRCODE_UNDEFINED_OBJECT),
1385 errmsg("user mapping for \"%s\" does not exist for server \"%s\"",
1386 MappingUserName(useId), stmt->servername)));
1387
1388 /* IF EXISTS specified, just note it */
1390 (errmsg("user mapping for \"%s\" does not exist for server \"%s\", skipping",
1391 MappingUserName(useId), stmt->servername)));
1392 return InvalidOid;
1393 }
1394
1396
1397 /*
1398 * Do the deletion
1399 */
1400 object.classId = UserMappingRelationId;
1401 object.objectId = umId;
1402 object.objectSubId = 0;
1403
1404 performDeletion(&object, DROP_CASCADE, 0);
1405
1406 return umId;
1407}
1408
1409
1410/*
1411 * Create a foreign table
1412 * call after DefineRelation().
1413 */
1414void
1416{
1417 Relation ftrel;
1418 Datum ftoptions;
1419 Datum values[Natts_pg_foreign_table];
1420 bool nulls[Natts_pg_foreign_table];
1421 HeapTuple tuple;
1422 AclResult aclresult;
1423 ObjectAddress myself;
1424 ObjectAddress referenced;
1425 Oid ownerId;
1426 ForeignDataWrapper *fdw;
1427 ForeignServer *server;
1428
1429 /*
1430 * Advance command counter to ensure the pg_attribute tuple is visible;
1431 * the tuple might be updated to add constraints in previous step.
1432 */
1434
1435 ftrel = table_open(ForeignTableRelationId, RowExclusiveLock);
1436
1437 /*
1438 * For now the owner cannot be specified on create. Use effective user ID.
1439 */
1440 ownerId = GetUserId();
1441
1442 /*
1443 * Check that the foreign server exists and that we have USAGE on it. Also
1444 * get the actual FDW for option validation etc.
1445 */
1446 server = GetForeignServerByName(stmt->servername, false);
1447 aclresult = object_aclcheck(ForeignServerRelationId, server->serverid, ownerId, ACL_USAGE);
1448 if (aclresult != ACLCHECK_OK)
1449 aclcheck_error(aclresult, OBJECT_FOREIGN_SERVER, server->servername);
1450
1451 fdw = GetForeignDataWrapper(server->fdwid);
1452
1453 /*
1454 * Insert tuple into pg_foreign_table.
1455 */
1456 memset(values, 0, sizeof(values));
1457 memset(nulls, false, sizeof(nulls));
1458
1459 values[Anum_pg_foreign_table_ftrelid - 1] = ObjectIdGetDatum(relid);
1460 values[Anum_pg_foreign_table_ftserver - 1] = ObjectIdGetDatum(server->serverid);
1461 /* Add table generic options */
1462 ftoptions = transformGenericOptions(ForeignTableRelationId,
1463 PointerGetDatum(NULL),
1464 stmt->options,
1465 fdw->fdwvalidator);
1466
1467 if (DatumGetPointer(ftoptions) != NULL)
1468 values[Anum_pg_foreign_table_ftoptions - 1] = ftoptions;
1469 else
1470 nulls[Anum_pg_foreign_table_ftoptions - 1] = true;
1471
1472 tuple = heap_form_tuple(ftrel->rd_att, values, nulls);
1473
1474 CatalogTupleInsert(ftrel, tuple);
1475
1476 heap_freetuple(tuple);
1477
1478 /* Add pg_class dependency on the server */
1479 myself.classId = RelationRelationId;
1480 myself.objectId = relid;
1481 myself.objectSubId = 0;
1482
1483 referenced.classId = ForeignServerRelationId;
1484 referenced.objectId = server->serverid;
1485 referenced.objectSubId = 0;
1486 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1487
1489}
1490
1491/*
1492 * Import a foreign schema
1493 */
1494void
1496{
1497 ForeignServer *server;
1498 ForeignDataWrapper *fdw;
1499 FdwRoutine *fdw_routine;
1500 AclResult aclresult;
1501 List *cmd_list;
1502 ListCell *lc;
1503
1504 /* Check that the foreign server exists and that we have USAGE on it */
1505 server = GetForeignServerByName(stmt->server_name, false);
1506 aclresult = object_aclcheck(ForeignServerRelationId, server->serverid, GetUserId(), ACL_USAGE);
1507 if (aclresult != ACLCHECK_OK)
1508 aclcheck_error(aclresult, OBJECT_FOREIGN_SERVER, server->servername);
1509
1510 /* Check that the schema exists and we have CREATE permissions on it */
1511 (void) LookupCreationNamespace(stmt->local_schema);
1512
1513 /* Get the FDW and check it supports IMPORT */
1514 fdw = GetForeignDataWrapper(server->fdwid);
1515 if (!OidIsValid(fdw->fdwhandler))
1516 ereport(ERROR,
1517 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1518 errmsg("foreign-data wrapper \"%s\" has no handler",
1519 fdw->fdwname)));
1520 fdw_routine = GetFdwRoutine(fdw->fdwhandler);
1521 if (fdw_routine->ImportForeignSchema == NULL)
1522 ereport(ERROR,
1523 (errcode(ERRCODE_FDW_NO_SCHEMAS),
1524 errmsg("foreign-data wrapper \"%s\" does not support IMPORT FOREIGN SCHEMA",
1525 fdw->fdwname)));
1526
1527 /* Call FDW to get a list of commands */
1528 cmd_list = fdw_routine->ImportForeignSchema(stmt, server->serverid);
1529
1530 /* Parse and execute each command */
1531 foreach(lc, cmd_list)
1532 {
1533 char *cmd = (char *) lfirst(lc);
1534 import_error_callback_arg callback_arg;
1535 ErrorContextCallback sqlerrcontext;
1536 List *raw_parsetree_list;
1537 ListCell *lc2;
1538
1539 /*
1540 * Setup error traceback support for ereport(). This is so that any
1541 * error in the generated SQL will be displayed nicely.
1542 */
1543 callback_arg.tablename = NULL; /* not known yet */
1544 callback_arg.cmd = cmd;
1545 sqlerrcontext.callback = import_error_callback;
1546 sqlerrcontext.arg = &callback_arg;
1547 sqlerrcontext.previous = error_context_stack;
1548 error_context_stack = &sqlerrcontext;
1549
1550 /*
1551 * Parse the SQL string into a list of raw parse trees.
1552 */
1553 raw_parsetree_list = pg_parse_query(cmd);
1554
1555 /*
1556 * Process each parse tree (we allow the FDW to put more than one
1557 * command per string, though this isn't really advised).
1558 */
1559 foreach(lc2, raw_parsetree_list)
1560 {
1561 RawStmt *rs = lfirst_node(RawStmt, lc2);
1563 PlannedStmt *pstmt;
1564
1565 /*
1566 * Because we only allow CreateForeignTableStmt, we can skip parse
1567 * analysis, rewrite, and planning steps here.
1568 */
1569 if (!IsA(cstmt, CreateForeignTableStmt))
1570 elog(ERROR,
1571 "foreign-data wrapper \"%s\" returned incorrect statement type %d",
1572 fdw->fdwname, (int) nodeTag(cstmt));
1573
1574 /* Ignore commands for tables excluded by filter options */
1576 continue;
1577
1578 /* Enable reporting of current table's name on error */
1579 callback_arg.tablename = cstmt->base.relation->relname;
1580
1581 /* Ensure creation schema is the one given in IMPORT statement */
1582 cstmt->base.relation->schemaname = pstrdup(stmt->local_schema);
1583
1584 /* No planning needed, just make a wrapper PlannedStmt */
1585 pstmt = makeNode(PlannedStmt);
1586 pstmt->commandType = CMD_UTILITY;
1587 pstmt->canSetTag = false;
1588 pstmt->utilityStmt = (Node *) cstmt;
1589 pstmt->stmt_location = rs->stmt_location;
1590 pstmt->stmt_len = rs->stmt_len;
1591 pstmt->planOrigin = PLAN_STMT_INTERNAL;
1592
1593 /* Execute statement */
1594 ProcessUtility(pstmt, cmd, false,
1595 PROCESS_UTILITY_SUBCOMMAND, NULL, NULL,
1596 None_Receiver, NULL);
1597
1598 /* Be sure to advance the command counter between subcommands */
1600
1601 callback_arg.tablename = NULL;
1602 }
1603
1604 error_context_stack = sqlerrcontext.previous;
1605 }
1606}
1607
1608/*
1609 * error context callback to let us supply the failing SQL statement's text
1610 */
1611static void
1613{
1615 int syntaxerrposition;
1616
1617 /* If it's a syntax error, convert to internal syntax error report */
1618 syntaxerrposition = geterrposition();
1619 if (syntaxerrposition > 0)
1620 {
1621 errposition(0);
1622 internalerrposition(syntaxerrposition);
1623 internalerrquery(callback_arg->cmd);
1624 }
1625
1626 if (callback_arg->tablename)
1627 errcontext("importing foreign table \"%s\"",
1628 callback_arg->tablename);
1629}
Acl * aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
Definition: acl.c:1119
void check_can_set_role(Oid member, Oid role)
Definition: acl.c:5341
Oid get_rolespec_oid(const RoleSpec *role, bool missing_ok)
Definition: acl.c:5586
AclResult
Definition: acl.h:182
@ ACLCHECK_OK
Definition: acl.h:183
@ ACLCHECK_NOT_OWNER
Definition: acl.h:185
#define DatumGetAclP(X)
Definition: acl.h:120
#define ACL_ID_PUBLIC
Definition: acl.h:46
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:2652
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:3834
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4088
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5350
ArrayType * construct_empty_array(Oid elmtype)
Definition: arrayfuncs.c:3580
Datum makeArrayResult(ArrayBuildState *astate, MemoryContext rcontext)
Definition: arrayfuncs.c:5420
static Datum values[MAXATTR]
Definition: bootstrap.c:153
#define CStringGetTextDatum(s)
Definition: builtins.h:97
#define NameStr(name)
Definition: c.h:752
#define VARHDRSZ
Definition: c.h:698
#define OidIsValid(objectId)
Definition: c.h:775
size_t Size
Definition: c.h:611
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:448
char * defGetString(DefElem *def)
Definition: define.c:35
void errorConflictingDefElem(DefElem *defel, ParseState *pstate)
Definition: define.c:371
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition: dependency.c:273
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
DestReceiver * None_Receiver
Definition: dest.c:96
int internalerrquery(const char *query)
Definition: elog.c:1507
int internalerrposition(int cursorpos)
Definition: elog.c:1487
ErrorContextCallback * error_context_stack
Definition: elog.c:95
int errhint(const char *fmt,...)
Definition: elog.c:1321
int geterrposition(void)
Definition: elog.c:1603
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
int errposition(int cursorpos)
Definition: elog.c:1471
#define errcontext
Definition: elog.h:198
#define WARNING
Definition: elog.h:36
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
#define NOTICE
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:150
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:682
#define OidFunctionCall2(functionId, arg1, arg2)
Definition: fmgr.h:722
ForeignDataWrapper * GetForeignDataWrapper(Oid fdwid)
Definition: foreign.c:38
ForeignServer * GetForeignServerByName(const char *srvname, bool missing_ok)
Definition: foreign.c:183
Oid get_foreign_server_oid(const char *servername, bool missing_ok)
Definition: foreign.c:705
ForeignDataWrapper * GetForeignDataWrapperByName(const char *fdwname, bool missing_ok)
Definition: foreign.c:97
bool IsImportableForeignTable(const char *tablename, ImportForeignSchemaStmt *stmt)
Definition: foreign.c:483
FdwRoutine * GetFdwRoutine(Oid fdwhandler)
Definition: foreign.c:326
#define MappingUserName(userid)
Definition: foreign.h:20
static void AlterForeignServerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
Definition: foreigncmds.c:349
static Oid lookup_fdw_handler_func(DefElem *handler)
Definition: foreigncmds.c:486
ObjectAddress AlterForeignServerOwner(const char *name, Oid newOwnerId)
Definition: foreigncmds.c:426
static void import_error_callback(void *arg)
Definition: foreigncmds.c:1612
void AlterForeignServerOwner_oid(Oid srvId, Oid newOwnerId)
Definition: foreigncmds.c:461
void ImportForeignSchema(ImportForeignSchemaStmt *stmt)
Definition: foreigncmds.c:1495
ObjectAddress AlterForeignDataWrapperOwner(const char *name, Oid newOwnerId)
Definition: foreigncmds.c:286
ObjectAddress AlterForeignServer(AlterForeignServerStmt *stmt)
Definition: foreigncmds.c:985
static Datum optionListToArray(List *options)
Definition: foreigncmds.c:66
static void AlterForeignDataWrapperOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
Definition: foreigncmds.c:216
static Oid lookup_fdw_validator_func(DefElem *validator)
Definition: foreigncmds.c:510
void AlterForeignDataWrapperOwner_oid(Oid fwdId, Oid newOwnerId)
Definition: foreigncmds.c:324
static void user_mapping_ddl_aclcheck(Oid umuserid, Oid serverid, const char *servername)
Definition: foreigncmds.c:1086
ObjectAddress AlterForeignDataWrapper(ParseState *pstate, AlterFdwStmt *stmt)
Definition: foreigncmds.c:685
ObjectAddress CreateForeignServer(CreateForeignServerStmt *stmt)
Definition: foreigncmds.c:849
Oid RemoveUserMapping(DropUserMappingStmt *stmt)
Definition: foreigncmds.c:1335
ObjectAddress CreateForeignDataWrapper(ParseState *pstate, CreateFdwStmt *stmt)
Definition: foreigncmds.c:569
static void parse_func_options(ParseState *pstate, List *func_options, bool *handler_given, Oid *fdwhandler, bool *validator_given, Oid *fdwvalidator)
Definition: foreigncmds.c:529
ObjectAddress AlterUserMapping(AlterUserMappingStmt *stmt)
Definition: foreigncmds.c:1237
void CreateForeignTable(CreateForeignTableStmt *stmt, Oid relid)
Definition: foreigncmds.c:1415
Datum transformGenericOptions(Oid catalogId, Datum oldOptions, List *options, Oid fdwvalidator)
Definition: foreigncmds.c:121
ObjectAddress CreateUserMapping(CreateUserMappingStmt *stmt)
Definition: foreigncmds.c:1111
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, const Datum *replValues, const bool *replIsnull, const bool *doReplace)
Definition: heaptuple.c:1210
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1117
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1435
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:904
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
#define stmt
Definition: indent_codes.h:59
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:313
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:233
static struct @166 value
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:81
List * lappend(List *list, void *datum)
Definition: list.c:339
List * list_delete_cell(List *list, ListCell *cell)
Definition: list.c:841
#define RowExclusiveLock
Definition: lockdefs.h:38
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1822
char * pstrdup(const char *in)
Definition: mcxt.c:1759
void * palloc(Size size)
Definition: mcxt.c:1365
MemoryContext CurrentMemoryContext
Definition: mcxt.c:160
Oid GetUserId(void)
Definition: miscinit.c:469
Datum namein(PG_FUNCTION_ARGS)
Definition: name.c:48
char * NameListToString(const List *names)
Definition: namespace.c:3661
Oid LookupCreationNamespace(const char *nspname)
Definition: namespace.c:3495
#define IsA(nodeptr, _type_)
Definition: nodes.h:164
#define nodeTag(nodeptr)
Definition: nodes.h:139
@ CMD_UTILITY
Definition: nodes.h:280
#define makeNode(_type_)
Definition: nodes.h:161
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:173
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:197
const ObjectAddress InvalidObjectAddress
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
Definition: parse_func.c:2260
@ ROLESPEC_PUBLIC
Definition: parsenodes.h:422
#define ACL_USAGE
Definition: parsenodes.h:84
@ DEFELEM_UNSPEC
Definition: parsenodes.h:831
@ DEFELEM_DROP
Definition: parsenodes.h:834
@ DEFELEM_SET
Definition: parsenodes.h:832
@ DEFELEM_ADD
Definition: parsenodes.h:833
@ DROP_CASCADE
Definition: parsenodes.h:2396
@ OBJECT_FDW
Definition: parsenodes.h:2338
@ OBJECT_FOREIGN_SERVER
Definition: parsenodes.h:2339
void * arg
const void size_t len
void checkMembershipInCurrentExtension(const ObjectAddress *object)
Definition: pg_depend.c:258
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:45
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition: pg_depend.c:351
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition: pg_depend.c:193
FormData_pg_foreign_data_wrapper * Form_pg_foreign_data_wrapper
FormData_pg_foreign_server * Form_pg_foreign_server
#define lfirst(lc)
Definition: pg_list.h:172
#define lfirst_node(type, lc)
Definition: pg_list.h:176
void changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
Definition: pg_shdepend.c:316
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:168
@ PLAN_STMT_INTERNAL
Definition: plannodes.h:40
#define sprintf
Definition: port.h:241
List * pg_parse_query(const char *query_string)
Definition: postgres.c:603
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:332
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:262
uint64_t Datum
Definition: postgres.h:70
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:322
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:360
#define InvalidOid
Definition: postgres_ext.h:37
unsigned int Oid
Definition: postgres_ext.h:32
#define RelationGetDescr(relation)
Definition: rel.h:540
List * untransformRelOptions(Datum options)
Definition: reloptions.c:1351
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:30
RangeVar * relation
Definition: parsenodes.h:2747
DefElemAction defaction
Definition: parsenodes.h:844
char * defname
Definition: parsenodes.h:841
Node * arg
Definition: parsenodes.h:842
struct ErrorContextCallback * previous
Definition: elog.h:297
void(* callback)(void *arg)
Definition: elog.h:298
ImportForeignSchema_function ImportForeignSchema
Definition: fdwapi.h:260
char * fdwname
Definition: foreign.h:28
char * servername
Definition: foreign.h:39
Oid serverid
Definition: foreign.h:36
ItemPointerData t_self
Definition: htup.h:65
Definition: pg_list.h:54
Definition: nodes.h:135
char * relname
Definition: primnodes.h:83
char * schemaname
Definition: primnodes.h:80
ParseLoc stmt_location
Definition: parsenodes.h:2087
ParseLoc stmt_len
Definition: parsenodes.h:2088
Node * stmt
Definition: parsenodes.h:2086
TupleDesc rd_att
Definition: rel.h:112
RoleSpecType roletype
Definition: parsenodes.h:428
char * rolename
Definition: parsenodes.h:429
Definition: c.h:693
bool superuser_arg(Oid roleid)
Definition: superuser.c:56
bool superuser(void)
Definition: superuser.c:46
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:595
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:91
#define GetSysCacheOid2(cacheId, oidcol, key1, key2)
Definition: syscache.h:111
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
void ProcessUtility(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc)
Definition: utility.c:499
@ PROCESS_UTILITY_SUBCOMMAND
Definition: utility.h:26
static char * VARDATA(const void *PTR)
Definition: varatt.h:305
static void SET_VARSIZE(void *PTR, Size len)
Definition: varatt.h:432
const char * name
void CommandCounterIncrement(void)
Definition: xact.c:1100