Skip to content

Commit 07642a1

Browse files
committed
test(analyzer): refactor and move VALUES tests to dedicated file
Reorg VALUES bats tests to its own values.bats from types.bats. Also, inline the getFieldWithType helper func, improve error messages in transformValuesNode, and add test cases for case-sensitive quoted column names and case-differing aggregate columns. Refs: #1648
1 parent 5b72cf1 commit 07642a1

4 files changed

Lines changed: 300 additions & 270 deletions

File tree

server/analyzer/resolve_values_types.go

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,10 @@ func ResolveValuesTypes(ctx *sql.Context, a *analyzer.Analyzer, node sql.Node, s
8888
return expr, transform.SameTree, nil
8989
}
9090

91-
return getFieldWithType(gf, newType), transform.NewTree, nil
91+
return expression.NewGetFieldWithTable(
92+
gf.Index(), int(gf.TableId()), newType,
93+
gf.Database(), gf.Table(), gf.Name(), gf.IsNullable(),
94+
), transform.NewTree, nil
9295
})
9396
if err != nil {
9497
return nil, transform.SameTree, err
@@ -128,11 +131,17 @@ func ResolveValuesTypes(ctx *sql.Context, a *analyzer.Analyzer, node sql.Node, s
128131
for _, child := range n.Children() {
129132
childSchema = append(childSchema, child.Schema()...)
130133
}
131-
// Find the matching column by name and update if the type changed
132-
gfNameLower := strings.ToLower(gf.Name())
134+
// Find the matching column by name and update if the type changed.
135+
// Use case-insensitive matching here because internally generated
136+
// names (e.g., aggregate results like "sum(v.n)") may differ in
137+
// casing between the GetField and the child schema.
138+
gfName := strings.ToLower(gf.Name())
133139
for _, col := range childSchema {
134-
if strings.ToLower(col.Name) == gfNameLower && gf.Type() != col.Type {
135-
return getFieldWithType(gf, col.Type), transform.NewTree, nil
140+
if strings.ToLower(col.Name) == gfName && gf.Type() != col.Type {
141+
return expression.NewGetFieldWithTable(
142+
gf.Index(), int(gf.TableId()), col.Type,
143+
gf.Database(), gf.Table(), gf.Name(), gf.IsNullable(),
144+
), transform.NewTree, nil
136145
}
137146
}
138147
return expr, transform.SameTree, nil
@@ -145,19 +154,6 @@ func ResolveValuesTypes(ctx *sql.Context, a *analyzer.Analyzer, node sql.Node, s
145154
return node, same, nil
146155
}
147156

148-
// getFieldWithType returns a copy of the GetField with a new type.
149-
func getFieldWithType(gf *expression.GetField, newType sql.Type) *expression.GetField {
150-
return expression.NewGetFieldWithTable(
151-
gf.Index(),
152-
int(gf.TableId()),
153-
newType,
154-
gf.Database(),
155-
gf.Table(),
156-
gf.Name(),
157-
gf.IsNullable(),
158-
)
159-
}
160-
161157
// transformValuesNode transforms a plan.Values or plan.ValueDerivedTable node to use common types
162158
func transformValuesNode(n sql.Node) (sql.Node, transform.TreeIdentity, error) {
163159
var values *plan.Values
@@ -180,7 +176,7 @@ func transformValuesNode(n sql.Node) (sql.Node, transform.TreeIdentity, error) {
180176
numCols := len(values.ExpressionTuples[0])
181177
for i := 1; i < len(values.ExpressionTuples); i++ {
182178
if len(values.ExpressionTuples[i]) != numCols {
183-
return nil, transform.NewTree, errors.New("VALUES: VALUES lists must all be the same length")
179+
return nil, transform.NewTree, errors.Errorf("VALUES: row %d has %d columns, expected %d", i+1, len(values.ExpressionTuples[i]), numCols)
184180
}
185181
}
186182
if numCols == 0 {
@@ -198,7 +194,7 @@ func transformValuesNode(n sql.Node) (sql.Node, transform.TreeIdentity, error) {
198194
} else if pgType, ok := exprType.(*pgtypes.DoltgresType); ok {
199195
columnTypes[colIdx][rowIdx] = pgType
200196
} else {
201-
return nil, transform.NewTree, errors.New("VALUES: VALUES cannot use GMS types")
197+
return nil, transform.NewTree, errors.Errorf("VALUES: non-Doltgres type found in row %d, column %d: %s", rowIdx, colIdx, exprType.String())
202198
}
203199
}
204200
}

testing/bats/types.bats

Lines changed: 1 addition & 208 deletions
Original file line numberDiff line numberDiff line change
@@ -37,211 +37,4 @@ SQL
3737
[[ "$output" =~ '4,"{f,f}"' ]] || false
3838
[[ "$output" =~ '5,{t}' ]] || false
3939
[[ "$output" =~ '6,{f}' ]] || false
40-
}
41-
42-
@test 'types: VALUES clause mixed int and decimal' {
43-
# Integer first, then decimal - should resolve to numeric
44-
run query_server -t -c "SELECT * FROM (VALUES(1),(2.01),(3)) v(n);"
45-
[ "$status" -eq 0 ]
46-
[[ "$output" =~ "1" ]] || false
47-
[[ "$output" =~ "2.01" ]] || false
48-
[[ "$output" =~ "3" ]] || false
49-
}
50-
51-
@test 'types: VALUES clause decimal first then int' {
52-
# Decimal first, then integers - should resolve to numeric
53-
run query_server -t -c "SELECT * FROM (VALUES(1.01),(2),(3)) v(n);"
54-
[ "$status" -eq 0 ]
55-
[[ "$output" =~ "1.01" ]] || false
56-
[[ "$output" =~ "2" ]] || false
57-
[[ "$output" =~ "3" ]] || false
58-
}
59-
60-
@test 'types: VALUES clause SUM with mixed types' {
61-
# SUM should work directly now that VALUES has correct type
62-
run query_server -t -c "SELECT SUM(n) FROM (VALUES(1),(2.01),(3)) v(n);"
63-
[ "$status" -eq 0 ]
64-
[[ "$output" =~ "6.01" ]] || false
65-
}
66-
67-
@test 'types: VALUES clause multiple columns mixed types' {
68-
run query_server -t -c "SELECT * FROM (VALUES(1, 'a'), (2.5, 'b')) v(num, str);"
69-
[ "$status" -eq 0 ]
70-
[[ "$output" =~ "1" ]] || false
71-
[[ "$output" =~ "a" ]] || false
72-
[[ "$output" =~ "2.5" ]] || false
73-
[[ "$output" =~ "b" ]] || false
74-
}
75-
76-
@test 'types: VALUES clause SUM with explicit cast' {
77-
run query_server -t -c "SELECT SUM(n::numeric) FROM (VALUES(1),(2.01),(3)) v(n);"
78-
[ "$status" -eq 0 ]
79-
[[ "$output" =~ "6.01" ]] || false
80-
}
81-
82-
@test 'types: VALUES clause MIN and MAX with mixed types' {
83-
run query_server -t -c "SELECT MIN(n), MAX(n) FROM (VALUES(1),(2.5),(3),(0.5)) v(n);"
84-
[ "$status" -eq 0 ]
85-
[[ "$output" =~ "0.5" ]] || false
86-
[[ "$output" =~ "3" ]] || false
87-
}
88-
89-
@test 'types: VALUES clause GROUP BY with mixed types' {
90-
run query_server -t -c "SELECT n, COUNT(*) FROM (VALUES(1),(2.5),(1),(3.5),(2.5)) v(n) GROUP BY n ORDER BY n;"
91-
[ "$status" -eq 0 ]
92-
[[ "$output" =~ "1" ]] || false
93-
[[ "$output" =~ "2.5" ]] || false
94-
[[ "$output" =~ "3.5" ]] || false
95-
}
96-
97-
@test 'types: VALUES clause SUM GROUP BY with mixed types' {
98-
run query_server -t -c "SELECT category, SUM(amount) FROM (VALUES('a', 1),('b', 2.5),('a', 3),('b', 4.5)) v(category, amount) GROUP BY category ORDER BY category;"
99-
[ "$status" -eq 0 ]
100-
[[ "$output" =~ "a" ]] || false
101-
[[ "$output" =~ "4" ]] || false
102-
[[ "$output" =~ "b" ]] || false
103-
[[ "$output" =~ "7.0" ]] || false
104-
}
105-
106-
@test 'types: VALUES clause DISTINCT with mixed types' {
107-
run query_server -t -c "SELECT DISTINCT n FROM (VALUES(1),(2.5),(1),(2.5),(3)) v(n) ORDER BY n;"
108-
[ "$status" -eq 0 ]
109-
[[ "$output" =~ "1" ]] || false
110-
[[ "$output" =~ "2.5" ]] || false
111-
[[ "$output" =~ "3" ]] || false
112-
}
113-
114-
@test 'types: VALUES clause ORDER BY with mixed types' {
115-
run query_server -t -c "SELECT * FROM (VALUES(3),(1.5),(2),(4.5)) v(n) ORDER BY n;"
116-
[ "$status" -eq 0 ]
117-
[[ "$output" =~ "1.5" ]] || false
118-
[[ "$output" =~ "2" ]] || false
119-
[[ "$output" =~ "3" ]] || false
120-
[[ "$output" =~ "4.5" ]] || false
121-
}
122-
123-
@test 'types: VALUES clause ORDER BY DESC with mixed types' {
124-
run query_server -t -c "SELECT * FROM (VALUES(3),(1.5),(2),(4.5)) v(n) ORDER BY n DESC;"
125-
[ "$status" -eq 0 ]
126-
[[ "$output" =~ "4.5" ]] || false
127-
[[ "$output" =~ "3" ]] || false
128-
[[ "$output" =~ "2" ]] || false
129-
[[ "$output" =~ "1.5" ]] || false
130-
}
131-
132-
@test 'types: VALUES clause LIMIT with mixed types' {
133-
run query_server -t -c "SELECT * FROM (VALUES(1),(2.5),(3),(4.5),(5)) v(n) LIMIT 3;"
134-
[ "$status" -eq 0 ]
135-
[[ "$output" =~ "1" ]] || false
136-
[[ "$output" =~ "2.5" ]] || false
137-
[[ "$output" =~ "3" ]] || false
138-
! [[ "$output" =~ "4.5" ]] || false
139-
! [[ "$output" =~ " 5" ]] || false
140-
}
141-
142-
@test 'types: VALUES clause WHERE filter with mixed types' {
143-
run query_server -t -c "SELECT * FROM (VALUES(1),(2.5),(3),(4.5),(5)) v(n) WHERE n > 2;"
144-
[ "$status" -eq 0 ]
145-
[[ "$output" =~ "2.5" ]] || false
146-
[[ "$output" =~ "3" ]] || false
147-
[[ "$output" =~ "4.5" ]] || false
148-
[[ "$output" =~ "5" ]] || false
149-
}
150-
151-
@test 'types: VALUES clause with NULLs and mixed types' {
152-
run query_server -t -c "SELECT * FROM (VALUES(1),(NULL),(2.5)) v(n);"
153-
[ "$status" -eq 0 ]
154-
[[ "$output" =~ "1" ]] || false
155-
[[ "$output" =~ "2.5" ]] || false
156-
}
157-
158-
@test 'types: VALUES clause all same type no cast needed' {
159-
run query_server -t -c "SELECT * FROM (VALUES(1),(2),(3)) v(n);"
160-
[ "$status" -eq 0 ]
161-
[[ "$output" =~ "1" ]] || false
162-
[[ "$output" =~ "2" ]] || false
163-
[[ "$output" =~ "3" ]] || false
164-
}
165-
166-
@test 'types: VALUES clause all string literals' {
167-
run query_server -t -c "SELECT * FROM (VALUES('a'),('b'),('c')) v(n);"
168-
[ "$status" -eq 0 ]
169-
[[ "$output" =~ "a" ]] || false
170-
[[ "$output" =~ "b" ]] || false
171-
[[ "$output" =~ "c" ]] || false
172-
}
173-
174-
@test 'types: VALUES clause string concatenation' {
175-
run query_server -t -c "SELECT n || '!' FROM (VALUES('hello'),('world')) v(n);"
176-
[ "$status" -eq 0 ]
177-
[[ "$output" =~ "hello!" ]] || false
178-
[[ "$output" =~ "world!" ]] || false
179-
}
180-
181-
@test 'types: VALUES clause type mismatch bool and int errors' {
182-
run query_server -t -c "SELECT * FROM (VALUES(true),(1),(false)) v(n);"
183-
[ "$status" -ne 0 ]
184-
[[ "$output" =~ "cannot be matched" ]] || false
185-
}
186-
187-
@test 'types: VALUES clause JOIN with same types' {
188-
run query_server -t -c "SELECT a.n, b.label FROM (VALUES(1),(2),(3)) a(n) JOIN (VALUES(1, 'one'),(2, 'two'),(3, 'three')) b(id, label) ON a.n = b.id;"
189-
[ "$status" -eq 0 ]
190-
[[ "$output" =~ "1" ]] || false
191-
[[ "$output" =~ "one" ]] || false
192-
[[ "$output" =~ "2" ]] || false
193-
[[ "$output" =~ "two" ]] || false
194-
[[ "$output" =~ "3" ]] || false
195-
[[ "$output" =~ "three" ]] || false
196-
}
197-
198-
@test 'types: VALUES clause JOIN with mixed types' {
199-
run query_server -t -c "SELECT a.n, b.label FROM (VALUES(1),(2.5),(3)) a(n) JOIN (VALUES(1, 'one'),(3, 'three')) b(id, label) ON a.n = b.id;"
200-
[ "$status" -eq 0 ]
201-
[[ "$output" =~ "1" ]] || false
202-
[[ "$output" =~ "one" ]] || false
203-
[[ "$output" =~ "3" ]] || false
204-
[[ "$output" =~ "three" ]] || false
205-
}
206-
207-
@test 'types: VALUES clause CTE with mixed types' {
208-
run query_server -t -c "WITH nums AS (SELECT * FROM (VALUES(1),(2.5),(3)) v(n)) SELECT * FROM nums;"
209-
[ "$status" -eq 0 ]
210-
[[ "$output" =~ "1" ]] || false
211-
[[ "$output" =~ "2.5" ]] || false
212-
[[ "$output" =~ "3" ]] || false
213-
}
214-
215-
@test 'types: VALUES clause CTE SUM with mixed types' {
216-
run query_server -t -c "WITH nums AS (SELECT * FROM (VALUES(1),(2.5),(3)) v(n)) SELECT SUM(n) FROM nums;"
217-
[ "$status" -eq 0 ]
218-
[[ "$output" =~ "6.5" ]] || false
219-
}
220-
221-
@test 'types: VALUES clause multi-column partial cast' {
222-
# Only second column needs cast, first stays int
223-
run query_server -t -c "SELECT * FROM (VALUES(1, 10),(2, 20.5),(3, 30)) v(a, b);"
224-
[ "$status" -eq 0 ]
225-
[[ "$output" =~ "1" ]] || false
226-
[[ "$output" =~ "10" ]] || false
227-
[[ "$output" =~ "2" ]] || false
228-
[[ "$output" =~ "20.5" ]] || false
229-
[[ "$output" =~ "3" ]] || false
230-
[[ "$output" =~ "30" ]] || false
231-
}
232-
233-
@test 'types: VALUES clause combined GROUP BY ORDER BY LIMIT' {
234-
run query_server -t -c "SELECT n, COUNT(*) as cnt FROM (VALUES(1),(2.5),(1),(2.5),(3),(1)) v(n) GROUP BY n ORDER BY cnt DESC LIMIT 2;"
235-
[ "$status" -eq 0 ]
236-
[[ "$output" =~ "1" ]] || false
237-
[[ "$output" =~ "3" ]] || false
238-
[[ "$output" =~ "2.5" ]] || false
239-
[[ "$output" =~ "2" ]] || false
240-
}
241-
242-
@test 'types: VALUES clause combined WHERE ORDER BY LIMIT' {
243-
run query_server -t -c "SELECT * FROM (VALUES(1),(2.5),(3),(4.5),(5)) v(n) WHERE n > 1 ORDER BY n DESC LIMIT 2;"
244-
[ "$status" -eq 0 ]
245-
[[ "$output" =~ "5" ]] || false
246-
[[ "$output" =~ "4.5" ]] || false
247-
}
40+
}

0 commit comments

Comments
 (0)