Skip to content
This repository was archived by the owner on Jan 28, 2021. It is now read-only.

Commit e9c9ff5

Browse files
jfontanajnavarro
authored andcommitted
analyzer: fix crash with aliases used multiple times
The reorder projection rule recreates the projection with the table columns and aliases. When an alias is used more than once in a node expression, for example, a filter (a=1 or a=2) it is added twice. This caused the second time to add nil as the aliases where deleted after adding them to projections list. Now the columns are added only once. Signed-off-by: Javi Fontan <[email protected]> (cherry picked from commit 1dddaa4)
1 parent d42e83a commit e9c9ff5

File tree

2 files changed

+98
-38
lines changed

2 files changed

+98
-38
lines changed

sql/analyzer/optimization_rules.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,10 @@ func reorderProjection(ctx *sql.Context, a *Analyzer, n sql.Node) (sql.Node, err
120120
}
121121

122122
for _, col := range requiredColumns {
123-
projections = append(projections, newColumns[col])
124-
delete(newColumns, col)
123+
if c, ok := newColumns[col]; ok {
124+
projections = append(projections, c)
125+
delete(newColumns, col)
126+
}
125127
}
126128

127129
child = plan.NewProject(projections, child)

sql/analyzer/optimization_rules_test.go

Lines changed: 94 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -11,68 +11,126 @@ import (
1111
)
1212

1313
func TestReorderProjection(t *testing.T) {
14-
require := require.New(t)
1514
f := getRule("reorder_projection")
1615

1716
table := mem.NewTable("mytable", sql.Schema{{
1817
Name: "i", Source: "mytable", Type: sql.Int64,
1918
}})
2019

21-
node := plan.NewProject(
22-
[]sql.Expression{
23-
expression.NewGetFieldWithTable(0, sql.Int64, "mytable", "i", false),
24-
expression.NewAlias(expression.NewLiteral(1, sql.Int64), "foo"),
25-
expression.NewAlias(expression.NewLiteral(2, sql.Int64), "bar"),
26-
},
27-
plan.NewSort(
28-
[]plan.SortField{
29-
{Column: expression.NewUnresolvedColumn("foo")},
30-
},
31-
plan.NewFilter(
32-
expression.NewEquals(
33-
expression.NewLiteral(1, sql.Int64),
34-
expression.NewUnresolvedColumn("bar"),
20+
testCases := []struct {
21+
name string
22+
project sql.Node
23+
expected sql.Node
24+
}{
25+
{
26+
"sort",
27+
plan.NewProject(
28+
[]sql.Expression{
29+
expression.NewGetFieldWithTable(0, sql.Int64, "mytable", "i", false),
30+
expression.NewAlias(expression.NewLiteral(1, sql.Int64), "foo"),
31+
expression.NewAlias(expression.NewLiteral(2, sql.Int64), "bar"),
32+
},
33+
plan.NewSort(
34+
[]plan.SortField{
35+
{Column: expression.NewUnresolvedColumn("foo")},
36+
},
37+
plan.NewFilter(
38+
expression.NewEquals(
39+
expression.NewLiteral(1, sql.Int64),
40+
expression.NewUnresolvedColumn("bar"),
41+
),
42+
plan.NewResolvedTable(table),
43+
),
3544
),
36-
plan.NewResolvedTable(table),
3745
),
38-
),
39-
)
40-
41-
expected := plan.NewProject(
42-
[]sql.Expression{
43-
expression.NewGetFieldWithTable(0, sql.Int64, "mytable", "i", false),
44-
expression.NewGetField(2, sql.Int64, "foo", false),
45-
expression.NewGetField(1, sql.Int64, "bar", false),
46-
},
47-
plan.NewSort(
48-
[]plan.SortField{{Column: expression.NewGetField(2, sql.Int64, "foo", false)}},
4946
plan.NewProject(
5047
[]sql.Expression{
5148
expression.NewGetFieldWithTable(0, sql.Int64, "mytable", "i", false),
49+
expression.NewGetField(2, sql.Int64, "foo", false),
5250
expression.NewGetField(1, sql.Int64, "bar", false),
51+
},
52+
plan.NewSort(
53+
[]plan.SortField{{Column: expression.NewGetField(2, sql.Int64, "foo", false)}},
54+
plan.NewProject(
55+
[]sql.Expression{
56+
expression.NewGetFieldWithTable(0, sql.Int64, "mytable", "i", false),
57+
expression.NewGetField(1, sql.Int64, "bar", false),
58+
expression.NewAlias(expression.NewLiteral(1, sql.Int64), "foo"),
59+
},
60+
plan.NewFilter(
61+
expression.NewEquals(
62+
expression.NewLiteral(1, sql.Int64),
63+
expression.NewGetField(1, sql.Int64, "bar", false),
64+
),
65+
plan.NewProject(
66+
[]sql.Expression{
67+
expression.NewGetFieldWithTable(0, sql.Int64, "mytable", "i", false),
68+
expression.NewAlias(expression.NewLiteral(2, sql.Int64), "bar"),
69+
},
70+
plan.NewResolvedTable(table),
71+
),
72+
),
73+
),
74+
),
75+
),
76+
},
77+
{
78+
"use alias twice",
79+
plan.NewProject(
80+
[]sql.Expression{
5381
expression.NewAlias(expression.NewLiteral(1, sql.Int64), "foo"),
5482
},
5583
plan.NewFilter(
56-
expression.NewEquals(
57-
expression.NewLiteral(1, sql.Int64),
58-
expression.NewGetField(1, sql.Int64, "bar", false),
84+
expression.NewOr(
85+
expression.NewEquals(
86+
expression.NewLiteral(1, sql.Int64),
87+
expression.NewUnresolvedColumn("foo"),
88+
),
89+
expression.NewEquals(
90+
expression.NewLiteral(1, sql.Int64),
91+
expression.NewUnresolvedColumn("foo"),
92+
),
93+
),
94+
plan.NewResolvedTable(table),
95+
),
96+
),
97+
plan.NewProject(
98+
[]sql.Expression{
99+
expression.NewGetField(1, sql.Int64, "foo", false),
100+
},
101+
plan.NewFilter(
102+
expression.NewOr(
103+
expression.NewEquals(
104+
expression.NewLiteral(1, sql.Int64),
105+
expression.NewGetField(1, sql.Int64, "foo", false),
106+
),
107+
expression.NewEquals(
108+
expression.NewLiteral(1, sql.Int64),
109+
expression.NewGetField(1, sql.Int64, "foo", false),
110+
),
59111
),
60112
plan.NewProject(
61113
[]sql.Expression{
62114
expression.NewGetFieldWithTable(0, sql.Int64, "mytable", "i", false),
63-
expression.NewAlias(expression.NewLiteral(2, sql.Int64), "bar"),
115+
expression.NewAlias(expression.NewLiteral(1, sql.Int64), "foo"),
64116
},
65117
plan.NewResolvedTable(table),
66118
),
67119
),
68120
),
69-
),
70-
)
121+
},
122+
}
71123

72-
result, err := f.Apply(sql.NewEmptyContext(), NewDefault(nil), node)
73-
require.NoError(err)
124+
for _, tt := range testCases {
125+
t.Run(tt.name, func(t *testing.T) {
126+
require := require.New(t)
74127

75-
require.Equal(expected, result)
128+
result, err := f.Apply(sql.NewEmptyContext(), NewDefault(nil), tt.project)
129+
require.NoError(err)
130+
131+
require.Equal(tt.expected, result)
132+
})
133+
}
76134
}
77135

78136
func TestEraseProjection(t *testing.T) {

0 commit comments

Comments
 (0)