PageRenderTime 54ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/src/backend/commands/foreigncmds.c

https://bitbucket.org/gencer/postgres
C | 1429 lines | 893 code | 286 blank | 250 comment | 101 complexity | 9a29c3a1e0f58bfc05a598882f5dcf1e MD5 | raw file
Possible License(s): AGPL-3.0
  1. /*-------------------------------------------------------------------------
  2. *
  3. * foreigncmds.c
  4. * foreign-data wrapper/server creation/manipulation commands
  5. *
  6. * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
  7. *
  8. *
  9. * IDENTIFICATION
  10. * src/backend/commands/foreigncmds.c
  11. *
  12. *-------------------------------------------------------------------------
  13. */
  14. #include "postgres.h"
  15. #include "access/heapam.h"
  16. #include "access/htup_details.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. * Convert a DefElem list to the text array format that is used in
  39. * pg_foreign_data_wrapper, pg_foreign_server, pg_user_mapping, and
  40. * pg_foreign_table.
  41. *
  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. foreach(cell, options)
  55. {
  56. DefElem *def = lfirst(cell);
  57. const char *value;
  58. Size len;
  59. text *t;
  60. value = defGetString(def);
  61. len = VARHDRSZ + strlen(def->defname) + 1 + strlen(value);
  62. t = palloc(len + 1);
  63. SET_VARSIZE(t, len);
  64. sprintf(VARDATA(t), "%s=%s", def->defname, value);
  65. astate = accumArrayResult(astate, PointerGetDatum(t),
  66. false, TEXTOID,
  67. CurrentMemoryContext);
  68. }
  69. if (astate)
  70. return makeArrayResult(astate, CurrentMemoryContext);
  71. return PointerGetDatum(NULL);
  72. }
  73. /*
  74. * Transform a list of DefElem into text array format. This is substantially
  75. * the same thing as optionListToArray(), except we recognize SET/ADD/DROP
  76. * actions for modifying an existing list of options, which is passed in
  77. * Datum form as oldOptions. Also, if fdwvalidator isn't InvalidOid
  78. * it specifies a validator function to call on the result.
  79. *
  80. * Returns the array in the form of a Datum, or PointerGetDatum(NULL)
  81. * if the list is empty.
  82. *
  83. * This is used by CREATE/ALTER of FOREIGN DATA WRAPPER/SERVER/USER MAPPING/
  84. * FOREIGN TABLE.
  85. */
  86. Datum
  87. transformGenericOptions(Oid catalogId,
  88. Datum oldOptions,
  89. List *options,
  90. Oid fdwvalidator)
  91. {
  92. List *resultOptions = untransformRelOptions(oldOptions);
  93. ListCell *optcell;
  94. Datum result;
  95. foreach(optcell, options)
  96. {
  97. DefElem *od = lfirst(optcell);
  98. ListCell *cell;
  99. ListCell *prev = NULL;
  100. /*
  101. * Find the element in resultOptions. We need this for validation in
  102. * all cases. Also identify the previous element.
  103. */
  104. foreach(cell, resultOptions)
  105. {
  106. DefElem *def = lfirst(cell);
  107. if (strcmp(def->defname, od->defname) == 0)
  108. break;
  109. else
  110. prev = cell;
  111. }
  112. /*
  113. * It is possible to perform multiple SET/DROP actions on the same
  114. * option. The standard permits this, as long as the options to be
  115. * added are unique. Note that an unspecified action is taken to be
  116. * ADD.
  117. */
  118. switch (od->defaction)
  119. {
  120. case DEFELEM_DROP:
  121. if (!cell)
  122. ereport(ERROR,
  123. (errcode(ERRCODE_UNDEFINED_OBJECT),
  124. errmsg("option \"%s\" not found",
  125. od->defname)));
  126. resultOptions = list_delete_cell(resultOptions, cell, prev);
  127. break;
  128. case DEFELEM_SET:
  129. if (!cell)
  130. ereport(ERROR,
  131. (errcode(ERRCODE_UNDEFINED_OBJECT),
  132. errmsg("option \"%s\" not found",
  133. od->defname)));
  134. lfirst(cell) = od;
  135. break;
  136. case DEFELEM_ADD:
  137. case DEFELEM_UNSPEC:
  138. if (cell)
  139. ereport(ERROR,
  140. (errcode(ERRCODE_DUPLICATE_OBJECT),
  141. errmsg("option \"%s\" provided more than once",
  142. od->defname)));
  143. resultOptions = lappend(resultOptions, od);
  144. break;
  145. default:
  146. elog(ERROR, "unrecognized action %d on option \"%s\"",
  147. (int) od->defaction, od->defname);
  148. break;
  149. }
  150. }
  151. result = optionListToArray(resultOptions);
  152. if (OidIsValid(fdwvalidator))
  153. {
  154. Datum valarg = result;
  155. /*
  156. * Pass a null options list as an empty array, so that validators
  157. * don't have to be declared non-strict to handle the case.
  158. */
  159. if (DatumGetPointer(valarg) == NULL)
  160. valarg = PointerGetDatum(construct_empty_array(TEXTOID));
  161. OidFunctionCall2(fdwvalidator, valarg, ObjectIdGetDatum(catalogId));
  162. }
  163. return result;
  164. }
  165. /*
  166. * Convert the user mapping user name to OID
  167. */
  168. static Oid
  169. GetUserOidFromMapping(const char *username, bool missing_ok)
  170. {
  171. if (!username)
  172. /* PUBLIC user mapping */
  173. return InvalidOid;
  174. if (strcmp(username, "current_user") == 0)
  175. /* map to the owner */
  176. return GetUserId();
  177. /* map to provided user */
  178. return get_role_oid(username, missing_ok);
  179. }
  180. /*
  181. * Internal workhorse for changing a data wrapper's owner.
  182. *
  183. * Allow this only for superusers; also the new owner must be a
  184. * superuser.
  185. */
  186. static void
  187. AlterForeignDataWrapperOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
  188. {
  189. Form_pg_foreign_data_wrapper form;
  190. form = (Form_pg_foreign_data_wrapper) GETSTRUCT(tup);
  191. /* Must be a superuser to change a FDW owner */
  192. if (!superuser())
  193. ereport(ERROR,
  194. (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  195. errmsg("permission denied to change owner of foreign-data wrapper \"%s\"",
  196. NameStr(form->fdwname)),
  197. errhint("Must be superuser to change owner of a foreign-data wrapper.")));
  198. /* New owner must also be a superuser */
  199. if (!superuser_arg(newOwnerId))
  200. ereport(ERROR,
  201. (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  202. errmsg("permission denied to change owner of foreign-data wrapper \"%s\"",
  203. NameStr(form->fdwname)),
  204. errhint("The owner of a foreign-data wrapper must be a superuser.")));
  205. if (form->fdwowner != newOwnerId)
  206. {
  207. form->fdwowner = newOwnerId;
  208. simple_heap_update(rel, &tup->t_self, tup);
  209. CatalogUpdateIndexes(rel, tup);
  210. /* Update owner dependency reference */
  211. changeDependencyOnOwner(ForeignDataWrapperRelationId,
  212. HeapTupleGetOid(tup),
  213. newOwnerId);
  214. }
  215. InvokeObjectPostAlterHook(ForeignDataWrapperRelationId,
  216. HeapTupleGetOid(tup), 0);
  217. }
  218. /*
  219. * Change foreign-data wrapper owner -- by name
  220. *
  221. * Note restrictions in the "_internal" function, above.
  222. */
  223. Oid
  224. AlterForeignDataWrapperOwner(const char *name, Oid newOwnerId)
  225. {
  226. Oid fdwId;
  227. HeapTuple tup;
  228. Relation rel;
  229. rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
  230. tup = SearchSysCacheCopy1(FOREIGNDATAWRAPPERNAME, CStringGetDatum(name));
  231. if (!HeapTupleIsValid(tup))
  232. ereport(ERROR,
  233. (errcode(ERRCODE_UNDEFINED_OBJECT),
  234. errmsg("foreign-data wrapper \"%s\" does not exist", name)));
  235. fdwId = HeapTupleGetOid(tup);
  236. AlterForeignDataWrapperOwner_internal(rel, tup, newOwnerId);
  237. heap_freetuple(tup);
  238. heap_close(rel, RowExclusiveLock);
  239. return fdwId;
  240. }
  241. /*
  242. * Change foreign-data wrapper owner -- by OID
  243. *
  244. * Note restrictions in the "_internal" function, above.
  245. */
  246. void
  247. AlterForeignDataWrapperOwner_oid(Oid fwdId, Oid newOwnerId)
  248. {
  249. HeapTuple tup;
  250. Relation rel;
  251. rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
  252. tup = SearchSysCacheCopy1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fwdId));
  253. if (!HeapTupleIsValid(tup))
  254. ereport(ERROR,
  255. (errcode(ERRCODE_UNDEFINED_OBJECT),
  256. errmsg("foreign-data wrapper with OID %u does not exist", fwdId)));
  257. AlterForeignDataWrapperOwner_internal(rel, tup, newOwnerId);
  258. heap_freetuple(tup);
  259. heap_close(rel, RowExclusiveLock);
  260. }
  261. /*
  262. * Internal workhorse for changing a foreign server's owner
  263. */
  264. static void
  265. AlterForeignServerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
  266. {
  267. Form_pg_foreign_server form;
  268. form = (Form_pg_foreign_server) GETSTRUCT(tup);
  269. if (form->srvowner != newOwnerId)
  270. {
  271. /* Superusers can always do it */
  272. if (!superuser())
  273. {
  274. Oid srvId;
  275. AclResult aclresult;
  276. srvId = HeapTupleGetOid(tup);
  277. /* Must be owner */
  278. if (!pg_foreign_server_ownercheck(srvId, GetUserId()))
  279. aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
  280. NameStr(form->srvname));
  281. /* Must be able to become new owner */
  282. check_is_member_of_role(GetUserId(), newOwnerId);
  283. /* New owner must have USAGE privilege on foreign-data wrapper */
  284. aclresult = pg_foreign_data_wrapper_aclcheck(form->srvfdw, newOwnerId, ACL_USAGE);
  285. if (aclresult != ACLCHECK_OK)
  286. {
  287. ForeignDataWrapper *fdw = GetForeignDataWrapper(form->srvfdw);
  288. aclcheck_error(aclresult, ACL_KIND_FDW, fdw->fdwname);
  289. }
  290. }
  291. form->srvowner = newOwnerId;
  292. simple_heap_update(rel, &tup->t_self, tup);
  293. CatalogUpdateIndexes(rel, tup);
  294. /* Update owner dependency reference */
  295. changeDependencyOnOwner(ForeignServerRelationId, HeapTupleGetOid(tup),
  296. newOwnerId);
  297. }
  298. InvokeObjectPostAlterHook(ForeignServerRelationId,
  299. HeapTupleGetOid(tup), 0);
  300. }
  301. /*
  302. * Change foreign server owner -- by name
  303. */
  304. Oid
  305. AlterForeignServerOwner(const char *name, Oid newOwnerId)
  306. {
  307. Oid servOid;
  308. HeapTuple tup;
  309. Relation rel;
  310. rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
  311. tup = SearchSysCacheCopy1(FOREIGNSERVERNAME, CStringGetDatum(name));
  312. if (!HeapTupleIsValid(tup))
  313. ereport(ERROR,
  314. (errcode(ERRCODE_UNDEFINED_OBJECT),
  315. errmsg("server \"%s\" does not exist", name)));
  316. servOid = HeapTupleGetOid(tup);
  317. AlterForeignServerOwner_internal(rel, tup, newOwnerId);
  318. heap_freetuple(tup);
  319. heap_close(rel, RowExclusiveLock);
  320. return servOid;
  321. }
  322. /*
  323. * Change foreign server owner -- by OID
  324. */
  325. void
  326. AlterForeignServerOwner_oid(Oid srvId, Oid newOwnerId)
  327. {
  328. HeapTuple tup;
  329. Relation rel;
  330. rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
  331. tup = SearchSysCacheCopy1(FOREIGNSERVEROID, ObjectIdGetDatum(srvId));
  332. if (!HeapTupleIsValid(tup))
  333. ereport(ERROR,
  334. (errcode(ERRCODE_UNDEFINED_OBJECT),
  335. errmsg("foreign server with OID %u does not exist", srvId)));
  336. AlterForeignServerOwner_internal(rel, tup, newOwnerId);
  337. heap_freetuple(tup);
  338. heap_close(rel, RowExclusiveLock);
  339. }
  340. /*
  341. * Convert a handler function name passed from the parser to an Oid.
  342. */
  343. static Oid
  344. lookup_fdw_handler_func(DefElem *handler)
  345. {
  346. Oid handlerOid;
  347. if (handler == NULL || handler->arg == NULL)
  348. return InvalidOid;
  349. /* handlers have no arguments */
  350. handlerOid = LookupFuncName((List *) handler->arg, 0, NULL, false);
  351. /* check that handler has correct return type */
  352. if (get_func_rettype(handlerOid) != FDW_HANDLEROID)
  353. ereport(ERROR,
  354. (errcode(ERRCODE_WRONG_OBJECT_TYPE),
  355. errmsg("function %s must return type \"fdw_handler\"",
  356. NameListToString((List *) handler->arg))));
  357. return handlerOid;
  358. }
  359. /*
  360. * Convert a validator function name passed from the parser to an Oid.
  361. */
  362. static Oid
  363. lookup_fdw_validator_func(DefElem *validator)
  364. {
  365. Oid funcargtypes[2];
  366. if (validator == NULL || validator->arg == NULL)
  367. return InvalidOid;
  368. /* validators take text[], oid */
  369. funcargtypes[0] = TEXTARRAYOID;
  370. funcargtypes[1] = OIDOID;
  371. return LookupFuncName((List *) validator->arg, 2, funcargtypes, false);
  372. /* validator's return value is ignored, so we don't check the type */
  373. }
  374. /*
  375. * Process function options of CREATE/ALTER FDW
  376. */
  377. static void
  378. parse_func_options(List *func_options,
  379. bool *handler_given, Oid *fdwhandler,
  380. bool *validator_given, Oid *fdwvalidator)
  381. {
  382. ListCell *cell;
  383. *handler_given = false;
  384. *validator_given = false;
  385. /* return InvalidOid if not given */
  386. *fdwhandler = InvalidOid;
  387. *fdwvalidator = InvalidOid;
  388. foreach(cell, func_options)
  389. {
  390. DefElem *def = (DefElem *) lfirst(cell);
  391. if (strcmp(def->defname, "handler") == 0)
  392. {
  393. if (*handler_given)
  394. ereport(ERROR,
  395. (errcode(ERRCODE_SYNTAX_ERROR),
  396. errmsg("conflicting or redundant options")));
  397. *handler_given = true;
  398. *fdwhandler = lookup_fdw_handler_func(def);
  399. }
  400. else if (strcmp(def->defname, "validator") == 0)
  401. {
  402. if (*validator_given)
  403. ereport(ERROR,
  404. (errcode(ERRCODE_SYNTAX_ERROR),
  405. errmsg("conflicting or redundant options")));
  406. *validator_given = true;
  407. *fdwvalidator = lookup_fdw_validator_func(def);
  408. }
  409. else
  410. elog(ERROR, "option \"%s\" not recognized",
  411. def->defname);
  412. }
  413. }
  414. /*
  415. * Create a foreign-data wrapper
  416. */
  417. Oid
  418. CreateForeignDataWrapper(CreateFdwStmt *stmt)
  419. {
  420. Relation rel;
  421. Datum values[Natts_pg_foreign_data_wrapper];
  422. bool nulls[Natts_pg_foreign_data_wrapper];
  423. HeapTuple tuple;
  424. Oid fdwId;
  425. bool handler_given;
  426. bool validator_given;
  427. Oid fdwhandler;
  428. Oid fdwvalidator;
  429. Datum fdwoptions;
  430. Oid ownerId;
  431. ObjectAddress myself;
  432. ObjectAddress referenced;
  433. rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
  434. /* Must be super user */
  435. if (!superuser())
  436. ereport(ERROR,
  437. (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  438. errmsg("permission denied to create foreign-data wrapper \"%s\"",
  439. stmt->fdwname),
  440. errhint("Must be superuser to create a foreign-data wrapper.")));
  441. /* For now the owner cannot be specified on create. Use effective user ID. */
  442. ownerId = GetUserId();
  443. /*
  444. * Check that there is no other foreign-data wrapper by this name.
  445. */
  446. if (GetForeignDataWrapperByName(stmt->fdwname, true) != NULL)
  447. ereport(ERROR,
  448. (errcode(ERRCODE_DUPLICATE_OBJECT),
  449. errmsg("foreign-data wrapper \"%s\" already exists",
  450. stmt->fdwname)));
  451. /*
  452. * Insert tuple into pg_foreign_data_wrapper.
  453. */
  454. memset(values, 0, sizeof(values));
  455. memset(nulls, false, sizeof(nulls));
  456. values[Anum_pg_foreign_data_wrapper_fdwname - 1] =
  457. DirectFunctionCall1(namein, CStringGetDatum(stmt->fdwname));
  458. values[Anum_pg_foreign_data_wrapper_fdwowner - 1] = ObjectIdGetDatum(ownerId);
  459. /* Lookup handler and validator functions, if given */
  460. parse_func_options(stmt->func_options,
  461. &handler_given, &fdwhandler,
  462. &validator_given, &fdwvalidator);
  463. values[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = ObjectIdGetDatum(fdwhandler);
  464. values[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = ObjectIdGetDatum(fdwvalidator);
  465. nulls[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true;
  466. fdwoptions = transformGenericOptions(ForeignDataWrapperRelationId,
  467. PointerGetDatum(NULL),
  468. stmt->options,
  469. fdwvalidator);
  470. if (PointerIsValid(DatumGetPointer(fdwoptions)))
  471. values[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = fdwoptions;
  472. else
  473. nulls[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true;
  474. tuple = heap_form_tuple(rel->rd_att, values, nulls);
  475. fdwId = simple_heap_insert(rel, tuple);
  476. CatalogUpdateIndexes(rel, tuple);
  477. heap_freetuple(tuple);
  478. /* record dependencies */
  479. myself.classId = ForeignDataWrapperRelationId;
  480. myself.objectId = fdwId;
  481. myself.objectSubId = 0;
  482. if (OidIsValid(fdwhandler))
  483. {
  484. referenced.classId = ProcedureRelationId;
  485. referenced.objectId = fdwhandler;
  486. referenced.objectSubId = 0;
  487. recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
  488. }
  489. if (OidIsValid(fdwvalidator))
  490. {
  491. referenced.classId = ProcedureRelationId;
  492. referenced.objectId = fdwvalidator;
  493. referenced.objectSubId = 0;
  494. recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
  495. }
  496. recordDependencyOnOwner(ForeignDataWrapperRelationId, fdwId, ownerId);
  497. /* dependency on extension */
  498. recordDependencyOnCurrentExtension(&myself, false);
  499. /* Post creation hook for new foreign data wrapper */
  500. InvokeObjectPostCreateHook(ForeignDataWrapperRelationId, fdwId, 0);
  501. heap_close(rel, RowExclusiveLock);
  502. return fdwId;
  503. }
  504. /*
  505. * Alter foreign-data wrapper
  506. */
  507. Oid
  508. AlterForeignDataWrapper(AlterFdwStmt *stmt)
  509. {
  510. Relation rel;
  511. HeapTuple tp;
  512. Form_pg_foreign_data_wrapper fdwForm;
  513. Datum repl_val[Natts_pg_foreign_data_wrapper];
  514. bool repl_null[Natts_pg_foreign_data_wrapper];
  515. bool repl_repl[Natts_pg_foreign_data_wrapper];
  516. Oid fdwId;
  517. bool isnull;
  518. Datum datum;
  519. bool handler_given;
  520. bool validator_given;
  521. Oid fdwhandler;
  522. Oid fdwvalidator;
  523. rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
  524. /* Must be super user */
  525. if (!superuser())
  526. ereport(ERROR,
  527. (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  528. errmsg("permission denied to alter foreign-data wrapper \"%s\"",
  529. stmt->fdwname),
  530. errhint("Must be superuser to alter a foreign-data wrapper.")));
  531. tp = SearchSysCacheCopy1(FOREIGNDATAWRAPPERNAME,
  532. CStringGetDatum(stmt->fdwname));
  533. if (!HeapTupleIsValid(tp))
  534. ereport(ERROR,
  535. (errcode(ERRCODE_UNDEFINED_OBJECT),
  536. errmsg("foreign-data wrapper \"%s\" does not exist", stmt->fdwname)));
  537. fdwForm = (Form_pg_foreign_data_wrapper) GETSTRUCT(tp);
  538. fdwId = HeapTupleGetOid(tp);
  539. memset(repl_val, 0, sizeof(repl_val));
  540. memset(repl_null, false, sizeof(repl_null));
  541. memset(repl_repl, false, sizeof(repl_repl));
  542. parse_func_options(stmt->func_options,
  543. &handler_given, &fdwhandler,
  544. &validator_given, &fdwvalidator);
  545. if (handler_given)
  546. {
  547. repl_val[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = ObjectIdGetDatum(fdwhandler);
  548. repl_repl[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = true;
  549. /*
  550. * It could be that the behavior of accessing foreign table changes
  551. * with the new handler. Warn about this.
  552. */
  553. ereport(WARNING,
  554. (errmsg("changing the foreign-data wrapper handler can change behavior of existing foreign tables")));
  555. }
  556. if (validator_given)
  557. {
  558. repl_val[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = ObjectIdGetDatum(fdwvalidator);
  559. repl_repl[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = true;
  560. /*
  561. * It could be that existing options for the FDW or dependent SERVER,
  562. * USER MAPPING or FOREIGN TABLE objects are no longer valid according
  563. * to the new validator. Warn about this.
  564. */
  565. if (OidIsValid(fdwvalidator))
  566. ereport(WARNING,
  567. (errmsg("changing the foreign-data wrapper validator can cause "
  568. "the options for dependent objects to become invalid")));
  569. }
  570. else
  571. {
  572. /*
  573. * Validator is not changed, but we need it for validating options.
  574. */
  575. fdwvalidator = fdwForm->fdwvalidator;
  576. }
  577. /*
  578. * If options specified, validate and update.
  579. */
  580. if (stmt->options)
  581. {
  582. /* Extract the current options */
  583. datum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID,
  584. tp,
  585. Anum_pg_foreign_data_wrapper_fdwoptions,
  586. &isnull);
  587. if (isnull)
  588. datum = PointerGetDatum(NULL);
  589. /* Transform the options */
  590. datum = transformGenericOptions(ForeignDataWrapperRelationId,
  591. datum,
  592. stmt->options,
  593. fdwvalidator);
  594. if (PointerIsValid(DatumGetPointer(datum)))
  595. repl_val[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = datum;
  596. else
  597. repl_null[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true;
  598. repl_repl[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true;
  599. }
  600. /* Everything looks good - update the tuple */
  601. tp = heap_modify_tuple(tp, RelationGetDescr(rel),
  602. repl_val, repl_null, repl_repl);
  603. simple_heap_update(rel, &tp->t_self, tp);
  604. CatalogUpdateIndexes(rel, tp);
  605. heap_freetuple(tp);
  606. /* Update function dependencies if we changed them */
  607. if (handler_given || validator_given)
  608. {
  609. ObjectAddress myself;
  610. ObjectAddress referenced;
  611. /*
  612. * Flush all existing dependency records of this FDW on functions; we
  613. * assume there can be none other than the ones we are fixing.
  614. */
  615. deleteDependencyRecordsForClass(ForeignDataWrapperRelationId,
  616. fdwId,
  617. ProcedureRelationId,
  618. DEPENDENCY_NORMAL);
  619. /* And build new ones. */
  620. myself.classId = ForeignDataWrapperRelationId;
  621. myself.objectId = fdwId;
  622. myself.objectSubId = 0;
  623. if (OidIsValid(fdwhandler))
  624. {
  625. referenced.classId = ProcedureRelationId;
  626. referenced.objectId = fdwhandler;
  627. referenced.objectSubId = 0;
  628. recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
  629. }
  630. if (OidIsValid(fdwvalidator))
  631. {
  632. referenced.classId = ProcedureRelationId;
  633. referenced.objectId = fdwvalidator;
  634. referenced.objectSubId = 0;
  635. recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
  636. }
  637. }
  638. InvokeObjectPostAlterHook(ForeignDataWrapperRelationId, fdwId, 0);
  639. heap_close(rel, RowExclusiveLock);
  640. return fdwId;
  641. }
  642. /*
  643. * Drop foreign-data wrapper by OID
  644. */
  645. void
  646. RemoveForeignDataWrapperById(Oid fdwId)
  647. {
  648. HeapTuple tp;
  649. Relation rel;
  650. rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
  651. tp = SearchSysCache1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fdwId));
  652. if (!HeapTupleIsValid(tp))
  653. elog(ERROR, "cache lookup failed for foreign-data wrapper %u", fdwId);
  654. simple_heap_delete(rel, &tp->t_self);
  655. ReleaseSysCache(tp);
  656. heap_close(rel, RowExclusiveLock);
  657. }
  658. /*
  659. * Create a foreign server
  660. */
  661. Oid
  662. CreateForeignServer(CreateForeignServerStmt *stmt)
  663. {
  664. Relation rel;
  665. Datum srvoptions;
  666. Datum values[Natts_pg_foreign_server];
  667. bool nulls[Natts_pg_foreign_server];
  668. HeapTuple tuple;
  669. Oid srvId;
  670. Oid ownerId;
  671. AclResult aclresult;
  672. ObjectAddress myself;
  673. ObjectAddress referenced;
  674. ForeignDataWrapper *fdw;
  675. rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
  676. /* For now the owner cannot be specified on create. Use effective user ID. */
  677. ownerId = GetUserId();
  678. /*
  679. * Check that there is no other foreign server by this name.
  680. */
  681. if (GetForeignServerByName(stmt->servername, true) != NULL)
  682. ereport(ERROR,
  683. (errcode(ERRCODE_DUPLICATE_OBJECT),
  684. errmsg("server \"%s\" already exists",
  685. stmt->servername)));
  686. /*
  687. * Check that the FDW exists and that we have USAGE on it. Also get the
  688. * actual FDW for option validation etc.
  689. */
  690. fdw = GetForeignDataWrapperByName(stmt->fdwname, false);
  691. aclresult = pg_foreign_data_wrapper_aclcheck(fdw->fdwid, ownerId, ACL_USAGE);
  692. if (aclresult != ACLCHECK_OK)
  693. aclcheck_error(aclresult, ACL_KIND_FDW, fdw->fdwname);
  694. /*
  695. * Insert tuple into pg_foreign_server.
  696. */
  697. memset(values, 0, sizeof(values));
  698. memset(nulls, false, sizeof(nulls));
  699. values[Anum_pg_foreign_server_srvname - 1] =
  700. DirectFunctionCall1(namein, CStringGetDatum(stmt->servername));
  701. values[Anum_pg_foreign_server_srvowner - 1] = ObjectIdGetDatum(ownerId);
  702. values[Anum_pg_foreign_server_srvfdw - 1] = ObjectIdGetDatum(fdw->fdwid);
  703. /* Add server type if supplied */
  704. if (stmt->servertype)
  705. values[Anum_pg_foreign_server_srvtype - 1] =
  706. CStringGetTextDatum(stmt->servertype);
  707. else
  708. nulls[Anum_pg_foreign_server_srvtype - 1] = true;
  709. /* Add server version if supplied */
  710. if (stmt->version)
  711. values[Anum_pg_foreign_server_srvversion - 1] =
  712. CStringGetTextDatum(stmt->version);
  713. else
  714. nulls[Anum_pg_foreign_server_srvversion - 1] = true;
  715. /* Start with a blank acl */
  716. nulls[Anum_pg_foreign_server_srvacl - 1] = true;
  717. /* Add server options */
  718. srvoptions = transformGenericOptions(ForeignServerRelationId,
  719. PointerGetDatum(NULL),
  720. stmt->options,
  721. fdw->fdwvalidator);
  722. if (PointerIsValid(DatumGetPointer(srvoptions)))
  723. values[Anum_pg_foreign_server_srvoptions - 1] = srvoptions;
  724. else
  725. nulls[Anum_pg_foreign_server_srvoptions - 1] = true;
  726. tuple = heap_form_tuple(rel->rd_att, values, nulls);
  727. srvId = simple_heap_insert(rel, tuple);
  728. CatalogUpdateIndexes(rel, tuple);
  729. heap_freetuple(tuple);
  730. /* record dependencies */
  731. myself.classId = ForeignServerRelationId;
  732. myself.objectId = srvId;
  733. myself.objectSubId = 0;
  734. referenced.classId = ForeignDataWrapperRelationId;
  735. referenced.objectId = fdw->fdwid;
  736. referenced.objectSubId = 0;
  737. recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
  738. recordDependencyOnOwner(ForeignServerRelationId, srvId, ownerId);
  739. /* dependency on extension */
  740. recordDependencyOnCurrentExtension(&myself, false);
  741. /* Post creation hook for new foreign server */
  742. InvokeObjectPostCreateHook(ForeignServerRelationId, srvId, 0);
  743. heap_close(rel, RowExclusiveLock);
  744. return srvId;
  745. }
  746. /*
  747. * Alter foreign server
  748. */
  749. Oid
  750. AlterForeignServer(AlterForeignServerStmt *stmt)
  751. {
  752. Relation rel;
  753. HeapTuple tp;
  754. Datum repl_val[Natts_pg_foreign_server];
  755. bool repl_null[Natts_pg_foreign_server];
  756. bool repl_repl[Natts_pg_foreign_server];
  757. Oid srvId;
  758. Form_pg_foreign_server srvForm;
  759. rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
  760. tp = SearchSysCacheCopy1(FOREIGNSERVERNAME,
  761. CStringGetDatum(stmt->servername));
  762. if (!HeapTupleIsValid(tp))
  763. ereport(ERROR,
  764. (errcode(ERRCODE_UNDEFINED_OBJECT),
  765. errmsg("server \"%s\" does not exist", stmt->servername)));
  766. srvId = HeapTupleGetOid(tp);
  767. srvForm = (Form_pg_foreign_server) GETSTRUCT(tp);
  768. /*
  769. * Only owner or a superuser can ALTER a SERVER.
  770. */
  771. if (!pg_foreign_server_ownercheck(srvId, GetUserId()))
  772. aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
  773. stmt->servername);
  774. memset(repl_val, 0, sizeof(repl_val));
  775. memset(repl_null, false, sizeof(repl_null));
  776. memset(repl_repl, false, sizeof(repl_repl));
  777. if (stmt->has_version)
  778. {
  779. /*
  780. * Change the server VERSION string.
  781. */
  782. if (stmt->version)
  783. repl_val[Anum_pg_foreign_server_srvversion - 1] =
  784. CStringGetTextDatum(stmt->version);
  785. else
  786. repl_null[Anum_pg_foreign_server_srvversion - 1] = true;
  787. repl_repl[Anum_pg_foreign_server_srvversion - 1] = true;
  788. }
  789. if (stmt->options)
  790. {
  791. ForeignDataWrapper *fdw = GetForeignDataWrapper(srvForm->srvfdw);
  792. Datum datum;
  793. bool isnull;
  794. /* Extract the current srvoptions */
  795. datum = SysCacheGetAttr(FOREIGNSERVEROID,
  796. tp,
  797. Anum_pg_foreign_server_srvoptions,
  798. &isnull);
  799. if (isnull)
  800. datum = PointerGetDatum(NULL);
  801. /* Prepare the options array */
  802. datum = transformGenericOptions(ForeignServerRelationId,
  803. datum,
  804. stmt->options,
  805. fdw->fdwvalidator);
  806. if (PointerIsValid(DatumGetPointer(datum)))
  807. repl_val[Anum_pg_foreign_server_srvoptions - 1] = datum;
  808. else
  809. repl_null[Anum_pg_foreign_server_srvoptions - 1] = true;
  810. repl_repl[Anum_pg_foreign_server_srvoptions - 1] = true;
  811. }
  812. /* Everything looks good - update the tuple */
  813. tp = heap_modify_tuple(tp, RelationGetDescr(rel),
  814. repl_val, repl_null, repl_repl);
  815. simple_heap_update(rel, &tp->t_self, tp);
  816. CatalogUpdateIndexes(rel, tp);
  817. InvokeObjectPostAlterHook(ForeignServerRelationId, srvId, 0);
  818. heap_freetuple(tp);
  819. heap_close(rel, RowExclusiveLock);
  820. return srvId;
  821. }
  822. /*
  823. * Drop foreign server by OID
  824. */
  825. void
  826. RemoveForeignServerById(Oid srvId)
  827. {
  828. HeapTuple tp;
  829. Relation rel;
  830. rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
  831. tp = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(srvId));
  832. if (!HeapTupleIsValid(tp))
  833. elog(ERROR, "cache lookup failed for foreign server %u", srvId);
  834. simple_heap_delete(rel, &tp->t_self);
  835. ReleaseSysCache(tp);
  836. heap_close(rel, RowExclusiveLock);
  837. }
  838. /*
  839. * Common routine to check permission for user-mapping-related DDL
  840. * commands. We allow server owners to operate on any mapping, and
  841. * users to operate on their own mapping.
  842. */
  843. static void
  844. user_mapping_ddl_aclcheck(Oid umuserid, Oid serverid, const char *servername)
  845. {
  846. Oid curuserid = GetUserId();
  847. if (!pg_foreign_server_ownercheck(serverid, curuserid))
  848. {
  849. if (umuserid == curuserid)
  850. {
  851. AclResult aclresult;
  852. aclresult = pg_foreign_server_aclcheck(serverid, curuserid, ACL_USAGE);
  853. if (aclresult != ACLCHECK_OK)
  854. aclcheck_error(aclresult, ACL_KIND_FOREIGN_SERVER, servername);
  855. }
  856. else
  857. aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
  858. servername);
  859. }
  860. }
  861. /*
  862. * Create user mapping
  863. */
  864. Oid
  865. CreateUserMapping(CreateUserMappingStmt *stmt)
  866. {
  867. Relation rel;
  868. Datum useoptions;
  869. Datum values[Natts_pg_user_mapping];
  870. bool nulls[Natts_pg_user_mapping];
  871. HeapTuple tuple;
  872. Oid useId;
  873. Oid umId;
  874. ObjectAddress myself;
  875. ObjectAddress referenced;
  876. ForeignServer *srv;
  877. ForeignDataWrapper *fdw;
  878. rel = heap_open(UserMappingRelationId, RowExclusiveLock);
  879. useId = GetUserOidFromMapping(stmt->username, false);
  880. /* Check that the server exists. */
  881. srv = GetForeignServerByName(stmt->servername, false);
  882. user_mapping_ddl_aclcheck(useId, srv->serverid, stmt->servername);
  883. /*
  884. * Check that the user mapping is unique within server.
  885. */
  886. umId = GetSysCacheOid2(USERMAPPINGUSERSERVER,
  887. ObjectIdGetDatum(useId),
  888. ObjectIdGetDatum(srv->serverid));
  889. if (OidIsValid(umId))
  890. ereport(ERROR,
  891. (errcode(ERRCODE_DUPLICATE_OBJECT),
  892. errmsg("user mapping \"%s\" already exists for server %s",
  893. MappingUserName(useId),
  894. stmt->servername)));
  895. fdw = GetForeignDataWrapper(srv->fdwid);
  896. /*
  897. * Insert tuple into pg_user_mapping.
  898. */
  899. memset(values, 0, sizeof(values));
  900. memset(nulls, false, sizeof(nulls));
  901. values[Anum_pg_user_mapping_umuser - 1] = ObjectIdGetDatum(useId);
  902. values[Anum_pg_user_mapping_umserver - 1] = ObjectIdGetDatum(srv->serverid);
  903. /* Add user options */
  904. useoptions = transformGenericOptions(UserMappingRelationId,
  905. PointerGetDatum(NULL),
  906. stmt->options,
  907. fdw->fdwvalidator);
  908. if (PointerIsValid(DatumGetPointer(useoptions)))
  909. values[Anum_pg_user_mapping_umoptions - 1] = useoptions;
  910. else
  911. nulls[Anum_pg_user_mapping_umoptions - 1] = true;
  912. tuple = heap_form_tuple(rel->rd_att, values, nulls);
  913. umId = simple_heap_insert(rel, tuple);
  914. CatalogUpdateIndexes(rel, tuple);
  915. heap_freetuple(tuple);
  916. /* Add dependency on the server */
  917. myself.classId = UserMappingRelationId;
  918. myself.objectId = umId;
  919. myself.objectSubId = 0;
  920. referenced.classId = ForeignServerRelationId;
  921. referenced.objectId = srv->serverid;
  922. referenced.objectSubId = 0;
  923. recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
  924. if (OidIsValid(useId))
  925. {
  926. /* Record the mapped user dependency */
  927. recordDependencyOnOwner(UserMappingRelationId, umId, useId);
  928. }
  929. /* dependency on extension */
  930. recordDependencyOnCurrentExtension(&myself, false);
  931. /* Post creation hook for new user mapping */
  932. InvokeObjectPostCreateHook(UserMappingRelationId, umId, 0);
  933. heap_close(rel, RowExclusiveLock);
  934. return umId;
  935. }
  936. /*
  937. * Alter user mapping
  938. */
  939. Oid
  940. AlterUserMapping(AlterUserMappingStmt *stmt)
  941. {
  942. Relation rel;
  943. HeapTuple tp;
  944. Datum repl_val[Natts_pg_user_mapping];
  945. bool repl_null[Natts_pg_user_mapping];
  946. bool repl_repl[Natts_pg_user_mapping];
  947. Oid useId;
  948. Oid umId;
  949. ForeignServer *srv;
  950. rel = heap_open(UserMappingRelationId, RowExclusiveLock);
  951. useId = GetUserOidFromMapping(stmt->username, false);
  952. srv = GetForeignServerByName(stmt->servername, false);
  953. umId = GetSysCacheOid2(USERMAPPINGUSERSERVER,
  954. ObjectIdGetDatum(useId),
  955. ObjectIdGetDatum(srv->serverid));
  956. if (!OidIsValid(umId))
  957. ereport(ERROR,
  958. (errcode(ERRCODE_UNDEFINED_OBJECT),
  959. errmsg("user mapping \"%s\" does not exist for the server",
  960. MappingUserName(useId))));
  961. user_mapping_ddl_aclcheck(useId, srv->serverid, stmt->servername);
  962. tp = SearchSysCacheCopy1(USERMAPPINGOID, ObjectIdGetDatum(umId));
  963. if (!HeapTupleIsValid(tp))
  964. elog(ERROR, "cache lookup failed for user mapping %u", umId);
  965. memset(repl_val, 0, sizeof(repl_val));
  966. memset(repl_null, false, sizeof(repl_null));
  967. memset(repl_repl, false, sizeof(repl_repl));
  968. if (stmt->options)
  969. {
  970. ForeignDataWrapper *fdw;
  971. Datum datum;
  972. bool isnull;
  973. /*
  974. * Process the options.
  975. */
  976. fdw = GetForeignDataWrapper(srv->fdwid);
  977. datum = SysCacheGetAttr(USERMAPPINGUSERSERVER,
  978. tp,
  979. Anum_pg_user_mapping_umoptions,
  980. &isnull);
  981. if (isnull)
  982. datum = PointerGetDatum(NULL);
  983. /* Prepare the options array */
  984. datum = transformGenericOptions(UserMappingRelationId,
  985. datum,
  986. stmt->options,
  987. fdw->fdwvalidator);
  988. if (PointerIsValid(DatumGetPointer(datum)))
  989. repl_val[Anum_pg_user_mapping_umoptions - 1] = datum;
  990. else
  991. repl_null[Anum_pg_user_mapping_umoptions - 1] = true;
  992. repl_repl[Anum_pg_user_mapping_umoptions - 1] = true;
  993. }
  994. /* Everything looks good - update the tuple */
  995. tp = heap_modify_tuple(tp, RelationGetDescr(rel),
  996. repl_val, repl_null, repl_repl);
  997. simple_heap_update(rel, &tp->t_self, tp);
  998. CatalogUpdateIndexes(rel, tp);
  999. heap_freetuple(tp);
  1000. heap_close(rel, RowExclusiveLock);
  1001. return umId;
  1002. }
  1003. /*
  1004. * Drop user mapping
  1005. */
  1006. Oid
  1007. RemoveUserMapping(DropUserMappingStmt *stmt)
  1008. {
  1009. ObjectAddress object;
  1010. Oid useId;
  1011. Oid umId;
  1012. ForeignServer *srv;
  1013. useId = GetUserOidFromMapping(stmt->username, stmt->missing_ok);
  1014. srv = GetForeignServerByName(stmt->servername, true);
  1015. if (stmt->username && !OidIsValid(useId))
  1016. {
  1017. /*
  1018. * IF EXISTS specified, role not found and not public. Notice this and
  1019. * leave.
  1020. */
  1021. elog(NOTICE, "role \"%s\" does not exist, skipping", stmt->username);
  1022. return InvalidOid;
  1023. }
  1024. if (!srv)
  1025. {
  1026. if (!stmt->missing_ok)
  1027. ereport(ERROR,
  1028. (errcode(ERRCODE_UNDEFINED_OBJECT),
  1029. errmsg("server \"%s\" does not exist",
  1030. stmt->servername)));
  1031. /* IF EXISTS, just note it */
  1032. ereport(NOTICE, (errmsg("server does not exist, skipping")));
  1033. return InvalidOid;
  1034. }
  1035. umId = GetSysCacheOid2(USERMAPPINGUSERSERVER,
  1036. ObjectIdGetDatum(useId),
  1037. ObjectIdGetDatum(srv->serverid));
  1038. if (!OidIsValid(umId))
  1039. {
  1040. if (!stmt->missing_ok)
  1041. ereport(ERROR,
  1042. (errcode(ERRCODE_UNDEFINED_OBJECT),
  1043. errmsg("user mapping \"%s\" does not exist for the server",
  1044. MappingUserName(useId))));
  1045. /* IF EXISTS specified, just note it */
  1046. ereport(NOTICE,
  1047. (errmsg("user mapping \"%s\" does not exist for the server, skipping",
  1048. MappingUserName(useId))));
  1049. return InvalidOid;
  1050. }
  1051. user_mapping_ddl_aclcheck(useId, srv->serverid, srv->servername);
  1052. /*
  1053. * Do the deletion
  1054. */
  1055. object.classId = UserMappingRelationId;
  1056. object.objectId = umId;
  1057. object.objectSubId = 0;
  1058. performDeletion(&object, DROP_CASCADE, 0);
  1059. return umId;
  1060. }
  1061. /*
  1062. * Drop user mapping by OID. This is called to clean up dependencies.
  1063. */
  1064. void
  1065. RemoveUserMappingById(Oid umId)
  1066. {
  1067. HeapTuple tp;
  1068. Relation rel;
  1069. rel = heap_open(UserMappingRelationId, RowExclusiveLock);
  1070. tp = SearchSysCache1(USERMAPPINGOID, ObjectIdGetDatum(umId));
  1071. if (!HeapTupleIsValid(tp))
  1072. elog(ERROR, "cache lookup failed for user mapping %u", umId);
  1073. simple_heap_delete(rel, &tp->t_self);
  1074. ReleaseSysCache(tp);
  1075. heap_close(rel, RowExclusiveLock);
  1076. }
  1077. /*
  1078. * Create a foreign table
  1079. * call after DefineRelation().
  1080. */
  1081. void
  1082. CreateForeignTable(CreateForeignTableStmt *stmt, Oid relid)
  1083. {
  1084. Relation ftrel;
  1085. Datum ftoptions;
  1086. Datum values[Natts_pg_foreign_table];
  1087. bool nulls[Natts_pg_foreign_table];
  1088. HeapTuple tuple;
  1089. AclResult aclresult;
  1090. ObjectAddress myself;
  1091. ObjectAddress referenced;
  1092. Oid ownerId;
  1093. ForeignDataWrapper *fdw;
  1094. ForeignServer *server;
  1095. /*
  1096. * Advance command counter to ensure the pg_attribute tuple is visible;
  1097. * the tuple might be updated to add constraints in previous step.
  1098. */
  1099. CommandCounterIncrement();
  1100. ftrel = heap_open(ForeignTableRelationId, RowExclusiveLock);
  1101. /*
  1102. * For now the owner cannot be specified on create. Use effective user ID.
  1103. */
  1104. ownerId = GetUserId();
  1105. /*
  1106. * Check that the foreign server exists and that we have USAGE on it. Also
  1107. * get the actual FDW for option validation etc.
  1108. */
  1109. server = GetForeignServerByName(stmt->servername, false);
  1110. aclresult = pg_foreign_server_aclcheck(server->serverid, ownerId, ACL_USAGE);
  1111. if (aclresult != ACLCHECK_OK)
  1112. aclcheck_error(aclresult, ACL_KIND_FOREIGN_SERVER, server->servername);
  1113. fdw = GetForeignDataWrapper(server->fdwid);
  1114. /*
  1115. * Insert tuple into pg_foreign_table.
  1116. */
  1117. memset(values, 0, sizeof(values));
  1118. memset(nulls, false, sizeof(nulls));
  1119. values[Anum_pg_foreign_table_ftrelid - 1] = ObjectIdGetDatum(relid);
  1120. values[Anum_pg_foreign_table_ftserver - 1] = ObjectIdGetDatum(server->serverid);
  1121. /* Add table generic options */
  1122. ftoptions = transformGenericOptions(ForeignTableRelationId,
  1123. PointerGetDatum(NULL),
  1124. stmt->options,
  1125. fdw->fdwvalidator);
  1126. if (PointerIsValid(DatumGetPointer(ftoptions)))
  1127. values[Anum_pg_foreign_table_ftoptions - 1] = ftoptions;
  1128. else
  1129. nulls[Anum_pg_foreign_table_ftoptions - 1] = true;
  1130. tuple = heap_form_tuple(ftrel->rd_att, values, nulls);
  1131. simple_heap_insert(ftrel, tuple);
  1132. CatalogUpdateIndexes(ftrel, tuple);
  1133. heap_freetuple(tuple);
  1134. /* Add pg_class dependency on the server */
  1135. myself.classId = RelationRelationId;
  1136. myself.objectId = relid;
  1137. myself.objectSubId = 0;
  1138. referenced.classId = ForeignServerRelationId;
  1139. referenced.objectId = server->serverid;
  1140. referenced.objectSubId = 0;
  1141. recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
  1142. heap_close(ftrel, RowExclusiveLock);
  1143. }