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 }