1 /*-------------------------------------------------------------------------
5 * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
6 * Portions Copyright (c) 1994, Regents of the University of California
10 * $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.100 2006/07/11 17:26:59 momjian Exp $
12 *-------------------------------------------------------------------------
16 #include "catalog/pg_type.h"
17 #include "nodes/makefuncs.h"
18 #include "optimizer/clauses.h"
19 #include "optimizer/tlist.h"
20 #include "parser/parse_coerce.h"
21 #include "parser/parse_relation.h"
22 #include "parser/parsetree.h"
23 #include "rewrite/rewriteManip.h"
24 #include "utils/lsyscache.h"
30 } checkExprHasAggs_context;
32 static bool checkExprHasAggs_walker(Node *node,
33 checkExprHasAggs_context *context);
34 static bool checkExprHasSubLink_walker(Node *node, void *context);
35 static Relids offset_relid_set(Relids relids, int offset);
36 static Relids adjust_relid_set(Relids relids, int oldrelid, int newrelid);
41 * Check if an expression contains an aggregate function call.
43 * The objective of this routine is to detect whether there are aggregates
44 * belonging to the initial query level. Aggregates belonging to subqueries
45 * or outer queries do NOT cause a true result. We must recurse into
46 * subqueries to detect outer-reference aggregates that logically belong to
47 * the initial query level.
50 checkExprHasAggs(Node *node)
52 checkExprHasAggs_context context;
54 context.sublevels_up = 0;
57 * Must be prepared to start with a Query or a bare expression tree; if
58 * it's a Query, we don't want to increment sublevels_up.
60 return query_or_expression_tree_walker(node,
61 checkExprHasAggs_walker,
67 checkExprHasAggs_walker(Node *node, checkExprHasAggs_context *context)
71 if (IsA(node, Aggref))
73 if (((Aggref *) node)->agglevelsup == context->sublevels_up)
74 return true; /* abort the tree traversal and return true */
75 /* else fall through to examine argument */
79 /* Recurse into subselects */
82 context->sublevels_up++;
83 result = query_tree_walker((Query *) node,
84 checkExprHasAggs_walker,
86 context->sublevels_up--;
89 return expression_tree_walker(node, checkExprHasAggs_walker,
94 * checkExprHasSubLink -
95 * Check if an expression contains a SubLink.
98 checkExprHasSubLink(Node *node)
101 * If a Query is passed, examine it --- but we need not recurse into
104 return query_or_expression_tree_walker(node,
105 checkExprHasSubLink_walker,
107 QTW_IGNORE_RT_SUBQUERIES);
111 checkExprHasSubLink_walker(Node *node, void *context)
115 if (IsA(node, SubLink))
116 return true; /* abort the tree traversal and return true */
117 return expression_tree_walker(node, checkExprHasSubLink_walker, context);
122 * OffsetVarNodes - adjust Vars when appending one query's RT to another
124 * Find all Var nodes in the given tree with varlevelsup == sublevels_up,
125 * and increment their varno fields (rangetable indexes) by 'offset'.
126 * The varnoold fields are adjusted similarly. Also, adjust other nodes
127 * that contain rangetable indexes, such as RangeTblRef and JoinExpr.
129 * NOTE: although this has the form of a walker, we cheat and modify the
130 * nodes in-place. The given expression tree should have been copied
131 * earlier to ensure that no unwanted side-effects occur!
138 } OffsetVarNodes_context;
141 OffsetVarNodes_walker(Node *node, OffsetVarNodes_context *context)
147 Var *var = (Var *) node;
149 if (var->varlevelsup == context->sublevels_up)
151 var->varno += context->offset;
152 var->varnoold += context->offset;
156 if (IsA(node, RangeTblRef))
158 RangeTblRef *rtr = (RangeTblRef *) node;
160 if (context->sublevels_up == 0)
161 rtr->rtindex += context->offset;
162 /* the subquery itself is visited separately */
165 if (IsA(node, JoinExpr))
167 JoinExpr *j = (JoinExpr *) node;
169 if (context->sublevels_up == 0)
170 j->rtindex += context->offset;
171 /* fall through to examine children */
173 if (IsA(node, InClauseInfo))
175 InClauseInfo *ininfo = (InClauseInfo *) node;
177 if (context->sublevels_up == 0)
179 ininfo->lefthand = offset_relid_set(ininfo->lefthand,
181 ininfo->righthand = offset_relid_set(ininfo->righthand,
184 /* fall through to examine children */
186 if (IsA(node, AppendRelInfo))
188 AppendRelInfo *appinfo = (AppendRelInfo *) node;
190 if (context->sublevels_up == 0)
192 appinfo->parent_relid += context->offset;
193 appinfo->child_relid += context->offset;
195 /* fall through to examine children */
197 if (IsA(node, Query))
199 /* Recurse into subselects */
202 context->sublevels_up++;
203 result = query_tree_walker((Query *) node, OffsetVarNodes_walker,
204 (void *) context, 0);
205 context->sublevels_up--;
208 return expression_tree_walker(node, OffsetVarNodes_walker,
213 OffsetVarNodes(Node *node, int offset, int sublevels_up)
215 OffsetVarNodes_context context;
217 context.offset = offset;
218 context.sublevels_up = sublevels_up;
221 * Must be prepared to start with a Query or a bare expression tree; if
222 * it's a Query, go straight to query_tree_walker to make sure that
223 * sublevels_up doesn't get incremented prematurely.
225 if (node && IsA(node, Query))
227 Query *qry = (Query *) node;
230 * If we are starting at a Query, and sublevels_up is zero, then we
231 * must also fix rangetable indexes in the Query itself --- namely
232 * resultRelation and rowMarks entries. sublevels_up cannot be zero
233 * when recursing into a subquery, so there's no need to have the same
234 * logic inside OffsetVarNodes_walker.
236 if (sublevels_up == 0)
240 if (qry->resultRelation)
241 qry->resultRelation += offset;
242 foreach(l, qry->rowMarks)
244 RowMarkClause *rc = (RowMarkClause *) lfirst(l);
249 query_tree_walker(qry, OffsetVarNodes_walker,
250 (void *) &context, 0);
253 OffsetVarNodes_walker(node, &context);
257 offset_relid_set(Relids relids, int offset)
259 Relids result = NULL;
263 tmprelids = bms_copy(relids);
264 while ((rtindex = bms_first_member(tmprelids)) >= 0)
265 result = bms_add_member(result, rtindex + offset);
271 * ChangeVarNodes - adjust Var nodes for a specific change of RT index
273 * Find all Var nodes in the given tree belonging to a specific relation
274 * (identified by sublevels_up and rt_index), and change their varno fields
275 * to 'new_index'. The varnoold fields are changed too. Also, adjust other
276 * nodes that contain rangetable indexes, such as RangeTblRef and JoinExpr.
278 * NOTE: although this has the form of a walker, we cheat and modify the
279 * nodes in-place. The given expression tree should have been copied
280 * earlier to ensure that no unwanted side-effects occur!
288 } ChangeVarNodes_context;
291 ChangeVarNodes_walker(Node *node, ChangeVarNodes_context *context)
297 Var *var = (Var *) node;
299 if (var->varlevelsup == context->sublevels_up &&
300 var->varno == context->rt_index)
302 var->varno = context->new_index;
303 var->varnoold = context->new_index;
307 if (IsA(node, RangeTblRef))
309 RangeTblRef *rtr = (RangeTblRef *) node;
311 if (context->sublevels_up == 0 &&
312 rtr->rtindex == context->rt_index)
313 rtr->rtindex = context->new_index;
314 /* the subquery itself is visited separately */
317 if (IsA(node, JoinExpr))
319 JoinExpr *j = (JoinExpr *) node;
321 if (context->sublevels_up == 0 &&
322 j->rtindex == context->rt_index)
323 j->rtindex = context->new_index;
324 /* fall through to examine children */
326 if (IsA(node, InClauseInfo))
328 InClauseInfo *ininfo = (InClauseInfo *) node;
330 if (context->sublevels_up == 0)
332 ininfo->lefthand = adjust_relid_set(ininfo->lefthand,
335 ininfo->righthand = adjust_relid_set(ininfo->righthand,
339 /* fall through to examine children */
341 if (IsA(node, AppendRelInfo))
343 AppendRelInfo *appinfo = (AppendRelInfo *) node;
345 if (context->sublevels_up == 0)
347 if (appinfo->parent_relid == context->rt_index)
348 appinfo->parent_relid = context->new_index;
349 if (appinfo->child_relid == context->rt_index)
350 appinfo->child_relid = context->new_index;
352 /* fall through to examine children */
354 if (IsA(node, Query))
356 /* Recurse into subselects */
359 context->sublevels_up++;
360 result = query_tree_walker((Query *) node, ChangeVarNodes_walker,
361 (void *) context, 0);
362 context->sublevels_up--;
365 return expression_tree_walker(node, ChangeVarNodes_walker,
370 ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
372 ChangeVarNodes_context context;
374 context.rt_index = rt_index;
375 context.new_index = new_index;
376 context.sublevels_up = sublevels_up;
379 * Must be prepared to start with a Query or a bare expression tree; if
380 * it's a Query, go straight to query_tree_walker to make sure that
381 * sublevels_up doesn't get incremented prematurely.
383 if (node && IsA(node, Query))
385 Query *qry = (Query *) node;
388 * If we are starting at a Query, and sublevels_up is zero, then we
389 * must also fix rangetable indexes in the Query itself --- namely
390 * resultRelation and rowMarks entries. sublevels_up cannot be zero
391 * when recursing into a subquery, so there's no need to have the same
392 * logic inside ChangeVarNodes_walker.
394 if (sublevels_up == 0)
398 if (qry->resultRelation == rt_index)
399 qry->resultRelation = new_index;
400 foreach(l, qry->rowMarks)
402 RowMarkClause *rc = (RowMarkClause *) lfirst(l);
404 if (rc->rti == rt_index)
408 query_tree_walker(qry, ChangeVarNodes_walker,
409 (void *) &context, 0);
412 ChangeVarNodes_walker(node, &context);
416 * Substitute newrelid for oldrelid in a Relid set
419 adjust_relid_set(Relids relids, int oldrelid, int newrelid)
421 if (bms_is_member(oldrelid, relids))
423 /* Ensure we have a modifiable copy */
424 relids = bms_copy(relids);
425 /* Remove old, add new */
426 relids = bms_del_member(relids, oldrelid);
427 relids = bms_add_member(relids, newrelid);
433 * IncrementVarSublevelsUp - adjust Var nodes when pushing them down in tree
435 * Find all Var nodes in the given tree having varlevelsup >= min_sublevels_up,
436 * and add delta_sublevels_up to their varlevelsup value. This is needed when
437 * an expression that's correct for some nesting level is inserted into a
438 * subquery. Ordinarily the initial call has min_sublevels_up == 0 so that
439 * all Vars are affected. The point of min_sublevels_up is that we can
440 * increment it when we recurse into a sublink, so that local variables in
441 * that sublink are not affected, only outer references to vars that belong
442 * to the expression's original query level or parents thereof.
444 * Aggref nodes are adjusted similarly.
446 * NOTE: although this has the form of a walker, we cheat and modify the
447 * Var nodes in-place. The given expression tree should have been copied
448 * earlier to ensure that no unwanted side-effects occur!
453 int delta_sublevels_up;
454 int min_sublevels_up;
455 } IncrementVarSublevelsUp_context;
458 IncrementVarSublevelsUp_walker(Node *node,
459 IncrementVarSublevelsUp_context *context)
465 Var *var = (Var *) node;
467 if (var->varlevelsup >= context->min_sublevels_up)
468 var->varlevelsup += context->delta_sublevels_up;
469 return false; /* done here */
471 if (IsA(node, Aggref))
473 Aggref *agg = (Aggref *) node;
475 if (agg->agglevelsup >= context->min_sublevels_up)
476 agg->agglevelsup += context->delta_sublevels_up;
477 /* fall through to recurse into argument */
479 if (IsA(node, Query))
481 /* Recurse into subselects */
484 context->min_sublevels_up++;
485 result = query_tree_walker((Query *) node,
486 IncrementVarSublevelsUp_walker,
487 (void *) context, 0);
488 context->min_sublevels_up--;
491 return expression_tree_walker(node, IncrementVarSublevelsUp_walker,
496 IncrementVarSublevelsUp(Node *node, int delta_sublevels_up,
497 int min_sublevels_up)
499 IncrementVarSublevelsUp_context context;
501 context.delta_sublevels_up = delta_sublevels_up;
502 context.min_sublevels_up = min_sublevels_up;
505 * Must be prepared to start with a Query or a bare expression tree; if
506 * it's a Query, we don't want to increment sublevels_up.
508 query_or_expression_tree_walker(node,
509 IncrementVarSublevelsUp_walker,
516 * rangeTableEntry_used - detect whether an RTE is referenced somewhere
517 * in var nodes or join or setOp trees of a query or expression.
524 } rangeTableEntry_used_context;
527 rangeTableEntry_used_walker(Node *node,
528 rangeTableEntry_used_context *context)
534 Var *var = (Var *) node;
536 if (var->varlevelsup == context->sublevels_up &&
537 var->varno == context->rt_index)
541 if (IsA(node, RangeTblRef))
543 RangeTblRef *rtr = (RangeTblRef *) node;
545 if (rtr->rtindex == context->rt_index &&
546 context->sublevels_up == 0)
548 /* the subquery itself is visited separately */
551 if (IsA(node, JoinExpr))
553 JoinExpr *j = (JoinExpr *) node;
555 if (j->rtindex == context->rt_index &&
556 context->sublevels_up == 0)
558 /* fall through to examine children */
560 /* Shouldn't need to handle planner auxiliary nodes here */
561 Assert(!IsA(node, OuterJoinInfo));
562 Assert(!IsA(node, InClauseInfo));
563 Assert(!IsA(node, AppendRelInfo));
565 if (IsA(node, Query))
567 /* Recurse into subselects */
570 context->sublevels_up++;
571 result = query_tree_walker((Query *) node, rangeTableEntry_used_walker,
572 (void *) context, 0);
573 context->sublevels_up--;
576 return expression_tree_walker(node, rangeTableEntry_used_walker,
581 rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
583 rangeTableEntry_used_context context;
585 context.rt_index = rt_index;
586 context.sublevels_up = sublevels_up;
589 * Must be prepared to start with a Query or a bare expression tree; if
590 * it's a Query, we don't want to increment sublevels_up.
592 return query_or_expression_tree_walker(node,
593 rangeTableEntry_used_walker,
601 * Check if a specific attribute number of a RTE is used
602 * somewhere in the query or expression.
610 } attribute_used_context;
613 attribute_used_walker(Node *node,
614 attribute_used_context *context)
620 Var *var = (Var *) node;
622 if (var->varlevelsup == context->sublevels_up &&
623 var->varno == context->rt_index &&
624 var->varattno == context->attno)
628 if (IsA(node, Query))
630 /* Recurse into subselects */
633 context->sublevels_up++;
634 result = query_tree_walker((Query *) node, attribute_used_walker,
635 (void *) context, 0);
636 context->sublevels_up--;
639 return expression_tree_walker(node, attribute_used_walker,
644 attribute_used(Node *node, int rt_index, int attno, int sublevels_up)
646 attribute_used_context context;
648 context.rt_index = rt_index;
649 context.attno = attno;
650 context.sublevels_up = sublevels_up;
653 * Must be prepared to start with a Query or a bare expression tree; if
654 * it's a Query, we don't want to increment sublevels_up.
656 return query_or_expression_tree_walker(node,
657 attribute_used_walker,
664 * If the given Query is an INSERT ... SELECT construct, extract and
665 * return the sub-Query node that represents the SELECT part. Otherwise
666 * return the given Query.
668 * If subquery_ptr is not NULL, then *subquery_ptr is set to the location
669 * of the link to the SELECT subquery inside parsetree, or NULL if not an
672 * This is a hack needed because transformations on INSERT ... SELECTs that
673 * appear in rule actions should be applied to the source SELECT, not to the
674 * INSERT part. Perhaps this can be cleaned up with redesigned querytrees.
677 getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr)
680 RangeTblEntry *selectrte;
684 *subquery_ptr = NULL;
686 if (parsetree == NULL)
688 if (parsetree->commandType != CMD_INSERT)
692 * Currently, this is ONLY applied to rule-action queries, and so we
693 * expect to find the *OLD* and *NEW* placeholder entries in the given
694 * query. If they're not there, it must be an INSERT/SELECT in which
695 * they've been pushed down to the SELECT.
697 if (list_length(parsetree->rtable) >= 2 &&
698 strcmp(rt_fetch(PRS2_OLD_VARNO, parsetree->rtable)->eref->aliasname,
700 strcmp(rt_fetch(PRS2_NEW_VARNO, parsetree->rtable)->eref->aliasname,
703 Assert(parsetree->jointree && IsA(parsetree->jointree, FromExpr));
704 if (list_length(parsetree->jointree->fromlist) != 1)
705 elog(ERROR, "expected to find SELECT subquery");
706 rtr = (RangeTblRef *) linitial(parsetree->jointree->fromlist);
707 Assert(IsA(rtr, RangeTblRef));
708 selectrte = rt_fetch(rtr->rtindex, parsetree->rtable);
709 selectquery = selectrte->subquery;
710 if (!(selectquery && IsA(selectquery, Query) &&
711 selectquery->commandType == CMD_SELECT))
712 elog(ERROR, "expected to find SELECT subquery");
713 if (list_length(selectquery->rtable) >= 2 &&
714 strcmp(rt_fetch(PRS2_OLD_VARNO, selectquery->rtable)->eref->aliasname,
716 strcmp(rt_fetch(PRS2_NEW_VARNO, selectquery->rtable)->eref->aliasname,
720 *subquery_ptr = &(selectrte->subquery);
723 elog(ERROR, "could not find rule placeholders");
724 return NULL; /* not reached */
729 * Add the given qualifier condition to the query's WHERE clause
732 AddQual(Query *parsetree, Node *qual)
739 if (parsetree->commandType == CMD_UTILITY)
742 * There's noplace to put the qual on a utility statement.
744 * If it's a NOTIFY, silently ignore the qual; this means that the
745 * NOTIFY will execute, whether or not there are any qualifying rows.
746 * While clearly wrong, this is much more useful than refusing to
747 * execute the rule at all, and extra NOTIFY events are harmless for
748 * typical uses of NOTIFY.
750 * If it isn't a NOTIFY, error out, since unconditional execution of
751 * other utility stmts is unlikely to be wanted. (This case is not
752 * currently allowed anyway, but keep the test for safety.)
754 if (parsetree->utilityStmt && IsA(parsetree->utilityStmt, NotifyStmt))
758 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
759 errmsg("conditional utility statements are not implemented")));
762 if (parsetree->setOperations != NULL)
765 * There's noplace to put the qual on a setop statement, either. (This
766 * could be fixed, but right now the planner simply ignores any qual
767 * condition on a setop query.)
770 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
771 errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
774 /* INTERSECT want's the original, but we need to copy - Jan */
775 copy = copyObject(qual);
777 parsetree->jointree->quals = make_and_qual(parsetree->jointree->quals,
781 * We had better not have stuck an aggregate into the WHERE clause.
783 Assert(!checkExprHasAggs(copy));
786 * Make sure query is marked correctly if added qual has sublinks. Need
787 * not search qual when query is already marked.
789 if (!parsetree->hasSubLinks)
790 parsetree->hasSubLinks = checkExprHasSubLink(copy);
795 * Invert the given clause and add it to the WHERE qualifications of the
796 * given querytree. Inversion means "x IS NOT TRUE", not just "NOT x",
797 * else we will do the wrong thing when x evaluates to NULL.
800 AddInvertedQual(Query *parsetree, Node *qual)
802 BooleanTest *invqual;
807 /* Need not copy input qual, because AddQual will... */
808 invqual = makeNode(BooleanTest);
809 invqual->arg = (Expr *) qual;
810 invqual->booltesttype = IS_NOT_TRUE;
812 AddQual(parsetree, (Node *) invqual);
817 * ResolveNew - replace Vars with corresponding items from a targetlist
819 * Vars matching target_varno and sublevels_up are replaced by the
820 * entry with matching resno from targetlist, if there is one.
821 * If not, we either change the unmatched Var's varno to update_varno
822 * (when event == CMD_UPDATE) or replace it with a constant NULL.
824 * The caller must also provide target_rte, the RTE describing the target
825 * relation. This is needed to handle whole-row Vars referencing the target.
826 * We expand such Vars into RowExpr constructs.
828 * Note: the business with inserted_sublink is needed to update hasSubLinks
829 * in subqueries when the replacement adds a subquery inside a subquery.
830 * Messy, isn't it? We do not need to do similar pushups for hasAggs,
831 * because it isn't possible for this transformation to insert a level-zero
832 * aggregate reference into a subquery --- it could only insert outer aggs.
839 RangeTblEntry *target_rte;
843 bool inserted_sublink;
844 } ResolveNew_context;
847 resolve_one_var(Var *var, ResolveNew_context *context)
851 tle = get_tle_by_resno(context->targetlist, var->varattno);
855 /* Failed to find column in insert/update tlist */
856 if (context->event == CMD_UPDATE)
858 /* For update, just change unmatched var's varno */
859 var = (Var *) copyObject(var);
860 var->varno = context->update_varno;
861 var->varnoold = context->update_varno;
866 /* Otherwise replace unmatched var with a null */
867 /* need coerce_to_domain in case of NOT NULL domain constraint */
868 return coerce_to_domain((Node *) makeNullConst(var->vartype),
871 COERCE_IMPLICIT_CAST,
878 /* Make a copy of the tlist item to return */
879 Node *n = copyObject(tle->expr);
881 /* Adjust varlevelsup if tlist item is from higher query */
882 if (var->varlevelsup > 0)
883 IncrementVarSublevelsUp(n, var->varlevelsup, 0);
884 /* Report it if we are adding a sublink to query */
885 if (!context->inserted_sublink)
886 context->inserted_sublink = checkExprHasSubLink(n);
892 ResolveNew_mutator(Node *node, ResolveNew_context *context)
898 Var *var = (Var *) node;
899 int this_varno = (int) var->varno;
900 int this_varlevelsup = (int) var->varlevelsup;
902 if (this_varno == context->target_varno &&
903 this_varlevelsup == context->sublevels_up)
905 if (var->varattno == InvalidAttrNumber)
907 /* Must expand whole-tuple reference into RowExpr */
912 * If generating an expansion for a var of a named rowtype
913 * (ie, this is a plain relation RTE), then we must include
914 * dummy items for dropped columns. If the var is RECORD (ie,
915 * this is a JOIN), then omit dropped columns.
917 expandRTE(context->target_rte,
918 this_varno, this_varlevelsup,
919 (var->vartype != RECORDOID),
921 /* Adjust the generated per-field Vars... */
922 fields = (List *) ResolveNew_mutator((Node *) fields,
924 rowexpr = makeNode(RowExpr);
925 rowexpr->args = fields;
926 rowexpr->row_typeid = var->vartype;
927 rowexpr->row_format = COERCE_IMPLICIT_CAST;
929 return (Node *) rowexpr;
932 /* Normal case for scalar variable */
933 return resolve_one_var(var, context);
935 /* otherwise fall through to copy the var normally */
938 if (IsA(node, Query))
940 /* Recurse into RTE subquery or not-yet-planned sublink subquery */
942 bool save_inserted_sublink;
944 context->sublevels_up++;
945 save_inserted_sublink = context->inserted_sublink;
946 context->inserted_sublink = false;
947 newnode = query_tree_mutator((Query *) node,
951 newnode->hasSubLinks |= context->inserted_sublink;
952 context->inserted_sublink = save_inserted_sublink;
953 context->sublevels_up--;
954 return (Node *) newnode;
956 return expression_tree_mutator(node, ResolveNew_mutator,
961 ResolveNew(Node *node, int target_varno, int sublevels_up,
962 RangeTblEntry *target_rte,
963 List *targetlist, int event, int update_varno)
966 ResolveNew_context context;
968 context.target_varno = target_varno;
969 context.sublevels_up = sublevels_up;
970 context.target_rte = target_rte;
971 context.targetlist = targetlist;
972 context.event = event;
973 context.update_varno = update_varno;
974 context.inserted_sublink = false;
977 * Must be prepared to start with a Query or a bare expression tree; if
978 * it's a Query, we don't want to increment sublevels_up.
980 result = query_or_expression_tree_mutator(node,
985 if (context.inserted_sublink)
987 if (IsA(result, Query))
988 ((Query *) result)->hasSubLinks = true;
990 * Note: if we're called on a non-Query node then it's the caller's
991 * responsibility to update hasSubLinks in the ancestor Query.
992 * This is pretty fragile and perhaps should be rethought ...