vitess.io/vitess@v0.16.2/go/vt/vtgate/engine/pullout_subquery_test.go (about) 1 /* 2 Copyright 2019 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 engine 18 19 import ( 20 "context" 21 "errors" 22 "testing" 23 24 "github.com/stretchr/testify/require" 25 26 "vitess.io/vitess/go/sqltypes" 27 28 querypb "vitess.io/vitess/go/vt/proto/query" 29 ) 30 31 func TestPulloutSubqueryValueGood(t *testing.T) { 32 // Test one case with actual bind vars. 33 bindVars := map[string]*querypb.BindVariable{ 34 "aa": sqltypes.Int64BindVariable(1), 35 } 36 37 sqResult := sqltypes.MakeTestResult( 38 sqltypes.MakeTestFields( 39 "col1", 40 "int64", 41 ), 42 "1", 43 ) 44 sfp := &fakePrimitive{ 45 results: []*sqltypes.Result{sqResult}, 46 } 47 underlyingResult := sqltypes.MakeTestResult( 48 sqltypes.MakeTestFields( 49 "col", 50 "int64", 51 ), 52 "0", 53 ) 54 ufp := &fakePrimitive{ 55 results: []*sqltypes.Result{underlyingResult}, 56 } 57 ps := &PulloutSubquery{ 58 Opcode: PulloutValue, 59 SubqueryResult: "sq", 60 Subquery: sfp, 61 Underlying: ufp, 62 } 63 64 result, err := ps.TryExecute(context.Background(), &noopVCursor{}, bindVars, false) 65 require.NoError(t, err) 66 sfp.ExpectLog(t, []string{`Execute aa: type:INT64 value:"1" false`}) 67 ufp.ExpectLog(t, []string{`Execute aa: type:INT64 value:"1" sq: type:INT64 value:"1" false`}) 68 expectResult(t, "ps.Execute", result, underlyingResult) 69 } 70 71 func TestPulloutSubqueryValueNone(t *testing.T) { 72 sqResult := sqltypes.MakeTestResult( 73 sqltypes.MakeTestFields( 74 "col1", 75 "int64", 76 ), 77 ) 78 sfp := &fakePrimitive{ 79 results: []*sqltypes.Result{sqResult}, 80 } 81 ufp := &fakePrimitive{} 82 ps := &PulloutSubquery{ 83 Opcode: PulloutValue, 84 SubqueryResult: "sq", 85 Subquery: sfp, 86 Underlying: ufp, 87 } 88 89 if _, err := ps.TryExecute(context.Background(), &noopVCursor{}, make(map[string]*querypb.BindVariable), false); err != nil { 90 t.Error(err) 91 } 92 sfp.ExpectLog(t, []string{`Execute false`}) 93 ufp.ExpectLog(t, []string{`Execute sq: false`}) 94 } 95 96 func TestPulloutSubqueryValueBadColumns(t *testing.T) { 97 sqResult := sqltypes.MakeTestResult( 98 sqltypes.MakeTestFields( 99 "col1|col2", 100 "int64|int64", 101 ), 102 "1|1", 103 ) 104 sfp := &fakePrimitive{ 105 results: []*sqltypes.Result{sqResult}, 106 } 107 ps := &PulloutSubquery{ 108 Opcode: PulloutValue, 109 SubqueryResult: "sq", 110 Subquery: sfp, 111 } 112 113 _, err := ps.TryExecute(context.Background(), &noopVCursor{}, make(map[string]*querypb.BindVariable), false) 114 require.EqualError(t, err, "subquery returned more than one column") 115 } 116 117 func TestPulloutSubqueryValueBadRows(t *testing.T) { 118 sqResult := sqltypes.MakeTestResult( 119 sqltypes.MakeTestFields( 120 "col1", 121 "int64", 122 ), 123 "1", 124 "2", 125 ) 126 sfp := &fakePrimitive{ 127 results: []*sqltypes.Result{sqResult}, 128 } 129 ps := &PulloutSubquery{ 130 Opcode: PulloutValue, 131 SubqueryResult: "sq", 132 Subquery: sfp, 133 } 134 135 _, err := ps.TryExecute(context.Background(), &noopVCursor{}, make(map[string]*querypb.BindVariable), false) 136 require.EqualError(t, err, "subquery returned more than one row") 137 } 138 139 func TestPulloutSubqueryInNotinGood(t *testing.T) { 140 sqResult := sqltypes.MakeTestResult( 141 sqltypes.MakeTestFields( 142 "col1", 143 "int64", 144 ), 145 "1", 146 "2", 147 ) 148 sfp := &fakePrimitive{ 149 results: []*sqltypes.Result{sqResult}, 150 } 151 ufp := &fakePrimitive{} 152 ps := &PulloutSubquery{ 153 Opcode: PulloutIn, 154 SubqueryResult: "sq", 155 HasValues: "has_values", 156 Subquery: sfp, 157 Underlying: ufp, 158 } 159 160 if _, err := ps.TryExecute(context.Background(), &noopVCursor{}, make(map[string]*querypb.BindVariable), false); err != nil { 161 t.Error(err) 162 } 163 sfp.ExpectLog(t, []string{`Execute false`}) 164 ufp.ExpectLog(t, []string{`Execute has_values: type:INT64 value:"1" sq: type:TUPLE values:{type:INT64 value:"1"} values:{type:INT64 value:"2"} false`}) 165 166 // Test the NOT IN case just once even though it's common code. 167 sfp.rewind() 168 ufp.rewind() 169 ps.Opcode = PulloutNotIn 170 if _, err := ps.TryExecute(context.Background(), &noopVCursor{}, make(map[string]*querypb.BindVariable), false); err != nil { 171 t.Error(err) 172 } 173 sfp.ExpectLog(t, []string{`Execute false`}) 174 ufp.ExpectLog(t, []string{`Execute has_values: type:INT64 value:"1" sq: type:TUPLE values:{type:INT64 value:"1"} values:{type:INT64 value:"2"} false`}) 175 } 176 177 func TestPulloutSubqueryInNone(t *testing.T) { 178 sqResult := sqltypes.MakeTestResult( 179 sqltypes.MakeTestFields( 180 "col1", 181 "int64", 182 ), 183 ) 184 sfp := &fakePrimitive{ 185 results: []*sqltypes.Result{sqResult}, 186 } 187 ufp := &fakePrimitive{} 188 ps := &PulloutSubquery{ 189 Opcode: PulloutIn, 190 SubqueryResult: "sq", 191 HasValues: "has_values", 192 Subquery: sfp, 193 Underlying: ufp, 194 } 195 196 if _, err := ps.TryExecute(context.Background(), &noopVCursor{}, make(map[string]*querypb.BindVariable), false); err != nil { 197 t.Error(err) 198 } 199 sfp.ExpectLog(t, []string{`Execute false`}) 200 ufp.ExpectLog(t, []string{`Execute has_values: type:INT64 value:"0" sq: type:TUPLE values:{type:INT64 value:"0"} false`}) 201 } 202 203 func TestPulloutSubqueryInBadColumns(t *testing.T) { 204 sqResult := sqltypes.MakeTestResult( 205 sqltypes.MakeTestFields( 206 "col1|col2", 207 "int64|int64", 208 ), 209 "1|1", 210 ) 211 sfp := &fakePrimitive{ 212 results: []*sqltypes.Result{sqResult}, 213 } 214 ps := &PulloutSubquery{ 215 Opcode: PulloutIn, 216 SubqueryResult: "sq", 217 Subquery: sfp, 218 } 219 220 _, err := ps.TryExecute(context.Background(), &noopVCursor{}, make(map[string]*querypb.BindVariable), false) 221 require.EqualError(t, err, "subquery returned more than one column") 222 } 223 224 func TestPulloutSubqueryExists(t *testing.T) { 225 sqResult := sqltypes.MakeTestResult( 226 sqltypes.MakeTestFields( 227 "col1", 228 "int64", 229 ), 230 "1", 231 ) 232 sfp := &fakePrimitive{ 233 results: []*sqltypes.Result{sqResult}, 234 } 235 ufp := &fakePrimitive{} 236 ps := &PulloutSubquery{ 237 Opcode: PulloutExists, 238 HasValues: "has_values", 239 Subquery: sfp, 240 Underlying: ufp, 241 } 242 243 if _, err := ps.TryExecute(context.Background(), &noopVCursor{}, make(map[string]*querypb.BindVariable), false); err != nil { 244 t.Error(err) 245 } 246 sfp.ExpectLog(t, []string{`Execute false`}) 247 ufp.ExpectLog(t, []string{`Execute has_values: type:INT64 value:"1" false`}) 248 } 249 250 func TestPulloutSubqueryExistsNone(t *testing.T) { 251 sqResult := sqltypes.MakeTestResult( 252 sqltypes.MakeTestFields( 253 "col1", 254 "int64", 255 ), 256 ) 257 sfp := &fakePrimitive{ 258 results: []*sqltypes.Result{sqResult}, 259 } 260 ufp := &fakePrimitive{} 261 ps := &PulloutSubquery{ 262 Opcode: PulloutExists, 263 HasValues: "has_values", 264 Subquery: sfp, 265 Underlying: ufp, 266 } 267 268 if _, err := ps.TryExecute(context.Background(), &noopVCursor{}, make(map[string]*querypb.BindVariable), false); err != nil { 269 t.Error(err) 270 } 271 sfp.ExpectLog(t, []string{`Execute false`}) 272 ufp.ExpectLog(t, []string{`Execute has_values: type:INT64 value:"0" false`}) 273 } 274 275 func TestPulloutSubqueryError(t *testing.T) { 276 sfp := &fakePrimitive{ 277 sendErr: errors.New("err"), 278 } 279 ps := &PulloutSubquery{ 280 Opcode: PulloutExists, 281 SubqueryResult: "sq", 282 Subquery: sfp, 283 } 284 285 _, err := ps.TryExecute(context.Background(), &noopVCursor{}, make(map[string]*querypb.BindVariable), false) 286 require.EqualError(t, err, "err") 287 } 288 289 func TestPulloutSubqueryStream(t *testing.T) { 290 bindVars := map[string]*querypb.BindVariable{ 291 "aa": sqltypes.Int64BindVariable(1), 292 } 293 sqResult := sqltypes.MakeTestResult( 294 sqltypes.MakeTestFields( 295 "col1", 296 "int64", 297 ), 298 "1", 299 ) 300 sfp := &fakePrimitive{ 301 results: []*sqltypes.Result{sqResult}, 302 } 303 underlyingResult := sqltypes.MakeTestResult( 304 sqltypes.MakeTestFields( 305 "col", 306 "int64", 307 ), 308 "0", 309 ) 310 ufp := &fakePrimitive{ 311 results: []*sqltypes.Result{underlyingResult}, 312 } 313 ps := &PulloutSubquery{ 314 Opcode: PulloutValue, 315 SubqueryResult: "sq", 316 Subquery: sfp, 317 Underlying: ufp, 318 } 319 320 result, err := wrapStreamExecute(ps, &noopVCursor{}, bindVars, true) 321 require.NoError(t, err) 322 sfp.ExpectLog(t, []string{`Execute aa: type:INT64 value:"1" false`}) 323 ufp.ExpectLog(t, []string{`StreamExecute aa: type:INT64 value:"1" sq: type:INT64 value:"1" true`}) 324 expectResult(t, "ps.StreamExecute", result, underlyingResult) 325 } 326 327 func TestPulloutSubqueryGetFields(t *testing.T) { 328 bindVars := map[string]*querypb.BindVariable{ 329 "aa": sqltypes.Int64BindVariable(1), 330 } 331 ufp := &fakePrimitive{} 332 ps := &PulloutSubquery{ 333 Opcode: PulloutValue, 334 SubqueryResult: "sq", 335 HasValues: "has_values", 336 Underlying: ufp, 337 } 338 339 if _, err := ps.GetFields(context.Background(), nil, bindVars); err != nil { 340 t.Error(err) 341 } 342 ufp.ExpectLog(t, []string{ 343 `GetFields aa: type:INT64 value:"1" sq: `, 344 `Execute aa: type:INT64 value:"1" sq: true`, 345 }) 346 347 ufp.rewind() 348 ps.Opcode = PulloutIn 349 if _, err := ps.GetFields(context.Background(), nil, bindVars); err != nil { 350 t.Error(err) 351 } 352 ufp.ExpectLog(t, []string{ 353 `GetFields aa: type:INT64 value:"1" has_values: type:INT64 value:"0" sq: type:TUPLE values:{type:INT64 value:"0"}`, 354 `Execute aa: type:INT64 value:"1" has_values: type:INT64 value:"0" sq: type:TUPLE values:{type:INT64 value:"0"} true`, 355 }) 356 357 ufp.rewind() 358 ps.Opcode = PulloutNotIn 359 if _, err := ps.GetFields(context.Background(), nil, bindVars); err != nil { 360 t.Error(err) 361 } 362 ufp.ExpectLog(t, []string{ 363 `GetFields aa: type:INT64 value:"1" has_values: type:INT64 value:"0" sq: type:TUPLE values:{type:INT64 value:"0"}`, 364 `Execute aa: type:INT64 value:"1" has_values: type:INT64 value:"0" sq: type:TUPLE values:{type:INT64 value:"0"} true`, 365 }) 366 367 ufp.rewind() 368 ps.Opcode = PulloutExists 369 if _, err := ps.GetFields(context.Background(), nil, bindVars); err != nil { 370 t.Error(err) 371 } 372 ufp.ExpectLog(t, []string{ 373 `GetFields aa: type:INT64 value:"1" has_values: type:INT64 value:"0"`, 374 `Execute aa: type:INT64 value:"1" has_values: type:INT64 value:"0" true`, 375 }) 376 }