vitess.io/vitess@v0.16.2/go/vt/vtgate/planbuilder/operators/queryprojection_test.go (about) 1 /* 2 Copyright 2021 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 operators 18 19 import ( 20 "testing" 21 22 "vitess.io/vitess/go/vt/vtgate/planbuilder/plancontext" 23 "vitess.io/vitess/go/vt/vtgate/semantics" 24 25 "github.com/stretchr/testify/assert" 26 27 "github.com/stretchr/testify/require" 28 29 "vitess.io/vitess/go/vt/sqlparser" 30 ) 31 32 func TestQP(t *testing.T) { 33 tcases := []struct { 34 sql string 35 36 expErr string 37 expOrder []OrderBy 38 }{ 39 { 40 sql: "select * from user", 41 }, 42 { 43 sql: "select 1, count(1) from user", 44 }, 45 { 46 sql: "select max(id) from user", 47 }, 48 { 49 sql: "select 1, count(1) from user order by 1", 50 expOrder: []OrderBy{ 51 {Inner: &sqlparser.Order{Expr: sqlparser.NewIntLiteral("1")}, WeightStrExpr: sqlparser.NewIntLiteral("1")}, 52 }, 53 }, 54 { 55 sql: "select id from user order by col, id, 1", 56 expOrder: []OrderBy{ 57 {Inner: &sqlparser.Order{Expr: sqlparser.NewColName("col")}, WeightStrExpr: sqlparser.NewColName("col")}, 58 {Inner: &sqlparser.Order{Expr: sqlparser.NewColName("id")}, WeightStrExpr: sqlparser.NewColName("id")}, 59 {Inner: &sqlparser.Order{Expr: sqlparser.NewColName("id")}, WeightStrExpr: sqlparser.NewColName("id")}, 60 }, 61 }, 62 { 63 sql: "SELECT CONCAT(last_name,', ',first_name) AS full_name FROM mytable ORDER BY full_name", // alias in order not supported 64 expOrder: []OrderBy{ 65 { 66 Inner: &sqlparser.Order{Expr: sqlparser.NewColName("full_name")}, 67 WeightStrExpr: &sqlparser.FuncExpr{ 68 Name: sqlparser.NewIdentifierCI("CONCAT"), 69 Exprs: sqlparser.SelectExprs{ 70 &sqlparser.AliasedExpr{Expr: sqlparser.NewColName("last_name")}, 71 &sqlparser.AliasedExpr{Expr: sqlparser.NewStrLiteral(", ")}, 72 &sqlparser.AliasedExpr{Expr: sqlparser.NewColName("first_name")}, 73 }, 74 }, 75 }, 76 }, 77 }, { 78 sql: "select count(*) b from user group by b", 79 expErr: "cannot group on 'count(*)'", 80 }, 81 } 82 ctx := &plancontext.PlanningContext{SemTable: semantics.EmptySemTable()} 83 for _, tcase := range tcases { 84 t.Run(tcase.sql, func(t *testing.T) { 85 stmt, err := sqlparser.Parse(tcase.sql) 86 require.NoError(t, err) 87 88 sel := stmt.(*sqlparser.Select) 89 _, err = semantics.Analyze(sel, "", &semantics.FakeSI{}) 90 require.NoError(t, err) 91 92 qp, err := CreateQPFromSelect(ctx, sel) 93 if tcase.expErr != "" { 94 require.Error(t, err) 95 require.Contains(t, err.Error(), tcase.expErr) 96 } else { 97 require.NoError(t, err) 98 assert.Equal(t, len(sel.SelectExprs), len(qp.SelectExprs)) 99 require.Equal(t, len(tcase.expOrder), len(qp.OrderExprs), "not enough order expressions in QP") 100 for index, expOrder := range tcase.expOrder { 101 assert.True(t, sqlparser.Equals.SQLNode(expOrder.Inner, qp.OrderExprs[index].Inner), "want: %+v, got %+v", sqlparser.String(expOrder.Inner), sqlparser.String(qp.OrderExprs[index].Inner)) 102 assert.True(t, sqlparser.Equals.SQLNode(expOrder.WeightStrExpr, qp.OrderExprs[index].WeightStrExpr), "want: %v, got %v", sqlparser.String(expOrder.WeightStrExpr), sqlparser.String(qp.OrderExprs[index].WeightStrExpr)) 103 } 104 } 105 }) 106 } 107 } 108 109 func TestQPSimplifiedExpr(t *testing.T) { 110 testCases := []struct { 111 query, expected string 112 }{ 113 { 114 query: "select intcol, count(*) from user group by 1", 115 expected: ` 116 { 117 "Select": [ 118 "intcol", 119 "aggr: count(*)" 120 ], 121 "Grouping": [ 122 "intcol" 123 ], 124 "OrderBy": [], 125 "Distinct": false 126 }`, 127 }, 128 { 129 query: "select intcol, textcol from user order by 1, textcol", 130 expected: ` 131 { 132 "Select": [ 133 "intcol", 134 "textcol" 135 ], 136 "Grouping": [], 137 "OrderBy": [ 138 "intcol asc", 139 "textcol asc" 140 ], 141 "Distinct": false 142 }`, 143 }, 144 { 145 query: "select intcol, textcol, count(id) from user group by intcol, textcol, extracol order by 2 desc", 146 expected: ` 147 { 148 "Select": [ 149 "intcol", 150 "textcol", 151 "aggr: count(id)" 152 ], 153 "Grouping": [ 154 "intcol", 155 "textcol", 156 "extracol" 157 ], 158 "OrderBy": [ 159 "textcol desc" 160 ], 161 "Distinct": false 162 }`, 163 }, 164 { 165 query: "select distinct col1, col2 from user group by col1, col2", 166 expected: ` 167 { 168 "Select": [ 169 "col1", 170 "col2" 171 ], 172 "Grouping": [], 173 "OrderBy": [], 174 "Distinct": true 175 }`, 176 }, 177 { 178 query: "select distinct count(*) from user", 179 expected: ` 180 { 181 "Select": [ 182 "aggr: count(*)" 183 ], 184 "Grouping": [], 185 "OrderBy": [], 186 "Distinct": false 187 }`, 188 }, 189 } 190 191 for _, tc := range testCases { 192 t.Run(tc.query, func(t *testing.T) { 193 ast, err := sqlparser.Parse(tc.query) 194 require.NoError(t, err) 195 sel := ast.(*sqlparser.Select) 196 _, err = semantics.Analyze(sel, "", &semantics.FakeSI{}) 197 require.NoError(t, err) 198 ctx := &plancontext.PlanningContext{SemTable: semantics.EmptySemTable()} 199 qp, err := CreateQPFromSelect(ctx, sel) 200 require.NoError(t, err) 201 require.Equal(t, tc.expected[1:], qp.toString()) 202 }) 203 } 204 } 205 206 func TestCompareRefInt(t *testing.T) { 207 one := 1 208 two := 2 209 tests := []struct { 210 name string 211 a *int 212 b *int 213 want bool 214 }{ 215 { 216 name: "1<2", 217 a: &one, 218 b: &two, 219 want: true, 220 }, { 221 name: "2<1", 222 a: &two, 223 b: &one, 224 want: false, 225 }, { 226 name: "2<nil", 227 a: &two, 228 b: nil, 229 want: true, 230 }, { 231 name: "nil<1", 232 a: nil, 233 b: &one, 234 want: false, 235 }, { 236 name: "nil<nil", 237 a: nil, 238 b: nil, 239 want: false, 240 }, 241 } 242 for _, tt := range tests { 243 t.Run(tt.name, func(t *testing.T) { 244 require.Equal(t, tt.want, CompareRefInt(tt.a, tt.b)) 245 }) 246 } 247 }