vitess.io/vitess@v0.16.2/go/vt/vtgate/engine/join_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 TestJoinExecute(t *testing.T) {
    32  	leftPrim := &fakePrimitive{
    33  		results: []*sqltypes.Result{
    34  			sqltypes.MakeTestResult(
    35  				sqltypes.MakeTestFields(
    36  					"col1|col2|col3",
    37  					"int64|varchar|varchar",
    38  				),
    39  				"1|a|aa",
    40  				"2|b|bb",
    41  				"3|c|cc",
    42  			),
    43  		},
    44  	}
    45  	rightFields := sqltypes.MakeTestFields(
    46  		"col4|col5|col6",
    47  		"int64|varchar|varchar",
    48  	)
    49  	rightPrim := &fakePrimitive{
    50  		results: []*sqltypes.Result{
    51  			sqltypes.MakeTestResult(
    52  				rightFields,
    53  				"4|d|dd",
    54  			),
    55  			sqltypes.MakeTestResult(
    56  				rightFields,
    57  			),
    58  			sqltypes.MakeTestResult(
    59  				rightFields,
    60  				"5|e|ee",
    61  				"6|f|ff",
    62  				"7|g|gg",
    63  			),
    64  		},
    65  	}
    66  	bv := map[string]*querypb.BindVariable{
    67  		"a": sqltypes.Int64BindVariable(10),
    68  	}
    69  
    70  	// Normal join
    71  	jn := &Join{
    72  		Opcode: InnerJoin,
    73  		Left:   leftPrim,
    74  		Right:  rightPrim,
    75  		Cols:   []int{-1, -2, 1, 2},
    76  		Vars: map[string]int{
    77  			"bv": 1,
    78  		},
    79  	}
    80  	r, err := jn.TryExecute(context.Background(), &noopVCursor{}, bv, true)
    81  	if err != nil {
    82  		t.Fatal(err)
    83  	}
    84  	leftPrim.ExpectLog(t, []string{
    85  		`Execute a: type:INT64 value:"10" true`,
    86  	})
    87  	rightPrim.ExpectLog(t, []string{
    88  		`Execute a: type:INT64 value:"10" bv: type:VARCHAR value:"a" true`,
    89  		`Execute a: type:INT64 value:"10" bv: type:VARCHAR value:"b" false`,
    90  		`Execute a: type:INT64 value:"10" bv: type:VARCHAR value:"c" false`,
    91  	})
    92  	expectResult(t, "jn.Execute", r, sqltypes.MakeTestResult(
    93  		sqltypes.MakeTestFields(
    94  			"col1|col2|col4|col5",
    95  			"int64|varchar|int64|varchar",
    96  		),
    97  		"1|a|4|d",
    98  		"3|c|5|e",
    99  		"3|c|6|f",
   100  		"3|c|7|g",
   101  	))
   102  
   103  	// Left Join
   104  	leftPrim.rewind()
   105  	rightPrim.rewind()
   106  	jn.Opcode = LeftJoin
   107  	r, err = jn.TryExecute(context.Background(), &noopVCursor{}, bv, true)
   108  	if err != nil {
   109  		t.Fatal(err)
   110  	}
   111  	leftPrim.ExpectLog(t, []string{
   112  		`Execute a: type:INT64 value:"10" true`,
   113  	})
   114  	rightPrim.ExpectLog(t, []string{
   115  		`Execute a: type:INT64 value:"10" bv: type:VARCHAR value:"a" true`,
   116  		`Execute a: type:INT64 value:"10" bv: type:VARCHAR value:"b" false`,
   117  		`Execute a: type:INT64 value:"10" bv: type:VARCHAR value:"c" false`,
   118  	})
   119  	expectResult(t, "jn.Execute", r, sqltypes.MakeTestResult(
   120  		sqltypes.MakeTestFields(
   121  			"col1|col2|col4|col5",
   122  			"int64|varchar|int64|varchar",
   123  		),
   124  		"1|a|4|d",
   125  		"2|b|null|null",
   126  		"3|c|5|e",
   127  		"3|c|6|f",
   128  		"3|c|7|g",
   129  	))
   130  }
   131  
   132  func TestJoinExecuteMaxMemoryRows(t *testing.T) {
   133  	saveMax := testMaxMemoryRows
   134  	saveIgnore := testIgnoreMaxMemoryRows
   135  	testMaxMemoryRows = 3
   136  	defer func() {
   137  		testMaxMemoryRows = saveMax
   138  		testIgnoreMaxMemoryRows = saveIgnore
   139  	}()
   140  
   141  	testCases := []struct {
   142  		ignoreMaxMemoryRows bool
   143  		err                 string
   144  	}{
   145  		{true, ""},
   146  		{false, "in-memory row count exceeded allowed limit of 3"},
   147  	}
   148  	for _, test := range testCases {
   149  		leftPrim := &fakePrimitive{
   150  			results: []*sqltypes.Result{
   151  				sqltypes.MakeTestResult(
   152  					sqltypes.MakeTestFields(
   153  						"col1|col2|col3",
   154  						"int64|varchar|varchar",
   155  					),
   156  					"1|a|aa",
   157  					"2|b|bb",
   158  					"3|c|cc",
   159  				),
   160  			},
   161  		}
   162  		rightFields := sqltypes.MakeTestFields(
   163  			"col4|col5|col6",
   164  			"int64|varchar|varchar",
   165  		)
   166  		rightPrim := &fakePrimitive{
   167  			results: []*sqltypes.Result{
   168  				sqltypes.MakeTestResult(
   169  					rightFields,
   170  					"4|d|dd",
   171  				),
   172  				sqltypes.MakeTestResult(
   173  					rightFields,
   174  				),
   175  				sqltypes.MakeTestResult(
   176  					rightFields,
   177  					"5|e|ee",
   178  					"6|f|ff",
   179  					"7|g|gg",
   180  				),
   181  			},
   182  		}
   183  		bv := map[string]*querypb.BindVariable{
   184  			"a": sqltypes.Int64BindVariable(10),
   185  		}
   186  
   187  		// Normal join
   188  		jn := &Join{
   189  			Opcode: InnerJoin,
   190  			Left:   leftPrim,
   191  			Right:  rightPrim,
   192  			Cols:   []int{-1, -2, 1, 2},
   193  			Vars: map[string]int{
   194  				"bv": 1,
   195  			},
   196  		}
   197  		testIgnoreMaxMemoryRows = test.ignoreMaxMemoryRows
   198  		_, err := jn.TryExecute(context.Background(), &noopVCursor{}, bv, true)
   199  		if testIgnoreMaxMemoryRows {
   200  			require.NoError(t, err)
   201  		} else {
   202  			require.EqualError(t, err, test.err)
   203  		}
   204  	}
   205  }
   206  
   207  func TestJoinExecuteNoResult(t *testing.T) {
   208  	leftPrim := &fakePrimitive{
   209  		results: []*sqltypes.Result{
   210  			sqltypes.MakeTestResult(
   211  				sqltypes.MakeTestFields(
   212  					"col1|col2|col3",
   213  					"int64|varchar|varchar",
   214  				),
   215  			),
   216  		},
   217  	}
   218  	rightFields := sqltypes.MakeTestFields(
   219  		"col4|col5|col6",
   220  		"int64|varchar|varchar",
   221  	)
   222  	rightPrim := &fakePrimitive{
   223  		results: []*sqltypes.Result{
   224  			sqltypes.MakeTestResult(
   225  				rightFields,
   226  			),
   227  		},
   228  	}
   229  
   230  	jn := &Join{
   231  		Opcode: InnerJoin,
   232  		Left:   leftPrim,
   233  		Right:  rightPrim,
   234  		Cols:   []int{-1, -2, 1, 2},
   235  		Vars: map[string]int{
   236  			"bv": 1,
   237  		},
   238  	}
   239  	r, err := jn.TryExecute(context.Background(), &noopVCursor{}, map[string]*querypb.BindVariable{}, true)
   240  	if err != nil {
   241  		t.Fatal(err)
   242  	}
   243  	leftPrim.ExpectLog(t, []string{
   244  		`Execute  true`,
   245  	})
   246  	rightPrim.ExpectLog(t, []string{
   247  		`GetFields bv: `,
   248  		`Execute bv:  true`,
   249  	})
   250  	wantResult := sqltypes.MakeTestResult(
   251  		sqltypes.MakeTestFields(
   252  			"col1|col2|col4|col5",
   253  			"int64|varchar|int64|varchar",
   254  		),
   255  	)
   256  	expectResult(t, "jn.Execute", r, wantResult)
   257  }
   258  
   259  func TestJoinExecuteErrors(t *testing.T) {
   260  	// Error on left query
   261  	leftPrim := &fakePrimitive{
   262  		sendErr: errors.New("left err"),
   263  	}
   264  
   265  	jn := &Join{
   266  		Opcode: InnerJoin,
   267  		Left:   leftPrim,
   268  	}
   269  	_, err := jn.TryExecute(context.Background(), &noopVCursor{}, map[string]*querypb.BindVariable{}, true)
   270  	require.EqualError(t, err, "left err")
   271  
   272  	// Error on right query
   273  	leftPrim = &fakePrimitive{
   274  		results: []*sqltypes.Result{
   275  			sqltypes.MakeTestResult(
   276  				sqltypes.MakeTestFields(
   277  					"col1|col2|col3",
   278  					"int64|varchar|varchar",
   279  				),
   280  				"1|a|aa",
   281  				"2|b|bb",
   282  				"3|c|cc",
   283  			),
   284  		},
   285  	}
   286  	rightPrim := &fakePrimitive{
   287  		sendErr: errors.New("right err"),
   288  	}
   289  
   290  	jn = &Join{
   291  		Opcode: InnerJoin,
   292  		Left:   leftPrim,
   293  		Right:  rightPrim,
   294  		Cols:   []int{-1, -2, 1, 2},
   295  		Vars: map[string]int{
   296  			"bv": 1,
   297  		},
   298  	}
   299  	_, err = jn.TryExecute(context.Background(), &noopVCursor{}, map[string]*querypb.BindVariable{}, true)
   300  	require.EqualError(t, err, "right err")
   301  
   302  	// Error on right getfields
   303  	leftPrim = &fakePrimitive{
   304  		results: []*sqltypes.Result{
   305  			sqltypes.MakeTestResult(
   306  				sqltypes.MakeTestFields(
   307  					"col1|col2|col3",
   308  					"int64|varchar|varchar",
   309  				),
   310  			),
   311  		},
   312  	}
   313  	rightPrim = &fakePrimitive{
   314  		sendErr: errors.New("right err"),
   315  	}
   316  
   317  	jn = &Join{
   318  		Opcode: InnerJoin,
   319  		Left:   leftPrim,
   320  		Right:  rightPrim,
   321  		Cols:   []int{-1, -2, 1, 2},
   322  		Vars: map[string]int{
   323  			"bv": 1,
   324  		},
   325  	}
   326  	_, err = jn.TryExecute(context.Background(), &noopVCursor{}, map[string]*querypb.BindVariable{}, true)
   327  	require.EqualError(t, err, "right err")
   328  }
   329  
   330  func TestJoinStreamExecute(t *testing.T) {
   331  	leftPrim := &fakePrimitive{
   332  		results: []*sqltypes.Result{
   333  			sqltypes.MakeTestResult(
   334  				sqltypes.MakeTestFields(
   335  					"col1|col2|col3",
   336  					"int64|varchar|varchar",
   337  				),
   338  				"1|a|aa",
   339  				"2|b|bb",
   340  				"3|c|cc",
   341  			),
   342  		},
   343  	}
   344  	rightFields := sqltypes.MakeTestFields(
   345  		"col4|col5|col6",
   346  		"int64|varchar|varchar",
   347  	)
   348  	rightPrim := &fakePrimitive{
   349  		results: []*sqltypes.Result{
   350  			// First right query will always be a GetFields.
   351  			sqltypes.MakeTestResult(
   352  				rightFields,
   353  			),
   354  			sqltypes.MakeTestResult(
   355  				rightFields,
   356  				"4|d|dd",
   357  			),
   358  			sqltypes.MakeTestResult(
   359  				rightFields,
   360  			),
   361  			sqltypes.MakeTestResult(
   362  				rightFields,
   363  				"5|e|ee",
   364  				"6|f|ff",
   365  				"7|g|gg",
   366  			),
   367  		},
   368  	}
   369  
   370  	// Normal join
   371  	jn := &Join{
   372  		Opcode: InnerJoin,
   373  		Left:   leftPrim,
   374  		Right:  rightPrim,
   375  		Cols:   []int{-1, -2, 1, 2},
   376  		Vars: map[string]int{
   377  			"bv": 1,
   378  		},
   379  	}
   380  	r, err := wrapStreamExecute(jn, &noopVCursor{}, map[string]*querypb.BindVariable{}, true)
   381  	if err != nil {
   382  		t.Fatal(err)
   383  	}
   384  	leftPrim.ExpectLog(t, []string{
   385  		`StreamExecute  true`,
   386  	})
   387  	rightPrim.ExpectLog(t, []string{
   388  		`GetFields bv: `,
   389  		`Execute bv:  true`,
   390  		`StreamExecute bv: type:VARCHAR value:"a" false`,
   391  		`StreamExecute bv: type:VARCHAR value:"b" false`,
   392  		`StreamExecute bv: type:VARCHAR value:"c" false`,
   393  	})
   394  	expectResult(t, "jn.Execute", r, sqltypes.MakeTestResult(
   395  		sqltypes.MakeTestFields(
   396  			"col1|col2|col4|col5",
   397  			"int64|varchar|int64|varchar",
   398  		),
   399  		"1|a|4|d",
   400  		"3|c|5|e",
   401  		"3|c|6|f",
   402  		"3|c|7|g",
   403  	))
   404  
   405  	// Left Join
   406  	leftPrim.rewind()
   407  	rightPrim.rewind()
   408  	jn.Opcode = LeftJoin
   409  	r, err = wrapStreamExecute(jn, &noopVCursor{}, map[string]*querypb.BindVariable{}, true)
   410  	if err != nil {
   411  		t.Fatal(err)
   412  	}
   413  	leftPrim.ExpectLog(t, []string{
   414  		`StreamExecute  true`,
   415  	})
   416  	rightPrim.ExpectLog(t, []string{
   417  		`GetFields bv: `,
   418  		`Execute bv:  true`,
   419  		`StreamExecute bv: type:VARCHAR value:"a" false`,
   420  		`StreamExecute bv: type:VARCHAR value:"b" false`,
   421  		`StreamExecute bv: type:VARCHAR value:"c" false`,
   422  	})
   423  	expectResult(t, "jn.Execute", r, sqltypes.MakeTestResult(
   424  		sqltypes.MakeTestFields(
   425  			"col1|col2|col4|col5",
   426  			"int64|varchar|int64|varchar",
   427  		),
   428  		"1|a|4|d",
   429  		"2|b|null|null",
   430  		"3|c|5|e",
   431  		"3|c|6|f",
   432  		"3|c|7|g",
   433  	))
   434  }
   435  
   436  func TestGetFields(t *testing.T) {
   437  	leftPrim := &fakePrimitive{
   438  		results: []*sqltypes.Result{
   439  			sqltypes.MakeTestResult(
   440  				sqltypes.MakeTestFields(
   441  					"col1|col2|col3",
   442  					"int64|varchar|varchar",
   443  				),
   444  			),
   445  		},
   446  	}
   447  	rightFields := sqltypes.MakeTestFields(
   448  		"col4|col5|col6",
   449  		"int64|varchar|varchar",
   450  	)
   451  	rightPrim := &fakePrimitive{
   452  		results: []*sqltypes.Result{
   453  			sqltypes.MakeTestResult(
   454  				rightFields,
   455  			),
   456  		},
   457  	}
   458  
   459  	jn := &Join{
   460  		Opcode: InnerJoin,
   461  		Left:   leftPrim,
   462  		Right:  rightPrim,
   463  		Cols:   []int{-1, -2, 1, 2},
   464  		Vars: map[string]int{
   465  			"bv": 1,
   466  		},
   467  	}
   468  	r, err := jn.GetFields(context.Background(), nil, map[string]*querypb.BindVariable{})
   469  	if err != nil {
   470  		t.Fatal(err)
   471  	}
   472  	leftPrim.ExpectLog(t, []string{
   473  		`GetFields `,
   474  		`Execute  true`,
   475  	})
   476  	rightPrim.ExpectLog(t, []string{
   477  		`GetFields bv: `,
   478  		`Execute bv:  true`,
   479  	})
   480  	expectResult(t, "jn.Execute", r, sqltypes.MakeTestResult(
   481  		sqltypes.MakeTestFields(
   482  			"col1|col2|col4|col5",
   483  			"int64|varchar|int64|varchar",
   484  		),
   485  	))
   486  }
   487  
   488  func TestGetFieldsErrors(t *testing.T) {
   489  	leftPrim := &fakePrimitive{
   490  		sendErr: errors.New("left err"),
   491  	}
   492  	rightPrim := &fakePrimitive{
   493  		sendErr: errors.New("right err"),
   494  	}
   495  
   496  	jn := &Join{
   497  		Opcode: InnerJoin,
   498  		Left:   leftPrim,
   499  		Right:  rightPrim,
   500  		Cols:   []int{-1, -2, 1, 2},
   501  		Vars: map[string]int{
   502  			"bv": 1,
   503  		},
   504  	}
   505  	_, err := jn.GetFields(context.Background(), nil, map[string]*querypb.BindVariable{})
   506  	require.EqualError(t, err, "left err")
   507  
   508  	jn.Left = &fakePrimitive{
   509  		results: []*sqltypes.Result{
   510  			sqltypes.MakeTestResult(
   511  				sqltypes.MakeTestFields(
   512  					"col1|col2|col3",
   513  					"int64|varchar|varchar",
   514  				),
   515  			),
   516  		},
   517  	}
   518  	_, err = jn.GetFields(context.Background(), nil, map[string]*querypb.BindVariable{})
   519  	require.EqualError(t, err, "right err")
   520  }