aboutsummaryrefslogtreecommitdiff
path: root/contrib/postgres_fdw/postgres_fdw.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/postgres_fdw/postgres_fdw.c')
-rw-r--r--contrib/postgres_fdw/postgres_fdw.c65
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);