Skip to content

Commit 21df269

Browse files
Fix for simple projection showing no fields (vitessio#18489)
Signed-off-by: Dirkjan Bussink <[email protected]> Signed-off-by: Harshit Gangal <[email protected]> Co-authored-by: Harshit Gangal <[email protected]>
1 parent 4665972 commit 21df269

File tree

3 files changed

+118
-1
lines changed

3 files changed

+118
-1
lines changed
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
Copyright 2025 The Vitess Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package grpc_api
18+
19+
import (
20+
"context"
21+
"fmt"
22+
"testing"
23+
24+
"github.com/stretchr/testify/assert"
25+
"github.com/stretchr/testify/require"
26+
27+
"vitess.io/vitess/go/test/endtoend/cluster"
28+
)
29+
30+
// TestTransactionsWithGRPCAPI test the transaction queries through vtgate grpc apis.
31+
// It is done through both streaming api and non-streaming api.
32+
func TestPrepareWithGRPCAPI(t *testing.T) {
33+
ctx, cancel := context.WithCancel(context.Background())
34+
defer cancel()
35+
36+
vtgateConn, err := cluster.DialVTGate(ctx, t.Name(), vtgateGrpcAddress, "user_with_access", "test_password")
37+
require.NoError(t, err)
38+
defer vtgateConn.Close()
39+
40+
query := `SELECT DISTINCT
41+
BINARY table_info.table_name AS table_name,
42+
table_info.create_options AS create_options,
43+
table_info.table_comment AS table_comment
44+
FROM information_schema.tables AS table_info
45+
JOIN information_schema.columns AS column_info
46+
ON BINARY column_info.table_name = BINARY table_info.table_name
47+
WHERE
48+
table_info.table_schema = ?
49+
AND column_info.table_schema = ?
50+
-- Exclude views.
51+
AND table_info.table_type = 'BASE TABLE'
52+
ORDER BY BINARY table_info.table_name`
53+
54+
vtSession := vtgateConn.Session(keyspaceName, nil)
55+
fields, paramsCount, err := vtSession.Prepare(t.Context(), query)
56+
require.NoError(t, err)
57+
assert.Equal(t, `[name:"table_name" type:VARBINARY name:"create_options" type:VARCHAR name:"table_comment" type:VARCHAR]`, fmt.Sprintf("%v", fields))
58+
assert.EqualValues(t, 2, paramsCount)
59+
60+
}

go/vt/vtgate/engine/simple_projection.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,17 @@ func (sc *SimpleProjection) buildFields(inner *sqltypes.Result) []*querypb.Field
104104
if len(inner.Fields) == 0 {
105105
return nil
106106
}
107-
fields := make([]*querypb.Field, 0, len(sc.Cols))
107+
fields := make([]*querypb.Field, 0, len(sc.ColNames))
108+
if sc.namesOnly() {
109+
for idx, field := range inner.Fields {
110+
if sc.ColNames[idx] != "" {
111+
field = proto.Clone(field).(*querypb.Field)
112+
field.Name = sc.ColNames[idx]
113+
}
114+
fields = append(fields, field)
115+
}
116+
return fields
117+
}
108118
for idx, col := range sc.Cols {
109119
field := inner.Fields[col]
110120
if sc.ColNames[idx] != "" {

go/vt/vtgate/engine/simple_projection_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,3 +175,50 @@ func TestSubqueryGetFields(t *testing.T) {
175175
_, err = sq.GetFields(context.Background(), nil, bv)
176176
require.EqualError(t, err, `err`)
177177
}
178+
179+
func TestSubqueryGetFieldsNamesOnly(t *testing.T) {
180+
prim := &fakePrimitive{
181+
results: []*sqltypes.Result{
182+
sqltypes.MakeTestResult(
183+
sqltypes.MakeTestFields(
184+
"col1|col2|col3",
185+
"int64|varchar|varchar",
186+
),
187+
"1|a|aa",
188+
"2|b|bb",
189+
"3|c|cc",
190+
),
191+
},
192+
}
193+
194+
sq := &SimpleProjection{
195+
ColNames: []string{"col1alias", "", "col3alias"},
196+
Input: prim,
197+
}
198+
199+
bv := map[string]*querypb.BindVariable{
200+
"a": sqltypes.Int64BindVariable(1),
201+
}
202+
203+
r, err := sq.GetFields(context.Background(), nil, bv)
204+
if err != nil {
205+
t.Fatal(err)
206+
}
207+
prim.ExpectLog(t, []string{
208+
`GetFields a: type:INT64 value:"1"`,
209+
`Execute a: type:INT64 value:"1" true`,
210+
})
211+
expectResult(t, r, sqltypes.MakeTestResult(
212+
sqltypes.MakeTestFields(
213+
"col1alias|col2|col3alias",
214+
"int64|varchar|varchar",
215+
),
216+
))
217+
218+
// Error case.
219+
sq.Input = &fakePrimitive{
220+
sendErr: errors.New("err"),
221+
}
222+
_, err = sq.GetFields(context.Background(), nil, bv)
223+
require.EqualError(t, err, `err`)
224+
}

0 commit comments

Comments
 (0)