Skip to content

Commit fa723c3

Browse files
authored
planner, CTE, view: Fix default inline CTE which contains orderby/limit/distinct and inside of view (#56609)
close #56582, close #56603
1 parent 83c4a0f commit fa723c3

File tree

14 files changed

+307
-71
lines changed

14 files changed

+307
-71
lines changed

pkg/planner/core/casetest/flatplan/testdata/flat_plan_suite_out.json

Lines changed: 70 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -212,8 +212,8 @@
212212
{
213213
"Depth": 2,
214214
"Label": 0,
215-
"IsRoot": false,
216-
"StoreType": 0,
215+
"IsRoot": true,
216+
"StoreType": 2,
217217
"ReqType": 0,
218218
"IsPhysicalPlan": true,
219219
"TextTreeIndent": "│ │ ",
@@ -232,15 +232,80 @@
232232
{
233233
"Depth": 2,
234234
"Label": 0,
235-
"IsRoot": false,
236-
"StoreType": 0,
235+
"IsRoot": true,
236+
"StoreType": 2,
237237
"ReqType": 0,
238238
"IsPhysicalPlan": true,
239239
"TextTreeIndent": "",
240240
"IsLastChild": true
241241
}
242242
],
243-
"CTEs": null
243+
"CTEs": [
244+
[
245+
{
246+
"Depth": 0,
247+
"Label": 0,
248+
"IsRoot": true,
249+
"StoreType": 2,
250+
"ReqType": 0,
251+
"IsPhysicalPlan": true,
252+
"TextTreeIndent": "",
253+
"IsLastChild": true
254+
},
255+
{
256+
"Depth": 1,
257+
"Label": 3,
258+
"IsRoot": true,
259+
"StoreType": 2,
260+
"ReqType": 0,
261+
"IsPhysicalPlan": true,
262+
"TextTreeIndent": "",
263+
"IsLastChild": true
264+
},
265+
{
266+
"Depth": 2,
267+
"Label": 0,
268+
"IsRoot": false,
269+
"StoreType": 0,
270+
"ReqType": 0,
271+
"IsPhysicalPlan": true,
272+
"TextTreeIndent": "",
273+
"IsLastChild": true
274+
}
275+
],
276+
[
277+
{
278+
"Depth": 0,
279+
"Label": 0,
280+
"IsRoot": true,
281+
"StoreType": 2,
282+
"ReqType": 0,
283+
"IsPhysicalPlan": true,
284+
"TextTreeIndent": "",
285+
"IsLastChild": true
286+
},
287+
{
288+
"Depth": 1,
289+
"Label": 3,
290+
"IsRoot": true,
291+
"StoreType": 2,
292+
"ReqType": 0,
293+
"IsPhysicalPlan": true,
294+
"TextTreeIndent": "",
295+
"IsLastChild": true
296+
},
297+
{
298+
"Depth": 2,
299+
"Label": 0,
300+
"IsRoot": false,
301+
"StoreType": 0,
302+
"ReqType": 0,
303+
"IsPhysicalPlan": true,
304+
"TextTreeIndent": "",
305+
"IsLastChild": true
306+
}
307+
]
308+
]
244309
},
245310
{
246311
"SQL": "WITH RECURSIVE cte (n) AS( SELECT 1 UNION ALL SELECT n + 1 FROM cte WHERE n < 5)SELECT * FROM cte;",

pkg/planner/core/casetest/hint/testdata/integration_suite_out.json

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -796,18 +796,24 @@
796796
{
797797
"SQL": "explain format = 'brief' select /*+ qb_name(qb_v8, v8), merge(@qb_v8) */ * from v8;",
798798
"Plan": [
799-
"HashAgg 16000.00 root group by:Column#41, funcs:firstrow(Column#41)->Column#41",
799+
"HashAgg 16000.00 root group by:Column#21, funcs:firstrow(Column#21)->Column#21",
800800
"└─Union 1000000010000.00 root ",
801801
" ├─HashJoin 1000000000000.00 root CARTESIAN inner join",
802-
" │ ├─IndexReader(Build) 10000.00 root index:IndexFullScan",
803-
" │ │ └─IndexFullScan 10000.00 cop[tikv] table:t3, index:idx_a(a) keep order:false, stats:pseudo",
804-
" │ └─HashJoin(Probe) 100000000.00 root CARTESIAN inner join",
805-
" │ ├─IndexReader(Build) 10000.00 root index:IndexFullScan",
806-
" │ │ └─IndexFullScan 10000.00 cop[tikv] table:t2, index:idx_a(a) keep order:false, stats:pseudo",
807-
" │ └─TableReader(Probe) 10000.00 root data:TableFullScan",
808-
" │ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo",
802+
" │ ├─TableReader(Build) 10000.00 root data:TableFullScan",
803+
" │ │ └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo",
804+
" │ └─CTEFullScan(Probe) 100000000.00 root CTE:cte2 data:CTE_1",
809805
" └─TableReader 10000.00 root data:TableFullScan",
810-
" └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo"
806+
" └─TableFullScan 10000.00 cop[tikv] table:t1 keep order:false, stats:pseudo",
807+
"CTE_1 100000000.00 root Non-Recursive CTE",
808+
"└─HashJoin(Seed Part) 100000000.00 root CARTESIAN inner join",
809+
" ├─CTEFullScan(Build) 10000.00 root CTE:cte4 data:CTE_3",
810+
" └─CTEFullScan(Probe) 10000.00 root CTE:cte3 data:CTE_2",
811+
"CTE_3 10000.00 root Non-Recursive CTE",
812+
"└─IndexReader(Seed Part) 10000.00 root index:IndexFullScan",
813+
" └─IndexFullScan 10000.00 cop[tikv] table:t3, index:idx_a(a) keep order:false, stats:pseudo",
814+
"CTE_2 10000.00 root Non-Recursive CTE",
815+
"└─IndexReader(Seed Part) 10000.00 root index:IndexFullScan",
816+
" └─IndexFullScan 10000.00 cop[tikv] table:t2, index:idx_a(a) keep order:false, stats:pseudo"
811817
],
812818
"Warn": null
813819
},

pkg/planner/core/casetest/planstats/BUILD.bazel

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ go_test(
99
],
1010
data = glob(["testdata/**"]),
1111
flaky = True,
12-
shard_count = 5,
12+
shard_count = 6,
1313
deps = [
1414
"//pkg/config",
1515
"//pkg/domain",

pkg/planner/core/casetest/planstats/plan_stats_test.go

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -167,20 +167,6 @@ func TestPlanStatsLoad(t *testing.T) {
167167
require.Greater(t, countFullStats(ptr.StatsInfo().HistColl, tableInfo.Columns[2].ID), 0)
168168
},
169169
},
170-
{ // CTE
171-
sql: "with cte(x, y) as (select d + 1, b from t where c > 1) select * from cte where x < 3",
172-
check: func(p base.Plan, tableInfo *model.TableInfo) {
173-
ps, ok := p.(*plannercore.PhysicalProjection)
174-
require.True(t, ok)
175-
pc, ok := ps.Children()[0].(*plannercore.PhysicalTableReader)
176-
require.True(t, ok)
177-
pp, ok := pc.GetTablePlan().(*plannercore.PhysicalSelection)
178-
require.True(t, ok)
179-
reader, ok := pp.Children()[0].(*plannercore.PhysicalTableScan)
180-
require.True(t, ok)
181-
require.Greater(t, countFullStats(reader.StatsInfo().HistColl, tableInfo.Columns[2].ID), 0)
182-
},
183-
},
184170
{ // recursive CTE
185171
sql: "with recursive cte(x, y) as (select a, b from t where c > 1 union select x + 1, y from cte where x < 5) select * from cte",
186172
check: func(p base.Plan, tableInfo *model.TableInfo) {
@@ -225,6 +211,47 @@ func TestPlanStatsLoad(t *testing.T) {
225211
}
226212
}
227213

214+
func TestPlanStatsLoadForCTE(t *testing.T) {
215+
store, dom := testkit.CreateMockStoreAndDomain(t)
216+
217+
tk := testkit.NewTestKit(t, store)
218+
tk.MustExec("use test")
219+
tk.MustExec("drop table if exists t")
220+
tk.MustExec("set @@session.tidb_analyze_version=2")
221+
tk.MustExec("set @@session.tidb_partition_prune_mode = 'static'")
222+
tk.MustExec("set @@session.tidb_stats_load_sync_wait = 60000")
223+
tk.MustExec("set tidb_opt_projection_push_down = 0")
224+
tk.MustExec("create table t(a int, b int, c int, d int, primary key(a), key idx(b))")
225+
tk.MustExec("insert into t values (1,1,1,1),(2,2,2,2),(3,3,3,3)")
226+
tk.MustExec("create table pt(a int, b int, c int) partition by range(a) (partition p0 values less than (10), partition p1 values less than (20), partition p2 values less than maxvalue)")
227+
tk.MustExec("insert into pt values (1,1,1),(2,2,2),(13,13,13),(14,14,14),(25,25,25),(36,36,36)")
228+
229+
oriLease := dom.StatsHandle().Lease()
230+
dom.StatsHandle().SetLease(1)
231+
defer func() {
232+
dom.StatsHandle().SetLease(oriLease)
233+
}()
234+
tk.MustExec("analyze table t all columns")
235+
tk.MustExec("analyze table pt all columns")
236+
237+
var (
238+
input []string
239+
output []struct {
240+
Query string
241+
Result []string
242+
}
243+
)
244+
testData := GetPlanStatsData()
245+
testData.LoadTestCases(t, &input, &output)
246+
for i, sql := range input {
247+
testdata.OnRecord(func() {
248+
output[i].Query = input[i]
249+
output[i].Result = testdata.ConvertRowsToStrings(tk.MustQuery(sql).Rows())
250+
})
251+
tk.MustQuery(sql).Check(testkit.Rows(output[i].Result...))
252+
}
253+
}
254+
228255
func countFullStats(stats *statistics.HistColl, colID int64) int {
229256
cnt := -1
230257
stats.ForEachColumnImmutable(func(_ int64, col *statistics.Column) bool {

pkg/planner/core/casetest/planstats/testdata/plan_stats_suite_in.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,5 +70,11 @@
7070
"explain format = brief select * from t join tp where tp.a = 10 and t.b = tp.c",
7171
"explain format = brief select * from t join tp partition (p0) join t2 where t.a < 10 and t.b = tp.c and t2.a > 10 and t2.a = tp.c"
7272
]
73+
},
74+
{
75+
"name": "TestPlanStatsLoadForCTE",
76+
"cases": [
77+
"explain format= brief with cte(x, y) as (select d + 1, b from t where c > 1) select * from cte where x < 3"
78+
]
7379
}
7480
]

pkg/planner/core/casetest/planstats/testdata/plan_stats_suite_out.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,5 +143,19 @@
143143
]
144144
}
145145
]
146+
},
147+
{
148+
"Name": "TestPlanStatsLoadForCTE",
149+
"Cases": [
150+
{
151+
"Query": "explain format= brief with cte(x, y) as (select d + 1, b from t where c > 1) select * from cte where x < 3",
152+
"Result": [
153+
"Projection 1.60 root plus(test.t.d, 1)->Column#12, test.t.b",
154+
"└─TableReader 1.60 root data:Selection",
155+
" └─Selection 1.60 cop[tikv] gt(test.t.c, 1), lt(plus(test.t.d, 1), 3)",
156+
" └─TableFullScan 3.00 cop[tikv] table:t keep order:false"
157+
]
158+
}
159+
]
146160
}
147161
]

pkg/planner/core/casetest/rule/testdata/outer2inner_in.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
"select * from ((t1 left join t2 on a1=a2) left join t3 on b2=b3) join t4 on b3=b4 -- nested and propagation of null filtering",
2222
"select * from t1 right join t2 on a1=a2 where exists (select 1 from t3 where b1=b3) -- semi join is null filtering on the outer join",
2323
"select sum(l_extendedprice) / 7.0 as avg_yearly from lineitem, part where p_partkey = l_partkey and p_brand = 'Brand#44' and p_container = 'WRAP PKG' and l_quantity < ( select 0.2 * avg(l_quantity) from lineitem where l_partkey = p_partkey) -- Q17 in TPCH. null filter on derived outer join",
24-
"WITH cte AS ( SELECT alias1.col_date AS field1 FROM d AS alias1 LEFT JOIN dd AS alias2 ON alias1.col_blob_key=alias2.col_blob_key WHERE alias1.col_varchar_key IS NULL OR alias1.col_blob_key >= 'a') DELETE FROM outr1.*, outr2.* USING d AS outr1 LEFT OUTER JOIN dd AS outr2 ON (outr1.col_date=outr2.col_date) JOIN cte AS outrcte ON outr2.col_blob_key=outrcte.field1 -- nested complex case",
24+
"WITH cte AS ( SELECT alias1.col_date AS field1 FROM d AS alias1 LEFT JOIN dd AS alias2 ON alias1.col_blob_key=alias2.col_blob_key WHERE alias1.col_varchar_key IS NULL OR alias1.col_blob_key >= 'a') SELECT * FROM d AS outr1 LEFT OUTER JOIN dd AS outr2 ON (outr1.col_date=outr2.col_date) JOIN cte AS outrcte ON outr2.col_blob_key=outrcte.field1 -- nested complex case",
2525
"with cte as (select count(a2) as cnt,b2-5 as b3 from t1 left outer join t2 on a1=a2 group by b3) select * from cte where b3 > 1 -- aggregate case.",
2626
"select * from dd as outr1 WHERE outr1.col_blob IN (SELECT DISTINCT innr1.col_blob_key AS y FROM d AS innrcte left outer join dd AS innr1 ON innr1.pk = innrcte.col_date WHERE outr1.col_int_key > 6)",
2727
"select * from t0 left outer join t11 on a0=a1 where t0.b0 in (t11.b1, t11.c1) -- each = in the in list is null filtering",

pkg/planner/core/casetest/rule/testdata/outer2inner_out.json

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -279,26 +279,25 @@
279279
]
280280
},
281281
{
282-
"SQL": "WITH cte AS ( SELECT alias1.col_date AS field1 FROM d AS alias1 LEFT JOIN dd AS alias2 ON alias1.col_blob_key=alias2.col_blob_key WHERE alias1.col_varchar_key IS NULL OR alias1.col_blob_key >= 'a') DELETE FROM outr1.*, outr2.* USING d AS outr1 LEFT OUTER JOIN dd AS outr2 ON (outr1.col_date=outr2.col_date) JOIN cte AS outrcte ON outr2.col_blob_key=outrcte.field1 -- nested complex case",
283-
"Plan": [
284-
"Delete N/A root N/A",
285-
"└─Projection 6523.44 root test.d._tidb_rowid, test.dd._tidb_rowid, test.d.col_date",
286-
" └─HashJoin 6523.44 root inner join, equal:[eq(test.d.col_date, Column#41)]",
287-
" ├─HashJoin(Build) 4175.00 root left outer join, equal:[eq(test.d.col_blob_key, test.dd.col_blob_key)]",
288-
" │ ├─TableReader(Build) 3340.00 root data:Selection",
289-
" │ │ └─Selection 3340.00 cop[tikv] or(isnull(test.d.col_varchar_key), ge(test.d.col_blob_key, \"a\"))",
290-
" │ │ └─TableFullScan 10000.00 cop[tikv] table:alias1 keep order:false, stats:pseudo",
291-
" │ └─TableReader(Probe) 9990.00 root data:Selection",
292-
" │ └─Selection 9990.00 cop[tikv] not(isnull(test.dd.col_blob_key))",
293-
" │ └─TableFullScan 10000.00 cop[tikv] table:alias2 keep order:false, stats:pseudo",
294-
" └─Projection(Probe) 12487.50 root test.d._tidb_rowid, test.dd._tidb_rowid, cast(test.dd.col_blob_key, datetime(6) BINARY)->Column#41",
295-
" └─HashJoin 12487.50 root inner join, equal:[eq(test.d.col_date, test.dd.col_date)]",
296-
" ├─TableReader(Build) 9990.00 root data:Selection",
297-
" │ └─Selection 9990.00 cop[tikv] not(isnull(test.d.col_date))",
298-
" │ └─TableFullScan 10000.00 cop[tikv] table:outr1 keep order:false, stats:pseudo",
299-
" └─TableReader(Probe) 9990.00 root data:Selection",
300-
" └─Selection 9990.00 cop[tikv] not(isnull(test.dd.col_date))",
301-
" └─TableFullScan 10000.00 cop[tikv] table:outr2 keep order:false, stats:pseudo"
282+
"SQL": "WITH cte AS ( SELECT alias1.col_date AS field1 FROM d AS alias1 LEFT JOIN dd AS alias2 ON alias1.col_blob_key=alias2.col_blob_key WHERE alias1.col_varchar_key IS NULL OR alias1.col_blob_key >= 'a') SELECT * FROM d AS outr1 LEFT OUTER JOIN dd AS outr2 ON (outr1.col_date=outr2.col_date) JOIN cte AS outrcte ON outr2.col_blob_key=outrcte.field1 -- nested complex case",
283+
"Plan": [
284+
"Projection 6523.44 root test.d.pk, test.d.col_blob, test.d.col_blob_key, test.d.col_varchar_key, test.d.col_date, test.d.col_int_key, test.dd.pk, test.dd.col_blob, test.dd.col_blob_key, test.dd.col_date, test.dd.col_int_key, test.d.col_date",
285+
"└─HashJoin 6523.44 root inner join, equal:[eq(test.d.col_date, Column#41)]",
286+
" ├─HashJoin(Build) 4175.00 root left outer join, equal:[eq(test.d.col_blob_key, test.dd.col_blob_key)]",
287+
" │ ├─TableReader(Build) 3340.00 root data:Selection",
288+
" │ │ └─Selection 3340.00 cop[tikv] or(isnull(test.d.col_varchar_key), ge(test.d.col_blob_key, \"a\"))",
289+
" │ │ └─TableFullScan 10000.00 cop[tikv] table:alias1 keep order:false, stats:pseudo",
290+
" │ └─TableReader(Probe) 9990.00 root data:Selection",
291+
" │ └─Selection 9990.00 cop[tikv] not(isnull(test.dd.col_blob_key))",
292+
" │ └─TableFullScan 10000.00 cop[tikv] table:alias2 keep order:false, stats:pseudo",
293+
" └─Projection(Probe) 12487.50 root test.d.pk, test.d.col_blob, test.d.col_blob_key, test.d.col_varchar_key, test.d.col_date, test.d.col_int_key, test.dd.pk, test.dd.col_blob, test.dd.col_blob_key, test.dd.col_date, test.dd.col_int_key, cast(test.dd.col_blob_key, datetime(6) BINARY)->Column#41",
294+
" └─HashJoin 12487.50 root inner join, equal:[eq(test.d.col_date, test.dd.col_date)]",
295+
" ├─TableReader(Build) 9990.00 root data:Selection",
296+
" │ └─Selection 9990.00 cop[tikv] not(isnull(test.dd.col_date))",
297+
" │ └─TableFullScan 10000.00 cop[tikv] table:outr2 keep order:false, stats:pseudo",
298+
" └─TableReader(Probe) 9990.00 root data:Selection",
299+
" └─Selection 9990.00 cop[tikv] not(isnull(test.d.col_date))",
300+
" └─TableFullScan 10000.00 cop[tikv] table:outr1 keep order:false, stats:pseudo"
302301
]
303302
},
304303
{

pkg/planner/core/logical_plan_builder.go

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ func (b *PlanBuilder) buildAggregation(ctx context.Context, p base.LogicalPlan,
263263
}
264264
// flag it if cte contain aggregation
265265
if b.buildingCTE {
266-
b.outerCTEs[len(b.outerCTEs)-1].containAggOrWindow = true
266+
b.outerCTEs[len(b.outerCTEs)-1].containRecursiveForbiddenOperator = true
267267
}
268268
var rollupExpand *logicalop.LogicalExpand
269269
if expand, ok := p.(*logicalop.LogicalExpand); ok {
@@ -1496,6 +1496,10 @@ func (b *PlanBuilder) buildProjection(ctx context.Context, p base.LogicalPlan, f
14961496
func (b *PlanBuilder) buildDistinct(child base.LogicalPlan, length int) (*logicalop.LogicalAggregation, error) {
14971497
b.optFlag = b.optFlag | rule.FlagBuildKeyInfo
14981498
b.optFlag = b.optFlag | rule.FlagPushDownAgg
1499+
// flag it if cte contain distinct
1500+
if b.buildingCTE {
1501+
b.outerCTEs[len(b.outerCTEs)-1].containRecursiveForbiddenOperator = true
1502+
}
14991503
plan4Agg := logicalop.LogicalAggregation{
15001504
AggFuncs: make([]*aggregation.AggFuncDesc, 0, child.Schema().Len()),
15011505
GroupByItems: expression.Column2Exprs(child.Schema().Clone().Columns[:length]),
@@ -2091,6 +2095,10 @@ func extractLimitCountOffset(ctx expression.BuildContext, limit *ast.Limit) (cou
20912095

20922096
func (b *PlanBuilder) buildLimit(src base.LogicalPlan, limit *ast.Limit) (base.LogicalPlan, error) {
20932097
b.optFlag = b.optFlag | rule.FlagPushDownTopN
2098+
// flag it if cte contain limit
2099+
if b.buildingCTE {
2100+
b.outerCTEs[len(b.outerCTEs)-1].containRecursiveForbiddenOperator = true
2101+
}
20942102
var (
20952103
offset, count uint64
20962104
err error
@@ -3921,6 +3929,10 @@ func (b *PlanBuilder) buildSelect(ctx context.Context, sel *ast.SelectStmt) (p b
39213929
}
39223930

39233931
if sel.OrderBy != nil {
3932+
// flag it if cte contain order by
3933+
if b.buildingCTE {
3934+
b.outerCTEs[len(b.outerCTEs)-1].containRecursiveForbiddenOperator = true
3935+
}
39243936
// We need to keep the ORDER BY clause for the following cases:
39253937
// 1. The select is top level query, order should be honored
39263938
// 2. The query has LIMIT clause
@@ -4227,9 +4239,9 @@ func (b *PlanBuilder) tryBuildCTE(ctx context.Context, tn *ast.TableName, asName
42274239
prevSchema := cte.seedLP.Schema().Clone()
42284240
lp.SetSchema(getResultCTESchema(cte.seedLP.Schema(), b.ctx.GetSessionVars()))
42294241

4230-
// If current CTE query contain another CTE which 'containAggOrWindow' is true, current CTE 'containAggOrWindow' will be true
4242+
// If current CTE query contain another CTE which 'containRecursiveForbiddenOperator' is true, current CTE 'containRecursiveForbiddenOperator' will be true
42314243
if b.buildingCTE {
4232-
b.outerCTEs[len(b.outerCTEs)-1].containAggOrWindow = cte.containAggOrWindow || b.outerCTEs[len(b.outerCTEs)-1].containAggOrWindow
4244+
b.outerCTEs[len(b.outerCTEs)-1].containRecursiveForbiddenOperator = cte.containRecursiveForbiddenOperator || b.outerCTEs[len(b.outerCTEs)-1].containRecursiveForbiddenOperator
42334245
}
42344246
// Compute cte inline
42354247
b.computeCTEInlineFlag(cte)
@@ -4287,13 +4299,22 @@ func (b *PlanBuilder) computeCTEInlineFlag(cte *cteInfo) {
42874299
b.ctx.GetSessionVars().StmtCtx.SetHintWarning(
42884300
fmt.Sprintf("Recursive CTE %s can not be inlined by merge() or tidb_opt_force_inline_cte.", cte.def.Name))
42894301
}
4290-
} else if cte.containAggOrWindow && b.buildingRecursivePartForCTE {
4302+
cte.isInline = false
4303+
} else if cte.containRecursiveForbiddenOperator && b.buildingRecursivePartForCTE {
42914304
if cte.forceInlineByHintOrVar {
42924305
b.ctx.GetSessionVars().StmtCtx.AppendWarning(plannererrors.ErrCTERecursiveForbidsAggregation.FastGenByArgs(cte.def.Name))
42934306
}
4294-
} else if cte.consumerCount > 1 {
4307+
cte.isInline = false
4308+
} else if cte.consumerCount != 1 {
4309+
// If hint or session variable is set, it can be inlined by user.
42954310
if cte.forceInlineByHintOrVar {
42964311
cte.isInline = true
4312+
} else {
4313+
// Consumer count > 1 or = 0, CTE can not be inlined by default.
4314+
// Case the consumer count = 0 (issue #56582)
4315+
// It means that CTE maybe inside of view and the UpdateCTEConsumerCount(preprocess phase) is skipped
4316+
// So all of CTE.consumerCount is not updated, and we can not use it to determine whether CTE can be inlined.
4317+
cte.isInline = false
42974318
}
42984319
} else {
42994320
cte.isInline = true
@@ -6455,7 +6476,7 @@ func sortWindowSpecs(groupedFuncs map[*ast.WindowSpec][]*ast.WindowFuncExpr, ord
64556476

64566477
func (b *PlanBuilder) buildWindowFunctions(ctx context.Context, p base.LogicalPlan, groupedFuncs map[*ast.WindowSpec][]*ast.WindowFuncExpr, orderedSpec []*ast.WindowSpec, aggMap map[*ast.AggregateFuncExpr]int) (base.LogicalPlan, map[*ast.WindowFuncExpr]int, error) {
64576478
if b.buildingCTE {
6458-
b.outerCTEs[len(b.outerCTEs)-1].containAggOrWindow = true
6479+
b.outerCTEs[len(b.outerCTEs)-1].containRecursiveForbiddenOperator = true
64596480
}
64606481
args := make([]ast.ExprNode, 0, 4)
64616482
windowMap := make(map[*ast.WindowFuncExpr]int)

0 commit comments

Comments
 (0)