Header And Logo

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

Functions

foreigncmds.c File Reference

#include "postgres.h"
#include "access/heapam.h"
#include "access/htup_details.h"
#include "access/xact.h"
#include "access/reloptions.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/objectaccess.h"
#include "catalog/pg_foreign_data_wrapper.h"
#include "catalog/pg_foreign_server.h"
#include "catalog/pg_foreign_table.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "catalog/pg_user_mapping.h"
#include "commands/defrem.h"
#include "foreign/foreign.h"
#include "miscadmin.h"
#include "parser/parse_func.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"
#include "utils/syscache.h"
Include dependency graph for foreigncmds.c:

Go to the source code of this file.

Functions

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

Function Documentation

Oid AlterForeignDataWrapper ( AlterFdwStmt stmt  ) 

Definition at line 620 of file foreigncmds.c.

References Anum_pg_foreign_data_wrapper_fdwhandler, Anum_pg_foreign_data_wrapper_fdwoptions, Anum_pg_foreign_data_wrapper_fdwvalidator, CatalogUpdateIndexes(), ObjectAddress::classId, CStringGetDatum, DatumGetPointer, deleteDependencyRecordsForClass(), DEPENDENCY_NORMAL, ereport, errcode(), errhint(), errmsg(), ERROR, AlterFdwStmt::fdwname, FOREIGNDATAWRAPPERNAME, FOREIGNDATAWRAPPEROID, ForeignDataWrapperRelationId, AlterFdwStmt::func_options, GETSTRUCT, heap_close, heap_freetuple(), heap_modify_tuple(), heap_open(), HeapTupleGetOid, HeapTupleIsValid, InvokeObjectPostAlterHook, NULL, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, AlterFdwStmt::options, parse_func_options(), PointerGetDatum, PointerIsValid, ProcedureRelationId, recordDependencyOn(), RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, simple_heap_update(), superuser(), SysCacheGetAttr(), HeapTupleData::t_self, transformGenericOptions(), and WARNING.

Referenced by ProcessUtilitySlow().

{
    Relation    rel;
    HeapTuple   tp;
    Form_pg_foreign_data_wrapper fdwForm;
    Datum       repl_val[Natts_pg_foreign_data_wrapper];
    bool        repl_null[Natts_pg_foreign_data_wrapper];
    bool        repl_repl[Natts_pg_foreign_data_wrapper];
    Oid         fdwId;
    bool        isnull;
    Datum       datum;
    bool        handler_given;
    bool        validator_given;
    Oid         fdwhandler;
    Oid         fdwvalidator;

    rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);

    /* Must be super user */
    if (!superuser())
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
             errmsg("permission denied to alter foreign-data wrapper \"%s\"",
                    stmt->fdwname),
             errhint("Must be superuser to alter a foreign-data wrapper.")));

    tp = SearchSysCacheCopy1(FOREIGNDATAWRAPPERNAME,
                             CStringGetDatum(stmt->fdwname));

    if (!HeapTupleIsValid(tp))
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_OBJECT),
        errmsg("foreign-data wrapper \"%s\" does not exist", stmt->fdwname)));

    fdwForm = (Form_pg_foreign_data_wrapper) GETSTRUCT(tp);
    fdwId = HeapTupleGetOid(tp);

    memset(repl_val, 0, sizeof(repl_val));
    memset(repl_null, false, sizeof(repl_null));
    memset(repl_repl, false, sizeof(repl_repl));

    parse_func_options(stmt->func_options,
                       &handler_given, &fdwhandler,
                       &validator_given, &fdwvalidator);

    if (handler_given)
    {
        repl_val[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = ObjectIdGetDatum(fdwhandler);
        repl_repl[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = true;

        /*
         * It could be that the behavior of accessing foreign table changes
         * with the new handler.  Warn about this.
         */
        ereport(WARNING,
                (errmsg("changing the foreign-data wrapper handler can change behavior of existing foreign tables")));
    }

    if (validator_given)
    {
        repl_val[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = ObjectIdGetDatum(fdwvalidator);
        repl_repl[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = true;

        /*
         * It could be that the options for the FDW, SERVER and USER MAPPING
         * are no longer valid with the new validator.  Warn about this.
         */
        if (OidIsValid(fdwvalidator))
            ereport(WARNING,
             (errmsg("changing the foreign-data wrapper validator can cause "
                     "the options for dependent objects to become invalid")));
    }
    else
    {
        /*
         * Validator is not changed, but we need it for validating options.
         */
        fdwvalidator = fdwForm->fdwvalidator;
    }

    /*
     * If options specified, validate and update.
     */
    if (stmt->options)
    {
        /* Extract the current options */
        datum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID,
                                tp,
                                Anum_pg_foreign_data_wrapper_fdwoptions,
                                &isnull);
        if (isnull)
            datum = PointerGetDatum(NULL);

        /* Transform the options */
        datum = transformGenericOptions(ForeignDataWrapperRelationId,
                                        datum,
                                        stmt->options,
                                        fdwvalidator);

        if (PointerIsValid(DatumGetPointer(datum)))
            repl_val[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = datum;
        else
            repl_null[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true;

        repl_repl[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true;
    }

    /* Everything looks good - update the tuple */
    tp = heap_modify_tuple(tp, RelationGetDescr(rel),
                           repl_val, repl_null, repl_repl);

    simple_heap_update(rel, &tp->t_self, tp);
    CatalogUpdateIndexes(rel, tp);

    heap_freetuple(tp);

    /* Update function dependencies if we changed them */
    if (handler_given || validator_given)
    {
        ObjectAddress myself;
        ObjectAddress referenced;

        /*
         * Flush all existing dependency records of this FDW on functions; we
         * assume there can be none other than the ones we are fixing.
         */
        deleteDependencyRecordsForClass(ForeignDataWrapperRelationId,
                                        fdwId,
                                        ProcedureRelationId,
                                        DEPENDENCY_NORMAL);

        /* And build new ones. */
        myself.classId = ForeignDataWrapperRelationId;
        myself.objectId = fdwId;
        myself.objectSubId = 0;

        if (OidIsValid(fdwhandler))
        {
            referenced.classId = ProcedureRelationId;
            referenced.objectId = fdwhandler;
            referenced.objectSubId = 0;
            recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
        }

        if (OidIsValid(fdwvalidator))
        {
            referenced.classId = ProcedureRelationId;
            referenced.objectId = fdwvalidator;
            referenced.objectSubId = 0;
            recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
        }
    }

    InvokeObjectPostAlterHook(ForeignDataWrapperRelationId, fdwId, 0);

    heap_close(rel, RowExclusiveLock);

    return fdwId;
}

Oid AlterForeignDataWrapperOwner ( const char *  name,
Oid  newOwnerId 
)
static void AlterForeignDataWrapperOwner_internal ( Relation  rel,
HeapTuple  tup,
Oid  newOwnerId 
) [static]

Definition at line 210 of file foreigncmds.c.

References CatalogUpdateIndexes(), changeDependencyOnOwner(), ereport, errcode(), errhint(), errmsg(), ERROR, ForeignDataWrapperRelationId, GETSTRUCT, HeapTupleGetOid, InvokeObjectPostAlterHook, NameStr, simple_heap_update(), superuser(), superuser_arg(), and HeapTupleData::t_self.

Referenced by AlterForeignDataWrapperOwner(), and AlterForeignDataWrapperOwner_oid().

{
    Form_pg_foreign_data_wrapper form;

    form = (Form_pg_foreign_data_wrapper) GETSTRUCT(tup);

    /* Must be a superuser to change a FDW owner */
    if (!superuser())
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 errmsg("permission denied to change owner of foreign-data wrapper \"%s\"",
                        NameStr(form->fdwname)),
                 errhint("Must be superuser to change owner of a foreign-data wrapper.")));

    /* New owner must also be a superuser */
    if (!superuser_arg(newOwnerId))
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
                 errmsg("permission denied to change owner of foreign-data wrapper \"%s\"",
                        NameStr(form->fdwname)),
        errhint("The owner of a foreign-data wrapper must be a superuser.")));

    if (form->fdwowner != newOwnerId)
    {
        form->fdwowner = newOwnerId;

        simple_heap_update(rel, &tup->t_self, tup);
        CatalogUpdateIndexes(rel, tup);

        /* Update owner dependency reference */
        changeDependencyOnOwner(ForeignDataWrapperRelationId,
                                HeapTupleGetOid(tup),
                                newOwnerId);
    }

    InvokeObjectPostAlterHook(ForeignDataWrapperRelationId,
                              HeapTupleGetOid(tup), 0);
}

void AlterForeignDataWrapperOwner_oid ( Oid  fwdId,
Oid  newOwnerId 
)
Oid AlterForeignServer ( AlterForeignServerStmt stmt  ) 

Definition at line 922 of file foreigncmds.c.

References ACL_KIND_FOREIGN_SERVER, aclcheck_error(), ACLCHECK_NOT_OWNER, Anum_pg_foreign_server_srvoptions, Anum_pg_foreign_server_srvversion, CatalogUpdateIndexes(), CStringGetDatum, CStringGetTextDatum, DatumGetPointer, ereport, errcode(), errmsg(), ERROR, ForeignDataWrapper::fdwvalidator, FOREIGNSERVERNAME, FOREIGNSERVEROID, ForeignServerRelationId, GetForeignDataWrapper(), GETSTRUCT, GetUserId(), AlterForeignServerStmt::has_version, heap_close, heap_freetuple(), heap_modify_tuple(), heap_open(), HeapTupleGetOid, HeapTupleIsValid, InvokeObjectPostAlterHook, NULL, AlterForeignServerStmt::options, pg_foreign_server_ownercheck(), PointerGetDatum, PointerIsValid, RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, AlterForeignServerStmt::servername, simple_heap_update(), SysCacheGetAttr(), HeapTupleData::t_self, transformGenericOptions(), and AlterForeignServerStmt::version.

Referenced by ProcessUtilitySlow().

{
    Relation    rel;
    HeapTuple   tp;
    Datum       repl_val[Natts_pg_foreign_server];
    bool        repl_null[Natts_pg_foreign_server];
    bool        repl_repl[Natts_pg_foreign_server];
    Oid         srvId;
    Form_pg_foreign_server srvForm;

    rel = heap_open(ForeignServerRelationId, RowExclusiveLock);

    tp = SearchSysCacheCopy1(FOREIGNSERVERNAME,
                             CStringGetDatum(stmt->servername));

    if (!HeapTupleIsValid(tp))
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_OBJECT),
                 errmsg("server \"%s\" does not exist", stmt->servername)));

    srvId = HeapTupleGetOid(tp);
    srvForm = (Form_pg_foreign_server) GETSTRUCT(tp);

    /*
     * Only owner or a superuser can ALTER a SERVER.
     */
    if (!pg_foreign_server_ownercheck(srvId, GetUserId()))
        aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
                       stmt->servername);

    memset(repl_val, 0, sizeof(repl_val));
    memset(repl_null, false, sizeof(repl_null));
    memset(repl_repl, false, sizeof(repl_repl));

    if (stmt->has_version)
    {
        /*
         * Change the server VERSION string.
         */
        if (stmt->version)
            repl_val[Anum_pg_foreign_server_srvversion - 1] =
                CStringGetTextDatum(stmt->version);
        else
            repl_null[Anum_pg_foreign_server_srvversion - 1] = true;

        repl_repl[Anum_pg_foreign_server_srvversion - 1] = true;
    }

    if (stmt->options)
    {
        ForeignDataWrapper *fdw = GetForeignDataWrapper(srvForm->srvfdw);
        Datum       datum;
        bool        isnull;

        /* Extract the current srvoptions */
        datum = SysCacheGetAttr(FOREIGNSERVEROID,
                                tp,
                                Anum_pg_foreign_server_srvoptions,
                                &isnull);
        if (isnull)
            datum = PointerGetDatum(NULL);

        /* Prepare the options array */
        datum = transformGenericOptions(ForeignServerRelationId,
                                        datum,
                                        stmt->options,
                                        fdw->fdwvalidator);

        if (PointerIsValid(DatumGetPointer(datum)))
            repl_val[Anum_pg_foreign_server_srvoptions - 1] = datum;
        else
            repl_null[Anum_pg_foreign_server_srvoptions - 1] = true;

        repl_repl[Anum_pg_foreign_server_srvoptions - 1] = true;
    }

    /* Everything looks good - update the tuple */
    tp = heap_modify_tuple(tp, RelationGetDescr(rel),
                           repl_val, repl_null, repl_repl);

    simple_heap_update(rel, &tp->t_self, tp);
    CatalogUpdateIndexes(rel, tp);

    InvokeObjectPostAlterHook(ForeignServerRelationId, srvId, 0);

    heap_freetuple(tp);

    heap_close(rel, RowExclusiveLock);

    return srvId;
}

Oid AlterForeignServerOwner ( const char *  name,
Oid  newOwnerId 
)
static void AlterForeignServerOwner_internal ( Relation  rel,
HeapTuple  tup,
Oid  newOwnerId 
) [static]

Definition at line 312 of file foreigncmds.c.

References ACL_KIND_FDW, ACL_KIND_FOREIGN_SERVER, ACL_USAGE, aclcheck_error(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, CatalogUpdateIndexes(), changeDependencyOnOwner(), check_is_member_of_role(), ForeignDataWrapper::fdwname, ForeignServerRelationId, GetForeignDataWrapper(), GETSTRUCT, GetUserId(), HeapTupleGetOid, InvokeObjectPostAlterHook, NameStr, pg_foreign_data_wrapper_aclcheck(), pg_foreign_server_ownercheck(), simple_heap_update(), superuser(), and HeapTupleData::t_self.

Referenced by AlterForeignServerOwner(), and AlterForeignServerOwner_oid().

{
    Form_pg_foreign_server form;

    form = (Form_pg_foreign_server) GETSTRUCT(tup);

    if (form->srvowner != newOwnerId)
    {
        /* Superusers can always do it */
        if (!superuser())
        {
            Oid         srvId;
            AclResult   aclresult;

            srvId = HeapTupleGetOid(tup);

            /* Must be owner */
            if (!pg_foreign_server_ownercheck(srvId, GetUserId()))
                aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
                               NameStr(form->srvname));

            /* Must be able to become new owner */
            check_is_member_of_role(GetUserId(), newOwnerId);

            /* New owner must have USAGE privilege on foreign-data wrapper */
            aclresult = pg_foreign_data_wrapper_aclcheck(form->srvfdw, newOwnerId, ACL_USAGE);
            if (aclresult != ACLCHECK_OK)
            {
                ForeignDataWrapper *fdw = GetForeignDataWrapper(form->srvfdw);

                aclcheck_error(aclresult, ACL_KIND_FDW, fdw->fdwname);
            }
        }

        form->srvowner = newOwnerId;

        simple_heap_update(rel, &tup->t_self, tup);
        CatalogUpdateIndexes(rel, tup);

        /* Update owner dependency reference */
        changeDependencyOnOwner(ForeignServerRelationId, HeapTupleGetOid(tup),
                                newOwnerId);
    }

    InvokeObjectPostAlterHook(ForeignServerRelationId,
                              HeapTupleGetOid(tup), 0);
}

void AlterForeignServerOwner_oid ( Oid  srvId,
Oid  newOwnerId 
)
Oid AlterUserMapping ( AlterUserMappingStmt stmt  ) 

Definition at line 1168 of file foreigncmds.c.

References Anum_pg_user_mapping_umoptions, CatalogUpdateIndexes(), DatumGetPointer, elog, ereport, errcode(), errmsg(), ERROR, ForeignServer::fdwid, ForeignDataWrapper::fdwvalidator, GetForeignDataWrapper(), GetForeignServerByName(), GetSysCacheOid2, GetUserOidFromMapping(), heap_close, heap_freetuple(), heap_modify_tuple(), heap_open(), HeapTupleIsValid, MappingUserName, NULL, ObjectIdGetDatum, OidIsValid, AlterUserMappingStmt::options, PointerGetDatum, PointerIsValid, RelationGetDescr, RowExclusiveLock, SearchSysCacheCopy1, ForeignServer::serverid, AlterUserMappingStmt::servername, simple_heap_update(), SysCacheGetAttr(), HeapTupleData::t_self, transformGenericOptions(), user_mapping_ddl_aclcheck(), USERMAPPINGOID, UserMappingRelationId, USERMAPPINGUSERSERVER, and AlterUserMappingStmt::username.

Referenced by ProcessUtilitySlow().

{
    Relation    rel;
    HeapTuple   tp;
    Datum       repl_val[Natts_pg_user_mapping];
    bool        repl_null[Natts_pg_user_mapping];
    bool        repl_repl[Natts_pg_user_mapping];
    Oid         useId;
    Oid         umId;
    ForeignServer *srv;

    rel = heap_open(UserMappingRelationId, RowExclusiveLock);

    useId = GetUserOidFromMapping(stmt->username, false);
    srv = GetForeignServerByName(stmt->servername, false);

    umId = GetSysCacheOid2(USERMAPPINGUSERSERVER,
                           ObjectIdGetDatum(useId),
                           ObjectIdGetDatum(srv->serverid));
    if (!OidIsValid(umId))
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_OBJECT),
                 errmsg("user mapping \"%s\" does not exist for the server",
                        MappingUserName(useId))));

    user_mapping_ddl_aclcheck(useId, srv->serverid, stmt->servername);

    tp = SearchSysCacheCopy1(USERMAPPINGOID, ObjectIdGetDatum(umId));

    if (!HeapTupleIsValid(tp))
        elog(ERROR, "cache lookup failed for user mapping %u", umId);

    memset(repl_val, 0, sizeof(repl_val));
    memset(repl_null, false, sizeof(repl_null));
    memset(repl_repl, false, sizeof(repl_repl));

    if (stmt->options)
    {
        ForeignDataWrapper *fdw;
        Datum       datum;
        bool        isnull;

        /*
         * Process the options.
         */

        fdw = GetForeignDataWrapper(srv->fdwid);

        datum = SysCacheGetAttr(USERMAPPINGUSERSERVER,
                                tp,
                                Anum_pg_user_mapping_umoptions,
                                &isnull);
        if (isnull)
            datum = PointerGetDatum(NULL);

        /* Prepare the options array */
        datum = transformGenericOptions(UserMappingRelationId,
                                        datum,
                                        stmt->options,
                                        fdw->fdwvalidator);

        if (PointerIsValid(DatumGetPointer(datum)))
            repl_val[Anum_pg_user_mapping_umoptions - 1] = datum;
        else
            repl_null[Anum_pg_user_mapping_umoptions - 1] = true;

        repl_repl[Anum_pg_user_mapping_umoptions - 1] = true;
    }

    /* Everything looks good - update the tuple */
    tp = heap_modify_tuple(tp, RelationGetDescr(rel),
                           repl_val, repl_null, repl_repl);

    simple_heap_update(rel, &tp->t_self, tp);
    CatalogUpdateIndexes(rel, tp);

    heap_freetuple(tp);

    heap_close(rel, RowExclusiveLock);

    return umId;
}

Oid CreateForeignDataWrapper ( CreateFdwStmt stmt  ) 

Definition at line 506 of file foreigncmds.c.

References Anum_pg_foreign_data_wrapper_fdwacl, Anum_pg_foreign_data_wrapper_fdwhandler, Anum_pg_foreign_data_wrapper_fdwname, Anum_pg_foreign_data_wrapper_fdwoptions, Anum_pg_foreign_data_wrapper_fdwowner, Anum_pg_foreign_data_wrapper_fdwvalidator, CatalogUpdateIndexes(), ObjectAddress::classId, CStringGetDatum, DatumGetPointer, DEPENDENCY_NORMAL, DirectFunctionCall1, ereport, errcode(), errhint(), errmsg(), ERROR, CreateFdwStmt::fdwname, ForeignDataWrapperRelationId, CreateFdwStmt::func_options, GetForeignDataWrapperByName(), GetUserId(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), InvokeObjectPostCreateHook, namein(), NULL, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, CreateFdwStmt::options, parse_func_options(), PointerGetDatum, PointerIsValid, RelationData::rd_att, recordDependencyOn(), recordDependencyOnCurrentExtension(), recordDependencyOnOwner(), RowExclusiveLock, simple_heap_insert(), superuser(), transformGenericOptions(), and values.

Referenced by ProcessUtilitySlow().

{
    Relation    rel;
    Datum       values[Natts_pg_foreign_data_wrapper];
    bool        nulls[Natts_pg_foreign_data_wrapper];
    HeapTuple   tuple;
    Oid         fdwId;
    bool        handler_given;
    bool        validator_given;
    Oid         fdwhandler;
    Oid         fdwvalidator;
    Datum       fdwoptions;
    Oid         ownerId;
    ObjectAddress myself;
    ObjectAddress referenced;

    rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);

    /* Must be super user */
    if (!superuser())
        ereport(ERROR,
                (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
            errmsg("permission denied to create foreign-data wrapper \"%s\"",
                   stmt->fdwname),
            errhint("Must be superuser to create a foreign-data wrapper.")));

    /* For now the owner cannot be specified on create. Use effective user ID. */
    ownerId = GetUserId();

    /*
     * Check that there is no other foreign-data wrapper by this name.
     */
    if (GetForeignDataWrapperByName(stmt->fdwname, true) != NULL)
        ereport(ERROR,
                (errcode(ERRCODE_DUPLICATE_OBJECT),
                 errmsg("foreign-data wrapper \"%s\" already exists",
                        stmt->fdwname)));

    /*
     * Insert tuple into pg_foreign_data_wrapper.
     */
    memset(values, 0, sizeof(values));
    memset(nulls, false, sizeof(nulls));

    values[Anum_pg_foreign_data_wrapper_fdwname - 1] =
        DirectFunctionCall1(namein, CStringGetDatum(stmt->fdwname));
    values[Anum_pg_foreign_data_wrapper_fdwowner - 1] = ObjectIdGetDatum(ownerId);

    /* Lookup handler and validator functions, if given */
    parse_func_options(stmt->func_options,
                       &handler_given, &fdwhandler,
                       &validator_given, &fdwvalidator);

    values[Anum_pg_foreign_data_wrapper_fdwhandler - 1] = ObjectIdGetDatum(fdwhandler);
    values[Anum_pg_foreign_data_wrapper_fdwvalidator - 1] = ObjectIdGetDatum(fdwvalidator);

    nulls[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true;

    fdwoptions = transformGenericOptions(ForeignDataWrapperRelationId,
                                         PointerGetDatum(NULL),
                                         stmt->options,
                                         fdwvalidator);

    if (PointerIsValid(DatumGetPointer(fdwoptions)))
        values[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = fdwoptions;
    else
        nulls[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true;

    tuple = heap_form_tuple(rel->rd_att, values, nulls);

    fdwId = simple_heap_insert(rel, tuple);
    CatalogUpdateIndexes(rel, tuple);

    heap_freetuple(tuple);

    /* record dependencies */
    myself.classId = ForeignDataWrapperRelationId;
    myself.objectId = fdwId;
    myself.objectSubId = 0;

    if (OidIsValid(fdwhandler))
    {
        referenced.classId = ProcedureRelationId;
        referenced.objectId = fdwhandler;
        referenced.objectSubId = 0;
        recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
    }

    if (OidIsValid(fdwvalidator))
    {
        referenced.classId = ProcedureRelationId;
        referenced.objectId = fdwvalidator;
        referenced.objectSubId = 0;
        recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
    }

    recordDependencyOnOwner(ForeignDataWrapperRelationId, fdwId, ownerId);

    /* dependency on extension */
    recordDependencyOnCurrentExtension(&myself, false);

    /* Post creation hook for new foreign data wrapper */
    InvokeObjectPostCreateHook(ForeignDataWrapperRelationId, fdwId, 0);

    heap_close(rel, RowExclusiveLock);

    return fdwId;
}

Oid CreateForeignServer ( CreateForeignServerStmt stmt  ) 

Definition at line 809 of file foreigncmds.c.

References ACL_KIND_FDW, ACL_USAGE, aclcheck_error(), ACLCHECK_OK, Anum_pg_foreign_server_srvacl, Anum_pg_foreign_server_srvfdw, Anum_pg_foreign_server_srvname, Anum_pg_foreign_server_srvoptions, Anum_pg_foreign_server_srvowner, Anum_pg_foreign_server_srvtype, Anum_pg_foreign_server_srvversion, CatalogUpdateIndexes(), ObjectAddress::classId, CStringGetDatum, CStringGetTextDatum, DatumGetPointer, DEPENDENCY_NORMAL, DirectFunctionCall1, ereport, errcode(), errmsg(), ERROR, ForeignDataWrapper::fdwid, ForeignDataWrapper::fdwname, CreateForeignServerStmt::fdwname, ForeignDataWrapper::fdwvalidator, ForeignServerRelationId, GetForeignDataWrapperByName(), GetForeignServerByName(), GetUserId(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), InvokeObjectPostCreateHook, namein(), NULL, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, CreateForeignServerStmt::options, pg_foreign_data_wrapper_aclcheck(), PointerGetDatum, PointerIsValid, RelationData::rd_att, recordDependencyOn(), recordDependencyOnCurrentExtension(), recordDependencyOnOwner(), RowExclusiveLock, CreateForeignServerStmt::servername, CreateForeignServerStmt::servertype, simple_heap_insert(), transformGenericOptions(), values, and CreateForeignServerStmt::version.

Referenced by ProcessUtilitySlow().

{
    Relation    rel;
    Datum       srvoptions;
    Datum       values[Natts_pg_foreign_server];
    bool        nulls[Natts_pg_foreign_server];
    HeapTuple   tuple;
    Oid         srvId;
    Oid         ownerId;
    AclResult   aclresult;
    ObjectAddress myself;
    ObjectAddress referenced;
    ForeignDataWrapper *fdw;

    rel = heap_open(ForeignServerRelationId, RowExclusiveLock);

    /* For now the owner cannot be specified on create. Use effective user ID. */
    ownerId = GetUserId();

    /*
     * Check that there is no other foreign server by this name.
     */
    if (GetForeignServerByName(stmt->servername, true) != NULL)
        ereport(ERROR,
                (errcode(ERRCODE_DUPLICATE_OBJECT),
                 errmsg("server \"%s\" already exists",
                        stmt->servername)));

    /*
     * Check that the FDW exists and that we have USAGE on it. Also get the
     * actual FDW for option validation etc.
     */
    fdw = GetForeignDataWrapperByName(stmt->fdwname, false);

    aclresult = pg_foreign_data_wrapper_aclcheck(fdw->fdwid, ownerId, ACL_USAGE);
    if (aclresult != ACLCHECK_OK)
        aclcheck_error(aclresult, ACL_KIND_FDW, fdw->fdwname);

    /*
     * Insert tuple into pg_foreign_server.
     */
    memset(values, 0, sizeof(values));
    memset(nulls, false, sizeof(nulls));

    values[Anum_pg_foreign_server_srvname - 1] =
        DirectFunctionCall1(namein, CStringGetDatum(stmt->servername));
    values[Anum_pg_foreign_server_srvowner - 1] = ObjectIdGetDatum(ownerId);
    values[Anum_pg_foreign_server_srvfdw - 1] = ObjectIdGetDatum(fdw->fdwid);

    /* Add server type if supplied */
    if (stmt->servertype)
        values[Anum_pg_foreign_server_srvtype - 1] =
            CStringGetTextDatum(stmt->servertype);
    else
        nulls[Anum_pg_foreign_server_srvtype - 1] = true;

    /* Add server version if supplied */
    if (stmt->version)
        values[Anum_pg_foreign_server_srvversion - 1] =
            CStringGetTextDatum(stmt->version);
    else
        nulls[Anum_pg_foreign_server_srvversion - 1] = true;

    /* Start with a blank acl */
    nulls[Anum_pg_foreign_server_srvacl - 1] = true;

    /* Add server options */
    srvoptions = transformGenericOptions(ForeignServerRelationId,
                                         PointerGetDatum(NULL),
                                         stmt->options,
                                         fdw->fdwvalidator);

    if (PointerIsValid(DatumGetPointer(srvoptions)))
        values[Anum_pg_foreign_server_srvoptions - 1] = srvoptions;
    else
        nulls[Anum_pg_foreign_server_srvoptions - 1] = true;

    tuple = heap_form_tuple(rel->rd_att, values, nulls);

    srvId = simple_heap_insert(rel, tuple);

    CatalogUpdateIndexes(rel, tuple);

    heap_freetuple(tuple);

    /* record dependencies */
    myself.classId = ForeignServerRelationId;
    myself.objectId = srvId;
    myself.objectSubId = 0;

    referenced.classId = ForeignDataWrapperRelationId;
    referenced.objectId = fdw->fdwid;
    referenced.objectSubId = 0;
    recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

    recordDependencyOnOwner(ForeignServerRelationId, srvId, ownerId);

    /* dependency on extension */
    recordDependencyOnCurrentExtension(&myself, false);

    /* Post creation hook for new foreign server */
    InvokeObjectPostCreateHook(ForeignServerRelationId, srvId, 0);

    heap_close(rel, RowExclusiveLock);

    return srvId;
}

void CreateForeignTable ( CreateForeignTableStmt stmt,
Oid  relid 
)

Definition at line 1350 of file foreigncmds.c.

References ACL_KIND_FOREIGN_SERVER, ACL_USAGE, aclcheck_error(), ACLCHECK_OK, Anum_pg_foreign_table_ftoptions, Anum_pg_foreign_table_ftrelid, Anum_pg_foreign_table_ftserver, CatalogUpdateIndexes(), ObjectAddress::classId, CommandCounterIncrement(), DatumGetPointer, DEPENDENCY_NORMAL, ForeignServer::fdwid, ForeignDataWrapper::fdwvalidator, ForeignTableRelationId, GetForeignDataWrapper(), GetForeignServerByName(), GetUserId(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), NULL, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, CreateForeignTableStmt::options, pg_foreign_server_aclcheck(), PointerGetDatum, PointerIsValid, RelationData::rd_att, recordDependencyOn(), RowExclusiveLock, ForeignServer::serverid, ForeignServer::servername, CreateForeignTableStmt::servername, simple_heap_insert(), transformGenericOptions(), and values.

Referenced by ProcessUtilitySlow().

{
    Relation    ftrel;
    Datum       ftoptions;
    Datum       values[Natts_pg_foreign_table];
    bool        nulls[Natts_pg_foreign_table];
    HeapTuple   tuple;
    AclResult   aclresult;
    ObjectAddress myself;
    ObjectAddress referenced;
    Oid         ownerId;
    ForeignDataWrapper *fdw;
    ForeignServer *server;

    /*
     * Advance command counter to ensure the pg_attribute tuple is visible;
     * the tuple might be updated to add constraints in previous step.
     */
    CommandCounterIncrement();

    ftrel = heap_open(ForeignTableRelationId, RowExclusiveLock);

    /*
     * For now the owner cannot be specified on create. Use effective user ID.
     */
    ownerId = GetUserId();

    /*
     * Check that the foreign server exists and that we have USAGE on it. Also
     * get the actual FDW for option validation etc.
     */
    server = GetForeignServerByName(stmt->servername, false);
    aclresult = pg_foreign_server_aclcheck(server->serverid, ownerId, ACL_USAGE);
    if (aclresult != ACLCHECK_OK)
        aclcheck_error(aclresult, ACL_KIND_FOREIGN_SERVER, server->servername);

    fdw = GetForeignDataWrapper(server->fdwid);

    /*
     * Insert tuple into pg_foreign_table.
     */
    memset(values, 0, sizeof(values));
    memset(nulls, false, sizeof(nulls));

    values[Anum_pg_foreign_table_ftrelid - 1] = ObjectIdGetDatum(relid);
    values[Anum_pg_foreign_table_ftserver - 1] = ObjectIdGetDatum(server->serverid);
    /* Add table generic options */
    ftoptions = transformGenericOptions(ForeignTableRelationId,
                                        PointerGetDatum(NULL),
                                        stmt->options,
                                        fdw->fdwvalidator);

    if (PointerIsValid(DatumGetPointer(ftoptions)))
        values[Anum_pg_foreign_table_ftoptions - 1] = ftoptions;
    else
        nulls[Anum_pg_foreign_table_ftoptions - 1] = true;

    tuple = heap_form_tuple(ftrel->rd_att, values, nulls);

    simple_heap_insert(ftrel, tuple);
    CatalogUpdateIndexes(ftrel, tuple);

    heap_freetuple(tuple);

    /* Add pg_class dependency on the server */
    myself.classId = RelationRelationId;
    myself.objectId = relid;
    myself.objectSubId = 0;

    referenced.classId = ForeignServerRelationId;
    referenced.objectId = server->serverid;
    referenced.objectSubId = 0;
    recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

    heap_close(ftrel, RowExclusiveLock);
}

Oid CreateUserMapping ( CreateUserMappingStmt stmt  ) 

Definition at line 1070 of file foreigncmds.c.

References Anum_pg_user_mapping_umoptions, Anum_pg_user_mapping_umserver, Anum_pg_user_mapping_umuser, CatalogUpdateIndexes(), ObjectAddress::classId, DatumGetPointer, DEPENDENCY_NORMAL, ereport, errcode(), errmsg(), ERROR, ForeignServer::fdwid, ForeignDataWrapper::fdwvalidator, GetForeignDataWrapper(), GetForeignServerByName(), GetSysCacheOid2, GetUserOidFromMapping(), heap_close, heap_form_tuple(), heap_freetuple(), heap_open(), InvokeObjectPostCreateHook, MappingUserName, NULL, ObjectAddress::objectId, ObjectIdGetDatum, ObjectAddress::objectSubId, OidIsValid, CreateUserMappingStmt::options, PointerGetDatum, PointerIsValid, RelationData::rd_att, recordDependencyOn(), recordDependencyOnCurrentExtension(), recordDependencyOnOwner(), RowExclusiveLock, ForeignServer::serverid, CreateUserMappingStmt::servername, simple_heap_insert(), transformGenericOptions(), user_mapping_ddl_aclcheck(), UserMappingRelationId, USERMAPPINGUSERSERVER, CreateUserMappingStmt::username, and values.

Referenced by ProcessUtilitySlow().

{
    Relation    rel;
    Datum       useoptions;
    Datum       values[Natts_pg_user_mapping];
    bool        nulls[Natts_pg_user_mapping];
    HeapTuple   tuple;
    Oid         useId;
    Oid         umId;
    ObjectAddress myself;
    ObjectAddress referenced;
    ForeignServer *srv;
    ForeignDataWrapper *fdw;

    rel = heap_open(UserMappingRelationId, RowExclusiveLock);

    useId = GetUserOidFromMapping(stmt->username, false);

    /* Check that the server exists. */
    srv = GetForeignServerByName(stmt->servername, false);

    user_mapping_ddl_aclcheck(useId, srv->serverid, stmt->servername);

    /*
     * Check that the user mapping is unique within server.
     */
    umId = GetSysCacheOid2(USERMAPPINGUSERSERVER,
                           ObjectIdGetDatum(useId),
                           ObjectIdGetDatum(srv->serverid));
    if (OidIsValid(umId))
        ereport(ERROR,
                (errcode(ERRCODE_DUPLICATE_OBJECT),
                 errmsg("user mapping \"%s\" already exists for server %s",
                        MappingUserName(useId),
                        stmt->servername)));

    fdw = GetForeignDataWrapper(srv->fdwid);

    /*
     * Insert tuple into pg_user_mapping.
     */
    memset(values, 0, sizeof(values));
    memset(nulls, false, sizeof(nulls));

    values[Anum_pg_user_mapping_umuser - 1] = ObjectIdGetDatum(useId);
    values[Anum_pg_user_mapping_umserver - 1] = ObjectIdGetDatum(srv->serverid);

    /* Add user options */
    useoptions = transformGenericOptions(UserMappingRelationId,
                                         PointerGetDatum(NULL),
                                         stmt->options,
                                         fdw->fdwvalidator);

    if (PointerIsValid(DatumGetPointer(useoptions)))
        values[Anum_pg_user_mapping_umoptions - 1] = useoptions;
    else
        nulls[Anum_pg_user_mapping_umoptions - 1] = true;

    tuple = heap_form_tuple(rel->rd_att, values, nulls);

    umId = simple_heap_insert(rel, tuple);

    CatalogUpdateIndexes(rel, tuple);

    heap_freetuple(tuple);

    /* Add dependency on the server */
    myself.classId = UserMappingRelationId;
    myself.objectId = umId;
    myself.objectSubId = 0;

    referenced.classId = ForeignServerRelationId;
    referenced.objectId = srv->serverid;
    referenced.objectSubId = 0;
    recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);

    if (OidIsValid(useId))
    {
        /* Record the mapped user dependency */
        recordDependencyOnOwner(UserMappingRelationId, umId, useId);
    }

    /* dependency on extension */
    recordDependencyOnCurrentExtension(&myself, false);

    /* Post creation hook for new user mapping */
    InvokeObjectPostCreateHook(UserMappingRelationId, umId, 0);

    heap_close(rel, RowExclusiveLock);

    return umId;
}

static Oid GetUserOidFromMapping ( const char *  username,
bool  missing_ok 
) [static]

Definition at line 189 of file foreigncmds.c.

References get_role_oid(), and GetUserId().

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

{
    if (!username)
        /* PUBLIC user mapping */
        return InvalidOid;

    if (strcmp(username, "current_user") == 0)
        /* map to the owner */
        return GetUserId();

    /* map to provided user */
    return get_role_oid(username, missing_ok);
}

static Oid lookup_fdw_handler_func ( DefElem handler  )  [static]

Definition at line 419 of file foreigncmds.c.

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

Referenced by parse_func_options().

{
    Oid         handlerOid;

    if (handler == NULL || handler->arg == NULL)
        return InvalidOid;

    /* handlers have no arguments */
    handlerOid = LookupFuncName((List *) handler->arg, 0, NULL, false);

    /* check that handler has correct return type */
    if (get_func_rettype(handlerOid) != FDW_HANDLEROID)
        ereport(ERROR,
                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                 errmsg("function %s must return type \"fdw_handler\"",
                        NameListToString((List *) handler->arg))));

    return handlerOid;
}

static Oid lookup_fdw_validator_func ( DefElem validator  )  [static]

Definition at line 443 of file foreigncmds.c.

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

Referenced by parse_func_options().

{
    Oid         funcargtypes[2];

    if (validator == NULL || validator->arg == NULL)
        return InvalidOid;

    /* validators take text[], oid */
    funcargtypes[0] = TEXTARRAYOID;
    funcargtypes[1] = OIDOID;

    return LookupFuncName((List *) validator->arg, 2, funcargtypes, false);
    /* validator's return value is ignored, so we don't check the type */
}

static Datum optionListToArray ( List options  )  [static]

Definition at line 51 of file foreigncmds.c.

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

Referenced by transformGenericOptions().

{
    ArrayBuildState *astate = NULL;
    ListCell   *cell;

    foreach(cell, options)
    {
        DefElem    *def = lfirst(cell);
        const char *value;
        Size        len;
        text       *t;

        value = defGetString(def);
        len = VARHDRSZ + strlen(def->defname) + 1 + strlen(value);
        t = palloc(len + 1);
        SET_VARSIZE(t, len);
        sprintf(VARDATA(t), "%s=%s", def->defname, value);

        astate = accumArrayResult(astate, PointerGetDatum(t),
                                  false, TEXTOID,
                                  CurrentMemoryContext);
    }

    if (astate)
        return makeArrayResult(astate, CurrentMemoryContext);

    return PointerGetDatum(NULL);
}

static void parse_func_options ( List func_options,
bool handler_given,
Oid fdwhandler,
bool validator_given,
Oid fdwvalidator 
) [static]

Definition at line 462 of file foreigncmds.c.

References DefElem::defname, elog, ereport, errcode(), errmsg(), ERROR, lfirst, lookup_fdw_handler_func(), and lookup_fdw_validator_func().

Referenced by AlterForeignDataWrapper(), and CreateForeignDataWrapper().

{
    ListCell   *cell;

    *handler_given = false;
    *validator_given = false;
    /* return InvalidOid if not given */
    *fdwhandler = InvalidOid;
    *fdwvalidator = InvalidOid;

    foreach(cell, func_options)
    {
        DefElem    *def = (DefElem *) lfirst(cell);

        if (strcmp(def->defname, "handler") == 0)
        {
            if (*handler_given)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            *handler_given = true;
            *fdwhandler = lookup_fdw_handler_func(def);
        }
        else if (strcmp(def->defname, "validator") == 0)
        {
            if (*validator_given)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("conflicting or redundant options")));
            *validator_given = true;
            *fdwvalidator = lookup_fdw_validator_func(def);
        }
        else
            elog(ERROR, "option \"%s\" not recognized",
                 def->defname);
    }
}

void RemoveForeignDataWrapperById ( Oid  fdwId  ) 
void RemoveForeignServerById ( Oid  srvId  ) 
Oid RemoveUserMapping ( DropUserMappingStmt stmt  ) 

Definition at line 1256 of file foreigncmds.c.

References DROP_CASCADE, elog, ereport, errcode(), errmsg(), ERROR, GetForeignServerByName(), GetSysCacheOid2, GetUserOidFromMapping(), MappingUserName, DropUserMappingStmt::missing_ok, NOTICE, ObjectIdGetDatum, OidIsValid, performDeletion(), ForeignServer::serverid, ForeignServer::servername, DropUserMappingStmt::servername, user_mapping_ddl_aclcheck(), USERMAPPINGUSERSERVER, and DropUserMappingStmt::username.

Referenced by ProcessUtilitySlow().

{
    ObjectAddress object;
    Oid         useId;
    Oid         umId;
    ForeignServer *srv;

    useId = GetUserOidFromMapping(stmt->username, stmt->missing_ok);
    srv = GetForeignServerByName(stmt->servername, true);

    if (stmt->username && !OidIsValid(useId))
    {
        /*
         * IF EXISTS specified, role not found and not public. Notice this and
         * leave.
         */
        elog(NOTICE, "role \"%s\" does not exist, skipping", stmt->username);
        return InvalidOid;
    }

    if (!srv)
    {
        if (!stmt->missing_ok)
            ereport(ERROR,
                    (errcode(ERRCODE_UNDEFINED_OBJECT),
                     errmsg("server \"%s\" does not exist",
                            stmt->servername)));
        /* IF EXISTS, just note it */
        ereport(NOTICE, (errmsg("server does not exist, skipping")));
        return InvalidOid;
    }

    umId = GetSysCacheOid2(USERMAPPINGUSERSERVER,
                           ObjectIdGetDatum(useId),
                           ObjectIdGetDatum(srv->serverid));

    if (!OidIsValid(umId))
    {
        if (!stmt->missing_ok)
            ereport(ERROR,
                    (errcode(ERRCODE_UNDEFINED_OBJECT),
                  errmsg("user mapping \"%s\" does not exist for the server",
                         MappingUserName(useId))));

        /* IF EXISTS specified, just note it */
        ereport(NOTICE,
        (errmsg("user mapping \"%s\" does not exist for the server, skipping",
                MappingUserName(useId))));
        return InvalidOid;
    }

    user_mapping_ddl_aclcheck(useId, srv->serverid, srv->servername);

    /*
     * Do the deletion
     */
    object.classId = UserMappingRelationId;
    object.objectId = umId;
    object.objectSubId = 0;

    performDeletion(&object, DROP_CASCADE, 0);

    return umId;
}

void RemoveUserMappingById ( Oid  umId  ) 
Datum transformGenericOptions ( Oid  catalogId,
Datum  oldOptions,
List options,
Oid  fdwvalidator 
)

Definition at line 94 of file foreigncmds.c.

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

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

{
    List       *resultOptions = untransformRelOptions(oldOptions);
    ListCell   *optcell;
    Datum       result;

    foreach(optcell, options)
    {
        DefElem    *od = lfirst(optcell);
        ListCell   *cell;
        ListCell   *prev = NULL;

        /*
         * Find the element in resultOptions.  We need this for validation in
         * all cases.  Also identify the previous element.
         */
        foreach(cell, resultOptions)
        {
            DefElem    *def = lfirst(cell);

            if (strcmp(def->defname, od->defname) == 0)
                break;
            else
                prev = cell;
        }

        /*
         * It is possible to perform multiple SET/DROP actions on the same
         * option.  The standard permits this, as long as the options to be
         * added are unique.  Note that an unspecified action is taken to be
         * ADD.
         */
        switch (od->defaction)
        {
            case DEFELEM_DROP:
                if (!cell)
                    ereport(ERROR,
                            (errcode(ERRCODE_UNDEFINED_OBJECT),
                             errmsg("option \"%s\" not found",
                                    od->defname)));
                resultOptions = list_delete_cell(resultOptions, cell, prev);
                break;

            case DEFELEM_SET:
                if (!cell)
                    ereport(ERROR,
                            (errcode(ERRCODE_UNDEFINED_OBJECT),
                             errmsg("option \"%s\" not found",
                                    od->defname)));
                lfirst(cell) = od;
                break;

            case DEFELEM_ADD:
            case DEFELEM_UNSPEC:
                if (cell)
                    ereport(ERROR,
                            (errcode(ERRCODE_DUPLICATE_OBJECT),
                             errmsg("option \"%s\" provided more than once",
                                    od->defname)));
                resultOptions = lappend(resultOptions, od);
                break;

            default:
                elog(ERROR, "unrecognized action %d on option \"%s\"",
                     (int) od->defaction, od->defname);
                break;
        }
    }

    result = optionListToArray(resultOptions);

    if (OidIsValid(fdwvalidator))
    {
        Datum       valarg = result;

        /*
         * Pass a null options list as an empty array, so that validators
         * don't have to be declared non-strict to handle the case.
         */
        if (DatumGetPointer(valarg) == NULL)
            valarg = PointerGetDatum(construct_empty_array(TEXTOID));
        OidFunctionCall2(fdwvalidator, valarg, ObjectIdGetDatum(catalogId));
    }

    return result;
}

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

Definition at line 1045 of file foreigncmds.c.

References ACL_KIND_FOREIGN_SERVER, ACL_USAGE, aclcheck_error(), ACLCHECK_NOT_OWNER, ACLCHECK_OK, GetUserId(), pg_foreign_server_aclcheck(), and pg_foreign_server_ownercheck().

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

{
    Oid         curuserid = GetUserId();

    if (!pg_foreign_server_ownercheck(serverid, curuserid))
    {
        if (umuserid == curuserid)
        {
            AclResult   aclresult;

            aclresult = pg_foreign_server_aclcheck(serverid, curuserid, ACL_USAGE);
            if (aclresult != ACLCHECK_OK)
                aclcheck_error(aclresult, ACL_KIND_FOREIGN_SERVER, servername);
        }
        else
            aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
                           servername);
    }
}