]> granicus.if.org Git - postgresql/blob - src/backend/commands/foreigncmds.c
Run pgindent on 9.2 source tree in preparation for first 9.3
[postgresql] / src / backend / commands / foreigncmds.c
1 /*-------------------------------------------------------------------------
2  *
3  * foreigncmds.c
4  *        foreign-data wrapper/server creation/manipulation commands
5  *
6  * Portions Copyright (c) 1996-2012, 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/heapam.h"
17 #include "access/xact.h"
18 #include "access/reloptions.h"
19 #include "catalog/dependency.h"
20 #include "catalog/indexing.h"
21 #include "catalog/objectaccess.h"
22 #include "catalog/pg_foreign_data_wrapper.h"
23 #include "catalog/pg_foreign_server.h"
24 #include "catalog/pg_foreign_table.h"
25 #include "catalog/pg_proc.h"
26 #include "catalog/pg_type.h"
27 #include "catalog/pg_user_mapping.h"
28 #include "commands/defrem.h"
29 #include "foreign/foreign.h"
30 #include "miscadmin.h"
31 #include "parser/parse_func.h"
32 #include "utils/acl.h"
33 #include "utils/builtins.h"
34 #include "utils/lsyscache.h"
35 #include "utils/rel.h"
36 #include "utils/syscache.h"
37
38
39 /*
40  * Convert a DefElem list to the text array format that is used in
41  * pg_foreign_data_wrapper, pg_foreign_server, and pg_user_mapping.
42  * Returns the array in the form of a Datum, or PointerGetDatum(NULL)
43  * if the list is empty.
44  *
45  * Note: The array is usually stored to database without further
46  * processing, hence any validation should be done before this
47  * conversion.
48  */
49 static Datum
50 optionListToArray(List *options)
51 {
52         ArrayBuildState *astate = NULL;
53         ListCell   *cell;
54
55         foreach(cell, options)
56         {
57                 DefElem    *def = lfirst(cell);
58                 const char *value;
59                 Size            len;
60                 text       *t;
61
62                 value = defGetString(def);
63                 len = VARHDRSZ + strlen(def->defname) + 1 + strlen(value);
64                 t = palloc(len + 1);
65                 SET_VARSIZE(t, len);
66                 sprintf(VARDATA(t), "%s=%s", def->defname, value);
67
68                 astate = accumArrayResult(astate, PointerGetDatum(t),
69                                                                   false, TEXTOID,
70                                                                   CurrentMemoryContext);
71         }
72
73         if (astate)
74                 return makeArrayResult(astate, CurrentMemoryContext);
75
76         return PointerGetDatum(NULL);
77 }
78
79
80 /*
81  * Transform a list of DefElem into text array format.  This is substantially
82  * the same thing as optionListToArray(), except we recognize SET/ADD/DROP
83  * actions for modifying an existing list of options, which is passed in
84  * Datum form as oldOptions.  Also, if fdwvalidator isn't InvalidOid
85  * it specifies a validator function to call on the result.
86  *
87  * Returns the array in the form of a Datum, or PointerGetDatum(NULL)
88  * if the list is empty.
89  *
90  * This is used by CREATE/ALTER of FOREIGN DATA WRAPPER/SERVER/USER MAPPING.
91  */
92 Datum
93 transformGenericOptions(Oid catalogId,
94                                                 Datum oldOptions,
95                                                 List *options,
96                                                 Oid fdwvalidator)
97 {
98         List       *resultOptions = untransformRelOptions(oldOptions);
99         ListCell   *optcell;
100         Datum           result;
101
102         foreach(optcell, options)
103         {
104                 DefElem    *od = lfirst(optcell);
105                 ListCell   *cell;
106                 ListCell   *prev = NULL;
107
108                 /*
109                  * Find the element in resultOptions.  We need this for validation in
110                  * all cases.  Also identify the previous element.
111                  */
112                 foreach(cell, resultOptions)
113                 {
114                         DefElem    *def = lfirst(cell);
115
116                         if (strcmp(def->defname, od->defname) == 0)
117                                 break;
118                         else
119                                 prev = cell;
120                 }
121
122                 /*
123                  * It is possible to perform multiple SET/DROP actions on the same
124                  * option.      The standard permits this, as long as the options to be
125                  * added are unique.  Note that an unspecified action is taken to be
126                  * ADD.
127                  */
128                 switch (od->defaction)
129                 {
130                         case DEFELEM_DROP:
131                                 if (!cell)
132                                         ereport(ERROR,
133                                                         (errcode(ERRCODE_UNDEFINED_OBJECT),
134                                                          errmsg("option \"%s\" not found",
135                                                                         od->defname)));
136                                 resultOptions = list_delete_cell(resultOptions, cell, prev);
137                                 break;
138
139                         case DEFELEM_SET:
140                                 if (!cell)
141                                         ereport(ERROR,
142                                                         (errcode(ERRCODE_UNDEFINED_OBJECT),
143                                                          errmsg("option \"%s\" not found",
144                                                                         od->defname)));
145                                 lfirst(cell) = od;
146                                 break;
147
148                         case DEFELEM_ADD:
149                         case DEFELEM_UNSPEC:
150                                 if (cell)
151                                         ereport(ERROR,
152                                                         (errcode(ERRCODE_DUPLICATE_OBJECT),
153                                                          errmsg("option \"%s\" provided more than once",
154                                                                         od->defname)));
155                                 resultOptions = lappend(resultOptions, od);
156                                 break;
157
158                         default:
159                                 elog(ERROR, "unrecognized action %d on option \"%s\"",
160                                          (int) od->defaction, od->defname);
161                                 break;
162                 }
163         }
164
165         result = optionListToArray(resultOptions);
166
167         if (OidIsValid(fdwvalidator))
168         {
169                 Datum           valarg = result;
170
171                 /*
172                  * Pass a null options list as an empty array, so that validators
173                  * don't have to be declared non-strict to handle the case.
174                  */
175                 if (DatumGetPointer(valarg) == NULL)
176                         valarg = PointerGetDatum(construct_empty_array(TEXTOID));
177                 OidFunctionCall2(fdwvalidator, valarg, ObjectIdGetDatum(catalogId));
178         }
179
180         return result;
181 }
182
183
184 /*
185  * Convert the user mapping user name to OID
186  */
187 static Oid
188 GetUserOidFromMapping(const char *username, bool missing_ok)
189 {
190         if (!username)
191                 /* PUBLIC user mapping */
192                 return InvalidOid;
193
194         if (strcmp(username, "current_user") == 0)
195                 /* map to the owner */
196                 return GetUserId();
197
198         /* map to provided user */
199         return get_role_oid(username, missing_ok);
200 }
201
202
203 /*
204  * Rename foreign-data wrapper
205  */
206 void
207 RenameForeignDataWrapper(const char *oldname, const char *newname)
208 {
209         HeapTuple       tup;
210         Relation        rel;
211
212         rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
213
214         tup = SearchSysCacheCopy1(FOREIGNDATAWRAPPERNAME, CStringGetDatum(oldname));
215         if (!HeapTupleIsValid(tup))
216                 ereport(ERROR,
217                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
218                          errmsg("foreign-data wrapper \"%s\" does not exist", oldname)));
219
220         /* make sure the new name doesn't exist */
221         if (SearchSysCacheExists1(FOREIGNDATAWRAPPERNAME, CStringGetDatum(newname)))
222                 ereport(ERROR,
223                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
224                          errmsg("foreign-data wrapper \"%s\" already exists", newname)));
225
226         /* must be owner of FDW */
227         if (!pg_foreign_data_wrapper_ownercheck(HeapTupleGetOid(tup), GetUserId()))
228                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FDW,
229                                            oldname);
230
231         /* rename */
232         namestrcpy(&(((Form_pg_foreign_data_wrapper) GETSTRUCT(tup))->fdwname), newname);
233         simple_heap_update(rel, &tup->t_self, tup);
234         CatalogUpdateIndexes(rel, tup);
235
236         heap_close(rel, NoLock);
237         heap_freetuple(tup);
238 }
239
240
241 /*
242  * Rename foreign server
243  */
244 void
245 RenameForeignServer(const char *oldname, const char *newname)
246 {
247         HeapTuple       tup;
248         Relation        rel;
249
250         rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
251
252         tup = SearchSysCacheCopy1(FOREIGNSERVERNAME, CStringGetDatum(oldname));
253         if (!HeapTupleIsValid(tup))
254                 ereport(ERROR,
255                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
256                                  errmsg("server \"%s\" does not exist", oldname)));
257
258         /* make sure the new name doesn't exist */
259         if (SearchSysCacheExists1(FOREIGNSERVERNAME, CStringGetDatum(newname)))
260                 ereport(ERROR,
261                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
262                                  errmsg("server \"%s\" already exists", newname)));
263
264         /* must be owner of server */
265         if (!pg_foreign_server_ownercheck(HeapTupleGetOid(tup), GetUserId()))
266                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
267                                            oldname);
268
269         /* rename */
270         namestrcpy(&(((Form_pg_foreign_server) GETSTRUCT(tup))->srvname), newname);
271         simple_heap_update(rel, &tup->t_self, tup);
272         CatalogUpdateIndexes(rel, tup);
273
274         heap_close(rel, NoLock);
275         heap_freetuple(tup);
276 }
277
278
279 /*
280  * Internal workhorse for changing a data wrapper's owner.
281  *
282  * Allow this only for superusers; also the new owner must be a
283  * superuser.
284  */
285 static void
286 AlterForeignDataWrapperOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
287 {
288         Form_pg_foreign_data_wrapper form;
289
290         form = (Form_pg_foreign_data_wrapper) GETSTRUCT(tup);
291
292         /* Must be a superuser to change a FDW owner */
293         if (!superuser())
294                 ereport(ERROR,
295                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
296                                  errmsg("permission denied to change owner of foreign-data wrapper \"%s\"",
297                                                 NameStr(form->fdwname)),
298                                  errhint("Must be superuser to change owner of a foreign-data wrapper.")));
299
300         /* New owner must also be a superuser */
301         if (!superuser_arg(newOwnerId))
302                 ereport(ERROR,
303                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
304                                  errmsg("permission denied to change owner of foreign-data wrapper \"%s\"",
305                                                 NameStr(form->fdwname)),
306                 errhint("The owner of a foreign-data wrapper must be a superuser.")));
307
308         if (form->fdwowner != newOwnerId)
309         {
310                 form->fdwowner = newOwnerId;
311
312                 simple_heap_update(rel, &tup->t_self, tup);
313                 CatalogUpdateIndexes(rel, tup);
314
315                 /* Update owner dependency reference */
316                 changeDependencyOnOwner(ForeignDataWrapperRelationId,
317                                                                 HeapTupleGetOid(tup),
318                                                                 newOwnerId);
319         }
320 }
321
322 /*
323  * Change foreign-data wrapper owner -- by name
324  *
325  * Note restrictions in the "_internal" function, above.
326  */
327 void
328 AlterForeignDataWrapperOwner(const char *name, Oid newOwnerId)
329 {
330         HeapTuple       tup;
331         Relation        rel;
332
333         rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
334
335         tup = SearchSysCacheCopy1(FOREIGNDATAWRAPPERNAME, CStringGetDatum(name));
336
337         if (!HeapTupleIsValid(tup))
338                 ereport(ERROR,
339                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
340                                  errmsg("foreign-data wrapper \"%s\" does not exist", name)));
341
342         AlterForeignDataWrapperOwner_internal(rel, tup, newOwnerId);
343
344         heap_freetuple(tup);
345
346         heap_close(rel, RowExclusiveLock);
347 }
348
349 /*
350  * Change foreign-data wrapper owner -- by OID
351  *
352  * Note restrictions in the "_internal" function, above.
353  */
354 void
355 AlterForeignDataWrapperOwner_oid(Oid fwdId, Oid newOwnerId)
356 {
357         HeapTuple       tup;
358         Relation        rel;
359
360         rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
361
362         tup = SearchSysCacheCopy1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fwdId));
363
364         if (!HeapTupleIsValid(tup))
365                 ereport(ERROR,
366                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
367                   errmsg("foreign-data wrapper with OID %u does not exist", fwdId)));
368
369         AlterForeignDataWrapperOwner_internal(rel, tup, newOwnerId);
370
371         heap_freetuple(tup);
372
373         heap_close(rel, RowExclusiveLock);
374 }
375
376 /*
377  * Internal workhorse for changing a foreign server's owner
378  */
379 static void
380 AlterForeignServerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
381 {
382         Form_pg_foreign_server form;
383
384         form = (Form_pg_foreign_server) GETSTRUCT(tup);
385
386         if (form->srvowner != newOwnerId)
387         {
388                 /* Superusers can always do it */
389                 if (!superuser())
390                 {
391                         Oid                     srvId;
392                         AclResult       aclresult;
393
394                         srvId = HeapTupleGetOid(tup);
395
396                         /* Must be owner */
397                         if (!pg_foreign_server_ownercheck(srvId, GetUserId()))
398                                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
399                                                            NameStr(form->srvname));
400
401                         /* Must be able to become new owner */
402                         check_is_member_of_role(GetUserId(), newOwnerId);
403
404                         /* New owner must have USAGE privilege on foreign-data wrapper */
405                         aclresult = pg_foreign_data_wrapper_aclcheck(form->srvfdw, newOwnerId, ACL_USAGE);
406                         if (aclresult != ACLCHECK_OK)
407                         {
408                                 ForeignDataWrapper *fdw = GetForeignDataWrapper(form->srvfdw);
409
410                                 aclcheck_error(aclresult, ACL_KIND_FDW, fdw->fdwname);
411                         }
412                 }
413
414                 form->srvowner = newOwnerId;
415
416                 simple_heap_update(rel, &tup->t_self, tup);
417                 CatalogUpdateIndexes(rel, tup);
418
419                 /* Update owner dependency reference */
420                 changeDependencyOnOwner(ForeignServerRelationId, HeapTupleGetOid(tup),
421                                                                 newOwnerId);
422         }
423 }
424
425 /*
426  * Change foreign server owner -- by name
427  */
428 void
429 AlterForeignServerOwner(const char *name, Oid newOwnerId)
430 {
431         HeapTuple       tup;
432         Relation        rel;
433
434         rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
435
436         tup = SearchSysCacheCopy1(FOREIGNSERVERNAME, CStringGetDatum(name));
437
438         if (!HeapTupleIsValid(tup))
439                 ereport(ERROR,
440                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
441                                  errmsg("server \"%s\" does not exist", name)));
442
443         AlterForeignServerOwner_internal(rel, tup, newOwnerId);
444
445         heap_freetuple(tup);
446
447         heap_close(rel, RowExclusiveLock);
448 }
449
450 /*
451  * Change foreign server owner -- by OID
452  */
453 void
454 AlterForeignServerOwner_oid(Oid srvId, Oid newOwnerId)
455 {
456         HeapTuple       tup;
457         Relation        rel;
458
459         rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
460
461         tup = SearchSysCacheCopy1(FOREIGNSERVEROID, ObjectIdGetDatum(srvId));
462
463         if (!HeapTupleIsValid(tup))
464                 ereport(ERROR,
465                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
466                                  errmsg("foreign server with OID %u does not exist", srvId)));
467
468         AlterForeignServerOwner_internal(rel, tup, newOwnerId);
469
470         heap_freetuple(tup);
471
472         heap_close(rel, RowExclusiveLock);
473 }
474
475 /*
476  * Convert a handler function name passed from the parser to an Oid.
477  */
478 static Oid
479 lookup_fdw_handler_func(DefElem *handler)
480 {
481         Oid                     handlerOid;
482
483         if (handler == NULL || handler->arg == NULL)
484                 return InvalidOid;
485
486         /* handlers have no arguments */
487         handlerOid = LookupFuncName((List *) handler->arg, 0, NULL, false);
488
489         /* check that handler has correct return type */
490         if (get_func_rettype(handlerOid) != FDW_HANDLEROID)
491                 ereport(ERROR,
492                                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
493                                  errmsg("function %s must return type \"fdw_handler\"",
494                                                 NameListToString((List *) handler->arg))));
495
496         return handlerOid;
497 }
498
499 /*
500  * Convert a validator function name passed from the parser to an Oid.
501  */
502 static Oid
503 lookup_fdw_validator_func(DefElem *validator)
504 {
505         Oid                     funcargtypes[2];
506
507         if (validator == NULL || validator->arg == NULL)
508                 return InvalidOid;
509
510         /* validators take text[], oid */
511         funcargtypes[0] = TEXTARRAYOID;
512         funcargtypes[1] = OIDOID;
513
514         return LookupFuncName((List *) validator->arg, 2, funcargtypes, false);
515         /* validator's return value is ignored, so we don't check the type */
516 }
517
518 /*
519  * Process function options of CREATE/ALTER FDW
520  */
521 static void
522 parse_func_options(List *func_options,
523                                    bool *handler_given, Oid *fdwhandler,
524                                    bool *validator_given, Oid *fdwvalidator)
525 {
526         ListCell   *cell;
527
528         *handler_given = false;
529         *validator_given = false;
530         /* return InvalidOid if not given */
531         *fdwhandler = InvalidOid;
532         *fdwvalidator = InvalidOid;
533
534         foreach(cell, func_options)
535         {
536                 DefElem    *def = (DefElem *) lfirst(cell);
537
538                 if (strcmp(def->defname, "handler") == 0)
539                 {
540                         if (*handler_given)
541                                 ereport(ERROR,
542                                                 (errcode(ERRCODE_SYNTAX_ERROR),
543                                                  errmsg("conflicting or redundant options")));
544                         *handler_given = true;
545                         *fdwhandler = lookup_fdw_handler_func(def);
546                 }
547                 else if (strcmp(def->defname, "validator") == 0)
548                 {
549                         if (*validator_given)
550                                 ereport(ERROR,
551                                                 (errcode(ERRCODE_SYNTAX_ERROR),
552                                                  errmsg("conflicting or redundant options")));
553                         *validator_given = true;
554                         *fdwvalidator = lookup_fdw_validator_func(def);
555                 }
556                 else
557                         elog(ERROR, "option \"%s\" not recognized",
558                                  def->defname);
559         }
560 }
561
562 /*
563  * Create a foreign-data wrapper
564  */
565 void
566 CreateForeignDataWrapper(CreateFdwStmt *stmt)
567 {
568         Relation        rel;
569         Datum           values[Natts_pg_foreign_data_wrapper];
570         bool            nulls[Natts_pg_foreign_data_wrapper];
571         HeapTuple       tuple;
572         Oid                     fdwId;
573         bool            handler_given;
574         bool            validator_given;
575         Oid                     fdwhandler;
576         Oid                     fdwvalidator;
577         Datum           fdwoptions;
578         Oid                     ownerId;
579         ObjectAddress myself;
580         ObjectAddress referenced;
581
582         rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
583
584         /* Must be super user */
585         if (!superuser())
586                 ereport(ERROR,
587                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
588                         errmsg("permission denied to create foreign-data wrapper \"%s\"",
589                                    stmt->fdwname),
590                         errhint("Must be superuser to create a foreign-data wrapper.")));
591
592         /* For now the owner cannot be specified on create. Use effective user ID. */
593         ownerId = GetUserId();
594
595         /*
596          * Check that there is no other foreign-data wrapper by this name.
597          */
598         if (GetForeignDataWrapperByName(stmt->fdwname, true) != NULL)
599                 ereport(ERROR,
600                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
601                                  errmsg("foreign-data wrapper \"%s\" already exists",
602                                                 stmt->fdwname)));
603
604         /*
605          * Insert tuple into pg_foreign_data_wrapper.
606          */
607         memset(values, 0, sizeof(values));
608         memset(nulls, false, sizeof(nulls));
609
610         values[Anum_pg_foreign_data_wrapper_fdwname - 1] =
611                 DirectFunctionCall1(namein, CStringGetDatum(stmt->fdwname));
612         values[Anum_pg_foreign_data_wrapper_fdwowner - 1] = ObjectIdGetDatum(ownerId);
613
614         /* Lookup handler and validator functions, if given */
615         parse_func_options(stmt->func_options,
616                                            &handler_given, &fdwhandler,
617                                            &validator_given, &fdwvalidator);
618
619         values[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = ObjectIdGetDatum(fdwhandler);
620         values[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = ObjectIdGetDatum(fdwvalidator);
621
622         nulls[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true;
623
624         fdwoptions = transformGenericOptions(ForeignDataWrapperRelationId,
625                                                                                  PointerGetDatum(NULL),
626                                                                                  stmt->options,
627                                                                                  fdwvalidator);
628
629         if (PointerIsValid(DatumGetPointer(fdwoptions)))
630                 values[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = fdwoptions;
631         else
632                 nulls[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true;
633
634         tuple = heap_form_tuple(rel->rd_att, values, nulls);
635
636         fdwId = simple_heap_insert(rel, tuple);
637         CatalogUpdateIndexes(rel, tuple);
638
639         heap_freetuple(tuple);
640
641         /* record dependencies */
642         myself.classId = ForeignDataWrapperRelationId;
643         myself.objectId = fdwId;
644         myself.objectSubId = 0;
645
646         if (OidIsValid(fdwhandler))
647         {
648                 referenced.classId = ProcedureRelationId;
649                 referenced.objectId = fdwhandler;
650                 referenced.objectSubId = 0;
651                 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
652         }
653
654         if (OidIsValid(fdwvalidator))
655         {
656                 referenced.classId = ProcedureRelationId;
657                 referenced.objectId = fdwvalidator;
658                 referenced.objectSubId = 0;
659                 recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
660         }
661
662         recordDependencyOnOwner(ForeignDataWrapperRelationId, fdwId, ownerId);
663
664         /* dependency on extension */
665         recordDependencyOnCurrentExtension(&myself, false);
666
667         /* Post creation hook for new foreign data wrapper */
668         InvokeObjectAccessHook(OAT_POST_CREATE,
669                                                    ForeignDataWrapperRelationId, fdwId, 0, NULL);
670
671         heap_close(rel, RowExclusiveLock);
672 }
673
674
675 /*
676  * Alter foreign-data wrapper
677  */
678 void
679 AlterForeignDataWrapper(AlterFdwStmt *stmt)
680 {
681         Relation        rel;
682         HeapTuple       tp;
683         Form_pg_foreign_data_wrapper fdwForm;
684         Datum           repl_val[Natts_pg_foreign_data_wrapper];
685         bool            repl_null[Natts_pg_foreign_data_wrapper];
686         bool            repl_repl[Natts_pg_foreign_data_wrapper];
687         Oid                     fdwId;
688         bool            isnull;
689         Datum           datum;
690         bool            handler_given;
691         bool            validator_given;
692         Oid                     fdwhandler;
693         Oid                     fdwvalidator;
694
695         rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
696
697         /* Must be super user */
698         if (!superuser())
699                 ereport(ERROR,
700                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
701                          errmsg("permission denied to alter foreign-data wrapper \"%s\"",
702                                         stmt->fdwname),
703                          errhint("Must be superuser to alter a foreign-data wrapper.")));
704
705         tp = SearchSysCacheCopy1(FOREIGNDATAWRAPPERNAME,
706                                                          CStringGetDatum(stmt->fdwname));
707
708         if (!HeapTupleIsValid(tp))
709                 ereport(ERROR,
710                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
711                 errmsg("foreign-data wrapper \"%s\" does not exist", stmt->fdwname)));
712
713         fdwForm = (Form_pg_foreign_data_wrapper) GETSTRUCT(tp);
714         fdwId = HeapTupleGetOid(tp);
715
716         memset(repl_val, 0, sizeof(repl_val));
717         memset(repl_null, false, sizeof(repl_null));
718         memset(repl_repl, false, sizeof(repl_repl));
719
720         parse_func_options(stmt->func_options,
721                                            &handler_given, &fdwhandler,
722                                            &validator_given, &fdwvalidator);
723
724         if (handler_given)
725         {
726                 repl_val[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = ObjectIdGetDatum(fdwhandler);
727                 repl_repl[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = true;
728
729                 /*
730                  * It could be that the behavior of accessing foreign table changes
731                  * with the new handler.  Warn about this.
732                  */
733                 ereport(WARNING,
734                                 (errmsg("changing the foreign-data wrapper handler can change behavior of existing foreign tables")));
735         }
736
737         if (validator_given)
738         {
739                 repl_val[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = ObjectIdGetDatum(fdwvalidator);
740                 repl_repl[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = true;
741
742                 /*
743                  * It could be that the options for the FDW, SERVER and USER MAPPING
744                  * are no longer valid with the new validator.  Warn about this.
745                  */
746                 if (OidIsValid(fdwvalidator))
747                         ereport(WARNING,
748                          (errmsg("changing the foreign-data wrapper validator can cause "
749                                          "the options for dependent objects to become invalid")));
750         }
751         else
752         {
753                 /*
754                  * Validator is not changed, but we need it for validating options.
755                  */
756                 fdwvalidator = fdwForm->fdwvalidator;
757         }
758
759         /*
760          * If options specified, validate and update.
761          */
762         if (stmt->options)
763         {
764                 /* Extract the current options */
765                 datum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID,
766                                                                 tp,
767                                                                 Anum_pg_foreign_data_wrapper_fdwoptions,
768                                                                 &isnull);
769                 if (isnull)
770                         datum = PointerGetDatum(NULL);
771
772                 /* Transform the options */
773                 datum = transformGenericOptions(ForeignDataWrapperRelationId,
774                                                                                 datum,
775                                                                                 stmt->options,
776                                                                                 fdwvalidator);
777
778                 if (PointerIsValid(DatumGetPointer(datum)))
779                         repl_val[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = datum;
780                 else
781                         repl_null[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true;
782
783                 repl_repl[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true;
784         }
785
786         /* Everything looks good - update the tuple */
787         tp = heap_modify_tuple(tp, RelationGetDescr(rel),
788                                                    repl_val, repl_null, repl_repl);
789
790         simple_heap_update(rel, &tp->t_self, tp);
791         CatalogUpdateIndexes(rel, tp);
792
793         heap_freetuple(tp);
794
795         /* Update function dependencies if we changed them */
796         if (handler_given || validator_given)
797         {
798                 ObjectAddress myself;
799                 ObjectAddress referenced;
800
801                 /*
802                  * Flush all existing dependency records of this FDW on functions; we
803                  * assume there can be none other than the ones we are fixing.
804                  */
805                 deleteDependencyRecordsForClass(ForeignDataWrapperRelationId,
806                                                                                 fdwId,
807                                                                                 ProcedureRelationId,
808                                                                                 DEPENDENCY_NORMAL);
809
810                 /* And build new ones. */
811                 myself.classId = ForeignDataWrapperRelationId;
812                 myself.objectId = fdwId;
813                 myself.objectSubId = 0;
814
815                 if (OidIsValid(fdwhandler))
816                 {
817                         referenced.classId = ProcedureRelationId;
818                         referenced.objectId = fdwhandler;
819                         referenced.objectSubId = 0;
820                         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
821                 }
822
823                 if (OidIsValid(fdwvalidator))
824                 {
825                         referenced.classId = ProcedureRelationId;
826                         referenced.objectId = fdwvalidator;
827                         referenced.objectSubId = 0;
828                         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
829                 }
830         }
831
832         heap_close(rel, RowExclusiveLock);
833 }
834
835
836 /*
837  * Drop foreign-data wrapper by OID
838  */
839 void
840 RemoveForeignDataWrapperById(Oid fdwId)
841 {
842         HeapTuple       tp;
843         Relation        rel;
844
845         rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
846
847         tp = SearchSysCache1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fdwId));
848
849         if (!HeapTupleIsValid(tp))
850                 elog(ERROR, "cache lookup failed for foreign-data wrapper %u", fdwId);
851
852         simple_heap_delete(rel, &tp->t_self);
853
854         ReleaseSysCache(tp);
855
856         heap_close(rel, RowExclusiveLock);
857 }
858
859
860 /*
861  * Create a foreign server
862  */
863 void
864 CreateForeignServer(CreateForeignServerStmt *stmt)
865 {
866         Relation        rel;
867         Datum           srvoptions;
868         Datum           values[Natts_pg_foreign_server];
869         bool            nulls[Natts_pg_foreign_server];
870         HeapTuple       tuple;
871         Oid                     srvId;
872         Oid                     ownerId;
873         AclResult       aclresult;
874         ObjectAddress myself;
875         ObjectAddress referenced;
876         ForeignDataWrapper *fdw;
877
878         rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
879
880         /* For now the owner cannot be specified on create. Use effective user ID. */
881         ownerId = GetUserId();
882
883         /*
884          * Check that there is no other foreign server by this name.
885          */
886         if (GetForeignServerByName(stmt->servername, true) != NULL)
887                 ereport(ERROR,
888                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
889                                  errmsg("server \"%s\" already exists",
890                                                 stmt->servername)));
891
892         /*
893          * Check that the FDW exists and that we have USAGE on it. Also get the
894          * actual FDW for option validation etc.
895          */
896         fdw = GetForeignDataWrapperByName(stmt->fdwname, false);
897
898         aclresult = pg_foreign_data_wrapper_aclcheck(fdw->fdwid, ownerId, ACL_USAGE);
899         if (aclresult != ACLCHECK_OK)
900                 aclcheck_error(aclresult, ACL_KIND_FDW, fdw->fdwname);
901
902         /*
903          * Insert tuple into pg_foreign_server.
904          */
905         memset(values, 0, sizeof(values));
906         memset(nulls, false, sizeof(nulls));
907
908         values[Anum_pg_foreign_server_srvname - 1] =
909                 DirectFunctionCall1(namein, CStringGetDatum(stmt->servername));
910         values[Anum_pg_foreign_server_srvowner - 1] = ObjectIdGetDatum(ownerId);
911         values[Anum_pg_foreign_server_srvfdw - 1] = ObjectIdGetDatum(fdw->fdwid);
912
913         /* Add server type if supplied */
914         if (stmt->servertype)
915                 values[Anum_pg_foreign_server_srvtype - 1] =
916                         CStringGetTextDatum(stmt->servertype);
917         else
918                 nulls[Anum_pg_foreign_server_srvtype - 1] = true;
919
920         /* Add server version if supplied */
921         if (stmt->version)
922                 values[Anum_pg_foreign_server_srvversion - 1] =
923                         CStringGetTextDatum(stmt->version);
924         else
925                 nulls[Anum_pg_foreign_server_srvversion - 1] = true;
926
927         /* Start with a blank acl */
928         nulls[Anum_pg_foreign_server_srvacl - 1] = true;
929
930         /* Add server options */
931         srvoptions = transformGenericOptions(ForeignServerRelationId,
932                                                                                  PointerGetDatum(NULL),
933                                                                                  stmt->options,
934                                                                                  fdw->fdwvalidator);
935
936         if (PointerIsValid(DatumGetPointer(srvoptions)))
937                 values[Anum_pg_foreign_server_srvoptions - 1] = srvoptions;
938         else
939                 nulls[Anum_pg_foreign_server_srvoptions - 1] = true;
940
941         tuple = heap_form_tuple(rel->rd_att, values, nulls);
942
943         srvId = simple_heap_insert(rel, tuple);
944
945         CatalogUpdateIndexes(rel, tuple);
946
947         heap_freetuple(tuple);
948
949         /* record dependencies */
950         myself.classId = ForeignServerRelationId;
951         myself.objectId = srvId;
952         myself.objectSubId = 0;
953
954         referenced.classId = ForeignDataWrapperRelationId;
955         referenced.objectId = fdw->fdwid;
956         referenced.objectSubId = 0;
957         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
958
959         recordDependencyOnOwner(ForeignServerRelationId, srvId, ownerId);
960
961         /* dependency on extension */
962         recordDependencyOnCurrentExtension(&myself, false);
963
964         /* Post creation hook for new foreign server */
965         InvokeObjectAccessHook(OAT_POST_CREATE,
966                                                    ForeignServerRelationId, srvId, 0, NULL);
967
968         heap_close(rel, RowExclusiveLock);
969 }
970
971
972 /*
973  * Alter foreign server
974  */
975 void
976 AlterForeignServer(AlterForeignServerStmt *stmt)
977 {
978         Relation        rel;
979         HeapTuple       tp;
980         Datum           repl_val[Natts_pg_foreign_server];
981         bool            repl_null[Natts_pg_foreign_server];
982         bool            repl_repl[Natts_pg_foreign_server];
983         Oid                     srvId;
984         Form_pg_foreign_server srvForm;
985
986         rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
987
988         tp = SearchSysCacheCopy1(FOREIGNSERVERNAME,
989                                                          CStringGetDatum(stmt->servername));
990
991         if (!HeapTupleIsValid(tp))
992                 ereport(ERROR,
993                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
994                                  errmsg("server \"%s\" does not exist", stmt->servername)));
995
996         srvId = HeapTupleGetOid(tp);
997         srvForm = (Form_pg_foreign_server) GETSTRUCT(tp);
998
999         /*
1000          * Only owner or a superuser can ALTER a SERVER.
1001          */
1002         if (!pg_foreign_server_ownercheck(srvId, GetUserId()))
1003                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
1004                                            stmt->servername);
1005
1006         memset(repl_val, 0, sizeof(repl_val));
1007         memset(repl_null, false, sizeof(repl_null));
1008         memset(repl_repl, false, sizeof(repl_repl));
1009
1010         if (stmt->has_version)
1011         {
1012                 /*
1013                  * Change the server VERSION string.
1014                  */
1015                 if (stmt->version)
1016                         repl_val[Anum_pg_foreign_server_srvversion - 1] =
1017                                 CStringGetTextDatum(stmt->version);
1018                 else
1019                         repl_null[Anum_pg_foreign_server_srvversion - 1] = true;
1020
1021                 repl_repl[Anum_pg_foreign_server_srvversion - 1] = true;
1022         }
1023
1024         if (stmt->options)
1025         {
1026                 ForeignDataWrapper *fdw = GetForeignDataWrapper(srvForm->srvfdw);
1027                 Datum           datum;
1028                 bool            isnull;
1029
1030                 /* Extract the current srvoptions */
1031                 datum = SysCacheGetAttr(FOREIGNSERVEROID,
1032                                                                 tp,
1033                                                                 Anum_pg_foreign_server_srvoptions,
1034                                                                 &isnull);
1035                 if (isnull)
1036                         datum = PointerGetDatum(NULL);
1037
1038                 /* Prepare the options array */
1039                 datum = transformGenericOptions(ForeignServerRelationId,
1040                                                                                 datum,
1041                                                                                 stmt->options,
1042                                                                                 fdw->fdwvalidator);
1043
1044                 if (PointerIsValid(DatumGetPointer(datum)))
1045                         repl_val[Anum_pg_foreign_server_srvoptions - 1] = datum;
1046                 else
1047                         repl_null[Anum_pg_foreign_server_srvoptions - 1] = true;
1048
1049                 repl_repl[Anum_pg_foreign_server_srvoptions - 1] = true;
1050         }
1051
1052         /* Everything looks good - update the tuple */
1053         tp = heap_modify_tuple(tp, RelationGetDescr(rel),
1054                                                    repl_val, repl_null, repl_repl);
1055
1056         simple_heap_update(rel, &tp->t_self, tp);
1057         CatalogUpdateIndexes(rel, tp);
1058
1059         heap_freetuple(tp);
1060
1061         heap_close(rel, RowExclusiveLock);
1062 }
1063
1064
1065 /*
1066  * Drop foreign server by OID
1067  */
1068 void
1069 RemoveForeignServerById(Oid srvId)
1070 {
1071         HeapTuple       tp;
1072         Relation        rel;
1073
1074         rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
1075
1076         tp = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(srvId));
1077
1078         if (!HeapTupleIsValid(tp))
1079                 elog(ERROR, "cache lookup failed for foreign server %u", srvId);
1080
1081         simple_heap_delete(rel, &tp->t_self);
1082
1083         ReleaseSysCache(tp);
1084
1085         heap_close(rel, RowExclusiveLock);
1086 }
1087
1088
1089 /*
1090  * Common routine to check permission for user-mapping-related DDL
1091  * commands.  We allow server owners to operate on any mapping, and
1092  * users to operate on their own mapping.
1093  */
1094 static void
1095 user_mapping_ddl_aclcheck(Oid umuserid, Oid serverid, const char *servername)
1096 {
1097         Oid                     curuserid = GetUserId();
1098
1099         if (!pg_foreign_server_ownercheck(serverid, curuserid))
1100         {
1101                 if (umuserid == curuserid)
1102                 {
1103                         AclResult       aclresult;
1104
1105                         aclresult = pg_foreign_server_aclcheck(serverid, curuserid, ACL_USAGE);
1106                         if (aclresult != ACLCHECK_OK)
1107                                 aclcheck_error(aclresult, ACL_KIND_FOREIGN_SERVER, servername);
1108                 }
1109                 else
1110                         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
1111                                                    servername);
1112         }
1113 }
1114
1115
1116 /*
1117  * Create user mapping
1118  */
1119 void
1120 CreateUserMapping(CreateUserMappingStmt *stmt)
1121 {
1122         Relation        rel;
1123         Datum           useoptions;
1124         Datum           values[Natts_pg_user_mapping];
1125         bool            nulls[Natts_pg_user_mapping];
1126         HeapTuple       tuple;
1127         Oid                     useId;
1128         Oid                     umId;
1129         ObjectAddress myself;
1130         ObjectAddress referenced;
1131         ForeignServer *srv;
1132         ForeignDataWrapper *fdw;
1133
1134         rel = heap_open(UserMappingRelationId, RowExclusiveLock);
1135
1136         useId = GetUserOidFromMapping(stmt->username, false);
1137
1138         /* Check that the server exists. */
1139         srv = GetForeignServerByName(stmt->servername, false);
1140
1141         user_mapping_ddl_aclcheck(useId, srv->serverid, stmt->servername);
1142
1143         /*
1144          * Check that the user mapping is unique within server.
1145          */
1146         umId = GetSysCacheOid2(USERMAPPINGUSERSERVER,
1147                                                    ObjectIdGetDatum(useId),
1148                                                    ObjectIdGetDatum(srv->serverid));
1149         if (OidIsValid(umId))
1150                 ereport(ERROR,
1151                                 (errcode(ERRCODE_DUPLICATE_OBJECT),
1152                                  errmsg("user mapping \"%s\" already exists for server %s",
1153                                                 MappingUserName(useId),
1154                                                 stmt->servername)));
1155
1156         fdw = GetForeignDataWrapper(srv->fdwid);
1157
1158         /*
1159          * Insert tuple into pg_user_mapping.
1160          */
1161         memset(values, 0, sizeof(values));
1162         memset(nulls, false, sizeof(nulls));
1163
1164         values[Anum_pg_user_mapping_umuser - 1] = ObjectIdGetDatum(useId);
1165         values[Anum_pg_user_mapping_umserver - 1] = ObjectIdGetDatum(srv->serverid);
1166
1167         /* Add user options */
1168         useoptions = transformGenericOptions(UserMappingRelationId,
1169                                                                                  PointerGetDatum(NULL),
1170                                                                                  stmt->options,
1171                                                                                  fdw->fdwvalidator);
1172
1173         if (PointerIsValid(DatumGetPointer(useoptions)))
1174                 values[Anum_pg_user_mapping_umoptions - 1] = useoptions;
1175         else
1176                 nulls[Anum_pg_user_mapping_umoptions - 1] = true;
1177
1178         tuple = heap_form_tuple(rel->rd_att, values, nulls);
1179
1180         umId = simple_heap_insert(rel, tuple);
1181
1182         CatalogUpdateIndexes(rel, tuple);
1183
1184         heap_freetuple(tuple);
1185
1186         /* Add dependency on the server */
1187         myself.classId = UserMappingRelationId;
1188         myself.objectId = umId;
1189         myself.objectSubId = 0;
1190
1191         referenced.classId = ForeignServerRelationId;
1192         referenced.objectId = srv->serverid;
1193         referenced.objectSubId = 0;
1194         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1195
1196         if (OidIsValid(useId))
1197         {
1198                 /* Record the mapped user dependency */
1199                 recordDependencyOnOwner(UserMappingRelationId, umId, useId);
1200         }
1201
1202         /* dependency on extension */
1203         recordDependencyOnCurrentExtension(&myself, false);
1204
1205         /* Post creation hook for new user mapping */
1206         InvokeObjectAccessHook(OAT_POST_CREATE,
1207                                                    UserMappingRelationId, umId, 0, NULL);
1208
1209         heap_close(rel, RowExclusiveLock);
1210 }
1211
1212
1213 /*
1214  * Alter user mapping
1215  */
1216 void
1217 AlterUserMapping(AlterUserMappingStmt *stmt)
1218 {
1219         Relation        rel;
1220         HeapTuple       tp;
1221         Datum           repl_val[Natts_pg_user_mapping];
1222         bool            repl_null[Natts_pg_user_mapping];
1223         bool            repl_repl[Natts_pg_user_mapping];
1224         Oid                     useId;
1225         Oid                     umId;
1226         ForeignServer *srv;
1227
1228         rel = heap_open(UserMappingRelationId, RowExclusiveLock);
1229
1230         useId = GetUserOidFromMapping(stmt->username, false);
1231         srv = GetForeignServerByName(stmt->servername, false);
1232
1233         umId = GetSysCacheOid2(USERMAPPINGUSERSERVER,
1234                                                    ObjectIdGetDatum(useId),
1235                                                    ObjectIdGetDatum(srv->serverid));
1236         if (!OidIsValid(umId))
1237                 ereport(ERROR,
1238                                 (errcode(ERRCODE_UNDEFINED_OBJECT),
1239                                  errmsg("user mapping \"%s\" does not exist for the server",
1240                                                 MappingUserName(useId))));
1241
1242         user_mapping_ddl_aclcheck(useId, srv->serverid, stmt->servername);
1243
1244         tp = SearchSysCacheCopy1(USERMAPPINGOID, ObjectIdGetDatum(umId));
1245
1246         if (!HeapTupleIsValid(tp))
1247                 elog(ERROR, "cache lookup failed for user mapping %u", umId);
1248
1249         memset(repl_val, 0, sizeof(repl_val));
1250         memset(repl_null, false, sizeof(repl_null));
1251         memset(repl_repl, false, sizeof(repl_repl));
1252
1253         if (stmt->options)
1254         {
1255                 ForeignDataWrapper *fdw;
1256                 Datum           datum;
1257                 bool            isnull;
1258
1259                 /*
1260                  * Process the options.
1261                  */
1262
1263                 fdw = GetForeignDataWrapper(srv->fdwid);
1264
1265                 datum = SysCacheGetAttr(USERMAPPINGUSERSERVER,
1266                                                                 tp,
1267                                                                 Anum_pg_user_mapping_umoptions,
1268                                                                 &isnull);
1269                 if (isnull)
1270                         datum = PointerGetDatum(NULL);
1271
1272                 /* Prepare the options array */
1273                 datum = transformGenericOptions(UserMappingRelationId,
1274                                                                                 datum,
1275                                                                                 stmt->options,
1276                                                                                 fdw->fdwvalidator);
1277
1278                 if (PointerIsValid(DatumGetPointer(datum)))
1279                         repl_val[Anum_pg_user_mapping_umoptions - 1] = datum;
1280                 else
1281                         repl_null[Anum_pg_user_mapping_umoptions - 1] = true;
1282
1283                 repl_repl[Anum_pg_user_mapping_umoptions - 1] = true;
1284         }
1285
1286         /* Everything looks good - update the tuple */
1287         tp = heap_modify_tuple(tp, RelationGetDescr(rel),
1288                                                    repl_val, repl_null, repl_repl);
1289
1290         simple_heap_update(rel, &tp->t_self, tp);
1291         CatalogUpdateIndexes(rel, tp);
1292
1293         heap_freetuple(tp);
1294
1295         heap_close(rel, RowExclusiveLock);
1296 }
1297
1298
1299 /*
1300  * Drop user mapping
1301  */
1302 void
1303 RemoveUserMapping(DropUserMappingStmt *stmt)
1304 {
1305         ObjectAddress object;
1306         Oid                     useId;
1307         Oid                     umId;
1308         ForeignServer *srv;
1309
1310         useId = GetUserOidFromMapping(stmt->username, stmt->missing_ok);
1311         srv = GetForeignServerByName(stmt->servername, true);
1312
1313         if (stmt->username && !OidIsValid(useId))
1314         {
1315                 /*
1316                  * IF EXISTS specified, role not found and not public. Notice this and
1317                  * leave.
1318                  */
1319                 elog(NOTICE, "role \"%s\" does not exist, skipping", stmt->username);
1320                 return;
1321         }
1322
1323         if (!srv)
1324         {
1325                 if (!stmt->missing_ok)
1326                         ereport(ERROR,
1327                                         (errcode(ERRCODE_UNDEFINED_OBJECT),
1328                                          errmsg("server \"%s\" does not exist",
1329                                                         stmt->servername)));
1330                 /* IF EXISTS, just note it */
1331                 ereport(NOTICE, (errmsg("server does not exist, skipping")));
1332                 return;
1333         }
1334
1335         umId = GetSysCacheOid2(USERMAPPINGUSERSERVER,
1336                                                    ObjectIdGetDatum(useId),
1337                                                    ObjectIdGetDatum(srv->serverid));
1338
1339         if (!OidIsValid(umId))
1340         {
1341                 if (!stmt->missing_ok)
1342                         ereport(ERROR,
1343                                         (errcode(ERRCODE_UNDEFINED_OBJECT),
1344                                   errmsg("user mapping \"%s\" does not exist for the server",
1345                                                  MappingUserName(useId))));
1346
1347                 /* IF EXISTS specified, just note it */
1348                 ereport(NOTICE,
1349                 (errmsg("user mapping \"%s\" does not exist for the server, skipping",
1350                                 MappingUserName(useId))));
1351                 return;
1352         }
1353
1354         user_mapping_ddl_aclcheck(useId, srv->serverid, srv->servername);
1355
1356         /*
1357          * Do the deletion
1358          */
1359         object.classId = UserMappingRelationId;
1360         object.objectId = umId;
1361         object.objectSubId = 0;
1362
1363         performDeletion(&object, DROP_CASCADE, 0);
1364 }
1365
1366
1367 /*
1368  * Drop user mapping by OID.  This is called to clean up dependencies.
1369  */
1370 void
1371 RemoveUserMappingById(Oid umId)
1372 {
1373         HeapTuple       tp;
1374         Relation        rel;
1375
1376         rel = heap_open(UserMappingRelationId, RowExclusiveLock);
1377
1378         tp = SearchSysCache1(USERMAPPINGOID, ObjectIdGetDatum(umId));
1379
1380         if (!HeapTupleIsValid(tp))
1381                 elog(ERROR, "cache lookup failed for user mapping %u", umId);
1382
1383         simple_heap_delete(rel, &tp->t_self);
1384
1385         ReleaseSysCache(tp);
1386
1387         heap_close(rel, RowExclusiveLock);
1388 }
1389
1390 /*
1391  * Create a foreign table
1392  * call after DefineRelation().
1393  */
1394 void
1395 CreateForeignTable(CreateForeignTableStmt *stmt, Oid relid)
1396 {
1397         Relation        ftrel;
1398         Datum           ftoptions;
1399         Datum           values[Natts_pg_foreign_table];
1400         bool            nulls[Natts_pg_foreign_table];
1401         HeapTuple       tuple;
1402         AclResult       aclresult;
1403         ObjectAddress myself;
1404         ObjectAddress referenced;
1405         Oid                     ownerId;
1406         ForeignDataWrapper *fdw;
1407         ForeignServer *server;
1408
1409         /*
1410          * Advance command counter to ensure the pg_attribute tuple is visible;
1411          * the tuple might be updated to add constraints in previous step.
1412          */
1413         CommandCounterIncrement();
1414
1415         ftrel = heap_open(ForeignTableRelationId, RowExclusiveLock);
1416
1417         /*
1418          * For now the owner cannot be specified on create. Use effective user ID.
1419          */
1420         ownerId = GetUserId();
1421
1422         /*
1423          * Check that the foreign server exists and that we have USAGE on it. Also
1424          * get the actual FDW for option validation etc.
1425          */
1426         server = GetForeignServerByName(stmt->servername, false);
1427         aclresult = pg_foreign_server_aclcheck(server->serverid, ownerId, ACL_USAGE);
1428         if (aclresult != ACLCHECK_OK)
1429                 aclcheck_error(aclresult, ACL_KIND_FOREIGN_SERVER, server->servername);
1430
1431         fdw = GetForeignDataWrapper(server->fdwid);
1432
1433         /*
1434          * Insert tuple into pg_foreign_table.
1435          */
1436         memset(values, 0, sizeof(values));
1437         memset(nulls, false, sizeof(nulls));
1438
1439         values[Anum_pg_foreign_table_ftrelid - 1] = ObjectIdGetDatum(relid);
1440         values[Anum_pg_foreign_table_ftserver - 1] = ObjectIdGetDatum(server->serverid);
1441         /* Add table generic options */
1442         ftoptions = transformGenericOptions(ForeignTableRelationId,
1443                                                                                 PointerGetDatum(NULL),
1444                                                                                 stmt->options,
1445                                                                                 fdw->fdwvalidator);
1446
1447         if (PointerIsValid(DatumGetPointer(ftoptions)))
1448                 values[Anum_pg_foreign_table_ftoptions - 1] = ftoptions;
1449         else
1450                 nulls[Anum_pg_foreign_table_ftoptions - 1] = true;
1451
1452         tuple = heap_form_tuple(ftrel->rd_att, values, nulls);
1453
1454         simple_heap_insert(ftrel, tuple);
1455         CatalogUpdateIndexes(ftrel, tuple);
1456
1457         heap_freetuple(tuple);
1458
1459         /* Add pg_class dependency on the server */
1460         myself.classId = RelationRelationId;
1461         myself.objectId = relid;
1462         myself.objectSubId = 0;
1463
1464         referenced.classId = ForeignServerRelationId;
1465         referenced.objectId = server->serverid;
1466         referenced.objectSubId = 0;
1467         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1468
1469         heap_close(ftrel, RowExclusiveLock);
1470 }