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