diff options
Diffstat (limited to 'contrib/postgres_fdw/postgres_fdw.c')
-rw-r--r-- | contrib/postgres_fdw/postgres_fdw.c | 65 |
1 files changed, 64 insertions, 1 deletions
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index a6db061d603..95505c8a1c7 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -30,6 +30,7 @@ #include "optimizer/var.h" #include "parser/parsetree.h" #include "utils/builtins.h" +#include "utils/guc.h" #include "utils/lsyscache.h" #include "utils/memutils.h" @@ -1554,9 +1555,12 @@ create_cursor(ForeignScanState *node) if (numParams > 0 && !fsstate->extparams_done) { ParamListInfo params = node->ss.ps.state->es_param_list_info; + int nestlevel; List *param_numbers; ListCell *lc; + nestlevel = set_transmission_modes(); + param_numbers = (List *) list_nth(fsstate->fdw_private, FdwScanPrivateExternParamIds); foreach(lc, param_numbers) @@ -1598,6 +1602,9 @@ create_cursor(ForeignScanState *node) prm->value); } } + + reset_transmission_modes(nestlevel); + fsstate->extparams_done = true; } @@ -1706,6 +1713,56 @@ fetch_more_data(ForeignScanState *node) } /* + * Force assorted GUC parameters to settings that ensure that we'll output + * data values in a form that is unambiguous to the remote server. + * + * This is rather expensive and annoying to do once per row, but there's + * little choice if we want to be sure values are transmitted accurately; + * we can't leave the settings in place between rows for fear of affecting + * user-visible computations. + * + * We use the equivalent of a function SET option to allow the settings to + * persist only until the caller calls reset_transmission_modes(). If an + * error is thrown in between, guc.c will take care of undoing the settings. + * + * The return value is the nestlevel that must be passed to + * reset_transmission_modes() to undo things. + */ +int +set_transmission_modes(void) +{ + int nestlevel = NewGUCNestLevel(); + + /* + * The values set here should match what pg_dump does. See also + * configure_remote_session in connection.c. + */ + if (DateStyle != USE_ISO_DATES) + (void) set_config_option("datestyle", "ISO", + PGC_USERSET, PGC_S_SESSION, + GUC_ACTION_SAVE, true, 0); + if (IntervalStyle != INTSTYLE_POSTGRES) + (void) set_config_option("intervalstyle", "postgres", + PGC_USERSET, PGC_S_SESSION, + GUC_ACTION_SAVE, true, 0); + if (extra_float_digits < 3) + (void) set_config_option("extra_float_digits", "3", + PGC_USERSET, PGC_S_SESSION, + GUC_ACTION_SAVE, true, 0); + + return nestlevel; +} + +/* + * Undo the effects of set_transmission_modes(). + */ +void +reset_transmission_modes(int nestlevel) +{ + AtEOXact_GUC(true, nestlevel); +} + +/* * Utility routine to close a cursor. */ static void @@ -1791,16 +1848,20 @@ convert_prep_stmt_params(PgFdwModifyState *fmstate, /* 1st parameter should be ctid, if it's in use */ if (tupleid != NULL) { + /* don't need set_transmission_modes for TID output */ p_values[pindex] = OutputFunctionCall(&fmstate->p_flinfo[pindex], PointerGetDatum(tupleid)); pindex++; } /* get following parameters from slot */ - if (slot != NULL) + if (slot != NULL && fmstate->target_attrs != NIL) { + int nestlevel; ListCell *lc; + nestlevel = set_transmission_modes(); + foreach(lc, fmstate->target_attrs) { int attnum = lfirst_int(lc); @@ -1815,6 +1876,8 @@ convert_prep_stmt_params(PgFdwModifyState *fmstate, value); pindex++; } + + reset_transmission_modes(nestlevel); } Assert(pindex == fmstate->p_nums); |