Skip to content

Commit

Permalink
projection: Return correct collation information (#15801)
Browse files Browse the repository at this point in the history
Signed-off-by: Dirkjan Bussink <[email protected]>
  • Loading branch information
dbussink authored Apr 26, 2024
1 parent 8f6cfaa commit 5fd70c4
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 5 deletions.
16 changes: 11 additions & 5 deletions go/vt/vtgate/engine/projection.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"sync"

"vitess.io/vitess/go/mysql"
"vitess.io/vitess/go/mysql/collations"
"vitess.io/vitess/go/sqltypes"
querypb "vitess.io/vitess/go/vt/proto/query"
"vitess.io/vitess/go/vt/sqlparser"
Expand Down Expand Up @@ -75,7 +76,7 @@ func (p *Projection) TryExecute(ctx context.Context, vcursor VCursor, bindVars m
resultRows = append(resultRows, resultRow)
}
if wantfields {
result.Fields, err = p.evalFields(env, result.Fields)
result.Fields, err = p.evalFields(env, result.Fields, vcursor.ConnCollation())
if err != nil {
return nil, err
}
Expand All @@ -96,7 +97,7 @@ func (p *Projection) TryStreamExecute(ctx context.Context, vcursor VCursor, bind
defer mu.Unlock()
if wantfields {
once.Do(func() {
fields, err = p.evalFields(env, qr.Fields)
fields, err = p.evalFields(env, qr.Fields, vcursor.ConnCollation())
if err != nil {
return
}
Expand Down Expand Up @@ -135,14 +136,14 @@ func (p *Projection) GetFields(ctx context.Context, vcursor VCursor, bindVars ma
return nil, err
}
env := evalengine.NewExpressionEnv(ctx, bindVars, vcursor)
qr.Fields, err = p.evalFields(env, qr.Fields)
qr.Fields, err = p.evalFields(env, qr.Fields, vcursor.ConnCollation())
if err != nil {
return nil, err
}
return qr, nil
}

func (p *Projection) evalFields(env *evalengine.ExpressionEnv, infields []*querypb.Field) ([]*querypb.Field, error) {
func (p *Projection) evalFields(env *evalengine.ExpressionEnv, infields []*querypb.Field, coll collations.ID) ([]*querypb.Field, error) {
// TODO: once the evalengine becomes smart enough, we should be able to remove the
// dependency on these fields altogether
env.Fields = infields
Expand All @@ -157,10 +158,15 @@ func (p *Projection) evalFields(env *evalengine.ExpressionEnv, infields []*query
if !sqltypes.IsNull(typ.Type()) && !typ.Nullable() {
fl |= uint32(querypb.MySqlFlag_NOT_NULL_FLAG)
}
typCol := typ.Collation()
if sqltypes.IsTextOrBinary(typ.Type()) && typCol != collations.CollationBinaryID {
typCol = coll
}

fields = append(fields, &querypb.Field{
Name: col,
Type: typ.Type(),
Charset: uint32(typ.Collation()),
Charset: uint32(typCol),
ColumnLength: uint32(typ.Size()),
Decimals: uint32(typ.Scale()),
Flags: fl,
Expand Down
38 changes: 38 additions & 0 deletions go/vt/vtgate/engine/projection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,3 +228,41 @@ func TestFields(t *testing.T) {
})
}
}

func TestFieldConversion(t *testing.T) {
var testCases = []struct {
name string
expr string
typ querypb.Type
collation collations.ID
}{
{
name: `convert different charset`,
expr: `_latin1 0xFF`,
typ: sqltypes.VarChar,
collation: collations.MySQL8().DefaultConnectionCharset(),
},
}

for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
arg, err := sqlparser.NewTestParser().ParseExpr(testCase.expr)
require.NoError(t, err)
bindExpr, err := evalengine.Translate(arg, &evalengine.Config{
Environment: vtenv.NewTestEnv(),
Collation: collations.MySQL8().DefaultConnectionCharset(),
})
require.NoError(t, err)
proj := &Projection{
Cols: []string{"col"},
Exprs: []evalengine.Expr{bindExpr},
Input: &SingleRow{},
noTxNeeded: noTxNeeded{},
}
qr, err := proj.TryExecute(context.Background(), &noopVCursor{}, nil, true)
require.NoError(t, err)
assert.Equal(t, testCase.typ, qr.Fields[0].Type)
assert.Equal(t, testCase.collation, collations.ID(qr.Fields[0].Charset))
})
}
}

0 comments on commit 5fd70c4

Please sign in to comment.