summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPavan Deolasee2017-09-18 07:19:17 +0000
committerPavan Deolasee2017-09-18 07:19:17 +0000
commitb05a0a0b5609c547965efbb5d499fb7cc36a4315 (patch)
treeba88ee690e45f7c5e3bbdd66322652410bb16f78
parent3b19886e31cfda898acf773196b40c4994b036b8 (diff)
Ensure that we don't read rule definition with portable input on
Rules are converted in their string representation and stored in the catalog. While building relation descriptor, this information is read back and converted into a Node representation. Since relation descriptors could be built when we are reading plan information sent by the remote server in a stringified representation, trying to read the rules with portable input on may lead to unpleasant behaviour. So we must first reset portable input and restore it back after reading the rules. The same applies to RLS policies (even though we don't have a test showing the impact, but it looks like a sane thing to fix anyways)
-rw-r--r--src/backend/nodes/readfuncs.c4
-rw-r--r--src/backend/pgxc/pool/execRemote.c22
-rw-r--r--src/backend/utils/cache/plancache.c21
-rw-r--r--src/backend/utils/cache/relcache.c18
-rw-r--r--src/include/nodes/nodes.h2
5 files changed, 61 insertions, 6 deletions
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 99dfce1cb9..dd47b2698c 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -59,10 +59,12 @@
* Later we may want to add extra parameter in stringToNode() function
*/
static bool portable_input = false;
-void
+bool
set_portable_input(bool value)
{
+ bool old_portable_input = portable_input;
portable_input = value;
+ return old_portable_input;
}
#endif /* XCP */
diff --git a/src/backend/pgxc/pool/execRemote.c b/src/backend/pgxc/pool/execRemote.c
index 0286337639..2fd23687fc 100644
--- a/src/backend/pgxc/pool/execRemote.c
+++ b/src/backend/pgxc/pool/execRemote.c
@@ -5600,8 +5600,26 @@ ExecInitRemoteSubplan(RemoteSubplan *node, EState *estate, int eflags)
rstmt.distributionNodes = node->distributionNodes;
rstmt.distributionRestrict = node->distributionRestrict;
- set_portable_output(true);
- remotestate->subplanstr = nodeToString(&rstmt);
+ /*
+ * A try-catch block to ensure that we don't leave behind a stale state
+ * if nodeToString fails for whatever reason.
+ *
+ * XXX We should probably rewrite it someday by either passing a
+ * context to nodeToString() or remembering this information somewhere
+ * else which gets reset in case of errors. But for now, this seems
+ * enough.
+ */
+ PG_TRY();
+ {
+ set_portable_output(true);
+ remotestate->subplanstr = nodeToString(&rstmt);
+ }
+ PG_CATCH();
+ {
+ set_portable_output(false);
+ PG_RE_THROW();
+ }
+ PG_END_TRY();
set_portable_output(false);
/*
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index 524c62d7a0..501cd54b9b 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -2017,9 +2017,26 @@ SetRemoteSubplan(CachedPlanSource *plansource, const char *plan_string)
/*
* Restore query plan.
+ *
+ * A try-catch block to ensure that we don't leave behind a stale state
+ * if nodeToString fails for whatever reason.
+ *
+ * XXX We should probably rewrite it someday by either passing a
+ * context to nodeToString() or remembering this information somewhere
+ * else which gets reset in case of errors. But for now, this seems
+ * enough.
*/
- set_portable_input(true);
- rstmt = (RemoteStmt *) stringToNode((char *) plan_string);
+ PG_TRY();
+ {
+ set_portable_input(true);
+ rstmt = (RemoteStmt *) stringToNode((char *) plan_string);
+ }
+ PG_CATCH();
+ {
+ set_portable_input(false);
+ PG_RE_THROW();
+ }
+ PG_END_TRY();
set_portable_input(false);
stmt = makeNode(PlannedStmt);
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index c654213445..7a586f95cf 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -1340,7 +1340,20 @@ RelationBuildDesc(Oid targetRelId, bool insertIt)
* Fetch rules and triggers that affect this relation
*/
if (relation->rd_rel->relhasrules)
+ {
+ /*
+ * We could be in the middle of reading a portable input string and get
+ * called to build the relation descriptor. This might require
+ * recursive calls to stringToNode (e.g. while reading rules) and those
+ * must not be done with portable input turned on (because the
+ * stringified versions are not created with portable output turned
+ * on). So temporarily reset portable input to false and restore once
+ * we are done with reading rules.
+ */
+ bool saved_portable_input = set_portable_input(false);
RelationBuildRuleLock(relation);
+ set_portable_input(saved_portable_input);
+ }
else
{
relation->rd_rules = NULL;
@@ -1358,7 +1371,12 @@ RelationBuildDesc(Oid targetRelId, bool insertIt)
RelationBuildLocator(relation);
#endif
if (relation->rd_rel->relrowsecurity)
+ {
+ /* See comments near RelationBuildRuleLocok for details */
+ bool saved_portable_input = set_portable_input(false);
RelationBuildRowSecurity(relation);
+ set_portable_input(saved_portable_input);
+ }
else
relation->rd_rsdesc = NULL;
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 47e55dbb5f..a620f29d0c 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -651,7 +651,7 @@ extern char *bmsToString(const struct Bitmapset *bms);
* nodes/{readfuncs.c,read.c}
*/
#ifdef XCP
-extern void set_portable_input(bool value);
+extern bool set_portable_input(bool value);
#endif
extern void *stringToNode(char *str);
extern struct Bitmapset *readBitmapset(void);