Header And Logo

PostgreSQL
| The world's most advanced open source database.

foreigncmds.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * foreigncmds.c
00004  *    foreign-data wrapper/server creation/manipulation commands
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  *
00008  *
00009  * IDENTIFICATION
00010  *    src/backend/commands/foreigncmds.c
00011  *
00012  *-------------------------------------------------------------------------
00013  */
00014 #include "postgres.h"
00015 
00016 #include "access/heapam.h"
00017 #include "access/htup_details.h"
00018 #include "access/xact.h"
00019 #include "access/reloptions.h"
00020 #include "catalog/dependency.h"
00021 #include "catalog/indexing.h"
00022 #include "catalog/objectaccess.h"
00023 #include "catalog/pg_foreign_data_wrapper.h"
00024 #include "catalog/pg_foreign_server.h"
00025 #include "catalog/pg_foreign_table.h"
00026 #include "catalog/pg_proc.h"
00027 #include "catalog/pg_type.h"
00028 #include "catalog/pg_user_mapping.h"
00029 #include "commands/defrem.h"
00030 #include "foreign/foreign.h"
00031 #include "miscadmin.h"
00032 #include "parser/parse_func.h"
00033 #include "utils/acl.h"
00034 #include "utils/builtins.h"
00035 #include "utils/lsyscache.h"
00036 #include "utils/rel.h"
00037 #include "utils/syscache.h"
00038 
00039 
00040 /*
00041  * Convert a DefElem list to the text array format that is used in
00042  * pg_foreign_data_wrapper, pg_foreign_server, and pg_user_mapping.
00043  * Returns the array in the form of a Datum, or PointerGetDatum(NULL)
00044  * if the list is empty.
00045  *
00046  * Note: The array is usually stored to database without further
00047  * processing, hence any validation should be done before this
00048  * conversion.
00049  */
00050 static Datum
00051 optionListToArray(List *options)
00052 {
00053     ArrayBuildState *astate = NULL;
00054     ListCell   *cell;
00055 
00056     foreach(cell, options)
00057     {
00058         DefElem    *def = lfirst(cell);
00059         const char *value;
00060         Size        len;
00061         text       *t;
00062 
00063         value = defGetString(def);
00064         len = VARHDRSZ + strlen(def->defname) + 1 + strlen(value);
00065         t = palloc(len + 1);
00066         SET_VARSIZE(t, len);
00067         sprintf(VARDATA(t), "%s=%s", def->defname, value);
00068 
00069         astate = accumArrayResult(astate, PointerGetDatum(t),
00070                                   false, TEXTOID,
00071                                   CurrentMemoryContext);
00072     }
00073 
00074     if (astate)
00075         return makeArrayResult(astate, CurrentMemoryContext);
00076 
00077     return PointerGetDatum(NULL);
00078 }
00079 
00080 
00081 /*
00082  * Transform a list of DefElem into text array format.  This is substantially
00083  * the same thing as optionListToArray(), except we recognize SET/ADD/DROP
00084  * actions for modifying an existing list of options, which is passed in
00085  * Datum form as oldOptions.  Also, if fdwvalidator isn't InvalidOid
00086  * it specifies a validator function to call on the result.
00087  *
00088  * Returns the array in the form of a Datum, or PointerGetDatum(NULL)
00089  * if the list is empty.
00090  *
00091  * This is used by CREATE/ALTER of FOREIGN DATA WRAPPER/SERVER/USER MAPPING.
00092  */
00093 Datum
00094 transformGenericOptions(Oid catalogId,
00095                         Datum oldOptions,
00096                         List *options,
00097                         Oid fdwvalidator)
00098 {
00099     List       *resultOptions = untransformRelOptions(oldOptions);
00100     ListCell   *optcell;
00101     Datum       result;
00102 
00103     foreach(optcell, options)
00104     {
00105         DefElem    *od = lfirst(optcell);
00106         ListCell   *cell;
00107         ListCell   *prev = NULL;
00108 
00109         /*
00110          * Find the element in resultOptions.  We need this for validation in
00111          * all cases.  Also identify the previous element.
00112          */
00113         foreach(cell, resultOptions)
00114         {
00115             DefElem    *def = lfirst(cell);
00116 
00117             if (strcmp(def->defname, od->defname) == 0)
00118                 break;
00119             else
00120                 prev = cell;
00121         }
00122 
00123         /*
00124          * It is possible to perform multiple SET/DROP actions on the same
00125          * option.  The standard permits this, as long as the options to be
00126          * added are unique.  Note that an unspecified action is taken to be
00127          * ADD.
00128          */
00129         switch (od->defaction)
00130         {
00131             case DEFELEM_DROP:
00132                 if (!cell)
00133                     ereport(ERROR,
00134                             (errcode(ERRCODE_UNDEFINED_OBJECT),
00135                              errmsg("option \"%s\" not found",
00136                                     od->defname)));
00137                 resultOptions = list_delete_cell(resultOptions, cell, prev);
00138                 break;
00139 
00140             case DEFELEM_SET:
00141                 if (!cell)
00142                     ereport(ERROR,
00143                             (errcode(ERRCODE_UNDEFINED_OBJECT),
00144                              errmsg("option \"%s\" not found",
00145                                     od->defname)));
00146                 lfirst(cell) = od;
00147                 break;
00148 
00149             case DEFELEM_ADD:
00150             case DEFELEM_UNSPEC:
00151                 if (cell)
00152                     ereport(ERROR,
00153                             (errcode(ERRCODE_DUPLICATE_OBJECT),
00154                              errmsg("option \"%s\" provided more than once",
00155                                     od->defname)));
00156                 resultOptions = lappend(resultOptions, od);
00157                 break;
00158 
00159             default:
00160                 elog(ERROR, "unrecognized action %d on option \"%s\"",
00161                      (int) od->defaction, od->defname);
00162                 break;
00163         }
00164     }
00165 
00166     result = optionListToArray(resultOptions);
00167 
00168     if (OidIsValid(fdwvalidator))
00169     {
00170         Datum       valarg = result;
00171 
00172         /*
00173          * Pass a null options list as an empty array, so that validators
00174          * don't have to be declared non-strict to handle the case.
00175          */
00176         if (DatumGetPointer(valarg) == NULL)
00177             valarg = PointerGetDatum(construct_empty_array(TEXTOID));
00178         OidFunctionCall2(fdwvalidator, valarg, ObjectIdGetDatum(catalogId));
00179     }
00180 
00181     return result;
00182 }
00183 
00184 
00185 /*
00186  * Convert the user mapping user name to OID
00187  */
00188 static Oid
00189 GetUserOidFromMapping(const char *username, bool missing_ok)
00190 {
00191     if (!username)
00192         /* PUBLIC user mapping */
00193         return InvalidOid;
00194 
00195     if (strcmp(username, "current_user") == 0)
00196         /* map to the owner */
00197         return GetUserId();
00198 
00199     /* map to provided user */
00200     return get_role_oid(username, missing_ok);
00201 }
00202 
00203 /*
00204  * Internal workhorse for changing a data wrapper's owner.
00205  *
00206  * Allow this only for superusers; also the new owner must be a
00207  * superuser.
00208  */
00209 static void
00210 AlterForeignDataWrapperOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
00211 {
00212     Form_pg_foreign_data_wrapper form;
00213 
00214     form = (Form_pg_foreign_data_wrapper) GETSTRUCT(tup);
00215 
00216     /* Must be a superuser to change a FDW owner */
00217     if (!superuser())
00218         ereport(ERROR,
00219                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00220                  errmsg("permission denied to change owner of foreign-data wrapper \"%s\"",
00221                         NameStr(form->fdwname)),
00222                  errhint("Must be superuser to change owner of a foreign-data wrapper.")));
00223 
00224     /* New owner must also be a superuser */
00225     if (!superuser_arg(newOwnerId))
00226         ereport(ERROR,
00227                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00228                  errmsg("permission denied to change owner of foreign-data wrapper \"%s\"",
00229                         NameStr(form->fdwname)),
00230         errhint("The owner of a foreign-data wrapper must be a superuser.")));
00231 
00232     if (form->fdwowner != newOwnerId)
00233     {
00234         form->fdwowner = newOwnerId;
00235 
00236         simple_heap_update(rel, &tup->t_self, tup);
00237         CatalogUpdateIndexes(rel, tup);
00238 
00239         /* Update owner dependency reference */
00240         changeDependencyOnOwner(ForeignDataWrapperRelationId,
00241                                 HeapTupleGetOid(tup),
00242                                 newOwnerId);
00243     }
00244 
00245     InvokeObjectPostAlterHook(ForeignDataWrapperRelationId,
00246                               HeapTupleGetOid(tup), 0);
00247 }
00248 
00249 /*
00250  * Change foreign-data wrapper owner -- by name
00251  *
00252  * Note restrictions in the "_internal" function, above.
00253  */
00254 Oid
00255 AlterForeignDataWrapperOwner(const char *name, Oid newOwnerId)
00256 {
00257     Oid         fdwId;
00258     HeapTuple   tup;
00259     Relation    rel;
00260 
00261     rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
00262 
00263     tup = SearchSysCacheCopy1(FOREIGNDATAWRAPPERNAME, CStringGetDatum(name));
00264 
00265     if (!HeapTupleIsValid(tup))
00266         ereport(ERROR,
00267                 (errcode(ERRCODE_UNDEFINED_OBJECT),
00268                  errmsg("foreign-data wrapper \"%s\" does not exist", name)));
00269 
00270     fdwId = HeapTupleGetOid(tup);
00271 
00272     AlterForeignDataWrapperOwner_internal(rel, tup, newOwnerId);
00273 
00274     heap_freetuple(tup);
00275 
00276     heap_close(rel, RowExclusiveLock);
00277 
00278     return fdwId;
00279 }
00280 
00281 /*
00282  * Change foreign-data wrapper owner -- by OID
00283  *
00284  * Note restrictions in the "_internal" function, above.
00285  */
00286 void
00287 AlterForeignDataWrapperOwner_oid(Oid fwdId, Oid newOwnerId)
00288 {
00289     HeapTuple   tup;
00290     Relation    rel;
00291 
00292     rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
00293 
00294     tup = SearchSysCacheCopy1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fwdId));
00295 
00296     if (!HeapTupleIsValid(tup))
00297         ereport(ERROR,
00298                 (errcode(ERRCODE_UNDEFINED_OBJECT),
00299           errmsg("foreign-data wrapper with OID %u does not exist", fwdId)));
00300 
00301     AlterForeignDataWrapperOwner_internal(rel, tup, newOwnerId);
00302 
00303     heap_freetuple(tup);
00304 
00305     heap_close(rel, RowExclusiveLock);
00306 }
00307 
00308 /*
00309  * Internal workhorse for changing a foreign server's owner
00310  */
00311 static void
00312 AlterForeignServerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
00313 {
00314     Form_pg_foreign_server form;
00315 
00316     form = (Form_pg_foreign_server) GETSTRUCT(tup);
00317 
00318     if (form->srvowner != newOwnerId)
00319     {
00320         /* Superusers can always do it */
00321         if (!superuser())
00322         {
00323             Oid         srvId;
00324             AclResult   aclresult;
00325 
00326             srvId = HeapTupleGetOid(tup);
00327 
00328             /* Must be owner */
00329             if (!pg_foreign_server_ownercheck(srvId, GetUserId()))
00330                 aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
00331                                NameStr(form->srvname));
00332 
00333             /* Must be able to become new owner */
00334             check_is_member_of_role(GetUserId(), newOwnerId);
00335 
00336             /* New owner must have USAGE privilege on foreign-data wrapper */
00337             aclresult = pg_foreign_data_wrapper_aclcheck(form->srvfdw, newOwnerId, ACL_USAGE);
00338             if (aclresult != ACLCHECK_OK)
00339             {
00340                 ForeignDataWrapper *fdw = GetForeignDataWrapper(form->srvfdw);
00341 
00342                 aclcheck_error(aclresult, ACL_KIND_FDW, fdw->fdwname);
00343             }
00344         }
00345 
00346         form->srvowner = newOwnerId;
00347 
00348         simple_heap_update(rel, &tup->t_self, tup);
00349         CatalogUpdateIndexes(rel, tup);
00350 
00351         /* Update owner dependency reference */
00352         changeDependencyOnOwner(ForeignServerRelationId, HeapTupleGetOid(tup),
00353                                 newOwnerId);
00354     }
00355 
00356     InvokeObjectPostAlterHook(ForeignServerRelationId,
00357                               HeapTupleGetOid(tup), 0);
00358 }
00359 
00360 /*
00361  * Change foreign server owner -- by name
00362  */
00363 Oid
00364 AlterForeignServerOwner(const char *name, Oid newOwnerId)
00365 {
00366     Oid         servOid;
00367     HeapTuple   tup;
00368     Relation    rel;
00369 
00370     rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
00371 
00372     tup = SearchSysCacheCopy1(FOREIGNSERVERNAME, CStringGetDatum(name));
00373 
00374     if (!HeapTupleIsValid(tup))
00375         ereport(ERROR,
00376                 (errcode(ERRCODE_UNDEFINED_OBJECT),
00377                  errmsg("server \"%s\" does not exist", name)));
00378 
00379     servOid = HeapTupleGetOid(tup);
00380 
00381     AlterForeignServerOwner_internal(rel, tup, newOwnerId);
00382 
00383     heap_freetuple(tup);
00384 
00385     heap_close(rel, RowExclusiveLock);
00386 
00387     return servOid;
00388 }
00389 
00390 /*
00391  * Change foreign server owner -- by OID
00392  */
00393 void
00394 AlterForeignServerOwner_oid(Oid srvId, Oid newOwnerId)
00395 {
00396     HeapTuple   tup;
00397     Relation    rel;
00398 
00399     rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
00400 
00401     tup = SearchSysCacheCopy1(FOREIGNSERVEROID, ObjectIdGetDatum(srvId));
00402 
00403     if (!HeapTupleIsValid(tup))
00404         ereport(ERROR,
00405                 (errcode(ERRCODE_UNDEFINED_OBJECT),
00406                  errmsg("foreign server with OID %u does not exist", srvId)));
00407 
00408     AlterForeignServerOwner_internal(rel, tup, newOwnerId);
00409 
00410     heap_freetuple(tup);
00411 
00412     heap_close(rel, RowExclusiveLock);
00413 }
00414 
00415 /*
00416  * Convert a handler function name passed from the parser to an Oid.
00417  */
00418 static Oid
00419 lookup_fdw_handler_func(DefElem *handler)
00420 {
00421     Oid         handlerOid;
00422 
00423     if (handler == NULL || handler->arg == NULL)
00424         return InvalidOid;
00425 
00426     /* handlers have no arguments */
00427     handlerOid = LookupFuncName((List *) handler->arg, 0, NULL, false);
00428 
00429     /* check that handler has correct return type */
00430     if (get_func_rettype(handlerOid) != FDW_HANDLEROID)
00431         ereport(ERROR,
00432                 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
00433                  errmsg("function %s must return type \"fdw_handler\"",
00434                         NameListToString((List *) handler->arg))));
00435 
00436     return handlerOid;
00437 }
00438 
00439 /*
00440  * Convert a validator function name passed from the parser to an Oid.
00441  */
00442 static Oid
00443 lookup_fdw_validator_func(DefElem *validator)
00444 {
00445     Oid         funcargtypes[2];
00446 
00447     if (validator == NULL || validator->arg == NULL)
00448         return InvalidOid;
00449 
00450     /* validators take text[], oid */
00451     funcargtypes[0] = TEXTARRAYOID;
00452     funcargtypes[1] = OIDOID;
00453 
00454     return LookupFuncName((List *) validator->arg, 2, funcargtypes, false);
00455     /* validator's return value is ignored, so we don't check the type */
00456 }
00457 
00458 /*
00459  * Process function options of CREATE/ALTER FDW
00460  */
00461 static void
00462 parse_func_options(List *func_options,
00463                    bool *handler_given, Oid *fdwhandler,
00464                    bool *validator_given, Oid *fdwvalidator)
00465 {
00466     ListCell   *cell;
00467 
00468     *handler_given = false;
00469     *validator_given = false;
00470     /* return InvalidOid if not given */
00471     *fdwhandler = InvalidOid;
00472     *fdwvalidator = InvalidOid;
00473 
00474     foreach(cell, func_options)
00475     {
00476         DefElem    *def = (DefElem *) lfirst(cell);
00477 
00478         if (strcmp(def->defname, "handler") == 0)
00479         {
00480             if (*handler_given)
00481                 ereport(ERROR,
00482                         (errcode(ERRCODE_SYNTAX_ERROR),
00483                          errmsg("conflicting or redundant options")));
00484             *handler_given = true;
00485             *fdwhandler = lookup_fdw_handler_func(def);
00486         }
00487         else if (strcmp(def->defname, "validator") == 0)
00488         {
00489             if (*validator_given)
00490                 ereport(ERROR,
00491                         (errcode(ERRCODE_SYNTAX_ERROR),
00492                          errmsg("conflicting or redundant options")));
00493             *validator_given = true;
00494             *fdwvalidator = lookup_fdw_validator_func(def);
00495         }
00496         else
00497             elog(ERROR, "option \"%s\" not recognized",
00498                  def->defname);
00499     }
00500 }
00501 
00502 /*
00503  * Create a foreign-data wrapper
00504  */
00505 Oid
00506 CreateForeignDataWrapper(CreateFdwStmt *stmt)
00507 {
00508     Relation    rel;
00509     Datum       values[Natts_pg_foreign_data_wrapper];
00510     bool        nulls[Natts_pg_foreign_data_wrapper];
00511     HeapTuple   tuple;
00512     Oid         fdwId;
00513     bool        handler_given;
00514     bool        validator_given;
00515     Oid         fdwhandler;
00516     Oid         fdwvalidator;
00517     Datum       fdwoptions;
00518     Oid         ownerId;
00519     ObjectAddress myself;
00520     ObjectAddress referenced;
00521 
00522     rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
00523 
00524     /* Must be super user */
00525     if (!superuser())
00526         ereport(ERROR,
00527                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00528             errmsg("permission denied to create foreign-data wrapper \"%s\"",
00529                    stmt->fdwname),
00530             errhint("Must be superuser to create a foreign-data wrapper.")));
00531 
00532     /* For now the owner cannot be specified on create. Use effective user ID. */
00533     ownerId = GetUserId();
00534 
00535     /*
00536      * Check that there is no other foreign-data wrapper by this name.
00537      */
00538     if (GetForeignDataWrapperByName(stmt->fdwname, true) != NULL)
00539         ereport(ERROR,
00540                 (errcode(ERRCODE_DUPLICATE_OBJECT),
00541                  errmsg("foreign-data wrapper \"%s\" already exists",
00542                         stmt->fdwname)));
00543 
00544     /*
00545      * Insert tuple into pg_foreign_data_wrapper.
00546      */
00547     memset(values, 0, sizeof(values));
00548     memset(nulls, false, sizeof(nulls));
00549 
00550     values[Anum_pg_foreign_data_wrapper_fdwname - 1] =
00551         DirectFunctionCall1(namein, CStringGetDatum(stmt->fdwname));
00552     values[Anum_pg_foreign_data_wrapper_fdwowner - 1] = ObjectIdGetDatum(ownerId);
00553 
00554     /* Lookup handler and validator functions, if given */
00555     parse_func_options(stmt->func_options,
00556                        &handler_given, &fdwhandler,
00557                        &validator_given, &fdwvalidator);
00558 
00559     values[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = ObjectIdGetDatum(fdwhandler);
00560     values[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = ObjectIdGetDatum(fdwvalidator);
00561 
00562     nulls[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true;
00563 
00564     fdwoptions = transformGenericOptions(ForeignDataWrapperRelationId,
00565                                          PointerGetDatum(NULL),
00566                                          stmt->options,
00567                                          fdwvalidator);
00568 
00569     if (PointerIsValid(DatumGetPointer(fdwoptions)))
00570         values[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = fdwoptions;
00571     else
00572         nulls[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true;
00573 
00574     tuple = heap_form_tuple(rel->rd_att, values, nulls);
00575 
00576     fdwId = simple_heap_insert(rel, tuple);
00577     CatalogUpdateIndexes(rel, tuple);
00578 
00579     heap_freetuple(tuple);
00580 
00581     /* record dependencies */
00582     myself.classId = ForeignDataWrapperRelationId;
00583     myself.objectId = fdwId;
00584     myself.objectSubId = 0;
00585 
00586     if (OidIsValid(fdwhandler))
00587     {
00588         referenced.classId = ProcedureRelationId;
00589         referenced.objectId = fdwhandler;
00590         referenced.objectSubId = 0;
00591         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00592     }
00593 
00594     if (OidIsValid(fdwvalidator))
00595     {
00596         referenced.classId = ProcedureRelationId;
00597         referenced.objectId = fdwvalidator;
00598         referenced.objectSubId = 0;
00599         recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00600     }
00601 
00602     recordDependencyOnOwner(ForeignDataWrapperRelationId, fdwId, ownerId);
00603 
00604     /* dependency on extension */
00605     recordDependencyOnCurrentExtension(&myself, false);
00606 
00607     /* Post creation hook for new foreign data wrapper */
00608     InvokeObjectPostCreateHook(ForeignDataWrapperRelationId, fdwId, 0);
00609 
00610     heap_close(rel, RowExclusiveLock);
00611 
00612     return fdwId;
00613 }
00614 
00615 
00616 /*
00617  * Alter foreign-data wrapper
00618  */
00619 Oid
00620 AlterForeignDataWrapper(AlterFdwStmt *stmt)
00621 {
00622     Relation    rel;
00623     HeapTuple   tp;
00624     Form_pg_foreign_data_wrapper fdwForm;
00625     Datum       repl_val[Natts_pg_foreign_data_wrapper];
00626     bool        repl_null[Natts_pg_foreign_data_wrapper];
00627     bool        repl_repl[Natts_pg_foreign_data_wrapper];
00628     Oid         fdwId;
00629     bool        isnull;
00630     Datum       datum;
00631     bool        handler_given;
00632     bool        validator_given;
00633     Oid         fdwhandler;
00634     Oid         fdwvalidator;
00635 
00636     rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
00637 
00638     /* Must be super user */
00639     if (!superuser())
00640         ereport(ERROR,
00641                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
00642              errmsg("permission denied to alter foreign-data wrapper \"%s\"",
00643                     stmt->fdwname),
00644              errhint("Must be superuser to alter a foreign-data wrapper.")));
00645 
00646     tp = SearchSysCacheCopy1(FOREIGNDATAWRAPPERNAME,
00647                              CStringGetDatum(stmt->fdwname));
00648 
00649     if (!HeapTupleIsValid(tp))
00650         ereport(ERROR,
00651                 (errcode(ERRCODE_UNDEFINED_OBJECT),
00652         errmsg("foreign-data wrapper \"%s\" does not exist", stmt->fdwname)));
00653 
00654     fdwForm = (Form_pg_foreign_data_wrapper) GETSTRUCT(tp);
00655     fdwId = HeapTupleGetOid(tp);
00656 
00657     memset(repl_val, 0, sizeof(repl_val));
00658     memset(repl_null, false, sizeof(repl_null));
00659     memset(repl_repl, false, sizeof(repl_repl));
00660 
00661     parse_func_options(stmt->func_options,
00662                        &handler_given, &fdwhandler,
00663                        &validator_given, &fdwvalidator);
00664 
00665     if (handler_given)
00666     {
00667         repl_val[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = ObjectIdGetDatum(fdwhandler);
00668         repl_repl[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = true;
00669 
00670         /*
00671          * It could be that the behavior of accessing foreign table changes
00672          * with the new handler.  Warn about this.
00673          */
00674         ereport(WARNING,
00675                 (errmsg("changing the foreign-data wrapper handler can change behavior of existing foreign tables")));
00676     }
00677 
00678     if (validator_given)
00679     {
00680         repl_val[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = ObjectIdGetDatum(fdwvalidator);
00681         repl_repl[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = true;
00682 
00683         /*
00684          * It could be that the options for the FDW, SERVER and USER MAPPING
00685          * are no longer valid with the new validator.  Warn about this.
00686          */
00687         if (OidIsValid(fdwvalidator))
00688             ereport(WARNING,
00689              (errmsg("changing the foreign-data wrapper validator can cause "
00690                      "the options for dependent objects to become invalid")));
00691     }
00692     else
00693     {
00694         /*
00695          * Validator is not changed, but we need it for validating options.
00696          */
00697         fdwvalidator = fdwForm->fdwvalidator;
00698     }
00699 
00700     /*
00701      * If options specified, validate and update.
00702      */
00703     if (stmt->options)
00704     {
00705         /* Extract the current options */
00706         datum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID,
00707                                 tp,
00708                                 Anum_pg_foreign_data_wrapper_fdwoptions,
00709                                 &isnull);
00710         if (isnull)
00711             datum = PointerGetDatum(NULL);
00712 
00713         /* Transform the options */
00714         datum = transformGenericOptions(ForeignDataWrapperRelationId,
00715                                         datum,
00716                                         stmt->options,
00717                                         fdwvalidator);
00718 
00719         if (PointerIsValid(DatumGetPointer(datum)))
00720             repl_val[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = datum;
00721         else
00722             repl_null[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true;
00723 
00724         repl_repl[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true;
00725     }
00726 
00727     /* Everything looks good - update the tuple */
00728     tp = heap_modify_tuple(tp, RelationGetDescr(rel),
00729                            repl_val, repl_null, repl_repl);
00730 
00731     simple_heap_update(rel, &tp->t_self, tp);
00732     CatalogUpdateIndexes(rel, tp);
00733 
00734     heap_freetuple(tp);
00735 
00736     /* Update function dependencies if we changed them */
00737     if (handler_given || validator_given)
00738     {
00739         ObjectAddress myself;
00740         ObjectAddress referenced;
00741 
00742         /*
00743          * Flush all existing dependency records of this FDW on functions; we
00744          * assume there can be none other than the ones we are fixing.
00745          */
00746         deleteDependencyRecordsForClass(ForeignDataWrapperRelationId,
00747                                         fdwId,
00748                                         ProcedureRelationId,
00749                                         DEPENDENCY_NORMAL);
00750 
00751         /* And build new ones. */
00752         myself.classId = ForeignDataWrapperRelationId;
00753         myself.objectId = fdwId;
00754         myself.objectSubId = 0;
00755 
00756         if (OidIsValid(fdwhandler))
00757         {
00758             referenced.classId = ProcedureRelationId;
00759             referenced.objectId = fdwhandler;
00760             referenced.objectSubId = 0;
00761             recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00762         }
00763 
00764         if (OidIsValid(fdwvalidator))
00765         {
00766             referenced.classId = ProcedureRelationId;
00767             referenced.objectId = fdwvalidator;
00768             referenced.objectSubId = 0;
00769             recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00770         }
00771     }
00772 
00773     InvokeObjectPostAlterHook(ForeignDataWrapperRelationId, fdwId, 0);
00774 
00775     heap_close(rel, RowExclusiveLock);
00776 
00777     return fdwId;
00778 }
00779 
00780 
00781 /*
00782  * Drop foreign-data wrapper by OID
00783  */
00784 void
00785 RemoveForeignDataWrapperById(Oid fdwId)
00786 {
00787     HeapTuple   tp;
00788     Relation    rel;
00789 
00790     rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
00791 
00792     tp = SearchSysCache1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fdwId));
00793 
00794     if (!HeapTupleIsValid(tp))
00795         elog(ERROR, "cache lookup failed for foreign-data wrapper %u", fdwId);
00796 
00797     simple_heap_delete(rel, &tp->t_self);
00798 
00799     ReleaseSysCache(tp);
00800 
00801     heap_close(rel, RowExclusiveLock);
00802 }
00803 
00804 
00805 /*
00806  * Create a foreign server
00807  */
00808 Oid
00809 CreateForeignServer(CreateForeignServerStmt *stmt)
00810 {
00811     Relation    rel;
00812     Datum       srvoptions;
00813     Datum       values[Natts_pg_foreign_server];
00814     bool        nulls[Natts_pg_foreign_server];
00815     HeapTuple   tuple;
00816     Oid         srvId;
00817     Oid         ownerId;
00818     AclResult   aclresult;
00819     ObjectAddress myself;
00820     ObjectAddress referenced;
00821     ForeignDataWrapper *fdw;
00822 
00823     rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
00824 
00825     /* For now the owner cannot be specified on create. Use effective user ID. */
00826     ownerId = GetUserId();
00827 
00828     /*
00829      * Check that there is no other foreign server by this name.
00830      */
00831     if (GetForeignServerByName(stmt->servername, true) != NULL)
00832         ereport(ERROR,
00833                 (errcode(ERRCODE_DUPLICATE_OBJECT),
00834                  errmsg("server \"%s\" already exists",
00835                         stmt->servername)));
00836 
00837     /*
00838      * Check that the FDW exists and that we have USAGE on it. Also get the
00839      * actual FDW for option validation etc.
00840      */
00841     fdw = GetForeignDataWrapperByName(stmt->fdwname, false);
00842 
00843     aclresult = pg_foreign_data_wrapper_aclcheck(fdw->fdwid, ownerId, ACL_USAGE);
00844     if (aclresult != ACLCHECK_OK)
00845         aclcheck_error(aclresult, ACL_KIND_FDW, fdw->fdwname);
00846 
00847     /*
00848      * Insert tuple into pg_foreign_server.
00849      */
00850     memset(values, 0, sizeof(values));
00851     memset(nulls, false, sizeof(nulls));
00852 
00853     values[Anum_pg_foreign_server_srvname - 1] =
00854         DirectFunctionCall1(namein, CStringGetDatum(stmt->servername));
00855     values[Anum_pg_foreign_server_srvowner - 1] = ObjectIdGetDatum(ownerId);
00856     values[Anum_pg_foreign_server_srvfdw - 1] = ObjectIdGetDatum(fdw->fdwid);
00857 
00858     /* Add server type if supplied */
00859     if (stmt->servertype)
00860         values[Anum_pg_foreign_server_srvtype - 1] =
00861             CStringGetTextDatum(stmt->servertype);
00862     else
00863         nulls[Anum_pg_foreign_server_srvtype - 1] = true;
00864 
00865     /* Add server version if supplied */
00866     if (stmt->version)
00867         values[Anum_pg_foreign_server_srvversion - 1] =
00868             CStringGetTextDatum(stmt->version);
00869     else
00870         nulls[Anum_pg_foreign_server_srvversion - 1] = true;
00871 
00872     /* Start with a blank acl */
00873     nulls[Anum_pg_foreign_server_srvacl - 1] = true;
00874 
00875     /* Add server options */
00876     srvoptions = transformGenericOptions(ForeignServerRelationId,
00877                                          PointerGetDatum(NULL),
00878                                          stmt->options,
00879                                          fdw->fdwvalidator);
00880 
00881     if (PointerIsValid(DatumGetPointer(srvoptions)))
00882         values[Anum_pg_foreign_server_srvoptions - 1] = srvoptions;
00883     else
00884         nulls[Anum_pg_foreign_server_srvoptions - 1] = true;
00885 
00886     tuple = heap_form_tuple(rel->rd_att, values, nulls);
00887 
00888     srvId = simple_heap_insert(rel, tuple);
00889 
00890     CatalogUpdateIndexes(rel, tuple);
00891 
00892     heap_freetuple(tuple);
00893 
00894     /* record dependencies */
00895     myself.classId = ForeignServerRelationId;
00896     myself.objectId = srvId;
00897     myself.objectSubId = 0;
00898 
00899     referenced.classId = ForeignDataWrapperRelationId;
00900     referenced.objectId = fdw->fdwid;
00901     referenced.objectSubId = 0;
00902     recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
00903 
00904     recordDependencyOnOwner(ForeignServerRelationId, srvId, ownerId);
00905 
00906     /* dependency on extension */
00907     recordDependencyOnCurrentExtension(&myself, false);
00908 
00909     /* Post creation hook for new foreign server */
00910     InvokeObjectPostCreateHook(ForeignServerRelationId, srvId, 0);
00911 
00912     heap_close(rel, RowExclusiveLock);
00913 
00914     return srvId;
00915 }
00916 
00917 
00918 /*
00919  * Alter foreign server
00920  */
00921 Oid
00922 AlterForeignServer(AlterForeignServerStmt *stmt)
00923 {
00924     Relation    rel;
00925     HeapTuple   tp;
00926     Datum       repl_val[Natts_pg_foreign_server];
00927     bool        repl_null[Natts_pg_foreign_server];
00928     bool        repl_repl[Natts_pg_foreign_server];
00929     Oid         srvId;
00930     Form_pg_foreign_server srvForm;
00931 
00932     rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
00933 
00934     tp = SearchSysCacheCopy1(FOREIGNSERVERNAME,
00935                              CStringGetDatum(stmt->servername));
00936 
00937     if (!HeapTupleIsValid(tp))
00938         ereport(ERROR,
00939                 (errcode(ERRCODE_UNDEFINED_OBJECT),
00940                  errmsg("server \"%s\" does not exist", stmt->servername)));
00941 
00942     srvId = HeapTupleGetOid(tp);
00943     srvForm = (Form_pg_foreign_server) GETSTRUCT(tp);
00944 
00945     /*
00946      * Only owner or a superuser can ALTER a SERVER.
00947      */
00948     if (!pg_foreign_server_ownercheck(srvId, GetUserId()))
00949         aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
00950                        stmt->servername);
00951 
00952     memset(repl_val, 0, sizeof(repl_val));
00953     memset(repl_null, false, sizeof(repl_null));
00954     memset(repl_repl, false, sizeof(repl_repl));
00955 
00956     if (stmt->has_version)
00957     {
00958         /*
00959          * Change the server VERSION string.
00960          */
00961         if (stmt->version)
00962             repl_val[Anum_pg_foreign_server_srvversion - 1] =
00963                 CStringGetTextDatum(stmt->version);
00964         else
00965             repl_null[Anum_pg_foreign_server_srvversion - 1] = true;
00966 
00967         repl_repl[Anum_pg_foreign_server_srvversion - 1] = true;
00968     }
00969 
00970     if (stmt->options)
00971     {
00972         ForeignDataWrapper *fdw = GetForeignDataWrapper(srvForm->srvfdw);
00973         Datum       datum;
00974         bool        isnull;
00975 
00976         /* Extract the current srvoptions */
00977         datum = SysCacheGetAttr(FOREIGNSERVEROID,
00978                                 tp,
00979                                 Anum_pg_foreign_server_srvoptions,
00980                                 &isnull);
00981         if (isnull)
00982             datum = PointerGetDatum(NULL);
00983 
00984         /* Prepare the options array */
00985         datum = transformGenericOptions(ForeignServerRelationId,
00986                                         datum,
00987                                         stmt->options,
00988                                         fdw->fdwvalidator);
00989 
00990         if (PointerIsValid(DatumGetPointer(datum)))
00991             repl_val[Anum_pg_foreign_server_srvoptions - 1] = datum;
00992         else
00993             repl_null[Anum_pg_foreign_server_srvoptions - 1] = true;
00994 
00995         repl_repl[Anum_pg_foreign_server_srvoptions - 1] = true;
00996     }
00997 
00998     /* Everything looks good - update the tuple */
00999     tp = heap_modify_tuple(tp, RelationGetDescr(rel),
01000                            repl_val, repl_null, repl_repl);
01001 
01002     simple_heap_update(rel, &tp->t_self, tp);
01003     CatalogUpdateIndexes(rel, tp);
01004 
01005     InvokeObjectPostAlterHook(ForeignServerRelationId, srvId, 0);
01006 
01007     heap_freetuple(tp);
01008 
01009     heap_close(rel, RowExclusiveLock);
01010 
01011     return srvId;
01012 }
01013 
01014 
01015 /*
01016  * Drop foreign server by OID
01017  */
01018 void
01019 RemoveForeignServerById(Oid srvId)
01020 {
01021     HeapTuple   tp;
01022     Relation    rel;
01023 
01024     rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
01025 
01026     tp = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(srvId));
01027 
01028     if (!HeapTupleIsValid(tp))
01029         elog(ERROR, "cache lookup failed for foreign server %u", srvId);
01030 
01031     simple_heap_delete(rel, &tp->t_self);
01032 
01033     ReleaseSysCache(tp);
01034 
01035     heap_close(rel, RowExclusiveLock);
01036 }
01037 
01038 
01039 /*
01040  * Common routine to check permission for user-mapping-related DDL
01041  * commands.  We allow server owners to operate on any mapping, and
01042  * users to operate on their own mapping.
01043  */
01044 static void
01045 user_mapping_ddl_aclcheck(Oid umuserid, Oid serverid, const char *servername)
01046 {
01047     Oid         curuserid = GetUserId();
01048 
01049     if (!pg_foreign_server_ownercheck(serverid, curuserid))
01050     {
01051         if (umuserid == curuserid)
01052         {
01053             AclResult   aclresult;
01054 
01055             aclresult = pg_foreign_server_aclcheck(serverid, curuserid, ACL_USAGE);
01056             if (aclresult != ACLCHECK_OK)
01057                 aclcheck_error(aclresult, ACL_KIND_FOREIGN_SERVER, servername);
01058         }
01059         else
01060             aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
01061                            servername);
01062     }
01063 }
01064 
01065 
01066 /*
01067  * Create user mapping
01068  */
01069 Oid
01070 CreateUserMapping(CreateUserMappingStmt *stmt)
01071 {
01072     Relation    rel;
01073     Datum       useoptions;
01074     Datum       values[Natts_pg_user_mapping];
01075     bool        nulls[Natts_pg_user_mapping];
01076     HeapTuple   tuple;
01077     Oid         useId;
01078     Oid         umId;
01079     ObjectAddress myself;
01080     ObjectAddress referenced;
01081     ForeignServer *srv;
01082     ForeignDataWrapper *fdw;
01083 
01084     rel = heap_open(UserMappingRelationId, RowExclusiveLock);
01085 
01086     useId = GetUserOidFromMapping(stmt->username, false);
01087 
01088     /* Check that the server exists. */
01089     srv = GetForeignServerByName(stmt->servername, false);
01090 
01091     user_mapping_ddl_aclcheck(useId, srv->serverid, stmt->servername);
01092 
01093     /*
01094      * Check that the user mapping is unique within server.
01095      */
01096     umId = GetSysCacheOid2(USERMAPPINGUSERSERVER,
01097                            ObjectIdGetDatum(useId),
01098                            ObjectIdGetDatum(srv->serverid));
01099     if (OidIsValid(umId))
01100         ereport(ERROR,
01101                 (errcode(ERRCODE_DUPLICATE_OBJECT),
01102                  errmsg("user mapping \"%s\" already exists for server %s",
01103                         MappingUserName(useId),
01104                         stmt->servername)));
01105 
01106     fdw = GetForeignDataWrapper(srv->fdwid);
01107 
01108     /*
01109      * Insert tuple into pg_user_mapping.
01110      */
01111     memset(values, 0, sizeof(values));
01112     memset(nulls, false, sizeof(nulls));
01113 
01114     values[Anum_pg_user_mapping_umuser - 1] = ObjectIdGetDatum(useId);
01115     values[Anum_pg_user_mapping_umserver - 1] = ObjectIdGetDatum(srv->serverid);
01116 
01117     /* Add user options */
01118     useoptions = transformGenericOptions(UserMappingRelationId,
01119                                          PointerGetDatum(NULL),
01120                                          stmt->options,
01121                                          fdw->fdwvalidator);
01122 
01123     if (PointerIsValid(DatumGetPointer(useoptions)))
01124         values[Anum_pg_user_mapping_umoptions - 1] = useoptions;
01125     else
01126         nulls[Anum_pg_user_mapping_umoptions - 1] = true;
01127 
01128     tuple = heap_form_tuple(rel->rd_att, values, nulls);
01129 
01130     umId = simple_heap_insert(rel, tuple);
01131 
01132     CatalogUpdateIndexes(rel, tuple);
01133 
01134     heap_freetuple(tuple);
01135 
01136     /* Add dependency on the server */
01137     myself.classId = UserMappingRelationId;
01138     myself.objectId = umId;
01139     myself.objectSubId = 0;
01140 
01141     referenced.classId = ForeignServerRelationId;
01142     referenced.objectId = srv->serverid;
01143     referenced.objectSubId = 0;
01144     recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
01145 
01146     if (OidIsValid(useId))
01147     {
01148         /* Record the mapped user dependency */
01149         recordDependencyOnOwner(UserMappingRelationId, umId, useId);
01150     }
01151 
01152     /* dependency on extension */
01153     recordDependencyOnCurrentExtension(&myself, false);
01154 
01155     /* Post creation hook for new user mapping */
01156     InvokeObjectPostCreateHook(UserMappingRelationId, umId, 0);
01157 
01158     heap_close(rel, RowExclusiveLock);
01159 
01160     return umId;
01161 }
01162 
01163 
01164 /*
01165  * Alter user mapping
01166  */
01167 Oid
01168 AlterUserMapping(AlterUserMappingStmt *stmt)
01169 {
01170     Relation    rel;
01171     HeapTuple   tp;
01172     Datum       repl_val[Natts_pg_user_mapping];
01173     bool        repl_null[Natts_pg_user_mapping];
01174     bool        repl_repl[Natts_pg_user_mapping];
01175     Oid         useId;
01176     Oid         umId;
01177     ForeignServer *srv;
01178 
01179     rel = heap_open(UserMappingRelationId, RowExclusiveLock);
01180 
01181     useId = GetUserOidFromMapping(stmt->username, false);
01182     srv = GetForeignServerByName(stmt->servername, false);
01183 
01184     umId = GetSysCacheOid2(USERMAPPINGUSERSERVER,
01185                            ObjectIdGetDatum(useId),
01186                            ObjectIdGetDatum(srv->serverid));
01187     if (!OidIsValid(umId))
01188         ereport(ERROR,
01189                 (errcode(ERRCODE_UNDEFINED_OBJECT),
01190                  errmsg("user mapping \"%s\" does not exist for the server",
01191                         MappingUserName(useId))));
01192 
01193     user_mapping_ddl_aclcheck(useId, srv->serverid, stmt->servername);
01194 
01195     tp = SearchSysCacheCopy1(USERMAPPINGOID, ObjectIdGetDatum(umId));
01196 
01197     if (!HeapTupleIsValid(tp))
01198         elog(ERROR, "cache lookup failed for user mapping %u", umId);
01199 
01200     memset(repl_val, 0, sizeof(repl_val));
01201     memset(repl_null, false, sizeof(repl_null));
01202     memset(repl_repl, false, sizeof(repl_repl));
01203 
01204     if (stmt->options)
01205     {
01206         ForeignDataWrapper *fdw;
01207         Datum       datum;
01208         bool        isnull;
01209 
01210         /*
01211          * Process the options.
01212          */
01213 
01214         fdw = GetForeignDataWrapper(srv->fdwid);
01215 
01216         datum = SysCacheGetAttr(USERMAPPINGUSERSERVER,
01217                                 tp,
01218                                 Anum_pg_user_mapping_umoptions,
01219                                 &isnull);
01220         if (isnull)
01221             datum = PointerGetDatum(NULL);
01222 
01223         /* Prepare the options array */
01224         datum = transformGenericOptions(UserMappingRelationId,
01225                                         datum,
01226                                         stmt->options,
01227                                         fdw->fdwvalidator);
01228 
01229         if (PointerIsValid(DatumGetPointer(datum)))
01230             repl_val[Anum_pg_user_mapping_umoptions - 1] = datum;
01231         else
01232             repl_null[Anum_pg_user_mapping_umoptions - 1] = true;
01233 
01234         repl_repl[Anum_pg_user_mapping_umoptions - 1] = true;
01235     }
01236 
01237     /* Everything looks good - update the tuple */
01238     tp = heap_modify_tuple(tp, RelationGetDescr(rel),
01239                            repl_val, repl_null, repl_repl);
01240 
01241     simple_heap_update(rel, &tp->t_self, tp);
01242     CatalogUpdateIndexes(rel, tp);
01243 
01244     heap_freetuple(tp);
01245 
01246     heap_close(rel, RowExclusiveLock);
01247 
01248     return umId;
01249 }
01250 
01251 
01252 /*
01253  * Drop user mapping
01254  */
01255 Oid
01256 RemoveUserMapping(DropUserMappingStmt *stmt)
01257 {
01258     ObjectAddress object;
01259     Oid         useId;
01260     Oid         umId;
01261     ForeignServer *srv;
01262 
01263     useId = GetUserOidFromMapping(stmt->username, stmt->missing_ok);
01264     srv = GetForeignServerByName(stmt->servername, true);
01265 
01266     if (stmt->username && !OidIsValid(useId))
01267     {
01268         /*
01269          * IF EXISTS specified, role not found and not public. Notice this and
01270          * leave.
01271          */
01272         elog(NOTICE, "role \"%s\" does not exist, skipping", stmt->username);
01273         return InvalidOid;
01274     }
01275 
01276     if (!srv)
01277     {
01278         if (!stmt->missing_ok)
01279             ereport(ERROR,
01280                     (errcode(ERRCODE_UNDEFINED_OBJECT),
01281                      errmsg("server \"%s\" does not exist",
01282                             stmt->servername)));
01283         /* IF EXISTS, just note it */
01284         ereport(NOTICE, (errmsg("server does not exist, skipping")));
01285         return InvalidOid;
01286     }
01287 
01288     umId = GetSysCacheOid2(USERMAPPINGUSERSERVER,
01289                            ObjectIdGetDatum(useId),
01290                            ObjectIdGetDatum(srv->serverid));
01291 
01292     if (!OidIsValid(umId))
01293     {
01294         if (!stmt->missing_ok)
01295             ereport(ERROR,
01296                     (errcode(ERRCODE_UNDEFINED_OBJECT),
01297                   errmsg("user mapping \"%s\" does not exist for the server",
01298                          MappingUserName(useId))));
01299 
01300         /* IF EXISTS specified, just note it */
01301         ereport(NOTICE,
01302         (errmsg("user mapping \"%s\" does not exist for the server, skipping",
01303                 MappingUserName(useId))));
01304         return InvalidOid;
01305     }
01306 
01307     user_mapping_ddl_aclcheck(useId, srv->serverid, srv->servername);
01308 
01309     /*
01310      * Do the deletion
01311      */
01312     object.classId = UserMappingRelationId;
01313     object.objectId = umId;
01314     object.objectSubId = 0;
01315 
01316     performDeletion(&object, DROP_CASCADE, 0);
01317 
01318     return umId;
01319 }
01320 
01321 
01322 /*
01323  * Drop user mapping by OID.  This is called to clean up dependencies.
01324  */
01325 void
01326 RemoveUserMappingById(Oid umId)
01327 {
01328     HeapTuple   tp;
01329     Relation    rel;
01330 
01331     rel = heap_open(UserMappingRelationId, RowExclusiveLock);
01332 
01333     tp = SearchSysCache1(USERMAPPINGOID, ObjectIdGetDatum(umId));
01334 
01335     if (!HeapTupleIsValid(tp))
01336         elog(ERROR, "cache lookup failed for user mapping %u", umId);
01337 
01338     simple_heap_delete(rel, &tp->t_self);
01339 
01340     ReleaseSysCache(tp);
01341 
01342     heap_close(rel, RowExclusiveLock);
01343 }
01344 
01345 /*
01346  * Create a foreign table
01347  * call after DefineRelation().
01348  */
01349 void
01350 CreateForeignTable(CreateForeignTableStmt *stmt, Oid relid)
01351 {
01352     Relation    ftrel;
01353     Datum       ftoptions;
01354     Datum       values[Natts_pg_foreign_table];
01355     bool        nulls[Natts_pg_foreign_table];
01356     HeapTuple   tuple;
01357     AclResult   aclresult;
01358     ObjectAddress myself;
01359     ObjectAddress referenced;
01360     Oid         ownerId;
01361     ForeignDataWrapper *fdw;
01362     ForeignServer *server;
01363 
01364     /*
01365      * Advance command counter to ensure the pg_attribute tuple is visible;
01366      * the tuple might be updated to add constraints in previous step.
01367      */
01368     CommandCounterIncrement();
01369 
01370     ftrel = heap_open(ForeignTableRelationId, RowExclusiveLock);
01371 
01372     /*
01373      * For now the owner cannot be specified on create. Use effective user ID.
01374      */
01375     ownerId = GetUserId();
01376 
01377     /*
01378      * Check that the foreign server exists and that we have USAGE on it. Also
01379      * get the actual FDW for option validation etc.
01380      */
01381     server = GetForeignServerByName(stmt->servername, false);
01382     aclresult = pg_foreign_server_aclcheck(server->serverid, ownerId, ACL_USAGE);
01383     if (aclresult != ACLCHECK_OK)
01384         aclcheck_error(aclresult, ACL_KIND_FOREIGN_SERVER, server->servername);
01385 
01386     fdw = GetForeignDataWrapper(server->fdwid);
01387 
01388     /*
01389      * Insert tuple into pg_foreign_table.
01390      */
01391     memset(values, 0, sizeof(values));
01392     memset(nulls, false, sizeof(nulls));
01393 
01394     values[Anum_pg_foreign_table_ftrelid - 1] = ObjectIdGetDatum(relid);
01395     values[Anum_pg_foreign_table_ftserver - 1] = ObjectIdGetDatum(server->serverid);
01396     /* Add table generic options */
01397     ftoptions = transformGenericOptions(ForeignTableRelationId,
01398                                         PointerGetDatum(NULL),
01399                                         stmt->options,
01400                                         fdw->fdwvalidator);
01401 
01402     if (PointerIsValid(DatumGetPointer(ftoptions)))
01403         values[Anum_pg_foreign_table_ftoptions - 1] = ftoptions;
01404     else
01405         nulls[Anum_pg_foreign_table_ftoptions - 1] = true;
01406 
01407     tuple = heap_form_tuple(ftrel->rd_att, values, nulls);
01408 
01409     simple_heap_insert(ftrel, tuple);
01410     CatalogUpdateIndexes(ftrel, tuple);
01411 
01412     heap_freetuple(tuple);
01413 
01414     /* Add pg_class dependency on the server */
01415     myself.classId = RelationRelationId;
01416     myself.objectId = relid;
01417     myself.objectSubId = 0;
01418 
01419     referenced.classId = ForeignServerRelationId;
01420     referenced.objectId = server->serverid;
01421     referenced.objectSubId = 0;
01422     recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
01423 
01424     heap_close(ftrel, RowExclusiveLock);
01425 }