Skip to content

Commit f000616

Browse files
committed
diff/push: ignore CHECK constraint name changes unless --exact-match
In MySQL, check constraints have a schema-wide namespace. Since online schema change tools use a "shadow table" matching the new requested table definition, these tools manipulate the check constraint name in order to avoid a name collision between the old table and the shadow table. (pt-osc does this explicitly, similar to how it handles foreign key constraints; meanwhile gh-ost and spirit do it automatically by virtue of using CREATE TABLE ... LIKE to create the shadow table, which reverts check constraints to their server- default naming scheme.) However, as a side-effect of this CHECK constraint renaming, subsequent calls to `skeema diff` or `skeema push` could previously result in spurious diffs to return any named check constraints back to their original names from the *.sql file definitions. This commit changes Skeema's table diff logic to ignore check constraint name changes by default, just like how foreign key constraint name changes are also already ignored for the same reason. To override this behavior, the existing option --exact-match can be used if needed. Note that in MariaDB, check constraints have a per-table namespace instead of a schema-wide namespace, and CREATE TABLE ... LIKE retains check constraint names as-is, which means gh-ost won't rename check constraints. However, gh-ost does not officially support MariaDB anyway. Meanwhile pt-osc still renames check constraints on MariaDB even though it is not necessary. So the changes in this commit are applied equally to both MySQL and MariaDB, since some MariaDB users may be running pt-osc.
1 parent 9fa3d2a commit f000616

File tree

6 files changed

+170
-37
lines changed

6 files changed

+170
-37
lines changed

internal/applier/applier.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ func StatementModifiersForDir(dir *fs.Dir) (mods tengo.StatementModifiers, err e
351351
mods.LaxComments = dir.Config.GetBool("lax-comments")
352352
if dir.Config.GetBool("exact-match") {
353353
mods.StrictIndexOrder = true
354-
mods.StrictCheckOrder = true // only affects MariaDB
354+
mods.StrictCheckConstraints = true
355355
mods.StrictForeignKeyNaming = true
356356
mods.StrictColumnDefinition = true // only affects MySQL 8
357357
}

internal/applier/verifier.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ func VerifyDiff(altersInDiff []*tengo.TableDiff, vopts VerifierOptions) error {
5050
AllowUnsafe: true, // needed since we're just running against the temp schema
5151
AlgorithmClause: "copy", // needed so the DB doesn't ignore attempts to re-order indexes
5252
StrictIndexOrder: true, // needed since we want the SHOW CREATE TABLEs to match
53-
StrictCheckOrder: true, // ditto (only affects MariaDB)
54-
StrictForeignKeyNaming: true, // ditto
53+
StrictCheckConstraints: true, // ditto (strict naming, and on MariaDB strict ordering)
54+
StrictForeignKeyNaming: true, // ditto (strict naming, and don't conflate RESTRICT vs NO ACTION)
5555
StrictColumnDefinition: true, // ditto (only affects MySQL 8 edge cases)
5656
SkipPreDropAlters: true, // ignore DROP PARTITIONs that were only generated to speed up a DROP TABLE
5757
Flavor: vopts.Flavor,

internal/tengo/diff.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ type StatementModifiers struct {
7777
LockClause string // Include a LOCK=[value] clause in generated ALTER TABLE
7878
AlgorithmClause string // Include an ALGORITHM=[value] clause in generated ALTER TABLE
7979
StrictIndexOrder bool // If true, maintain index order even in cases where there is no functional difference
80-
StrictCheckOrder bool // If true, maintain check constraint order even though it never has a functional difference (only affects MariaDB)
80+
StrictCheckConstraints bool // If true, maintain check constraint definition even if differences are cosmetic (name change; relative order of check definitions in MariaDB)
8181
StrictForeignKeyNaming bool // If true, maintain foreign key definition even if differences are cosmetic (name change, RESTRICT vs NO ACTION, etc)
8282
StrictColumnDefinition bool // If true, maintain column properties that are purely cosmetic (only affects MySQL 8)
8383
LaxColumnOrder bool // If true, don't modify columns if they only differ by position

internal/tengo/table_alter_clause.go

Lines changed: 37 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -257,16 +257,28 @@ func (dfk DropForeignKey) Clause(mods StatementModifiers) string {
257257
// It satisfies the TableAlterClause interface.
258258
type AddCheck struct {
259259
Check *Check
260-
reorderOnly bool // true if check is being dropped and re-added just to re-order
260+
reorderOnly bool // true if check is being dropped and re-added just to re-order (only relevant in MariaDB)
261+
renameOnly bool // true if check is being dropped and re-added just to change name
261262
}
262263

263264
// Clause returns an ADD CONSTRAINT ... CHECK clause of an ALTER TABLE
264265
// statement.
265266
func (acc AddCheck) Clause(mods StatementModifiers) string {
266-
if acc.reorderOnly && !(mods.StrictCheckOrder && mods.Flavor.IsMariaDB()) {
267-
return ""
267+
if acc.renameOnly {
268+
// Renaming a CHECK is ignored unless strict modifier is used, because OSC
269+
// tools tend to rename CHECK constraints.
270+
if !mods.StrictCheckConstraints {
271+
return ""
272+
}
273+
} else if acc.reorderOnly {
274+
// Changing the relative order of CHECKs within a table is ignored unless
275+
// strict modifier is used and server is MariaDB, because the relative order
276+
// is purely cosmetic and cannot even be adjusted outside of MariaDB.
277+
if !mods.StrictCheckConstraints || !mods.Flavor.IsMariaDB() {
278+
return ""
279+
}
268280
}
269-
return fmt.Sprintf("ADD %s", acc.Check.Definition(mods.Flavor))
281+
return "ADD " + acc.Check.Definition(mods.Flavor)
270282
}
271283

272284
///// DropCheck ////////////////////////////////////////////////////////////////
@@ -276,20 +288,32 @@ func (acc AddCheck) Clause(mods StatementModifiers) string {
276288
// It satisfies the TableAlterClause interface.
277289
type DropCheck struct {
278290
Check *Check
279-
reorderOnly bool // true if index is being dropped and re-added just to re-order
291+
reorderOnly bool // true if index is being dropped and re-added just to re-order (only relevant in MariaDB)
292+
renameOnly bool // true if check is being dropped and re-added just to change name
280293
}
281294

282295
// Clause returns a DROP CHECK or DROP CONSTRAINT clause of an ALTER TABLE
283296
// statement, depending on the flavor.
284297
func (dcc DropCheck) Clause(mods StatementModifiers) string {
285-
if dcc.reorderOnly && !(mods.StrictCheckOrder && mods.Flavor.IsMariaDB()) {
286-
return ""
298+
if dcc.renameOnly {
299+
// Renaming a CHECK is ignored unless strict modifier is used, because OSC
300+
// tools tend to rename CHECK constraints as part of their normal operation
301+
if !mods.StrictCheckConstraints {
302+
return ""
303+
}
304+
} else if dcc.reorderOnly {
305+
// Changing the relative order of CHECKs within a table is ignored unless
306+
// strict modifier is used and server is MariaDB, because the relative order
307+
// is purely cosmetic and cannot even be adjusted outside of MariaDB
308+
if !mods.StrictCheckConstraints || !mods.Flavor.IsMariaDB() {
309+
return ""
310+
}
287311
}
288-
noun := "CHECK"
289312
if mods.Flavor.IsMariaDB() {
290-
noun = "CONSTRAINT"
313+
return "DROP CONSTRAINT " + EscapeIdentifier(dcc.Check.Name)
314+
} else {
315+
return "DROP CHECK " + EscapeIdentifier(dcc.Check.Name)
291316
}
292-
return fmt.Sprintf("DROP %s %s", noun, EscapeIdentifier(dcc.Check.Name))
293317
}
294318

295319
///// AlterCheck ///////////////////////////////////////////////////////////////
@@ -303,8 +327,9 @@ type AlterCheck struct {
303327

304328
// Clause returns an ALTER CHECK clause of an ALTER TABLE statement.
305329
func (alcc AlterCheck) Clause(mods StatementModifiers) string {
306-
// Note: if MariaDB ever supports NOT ENFORCED, this will need an extra check
307-
// similar to how AlterIndex.alsoReordering works
330+
// Note: if MariaDB ever supports NOT ENFORCED, this will need extra logic to
331+
// handle the situation where the same check is being reordered and altered
332+
// and strict mods are in-use.
308333
var status string
309334
if alcc.NewEnforcement {
310335
status = "ENFORCED"

internal/tengo/table_diff.go

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,10 @@ func diffTables(from, to *Table) (clauses []TableAlterClause, supported bool) {
475475
// Compare secondary indexes
476476
clauses = append(clauses, compareSecondaryIndexes(from, to)...)
477477

478-
// Compare foreign keys
478+
// Compare foreign keys. If only the name of an FK changes, we consider this
479+
// difference to be cosmetic, and suppress it at clause generation time unless
480+
// requested. (This is important for pt-osc support, since it renames FKs due
481+
// to their namespace being schema-wide.)
479482
fromForeignKeys := from.foreignKeysByName()
480483
toForeignKeys := to.foreignKeysByName()
481484
fkChangeCosmeticOnly := func(fk *ForeignKey, others []*ForeignKey) bool {
@@ -517,21 +520,36 @@ func diffTables(from, to *Table) (clauses []TableAlterClause, supported bool) {
517520

518521
// Compare check constraints. Although the order of check constraints has no
519522
// functional impact, ordering changes must nonetheless must be detected, as
520-
// MariaDB lists checks in creation order for I_S and SHOW CREATE.
523+
// MariaDB lists checks in creation order for I_S and SHOW CREATE. And similar
524+
// to FKs, we must detect naming-only changes for OSC tool compatibility.
521525
fromChecks := from.checksByName()
522526
toChecks := to.checksByName()
527+
checkChangeNameOnly := func(cc *Check, others []*Check) bool {
528+
for _, other := range others {
529+
if cc.Clause == other.Clause && cc.Enforced == other.Enforced {
530+
return true
531+
}
532+
}
533+
return false
534+
}
523535
var fromCheckStillExist []*Check // ordered list of checks from "from" that still exist in "to"
524536
for _, fromCheck := range from.Checks {
525537
if _, stillExists := toChecks[fromCheck.Name]; stillExists {
526538
fromCheckStillExist = append(fromCheckStillExist, fromCheck)
527539
} else {
528-
clauses = append(clauses, DropCheck{Check: fromCheck})
540+
clauses = append(clauses, DropCheck{
541+
Check: fromCheck,
542+
renameOnly: checkChangeNameOnly(fromCheck, to.Checks),
543+
})
529544
}
530545
}
531546
var reorderChecks bool
532547
for n, toCheck := range to.Checks {
533548
if fromCheck, existedBefore := fromChecks[toCheck.Name]; !existedBefore {
534-
clauses = append(clauses, AddCheck{Check: toCheck})
549+
clauses = append(clauses, AddCheck{
550+
Check: toCheck,
551+
renameOnly: checkChangeNameOnly(toCheck, from.Checks),
552+
})
535553
reorderChecks = true
536554
} else if fromCheck.Clause != toCheck.Clause {
537555
clauses = append(clauses, DropCheck{Check: fromCheck}, AddCheck{Check: toCheck})

internal/tengo/table_diff_test.go

Lines changed: 107 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -954,29 +954,73 @@ func TestAlterCheckConstraints(t *testing.T) {
954954
}
955955
}
956956

957-
// Test change in check clause on first check. This should result in 4 clauses:
958-
// drop and re-add the first check to modify it, and drop and re-add the second
959-
// check but only for ordering (which is typically ignored)
957+
// Test change in name of first check. This should result in 4 clauses: drop
958+
// and re-add the first check to rename (only emitted with strict modifier),
959+
// and drop and re-add the second check but only for ordering (only emitted
960+
// if MariaDB AND strict modifier)
961+
maria105 := ParseFlavor("mariadb:10.5")
962+
strictMySQLMods := StatementModifiers{Flavor: flavor, StrictCheckConstraints: true}
963+
strictMariaMods := StatementModifiers{Flavor: maria105, StrictCheckConstraints: true}
960964
tableChecks2 := aTableForFlavor(flavor, 1)
961965
tableChecks2.Checks = []*Check{
962-
{Name: "alivecheck", Clause: "alive = 1", Enforced: true},
966+
{Name: "_alivecheck", Clause: "alive != 0", Enforced: true},
963967
{Name: "stringythings", Clause: "ssn <> '000000000'", Enforced: true},
964968
}
965969
tableChecks2.CreateStatement = tableChecks2.GeneratedCreateStatement(flavor)
966970
td = NewAlterTable(&tableChecks, &tableChecks2)
967971
if len(td.alterClauses) != 4 {
968972
t.Errorf("Expected 4 alterClauses, instead found %d", len(td.alterClauses))
969973
} else {
970-
if dcc, ok := td.alterClauses[0].(DropCheck); !ok || dcc.Check != tableChecks.Checks[0] || dcc.reorderOnly {
974+
if dcc, ok := td.alterClauses[0].(DropCheck); !ok || dcc.Check != tableChecks.Checks[0] || dcc.reorderOnly || !dcc.renameOnly {
971975
t.Errorf("Found unexpected alterClause %+v", td.alterClauses[0])
972976
}
973-
if acc, ok := td.alterClauses[1].(AddCheck); !ok || acc.Check != tableChecks2.Checks[0] || acc.reorderOnly {
977+
if acc, ok := td.alterClauses[1].(AddCheck); !ok || acc.Check != tableChecks2.Checks[0] || acc.reorderOnly || !acc.renameOnly {
974978
t.Errorf("Found unexpected alterClause %+v", td.alterClauses[1])
975979
}
976-
if dcc, ok := td.alterClauses[2].(DropCheck); !ok || dcc.Check != tableChecks.Checks[1] || !dcc.reorderOnly {
980+
if dcc, ok := td.alterClauses[2].(DropCheck); !ok || dcc.Check != tableChecks.Checks[1] || !dcc.reorderOnly || dcc.renameOnly {
977981
t.Errorf("Found unexpected alterClause %+v", td.alterClauses[2])
978982
}
979-
if acc, ok := td.alterClauses[3].(AddCheck); !ok || acc.Check != tableChecks2.Checks[1] || !acc.reorderOnly {
983+
if acc, ok := td.alterClauses[3].(AddCheck); !ok || acc.Check != tableChecks2.Checks[1] || !acc.reorderOnly || acc.renameOnly {
984+
t.Errorf("Found unexpected alterClause %+v", td.alterClauses[3])
985+
}
986+
for n, alterClause := range td.alterClauses {
987+
// Expectations: all blank with regular mods; first two non-blank with strict
988+
// MySQL mods; all non-blank with strict MariaDB mods
989+
if clause := alterClause.Clause(mods); clause != "" {
990+
t.Errorf("Unexpected clause with basic mods at n=%d: expected blank, found %q", n, clause)
991+
}
992+
expectStrictBlank := n > 1
993+
actualStrictBlank := alterClause.Clause(strictMySQLMods) == ""
994+
if expectStrictBlank != actualStrictBlank {
995+
t.Errorf("Unexpected result from Clause() with strict MySQL modifier at n=%d", n)
996+
}
997+
if clause := alterClause.Clause(strictMariaMods); clause == "" {
998+
t.Errorf("Unexpected blank result from Clause() with strict MariaDB modifier at n=%d", n)
999+
}
1000+
}
1001+
}
1002+
1003+
// Revert first check's name change, but change its check clause instead.
1004+
// This should result in 4 clauses: drop and re-add the first check to modify
1005+
// it, and drop and re-add the second check but only for ordering (only emitted
1006+
// if MariaDB AND strict modifier)
1007+
tableChecks2.Checks[0].Name = tableChecks.Checks[0].Name
1008+
tableChecks2.Checks[0].Clause = "alive = 1"
1009+
tableChecks2.CreateStatement = tableChecks2.GeneratedCreateStatement(flavor)
1010+
td = NewAlterTable(&tableChecks, &tableChecks2)
1011+
if len(td.alterClauses) != 4 {
1012+
t.Errorf("Expected 4 alterClauses, instead found %d", len(td.alterClauses))
1013+
} else {
1014+
if dcc, ok := td.alterClauses[0].(DropCheck); !ok || dcc.Check != tableChecks.Checks[0] || dcc.reorderOnly || dcc.renameOnly {
1015+
t.Errorf("Found unexpected alterClause %+v", td.alterClauses[0])
1016+
}
1017+
if acc, ok := td.alterClauses[1].(AddCheck); !ok || acc.Check != tableChecks2.Checks[0] || acc.reorderOnly || acc.renameOnly {
1018+
t.Errorf("Found unexpected alterClause %+v", td.alterClauses[1])
1019+
}
1020+
if dcc, ok := td.alterClauses[2].(DropCheck); !ok || dcc.Check != tableChecks.Checks[1] || !dcc.reorderOnly || dcc.renameOnly {
1021+
t.Errorf("Found unexpected alterClause %+v", td.alterClauses[2])
1022+
}
1023+
if acc, ok := td.alterClauses[3].(AddCheck); !ok || acc.Check != tableChecks2.Checks[1] || !acc.reorderOnly || acc.renameOnly {
9801024
t.Errorf("Found unexpected alterClause %+v", td.alterClauses[3])
9811025
}
9821026
for n, alterClause := range td.alterClauses {
@@ -1005,31 +1049,29 @@ func TestAlterCheckConstraints(t *testing.T) {
10051049
}
10061050

10071051
// Create a table with 5 checks. Reorder one of them and confirm result.
1008-
flavor = ParseFlavor("mariadb:10.5")
1009-
tableChecks, tableChecks2 = aTableForFlavor(flavor, 1), aTableForFlavor(flavor, 1)
1052+
tableChecks, tableChecks2 = aTableForFlavor(maria105, 1), aTableForFlavor(maria105, 1)
10101053
tableChecks.Checks = []*Check{
10111054
{Name: "check1", Clause: "ssn <> '111111111'", Enforced: true},
10121055
{Name: "check2", Clause: "ssn <> '222222222'", Enforced: true},
10131056
{Name: "check3", Clause: "ssn <> '333333333'", Enforced: true},
10141057
{Name: "check4", Clause: "ssn <> '444444444'", Enforced: true},
10151058
{Name: "check5", Clause: "ssn <> '555555555'", Enforced: true},
10161059
}
1017-
tableChecks.CreateStatement = tableChecks.GeneratedCreateStatement(flavor)
1060+
tableChecks.CreateStatement = tableChecks.GeneratedCreateStatement(maria105)
10181061
tableChecks2.Checks = []*Check{
10191062
{Name: "check1", Clause: "ssn <> '111111111'", Enforced: true},
10201063
{Name: "check2", Clause: "ssn <> '222222222'", Enforced: true},
10211064
{Name: "check4", Clause: "ssn <> '444444444'", Enforced: true},
10221065
{Name: "check3", Clause: "ssn <> '333333333'", Enforced: true},
10231066
{Name: "check5", Clause: "ssn <> '555555555'", Enforced: true},
10241067
}
1025-
tableChecks2.CreateStatement = tableChecks2.GeneratedCreateStatement(flavor)
1068+
tableChecks2.CreateStatement = tableChecks2.GeneratedCreateStatement(maria105)
10261069
td = NewAlterTable(&tableChecks, &tableChecks2)
1027-
modsStrict := StatementModifiers{Flavor: flavor, StrictCheckOrder: true}
10281070
if len(td.alterClauses) != 4 {
10291071
t.Errorf("Expected 4 alterClauses, instead found %d", len(td.alterClauses))
10301072
}
10311073
for n, alterClause := range td.alterClauses {
1032-
str, strStrict := alterClause.Clause(mods), alterClause.Clause(modsStrict)
1074+
str, strStrict := alterClause.Clause(mods), alterClause.Clause(strictMariaMods)
10331075
if str != "" || strStrict == "" {
10341076
t.Errorf("Clauses don't match expectations: %q / %q", str, strStrict)
10351077
}
@@ -1043,6 +1085,32 @@ func TestAlterCheckConstraints(t *testing.T) {
10431085
}
10441086
}
10451087
}
1088+
1089+
// Confirm an edge case around behavior of Clause when being renamed AND
1090+
// reordered: output shouldn't ever be blank with strict mods, regardless of
1091+
// MySQL vs MariaDB. The conditionals in Clause should be organized in a way
1092+
// that properly handles this.
1093+
add := AddCheck{
1094+
Check: tableChecks.Checks[0],
1095+
reorderOnly: true,
1096+
renameOnly: true,
1097+
}
1098+
drop := DropCheck{
1099+
Check: tableChecks.Checks[0],
1100+
reorderOnly: true,
1101+
renameOnly: true,
1102+
}
1103+
for _, ac := range []TableAlterClause{add, drop} {
1104+
if clause := ac.Clause(mods); clause != "" {
1105+
t.Errorf("Expected blank clause with non-strict mods, instead found %q", clause)
1106+
}
1107+
if clause := ac.Clause(strictMySQLMods); clause == "" {
1108+
t.Error("Expected non-blank clause with strict MySQL mods, but it was blank")
1109+
}
1110+
if clause := ac.Clause(strictMariaMods); clause == "" {
1111+
t.Error("Expected non-blank clause with strict MariaDB mods, but it was blank")
1112+
}
1113+
}
10461114
}
10471115

10481116
// TestAlterCheckConstraints provides integration test coverage relating to
@@ -1086,7 +1154,7 @@ func (s TengoIntegrationSuite) TestAlterCheckConstraints(t *testing.T) {
10861154
tableChecks := getTableCopy("grab_bag")
10871155
tableChecks.Checks = []*Check{
10881156
{Name: "alivecheck", Clause: "alive != 0", Enforced: true},
1089-
{Name: "stringythings", Clause: "code != 'ABCD1234' AND name != 'ABCD1234'", Enforced: true},
1157+
{Name: "stringythings", Clause: "code != 'ABCD1234' AND owner_id != 123", Enforced: true},
10901158
}
10911159
tableChecks.CreateStatement = tableChecks.GeneratedCreateStatement(flavor)
10921160
td := NewAlterTable(tableNoChecks, tableChecks)
@@ -1096,9 +1164,10 @@ func (s TengoIntegrationSuite) TestAlterCheckConstraints(t *testing.T) {
10961164
t.Fatal("Table is unexpectedly unsupported for diffs now")
10971165
}
10981166

1099-
// Confirm that modifying a check's name or clause = drop and re-add
1167+
// Confirm that modifying a check's clause = drop and re-add, but changing name
1168+
// doesn't emit anything with non-strict mods
11001169
tableChecks2 := getTableCopy("grab_bag")
1101-
tableChecks2.Checks[0].Clause = "alive = 1"
1170+
tableChecks2.Checks[0].Clause = strings.ReplaceAll(tableChecks.Checks[0].Clause, "0", "9")
11021171
tableChecks2.Checks[1].Name = "stringycheck"
11031172
tableChecks2.CreateStatement = tableChecks2.GeneratedCreateStatement(flavor)
11041173
td = NewAlterTable(tableChecks, tableChecks2)
@@ -1113,6 +1182,27 @@ func (s TengoIntegrationSuite) TestAlterCheckConstraints(t *testing.T) {
11131182
if len(tableChecks.Checks) != 2 {
11141183
t.Errorf("Expected 2 check constraints, instead found %d", len(tableChecks.Checks))
11151184
}
1185+
// Now run an additional diff, which should still have 2 alter clauses relating
1186+
// to the name difference: both clauses should be blank with non-strict mods;
1187+
// but with strict mods, running them should actually update the name
1188+
td = NewAlterTable(tableChecks, tableChecks2)
1189+
if len(td.alterClauses) != 2 {
1190+
t.Errorf("Expected 2 alterClauses, instead found %d", len(td.alterClauses))
1191+
}
1192+
if stmt, err := td.Statement(StatementModifiers{Flavor: flavor}); stmt != "" || err != nil {
1193+
t.Errorf("Unexpected return from Statement: %q / %v", stmt, err)
1194+
}
1195+
if stmt, err := td.Statement(StatementModifiers{Flavor: flavor, StrictCheckConstraints: true}); stmt == "" || err != nil {
1196+
t.Errorf("Unexpected return from Statement: %q / %v", stmt, err)
1197+
} else if _, err := db.Exec(stmt); err != nil {
1198+
t.Fatalf("Unexpected error executing statement %q: %v", stmt, err)
1199+
} else {
1200+
tableChecks = getTableCopy("grab_bag")
1201+
td = NewAlterTable(tableChecks, tableChecks2)
1202+
if td != nil && len(td.alterClauses) > 0 {
1203+
t.Errorf("Expected 0 alterClauses, instead found %d", len(td.alterClauses))
1204+
}
1205+
}
11161206

11171207
// Confirm functionality related to MySQL's ALTER CHECK clause and the NOT
11181208
// ENFORCED modifier

0 commit comments

Comments
 (0)