vitess.io/vitess@v0.16.2/go/vt/vttablet/onlineddl/executor_test.go (about) 1 /* 2 Copyright 2021 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 /* 18 Functionality of this Executor is tested in go/test/endtoend/onlineddl/... 19 */ 20 21 package onlineddl 22 23 import ( 24 "context" 25 "testing" 26 27 "github.com/stretchr/testify/assert" 28 "github.com/stretchr/testify/require" 29 30 "vitess.io/vitess/go/vt/schema" 31 "vitess.io/vitess/go/vt/sqlparser" 32 ) 33 34 func TestVexecUpdateTemplates(t *testing.T) { 35 { 36 match, err := sqlparser.QueryMatchesTemplates("select 1 from dual", vexecUpdateTemplates) 37 assert.NoError(t, err) 38 assert.False(t, match) 39 } 40 queries := []string{ 41 `update _vt.schema_migrations set migration_status='cancel-all' where mysql_schema='vt_commerce'`, 42 `update _vt.schema_migrations set migration_status = 'cancel-all' where migration_uuid='a5a563da_dc1a_11ec_a416_0a43f95f28a3' and mysql_schema = 'vt_commerce'`, 43 `update _vt.schema_migrations set migration_status = 'cancel-all' where migration_uuid='a5a563da_dc1a_11ec_a416_0a43f95f28a3' and mysql_schema = 'vt_commerce' and shard='0'`, 44 } 45 for _, query := range queries { 46 t.Run(query, func(t *testing.T) { 47 match, err := sqlparser.QueryMatchesTemplates(query, vexecUpdateTemplates) 48 assert.NoError(t, err) 49 assert.True(t, match) 50 }) 51 } 52 } 53 54 func TestGetConstraintType(t *testing.T) { 55 { 56 typ := GetConstraintType(&sqlparser.CheckConstraintDefinition{}) 57 assert.Equal(t, CheckConstraintType, typ) 58 } 59 { 60 typ := GetConstraintType(&sqlparser.ForeignKeyDefinition{}) 61 assert.Equal(t, ForeignKeyConstraintType, typ) 62 } 63 } 64 65 func TestValidateAndEditCreateTableStatement(t *testing.T) { 66 e := Executor{} 67 tt := []struct { 68 name string 69 query string 70 strategyOptions string 71 expectError string 72 countConstraints int 73 }{ 74 { 75 name: "table with FK, not allowed", 76 query: ` 77 create table onlineddl_test ( 78 id int auto_increment, 79 i int not null, 80 parent_id int not null, 81 primary key(id), 82 constraint test_fk foreign key (parent_id) references onlineddl_test_parent (id) on delete no action 83 ) 84 `, 85 countConstraints: 1, 86 expectError: schema.ErrForeignKeyFound.Error(), 87 }, 88 { 89 name: "table with FK, allowed", 90 query: ` 91 create table onlineddl_test ( 92 id int auto_increment, 93 i int not null, 94 parent_id int not null, 95 primary key(id), 96 constraint test_fk foreign key (parent_id) references onlineddl_test_parent (id) on delete no action 97 ) 98 `, 99 strategyOptions: "--unsafe-allow-foreign-keys", 100 countConstraints: 1, 101 }, 102 { 103 name: "table with anonymous FK, allowed", 104 query: ` 105 create table onlineddl_test ( 106 id int auto_increment, 107 i int not null, 108 parent_id int not null, 109 primary key(id), 110 foreign key (parent_id) references onlineddl_test_parent (id) on delete no action 111 ) 112 `, 113 strategyOptions: "--unsafe-allow-foreign-keys", 114 countConstraints: 1, 115 }, 116 { 117 name: "table with CHECK constraints", 118 query: ` 119 create table onlineddl_test ( 120 id int auto_increment, 121 i int not null, 122 primary key(id), 123 constraint check_1 CHECK ((i >= 0)), 124 constraint check_2 CHECK ((i <> 5)), 125 constraint check_3 CHECK ((i >= 0)), 126 constraint chk_1111033c1d2d5908bf1f956ba900b192_check_4 CHECK ((i >= 0)) 127 ) 128 `, 129 countConstraints: 4, 130 }, 131 { 132 name: "table with both FOREIGN and CHECK constraints", 133 query: ` 134 create table onlineddl_test ( 135 id int auto_increment, 136 i int not null, 137 primary key(id), 138 constraint check_1 CHECK ((i >= 0)), 139 constraint test_fk foreign key (parent_id) references onlineddl_test_parent (id) on delete no action, 140 constraint chk_1111033c1d2d5908bf1f956ba900b192_check_4 CHECK ((i >= 0)) 141 ) 142 `, 143 strategyOptions: "--unsafe-allow-foreign-keys", 144 countConstraints: 3, 145 }, 146 } 147 for _, tc := range tt { 148 t.Run(tc.name, func(t *testing.T) { 149 stmt, err := sqlparser.ParseStrictDDL(tc.query) 150 require.NoError(t, err) 151 createTable, ok := stmt.(*sqlparser.CreateTable) 152 require.True(t, ok) 153 154 onlineDDL := &schema.OnlineDDL{UUID: "a5a563da_dc1a_11ec_a416_0a43f95f28a3", Table: "onlineddl_test", Options: tc.strategyOptions} 155 constraintMap, err := e.validateAndEditCreateTableStatement(context.Background(), onlineDDL, createTable) 156 if tc.expectError != "" { 157 require.Error(t, err) 158 assert.ErrorContains(t, err, tc.expectError) 159 } else { 160 assert.NoError(t, err) 161 } 162 uniqueConstraintNames := map[string]bool{} 163 err = sqlparser.Walk(func(node sqlparser.SQLNode) (kontinue bool, err error) { 164 switch node := node.(type) { 165 case *sqlparser.ConstraintDefinition: 166 uniqueConstraintNames[node.Name.String()] = true 167 } 168 return true, nil 169 }, createTable) 170 assert.NoError(t, err) 171 assert.Equal(t, tc.countConstraints, len(uniqueConstraintNames)) 172 assert.Equalf(t, tc.countConstraints, len(constraintMap), "got contraints: %v", constraintMap) 173 }) 174 } 175 } 176 177 func TestValidateAndEditAlterTableStatement(t *testing.T) { 178 e := Executor{} 179 tt := []struct { 180 alter string 181 expect []string 182 }{ 183 { 184 alter: "alter table t add column i int", 185 expect: []string{"alter table t add column i int, algorithm = copy"}, 186 }, 187 { 188 alter: "alter table t add column i int, add fulltext key name1_ft (name1)", 189 expect: []string{"alter table t add column i int, add fulltext key name1_ft (name1), algorithm = copy"}, 190 }, 191 { 192 alter: "alter table t add column i int, add fulltext key name1_ft (name1), add fulltext key name2_ft (name2)", 193 expect: []string{"alter table t add column i int, add fulltext key name1_ft (name1), algorithm = copy", "alter table t add fulltext key name2_ft (name2), algorithm = copy"}, 194 }, 195 { 196 alter: "alter table t add fulltext key name0_ft (name0), add column i int, add fulltext key name1_ft (name1), add fulltext key name2_ft (name2)", 197 expect: []string{"alter table t add fulltext key name0_ft (name0), add column i int, algorithm = copy", "alter table t add fulltext key name1_ft (name1), algorithm = copy", "alter table t add fulltext key name2_ft (name2), algorithm = copy"}, 198 }, 199 { 200 alter: "alter table t add constraint check (id != 1)", 201 expect: []string{"alter table t add constraint chk_aulpn7bjeortljhguy86phdn9 check (id != 1), algorithm = copy"}, 202 }, 203 { 204 alter: "alter table t add constraint t_chk_1 check (id != 1)", 205 expect: []string{"alter table t add constraint chk_1_aulpn7bjeortljhguy86phdn9 check (id != 1), algorithm = copy"}, 206 }, 207 { 208 alter: "alter table t add constraint some_check check (id != 1)", 209 expect: []string{"alter table t add constraint some_check_aulpn7bjeortljhguy86phdn9 check (id != 1), algorithm = copy"}, 210 }, 211 { 212 alter: "alter table t add constraint some_check check (id != 1), add constraint another_check check (id != 2)", 213 expect: []string{"alter table t add constraint some_check_aulpn7bjeortljhguy86phdn9 check (id != 1), add constraint another_check_4fa197273p3w96267pzm3gfi3 check (id != 2), algorithm = copy"}, 214 }, 215 { 216 alter: "alter table t add foreign key (parent_id) references onlineddl_test_parent (id) on delete no action", 217 expect: []string{"alter table t add constraint fk_6fmhzdlya89128u5j3xapq34i foreign key (parent_id) references onlineddl_test_parent (id) on delete no action, algorithm = copy"}, 218 }, 219 { 220 alter: "alter table t add constraint myfk foreign key (parent_id) references onlineddl_test_parent (id) on delete no action", 221 expect: []string{"alter table t add constraint myfk_6fmhzdlya89128u5j3xapq34i foreign key (parent_id) references onlineddl_test_parent (id) on delete no action, algorithm = copy"}, 222 }, 223 { 224 alter: "alter table t add constraint t_fk_1 foreign key (parent_id) references onlineddl_test_parent (id) on delete no action", 225 expect: []string{"alter table t add constraint fk_1_6fmhzdlya89128u5j3xapq34i foreign key (parent_id) references onlineddl_test_parent (id) on delete no action, algorithm = copy"}, 226 }, 227 { 228 alter: "alter table t add constraint t_fk_1 foreign key (parent_id) references onlineddl_test_parent (id) on delete no action, add constraint some_check check (id != 1)", 229 expect: []string{"alter table t add constraint fk_1_6fmhzdlya89128u5j3xapq34i foreign key (parent_id) references onlineddl_test_parent (id) on delete no action, add constraint some_check_aulpn7bjeortljhguy86phdn9 check (id != 1), algorithm = copy"}, 230 }, 231 } 232 for _, tc := range tt { 233 t.Run(tc.alter, func(t *testing.T) { 234 stmt, err := sqlparser.ParseStrictDDL(tc.alter) 235 require.NoError(t, err) 236 alterTable, ok := stmt.(*sqlparser.AlterTable) 237 require.True(t, ok) 238 239 m := map[string]string{} 240 onlineDDL := &schema.OnlineDDL{UUID: "a5a563da_dc1a_11ec_a416_0a43f95f28a3", Table: "t", Options: "--unsafe-allow-foreign-keys"} 241 alters, err := e.validateAndEditAlterTableStatement(context.Background(), onlineDDL, alterTable, m) 242 assert.NoError(t, err) 243 altersStrings := []string{} 244 for _, alter := range alters { 245 altersStrings = append(altersStrings, sqlparser.String(alter)) 246 } 247 assert.Equal(t, tc.expect, altersStrings) 248 }) 249 } 250 } 251 252 func TestAddInstantAlgorithm(t *testing.T) { 253 e := Executor{} 254 tt := []struct { 255 alter string 256 expect string 257 }{ 258 { 259 alter: "alter table t add column i2 int not null", 260 expect: "ALTER TABLE `t` ADD COLUMN `i2` int NOT NULL, ALGORITHM = INSTANT", 261 }, 262 { 263 alter: "alter table t add column i2 int not null, lock=none", 264 expect: "ALTER TABLE `t` ADD COLUMN `i2` int NOT NULL, LOCK NONE, ALGORITHM = INSTANT", 265 }, 266 { 267 alter: "alter table t add column i2 int not null, algorithm=inplace", 268 expect: "ALTER TABLE `t` ADD COLUMN `i2` int NOT NULL, ALGORITHM = INSTANT", 269 }, 270 { 271 alter: "alter table t add column i2 int not null, algorithm=inplace, lock=none", 272 expect: "ALTER TABLE `t` ADD COLUMN `i2` int NOT NULL, ALGORITHM = INSTANT, LOCK NONE", 273 }, 274 } 275 for _, tc := range tt { 276 t.Run(tc.alter, func(t *testing.T) { 277 stmt, err := sqlparser.ParseStrictDDL(tc.alter) 278 require.NoError(t, err) 279 alterTable, ok := stmt.(*sqlparser.AlterTable) 280 require.True(t, ok) 281 282 e.addInstantAlgorithm(alterTable) 283 alterInstant := sqlparser.CanonicalString(alterTable) 284 285 assert.Equal(t, tc.expect, alterInstant) 286 287 stmt, err = sqlparser.ParseStrictDDL(alterInstant) 288 require.NoError(t, err) 289 _, ok = stmt.(*sqlparser.AlterTable) 290 require.True(t, ok) 291 }) 292 } 293 }