PostgreSQL Source Code  git master
foreigncmds.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "access/reloptions.h"
#include "access/table.h"
#include "access/xact.h"
#include "catalog/catalog.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_foreign_data_wrapper.h"
#include "catalog/pg_foreign_server.h"
#include "catalog/pg_foreign_table.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "catalog/pg_user_mapping.h"
#include "commands/defrem.h"
#include "foreign/fdwapi.h"
#include "foreign/foreign.h"
#include "miscadmin.h"
#include "parser/parse_func.h"
#include "tcop/utility.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/syscache.h"
Include dependency graph for foreigncmds.c:

Go to the source code of this file.

Data Structures

struct  import_error_callback_arg
 

Functions

static void import_error_callback (void *arg)
 
static Datum optionListToArray (List *options)
 
Datum transformGenericOptions (Oid catalogId, Datum oldOptions, List *options, Oid fdwvalidator)
 
static void AlterForeignDataWrapperOwner_internal (Relation rel, HeapTuple tup, Oid newOwnerId)
 
ObjectAddress AlterForeignDataWrapperOwner (const char *name, Oid newOwnerId)
 
void AlterForeignDataWrapperOwner_oid (Oid fwdId, Oid newOwnerId)
 
static void AlterForeignServerOwner_internal (Relation rel, HeapTuple tup, Oid newOwnerId)
 
ObjectAddress AlterForeignServerOwner (const char *name, Oid newOwnerId)
 
void AlterForeignServerOwner_oid (Oid srvId, Oid newOwnerId)
 
static Oid lookup_fdw_handler_func (DefElem *handler)
 
static Oid lookup_fdw_validator_func (DefElem *validator)
 
static void parse_func_options (ParseState *pstate, List *func_options, bool *handler_given, Oid *fdwhandler, bool *validator_given, Oid *fdwvalidator)
 
ObjectAddress CreateForeignDataWrapper (ParseState *pstate, CreateFdwStmt *stmt)
 
ObjectAddress AlterForeignDataWrapper (ParseState *pstate, AlterFdwStmt *stmt)
 
ObjectAddress CreateForeignServer (CreateForeignServerStmt *stmt)
 
ObjectAddress AlterForeignServer (AlterForeignServerStmt *stmt)
 
static void user_mapping_ddl_aclcheck (Oid umuserid, Oid serverid, const char *servername)
 
ObjectAddress CreateUserMapping (CreateUserMappingStmt *stmt)
 
ObjectAddress AlterUserMapping (AlterUserMappingStmt *stmt)
 
Oid RemoveUserMapping (DropUserMappingStmt *stmt)
 
void CreateForeignTable (CreateForeignTableStmt *stmt, Oid relid)
 
void ImportForeignSchema (ImportForeignSchemaStmt *stmt)
 

Function Documentation

◆ AlterForeignDataWrapper()

ObjectAddress AlterForeignDataWrapper ( ParseState pstate,
AlterFdwStmt stmt 
)

Definition at line 674 of file foreigncmds.c.

675 {
676  Relation rel;
677  HeapTuple tp;
679  Datum repl_val[Natts_pg_foreign_data_wrapper];
680  bool repl_null[Natts_pg_foreign_data_wrapper];
681  bool repl_repl[Natts_pg_foreign_data_wrapper];
682  Oid fdwId;
683  bool isnull;
684  Datum datum;
685  bool handler_given;
686  bool validator_given;
687  Oid fdwhandler;
688  Oid fdwvalidator;
689  ObjectAddress myself;
690 
691  rel = table_open(ForeignDataWrapperRelationId, RowExclusiveLock);
692 
693  /* Must be superuser */
694  if (!superuser())
695  ereport(ERROR,
696  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
697  errmsg("permission denied to alter foreign-data wrapper \"%s\"",
698  stmt->fdwname),
699  errhint("Must be superuser to alter a foreign-data wrapper.")));
700 
702  CStringGetDatum(stmt->fdwname));
703 
704  if (!HeapTupleIsValid(tp))
705  ereport(ERROR,
706  (errcode(ERRCODE_UNDEFINED_OBJECT),
707  errmsg("foreign-data wrapper \"%s\" does not exist", stmt->fdwname)));
708 
709  fdwForm = (Form_pg_foreign_data_wrapper) GETSTRUCT(tp);
710  fdwId = fdwForm->oid;
711 
712  memset(repl_val, 0, sizeof(repl_val));
713  memset(repl_null, false, sizeof(repl_null));
714  memset(repl_repl, false, sizeof(repl_repl));
715 
716  parse_func_options(pstate, stmt->func_options,
717  &handler_given, &fdwhandler,
718  &validator_given, &fdwvalidator);
719 
720  if (handler_given)
721  {
722  repl_val[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = ObjectIdGetDatum(fdwhandler);
723  repl_repl[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = true;
724 
725  /*
726  * It could be that the behavior of accessing foreign table changes
727  * with the new handler. Warn about this.
728  */
730  (errmsg("changing the foreign-data wrapper handler can change behavior of existing foreign tables")));
731  }
732 
733  if (validator_given)
734  {
735  repl_val[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = ObjectIdGetDatum(fdwvalidator);
736  repl_repl[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = true;
737 
738  /*
739  * It could be that existing options for the FDW or dependent SERVER,
740  * USER MAPPING or FOREIGN TABLE objects are no longer valid according
741  * to the new validator. Warn about this.
742  */
743  if (OidIsValid(fdwvalidator))
745  (errmsg("changing the foreign-data wrapper validator can cause "
746  "the options for dependent objects to become invalid")));
747  }
748  else
749  {
750  /*
751  * Validator is not changed, but we need it for validating options.
752  */
753  fdwvalidator = fdwForm->fdwvalidator;
754  }
755 
756  /*
757  * If options specified, validate and update.
758  */
759  if (stmt->options)
760  {
761  /* Extract the current options */
763  tp,
764  Anum_pg_foreign_data_wrapper_fdwoptions,
765  &isnull);
766  if (isnull)
767  datum = PointerGetDatum(NULL);
768 
769  /* Transform the options */
770  datum = transformGenericOptions(ForeignDataWrapperRelationId,
771  datum,
772  stmt->options,
773  fdwvalidator);
774 
775  if (PointerIsValid(DatumGetPointer(datum)))
776  repl_val[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = datum;
777  else
778  repl_null[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true;
779 
780  repl_repl[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true;
781  }
782 
783  /* Everything looks good - update the tuple */
784  tp = heap_modify_tuple(tp, RelationGetDescr(rel),
785  repl_val, repl_null, repl_repl);
786 
787  CatalogTupleUpdate(rel, &tp->t_self, tp);
788 
789  heap_freetuple(tp);
790 
791  ObjectAddressSet(myself, ForeignDataWrapperRelationId, fdwId);
792 
793  /* Update function dependencies if we changed them */
794  if (handler_given || validator_given)
795  {
796  ObjectAddress referenced;
797 
798  /*
799  * Flush all existing dependency records of this FDW on functions; we
800  * assume there can be none other than the ones we are fixing.
801  */
802  deleteDependencyRecordsForClass(ForeignDataWrapperRelationId,
803  fdwId,
804  ProcedureRelationId,
806 
807  /* And build new ones. */
808 
809  if (OidIsValid(fdwhandler))
810  {
811  referenced.classId = ProcedureRelationId;
812  referenced.objectId = fdwhandler;
813  referenced.objectSubId = 0;
814  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
815  }
816 
817  if (OidIsValid(fdwvalidator))
818  {
819  referenced.classId = ProcedureRelationId;
820  referenced.objectId = fdwvalidator;
821  referenced.objectSubId = 0;
822  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
823  }
824  }
825 
826  InvokeObjectPostAlterHook(ForeignDataWrapperRelationId, fdwId, 0);
827 
829 
830  return myself;
831 }
#define PointerIsValid(pointer)
Definition: c.h:699
#define OidIsValid(objectId)
Definition: c.h:711
@ DEPENDENCY_NORMAL
Definition: dependency.h:33
int errhint(const char *fmt,...)
Definition: elog.c:1153
int errcode(int sqlerrcode)
Definition: elog.c:695
int errmsg(const char *fmt,...)
Definition: elog.c:906
#define WARNING
Definition: elog.h:32
#define ERROR
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:145
static void parse_func_options(ParseState *pstate, List *func_options, bool *handler_given, Oid *fdwhandler, bool *validator_given, Oid *fdwvalidator)
Definition: foreigncmds.c:518
Datum transformGenericOptions(Oid catalogId, Datum oldOptions, List *options, Oid fdwvalidator)
Definition: foreigncmds.c:110
HeapTuple heap_modify_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *replValues, bool *replIsnull, bool *doReplace)
Definition: heaptuple.c:1113
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1338
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
#define GETSTRUCT(TUP)
Definition: htup_details.h:649
void CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup)
Definition: indexing.c:301
#define RowExclusiveLock
Definition: lockdefs.h:38
#define InvokeObjectPostAlterHook(classId, objectId, subId)
Definition: objectaccess.h:197
#define ObjectAddressSet(addr, class_id, object_id)
Definition: objectaddress.h:40
void recordDependencyOn(const ObjectAddress *depender, const ObjectAddress *referenced, DependencyType behavior)
Definition: pg_depend.c:44
long deleteDependencyRecordsForClass(Oid classId, Oid objectId, Oid refclassId, char deptype)
Definition: pg_depend.c:350
FormData_pg_foreign_data_wrapper * Form_pg_foreign_data_wrapper
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:670
uintptr_t Datum
Definition: postgres.h:412
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:600
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:660
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:698
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationGetDescr(relation)
Definition: rel.h:527
List * func_options
Definition: parsenodes.h:2504
List * options
Definition: parsenodes.h:2505
char * fdwname
Definition: parsenodes.h:2503
ItemPointerData t_self
Definition: htup.h:65
bool superuser(void)
Definition: superuser.c:46
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1434
#define SearchSysCacheCopy1(cacheId, key1)
Definition: syscache.h:179
@ FOREIGNDATAWRAPPEROID
Definition: syscache.h:62
@ FOREIGNDATAWRAPPERNAME
Definition: syscache.h:61
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40

References CatalogTupleUpdate(), ObjectAddress::classId, CStringGetDatum(), DatumGetPointer(), deleteDependencyRecordsForClass(), DEPENDENCY_NORMAL, ereport, errcode(), errhint(), errmsg(), ERROR, AlterFdwStmt::fdwname, FOREIGNDATAWRAPPERNAME, FOREIGNDATAWRAPPEROID, AlterFdwStmt::func_options, GETSTRUCT, heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, InvokeObjectPostAlterHook, ObjectAddressSet, ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, OidIsValid, AlterFdwStmt::options, parse_func_options(), PointerGetDatum(), PointerIsValid, recordDependencyOn(), RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, superuser(), SysCacheGetAttr(), HeapTupleData::t_self, table_close(), table_open(), transformGenericOptions(), and WARNING.

Referenced by ProcessUtilitySlow().

◆ AlterForeignDataWrapperOwner()

ObjectAddress AlterForeignDataWrapperOwner ( const char *  name,
Oid  newOwnerId 
)

Definition at line 275 of file foreigncmds.c.

276 {
277  Oid fdwId;
278  HeapTuple tup;
279  Relation rel;
280  ObjectAddress address;
282 
283 
284  rel = table_open(ForeignDataWrapperRelationId, RowExclusiveLock);
285 
287 
288  if (!HeapTupleIsValid(tup))
289  ereport(ERROR,
290  (errcode(ERRCODE_UNDEFINED_OBJECT),
291  errmsg("foreign-data wrapper \"%s\" does not exist", name)));
292 
294  fdwId = form->oid;
295 
296  AlterForeignDataWrapperOwner_internal(rel, tup, newOwnerId);
297 
298  ObjectAddressSet(address, ForeignDataWrapperRelationId, fdwId);
299 
300  heap_freetuple(tup);
301 
303 
304  return address;
305 }
const char * name
Definition: encode.c:561
static void AlterForeignDataWrapperOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
Definition: foreigncmds.c:205

References AlterForeignDataWrapperOwner_internal(), CStringGetDatum(), ereport, errcode(), errmsg(), ERROR, FOREIGNDATAWRAPPERNAME, GETSTRUCT, heap_freetuple(), HeapTupleIsValid, name, ObjectAddressSet, RowExclusiveLock, SearchSysCacheCopy1, table_close(), and table_open().

Referenced by ExecAlterOwnerStmt().

◆ AlterForeignDataWrapperOwner_internal()

static void AlterForeignDataWrapperOwner_internal ( Relation  rel,
HeapTuple  tup,
Oid  newOwnerId 
)
static

Definition at line 205 of file foreigncmds.c.

206 {
208  Datum repl_val[Natts_pg_foreign_data_wrapper];
209  bool repl_null[Natts_pg_foreign_data_wrapper];
210  bool repl_repl[Natts_pg_foreign_data_wrapper];
211  Acl *newAcl;
212  Datum aclDatum;
213  bool isNull;
214 
216 
217  /* Must be a superuser to change a FDW owner */
218  if (!superuser())
219  ereport(ERROR,
220  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
221  errmsg("permission denied to change owner of foreign-data wrapper \"%s\"",
222  NameStr(form->fdwname)),
223  errhint("Must be superuser to change owner of a foreign-data wrapper.")));
224 
225  /* New owner must also be a superuser */
226  if (!superuser_arg(newOwnerId))
227  ereport(ERROR,
228  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
229  errmsg("permission denied to change owner of foreign-data wrapper \"%s\"",
230  NameStr(form->fdwname)),
231  errhint("The owner of a foreign-data wrapper must be a superuser.")));
232 
233  if (form->fdwowner != newOwnerId)
234  {
235  memset(repl_null, false, sizeof(repl_null));
236  memset(repl_repl, false, sizeof(repl_repl));
237 
238  repl_repl[Anum_pg_foreign_data_wrapper_fdwowner - 1] = true;
239  repl_val[Anum_pg_foreign_data_wrapper_fdwowner - 1] = ObjectIdGetDatum(newOwnerId);
240 
241  aclDatum = heap_getattr(tup,
242  Anum_pg_foreign_data_wrapper_fdwacl,
243  RelationGetDescr(rel),
244  &isNull);
245  /* Null ACLs do not require changes */
246  if (!isNull)
247  {
248  newAcl = aclnewowner(DatumGetAclP(aclDatum),
249  form->fdwowner, newOwnerId);
250  repl_repl[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true;
251  repl_val[Anum_pg_foreign_data_wrapper_fdwacl - 1] = PointerGetDatum(newAcl);
252  }
253 
254  tup = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null,
255  repl_repl);
256 
257  CatalogTupleUpdate(rel, &tup->t_self, tup);
258 
259  /* Update owner dependency reference */
260  changeDependencyOnOwner(ForeignDataWrapperRelationId,
261  form->oid,
262  newOwnerId);
263  }
264 
265  InvokeObjectPostAlterHook(ForeignDataWrapperRelationId,
266  form->oid, 0);
267 }
Acl * aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId)
Definition: acl.c:1065
#define DatumGetAclP(X)
Definition: acl.h:120
#define NameStr(name)
Definition: c.h:682
static Datum heap_getattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
Definition: htup_details.h:788
void changeDependencyOnOwner(Oid classId, Oid objectId, Oid newOwnerId)
Definition: pg_shdepend.c:313
bool superuser_arg(Oid roleid)
Definition: superuser.c:56

References aclnewowner(), CatalogTupleUpdate(), changeDependencyOnOwner(), DatumGetAclP, ereport, errcode(), errhint(), errmsg(), ERROR, GETSTRUCT, heap_getattr(), heap_modify_tuple(), InvokeObjectPostAlterHook, NameStr, ObjectIdGetDatum(), PointerGetDatum(), RelationGetDescr, superuser(), superuser_arg(), and HeapTupleData::t_self.

Referenced by AlterForeignDataWrapperOwner(), and AlterForeignDataWrapperOwner_oid().

◆ AlterForeignDataWrapperOwner_oid()

void AlterForeignDataWrapperOwner_oid ( Oid  fwdId,
Oid  newOwnerId 
)

Definition at line 313 of file foreigncmds.c.

314 {
315  HeapTuple tup;
316  Relation rel;
317 
318  rel = table_open(ForeignDataWrapperRelationId, RowExclusiveLock);
319 
321 
322  if (!HeapTupleIsValid(tup))
323  ereport(ERROR,
324  (errcode(ERRCODE_UNDEFINED_OBJECT),
325  errmsg("foreign-data wrapper with OID %u does not exist", fwdId)));
326 
327  AlterForeignDataWrapperOwner_internal(rel, tup, newOwnerId);
328 
329  heap_freetuple(tup);
330 
332 }

References AlterForeignDataWrapperOwner_internal(), ereport, errcode(), errmsg(), ERROR, FOREIGNDATAWRAPPEROID, heap_freetuple(), HeapTupleIsValid, ObjectIdGetDatum(), RowExclusiveLock, SearchSysCacheCopy1, table_close(), and table_open().

Referenced by shdepReassignOwned().

◆ AlterForeignServer()

ObjectAddress AlterForeignServer ( AlterForeignServerStmt stmt)

Definition at line 974 of file foreigncmds.c.

975 {
976  Relation rel;
977  HeapTuple tp;
978  Datum repl_val[Natts_pg_foreign_server];
979  bool repl_null[Natts_pg_foreign_server];
980  bool repl_repl[Natts_pg_foreign_server];
981  Oid srvId;
982  Form_pg_foreign_server srvForm;
983  ObjectAddress address;
984 
985  rel = table_open(ForeignServerRelationId, RowExclusiveLock);
986 
988  CStringGetDatum(stmt->servername));
989 
990  if (!HeapTupleIsValid(tp))
991  ereport(ERROR,
992  (errcode(ERRCODE_UNDEFINED_OBJECT),
993  errmsg("server \"%s\" does not exist", stmt->servername)));
994 
995  srvForm = (Form_pg_foreign_server) GETSTRUCT(tp);
996  srvId = srvForm->oid;
997 
998  /*
999  * Only owner or a superuser can ALTER a SERVER.
1000  */
1001  if (!object_ownercheck(ForeignServerRelationId, srvId, GetUserId()))
1003  stmt->servername);
1004 
1005  memset(repl_val, 0, sizeof(repl_val));
1006  memset(repl_null, false, sizeof(repl_null));
1007  memset(repl_repl, false, sizeof(repl_repl));
1008 
1009  if (stmt->has_version)
1010  {
1011  /*
1012  * Change the server VERSION string.
1013  */
1014  if (stmt->version)
1015  repl_val[Anum_pg_foreign_server_srvversion - 1] =
1017  else
1018  repl_null[Anum_pg_foreign_server_srvversion - 1] = true;
1019 
1020  repl_repl[Anum_pg_foreign_server_srvversion - 1] = true;
1021  }
1022 
1023  if (stmt->options)
1024  {
1025  ForeignDataWrapper *fdw = GetForeignDataWrapper(srvForm->srvfdw);
1026  Datum datum;
1027  bool isnull;
1028 
1029  /* Extract the current srvoptions */
1031  tp,
1032  Anum_pg_foreign_server_srvoptions,
1033  &isnull);
1034  if (isnull)
1035  datum = PointerGetDatum(NULL);
1036 
1037  /* Prepare the options array */
1038  datum = transformGenericOptions(ForeignServerRelationId,
1039  datum,
1040  stmt->options,
1041  fdw->fdwvalidator);
1042 
1043  if (PointerIsValid(DatumGetPointer(datum)))
1044  repl_val[Anum_pg_foreign_server_srvoptions - 1] = datum;
1045  else
1046  repl_null[Anum_pg_foreign_server_srvoptions - 1] = true;
1047 
1048  repl_repl[Anum_pg_foreign_server_srvoptions - 1] = true;
1049  }
1050 
1051  /* Everything looks good - update the tuple */
1052  tp = heap_modify_tuple(tp, RelationGetDescr(rel),
1053  repl_val, repl_null, repl_repl);
1054 
1055  CatalogTupleUpdate(rel, &tp->t_self, tp);
1056 
1057  InvokeObjectPostAlterHook(ForeignServerRelationId, srvId, 0);
1058 
1059  ObjectAddressSet(address, ForeignServerRelationId, srvId);
1060 
1061  heap_freetuple(tp);
1062 
1064 
1065  return address;
1066 }
@ ACLCHECK_NOT_OWNER
Definition: acl.h:186
void aclcheck_error(AclResult aclerr, ObjectType objtype, const char *objectname)
Definition: aclchk.c:3485
bool object_ownercheck(Oid classid, Oid objectid, Oid roleid)
Definition: aclchk.c:4799
#define CStringGetTextDatum(s)
Definition: builtins.h:85
ForeignDataWrapper * GetForeignDataWrapper(Oid fdwid)
Definition: foreign.c:37
Oid GetUserId(void)
Definition: miscinit.c:497
@ OBJECT_FOREIGN_SERVER
Definition: parsenodes.h:1905
FormData_pg_foreign_server * Form_pg_foreign_server
@ FOREIGNSERVEROID
Definition: syscache.h:64
@ FOREIGNSERVERNAME
Definition: syscache.h:63

References aclcheck_error(), ACLCHECK_NOT_OWNER, CatalogTupleUpdate(), CStringGetDatum(), CStringGetTextDatum, DatumGetPointer(), ereport, errcode(), errmsg(), ERROR, ForeignDataWrapper::fdwvalidator, FOREIGNSERVERNAME, FOREIGNSERVEROID, GetForeignDataWrapper(), GETSTRUCT, GetUserId(), AlterForeignServerStmt::has_version, heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, InvokeObjectPostAlterHook, OBJECT_FOREIGN_SERVER, object_ownercheck(), ObjectAddressSet, AlterForeignServerStmt::options, PointerGetDatum(), PointerIsValid, RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, AlterForeignServerStmt::servername, SysCacheGetAttr(), HeapTupleData::t_self, table_close(), table_open(), transformGenericOptions(), and AlterForeignServerStmt::version.

Referenced by ProcessUtilitySlow().

◆ AlterForeignServerOwner()

ObjectAddress AlterForeignServerOwner ( const char *  name,
Oid  newOwnerId 
)

Definition at line 415 of file foreigncmds.c.

416 {
417  Oid servOid;
418  HeapTuple tup;
419  Relation rel;
420  ObjectAddress address;
422 
423  rel = table_open(ForeignServerRelationId, RowExclusiveLock);
424 
426 
427  if (!HeapTupleIsValid(tup))
428  ereport(ERROR,
429  (errcode(ERRCODE_UNDEFINED_OBJECT),
430  errmsg("server \"%s\" does not exist", name)));
431 
432  form = (Form_pg_foreign_server) GETSTRUCT(tup);
433  servOid = form->oid;
434 
435  AlterForeignServerOwner_internal(rel, tup, newOwnerId);
436 
437  ObjectAddressSet(address, ForeignServerRelationId, servOid);
438 
439  heap_freetuple(tup);
440 
442 
443  return address;
444 }
static void AlterForeignServerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
Definition: foreigncmds.c:338

References AlterForeignServerOwner_internal(), CStringGetDatum(), ereport, errcode(), errmsg(), ERROR, FOREIGNSERVERNAME, GETSTRUCT, heap_freetuple(), HeapTupleIsValid, name, ObjectAddressSet, RowExclusiveLock, SearchSysCacheCopy1, table_close(), and table_open().

Referenced by ExecAlterOwnerStmt().

◆ AlterForeignServerOwner_internal()

static void AlterForeignServerOwner_internal ( Relation  rel,
HeapTuple  tup,
Oid  newOwnerId 
)
static

Definition at line 338 of file foreigncmds.c.

339 {
341  Datum repl_val[Natts_pg_foreign_server];
342  bool repl_null[Natts_pg_foreign_server];
343  bool repl_repl[Natts_pg_foreign_server];
344  Acl *newAcl;
345  Datum aclDatum;
346  bool isNull;
347 
348  form = (Form_pg_foreign_server) GETSTRUCT(tup);
349 
350  if (form->srvowner != newOwnerId)
351  {
352  /* Superusers can always do it */
353  if (!superuser())
354  {
355  Oid srvId;
356  AclResult aclresult;
357 
358  srvId = form->oid;
359 
360  /* Must be owner */
361  if (!object_ownercheck(ForeignServerRelationId, srvId, GetUserId()))
363  NameStr(form->srvname));
364 
365  /* Must be able to become new owner */
366  check_can_set_role(GetUserId(), newOwnerId);
367 
368  /* New owner must have USAGE privilege on foreign-data wrapper */
369  aclresult = object_aclcheck(ForeignDataWrapperRelationId, form->srvfdw, newOwnerId, ACL_USAGE);
370  if (aclresult != ACLCHECK_OK)
371  {
372  ForeignDataWrapper *fdw = GetForeignDataWrapper(form->srvfdw);
373 
374  aclcheck_error(aclresult, OBJECT_FDW, fdw->fdwname);
375  }
376  }
377 
378  memset(repl_null, false, sizeof(repl_null));
379  memset(repl_repl, false, sizeof(repl_repl));
380 
381  repl_repl[Anum_pg_foreign_server_srvowner - 1] = true;
382  repl_val[Anum_pg_foreign_server_srvowner - 1] = ObjectIdGetDatum(newOwnerId);
383 
384  aclDatum = heap_getattr(tup,
385  Anum_pg_foreign_server_srvacl,
386  RelationGetDescr(rel),
387  &isNull);
388  /* Null ACLs do not require changes */
389  if (!isNull)
390  {
391  newAcl = aclnewowner(DatumGetAclP(aclDatum),
392  form->srvowner, newOwnerId);
393  repl_repl[Anum_pg_foreign_server_srvacl - 1] = true;
394  repl_val[Anum_pg_foreign_server_srvacl - 1] = PointerGetDatum(newAcl);
395  }
396 
397  tup = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null,
398  repl_repl);
399 
400  CatalogTupleUpdate(rel, &tup->t_self, tup);
401 
402  /* Update owner dependency reference */
403  changeDependencyOnOwner(ForeignServerRelationId, form->oid,
404  newOwnerId);
405  }
406 
407  InvokeObjectPostAlterHook(ForeignServerRelationId,
408  form->oid, 0);
409 }
void check_can_set_role(Oid member, Oid role)
Definition: acl.c:5006
AclResult
Definition: acl.h:183
@ ACLCHECK_OK
Definition: acl.h:184
AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
Definition: aclchk.c:4598
#define ACL_USAGE
Definition: parsenodes.h:91
@ OBJECT_FDW
Definition: parsenodes.h:1904
char * fdwname
Definition: foreign.h:28

References ACL_USAGE, aclcheck_error(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, aclnewowner(), CatalogTupleUpdate(), changeDependencyOnOwner(), check_can_set_role(), DatumGetAclP, ForeignDataWrapper::fdwname, GetForeignDataWrapper(), GETSTRUCT, GetUserId(), heap_getattr(), heap_modify_tuple(), InvokeObjectPostAlterHook, NameStr, object_aclcheck(), OBJECT_FDW, OBJECT_FOREIGN_SERVER, object_ownercheck(), ObjectIdGetDatum(), PointerGetDatum(), RelationGetDescr, superuser(), and HeapTupleData::t_self.

Referenced by AlterForeignServerOwner(), and AlterForeignServerOwner_oid().

◆ AlterForeignServerOwner_oid()

void AlterForeignServerOwner_oid ( Oid  srvId,
Oid  newOwnerId 
)

Definition at line 450 of file foreigncmds.c.

451 {
452  HeapTuple tup;
453  Relation rel;
454 
455  rel = table_open(ForeignServerRelationId, RowExclusiveLock);
456 
458 
459  if (!HeapTupleIsValid(tup))
460  ereport(ERROR,
461  (errcode(ERRCODE_UNDEFINED_OBJECT),
462  errmsg("foreign server with OID %u does not exist", srvId)));
463 
464  AlterForeignServerOwner_internal(rel, tup, newOwnerId);
465 
466  heap_freetuple(tup);
467 
469 }

References AlterForeignServerOwner_internal(), ereport, errcode(), errmsg(), ERROR, FOREIGNSERVEROID, heap_freetuple(), HeapTupleIsValid, ObjectIdGetDatum(), RowExclusiveLock, SearchSysCacheCopy1, table_close(), and table_open().

Referenced by shdepReassignOwned().

◆ AlterUserMapping()

ObjectAddress AlterUserMapping ( AlterUserMappingStmt stmt)

Definition at line 1226 of file foreigncmds.c.

1227 {
1228  Relation rel;
1229  HeapTuple tp;
1230  Datum repl_val[Natts_pg_user_mapping];
1231  bool repl_null[Natts_pg_user_mapping];
1232  bool repl_repl[Natts_pg_user_mapping];
1233  Oid useId;
1234  Oid umId;
1235  ForeignServer *srv;
1236  ObjectAddress address;
1237  RoleSpec *role = (RoleSpec *) stmt->user;
1238 
1239  rel = table_open(UserMappingRelationId, RowExclusiveLock);
1240 
1241  if (role->roletype == ROLESPEC_PUBLIC)
1242  useId = ACL_ID_PUBLIC;
1243  else
1244  useId = get_rolespec_oid(stmt->user, false);
1245 
1246  srv = GetForeignServerByName(stmt->servername, false);
1247 
1248  umId = GetSysCacheOid2(USERMAPPINGUSERSERVER, Anum_pg_user_mapping_oid,
1249  ObjectIdGetDatum(useId),
1250  ObjectIdGetDatum(srv->serverid));
1251  if (!OidIsValid(umId))
1252  ereport(ERROR,
1253  (errcode(ERRCODE_UNDEFINED_OBJECT),
1254  errmsg("user mapping for \"%s\" does not exist for server \"%s\"",
1255  MappingUserName(useId), stmt->servername)));
1256 
1257  user_mapping_ddl_aclcheck(useId, srv->serverid, stmt->servername);
1258 
1260 
1261  if (!HeapTupleIsValid(tp))
1262  elog(ERROR, "cache lookup failed for user mapping %u", umId);
1263 
1264  memset(repl_val, 0, sizeof(repl_val));
1265  memset(repl_null, false, sizeof(repl_null));
1266  memset(repl_repl, false, sizeof(repl_repl));
1267 
1268  if (stmt->options)
1269  {
1270  ForeignDataWrapper *fdw;
1271  Datum datum;
1272  bool isnull;
1273 
1274  /*
1275  * Process the options.
1276  */
1277 
1278  fdw = GetForeignDataWrapper(srv->fdwid);
1279 
1280  datum = SysCacheGetAttr(USERMAPPINGUSERSERVER,
1281  tp,
1282  Anum_pg_user_mapping_umoptions,
1283  &isnull);
1284  if (isnull)
1285  datum = PointerGetDatum(NULL);
1286 
1287  /* Prepare the options array */
1288  datum = transformGenericOptions(UserMappingRelationId,
1289  datum,
1290  stmt->options,
1291  fdw->fdwvalidator);
1292 
1293  if (PointerIsValid(DatumGetPointer(datum)))
1294  repl_val[Anum_pg_user_mapping_umoptions - 1] = datum;
1295  else
1296  repl_null[Anum_pg_user_mapping_umoptions - 1] = true;
1297 
1298  repl_repl[Anum_pg_user_mapping_umoptions - 1] = true;
1299  }
1300 
1301  /* Everything looks good - update the tuple */
1302  tp = heap_modify_tuple(tp, RelationGetDescr(rel),
1303  repl_val, repl_null, repl_repl);
1304 
1305  CatalogTupleUpdate(rel, &tp->t_self, tp);
1306 
1307  InvokeObjectPostAlterHook(UserMappingRelationId,
1308  umId, 0);
1309 
1310  ObjectAddressSet(address, UserMappingRelationId, umId);
1311 
1312  heap_freetuple(tp);
1313 
1315 
1316  return address;
1317 }
Oid get_rolespec_oid(const RoleSpec *role, bool missing_ok)
Definition: acl.c:5269
#define ACL_ID_PUBLIC
Definition: acl.h:46
ForeignServer * GetForeignServerByName(const char *srvname, bool missing_ok)
Definition: foreign.c:182
#define MappingUserName(userid)
Definition: foreign.h:20
static void user_mapping_ddl_aclcheck(Oid umuserid, Oid serverid, const char *servername)
Definition: foreigncmds.c:1075
@ ROLESPEC_PUBLIC
Definition: parsenodes.h:365
Oid serverid
Definition: foreign.h:36
RoleSpecType roletype
Definition: parsenodes.h:371
@ USERMAPPINGOID
Definition: syscache.h:115
#define GetSysCacheOid2(cacheId, oidcol, key1, key2)
Definition: syscache.h:199

References ACL_ID_PUBLIC, CatalogTupleUpdate(), DatumGetPointer(), elog(), ereport, errcode(), errmsg(), ERROR, ForeignServer::fdwid, ForeignDataWrapper::fdwvalidator, get_rolespec_oid(), GetForeignDataWrapper(), GetForeignServerByName(), GetSysCacheOid2, heap_freetuple(), heap_modify_tuple(), HeapTupleIsValid, InvokeObjectPostAlterHook, MappingUserName, ObjectAddressSet, ObjectIdGetDatum(), OidIsValid, AlterUserMappingStmt::options, PointerGetDatum(), PointerIsValid, RelationGetDescr, ROLESPEC_PUBLIC, RoleSpec::roletype, RowExclusiveLock, SearchSysCacheCopy1, ForeignServer::serverid, AlterUserMappingStmt::servername, SysCacheGetAttr(), HeapTupleData::t_self, table_close(), table_open(), transformGenericOptions(), AlterUserMappingStmt::user, user_mapping_ddl_aclcheck(), and USERMAPPINGOID.

Referenced by ProcessUtilitySlow().

◆ CreateForeignDataWrapper()

ObjectAddress CreateForeignDataWrapper ( ParseState pstate,
CreateFdwStmt stmt 
)

Definition at line 558 of file foreigncmds.c.

559 {
560  Relation rel;
561  Datum values[Natts_pg_foreign_data_wrapper];
562  bool nulls[Natts_pg_foreign_data_wrapper];
563  HeapTuple tuple;
564  Oid fdwId;
565  bool handler_given;
566  bool validator_given;
567  Oid fdwhandler;
568  Oid fdwvalidator;
569  Datum fdwoptions;
570  Oid ownerId;
571  ObjectAddress myself;
572  ObjectAddress referenced;
573 
574  rel = table_open(ForeignDataWrapperRelationId, RowExclusiveLock);
575 
576  /* Must be superuser */
577  if (!superuser())
578  ereport(ERROR,
579  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
580  errmsg("permission denied to create foreign-data wrapper \"%s\"",
581  stmt->fdwname),
582  errhint("Must be superuser to create a foreign-data wrapper.")));
583 
584  /* For now the owner cannot be specified on create. Use effective user ID. */
585  ownerId = GetUserId();
586 
587  /*
588  * Check that there is no other foreign-data wrapper by this name.
589  */
590  if (GetForeignDataWrapperByName(stmt->fdwname, true) != NULL)
591  ereport(ERROR,
593  errmsg("foreign-data wrapper \"%s\" already exists",
594  stmt->fdwname)));
595 
596  /*
597  * Insert tuple into pg_foreign_data_wrapper.
598  */
599  memset(values, 0, sizeof(values));
600  memset(nulls, false, sizeof(nulls));
601 
602  fdwId = GetNewOidWithIndex(rel, ForeignDataWrapperOidIndexId,
603  Anum_pg_foreign_data_wrapper_oid);
604  values[Anum_pg_foreign_data_wrapper_oid - 1] = ObjectIdGetDatum(fdwId);
605  values[Anum_pg_foreign_data_wrapper_fdwname - 1] =
607  values[Anum_pg_foreign_data_wrapper_fdwowner - 1] = ObjectIdGetDatum(ownerId);
608 
609  /* Lookup handler and validator functions, if given */
610  parse_func_options(pstate, stmt->func_options,
611  &handler_given, &fdwhandler,
612  &validator_given, &fdwvalidator);
613 
614  values[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = ObjectIdGetDatum(fdwhandler);
615  values[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = ObjectIdGetDatum(fdwvalidator);
616 
617  nulls[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true;
618 
619  fdwoptions = transformGenericOptions(ForeignDataWrapperRelationId,
620  PointerGetDatum(NULL),
621  stmt->options,
622  fdwvalidator);
623 
624  if (PointerIsValid(DatumGetPointer(fdwoptions)))
625  values[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = fdwoptions;
626  else
627  nulls[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true;
628 
629  tuple = heap_form_tuple(rel->rd_att, values, nulls);
630 
631  CatalogTupleInsert(rel, tuple);
632 
633  heap_freetuple(tuple);
634 
635  /* record dependencies */
636  myself.classId = ForeignDataWrapperRelationId;
637  myself.objectId = fdwId;
638  myself.objectSubId = 0;
639 
640  if (OidIsValid(fdwhandler))
641  {
642  referenced.classId = ProcedureRelationId;
643  referenced.objectId = fdwhandler;
644  referenced.objectSubId = 0;
645  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
646  }
647 
648  if (OidIsValid(fdwvalidator))
649  {
650  referenced.classId = ProcedureRelationId;
651  referenced.objectId = fdwvalidator;
652  referenced.objectSubId = 0;
653  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
654  }
655 
656  recordDependencyOnOwner(ForeignDataWrapperRelationId, fdwId, ownerId);
657 
658  /* dependency on extension */
659  recordDependencyOnCurrentExtension(&myself, false);
660 
661  /* Post creation hook for new foreign data wrapper */
662  InvokeObjectPostCreateHook(ForeignDataWrapperRelationId, fdwId, 0);
663 
665 
666  return myself;
667 }
static Datum values[MAXATTR]
Definition: bootstrap.c:156
Oid GetNewOidWithIndex(Relation relation, Oid indexId, AttrNumber oidcolumn)
Definition: catalog.c:393
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:642
ForeignDataWrapper * GetForeignDataWrapperByName(const char *fdwname, bool missing_ok)
Definition: foreign.c:96
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
void CatalogTupleInsert(Relation heapRel, HeapTuple tup)
Definition: indexing.c:221
Datum namein(PG_FUNCTION_ARGS)
Definition: name.c:48
#define InvokeObjectPostCreateHook(classId, objectId, subId)
Definition: objectaccess.h:173
void recordDependencyOnCurrentExtension(const ObjectAddress *object, bool isReplace)
Definition: pg_depend.c:192
void recordDependencyOnOwner(Oid classId, Oid objectId, Oid owner)
Definition: pg_shdepend.c:165
#define ERRCODE_DUPLICATE_OBJECT
Definition: streamutil.c:32
List * func_options
Definition: parsenodes.h:2496
char * fdwname
Definition: parsenodes.h:2495
List * options
Definition: parsenodes.h:2497
TupleDesc rd_att
Definition: rel.h:111

References CatalogTupleInsert(), ObjectAddress::classId, CStringGetDatum(), DatumGetPointer(), DEPENDENCY_NORMAL, DirectFunctionCall1, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errhint(), errmsg(), ERROR, CreateFdwStmt::fdwname, CreateFdwStmt::func_options, GetForeignDataWrapperByName(), GetNewOidWithIndex(), GetUserId(), heap_form_tuple(), heap_freetuple(), InvokeObjectPostCreateHook, namein(), ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, OidIsValid, CreateFdwStmt::options, parse_func_options(), PointerGetDatum(), PointerIsValid, RelationData::rd_att, recordDependencyOn(), recordDependencyOnCurrentExtension(), recordDependencyOnOwner(), RowExclusiveLock, superuser(), table_close(), table_open(), transformGenericOptions(), and values.

Referenced by ProcessUtilitySlow().

◆ CreateForeignServer()

ObjectAddress CreateForeignServer ( CreateForeignServerStmt stmt)

Definition at line 838 of file foreigncmds.c.

839 {
840  Relation rel;
841  Datum srvoptions;
842  Datum values[Natts_pg_foreign_server];
843  bool nulls[Natts_pg_foreign_server];
844  HeapTuple tuple;
845  Oid srvId;
846  Oid ownerId;
847  AclResult aclresult;
848  ObjectAddress myself;
849  ObjectAddress referenced;
850  ForeignDataWrapper *fdw;
851 
852  rel = table_open(ForeignServerRelationId, RowExclusiveLock);
853 
854  /* For now the owner cannot be specified on create. Use effective user ID. */
855  ownerId = GetUserId();
856 
857  /*
858  * Check that there is no other foreign server by this name. If there is
859  * one, do nothing if IF NOT EXISTS was specified.
860  */
861  srvId = get_foreign_server_oid(stmt->servername, true);
862  if (OidIsValid(srvId))
863  {
864  if (stmt->if_not_exists)
865  {
866  /*
867  * If we are in an extension script, insist that the pre-existing
868  * object be a member of the extension, to avoid security risks.
869  */
870  ObjectAddressSet(myself, ForeignServerRelationId, srvId);
872 
873  /* OK to skip */
874  ereport(NOTICE,
876  errmsg("server \"%s\" already exists, skipping",
877  stmt->servername)));
879  return InvalidObjectAddress;
880  }
881  else
882  ereport(ERROR,
884  errmsg("server \"%s\" already exists",
885  stmt->servername)));
886  }
887 
888  /*
889  * Check that the FDW exists and that we have USAGE on it. Also get the
890  * actual FDW for option validation etc.
891  */
892  fdw = GetForeignDataWrapperByName(stmt->fdwname, false);
893 
894  aclresult = object_aclcheck(ForeignDataWrapperRelationId, fdw->fdwid, ownerId, ACL_USAGE);
895  if (aclresult != ACLCHECK_OK)
896  aclcheck_error(aclresult, OBJECT_FDW, fdw->fdwname);
897 
898  /*
899  * Insert tuple into pg_foreign_server.
900  */
901  memset(values, 0, sizeof(values));
902  memset(nulls, false, sizeof(nulls));
903 
904  srvId = GetNewOidWithIndex(rel, ForeignServerOidIndexId,
905  Anum_pg_foreign_server_oid);
906  values[Anum_pg_foreign_server_oid - 1] = ObjectIdGetDatum(srvId);
907  values[Anum_pg_foreign_server_srvname - 1] =
909  values[Anum_pg_foreign_server_srvowner - 1] = ObjectIdGetDatum(ownerId);
910  values[Anum_pg_foreign_server_srvfdw - 1] = ObjectIdGetDatum(fdw->fdwid);
911 
912  /* Add server type if supplied */
913  if (stmt->servertype)
914  values[Anum_pg_foreign_server_srvtype - 1] =
916  else
917  nulls[Anum_pg_foreign_server_srvtype - 1] = true;
918 
919  /* Add server version if supplied */
920  if (stmt->version)
921  values[Anum_pg_foreign_server_srvversion - 1] =
923  else
924  nulls[Anum_pg_foreign_server_srvversion - 1] = true;
925 
926  /* Start with a blank acl */
927  nulls[Anum_pg_foreign_server_srvacl - 1] = true;
928 
929  /* Add server options */
930  srvoptions = transformGenericOptions(ForeignServerRelationId,
931  PointerGetDatum(NULL),
932  stmt->options,
933  fdw->fdwvalidator);
934 
935  if (PointerIsValid(DatumGetPointer(srvoptions)))
936  values[Anum_pg_foreign_server_srvoptions - 1] = srvoptions;
937  else
938  nulls[Anum_pg_foreign_server_srvoptions - 1] = true;
939 
940  tuple = heap_form_tuple(rel->rd_att, values, nulls);
941 
942  CatalogTupleInsert(rel, tuple);
943 
944  heap_freetuple(tuple);
945 
946  /* record dependencies */
947  myself.classId = ForeignServerRelationId;
948  myself.objectId = srvId;
949  myself.objectSubId = 0;
950 
951  referenced.classId = ForeignDataWrapperRelationId;
952  referenced.objectId = fdw->fdwid;
953  referenced.objectSubId = 0;
954  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
955 
956  recordDependencyOnOwner(ForeignServerRelationId, srvId, ownerId);
957 
958  /* dependency on extension */
959  recordDependencyOnCurrentExtension(&myself, false);
960 
961  /* Post creation hook for new foreign server */
962  InvokeObjectPostCreateHook(ForeignServerRelationId, srvId, 0);
963 
965 
966  return myself;
967 }
#define NOTICE
Definition: elog.h:31
Oid get_foreign_server_oid(const char *servername, bool missing_ok)
Definition: foreign.c:690
const ObjectAddress InvalidObjectAddress
void checkMembershipInCurrentExtension(const ObjectAddress *object)
Definition: pg_depend.c:257

References ACL_USAGE, aclcheck_error(), ACLCHECK_OK, CatalogTupleInsert(), checkMembershipInCurrentExtension(), ObjectAddress::classId, CStringGetDatum(), CStringGetTextDatum, DatumGetPointer(), DEPENDENCY_NORMAL, DirectFunctionCall1, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, ForeignDataWrapper::fdwid, ForeignDataWrapper::fdwname, CreateForeignServerStmt::fdwname, ForeignDataWrapper::fdwvalidator, get_foreign_server_oid(), GetForeignDataWrapperByName(), GetNewOidWithIndex(), GetUserId(), heap_form_tuple(), heap_freetuple(), CreateForeignServerStmt::if_not_exists, InvalidObjectAddress, InvokeObjectPostCreateHook, namein(), NOTICE, object_aclcheck(), OBJECT_FDW, ObjectAddressSet, ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, OidIsValid, CreateForeignServerStmt::options, PointerGetDatum(), PointerIsValid, RelationData::rd_att, recordDependencyOn(), recordDependencyOnCurrentExtension(), recordDependencyOnOwner(), RowExclusiveLock, CreateForeignServerStmt::servername, CreateForeignServerStmt::servertype, table_close(), table_open(), transformGenericOptions(), values, and CreateForeignServerStmt::version.

Referenced by ProcessUtilitySlow().

◆ CreateForeignTable()

void CreateForeignTable ( CreateForeignTableStmt stmt,
Oid  relid 
)

Definition at line 1404 of file foreigncmds.c.

1405 {
1406  Relation ftrel;
1407  Datum ftoptions;
1408  Datum values[Natts_pg_foreign_table];
1409  bool nulls[Natts_pg_foreign_table];
1410  HeapTuple tuple;
1411  AclResult aclresult;
1412  ObjectAddress myself;
1413  ObjectAddress referenced;
1414  Oid ownerId;
1415  ForeignDataWrapper *fdw;
1416  ForeignServer *server;
1417 
1418  /*
1419  * Advance command counter to ensure the pg_attribute tuple is visible;
1420  * the tuple might be updated to add constraints in previous step.
1421  */
1423 
1424  ftrel = table_open(ForeignTableRelationId, RowExclusiveLock);
1425 
1426  /*
1427  * For now the owner cannot be specified on create. Use effective user ID.
1428  */
1429  ownerId = GetUserId();
1430 
1431  /*
1432  * Check that the foreign server exists and that we have USAGE on it. Also
1433  * get the actual FDW for option validation etc.
1434  */
1435  server = GetForeignServerByName(stmt->servername, false);
1436  aclresult = object_aclcheck(ForeignServerRelationId, server->serverid, ownerId, ACL_USAGE);
1437  if (aclresult != ACLCHECK_OK)
1438  aclcheck_error(aclresult, OBJECT_FOREIGN_SERVER, server->servername);
1439 
1440  fdw = GetForeignDataWrapper(server->fdwid);
1441 
1442  /*
1443  * Insert tuple into pg_foreign_table.
1444  */
1445  memset(values, 0, sizeof(values));
1446  memset(nulls, false, sizeof(nulls));
1447 
1448  values[Anum_pg_foreign_table_ftrelid - 1] = ObjectIdGetDatum(relid);
1449  values[Anum_pg_foreign_table_ftserver - 1] = ObjectIdGetDatum(server->serverid);
1450  /* Add table generic options */
1451  ftoptions = transformGenericOptions(ForeignTableRelationId,
1452  PointerGetDatum(NULL),
1453  stmt->options,
1454  fdw->fdwvalidator);
1455 
1456  if (PointerIsValid(DatumGetPointer(ftoptions)))
1457  values[Anum_pg_foreign_table_ftoptions - 1] = ftoptions;
1458  else
1459  nulls[Anum_pg_foreign_table_ftoptions - 1] = true;
1460 
1461  tuple = heap_form_tuple(ftrel->rd_att, values, nulls);
1462 
1463  CatalogTupleInsert(ftrel, tuple);
1464 
1465  heap_freetuple(tuple);
1466 
1467  /* Add pg_class dependency on the server */
1468  myself.classId = RelationRelationId;
1469  myself.objectId = relid;
1470  myself.objectSubId = 0;
1471 
1472  referenced.classId = ForeignServerRelationId;
1473  referenced.objectId = server->serverid;
1474  referenced.objectSubId = 0;
1475  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1476 
1477  table_close(ftrel, RowExclusiveLock);
1478 }
char * servername
Definition: foreign.h:39
void CommandCounterIncrement(void)
Definition: xact.c:1077

References ACL_USAGE, aclcheck_error(), ACLCHECK_OK, CatalogTupleInsert(), ObjectAddress::classId, CommandCounterIncrement(), DatumGetPointer(), DEPENDENCY_NORMAL, ForeignServer::fdwid, ForeignDataWrapper::fdwvalidator, GetForeignDataWrapper(), GetForeignServerByName(), GetUserId(), heap_form_tuple(), heap_freetuple(), object_aclcheck(), OBJECT_FOREIGN_SERVER, ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, CreateForeignTableStmt::options, PointerGetDatum(), PointerIsValid, RelationData::rd_att, recordDependencyOn(), RowExclusiveLock, ForeignServer::serverid, ForeignServer::servername, CreateForeignTableStmt::servername, table_close(), table_open(), transformGenericOptions(), and values.

Referenced by ProcessUtilitySlow().

◆ CreateUserMapping()

ObjectAddress CreateUserMapping ( CreateUserMappingStmt stmt)

Definition at line 1100 of file foreigncmds.c.

1101 {
1102  Relation rel;
1103  Datum useoptions;
1104  Datum values[Natts_pg_user_mapping];
1105  bool nulls[Natts_pg_user_mapping];
1106  HeapTuple tuple;
1107  Oid useId;
1108  Oid umId;
1109  ObjectAddress myself;
1110  ObjectAddress referenced;
1111  ForeignServer *srv;
1112  ForeignDataWrapper *fdw;
1113  RoleSpec *role = (RoleSpec *) stmt->user;
1114 
1115  rel = table_open(UserMappingRelationId, RowExclusiveLock);
1116 
1117  if (role->roletype == ROLESPEC_PUBLIC)
1118  useId = ACL_ID_PUBLIC;
1119  else
1120  useId = get_rolespec_oid(stmt->user, false);
1121 
1122  /* Check that the server exists. */
1123  srv = GetForeignServerByName(stmt->servername, false);
1124 
1125  user_mapping_ddl_aclcheck(useId, srv->serverid, stmt->servername);
1126 
1127  /*
1128  * Check that the user mapping is unique within server.
1129  */
1130  umId = GetSysCacheOid2(USERMAPPINGUSERSERVER, Anum_pg_user_mapping_oid,
1131  ObjectIdGetDatum(useId),
1132  ObjectIdGetDatum(srv->serverid));
1133 
1134  if (OidIsValid(umId))
1135  {
1136  if (stmt->if_not_exists)
1137  {
1138  /*
1139  * Since user mappings aren't members of extensions (see comments
1140  * below), no need for checkMembershipInCurrentExtension here.
1141  */
1142  ereport(NOTICE,
1144  errmsg("user mapping for \"%s\" already exists for server \"%s\", skipping",
1145  MappingUserName(useId),
1146  stmt->servername)));
1147 
1149  return InvalidObjectAddress;
1150  }
1151  else
1152  ereport(ERROR,
1154  errmsg("user mapping for \"%s\" already exists for server \"%s\"",
1155  MappingUserName(useId),
1156  stmt->servername)));
1157  }
1158 
1159  fdw = GetForeignDataWrapper(srv->fdwid);
1160 
1161  /*
1162  * Insert tuple into pg_user_mapping.
1163  */
1164  memset(values, 0, sizeof(values));
1165  memset(nulls, false, sizeof(nulls));
1166 
1167  umId = GetNewOidWithIndex(rel, UserMappingOidIndexId,
1168  Anum_pg_user_mapping_oid);
1169  values[Anum_pg_user_mapping_oid - 1] = ObjectIdGetDatum(umId);
1170  values[Anum_pg_user_mapping_umuser - 1] = ObjectIdGetDatum(useId);
1171  values[Anum_pg_user_mapping_umserver - 1] = ObjectIdGetDatum(srv->serverid);
1172 
1173  /* Add user options */
1174  useoptions = transformGenericOptions(UserMappingRelationId,
1175  PointerGetDatum(NULL),
1176  stmt->options,
1177  fdw->fdwvalidator);
1178 
1179  if (PointerIsValid(DatumGetPointer(useoptions)))
1180  values[Anum_pg_user_mapping_umoptions - 1] = useoptions;
1181  else
1182  nulls[Anum_pg_user_mapping_umoptions - 1] = true;
1183 
1184  tuple = heap_form_tuple(rel->rd_att, values, nulls);
1185 
1186  CatalogTupleInsert(rel, tuple);
1187 
1188  heap_freetuple(tuple);
1189 
1190  /* Add dependency on the server */
1191  myself.classId = UserMappingRelationId;
1192  myself.objectId = umId;
1193  myself.objectSubId = 0;
1194 
1195  referenced.classId = ForeignServerRelationId;
1196  referenced.objectId = srv->serverid;
1197  referenced.objectSubId = 0;
1198  recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
1199 
1200  if (OidIsValid(useId))
1201  {
1202  /* Record the mapped user dependency */
1203  recordDependencyOnOwner(UserMappingRelationId, umId, useId);
1204  }
1205 
1206  /*
1207  * Perhaps someday there should be a recordDependencyOnCurrentExtension
1208  * call here; but since roles aren't members of extensions, it seems like
1209  * user mappings shouldn't be either. Note that the grammar and pg_dump
1210  * would need to be extended too if we change this.
1211  */
1212 
1213  /* Post creation hook for new user mapping */
1214  InvokeObjectPostCreateHook(UserMappingRelationId, umId, 0);
1215 
1217 
1218  return myself;
1219 }

References ACL_ID_PUBLIC, CatalogTupleInsert(), ObjectAddress::classId, DatumGetPointer(), DEPENDENCY_NORMAL, ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, ForeignServer::fdwid, ForeignDataWrapper::fdwvalidator, get_rolespec_oid(), GetForeignDataWrapper(), GetForeignServerByName(), GetNewOidWithIndex(), GetSysCacheOid2, heap_form_tuple(), heap_freetuple(), CreateUserMappingStmt::if_not_exists, InvalidObjectAddress, InvokeObjectPostCreateHook, MappingUserName, NOTICE, ObjectAddress::objectId, ObjectIdGetDatum(), ObjectAddress::objectSubId, OidIsValid, CreateUserMappingStmt::options, PointerGetDatum(), PointerIsValid, RelationData::rd_att, recordDependencyOn(), recordDependencyOnOwner(), ROLESPEC_PUBLIC, RoleSpec::roletype, RowExclusiveLock, ForeignServer::serverid, CreateUserMappingStmt::servername, table_close(), table_open(), transformGenericOptions(), CreateUserMappingStmt::user, user_mapping_ddl_aclcheck(), and values.

Referenced by ProcessUtilitySlow().

◆ import_error_callback()

static void import_error_callback ( void *  arg)
static

Definition at line 1600 of file foreigncmds.c.

1601 {
1603  int syntaxerrposition;
1604 
1605  /* If it's a syntax error, convert to internal syntax error report */
1606  syntaxerrposition = geterrposition();
1607  if (syntaxerrposition > 0)
1608  {
1609  errposition(0);
1610  internalerrposition(syntaxerrposition);
1611  internalerrquery(callback_arg->cmd);
1612  }
1613 
1614  if (callback_arg->tablename)
1615  errcontext("importing foreign table \"%s\"",
1616  callback_arg->tablename);
1617 }
int internalerrquery(const char *query)
Definition: elog.c:1318
int internalerrposition(int cursorpos)
Definition: elog.c:1298
int geterrposition(void)
Definition: elog.c:1414
int errposition(int cursorpos)
Definition: elog.c:1282
#define errcontext
Definition: elog.h:192
void * arg

References arg, import_error_callback_arg::cmd, errcontext, errposition(), geterrposition(), internalerrposition(), internalerrquery(), and import_error_callback_arg::tablename.

Referenced by ImportForeignSchema().

◆ ImportForeignSchema()

void ImportForeignSchema ( ImportForeignSchemaStmt stmt)

Definition at line 1484 of file foreigncmds.c.

1485 {
1486  ForeignServer *server;
1487  ForeignDataWrapper *fdw;
1488  FdwRoutine *fdw_routine;
1489  AclResult aclresult;
1490  List *cmd_list;
1491  ListCell *lc;
1492 
1493  /* Check that the foreign server exists and that we have USAGE on it */
1494  server = GetForeignServerByName(stmt->server_name, false);
1495  aclresult = object_aclcheck(ForeignServerRelationId, server->serverid, GetUserId(), ACL_USAGE);
1496  if (aclresult != ACLCHECK_OK)
1497  aclcheck_error(aclresult, OBJECT_FOREIGN_SERVER, server->servername);
1498 
1499  /* Check that the schema exists and we have CREATE permissions on it */
1500  (void) LookupCreationNamespace(stmt->local_schema);
1501 
1502  /* Get the FDW and check it supports IMPORT */
1503  fdw = GetForeignDataWrapper(server->fdwid);
1504  if (!OidIsValid(fdw->fdwhandler))
1505  ereport(ERROR,
1506  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1507  errmsg("foreign-data wrapper \"%s\" has no handler",
1508  fdw->fdwname)));
1509  fdw_routine = GetFdwRoutine(fdw->fdwhandler);
1510  if (fdw_routine->ImportForeignSchema == NULL)
1511  ereport(ERROR,
1512  (errcode(ERRCODE_FDW_NO_SCHEMAS),
1513  errmsg("foreign-data wrapper \"%s\" does not support IMPORT FOREIGN SCHEMA",
1514  fdw->fdwname)));
1515 
1516  /* Call FDW to get a list of commands */
1517  cmd_list = fdw_routine->ImportForeignSchema(stmt, server->serverid);
1518 
1519  /* Parse and execute each command */
1520  foreach(lc, cmd_list)
1521  {
1522  char *cmd = (char *) lfirst(lc);
1523  import_error_callback_arg callback_arg;
1524  ErrorContextCallback sqlerrcontext;
1525  List *raw_parsetree_list;
1526  ListCell *lc2;
1527 
1528  /*
1529  * Setup error traceback support for ereport(). This is so that any
1530  * error in the generated SQL will be displayed nicely.
1531  */
1532  callback_arg.tablename = NULL; /* not known yet */
1533  callback_arg.cmd = cmd;
1534  sqlerrcontext.callback = import_error_callback;
1535  sqlerrcontext.arg = (void *) &callback_arg;
1536  sqlerrcontext.previous = error_context_stack;
1537  error_context_stack = &sqlerrcontext;
1538 
1539  /*
1540  * Parse the SQL string into a list of raw parse trees.
1541  */
1542  raw_parsetree_list = pg_parse_query(cmd);
1543 
1544  /*
1545  * Process each parse tree (we allow the FDW to put more than one
1546  * command per string, though this isn't really advised).
1547  */
1548  foreach(lc2, raw_parsetree_list)
1549  {
1550  RawStmt *rs = lfirst_node(RawStmt, lc2);
1552  PlannedStmt *pstmt;
1553 
1554  /*
1555  * Because we only allow CreateForeignTableStmt, we can skip parse
1556  * analysis, rewrite, and planning steps here.
1557  */
1558  if (!IsA(cstmt, CreateForeignTableStmt))
1559  elog(ERROR,
1560  "foreign-data wrapper \"%s\" returned incorrect statement type %d",
1561  fdw->fdwname, (int) nodeTag(cstmt));
1562 
1563  /* Ignore commands for tables excluded by filter options */
1564  if (!IsImportableForeignTable(cstmt->base.relation->relname, stmt))
1565  continue;
1566 
1567  /* Enable reporting of current table's name on error */
1568  callback_arg.tablename = cstmt->base.relation->relname;
1569 
1570  /* Ensure creation schema is the one given in IMPORT statement */
1571  cstmt->base.relation->schemaname = pstrdup(stmt->local_schema);
1572 
1573  /* No planning needed, just make a wrapper PlannedStmt */
1574  pstmt = makeNode(PlannedStmt);
1575  pstmt->commandType = CMD_UTILITY;
1576  pstmt->canSetTag = false;
1577  pstmt->utilityStmt = (Node *) cstmt;
1578  pstmt->stmt_location = rs->stmt_location;
1579  pstmt->stmt_len = rs->stmt_len;
1580 
1581  /* Execute statement */
1582  ProcessUtility(pstmt, cmd, false,
1583  PROCESS_UTILITY_SUBCOMMAND, NULL, NULL,
1584  None_Receiver, NULL);
1585 
1586  /* Be sure to advance the command counter between subcommands */
1588 
1589  callback_arg.tablename = NULL;
1590  }
1591 
1592  error_context_stack = sqlerrcontext.previous;
1593  }
1594 }
DestReceiver * None_Receiver
Definition: dest.c:96
ErrorContextCallback * error_context_stack
Definition: elog.c:94
FdwRoutine * GetFdwRoutine(Oid fdwhandler)
Definition: foreign.c:321
bool IsImportableForeignTable(const char *tablename, ImportForeignSchemaStmt *stmt)
Definition: foreign.c:469
static void import_error_callback(void *arg)
Definition: foreigncmds.c:1600
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
char * pstrdup(const char *in)
Definition: mcxt.c:1483
Oid LookupCreationNamespace(const char *nspname)
Definition: namespace.c:2979
#define IsA(nodeptr, _type_)
Definition: nodes.h:168
#define nodeTag(nodeptr)
Definition: nodes.h:122
@ CMD_UTILITY
Definition: nodes.h:270
#define makeNode(_type_)
Definition: nodes.h:165
#define lfirst(lc)
Definition: pg_list.h:170
#define lfirst_node(type, lc)
Definition: pg_list.h:174
List * pg_parse_query(const char *query_string)
Definition: postgres.c:578
RangeVar * relation
Definition: parsenodes.h:2285
struct ErrorContextCallback * previous
Definition: elog.h:234
void(* callback)(void *arg)
Definition: elog.h:235
ImportForeignSchema_function ImportForeignSchema
Definition: fdwapi.h:260
Definition: pg_list.h:52
Definition: nodes.h:118
char * relname
Definition: primnodes.h:77
char * schemaname
Definition: primnodes.h:74
int stmt_len
Definition: parsenodes.h:1659
Node * stmt
Definition: parsenodes.h:1657
int stmt_location
Definition: parsenodes.h:1658
void ProcessUtility(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc)
Definition: utility.c:506
@ PROCESS_UTILITY_SUBCOMMAND
Definition: utility.h:26

References ACL_USAGE, aclcheck_error(), ACLCHECK_OK, ErrorContextCallback::arg, CreateForeignTableStmt::base, ErrorContextCallback::callback, import_error_callback_arg::cmd, CMD_UTILITY, CommandCounterIncrement(), elog(), ereport, errcode(), errmsg(), ERROR, error_context_stack, ForeignDataWrapper::fdwhandler, ForeignServer::fdwid, ForeignDataWrapper::fdwname, GetFdwRoutine(), GetForeignDataWrapper(), GetForeignServerByName(), GetUserId(), if(), import_error_callback(), FdwRoutine::ImportForeignSchema, IsA, IsImportableForeignTable(), lfirst, lfirst_node, ImportForeignSchemaStmt::local_schema, LookupCreationNamespace(), makeNode, nodeTag, None_Receiver, object_aclcheck(), OBJECT_FOREIGN_SERVER, OidIsValid, pg_parse_query(), ErrorContextCallback::previous, PROCESS_UTILITY_SUBCOMMAND, ProcessUtility(), pstrdup(), CreateStmt::relation, RangeVar::relname, RangeVar::schemaname, ImportForeignSchemaStmt::server_name, ForeignServer::serverid, ForeignServer::servername, RawStmt::stmt, RawStmt::stmt_len, RawStmt::stmt_location, and import_error_callback_arg::tablename.

Referenced by ProcessUtilitySlow().

◆ lookup_fdw_handler_func()

static Oid lookup_fdw_handler_func ( DefElem handler)
static

Definition at line 475 of file foreigncmds.c.

476 {
477  Oid handlerOid;
478 
479  if (handler == NULL || handler->arg == NULL)
480  return InvalidOid;
481 
482  /* handlers have no arguments */
483  handlerOid = LookupFuncName((List *) handler->arg, 0, NULL, false);
484 
485  /* check that handler has correct return type */
486  if (get_func_rettype(handlerOid) != FDW_HANDLEROID)
487  ereport(ERROR,
488  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
489  errmsg("function %s must return type %s",
490  NameListToString((List *) handler->arg), "fdw_handler")));
491 
492  return handlerOid;
493 }
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1637
char * NameListToString(List *names)
Definition: namespace.c:3145
Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool missing_ok)
Definition: parse_func.c:2146
#define InvalidOid
Definition: postgres_ext.h:36
Node * arg
Definition: parsenodes.h:780

References DefElem::arg, ereport, errcode(), errmsg(), ERROR, get_func_rettype(), InvalidOid, LookupFuncName(), and NameListToString().

Referenced by parse_func_options().

◆ lookup_fdw_validator_func()

static Oid lookup_fdw_validator_func ( DefElem validator)
static

Definition at line 499 of file foreigncmds.c.

500 {
501  Oid funcargtypes[2];
502 
503  if (validator == NULL || validator->arg == NULL)
504  return InvalidOid;
505 
506  /* validators take text[], oid */
507  funcargtypes[0] = TEXTARRAYOID;
508  funcargtypes[1] = OIDOID;
509 
510  return LookupFuncName((List *) validator->arg, 2, funcargtypes, false);
511  /* validator's return value is ignored, so we don't check the type */
512 }

References DefElem::arg, InvalidOid, and LookupFuncName().

Referenced by parse_func_options().

◆ optionListToArray()

static Datum optionListToArray ( List options)
static

Definition at line 66 of file foreigncmds.c.

67 {
68  ArrayBuildState *astate = NULL;
69  ListCell *cell;
70 
71  foreach(cell, options)
72  {
73  DefElem *def = lfirst(cell);
74  const char *value;
75  Size len;
76  text *t;
77 
78  value = defGetString(def);
79  len = VARHDRSZ + strlen(def->defname) + 1 + strlen(value);
80  t = palloc(len + 1);
81  SET_VARSIZE(t, len);
82  sprintf(VARDATA(t), "%s=%s", def->defname, value);
83 
84  astate = accumArrayResult(astate, PointerGetDatum(t),
85  false, TEXTOID,
87  }
88 
89  if (astate)
90  return makeArrayResult(astate, CurrentMemoryContext);
91 
92  return PointerGetDatum(NULL);
93 }
ArrayBuildState * accumArrayResult(ArrayBuildState *astate, Datum dvalue, bool disnull, Oid element_type, MemoryContext rcontext)
Definition: arrayfuncs.c:5277
Datum makeArrayResult(ArrayBuildState *astate, MemoryContext rcontext)
Definition: arrayfuncs.c:5341
#define VARHDRSZ
Definition: c.h:628
size_t Size
Definition: c.h:541
char * defGetString(DefElem *def)
Definition: define.c:49
static struct @143 value
MemoryContext CurrentMemoryContext
Definition: mcxt.c:124
void * palloc(Size size)
Definition: mcxt.c:1199
const void size_t len
#define sprintf
Definition: port.h:240
#define VARDATA(PTR)
Definition: postgres.h:316
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:343
char * defname
Definition: parsenodes.h:779
Definition: c.h:623

References accumArrayResult(), CurrentMemoryContext, defGetString(), DefElem::defname, len, lfirst, makeArrayResult(), palloc(), PointerGetDatum(), SET_VARSIZE, sprintf, value, VARDATA, and VARHDRSZ.

Referenced by transformGenericOptions().

◆ parse_func_options()

static void parse_func_options ( ParseState pstate,
List func_options,
bool handler_given,
Oid fdwhandler,
bool validator_given,
Oid fdwvalidator 
)
static

Definition at line 518 of file foreigncmds.c.

521 {
522  ListCell *cell;
523 
524  *handler_given = false;
525  *validator_given = false;
526  /* return InvalidOid if not given */
527  *fdwhandler = InvalidOid;
528  *fdwvalidator = InvalidOid;
529 
530  foreach(cell, func_options)
531  {
532  DefElem *def = (DefElem *) lfirst(cell);
533 
534  if (strcmp(def->defname, "handler") == 0)
535  {
536  if (*handler_given)
537  errorConflictingDefElem(def, pstate);
538  *handler_given = true;
539  *fdwhandler = lookup_fdw_handler_func(def);
540  }
541  else if (strcmp(def->defname, "validator") == 0)
542  {
543  if (*validator_given)
544  errorConflictingDefElem(def, pstate);
545  *validator_given = true;
546  *fdwvalidator = lookup_fdw_validator_func(def);
547  }
548  else
549  elog(ERROR, "option \"%s\" not recognized",
550  def->defname);
551  }
552 }
void errorConflictingDefElem(DefElem *defel, ParseState *pstate)
Definition: define.c:385
static Oid lookup_fdw_handler_func(DefElem *handler)
Definition: foreigncmds.c:475
static Oid lookup_fdw_validator_func(DefElem *validator)
Definition: foreigncmds.c:499

References DefElem::defname, elog(), ERROR, errorConflictingDefElem(), InvalidOid, lfirst, lookup_fdw_handler_func(), and lookup_fdw_validator_func().

Referenced by AlterForeignDataWrapper(), and CreateForeignDataWrapper().

◆ RemoveUserMapping()

Oid RemoveUserMapping ( DropUserMappingStmt stmt)

Definition at line 1324 of file foreigncmds.c.

1325 {
1326  ObjectAddress object;
1327  Oid useId;
1328  Oid umId;
1329  ForeignServer *srv;
1330  RoleSpec *role = (RoleSpec *) stmt->user;
1331 
1332  if (role->roletype == ROLESPEC_PUBLIC)
1333  useId = ACL_ID_PUBLIC;
1334  else
1335  {
1336  useId = get_rolespec_oid(stmt->user, stmt->missing_ok);
1337  if (!OidIsValid(useId))
1338  {
1339  /*
1340  * IF EXISTS specified, role not found and not public. Notice this
1341  * and leave.
1342  */
1343  elog(NOTICE, "role \"%s\" does not exist, skipping",
1344  role->rolename);
1345  return InvalidOid;
1346  }
1347  }
1348 
1349  srv = GetForeignServerByName(stmt->servername, true);
1350 
1351  if (!srv)
1352  {
1353  if (!stmt->missing_ok)
1354  ereport(ERROR,
1355  (errcode(ERRCODE_UNDEFINED_OBJECT),
1356  errmsg("server \"%s\" does not exist",
1357  stmt->servername)));
1358  /* IF EXISTS, just note it */
1359  ereport(NOTICE,
1360  (errmsg("server \"%s\" does not exist, skipping",
1361  stmt->servername)));
1362  return InvalidOid;
1363  }
1364 
1365  umId = GetSysCacheOid2(USERMAPPINGUSERSERVER, Anum_pg_user_mapping_oid,
1366  ObjectIdGetDatum(useId),
1367  ObjectIdGetDatum(srv->serverid));
1368 
1369  if (!OidIsValid(umId))
1370  {
1371  if (!stmt->missing_ok)
1372  ereport(ERROR,
1373  (errcode(ERRCODE_UNDEFINED_OBJECT),
1374  errmsg("user mapping for \"%s\" does not exist for server \"%s\"",
1375  MappingUserName(useId), stmt->servername)));
1376 
1377  /* IF EXISTS specified, just note it */
1378  ereport(NOTICE,
1379  (errmsg("user mapping for \"%s\" does not exist for server \"%s\", skipping",
1380  MappingUserName(useId), stmt->servername)));
1381  return InvalidOid;
1382  }
1383 
1384  user_mapping_ddl_aclcheck(useId, srv->serverid, srv->servername);
1385 
1386  /*
1387  * Do the deletion
1388  */
1389  object.classId = UserMappingRelationId;
1390  object.objectId = umId;
1391  object.objectSubId = 0;
1392 
1393  performDeletion(&object, DROP_CASCADE, 0);
1394 
1395  return umId;
1396 }
void performDeletion(const ObjectAddress *object, DropBehavior behavior, int flags)
Definition: dependency.c:322
@ DROP_CASCADE
Definition: parsenodes.h:1962
char * rolename
Definition: parsenodes.h:372

References ACL_ID_PUBLIC, DROP_CASCADE, elog(), ereport, errcode(), errmsg(), ERROR, get_rolespec_oid(), GetForeignServerByName(), GetSysCacheOid2, if(), InvalidOid, MappingUserName, DropUserMappingStmt::missing_ok, NOTICE, ObjectIdGetDatum(), OidIsValid, performDeletion(), RoleSpec::rolename, ROLESPEC_PUBLIC, RoleSpec::roletype, ForeignServer::serverid, ForeignServer::servername, DropUserMappingStmt::servername, DropUserMappingStmt::user, and user_mapping_ddl_aclcheck().

Referenced by ProcessUtilitySlow().

◆ transformGenericOptions()

Datum transformGenericOptions ( Oid  catalogId,
Datum  oldOptions,
List options,
Oid  fdwvalidator 
)

Definition at line 110 of file foreigncmds.c.

114 {
115  List *resultOptions = untransformRelOptions(oldOptions);
116  ListCell *optcell;
117  Datum result;
118 
119  foreach(optcell, options)
120  {
121  DefElem *od = lfirst(optcell);
122  ListCell *cell;
123 
124  /*
125  * Find the element in resultOptions. We need this for validation in
126  * all cases.
127  */
128  foreach(cell, resultOptions)
129  {
130  DefElem *def = lfirst(cell);
131 
132  if (strcmp(def->defname, od->defname) == 0)
133  break;
134  }
135 
136  /*
137  * It is possible to perform multiple SET/DROP actions on the same
138  * option. The standard permits this, as long as the options to be
139  * added are unique. Note that an unspecified action is taken to be
140  * ADD.
141  */
142  switch (od->defaction)
143  {
144  case DEFELEM_DROP:
145  if (!cell)
146  ereport(ERROR,
147  (errcode(ERRCODE_UNDEFINED_OBJECT),
148  errmsg("option \"%s\" not found",
149  od->defname)));
150  resultOptions = list_delete_cell(resultOptions, cell);
151  break;
152 
153  case DEFELEM_SET:
154  if (!cell)
155  ereport(ERROR,
156  (errcode(ERRCODE_UNDEFINED_OBJECT),
157  errmsg("option \"%s\" not found",
158  od->defname)));
159  lfirst(cell) = od;
160  break;
161 
162  case DEFELEM_ADD:
163  case DEFELEM_UNSPEC:
164  if (cell)
165  ereport(ERROR,
167  errmsg("option \"%s\" provided more than once",
168  od->defname)));
169  resultOptions = lappend(resultOptions, od);
170  break;
171 
172  default:
173  elog(ERROR, "unrecognized action %d on option \"%s\"",
174  (int) od->defaction, od->defname);
175  break;
176  }
177  }
178 
179  result = optionListToArray(resultOptions);
180 
181  if (OidIsValid(fdwvalidator))
182  {
183  Datum valarg = result;
184 
185  /*
186  * Pass a null options list as an empty array, so that validators
187  * don't have to be declared non-strict to handle the case.
188  */
189  if (DatumGetPointer(valarg) == NULL)
190  valarg = PointerGetDatum(construct_empty_array(TEXTOID));
191  OidFunctionCall2(fdwvalidator, valarg, ObjectIdGetDatum(catalogId));
192  }
193 
194  return result;
195 }
ArrayType * construct_empty_array(Oid elmtype)
Definition: arrayfuncs.c:3525
#define OidFunctionCall2(functionId, arg1, arg2)
Definition: fmgr.h:682
static Datum optionListToArray(List *options)
Definition: foreigncmds.c:66
List * lappend(List *list, void *datum)
Definition: list.c:338
List * list_delete_cell(List *list, ListCell *cell)
Definition: list.c:840
@ DEFELEM_UNSPEC
Definition: parsenodes.h:769
@ DEFELEM_DROP
Definition: parsenodes.h:772
@ DEFELEM_SET
Definition: parsenodes.h:770
@ DEFELEM_ADD
Definition: parsenodes.h:771
List * untransformRelOptions(Datum options)
Definition: reloptions.c:1333
DefElemAction defaction
Definition: parsenodes.h:782

References construct_empty_array(), DatumGetPointer(), DefElem::defaction, DEFELEM_ADD, DEFELEM_DROP, DEFELEM_SET, DEFELEM_UNSPEC, DefElem::defname, elog(), ereport, errcode(), ERRCODE_DUPLICATE_OBJECT, errmsg(), ERROR, lappend(), lfirst, list_delete_cell(), ObjectIdGetDatum(), OidFunctionCall2, OidIsValid, optionListToArray(), PointerGetDatum(), and untransformRelOptions().

Referenced by AlterForeignDataWrapper(), AlterForeignServer(), AlterUserMapping(), ATExecAlterColumnGenericOptions(), ATExecGenericOptions(), CreateForeignDataWrapper(), CreateForeignServer(), CreateForeignTable(), and CreateUserMapping().

◆ user_mapping_ddl_aclcheck()

static void user_mapping_ddl_aclcheck ( Oid  umuserid,
Oid  serverid,
const char *  servername 
)
static

Definition at line 1075 of file foreigncmds.c.

1076 {
1077  Oid curuserid = GetUserId();
1078 
1079  if (!object_ownercheck(ForeignServerRelationId, serverid, curuserid))
1080  {
1081  if (umuserid == curuserid)
1082  {
1083  AclResult aclresult;
1084 
1085  aclresult = object_aclcheck(ForeignServerRelationId, serverid, curuserid, ACL_USAGE);
1086  if (aclresult != ACLCHECK_OK)
1087  aclcheck_error(aclresult, OBJECT_FOREIGN_SERVER, servername);
1088  }
1089  else
1091  servername);
1092  }
1093 }

References ACL_USAGE, aclcheck_error(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, GetUserId(), object_aclcheck(), OBJECT_FOREIGN_SERVER, and object_ownercheck().

Referenced by AlterUserMapping(), CreateUserMapping(), and RemoveUserMapping().