diff --git a/executor/builder.go b/executor/builder.go index 6a2953464f0c5..06b553377070f 100644 --- a/executor/builder.go +++ b/executor/builder.go @@ -5458,7 +5458,7 @@ func (b *executorBuilder) buildCTE(v *plannercore.PhysicalCTE) Executor { var corColHashCodes [][]byte for _, corCol := range corCols { - corColHashCodes = append(corColHashCodes, corCol.HashCode(b.ctx.GetSessionVars().StmtCtx)) + corColHashCodes = append(corColHashCodes, getCorColHashCode(corCol)) } producer = &cteProducer{ diff --git a/executor/cte.go b/executor/cte.go index 8fc9adef5a26f..233ee4678204b 100644 --- a/executor/cte.go +++ b/executor/cte.go @@ -661,12 +661,15 @@ func (p *cteProducer) checkHasDup(probeKey uint64, return false, nil } +func getCorColHashCode(corCol *expression.CorrelatedColumn) (res []byte) { + return codec.HashCode(res, *corCol.Data) +} + // Return true if cor col has changed. func (p *cteProducer) checkAndUpdateCorColHashCode() bool { var changed bool for i, corCol := range p.corCols { - corCol.CleanHashCode() - newHashCode := corCol.HashCode(p.ctx.GetSessionVars().StmtCtx) + newHashCode := getCorColHashCode(corCol) if !bytes.Equal(newHashCode, p.corColHashCodes[i]) { changed = true p.corColHashCodes[i] = newHashCode diff --git a/expression/column.go b/expression/column.go index 6c9ef8f667ab6..094c250855946 100644 --- a/expression/column.go +++ b/expression/column.go @@ -37,8 +37,7 @@ import ( type CorrelatedColumn struct { Column - Data *types.Datum - columnHashCode []byte + Data *types.Datum } // Clone implements Expression interface. @@ -224,30 +223,6 @@ func (col *CorrelatedColumn) RemapColumn(m map[int64]*Column) (Expression, error }, nil } -// HashCode implements Expression interface. -func (col *CorrelatedColumn) HashCode(sc *stmtctx.StatementContext) []byte { - if len(col.columnHashCode) == 0 { - col.columnHashCode = make([]byte, 0, 9) - col.columnHashCode = append(col.columnHashCode, columnFlag) - col.columnHashCode = codec.EncodeInt(col.columnHashCode, col.UniqueID) - } - - if len(col.hashcode) < len(col.columnHashCode) { - if len(col.hashcode) == 0 { - col.hashcode = make([]byte, 0, len(col.columnHashCode)) - } else { - col.hashcode = col.hashcode[:0] - } - col.hashcode = append(col.hashcode, col.columnHashCode...) - } - - // Because col.Data can be changed anytime, so always use newest Datum to calc hash code. - if col.Data != nil { - col.hashcode = codec.HashCode(col.hashcode, *col.Data) - } - return col.hashcode -} - // Column represents a column. type Column struct { RetType *types.FieldType diff --git a/expression/column_test.go b/expression/column_test.go index 66544ff7a7eed..631081a1ebd3a 100644 --- a/expression/column_test.go +++ b/expression/column_test.go @@ -15,7 +15,6 @@ package expression import ( - "bytes" "fmt" "testing" @@ -264,30 +263,3 @@ func TestGcColumnExprIsTidbShard(t *testing.T) { shardExpr := NewFunctionInternal(ctx, ast.TiDBShard, ft, col) require.True(t, GcColumnExprIsTidbShard(shardExpr)) } - -func TestCorColHashCode(t *testing.T) { - ctx := mock.NewContext() - sc := ctx.GetSessionVars().StmtCtx - col := &Column{UniqueID: 0, ID: 0, RetType: types.NewFieldType(mysql.TypeLonglong)} - - corCol := CorrelatedColumn{ - Column: *col, - } - - oriCorColHashCode := corCol.HashCode(sc) - oriColHashCode := col.HashCode(sc) - // hash code is same when Data is not set. - require.True(t, bytes.Equal(oriColHashCode, oriCorColHashCode)) - - // corCol.hashcode changes after datum changed. - d1 := types.NewDatum(1) - corCol.Data = &d1 - require.False(t, bytes.Equal(col.HashCode(sc), corCol.HashCode(sc))) - d1HashCode := corCol.HashCode(sc) - d2 := types.NewFloat64Datum(1.1) - corCol.Data = &d2 - require.False(t, bytes.Equal(d1HashCode, corCol.HashCode(sc))) - - // col.hashcode doesn't change. - require.True(t, bytes.Equal(oriColHashCode, col.HashCode(sc))) -} diff --git a/planner/core/integration_test.go b/planner/core/integration_test.go index 5e105251a4780..cbb9dc5d2ac03 100644 --- a/planner/core/integration_test.go +++ b/planner/core/integration_test.go @@ -5303,3 +5303,32 @@ func TestIssue43116(t *testing.T) { " └─TableFullScan 10000.00 cop[tikv] table:a keep order:false, stats:pseudo")) tk.MustQuery("show warnings").Check(testkit.Rows("Warning 1105 Memory capacity of 111 bytes for 'tidb_opt_range_max_size' exceeded when building ranges. Less accurate ranges such as full range are chosen")) } + +func TestIssue45033(t *testing.T) { + store := testkit.CreateMockStore(t) + tk := testkit.NewTestKit(t, store) + tk.MustExec("use test") + tk.MustExec("drop table if exists t1, t2, t3, t4;") + tk.MustExec("create table t1 (c1 int, c2 int, c3 int, primary key(c1, c2));") + tk.MustExec("create table t2 (c2 int, c1 int, primary key(c2, c1));") + tk.MustExec("create table t3 (c4 int, key(c4));") + tk.MustExec("create table t4 (c2 varchar(20) , test_col varchar(50), gen_col varchar(50) generated always as(concat(test_col,'')) virtual not null, unique key(gen_col));") + tk.MustQuery(`select count(1) + from (select ( case + when count(1) + over( + partition by a.c2) >= 50 then 1 + else 0 + end ) alias1, + b.c2 as alias_col1 + from t1 a + left join (select c2 + from t4 f) k + on k.c2 = a.c2 + inner join t2 b + on b.c1 = a.c3) alias2 + where exists (select 1 + from (select distinct alias3.c4 as c2 + from t3 alias3) alias4 + where alias4.c2 = alias2.alias_col1);`).Check(testkit.Rows("0")) +}