github.com/dolthub/go-mysql-server@v0.18.0/sql/analyzer/validation_rules_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 analyzer
    16  
    17  import (
    18  	"testing"
    19  
    20  	"github.com/stretchr/testify/require"
    21  
    22  	"github.com/dolthub/go-mysql-server/memory"
    23  	"github.com/dolthub/go-mysql-server/sql"
    24  	"github.com/dolthub/go-mysql-server/sql/analyzer/analyzererrors"
    25  	"github.com/dolthub/go-mysql-server/sql/expression"
    26  	"github.com/dolthub/go-mysql-server/sql/expression/function"
    27  	"github.com/dolthub/go-mysql-server/sql/expression/function/aggregation"
    28  	"github.com/dolthub/go-mysql-server/sql/plan"
    29  	"github.com/dolthub/go-mysql-server/sql/types"
    30  	"github.com/dolthub/go-mysql-server/sql/variables"
    31  )
    32  
    33  func TestValidateResolved(t *testing.T) {
    34  	require := require.New(t)
    35  
    36  	vr := getValidationRule(validateResolvedId)
    37  
    38  	_, _, err := vr.Apply(sql.NewEmptyContext(), nil, dummyNode{true}, nil, DefaultRuleSelector)
    39  	require.NoError(err)
    40  
    41  	_, _, err = vr.Apply(sql.NewEmptyContext(), nil, dummyNode{false}, nil, DefaultRuleSelector)
    42  	require.Error(err)
    43  }
    44  
    45  func TestValidateOrderBy(t *testing.T) {
    46  	require := require.New(t)
    47  
    48  	vr := getValidationRule(validateOrderById)
    49  
    50  	_, _, err := vr.Apply(sql.NewEmptyContext(), nil, dummyNode{true}, nil, DefaultRuleSelector)
    51  	require.NoError(err)
    52  	_, _, err = vr.Apply(sql.NewEmptyContext(), nil, dummyNode{false}, nil, DefaultRuleSelector)
    53  	require.NoError(err)
    54  
    55  	_, _, err = vr.Apply(sql.NewEmptyContext(), nil, plan.NewSort(
    56  		[]sql.SortField{{Column: aggregation.NewCount(nil), Order: sql.Descending}},
    57  		nil,
    58  	), nil, DefaultRuleSelector)
    59  	require.Error(err)
    60  }
    61  
    62  func TestValidateGroupBy(t *testing.T) {
    63  	variables.InitSystemVariables()
    64  	require := require.New(t)
    65  
    66  	vr := getValidationRule(validateGroupById)
    67  
    68  	_, _, err := vr.Apply(sql.NewEmptyContext(), nil, dummyNode{true}, nil, DefaultRuleSelector)
    69  	require.NoError(err)
    70  	_, _, err = vr.Apply(sql.NewEmptyContext(), nil, dummyNode{false}, nil, DefaultRuleSelector)
    71  	require.NoError(err)
    72  
    73  	childSchema := sql.NewPrimaryKeySchema(sql.Schema{
    74  		{Name: "col1", Type: types.Text},
    75  		{Name: "col2", Type: types.Int64},
    76  	})
    77  
    78  	db := memory.NewDatabase("db")
    79  	pro := memory.NewDBProvider(db)
    80  	ctx := newContext(pro)
    81  
    82  	child := memory.NewTable(db, "test", childSchema, nil)
    83  
    84  	rows := []sql.Row{
    85  		sql.NewRow("col1_1", int64(1111)),
    86  		sql.NewRow("col1_1", int64(2222)),
    87  		sql.NewRow("col1_2", int64(4444)),
    88  		sql.NewRow("col1_1", int64(1111)),
    89  		sql.NewRow("col1_2", int64(4444)),
    90  	}
    91  
    92  	for _, r := range rows {
    93  		require.NoError(child.Insert(ctx, r))
    94  	}
    95  
    96  	p := plan.NewGroupBy(
    97  		[]sql.Expression{
    98  			expression.NewAlias("alias", expression.NewGetField(0, types.Text, "col1", true)),
    99  			expression.NewGetField(0, types.Text, "col1", true),
   100  			aggregation.NewCount(expression.NewGetField(1, types.Int64, "col2", true)),
   101  		},
   102  		[]sql.Expression{
   103  			expression.NewGetField(0, types.Text, "col1", true),
   104  		},
   105  		plan.NewResolvedTable(child, nil, nil),
   106  	)
   107  
   108  	_, _, err = vr.Apply(sql.NewEmptyContext(), nil, p, nil, DefaultRuleSelector)
   109  	require.NoError(err)
   110  }
   111  
   112  func TestValidateGroupByErr(t *testing.T) {
   113  	require := require.New(t)
   114  	vr := getValidationRule(validateGroupById)
   115  
   116  	_, _, err := vr.Apply(sql.NewEmptyContext(), nil, dummyNode{true}, nil, DefaultRuleSelector)
   117  	require.NoError(err)
   118  	_, _, err = vr.Apply(sql.NewEmptyContext(), nil, dummyNode{false}, nil, DefaultRuleSelector)
   119  	require.NoError(err)
   120  
   121  	childSchema := sql.NewPrimaryKeySchema(sql.Schema{
   122  		{Name: "col1", Type: types.Text},
   123  		{Name: "col2", Type: types.Int64},
   124  	})
   125  
   126  	db := memory.NewDatabase("db")
   127  	pro := memory.NewDBProvider(db)
   128  	ctx := newContext(pro)
   129  
   130  	child := memory.NewTable(db, "test", childSchema, nil)
   131  
   132  	rows := []sql.Row{
   133  		sql.NewRow("col1_1", int64(1111)),
   134  		sql.NewRow("col1_1", int64(2222)),
   135  		sql.NewRow("col1_2", int64(4444)),
   136  		sql.NewRow("col1_1", int64(1111)),
   137  		sql.NewRow("col1_2", int64(4444)),
   138  	}
   139  
   140  	for _, r := range rows {
   141  		require.NoError(child.Insert(ctx, r))
   142  	}
   143  
   144  	p := plan.NewGroupBy(
   145  		[]sql.Expression{
   146  			expression.NewGetField(0, types.Text, "col1", true),
   147  			expression.NewGetField(1, types.Int64, "col2", true),
   148  		},
   149  		[]sql.Expression{
   150  			expression.NewGetField(0, types.Text, "col1", true),
   151  		},
   152  		plan.NewResolvedTable(child, nil, nil),
   153  	)
   154  
   155  	err = sql.SystemVariables.SetGlobal("sql_mode", "NO_ENGINE_SUBSTITUTION,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES")
   156  	require.NoError(err)
   157  	_, _, err = vr.Apply(ctx, nil, p, nil, DefaultRuleSelector)
   158  	require.Error(err)
   159  }
   160  
   161  func TestValidateSchemaSource(t *testing.T) {
   162  	db := memory.NewDatabase("db")
   163  	pro := memory.NewDBProvider(db)
   164  	ctx := newContext(pro)
   165  
   166  	testCases := []struct {
   167  		name string
   168  		node sql.Node
   169  		ok   bool
   170  	}{
   171  		{
   172  			"some random node",
   173  			plan.NewProject(nil, nil),
   174  			true,
   175  		},
   176  		{
   177  			"table with valid schema",
   178  			plan.NewResolvedTable(memory.NewTable(db, "mytable", sql.NewPrimaryKeySchema(sql.Schema{
   179  				{Name: "foo", Source: "mytable"},
   180  				{Name: "bar", Source: "mytable"},
   181  			}), nil), nil, nil),
   182  			true,
   183  		},
   184  		{
   185  			"table with invalid schema",
   186  			plan.NewResolvedTable(memory.NewTable(db, "mytable", sql.NewPrimaryKeySchema(sql.Schema{
   187  				{Name: "foo", Source: ""},
   188  				{Name: "bar", Source: "something"},
   189  			}), nil), nil, nil),
   190  			false,
   191  		},
   192  		{
   193  			"table alias with table",
   194  			plan.NewTableAlias("foo", plan.NewResolvedTable(memory.NewTable(db, "mytable", sql.NewPrimaryKeySchema(sql.Schema{
   195  				{Name: "foo", Source: "mytable"},
   196  			}), nil), nil, nil)),
   197  			true,
   198  		},
   199  		{
   200  			"table alias with subquery",
   201  			plan.NewTableAlias(
   202  				"foo",
   203  				plan.NewProject(
   204  					[]sql.Expression{
   205  						expression.NewGetField(0, types.Text, "bar", false),
   206  						expression.NewGetField(1, types.Int64, "baz", false),
   207  					},
   208  					nil,
   209  				),
   210  			),
   211  			true,
   212  		},
   213  	}
   214  
   215  	rule := getValidationRule(validateSchemaSourceId)
   216  	for _, tt := range testCases {
   217  		t.Run(tt.name, func(t *testing.T) {
   218  			require := require.New(t)
   219  			_, _, err := rule.Apply(ctx, nil, tt.node, nil, DefaultRuleSelector)
   220  			if tt.ok {
   221  				require.NoError(err)
   222  			} else {
   223  				require.Error(err)
   224  				require.True(analyzererrors.ErrValidationSchemaSource.Is(err))
   225  			}
   226  		})
   227  	}
   228  }
   229  
   230  func TestValidateUnionSchemasMatch(t *testing.T) {
   231  	db := memory.NewDatabase("db")
   232  	pro := memory.NewDBProvider(db)
   233  	ctx := newContext(pro)
   234  
   235  	table := plan.NewResolvedTable(memory.NewTable(db, "mytable", sql.NewPrimaryKeySchema(sql.Schema{
   236  		{Name: "foo", Source: "mytable", Type: types.Text},
   237  		{Name: "bar", Source: "mytable", Type: types.Int64},
   238  		{Name: "rab", Source: "mytable", Type: types.Text},
   239  		{Name: "zab", Source: "mytable", Type: types.Int64},
   240  		{Name: "quuz", Source: "mytable", Type: types.Boolean},
   241  	}), nil), nil, nil)
   242  	testCases := []struct {
   243  		name string
   244  		node sql.Node
   245  		ok   bool
   246  	}{
   247  		{
   248  			"some random node",
   249  			plan.NewProject(
   250  				[]sql.Expression{
   251  					expression.NewGetField(0, types.Text, "bar", false),
   252  					expression.NewGetField(1, types.Int64, "baz", false),
   253  				},
   254  				table,
   255  			),
   256  			true,
   257  		},
   258  		{
   259  			"top-level union with matching schemas",
   260  			plan.NewSetOp(
   261  				plan.UnionType,
   262  				plan.NewProject(
   263  					[]sql.Expression{
   264  						expression.NewGetField(0, types.Text, "bar", false),
   265  						expression.NewGetField(1, types.Int64, "baz", false),
   266  					},
   267  					table,
   268  				),
   269  				plan.NewProject(
   270  					[]sql.Expression{
   271  						expression.NewGetField(2, types.Text, "rab", false),
   272  						expression.NewGetField(3, types.Int64, "zab", false),
   273  					},
   274  					table,
   275  				),
   276  				false, nil, nil, nil,
   277  			),
   278  			true,
   279  		},
   280  		{
   281  			"top-level union with longer left schema",
   282  			plan.NewSetOp(
   283  				plan.UnionType,
   284  				plan.NewProject(
   285  					[]sql.Expression{
   286  						expression.NewGetField(0, types.Text, "bar", false),
   287  						expression.NewGetField(1, types.Int64, "baz", false),
   288  						expression.NewGetField(4, types.Boolean, "quuz", false),
   289  					},
   290  					table,
   291  				),
   292  				plan.NewProject(
   293  					[]sql.Expression{
   294  						expression.NewGetField(2, types.Text, "rab", false),
   295  						expression.NewGetField(3, types.Int64, "zab", false),
   296  					},
   297  					table,
   298  				),
   299  				false, nil, nil, nil,
   300  			),
   301  			false,
   302  		},
   303  		{
   304  			"top-level union with longer right schema",
   305  			plan.NewSetOp(
   306  				plan.UnionType,
   307  				plan.NewProject(
   308  					[]sql.Expression{
   309  						expression.NewGetField(0, types.Text, "bar", false),
   310  						expression.NewGetField(1, types.Int64, "baz", false),
   311  					},
   312  					table,
   313  				),
   314  				plan.NewProject(
   315  					[]sql.Expression{
   316  						expression.NewGetField(2, types.Text, "rab", false),
   317  						expression.NewGetField(3, types.Int64, "zab", false),
   318  						expression.NewGetField(4, types.Boolean, "quuz", false),
   319  					},
   320  					table,
   321  				),
   322  				false, nil, nil, nil,
   323  			),
   324  			false,
   325  		},
   326  		{
   327  			"top-level union with mismatched type in schema",
   328  			plan.NewSetOp(
   329  				plan.UnionType,
   330  				plan.NewProject(
   331  					[]sql.Expression{
   332  						expression.NewGetField(0, types.Text, "bar", false),
   333  						expression.NewGetField(1, types.Int64, "baz", false),
   334  					},
   335  					table,
   336  				),
   337  				plan.NewProject(
   338  					[]sql.Expression{
   339  						expression.NewGetField(2, types.Text, "rab", false),
   340  						expression.NewGetField(3, types.Boolean, "zab", false),
   341  					},
   342  					table,
   343  				),
   344  				false, nil, nil, nil,
   345  			),
   346  			false,
   347  		},
   348  		{
   349  			"subquery union",
   350  			plan.NewSubqueryAlias(
   351  				"aliased", "select bar, baz from mytable union select rab, zab from mytable",
   352  				plan.NewSetOp(
   353  					plan.UnionType,
   354  					plan.NewProject(
   355  						[]sql.Expression{
   356  							expression.NewGetField(0, types.Text, "bar", false),
   357  							expression.NewGetField(1, types.Int64, "baz", false),
   358  						},
   359  						table,
   360  					),
   361  					plan.NewProject(
   362  						[]sql.Expression{
   363  							expression.NewGetField(2, types.Text, "rab", false),
   364  							expression.NewGetField(3, types.Boolean, "zab", false),
   365  						},
   366  						table,
   367  					),
   368  					false, nil, nil, nil),
   369  			),
   370  			false,
   371  		},
   372  	}
   373  
   374  	rule := getValidationRule(validateUnionSchemasMatchId)
   375  	for _, tt := range testCases {
   376  		t.Run(tt.name, func(t *testing.T) {
   377  			require := require.New(t)
   378  			_, _, err := rule.Apply(ctx, nil, tt.node, nil, DefaultRuleSelector)
   379  			if tt.ok {
   380  				require.NoError(err)
   381  			} else {
   382  				require.Error(err)
   383  				require.True(analyzererrors.ErrUnionSchemasMatch.Is(err))
   384  			}
   385  		})
   386  	}
   387  }
   388  
   389  func TestValidateOperands(t *testing.T) {
   390  	testCases := []struct {
   391  		name string
   392  		node sql.Node
   393  		ok   bool
   394  	}{
   395  		{
   396  			"project with no tuple",
   397  			plan.NewProject([]sql.Expression{
   398  				expression.NewLiteral(1, types.Int64),
   399  			}, nil),
   400  			true,
   401  		},
   402  		{
   403  			"project with a 1 elem tuple",
   404  			plan.NewProject([]sql.Expression{
   405  				expression.NewTuple(
   406  					expression.NewLiteral(1, types.Int64),
   407  				),
   408  			}, nil),
   409  			true,
   410  		},
   411  		{
   412  			"project with a 2 elem tuple",
   413  			plan.NewProject([]sql.Expression{
   414  				expression.NewTuple(
   415  					expression.NewLiteral(1, types.Int64),
   416  					expression.NewLiteral(2, types.Int64),
   417  				),
   418  			}, nil),
   419  			false,
   420  		},
   421  		{
   422  			"distinct with a 2 elem tuple inside the project",
   423  			plan.NewDistinct(
   424  				plan.NewProject([]sql.Expression{
   425  					expression.NewTuple(
   426  						expression.NewLiteral(1, types.Int64),
   427  						expression.NewLiteral(2, types.Int64),
   428  					),
   429  				}, nil)),
   430  			false,
   431  		},
   432  		{
   433  			"alias with a tuple",
   434  			plan.NewProject(
   435  				[]sql.Expression{
   436  					expression.NewAlias("foo", expression.NewTuple(
   437  						expression.NewLiteral(1, types.Int64),
   438  						expression.NewLiteral(2, types.Int64),
   439  					)),
   440  				},
   441  				plan.NewUnresolvedTable("dual", ""),
   442  			),
   443  			false,
   444  		},
   445  		{
   446  			"groupby with no tuple",
   447  			plan.NewGroupBy([]sql.Expression{
   448  				expression.NewLiteral(1, types.Int64),
   449  			}, nil, nil),
   450  			true,
   451  		},
   452  		{
   453  			"groupby with a 1 elem tuple",
   454  			plan.NewGroupBy([]sql.Expression{
   455  				expression.NewTuple(
   456  					expression.NewLiteral(1, types.Int64),
   457  				),
   458  			}, nil, nil),
   459  			true,
   460  		},
   461  		{
   462  			"groupby with a 2 elem tuple",
   463  			plan.NewGroupBy([]sql.Expression{
   464  				expression.NewTuple(
   465  					expression.NewLiteral(1, types.Int64),
   466  					expression.NewLiteral(1, types.Int64),
   467  				),
   468  			}, nil, nil),
   469  			false,
   470  		},
   471  		{
   472  			"validate subquery columns",
   473  			plan.NewProject([]sql.Expression{
   474  				plan.NewSubquery(plan.NewProject(
   475  					[]sql.Expression{
   476  						lit(1),
   477  						lit(2),
   478  					},
   479  					dummyNode{true},
   480  				), "select 1, 2"),
   481  			}, dummyNode{true}),
   482  			false,
   483  		},
   484  	}
   485  
   486  	rule := getValidationRule(validateOperandsId)
   487  	for _, tt := range testCases {
   488  		t.Run(tt.name, func(t *testing.T) {
   489  			require := require.New(t)
   490  			_, _, err := rule.Apply(sql.NewEmptyContext(), nil, tt.node, nil, DefaultRuleSelector)
   491  			if tt.ok {
   492  				require.NoError(err)
   493  			} else {
   494  				require.Error(err)
   495  				require.True(sql.ErrInvalidOperandColumns.Is(err))
   496  			}
   497  		})
   498  	}
   499  }
   500  
   501  func TestValidateIndexCreation(t *testing.T) {
   502  	db := memory.NewDatabase("db")
   503  	pro := memory.NewDBProvider(db)
   504  	ctx := newContext(pro)
   505  
   506  	table := memory.NewTable(db, "foo", sql.NewPrimaryKeySchema(sql.Schema{
   507  		{Name: "a", Source: "foo"},
   508  		{Name: "b", Source: "foo"},
   509  	}), nil)
   510  
   511  	testCases := []struct {
   512  		name string
   513  		node sql.Node
   514  		ok   bool
   515  	}{
   516  		{
   517  			"columns from another table",
   518  			plan.NewCreateIndex(
   519  				"idx", plan.NewResolvedTable(table, nil, nil),
   520  				[]sql.Expression{expression.NewEquals(
   521  					expression.NewGetFieldWithTable(0, 0, types.Int64, "db", "foo", "a", false),
   522  					expression.NewGetFieldWithTable(0, 0, types.Int64, "db", "bar", "b", false),
   523  				)},
   524  				"",
   525  				make(map[string]string),
   526  			),
   527  			false,
   528  		},
   529  		{
   530  			"columns that don't exist",
   531  			plan.NewCreateIndex(
   532  				"idx", plan.NewResolvedTable(table, nil, nil),
   533  				[]sql.Expression{expression.NewEquals(
   534  					expression.NewGetFieldWithTable(0, 0, types.Int64, "db", "foo", "a", false),
   535  					expression.NewGetFieldWithTable(0, 0, types.Int64, "db", "foo", "c", false),
   536  				)},
   537  				"",
   538  				make(map[string]string),
   539  			),
   540  			false,
   541  		},
   542  		{
   543  			"columns only from table",
   544  			plan.NewCreateIndex(
   545  				"idx", plan.NewResolvedTable(table, nil, nil),
   546  				[]sql.Expression{expression.NewEquals(
   547  					expression.NewGetFieldWithTable(0, 0, types.Int64, "db", "foo", "a", false),
   548  					expression.NewGetFieldWithTable(0, 0, types.Int64, "db", "foo", "b", false),
   549  				)},
   550  				"",
   551  				make(map[string]string),
   552  			),
   553  			true,
   554  		},
   555  	}
   556  
   557  	rule := getValidationRule(validateIndexCreationId)
   558  	for _, tt := range testCases {
   559  		t.Run(tt.name, func(t *testing.T) {
   560  			require := require.New(t)
   561  			_, _, err := rule.Apply(ctx, nil, tt.node, nil, DefaultRuleSelector)
   562  			if tt.ok {
   563  				require.NoError(err)
   564  			} else {
   565  				require.Error(err)
   566  				require.True(analyzererrors.ErrUnknownIndexColumns.Is(err))
   567  			}
   568  		})
   569  	}
   570  }
   571  
   572  func mustFunc(e sql.Expression, err error) sql.Expression {
   573  	if err != nil {
   574  		panic(err)
   575  	}
   576  	return e
   577  }
   578  
   579  func TestValidateIntervalUsage(t *testing.T) {
   580  	testCases := []struct {
   581  		name string
   582  		node sql.Node
   583  		ok   bool
   584  	}{
   585  		{
   586  			"date add",
   587  			plan.NewProject(
   588  				[]sql.Expression{
   589  					mustFunc(function.NewDateAdd(
   590  						expression.NewLiteral("2018-05-01", types.LongText),
   591  						expression.NewInterval(
   592  							expression.NewLiteral(int64(1), types.Int64),
   593  							"DAY",
   594  						),
   595  					)),
   596  				},
   597  				plan.NewUnresolvedTable("dual", ""),
   598  			),
   599  			true,
   600  		},
   601  		{
   602  			"date sub",
   603  			plan.NewProject(
   604  				[]sql.Expression{
   605  					mustFunc(function.NewDateSub(
   606  						expression.NewLiteral("2018-05-01", types.LongText),
   607  						expression.NewInterval(
   608  							expression.NewLiteral(int64(1), types.Int64),
   609  							"DAY",
   610  						),
   611  					)),
   612  				},
   613  				plan.NewUnresolvedTable("dual", ""),
   614  			),
   615  			true,
   616  		},
   617  		{
   618  			"+ op",
   619  			plan.NewProject(
   620  				[]sql.Expression{
   621  					expression.NewPlus(
   622  						expression.NewLiteral("2018-05-01", types.LongText),
   623  						expression.NewInterval(
   624  							expression.NewLiteral(int64(1), types.Int64),
   625  							"DAY",
   626  						),
   627  					),
   628  				},
   629  				plan.NewUnresolvedTable("dual", ""),
   630  			),
   631  			true,
   632  		},
   633  		{
   634  			"- op",
   635  			plan.NewProject(
   636  				[]sql.Expression{
   637  					expression.NewMinus(
   638  						expression.NewLiteral("2018-05-01", types.LongText),
   639  						expression.NewInterval(
   640  							expression.NewLiteral(int64(1), types.Int64),
   641  							"DAY",
   642  						),
   643  					),
   644  				},
   645  				plan.NewUnresolvedTable("dual", ""),
   646  			),
   647  			true,
   648  		},
   649  		{
   650  			"invalid",
   651  			plan.NewProject(
   652  				[]sql.Expression{
   653  					expression.NewInterval(
   654  						expression.NewLiteral(int64(1), types.Int64),
   655  						"DAY",
   656  					),
   657  				},
   658  				plan.NewUnresolvedTable("dual", ""),
   659  			),
   660  			false,
   661  		},
   662  		{
   663  			"alias",
   664  			plan.NewProject(
   665  				[]sql.Expression{
   666  					expression.NewAlias("foo", expression.NewInterval(
   667  						expression.NewLiteral(int64(1), types.Int64),
   668  						"DAY",
   669  					)),
   670  				},
   671  				plan.NewUnresolvedTable("dual", ""),
   672  			),
   673  			false,
   674  		},
   675  	}
   676  
   677  	for _, tt := range testCases {
   678  		t.Run(tt.name, func(t *testing.T) {
   679  			require := require.New(t)
   680  
   681  			_, _, err := validateIntervalUsage(sql.NewEmptyContext(), nil, tt.node, nil, DefaultRuleSelector)
   682  			if tt.ok {
   683  				require.NoError(err)
   684  			} else {
   685  				require.Error(err)
   686  				require.True(analyzererrors.ErrIntervalInvalidUse.Is(err))
   687  			}
   688  		})
   689  	}
   690  }
   691  
   692  func TestValidateSubqueryColumns(t *testing.T) {
   693  	t.Skip()
   694  
   695  	require := require.New(t)
   696  
   697  	db := memory.NewDatabase("db")
   698  	pro := memory.NewDBProvider(db)
   699  	ctx := newContext(pro)
   700  
   701  	table := memory.NewTable(db, "test", sql.NewPrimaryKeySchema(sql.Schema{
   702  		{Name: "foo", Type: types.Text},
   703  	}), nil)
   704  	subTable := memory.NewTable(db, "subtest", sql.NewPrimaryKeySchema(sql.Schema{
   705  		{Name: "bar", Type: types.Text},
   706  	}), nil)
   707  
   708  	var node sql.Node
   709  	node = plan.NewProject([]sql.Expression{
   710  		plan.NewSubquery(plan.NewFilter(expression.NewGreaterThan(
   711  			expression.NewGetField(0, types.Boolean, "foo", false),
   712  			lit(1),
   713  		), plan.NewProject(
   714  			[]sql.Expression{
   715  				expression.NewGetField(1, types.Boolean, "bar", false),
   716  			},
   717  			plan.NewResolvedTable(subTable, nil, nil),
   718  		)), "select bar from subtest where foo > 1"),
   719  	}, plan.NewResolvedTable(table, nil, nil))
   720  
   721  	_, _, err := validateSubqueryColumns(ctx, nil, node, nil, DefaultRuleSelector)
   722  	require.NoError(err)
   723  
   724  	node = plan.NewProject([]sql.Expression{
   725  		plan.NewSubquery(plan.NewFilter(expression.NewGreaterThan(
   726  			expression.NewGetField(1, types.Boolean, "foo", false),
   727  			lit(1),
   728  		), plan.NewProject(
   729  			[]sql.Expression{
   730  				expression.NewGetField(2, types.Boolean, "bar", false),
   731  			},
   732  			plan.NewResolvedTable(subTable, nil, nil),
   733  		)), "select bar from subtest where foo > 1"),
   734  	}, plan.NewResolvedTable(table, nil, nil))
   735  
   736  	_, _, err = validateSubqueryColumns(ctx, nil, node, nil, DefaultRuleSelector)
   737  	require.Error(err)
   738  	require.True(analyzererrors.ErrSubqueryFieldIndex.Is(err))
   739  
   740  	node = plan.NewProject([]sql.Expression{
   741  		plan.NewSubquery(plan.NewProject(
   742  			[]sql.Expression{
   743  				lit(1),
   744  			},
   745  			dummyNode{true},
   746  		), "select 1"),
   747  	}, dummyNode{true})
   748  
   749  	_, _, err = validateSubqueryColumns(ctx, nil, node, nil, DefaultRuleSelector)
   750  	require.NoError(err)
   751  
   752  }
   753  
   754  type dummyNode struct{ resolved bool }
   755  
   756  var _ sql.Node = dummyNode{}
   757  var _ sql.CollationCoercible = dummyNode{}
   758  
   759  func (n dummyNode) String() string                                   { return "dummynode" }
   760  func (n dummyNode) Resolved() bool                                   { return n.resolved }
   761  func (dummyNode) IsReadOnly() bool                                   { return true }
   762  func (dummyNode) Schema() sql.Schema                                 { return nil }
   763  func (dummyNode) Children() []sql.Node                               { return nil }
   764  func (dummyNode) RowIter(*sql.Context, sql.Row) (sql.RowIter, error) { return nil, nil }
   765  func (dummyNode) WithChildren(...sql.Node) (sql.Node, error)         { return nil, nil }
   766  func (dummyNode) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool {
   767  	return true
   768  }
   769  func (dummyNode) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) {
   770  	return sql.Collation_binary, 7
   771  }
   772  
   773  func getValidationRule(id RuleId) Rule {
   774  	for _, rule := range DefaultValidationRules {
   775  		if rule.Id == id {
   776  			return rule
   777  		}
   778  	}
   779  	panic("missing rule")
   780  }