aboutsummaryrefslogtreecommitdiff
path: root/src/include/nodes
diff options
context:
space:
mode:
authorRichard Guo <rguo@postgresql.org>2024-09-10 12:35:34 +0900
committerRichard Guo <rguo@postgresql.org>2024-09-10 12:35:34 +0900
commit247dea89f7616fdf06b7272b74abafc29e8e5860 (patch)
tree8f4f7c0acb5b9842df4517019805d7531aec1b46 /src/include/nodes
parentfba49d5293b4455b25485450baf02af42bf543d7 (diff)
downloadpostgresql-247dea89f7616fdf06b7272b74abafc29e8e5860.tar.gz
postgresql-247dea89f7616fdf06b7272b74abafc29e8e5860.zip
Introduce an RTE for the grouping step
If there are subqueries in the grouping expressions, each of these subqueries in the targetlist and HAVING clause is expanded into distinct SubPlan nodes. As a result, only one of these SubPlan nodes would be converted to reference to the grouping key column output by the Agg node; others would have to get evaluated afresh. This is not efficient, and with grouping sets this can cause wrong results issues in cases where they should go to NULL because they are from the wrong grouping set. Furthermore, during re-evaluation, these SubPlan nodes might use nulled column values from grouping sets, which is not correct. This issue is not limited to subqueries. For other types of expressions that are part of grouping items, if they are transformed into another form during preprocessing, they may fail to match lower target items. This can also lead to wrong results with grouping sets. To fix this issue, we introduce a new kind of RTE representing the output of the grouping step, with columns that are the Vars or expressions being grouped on. In the parser, we replace the grouping expressions in the targetlist and HAVING clause with Vars referencing this new RTE, so that the output of the parser directly expresses the semantic requirement that the grouping expressions be gotten from the grouping output rather than computed some other way. In the planner, we first preprocess all the columns of this new RTE and then replace any Vars in the targetlist and HAVING clause that reference this new RTE with the underlying grouping expressions, so that we will have only one instance of a SubPlan node for each subquery contained in the grouping expressions. Bump catversion because this changes the querytree produced by the parser. Thanks to Tom Lane for the idea to invent a new kind of RTE. Per reports from Geoff Winkless, Tobias Wendorff, Richard Guo from various threads. Author: Richard Guo Reviewed-by: Ashutosh Bapat, Sutou Kouhei Discussion: https://postgr.es/m/CAMbWs4_dp7e7oTwaiZeBX8+P1rXw4ThkZxh1QG81rhu9Z47VsQ@mail.gmail.com
Diffstat (limited to 'src/include/nodes')
-rw-r--r--src/include/nodes/nodeFuncs.h2
-rw-r--r--src/include/nodes/parsenodes.h9
-rw-r--r--src/include/nodes/pathnodes.h6
3 files changed, 17 insertions, 0 deletions
diff --git a/src/include/nodes/nodeFuncs.h b/src/include/nodes/nodeFuncs.h
index eaba59bed83..caefc39f6a2 100644
--- a/src/include/nodes/nodeFuncs.h
+++ b/src/include/nodes/nodeFuncs.h
@@ -31,6 +31,8 @@ struct PlanState; /* avoid including execnodes.h too */
#define QTW_DONT_COPY_QUERY 0x40 /* do not copy top Query */
#define QTW_EXAMINE_SORTGROUP 0x80 /* include SortGroupClause lists */
+#define QTW_IGNORE_GROUPEXPRS 0x100 /* GROUP expressions list */
+
/* callback function for check_functions_in_node */
typedef bool (*check_function_callback) (Oid func_id, void *context);
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 124d853e499..d6f7e795fe1 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -160,6 +160,8 @@ typedef struct Query
bool hasForUpdate pg_node_attr(query_jumble_ignore);
/* rewriter has applied some RLS policy */
bool hasRowSecurity pg_node_attr(query_jumble_ignore);
+ /* parser has added an RTE_GROUP RTE */
+ bool hasGroupRTE pg_node_attr(query_jumble_ignore);
/* is a RETURN statement */
bool isReturn pg_node_attr(query_jumble_ignore);
@@ -1023,6 +1025,7 @@ typedef enum RTEKind
RTE_RESULT, /* RTE represents an empty FROM clause; such
* RTEs are added by the planner, they're not
* present during parsing or rewriting */
+ RTE_GROUP, /* the grouping step */
} RTEKind;
typedef struct RangeTblEntry
@@ -1230,6 +1233,12 @@ typedef struct RangeTblEntry
Cardinality enrtuples pg_node_attr(query_jumble_ignore);
/*
+ * Fields valid for a GROUP RTE (else NIL):
+ */
+ /* list of grouping expressions */
+ List *groupexprs pg_node_attr(query_jumble_ignore);
+
+ /*
* Fields valid in all RTEs:
*/
/* was LATERAL specified? */
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 540d021592e..07e2415398e 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -510,6 +510,12 @@ struct PlannerInfo
bool hasRecursion;
/*
+ * The rangetable index for the RTE_GROUP RTE, or 0 if there is no
+ * RTE_GROUP RTE.
+ */
+ int group_rtindex;
+
+ /*
* Information about aggregates. Filled by preprocess_aggrefs().
*/
/* AggInfo structs */