00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "postgres.h"
00014
00015 #include "postgres_fdw.h"
00016
00017 #include "access/reloptions.h"
00018 #include "catalog/pg_foreign_server.h"
00019 #include "catalog/pg_foreign_table.h"
00020 #include "catalog/pg_user_mapping.h"
00021 #include "commands/defrem.h"
00022
00023
00024
00025
00026
00027 typedef struct PgFdwOption
00028 {
00029 const char *keyword;
00030 Oid optcontext;
00031 bool is_libpq_opt;
00032 } PgFdwOption;
00033
00034
00035
00036
00037
00038 static PgFdwOption *postgres_fdw_options;
00039
00040
00041
00042
00043
00044 static PQconninfoOption *libpq_options;
00045
00046
00047
00048
00049 static void InitPgFdwOptions(void);
00050 static bool is_valid_option(const char *keyword, Oid context);
00051 static bool is_libpq_option(const char *keyword);
00052
00053
00054
00055
00056
00057
00058
00059
00060 extern Datum postgres_fdw_validator(PG_FUNCTION_ARGS);
00061
00062 PG_FUNCTION_INFO_V1(postgres_fdw_validator);
00063
00064 Datum
00065 postgres_fdw_validator(PG_FUNCTION_ARGS)
00066 {
00067 List *options_list = untransformRelOptions(PG_GETARG_DATUM(0));
00068 Oid catalog = PG_GETARG_OID(1);
00069 ListCell *cell;
00070
00071
00072 InitPgFdwOptions();
00073
00074
00075
00076
00077
00078 foreach(cell, options_list)
00079 {
00080 DefElem *def = (DefElem *) lfirst(cell);
00081
00082 if (!is_valid_option(def->defname, catalog))
00083 {
00084
00085
00086
00087
00088 PgFdwOption *opt;
00089 StringInfoData buf;
00090
00091 initStringInfo(&buf);
00092 for (opt = postgres_fdw_options; opt->keyword; opt++)
00093 {
00094 if (catalog == opt->optcontext)
00095 appendStringInfo(&buf, "%s%s", (buf.len > 0) ? ", " : "",
00096 opt->keyword);
00097 }
00098
00099 ereport(ERROR,
00100 (errcode(ERRCODE_FDW_INVALID_OPTION_NAME),
00101 errmsg("invalid option \"%s\"", def->defname),
00102 errhint("Valid options in this context are: %s",
00103 buf.data)));
00104 }
00105
00106
00107
00108
00109 if (strcmp(def->defname, "use_remote_estimate") == 0)
00110 {
00111
00112 (void) defGetBoolean(def);
00113 }
00114 else if (strcmp(def->defname, "fdw_startup_cost") == 0 ||
00115 strcmp(def->defname, "fdw_tuple_cost") == 0)
00116 {
00117
00118 double val;
00119 char *endp;
00120
00121 val = strtod(defGetString(def), &endp);
00122 if (*endp || val < 0)
00123 ereport(ERROR,
00124 (errcode(ERRCODE_SYNTAX_ERROR),
00125 errmsg("%s requires a non-negative numeric value",
00126 def->defname)));
00127 }
00128 }
00129
00130 PG_RETURN_VOID();
00131 }
00132
00133
00134
00135
00136 static void
00137 InitPgFdwOptions(void)
00138 {
00139 int num_libpq_opts;
00140 PQconninfoOption *lopt;
00141 PgFdwOption *popt;
00142
00143
00144 static const PgFdwOption non_libpq_options[] = {
00145 {"schema_name", ForeignTableRelationId, false},
00146 {"table_name", ForeignTableRelationId, false},
00147 {"column_name", AttributeRelationId, false},
00148
00149 {"use_remote_estimate", ForeignServerRelationId, false},
00150 {"use_remote_estimate", ForeignTableRelationId, false},
00151
00152 {"fdw_startup_cost", ForeignServerRelationId, false},
00153 {"fdw_tuple_cost", ForeignServerRelationId, false},
00154 {NULL, InvalidOid, false}
00155 };
00156
00157
00158 if (postgres_fdw_options)
00159 return;
00160
00161
00162
00163
00164
00165
00166
00167
00168 libpq_options = PQconndefaults();
00169 if (!libpq_options)
00170 ereport(ERROR,
00171 (errcode(ERRCODE_FDW_OUT_OF_MEMORY),
00172 errmsg("out of memory"),
00173 errdetail("could not get libpq's default connection options")));
00174
00175
00176 num_libpq_opts = 0;
00177 for (lopt = libpq_options; lopt->keyword; lopt++)
00178 num_libpq_opts++;
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189 postgres_fdw_options = (PgFdwOption *)
00190 malloc(sizeof(PgFdwOption) * num_libpq_opts +
00191 sizeof(non_libpq_options));
00192 if (postgres_fdw_options == NULL)
00193 ereport(ERROR,
00194 (errcode(ERRCODE_FDW_OUT_OF_MEMORY),
00195 errmsg("out of memory")));
00196
00197 popt = postgres_fdw_options;
00198 for (lopt = libpq_options; lopt->keyword; lopt++)
00199 {
00200
00201 if (strchr(lopt->dispchar, 'D') ||
00202 strcmp(lopt->keyword, "fallback_application_name") == 0 ||
00203 strcmp(lopt->keyword, "client_encoding") == 0)
00204 continue;
00205
00206
00207 popt->keyword = lopt->keyword;
00208
00209
00210
00211
00212
00213 if (strcmp(lopt->keyword, "user") == 0 || strchr(lopt->dispchar, '*'))
00214 popt->optcontext = UserMappingRelationId;
00215 else
00216 popt->optcontext = ForeignServerRelationId;
00217 popt->is_libpq_opt = true;
00218
00219 popt++;
00220 }
00221
00222
00223 memcpy(popt, non_libpq_options, sizeof(non_libpq_options));
00224 }
00225
00226
00227
00228
00229
00230 static bool
00231 is_valid_option(const char *keyword, Oid context)
00232 {
00233 PgFdwOption *opt;
00234
00235 Assert(postgres_fdw_options);
00236
00237 for (opt = postgres_fdw_options; opt->keyword; opt++)
00238 {
00239 if (context == opt->optcontext && strcmp(opt->keyword, keyword) == 0)
00240 return true;
00241 }
00242
00243 return false;
00244 }
00245
00246
00247
00248
00249 static bool
00250 is_libpq_option(const char *keyword)
00251 {
00252 PgFdwOption *opt;
00253
00254 Assert(postgres_fdw_options);
00255
00256 for (opt = postgres_fdw_options; opt->keyword; opt++)
00257 {
00258 if (opt->is_libpq_opt && strcmp(opt->keyword, keyword) == 0)
00259 return true;
00260 }
00261
00262 return false;
00263 }
00264
00265
00266
00267
00268
00269
00270 int
00271 ExtractConnectionOptions(List *defelems, const char **keywords,
00272 const char **values)
00273 {
00274 ListCell *lc;
00275 int i;
00276
00277
00278 InitPgFdwOptions();
00279
00280 i = 0;
00281 foreach(lc, defelems)
00282 {
00283 DefElem *d = (DefElem *) lfirst(lc);
00284
00285 if (is_libpq_option(d->defname))
00286 {
00287 keywords[i] = d->defname;
00288 values[i] = defGetString(d);
00289 i++;
00290 }
00291 }
00292 return i;
00293 }