Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions pkg/expression/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ go_library(
"//pkg/parser/opcode",
"//pkg/parser/terror",
"//pkg/parser/types",
"//pkg/planner/cascades/base",
"//pkg/sessionctx/stmtctx",
"//pkg/sessionctx/variable",
"//pkg/types",
Expand Down Expand Up @@ -212,6 +213,7 @@ go_test(
"//pkg/parser/model",
"//pkg/parser/mysql",
"//pkg/parser/terror",
"//pkg/planner/cascades/base",
"//pkg/planner/core",
"//pkg/session",
"//pkg/sessionctx/stmtctx",
Expand Down Expand Up @@ -245,6 +247,7 @@ go_test(
"@com_github_tikv_client_go_v2//oracle",
"@com_github_tikv_client_go_v2//tikv",
"@io_opencensus_go//stats/view",
"@org_uber_go_atomic//:atomic",
"@org_uber_go_goleak//:goleak",
],
)
34 changes: 34 additions & 0 deletions pkg/expression/collation.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/pingcap/tidb/pkg/parser/ast"
"github.com/pingcap/tidb/pkg/parser/charset"
"github.com/pingcap/tidb/pkg/parser/mysql"
"github.com/pingcap/tidb/pkg/planner/cascades/base"
"github.com/pingcap/tidb/pkg/types"
"github.com/pingcap/tidb/pkg/util/chunk"
"github.com/pingcap/tidb/pkg/util/collate"
Expand All @@ -28,6 +29,8 @@ import (
"go.uber.org/atomic"
)

var _ base.HashEquals = &collationInfo{}

// ExprCollation is a struct that store the collation related information.
type ExprCollation struct {
Coer Coercibility
Expand All @@ -45,6 +48,37 @@ type collationInfo struct {
collation string
}

// Hash64 implements the base.Hasher.<0th> interface.
func (c *collationInfo) Hash64(h base.Hasher) {
h.HashInt64(int64(c.coer))
h.HashBool(c.coerInit.Load())
h.HashInt(int(c.repertoire))
h.HashString(c.charset)
h.HashString(c.collation)
}

// Equals implements the base.Hasher.<1th> interface.
func (c *collationInfo) Equals(other any) bool {
// the caller should care about c is nil or not.
if other == nil {
return false
}
var c2 *collationInfo
switch x := other.(type) {
case *collationInfo:
c2 = x
case collationInfo:
c2 = &x
default:
return false
}
return c.coer == c2.coer &&
c.coerInit.Load() == c2.coerInit.Load() &&
c.repertoire == c2.repertoire &&
c.charset == c2.charset &&
c.collation == c2.collation
}

func (c *collationInfo) HasCoercibility() bool {
return c.coerInit.Load()
}
Expand Down
67 changes: 67 additions & 0 deletions pkg/expression/collation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@ import (
"github.com/pingcap/tidb/pkg/parser/ast"
"github.com/pingcap/tidb/pkg/parser/charset"
"github.com/pingcap/tidb/pkg/parser/mysql"
"github.com/pingcap/tidb/pkg/planner/cascades/base"
"github.com/pingcap/tidb/pkg/types"
"github.com/pingcap/tidb/pkg/util/chunk"
"github.com/pingcap/tidb/pkg/util/mock"
"github.com/stretchr/testify/require"
"go.uber.org/atomic"
)

func newExpression(coercibility Coercibility, repertoire Repertoire, chs, coll string) Expression {
Expand All @@ -33,6 +35,71 @@ func newExpression(coercibility Coercibility, repertoire Repertoire, chs, coll s
return constant
}

func TestCollationHashEquals(t *testing.T) {
c1 := collationInfo{
coer: 1,
coerInit: atomic.Bool{},
repertoire: 1,
charset: "aa",
collation: "bb",
}
c2 := collationInfo{
coer: 1,
coerInit: atomic.Bool{},
repertoire: 1,
charset: "aabb",
collation: "",
}
hasher1 := base.NewHashEqualer()
hasher2 := base.NewHashEqualer()
c1.Hash64(hasher1)
c2.Hash64(hasher2)
require.NotEqual(t, hasher1.Sum64(), hasher2.Sum64())
require.False(t, c1.Equals(c2))

c2.charset = "aa"
c2.collation = "bb"
hasher2.Reset()
c2.Hash64(hasher2)
require.Equal(t, hasher1.Sum64(), hasher2.Sum64())
require.True(t, c1.Equals(c2))

c2.coer = 2
hasher2.Reset()
c2.Hash64(hasher2)
require.NotEqual(t, hasher1.Sum64(), hasher2.Sum64())
require.False(t, c1.Equals(c2))

c2.coer = 1
c2.coerInit.Store(true)
hasher2.Reset()
c2.Hash64(hasher2)
require.NotEqual(t, hasher1.Sum64(), hasher2.Sum64())
require.False(t, c1.Equals(c2))

c2.coerInit.Store(false)
c2.repertoire = 2
hasher2.Reset()
c2.Hash64(hasher2)
require.NotEqual(t, hasher1.Sum64(), hasher2.Sum64())
require.False(t, c1.Equals(c2))

c2.repertoire = 1
c2.charset = ""
c2.collation = "aabb"
hasher2.Reset()
c2.Hash64(hasher2)
require.NotEqual(t, hasher1.Sum64(), hasher2.Sum64())
require.False(t, c1.Equals(c2))

c2.charset = "aa"
c2.collation = "bb"
hasher2.Reset()
c2.Hash64(hasher2)
require.Equal(t, hasher1.Sum64(), hasher2.Sum64())
require.True(t, c1.Equals(c2))
}

func TestInferCollation(t *testing.T) {
tests := []struct {
exprs []Expression
Expand Down
60 changes: 60 additions & 0 deletions pkg/expression/column.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,17 @@ import (
"github.com/pingcap/tidb/pkg/parser/charset"
"github.com/pingcap/tidb/pkg/parser/model"
"github.com/pingcap/tidb/pkg/parser/mysql"
"github.com/pingcap/tidb/pkg/planner/cascades/base"
"github.com/pingcap/tidb/pkg/types"
"github.com/pingcap/tidb/pkg/util/chunk"
"github.com/pingcap/tidb/pkg/util/codec"
"github.com/pingcap/tidb/pkg/util/size"
)

var (
_ base.HashEquals = &Column{}
)

// CorrelatedColumn stands for a column in a correlated sub query.
type CorrelatedColumn struct {
Column
Expand Down Expand Up @@ -442,6 +447,61 @@ func (col *Column) GetStaticType() *types.FieldType {
return col.RetType
}

// Hash64 implements HashEquals.<0th> interface.
func (col *Column) Hash64(h base.Hasher) {
if col.RetType == nil {
h.HashByte(base.NilFlag)
} else {
h.HashByte(base.NotNilFlag)
col.RetType.Hash64(h)
}
h.HashInt64(col.ID)
h.HashInt64(col.UniqueID)
h.HashInt(col.Index)
if col.VirtualExpr != nil {
h.HashByte(base.NilFlag)
} else {
h.HashByte(base.NotNilFlag)
//col.VirtualExpr.Hash64(h)
}
h.HashString(col.OrigName)
h.HashBool(col.IsHidden)
h.HashBool(col.IsPrefix)
h.HashBool(col.InOperand)
col.collationInfo.Hash64(h)
h.HashInt64(col.CorrelatedColUniqueID)
}

// Equals implements HashEquals.<1st> interface.
func (col *Column) Equals(other any) bool {
if other == nil {
return false
}
var col2 *Column
switch x := other.(type) {
case Column:
col2 = &x
case *Column:
col2 = x
default:
return false
}
// when step into here, we could ensure that col1.RetType and col2.RetType are same type.
// and we should ensure col1.RetType and col2.RetType is not nil ourselves.
ftEqual := col.RetType == nil && col2.RetType == nil || col.RetType != nil && col2.RetType != nil && col.RetType.Equal(col2.RetType)
return ftEqual &&
col.ID == col2.ID &&
col.UniqueID == col2.UniqueID &&
col.Index == col2.Index &&
//col.VirtualExpr.Equals(col2.VirtualExpr) &&
col.OrigName == col2.OrigName &&
col.IsHidden == col2.IsHidden &&
col.IsPrefix == col2.IsPrefix &&
col.InOperand == col2.InOperand &&
col.collationInfo.Equals(&col2.collationInfo) &&
col.CorrelatedColUniqueID == col2.CorrelatedColUniqueID
}

// Traverse implements the TraverseDown interface.
func (col *Column) Traverse(action TraverseAction) Expression {
return action.Transform(col)
Expand Down
Loading