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 }