Header And Logo

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

Data Structures | Typedefs | Functions | Variables

option.c File Reference

#include "postgres.h"
#include "postgres_fdw.h"
#include "access/reloptions.h"
#include "catalog/pg_foreign_server.h"
#include "catalog/pg_foreign_table.h"
#include "catalog/pg_user_mapping.h"
#include "commands/defrem.h"
Include dependency graph for option.c:

Go to the source code of this file.

Data Structures

struct  PgFdwOption

Typedefs

typedef struct PgFdwOption PgFdwOption

Functions

static void InitPgFdwOptions (void)
static bool is_valid_option (const char *keyword, Oid context)
static bool is_libpq_option (const char *keyword)
Datum postgres_fdw_validator (PG_FUNCTION_ARGS)
 PG_FUNCTION_INFO_V1 (postgres_fdw_validator)
int ExtractConnectionOptions (List *defelems, const char **keywords, const char **values)

Variables

static PgFdwOptionpostgres_fdw_options
static PQconninfoOptionlibpq_options

Typedef Documentation

typedef struct PgFdwOption PgFdwOption

Function Documentation

int ExtractConnectionOptions ( List defelems,
const char **  keywords,
const char **  values 
)

Definition at line 271 of file option.c.

References defGetString(), DefElem::defname, i, InitPgFdwOptions(), is_libpq_option(), and lfirst.

Referenced by connect_pg_server().

{
    ListCell   *lc;
    int         i;

    /* Build our options lists if we didn't yet. */
    InitPgFdwOptions();

    i = 0;
    foreach(lc, defelems)
    {
        DefElem    *d = (DefElem *) lfirst(lc);

        if (is_libpq_option(d->defname))
        {
            keywords[i] = d->defname;
            values[i] = defGetString(d);
            i++;
        }
    }
    return i;
}

static void InitPgFdwOptions ( void   )  [static]

Definition at line 137 of file option.c.

References _PQconninfoOption::dispchar, ereport, errcode(), errdetail(), errmsg(), ERROR, PgFdwOption::is_libpq_opt, PgFdwOption::keyword, _PQconninfoOption::keyword, malloc, NULL, PgFdwOption::optcontext, and PQconndefaults().

Referenced by ExtractConnectionOptions(), and postgres_fdw_validator().

{
    int         num_libpq_opts;
    PQconninfoOption *lopt;
    PgFdwOption *popt;

    /* non-libpq FDW-specific FDW options */
    static const PgFdwOption non_libpq_options[] = {
        {"schema_name", ForeignTableRelationId, false},
        {"table_name", ForeignTableRelationId, false},
        {"column_name", AttributeRelationId, false},
        /* use_remote_estimate is available on both server and table */
        {"use_remote_estimate", ForeignServerRelationId, false},
        {"use_remote_estimate", ForeignTableRelationId, false},
        /* cost factors */
        {"fdw_startup_cost", ForeignServerRelationId, false},
        {"fdw_tuple_cost", ForeignServerRelationId, false},
        {NULL, InvalidOid, false}
    };

    /* Prevent redundant initialization. */
    if (postgres_fdw_options)
        return;

    /*
     * Get list of valid libpq options.
     *
     * To avoid unnecessary work, we get the list once and use it throughout
     * the lifetime of this backend process.  We don't need to care about
     * memory context issues, because PQconndefaults allocates with malloc.
     */
    libpq_options = PQconndefaults();
    if (!libpq_options)         /* assume reason for failure is OOM */
        ereport(ERROR,
                (errcode(ERRCODE_FDW_OUT_OF_MEMORY),
                 errmsg("out of memory"),
             errdetail("could not get libpq's default connection options")));

    /* Count how many libpq options are available. */
    num_libpq_opts = 0;
    for (lopt = libpq_options; lopt->keyword; lopt++)
        num_libpq_opts++;

    /*
     * Construct an array which consists of all valid options for
     * postgres_fdw, by appending FDW-specific options to libpq options.
     *
     * We use plain malloc here to allocate postgres_fdw_options because it
     * lives as long as the backend process does.  Besides, keeping
     * libpq_options in memory allows us to avoid copying every keyword
     * string.
     */
    postgres_fdw_options = (PgFdwOption *)
        malloc(sizeof(PgFdwOption) * num_libpq_opts +
               sizeof(non_libpq_options));
    if (postgres_fdw_options == NULL)
        ereport(ERROR,
                (errcode(ERRCODE_FDW_OUT_OF_MEMORY),
                 errmsg("out of memory")));

    popt = postgres_fdw_options;
    for (lopt = libpq_options; lopt->keyword; lopt++)
    {
        /* Hide debug options, as well as settings we override internally. */
        if (strchr(lopt->dispchar, 'D') ||
            strcmp(lopt->keyword, "fallback_application_name") == 0 ||
            strcmp(lopt->keyword, "client_encoding") == 0)
            continue;

        /* We don't have to copy keyword string, as described above. */
        popt->keyword = lopt->keyword;

        /*
         * "user" and any secret options are allowed only on user mappings.
         * Everything else is a server option.
         */
        if (strcmp(lopt->keyword, "user") == 0 || strchr(lopt->dispchar, '*'))
            popt->optcontext = UserMappingRelationId;
        else
            popt->optcontext = ForeignServerRelationId;
        popt->is_libpq_opt = true;

        popt++;
    }

    /* Append FDW-specific options and dummy terminator. */
    memcpy(popt, non_libpq_options, sizeof(non_libpq_options));
}

static bool is_libpq_option ( const char *  keyword  )  [static]

Definition at line 250 of file option.c.

References Assert, PgFdwOption::is_libpq_opt, and PgFdwOption::keyword.

Referenced by ExtractConnectionOptions().

{
    PgFdwOption *opt;

    Assert(postgres_fdw_options);       /* must be initialized already */

    for (opt = postgres_fdw_options; opt->keyword; opt++)
    {
        if (opt->is_libpq_opt && strcmp(opt->keyword, keyword) == 0)
            return true;
    }

    return false;
}

static bool is_valid_option ( const char *  keyword,
Oid  context 
) [static]

Definition at line 231 of file option.c.

References Assert, PgFdwOption::keyword, and PgFdwOption::optcontext.

Referenced by postgres_fdw_validator().

{
    PgFdwOption *opt;

    Assert(postgres_fdw_options);       /* must be initialized already */

    for (opt = postgres_fdw_options; opt->keyword; opt++)
    {
        if (context == opt->optcontext && strcmp(opt->keyword, keyword) == 0)
            return true;
    }

    return false;
}

PG_FUNCTION_INFO_V1 ( postgres_fdw_validator   ) 
Datum postgres_fdw_validator ( PG_FUNCTION_ARGS   ) 

Definition at line 65 of file option.c.

References appendStringInfo(), buf, StringInfoData::data, defGetBoolean(), defGetString(), DefElem::defname, ereport, errcode(), errhint(), errmsg(), ERROR, InitPgFdwOptions(), initStringInfo(), is_valid_option(), PgFdwOption::keyword, StringInfoData::len, lfirst, PgFdwOption::optcontext, PG_GETARG_DATUM, PG_GETARG_OID, PG_RETURN_VOID, untransformRelOptions(), and val.

{
    List       *options_list = untransformRelOptions(PG_GETARG_DATUM(0));
    Oid         catalog = PG_GETARG_OID(1);
    ListCell   *cell;

    /* Build our options lists if we didn't yet. */
    InitPgFdwOptions();

    /*
     * Check that only options supported by postgres_fdw, and allowed for the
     * current object type, are given.
     */
    foreach(cell, options_list)
    {
        DefElem    *def = (DefElem *) lfirst(cell);

        if (!is_valid_option(def->defname, catalog))
        {
            /*
             * Unknown option specified, complain about it. Provide a hint
             * with list of valid options for the object.
             */
            PgFdwOption *opt;
            StringInfoData buf;

            initStringInfo(&buf);
            for (opt = postgres_fdw_options; opt->keyword; opt++)
            {
                if (catalog == opt->optcontext)
                    appendStringInfo(&buf, "%s%s", (buf.len > 0) ? ", " : "",
                                     opt->keyword);
            }

            ereport(ERROR,
                    (errcode(ERRCODE_FDW_INVALID_OPTION_NAME),
                     errmsg("invalid option \"%s\"", def->defname),
                     errhint("Valid options in this context are: %s",
                             buf.data)));
        }

        /*
         * Validate option value, when we can do so without any context.
         */
        if (strcmp(def->defname, "use_remote_estimate") == 0)
        {
            /* use_remote_estimate accepts only boolean values */
            (void) defGetBoolean(def);
        }
        else if (strcmp(def->defname, "fdw_startup_cost") == 0 ||
                 strcmp(def->defname, "fdw_tuple_cost") == 0)
        {
            /* these must have a non-negative numeric value */
            double      val;
            char       *endp;

            val = strtod(defGetString(def), &endp);
            if (*endp || val < 0)
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
                         errmsg("%s requires a non-negative numeric value",
                                def->defname)));
        }
    }

    PG_RETURN_VOID();
}


Variable Documentation

Definition at line 44 of file option.c.

Definition at line 38 of file option.c.