github.com/dolthub/go-mysql-server@v0.18.0/sql/rowexec/insubquery_test.go (about)

     1  // Copyright 2020-2021 Dolthub, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package rowexec
    16  
    17  import (
    18  	"testing"
    19  
    20  	"github.com/dolthub/vitess/go/sqltypes"
    21  	"github.com/stretchr/testify/require"
    22  	"gopkg.in/src-d/go-errors.v1"
    23  
    24  	"github.com/dolthub/go-mysql-server/memory"
    25  	"github.com/dolthub/go-mysql-server/sql"
    26  	"github.com/dolthub/go-mysql-server/sql/expression"
    27  	"github.com/dolthub/go-mysql-server/sql/plan"
    28  	"github.com/dolthub/go-mysql-server/sql/types"
    29  )
    30  
    31  func TestInSubquery(t *testing.T) {
    32  	varChar3 := types.MustCreateString(sqltypes.VarChar, 3, sql.Collation_Default)
    33  	varChar6 := types.MustCreateString(sqltypes.VarChar, 6, sql.Collation_Default)
    34  
    35  	db := memory.NewDatabase("foo")
    36  	pro := memory.NewDBProvider(db)
    37  	ctx := newContext(pro)
    38  
    39  	table := memory.NewTable(db.BaseDatabase, "foo", sql.NewPrimaryKeySchema(sql.Schema{
    40  		{Name: "t", Source: "foo", Type: varChar3},
    41  	}), nil)
    42  
    43  	require.NoError(t, table.Insert(ctx, sql.Row{"one"}))
    44  	require.NoError(t, table.Insert(ctx, sql.Row{"two"}))
    45  
    46  	project := func(expr sql.Expression) sql.Node {
    47  		return plan.NewProject([]sql.Expression{
    48  			expr,
    49  		}, plan.NewResolvedTable(table, nil, nil))
    50  	}
    51  
    52  	testCases := []struct {
    53  		name   string
    54  		left   sql.Expression
    55  		right  sql.Node
    56  		row    sql.Row
    57  		result interface{}
    58  		err    *errors.Kind
    59  	}{
    60  		{
    61  			"left is nil",
    62  			expression.NewGetField(0, types.Text, "foo", false),
    63  			project(
    64  				expression.NewGetField(1, types.Text, "foo", false),
    65  			),
    66  			sql.NewRow(nil),
    67  			nil,
    68  			nil,
    69  		},
    70  		{
    71  			"left and right don't have the same cols",
    72  			expression.NewTuple(
    73  				expression.NewLiteral(int64(1), types.Int64),
    74  				expression.NewLiteral(int64(1), types.Int64),
    75  			),
    76  			project(
    77  				expression.NewGetField(1, types.Text, "foo", false),
    78  			),
    79  			nil,
    80  			nil,
    81  			sql.ErrInvalidOperandColumns,
    82  		},
    83  		{
    84  			"left is in right",
    85  			expression.NewGetField(0, types.Text, "foo", false),
    86  			project(
    87  				expression.NewGetField(1, types.Text, "foo", false),
    88  			),
    89  			sql.NewRow("two"),
    90  			true,
    91  			nil,
    92  		},
    93  		{
    94  			"left is not in right",
    95  			expression.NewGetField(0, types.Text, "foo", false),
    96  			project(
    97  				expression.NewGetField(1, types.Text, "foo", false),
    98  			),
    99  			sql.NewRow("four"),
   100  			false,
   101  			nil,
   102  		},
   103  		{
   104  			"big varchar successful cast to smaller varchar",
   105  			expression.NewGetField(0, varChar6, "foo", false),
   106  			project(
   107  				expression.NewGetField(1, varChar3, "foo", false),
   108  			),
   109  			sql.NewRow("one"),
   110  			true,
   111  			nil,
   112  		},
   113  		{
   114  			"big varchar unsuccessful cast to smaller varchar does not error",
   115  			expression.NewGetField(0, varChar6, "foo", false),
   116  			project(
   117  				expression.NewGetField(1, varChar3, "foo", false),
   118  			),
   119  			sql.NewRow("oneone"),
   120  			false,
   121  			nil,
   122  		},
   123  	}
   124  
   125  	for _, tt := range testCases {
   126  		t.Run(tt.name, func(t *testing.T) {
   127  			require := require.New(t)
   128  
   129  			result, err := plan.NewInSubquery(
   130  				tt.left,
   131  				plan.NewSubquery(tt.right, "").WithExecBuilder(DefaultBuilder),
   132  			).Eval(ctx, tt.row)
   133  			if tt.err != nil {
   134  				require.Error(err)
   135  				require.True(tt.err.Is(err))
   136  			} else {
   137  				require.NoError(err)
   138  				require.Equal(tt.result, result)
   139  			}
   140  		})
   141  	}
   142  }
   143  
   144  func TestNotInSubquery(t *testing.T) {
   145  	db := memory.NewDatabase("foo")
   146  	pro := memory.NewDBProvider(db)
   147  	ctx := newContext(pro)
   148  
   149  	table := memory.NewTable(db.BaseDatabase, "foo", sql.NewPrimaryKeySchema(sql.Schema{
   150  		{Name: "t", Source: "foo", Type: types.Text},
   151  	}), nil)
   152  
   153  	require.NoError(t, table.Insert(ctx, sql.Row{"one"}))
   154  	require.NoError(t, table.Insert(ctx, sql.Row{"two"}))
   155  	require.NoError(t, table.Insert(ctx, sql.Row{"three"}))
   156  
   157  	project := func(expr sql.Expression) sql.Node {
   158  		return plan.NewProject([]sql.Expression{
   159  			expr,
   160  		}, plan.NewResolvedTable(table, nil, nil))
   161  	}
   162  
   163  	testCases := []struct {
   164  		name   string
   165  		left   sql.Expression
   166  		right  sql.Node
   167  		row    sql.Row
   168  		result interface{}
   169  		err    *errors.Kind
   170  	}{
   171  		{
   172  			"left is nil",
   173  			expression.NewGetField(0, types.Text, "foo", false),
   174  			project(
   175  				expression.NewGetField(1, types.Text, "foo", false),
   176  			),
   177  			sql.NewRow(nil),
   178  			nil,
   179  			nil,
   180  		},
   181  		{
   182  			"left and right don't have the same cols",
   183  			expression.NewTuple(
   184  				expression.NewLiteral(int64(1), types.Int64),
   185  				expression.NewLiteral(int64(1), types.Int64),
   186  			),
   187  			project(
   188  				expression.NewLiteral(int64(2), types.Int64),
   189  			),
   190  			nil,
   191  			nil,
   192  			sql.ErrInvalidOperandColumns,
   193  		},
   194  		{
   195  			"left is in right",
   196  			expression.NewGetField(0, types.Text, "foo", false),
   197  			project(
   198  				expression.NewGetField(1, types.Text, "foo", false),
   199  			),
   200  			sql.NewRow("two"),
   201  			false,
   202  			nil,
   203  		},
   204  		{
   205  			"left is not in right",
   206  			expression.NewGetField(0, types.Text, "foo", false),
   207  			project(
   208  				expression.NewGetField(1, types.Text, "foo", false),
   209  			),
   210  			sql.NewRow("four"),
   211  			true,
   212  			nil,
   213  		},
   214  	}
   215  
   216  	for _, tt := range testCases {
   217  		t.Run(tt.name, func(t *testing.T) {
   218  			require := require.New(t)
   219  
   220  			result, err := plan.NewNotInSubquery(
   221  				tt.left,
   222  				plan.NewSubquery(tt.right, "").WithExecBuilder(DefaultBuilder),
   223  			).Eval(ctx, tt.row)
   224  			if tt.err != nil {
   225  				require.Error(err)
   226  				require.True(tt.err.Is(err))
   227  			} else {
   228  				require.NoError(err)
   229  				require.Equal(tt.result, result)
   230  			}
   231  		})
   232  	}
   233  }