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

     1  // Copyright 2019 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  	"fmt"
    20  	"strings"
    21  	"testing"
    22  
    23  	"github.com/dolthub/go-mysql-server/sql"
    24  	"github.com/dolthub/vitess/go/sqltypes"
    25  	"github.com/stretchr/testify/assert"
    26  	"github.com/stretchr/testify/require"
    27  
    28  	"github.com/dolthub/dolt/go/libraries/doltcore/doltdb"
    29  	"github.com/dolthub/dolt/go/libraries/doltcore/doltdocs"
    30  	"github.com/dolthub/dolt/go/libraries/doltcore/dtestutils"
    31  	"github.com/dolthub/dolt/go/libraries/doltcore/env"
    32  	"github.com/dolthub/dolt/go/libraries/doltcore/row"
    33  	"github.com/dolthub/dolt/go/libraries/doltcore/schema"
    34  	. "github.com/dolthub/dolt/go/libraries/doltcore/sql/sqltestutil"
    35  	"github.com/dolthub/dolt/go/libraries/doltcore/sqle/dtables"
    36  	"github.com/dolthub/dolt/go/libraries/doltcore/sqle/sqlutil"
    37  	"github.com/dolthub/dolt/go/store/types"
    38  )
    39  
    40  func TestCreateTable(t *testing.T) {
    41  	tests := []struct {
    42  		name           string
    43  		query          string
    44  		expectedTable  string
    45  		expectedSchema schema.Schema
    46  		expectedErr    string
    47  	}{
    48  		{
    49  			name:          "Test create single column schema",
    50  			query:         "create table testTable (id int primary key)",
    51  			expectedTable: "testTable",
    52  			expectedSchema: dtestutils.CreateSchema(
    53  				schemaNewColumn(t, "id", 4817, sql.Int32, true, schema.NotNullConstraint{})),
    54  		},
    55  		{
    56  			name:          "Test create two column schema",
    57  			query:         "create table testTable (id int primary key, age int)",
    58  			expectedTable: "testTable",
    59  			expectedSchema: dtestutils.CreateSchema(
    60  				schemaNewColumn(t, "id", 4817, sql.Int32, true, schema.NotNullConstraint{}),
    61  				schemaNewColumn(t, "age", 7208, sql.Int32, false)),
    62  		},
    63  		{
    64  			name:          "Test create two column keyless schema",
    65  			query:         "create table testTable (id int, age int)",
    66  			expectedTable: "testTable",
    67  			expectedSchema: dtestutils.CreateSchema(
    68  				schemaNewColumn(t, "id", 4817, sql.Int32, false),
    69  				schemaNewColumn(t, "age", 7208, sql.Int32, false)),
    70  		},
    71  		{
    72  			name:          "Test syntax error",
    73  			query:         "create table testTable id int, age int",
    74  			expectedTable: "testTable",
    75  			expectedErr:   "syntax error",
    76  		},
    77  		{
    78  			name:        "Test bad table name",
    79  			query:       "create table -testTable (id int primary key, age int)",
    80  			expectedErr: "syntax error",
    81  		},
    82  		{
    83  			name:        "Test reserved table name",
    84  			query:       "create table dolt_table (id int primary key, age int)",
    85  			expectedErr: "Invalid table name",
    86  		},
    87  		{
    88  			name:        "Test bad table name begins with number",
    89  			query:       "create table 1testTable (id int primary key, age int)",
    90  			expectedErr: "syntax error",
    91  		},
    92  		{
    93  			name:        "Test in use table name",
    94  			query:       "create table people (id int primary key, age int)",
    95  			expectedErr: "table with name people already exists",
    96  		},
    97  		{
    98  			name:           "Test in use table name with if not exists",
    99  			query:          "create table if not exists people (id int primary key, age int)",
   100  			expectedTable:  "people",
   101  			expectedSchema: PeopleTestSchema,
   102  		},
   103  		{
   104  			name: "Test types",
   105  			query: `create table testTable (
   106  								id int primary key, 
   107  								age int, 
   108  								first_name varchar(255), 
   109  								is_married boolean) `,
   110  			expectedTable: "testTable",
   111  			expectedSchema: dtestutils.CreateSchema(
   112  				schemaNewColumn(t, "id", 4817, sql.Int32, true, schema.NotNullConstraint{}),
   113  				schemaNewColumn(t, "age", 7208, sql.Int32, false),
   114  				schemaNewColumn(t, "first_name", 3264, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 255), false),
   115  				schemaNewColumn(t, "is_married", 14626, sql.Boolean, false)),
   116  		},
   117  		{
   118  			name:          "Test all supported types",
   119  			expectedTable: "testTable",
   120  			query: `create table testTable (
   121  							c0 int primary key,
   122  							c1 tinyint,
   123  							c2 smallint,
   124  							c3 mediumint,
   125  							c4 integer,
   126  							c5 bigint,
   127  							c6 bool,
   128  							c7 boolean,
   129  							c8 bit(10),
   130  							c9 text,
   131  							c10 tinytext,
   132  							c11 mediumtext,
   133  							c12 longtext,
   134  							c16 char(5),
   135  							c17 varchar(255),
   136  							c18 varchar(80),
   137  							c19 float,
   138  							c20 double,
   139  							c22 int unsigned,
   140  							c23 tinyint unsigned,
   141  							c24 smallint unsigned,
   142  							c25 mediumint unsigned,
   143  							c26 bigint unsigned)`,
   144  			expectedSchema: dtestutils.CreateSchema(
   145  				schemaNewColumn(t, "c0", 594, sql.Int32, true, schema.NotNullConstraint{}),
   146  				schemaNewColumn(t, "c1", 601, sql.Int8, false),
   147  				schemaNewColumn(t, "c2", 14542, sql.Int16, false),
   148  				schemaNewColumn(t, "c3", 13309, sql.Int24, false),
   149  				schemaNewColumn(t, "c4", 15884, sql.Int32, false),
   150  				schemaNewColumn(t, "c5", 14619, sql.Int64, false),
   151  				schemaNewColumn(t, "c6", 13192, sql.Boolean, false),
   152  				schemaNewColumn(t, "c7", 5981, sql.Boolean, false),
   153  				schemaNewColumn(t, "c8", 14871, sql.MustCreateBitType(10), false),
   154  				schemaNewColumn(t, "c9", 4167, sql.Text, false),
   155  				schemaNewColumn(t, "c10", 1965, sql.TinyText, false),
   156  				schemaNewColumn(t, "c11", 12860, sql.MediumText, false),
   157  				schemaNewColumn(t, "c12", 7155, sql.LongText, false),
   158  				//schemaNewColumn(t, "c13", 113, sql.TinyBlob, false),
   159  				//schemaNewColumn(t, "c14", 114, sql.Blob, false),
   160  				//schemaNewColumn(t, "c15", 115, sql.LongBlob, false),
   161  				schemaNewColumn(t, "c16", 15859, sql.MustCreateStringWithDefaults(sqltypes.Char, 5), false),
   162  				schemaNewColumn(t, "c17", 11710, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 255), false),
   163  				schemaNewColumn(t, "c18", 6838, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 80), false),
   164  				schemaNewColumn(t, "c19", 9377, sql.Float32, false),
   165  				schemaNewColumn(t, "c20", 15979, sql.Float64, false),
   166  				//schemaNewColumn(t, "c21", 121, sql.MustCreateDecimalType(10, 5), false),
   167  				schemaNewColumn(t, "c22", 2910, sql.Uint32, false),
   168  				schemaNewColumn(t, "c23", 8740, sql.Uint8, false),
   169  				schemaNewColumn(t, "c24", 8689, sql.Uint16, false),
   170  				schemaNewColumn(t, "c25", 5243, sql.Uint24, false),
   171  				schemaNewColumn(t, "c26", 9338, sql.Uint64, false),
   172  			),
   173  		},
   174  		{
   175  			name: "Test primary keys",
   176  			query: `create table testTable (
   177  								id int, 
   178  								age int, 
   179  								first_name varchar(80), 
   180  								is_married bool, 
   181  								primary key (id, age))`,
   182  			expectedTable: "testTable",
   183  			expectedSchema: dtestutils.CreateSchema(
   184  				schemaNewColumn(t, "id", 4817, sql.Int32, true, schema.NotNullConstraint{}),
   185  				schemaNewColumn(t, "age", 7208, sql.Int32, true, schema.NotNullConstraint{}),
   186  				schemaNewColumn(t, "first_name", 3264, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 80), false),
   187  				schemaNewColumn(t, "is_married", 14626, sql.Boolean, false)),
   188  		},
   189  		{
   190  			name: "Test not null constraints",
   191  			query: `create table testTable (
   192  								id int, 
   193  								age int, 
   194  								first_name varchar(80) not null, 
   195  								is_married bool, 
   196  								primary key (id, age))`,
   197  			expectedTable: "testTable",
   198  			expectedSchema: dtestutils.CreateSchema(
   199  				schemaNewColumn(t, "id", 4817, sql.Int32, true, schema.NotNullConstraint{}),
   200  				schemaNewColumn(t, "age", 7208, sql.Int32, true, schema.NotNullConstraint{}),
   201  				schemaNewColumn(t, "first_name", 3264, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 80), false, schema.NotNullConstraint{}),
   202  				schemaNewColumn(t, "is_married", 14626, sql.Boolean, false)),
   203  		},
   204  		{
   205  			name: "Test quoted columns",
   206  			query: "create table testTable (" +
   207  				"`id` int, " +
   208  				"`age` int, " +
   209  				"`timestamp` varchar(80), " +
   210  				"`is married` bool, " +
   211  				"primary key (`id`, `age`))",
   212  			expectedTable: "testTable",
   213  			expectedSchema: dtestutils.CreateSchema(
   214  				schemaNewColumn(t, "id", 4817, sql.Int32, true, schema.NotNullConstraint{}),
   215  				schemaNewColumn(t, "age", 7208, sql.Int32, true, schema.NotNullConstraint{}),
   216  				schemaNewColumn(t, "timestamp", 10168, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 80), false),
   217  				schemaNewColumn(t, "is married", 14626, sql.Boolean, false)),
   218  		},
   219  		{
   220  			name: "Test tag comments",
   221  			query: `create table testTable (
   222  								id int primary key, age int)`,
   223  			expectedTable: "testTable",
   224  			expectedSchema: dtestutils.CreateSchema(
   225  				schemaNewColumn(t, "id", 4817, sql.Int32, true, schema.NotNullConstraint{}),
   226  				schemaNewColumn(t, "age", 7208, sql.Int32, false)),
   227  		},
   228  		// Real world examples for regression testing
   229  		{
   230  			name: "Test ip2nation",
   231  			query: `CREATE TABLE ip2nation (
   232  							ip int(11) unsigned NOT NULL default 0,
   233  							country char(2) NOT NULL default '',
   234  							PRIMARY KEY (ip));`,
   235  			expectedTable: "ip2nation",
   236  			expectedSchema: dtestutils.CreateSchema(
   237  				schemaNewColumnWDefVal(t, "ip", 7265, sql.Uint32, true, "0", schema.NotNullConstraint{}),
   238  				schemaNewColumnWDefVal(t, "country", 6630, sql.MustCreateStringWithDefaults(sqltypes.Char, 2), false, `""`, schema.NotNullConstraint{})),
   239  		},
   240  		{
   241  			name:          "Test ip2nationCountries",
   242  			expectedTable: "ip2nationCountries",
   243  			query: `CREATE TABLE ip2nationCountries (
   244  							code varchar(4) NOT NULL default '',
   245  							iso_code_2 varchar(2) NOT NULL default '',
   246  							iso_code_3 varchar(3) default '',
   247  							iso_country varchar(255) NOT NULL default '',
   248  							country varchar(255) NOT NULL default '',
   249  							lat float NOT NULL default 0.0,
   250  							lon float NOT NULL default 0.0,
   251  							PRIMARY KEY (code));`,
   252  			expectedSchema: dtestutils.CreateSchema(
   253  				schemaNewColumnWDefVal(t, "code", 7802, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 4), true, `""`, schema.NotNullConstraint{}),
   254  				schemaNewColumnWDefVal(t, "iso_code_2", 9266, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2), false, `""`, schema.NotNullConstraint{}),
   255  				schemaNewColumnWDefVal(t, "iso_code_3", 8427, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 3), false, `""`),
   256  				schemaNewColumnWDefVal(t, "iso_country", 7151, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 255), false, `""`, schema.NotNullConstraint{}),
   257  				schemaNewColumnWDefVal(t, "country", 879, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 255), false, `""`, schema.NotNullConstraint{}),
   258  				schemaNewColumnWDefVal(t, "lat", 3502, sql.Float32, false, "0", schema.NotNullConstraint{}),
   259  				schemaNewColumnWDefVal(t, "lon", 9907, sql.Float32, false, "0", schema.NotNullConstraint{})),
   260  		},
   261  	}
   262  
   263  	for _, tt := range tests {
   264  		t.Run(tt.name, func(t *testing.T) {
   265  			dEnv := dtestutils.CreateTestEnv()
   266  			dtestutils.CreateTestTable(t, dEnv, PeopleTableName, PeopleTestSchema, AllPeopleRows...)
   267  			ctx := context.Background()
   268  			root, _ := dEnv.WorkingRoot(ctx)
   269  
   270  			updatedRoot, err := ExecuteSql(dEnv, root, tt.query)
   271  
   272  			if tt.expectedErr == "" {
   273  				require.NoError(t, err)
   274  			} else {
   275  				require.Error(t, err)
   276  				assert.Contains(t, err.Error(), tt.expectedErr)
   277  				return
   278  			}
   279  
   280  			require.NotNil(t, updatedRoot)
   281  
   282  			table, ok, err := updatedRoot.GetTable(ctx, tt.expectedTable)
   283  			require.True(t, ok)
   284  			require.NoError(t, err)
   285  
   286  			sch, err := table.GetSchema(ctx)
   287  			require.NoError(t, err)
   288  			equalSchemas(t, tt.expectedSchema, sch)
   289  		})
   290  	}
   291  }
   292  
   293  func TestDropTable(t *testing.T) {
   294  	tests := []struct {
   295  		name        string
   296  		query       string
   297  		tableNames  []string
   298  		expectedErr string
   299  	}{
   300  		{
   301  			name:       "drop table",
   302  			query:      "drop table people",
   303  			tableNames: []string{"people"},
   304  		},
   305  		{
   306  			name:       "drop table case insensitive",
   307  			query:      "drop table PEOPLE",
   308  			tableNames: []string{"people"},
   309  		},
   310  		{
   311  			name:       "drop table if exists",
   312  			query:      "drop table if exists people",
   313  			tableNames: []string{"people"},
   314  		},
   315  		{
   316  			name:        "drop non existent",
   317  			query:       "drop table notfound",
   318  			expectedErr: "table not found: notfound",
   319  		},
   320  		{
   321  			name:       "drop non existent if exists",
   322  			query:      "drop table if exists notFound",
   323  			tableNames: []string{"notFound"},
   324  		},
   325  		{
   326  			name:       "drop many tables",
   327  			query:      "drop table people, appearances, episodes",
   328  			tableNames: []string{"people", "appearances", "episodes"},
   329  		},
   330  		{
   331  			name:       "drop many tables, some don't exist",
   332  			query:      "drop table if exists people, not_real, appearances, episodes",
   333  			tableNames: []string{"people", "appearances", "not_real", "episodes"},
   334  		},
   335  	}
   336  
   337  	for _, tt := range tests {
   338  		t.Run(tt.name, func(t *testing.T) {
   339  			dEnv := dtestutils.CreateTestEnv()
   340  			CreateTestDatabase(dEnv, t)
   341  			ctx := context.Background()
   342  			root, _ := dEnv.WorkingRoot(ctx)
   343  
   344  			updatedRoot, err := ExecuteSql(dEnv, root, tt.query)
   345  
   346  			if tt.expectedErr == "" {
   347  				require.NoError(t, err)
   348  			} else {
   349  				require.Error(t, err)
   350  				assert.Contains(t, err.Error(), tt.expectedErr)
   351  				return
   352  			}
   353  
   354  			require.NotNil(t, updatedRoot)
   355  			for _, tableName := range tt.tableNames {
   356  				has, err := updatedRoot.HasTable(ctx, tableName)
   357  				assert.NoError(t, err)
   358  				assert.False(t, has)
   359  			}
   360  		})
   361  	}
   362  }
   363  
   364  func TestAddColumn(t *testing.T) {
   365  	tests := []struct {
   366  		name           string
   367  		query          string
   368  		expectedSchema schema.Schema
   369  		expectedRows   []row.Row
   370  		expectedErr    string
   371  	}{
   372  		{
   373  			name:  "alter add column",
   374  			query: "alter table people add (newColumn varchar(80))",
   375  			expectedSchema: dtestutils.AddColumnToSchema(PeopleTestSchema,
   376  				schemaNewColumn(t, "newColumn", 4208, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 80), false)),
   377  			expectedRows: dtestutils.AddColToRows(t, AllPeopleRows, 4208, nil),
   378  		},
   379  		{
   380  			name:  "alter add column first",
   381  			query: "alter table people add newColumn varchar(80) first",
   382  			expectedSchema: dtestutils.CreateSchema(
   383  				schemaNewColumn(t, "newColumn", 4208, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 80), false),
   384  				schema.NewColumn("id", IdTag, types.IntKind, true, schema.NotNullConstraint{}),
   385  				schema.NewColumn("first_name", FirstNameTag, types.StringKind, false, schema.NotNullConstraint{}),
   386  				schema.NewColumn("last_name", LastNameTag, types.StringKind, false, schema.NotNullConstraint{}),
   387  				schema.NewColumn("is_married", IsMarriedTag, types.BoolKind, false),
   388  				schema.NewColumn("age", AgeTag, types.IntKind, false),
   389  				schema.NewColumn("rating", RatingTag, types.FloatKind, false),
   390  				schema.NewColumn("uuid", UuidTag, types.UUIDKind, false),
   391  				schema.NewColumn("num_episodes", NumEpisodesTag, types.UintKind, false),
   392  			),
   393  			expectedRows: dtestutils.AddColToRows(t, AllPeopleRows, 4208, nil),
   394  		},
   395  		{
   396  			name:  "alter add column middle",
   397  			query: "alter table people add newColumn varchar(80) after last_name",
   398  			expectedSchema: dtestutils.CreateSchema(
   399  				schema.NewColumn("id", IdTag, types.IntKind, true, schema.NotNullConstraint{}),
   400  				schema.NewColumn("first_name", FirstNameTag, types.StringKind, false, schema.NotNullConstraint{}),
   401  				schema.NewColumn("last_name", LastNameTag, types.StringKind, false, schema.NotNullConstraint{}),
   402  				schemaNewColumn(t, "newColumn", 4208, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 80), false),
   403  				schema.NewColumn("is_married", IsMarriedTag, types.BoolKind, false),
   404  				schema.NewColumn("age", AgeTag, types.IntKind, false),
   405  				schema.NewColumn("rating", RatingTag, types.FloatKind, false),
   406  				schema.NewColumn("uuid", UuidTag, types.UUIDKind, false),
   407  				schema.NewColumn("num_episodes", NumEpisodesTag, types.UintKind, false),
   408  			),
   409  			expectedRows: dtestutils.AddColToRows(t, AllPeopleRows, 4208, nil),
   410  		},
   411  		{
   412  			name:  "alter add column not null",
   413  			query: "alter table people add (newColumn varchar(80) not null default 'default')",
   414  			expectedSchema: dtestutils.AddColumnToSchema(PeopleTestSchema,
   415  				schemaNewColumnWDefVal(t, "newColumn", 4208, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 80), false, `"default"`, schema.NotNullConstraint{})),
   416  			expectedRows: dtestutils.AddColToRows(t, AllPeopleRows, 4208, types.String("default")),
   417  		},
   418  		{
   419  			name:  "alter add column not null with expression default",
   420  			query: "alter table people add (newColumn int not null default 2+2/2)",
   421  			expectedSchema: dtestutils.AddColumnToSchema(PeopleTestSchema,
   422  				schemaNewColumnWDefVal(t, "newColumn", 4435, sql.Int32, false, "((2 + (2 / 2)))", schema.NotNullConstraint{})),
   423  			expectedRows: dtestutils.AddColToRows(t, AllPeopleRows, 4435, types.Int(3)),
   424  		},
   425  		{
   426  			name:  "alter add column not null with negative expression",
   427  			query: "alter table people add (newColumn float not null default -1.1)",
   428  			expectedSchema: dtestutils.AddColumnToSchema(PeopleTestSchema,
   429  				schemaNewColumnWDefVal(t, "newColumn", 13066, sql.Float32, false, "-1.1", schema.NotNullConstraint{})),
   430  			expectedRows: dtestutils.AddColToRows(t, AllPeopleRows, 13066, types.Float(float32(-1.1))),
   431  		},
   432  		{
   433  			name:        "alter add column not null with type mismatch in default",
   434  			query:       "alter table people add (newColumn float not null default 'not a number')",
   435  			expectedErr: "incompatible type",
   436  		},
   437  		{
   438  			name:        "alter add column column not found",
   439  			query:       "alter table people add column newColumn float after notFound",
   440  			expectedErr: `table "people" does not have column "notFound"`,
   441  		},
   442  		{
   443  			name:        "alter add column table not found",
   444  			query:       "alter table notFound add column newColumn float",
   445  			expectedErr: "table not found: notFound",
   446  		},
   447  		{
   448  			name:  "alter add column not null without default",
   449  			query: "alter table people add (newColumn varchar(80) not null)",
   450  			expectedSchema: dtestutils.AddColumnToSchema(PeopleTestSchema,
   451  				schemaNewColumnWDefVal(t, "newColumn", 4208, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 80), false, "", schema.NotNullConstraint{})),
   452  			expectedRows: dtestutils.AddColToRows(t, AllPeopleRows, 4208, types.String("")),
   453  		},
   454  		{
   455  			name:  "alter add column nullable",
   456  			query: "alter table people add (newColumn bigint)",
   457  			expectedSchema: dtestutils.AddColumnToSchema(PeopleTestSchema,
   458  				schemaNewColumn(t, "newColumn", 4435, sql.Int64, false)),
   459  			expectedRows: AllPeopleRows,
   460  		},
   461  		{
   462  			name:  "alter add column with optional column keyword",
   463  			query: "alter table people add column (newColumn varchar(80))",
   464  			expectedSchema: dtestutils.AddColumnToSchema(PeopleTestSchema,
   465  				schemaNewColumn(t, "newColumn", 4208, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 80), false)),
   466  			expectedRows: AllPeopleRows,
   467  		},
   468  	}
   469  
   470  	for _, tt := range tests {
   471  		t.Run(tt.name, func(t *testing.T) {
   472  			dEnv := dtestutils.CreateTestEnv()
   473  			CreateTestDatabase(dEnv, t)
   474  			ctx := context.Background()
   475  			root, _ := dEnv.WorkingRoot(ctx)
   476  
   477  			updatedRoot, err := ExecuteSql(dEnv, root, tt.query)
   478  
   479  			if tt.expectedErr == "" {
   480  				require.NoError(t, err)
   481  			} else {
   482  				require.Error(t, err)
   483  				assert.Contains(t, err.Error(), tt.expectedErr)
   484  				return
   485  			}
   486  
   487  			assert.NotNil(t, updatedRoot)
   488  			table, _, err := updatedRoot.GetTable(ctx, PeopleTableName)
   489  			assert.NoError(t, err)
   490  			sch, err := table.GetSchema(ctx)
   491  			assert.NoError(t, err)
   492  			equalSchemas(t, tt.expectedSchema, sch)
   493  
   494  			updatedTable, ok, err := updatedRoot.GetTable(ctx, "people")
   495  			assert.NoError(t, err)
   496  			require.True(t, ok)
   497  
   498  			rowData, err := updatedTable.GetRowData(ctx)
   499  			assert.NoError(t, err)
   500  			var foundRows []row.Row
   501  			err = rowData.Iter(ctx, func(key, value types.Value) (stop bool, err error) {
   502  				r, err := row.FromNoms(tt.expectedSchema, key.(types.Tuple), value.(types.Tuple))
   503  				assert.NoError(t, err)
   504  				foundRows = append(foundRows, r)
   505  				return false, nil
   506  			})
   507  
   508  			assert.NoError(t, err)
   509  			assert.Equal(t, tt.expectedRows, foundRows)
   510  		})
   511  	}
   512  }
   513  
   514  func TestModifyAndChangeColumn(t *testing.T) {
   515  	tests := []struct {
   516  		name           string
   517  		query          string
   518  		expectedSchema schema.Schema
   519  		expectedRows   []row.Row
   520  		expectedErr    string
   521  	}{
   522  		{
   523  			name:  "alter modify column reorder middle",
   524  			query: "alter table people modify column first_name longtext not null after last_name",
   525  			expectedSchema: dtestutils.CreateSchema(
   526  				schema.NewColumn("id", IdTag, types.IntKind, true, schema.NotNullConstraint{}),
   527  				schema.NewColumn("last_name", LastNameTag, types.StringKind, false, schema.NotNullConstraint{}),
   528  				schema.NewColumn("first_name", FirstNameTag, types.StringKind, false, schema.NotNullConstraint{}),
   529  				schema.NewColumn("is_married", IsMarriedTag, types.BoolKind, false),
   530  				schema.NewColumn("age", AgeTag, types.IntKind, false),
   531  				schema.NewColumn("rating", RatingTag, types.FloatKind, false),
   532  				schema.NewColumn("uuid", UuidTag, types.UUIDKind, false),
   533  				schema.NewColumn("num_episodes", NumEpisodesTag, types.UintKind, false),
   534  			),
   535  			expectedRows: AllPeopleRows,
   536  		},
   537  		{
   538  			name:  "alter modify column reorder first",
   539  			query: "alter table people modify column first_name longtext not null first",
   540  			expectedSchema: dtestutils.CreateSchema(
   541  				schema.NewColumn("first_name", FirstNameTag, types.StringKind, false, schema.NotNullConstraint{}),
   542  				schema.NewColumn("id", IdTag, types.IntKind, true, schema.NotNullConstraint{}),
   543  				schema.NewColumn("last_name", LastNameTag, types.StringKind, false, schema.NotNullConstraint{}),
   544  				schema.NewColumn("is_married", IsMarriedTag, types.BoolKind, false),
   545  				schema.NewColumn("age", AgeTag, types.IntKind, false),
   546  				schema.NewColumn("rating", RatingTag, types.FloatKind, false),
   547  				schema.NewColumn("uuid", UuidTag, types.UUIDKind, false),
   548  				schema.NewColumn("num_episodes", NumEpisodesTag, types.UintKind, false),
   549  			),
   550  			expectedRows: AllPeopleRows,
   551  		},
   552  		{
   553  			name:  "alter modify column drop null constraint",
   554  			query: "alter table people modify column first_name longtext null",
   555  			expectedSchema: dtestutils.CreateSchema(
   556  				schema.NewColumn("id", IdTag, types.IntKind, true, schema.NotNullConstraint{}),
   557  				schema.NewColumn("first_name", FirstNameTag, types.StringKind, false),
   558  				schema.NewColumn("last_name", LastNameTag, types.StringKind, false, schema.NotNullConstraint{}),
   559  				schema.NewColumn("is_married", IsMarriedTag, types.BoolKind, false),
   560  				schema.NewColumn("age", AgeTag, types.IntKind, false),
   561  				schema.NewColumn("rating", RatingTag, types.FloatKind, false),
   562  				schema.NewColumn("uuid", UuidTag, types.UUIDKind, false),
   563  				schema.NewColumn("num_episodes", NumEpisodesTag, types.UintKind, false),
   564  			),
   565  			expectedRows: AllPeopleRows,
   566  		},
   567  		{
   568  			name:  "alter change column rename and reorder",
   569  			query: "alter table people change first_name christian_name longtext not null after last_name",
   570  			expectedSchema: dtestutils.CreateSchema(
   571  				schema.NewColumn("id", IdTag, types.IntKind, true, schema.NotNullConstraint{}),
   572  				schema.NewColumn("last_name", LastNameTag, types.StringKind, false, schema.NotNullConstraint{}),
   573  				schema.NewColumn("christian_name", FirstNameTag, types.StringKind, false, schema.NotNullConstraint{}),
   574  				schema.NewColumn("is_married", IsMarriedTag, types.BoolKind, false),
   575  				schema.NewColumn("age", AgeTag, types.IntKind, false),
   576  				schema.NewColumn("rating", RatingTag, types.FloatKind, false),
   577  				schema.NewColumn("uuid", UuidTag, types.UUIDKind, false),
   578  				schema.NewColumn("num_episodes", NumEpisodesTag, types.UintKind, false),
   579  			),
   580  			expectedRows: AllPeopleRows,
   581  		},
   582  		{
   583  			name:  "alter change column rename and reorder first",
   584  			query: "alter table people change column first_name christian_name longtext not null first",
   585  			expectedSchema: dtestutils.CreateSchema(
   586  				schema.NewColumn("christian_name", FirstNameTag, types.StringKind, false, schema.NotNullConstraint{}),
   587  				schema.NewColumn("id", IdTag, types.IntKind, true, schema.NotNullConstraint{}),
   588  				schema.NewColumn("last_name", LastNameTag, types.StringKind, false, schema.NotNullConstraint{}),
   589  				schema.NewColumn("is_married", IsMarriedTag, types.BoolKind, false),
   590  				schema.NewColumn("age", AgeTag, types.IntKind, false),
   591  				schema.NewColumn("rating", RatingTag, types.FloatKind, false),
   592  				schema.NewColumn("uuid", UuidTag, types.UUIDKind, false),
   593  				schema.NewColumn("num_episodes", NumEpisodesTag, types.UintKind, false),
   594  			),
   595  			expectedRows: AllPeopleRows,
   596  		},
   597  		{
   598  			name:  "alter change column drop null constraint",
   599  			query: "alter table people change column first_name first_name longtext null",
   600  			expectedSchema: dtestutils.CreateSchema(
   601  				schema.NewColumn("id", IdTag, types.IntKind, true, schema.NotNullConstraint{}),
   602  				schema.NewColumn("first_name", FirstNameTag, types.StringKind, false),
   603  				schema.NewColumn("last_name", LastNameTag, types.StringKind, false, schema.NotNullConstraint{}),
   604  				schema.NewColumn("is_married", IsMarriedTag, types.BoolKind, false),
   605  				schema.NewColumn("age", AgeTag, types.IntKind, false),
   606  				schema.NewColumn("rating", RatingTag, types.FloatKind, false),
   607  				schema.NewColumn("uuid", UuidTag, types.UUIDKind, false),
   608  				schema.NewColumn("num_episodes", NumEpisodesTag, types.UintKind, false),
   609  			),
   610  			expectedRows: AllPeopleRows,
   611  		},
   612  		{
   613  			name:        "alter modify column not null with type mismatch in default",
   614  			query:       "alter table people modify rating double default 'not a number'",
   615  			expectedErr: "incompatible type for default value",
   616  		},
   617  		{
   618  			name:        "alter modify column not null, existing null values",
   619  			query:       "alter table people modify num_episodes bigint unsigned not null",
   620  			expectedErr: "cannot change column to NOT NULL",
   621  		},
   622  	}
   623  
   624  	for _, tt := range tests {
   625  		t.Run(tt.name, func(t *testing.T) {
   626  			dEnv := dtestutils.CreateTestEnv()
   627  			CreateTestDatabase(dEnv, t)
   628  			ctx := context.Background()
   629  			root, _ := dEnv.WorkingRoot(ctx)
   630  
   631  			updatedRoot, err := ExecuteSql(dEnv, root, tt.query)
   632  
   633  			if tt.expectedErr == "" {
   634  				require.NoError(t, err)
   635  			} else {
   636  				require.Error(t, err)
   637  				assert.Contains(t, err.Error(), tt.expectedErr)
   638  				return
   639  			}
   640  
   641  			assert.NotNil(t, updatedRoot)
   642  			table, _, err := updatedRoot.GetTable(ctx, PeopleTableName)
   643  			assert.NoError(t, err)
   644  			sch, err := table.GetSchema(ctx)
   645  			assert.NoError(t, err)
   646  			equalSchemas(t, tt.expectedSchema, sch)
   647  
   648  			updatedTable, ok, err := updatedRoot.GetTable(ctx, "people")
   649  			assert.NoError(t, err)
   650  			require.True(t, ok)
   651  
   652  			rowData, err := updatedTable.GetRowData(ctx)
   653  			assert.NoError(t, err)
   654  			var foundRows []row.Row
   655  			err = rowData.Iter(ctx, func(key, value types.Value) (stop bool, err error) {
   656  				r, err := row.FromNoms(tt.expectedSchema, key.(types.Tuple), value.(types.Tuple))
   657  				assert.NoError(t, err)
   658  				foundRows = append(foundRows, r)
   659  				return false, nil
   660  			})
   661  
   662  			assert.NoError(t, err)
   663  			assert.Equal(t, tt.expectedRows, foundRows)
   664  		})
   665  	}
   666  }
   667  
   668  func TestModifyColumnType(t *testing.T) {
   669  	tests := []struct {
   670  		name            string
   671  		setupStmts      []string
   672  		alterStmt       string
   673  		tableName       string
   674  		expectedRows    [][]types.Value
   675  		expectedIdxRows [][]types.Value
   676  		expectedErr     bool
   677  	}{
   678  		{
   679  			name: "alter modify column type similar types",
   680  			setupStmts: []string{
   681  				"create table test(pk bigint primary key, v1 bigint, index (v1))",
   682  				"insert into test values (0, 3), (1, 2)",
   683  			},
   684  			alterStmt: "alter table test modify column v1 int",
   685  			tableName: "test",
   686  			expectedRows: [][]types.Value{
   687  				{types.Int(0), types.Int(3)},
   688  				{types.Int(1), types.Int(2)},
   689  			},
   690  			expectedIdxRows: [][]types.Value{
   691  				{types.Int(2), types.Int(1)},
   692  				{types.Int(3), types.Int(0)},
   693  			},
   694  		},
   695  		{
   696  			name: "alter modify column type different types",
   697  			setupStmts: []string{
   698  				"create table test(pk bigint primary key, v1 bigint, index (v1))",
   699  				"insert into test values (0, 3), (1, 2)",
   700  			},
   701  			alterStmt: "alter table test modify column v1 varchar(20)",
   702  			tableName: "test",
   703  			expectedRows: [][]types.Value{
   704  				{types.Int(0), types.String("3")},
   705  				{types.Int(1), types.String("2")},
   706  			},
   707  			expectedIdxRows: [][]types.Value{
   708  				{types.String("2"), types.Int(1)},
   709  				{types.String("3"), types.Int(0)},
   710  			},
   711  		},
   712  		{
   713  			name: "alter modify column type different types reversed",
   714  			setupStmts: []string{
   715  				"create table test(pk bigint primary key, v1 varchar(20), index (v1))",
   716  				`insert into test values (0, "3"), (1, "2")`,
   717  			},
   718  			alterStmt: "alter table test modify column v1 bigint",
   719  			tableName: "test",
   720  			expectedRows: [][]types.Value{
   721  				{types.Int(0), types.Int(3)},
   722  				{types.Int(1), types.Int(2)},
   723  			},
   724  			expectedIdxRows: [][]types.Value{
   725  				{types.Int(2), types.Int(1)},
   726  				{types.Int(3), types.Int(0)},
   727  			},
   728  		},
   729  		{
   730  			name: "alter modify column type primary key",
   731  			setupStmts: []string{
   732  				"create table test(pk bigint primary key, v1 bigint, index (v1))",
   733  				"insert into test values (0, 3), (1, 2)",
   734  			},
   735  			alterStmt: "alter table test modify column pk varchar(20)",
   736  			tableName: "test",
   737  			expectedRows: [][]types.Value{
   738  				{types.String("0"), types.Int(3)},
   739  				{types.String("1"), types.Int(2)},
   740  			},
   741  			expectedIdxRows: [][]types.Value{
   742  				{types.Int(2), types.String("1")},
   743  				{types.Int(3), types.String("0")},
   744  			},
   745  		},
   746  		{
   747  			name: "alter modify column type incompatible types with empty table",
   748  			setupStmts: []string{
   749  				"create table test(pk bigint primary key, v1 bit(20), index (v1))",
   750  			},
   751  			alterStmt:       "alter table test modify column pk datetime",
   752  			tableName:       "test",
   753  			expectedRows:    [][]types.Value(nil),
   754  			expectedIdxRows: [][]types.Value(nil),
   755  		},
   756  		{
   757  			name: "alter modify column type incompatible types with non-empty table",
   758  			setupStmts: []string{
   759  				"create table test(pk bigint primary key, v1 bit(20), index (v1))",
   760  				"insert into test values (1, 1)",
   761  			},
   762  			alterStmt:   "alter table test modify column pk datetime",
   763  			expectedErr: true,
   764  		},
   765  		{
   766  			name: "alter modify column type different types incompatible values",
   767  			setupStmts: []string{
   768  				"create table test(pk bigint primary key, v1 varchar(20), index (v1))",
   769  				"insert into test values (0, 3), (1, 'a')",
   770  			},
   771  			alterStmt:   "alter table test modify column v1 bigint",
   772  			expectedErr: true,
   773  		},
   774  		{
   775  			name: "alter modify column type foreign key parent",
   776  			setupStmts: []string{
   777  				"create table test(pk bigint primary key, v1 bigint, index (v1))",
   778  				"create table test2(pk bigint primary key, v1 bigint, index (v1), foreign key (v1) references test(v1))",
   779  			},
   780  			alterStmt:   "alter table test modify column v1 varchar(20)",
   781  			expectedErr: true,
   782  		},
   783  		{
   784  			name: "alter modify column type foreign key child",
   785  			setupStmts: []string{
   786  				"create table test(pk bigint primary key, v1 bigint, index (v1))",
   787  				"create table test2(pk bigint primary key, v1 bigint, index (v1), foreign key (v1) references test(v1))",
   788  			},
   789  			alterStmt:   "alter table test2 modify column v1 varchar(20)",
   790  			expectedErr: true,
   791  		},
   792  	}
   793  
   794  	for _, test := range tests {
   795  		t.Run(test.name, func(t *testing.T) {
   796  			dEnv := dtestutils.CreateTestEnv()
   797  			ctx := context.Background()
   798  			root, _ := dEnv.WorkingRoot(ctx)
   799  			var err error
   800  
   801  			for _, stmt := range test.setupStmts {
   802  				root, err = ExecuteSql(dEnv, root, stmt)
   803  				require.NoError(t, err)
   804  			}
   805  			root, err = ExecuteSql(dEnv, root, test.alterStmt)
   806  			if test.expectedErr == false {
   807  				require.NoError(t, err)
   808  			} else {
   809  				require.Error(t, err)
   810  				return
   811  			}
   812  
   813  			table, _, err := root.GetTable(ctx, test.tableName)
   814  			require.NoError(t, err)
   815  			sch, err := table.GetSchema(ctx)
   816  			require.NoError(t, err)
   817  			rowData, err := table.GetRowData(ctx)
   818  			require.NoError(t, err)
   819  
   820  			var foundRows [][]types.Value
   821  			err = rowData.Iter(ctx, func(key, value types.Value) (stop bool, err error) {
   822  				r, err := row.FromNoms(sch, key.(types.Tuple), value.(types.Tuple))
   823  				require.NoError(t, err)
   824  				var vals []types.Value
   825  				_, _ = r.IterSchema(sch, func(tag uint64, val types.Value) (stop bool, err error) {
   826  					vals = append(vals, val)
   827  					return false, nil
   828  				})
   829  				foundRows = append(foundRows, vals)
   830  				return false, nil
   831  			})
   832  			require.NoError(t, err)
   833  			assert.Equal(t, test.expectedRows, foundRows)
   834  
   835  			foundRows = nil
   836  			idx := sch.Indexes().AllIndexes()[0]
   837  			idxRowData, err := table.GetIndexRowData(ctx, idx.Name())
   838  			require.NoError(t, err)
   839  			err = idxRowData.Iter(ctx, func(key, value types.Value) (stop bool, err error) {
   840  				r, err := row.FromNoms(idx.Schema(), key.(types.Tuple), value.(types.Tuple))
   841  				require.NoError(t, err)
   842  				var vals []types.Value
   843  				_, _ = r.IterSchema(idx.Schema(), func(tag uint64, val types.Value) (stop bool, err error) {
   844  					vals = append(vals, val)
   845  					return false, nil
   846  				})
   847  				foundRows = append(foundRows, vals)
   848  				return false, nil
   849  			})
   850  			require.NoError(t, err)
   851  			assert.Equal(t, test.expectedIdxRows, foundRows)
   852  		})
   853  	}
   854  }
   855  
   856  func TestDropColumn(t *testing.T) {
   857  	tests := []struct {
   858  		name           string
   859  		query          string
   860  		expectedSchema schema.Schema
   861  		expectedRows   []row.Row
   862  		expectedErr    string
   863  	}{
   864  		{
   865  			name:           "alter drop column",
   866  			query:          "alter table people drop rating",
   867  			expectedSchema: dtestutils.RemoveColumnFromSchema(PeopleTestSchema, RatingTag),
   868  			expectedRows:   dtestutils.ConvertToSchema(dtestutils.RemoveColumnFromSchema(PeopleTestSchema, RatingTag), AllPeopleRows...),
   869  		},
   870  		{
   871  			name:           "alter drop column with optional column keyword",
   872  			query:          "alter table people drop column rating",
   873  			expectedSchema: dtestutils.RemoveColumnFromSchema(PeopleTestSchema, RatingTag),
   874  			expectedRows:   dtestutils.ConvertToSchema(dtestutils.RemoveColumnFromSchema(PeopleTestSchema, RatingTag), AllPeopleRows...),
   875  		},
   876  		{
   877  			name:        "drop primary key",
   878  			query:       "alter table people drop column id",
   879  			expectedErr: "Cannot drop column in primary key",
   880  		},
   881  		{
   882  			name:        "table not found",
   883  			query:       "alter table notFound drop column id",
   884  			expectedErr: "table not found: notFound",
   885  		},
   886  		{
   887  			name:        "column not found",
   888  			query:       "alter table people drop column notFound",
   889  			expectedErr: `table "people" does not have column "notFound"`,
   890  		},
   891  	}
   892  
   893  	for _, tt := range tests {
   894  		t.Run(tt.name, func(t *testing.T) {
   895  			dEnv := dtestutils.CreateTestEnv()
   896  			CreateTestDatabase(dEnv, t)
   897  			ctx := context.Background()
   898  			root, _ := dEnv.WorkingRoot(ctx)
   899  
   900  			updatedRoot, err := ExecuteSql(dEnv, root, tt.query)
   901  
   902  			if tt.expectedErr == "" {
   903  				require.NoError(t, err)
   904  			} else {
   905  				require.Error(t, err)
   906  				assert.Contains(t, err.Error(), tt.expectedErr)
   907  				return
   908  			}
   909  
   910  			require.NotNil(t, updatedRoot)
   911  			table, _, err := updatedRoot.GetTable(ctx, PeopleTableName)
   912  			assert.NoError(t, err)
   913  			sch, err := table.GetSchema(ctx)
   914  			assert.NoError(t, err)
   915  			assert.Equal(t, tt.expectedSchema, sch)
   916  
   917  			updatedTable, ok, err := updatedRoot.GetTable(ctx, "people")
   918  			assert.NoError(t, err)
   919  			require.True(t, ok)
   920  
   921  			rowData, err := updatedTable.GetRowData(ctx)
   922  			assert.NoError(t, err)
   923  			var foundRows []row.Row
   924  			err = rowData.Iter(ctx, func(key, value types.Value) (stop bool, err error) {
   925  				updatedSch, err := updatedTable.GetSchema(ctx)
   926  				assert.NoError(t, err)
   927  				r, err := row.FromNoms(updatedSch, key.(types.Tuple), value.(types.Tuple))
   928  				assert.NoError(t, err)
   929  				foundRows = append(foundRows, r)
   930  				return false, nil
   931  			})
   932  
   933  			assert.NoError(t, err)
   934  			assert.Equal(t, tt.expectedRows, foundRows)
   935  		})
   936  	}
   937  }
   938  
   939  func TestRenameColumn(t *testing.T) {
   940  	tests := []struct {
   941  		name           string
   942  		query          string
   943  		expectedSchema schema.Schema
   944  		expectedRows   []row.Row
   945  		expectedErr    string
   946  	}{
   947  		{
   948  			name:  "alter rename column with column and as keywords",
   949  			query: "alter table people rename column rating as newRating",
   950  			expectedSchema: dtestutils.CreateSchema(
   951  				schema.NewColumn("id", IdTag, types.IntKind, true, schema.NotNullConstraint{}),
   952  				schema.NewColumn("first_name", FirstNameTag, types.StringKind, false, schema.NotNullConstraint{}),
   953  				schema.NewColumn("last_name", LastNameTag, types.StringKind, false, schema.NotNullConstraint{}),
   954  				schema.NewColumn("is_married", IsMarriedTag, types.BoolKind, false),
   955  				schema.NewColumn("age", AgeTag, types.IntKind, false),
   956  				schema.NewColumn("newRating", RatingTag, types.FloatKind, false),
   957  				schema.NewColumn("uuid", UuidTag, types.UUIDKind, false),
   958  				schema.NewColumn("num_episodes", NumEpisodesTag, types.UintKind, false),
   959  			),
   960  			expectedRows: AllPeopleRows,
   961  		},
   962  		{
   963  			name:  "alter rename column with column and to keyword",
   964  			query: "alter table people rename column rating to newRating",
   965  			expectedSchema: dtestutils.CreateSchema(
   966  				schema.NewColumn("id", IdTag, types.IntKind, true, schema.NotNullConstraint{}),
   967  				schema.NewColumn("first_name", FirstNameTag, types.StringKind, false, schema.NotNullConstraint{}),
   968  				schema.NewColumn("last_name", LastNameTag, types.StringKind, false, schema.NotNullConstraint{}),
   969  				schema.NewColumn("is_married", IsMarriedTag, types.BoolKind, false),
   970  				schema.NewColumn("age", AgeTag, types.IntKind, false),
   971  				schema.NewColumn("newRating", RatingTag, types.FloatKind, false),
   972  				schema.NewColumn("uuid", UuidTag, types.UUIDKind, false),
   973  				schema.NewColumn("num_episodes", NumEpisodesTag, types.UintKind, false),
   974  			),
   975  			expectedRows: AllPeopleRows,
   976  		},
   977  		{
   978  			name:  "alter rename primary key column",
   979  			query: "alter table people rename column id to newId",
   980  			expectedSchema: dtestutils.CreateSchema(
   981  				schema.NewColumn("newId", IdTag, types.IntKind, true, schema.NotNullConstraint{}),
   982  				schema.NewColumn("first_name", FirstNameTag, types.StringKind, false, schema.NotNullConstraint{}),
   983  				schema.NewColumn("last_name", LastNameTag, types.StringKind, false, schema.NotNullConstraint{}),
   984  				schema.NewColumn("is_married", IsMarriedTag, types.BoolKind, false),
   985  				schema.NewColumn("age", AgeTag, types.IntKind, false),
   986  				schema.NewColumn("rating", RatingTag, types.FloatKind, false),
   987  				schema.NewColumn("uuid", UuidTag, types.UUIDKind, false),
   988  				schema.NewColumn("num_episodes", NumEpisodesTag, types.UintKind, false),
   989  			),
   990  			expectedRows: AllPeopleRows,
   991  		},
   992  		{
   993  			name:        "table not found",
   994  			query:       "alter table notFound rename column id to newId",
   995  			expectedErr: "table not found: notFound",
   996  		},
   997  		{
   998  			name:        "column not found",
   999  			query:       "alter table people rename column notFound to newNotFound",
  1000  			expectedErr: `table "people" does not have column "notFound"`,
  1001  		},
  1002  		{
  1003  			name:        "column name collision",
  1004  			query:       "alter table people rename column id to age",
  1005  			expectedErr: "A column with the name age already exists",
  1006  		},
  1007  	}
  1008  
  1009  	for _, tt := range tests {
  1010  		t.Run(tt.name, func(t *testing.T) {
  1011  			dEnv := dtestutils.CreateTestEnv()
  1012  			CreateTestDatabase(dEnv, t)
  1013  			ctx := context.Background()
  1014  			root, _ := dEnv.WorkingRoot(ctx)
  1015  
  1016  			updatedRoot, err := ExecuteSql(dEnv, root, tt.query)
  1017  
  1018  			if tt.expectedErr == "" {
  1019  				require.NoError(t, err)
  1020  			} else {
  1021  				require.Error(t, err)
  1022  				assert.Contains(t, err.Error(), tt.expectedErr)
  1023  				return
  1024  			}
  1025  
  1026  			require.NotNil(t, updatedRoot)
  1027  			table, _, err := updatedRoot.GetTable(ctx, PeopleTableName)
  1028  			assert.NoError(t, err)
  1029  			sch, err := table.GetSchema(ctx)
  1030  			require.NoError(t, err)
  1031  			assert.Equal(t, tt.expectedSchema, sch)
  1032  
  1033  			updatedTable, ok, err := updatedRoot.GetTable(ctx, "people")
  1034  			assert.NoError(t, err)
  1035  			require.True(t, ok)
  1036  
  1037  			rowData, err := updatedTable.GetRowData(ctx)
  1038  			assert.NoError(t, err)
  1039  			var foundRows []row.Row
  1040  			err = rowData.Iter(ctx, func(key, value types.Value) (stop bool, err error) {
  1041  				updatedSch, err := updatedTable.GetSchema(ctx)
  1042  				assert.NoError(t, err)
  1043  				r, err := row.FromNoms(updatedSch, key.(types.Tuple), value.(types.Tuple))
  1044  				assert.NoError(t, err)
  1045  				foundRows = append(foundRows, r)
  1046  				return false, nil
  1047  			})
  1048  
  1049  			assert.NoError(t, err)
  1050  			assert.Equal(t, tt.expectedRows, foundRows)
  1051  		})
  1052  	}
  1053  }
  1054  
  1055  func TestRenameTable(t *testing.T) {
  1056  	tests := []struct {
  1057  		name           string
  1058  		query          string
  1059  		oldTableName   string
  1060  		newTableName   string
  1061  		expectedSchema schema.Schema
  1062  		expectedRows   []row.Row
  1063  		expectedErr    string
  1064  	}{
  1065  		{
  1066  			name:           "alter rename table",
  1067  			query:          "rename table people to newPeople",
  1068  			oldTableName:   "people",
  1069  			newTableName:   "newPeople",
  1070  			expectedSchema: PeopleTestSchema,
  1071  			expectedRows:   AllPeopleRows,
  1072  		},
  1073  		{
  1074  			name:           "alter rename table with alter syntax",
  1075  			query:          "alter table people rename to newPeople",
  1076  			oldTableName:   "people",
  1077  			newTableName:   "newPeople",
  1078  			expectedSchema: PeopleTestSchema,
  1079  			expectedRows:   AllPeopleRows,
  1080  		},
  1081  		{
  1082  			name:           "rename multiple tables",
  1083  			query:          "rename table people to newPeople, appearances to newAppearances",
  1084  			oldTableName:   "appearances",
  1085  			newTableName:   "newAppearances",
  1086  			expectedSchema: AppearancesTestSchema,
  1087  			expectedRows:   AllAppsRows,
  1088  		},
  1089  		{
  1090  			name:        "table not found",
  1091  			query:       "rename table notFound to newNowFound",
  1092  			expectedErr: "table not found: notFound",
  1093  		},
  1094  		{
  1095  			name:        "invalid table name",
  1096  			query:       "rename table people to `123`",
  1097  			expectedErr: "Invalid table name",
  1098  		},
  1099  		{
  1100  			name:        "reserved table name",
  1101  			query:       "rename table people to dolt_table",
  1102  			expectedErr: "Invalid table name",
  1103  		},
  1104  		{
  1105  			name:        "table name in use",
  1106  			query:       "rename table people to appearances",
  1107  			expectedErr: "already exists",
  1108  		},
  1109  	}
  1110  
  1111  	for _, tt := range tests {
  1112  		t.Run(tt.name, func(t *testing.T) {
  1113  			dEnv := dtestutils.CreateTestEnv()
  1114  			CreateTestDatabase(dEnv, t)
  1115  			ctx := context.Background()
  1116  			root, _ := dEnv.WorkingRoot(ctx)
  1117  
  1118  			updatedRoot, err := ExecuteSql(dEnv, root, tt.query)
  1119  			if len(tt.expectedErr) > 0 {
  1120  				require.Error(t, err)
  1121  				assert.Contains(t, err.Error(), tt.expectedErr)
  1122  				return
  1123  			} else {
  1124  				require.NoError(t, err)
  1125  			}
  1126  			require.NotNil(t, updatedRoot)
  1127  
  1128  			has, err := updatedRoot.HasTable(ctx, tt.oldTableName)
  1129  			require.NoError(t, err)
  1130  			assert.False(t, has)
  1131  			newTable, ok, err := updatedRoot.GetTable(ctx, tt.newTableName)
  1132  			require.NoError(t, err)
  1133  			require.True(t, ok)
  1134  
  1135  			sch, err := newTable.GetSchema(ctx)
  1136  			require.NoError(t, err)
  1137  			require.Equal(t, tt.expectedSchema, sch)
  1138  
  1139  			rowData, err := newTable.GetRowData(ctx)
  1140  			require.NoError(t, err)
  1141  			var foundRows []row.Row
  1142  			err = rowData.Iter(ctx, func(key, value types.Value) (stop bool, err error) {
  1143  				r, err := row.FromNoms(tt.expectedSchema, key.(types.Tuple), value.(types.Tuple))
  1144  				require.NoError(t, err)
  1145  				foundRows = append(foundRows, r)
  1146  				return false, nil
  1147  			})
  1148  
  1149  			require.NoError(t, err)
  1150  
  1151  			// Some test cases deal with rows declared in a different order than noms returns them, so use an order-
  1152  			// insensitive comparison here.
  1153  			assert.ElementsMatch(t, tt.expectedRows, foundRows)
  1154  		})
  1155  	}
  1156  }
  1157  
  1158  func TestAlterSystemTables(t *testing.T) {
  1159  	systemTableNames := []string{"dolt_docs", "dolt_log", "dolt_history_people", "dolt_diff_people", "dolt_commit_diff_people"}
  1160  	reservedTableNames := []string{"dolt_schemas", "dolt_query_catalog"}
  1161  
  1162  	var dEnv *env.DoltEnv
  1163  	setup := func() {
  1164  		dEnv = dtestutils.CreateTestEnv()
  1165  		CreateTestDatabase(dEnv, t)
  1166  
  1167  		dtestutils.CreateTestTable(t, dEnv, "dolt_docs",
  1168  			doltdocs.Schema,
  1169  			NewRow(types.String("LICENSE.md"), types.String("A license")))
  1170  		dtestutils.CreateTestTable(t, dEnv, doltdb.DoltQueryCatalogTableName,
  1171  			dtables.DoltQueryCatalogSchema,
  1172  			NewRow(types.String("abc123"), types.Uint(1), types.String("example"), types.String("select 2+2 from dual"), types.String("description")))
  1173  		dtestutils.CreateTestTable(t, dEnv, doltdb.SchemasTableName,
  1174  			schemasTableDoltSchema(),
  1175  			NewRowWithPks([]types.Value{types.String("view"), types.String("name")}, types.String("select 2+2 from dual")))
  1176  	}
  1177  
  1178  	t.Run("Create", func(t *testing.T) {
  1179  		setup()
  1180  		for _, tableName := range append(systemTableNames, reservedTableNames...) {
  1181  			assertFails(t, dEnv, fmt.Sprintf("create table %s (a int primary key not null)", tableName), "reserved")
  1182  		}
  1183  	})
  1184  
  1185  	// The _history and _diff tables give not found errors right now because of https://github.com/dolthub/dolt/issues/373.
  1186  	// We can remove the divergent failure logic when the issue is fixed.
  1187  	t.Run("Drop", func(t *testing.T) {
  1188  		setup()
  1189  		for _, tableName := range systemTableNames {
  1190  			expectedErr := "system table"
  1191  			if strings.HasPrefix(tableName, "dolt_diff") || strings.HasPrefix(tableName, "dolt_history") {
  1192  				expectedErr = "system tables cannot be dropped or altered"
  1193  			}
  1194  			assertFails(t, dEnv, fmt.Sprintf("drop table %s", tableName), expectedErr)
  1195  		}
  1196  		for _, tableName := range reservedTableNames {
  1197  			assertSucceeds(t, dEnv, fmt.Sprintf("drop table %s", tableName))
  1198  		}
  1199  	})
  1200  
  1201  	t.Run("Rename", func(t *testing.T) {
  1202  		setup()
  1203  		for _, tableName := range systemTableNames {
  1204  			expectedErr := "system table"
  1205  			if strings.HasPrefix(tableName, "dolt_diff") || strings.HasPrefix(tableName, "dolt_history") {
  1206  				expectedErr = "system tables cannot be dropped or altered"
  1207  			}
  1208  			assertFails(t, dEnv, fmt.Sprintf("rename table %s to newname", tableName), expectedErr)
  1209  		}
  1210  		for i, tableName := range reservedTableNames {
  1211  			assertSucceeds(t, dEnv, fmt.Sprintf("rename table %s to newname%d", tableName, i))
  1212  		}
  1213  	})
  1214  
  1215  	t.Run("Alter", func(t *testing.T) {
  1216  		setup()
  1217  		for _, tableName := range append(systemTableNames, reservedTableNames...) {
  1218  			expectedErr := "cannot be altered"
  1219  			if strings.HasPrefix(tableName, "dolt_diff") || strings.HasPrefix(tableName, "dolt_history") {
  1220  				expectedErr = " cannot be altered"
  1221  			}
  1222  			assertFails(t, dEnv, fmt.Sprintf("alter table %s add column a int", tableName), expectedErr)
  1223  		}
  1224  	})
  1225  }
  1226  
  1227  func TestParseCreateTableStatement(t *testing.T) {
  1228  	tests := []struct {
  1229  		name           string
  1230  		query          string
  1231  		expectedTable  string
  1232  		expectedSchema schema.Schema
  1233  		expectedErr    string
  1234  	}{
  1235  		{
  1236  			name:          "Test create single column schema",
  1237  			query:         "create table testTable (id int primary key)",
  1238  			expectedTable: "testTable",
  1239  			expectedSchema: dtestutils.CreateSchema(
  1240  				schemaNewColumn(t, "id", 4817, sql.Int32, true, schema.NotNullConstraint{})),
  1241  		},
  1242  		{
  1243  			name:          "Test create two column schema",
  1244  			query:         "create table testTable (id int primary key, age int)",
  1245  			expectedTable: "testTable",
  1246  			expectedSchema: dtestutils.CreateSchema(
  1247  				schemaNewColumn(t, "id", 4817, sql.Int32, true, schema.NotNullConstraint{}),
  1248  				schemaNewColumn(t, "age", 7208, sql.Int32, false)),
  1249  		},
  1250  		{
  1251  			name:          "Test syntax error",
  1252  			query:         "create table testTable id int, age int",
  1253  			expectedTable: "testTable",
  1254  			expectedErr:   "syntax error",
  1255  		},
  1256  		{
  1257  			name:        "Test bad table name begins with number",
  1258  			query:       "create table 1testTable (id int primary key, age int)",
  1259  			expectedErr: "syntax error",
  1260  		},
  1261  		{
  1262  			name: "Test types",
  1263  			query: `create table testTable (
  1264  								id int primary key, 
  1265  								age int, 
  1266  								first_name varchar(255), 
  1267  								is_married boolean) `,
  1268  			expectedTable: "testTable",
  1269  			expectedSchema: dtestutils.CreateSchema(
  1270  				schemaNewColumn(t, "id", 4817, sql.Int32, true, schema.NotNullConstraint{}),
  1271  				schemaNewColumn(t, "age", 7208, sql.Int32, false),
  1272  				schemaNewColumn(t, "first_name", 3264, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 255), false),
  1273  				schemaNewColumn(t, "is_married", 14626, sql.Boolean, false)),
  1274  		},
  1275  		{
  1276  			name:          "Test all supported types",
  1277  			expectedTable: "testTable",
  1278  			query: `create table testTable (
  1279  							c0 int primary key,
  1280  							c1 tinyint,
  1281  							c2 smallint,
  1282  							c3 mediumint,
  1283  							c4 integer,
  1284  							c5 bigint,
  1285  							c6 bool,
  1286  							c7 boolean,
  1287  							c8 bit(10),
  1288  							c9 text,
  1289  							c10 tinytext,
  1290  							c11 mediumtext,
  1291  							c12 longtext,
  1292  							c16 char(5),
  1293  							c17 varchar(255),
  1294  							c18 varchar(80),
  1295  							c19 float,
  1296  							c20 double,
  1297  							c22 int unsigned,
  1298  							c23 tinyint unsigned,
  1299  							c24 smallint unsigned,
  1300  							c25 mediumint unsigned,
  1301  							c26 bigint unsigned)`,
  1302  			expectedSchema: dtestutils.CreateSchema(
  1303  				schemaNewColumn(t, "c0", 594, sql.Int32, true, schema.NotNullConstraint{}),
  1304  				schemaNewColumn(t, "c1", 601, sql.Int8, false),
  1305  				schemaNewColumn(t, "c2", 14542, sql.Int16, false),
  1306  				schemaNewColumn(t, "c3", 13309, sql.Int24, false),
  1307  				schemaNewColumn(t, "c4", 15884, sql.Int32, false),
  1308  				schemaNewColumn(t, "c5", 14619, sql.Int64, false),
  1309  				schemaNewColumn(t, "c6", 13192, sql.Boolean, false),
  1310  				schemaNewColumn(t, "c7", 5981, sql.Boolean, false),
  1311  				schemaNewColumn(t, "c8", 14871, sql.MustCreateBitType(10), false),
  1312  				schemaNewColumn(t, "c9", 4167, sql.Text, false),
  1313  				schemaNewColumn(t, "c10", 1965, sql.TinyText, false),
  1314  				schemaNewColumn(t, "c11", 12860, sql.MediumText, false),
  1315  				schemaNewColumn(t, "c12", 7155, sql.LongText, false),
  1316  				//schemaNewColumn(t, "c13", 113, sql.TinyBlob, false),
  1317  				//schemaNewColumn(t, "c14", 114, sql.Blob, false),
  1318  				//schemaNewColumn(t, "c15", 115, sql.LongBlob, false),
  1319  				schemaNewColumn(t, "c16", 15859, sql.MustCreateStringWithDefaults(sqltypes.Char, 5), false),
  1320  				schemaNewColumn(t, "c17", 11710, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 255), false),
  1321  				schemaNewColumn(t, "c18", 6838, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 80), false),
  1322  				schemaNewColumn(t, "c19", 9377, sql.Float32, false),
  1323  				schemaNewColumn(t, "c20", 15979, sql.Float64, false),
  1324  				//schemaNewColumn(t, "c21", 121, sql.MustCreateDecimalType(10, 5), false),
  1325  				schemaNewColumn(t, "c22", 2910, sql.Uint32, false),
  1326  				schemaNewColumn(t, "c23", 8740, sql.Uint8, false),
  1327  				schemaNewColumn(t, "c24", 8689, sql.Uint16, false),
  1328  				schemaNewColumn(t, "c25", 5243, sql.Uint24, false),
  1329  				schemaNewColumn(t, "c26", 9338, sql.Uint64, false),
  1330  			),
  1331  		},
  1332  		{
  1333  			name: "Test primary keys",
  1334  			query: `create table testTable (
  1335  								id int, 
  1336  								age int, 
  1337  								first_name varchar(80), 
  1338  								is_married bool, 
  1339  								primary key (id, age))`,
  1340  			expectedTable: "testTable",
  1341  			expectedSchema: dtestutils.CreateSchema(
  1342  				schemaNewColumn(t, "id", 4817, sql.Int32, true, schema.NotNullConstraint{}),
  1343  				schemaNewColumn(t, "age", 7208, sql.Int32, true, schema.NotNullConstraint{}),
  1344  				schemaNewColumn(t, "first_name", 3264, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 80), false),
  1345  				schemaNewColumn(t, "is_married", 14626, sql.Boolean, false)),
  1346  		},
  1347  		{
  1348  			name: "Test not null constraints",
  1349  			query: `create table testTable (
  1350  								id int, 
  1351  								age int, 
  1352  								first_name varchar(80) not null, 
  1353  								is_married bool, 
  1354  								primary key (id, age))`,
  1355  			expectedTable: "testTable",
  1356  			expectedSchema: dtestutils.CreateSchema(
  1357  				schemaNewColumn(t, "id", 4817, sql.Int32, true, schema.NotNullConstraint{}),
  1358  				schemaNewColumn(t, "age", 7208, sql.Int32, true, schema.NotNullConstraint{}),
  1359  				schemaNewColumn(t, "first_name", 3264, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 80), false, schema.NotNullConstraint{}),
  1360  				schemaNewColumn(t, "is_married", 14626, sql.Boolean, false)),
  1361  		},
  1362  		{
  1363  			name: "Test quoted columns",
  1364  			query: "create table testTable (" +
  1365  				"`id` int, " +
  1366  				"`age` int, " +
  1367  				"`timestamp` varchar(80), " +
  1368  				"`is married` bool, " +
  1369  				"primary key (`id`, `age`))",
  1370  			expectedTable: "testTable",
  1371  			expectedSchema: dtestutils.CreateSchema(
  1372  				schemaNewColumn(t, "id", 4817, sql.Int32, true, schema.NotNullConstraint{}),
  1373  				schemaNewColumn(t, "age", 7208, sql.Int32, true, schema.NotNullConstraint{}),
  1374  				schemaNewColumn(t, "timestamp", 10168, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 80), false),
  1375  				schemaNewColumn(t, "is married", 14626, sql.Boolean, false)),
  1376  		},
  1377  		{
  1378  			name: "Test tag comments",
  1379  			query: `create table testTable (
  1380  								id int primary key, age int)`,
  1381  			expectedTable: "testTable",
  1382  			expectedSchema: dtestutils.CreateSchema(
  1383  				schemaNewColumn(t, "id", 4817, sql.Int32, true, schema.NotNullConstraint{}),
  1384  				schemaNewColumn(t, "age", 7208, sql.Int32, false)),
  1385  		},
  1386  		// Real world examples for regression testing
  1387  		{
  1388  			name: "Test ip2nation",
  1389  			query: `CREATE TABLE ip2nation (
  1390  							ip int(11) unsigned NOT NULL default 0,
  1391  							country char(2) NOT NULL default '',
  1392  							PRIMARY KEY (ip));`,
  1393  			expectedTable: "ip2nation",
  1394  			expectedSchema: dtestutils.CreateSchema(
  1395  				schemaNewColumnWDefVal(t, "ip", 7265, sql.Uint32, true, "0", schema.NotNullConstraint{}),
  1396  				schemaNewColumnWDefVal(t, "country", 6630, sql.MustCreateStringWithDefaults(sqltypes.Char, 2), false, `""`, schema.NotNullConstraint{})),
  1397  		},
  1398  		{
  1399  			name:          "Test ip2nationCountries",
  1400  			expectedTable: "ip2nationCountries",
  1401  			query: `CREATE TABLE ip2nationCountries (
  1402  							code varchar(4) NOT NULL default '',
  1403  							iso_code_2 varchar(2) NOT NULL default '',
  1404  							iso_code_3 varchar(3) default '',
  1405  							iso_country varchar(255) NOT NULL default '',
  1406  							country varchar(255) NOT NULL default '',
  1407  							lat float NOT NULL default 0.0,
  1408  							lon float NOT NULL default 0.0,
  1409  							PRIMARY KEY (code));`,
  1410  			expectedSchema: dtestutils.CreateSchema(
  1411  				schemaNewColumnWDefVal(t, "code", 7802, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 4), true, `""`, schema.NotNullConstraint{}),
  1412  				schemaNewColumnWDefVal(t, "iso_code_2", 9266, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 2), false, `""`, schema.NotNullConstraint{}),
  1413  				schemaNewColumnWDefVal(t, "iso_code_3", 8427, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 3), false, `""`),
  1414  				schemaNewColumnWDefVal(t, "iso_country", 7151, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 255), false, `""`, schema.NotNullConstraint{}),
  1415  				schemaNewColumnWDefVal(t, "country", 879, sql.MustCreateStringWithDefaults(sqltypes.VarChar, 255), false, `""`, schema.NotNullConstraint{}),
  1416  				schemaNewColumnWDefVal(t, "lat", 3502, sql.Float32, false, "0", schema.NotNullConstraint{}),
  1417  				schemaNewColumnWDefVal(t, "lon", 9907, sql.Float32, false, "0", schema.NotNullConstraint{})),
  1418  		},
  1419  	}
  1420  
  1421  	for _, tt := range tests {
  1422  		t.Run(tt.name, func(t *testing.T) {
  1423  			dEnv := dtestutils.CreateTestEnv()
  1424  			ctx := context.Background()
  1425  			root, _ := dEnv.WorkingRoot(ctx)
  1426  
  1427  			tblName, sch, err := sqlutil.ParseCreateTableStatement(ctx, root, tt.query)
  1428  
  1429  			if tt.expectedErr != "" {
  1430  				require.Error(t, err)
  1431  				assert.Contains(t, err.Error(), tt.expectedErr)
  1432  			} else {
  1433  				require.NoError(t, err)
  1434  				equalSchemas(t, tt.expectedSchema, sch)
  1435  				assert.Equal(t, tt.expectedTable, tblName)
  1436  			}
  1437  		})
  1438  	}
  1439  }
  1440  
  1441  func TestIndexOverwrite(t *testing.T) {
  1442  	ctx := context.Background()
  1443  	dEnv := dtestutils.CreateTestEnv()
  1444  	root, err := dEnv.WorkingRoot(ctx)
  1445  	if err != nil {
  1446  		panic(err)
  1447  	}
  1448  	root, err = ExecuteSql(dEnv, root, `
  1449  CREATE TABLE parent (
  1450    pk bigint PRIMARY KEY,
  1451    v1 bigint,
  1452    INDEX (v1)
  1453  );
  1454  CREATE TABLE child (
  1455    pk varchar(10) PRIMARY KEY,
  1456    parent_value bigint,
  1457    CONSTRAINT fk_child FOREIGN KEY (parent_value)
  1458      REFERENCES parent(v1)
  1459  );
  1460  CREATE TABLE child_idx (
  1461    pk varchar(10) PRIMARY KEY,
  1462    parent_value bigint,
  1463    INDEX (parent_value),
  1464    CONSTRAINT fk_child_idx FOREIGN KEY (parent_value)
  1465      REFERENCES parent(v1)
  1466  );
  1467  CREATE TABLE child_unq (
  1468    pk varchar(10) PRIMARY KEY,
  1469    parent_value bigint,
  1470    CONSTRAINT fk_child_unq FOREIGN KEY (parent_value)
  1471      REFERENCES parent(v1)
  1472  );
  1473  CREATE TABLE child_non_unq (
  1474    pk varchar(10) PRIMARY KEY,
  1475    parent_value bigint,
  1476    CONSTRAINT fk_child_non_unq FOREIGN KEY (parent_value)
  1477      REFERENCES parent(v1)
  1478  );
  1479  INSERT INTO parent VALUES (1, 1), (2, 2), (3, 3), (4, NULL), (5, 5), (6, 6), (7, 7);
  1480  INSERT INTO child VALUES ('1', 1), ('2', NULL), ('3', 3), ('4', 3), ('5', 5);
  1481  INSERT INTO child_idx VALUES ('1', 1), ('2', NULL), ('3', 3), ('4', 3), ('5', 5);
  1482  INSERT INTO child_unq VALUES ('1', 1), ('2', NULL), ('3', 3), ('4', NULL), ('5', 5);
  1483  INSERT INTO child_non_unq VALUES ('1', 1), ('2', NULL), ('3', 3), ('4', 3), ('5', 5);
  1484  `)
  1485  	// test index creation
  1486  	require.NoError(t, err)
  1487  	root, err = ExecuteSql(dEnv, root, "CREATE INDEX abc ON child (parent_value);")
  1488  	require.NoError(t, err)
  1489  	_, err = ExecuteSql(dEnv, root, "CREATE INDEX abc_idx ON child_idx (parent_value);")
  1490  	if assert.Error(t, err) {
  1491  		assert.Contains(t, err.Error(), "duplicate")
  1492  	}
  1493  	root, err = ExecuteSql(dEnv, root, "CREATE UNIQUE INDEX abc_unq ON child_unq (parent_value);")
  1494  	require.NoError(t, err)
  1495  	_, err = ExecuteSql(dEnv, root, "CREATE UNIQUE INDEX abc_non_unq ON child_non_unq (parent_value);")
  1496  	if assert.Error(t, err) {
  1497  		assert.Contains(t, err.Error(), "UNIQUE constraint violation")
  1498  	}
  1499  
  1500  	// check foreign keys for updated index (or verify they weren't updated)
  1501  	fkc, err := root.GetForeignKeyCollection(ctx)
  1502  	require.NoError(t, err)
  1503  	fkChild, ok := fkc.GetByNameCaseInsensitive("fk_child")
  1504  	require.True(t, ok)
  1505  	require.Equal(t, "abc", fkChild.TableIndex)
  1506  	fkChildIdx, ok := fkc.GetByNameCaseInsensitive("fk_child_idx")
  1507  	require.True(t, ok)
  1508  	require.Equal(t, "parent_value", fkChildIdx.TableIndex)
  1509  	fkChildUnq, ok := fkc.GetByNameCaseInsensitive("fk_child_unq")
  1510  	require.True(t, ok)
  1511  	require.Equal(t, "abc_unq", fkChildUnq.TableIndex)
  1512  	fkChildNonUnq, ok := fkc.GetByNameCaseInsensitive("fk_child_non_unq")
  1513  	require.True(t, ok)
  1514  	require.Equal(t, "parent_value", fkChildNonUnq.TableIndex)
  1515  
  1516  	// insert tests against index
  1517  	root, err = ExecuteSql(dEnv, root, "INSERT INTO child VALUES ('6', 5)")
  1518  	require.NoError(t, err)
  1519  	root, err = ExecuteSql(dEnv, root, "INSERT INTO child_idx VALUES ('6', 5)")
  1520  	require.NoError(t, err)
  1521  	_, err = ExecuteSql(dEnv, root, "INSERT INTO child_unq VALUES ('6', 5)")
  1522  	if assert.Error(t, err) {
  1523  		assert.True(t, sql.ErrUniqueKeyViolation.Is(err))
  1524  	}
  1525  	root, err = ExecuteSql(dEnv, root, "INSERT INTO child_non_unq VALUES ('6', 5)")
  1526  	require.NoError(t, err)
  1527  
  1528  	// insert tests against foreign key
  1529  	_, err = ExecuteSql(dEnv, root, "INSERT INTO child VALUES ('9', 9)")
  1530  	if assert.Error(t, err) {
  1531  		assert.Contains(t, err.Error(), "Foreign key violation")
  1532  	}
  1533  	_, err = ExecuteSql(dEnv, root, "INSERT INTO child_idx VALUES ('9', 9)")
  1534  	if assert.Error(t, err) {
  1535  		assert.Contains(t, err.Error(), "Foreign key violation")
  1536  	}
  1537  	_, err = ExecuteSql(dEnv, root, "INSERT INTO child_unq VALUES ('9', 9)")
  1538  	if assert.Error(t, err) {
  1539  		assert.Contains(t, err.Error(), "Foreign key violation")
  1540  	}
  1541  	_, err = ExecuteSql(dEnv, root, "INSERT INTO child_non_unq VALUES ('9', 9)")
  1542  	if assert.Error(t, err) {
  1543  		assert.Contains(t, err.Error(), "Foreign key violation")
  1544  	}
  1545  }
  1546  
  1547  func TestCreateIndexUnique(t *testing.T) {
  1548  	dEnv := dtestutils.CreateTestEnv()
  1549  	root, err := dEnv.WorkingRoot(context.Background())
  1550  	if err != nil {
  1551  		panic(err)
  1552  	}
  1553  	root, err = ExecuteSql(dEnv, root, `
  1554  CREATE TABLE pass_unique (
  1555    pk1 BIGINT PRIMARY KEY,
  1556    v1 BIGINT,
  1557    v2 BIGINT
  1558  );
  1559  CREATE TABLE fail_unique (
  1560    pk1 BIGINT PRIMARY KEY,
  1561    v1 BIGINT,
  1562    v2 BIGINT
  1563  );
  1564  INSERT INTO pass_unique VALUES (1, 1, 1), (2, 2, 2), (3, 3, 3);
  1565  INSERT INTO fail_unique VALUES (1, 1, 1), (2, 2, 2), (3, 2, 3);
  1566  `)
  1567  	require.NoError(t, err)
  1568  	root, err = ExecuteSql(dEnv, root, "CREATE UNIQUE INDEX idx_v1 ON pass_unique(v1)")
  1569  	assert.NoError(t, err)
  1570  	root, err = ExecuteSql(dEnv, root, "CREATE UNIQUE INDEX idx_v1 ON fail_unique(v1)")
  1571  	if assert.Error(t, err) {
  1572  		assert.Contains(t, strings.ToLower(err.Error()), "unique")
  1573  	}
  1574  }
  1575  
  1576  func schemasTableDoltSchema() schema.Schema {
  1577  	// this is a dummy test environment and will not be used,
  1578  	// dolt_schema table tags will be parsed from the comments in SchemaTableSchema()
  1579  	testEnv := dtestutils.CreateTestEnv()
  1580  	return mustGetDoltSchema(SchemasTableSqlSchema(), doltdb.SchemasTableName, testEnv)
  1581  }
  1582  
  1583  func assertFails(t *testing.T, dEnv *env.DoltEnv, query, expectedErr string) {
  1584  	ctx := context.Background()
  1585  	root, _ := dEnv.WorkingRoot(ctx)
  1586  	_, err := ExecuteSql(dEnv, root, query)
  1587  	require.Error(t, err, query)
  1588  	assert.Contains(t, err.Error(), expectedErr)
  1589  }
  1590  
  1591  func assertSucceeds(t *testing.T, dEnv *env.DoltEnv, query string) {
  1592  	ctx := context.Background()
  1593  	root, _ := dEnv.WorkingRoot(ctx)
  1594  	_, err := ExecuteSql(dEnv, root, query)
  1595  	assert.NoError(t, err, query)
  1596  }