Skip to content

Commit 5fd70c4

Browse files
authored
projection: Return correct collation information (#15801)
Signed-off-by: Dirkjan Bussink <d.bussink@gmail.com>
1 parent 8f6cfaa commit 5fd70c4

File tree

2 files changed

+49
-5
lines changed

2 files changed

+49
-5
lines changed

go/vt/vtgate/engine/projection.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"sync"
2222

2323
"vitess.io/vitess/go/mysql"
24+
"vitess.io/vitess/go/mysql/collations"
2425
"vitess.io/vitess/go/sqltypes"
2526
querypb "vitess.io/vitess/go/vt/proto/query"
2627
"vitess.io/vitess/go/vt/sqlparser"
@@ -75,7 +76,7 @@ func (p *Projection) TryExecute(ctx context.Context, vcursor VCursor, bindVars m
7576
resultRows = append(resultRows, resultRow)
7677
}
7778
if wantfields {
78-
result.Fields, err = p.evalFields(env, result.Fields)
79+
result.Fields, err = p.evalFields(env, result.Fields, vcursor.ConnCollation())
7980
if err != nil {
8081
return nil, err
8182
}
@@ -96,7 +97,7 @@ func (p *Projection) TryStreamExecute(ctx context.Context, vcursor VCursor, bind
9697
defer mu.Unlock()
9798
if wantfields {
9899
once.Do(func() {
99-
fields, err = p.evalFields(env, qr.Fields)
100+
fields, err = p.evalFields(env, qr.Fields, vcursor.ConnCollation())
100101
if err != nil {
101102
return
102103
}
@@ -135,14 +136,14 @@ func (p *Projection) GetFields(ctx context.Context, vcursor VCursor, bindVars ma
135136
return nil, err
136137
}
137138
env := evalengine.NewExpressionEnv(ctx, bindVars, vcursor)
138-
qr.Fields, err = p.evalFields(env, qr.Fields)
139+
qr.Fields, err = p.evalFields(env, qr.Fields, vcursor.ConnCollation())
139140
if err != nil {
140141
return nil, err
141142
}
142143
return qr, nil
143144
}
144145

145-
func (p *Projection) evalFields(env *evalengine.ExpressionEnv, infields []*querypb.Field) ([]*querypb.Field, error) {
146+
func (p *Projection) evalFields(env *evalengine.ExpressionEnv, infields []*querypb.Field, coll collations.ID) ([]*querypb.Field, error) {
146147
// TODO: once the evalengine becomes smart enough, we should be able to remove the
147148
// dependency on these fields altogether
148149
env.Fields = infields
@@ -157,10 +158,15 @@ func (p *Projection) evalFields(env *evalengine.ExpressionEnv, infields []*query
157158
if !sqltypes.IsNull(typ.Type()) && !typ.Nullable() {
158159
fl |= uint32(querypb.MySqlFlag_NOT_NULL_FLAG)
159160
}
161+
typCol := typ.Collation()
162+
if sqltypes.IsTextOrBinary(typ.Type()) && typCol != collations.CollationBinaryID {
163+
typCol = coll
164+
}
165+
160166
fields = append(fields, &querypb.Field{
161167
Name: col,
162168
Type: typ.Type(),
163-
Charset: uint32(typ.Collation()),
169+
Charset: uint32(typCol),
164170
ColumnLength: uint32(typ.Size()),
165171
Decimals: uint32(typ.Scale()),
166172
Flags: fl,

go/vt/vtgate/engine/projection_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,3 +228,41 @@ func TestFields(t *testing.T) {
228228
})
229229
}
230230
}
231+
232+
func TestFieldConversion(t *testing.T) {
233+
var testCases = []struct {
234+
name string
235+
expr string
236+
typ querypb.Type
237+
collation collations.ID
238+
}{
239+
{
240+
name: `convert different charset`,
241+
expr: `_latin1 0xFF`,
242+
typ: sqltypes.VarChar,
243+
collation: collations.MySQL8().DefaultConnectionCharset(),
244+
},
245+
}
246+
247+
for _, testCase := range testCases {
248+
t.Run(testCase.name, func(t *testing.T) {
249+
arg, err := sqlparser.NewTestParser().ParseExpr(testCase.expr)
250+
require.NoError(t, err)
251+
bindExpr, err := evalengine.Translate(arg, &evalengine.Config{
252+
Environment: vtenv.NewTestEnv(),
253+
Collation: collations.MySQL8().DefaultConnectionCharset(),
254+
})
255+
require.NoError(t, err)
256+
proj := &Projection{
257+
Cols: []string{"col"},
258+
Exprs: []evalengine.Expr{bindExpr},
259+
Input: &SingleRow{},
260+
noTxNeeded: noTxNeeded{},
261+
}
262+
qr, err := proj.TryExecute(context.Background(), &noopVCursor{}, nil, true)
263+
require.NoError(t, err)
264+
assert.Equal(t, testCase.typ, qr.Fields[0].Type)
265+
assert.Equal(t, testCase.collation, collations.ID(qr.Fields[0].Charset))
266+
})
267+
}
268+
}

0 commit comments

Comments
 (0)