readfuncs.c deliberately ignores any opfuncid read in for an OpExpr,
DistinctExpr, NullIfExpr, or ScalarArrayOpExpr, instead resetting the
value in the newly-created node to InvalidOid.  This is because it
assumes we're reading the node from a pg_node_tree column in some
system catalog, and if in the future we wanted to allow an ALTER
OPERATOR command to change the pg_proc mapping, then the opfuncid
could change.  We'd want to look it up again rather than using the
previous value.

As previously discussed, parallel query will use outfuncs/readfuncs to
copy the Plan to be executed by a parallel worker to that worker.
That plan may contain expressions, and the round-trip through
outfuncs/readfuncs will lose their opfuncids.  In this case, that's
pretty annoying, if not outright wrong.  It's annoying because it
means that, after the worker reads the plan tree, it's got to iterate
over the whole thing and repeat the lookups of all the opfuncid
fields.  This turns out not to be straightforward to code, because we
don't have a generic plan tree walker, and even if we did, you still
need knowledge of which plan nodes have expressions inside which
fields, and we don't have a generic facility for that either: it's
there inside e.g. set_plan_refs, but not in a form other code can use.
Moreover, if we ever did have an ALTER OPERATOR command that could
change the pg_proc mapping, this would go from annoying to outright
broken, because it would be real bad if the worker and the leader came
to different conclusions about what opfuncid to use.  Maybe we could
add heavyweight locking to prevent that, but that would be expensive
and we surely don't have it today.

So I think we should abandon the approach Amit took, namely trying to
reset all of the opfuncids.  Instead, I think we should provide a
method of not throwing them out in the first place.  The attached
patch does by adding an "int flags" field to the relevant read
routines.  stringToNode() becomes a macro which passes
STRINGTONODE_INVALIDATE_OPFUNCID to stringToNodeExtended(), which is
one of the functions that now takes an additional "int flags"
argument.  If a caller doesn't wish to ignore opfuncid, they can call
stringToNodeExtended directly.  This way, existing stringToNode()
callers see no behavior change, but the parallel query code can easily
get the behavior that it wants.

Thoughts?  Better ideas?  Objections?

-- 
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
diff --git a/src/backend/nodes/read.c b/src/backend/nodes/read.c
index 0dabfa7..87ece914 100644
--- a/src/backend/nodes/read.c
+++ b/src/backend/nodes/read.c
@@ -35,7 +35,7 @@ static char *pg_strtok_ptr = NULL;
  *	  returns a Node with a given legal ASCII representation
  */
 void *
-stringToNode(char *str)
+stringToNodeExtended(char *str, int flags)
 {
 	char	   *save_strtok;
 	void	   *retval;
@@ -50,7 +50,7 @@ stringToNode(char *str)
 
 	pg_strtok_ptr = str;		/* point pg_strtok at the string to read */
 
-	retval = nodeRead(NULL, 0); /* do the reading */
+	retval = nodeRead(NULL, 0, flags); /* do the reading */
 
 	pg_strtok_ptr = save_strtok;
 
@@ -275,7 +275,7 @@ nodeTokenType(char *token, int length)
  * this should only be invoked from within a stringToNode operation).
  */
 void *
-nodeRead(char *token, int tok_len)
+nodeRead(char *token, int tok_len, int flags)
 {
 	Node	   *result;
 	NodeTag		type;
@@ -293,7 +293,7 @@ nodeRead(char *token, int tok_len)
 	switch ((int) type)
 	{
 		case LEFT_BRACE:
-			result = parseNodeString();
+			result = parseNodeString(flags);
 			token = pg_strtok(&tok_len);
 			if (token == NULL || token[0] != '}')
 				elog(ERROR, "did not find '}' at end of input node");
@@ -359,7 +359,7 @@ nodeRead(char *token, int tok_len)
 						/* We have already scanned next token... */
 						if (token[0] == ')')
 							break;
-						l = lappend(l, nodeRead(token, tok_len));
+						l = lappend(l, nodeRead(token, tok_len, flags));
 						token = pg_strtok(&tok_len);
 						if (token == NULL)
 							elog(ERROR, "unterminated List structure");
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index ef88209..bf101ae 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -121,7 +121,7 @@
 #define READ_NODE_FIELD(fldname) \
 	token = pg_strtok(&length);		/* skip :fldname */ \
 	(void) token;				/* in case not used elsewhere */ \
-	local_node->fldname = nodeRead(NULL, 0)
+	local_node->fldname = nodeRead(NULL, 0, flags)
 
 /* Read a bitmapset field */
 #define READ_BITMAPSET_FIELD(fldname) \
@@ -222,7 +222,7 @@ _readBitmapset(void)
  * _readQuery
  */
 static Query *
-_readQuery(void)
+_readQuery(int flags)
 {
 	READ_LOCALS(Query);
 
@@ -266,7 +266,7 @@ _readQuery(void)
  * _readNotifyStmt
  */
 static NotifyStmt *
-_readNotifyStmt(void)
+_readNotifyStmt(int flags)
 {
 	READ_LOCALS(NotifyStmt);
 
@@ -280,7 +280,7 @@ _readNotifyStmt(void)
  * _readDeclareCursorStmt
  */
 static DeclareCursorStmt *
-_readDeclareCursorStmt(void)
+_readDeclareCursorStmt(int flags)
 {
 	READ_LOCALS(DeclareCursorStmt);
 
@@ -295,7 +295,7 @@ _readDeclareCursorStmt(void)
  * _readWithCheckOption
  */
 static WithCheckOption *
-_readWithCheckOption(void)
+_readWithCheckOption(int flags)
 {
 	READ_LOCALS(WithCheckOption);
 
@@ -312,7 +312,7 @@ _readWithCheckOption(void)
  * _readSortGroupClause
  */
 static SortGroupClause *
-_readSortGroupClause(void)
+_readSortGroupClause(int flags)
 {
 	READ_LOCALS(SortGroupClause);
 
@@ -329,7 +329,7 @@ _readSortGroupClause(void)
  * _readGroupingSet
  */
 static GroupingSet *
-_readGroupingSet(void)
+_readGroupingSet(int flags)
 {
 	READ_LOCALS(GroupingSet);
 
@@ -344,7 +344,7 @@ _readGroupingSet(void)
  * _readWindowClause
  */
 static WindowClause *
-_readWindowClause(void)
+_readWindowClause(int flags)
 {
 	READ_LOCALS(WindowClause);
 
@@ -365,7 +365,7 @@ _readWindowClause(void)
  * _readRowMarkClause
  */
 static RowMarkClause *
-_readRowMarkClause(void)
+_readRowMarkClause(int flags)
 {
 	READ_LOCALS(RowMarkClause);
 
@@ -381,7 +381,7 @@ _readRowMarkClause(void)
  * _readCommonTableExpr
  */
 static CommonTableExpr *
-_readCommonTableExpr(void)
+_readCommonTableExpr(int flags)
 {
 	READ_LOCALS(CommonTableExpr);
 
@@ -403,7 +403,7 @@ _readCommonTableExpr(void)
  * _readSetOperationStmt
  */
 static SetOperationStmt *
-_readSetOperationStmt(void)
+_readSetOperationStmt(int flags)
 {
 	READ_LOCALS(SetOperationStmt);
 
@@ -425,7 +425,7 @@ _readSetOperationStmt(void)
  */
 
 static Alias *
-_readAlias(void)
+_readAlias(int flags)
 {
 	READ_LOCALS(Alias);
 
@@ -436,7 +436,7 @@ _readAlias(void)
 }
 
 static RangeVar *
-_readRangeVar(void)
+_readRangeVar(int flags)
 {
 	READ_LOCALS(RangeVar);
 
@@ -454,7 +454,7 @@ _readRangeVar(void)
 }
 
 static IntoClause *
-_readIntoClause(void)
+_readIntoClause(int flags)
 {
 	READ_LOCALS(IntoClause);
 
@@ -473,7 +473,7 @@ _readIntoClause(void)
  * _readVar
  */
 static Var *
-_readVar(void)
+_readVar(int flags)
 {
 	READ_LOCALS(Var);
 
@@ -494,7 +494,7 @@ _readVar(void)
  * _readConst
  */
 static Const *
-_readConst(void)
+_readConst(int flags)
 {
 	READ_LOCALS(Const);
 
@@ -519,7 +519,7 @@ _readConst(void)
  * _readParam
  */
 static Param *
-_readParam(void)
+_readParam(int flags)
 {
 	READ_LOCALS(Param);
 
@@ -537,7 +537,7 @@ _readParam(void)
  * _readAggref
  */
 static Aggref *
-_readAggref(void)
+_readAggref(int flags)
 {
 	READ_LOCALS(Aggref);
 
@@ -563,7 +563,7 @@ _readAggref(void)
  * _readGroupingFunc
  */
 static GroupingFunc *
-_readGroupingFunc(void)
+_readGroupingFunc(int flags)
 {
 	READ_LOCALS(GroupingFunc);
 
@@ -580,7 +580,7 @@ _readGroupingFunc(void)
  * _readWindowFunc
  */
 static WindowFunc *
-_readWindowFunc(void)
+_readWindowFunc(int flags)
 {
 	READ_LOCALS(WindowFunc);
 
@@ -602,7 +602,7 @@ _readWindowFunc(void)
  * _readArrayRef
  */
 static ArrayRef *
-_readArrayRef(void)
+_readArrayRef(int flags)
 {
 	READ_LOCALS(ArrayRef);
 
@@ -622,7 +622,7 @@ _readArrayRef(void)
  * _readFuncExpr
  */
 static FuncExpr *
-_readFuncExpr(void)
+_readFuncExpr(int flags)
 {
 	READ_LOCALS(FuncExpr);
 
@@ -643,7 +643,7 @@ _readFuncExpr(void)
  * _readNamedArgExpr
  */
 static NamedArgExpr *
-_readNamedArgExpr(void)
+_readNamedArgExpr(int flags)
 {
 	READ_LOCALS(NamedArgExpr);
 
@@ -659,22 +659,16 @@ _readNamedArgExpr(void)
  * _readOpExpr
  */
 static OpExpr *
-_readOpExpr(void)
+_readOpExpr(int flags)
 {
 	READ_LOCALS(OpExpr);
 
 	READ_OID_FIELD(opno);
 	READ_OID_FIELD(opfuncid);
 
-	/*
-	 * The opfuncid is stored in the textual format primarily for debugging
-	 * and documentation reasons.  We want to always read it as zero to force
-	 * it to be re-looked-up in the pg_operator entry.  This ensures that
-	 * stored rules don't have hidden dependencies on operators' functions.
-	 * (We don't currently support an ALTER OPERATOR command, but might
-	 * someday.)
-	 */
-	local_node->opfuncid = InvalidOid;
+	/* Most callers want to zero opfuncid; see comments in nodes.h */
+	if (flags & STRINGTONODE_INVALIDATE_OPFUNCID)
+		local_node->opfuncid = InvalidOid;
 
 	READ_OID_FIELD(opresulttype);
 	READ_BOOL_FIELD(opretset);
@@ -690,22 +684,16 @@ _readOpExpr(void)
  * _readDistinctExpr
  */
 static DistinctExpr *
-_readDistinctExpr(void)
+_readDistinctExpr(int flags)
 {
 	READ_LOCALS(DistinctExpr);
 
 	READ_OID_FIELD(opno);
 	READ_OID_FIELD(opfuncid);
 
-	/*
-	 * The opfuncid is stored in the textual format primarily for debugging
-	 * and documentation reasons.  We want to always read it as zero to force
-	 * it to be re-looked-up in the pg_operator entry.  This ensures that
-	 * stored rules don't have hidden dependencies on operators' functions.
-	 * (We don't currently support an ALTER OPERATOR command, but might
-	 * someday.)
-	 */
-	local_node->opfuncid = InvalidOid;
+	/* Most callers want to zero opfuncid; see comments in nodes.h */
+	if (flags & STRINGTONODE_INVALIDATE_OPFUNCID)
+		local_node->opfuncid = InvalidOid;
 
 	READ_OID_FIELD(opresulttype);
 	READ_BOOL_FIELD(opretset);
@@ -721,22 +709,16 @@ _readDistinctExpr(void)
  * _readNullIfExpr
  */
 static NullIfExpr *
-_readNullIfExpr(void)
+_readNullIfExpr(int flags)
 {
 	READ_LOCALS(NullIfExpr);
 
 	READ_OID_FIELD(opno);
 	READ_OID_FIELD(opfuncid);
 
-	/*
-	 * The opfuncid is stored in the textual format primarily for debugging
-	 * and documentation reasons.  We want to always read it as zero to force
-	 * it to be re-looked-up in the pg_operator entry.  This ensures that
-	 * stored rules don't have hidden dependencies on operators' functions.
-	 * (We don't currently support an ALTER OPERATOR command, but might
-	 * someday.)
-	 */
-	local_node->opfuncid = InvalidOid;
+	/* Most callers want to zero opfuncid; see comments in nodes.h */
+	if (flags & STRINGTONODE_INVALIDATE_OPFUNCID)
+		local_node->opfuncid = InvalidOid;
 
 	READ_OID_FIELD(opresulttype);
 	READ_BOOL_FIELD(opretset);
@@ -752,22 +734,16 @@ _readNullIfExpr(void)
  * _readScalarArrayOpExpr
  */
 static ScalarArrayOpExpr *
-_readScalarArrayOpExpr(void)
+_readScalarArrayOpExpr(int flags)
 {
 	READ_LOCALS(ScalarArrayOpExpr);
 
 	READ_OID_FIELD(opno);
 	READ_OID_FIELD(opfuncid);
 
-	/*
-	 * The opfuncid is stored in the textual format primarily for debugging
-	 * and documentation reasons.  We want to always read it as zero to force
-	 * it to be re-looked-up in the pg_operator entry.  This ensures that
-	 * stored rules don't have hidden dependencies on operators' functions.
-	 * (We don't currently support an ALTER OPERATOR command, but might
-	 * someday.)
-	 */
-	local_node->opfuncid = InvalidOid;
+	/* Most callers want to zero opfuncid; see comments in nodes.h */
+	if (flags & STRINGTONODE_INVALIDATE_OPFUNCID)
+		local_node->opfuncid = InvalidOid;
 
 	READ_BOOL_FIELD(useOr);
 	READ_OID_FIELD(inputcollid);
@@ -781,7 +757,7 @@ _readScalarArrayOpExpr(void)
  * _readBoolExpr
  */
 static BoolExpr *
-_readBoolExpr(void)
+_readBoolExpr(int flags)
 {
 	READ_LOCALS(BoolExpr);
 
@@ -807,7 +783,7 @@ _readBoolExpr(void)
  * _readSubLink
  */
 static SubLink *
-_readSubLink(void)
+_readSubLink(int flags)
 {
 	READ_LOCALS(SubLink);
 
@@ -829,7 +805,7 @@ _readSubLink(void)
  * _readFieldSelect
  */
 static FieldSelect *
-_readFieldSelect(void)
+_readFieldSelect(int flags)
 {
 	READ_LOCALS(FieldSelect);
 
@@ -846,7 +822,7 @@ _readFieldSelect(void)
  * _readFieldStore
  */
 static FieldStore *
-_readFieldStore(void)
+_readFieldStore(int flags)
 {
 	READ_LOCALS(FieldStore);
 
@@ -862,7 +838,7 @@ _readFieldStore(void)
  * _readRelabelType
  */
 static RelabelType *
-_readRelabelType(void)
+_readRelabelType(int flags)
 {
 	READ_LOCALS(RelabelType);
 
@@ -880,7 +856,7 @@ _readRelabelType(void)
  * _readCoerceViaIO
  */
 static CoerceViaIO *
-_readCoerceViaIO(void)
+_readCoerceViaIO(int flags)
 {
 	READ_LOCALS(CoerceViaIO);
 
@@ -897,7 +873,7 @@ _readCoerceViaIO(void)
  * _readArrayCoerceExpr
  */
 static ArrayCoerceExpr *
-_readArrayCoerceExpr(void)
+_readArrayCoerceExpr(int flags)
 {
 	READ_LOCALS(ArrayCoerceExpr);
 
@@ -917,7 +893,7 @@ _readArrayCoerceExpr(void)
  * _readConvertRowtypeExpr
  */
 static ConvertRowtypeExpr *
-_readConvertRowtypeExpr(void)
+_readConvertRowtypeExpr(int flags)
 {
 	READ_LOCALS(ConvertRowtypeExpr);
 
@@ -933,7 +909,7 @@ _readConvertRowtypeExpr(void)
  * _readCollateExpr
  */
 static CollateExpr *
-_readCollateExpr(void)
+_readCollateExpr(int flags)
 {
 	READ_LOCALS(CollateExpr);
 
@@ -948,7 +924,7 @@ _readCollateExpr(void)
  * _readCaseExpr
  */
 static CaseExpr *
-_readCaseExpr(void)
+_readCaseExpr(int flags)
 {
 	READ_LOCALS(CaseExpr);
 
@@ -966,7 +942,7 @@ _readCaseExpr(void)
  * _readCaseWhen
  */
 static CaseWhen *
-_readCaseWhen(void)
+_readCaseWhen(int flags)
 {
 	READ_LOCALS(CaseWhen);
 
@@ -981,7 +957,7 @@ _readCaseWhen(void)
  * _readCaseTestExpr
  */
 static CaseTestExpr *
-_readCaseTestExpr(void)
+_readCaseTestExpr(int flags)
 {
 	READ_LOCALS(CaseTestExpr);
 
@@ -996,7 +972,7 @@ _readCaseTestExpr(void)
  * _readArrayExpr
  */
 static ArrayExpr *
-_readArrayExpr(void)
+_readArrayExpr(int flags)
 {
 	READ_LOCALS(ArrayExpr);
 
@@ -1014,7 +990,7 @@ _readArrayExpr(void)
  * _readRowExpr
  */
 static RowExpr *
-_readRowExpr(void)
+_readRowExpr(int flags)
 {
 	READ_LOCALS(RowExpr);
 
@@ -1031,7 +1007,7 @@ _readRowExpr(void)
  * _readRowCompareExpr
  */
 static RowCompareExpr *
-_readRowCompareExpr(void)
+_readRowCompareExpr(int flags)
 {
 	READ_LOCALS(RowCompareExpr);
 
@@ -1049,7 +1025,7 @@ _readRowCompareExpr(void)
  * _readCoalesceExpr
  */
 static CoalesceExpr *
-_readCoalesceExpr(void)
+_readCoalesceExpr(int flags)
 {
 	READ_LOCALS(CoalesceExpr);
 
@@ -1065,7 +1041,7 @@ _readCoalesceExpr(void)
  * _readMinMaxExpr
  */
 static MinMaxExpr *
-_readMinMaxExpr(void)
+_readMinMaxExpr(int flags)
 {
 	READ_LOCALS(MinMaxExpr);
 
@@ -1083,7 +1059,7 @@ _readMinMaxExpr(void)
  * _readXmlExpr
  */
 static XmlExpr *
-_readXmlExpr(void)
+_readXmlExpr(int flags)
 {
 	READ_LOCALS(XmlExpr);
 
@@ -1104,7 +1080,7 @@ _readXmlExpr(void)
  * _readNullTest
  */
 static NullTest *
-_readNullTest(void)
+_readNullTest(int flags)
 {
 	READ_LOCALS(NullTest);
 
@@ -1120,7 +1096,7 @@ _readNullTest(void)
  * _readBooleanTest
  */
 static BooleanTest *
-_readBooleanTest(void)
+_readBooleanTest(int flags)
 {
 	READ_LOCALS(BooleanTest);
 
@@ -1135,7 +1111,7 @@ _readBooleanTest(void)
  * _readCoerceToDomain
  */
 static CoerceToDomain *
-_readCoerceToDomain(void)
+_readCoerceToDomain(int flags)
 {
 	READ_LOCALS(CoerceToDomain);
 
@@ -1153,7 +1129,7 @@ _readCoerceToDomain(void)
  * _readCoerceToDomainValue
  */
 static CoerceToDomainValue *
-_readCoerceToDomainValue(void)
+_readCoerceToDomainValue(int flags)
 {
 	READ_LOCALS(CoerceToDomainValue);
 
@@ -1169,7 +1145,7 @@ _readCoerceToDomainValue(void)
  * _readSetToDefault
  */
 static SetToDefault *
-_readSetToDefault(void)
+_readSetToDefault(int flags)
 {
 	READ_LOCALS(SetToDefault);
 
@@ -1185,7 +1161,7 @@ _readSetToDefault(void)
  * _readCurrentOfExpr
  */
 static CurrentOfExpr *
-_readCurrentOfExpr(void)
+_readCurrentOfExpr(int flags)
 {
 	READ_LOCALS(CurrentOfExpr);
 
@@ -1200,7 +1176,7 @@ _readCurrentOfExpr(void)
  * _readInferenceElem
  */
 static InferenceElem *
-_readInferenceElem(void)
+_readInferenceElem(int flags)
 {
 	READ_LOCALS(InferenceElem);
 
@@ -1215,7 +1191,7 @@ _readInferenceElem(void)
  * _readTargetEntry
  */
 static TargetEntry *
-_readTargetEntry(void)
+_readTargetEntry(int flags)
 {
 	READ_LOCALS(TargetEntry);
 
@@ -1234,7 +1210,7 @@ _readTargetEntry(void)
  * _readRangeTblRef
  */
 static RangeTblRef *
-_readRangeTblRef(void)
+_readRangeTblRef(int flags)
 {
 	READ_LOCALS(RangeTblRef);
 
@@ -1247,7 +1223,7 @@ _readRangeTblRef(void)
  * _readJoinExpr
  */
 static JoinExpr *
-_readJoinExpr(void)
+_readJoinExpr(int flags)
 {
 	READ_LOCALS(JoinExpr);
 
@@ -1267,7 +1243,7 @@ _readJoinExpr(void)
  * _readFromExpr
  */
 static FromExpr *
-_readFromExpr(void)
+_readFromExpr(int flags)
 {
 	READ_LOCALS(FromExpr);
 
@@ -1281,7 +1257,7 @@ _readFromExpr(void)
  * _readOnConflictExpr
  */
 static OnConflictExpr *
-_readOnConflictExpr(void)
+_readOnConflictExpr(int flags)
 {
 	READ_LOCALS(OnConflictExpr);
 
@@ -1305,7 +1281,7 @@ _readOnConflictExpr(void)
  * _readRangeTblEntry
  */
 static RangeTblEntry *
-_readRangeTblEntry(void)
+_readRangeTblEntry(int flags)
 {
 	READ_LOCALS(RangeTblEntry);
 
@@ -1368,7 +1344,7 @@ _readRangeTblEntry(void)
  * _readRangeTblFunction
  */
 static RangeTblFunction *
-_readRangeTblFunction(void)
+_readRangeTblFunction(int flags)
 {
 	READ_LOCALS(RangeTblFunction);
 
@@ -1387,7 +1363,7 @@ _readRangeTblFunction(void)
  * _readTableSampleClause
  */
 static TableSampleClause *
-_readTableSampleClause(void)
+_readTableSampleClause(int flags)
 {
 	READ_LOCALS(TableSampleClause);
 
@@ -1402,7 +1378,7 @@ _readTableSampleClause(void)
  * _readDefElem
  */
 static DefElem *
-_readDefElem(void)
+_readDefElem(int flags)
 {
 	READ_LOCALS(DefElem);
 
@@ -1418,7 +1394,7 @@ _readDefElem(void)
  * _readPlannedStmt
  */
 static PlannedStmt *
-_readPlannedStmt(void)
+_readPlannedStmt(int flags)
 {
 	READ_LOCALS(PlannedStmt);
 
@@ -1449,7 +1425,7 @@ _readPlannedStmt(void)
  *	Assign the basic stuff of all nodes that inherit from Plan
  */
 static void
-ReadCommonPlan(Plan *local_node)
+ReadCommonPlan(Plan *local_node, int flags)
 {
 	READ_TEMP_LOCALS();
 
@@ -1470,11 +1446,11 @@ ReadCommonPlan(Plan *local_node)
  * _readPlan
  */
 static Plan *
-_readPlan(void)
+_readPlan(int flags)
 {
 	READ_LOCALS_NO_FIELDS(Plan);
 
-	ReadCommonPlan(local_node);
+	ReadCommonPlan(local_node, flags);
 
 	READ_DONE();
 }
@@ -1483,11 +1459,11 @@ _readPlan(void)
  * _readResult
  */
 static Result *
-_readResult(void)
+_readResult(int flags)
 {
 	READ_LOCALS(Result);
 
-	ReadCommonPlan(&local_node->plan);
+	ReadCommonPlan(&local_node->plan, flags);
 
 	READ_NODE_FIELD(resconstantqual);
 
@@ -1498,11 +1474,11 @@ _readResult(void)
  * _readModifyTable
  */
 static ModifyTable *
-_readModifyTable(void)
+_readModifyTable(int flags)
 {
 	READ_LOCALS(ModifyTable);
 
-	ReadCommonPlan(&local_node->plan);
+	ReadCommonPlan(&local_node->plan, flags);
 
 	READ_ENUM_FIELD(operation, CmdType);
 	READ_BOOL_FIELD(canSetTag);
@@ -1529,11 +1505,11 @@ _readModifyTable(void)
  * _readAppend
  */
 static Append *
-_readAppend(void)
+_readAppend(int flags)
 {
 	READ_LOCALS(Append);
 
-	ReadCommonPlan(&local_node->plan);
+	ReadCommonPlan(&local_node->plan, flags);
 
 	READ_NODE_FIELD(appendplans);
 
@@ -1544,11 +1520,11 @@ _readAppend(void)
  * _readMergeAppend
  */
 static MergeAppend *
-_readMergeAppend(void)
+_readMergeAppend(int flags)
 {
 	READ_LOCALS(MergeAppend);
 
-	ReadCommonPlan(&local_node->plan);
+	ReadCommonPlan(&local_node->plan, flags);
 
 	READ_NODE_FIELD(mergeplans);
 	READ_INT_FIELD(numCols);
@@ -1564,11 +1540,11 @@ _readMergeAppend(void)
  * _readRecursiveUnion
  */
 static RecursiveUnion *
-_readRecursiveUnion(void)
+_readRecursiveUnion(int flags)
 {
 	READ_LOCALS(RecursiveUnion);
 
-	ReadCommonPlan(&local_node->plan);
+	ReadCommonPlan(&local_node->plan, flags);
 
 	READ_INT_FIELD(wtParam);
 	READ_INT_FIELD(numCols);
@@ -1583,11 +1559,11 @@ _readRecursiveUnion(void)
  * _readBitmapAnd
  */
 static BitmapAnd *
-_readBitmapAnd(void)
+_readBitmapAnd(int flags)
 {
 	READ_LOCALS(BitmapAnd);
 
-	ReadCommonPlan(&local_node->plan);
+	ReadCommonPlan(&local_node->plan, flags);
 
 	READ_NODE_FIELD(bitmapplans);
 
@@ -1598,11 +1574,11 @@ _readBitmapAnd(void)
  * _readBitmapOr
  */
 static BitmapOr *
-_readBitmapOr(void)
+_readBitmapOr(int flags)
 {
 	READ_LOCALS(BitmapOr);
 
-	ReadCommonPlan(&local_node->plan);
+	ReadCommonPlan(&local_node->plan, flags);
 
 	READ_NODE_FIELD(bitmapplans);
 
@@ -1614,11 +1590,11 @@ _readBitmapOr(void)
  *	Assign the basic stuff of all nodes that inherit from Scan
  */
 static void
-ReadCommonScan(Scan *local_node)
+ReadCommonScan(Scan *local_node, int flags)
 {
 	READ_TEMP_LOCALS();
 
-	ReadCommonPlan(&local_node->plan);
+	ReadCommonPlan(&local_node->plan, flags);
 
 	READ_UINT_FIELD(scanrelid);
 }
@@ -1627,11 +1603,11 @@ ReadCommonScan(Scan *local_node)
  * _readScan
  */
 static Scan *
-_readScan(void)
+_readScan(int flags)
 {
 	READ_LOCALS_NO_FIELDS(Scan);
 
-	ReadCommonScan(local_node);
+	ReadCommonScan(local_node, flags);
 
 	READ_DONE();
 }
@@ -1640,11 +1616,11 @@ _readScan(void)
  * _readSeqScan
  */
 static SeqScan *
-_readSeqScan(void)
+_readSeqScan(int flags)
 {
 	READ_LOCALS_NO_FIELDS(SeqScan);
 
-	ReadCommonScan(local_node);
+	ReadCommonScan(local_node, flags);
 
 	READ_DONE();
 }
@@ -1653,11 +1629,11 @@ _readSeqScan(void)
  * _readSampleScan
  */
 static SampleScan *
-_readSampleScan(void)
+_readSampleScan(int flags)
 {
 	READ_LOCALS(SampleScan);
 
-	ReadCommonScan(&local_node->scan);
+	ReadCommonScan(&local_node->scan, flags);
 
 	READ_NODE_FIELD(tablesample);
 
@@ -1668,11 +1644,11 @@ _readSampleScan(void)
  * _readIndexScan
  */
 static IndexScan *
-_readIndexScan(void)
+_readIndexScan(int flags)
 {
 	READ_LOCALS(IndexScan);
 
-	ReadCommonScan(&local_node->scan);
+	ReadCommonScan(&local_node->scan, flags);
 
 	READ_OID_FIELD(indexid);
 	READ_NODE_FIELD(indexqual);
@@ -1689,11 +1665,11 @@ _readIndexScan(void)
  * _readIndexOnlyScan
  */
 static IndexOnlyScan *
-_readIndexOnlyScan(void)
+_readIndexOnlyScan(int flags)
 {
 	READ_LOCALS(IndexOnlyScan);
 
-	ReadCommonScan(&local_node->scan);
+	ReadCommonScan(&local_node->scan, flags);
 
 	READ_OID_FIELD(indexid);
 	READ_NODE_FIELD(indexqual);
@@ -1708,11 +1684,11 @@ _readIndexOnlyScan(void)
  * _readBitmapIndexScan
  */
 static BitmapIndexScan *
-_readBitmapIndexScan(void)
+_readBitmapIndexScan(int flags)
 {
 	READ_LOCALS(BitmapIndexScan);
 
-	ReadCommonScan(&local_node->scan);
+	ReadCommonScan(&local_node->scan, flags);
 
 	READ_OID_FIELD(indexid);
 	READ_NODE_FIELD(indexqual);
@@ -1725,11 +1701,11 @@ _readBitmapIndexScan(void)
  * _readBitmapHeapScan
  */
 static BitmapHeapScan *
-_readBitmapHeapScan(void)
+_readBitmapHeapScan(int flags)
 {
 	READ_LOCALS(BitmapHeapScan);
 
-	ReadCommonScan(&local_node->scan);
+	ReadCommonScan(&local_node->scan, flags);
 
 	READ_NODE_FIELD(bitmapqualorig);
 
@@ -1740,11 +1716,11 @@ _readBitmapHeapScan(void)
  * _readTidScan
  */
 static TidScan *
-_readTidScan(void)
+_readTidScan(int flags)
 {
 	READ_LOCALS(TidScan);
 
-	ReadCommonScan(&local_node->scan);
+	ReadCommonScan(&local_node->scan, flags);
 
 	READ_NODE_FIELD(tidquals);
 
@@ -1755,11 +1731,11 @@ _readTidScan(void)
  * _readSubqueryScan
  */
 static SubqueryScan *
-_readSubqueryScan(void)
+_readSubqueryScan(int flags)
 {
 	READ_LOCALS(SubqueryScan);
 
-	ReadCommonScan(&local_node->scan);
+	ReadCommonScan(&local_node->scan, flags);
 
 	READ_NODE_FIELD(subplan);
 
@@ -1770,11 +1746,11 @@ _readSubqueryScan(void)
  * _readFunctionScan
  */
 static FunctionScan *
-_readFunctionScan(void)
+_readFunctionScan(int flags)
 {
 	READ_LOCALS(FunctionScan);
 
-	ReadCommonScan(&local_node->scan);
+	ReadCommonScan(&local_node->scan, flags);
 
 	READ_NODE_FIELD(functions);
 	READ_BOOL_FIELD(funcordinality);
@@ -1786,11 +1762,11 @@ _readFunctionScan(void)
  * _readValuesScan
  */
 static ValuesScan *
-_readValuesScan(void)
+_readValuesScan(int flags)
 {
 	READ_LOCALS(ValuesScan);
 
-	ReadCommonScan(&local_node->scan);
+	ReadCommonScan(&local_node->scan, flags);
 
 	READ_NODE_FIELD(values_lists);
 
@@ -1801,11 +1777,11 @@ _readValuesScan(void)
  * _readCteScan
  */
 static CteScan *
-_readCteScan(void)
+_readCteScan(int flags)
 {
 	READ_LOCALS(CteScan);
 
-	ReadCommonScan(&local_node->scan);
+	ReadCommonScan(&local_node->scan, flags);
 
 	READ_INT_FIELD(ctePlanId);
 	READ_INT_FIELD(cteParam);
@@ -1817,11 +1793,11 @@ _readCteScan(void)
  * _readWorkTableScan
  */
 static WorkTableScan *
-_readWorkTableScan(void)
+_readWorkTableScan(int flags)
 {
 	READ_LOCALS(WorkTableScan);
 
-	ReadCommonScan(&local_node->scan);
+	ReadCommonScan(&local_node->scan, flags);
 
 	READ_INT_FIELD(wtParam);
 
@@ -1832,11 +1808,11 @@ _readWorkTableScan(void)
  * _readForeignScan
  */
 static ForeignScan *
-_readForeignScan(void)
+_readForeignScan(int flags)
 {
 	READ_LOCALS(ForeignScan);
 
-	ReadCommonScan(&local_node->scan);
+	ReadCommonScan(&local_node->scan, flags);
 
 	READ_OID_FIELD(fs_server);
 	READ_NODE_FIELD(fdw_exprs);
@@ -1853,11 +1829,11 @@ _readForeignScan(void)
  *	Assign the basic stuff of all nodes that inherit from Join
  */
 static void
-ReadCommonJoin(Join *local_node)
+ReadCommonJoin(Join *local_node, int flags)
 {
 	READ_TEMP_LOCALS();
 
-	ReadCommonPlan(&local_node->plan);
+	ReadCommonPlan(&local_node->plan, flags);
 
 	READ_ENUM_FIELD(jointype, JoinType);
 	READ_NODE_FIELD(joinqual);
@@ -1867,11 +1843,11 @@ ReadCommonJoin(Join *local_node)
  * _readJoin
  */
 static Join *
-_readJoin(void)
+_readJoin(int flags)
 {
 	READ_LOCALS_NO_FIELDS(Join);
 
-	ReadCommonJoin(local_node);
+	ReadCommonJoin(local_node, flags);
 
 	READ_DONE();
 }
@@ -1880,11 +1856,11 @@ _readJoin(void)
  * _readNestLoop
  */
 static NestLoop *
-_readNestLoop(void)
+_readNestLoop(int flags)
 {
 	READ_LOCALS(NestLoop);
 
-	ReadCommonJoin(&local_node->join);
+	ReadCommonJoin(&local_node->join, flags);
 
 	READ_NODE_FIELD(nestParams);
 
@@ -1895,13 +1871,13 @@ _readNestLoop(void)
  * _readMergeJoin
  */
 static MergeJoin *
-_readMergeJoin(void)
+_readMergeJoin(int flags)
 {
 	int			numCols;
 
 	READ_LOCALS(MergeJoin);
 
-	ReadCommonJoin(&local_node->join);
+	ReadCommonJoin(&local_node->join, flags);
 
 	READ_NODE_FIELD(mergeclauses);
 
@@ -1919,11 +1895,11 @@ _readMergeJoin(void)
  * _readHashJoin
  */
 static HashJoin *
-_readHashJoin(void)
+_readHashJoin(int flags)
 {
 	READ_LOCALS(HashJoin);
 
-	ReadCommonJoin(&local_node->join);
+	ReadCommonJoin(&local_node->join, flags);
 
 	READ_NODE_FIELD(hashclauses);
 
@@ -1934,11 +1910,11 @@ _readHashJoin(void)
  * _readMaterial
  */
 static Material *
-_readMaterial(void)
+_readMaterial(int flags)
 {
 	READ_LOCALS_NO_FIELDS(Material);
 
-	ReadCommonPlan(&local_node->plan);
+	ReadCommonPlan(&local_node->plan, flags);
 
 	READ_DONE();
 }
@@ -1947,11 +1923,11 @@ _readMaterial(void)
  * _readSort
  */
 static Sort *
-_readSort(void)
+_readSort(int flags)
 {
 	READ_LOCALS(Sort);
 
-	ReadCommonPlan(&local_node->plan);
+	ReadCommonPlan(&local_node->plan, flags);
 
 	READ_INT_FIELD(numCols);
 	READ_ATTRNUMBER_ARRAY(sortColIdx, local_node->numCols);
@@ -1966,11 +1942,11 @@ _readSort(void)
  * _readGroup
  */
 static Group *
-_readGroup(void)
+_readGroup(int flags)
 {
 	READ_LOCALS(Group);
 
-	ReadCommonPlan(&local_node->plan);
+	ReadCommonPlan(&local_node->plan, flags);
 
 	READ_INT_FIELD(numCols);
 	READ_ATTRNUMBER_ARRAY(grpColIdx, local_node->numCols);
@@ -1983,11 +1959,11 @@ _readGroup(void)
  * _readAgg
  */
 static Agg *
-_readAgg(void)
+_readAgg(int flags)
 {
 	READ_LOCALS(Agg);
 
-	ReadCommonPlan(&local_node->plan);
+	ReadCommonPlan(&local_node->plan, flags);
 
 	READ_ENUM_FIELD(aggstrategy, AggStrategy);
 	READ_INT_FIELD(numCols);
@@ -2004,11 +1980,11 @@ _readAgg(void)
  * _readWindowAgg
  */
 static WindowAgg *
-_readWindowAgg(void)
+_readWindowAgg(int flags)
 {
 	READ_LOCALS(WindowAgg);
 
-	ReadCommonPlan(&local_node->plan);
+	ReadCommonPlan(&local_node->plan, flags);
 
 	READ_UINT_FIELD(winref);
 	READ_INT_FIELD(partNumCols);
@@ -2028,11 +2004,11 @@ _readWindowAgg(void)
  * _readUnique
  */
 static Unique *
-_readUnique(void)
+_readUnique(int flags)
 {
 	READ_LOCALS(Unique);
 
-	ReadCommonPlan(&local_node->plan);
+	ReadCommonPlan(&local_node->plan, flags);
 
 	READ_INT_FIELD(numCols);
 	READ_ATTRNUMBER_ARRAY(uniqColIdx, local_node->numCols);
@@ -2045,11 +2021,11 @@ _readUnique(void)
  * _readHash
  */
 static Hash *
-_readHash(void)
+_readHash(int flags)
 {
 	READ_LOCALS(Hash);
 
-	ReadCommonPlan(&local_node->plan);
+	ReadCommonPlan(&local_node->plan, flags);
 
 	READ_OID_FIELD(skewTable);
 	READ_INT_FIELD(skewColumn);
@@ -2064,11 +2040,11 @@ _readHash(void)
  * _readSetOp
  */
 static SetOp *
-_readSetOp(void)
+_readSetOp(int flags)
 {
 	READ_LOCALS(SetOp);
 
-	ReadCommonPlan(&local_node->plan);
+	ReadCommonPlan(&local_node->plan, flags);
 
 	READ_ENUM_FIELD(cmd, SetOpCmd);
 	READ_ENUM_FIELD(strategy, SetOpStrategy);
@@ -2086,11 +2062,11 @@ _readSetOp(void)
  * _readLockRows
  */
 static LockRows *
-_readLockRows(void)
+_readLockRows(int flags)
 {
 	READ_LOCALS(LockRows);
 
-	ReadCommonPlan(&local_node->plan);
+	ReadCommonPlan(&local_node->plan, flags);
 
 	READ_NODE_FIELD(rowMarks);
 	READ_INT_FIELD(epqParam);
@@ -2102,11 +2078,11 @@ _readLockRows(void)
  * _readLimit
  */
 static Limit *
-_readLimit(void)
+_readLimit(int flags)
 {
 	READ_LOCALS(Limit);
 
-	ReadCommonPlan(&local_node->plan);
+	ReadCommonPlan(&local_node->plan, flags);
 
 	READ_NODE_FIELD(limitOffset);
 	READ_NODE_FIELD(limitCount);
@@ -2118,7 +2094,7 @@ _readLimit(void)
  * _readNestLoopParam
  */
 static NestLoopParam *
-_readNestLoopParam(void)
+_readNestLoopParam(int flags)
 {
 	READ_LOCALS(NestLoopParam);
 
@@ -2132,7 +2108,7 @@ _readNestLoopParam(void)
  * _readPlanRowMark
  */
 static PlanRowMark *
-_readPlanRowMark(void)
+_readPlanRowMark(int flags)
 {
 	READ_LOCALS(PlanRowMark);
 
@@ -2152,7 +2128,7 @@ _readPlanRowMark(void)
  * _readPlanInvalItem
  */
 static PlanInvalItem *
-_readPlanInvalItem(void)
+_readPlanInvalItem(int flags)
 {
 	READ_LOCALS(PlanInvalItem);
 
@@ -2166,7 +2142,7 @@ _readPlanInvalItem(void)
  * _readSubPlan
  */
 static SubPlan *
-_readSubPlan(void)
+_readSubPlan(int flags)
 {
 	READ_LOCALS(SubPlan);
 
@@ -2193,7 +2169,7 @@ _readSubPlan(void)
  * _readAlternativeSubPlan
  */
 static AlternativeSubPlan *
-_readAlternativeSubPlan(void)
+_readAlternativeSubPlan(int flags)
 {
 	READ_LOCALS(AlternativeSubPlan);
 
@@ -2211,7 +2187,7 @@ _readAlternativeSubPlan(void)
  * The string to be read must already have been loaded into pg_strtok().
  */
 Node *
-parseNodeString(void)
+parseNodeString(int flags)
 {
 	void	   *return_value;
 
@@ -2223,209 +2199,209 @@ parseNodeString(void)
 	(length == namelen && memcmp(token, tokname, namelen) == 0)
 
 	if (MATCH("QUERY", 5))
-		return_value = _readQuery();
+		return_value = _readQuery(flags);
 	else if (MATCH("WITHCHECKOPTION", 15))
-		return_value = _readWithCheckOption();
+		return_value = _readWithCheckOption(flags);
 	else if (MATCH("SORTGROUPCLAUSE", 15))
-		return_value = _readSortGroupClause();
+		return_value = _readSortGroupClause(flags);
 	else if (MATCH("GROUPINGSET", 11))
-		return_value = _readGroupingSet();
+		return_value = _readGroupingSet(flags);
 	else if (MATCH("WINDOWCLAUSE", 12))
-		return_value = _readWindowClause();
+		return_value = _readWindowClause(flags);
 	else if (MATCH("ROWMARKCLAUSE", 13))
-		return_value = _readRowMarkClause();
+		return_value = _readRowMarkClause(flags);
 	else if (MATCH("COMMONTABLEEXPR", 15))
-		return_value = _readCommonTableExpr();
+		return_value = _readCommonTableExpr(flags);
 	else if (MATCH("SETOPERATIONSTMT", 16))
-		return_value = _readSetOperationStmt();
+		return_value = _readSetOperationStmt(flags);
 	else if (MATCH("ALIAS", 5))
-		return_value = _readAlias();
+		return_value = _readAlias(flags);
 	else if (MATCH("RANGEVAR", 8))
-		return_value = _readRangeVar();
+		return_value = _readRangeVar(flags);
 	else if (MATCH("INTOCLAUSE", 10))
-		return_value = _readIntoClause();
+		return_value = _readIntoClause(flags);
 	else if (MATCH("VAR", 3))
-		return_value = _readVar();
+		return_value = _readVar(flags);
 	else if (MATCH("CONST", 5))
-		return_value = _readConst();
+		return_value = _readConst(flags);
 	else if (MATCH("PARAM", 5))
-		return_value = _readParam();
+		return_value = _readParam(flags);
 	else if (MATCH("AGGREF", 6))
-		return_value = _readAggref();
+		return_value = _readAggref(flags);
 	else if (MATCH("GROUPINGFUNC", 12))
-		return_value = _readGroupingFunc();
+		return_value = _readGroupingFunc(flags);
 	else if (MATCH("WINDOWFUNC", 10))
-		return_value = _readWindowFunc();
+		return_value = _readWindowFunc(flags);
 	else if (MATCH("ARRAYREF", 8))
-		return_value = _readArrayRef();
+		return_value = _readArrayRef(flags);
 	else if (MATCH("FUNCEXPR", 8))
-		return_value = _readFuncExpr();
+		return_value = _readFuncExpr(flags);
 	else if (MATCH("NAMEDARGEXPR", 12))
-		return_value = _readNamedArgExpr();
+		return_value = _readNamedArgExpr(flags);
 	else if (MATCH("OPEXPR", 6))
-		return_value = _readOpExpr();
+		return_value = _readOpExpr(flags);
 	else if (MATCH("DISTINCTEXPR", 12))
-		return_value = _readDistinctExpr();
+		return_value = _readDistinctExpr(flags);
 	else if (MATCH("NULLIFEXPR", 10))
-		return_value = _readNullIfExpr();
+		return_value = _readNullIfExpr(flags);
 	else if (MATCH("SCALARARRAYOPEXPR", 17))
-		return_value = _readScalarArrayOpExpr();
+		return_value = _readScalarArrayOpExpr(flags);
 	else if (MATCH("BOOLEXPR", 8))
-		return_value = _readBoolExpr();
+		return_value = _readBoolExpr(flags);
 	else if (MATCH("SUBLINK", 7))
-		return_value = _readSubLink();
+		return_value = _readSubLink(flags);
 	else if (MATCH("FIELDSELECT", 11))
-		return_value = _readFieldSelect();
+		return_value = _readFieldSelect(flags);
 	else if (MATCH("FIELDSTORE", 10))
-		return_value = _readFieldStore();
+		return_value = _readFieldStore(flags);
 	else if (MATCH("RELABELTYPE", 11))
-		return_value = _readRelabelType();
+		return_value = _readRelabelType(flags);
 	else if (MATCH("COERCEVIAIO", 11))
-		return_value = _readCoerceViaIO();
+		return_value = _readCoerceViaIO(flags);
 	else if (MATCH("ARRAYCOERCEEXPR", 15))
-		return_value = _readArrayCoerceExpr();
+		return_value = _readArrayCoerceExpr(flags);
 	else if (MATCH("CONVERTROWTYPEEXPR", 18))
-		return_value = _readConvertRowtypeExpr();
+		return_value = _readConvertRowtypeExpr(flags);
 	else if (MATCH("COLLATE", 7))
-		return_value = _readCollateExpr();
+		return_value = _readCollateExpr(flags);
 	else if (MATCH("CASE", 4))
-		return_value = _readCaseExpr();
+		return_value = _readCaseExpr(flags);
 	else if (MATCH("WHEN", 4))
-		return_value = _readCaseWhen();
+		return_value = _readCaseWhen(flags);
 	else if (MATCH("CASETESTEXPR", 12))
-		return_value = _readCaseTestExpr();
+		return_value = _readCaseTestExpr(flags);
 	else if (MATCH("ARRAY", 5))
-		return_value = _readArrayExpr();
+		return_value = _readArrayExpr(flags);
 	else if (MATCH("ROW", 3))
-		return_value = _readRowExpr();
+		return_value = _readRowExpr(flags);
 	else if (MATCH("ROWCOMPARE", 10))
-		return_value = _readRowCompareExpr();
+		return_value = _readRowCompareExpr(flags);
 	else if (MATCH("COALESCE", 8))
-		return_value = _readCoalesceExpr();
+		return_value = _readCoalesceExpr(flags);
 	else if (MATCH("MINMAX", 6))
-		return_value = _readMinMaxExpr();
+		return_value = _readMinMaxExpr(flags);
 	else if (MATCH("XMLEXPR", 7))
-		return_value = _readXmlExpr();
+		return_value = _readXmlExpr(flags);
 	else if (MATCH("NULLTEST", 8))
-		return_value = _readNullTest();
+		return_value = _readNullTest(flags);
 	else if (MATCH("BOOLEANTEST", 11))
-		return_value = _readBooleanTest();
+		return_value = _readBooleanTest(flags);
 	else if (MATCH("COERCETODOMAIN", 14))
-		return_value = _readCoerceToDomain();
+		return_value = _readCoerceToDomain(flags);
 	else if (MATCH("COERCETODOMAINVALUE", 19))
-		return_value = _readCoerceToDomainValue();
+		return_value = _readCoerceToDomainValue(flags);
 	else if (MATCH("SETTODEFAULT", 12))
-		return_value = _readSetToDefault();
+		return_value = _readSetToDefault(flags);
 	else if (MATCH("CURRENTOFEXPR", 13))
-		return_value = _readCurrentOfExpr();
+		return_value = _readCurrentOfExpr(flags);
 	else if (MATCH("INFERENCEELEM", 13))
-		return_value = _readInferenceElem();
+		return_value = _readInferenceElem(flags);
 	else if (MATCH("TARGETENTRY", 11))
-		return_value = _readTargetEntry();
+		return_value = _readTargetEntry(flags);
 	else if (MATCH("RANGETBLREF", 11))
-		return_value = _readRangeTblRef();
+		return_value = _readRangeTblRef(flags);
 	else if (MATCH("JOINEXPR", 8))
-		return_value = _readJoinExpr();
+		return_value = _readJoinExpr(flags);
 	else if (MATCH("FROMEXPR", 8))
-		return_value = _readFromExpr();
+		return_value = _readFromExpr(flags);
 	else if (MATCH("ONCONFLICTEXPR", 14))
-		return_value = _readOnConflictExpr();
+		return_value = _readOnConflictExpr(flags);
 	else if (MATCH("RTE", 3))
-		return_value = _readRangeTblEntry();
+		return_value = _readRangeTblEntry(flags);
 	else if (MATCH("RANGETBLFUNCTION", 16))
-		return_value = _readRangeTblFunction();
+		return_value = _readRangeTblFunction(flags);
 	else if (MATCH("TABLESAMPLECLAUSE", 17))
-		return_value = _readTableSampleClause();
+		return_value = _readTableSampleClause(flags);
 	else if (MATCH("NOTIFY", 6))
-		return_value = _readNotifyStmt();
+		return_value = _readNotifyStmt(flags);
 	else if (MATCH("DEFELEM", 7))
-		return_value = _readDefElem();
+		return_value = _readDefElem(flags);
 	else if (MATCH("DECLARECURSOR", 13))
-		return_value = _readDeclareCursorStmt();
+		return_value = _readDeclareCursorStmt(flags);
 	else if (MATCH("PLANNEDSTMT", 11))
-		return_value = _readPlannedStmt();
+		return_value = _readPlannedStmt(flags);
 	else if (MATCH("PLAN", 4))
-		return_value = _readPlan();
+		return_value = _readPlan(flags);
 	else if (MATCH("RESULT", 6))
-		return_value = _readResult();
+		return_value = _readResult(flags);
 	else if (MATCH("MODIFYTABLE", 11))
-		return_value = _readModifyTable();
+		return_value = _readModifyTable(flags);
 	else if (MATCH("APPEND", 6))
-		return_value = _readAppend();
+		return_value = _readAppend(flags);
 	else if (MATCH("MERGEAPPEND", 11))
-		return_value = _readMergeAppend();
+		return_value = _readMergeAppend(flags);
 	else if (MATCH("RECURSIVEUNION", 14))
-		return_value = _readRecursiveUnion();
+		return_value = _readRecursiveUnion(flags);
 	else if (MATCH("BITMAPAND", 9))
-		return_value = _readBitmapAnd();
+		return_value = _readBitmapAnd(flags);
 	else if (MATCH("BITMAPOR", 8))
-		return_value = _readBitmapOr();
+		return_value = _readBitmapOr(flags);
 	else if (MATCH("SCAN", 4))
-		return_value = _readScan();
+		return_value = _readScan(flags);
 	else if (MATCH("SEQSCAN", 7))
-		return_value = _readSeqScan();
+		return_value = _readSeqScan(flags);
 	else if (MATCH("SAMPLESCAN", 10))
-		return_value = _readSampleScan();
+		return_value = _readSampleScan(flags);
 	else if (MATCH("INDEXSCAN", 9))
-		return_value = _readIndexScan();
+		return_value = _readIndexScan(flags);
 	else if (MATCH("INDEXONLYSCAN", 13))
-		return_value = _readIndexOnlyScan();
+		return_value = _readIndexOnlyScan(flags);
 	else if (MATCH("BITMAPINDEXSCAN", 15))
-		return_value = _readBitmapIndexScan();
+		return_value = _readBitmapIndexScan(flags);
 	else if (MATCH("BITMAPHEAPSCAN", 14))
-		return_value = _readBitmapHeapScan();
+		return_value = _readBitmapHeapScan(flags);
 	else if (MATCH("TIDSCAN", 7))
-		return_value = _readTidScan();
+		return_value = _readTidScan(flags);
 	else if (MATCH("SUBQUERYSCAN", 12))
-		return_value = _readSubqueryScan();
+		return_value = _readSubqueryScan(flags);
 	else if (MATCH("FUNCTIONSCAN", 12))
-		return_value = _readFunctionScan();
+		return_value = _readFunctionScan(flags);
 	else if (MATCH("VALUESSCAN", 10))
-		return_value = _readValuesScan();
+		return_value = _readValuesScan(flags);
 	else if (MATCH("CTESCAN", 7))
-		return_value = _readCteScan();
+		return_value = _readCteScan(flags);
 	else if (MATCH("WORKTABLESCAN", 13))
-		return_value = _readWorkTableScan();
+		return_value = _readWorkTableScan(flags);
 	else if (MATCH("FOREIGNSCAN", 11))
-		return_value = _readForeignScan();
+		return_value = _readForeignScan(flags);
 	else if (MATCH("JOIN", 4))
-		return_value = _readJoin();
+		return_value = _readJoin(flags);
 	else if (MATCH("NESTLOOP", 8))
-		return_value = _readNestLoop();
+		return_value = _readNestLoop(flags);
 	else if (MATCH("MERGEJOIN", 9))
-		return_value = _readMergeJoin();
+		return_value = _readMergeJoin(flags);
 	else if (MATCH("HASHJOIN", 8))
-		return_value = _readHashJoin();
+		return_value = _readHashJoin(flags);
 	else if (MATCH("MATERIAL", 8))
-		return_value = _readMaterial();
+		return_value = _readMaterial(flags);
 	else if (MATCH("SORT", 4))
-		return_value = _readSort();
+		return_value = _readSort(flags);
 	else if (MATCH("GROUP", 5))
-		return_value = _readGroup();
+		return_value = _readGroup(flags);
 	else if (MATCH("AGG", 3))
-		return_value = _readAgg();
+		return_value = _readAgg(flags);
 	else if (MATCH("WINDOWAGG", 9))
-		return_value = _readWindowAgg();
+		return_value = _readWindowAgg(flags);
 	else if (MATCH("UNIQUE", 6))
-		return_value = _readUnique();
+		return_value = _readUnique(flags);
 	else if (MATCH("HASH", 4))
-		return_value = _readHash();
+		return_value = _readHash(flags);
 	else if (MATCH("SETOP", 5))
-		return_value = _readSetOp();
+		return_value = _readSetOp(flags);
 	else if (MATCH("LOCKROWS", 8))
-		return_value = _readLockRows();
+		return_value = _readLockRows(flags);
 	else if (MATCH("LIMIT", 5))
-		return_value = _readLimit();
+		return_value = _readLimit(flags);
 	else if (MATCH("NESTLOOPPARAM", 13))
-		return_value = _readNestLoopParam();
+		return_value = _readNestLoopParam(flags);
 	else if (MATCH("PLANROWMARK", 11))
-		return_value = _readPlanRowMark();
+		return_value = _readPlanRowMark(flags);
 	else if (MATCH("PLANINVALITEM", 13))
-		return_value = _readPlanInvalItem();
+		return_value = _readPlanInvalItem(flags);
 	else if (MATCH("SUBPLAN", 7))
-		return_value = _readSubPlan();
+		return_value = _readSubPlan(flags);
 	else if (MATCH("ALTERNATIVESUBPLAN", 18))
-		return_value = _readAlternativeSubPlan();
+		return_value = _readAlternativeSubPlan(flags);
 	else
 	{
 		elog(ERROR, "badly formatted node string \"%.32s\"...", token);
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 274480e..0e9e28b 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -527,7 +527,23 @@ extern char *nodeToString(const void *obj);
 /*
  * nodes/{readfuncs.c,read.c}
  */
-extern void *stringToNode(char *str);
+extern void *stringToNodeExtended(char *str, int flags);
+
+#define STRINGTONODE_INVALIDATE_OPFUNCID			0x0001
+
+/*
+ * Most callers want to zero out opfuncid fields in parsed node trees,
+ * because most of the time a node tree we've just parsed is taken from
+ * a system catalog.  We want to always read it as zero to force it to be
+ * re-looked-up in the pg_operator entry.  This ensures that stored rules
+ * don't have hidden dependencies on operators' functions.  (We don't
+ * currently support an ALTER OPERATOR command, but might someday.)
+ *
+ * Callers who don't want this behavior can use stringToNodeExtended
+ * directly.
+ */
+#define stringToNode(x) \
+	stringToNodeExtended((x), STRINGTONODE_INVALIDATE_OPFUNCID)
 
 /*
  * nodes/copyfuncs.c
diff --git a/src/include/nodes/readfuncs.h b/src/include/nodes/readfuncs.h
index 703307e..f2fc61e 100644
--- a/src/include/nodes/readfuncs.h
+++ b/src/include/nodes/readfuncs.h
@@ -21,11 +21,11 @@
  */
 extern char *pg_strtok(int *length);
 extern char *debackslash(char *token, int length);
-extern void *nodeRead(char *token, int tok_len);
+extern void *nodeRead(char *token, int tok_len, int flags);
 
 /*
  * prototypes for functions in readfuncs.c
  */
-extern Node *parseNodeString(void);
+extern Node *parseNodeString(int flags);
 
 #endif   /* READFUNCS_H */
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to