github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/libraries/doltcore/sqle/sqlselect_test.go (about)

     1  // Copyright 2020 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 sqle
    16  
    17  import (
    18  	"context"
    19  	"testing"
    20  	"time"
    21  
    22  	"github.com/dolthub/go-mysql-server/sql"
    23  	"github.com/stretchr/testify/assert"
    24  	"github.com/stretchr/testify/require"
    25  
    26  	"github.com/dolthub/dolt/go/libraries/doltcore/doltdb"
    27  	"github.com/dolthub/dolt/go/libraries/doltcore/doltdocs"
    28  	"github.com/dolthub/dolt/go/libraries/doltcore/dtestutils"
    29  	"github.com/dolthub/dolt/go/libraries/doltcore/envtestutils"
    30  	"github.com/dolthub/dolt/go/libraries/doltcore/row"
    31  	"github.com/dolthub/dolt/go/libraries/doltcore/schema"
    32  	. "github.com/dolthub/dolt/go/libraries/doltcore/sql/sqltestutil"
    33  	"github.com/dolthub/dolt/go/libraries/doltcore/sqle/dtables"
    34  	"github.com/dolthub/dolt/go/store/types"
    35  )
    36  
    37  // Set to the name of a single test to run just that test, useful for debugging
    38  const singleSelectQueryTest = "" //"Natural join with join clause"
    39  
    40  // Set to false to run tests known to be broken
    41  const skipBrokenSelect = true
    42  
    43  // Structure for a test of a select query
    44  type SelectTest struct {
    45  	// The name of this test. Names should be unique and descriptive.
    46  	Name string
    47  	// The query to run, excluding an ending semicolon
    48  	Query string
    49  	// The schema of the result of the query, nil if an error is expected
    50  	ExpectedSchema schema.Schema
    51  	// The schema of the result of the query, nil if an error is expected. Mutually exclusive with ExpectedSchema. Use if
    52  	// the schema is difficult to specify with dolt schemas.
    53  	ExpectedSqlSchema sql.Schema
    54  	// The rows this query should return, nil if an error is expected
    55  	ExpectedRows []sql.Row
    56  	// An expected error string
    57  	ExpectedErr string
    58  	// Setup logic to run before executing this test, after initial tables have been created and populated
    59  	AdditionalSetup SetupFn
    60  	// Whether to skip this test on SqlEngine (go-mysql-server) execution.
    61  	// Over time, this should become false for every query.
    62  	SkipOnSqlEngine bool
    63  }
    64  
    65  // BasicSelectTests cover basic select statement features and error handling
    66  var BasicSelectTests = []SelectTest{
    67  	{
    68  		Name:           "select * on primary key",
    69  		Query:          "select * from people where id = 2",
    70  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Bart),
    71  		ExpectedSchema: CompressSchema(PeopleTestSchema),
    72  	},
    73  	{
    74  		Name:           "select * ",
    75  		Query:          "select * from people",
    76  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer, Marge, Bart, Lisa, Moe, Barney),
    77  		ExpectedSchema: CompressSchema(PeopleTestSchema),
    78  	},
    79  	{
    80  		Name:           "select *, limit 1",
    81  		Query:          "select * from people limit 1",
    82  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer),
    83  		ExpectedSchema: CompressSchema(PeopleTestSchema),
    84  	},
    85  	{
    86  		Name:           "select *, limit 1 offset 0",
    87  		Query:          "select * from people limit 0,1",
    88  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer),
    89  		ExpectedSchema: CompressSchema(PeopleTestSchema),
    90  	},
    91  	{
    92  		Name:           "select *, limit 1 offset 1",
    93  		Query:          "select * from people limit 1 offset 1;",
    94  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Marge),
    95  		ExpectedSchema: CompressSchema(PeopleTestSchema),
    96  	},
    97  	{
    98  		Name:           "select *, limit 1 offset 5",
    99  		Query:          "select * from people limit 5,1",
   100  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Barney),
   101  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   102  	},
   103  	{
   104  		Name:           "select *, limit 1 offset 6",
   105  		Query:          "select * from people limit 6,1",
   106  		ExpectedRows:   ToSqlRows(PeopleTestSchema),
   107  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   108  	},
   109  	{
   110  		Name:           "select *, limit 0",
   111  		Query:          "select * from people limit 0",
   112  		ExpectedRows:   ToSqlRows(PeopleTestSchema),
   113  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   114  	},
   115  	{
   116  		Name:           "select *, limit 0 offset 0",
   117  		Query:          "select * from people limit 0,0",
   118  		ExpectedRows:   ToSqlRows(PeopleTestSchema),
   119  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   120  	},
   121  	{
   122  		Name:        "select *, limit -1",
   123  		Query:       "select * from people limit -1",
   124  		ExpectedErr: "Limit must be >= 0 if supplied",
   125  	},
   126  	{
   127  		Name:        "select *, offset -1",
   128  		Query:       "select * from people limit -1,1",
   129  		ExpectedErr: "Offset must be >= 0 if supplied",
   130  	},
   131  	{
   132  		Name:           "select *, limit 100",
   133  		Query:          "select * from people limit 100",
   134  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer, Marge, Bart, Lisa, Moe, Barney),
   135  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   136  	},
   137  	{
   138  		Name:           "select *, where < int",
   139  		Query:          "select * from people where age < 40",
   140  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Marge, Bart, Lisa),
   141  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   142  	},
   143  	{
   144  		Name:           "select *, where < int, limit 1",
   145  		Query:          "select * from people where age < 40 limit 1",
   146  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Marge),
   147  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   148  	},
   149  	{
   150  		Name:           "select *, where < int, limit 2",
   151  		Query:          "select * from people where age < 40 limit 2",
   152  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Marge, Bart),
   153  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   154  	},
   155  	{
   156  		Name:           "select *, where < int, limit 100",
   157  		Query:          "select * from people where age < 40 limit 100",
   158  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Marge, Bart, Lisa),
   159  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   160  	},
   161  	{
   162  		Name:           "select *, order by int",
   163  		Query:          "select * from people order by id",
   164  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer, Marge, Bart, Lisa, Moe, Barney),
   165  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   166  	},
   167  	{
   168  		Name:           "select *, order by int desc",
   169  		Query:          "select * from people order by id desc",
   170  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Barney, Moe, Lisa, Bart, Marge, Homer),
   171  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   172  	},
   173  	{
   174  		Name:           "select *, order by float",
   175  		Query:          "select * from people order by rating",
   176  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Barney, Moe, Marge, Homer, Bart, Lisa),
   177  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   178  	},
   179  	{
   180  		Name:           "select *, order by string",
   181  		Query:          "select * from people order by first_name",
   182  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Barney, Bart, Homer, Lisa, Marge, Moe),
   183  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   184  	},
   185  	{
   186  		Name:           "select *, order by string,string",
   187  		Query:          "select * from people order by last_name desc, first_name asc",
   188  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Moe, Bart, Homer, Lisa, Marge, Barney),
   189  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   190  	},
   191  	{
   192  		Name:           "select *, order by with limit",
   193  		Query:          "select * from people order by first_name limit 2",
   194  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Barney, Bart),
   195  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   196  	},
   197  	{
   198  		Name:           "select *, order by string,string with limit",
   199  		Query:          "select * from people order by last_name desc, first_name asc limit 2",
   200  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Moe, Bart),
   201  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   202  	},
   203  	{
   204  		Name:           "select *, where > int reversed",
   205  		Query:          "select * from people where 40 > age",
   206  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Marge, Bart, Lisa),
   207  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   208  	},
   209  	{
   210  		Name:           "select *, where <= int",
   211  		Query:          "select * from people where age <= 40",
   212  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer, Marge, Bart, Lisa, Barney),
   213  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   214  	},
   215  	{
   216  		Name:           "select *, where >= int reversed",
   217  		Query:          "select * from people where 40 >= age",
   218  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer, Marge, Bart, Lisa, Barney),
   219  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   220  	},
   221  	{
   222  		Name:           "select *, where > int",
   223  		Query:          "select * from people where age > 40",
   224  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Moe),
   225  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   226  	},
   227  	{
   228  		Name:           "select *, where < int reversed",
   229  		Query:          "select * from people where 40 < age",
   230  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Moe),
   231  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   232  	},
   233  	{
   234  		Name:           "select *, where >= int",
   235  		Query:          "select * from people where age >= 40",
   236  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer, Moe, Barney),
   237  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   238  	},
   239  	{
   240  		Name:           "select *, where <= int reversed",
   241  		Query:          "select * from people where 40 <= age",
   242  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer, Moe, Barney),
   243  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   244  	},
   245  	{
   246  		Name:           "select *, where > string",
   247  		Query:          "select * from people where last_name > 'Simpson'",
   248  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Moe),
   249  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   250  	},
   251  	{
   252  		Name:           "select *, where < string",
   253  		Query:          "select * from people where last_name < 'Simpson'",
   254  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Barney),
   255  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   256  	},
   257  	{
   258  		Name:           "select *, where = string",
   259  		Query:          "select * from people where last_name = 'Simpson'",
   260  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer, Marge, Bart, Lisa),
   261  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   262  	},
   263  	{
   264  		Name:           "select *, where > float",
   265  		Query:          "select * from people where rating > 8.0 order by id",
   266  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer, Bart, Lisa),
   267  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   268  	},
   269  	{
   270  		Name:           "select *, where < float",
   271  		Query:          "select * from people where rating < 8.0",
   272  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Moe, Barney),
   273  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   274  	},
   275  	{
   276  		Name:           "select *, where = float",
   277  		Query:          "select * from people where rating = 8.0",
   278  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Marge),
   279  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   280  	},
   281  	{
   282  		Name:           "select *, where < float reversed",
   283  		Query:          "select * from people where 8.0 < rating",
   284  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer, Bart, Lisa),
   285  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   286  	},
   287  	{
   288  		Name:           "select *, where > float reversed",
   289  		Query:          "select * from people where 8.0 > rating",
   290  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Moe, Barney),
   291  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   292  	},
   293  	{
   294  		Name:           "select *, where = float reversed",
   295  		Query:          "select * from people where 8.0 = rating",
   296  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Marge),
   297  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   298  	},
   299  	{
   300  		Name:           "select *, where bool = ",
   301  		Query:          "select * from people where is_married = true",
   302  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer, Marge),
   303  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   304  	},
   305  	{
   306  		Name:           "select *, where bool = false ",
   307  		Query:          "select * from people where is_married = false",
   308  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Bart, Lisa, Moe, Barney),
   309  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   310  	},
   311  	{
   312  		Name:           "select *, where bool <> ",
   313  		Query:          "select * from people where is_married <> false",
   314  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer, Marge),
   315  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   316  	},
   317  	{
   318  		Name:           "select *, where bool",
   319  		Query:          "select * from people where is_married",
   320  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer, Marge),
   321  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   322  	},
   323  	{
   324  		Name:           "select *, and clause",
   325  		Query:          "select * from people where is_married and age > 38",
   326  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer),
   327  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   328  	},
   329  	{
   330  		Name:           "select *, or clause",
   331  		Query:          "select * from people where is_married or age < 20",
   332  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer, Marge, Bart, Lisa),
   333  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   334  	},
   335  	{
   336  		Name:           "select *, in clause string",
   337  		Query:          "select * from people where first_name in ('Homer', 'Marge')",
   338  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer, Marge),
   339  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   340  	},
   341  	{
   342  		Name:           "select *, in clause integer",
   343  		Query:          "select * from people where age in (-10, 40)",
   344  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer, Barney),
   345  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   346  	},
   347  	{
   348  		Name:           "select *, in clause float",
   349  		Query:          "select * from people where rating in (-10.0, 8.5)",
   350  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer),
   351  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   352  	},
   353  	{
   354  		Name:           "select *, in clause, mixed types",
   355  		Query:          "select * from people where first_name in ('Homer', 40)",
   356  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   357  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer),
   358  	},
   359  	{
   360  		Name:           "select *, in clause, mixed numeric types",
   361  		Query:          "select * from people where age in (-10.0, 40)",
   362  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   363  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer, Barney),
   364  	},
   365  	{
   366  		Name:           "select *, not in clause",
   367  		Query:          "select * from people where first_name not in ('Homer', 'Marge')",
   368  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Bart, Lisa, Moe, Barney),
   369  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   370  	},
   371  	{
   372  		Name:           "select *, in clause single element",
   373  		Query:          "select * from people where first_name in ('Homer')",
   374  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer),
   375  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   376  	},
   377  	{
   378  		Name:           "select *, in clause single type mismatch",
   379  		Query:          "select * from people where first_name in (1.0)",
   380  		ExpectedRows:   ToSqlRows(PeopleTestSchema),
   381  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   382  	},
   383  	{
   384  		Name:           "select *, is null clause ",
   385  		Query:          "select * from people where uuid is null",
   386  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer),
   387  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   388  	},
   389  	{
   390  		Name:           "select *, is not null clause ",
   391  		Query:          "select * from people where uuid is not null",
   392  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Marge, Bart, Lisa, Moe, Barney),
   393  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   394  	},
   395  	{
   396  		Name:           "select *, is true clause ",
   397  		Query:          "select * from people where is_married is true",
   398  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer, Marge),
   399  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   400  	},
   401  	{
   402  		Name:           "select *, is not true clause ",
   403  		Query:          "select * from people where is_married is not true",
   404  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Bart, Lisa, Moe, Barney),
   405  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   406  	},
   407  	{
   408  		Name:           "select *, is false clause ",
   409  		Query:          "select * from people where is_married is false",
   410  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Bart, Lisa, Moe, Barney),
   411  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   412  	},
   413  	{
   414  		Name:           "select *, is not false clause ",
   415  		Query:          "select * from people where is_married is not false",
   416  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer, Marge),
   417  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   418  	},
   419  	{
   420  		Name:           "select *, is true clause on non-bool column",
   421  		Query:          "select * from people where age is true",
   422  		ExpectedRows:   ToSqlRows(PeopleTestSchema, AllPeopleRows...),
   423  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   424  	},
   425  	{
   426  		Name:           "binary expression in select",
   427  		Query:          "select age + 1 as a from people where is_married order by a",
   428  		ExpectedRows:   ToSqlRows(NewResultSetSchema("a", types.IntKind), NewResultSetRow(types.Int(39)), NewResultSetRow(types.Int(41))),
   429  		ExpectedSchema: NewResultSetSchema("a", types.IntKind),
   430  	},
   431  	{
   432  		Name:         "and expression in select",
   433  		Query:        "select is_married and age >= 40 from people where last_name = 'Simpson' order by id limit 2",
   434  		ExpectedRows: []sql.Row{{true}, {false}},
   435  		ExpectedSqlSchema: sql.Schema{
   436  			&sql.Column{Name: "is_married and age >= 40", Type: sql.Int8},
   437  		},
   438  	},
   439  	{
   440  		Name:  "or expression in select",
   441  		Query: "select first_name, age <= 10 or age >= 40 as not_marge from people where last_name = 'Simpson' order by id desc",
   442  		ExpectedRows: []sql.Row{
   443  			{"Lisa", true},
   444  			{"Bart", true},
   445  			{"Marge", false},
   446  			{"Homer", true},
   447  		},
   448  		ExpectedSqlSchema: sql.Schema{
   449  			&sql.Column{Name: "first_name", Type: sql.LongText},
   450  			&sql.Column{Name: "not_marge", Type: sql.Int8},
   451  		},
   452  	},
   453  	{
   454  		Name:           "unary expression in select",
   455  		Query:          "select -age as age from people where is_married order by age",
   456  		ExpectedRows:   ToSqlRows(NewResultSetSchema("age", types.IntKind), NewResultSetRow(types.Int(-40)), NewResultSetRow(types.Int(-38))),
   457  		ExpectedSchema: NewResultSetSchema("age", types.IntKind),
   458  	},
   459  	{
   460  		Name:            "unary expression in select, alias named after column",
   461  		Query:           "select -age as age from people where is_married order by people.age",
   462  		ExpectedRows:    ToSqlRows(NewResultSetSchema("age", types.IntKind), NewResultSetRow(types.Int(-38)), NewResultSetRow(types.Int(-40))),
   463  		ExpectedSchema:  NewResultSetSchema("age", types.IntKind),
   464  		SkipOnSqlEngine: true, // this seems to be a bug in the engine
   465  	},
   466  	{
   467  		Name:           "select *, -column",
   468  		Query:          "select * from people where -rating = -8.5",
   469  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer),
   470  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   471  	},
   472  	{
   473  		Name:           "select *, -column, string type",
   474  		Query:          "select * from people where -first_name = 'Homer'",
   475  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   476  		ExpectedRows:   ToSqlRows(PeopleTestSchema, AllPeopleRows...), // A little weird, but correct due to mysql type conversion rules (both expression evaluate to 0 after conversion)
   477  	},
   478  	{
   479  		Name:           "select *, binary + in where",
   480  		Query:          "select * from people where age + 1 = 41",
   481  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer, Barney),
   482  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   483  	},
   484  	{
   485  		Name:           "select *, binary - in where",
   486  		Query:          "select * from people where age - 1 = 39",
   487  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer, Barney),
   488  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   489  	},
   490  	{
   491  		Name:           "select *, binary / in where",
   492  		Query:          "select * from people where age / 2 = 20",
   493  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer, Barney),
   494  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   495  	},
   496  	{
   497  		Name:           "select *, binary * in where",
   498  		Query:          "select * from people where age * 2 = 80",
   499  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer, Barney),
   500  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   501  	},
   502  	{
   503  		Name:           "select *, binary % in where",
   504  		Query:          "select * from people where age % 4 = 0",
   505  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer, Lisa, Moe, Barney),
   506  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   507  	},
   508  	{
   509  		Name:           "select *, complex binary expr in where",
   510  		Query:          "select * from people where age / 4 + 2 * 2 = 14",
   511  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer, Barney),
   512  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   513  	},
   514  	{
   515  		Name:        "select *, binary + in where type mismatch",
   516  		Query:       "select * from people where first_name + 1 = 41",
   517  		ExpectedErr: "Type mismatch evaluating expression 'first_name + 1'",
   518  	},
   519  	{
   520  		Name:        "select *, binary - in where type mismatch",
   521  		Query:       "select * from people where first_name - 1 = 39",
   522  		ExpectedErr: "Type mismatch evaluating expression 'first_name - 1'",
   523  	},
   524  	{
   525  		Name:        "select *, binary / in where type mismatch",
   526  		Query:       "select * from people where first_name / 2 = 20",
   527  		ExpectedErr: "Type mismatch evaluating expression 'first_name / 2'",
   528  	},
   529  	{
   530  		Name:        "select *, binary * in where type mismatch",
   531  		Query:       "select * from people where first_name * 2 = 80",
   532  		ExpectedErr: "Type mismatch evaluating expression 'first_name * 2'",
   533  	},
   534  	{
   535  		Name:        "select *, binary % in where type mismatch",
   536  		Query:       "select * from people where first_name % 4 = 0",
   537  		ExpectedErr: "Type mismatch evaluating expression 'first_name % 4'",
   538  	},
   539  	{
   540  		Name:           "select * with where, order by",
   541  		Query:          "select * from people where `uuid` is not null and first_name <> 'Marge' order by last_name desc, age",
   542  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Moe, Lisa, Bart, Barney),
   543  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   544  	},
   545  	{
   546  		Name:           "select subset of cols",
   547  		Query:          "select first_name, last_name from people where age >= 40",
   548  		ExpectedRows:   ToSqlRows(SubsetSchema(PeopleTestSchema, "first_name", "last_name"), Homer, Moe, Barney),
   549  		ExpectedSchema: CompressSchema(PeopleTestSchema, "first_name", "last_name"),
   550  	},
   551  	{
   552  		Name:           "column aliases",
   553  		Query:          "select first_name as f, last_name as l from people where age >= 40",
   554  		ExpectedRows:   ToSqlRows(SubsetSchema(PeopleTestSchema, "first_name", "last_name"), Homer, Moe, Barney),
   555  		ExpectedSchema: NewResultSetSchema("f", types.StringKind, "l", types.StringKind),
   556  	},
   557  	{
   558  		Name:           "duplicate column aliases",
   559  		Query:          "select first_name as f, last_name as f from people where age >= 40",
   560  		ExpectedRows:   ToSqlRows(SubsetSchema(PeopleTestSchema, "first_name", "last_name"), Homer, Moe, Barney),
   561  		ExpectedSchema: NewResultSetSchema("f", types.StringKind, "f", types.StringKind),
   562  	},
   563  	{
   564  		Name:  "column selected more than once",
   565  		Query: "select first_name, first_name from people where age >= 40 order by id",
   566  		ExpectedRows: []sql.Row{
   567  			{"Homer", "Homer"},
   568  			{"Moe", "Moe"},
   569  			{"Barney", "Barney"},
   570  		},
   571  		ExpectedSchema: NewResultSetSchema("first_name", types.StringKind, "first_name", types.StringKind),
   572  	},
   573  	{
   574  		Name:        "duplicate table selection",
   575  		Query:       "select first_name as f, last_name as f from people, people where age >= 40",
   576  		ExpectedErr: "Non-unique table name / alias: people",
   577  	},
   578  	{
   579  		Name:        "duplicate table alias",
   580  		Query:       "select * from people p, people p where age >= 40",
   581  		ExpectedErr: "Non-unique table name / alias: 'p'",
   582  	},
   583  	{
   584  		Name:            "column aliases in where clause",
   585  		Query:           `select first_name as f, last_name as l from people where f = "Homer"`,
   586  		ExpectedErr:     "Unknown column: 'f'",
   587  		SkipOnSqlEngine: true, // this is actually a bug (aliases aren't usable in filters)
   588  	},
   589  	{
   590  		Name:           "select subset of columns with order by",
   591  		Query:          "select first_name from people order by age, first_name",
   592  		ExpectedRows:   ToSqlRows(SubsetSchema(PeopleTestSchema, "first_name"), Lisa, Bart, Marge, Barney, Homer, Moe),
   593  		ExpectedSchema: CompressSchema(PeopleTestSchema, "first_name"),
   594  	},
   595  	{
   596  		Name:           "column aliases with order by",
   597  		Query:          "select first_name as f from people order by age, f",
   598  		ExpectedRows:   ToSqlRows(SubsetSchema(PeopleTestSchema, "first_name"), Lisa, Bart, Marge, Barney, Homer, Moe),
   599  		ExpectedSchema: NewResultSetSchema("f", types.StringKind),
   600  	},
   601  	{
   602  		Name:            "ambiguous column in order by",
   603  		Query:           "select first_name as f, last_name as f from people order by f",
   604  		ExpectedErr:     "Ambiguous column: 'f'",
   605  		SkipOnSqlEngine: true, // this is a bug in go-mysql-server
   606  	},
   607  	{
   608  		Name:           "table aliases",
   609  		Query:          "select p.first_name as f, p.last_name as l from people p where p.first_name = 'Homer'",
   610  		ExpectedRows:   ToSqlRows(SubsetSchema(PeopleTestSchema, "first_name", "last_name"), Homer),
   611  		ExpectedSchema: NewResultSetSchema("f", types.StringKind, "l", types.StringKind),
   612  	},
   613  	{
   614  		Name:           "table aliases without column aliases",
   615  		Query:          "select p.first_name, p.last_name from people p where p.first_name = 'Homer'",
   616  		ExpectedRows:   ToSqlRows(SubsetSchema(PeopleTestSchema, "first_name", "last_name"), Homer),
   617  		ExpectedSchema: NewResultSetSchema("first_name", types.StringKind, "last_name", types.StringKind),
   618  	},
   619  	{
   620  		Name:        "table aliases with bad alias",
   621  		Query:       "select m.first_name as f, p.last_name as l from people p where p.f = 'Homer'",
   622  		ExpectedErr: "Unknown table: 'm'",
   623  	},
   624  	{
   625  		Name: "column aliases, all columns",
   626  		Query: `select id as i, first_name as f, last_name as l, is_married as m, age as a,
   627  					rating as r, uuid as u, num_episodes as n from people
   628  					where age >= 40`,
   629  		ExpectedRows: ToSqlRows(PeopleTestSchema, Homer, Moe, Barney),
   630  		ExpectedSchema: NewResultSetSchema("i", types.IntKind, "f", types.StringKind,
   631  			"l", types.StringKind, "m", types.BoolKind, "a", types.IntKind, "r", types.FloatKind,
   632  			"u", types.UUIDKind, "n", types.UintKind),
   633  	},
   634  	{
   635  		Name:           "select *, not equals",
   636  		Query:          "select * from people where age <> 40",
   637  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Marge, Bart, Lisa, Moe),
   638  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   639  	},
   640  	{
   641  		Name:           "empty result set",
   642  		Query:          "select * from people where age > 80",
   643  		ExpectedRows:   ToSqlRows(PeopleTestSchema),
   644  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   645  	},
   646  	{
   647  		Name:           "empty result set with columns",
   648  		Query:          "select id, age from people where age > 80",
   649  		ExpectedRows:   ToSqlRows(PeopleTestSchema),
   650  		ExpectedSchema: CompressSchema(PeopleTestSchema, "id", "age"),
   651  	},
   652  	{
   653  		Name:        "unknown table",
   654  		Query:       "select * from dne",
   655  		ExpectedErr: `Unknown table: 'dne'`,
   656  	},
   657  	{
   658  		Name:        "unknown diff table",
   659  		Query:       "select * from dolt_diff_dne",
   660  		ExpectedErr: `Unknown table: 'dolt_diff_dne'`,
   661  	},
   662  	{
   663  		Name:        "unknown diff table",
   664  		Query:       "select * from dolt_commit_diff_dne",
   665  		ExpectedErr: `Unknown table: 'dolt_commit_diff_dne'`,
   666  	},
   667  	{
   668  		Name:        "unknown history table",
   669  		Query:       "select * from dolt_history_dne",
   670  		ExpectedErr: `Unknown table: 'dolt_history_dne'`,
   671  	},
   672  	{
   673  		Name:        "unknown table in join",
   674  		Query:       "select * from people join dne",
   675  		ExpectedErr: `Unknown table: 'dne'`,
   676  	},
   677  	{
   678  		Name:  "no table",
   679  		Query: "select 1",
   680  		ExpectedSqlSchema: sql.Schema{
   681  			&sql.Column{
   682  				Name: "1",
   683  				Type: sql.Int8,
   684  			},
   685  		},
   686  		ExpectedRows: []sql.Row{{int8(1)}},
   687  	},
   688  	{
   689  		Name:        "unknown column in where",
   690  		Query:       "select * from people where dne > 8.0",
   691  		ExpectedErr: `Unknown column: 'dne'`,
   692  	},
   693  	{
   694  		Name:        "unknown column in order by",
   695  		Query:       "select * from people where rating > 8.0 order by dne",
   696  		ExpectedErr: `Unknown column: 'dne'`,
   697  	},
   698  	{
   699  		Name:        "unsupported comparison",
   700  		Query:       "select * from people where function(first_name)",
   701  		ExpectedErr: "not supported",
   702  	},
   703  	{
   704  		Name:           "type mismatch in where clause",
   705  		Query:          `select * from people where id = "0"`,
   706  		ExpectedSchema: CompressSchema(PeopleTestSchema),
   707  		ExpectedRows:   ToSqlRows(PeopleTestSchema, Homer),
   708  	},
   709  	{
   710  		Name:  "select * from log system table",
   711  		Query: "select * from dolt_log",
   712  		ExpectedRows: []sql.Row{
   713  			{
   714  				"m8lrhp8bmfesmknc6d5iatmjbcjf17al",
   715  				"billy bob",
   716  				"bigbillieb@fake.horse",
   717  				time.Date(1970, 1, 1, 0, 0, 0, 0, &time.Location{}),
   718  				"Initialize data repository",
   719  			},
   720  		},
   721  		ExpectedSqlSchema: sql.Schema{
   722  			&sql.Column{Name: "commit_hash", Type: sql.Text},
   723  			&sql.Column{Name: "committer", Type: sql.Text},
   724  			&sql.Column{Name: "email", Type: sql.Text},
   725  			&sql.Column{Name: "date", Type: sql.Datetime},
   726  			&sql.Column{Name: "message", Type: sql.Text},
   727  		},
   728  	},
   729  	{
   730  		Name:         "select * from conflicts system table",
   731  		Query:        "select * from dolt_conflicts",
   732  		ExpectedRows: []sql.Row{},
   733  		ExpectedSqlSchema: sql.Schema{
   734  			&sql.Column{Name: "table", Type: sql.Text},
   735  			&sql.Column{Name: "num_conflicts", Type: sql.Uint64},
   736  		},
   737  	},
   738  	{
   739  		Name:  "select * from branches system table",
   740  		Query: "select * from dolt_branches",
   741  		ExpectedRows: []sql.Row{
   742  			{
   743  				"master",
   744  				"m8lrhp8bmfesmknc6d5iatmjbcjf17al",
   745  				"billy bob", "bigbillieb@fake.horse",
   746  				time.Date(1970, 1, 1, 0, 0, 0, 0, &time.Location{}),
   747  				"Initialize data repository",
   748  			},
   749  		},
   750  		ExpectedSqlSchema: sql.Schema{
   751  			&sql.Column{Name: "name", Type: sql.Text},
   752  			&sql.Column{Name: "hash", Type: sql.Text},
   753  			&sql.Column{Name: "latest_committer", Type: sql.Text},
   754  			&sql.Column{Name: "latest_committer_email", Type: sql.Text},
   755  			&sql.Column{Name: "latest_commit_date", Type: sql.Datetime},
   756  			&sql.Column{Name: "latest_commit_message", Type: sql.Text},
   757  		},
   758  	},
   759  }
   760  
   761  var sqlDiffSchema = sql.Schema{
   762  	&sql.Column{Name: "to_id", Type: sql.Int64},
   763  	&sql.Column{Name: "to_first_name", Type: sql.LongText},
   764  	&sql.Column{Name: "to_last_name", Type: sql.LongText},
   765  	&sql.Column{Name: "to_addr", Type: sql.LongText},
   766  	&sql.Column{Name: "from_id", Type: sql.Int64},
   767  	&sql.Column{Name: "from_first_name", Type: sql.LongText},
   768  	&sql.Column{Name: "from_last_name", Type: sql.LongText},
   769  	&sql.Column{Name: "from_addr", Type: sql.LongText},
   770  	&sql.Column{Name: "diff_type", Type: sql.Text},
   771  }
   772  
   773  var SelectDiffTests = []SelectTest{
   774  	{
   775  		Name:  "select from diff system table",
   776  		Query: "select to_id, to_first_name, to_last_name, to_addr, from_id, from_first_name, from_last_name, from_addr, diff_type from dolt_diff_test_table",
   777  		ExpectedRows: ToSqlRows(DiffSchema,
   778  			mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{0: types.Int(6), 1: types.String("Katie"), 2: types.String("McCulloch"), 14: types.String("added")})),
   779  			mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{0: types.Int(0), 1: types.String("Aaron"), 2: types.String("Son"), 3: types.String("123 Fake St"), 7: types.Int(0), 8: types.String("Aaron"), 9: types.String("Son"), 10: types.String("123 Fake St"), 14: types.String("modified")})),
   780  			mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{0: types.Int(1), 1: types.String("Brian"), 2: types.String("Hendriks"), 3: types.String("456 Bull Ln"), 7: types.Int(1), 8: types.String("Brian"), 9: types.String("Hendriks"), 10: types.String("456 Bull Ln"), 14: types.String("modified")})),
   781  			mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{0: types.Int(2), 1: types.String("Tim"), 2: types.String("Sehn"), 3: types.String("789 Not Real Ct"), 7: types.Int(2), 8: types.String("Tim"), 9: types.String("Sehn"), 10: types.String("789 Not Real Ct"), 14: types.String("modified")})),
   782  			mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{0: types.Int(3), 1: types.String("Zach"), 2: types.String("Musgrave"), 3: types.String("-1 Imaginary Wy"), 7: types.Int(3), 8: types.String("Zach"), 9: types.String("Musgrave"), 14: types.String("modified")})),
   783  			mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{0: types.Int(5), 1: types.String("Daylon"), 2: types.String("Wilkins"), 14: types.String("added")})),
   784  			mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{0: types.Int(0), 1: types.String("Aaron"), 2: types.String("Son"), 3: types.String("123 Fake St"), 14: types.String("added")})),
   785  			mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{0: types.Int(1), 1: types.String("Brian"), 2: types.String("Hendriks"), 3: types.String("456 Bull Ln"), 14: types.String("added")})),
   786  			mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{0: types.Int(2), 1: types.String("Tim"), 2: types.String("Sehn"), 3: types.String("789 Not Real Ct"), 14: types.String("added")})),
   787  			mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{0: types.Int(3), 1: types.String("Zach"), 2: types.String("Musgrave"), 14: types.String("added")})),
   788  			mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{0: types.Int(4), 1: types.String("Matt"), 2: types.String("Jesuele"), 14: types.String("added")})),
   789  		),
   790  		ExpectedSqlSchema: sqlDiffSchema,
   791  	},
   792  	{
   793  		Name:  "select from diff system table with to commit",
   794  		Query: "select to_id, to_first_name, to_last_name, to_addr, from_id, from_first_name, from_last_name, from_addr, diff_type from dolt_diff_test_table where to_commit = 'WORKING'",
   795  		ExpectedRows: ToSqlRows(DiffSchema,
   796  			mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{0: types.Int(6), 1: types.String("Katie"), 2: types.String("McCulloch"), 14: types.String("added")})),
   797  		),
   798  		ExpectedSqlSchema: sqlDiffSchema,
   799  	},
   800  	// TODO: fix dependencies to hashof function can be registered and used here, also create branches when generating the history so that different from and to commits can be tested.
   801  	/*{
   802  		Name:  "select from diff system table with from and to commit and test insensitive name",
   803  		Query: "select to_id, to_first_name, to_last_name, to_addr, to_age_4, to_age_5, from_id, from_first_name, from_last_name, from_addr, from_age_4, from_age_5, diff_type from dolt_diff_TeSt_TaBlE where from_commit = 'add-age' and to_commit = 'master'",
   804  		ExpectedRows: ToSqlRows(DiffSchema,
   805  			mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{7: types.Int(0), 8: types.String("Aaron"), 9: types.String("Son"), 11: types.Int(35), 0: types.Int(0), 1: types.String("Aaron"), 2: types.String("Son"), 3: types.String("123 Fake St"), 5: types.Uint(35), 13: types.String("add-age"), 6: types.String("master"), 14: types.String("modified")})),
   806  			mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{7: types.Int(1), 8: types.String("Brian"), 9: types.String("Hendriks"), 11: types.Int(38), 0: types.Int(1), 1: types.String("Brian"), 2: types.String("Hendriks"), 3: types.String("456 Bull Ln"), 5: types.Uint(38), 13: types.String("add-age"), 6: types.String("master"), 14: types.String("modified")})),
   807  			mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{7: types.Int(2), 8: types.String("Tim"), 9: types.String("Sehn"), 11: types.Int(37), 0: types.Int(2), 1: types.String("Tim"), 2: types.String("Sehn"), 3: types.String("789 Not Real Ct"), 5: types.Uint(37), 13: types.String("add-age"), 6: types.String("master"), 14: types.String("modified")})),
   808  			mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{7: types.Int(3), 8: types.String("Zach"), 9: types.String("Musgrave"), 11: types.Int(37), 0: types.Int(3), 1: types.String("Zach"), 2: types.String("Musgrave"), 3: types.String("-1 Imaginary Wy"), 5: types.Uint(37), 13: types.String("add-age"), 6: types.String("master"), 14: types.String("modified")})),
   809  			mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{0: types.Int(4), 1: types.String("Matt"), 2: types.String("Jesuele"), 3: types.NullValue, 13: types.String("add-age"), 6: types.String("master"), 14: types.String("added")})),
   810  			mustRow(row.New(types.Format_Default, DiffSchema, row.TaggedValues{0: types.Int(5), 1: types.String("Daylon"), 2: types.String("Wilkins"), 3: types.NullValue, 13: types.String("add-age"), 6: types.String("master"), 14: types.String("added")})),
   811  		),
   812  		ExpectedSqlSchema: sqlDiffSchema,
   813  	},*/
   814  }
   815  
   816  var AsOfTests = []SelectTest{
   817  	{
   818  		Name:  "select * from seed branch",
   819  		Query: "select * from test_table as of 'seed'",
   820  		ExpectedRows: ToSqlRows(InitialHistSch,
   821  			mustRow(row.New(types.Format_Default, InitialHistSch, row.TaggedValues{0: types.Int(0), 1: types.String("Aaron"), 2: types.String("Son")})),
   822  			mustRow(row.New(types.Format_Default, InitialHistSch, row.TaggedValues{0: types.Int(1), 1: types.String("Brian"), 2: types.String("Hendriks")})),
   823  			mustRow(row.New(types.Format_Default, InitialHistSch, row.TaggedValues{0: types.Int(2), 1: types.String("Tim"), 2: types.String("Sehn")})),
   824  		),
   825  		ExpectedSchema: InitialHistSch,
   826  	},
   827  	{
   828  		Name:  "select * from add-age branch",
   829  		Query: "select * from test_table as of 'add-age'",
   830  		ExpectedRows: ToSqlRows(AddAgeAt4HistSch,
   831  			mustRow(row.New(types.Format_Default, AddAgeAt4HistSch, row.TaggedValues{0: types.Int(0), 1: types.String("Aaron"), 2: types.String("Son"), 4: types.Int(35)})),
   832  			mustRow(row.New(types.Format_Default, AddAgeAt4HistSch, row.TaggedValues{0: types.Int(1), 1: types.String("Brian"), 2: types.String("Hendriks"), 4: types.Int(38)})),
   833  			mustRow(row.New(types.Format_Default, AddAgeAt4HistSch, row.TaggedValues{0: types.Int(2), 1: types.String("Tim"), 2: types.String("Sehn"), 4: types.Int(37)})),
   834  			mustRow(row.New(types.Format_Default, AddAgeAt4HistSch, row.TaggedValues{0: types.Int(3), 1: types.String("Zach"), 2: types.String("Musgrave"), 4: types.Int(37)})),
   835  		),
   836  		ExpectedSchema: AddAgeAt4HistSch,
   837  	},
   838  	{
   839  		Name:  "select * from master branch",
   840  		Query: "select * from test_table as of 'master'",
   841  		ExpectedRows: ToSqlRows(ReaddAgeAt5HistSch,
   842  			mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(0), 1: types.String("Aaron"), 2: types.String("Son"), 3: types.String("123 Fake St"), 5: types.Uint(35)})),
   843  			mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(1), 1: types.String("Brian"), 2: types.String("Hendriks"), 3: types.String("456 Bull Ln"), 5: types.Uint(38)})),
   844  			mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(2), 1: types.String("Tim"), 2: types.String("Sehn"), 3: types.String("789 Not Real Ct"), 5: types.Uint(37)})),
   845  			mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(3), 1: types.String("Zach"), 2: types.String("Musgrave"), 3: types.String("-1 Imaginary Wy"), 5: types.Uint(37)})),
   846  			mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(4), 1: types.String("Matt"), 2: types.String("Jesuele")})),
   847  			mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(5), 1: types.String("Daylon"), 2: types.String("Wilkins")})),
   848  		),
   849  		ExpectedSchema: ReaddAgeAt5HistSch,
   850  	},
   851  	{
   852  		Name:  "select * from HEAD~",
   853  		Query: "select * from test_table as of 'HEAD~'",
   854  		ExpectedRows: ToSqlRows(AddAddrAt3HistSch,
   855  			mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(0), 1: types.String("Aaron"), 2: types.String("Son"), 3: types.String("123 Fake St")})),
   856  			mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(1), 1: types.String("Brian"), 2: types.String("Hendriks"), 3: types.String("456 Bull Ln")})),
   857  			mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(2), 1: types.String("Tim"), 2: types.String("Sehn"), 3: types.String("789 Not Real Ct")})),
   858  			mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(3), 1: types.String("Zach"), 2: types.String("Musgrave")})),
   859  			mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(4), 1: types.String("Matt"), 2: types.String("Jesuele")})),
   860  		),
   861  		ExpectedSchema: AddAddrAt3HistSch,
   862  	},
   863  	{
   864  		Name:  "select * from HEAD^",
   865  		Query: "select * from test_table as of 'HEAD^'",
   866  		ExpectedRows: ToSqlRows(AddAddrAt3HistSch,
   867  			mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(0), 1: types.String("Aaron"), 2: types.String("Son"), 3: types.String("123 Fake St")})),
   868  			mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(1), 1: types.String("Brian"), 2: types.String("Hendriks"), 3: types.String("456 Bull Ln")})),
   869  			mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(2), 1: types.String("Tim"), 2: types.String("Sehn"), 3: types.String("789 Not Real Ct")})),
   870  			mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(3), 1: types.String("Zach"), 2: types.String("Musgrave")})),
   871  			mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(4), 1: types.String("Matt"), 2: types.String("Jesuele")})),
   872  		),
   873  		ExpectedSchema: AddAddrAt3HistSch,
   874  	},
   875  	{
   876  		Name:  "select * from master^",
   877  		Query: "select * from test_table as of 'master^'",
   878  		ExpectedRows: ToSqlRows(AddAddrAt3HistSch,
   879  			mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(0), 1: types.String("Aaron"), 2: types.String("Son"), 3: types.String("123 Fake St")})),
   880  			mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(1), 1: types.String("Brian"), 2: types.String("Hendriks"), 3: types.String("456 Bull Ln")})),
   881  			mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(2), 1: types.String("Tim"), 2: types.String("Sehn"), 3: types.String("789 Not Real Ct")})),
   882  			mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(3), 1: types.String("Zach"), 2: types.String("Musgrave")})),
   883  			mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(4), 1: types.String("Matt"), 2: types.String("Jesuele")})),
   884  		),
   885  		ExpectedSchema: AddAddrAt3HistSch,
   886  	},
   887  	// Because of an implementation detail in the way we process history for test setup, each commit is 2 hours apart.
   888  	{
   889  		Name:  "select * from timestamp after HEAD",
   890  		Query: "select * from test_table as of CONVERT('1970-01-01 10:00:00', DATETIME)",
   891  		ExpectedRows: ToSqlRows(ReaddAgeAt5HistSch,
   892  			mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(0), 1: types.String("Aaron"), 2: types.String("Son"), 3: types.String("123 Fake St"), 5: types.Uint(35)})),
   893  			mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(1), 1: types.String("Brian"), 2: types.String("Hendriks"), 3: types.String("456 Bull Ln"), 5: types.Uint(38)})),
   894  			mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(2), 1: types.String("Tim"), 2: types.String("Sehn"), 3: types.String("789 Not Real Ct"), 5: types.Uint(37)})),
   895  			mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(3), 1: types.String("Zach"), 2: types.String("Musgrave"), 3: types.String("-1 Imaginary Wy"), 5: types.Uint(37)})),
   896  			mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(4), 1: types.String("Matt"), 2: types.String("Jesuele")})),
   897  			mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(5), 1: types.String("Daylon"), 2: types.String("Wilkins")})),
   898  		),
   899  		ExpectedSchema: ReaddAgeAt5HistSch,
   900  	},
   901  	{
   902  		Name:  "select * from timestamp, HEAD exact",
   903  		Query: "select * from test_table as of CONVERT('1970-01-01 08:00:00', DATETIME)",
   904  		ExpectedRows: ToSqlRows(ReaddAgeAt5HistSch,
   905  			mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(0), 1: types.String("Aaron"), 2: types.String("Son"), 3: types.String("123 Fake St"), 5: types.Uint(35)})),
   906  			mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(1), 1: types.String("Brian"), 2: types.String("Hendriks"), 3: types.String("456 Bull Ln"), 5: types.Uint(38)})),
   907  			mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(2), 1: types.String("Tim"), 2: types.String("Sehn"), 3: types.String("789 Not Real Ct"), 5: types.Uint(37)})),
   908  			mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(3), 1: types.String("Zach"), 2: types.String("Musgrave"), 3: types.String("-1 Imaginary Wy"), 5: types.Uint(37)})),
   909  			mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(4), 1: types.String("Matt"), 2: types.String("Jesuele")})),
   910  			mustRow(row.New(types.Format_Default, ReaddAgeAt5HistSch, row.TaggedValues{0: types.Int(5), 1: types.String("Daylon"), 2: types.String("Wilkins")})),
   911  		),
   912  		ExpectedSchema: ReaddAgeAt5HistSch,
   913  	},
   914  	{
   915  		Name:  "select * from timestamp, HEAD~ + 1",
   916  		Query: "select * from test_table as of CONVERT('1970-01-01 07:00:00', DATETIME)",
   917  		ExpectedRows: ToSqlRows(AddAddrAt3HistSch,
   918  			mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(0), 1: types.String("Aaron"), 2: types.String("Son"), 3: types.String("123 Fake St")})),
   919  			mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(1), 1: types.String("Brian"), 2: types.String("Hendriks"), 3: types.String("456 Bull Ln")})),
   920  			mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(2), 1: types.String("Tim"), 2: types.String("Sehn"), 3: types.String("789 Not Real Ct")})),
   921  			mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(3), 1: types.String("Zach"), 2: types.String("Musgrave")})),
   922  			mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(4), 1: types.String("Matt"), 2: types.String("Jesuele")})),
   923  		),
   924  		ExpectedSchema: AddAddrAt3HistSch,
   925  	},
   926  	{
   927  		Name:  "select * from timestamp, HEAD~",
   928  		Query: "select * from test_table as of CONVERT('1970-01-01 06:00:00', DATETIME)",
   929  		ExpectedRows: ToSqlRows(AddAddrAt3HistSch,
   930  			mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(0), 1: types.String("Aaron"), 2: types.String("Son"), 3: types.String("123 Fake St")})),
   931  			mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(1), 1: types.String("Brian"), 2: types.String("Hendriks"), 3: types.String("456 Bull Ln")})),
   932  			mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(2), 1: types.String("Tim"), 2: types.String("Sehn"), 3: types.String("789 Not Real Ct")})),
   933  			mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(3), 1: types.String("Zach"), 2: types.String("Musgrave")})),
   934  			mustRow(row.New(types.Format_Default, AddAddrAt3HistSch, row.TaggedValues{0: types.Int(4), 1: types.String("Matt"), 2: types.String("Jesuele")})),
   935  		),
   936  		ExpectedSchema: AddAddrAt3HistSch,
   937  	},
   938  	{
   939  		Name:        "select * from timestamp, before table creation",
   940  		Query:       "select * from test_table as of CONVERT('1970-01-01 02:00:00', DATETIME)",
   941  		ExpectedErr: "not found",
   942  	},
   943  }
   944  
   945  // SQL is supposed to be case insensitive. These are tests of that promise.
   946  // Many of these are currently broken in go-myqsl-server. The queries return the correct results in all cases, but the
   947  // column names in the result schemas often have the wrong case. They sometimes use the case from the table, rather
   948  // than the case of the expression in the query (the correct behavior). This is a minor issue, but we should fix it
   949  // eventually.
   950  var CaseSensitivityTests = []SelectTest{
   951  	{
   952  		Name: "table name has mixed case, select lower case",
   953  		AdditionalSetup: CreateTableWithRowsFn("MiXeDcAsE",
   954  			NewSchema("test", types.StringKind),
   955  			[]types.Value{types.String("1")}),
   956  		Query:          "select test from mixedcase",
   957  		ExpectedSchema: NewResultSetSchema("test", types.StringKind),
   958  		ExpectedRows:   []sql.Row{{"1"}},
   959  	},
   960  	{
   961  		Name: "table name has mixed case, select upper case",
   962  		AdditionalSetup: CreateTableWithRowsFn("MiXeDcAsE",
   963  			NewSchema("test", types.StringKind),
   964  			[]types.Value{types.String("1")}),
   965  		Query:          "select test from MIXEDCASE",
   966  		ExpectedSchema: NewResultSetSchema("test", types.StringKind),
   967  		ExpectedRows:   []sql.Row{{"1"}},
   968  	},
   969  	{
   970  		Name: "qualified select *",
   971  		AdditionalSetup: CreateTableWithRowsFn("MiXeDcAsE",
   972  			NewSchema("test", types.StringKind),
   973  			[]types.Value{types.String("1")}),
   974  		Query:          "select mixedcAse.* from MIXEDCASE",
   975  		ExpectedSchema: NewResultSetSchema("test", types.StringKind),
   976  		ExpectedRows:   []sql.Row{{"1"}},
   977  	},
   978  	{
   979  		Name: "qualified select column",
   980  		AdditionalSetup: CreateTableWithRowsFn("MiXeDcAsE",
   981  			NewSchema("test", types.StringKind),
   982  			[]types.Value{types.String("1")}),
   983  		Query:           "select mixedcAse.TeSt from MIXEDCASE",
   984  		ExpectedSchema:  NewResultSetSchema("TeSt", types.StringKind),
   985  		ExpectedRows:    []sql.Row{{"1"}},
   986  		SkipOnSqlEngine: true,
   987  	},
   988  	{
   989  		Name: "table alias select *",
   990  		AdditionalSetup: CreateTableWithRowsFn("MiXeDcAsE",
   991  			NewSchema("test", types.StringKind),
   992  			[]types.Value{types.String("1")}),
   993  		Query:          "select Mc.* from MIXEDCASE as mc",
   994  		ExpectedSchema: NewResultSetSchema("test", types.StringKind),
   995  		ExpectedRows:   []sql.Row{{"1"}},
   996  	},
   997  	{
   998  		Name: "table alias select column",
   999  		AdditionalSetup: CreateTableWithRowsFn("MiXeDcAsE",
  1000  			NewSchema("test", types.StringKind),
  1001  			[]types.Value{types.String("1")}),
  1002  		Query:           "select mC.TeSt from MIXEDCASE as MC",
  1003  		ExpectedSchema:  NewResultSetSchema("TeSt", types.StringKind),
  1004  		ExpectedRows:    []sql.Row{{"1"}},
  1005  		SkipOnSqlEngine: true,
  1006  	},
  1007  	{
  1008  		Name: "multiple tables with the same case-insensitive name, exact match",
  1009  		AdditionalSetup: Compose(
  1010  			// the table name passed to NewSchemaForTable isn't important, except to get unique tags
  1011  			CreateTableWithRowsFn("tableName", NewSchemaForTable("tableName1", "test", types.StringKind), []types.Value{types.String("1")}),
  1012  			CreateTableWithRowsFn("TABLENAME", NewSchemaForTable("TABLENAME2", "test", types.StringKind)),
  1013  			CreateTableWithRowsFn("tablename", NewSchemaForTable("tablename3", "test", types.StringKind)),
  1014  		),
  1015  		Query:          "select test from tableName",
  1016  		ExpectedSchema: NewResultSetSchema("test", types.StringKind),
  1017  		ExpectedRows:   []sql.Row{{"1"}},
  1018  	},
  1019  	{
  1020  		Name: "alias with same name as table",
  1021  		AdditionalSetup: Compose(
  1022  			CreateTableWithRowsFn("tableName", NewSchema("test", types.StringKind)),
  1023  			CreateTableWithRowsFn("other", NewSchema("othercol", types.StringKind)),
  1024  		),
  1025  		Query:       "select other.test from tablename as other, other",
  1026  		ExpectedErr: "Non-unique table name / alias: 'other'",
  1027  	},
  1028  	{
  1029  		Name: "two table aliases with same name",
  1030  		AdditionalSetup: Compose(
  1031  			CreateTableWithRowsFn("tableName", NewSchema("test", types.StringKind)),
  1032  			CreateTableWithRowsFn("other", NewSchema("othercol", types.StringKind)),
  1033  		),
  1034  		Query:       "select bad.test from tablename as bad, other as bad",
  1035  		ExpectedErr: "Non-unique table name / alias: 'bad'",
  1036  	},
  1037  	{
  1038  		Name: "column name has mixed case, select lower case",
  1039  		AdditionalSetup: CreateTableWithRowsFn("test",
  1040  			NewSchema("MiXeDcAsE", types.StringKind),
  1041  			[]types.Value{types.String("1")}),
  1042  		Query:           "select mixedcase from test",
  1043  		ExpectedSchema:  NewResultSetSchema("mixedcase", types.StringKind),
  1044  		ExpectedRows:    []sql.Row{{"1"}},
  1045  		SkipOnSqlEngine: true,
  1046  	},
  1047  	{
  1048  		Name: "column name has mixed case, select upper case",
  1049  		AdditionalSetup: CreateTableWithRowsFn("test",
  1050  			NewSchema("MiXeDcAsE", types.StringKind),
  1051  			[]types.Value{types.String("1")}),
  1052  		Query:           "select MIXEDCASE from test",
  1053  		ExpectedSchema:  NewResultSetSchema("MIXEDCASE", types.StringKind),
  1054  		ExpectedRows:    []sql.Row{{"1"}},
  1055  		SkipOnSqlEngine: true,
  1056  	},
  1057  	{
  1058  		Name: "select with multiple matching columns, exact match",
  1059  		AdditionalSetup: CreateTableWithRowsFn("test",
  1060  			NewSchema("MiXeDcAsE", types.StringKind, "mixedcase", types.StringKind),
  1061  			[]types.Value{types.String("1"), types.String("2")}),
  1062  		Query:           "select mixedcase from test",
  1063  		ExpectedSchema:  NewResultSetSchema("mixedcase", types.StringKind),
  1064  		ExpectedRows:    []sql.Row{{"1"}},
  1065  		SkipOnSqlEngine: true, // TODO: table should be illegal. field names cannot be the same case-insensitive
  1066  	},
  1067  	{
  1068  		Name: "column is reserved word, select not backticked",
  1069  		AdditionalSetup: CreateTableWithRowsFn("test",
  1070  			NewSchema(
  1071  				"Timestamp", types.StringKind,
  1072  				"and", types.StringKind,
  1073  				"or", types.StringKind,
  1074  				"select", types.StringKind),
  1075  			[]types.Value{types.String("1"), types.String("1.1"), types.String("aaa"), types.String("create")}),
  1076  		Query:          "select Timestamp from test",
  1077  		ExpectedRows:   []sql.Row{{"1"}},
  1078  		ExpectedSchema: NewResultSetSchema("Timestamp", types.StringKind),
  1079  	},
  1080  	{
  1081  		Name: "column is reserved word, qualified with table alias",
  1082  		AdditionalSetup: CreateTableWithRowsFn("test",
  1083  			NewSchema(
  1084  				"Timestamp", types.StringKind,
  1085  				"and", types.StringKind,
  1086  				"or", types.StringKind,
  1087  				"select", types.StringKind),
  1088  			[]types.Value{types.String("1"), types.String("1.1"), types.String("aaa"), types.String("create")}),
  1089  		Query:          "select t.Timestamp from test as t",
  1090  		ExpectedRows:   []sql.Row{{"1"}},
  1091  		ExpectedSchema: NewResultSetSchema("Timestamp", types.StringKind),
  1092  	},
  1093  	{
  1094  		Name: "column is reserved word, select not backticked #2",
  1095  		AdditionalSetup: CreateTableWithRowsFn("test",
  1096  			NewSchema("YeAr", types.StringKind),
  1097  			[]types.Value{types.String("1")}),
  1098  		Query:           "select Year from test",
  1099  		ExpectedSchema:  NewResultSetSchema("Year", types.StringKind),
  1100  		ExpectedRows:    []sql.Row{{"1"}},
  1101  		SkipOnSqlEngine: true,
  1102  	},
  1103  	{
  1104  		Name: "column is reserved word, select backticked",
  1105  		AdditionalSetup: CreateTableWithRowsFn("test",
  1106  			NewSchema(
  1107  				"Timestamp", types.StringKind,
  1108  				"and", types.StringKind,
  1109  				"or", types.StringKind,
  1110  				"select", types.StringKind),
  1111  			[]types.Value{types.String("1"), types.String("1.1"), types.String("aaa"), types.String("create")}),
  1112  		Query:           "select `Timestamp` from test",
  1113  		ExpectedRows:    []sql.Row{{"1"}},
  1114  		ExpectedSchema:  NewResultSetSchema("Timestamp", types.StringKind),
  1115  		SkipOnSqlEngine: true,
  1116  	},
  1117  	{
  1118  		Name: "column is reserved word, select backticked #2",
  1119  		AdditionalSetup: CreateTableWithRowsFn("test",
  1120  			NewSchema(
  1121  				"Year", types.StringKind,
  1122  				"and", types.StringKind,
  1123  				"or", types.StringKind,
  1124  				"select", types.StringKind),
  1125  			[]types.Value{types.String("1"), types.String("1.1"), types.String("aaa"), types.String("create")}),
  1126  		Query: "select `Year`, `OR`, `SELect`, `anD` from test",
  1127  		ExpectedSchema: NewResultSetSchema(
  1128  			"Year", types.StringKind,
  1129  			"OR", types.StringKind,
  1130  			"SELect", types.StringKind,
  1131  			"anD", types.StringKind),
  1132  		ExpectedRows:    []sql.Row{{"1", "aaa", "create", "1.1"}},
  1133  		SkipOnSqlEngine: true,
  1134  	},
  1135  	{
  1136  		Name: "column is reserved word, table qualified",
  1137  		AdditionalSetup: CreateTableWithRowsFn("test",
  1138  			NewSchema(
  1139  				"Year", types.StringKind,
  1140  				"and", types.StringKind,
  1141  				"or", types.StringKind,
  1142  				"select", types.StringKind),
  1143  			[]types.Value{types.String("1"), types.String("1.1"), types.String("aaa"), types.String("create")}),
  1144  		Query: "select Year, t.OR, t.SELect, t.anD from test t",
  1145  		ExpectedSchema: NewResultSetSchema(
  1146  			"Year", types.StringKind,
  1147  			"OR", types.StringKind,
  1148  			"SELect", types.StringKind,
  1149  			"anD", types.StringKind),
  1150  		ExpectedRows:    []sql.Row{{"1", "aaa", "create", "1.1"}},
  1151  		SkipOnSqlEngine: true,
  1152  	},
  1153  }
  1154  
  1155  // Tests of join functionality, basically any query involving more than one table should go here for now.
  1156  var JoinTests = []SelectTest{
  1157  	{
  1158  		Name:  "Full cross product",
  1159  		Query: `select * from people, episodes`,
  1160  		ExpectedRows: ToSqlRows(CompressSchemas(PeopleTestSchema, EpisodesTestSchema),
  1161  			ConcatRows(PeopleTestSchema, Homer, EpisodesTestSchema, Ep1),
  1162  			ConcatRows(PeopleTestSchema, Homer, EpisodesTestSchema, Ep2),
  1163  			ConcatRows(PeopleTestSchema, Homer, EpisodesTestSchema, Ep3),
  1164  			ConcatRows(PeopleTestSchema, Homer, EpisodesTestSchema, Ep4),
  1165  			ConcatRows(PeopleTestSchema, Marge, EpisodesTestSchema, Ep1),
  1166  			ConcatRows(PeopleTestSchema, Marge, EpisodesTestSchema, Ep2),
  1167  			ConcatRows(PeopleTestSchema, Marge, EpisodesTestSchema, Ep3),
  1168  			ConcatRows(PeopleTestSchema, Marge, EpisodesTestSchema, Ep4),
  1169  			ConcatRows(PeopleTestSchema, Bart, EpisodesTestSchema, Ep1),
  1170  			ConcatRows(PeopleTestSchema, Bart, EpisodesTestSchema, Ep2),
  1171  			ConcatRows(PeopleTestSchema, Bart, EpisodesTestSchema, Ep3),
  1172  			ConcatRows(PeopleTestSchema, Bart, EpisodesTestSchema, Ep4),
  1173  			ConcatRows(PeopleTestSchema, Lisa, EpisodesTestSchema, Ep1),
  1174  			ConcatRows(PeopleTestSchema, Lisa, EpisodesTestSchema, Ep2),
  1175  			ConcatRows(PeopleTestSchema, Lisa, EpisodesTestSchema, Ep3),
  1176  			ConcatRows(PeopleTestSchema, Lisa, EpisodesTestSchema, Ep4),
  1177  			ConcatRows(PeopleTestSchema, Moe, EpisodesTestSchema, Ep1),
  1178  			ConcatRows(PeopleTestSchema, Moe, EpisodesTestSchema, Ep2),
  1179  			ConcatRows(PeopleTestSchema, Moe, EpisodesTestSchema, Ep3),
  1180  			ConcatRows(PeopleTestSchema, Moe, EpisodesTestSchema, Ep4),
  1181  			ConcatRows(PeopleTestSchema, Barney, EpisodesTestSchema, Ep1),
  1182  			ConcatRows(PeopleTestSchema, Barney, EpisodesTestSchema, Ep2),
  1183  			ConcatRows(PeopleTestSchema, Barney, EpisodesTestSchema, Ep3),
  1184  			ConcatRows(PeopleTestSchema, Barney, EpisodesTestSchema, Ep4),
  1185  		),
  1186  		ExpectedSchema: CompressSchemas(PeopleTestSchema, EpisodesTestSchema),
  1187  	},
  1188  	{
  1189  		Name:  "Natural join with where clause",
  1190  		Query: `select * from people p, episodes e where e.id = p.id`,
  1191  		ExpectedRows: ToSqlRows(CompressSchemas(PeopleTestSchema, EpisodesTestSchema),
  1192  			ConcatRows(PeopleTestSchema, Marge, EpisodesTestSchema, Ep1),
  1193  			ConcatRows(PeopleTestSchema, Bart, EpisodesTestSchema, Ep2),
  1194  			ConcatRows(PeopleTestSchema, Lisa, EpisodesTestSchema, Ep3),
  1195  			ConcatRows(PeopleTestSchema, Moe, EpisodesTestSchema, Ep4),
  1196  		),
  1197  		ExpectedSchema: CompressSchemas(PeopleTestSchema, EpisodesTestSchema),
  1198  	},
  1199  	{
  1200  		Name:  "Three table natural join with where clause",
  1201  		Query: `select p.*, e.* from people p, episodes e, appearances a where a.episode_id = e.id and a.character_id = p.id`,
  1202  		ExpectedRows: ToSqlRows(CompressSchemas(PeopleTestSchema, EpisodesTestSchema),
  1203  			ConcatRows(PeopleTestSchema, Homer, EpisodesTestSchema, Ep1),
  1204  			ConcatRows(PeopleTestSchema, Homer, EpisodesTestSchema, Ep2),
  1205  			ConcatRows(PeopleTestSchema, Homer, EpisodesTestSchema, Ep3),
  1206  			ConcatRows(PeopleTestSchema, Marge, EpisodesTestSchema, Ep1),
  1207  			ConcatRows(PeopleTestSchema, Marge, EpisodesTestSchema, Ep3),
  1208  			ConcatRows(PeopleTestSchema, Bart, EpisodesTestSchema, Ep2),
  1209  			ConcatRows(PeopleTestSchema, Lisa, EpisodesTestSchema, Ep2),
  1210  			ConcatRows(PeopleTestSchema, Lisa, EpisodesTestSchema, Ep3),
  1211  			ConcatRows(PeopleTestSchema, Moe, EpisodesTestSchema, Ep2),
  1212  			ConcatRows(PeopleTestSchema, Barney, EpisodesTestSchema, Ep3),
  1213  		),
  1214  		ExpectedSchema: CompressSchemas(PeopleTestSchema, EpisodesTestSchema),
  1215  	},
  1216  	// TODO: error messages are different in SQL engine
  1217  	{
  1218  		Name:        "ambiguous column in select",
  1219  		Query:       `select id from people p, episodes e, appearances a where a.episode_id = e.id and a.character_id = p.id`,
  1220  		ExpectedErr: "Ambiguous column: 'id'",
  1221  	},
  1222  	{
  1223  		Name:        "ambiguous column in where",
  1224  		Query:       `select p.*, e.* from people p, episodes e, appearances a where a.episode_id = id and a.character_id = id`,
  1225  		ExpectedErr: "Ambiguous column: 'id'",
  1226  	},
  1227  	{
  1228  		Name:  "Natural join with where clause, select subset of columns",
  1229  		Query: `select e.id, p.id, e.name, p.first_name, p.last_name from people p, episodes e where e.id = p.id`,
  1230  		ExpectedRows: ToSqlRows(
  1231  			NewResultSetSchema("id", types.IntKind, "id", types.IntKind,
  1232  				"name", types.StringKind, "first_name", types.StringKind, "last_name", types.StringKind),
  1233  			NewResultSetRow(types.Int(1), types.Int(1), types.String("Simpsons Roasting On an Open Fire"), types.String("Marge"), types.String("Simpson")),
  1234  			NewResultSetRow(types.Int(2), types.Int(2), types.String("Bart the Genius"), types.String("Bart"), types.String("Simpson")),
  1235  			NewResultSetRow(types.Int(3), types.Int(3), types.String("Homer's Odyssey"), types.String("Lisa"), types.String("Simpson")),
  1236  			NewResultSetRow(types.Int(4), types.Int(4), types.String("There's No Disgrace Like Home"), types.String("Moe"), types.String("Szyslak")),
  1237  		),
  1238  		ExpectedSchema: NewResultSetSchema("id", types.IntKind, "id", types.IntKind,
  1239  			"name", types.StringKind, "first_name", types.StringKind, "last_name", types.StringKind),
  1240  	},
  1241  	{
  1242  		Name:  "Natural join with where clause and column aliases",
  1243  		Query: "select e.id as eid, p.id as pid, e.name as ename, p.first_name as pfirst_name, p.last_name last_name from people p, episodes e where e.id = p.id",
  1244  		ExpectedRows: ToSqlRows(
  1245  			NewResultSetSchema("eid", types.IntKind, "pid", types.IntKind,
  1246  				"ename", types.StringKind, "pfirst_name", types.StringKind, "last_name", types.StringKind),
  1247  			NewResultSetRow(types.Int(1), types.Int(1), types.String("Simpsons Roasting On an Open Fire"), types.String("Marge"), types.String("Simpson")),
  1248  			NewResultSetRow(types.Int(2), types.Int(2), types.String("Bart the Genius"), types.String("Bart"), types.String("Simpson")),
  1249  			NewResultSetRow(types.Int(3), types.Int(3), types.String("Homer's Odyssey"), types.String("Lisa"), types.String("Simpson")),
  1250  			NewResultSetRow(types.Int(4), types.Int(4), types.String("There's No Disgrace Like Home"), types.String("Moe"), types.String("Szyslak")),
  1251  		),
  1252  		ExpectedSchema: NewResultSetSchema("eid", types.IntKind, "pid", types.IntKind,
  1253  			"ename", types.StringKind, "pfirst_name", types.StringKind, "last_name", types.StringKind),
  1254  	},
  1255  	{
  1256  		Name:  "Natural join with where clause and quoted column alias",
  1257  		Query: "select e.id as eid, p.id as `p.id`, e.name as ename, p.first_name as pfirst_name, p.last_name last_name from people p, episodes e where e.id = p.id",
  1258  		ExpectedRows: ToSqlRows(
  1259  			NewResultSetSchema("eid", types.IntKind, "p.id", types.IntKind,
  1260  				"ename", types.StringKind, "pfirst_name", types.StringKind, "last_name", types.StringKind),
  1261  			NewResultSetRow(types.Int(1), types.Int(1), types.String("Simpsons Roasting On an Open Fire"), types.String("Marge"), types.String("Simpson")),
  1262  			NewResultSetRow(types.Int(2), types.Int(2), types.String("Bart the Genius"), types.String("Bart"), types.String("Simpson")),
  1263  			NewResultSetRow(types.Int(3), types.Int(3), types.String("Homer's Odyssey"), types.String("Lisa"), types.String("Simpson")),
  1264  			NewResultSetRow(types.Int(4), types.Int(4), types.String("There's No Disgrace Like Home"), types.String("Moe"), types.String("Szyslak")),
  1265  		),
  1266  		ExpectedSchema: NewResultSetSchema("eid", types.IntKind, "p.id", types.IntKind,
  1267  			"ename", types.StringKind, "pfirst_name", types.StringKind, "last_name", types.StringKind),
  1268  	},
  1269  	{
  1270  		Name:  "Natural join with join clause",
  1271  		Query: `select * from people p join episodes e on e.id = p.id`,
  1272  		ExpectedRows: ToSqlRows(CompressSchemas(PeopleTestSchema, EpisodesTestSchema),
  1273  			ConcatRows(PeopleTestSchema, Marge, EpisodesTestSchema, Ep1),
  1274  			ConcatRows(PeopleTestSchema, Bart, EpisodesTestSchema, Ep2),
  1275  			ConcatRows(PeopleTestSchema, Lisa, EpisodesTestSchema, Ep3),
  1276  			ConcatRows(PeopleTestSchema, Moe, EpisodesTestSchema, Ep4),
  1277  		),
  1278  		ExpectedSchema: CompressSchemas(PeopleTestSchema, EpisodesTestSchema),
  1279  	},
  1280  	{
  1281  		Name:  "Three table natural join with join clause",
  1282  		Query: `select p.*, e.* from people p join appearances a on a.character_id = p.id join episodes e on a.episode_id = e.id`,
  1283  		ExpectedRows: ToSqlRows(CompressSchemas(PeopleTestSchema, EpisodesTestSchema),
  1284  			ConcatRows(PeopleTestSchema, Homer, EpisodesTestSchema, Ep1),
  1285  			ConcatRows(PeopleTestSchema, Homer, EpisodesTestSchema, Ep2),
  1286  			ConcatRows(PeopleTestSchema, Homer, EpisodesTestSchema, Ep3),
  1287  			ConcatRows(PeopleTestSchema, Marge, EpisodesTestSchema, Ep1),
  1288  			ConcatRows(PeopleTestSchema, Marge, EpisodesTestSchema, Ep3),
  1289  			ConcatRows(PeopleTestSchema, Bart, EpisodesTestSchema, Ep2),
  1290  			ConcatRows(PeopleTestSchema, Lisa, EpisodesTestSchema, Ep2),
  1291  			ConcatRows(PeopleTestSchema, Lisa, EpisodesTestSchema, Ep3),
  1292  			ConcatRows(PeopleTestSchema, Moe, EpisodesTestSchema, Ep2),
  1293  			ConcatRows(PeopleTestSchema, Barney, EpisodesTestSchema, Ep3),
  1294  		),
  1295  		ExpectedSchema: CompressSchemas(PeopleTestSchema, EpisodesTestSchema),
  1296  	},
  1297  	{
  1298  		Name:  "Natural join with join clause, select subset of columns",
  1299  		Query: `select e.id, p.id, e.name, p.first_name, p.last_name from people p join episodes e on e.id = p.id`,
  1300  		ExpectedRows: ToSqlRows(
  1301  			NewResultSetSchema("id", types.IntKind, "id", types.IntKind,
  1302  				"name", types.StringKind, "first_name", types.StringKind, "last_name", types.StringKind),
  1303  			NewResultSetRow(types.Int(1), types.Int(1), types.String("Simpsons Roasting On an Open Fire"), types.String("Marge"), types.String("Simpson")),
  1304  			NewResultSetRow(types.Int(2), types.Int(2), types.String("Bart the Genius"), types.String("Bart"), types.String("Simpson")),
  1305  			NewResultSetRow(types.Int(3), types.Int(3), types.String("Homer's Odyssey"), types.String("Lisa"), types.String("Simpson")),
  1306  			NewResultSetRow(types.Int(4), types.Int(4), types.String("There's No Disgrace Like Home"), types.String("Moe"), types.String("Szyslak")),
  1307  		),
  1308  		ExpectedSchema: NewResultSetSchema("id", types.IntKind, "id", types.IntKind,
  1309  			"name", types.StringKind, "first_name", types.StringKind, "last_name", types.StringKind),
  1310  	},
  1311  	{
  1312  		Name:  "Natural join with join clause, select subset of columns, join columns not selected",
  1313  		Query: `select e.name, p.first_name, p.last_name from people p join episodes e on e.id = p.id`,
  1314  		ExpectedRows: ToSqlRows(NewResultSetSchema("name", types.StringKind, "first_name", types.StringKind, "last_name", types.StringKind),
  1315  			NewResultSetRow(types.String("Simpsons Roasting On an Open Fire"), types.String("Marge"), types.String("Simpson")),
  1316  			NewResultSetRow(types.String("Bart the Genius"), types.String("Bart"), types.String("Simpson")),
  1317  			NewResultSetRow(types.String("Homer's Odyssey"), types.String("Lisa"), types.String("Simpson")),
  1318  			NewResultSetRow(types.String("There's No Disgrace Like Home"), types.String("Moe"), types.String("Szyslak")),
  1319  		),
  1320  		ExpectedSchema: NewResultSetSchema("name", types.StringKind, "first_name", types.StringKind, "last_name", types.StringKind),
  1321  	},
  1322  	{
  1323  		Name: "Natural join with join clause, select subset of columns, order by clause",
  1324  		Query: `select e.id, p.id, e.name, p.first_name, p.last_name from people p 
  1325  							join episodes e on e.id = p.id
  1326  							order by e.name`,
  1327  		ExpectedRows: ToSqlRows(
  1328  			NewResultSetSchema("id", types.IntKind, "id", types.IntKind,
  1329  				"name", types.StringKind, "first_name", types.StringKind, "last_name", types.StringKind),
  1330  			NewResultSetRow(types.Int(2), types.Int(2), types.String("Bart the Genius"), types.String("Bart"), types.String("Simpson")),
  1331  			NewResultSetRow(types.Int(3), types.Int(3), types.String("Homer's Odyssey"), types.String("Lisa"), types.String("Simpson")),
  1332  			NewResultSetRow(types.Int(1), types.Int(1), types.String("Simpsons Roasting On an Open Fire"), types.String("Marge"), types.String("Simpson")),
  1333  			NewResultSetRow(types.Int(4), types.Int(4), types.String("There's No Disgrace Like Home"), types.String("Moe"), types.String("Szyslak")),
  1334  		),
  1335  		ExpectedSchema: NewResultSetSchema("id", types.IntKind, "id", types.IntKind,
  1336  			"name", types.StringKind, "first_name", types.StringKind, "last_name", types.StringKind),
  1337  	},
  1338  	{
  1339  		Name: "Natural join with join clause, select subset of columns, order by clause on non-selected column",
  1340  		Query: `select e.id, p.id, e.name, p.first_name, p.last_name from people p 
  1341  							join episodes e on e.id = p.id
  1342  							order by age`,
  1343  		ExpectedRows: ToSqlRows(
  1344  			NewResultSetSchema("id", types.IntKind, "id", types.IntKind,
  1345  				"name", types.StringKind, "first_name", types.StringKind, "last_name", types.StringKind),
  1346  			NewResultSetRow(types.Int(3), types.Int(3), types.String("Homer's Odyssey"), types.String("Lisa"), types.String("Simpson")),
  1347  			NewResultSetRow(types.Int(2), types.Int(2), types.String("Bart the Genius"), types.String("Bart"), types.String("Simpson")),
  1348  			NewResultSetRow(types.Int(1), types.Int(1), types.String("Simpsons Roasting On an Open Fire"), types.String("Marge"), types.String("Simpson")),
  1349  			NewResultSetRow(types.Int(4), types.Int(4), types.String("There's No Disgrace Like Home"), types.String("Moe"), types.String("Szyslak")),
  1350  		),
  1351  		ExpectedSchema: NewResultSetSchema("id", types.IntKind, "id", types.IntKind,
  1352  			"name", types.StringKind, "first_name", types.StringKind, "last_name", types.StringKind),
  1353  	},
  1354  	{
  1355  		Name:  "Natural join with join clause and column aliases",
  1356  		Query: "select e.id as eid, p.id as pid, e.name as ename, p.first_name as pfirst_name, p.last_name last_name from people p join episodes e on e.id = p.id",
  1357  		ExpectedRows: ToSqlRows(
  1358  			NewResultSetSchema("eid", types.IntKind, "pid", types.IntKind,
  1359  				"ename", types.StringKind, "pfirst_name", types.StringKind, "last_name", types.StringKind),
  1360  			NewResultSetRow(types.Int(1), types.Int(1), types.String("Simpsons Roasting On an Open Fire"), types.String("Marge"), types.String("Simpson")),
  1361  			NewResultSetRow(types.Int(2), types.Int(2), types.String("Bart the Genius"), types.String("Bart"), types.String("Simpson")),
  1362  			NewResultSetRow(types.Int(3), types.Int(3), types.String("Homer's Odyssey"), types.String("Lisa"), types.String("Simpson")),
  1363  			NewResultSetRow(types.Int(4), types.Int(4), types.String("There's No Disgrace Like Home"), types.String("Moe"), types.String("Szyslak")),
  1364  		),
  1365  		ExpectedSchema: NewResultSetSchema("eid", types.IntKind, "pid", types.IntKind,
  1366  			"ename", types.StringKind, "pfirst_name", types.StringKind, "last_name", types.StringKind),
  1367  	},
  1368  	{
  1369  		Name:  "Natural join with join clause and column aliases, order by",
  1370  		Query: "select e.id as eid, p.id as pid, e.name as ename, p.first_name as pfirst_name, p.last_name last_name from people p join episodes e on e.id = p.id order by ename",
  1371  		ExpectedRows: ToSqlRows(
  1372  			NewResultSetSchema("eid", types.IntKind, "pid", types.IntKind,
  1373  				"ename", types.StringKind, "pfirst_name", types.StringKind, "last_name", types.StringKind),
  1374  			NewResultSetRow(types.Int(2), types.Int(2), types.String("Bart the Genius"), types.String("Bart"), types.String("Simpson")),
  1375  			NewResultSetRow(types.Int(3), types.Int(3), types.String("Homer's Odyssey"), types.String("Lisa"), types.String("Simpson")),
  1376  			NewResultSetRow(types.Int(1), types.Int(1), types.String("Simpsons Roasting On an Open Fire"), types.String("Marge"), types.String("Simpson")),
  1377  			NewResultSetRow(types.Int(4), types.Int(4), types.String("There's No Disgrace Like Home"), types.String("Moe"), types.String("Szyslak")),
  1378  		),
  1379  		ExpectedSchema: NewResultSetSchema("eid", types.IntKind, "pid", types.IntKind,
  1380  			"ename", types.StringKind, "pfirst_name", types.StringKind, "last_name", types.StringKind),
  1381  	},
  1382  	{
  1383  		Name:  "Natural join with join clause and quoted column alias",
  1384  		Query: "select e.id as eid, p.id as `p.id`, e.name as ename, p.first_name as pfirst_name, p.last_name last_name from people p join episodes e on e.id = p.id",
  1385  		ExpectedRows: ToSqlRows(
  1386  			NewResultSetSchema("eid", types.IntKind, "p.id", types.IntKind,
  1387  				"ename", types.StringKind, "pfirst_name", types.StringKind, "last_name", types.StringKind),
  1388  			NewResultSetRow(types.Int(1), types.Int(1), types.String("Simpsons Roasting On an Open Fire"), types.String("Marge"), types.String("Simpson")),
  1389  			NewResultSetRow(types.Int(2), types.Int(2), types.String("Bart the Genius"), types.String("Bart"), types.String("Simpson")),
  1390  			NewResultSetRow(types.Int(3), types.Int(3), types.String("Homer's Odyssey"), types.String("Lisa"), types.String("Simpson")),
  1391  			NewResultSetRow(types.Int(4), types.Int(4), types.String("There's No Disgrace Like Home"), types.String("Moe"), types.String("Szyslak")),
  1392  		),
  1393  		ExpectedSchema: NewResultSetSchema("eid", types.IntKind, "p.id", types.IntKind,
  1394  			"ename", types.StringKind, "pfirst_name", types.StringKind, "last_name", types.StringKind),
  1395  	},
  1396  	{
  1397  		Name: "Join from table with two key columns to table with one key column",
  1398  		Query: `select a.episode_id as eid, p.id as pid, p.first_name
  1399  						from appearances a join people p on a.character_id = p.id order by eid, pid`,
  1400  		ExpectedRows: ToSqlRows(
  1401  			NewResultSetSchema("eid", types.IntKind, "pid", types.IntKind,
  1402  				"first_name", types.StringKind),
  1403  			NewResultSetRow(types.Int(1), types.Int(0), types.String("Homer")),
  1404  			NewResultSetRow(types.Int(1), types.Int(1), types.String("Marge")),
  1405  			NewResultSetRow(types.Int(2), types.Int(0), types.String("Homer")),
  1406  			NewResultSetRow(types.Int(2), types.Int(2), types.String("Bart")),
  1407  			NewResultSetRow(types.Int(2), types.Int(3), types.String("Lisa")),
  1408  			NewResultSetRow(types.Int(2), types.Int(4), types.String("Moe")),
  1409  			NewResultSetRow(types.Int(3), types.Int(0), types.String("Homer")),
  1410  			NewResultSetRow(types.Int(3), types.Int(1), types.String("Marge")),
  1411  			NewResultSetRow(types.Int(3), types.Int(3), types.String("Lisa")),
  1412  			NewResultSetRow(types.Int(3), types.Int(5), types.String("Barney")),
  1413  		),
  1414  		ExpectedSchema: NewResultSetSchema("eid", types.IntKind, "pid", types.IntKind,
  1415  			"first_name", types.StringKind),
  1416  	},
  1417  }
  1418  
  1419  func TestSelect(t *testing.T) {
  1420  	for _, test := range BasicSelectTests {
  1421  		t.Run(test.Name, func(t *testing.T) {
  1422  			testSelectQuery(t, test)
  1423  		})
  1424  	}
  1425  }
  1426  
  1427  func TestDiffQueries(t *testing.T) {
  1428  	for _, test := range SelectDiffTests {
  1429  		t.Run(test.Name, func(t *testing.T) {
  1430  			testSelectDiffQuery(t, test)
  1431  		})
  1432  	}
  1433  }
  1434  
  1435  func TestAsOfQueries(t *testing.T) {
  1436  	for _, test := range AsOfTests {
  1437  		t.Run(test.Name, func(t *testing.T) {
  1438  			// AS OF queries use the same history as the diff tests, so exercise the same test setup
  1439  			testSelectDiffQuery(t, test)
  1440  		})
  1441  	}
  1442  }
  1443  
  1444  func TestJoins(t *testing.T) {
  1445  	for _, tt := range JoinTests {
  1446  		if tt.Name == "Join from table with two key columns to table with one key column" {
  1447  			t.Run(tt.Name, func(t *testing.T) {
  1448  				testSelectQuery(t, tt)
  1449  			})
  1450  		}
  1451  	}
  1452  }
  1453  
  1454  // Tests of case sensitivity handling
  1455  func TestCaseSensitivity(t *testing.T) {
  1456  	for _, tt := range CaseSensitivityTests {
  1457  		t.Run(tt.Name, func(t *testing.T) {
  1458  			testSelectQuery(t, tt)
  1459  		})
  1460  	}
  1461  }
  1462  
  1463  var systemTableSelectTests = []SelectTest{
  1464  	{
  1465  		Name: "select from dolt_docs",
  1466  		AdditionalSetup: CreateTableFn("dolt_docs",
  1467  			doltdocs.Schema,
  1468  			NewRowWithSchema(doltdocs.Schema,
  1469  				types.String("LICENSE.md"),
  1470  				types.String("A license")),
  1471  		),
  1472  		Query: "select * from dolt_docs",
  1473  		ExpectedRows: ToSqlRows(CompressSchema(doltdocs.Schema),
  1474  			NewRow(types.String("LICENSE.md"), types.String("A license"))),
  1475  		ExpectedSchema: CompressSchema(doltdocs.Schema),
  1476  	},
  1477  	{
  1478  		Name: "select from dolt_query_catalog",
  1479  		AdditionalSetup: CreateTableFn(doltdb.DoltQueryCatalogTableName,
  1480  			dtables.DoltQueryCatalogSchema,
  1481  			NewRowWithSchema(dtables.DoltQueryCatalogSchema,
  1482  				types.String("existingEntry"),
  1483  				types.Uint(2),
  1484  				types.String("example"),
  1485  				types.String("select 2+2 from dual"),
  1486  				types.String("description")),
  1487  		),
  1488  		Query: "select * from dolt_query_catalog",
  1489  		ExpectedRows: ToSqlRows(CompressSchema(dtables.DoltQueryCatalogSchema),
  1490  			NewRow(types.String("existingEntry"), types.Uint(2), types.String("example"), types.String("select 2+2 from dual"), types.String("description")),
  1491  		),
  1492  		ExpectedSchema: CompressSchema(dtables.DoltQueryCatalogSchema),
  1493  	},
  1494  	{
  1495  		Name: "select from dolt_schemas",
  1496  		AdditionalSetup: CreateTableFn(doltdb.SchemasTableName,
  1497  			schemasTableDoltSchema(),
  1498  			NewRowWithSchema(schemasTableDoltSchema(),
  1499  				types.String("view"),
  1500  				types.String("name"),
  1501  				types.String("select 2+2 from dual"),
  1502  				types.Int(1),
  1503  			)),
  1504  		Query: "select * from dolt_schemas",
  1505  		ExpectedRows: ToSqlRows(CompressSchema(schemasTableDoltSchema()),
  1506  			NewRow(types.String("view"), types.String("name"), types.String("select 2+2 from dual"), types.Int(1)),
  1507  		),
  1508  		ExpectedSchema: CompressSchema(schemasTableDoltSchema()),
  1509  	},
  1510  }
  1511  
  1512  func TestSelectSystemTables(t *testing.T) {
  1513  	for _, test := range systemTableSelectTests {
  1514  		t.Run(test.Name, func(t *testing.T) {
  1515  			testSelectQuery(t, test)
  1516  		})
  1517  	}
  1518  }
  1519  
  1520  type testCommitClock struct {
  1521  	unixNano int64
  1522  }
  1523  
  1524  func (tcc *testCommitClock) Now() time.Time {
  1525  	now := time.Unix(0, tcc.unixNano)
  1526  	tcc.unixNano += int64(time.Hour)
  1527  	return now
  1528  }
  1529  
  1530  // Tests the given query on a freshly created dataset, asserting that the result has the given schema and rows. If
  1531  // expectedErr is set, asserts instead that the execution returns an error that matches.
  1532  func testSelectQuery(t *testing.T, test SelectTest) {
  1533  	validateTest(t, test)
  1534  
  1535  	tcc := &testCommitClock{}
  1536  	doltdb.CommitNowFunc = tcc.Now
  1537  	doltdb.CommitLoc = time.UTC
  1538  
  1539  	dEnv := dtestutils.CreateTestEnv()
  1540  	CreateTestDatabase(dEnv, t)
  1541  
  1542  	if test.AdditionalSetup != nil {
  1543  		test.AdditionalSetup(t, dEnv)
  1544  	}
  1545  
  1546  	root, _ := dEnv.WorkingRoot(context.Background())
  1547  	actualRows, sch, err := executeSelect(context.Background(), dEnv, root, test.Query)
  1548  	if len(test.ExpectedErr) > 0 {
  1549  		require.Error(t, err)
  1550  		// Too much work to synchronize error messages between the two implementations, so for now we'll just assert that an error occurred.
  1551  		// require.Contains(t, err.Error(), test.ExpectedErr)
  1552  		return
  1553  	} else {
  1554  		require.NoError(t, err)
  1555  	}
  1556  
  1557  	assert.Equal(t, test.ExpectedRows, actualRows)
  1558  	var sqlSchema sql.Schema
  1559  	if test.ExpectedSqlSchema != nil {
  1560  		sqlSchema = test.ExpectedSqlSchema
  1561  	} else {
  1562  		sqlSchema = mustSqlSchema(test.ExpectedSchema)
  1563  	}
  1564  
  1565  	assertSchemasEqual(t, sqlSchema, sch)
  1566  }
  1567  
  1568  func testSelectDiffQuery(t *testing.T, test SelectTest) {
  1569  	validateTest(t, test)
  1570  
  1571  	ctx := context.Background()
  1572  	tcc := &testCommitClock{}
  1573  	doltdb.CommitNowFunc = tcc.Now
  1574  	doltdb.CommitLoc = time.UTC
  1575  
  1576  	dEnv := dtestutils.CreateTestEnv()
  1577  	envtestutils.InitializeWithHistory(t, ctx, dEnv, CreateHistory(ctx, dEnv, t)...)
  1578  	if test.AdditionalSetup != nil {
  1579  		test.AdditionalSetup(t, dEnv)
  1580  	}
  1581  
  1582  	cs, err := doltdb.NewCommitSpec("master")
  1583  	require.NoError(t, err)
  1584  
  1585  	cm, err := dEnv.DoltDB.Resolve(ctx, cs, nil)
  1586  	require.NoError(t, err)
  1587  
  1588  	root, err := cm.GetRootValue()
  1589  	require.NoError(t, err)
  1590  
  1591  	_, err = dEnv.UpdateStagedRoot(ctx, root)
  1592  	require.NoError(t, err)
  1593  
  1594  	err = dEnv.UpdateWorkingRoot(ctx, root)
  1595  	require.NoError(t, err)
  1596  
  1597  	root, err = dEnv.WorkingRoot(context.Background())
  1598  	require.NoError(t, err)
  1599  
  1600  	root = envtestutils.UpdateTables(t, ctx, root, CreateWorkingRootUpdate())
  1601  
  1602  	err = dEnv.UpdateWorkingRoot(ctx, root)
  1603  	require.NoError(t, err)
  1604  
  1605  	actualRows, sch, err := executeSelect(ctx, dEnv, root, test.Query)
  1606  	if len(test.ExpectedErr) > 0 {
  1607  		require.Error(t, err)
  1608  		return
  1609  	} else {
  1610  		require.NoError(t, err)
  1611  	}
  1612  
  1613  	assert.Equal(t, test.ExpectedRows, actualRows)
  1614  
  1615  	var sqlSchema sql.Schema
  1616  	if test.ExpectedSqlSchema != nil {
  1617  		sqlSchema = test.ExpectedSqlSchema
  1618  	} else {
  1619  		sqlSchema = mustSqlSchema(test.ExpectedSchema)
  1620  	}
  1621  
  1622  	assertSchemasEqual(t, sqlSchema, sch)
  1623  }
  1624  
  1625  func validateTest(t *testing.T, test SelectTest) {
  1626  	if (test.ExpectedRows == nil) != (test.ExpectedSchema == nil && test.ExpectedSqlSchema == nil) {
  1627  		require.Fail(t, "Incorrect test setup: schema and rows must both be provided if one is")
  1628  	}
  1629  
  1630  	if len(test.ExpectedErr) == 0 && (test.ExpectedSchema == nil) == (test.ExpectedSqlSchema == nil) {
  1631  		require.Fail(t, "Incorrect test setup: must set at most one of ExpectedSchema, ExpectedSqlSchema")
  1632  	}
  1633  
  1634  	if len(singleSelectQueryTest) > 0 && test.Name != singleSelectQueryTest {
  1635  		t.Skip("Skipping tests until " + singleSelectQueryTest)
  1636  	}
  1637  
  1638  	if len(singleSelectQueryTest) == 0 && test.SkipOnSqlEngine && skipBrokenSelect {
  1639  		t.Skip("Skipping test broken on SQL engine")
  1640  	}
  1641  }