Sorry. I forgot to save a file. This is the latest.

On 2024/2/20 18:07, Quan Zongliang wrote:

The Query structure has an increasing number of bool attributes. This is likely to increase in the future. And they have the same properties. Wouldn't it be better to store them in bits? Common statements don't use them, so they have little impact. This also saves memory space.

--
Quan Zongliang
diff --git a/contrib/postgres_fdw/postgres_fdw.c 
b/contrib/postgres_fdw/postgres_fdw.c
index 142dcfc995..a28d625147 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -3341,7 +3341,7 @@ estimate_path_cost_size(PlannerInfo *root,
 
                        /* Collect statistics about aggregates for estimating 
costs. */
                        MemSet(&aggcosts, 0, sizeof(AggClauseCosts));
-                       if (root->parse->hasAggs)
+                       if (QueryHasAggs(root->parse))
                        {
                                get_agg_clause_costs(root, AGGSPLIT_SIMPLE, 
&aggcosts);
                        }
@@ -6762,7 +6762,7 @@ add_foreign_grouping_paths(PlannerInfo *root, RelOptInfo 
*input_rel,
        Cost            total_cost;
 
        /* Nothing to be done, if there is no grouping or aggregation required. 
*/
-       if (!parse->groupClause && !parse->groupingSets && !parse->hasAggs &&
+       if (!parse->groupClause && !parse->groupingSets && !QueryHasAggs(parse) 
&&
                !root->hasHavingQual)
                return;
 
@@ -6859,7 +6859,7 @@ add_foreign_ordered_paths(PlannerInfo *root, RelOptInfo 
*input_rel,
        Assert(parse->sortClause);
 
        /* We don't support cases where there are any SRFs in the targetlist */
-       if (parse->hasTargetSRFs)
+       if (QueryHasTargetSRFs(parse))
                return;
 
        /* Save the input_rel as outerrel in fpinfo */
@@ -7007,7 +7007,7 @@ add_foreign_final_paths(PlannerInfo *root, RelOptInfo 
*input_rel,
                return;
 
        /* We don't support cases where there are any SRFs in the targetlist */
-       if (parse->hasTargetSRFs)
+       if (QueryHasTargetSRFs(parse))
                return;
 
        /* Save the input_rel as outerrel in fpinfo */
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index dce898c751..e328bd9242 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -398,7 +398,7 @@ DefineView(ViewStmt *stmt, const char *queryString,
         * DefineQueryRewrite(), but that function will complain about a bogus 
ON
         * SELECT rule, and we'd rather the message complain about a view.
         */
-       if (viewParse->hasModifyingCTE)
+       if (QueryHasModifyingCTE(viewParse))
                ereport(ERROR,
                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                 errmsg("views must not contain data-modifying 
statements in WITH")));
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index 0f811fd2fc..cdc94f082d 100644
--- a/src/backend/executor/functions.c
+++ b/src/backend/executor/functions.c
@@ -488,7 +488,7 @@ init_execution_state(List *queryTree_list,
                                /* Utility commands require no planning. */
                                stmt = makeNode(PlannedStmt);
                                stmt->commandType = CMD_UTILITY;
-                               stmt->canSetTag = queryTree->canSetTag;
+                               stmt->canSetTag = QueryCanSetTag(queryTree);
                                stmt->utilityStmt = queryTree->utilityStmt;
                                stmt->stmt_location = queryTree->stmt_location;
                                stmt->stmt_len = queryTree->stmt_len;
@@ -540,7 +540,7 @@ init_execution_state(List *queryTree_list,
                        newes->stmt = stmt;
                        newes->qd = NULL;
 
-                       if (queryTree->canSetTag)
+                       if (QueryCanSetTag(queryTree))
                                lasttages = newes;
 
                        preves = newes;
@@ -1650,7 +1650,7 @@ check_sql_fn_retval(List *queryTreeLists,
                {
                        Query      *q = lfirst_node(Query, lc2);
 
-                       if (q->canSetTag)
+                       if (QueryCanSetTag(q))
                        {
                                parse = q;
                                parse_cell = lc2;
@@ -1934,7 +1934,7 @@ tlist_coercion_finished:
                newquery = makeNode(Query);
                newquery->commandType = CMD_SELECT;
                newquery->querySource = parse->querySource;
-               newquery->canSetTag = true;
+               QuerySetFlag(newquery, CAN_SET_TAG);
                newquery->targetList = upper_tlist;
 
                /* We need a moderately realistic colnames list for the 
subquery RTE */
diff --git a/src/backend/optimizer/path/allpaths.c 
b/src/backend/optimizer/path/allpaths.c
index d404fbf262..bd359fd636 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -2595,7 +2595,7 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
                                         * so then it might be useful to use 
for the WindowAgg's
                                         * runCondition.
                                         */
-                                       if (!subquery->hasWindowFuncs ||
+                                       if (!QueryHasWindowFuncs(subquery) ||
                                                
check_and_push_window_quals(subquery, rte, rti, clause,
                                                                                
                        &run_cond_attrs))
                                        {
@@ -2633,7 +2633,7 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
         * we'd better tell the subquery to plan for full retrieval. (XXX This
         * could probably be made more intelligent ...)
         */
-       if (parse->hasAggs ||
+       if (QueryHasAggs(parse) ||
                parse->groupClause ||
                parse->groupingSets ||
                root->hasHavingQual ||
@@ -3604,8 +3604,8 @@ subquery_is_pushdown_safe(Query *subquery, Query 
*topquery,
 
        /* Check points 3, 4, and 5 */
        if (subquery->distinctClause ||
-               subquery->hasWindowFuncs ||
-               subquery->hasTargetSRFs)
+               QueryHasWindowFuncs(subquery) ||
+               QueryHasTargetSRFs(subquery))
                safetyInfo->unsafeVolatile = true;
 
        /*
@@ -3726,7 +3726,7 @@ check_output_expressions(Query *subquery, 
pushdown_safety_info *safetyInfo)
                        continue;                       /* ignore resjunk 
columns */
 
                /* Functions returning sets are unsafe (point 1) */
-               if (subquery->hasTargetSRFs &&
+               if (QueryHasTargetSRFs(subquery) &&
                        (safetyInfo->unsafeFlags[tle->resno] &
                         UNSAFE_HAS_SET_FUNC) == 0 &&
                        expression_returns_set((Node *) tle->expr))
@@ -3745,7 +3745,7 @@ check_output_expressions(Query *subquery, 
pushdown_safety_info *safetyInfo)
                }
 
                /* If subquery uses DISTINCT ON, check point 3 */
-               if (subquery->hasDistinctOn &&
+               if (QueryHasDistinctOn(subquery) &&
                        (safetyInfo->unsafeFlags[tle->resno] &
                         UNSAFE_NOTIN_DISTINCTON_CLAUSE) == 0 &&
                        !targetIsInSortList(tle, InvalidOid, 
subquery->distinctClause))
@@ -3756,7 +3756,7 @@ check_output_expressions(Query *subquery, 
pushdown_safety_info *safetyInfo)
                }
 
                /* If subquery uses window functions, check point 4 */
-               if (subquery->hasWindowFuncs &&
+               if (QueryHasWindowFuncs(subquery) &&
                        (safetyInfo->unsafeFlags[tle->resno] &
                         UNSAFE_NOTIN_DISTINCTON_CLAUSE) == 0 &&
                        !targetIsInAllPartitionLists(tle, subquery))
@@ -3985,14 +3985,14 @@ subquery_push_qual(Query *subquery, RangeTblEntry *rte, 
Index rti, Node *qual)
                qual = ReplaceVarsFromTargetList(qual, rti, 0, rte,
                                                                                
 subquery->targetList,
                                                                                
 REPLACEVARS_REPORT_ERROR, 0,
-                                                                               
 &subquery->hasSubLinks);
+                                                                               
 &subquery->flags);
 
                /*
                 * Now attach the qual to the proper place: normally WHERE, but 
if the
                 * subquery uses grouping or aggregation, put it in HAVING 
(since the
                 * qual really refers to the group-result rows).
                 */
-               if (subquery->hasAggs || subquery->groupClause || 
subquery->groupingSets || subquery->havingQual)
+               if (QueryHasAggs(subquery) || subquery->groupClause || 
subquery->groupingSets || subquery->havingQual)
                        subquery->havingQual = 
make_and_qual(subquery->havingQual, qual);
                else
                        subquery->jointree->quals =
@@ -4086,7 +4086,7 @@ remove_unused_subquery_outputs(Query *subquery, 
RelOptInfo *rel,
         * If subquery has regular DISTINCT (not DISTINCT ON), we're wasting our
         * time: all its output columns must be used in the distinctClause.
         */
-       if (subquery->distinctClause && !subquery->hasDistinctOn)
+       if (subquery->distinctClause && !QueryHasDistinctOn(subquery))
                return;
 
        /*
@@ -4147,7 +4147,7 @@ remove_unused_subquery_outputs(Query *subquery, 
RelOptInfo *rel,
                 * If it contains a set-returning function, we can't remove it 
since
                 * that could change the number of rows returned by the 
subquery.
                 */
-               if (subquery->hasTargetSRFs &&
+               if (QueryHasTargetSRFs(subquery) &&
                        expression_returns_set(texpr))
                        continue;
 
diff --git a/src/backend/optimizer/plan/analyzejoins.c 
b/src/backend/optimizer/plan/analyzejoins.c
index e494acd51a..618fed25fb 100644
--- a/src/backend/optimizer/plan/analyzejoins.c
+++ b/src/backend/optimizer/plan/analyzejoins.c
@@ -1010,14 +1010,14 @@ bool
 query_supports_distinctness(Query *query)
 {
        /* SRFs break distinctness except with DISTINCT, see below */
-       if (query->hasTargetSRFs && query->distinctClause == NIL)
+       if (QueryHasTargetSRFs(query) && query->distinctClause == NIL)
                return false;
 
        /* check for features we can prove distinctness with */
        if (query->distinctClause != NIL ||
                query->groupClause != NIL ||
                query->groupingSets != NIL ||
-               query->hasAggs ||
+               QueryHasAggs(query) ||
                query->havingQual ||
                query->setOperations)
                return true;
@@ -1081,7 +1081,7 @@ query_is_distinct_for(Query *query, List *colnos, List 
*opids)
         * columns, it would be safe because they'd be expanded before grouping.
         * But it doesn't currently seem worth the effort to check for that.)
         */
-       if (query->hasTargetSRFs)
+       if (QueryHasTargetSRFs(query))
                return false;
 
        /*
@@ -1131,7 +1131,7 @@ query_is_distinct_for(Query *query, List *colnos, List 
*opids)
                 * If we have no GROUP BY, but do have aggregates or HAVING, 
then the
                 * result is at most one row so it's surely unique, for any 
operators.
                 */
-               if (query->hasAggs || query->havingQual)
+               if (QueryHasAggs(query) || query->havingQual)
                        return true;
        }
 
diff --git a/src/backend/optimizer/plan/planagg.c 
b/src/backend/optimizer/plan/planagg.c
index 700c0b7ac7..fe5daaa332 100644
--- a/src/backend/optimizer/plan/planagg.c
+++ b/src/backend/optimizer/plan/planagg.c
@@ -84,7 +84,7 @@ preprocess_minmax_aggregates(PlannerInfo *root)
        Assert(root->minmax_aggs == NIL);
 
        /* Nothing to do if query has no aggregates */
-       if (!parse->hasAggs)
+       if (!QueryHasAggs(parse))
                return;
 
        Assert(!parse->setOperations);  /* shouldn't get here if a setop */
@@ -98,7 +98,7 @@ preprocess_minmax_aggregates(PlannerInfo *root)
         * so there's not much point in optimizing MIN/MAX.
         */
        if (parse->groupClause || list_length(parse->groupingSets) > 1 ||
-               parse->hasWindowFuncs)
+               QueryHasWindowFuncs(parse))
                return;
 
        /*
@@ -379,8 +379,8 @@ build_minmax_path(PlannerInfo *root, MinMaxAggInfo *mminfo,
        parse->havingQual = NULL;
        subroot->hasHavingQual = false;
        parse->distinctClause = NIL;
-       parse->hasDistinctOn = false;
-       parse->hasAggs = false;
+       QueryClearFlag(parse, HAS_DISTINCT_ON);
+       QueryClearFlag(parse, HAS_AGGS);
 
        /* Build "target IS NOT NULL" expression */
        ntest = makeNode(NullTest);
diff --git a/src/backend/optimizer/plan/planner.c 
b/src/backend/optimizer/plan/planner.c
index be4e182869..a18832507f 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -348,7 +348,7 @@ standard_planner(Query *parse, const char *query_string, 
int cursorOptions,
        if ((cursorOptions & CURSOR_OPT_PARALLEL_OK) != 0 &&
                IsUnderPostmaster &&
                parse->commandType == CMD_SELECT &&
-               !parse->hasModifyingCTE &&
+               !QueryHasModifyingCTE(parse) &&
                max_parallel_workers_per_gather > 0 &&
                !IsParallelWorker())
        {
@@ -540,8 +540,8 @@ standard_planner(Query *parse, const char *query_string, 
int cursorOptions,
        result->commandType = parse->commandType;
        result->queryId = parse->queryId;
        result->hasReturning = (parse->returningList != NIL);
-       result->hasModifyingCTE = parse->hasModifyingCTE;
-       result->canSetTag = parse->canSetTag;
+       result->hasModifyingCTE = QueryHasModifyingCTE(parse);
+       result->canSetTag = QueryCanSetTag(parse);
        result->transientPlan = glob->transientPlan;
        result->dependsOnRole = glob->dependsOnRole;
        result->parallelModeNeeded = glob->parallelModeNeeded;
@@ -707,7 +707,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
         * into subqueries; if we pull up any subqueries below, their SubLinks 
are
         * processed just before pulling them up.
         */
-       if (parse->hasSubLinks)
+       if (QueryHasSubLinks(parse))
                pull_up_sublinks(root);
 
        /*
@@ -834,8 +834,12 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
                                                          EXPRKIND_TARGET);
 
        /* Constant-folding might have removed all set-returning functions */
-       if (parse->hasTargetSRFs)
-               parse->hasTargetSRFs = expression_returns_set((Node *) 
parse->targetList);
+       if (QueryHasTargetSRFs(parse))
+       {
+               QueryCondSetFlag(parse,
+                                       expression_returns_set((Node *) 
parse->targetList),
+                                       HAS_TARGET_SRFS);
+       }
 
        newWithCheckOptions = NIL;
        foreach(l, parse->withCheckOptions)
@@ -1189,7 +1193,7 @@ preprocess_expression(PlannerInfo *root, Node *expr, int 
kind)
        }
 
        /* Expand SubLinks to SubPlans */
-       if (root->parse->hasSubLinks)
+       if (QueryHasSubLinks(root->parse))
                expr = SS_process_sublinks(root, expr, (kind == EXPRKIND_QUAL));
 
        /*
@@ -1368,7 +1372,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                        is_parallel_safe(root, (Node *) final_target->exprs);
 
                /* The setop result tlist couldn't contain any SRFs */
-               Assert(!parse->hasTargetSRFs);
+               Assert(!QueryHasTargetSRFs(parse));
                final_targets = final_targets_contain_srfs = NIL;
 
                /*
@@ -1446,7 +1450,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                 * pathtargets, else some copies of the Aggref nodes might 
escape
                 * being marked.
                 */
-               if (parse->hasAggs)
+               if (QueryHasAggs(parse))
                {
                        preprocess_aggrefs(root, (Node *) 
root->processed_tlist);
                        preprocess_aggrefs(root, (Node *) parse->havingQual);
@@ -1458,7 +1462,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                 * too.)  Note that they could all have been eliminated by 
constant
                 * folding, in which case we don't need to do any more work.
                 */
-               if (parse->hasWindowFuncs)
+               if (QueryHasWindowFuncs(parse))
                {
                        wflists = find_window_functions((Node *) 
root->processed_tlist,
                                                                                
        list_length(parse->windowClause));
@@ -1474,7 +1478,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                                activeWindows = select_active_windows(root, 
wflists);
                        }
                        else
-                               parse->hasWindowFuncs = false;
+                               QueryClearFlag(parse, HAS_WINDOW_FUNCS);
                }
 
                /*
@@ -1483,7 +1487,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                 * that is needed in MIN/MAX-optimizable cases will have to be
                 * duplicated in planagg.c.
                 */
-               if (parse->hasAggs)
+               if (QueryHasAggs(parse))
                        preprocess_minmax_aggregates(root);
 
                /*
@@ -1495,9 +1499,9 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                if (parse->groupClause ||
                        parse->groupingSets ||
                        parse->distinctClause ||
-                       parse->hasAggs ||
-                       parse->hasWindowFuncs ||
-                       parse->hasTargetSRFs ||
+                       QueryHasAggs(parse) ||
+                       QueryHasWindowFuncs(parse) ||
+                       QueryHasTargetSRFs(parse) ||
                        root->hasHavingQual)
                        root->limit_tuples = -1.0;
                else
@@ -1573,7 +1577,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                 * should emit grouping_target.
                 */
                have_grouping = (parse->groupClause || parse->groupingSets ||
-                                                parse->hasAggs || 
root->hasHavingQual);
+                                                QueryHasAggs(parse) || 
root->hasHavingQual);
                if (have_grouping)
                {
                        scanjoin_target = make_group_input_target(root, 
final_target);
@@ -1592,7 +1596,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                 * each of the named targets with a SRF-free version, and 
remember the
                 * list of additional projection steps we need to add 
afterwards.
                 */
-               if (parse->hasTargetSRFs)
+               if (QueryHasTargetSRFs(parse))
                {
                        /* final_target doesn't recompute any SRFs in 
sort_input_target */
                        split_pathtarget_at_srfs(root, final_target, 
sort_input_target,
@@ -1664,7 +1668,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                                                                                
                grouping_target_parallel_safe,
                                                                                
                gset_data);
                        /* Fix things up if grouping_target contains SRFs */
-                       if (parse->hasTargetSRFs)
+                       if (QueryHasTargetSRFs(parse))
                                adjust_paths_for_srfs(root, current_rel,
                                                                          
grouping_targets,
                                                                          
grouping_targets_contain_srfs);
@@ -1684,7 +1688,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                                                                                
          wflists,
                                                                                
          activeWindows);
                        /* Fix things up if sort_input_target contains SRFs */
-                       if (parse->hasTargetSRFs)
+                       if (QueryHasTargetSRFs(parse))
                                adjust_paths_for_srfs(root, current_rel,
                                                                          
sort_input_targets,
                                                                          
sort_input_targets_contain_srfs);
@@ -1718,7 +1722,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                                                                                
   have_postponed_srfs ? -1.0 :
                                                                                
   limit_tuples);
                /* Fix things up if final_target contains SRFs */
-               if (parse->hasTargetSRFs)
+               if (QueryHasTargetSRFs(parse))
                        adjust_paths_for_srfs(root, current_rel,
                                                                  final_targets,
                                                                  
final_targets_contain_srfs);
@@ -1955,7 +1959,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                                create_modifytable_path(root, final_rel,
                                                                                
path,
                                                                                
parse->commandType,
-                                                                               
parse->canSetTag,
+                                                                               
QueryCanSetTag(parse),
                                                                                
parse->resultRelation,
                                                                                
rootRelation,
                                                                                
root->partColsUpdated,
@@ -3573,7 +3577,7 @@ get_number_of_groups(PlannerInfo *root,
                /* Empty grouping sets ... one result row for each one */
                dNumGroups = list_length(parse->groupingSets);
        }
-       else if (parse->hasAggs || root->hasHavingQual)
+       else if (QueryHasAggs(parse) || root->hasHavingQual)
        {
                /* Plain aggregation, one result row */
                dNumGroups = 1;
@@ -3776,7 +3780,7 @@ is_degenerate_grouping(PlannerInfo *root)
        Query      *parse = root->parse;
 
        return (root->hasHavingQual || parse->groupingSets) &&
-               !parse->hasAggs && parse->groupClause == NIL;
+               !QueryHasAggs(parse) && parse->groupClause == NIL;
 }
 
 /*
@@ -4665,7 +4669,7 @@ create_partial_distinct_paths(PlannerInfo *root, 
RelOptInfo *input_rel,
        parse = root->parse;
 
        /* can't do parallel DISTINCT ON */
-       if (parse->hasDistinctOn)
+       if (QueryHasDistinctOn(parse))
                return;
 
        partial_distinct_rel = fetch_upper_rel(root, UPPERREL_PARTIAL_DISTINCT,
@@ -4855,7 +4859,7 @@ create_final_distinct_paths(PlannerInfo *root, RelOptInfo 
*input_rel,
        bool            allow_hash;
 
        /* Estimate number of distinct rows there will be */
-       if (parse->groupClause || parse->groupingSets || parse->hasAggs ||
+       if (parse->groupClause || parse->groupingSets || QueryHasAggs(parse) ||
                root->hasHavingQual)
        {
                /*
@@ -4902,7 +4906,7 @@ create_final_distinct_paths(PlannerInfo *root, RelOptInfo 
*input_rel,
                ListCell   *lc;
                double          limittuples = root->distinct_pathkeys == NIL ? 
1.0 : -1.0;
 
-               if (parse->hasDistinctOn &&
+               if (QueryHasDistinctOn(parse) &&
                        list_length(root->distinct_pathkeys) <
                        list_length(root->sort_pathkeys))
                        needed_pathkeys = root->sort_pathkeys;
@@ -5011,7 +5015,7 @@ create_final_distinct_paths(PlannerInfo *root, RelOptInfo 
*input_rel,
         */
        if (distinct_rel->pathlist == NIL)
                allow_hash = true;              /* we have no alternatives */
-       else if (parse->hasDistinctOn || !enable_hashagg)
+       else if (QueryHasDistinctOn(parse) || !enable_hashagg)
                allow_hash = false;             /* policy-based decision not to 
hash */
        else
                allow_hash = true;              /* default */
@@ -5839,7 +5843,7 @@ make_window_input_target(PlannerInfo *root,
        int                     i;
        ListCell   *lc;
 
-       Assert(root->parse->hasWindowFuncs);
+       Assert(QueryHasWindowFuncs(root->parse));
 
        /*
         * Collect the sortgroupref numbers of window PARTITION/ORDER BY clauses
@@ -6123,7 +6127,7 @@ make_sort_input_target(PlannerInfo *root,
                         * Check for SRF or volatile functions.  Check the SRF 
case first
                         * because we must know whether we have any postponed 
SRFs.
                         */
-                       if (parse->hasTargetSRFs &&
+                       if (QueryHasTargetSRFs(parse) &&
                                expression_returns_set((Node *) expr))
                        {
                                /* We'll decide below whether these are 
postponable */
@@ -6163,7 +6167,7 @@ make_sort_input_target(PlannerInfo *root,
                {
                        /* For sortgroupref cols, just check if any contain 
SRFs */
                        if (!have_srf_sortcols &&
-                               parse->hasTargetSRFs &&
+                               QueryHasTargetSRFs(parse) &&
                                expression_returns_set((Node *) expr))
                                have_srf_sortcols = true;
                }
@@ -6845,7 +6849,7 @@ add_paths_to_grouping_rel(PlannerInfo *root, RelOptInfo 
*input_rel,
                                                                                
                path, true, can_hash,
                                                                                
                gd, agg_costs, dNumGroups);
                                }
-                               else if (parse->hasAggs)
+                               else if (QueryHasAggs(parse))
                                {
                                        /*
                                         * We have aggregation, possibly with 
plain GROUP BY. Make
@@ -6920,7 +6924,7 @@ add_paths_to_grouping_rel(PlannerInfo *root, RelOptInfo 
*input_rel,
                                        if (path == NULL)
                                                continue;
 
-                                       if (parse->hasAggs)
+                                       if (QueryHasAggs(parse))
                                                add_path(grouped_rel, (Path *)
                                                                 
create_agg_path(root,
                                                                                
                 grouped_rel,
@@ -7105,7 +7109,7 @@ create_partial_grouping_paths(PlannerInfo *root,
                 */
                MemSet(agg_partial_costs, 0, sizeof(AggClauseCosts));
                MemSet(agg_final_costs, 0, sizeof(AggClauseCosts));
-               if (parse->hasAggs)
+               if (QueryHasAggs(parse))
                {
                        /* partial phase */
                        get_agg_clause_costs(root, AGGSPLIT_INITIAL_SERIAL,
@@ -7136,7 +7140,7 @@ create_partial_grouping_paths(PlannerInfo *root,
        if (can_sort && cheapest_total_path != NULL)
        {
                /* This should have been checked previously */
-               Assert(parse->hasAggs || parse->groupClause);
+               Assert(QueryHasAggs(parse) || parse->groupClause);
 
                /*
                 * Use any available suitably-sorted path as input, and also 
consider
@@ -7171,7 +7175,7 @@ create_partial_grouping_paths(PlannerInfo *root,
                                if (path == NULL)
                                        continue;
 
-                               if (parse->hasAggs)
+                               if (QueryHasAggs(parse))
                                        add_path(partially_grouped_rel, (Path *)
                                                         create_agg_path(root,
                                                                                
         partially_grouped_rel,
@@ -7228,7 +7232,7 @@ create_partial_grouping_paths(PlannerInfo *root,
                                if (path == NULL)
                                        continue;
 
-                               if (parse->hasAggs)
+                               if (QueryHasAggs(parse))
                                        add_partial_path(partially_grouped_rel, 
(Path *)
                                                                         
create_agg_path(root,
                                                                                
                         partially_grouped_rel,
@@ -7258,7 +7262,7 @@ create_partial_grouping_paths(PlannerInfo *root,
        if (can_hash && cheapest_total_path != NULL)
        {
                /* Checked above */
-               Assert(parse->hasAggs || parse->groupClause);
+               Assert(QueryHasAggs(parse) || parse->groupClause);
 
                add_path(partially_grouped_rel, (Path *)
                                 create_agg_path(root,
@@ -7401,7 +7405,7 @@ can_partial_agg(PlannerInfo *root)
 {
        Query      *parse = root->parse;
 
-       if (!parse->hasAggs && parse->groupClause == NIL)
+       if (!QueryHasAggs(parse) && parse->groupClause == NIL)
        {
                /*
                 * We don't know how to do parallel aggregation unless we have 
either
@@ -7560,7 +7564,7 @@ apply_scanjoin_target_to_paths(PlannerInfo *root,
         * cheapest-path fields, which is a good thing because they're bogus 
right
         * now.)
         */
-       if (root->parse->hasTargetSRFs)
+       if (QueryHasTargetSRFs(root->parse))
                adjust_paths_for_srfs(root, rel,
                                                          scanjoin_targets,
                                                          
scanjoin_targets_contain_srfs);
diff --git a/src/backend/optimizer/plan/setrefs.c 
b/src/backend/optimizer/plan/setrefs.c
index 22a1fa29f3..3c45431d84 100644
--- a/src/backend/optimizer/plan/setrefs.c
+++ b/src/backend/optimizer/plan/setrefs.c
@@ -3600,7 +3600,7 @@ extract_query_dependencies_walker(Node *node, PlannerInfo 
*context)
                }
 
                /* Remember if any Query has RLS quals applied by rewriter */
-               if (query->hasRowSecurity)
+               if (QueryHasRowSecurity(query))
                        context->glob->dependsOnRole = true;
 
                /* Collect relation OIDs in this Query's rtable */
diff --git a/src/backend/optimizer/plan/subselect.c 
b/src/backend/optimizer/plan/subselect.c
index 47e14723d2..e65a1a1740 100644
--- a/src/backend/optimizer/plan/subselect.c
+++ b/src/backend/optimizer/plan/subselect.c
@@ -1562,11 +1562,11 @@ simplify_EXISTS_query(PlannerInfo *root, Query *query)
         */
        if (query->commandType != CMD_SELECT ||
                query->setOperations ||
-               query->hasAggs ||
+               QueryHasAggs(query) ||
                query->groupingSets ||
-               query->hasWindowFuncs ||
-               query->hasTargetSRFs ||
-               query->hasModifyingCTE ||
+               QueryHasWindowFuncs(query) ||
+               QueryHasTargetSRFs(query) ||
+               QueryHasModifyingCTE(query) ||
                query->havingQual ||
                query->limitOffset ||
                query->rowMarks)
@@ -1618,7 +1618,7 @@ simplify_EXISTS_query(PlannerInfo *root, Query *query)
        query->windowClause = NIL;
        query->distinctClause = NIL;
        query->sortClause = NIL;
-       query->hasDistinctOn = false;
+       QueryClearFlag(query, HAS_DISTINCT_ON);
 
        return true;
 }
@@ -1779,7 +1779,7 @@ convert_EXISTS_to_ANY(PlannerInfo *root, Query *subselect,
        if (contain_vars_of_level((Node *) newWhere, 1) ||
                contain_vars_of_level((Node *) rightargs, 1))
                return NULL;
-       if (root->parse->hasAggs &&
+       if (QueryHasAggs(root->parse) &&
                (contain_aggs_of_level((Node *) newWhere, 1) ||
                 contain_aggs_of_level((Node *) rightargs, 1)))
                return NULL;
diff --git a/src/backend/optimizer/prep/prepjointree.c 
b/src/backend/optimizer/prep/prepjointree.c
index aa83dd3636..5b85aa8ff9 100644
--- a/src/backend/optimizer/prep/prepjointree.c
+++ b/src/backend/optimizer/prep/prepjointree.c
@@ -49,7 +49,7 @@ typedef struct pullup_replace_vars_context
        RangeTblEntry *target_rte;      /* RTE of subquery */
        Relids          relids;                 /* relids within subquery, as 
numbered after
                                                                 * pullup (set 
only if target_rte->lateral) */
-       bool       *outer_hasSubLinks;  /* -> outer query's hasSubLinks */
+       int                *outer_flags;        /* -> outer query's flags */
        int                     varno;                  /* varno of subquery */
        bool            wrap_non_vars;  /* do we need all non-Var outputs to be 
PHVs? */
        Node      **rv_cache;           /* cache for results with PHVs */
@@ -168,7 +168,7 @@ transform_MERGE_to_join(Query *parse)
         * outer join so that we process all unmatched tuples from the source
         * relation.  If none exist, we can use an inner join.
         */
-       if (parse->mergeUseOuterJoin)
+       if (QueryMergeUseOuterJoin(parse))
                jointype = JOIN_RIGHT;
        else
                jointype = JOIN_INNER;
@@ -1028,7 +1028,7 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, 
RangeTblEntry *rte,
         * Pull up any SubLinks within the subquery's quals, so that we don't
         * leave unoptimized SubLinks behind.
         */
-       if (subquery->hasSubLinks)
+       if (QueryHasSubLinks(subquery))
                pull_up_sublinks(subroot);
 
        /*
@@ -1119,7 +1119,7 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, 
RangeTblEntry *rte,
                                                                                
                  true, true);
        else                                            /* won't need relids */
                rvcontext.relids = NULL;
-       rvcontext.outer_hasSubLinks = &parse->hasSubLinks;
+       rvcontext.outer_flags = &parse->flags;
        rvcontext.varno = varno;
        /* this flag will be set below, if needed */
        rvcontext.wrap_non_vars = false;
@@ -1260,10 +1260,14 @@ pull_up_simple_subquery(PlannerInfo *root, Node 
*jtnode, RangeTblEntry *rte,
         * and VALUES RTEs copied up from the subquery.  So it's necessary to 
copy
         * subquery->hasSubLinks anyway.  Perhaps this can be improved someday.
         */
-       parse->hasSubLinks |= subquery->hasSubLinks;
+       QueryCondSetFlag(parse,
+                       QueryHasSubLinks(parse) || QueryHasSubLinks(subquery),
+                       HAS_SUB_LINKS);
 
        /* If subquery had any RLS conditions, now main query does too */
-       parse->hasRowSecurity |= subquery->hasRowSecurity;
+       QueryCondSetFlag(parse,
+                       QueryHasRowSecurity(parse) || 
QueryHasRowSecurity(subquery),
+                       HAS_ROW_SECURITY);
 
        /*
         * subquery won't be pulled up if it hasAggs, hasWindowFuncs, or
@@ -1512,9 +1516,9 @@ is_simple_subquery(PlannerInfo *root, Query *subquery, 
RangeTblEntry *rte,
         * that case the locking was originally declared in the upper query
         * anyway.
         */
-       if (subquery->hasAggs ||
-               subquery->hasWindowFuncs ||
-               subquery->hasTargetSRFs ||
+       if (QueryHasAggs(subquery) ||
+               QueryHasWindowFuncs(subquery) ||
+               QueryHasTargetSRFs(subquery) ||
                subquery->groupClause ||
                subquery->groupingSets ||
                subquery->havingQual ||
@@ -1522,7 +1526,7 @@ is_simple_subquery(PlannerInfo *root, Query *subquery, 
RangeTblEntry *rte,
                subquery->distinctClause ||
                subquery->limitOffset ||
                subquery->limitCount ||
-               subquery->hasForUpdate ||
+               QueryHasForUpdate(subquery) ||
                subquery->cteList)
                return false;
 
@@ -1665,7 +1669,7 @@ pull_up_simple_values(PlannerInfo *root, Node *jtnode, 
RangeTblEntry *rte)
        rvcontext.targetlist = tlist;
        rvcontext.target_rte = rte;
        rvcontext.relids = NULL;
-       rvcontext.outer_hasSubLinks = &parse->hasSubLinks;
+       rvcontext.outer_flags = &parse->flags;
        rvcontext.varno = varno;
        rvcontext.wrap_non_vars = false;
        /* initialize cache array with indexes 0 .. length(tlist) */
@@ -1826,7 +1830,7 @@ pull_up_constant_function(PlannerInfo *root, Node *jtnode,
         */
        rvcontext.relids = NULL;
 
-       rvcontext.outer_hasSubLinks = &parse->hasSubLinks;
+       rvcontext.outer_flags = &parse->flags;
        rvcontext.varno = ((RangeTblRef *) jtnode)->rtindex;
        /* this flag will be set below, if needed */
        rvcontext.wrap_non_vars = false;
@@ -2302,7 +2306,7 @@ pullup_replace_vars(Node *expr, 
pullup_replace_vars_context *context)
                                                                 
context->varno, 0,
                                                                 
pullup_replace_vars_callback,
                                                                 (void *) 
context,
-                                                                
context->outer_hasSubLinks);
+                                                                
context->outer_flags);
 }
 
 static Node *
diff --git a/src/backend/optimizer/prep/prepunion.c 
b/src/backend/optimizer/prep/prepunion.c
index c939b5a45f..354aae9464 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -340,7 +340,7 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
                {
                        if (subquery->groupClause || subquery->groupingSets ||
                                subquery->distinctClause ||
-                               subroot->hasHavingQual || subquery->hasAggs)
+                               subroot->hasHavingQual || 
QueryHasAggs(subquery))
                                *pNumGroups = subpath->rows;
                        else
                                *pNumGroups = estimate_num_groups(subroot,
diff --git a/src/backend/optimizer/util/clauses.c 
b/src/backend/optimizer/util/clauses.c
index edc25d712e..3d513194a3 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -4672,10 +4672,10 @@ inline_function(Oid funcid, Oid result_type, Oid 
result_collid,
         */
        if (!IsA(querytree, Query) ||
                querytree->commandType != CMD_SELECT ||
-               querytree->hasAggs ||
-               querytree->hasWindowFuncs ||
-               querytree->hasTargetSRFs ||
-               querytree->hasSubLinks ||
+               QueryHasAggs(querytree) ||
+               QueryHasWindowFuncs(querytree) ||
+               QueryHasTargetSRFs(querytree) ||
+               QueryHasSubLinks(querytree) ||
                querytree->cteList ||
                querytree->rtable ||
                querytree->jointree->fromlist ||
@@ -5298,7 +5298,7 @@ inline_set_returning_function(PlannerInfo *root, 
RangeTblEntry *rte)
         * We must also notice if the inserted query adds a dependency on the
         * calling role due to RLS quals.
         */
-       if (querytree->hasRowSecurity)
+       if (QueryHasRowSecurity(querytree))
                root->glob->dependsOnRole = true;
 
        return querytree;
diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c
index 844fc30978..4e1d2a5e1c 100644
--- a/src/backend/optimizer/util/var.c
+++ b/src/backend/optimizer/util/var.c
@@ -756,9 +756,9 @@ flatten_join_alias_vars(PlannerInfo *root, Query *query, 
Node *node)
        context.query = query;
        context.sublevels_up = 0;
        /* flag whether join aliases could possibly contain SubLinks */
-       context.possible_sublink = query->hasSubLinks;
+       context.possible_sublink = QueryHasSubLinks(query);
        /* if hasSubLinks is already true, no need to work hard */
-       context.inserted_sublink = query->hasSubLinks;
+       context.inserted_sublink = QueryHasSubLinks(query);
 
        return flatten_join_alias_vars_mutator(node, &context);
 }
@@ -881,12 +881,13 @@ flatten_join_alias_vars_mutator(Node *node,
 
                context->sublevels_up++;
                save_inserted_sublink = context->inserted_sublink;
-               context->inserted_sublink = ((Query *) node)->hasSubLinks;
+               context->inserted_sublink = QueryHasSubLinks(((Query *) node));
                newnode = query_tree_mutator((Query *) node,
                                                                         
flatten_join_alias_vars_mutator,
                                                                         (void 
*) context,
                                                                         
QTW_IGNORE_JOINALIASES);
-               newnode->hasSubLinks |= context->inserted_sublink;
+               if (context->inserted_sublink)
+                       QuerySetFlag(newnode, HAS_SUB_LINKS);
                context->inserted_sublink = save_inserted_sublink;
                context->sublevels_up--;
                return (Node *) newnode;
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index dbdf6bf896..7b67016d36 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -420,7 +420,7 @@ transformStmt(ParseState *pstate, Node *parseTree)
 
        /* Mark as original query until we learn differently */
        result->querySource = QSRC_ORIGINAL;
-       result->canSetTag = true;
+       QuerySetFlag(result, CAN_SET_TAG);
 
        return result;
 }
@@ -519,9 +519,9 @@ transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
        /* process the WITH clause independently of all else */
        if (stmt->withClause)
        {
-               qry->hasRecursive = stmt->withClause->recursive;
+               QueryCondSetFlag(qry, stmt->withClause->recursive, 
HAS_RECURSIVE);
                qry->cteList = transformWithClause(pstate, stmt->withClause);
-               qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
+               QueryCondSetFlag(qry, pstate->p_hasModifyingCTE, 
HAS_MODIFYING_CTE);
        }
 
        /* set up range table with just the result rel */
@@ -560,10 +560,10 @@ transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
        qry->rteperminfos = pstate->p_rteperminfos;
        qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
 
-       qry->hasSubLinks = pstate->p_hasSubLinks;
-       qry->hasWindowFuncs = pstate->p_hasWindowFuncs;
-       qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
-       qry->hasAggs = pstate->p_hasAggs;
+       QueryCondSetFlag(qry, pstate->p_hasSubLinks, HAS_SUB_LINKS);
+       QueryCondSetFlag(qry, pstate->p_hasWindowFuncs, HAS_WINDOW_FUNCS);
+       QueryCondSetFlag(qry, pstate->p_hasTargetSRFs, HAS_TARGET_SRFS);
+       QueryCondSetFlag(qry, pstate->p_hasAggs, HAS_AGGS);
 
        assign_query_collations(pstate, qry);
 
@@ -607,9 +607,9 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
        /* process the WITH clause independently of all else */
        if (stmt->withClause)
        {
-               qry->hasRecursive = stmt->withClause->recursive;
+               QueryCondSetFlag(qry, stmt->withClause->recursive, 
HAS_RECURSIVE);
                qry->cteList = transformWithClause(pstate, stmt->withClause);
-               qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
+               QueryCondSetFlag(qry, pstate->p_hasModifyingCTE, 
HAS_MODIFYING_CTE);
        }
 
        qry->override = stmt->override;
@@ -987,8 +987,8 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
        qry->rteperminfos = pstate->p_rteperminfos;
        qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
 
-       qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
-       qry->hasSubLinks = pstate->p_hasSubLinks;
+       QueryCondSetFlag(qry, pstate->p_hasTargetSRFs, HAS_TARGET_SRFS);
+       QueryCondSetFlag(qry, pstate->p_hasSubLinks, HAS_SUB_LINKS);
 
        assign_query_collations(pstate, qry);
 
@@ -1335,9 +1335,9 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
        /* process the WITH clause independently of all else */
        if (stmt->withClause)
        {
-               qry->hasRecursive = stmt->withClause->recursive;
+               QueryCondSetFlag(qry, stmt->withClause->recursive, 
HAS_RECURSIVE);
                qry->cteList = transformWithClause(pstate, stmt->withClause);
-               qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
+               QueryCondSetFlag(qry, pstate->p_hasModifyingCTE, 
HAS_MODIFYING_CTE);
        }
 
        /* Complain if we get called from someplace where INTO is not allowed */
@@ -1396,7 +1396,7 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
        if (stmt->distinctClause == NIL)
        {
                qry->distinctClause = NIL;
-               qry->hasDistinctOn = false;
+               QueryClearFlag(qry, HAS_DISTINCT_ON);
        }
        else if (linitial(stmt->distinctClause) == NULL)
        {
@@ -1405,7 +1405,7 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
                                                                                
                          &qry->targetList,
                                                                                
                          qry->sortClause,
                                                                                
                          false);
-               qry->hasDistinctOn = false;
+               QueryClearFlag(qry, HAS_DISTINCT_ON);
        }
        else
        {
@@ -1414,7 +1414,7 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
                                                                                
                                stmt->distinctClause,
                                                                                
                                &qry->targetList,
                                                                                
                                qry->sortClause);
-               qry->hasDistinctOn = true;
+               QuerySetFlag(qry, HAS_DISTINCT_ON);
        }
 
        /* transform LIMIT */
@@ -1439,10 +1439,11 @@ transformSelectStmt(ParseState *pstate, SelectStmt 
*stmt)
        qry->rteperminfos = pstate->p_rteperminfos;
        qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
 
-       qry->hasSubLinks = pstate->p_hasSubLinks;
-       qry->hasWindowFuncs = pstate->p_hasWindowFuncs;
-       qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
-       qry->hasAggs = pstate->p_hasAggs;
+       QueryCondSetFlag(qry, pstate->p_hasSubLinks, HAS_SUB_LINKS);
+       QueryCondSetFlag(qry, pstate->p_hasWindowFuncs, HAS_WINDOW_FUNCS);
+       QueryCondSetFlag(qry, pstate->p_hasTargetSRFs, HAS_TARGET_SRFS);
+       QueryCondSetFlag(qry, pstate->p_hasAggs, HAS_AGGS);
+
 
        foreach(l, stmt->lockingClause)
        {
@@ -1498,9 +1499,9 @@ transformValuesClause(ParseState *pstate, SelectStmt 
*stmt)
        /* process the WITH clause independently of all else */
        if (stmt->withClause)
        {
-               qry->hasRecursive = stmt->withClause->recursive;
+               QueryCondSetFlag(qry, stmt->withClause->recursive, 
HAS_RECURSIVE);
                qry->cteList = transformWithClause(pstate, stmt->withClause);
-               qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
+               QueryCondSetFlag(qry, pstate->p_hasModifyingCTE, 
HAS_MODIFYING_CTE);
        }
 
        /*
@@ -1668,7 +1669,7 @@ transformValuesClause(ParseState *pstate, SelectStmt 
*stmt)
        qry->rteperminfos = pstate->p_rteperminfos;
        qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
 
-       qry->hasSubLinks = pstate->p_hasSubLinks;
+       QueryCondSetFlag(qry, pstate->p_hasSubLinks, HAS_SUB_LINKS);
 
        assign_query_collations(pstate, qry);
 
@@ -1765,9 +1766,9 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt 
*stmt)
        /* Process the WITH clause independently of all else */
        if (withClause)
        {
-               qry->hasRecursive = withClause->recursive;
+               QueryCondSetFlag(qry, withClause->recursive, HAS_RECURSIVE);
                qry->cteList = transformWithClause(pstate, withClause);
-               qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
+               QueryCondSetFlag(qry, pstate->p_hasModifyingCTE, 
HAS_MODIFYING_CTE);
        }
 
        /*
@@ -1915,10 +1916,10 @@ transformSetOperationStmt(ParseState *pstate, 
SelectStmt *stmt)
        qry->rteperminfos = pstate->p_rteperminfos;
        qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
 
-       qry->hasSubLinks = pstate->p_hasSubLinks;
-       qry->hasWindowFuncs = pstate->p_hasWindowFuncs;
-       qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
-       qry->hasAggs = pstate->p_hasAggs;
+       QueryCondSetFlag(qry, pstate->p_hasSubLinks, HAS_SUB_LINKS);
+       QueryCondSetFlag(qry, pstate->p_hasWindowFuncs, HAS_WINDOW_FUNCS);
+       QueryCondSetFlag(qry, pstate->p_hasTargetSRFs, HAS_TARGET_SRFS);
+       QueryCondSetFlag(qry, pstate->p_hasAggs, HAS_AGGS);
 
        foreach(l, lockingClause)
        {
@@ -2379,7 +2380,7 @@ transformReturnStmt(ParseState *pstate, ReturnStmt *stmt)
        Query      *qry = makeNode(Query);
 
        qry->commandType = CMD_SELECT;
-       qry->isReturn = true;
+       QuerySetFlag(qry, IS_RETURN);
 
        qry->targetList = list_make1(makeTargetEntry((Expr *) 
transformExpr(pstate, stmt->returnval, EXPR_KIND_SELECT_TARGET),
                                                                                
                 1, NULL, false));
@@ -2389,10 +2390,10 @@ transformReturnStmt(ParseState *pstate, ReturnStmt 
*stmt)
        qry->rtable = pstate->p_rtable;
        qry->rteperminfos = pstate->p_rteperminfos;
        qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
-       qry->hasSubLinks = pstate->p_hasSubLinks;
-       qry->hasWindowFuncs = pstate->p_hasWindowFuncs;
-       qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
-       qry->hasAggs = pstate->p_hasAggs;
+       QueryCondSetFlag(qry, pstate->p_hasSubLinks, HAS_SUB_LINKS);
+       QueryCondSetFlag(qry, pstate->p_hasWindowFuncs, HAS_WINDOW_FUNCS);
+       QueryCondSetFlag(qry, pstate->p_hasTargetSRFs, HAS_TARGET_SRFS);
+       QueryCondSetFlag(qry, pstate->p_hasAggs, HAS_AGGS);
 
        assign_query_collations(pstate, qry);
 
@@ -2417,9 +2418,9 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
        /* process the WITH clause independently of all else */
        if (stmt->withClause)
        {
-               qry->hasRecursive = stmt->withClause->recursive;
+               QueryCondSetFlag(qry, stmt->withClause->recursive, 
HAS_RECURSIVE);
                qry->cteList = transformWithClause(pstate, stmt->withClause);
-               qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
+               QueryCondSetFlag(qry, pstate->p_hasModifyingCTE, 
HAS_MODIFYING_CTE);
        }
 
        qry->resultRelation = setTargetTable(pstate, stmt->relation,
@@ -2457,8 +2458,9 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
        qry->rteperminfos = pstate->p_rteperminfos;
        qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
 
-       qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
-       qry->hasSubLinks = pstate->p_hasSubLinks;
+       QueryCondSetFlag(qry, pstate->p_hasTargetSRFs, HAS_TARGET_SRFS);
+       QueryCondSetFlag(qry, pstate->p_hasSubLinks, HAS_SUB_LINKS);
+
 
        assign_query_collations(pstate, qry);
 
@@ -2781,7 +2783,7 @@ transformPLAssignStmt(ParseState *pstate, PLAssignStmt 
*stmt)
        if (sstmt->distinctClause == NIL)
        {
                qry->distinctClause = NIL;
-               qry->hasDistinctOn = false;
+               QueryClearFlag(qry, HAS_DISTINCT_ON);
        }
        else if (linitial(sstmt->distinctClause) == NULL)
        {
@@ -2790,7 +2792,7 @@ transformPLAssignStmt(ParseState *pstate, PLAssignStmt 
*stmt)
                                                                                
                          &qry->targetList,
                                                                                
                          qry->sortClause,
                                                                                
                          false);
-               qry->hasDistinctOn = false;
+               QueryClearFlag(qry, HAS_DISTINCT_ON);
        }
        else
        {
@@ -2799,7 +2801,7 @@ transformPLAssignStmt(ParseState *pstate, PLAssignStmt 
*stmt)
                                                                                
                                sstmt->distinctClause,
                                                                                
                                &qry->targetList,
                                                                                
                                qry->sortClause);
-               qry->hasDistinctOn = true;
+               QuerySetFlag(qry, HAS_DISTINCT_ON);
        }
 
        /* transform LIMIT */
@@ -2820,10 +2822,10 @@ transformPLAssignStmt(ParseState *pstate, PLAssignStmt 
*stmt)
        qry->rteperminfos = pstate->p_rteperminfos;
        qry->jointree = makeFromExpr(pstate->p_joinlist, qual);
 
-       qry->hasSubLinks = pstate->p_hasSubLinks;
-       qry->hasWindowFuncs = pstate->p_hasWindowFuncs;
-       qry->hasTargetSRFs = pstate->p_hasTargetSRFs;
-       qry->hasAggs = pstate->p_hasAggs;
+       QueryCondSetFlag(qry, pstate->p_hasSubLinks, HAS_SUB_LINKS);
+       QueryCondSetFlag(qry, pstate->p_hasWindowFuncs, HAS_WINDOW_FUNCS);
+       QueryCondSetFlag(qry, pstate->p_hasTargetSRFs, HAS_TARGET_SRFS);
+       QueryCondSetFlag(qry, pstate->p_hasAggs, HAS_AGGS);
 
        foreach(l, sstmt->lockingClause)
        {
@@ -2887,7 +2889,7 @@ transformDeclareCursorStmt(ParseState *pstate, 
DeclareCursorStmt *stmt)
         * allowed, but the semantics of when the updates occur might be
         * surprising.)
         */
-       if (query->hasModifyingCTE)
+       if (QueryHasModifyingCTE(query))
                ereport(ERROR,
                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                 errmsg("DECLARE CURSOR must not contain 
data-modifying statements in WITH")));
@@ -3014,7 +3016,7 @@ transformCreateTableAsStmt(ParseState *pstate, 
CreateTableAsStmt *stmt)
                 * materialized view. It's not sufficiently clear what the user 
would
                 * want to happen if the MV is refreshed or incrementally 
maintained.
                 */
-               if (query->hasModifyingCTE)
+               if (QueryHasModifyingCTE(query))
                        ereport(ERROR,
                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                         errmsg("materialized views must not 
use data-modifying statements in WITH")));
@@ -3254,21 +3256,21 @@ CheckSelectLocking(Query *qry, LockClauseStrength 
strength)
                  translator: %s is a SQL row locking clause such as FOR UPDATE 
*/
                                 errmsg("%s is not allowed with HAVING clause",
                                                LCS_asString(strength))));
-       if (qry->hasAggs)
+       if (QueryHasAggs(qry))
                ereport(ERROR,
                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                /*------
                  translator: %s is a SQL row locking clause such as FOR UPDATE 
*/
                                 errmsg("%s is not allowed with aggregate 
functions",
                                                LCS_asString(strength))));
-       if (qry->hasWindowFuncs)
+       if (QueryHasWindowFuncs(qry))
                ereport(ERROR,
                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                /*------
                  translator: %s is a SQL row locking clause such as FOR UPDATE 
*/
                                 errmsg("%s is not allowed with window 
functions",
                                                LCS_asString(strength))));
-       if (qry->hasTargetSRFs)
+       if (QueryHasTargetSRFs(qry))
                ereport(ERROR,
                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                /*------
@@ -3523,7 +3525,7 @@ applyLockingClause(Query *qry, Index rtindex,
 
        /* If it's an explicit clause, make sure hasForUpdate gets set */
        if (!pushedDown)
-               qry->hasForUpdate = true;
+               QuerySetFlag(qry, HAS_FOR_UPDATE);
 
        /* Check for pre-existing entry for same rtindex */
        if ((rc = get_parse_rowmark(qry, rtindex)) != NULL)
diff --git a/src/backend/parser/parse_cte.c b/src/backend/parser/parse_cte.c
index 3c88c9abba..5719b437cb 100644
--- a/src/backend/parser/parse_cte.c
+++ b/src/backend/parser/parse_cte.c
@@ -346,7 +346,7 @@ analyzeCTE(ParseState *pstate, CommonTableExpr *cte)
         * matters for data-modifying statements, for which the flag will be
         * propagated to the ModifyTable plan node.)
         */
-       query->canSetTag = false;
+       QueryClearFlag(query, CAN_SET_TAG);
 
        if (!cte->cterecursive)
        {
diff --git a/src/backend/parser/parse_merge.c b/src/backend/parser/parse_merge.c
index 5f6a683ab9..bdecfb2246 100644
--- a/src/backend/parser/parse_merge.c
+++ b/src/backend/parser/parse_merge.c
@@ -108,7 +108,7 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt)
        Assert(pstate->p_ctenamespace == NIL);
 
        qry->commandType = CMD_MERGE;
-       qry->hasRecursive = false;
+       QueryClearFlag(qry, HAS_RECURSIVE);
 
        /* process the WITH clause independently of all else */
        if (stmt->withClause)
@@ -119,7 +119,7 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt)
                                         errmsg("WITH RECURSIVE is not 
supported for MERGE statement")));
 
                qry->cteList = transformWithClause(pstate, stmt->withClause);
-               qry->hasModifyingCTE = pstate->p_hasModifyingCTE;
+               QueryCondSetFlag(qry, pstate->p_hasModifyingCTE, 
HAS_MODIFYING_CTE);
        }
 
        /*
@@ -259,7 +259,7 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt)
 
                /* Use an outer join if any INSERT actions exist in the 
command. */
                if (action->commandType == CMD_INSERT)
-                       qry->mergeUseOuterJoin = true;
+                       QuerySetFlag(qry, MERGE_USE_OUTERJOIN);
 
                /*
                 * Set namespace for the specific action. This must be done 
before
@@ -393,8 +393,8 @@ transformMergeStmt(ParseState *pstate, MergeStmt *stmt)
        /* RETURNING could potentially be added in the future, but not in SQL 
std */
        qry->returningList = NULL;
 
-       qry->hasTargetSRFs = false;
-       qry->hasSubLinks = pstate->p_hasSubLinks;
+       QueryClearFlag(qry, HAS_TARGET_SRFS);
+       QueryCondSetFlag(qry, pstate->p_hasSubLinks, HAS_SUB_LINKS);
 
        assign_query_collations(pstate, qry);
 
diff --git a/src/backend/rewrite/rewriteDefine.c 
b/src/backend/rewrite/rewriteDefine.c
index b449244a53..e0ed3f6148 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -350,7 +350,7 @@ DefineQueryRewrite(const char *rulename,
                /*
                 * ... it cannot contain data-modifying WITH ...
                 */
-               if (query->hasModifyingCTE)
+               if (QueryHasModifyingCTE(query))
                        ereport(ERROR,
                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                         errmsg("rules on SELECT must not 
contain data-modifying statements in WITH")));
@@ -685,7 +685,7 @@ setRuleCheckAsUser_Query(Query *qry, Oid userid)
        }
 
        /* If there are sublinks, search for them and process their RTEs */
-       if (qry->hasSubLinks)
+       if (QueryHasSubLinks(qry))
                query_tree_walker(qry, setRuleCheckAsUser_walker, (void *) 
&userid,
                                                  QTW_IGNORE_RC_SUBQUERIES);
 }
diff --git a/src/backend/rewrite/rewriteHandler.c 
b/src/backend/rewrite/rewriteHandler.c
index f60b34deb6..42b23a6d84 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -292,7 +292,7 @@ AcquireRewriteLocks(Query *parsetree,
         * Recurse into sublink subqueries, too.  But we already did the ones in
         * the rtable and cteList.
         */
-       if (parsetree->hasSubLinks)
+       if (QueryHasSubLinks(parsetree))
                query_tree_walker(parsetree, acquireLocksOnSubLinks, &context,
                                                  QTW_IGNORE_RC_SUBQUERIES);
 }
@@ -457,7 +457,7 @@ rewriteRuleAction(Query *parsetree,
         * There could have been some SubLinks in parsetree's rtable, in which
         * case we'd better mark the sub_action correctly.
         */
-       if (parsetree->hasSubLinks && !sub_action->hasSubLinks)
+       if (QueryHasSubLinks(parsetree) && !QueryHasSubLinks(sub_action))
        {
                foreach(lc, parsetree->rtable)
                {
@@ -466,28 +466,28 @@ rewriteRuleAction(Query *parsetree,
                        switch (rte->rtekind)
                        {
                                case RTE_RELATION:
-                                       sub_action->hasSubLinks =
-                                               checkExprHasSubLink((Node *) 
rte->tablesample);
+                                       QueryCondSetFlag(sub_action,
+                                               checkExprHasSubLink((Node *) 
rte->tablesample), HAS_SUB_LINKS);
                                        break;
                                case RTE_FUNCTION:
-                                       sub_action->hasSubLinks =
-                                               checkExprHasSubLink((Node *) 
rte->functions);
+                                       QueryCondSetFlag(sub_action,
+                                               checkExprHasSubLink((Node *) 
rte->functions), HAS_SUB_LINKS);
                                        break;
                                case RTE_TABLEFUNC:
-                                       sub_action->hasSubLinks =
-                                               checkExprHasSubLink((Node *) 
rte->tablefunc);
+                                       QueryCondSetFlag(sub_action,
+                                               checkExprHasSubLink((Node *) 
rte->tablefunc), HAS_SUB_LINKS);
                                        break;
                                case RTE_VALUES:
-                                       sub_action->hasSubLinks =
-                                               checkExprHasSubLink((Node *) 
rte->values_lists);
+                                       QueryCondSetFlag(sub_action,
+                                               checkExprHasSubLink((Node *) 
rte->values_lists), HAS_SUB_LINKS);
                                        break;
                                default:
                                        /* other RTE types don't contain bare 
expressions */
                                        break;
                        }
-                       sub_action->hasSubLinks |=
-                               checkExprHasSubLink((Node *) 
rte->securityQuals);
-                       if (sub_action->hasSubLinks)
+                       if (checkExprHasSubLink((Node *) rte->securityQuals))
+                               QuerySetFlag(sub_action, HAS_SUB_LINKS);
+                       if (QueryHasSubLinks(sub_action))
                                break;                  /* no need to keep 
scanning rtable */
                }
        }
@@ -499,7 +499,8 @@ rewriteRuleAction(Query *parsetree,
         * this is a no-op because RLS conditions aren't added till later, but 
it
         * seems like good future-proofing to do this anyway.)
         */
-       sub_action->hasRowSecurity |= parsetree->hasRowSecurity;
+       if(QueryHasRowSecurity(parsetree))
+               QuerySetFlag(sub_action, HAS_ROW_SECURITY);
 
        /*
         * Each rule action's jointree should be the main parsetree's jointree
@@ -546,9 +547,9 @@ rewriteRuleAction(Query *parsetree,
                         * There could have been some SubLinks in newjointree, 
in which
                         * case we'd better mark the sub_action correctly.
                         */
-                       if (parsetree->hasSubLinks && !sub_action->hasSubLinks)
-                               sub_action->hasSubLinks =
-                                       checkExprHasSubLink((Node *) 
newjointree);
+                       if (QueryHasSubLinks(parsetree) && 
!QueryHasSubLinks(sub_action))
+                               QueryCondSetFlag(sub_action,
+                                                                
checkExprHasSubLink((Node *) newjointree), HAS_SUB_LINKS);
                }
        }
 
@@ -590,8 +591,10 @@ rewriteRuleAction(Query *parsetree,
                sub_action->cteList = list_concat(sub_action->cteList,
                                                                                
  copyObject(parsetree->cteList));
                /* ... and don't forget about the associated flags */
-               sub_action->hasRecursive |= parsetree->hasRecursive;
-               sub_action->hasModifyingCTE |= parsetree->hasModifyingCTE;
+               if (QueryHasRecursive(parsetree))
+                       QuerySetFlag(sub_action, HAS_RECURSIVE);
+               if (QueryHasModifyingCTE(parsetree))
+                       QuerySetFlag(sub_action, HAS_MODIFYING_CTE);
 
                /*
                 * If rule_action is different from sub_action (i.e., the rule 
action
@@ -605,7 +608,7 @@ rewriteRuleAction(Query *parsetree,
                 * have to increment ctelevelsup in RTEs and SubLinks copied 
from the
                 * original query.  For now, it doesn't seem worth the trouble.
                 */
-               if (sub_action->hasModifyingCTE && rule_action != sub_action)
+               if (QueryHasModifyingCTE(sub_action) && rule_action != 
sub_action)
                        ereport(ERROR,
                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                         errmsg("INSERT ... SELECT rule actions 
are not supported for queries having data-modifying statements in WITH")));
@@ -672,15 +675,16 @@ rewriteRuleAction(Query *parsetree,
                                                                          
rule_action->returningList,
                                                                          
REPLACEVARS_REPORT_ERROR,
                                                                          0,
-                                                                         
&rule_action->hasSubLinks);
+                                                                         
&rule_action->flags);
 
                /*
                 * There could have been some SubLinks in parsetree's 
returningList,
                 * in which case we'd better mark the rule_action correctly.
                 */
-               if (parsetree->hasSubLinks && !rule_action->hasSubLinks)
-                       rule_action->hasSubLinks =
-                               checkExprHasSubLink((Node *) 
rule_action->returningList);
+               if (QueryHasSubLinks(parsetree) && 
!QueryHasSubLinks(rule_action))
+                       QueryCondSetFlag(rule_action,
+                                                        
checkExprHasSubLink((Node *) rule_action->returningList),
+                                                        HAS_SUB_LINKS);
        }
 
        return rule_action;
@@ -2154,7 +2158,7 @@ fireRIRrules(Query *parsetree, List *activeRIRs)
         * Recurse into sublink subqueries, too.  But we already did the ones in
         * the rtable and cteList.
         */
-       if (parsetree->hasSubLinks)
+       if (QueryHasSubLinks(parsetree))
                query_tree_walker(parsetree, fireRIRonSubLink, (void *) 
activeRIRs,
                                                  QTW_IGNORE_RC_SUBQUERIES);
 
@@ -2253,9 +2257,9 @@ fireRIRrules(Query *parsetree, List *activeRIRs)
                 * applies, or if the new quals had sublinks.
                 */
                if (hasRowSecurity)
-                       parsetree->hasRowSecurity = true;
+                       QuerySetFlag(parsetree, HAS_ROW_SECURITY);
                if (hasSubLinks)
-                       parsetree->hasSubLinks = true;
+                       QuerySetFlag(parsetree, HAS_SUB_LINKS);
 
                table_close(rel, NoLock);
        }
@@ -2311,7 +2315,7 @@ CopyAndAddInvertedQual(Query *parsetree,
                                                                                
         REPLACEVARS_CHANGE_VARNO :
                                                                                
         REPLACEVARS_SUBSTITUTE_NULL,
                                                                                
         rt_index,
-                                                                               
         &parsetree->hasSubLinks);
+                                                                               
         &parsetree->flags);
        /* And attach the fixed qual */
        AddInvertedQual(parsetree, new_qual);
 
@@ -2419,7 +2423,7 @@ fireRules(Query *parsetree,
                                                                                
        returning_flag);
 
                        rule_action->querySource = qsrc;
-                       rule_action->canSetTag = false; /* might change later */
+                       QueryClearFlag(rule_action, CAN_SET_TAG); /* might 
change later */
 
                        results = lappend(results, rule_action);
                }
@@ -2622,13 +2626,13 @@ view_query_is_auto_updatable(Query *viewquery, bool 
check_cols)
         * These restrictions ensure that each row of the view corresponds to a
         * unique row in the underlying base relation.
         */
-       if (viewquery->hasAggs)
+       if (QueryHasAggs(viewquery))
                return gettext_noop("Views that return aggregate functions are 
not automatically updatable.");
 
-       if (viewquery->hasWindowFuncs)
+       if (QueryHasWindowFuncs(viewquery))
                return gettext_noop("Views that return window functions are not 
automatically updatable.");
 
-       if (viewquery->hasTargetSRFs)
+       if (QueryHasTargetSRFs(viewquery))
                return gettext_noop("Views that return set-returning functions 
are not automatically updatable.");
 
        /*
@@ -3212,7 +3216,7 @@ rewriteTargetView(Query *parsetree, Relation view)
         * be any subqueries in the range table or CTEs, so we can skip those, 
as
         * in AcquireRewriteLocks.
         */
-       if (viewquery->hasSubLinks)
+       if (QueryHasSubLinks(viewquery))
        {
                acquireLocksOnSubLinks_context context;
 
@@ -3473,7 +3477,7 @@ rewriteTargetView(Query *parsetree, Relation view)
                                                                          
tmp_tlist,
                                                                          
REPLACEVARS_REPORT_ERROR,
                                                                          0,
-                                                                         
&parsetree->hasSubLinks);
+                                                                         
&parsetree->flags);
        }
 
        /*
@@ -3524,8 +3528,8 @@ rewriteTargetView(Query *parsetree, Relation view)
                         * Make sure that the query is marked correctly if the 
added qual
                         * has sublinks.
                         */
-                       if (!parsetree->hasSubLinks)
-                               parsetree->hasSubLinks = 
checkExprHasSubLink(viewqual);
+                       if (!QueryHasSubLinks(parsetree))
+                               QueryCondSetFlag(parsetree, 
checkExprHasSubLink(viewqual), HAS_SUB_LINKS);
                }
                else
                        AddQual(parsetree, (Node *) viewqual);
@@ -3596,9 +3600,9 @@ rewriteTargetView(Query *parsetree, Relation view)
                                 * case the same qual will have already been 
added, and this
                                 * check will already have been done.
                                 */
-                               if (!parsetree->hasSubLinks &&
+                               if (!QueryHasSubLinks(parsetree) &&
                                        parsetree->commandType != CMD_UPDATE)
-                                       parsetree->hasSubLinks = 
checkExprHasSubLink(wco->qual);
+                                       QueryCondSetFlag(parsetree, 
checkExprHasSubLink(wco->qual), HAS_SUB_LINKS);
                        }
                }
        }
@@ -3670,7 +3674,7 @@ RewriteQuery(Query *parsetree, List *rewrite_events, int 
orig_rt_length)
                                                 errmsg("DO INSTEAD NOTIFY 
rules are not supported for data-modifying statements in WITH")));
                        }
                        /* WITH queries should never be canSetTag */
-                       Assert(!ctequery->canSetTag);
+                       Assert(!QueryCanSetTag(ctequery));
                        /* Push the single Query back into the CTE node */
                        cte->ctequery = (Node *) ctequery;
                }
@@ -4211,7 +4215,7 @@ QueryRewrite(Query *parsetree)
         * This function is only applied to top-level original queries
         */
        Assert(parsetree->querySource == QSRC_ORIGINAL);
-       Assert(parsetree->canSetTag);
+       Assert(QueryCanSetTag(parsetree));
 
        /*
         * Step 1
@@ -4265,7 +4269,7 @@ QueryRewrite(Query *parsetree)
 
                if (query->querySource == QSRC_ORIGINAL)
                {
-                       Assert(query->canSetTag);
+                       Assert(QueryCanSetTag(query));
                        Assert(!foundOriginalQuery);
                        foundOriginalQuery = true;
 #ifndef USE_ASSERT_CHECKING
@@ -4274,7 +4278,7 @@ QueryRewrite(Query *parsetree)
                }
                else
                {
-                       Assert(!query->canSetTag);
+                       Assert(!QueryCanSetTag(query));
                        if (query->commandType == origCmdType &&
                                (query->querySource == QSRC_INSTEAD_RULE ||
                                 query->querySource == QSRC_QUAL_INSTEAD_RULE))
@@ -4283,7 +4287,7 @@ QueryRewrite(Query *parsetree)
        }
 
        if (!foundOriginalQuery && lastInstead != NULL)
-               lastInstead->canSetTag = true;
+               QuerySetFlag(lastInstead, CAN_SET_TAG);
 
        return results;
 }
diff --git a/src/backend/rewrite/rewriteManip.c 
b/src/backend/rewrite/rewriteManip.c
index 76c97a5b28..7fb2859b8f 100644
--- a/src/backend/rewrite/rewriteManip.c
+++ b/src/backend/rewrite/rewriteManip.c
@@ -1102,8 +1102,8 @@ AddQual(Query *parsetree, Node *qual)
         * Make sure query is marked correctly if added qual has sublinks. Need
         * not search qual when query is already marked.
         */
-       if (!parsetree->hasSubLinks)
-               parsetree->hasSubLinks = checkExprHasSubLink(copy);
+       if (!QueryHasSubLinks(parsetree))
+               QueryCondSetFlag(parsetree, checkExprHasSubLink(copy), 
HAS_SUB_LINKS);
 }
 
 
@@ -1334,7 +1334,7 @@ Node *
 replace_rte_variables(Node *node, int target_varno, int sublevels_up,
                                          replace_rte_variables_callback 
callback,
                                          void *callback_arg,
-                                         bool *outer_hasSubLinks)
+                                         int *outer_flags)
 {
        Node       *result;
        replace_rte_variables_context context;
@@ -1349,9 +1349,9 @@ replace_rte_variables(Node *node, int target_varno, int 
sublevels_up,
         * detect new sublinks because the query already has some.
         */
        if (node && IsA(node, Query))
-               context.inserted_sublink = ((Query *) node)->hasSubLinks;
-       else if (outer_hasSubLinks)
-               context.inserted_sublink = *outer_hasSubLinks;
+               context.inserted_sublink = QueryHasSubLinks((Query *) node);
+       else if (outer_flags)
+               context.inserted_sublink = QueryFlagIsSet(*outer_flags, 
HAS_SUB_LINKS);
        else
                context.inserted_sublink = false;
 
@@ -1367,9 +1367,9 @@ replace_rte_variables(Node *node, int target_varno, int 
sublevels_up,
        if (context.inserted_sublink)
        {
                if (result && IsA(result, Query))
-                       ((Query *) result)->hasSubLinks = true;
-               else if (outer_hasSubLinks)
-                       *outer_hasSubLinks = true;
+                       QuerySetFlag(((Query *) result), HAS_SUB_LINKS);
+               else if (outer_flags)
+                       QueryFlagSet(*outer_flags, HAS_SUB_LINKS);
                else
                        elog(ERROR, "replace_rte_variables inserted a SubLink, 
but has noplace to record it");
        }
@@ -1428,12 +1428,13 @@ replace_rte_variables_mutator(Node *node,
 
                context->sublevels_up++;
                save_inserted_sublink = context->inserted_sublink;
-               context->inserted_sublink = ((Query *) node)->hasSubLinks;
+               context->inserted_sublink = QueryHasSubLinks((Query *) node);
                newnode = query_tree_mutator((Query *) node,
                                                                         
replace_rte_variables_mutator,
                                                                         (void 
*) context,
                                                                         0);
-               newnode->hasSubLinks |= context->inserted_sublink;
+               if (context->inserted_sublink)
+                       QuerySetFlag(newnode, HAS_SUB_LINKS);
                context->inserted_sublink = save_inserted_sublink;
                context->sublevels_up--;
                return (Node *) newnode;
@@ -1764,7 +1765,7 @@ ReplaceVarsFromTargetList(Node *node,
                                                  List *targetlist,
                                                  ReplaceVarsNoMatchOption 
nomatch_option,
                                                  int nomatch_varno,
-                                                 bool *outer_hasSubLinks)
+                                                 int *outer_flags)
 {
        ReplaceVarsFromTargetList_context context;
 
@@ -1776,5 +1777,5 @@ ReplaceVarsFromTargetList(Node *node,
        return replace_rte_variables(node, target_varno, sublevels_up,
                                                                 
ReplaceVarsFromTargetList_callback,
                                                                 (void *) 
&context,
-                                                                
outer_hasSubLinks);
+                                                                outer_flags);
 }
diff --git a/src/backend/rewrite/rewriteSearchCycle.c 
b/src/backend/rewrite/rewriteSearchCycle.c
index 911a901808..d3cd02c4e0 100644
--- a/src/backend/rewrite/rewriteSearchCycle.c
+++ b/src/backend/rewrite/rewriteSearchCycle.c
@@ -278,7 +278,7 @@ rewriteSearchAndCycle(CommonTableExpr *cte)
         */
        newq1 = makeNode(Query);
        newq1->commandType = CMD_SELECT;
-       newq1->canSetTag = true;
+       QuerySetFlag(newq1, CAN_SET_TAG);
 
        newrte = makeNode(RangeTblEntry);
        newrte->rtekind = RTE_SUBQUERY;
@@ -365,7 +365,7 @@ rewriteSearchAndCycle(CommonTableExpr *cte)
         */
        newq2 = makeNode(Query);
        newq2->commandType = CMD_SELECT;
-       newq2->canSetTag = true;
+       QuerySetFlag(newq2, CAN_SET_TAG);
 
        newrte = makeNode(RangeTblEntry);
        newrte->rtekind = RTE_SUBQUERY;
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 2c63b7875a..18100128cc 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -984,7 +984,7 @@ pg_plan_queries(List *querytrees, const char *query_string, 
int cursorOptions,
                        /* Utility commands require no planning. */
                        stmt = makeNode(PlannedStmt);
                        stmt->commandType = CMD_UTILITY;
-                       stmt->canSetTag = query->canSetTag;
+                       stmt->canSetTag = QueryCanSetTag(query);
                        stmt->utilityStmt = query->utilityStmt;
                        stmt->stmt_location = query->stmt_location;
                        stmt->stmt_len = query->stmt_len;
diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c
index 0c45fcf318..329fc05ac4 100644
--- a/src/backend/tcop/pquery.c
+++ b/src/backend/tcop/pquery.c
@@ -225,11 +225,11 @@ ChoosePortalStrategy(List *stmts)
                {
                        Query      *query = (Query *) stmt;
 
-                       if (query->canSetTag)
+                       if (QueryCanSetTag(query))
                        {
                                if (query->commandType == CMD_SELECT)
                                {
-                                       if (query->hasModifyingCTE)
+                                       if (QueryHasModifyingCTE(query))
                                                return PORTAL_ONE_MOD_WITH;
                                        else
                                                return PORTAL_ONE_SELECT;
@@ -283,7 +283,7 @@ ChoosePortalStrategy(List *stmts)
                {
                        Query      *query = (Query *) stmt;
 
-                       if (query->canSetTag)
+                       if (QueryCanSetTag(query))
                        {
                                if (++nSetTag > 1)
                                        return PORTAL_MULTI_QUERY;      /* no 
need to look further */
diff --git a/src/backend/utils/adt/ruleutils.c 
b/src/backend/utils/adt/ruleutils.c
index a928a8c55d..daec49c286 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -5562,7 +5562,7 @@ get_with_clause(Query *query, deparse_context *context)
                appendStringInfoChar(buf, ' ');
        }
 
-       if (query->hasRecursive)
+       if (QueryHasRecursive(query))
                sep = "WITH RECURSIVE ";
        else
                sep = "WITH ";
@@ -5763,7 +5763,7 @@ get_select_query_def(Query *query, deparse_context 
*context,
        }
 
        /* Add FOR [KEY] UPDATE/SHARE clauses if present */
-       if (query->hasForUpdate)
+       if (QueryHasForUpdate(query))
        {
                foreach(l, query->rowMarks)
                {
@@ -5916,7 +5916,7 @@ get_basic_select_query(Query *query, deparse_context 
*context,
        /*
         * Build up the query string - first we say SELECT
         */
-       if (query->isReturn)
+       if (QueryIsReturn(query))
                appendStringInfoString(buf, "RETURN");
        else
                appendStringInfoString(buf, "SELECT");
@@ -5924,7 +5924,7 @@ get_basic_select_query(Query *query, deparse_context 
*context,
        /* Add the DISTINCT clause if given */
        if (query->distinctClause != NIL)
        {
-               if (query->hasDistinctOn)
+               if (QueryHasDistinctOn(query))
                {
                        appendStringInfoString(buf, " DISTINCT ON (");
                        sep = "";
@@ -6898,7 +6898,7 @@ get_update_query_targetlist_def(Query *query, List 
*targetList,
         * entries.
         */
        ma_sublinks = NIL;
-       if (query->hasSubLinks)         /* else there can't be any */
+       if (QueryHasSubLinks(query))            /* else there can't be any */
        {
                foreach(l, targetList)
                {
diff --git a/src/backend/utils/cache/plancache.c 
b/src/backend/utils/cache/plancache.c
index 5194cbf2cc..fcf371622a 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -1384,7 +1384,7 @@ CachedPlanAllowsSimpleValidityCheck(CachedPlanSource 
*plansource,
 
                if (query->commandType == CMD_UTILITY)
                        return false;
-               if (query->rtable || query->cteList || query->hasSubLinks)
+               if (query->rtable || query->cteList || QueryHasSubLinks(query))
                        return false;
        }
 
@@ -1760,7 +1760,7 @@ QueryListGetPrimaryStmt(List *stmts)
        {
                Query      *stmt = lfirst_node(Query, lc);
 
-               if (stmt->canSetTag)
+               if (QueryCanSetTag(stmt))
                        return stmt;
        }
        return NULL;
@@ -1907,7 +1907,7 @@ ScanQueryForLocks(Query *parsetree, bool acquire)
         * Recurse into sublink subqueries, too.  But we already did the ones in
         * the rtable and cteList.
         */
-       if (parsetree->hasSubLinks)
+       if (QueryHasSubLinks(parsetree))
        {
                query_tree_walker(parsetree, ScanQueryWalker,
                                                  (void *) &acquire,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index d5b08ded44..ecaefe9b1a 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -129,9 +129,6 @@ typedef struct Query
         */
        uint64          queryId pg_node_attr(equal_ignore, query_jumble_ignore, 
read_write_ignore, read_as(0));
 
-       /* do I set the command result tag? */
-       bool            canSetTag pg_node_attr(query_jumble_ignore);
-
        Node       *utilityStmt;        /* non-null if commandType == 
CMD_UTILITY */
 
        /*
@@ -141,26 +138,7 @@ typedef struct Query
         */
        int                     resultRelation 
pg_node_attr(query_jumble_ignore);
 
-       /* has aggregates in tlist or havingQual */
-       bool            hasAggs pg_node_attr(query_jumble_ignore);
-       /* has window functions in tlist */
-       bool            hasWindowFuncs pg_node_attr(query_jumble_ignore);
-       /* has set-returning functions in tlist */
-       bool            hasTargetSRFs pg_node_attr(query_jumble_ignore);
-       /* has subquery SubLink */
-       bool            hasSubLinks pg_node_attr(query_jumble_ignore);
-       /* distinctClause is from DISTINCT ON */
-       bool            hasDistinctOn pg_node_attr(query_jumble_ignore);
-       /* WITH RECURSIVE was specified */
-       bool            hasRecursive pg_node_attr(query_jumble_ignore);
-       /* has INSERT/UPDATE/DELETE in WITH */
-       bool            hasModifyingCTE pg_node_attr(query_jumble_ignore);
-       /* FOR [KEY] UPDATE/SHARE was specified */
-       bool            hasForUpdate pg_node_attr(query_jumble_ignore);
-       /* rewriter has applied some RLS policy */
-       bool            hasRowSecurity pg_node_attr(query_jumble_ignore);
-       /* is a RETURN statement */
-       bool            isReturn pg_node_attr(query_jumble_ignore);
+       int                     flags pg_node_attr(query_jumble_ignore);
 
        List       *cteList;            /* WITH list (of CommonTableExpr's) */
 
@@ -175,8 +153,6 @@ typedef struct Query
                                                                 * also USING 
clause for MERGE */
 
        List       *mergeActionList;    /* list of actions for MERGE (only) */
-       /* whether to use outer join */
-       bool            mergeUseOuterJoin pg_node_attr(query_jumble_ignore);
 
        List       *targetList;         /* target list (of TargetEntry) */
 
@@ -230,6 +206,60 @@ typedef struct Query
        int                     stmt_len pg_node_attr(query_jumble_ignore);
 } Query;
 
+/* do I set the command result tag? */
+#define QUERY_CAN_SET_TAG                              (1)
+/* has aggregates in tlist or havingQual */
+#define QUERY_HAS_AGGS                                 (1 << 1)
+/* has window functions in tlist */
+#define QUERY_HAS_WINDOW_FUNCS                 (1 << 2)
+/* has set-returning functions in tlist */
+#define QUERY_HAS_TARGET_SRFS                  (1 << 3)
+/* has subquery SubLink */
+#define QUERY_HAS_SUB_LINKS                            (1 << 4)
+/* distinctClause is from DISTINCT ON */
+#define QUERY_HAS_DISTINCT_ON                  (1 << 5)
+/* WITH RECURSIVE was specified */
+#define QUERY_HAS_RECURSIVE                            (1 << 6)
+/* has INSERT/UPDATE/DELETE in WITH */
+#define QUERY_HAS_MODIFYING_CTE                        (1 << 7)
+/* FOR [KEY] UPDATE/SHARE was specified */
+#define QUERY_HAS_FOR_UPDATE                   (1 << 8)
+/* rewriter has applied some RLS policy */
+#define QUERY_HAS_ROW_SECURITY                 (1 << 9)
+/* is a RETURN statement */
+#define QUERY_IS_RETURN                                        (1 << 10)
+/* whether to use outer join */
+#define QUERY_MERGE_USE_OUTERJOIN              (1 << 11)
+
+#define        QueryCanSetTag(query)                   ((query)->flags & 
QUERY_CAN_SET_TAG)
+#define        QueryHasAggs(query)                             ((query)->flags 
& QUERY_HAS_AGGS)
+#define        QueryHasWindowFuncs(query)              ((query)->flags & 
QUERY_HAS_WINDOW_FUNCS)
+#define        QueryHasTargetSRFs(query)               ((query)->flags & 
QUERY_HAS_TARGET_SRFS)
+#define        QueryHasSubLinks(query)                 ((query)->flags & 
QUERY_HAS_SUB_LINKS)
+#define        QueryHasDistinctOn(query)               ((query)->flags & 
QUERY_HAS_DISTINCT_ON)
+#define        QueryHasRecursive(query)                ((query)->flags & 
QUERY_HAS_RECURSIVE)
+#define        QueryHasModifyingCTE(query)             ((query)->flags & 
QUERY_HAS_MODIFYING_CTE)
+#define        QueryHasForUpdate(query)                ((query)->flags & 
QUERY_HAS_FOR_UPDATE)
+#define        QueryHasRowSecurity(query)              ((query)->flags & 
QUERY_HAS_ROW_SECURITY)
+#define        QueryIsReturn(query)                    ((query)->flags & 
QUERY_IS_RETURN)
+#define        QueryMergeUseOuterJoin(query)   ((query)->flags & 
QUERY_MERGE_USE_OUTERJOIN)
+
+#define        QueryFlagSet(flags, fname)              ((flags) |= 
(QUERY_##fname))
+#define        QuerySetFlag(query, fname)              
QueryFlagSet((query)->flags, fname)
+
+#define        QueryFlagIsSet(flags, fname)    ((flags) & (QUERY_##fname))
+
+#define        QueryFlagClear(flags, fname)    ((flags) &= ~(QUERY_##fname))
+#define        QueryClearFlag(query, fname)    QueryFlagClear((query)->flags, 
fname)
+
+#define        QueryCondSetFlag(query, cond, pname) \
+       { \
+               if (cond) \
+                       QuerySetFlag(query, pname); \
+               else \
+                       QueryClearFlag(query, pname); \
+       }
+
 
 /****************************************************************************
  *     Supporting data structures for Parse Trees
diff --git a/src/include/rewrite/rewriteManip.h 
b/src/include/rewrite/rewriteManip.h
index ac6d2049e8..d04443ef97 100644
--- a/src/include/rewrite/rewriteManip.h
+++ b/src/include/rewrite/rewriteManip.h
@@ -76,7 +76,7 @@ extern Node *replace_rte_variables(Node *node,
                                                                   int 
target_varno, int sublevels_up,
                                                                   
replace_rte_variables_callback callback,
                                                                   void 
*callback_arg,
-                                                                  bool 
*outer_hasSubLinks);
+                                                                  int 
*outer_flags);
 extern Node *replace_rte_variables_mutator(Node *node,
                                                                                
   replace_rte_variables_context *context);
 
@@ -91,6 +91,6 @@ extern Node *ReplaceVarsFromTargetList(Node *node,
                                                                           List 
*targetlist,
                                                                           
ReplaceVarsNoMatchOption nomatch_option,
                                                                           int 
nomatch_varno,
-                                                                          bool 
*outer_hasSubLinks);
+                                                                          int 
*outer_flags);
 
 #endif                                                 /* REWRITEMANIP_H */
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 6d1691340c..e7f3652863 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -8020,10 +8020,10 @@ exec_simple_check_plan(PLpgSQL_execstate *estate, 
PLpgSQL_expr *expr)
         * inlining a SQL function; otherwise, inlining could change our
         * conclusion about whether an expression is simple, which we don't 
want.)
         */
-       if (query->hasAggs ||
-               query->hasWindowFuncs ||
-               query->hasTargetSRFs ||
-               query->hasSubLinks ||
+       if (QueryHasAggs(query) ||
+               QueryHasWindowFuncs(query) ||
+               QueryHasTargetSRFs(query) ||
+               QueryHasSubLinks(query) ||
                query->cteList ||
                query->jointree->fromlist ||
                query->jointree->quals ||

Reply via email to