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)
* 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 */
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);
/*
/*
* 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);
* 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;
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;
* 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);