vitess.io/vitess@v0.16.2/go/vt/vttablet/onlineddl/analysis_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  	"testing"
    25  
    26  	"github.com/stretchr/testify/assert"
    27  	"github.com/stretchr/testify/require"
    28  
    29  	"vitess.io/vitess/go/mysql"
    30  	"vitess.io/vitess/go/vt/sqlparser"
    31  )
    32  
    33  func TestAnalyzeInstantDDL(t *testing.T) {
    34  	tt := []struct {
    35  		version     string
    36  		create      string
    37  		alter       string
    38  		expectError bool
    39  		instant     bool
    40  	}{
    41  		// add/drop columns
    42  		{
    43  			version: "5.7.28",
    44  			create:  "create table t(id int, i1 int not null, primary key(id))",
    45  			alter:   "alter table t add column i2 int not null",
    46  			instant: false,
    47  		},
    48  		{
    49  			version: "8.0.21",
    50  			create:  "create table t(id int, i1 int not null, primary key(id))",
    51  			alter:   "alter table t add column i2 int not null",
    52  			instant: true,
    53  		},
    54  		{
    55  			version: "8.0.21",
    56  			create:  "create table t(id int, i1 int not null, primary key(id))",
    57  			alter:   "alter table t add column i2 int not null, add column i3 int not null",
    58  			instant: true,
    59  		},
    60  		{
    61  			// fail add mid column in older versions
    62  			version: "8.0.21",
    63  			create:  "create table t(id int, i1 int not null, primary key(id))",
    64  			alter:   "alter table t add column i2 int not null after id",
    65  			instant: false,
    66  		},
    67  		{
    68  			version: "8.0.21",
    69  			create:  "create table t(id int, i1 int not null, primary key(id))",
    70  			alter:   "alter table t drop column i1",
    71  			instant: false,
    72  		},
    73  		{
    74  			// drop virtual column
    75  			version: "8.0.21",
    76  			create:  "create table t(id int, i1 int not null, i2 int generated always as (i1 + 1) virtual, primary key(id))",
    77  			alter:   "alter table t drop column i2",
    78  			instant: true,
    79  		},
    80  		{
    81  			version: "8.0.21",
    82  			create:  "create table t(id int, i1 int not null, i2 int generated always as (i1 + 1) stored, primary key(id))",
    83  			alter:   "alter table t drop column i2",
    84  			instant: false,
    85  		},
    86  		{
    87  			// add mid column
    88  			version: "8.0.29",
    89  			create:  "create table t(id int, i1 int not null, primary key(id))",
    90  			alter:   "alter table t add column i2 int not null after id",
    91  			instant: true,
    92  		},
    93  		{
    94  			// drop mid column
    95  			version: "8.0.29",
    96  			create:  "create table t(id int, i1 int not null, i2 int not null, primary key(id))",
    97  			alter:   "alter table t drop column i1",
    98  			instant: true,
    99  		},
   100  		{
   101  			// fail due to row_format=compressed
   102  			version: "8.0.29",
   103  			create:  "create table t(id int, i1 int not null, i2 int not null, primary key(id)) row_format=compressed",
   104  			alter:   "alter table t drop column i1",
   105  			instant: false,
   106  		},
   107  		{
   108  			version: "8.0.29",
   109  			create:  "create table t(id int, i1 int not null, primary key(id))",
   110  			alter:   "alter table t add column i2 int not null after id, add column i3 int not null",
   111  			instant: true,
   112  		},
   113  		{
   114  			version: "8.0.29",
   115  			create:  "create table t(id int, i1 int not null, primary key(id))",
   116  			alter:   "alter table t add column i2 int not null after id, add column i3 int not null, drop column i1",
   117  			instant: true,
   118  		},
   119  		// change/remove column default
   120  		{
   121  			// set a default value
   122  			version: "8.0.21",
   123  			create:  "create table t(id int, i1 int not null, primary key(id))",
   124  			alter:   "alter table t modify column i1 int not null default 0",
   125  			instant: true,
   126  		},
   127  		{
   128  			// change a default value
   129  			version: "8.0.21",
   130  			create:  "create table t(id int, i1 int not null, primary key(id))",
   131  			alter:   "alter table t modify column i1 int not null default 3",
   132  			instant: true,
   133  		},
   134  		{
   135  			// change default value to null
   136  			version: "8.0.21",
   137  			create:  "create table t(id int, i1 int not null, primary key(id))",
   138  			alter:   "alter table t modify column i1 int default null",
   139  			instant: false,
   140  		},
   141  		{
   142  			// fail because on top of changing the default value, the datatype is changed, too
   143  			version: "8.0.21",
   144  			create:  "create table t(id int, i1 int not null, primary key(id))",
   145  			alter:   "alter table t modify column i1 bigint not null default 3",
   146  			instant: false,
   147  		},
   148  		{
   149  			version: "8.0.21",
   150  			create:  "create table t(id int, i1 int, primary key(id))",
   151  			alter:   "alter table t modify column i1 int default 0",
   152  			instant: true,
   153  		},
   154  		{
   155  			version: "8.0.21",
   156  			create:  "create table t(id int, i1 int, primary key(id))",
   157  			alter:   "alter table t modify column i1 int default null",
   158  			instant: true,
   159  		},
   160  		// enum/set:
   161  		{
   162  			// enum same, with changed default
   163  			version: "8.0.21",
   164  			create:  "create table t(id int, c1 enum('a', 'b', 'c'), primary key(id))",
   165  			alter:   "alter table t modify column c1 enum('a', 'b', 'c') default 'b'",
   166  			instant: true,
   167  		},
   168  		{
   169  			// enum append
   170  			version: "8.0.21",
   171  			create:  "create table t(id int, c1 enum('a', 'b', 'c'), primary key(id))",
   172  			alter:   "alter table t modify column c1 enum('a', 'b', 'c', 'd')",
   173  			instant: true,
   174  		},
   175  		{
   176  			// enum append with changed default
   177  			version: "8.0.21",
   178  			create:  "create table t(id int, c1 enum('a', 'b', 'c') default 'a', primary key(id))",
   179  			alter:   "alter table t modify column c1 enum('a', 'b', 'c', 'd') default 'd'",
   180  			instant: true,
   181  		},
   182  		{
   183  			// fail insert in middle
   184  			version: "8.0.21",
   185  			create:  "create table t(id int, c1 enum('a', 'b', 'c'), primary key(id))",
   186  			alter:   "alter table t modify column c1 enum('a', 'b', 'x', 'c')",
   187  			instant: false,
   188  		},
   189  		{
   190  			// fail change
   191  			version: "8.0.21",
   192  			create:  "create table t(id int, c1 enum('a', 'b', 'c'), primary key(id))",
   193  			alter:   "alter table t modify column c1 enum('a', 'x', 'c')",
   194  			instant: false,
   195  		},
   196  		{
   197  			// set append
   198  			version: "8.0.21",
   199  			create:  "create table t(id int, c1 set('a', 'b', 'c'), primary key(id))",
   200  			alter:   "alter table t modify column c1 set('a', 'b', 'c', 'd')",
   201  			instant: true,
   202  		},
   203  		{
   204  			// fail set append when over threshold (increase from 8 to 9 values => storage goes from 1 byte to 2 bytes)
   205  			version: "8.0.21",
   206  			create:  "create table t(id int, c1 set('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'), primary key(id))",
   207  			alter:   "alter table t modify column c1 set('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i')",
   208  			instant: false,
   209  		},
   210  	}
   211  	for _, tc := range tt {
   212  		name := tc.version + " " + tc.create
   213  		t.Run(name, func(t *testing.T) {
   214  			stmt, err := sqlparser.ParseStrictDDL(tc.create)
   215  			require.NoError(t, err)
   216  			createTable, ok := stmt.(*sqlparser.CreateTable)
   217  			require.True(t, ok)
   218  
   219  			stmt, err = sqlparser.ParseStrictDDL(tc.alter)
   220  			require.NoError(t, err)
   221  			alterTable, ok := stmt.(*sqlparser.AlterTable)
   222  			require.True(t, ok)
   223  
   224  			_, capableOf, _ := mysql.GetFlavor(tc.version, nil)
   225  			plan, err := AnalyzeInstantDDL(alterTable, createTable, capableOf)
   226  			if tc.expectError {
   227  				assert.Error(t, err)
   228  			} else {
   229  				assert.NoError(t, err)
   230  				if tc.instant {
   231  					require.NotNil(t, plan)
   232  					assert.Equal(t, instantDDLSpecialOperation, plan.operation)
   233  				} else {
   234  					require.Nil(t, plan)
   235  				}
   236  			}
   237  		})
   238  	}
   239  }