diff options
author | Pavan Deolasee | 2017-09-18 07:19:17 +0000 |
---|---|---|
committer | Pavan Deolasee | 2017-09-18 07:19:17 +0000 |
commit | b05a0a0b5609c547965efbb5d499fb7cc36a4315 (patch) | |
tree | ba88ee690e45f7c5e3bbdd66322652410bb16f78 | |
parent | 3b19886e31cfda898acf773196b40c4994b036b8 (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.c | 4 | ||||
-rw-r--r-- | src/backend/pgxc/pool/execRemote.c | 22 | ||||
-rw-r--r-- | src/backend/utils/cache/plancache.c | 21 | ||||
-rw-r--r-- | src/backend/utils/cache/relcache.c | 18 | ||||
-rw-r--r-- | src/include/nodes/nodes.h | 2 |
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); |