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..2bb8bb1314 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_hasSubLinks); 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_hasSubLinks); #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 ||