vitess.io/vitess@v0.16.2/go/vt/schemadiff/table.go (about)

     1  /*
     2  Copyright 2022 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  package schemadiff
    18  
    19  import (
    20  	"fmt"
    21  	"math"
    22  	"sort"
    23  	"strconv"
    24  	"strings"
    25  
    26  	golcs "github.com/yudai/golcs"
    27  
    28  	"vitess.io/vitess/go/mysql/collations"
    29  	"vitess.io/vitess/go/vt/sqlparser"
    30  )
    31  
    32  type AlterTableEntityDiff struct {
    33  	from       *CreateTableEntity
    34  	to         *CreateTableEntity
    35  	alterTable *sqlparser.AlterTable
    36  
    37  	subsequentDiff *AlterTableEntityDiff
    38  }
    39  
    40  // IsEmpty implements EntityDiff
    41  func (d *AlterTableEntityDiff) IsEmpty() bool {
    42  	return d.Statement() == nil
    43  }
    44  
    45  // Entities implements EntityDiff
    46  func (d *AlterTableEntityDiff) Entities() (from Entity, to Entity) {
    47  	return d.from, d.to
    48  }
    49  
    50  // Statement implements EntityDiff
    51  func (d *AlterTableEntityDiff) Statement() sqlparser.Statement {
    52  	if d == nil {
    53  		return nil
    54  	}
    55  	return d.alterTable
    56  }
    57  
    58  // AlterTable returns the underlying sqlparser.AlterTable that was generated for the diff.
    59  func (d *AlterTableEntityDiff) AlterTable() *sqlparser.AlterTable {
    60  	if d == nil {
    61  		return nil
    62  	}
    63  	return d.alterTable
    64  }
    65  
    66  // StatementString implements EntityDiff
    67  func (d *AlterTableEntityDiff) StatementString() (s string) {
    68  	if stmt := d.Statement(); stmt != nil {
    69  		s = sqlparser.String(stmt)
    70  	}
    71  	return s
    72  }
    73  
    74  // CanonicalStatementString implements EntityDiff
    75  func (d *AlterTableEntityDiff) CanonicalStatementString() (s string) {
    76  	if stmt := d.Statement(); stmt != nil {
    77  		s = sqlparser.CanonicalString(stmt)
    78  	}
    79  	return s
    80  }
    81  
    82  // SubsequentDiff implements EntityDiff
    83  func (d *AlterTableEntityDiff) SubsequentDiff() EntityDiff {
    84  	if d == nil {
    85  		return nil
    86  	}
    87  	return d.subsequentDiff
    88  }
    89  
    90  // SetSubsequentDiff implements EntityDiff
    91  func (d *AlterTableEntityDiff) SetSubsequentDiff(subDiff EntityDiff) {
    92  	if d == nil {
    93  		return
    94  	}
    95  	if subTableDiff, ok := subDiff.(*AlterTableEntityDiff); ok {
    96  		d.subsequentDiff = subTableDiff
    97  	} else {
    98  		d.subsequentDiff = nil
    99  	}
   100  }
   101  
   102  // addSubsequentDiff adds a subsequent diff to the tail of the diff sequence
   103  func (d *AlterTableEntityDiff) addSubsequentDiff(diff *AlterTableEntityDiff) {
   104  	if d.subsequentDiff == nil {
   105  		d.subsequentDiff = diff
   106  	} else {
   107  		d.subsequentDiff.addSubsequentDiff(diff)
   108  	}
   109  }
   110  
   111  type CreateTableEntityDiff struct {
   112  	to          *CreateTableEntity
   113  	createTable *sqlparser.CreateTable
   114  }
   115  
   116  // IsEmpty implements EntityDiff
   117  func (d *CreateTableEntityDiff) IsEmpty() bool {
   118  	return d.Statement() == nil
   119  }
   120  
   121  // Entities implements EntityDiff
   122  func (d *CreateTableEntityDiff) Entities() (from Entity, to Entity) {
   123  	return nil, &CreateTableEntity{CreateTable: d.createTable}
   124  }
   125  
   126  // Statement implements EntityDiff
   127  func (d *CreateTableEntityDiff) Statement() sqlparser.Statement {
   128  	if d == nil {
   129  		return nil
   130  	}
   131  	return d.createTable
   132  }
   133  
   134  // CreateTable returns the underlying sqlparser.CreateTable that was generated for the diff.
   135  func (d *CreateTableEntityDiff) CreateTable() *sqlparser.CreateTable {
   136  	if d == nil {
   137  		return nil
   138  	}
   139  	return d.createTable
   140  }
   141  
   142  // StatementString implements EntityDiff
   143  func (d *CreateTableEntityDiff) StatementString() (s string) {
   144  	if stmt := d.Statement(); stmt != nil {
   145  		s = sqlparser.String(stmt)
   146  	}
   147  	return s
   148  }
   149  
   150  // CanonicalStatementString implements EntityDiff
   151  func (d *CreateTableEntityDiff) CanonicalStatementString() (s string) {
   152  	if stmt := d.Statement(); stmt != nil {
   153  		s = sqlparser.CanonicalString(stmt)
   154  	}
   155  	return s
   156  }
   157  
   158  // SubsequentDiff implements EntityDiff
   159  func (d *CreateTableEntityDiff) SubsequentDiff() EntityDiff {
   160  	return nil
   161  }
   162  
   163  // SetSubsequentDiff implements EntityDiff
   164  func (d *CreateTableEntityDiff) SetSubsequentDiff(EntityDiff) {
   165  }
   166  
   167  type DropTableEntityDiff struct {
   168  	from      *CreateTableEntity
   169  	dropTable *sqlparser.DropTable
   170  }
   171  
   172  // IsEmpty implements EntityDiff
   173  func (d *DropTableEntityDiff) IsEmpty() bool {
   174  	return d.Statement() == nil
   175  }
   176  
   177  // Entities implements EntityDiff
   178  func (d *DropTableEntityDiff) Entities() (from Entity, to Entity) {
   179  	return d.from, nil
   180  }
   181  
   182  // Statement implements EntityDiff
   183  func (d *DropTableEntityDiff) Statement() sqlparser.Statement {
   184  	if d == nil {
   185  		return nil
   186  	}
   187  	return d.dropTable
   188  }
   189  
   190  // DropTable returns the underlying sqlparser.DropTable that was generated for the diff.
   191  func (d *DropTableEntityDiff) DropTable() *sqlparser.DropTable {
   192  	if d == nil {
   193  		return nil
   194  	}
   195  	return d.dropTable
   196  }
   197  
   198  // StatementString implements EntityDiff
   199  func (d *DropTableEntityDiff) StatementString() (s string) {
   200  	if stmt := d.Statement(); stmt != nil {
   201  		s = sqlparser.String(stmt)
   202  	}
   203  	return s
   204  }
   205  
   206  // CanonicalStatementString implements EntityDiff
   207  func (d *DropTableEntityDiff) CanonicalStatementString() (s string) {
   208  	if stmt := d.Statement(); stmt != nil {
   209  		s = sqlparser.CanonicalString(stmt)
   210  	}
   211  	return s
   212  }
   213  
   214  // SubsequentDiff implements EntityDiff
   215  func (d *DropTableEntityDiff) SubsequentDiff() EntityDiff {
   216  	return nil
   217  }
   218  
   219  // SetSubsequentDiff implements EntityDiff
   220  func (d *DropTableEntityDiff) SetSubsequentDiff(EntityDiff) {
   221  }
   222  
   223  type RenameTableEntityDiff struct {
   224  	from        *CreateTableEntity
   225  	to          *CreateTableEntity
   226  	renameTable *sqlparser.RenameTable
   227  }
   228  
   229  // IsEmpty implements EntityDiff
   230  func (d *RenameTableEntityDiff) IsEmpty() bool {
   231  	return d.Statement() == nil
   232  }
   233  
   234  // Entities implements EntityDiff
   235  func (d *RenameTableEntityDiff) Entities() (from Entity, to Entity) {
   236  	return d.from, d.to
   237  }
   238  
   239  // Statement implements EntityDiff
   240  func (d *RenameTableEntityDiff) Statement() sqlparser.Statement {
   241  	if d == nil {
   242  		return nil
   243  	}
   244  	return d.renameTable
   245  }
   246  
   247  // RenameTable returns the underlying sqlparser.RenameTable that was generated for the diff.
   248  func (d *RenameTableEntityDiff) RenameTable() *sqlparser.RenameTable {
   249  	if d == nil {
   250  		return nil
   251  	}
   252  	return d.renameTable
   253  }
   254  
   255  // StatementString implements EntityDiff
   256  func (d *RenameTableEntityDiff) StatementString() (s string) {
   257  	if stmt := d.Statement(); stmt != nil {
   258  		s = sqlparser.String(stmt)
   259  	}
   260  	return s
   261  }
   262  
   263  // CanonicalStatementString implements EntityDiff
   264  func (d *RenameTableEntityDiff) CanonicalStatementString() (s string) {
   265  	if stmt := d.Statement(); stmt != nil {
   266  		s = sqlparser.CanonicalString(stmt)
   267  	}
   268  	return s
   269  }
   270  
   271  // SubsequentDiff implements EntityDiff
   272  func (d *RenameTableEntityDiff) SubsequentDiff() EntityDiff {
   273  	return nil
   274  }
   275  
   276  // SetSubsequentDiff implements EntityDiff
   277  func (d *RenameTableEntityDiff) SetSubsequentDiff(EntityDiff) {
   278  }
   279  
   280  // CreateTableEntity stands for a TABLE construct. It contains the table's CREATE statement.
   281  type CreateTableEntity struct {
   282  	*sqlparser.CreateTable
   283  }
   284  
   285  func NewCreateTableEntity(c *sqlparser.CreateTable) (*CreateTableEntity, error) {
   286  	if !c.IsFullyParsed() {
   287  		return nil, &NotFullyParsedError{Entity: c.Table.Name.String(), Statement: sqlparser.CanonicalString(c)}
   288  	}
   289  	entity := &CreateTableEntity{CreateTable: c}
   290  	entity.normalize()
   291  	return entity, nil
   292  }
   293  
   294  // normalize cleans up the table definition:
   295  // - setting names to all keys
   296  // - table option case (upper/lower/special)
   297  // The function returns this receiver as courtesy
   298  func (c *CreateTableEntity) normalize() *CreateTableEntity {
   299  	c.normalizePrimaryKeyColumns()
   300  	c.normalizeForeignKeyIndexes() // implicitly add missing indexes for foreign keys
   301  	c.normalizeKeys()              // assign names to keys
   302  	c.normalizeUnnamedConstraints()
   303  	c.normalizeTableOptions()
   304  	c.normalizeColumnOptions()
   305  	c.normalizeIndexOptions()
   306  	c.normalizePartitionOptions()
   307  	return c
   308  }
   309  
   310  func (c *CreateTableEntity) normalizeTableOptions() {
   311  	for _, opt := range c.CreateTable.TableSpec.Options {
   312  		opt.Name = strings.ToLower(opt.Name)
   313  		switch opt.Name {
   314  		case "charset":
   315  			opt.String = strings.ToLower(opt.String)
   316  			if charset, ok := collationEnv.CharsetAlias(opt.String); ok {
   317  				opt.String = charset
   318  			}
   319  		case "collate":
   320  			opt.String = strings.ToLower(opt.String)
   321  			if collation, ok := collationEnv.CollationAlias(opt.String); ok {
   322  				opt.String = collation
   323  			}
   324  		case "engine":
   325  			opt.String = strings.ToUpper(opt.String)
   326  			if engineName, ok := engineCasing[opt.String]; ok {
   327  				opt.String = engineName
   328  			}
   329  		case "row_format":
   330  			opt.String = strings.ToUpper(opt.String)
   331  		}
   332  	}
   333  }
   334  
   335  func (c *CreateTableEntity) Clone() Entity {
   336  	return &CreateTableEntity{CreateTable: sqlparser.CloneRefOfCreateTable(c.CreateTable)}
   337  }
   338  
   339  // Right now we assume MySQL 8.0 for the collation normalization handling.
   340  const mysqlCollationVersion = "8.0.0"
   341  
   342  var collationEnv = collations.NewEnvironment(mysqlCollationVersion)
   343  
   344  func defaultCharset() string {
   345  	collation := collationEnv.LookupByID(collations.ID(collationEnv.DefaultConnectionCharset()))
   346  	if collation == nil {
   347  		return ""
   348  	}
   349  	return collation.Charset().Name()
   350  }
   351  
   352  func defaultCharsetCollation(charset string) string {
   353  	collation := collationEnv.DefaultCollationForCharset(charset)
   354  	if collation == nil {
   355  		return ""
   356  	}
   357  	return collation.Name()
   358  }
   359  
   360  func (c *CreateTableEntity) normalizeColumnOptions() {
   361  	tableCharset := defaultCharset()
   362  	tableCollation := ""
   363  	for _, option := range c.CreateTable.TableSpec.Options {
   364  		switch strings.ToUpper(option.Name) {
   365  		case "CHARSET":
   366  			tableCharset = option.String
   367  		case "COLLATE":
   368  			tableCollation = option.String
   369  		}
   370  	}
   371  	defaultCollation := defaultCharsetCollation(tableCharset)
   372  	if tableCollation == "" {
   373  		tableCollation = defaultCollation
   374  	}
   375  
   376  	for _, col := range c.CreateTable.TableSpec.Columns {
   377  		if col.Type.Options == nil {
   378  			col.Type.Options = &sqlparser.ColumnTypeOptions{}
   379  		}
   380  
   381  		// Map known lowercase fields to always be lowercase
   382  		col.Type.Type = strings.ToLower(col.Type.Type)
   383  		col.Type.Charset.Name = strings.ToLower(col.Type.Charset.Name)
   384  		col.Type.Options.Collate = strings.ToLower(col.Type.Options.Collate)
   385  
   386  		// See https://dev.mysql.com/doc/refman/8.0/en/create-table.html
   387  		// If neither NULL nor NOT NULL is specified, the column is treated as though NULL had been specified.
   388  		// That documentation though is not 100% true. There's an exception, and that is
   389  		// the `explicit_defaults_for_timestamp` flag. When that is disabled (the default on 5.7),
   390  		// a timestamp defaults to `NOT NULL`.
   391  		//
   392  		// We opt here to instead remove that difference and always then add `NULL` and treat
   393  		// `explicit_defaults_for_timestamp` as always enabled in the context of DDL for diffing.
   394  		if col.Type.Type == "timestamp" {
   395  			if col.Type.Options.Null == nil || *col.Type.Options.Null {
   396  				timestampNull := true
   397  				col.Type.Options.Null = &timestampNull
   398  			}
   399  		} else {
   400  			if col.Type.Options.Null != nil && *col.Type.Options.Null {
   401  				col.Type.Options.Null = nil
   402  			}
   403  		}
   404  		if col.Type.Options.Null == nil || *col.Type.Options.Null {
   405  			// If `DEFAULT NULL` is specified and the column allows NULL,
   406  			// we drop that in the normalized form since that is equivalent to the default value.
   407  			// See also https://dev.mysql.com/doc/refman/8.0/en/data-type-defaults.html
   408  			if _, ok := col.Type.Options.Default.(*sqlparser.NullVal); ok {
   409  				col.Type.Options.Default = nil
   410  			}
   411  		}
   412  
   413  		if col.Type.Options.Invisible != nil && !*col.Type.Options.Invisible {
   414  			// If a column is marked `VISIBLE`, that's the same as the default.
   415  			col.Type.Options.Invisible = nil
   416  		}
   417  
   418  		// Map any charset aliases to the real charset. This applies mainly right
   419  		// now to utf8 being an alias for utf8mb3.
   420  		if charset, ok := collationEnv.CharsetAlias(col.Type.Charset.Name); ok {
   421  			col.Type.Charset.Name = charset
   422  		}
   423  
   424  		// Map any collation aliases to the real collation. This applies mainly right
   425  		// now to utf8 being an alias for utf8mb3 collations.
   426  		if collation, ok := collationEnv.CollationAlias(col.Type.Options.Collate); ok {
   427  			col.Type.Options.Collate = collation
   428  		}
   429  
   430  		// Remove any lengths for integral types since it is deprecated there and
   431  		// doesn't mean anything anymore.
   432  		if _, ok := integralTypes[col.Type.Type]; ok {
   433  			// We can remove the length except when we have a boolean, which is
   434  			// stored as a tinyint(1) and treated special.
   435  			if !isBool(col.Type) {
   436  				col.Type.Length = nil
   437  			}
   438  		}
   439  
   440  		if _, ok := floatTypes[col.Type.Type]; ok {
   441  			// First, normalize the actual type
   442  			switch col.Type.Type {
   443  			case "float4":
   444  				col.Type.Type = "float"
   445  			case "float8", "real":
   446  				col.Type.Type = "double"
   447  			}
   448  
   449  			if col.Type.Length != nil && col.Type.Scale == nil && col.Type.Length.Type == sqlparser.IntVal {
   450  				if l, err := strconv.ParseInt(col.Type.Length.Val, 10, 64); err == nil {
   451  					// See https://dev.mysql.com/doc/refman/8.0/en/floating-point-types.html, but the docs are
   452  					// subtly wrong. We use a float for a precision of 24, not a double as the documentation
   453  					// mentioned. Validated against the actual behavior of MySQL.
   454  					if l <= 24 {
   455  						col.Type.Type = "float"
   456  					} else {
   457  						col.Type.Type = "double"
   458  					}
   459  				}
   460  				col.Type.Length = nil
   461  			}
   462  		}
   463  
   464  		if _, ok := charsetTypes[col.Type.Type]; ok {
   465  			// If the charset is explicitly configured and it mismatches, we don't normalize
   466  			// anything for charsets or collations and move on.
   467  			if col.Type.Charset.Name != "" && col.Type.Charset.Name != tableCharset {
   468  				continue
   469  			}
   470  
   471  			// Alright, first check if both charset and collation are the same as
   472  			// the table level options, in that case we can remove both since that's equivalent.
   473  			if col.Type.Charset.Name == tableCharset && col.Type.Options.Collate == tableCollation {
   474  				col.Type.Charset.Name = ""
   475  				col.Type.Options.Collate = ""
   476  			}
   477  			// If we have no charset or collation defined, we inherit the table defaults
   478  			// and don't need to do anything here and can continue to the next column.
   479  			// It doesn't matter if that's because it's not defined, or if it was because
   480  			// it was explicitly set to the same values.
   481  			if col.Type.Charset.Name == "" && col.Type.Options.Collate == "" {
   482  				continue
   483  			}
   484  
   485  			// We have a matching charset as the default, but it is explicitly set. In that
   486  			// case we still want to clear it, but set the default collation for the given charset
   487  			// if no collation is defined yet. We set then the collation to the default collation.
   488  			if col.Type.Charset.Name != "" {
   489  				col.Type.Charset.Name = ""
   490  				if col.Type.Options.Collate == "" {
   491  					col.Type.Options.Collate = defaultCollation
   492  				}
   493  			}
   494  
   495  			// We now have one case left, which is when we have set a collation but it's the same
   496  			// as the table level. In that case, we can clear it since that is equivalent.
   497  			if col.Type.Options.Collate == tableCollation {
   498  				col.Type.Options.Collate = ""
   499  			}
   500  		}
   501  	}
   502  }
   503  
   504  func (c *CreateTableEntity) normalizeIndexOptions() {
   505  	for _, idx := range c.CreateTable.TableSpec.Indexes {
   506  		// This name is taking straight from the input string
   507  		// so we want to normalize this to always lowercase.
   508  		idx.Info.Type = strings.ToLower(idx.Info.Type)
   509  		for _, opt := range idx.Options {
   510  			opt.Name = strings.ToLower(opt.Name)
   511  			opt.String = strings.ToLower(opt.String)
   512  		}
   513  	}
   514  }
   515  
   516  func isBool(colType *sqlparser.ColumnType) bool {
   517  	return colType.Type == sqlparser.KeywordString(sqlparser.TINYINT) && colType.Length != nil && sqlparser.CanonicalString(colType.Length) == "1"
   518  }
   519  
   520  func (c *CreateTableEntity) normalizePartitionOptions() {
   521  	if c.CreateTable.TableSpec.PartitionOption == nil {
   522  		return
   523  	}
   524  
   525  	for _, def := range c.CreateTable.TableSpec.PartitionOption.Definitions {
   526  		if def.Options == nil || def.Options.Engine == nil {
   527  			continue
   528  		}
   529  
   530  		def.Options.Engine.Name = strings.ToUpper(def.Options.Engine.Name)
   531  		if engineName, ok := engineCasing[def.Options.Engine.Name]; ok {
   532  			def.Options.Engine.Name = engineName
   533  		}
   534  	}
   535  }
   536  
   537  func newPrimaryKeyIndexDefinitionSingleColumn(name sqlparser.IdentifierCI) *sqlparser.IndexDefinition {
   538  	index := &sqlparser.IndexDefinition{
   539  		Info: &sqlparser.IndexInfo{
   540  			Name:    sqlparser.NewIdentifierCI("PRIMARY"),
   541  			Type:    "PRIMARY KEY",
   542  			Primary: true,
   543  			Unique:  true,
   544  		},
   545  		Columns: []*sqlparser.IndexColumn{{Column: name}},
   546  	}
   547  	return index
   548  }
   549  
   550  func (c *CreateTableEntity) normalizePrimaryKeyColumns() {
   551  	// normalize PRIMARY KEY:
   552  	// `create table t (id int primary key)`
   553  	// should turn into:
   554  	// `create table t (id int, primary key (id))`
   555  	// Also, PRIMARY KEY must come first before all other keys
   556  	for _, col := range c.CreateTable.TableSpec.Columns {
   557  		if col.Type.Options.KeyOpt == sqlparser.ColKeyPrimary {
   558  			c.CreateTable.TableSpec.Indexes = append([]*sqlparser.IndexDefinition{newPrimaryKeyIndexDefinitionSingleColumn(col.Name)}, c.CreateTable.TableSpec.Indexes...)
   559  			col.Type.Options.KeyOpt = sqlparser.ColKeyNone
   560  		}
   561  	}
   562  }
   563  
   564  func (c *CreateTableEntity) normalizeKeys() {
   565  	c.normalizePrimaryKeyColumns()
   566  
   567  	// let's ensure all keys have names
   568  	keyNameExists := map[string]bool{}
   569  	// first, we iterate and take note for all keys that do already have names
   570  	for _, key := range c.CreateTable.TableSpec.Indexes {
   571  		if name := key.Info.Name.Lowered(); name != "" {
   572  			keyNameExists[name] = true
   573  		}
   574  	}
   575  	for _, key := range c.CreateTable.TableSpec.Indexes {
   576  		// Normalize to KEY which matches MySQL behavior for the type.
   577  		if key.Info.Type == sqlparser.KeywordString(sqlparser.INDEX) {
   578  			key.Info.Type = sqlparser.KeywordString(sqlparser.KEY)
   579  		}
   580  		// now, let's look at keys that do not have names, and assign them new names
   581  		if name := key.Info.Name.String(); name == "" {
   582  			// we know there must be at least one column covered by this key
   583  			var colName string
   584  			if len(key.Columns) > 0 {
   585  				expressionFound := false
   586  				for _, col := range key.Columns {
   587  					if col.Expression != nil {
   588  						expressionFound = true
   589  					}
   590  				}
   591  				if expressionFound {
   592  					// that's the name MySQL picks for an unnamed key when there's at least one functional index expression
   593  					colName = "functional_index"
   594  				} else {
   595  					// like MySQL, we first try to call our index by the name of the first column:
   596  					colName = key.Columns[0].Column.String()
   597  				}
   598  			}
   599  			suggestedKeyName := colName
   600  			// now let's see if that name is taken; if it is, enumerate new news until we find a free name
   601  			for enumerate := 2; keyNameExists[strings.ToLower(suggestedKeyName)]; enumerate++ {
   602  				suggestedKeyName = fmt.Sprintf("%s_%d", colName, enumerate)
   603  			}
   604  			// OK we found a free slot!
   605  			key.Info.Name = sqlparser.NewIdentifierCI(suggestedKeyName)
   606  			keyNameExists[strings.ToLower(suggestedKeyName)] = true
   607  		}
   608  
   609  		// Drop options that are the same as the default.
   610  		keptOptions := make([]*sqlparser.IndexOption, 0, len(key.Options))
   611  		for _, option := range key.Options {
   612  			switch strings.ToUpper(option.Name) {
   613  			case "USING":
   614  				if strings.EqualFold(option.String, "BTREE") {
   615  					continue
   616  				}
   617  			case "VISIBLE":
   618  				continue
   619  			}
   620  			keptOptions = append(keptOptions, option)
   621  		}
   622  		key.Options = keptOptions
   623  	}
   624  }
   625  
   626  func (c *CreateTableEntity) normalizeUnnamedConstraints() {
   627  	// let's ensure all constraints have names
   628  	constraintNameExists := map[string]bool{}
   629  	// first, we iterate and take note for all keys that do already have names
   630  	for _, constraint := range c.CreateTable.TableSpec.Constraints {
   631  		if name := constraint.Name.Lowered(); name != "" {
   632  			constraintNameExists[name] = true
   633  		}
   634  	}
   635  
   636  	// now, let's look at keys that do not have names, and assign them new names
   637  	for _, constraint := range c.CreateTable.TableSpec.Constraints {
   638  		if name := constraint.Name.String(); name == "" {
   639  			nameFormat := "%s_chk_%d"
   640  			if _, fk := constraint.Details.(*sqlparser.ForeignKeyDefinition); fk {
   641  				nameFormat = "%s_ibfk_%d"
   642  			}
   643  			suggestedCheckName := fmt.Sprintf(nameFormat, c.CreateTable.Table.Name.String(), 1)
   644  			// now let's see if that name is taken; if it is, enumerate new news until we find a free name
   645  			for enumerate := 2; constraintNameExists[strings.ToLower(suggestedCheckName)]; enumerate++ {
   646  				suggestedCheckName = fmt.Sprintf(nameFormat, c.CreateTable.Table.Name.String(), enumerate)
   647  			}
   648  			// OK we found a free slot!
   649  			constraint.Name = sqlparser.NewIdentifierCI(suggestedCheckName)
   650  			constraintNameExists[strings.ToLower(suggestedCheckName)] = true
   651  		}
   652  	}
   653  }
   654  
   655  func (c *CreateTableEntity) normalizeForeignKeyIndexes() {
   656  	for _, constraint := range c.CreateTable.TableSpec.Constraints {
   657  		fk, ok := constraint.Details.(*sqlparser.ForeignKeyDefinition)
   658  		if !ok {
   659  			continue
   660  		}
   661  		if !c.columnsCoveredByInOrderIndex(fk.Source) {
   662  			// We add a foreign key, but the local FK columns are not indexed.
   663  			// MySQL's behavior is to implicitly add an index that covers the foreign key's local columns.
   664  			// The name of the index is either:
   665  			// - the same name of the constraint, if such name is provided
   666  			//   - and error if an index by this name exists
   667  			// - or, a standard auto-generated index name, if the constraint name is not provided
   668  			indexDefinition := &sqlparser.IndexDefinition{
   669  				Info: &sqlparser.IndexInfo{
   670  					Type: "key",
   671  					Name: constraint.Name, // if name is empty, then the name is later auto populated
   672  				},
   673  			}
   674  			for _, col := range fk.Source {
   675  				indexColumn := &sqlparser.IndexColumn{Column: col}
   676  				indexDefinition.Columns = append(indexDefinition.Columns, indexColumn)
   677  			}
   678  			c.TableSpec.Indexes = append(c.TableSpec.Indexes, indexDefinition)
   679  		}
   680  	}
   681  }
   682  
   683  // Name implements Entity interface
   684  func (c *CreateTableEntity) Name() string {
   685  	return c.CreateTable.GetTable().Name.String()
   686  }
   687  
   688  // Diff implements Entity interface function
   689  func (c *CreateTableEntity) Diff(other Entity, hints *DiffHints) (EntityDiff, error) {
   690  	otherCreateTable, ok := other.(*CreateTableEntity)
   691  	if !ok {
   692  		return nil, ErrEntityTypeMismatch
   693  	}
   694  	if hints.StrictIndexOrdering {
   695  		return nil, ErrStrictIndexOrderingUnsupported
   696  	}
   697  	if c.CreateTable.TableSpec == nil {
   698  		return nil, ErrUnexpectedTableSpec
   699  	}
   700  
   701  	d, err := c.TableDiff(otherCreateTable, hints)
   702  	if err != nil {
   703  		return nil, err
   704  	}
   705  	return d, nil
   706  }
   707  
   708  // TableDiff compares this table statement with another table statement, and sees what it takes to
   709  // change this table to look like the other table.
   710  // It returns an AlterTable statement if changes are found, or nil if not.
   711  // the other table may be of different name; its name is ignored.
   712  func (c *CreateTableEntity) TableDiff(other *CreateTableEntity, hints *DiffHints) (*AlterTableEntityDiff, error) {
   713  	if !c.CreateTable.IsFullyParsed() {
   714  		return nil, &NotFullyParsedError{Entity: c.Name(), Statement: sqlparser.CanonicalString(c.CreateTable)}
   715  	}
   716  	if !other.CreateTable.IsFullyParsed() {
   717  		return nil, &NotFullyParsedError{Entity: other.Name(), Statement: sqlparser.CanonicalString(other.CreateTable)}
   718  	}
   719  
   720  	if c.identicalOtherThanName(other) {
   721  		return nil, nil
   722  	}
   723  
   724  	alterTable := &sqlparser.AlterTable{
   725  		Table: c.CreateTable.Table,
   726  	}
   727  	diffedTableCharset := ""
   728  	var parentAlterTableEntityDiff *AlterTableEntityDiff
   729  	var partitionSpecs []*sqlparser.PartitionSpec
   730  	var superfluousFulltextKeys []*sqlparser.AddIndexDefinition
   731  	{
   732  		t1Options := c.CreateTable.TableSpec.Options
   733  		t2Options := other.CreateTable.TableSpec.Options
   734  		diffedTableCharset = c.diffTableCharset(t1Options, t2Options)
   735  	}
   736  	{
   737  		// diff columns
   738  		// ordered columns for both tables:
   739  		t1Columns := c.CreateTable.TableSpec.Columns
   740  		t2Columns := other.CreateTable.TableSpec.Columns
   741  		c.diffColumns(alterTable, t1Columns, t2Columns, hints, diffedTableCharset != "")
   742  	}
   743  	{
   744  		// diff keys
   745  		// ordered keys for both tables:
   746  		t1Keys := c.CreateTable.TableSpec.Indexes
   747  		t2Keys := other.CreateTable.TableSpec.Indexes
   748  		superfluousFulltextKeys = c.diffKeys(alterTable, t1Keys, t2Keys, hints)
   749  	}
   750  	{
   751  		// diff constraints
   752  		// ordered constraints for both tables:
   753  		t1Constraints := c.CreateTable.TableSpec.Constraints
   754  		t2Constraints := other.CreateTable.TableSpec.Constraints
   755  		c.diffConstraints(alterTable, t1Constraints, t2Constraints, hints)
   756  	}
   757  	{
   758  		// diff partitions
   759  		// ordered keys for both tables:
   760  		t1Partitions := c.CreateTable.TableSpec.PartitionOption
   761  		t2Partitions := other.CreateTable.TableSpec.PartitionOption
   762  		var err error
   763  		partitionSpecs, err = c.diffPartitions(alterTable, t1Partitions, t2Partitions, hints)
   764  		if err != nil {
   765  			return nil, err
   766  		}
   767  	}
   768  	{
   769  		// diff table options
   770  		// ordered keys for both tables:
   771  		t1Options := c.CreateTable.TableSpec.Options
   772  		t2Options := other.CreateTable.TableSpec.Options
   773  		if err := c.diffOptions(alterTable, t1Options, t2Options, hints); err != nil {
   774  			return nil, err
   775  		}
   776  	}
   777  	tableSpecHasChanged := len(alterTable.AlterOptions) > 0 || alterTable.PartitionOption != nil || alterTable.PartitionSpec != nil
   778  
   779  	newAlterTableEntityDiff := func(alterTable *sqlparser.AlterTable) *AlterTableEntityDiff {
   780  		d := &AlterTableEntityDiff{alterTable: alterTable, from: c, to: other}
   781  
   782  		var algorithmValue sqlparser.AlgorithmValue
   783  
   784  		switch hints.AlterTableAlgorithmStrategy {
   785  		case AlterTableAlgorithmStrategyCopy:
   786  			algorithmValue = sqlparser.AlgorithmValue("COPY")
   787  		case AlterTableAlgorithmStrategyInplace:
   788  			algorithmValue = sqlparser.AlgorithmValue("INPLACE")
   789  		case AlterTableAlgorithmStrategyInstant:
   790  			algorithmValue = sqlparser.AlgorithmValue("INSTANT")
   791  		}
   792  		if algorithmValue != "" {
   793  			alterTable.AlterOptions = append(alterTable.AlterOptions, algorithmValue)
   794  		}
   795  		return d
   796  	}
   797  	if tableSpecHasChanged {
   798  		parentAlterTableEntityDiff = newAlterTableEntityDiff(alterTable)
   799  	}
   800  	for _, superfluousFulltextKey := range superfluousFulltextKeys {
   801  		alterTable := &sqlparser.AlterTable{
   802  			Table:        c.CreateTable.Table,
   803  			AlterOptions: []sqlparser.AlterOption{superfluousFulltextKey},
   804  		}
   805  		diff := newAlterTableEntityDiff(alterTable)
   806  		// if we got superfluous fulltext keys, that means the table spec has changed, ie
   807  		// parentAlterTableEntityDiff is not nil
   808  		parentAlterTableEntityDiff.addSubsequentDiff(diff)
   809  	}
   810  	for _, partitionSpec := range partitionSpecs {
   811  		alterTable := &sqlparser.AlterTable{
   812  			Table:         c.CreateTable.Table,
   813  			PartitionSpec: partitionSpec,
   814  		}
   815  		diff := newAlterTableEntityDiff(alterTable)
   816  		if parentAlterTableEntityDiff == nil {
   817  			parentAlterTableEntityDiff = diff
   818  		} else {
   819  			parentAlterTableEntityDiff.addSubsequentDiff(diff)
   820  		}
   821  	}
   822  	return parentAlterTableEntityDiff, nil
   823  }
   824  
   825  func (c *CreateTableEntity) diffTableCharset(
   826  	t1Options sqlparser.TableOptions,
   827  	t2Options sqlparser.TableOptions,
   828  ) string {
   829  	getcharset := func(options sqlparser.TableOptions) string {
   830  		for _, option := range options {
   831  			if strings.EqualFold(option.Name, "CHARSET") {
   832  				return option.String
   833  			}
   834  		}
   835  		return ""
   836  	}
   837  	t1Charset := getcharset(t1Options)
   838  	t2Charset := getcharset(t2Options)
   839  	if t1Charset != t2Charset {
   840  		return t2Charset
   841  	}
   842  	return ""
   843  }
   844  
   845  // isDefaultTableOptionValue sees if the value for a TableOption is also its default value
   846  func isDefaultTableOptionValue(option *sqlparser.TableOption) bool {
   847  	var value string
   848  	if option.Value != nil {
   849  		value = sqlparser.CanonicalString(option.Value)
   850  	}
   851  	switch strings.ToUpper(option.Name) {
   852  	case "CHECKSUM":
   853  		return value == "0"
   854  	case "COMMENT":
   855  		return option.String == ""
   856  	case "COMPRESSION":
   857  		return value == "" || value == "''"
   858  	case "CONNECTION":
   859  		return value == "" || value == "''"
   860  	case "DATA DIRECTORY":
   861  		return value == "" || value == "''"
   862  	case "DELAY_KEY_WRITE":
   863  		return value == "0"
   864  	case "ENCRYPTION":
   865  		return value == "N"
   866  	case "INDEX DIRECTORY":
   867  		return value == "" || value == "''"
   868  	case "KEY_BLOCK_SIZE":
   869  		return value == "0"
   870  	case "MAX_ROWS":
   871  		return value == "0"
   872  	case "MIN_ROWS":
   873  		return value == "0"
   874  	case "PACK_KEYS":
   875  		return strings.EqualFold(option.String, "DEFAULT")
   876  	case "ROW_FORMAT":
   877  		return strings.EqualFold(option.String, "DEFAULT")
   878  	case "STATS_AUTO_RECALC":
   879  		return strings.EqualFold(option.String, "DEFAULT")
   880  	case "STATS_PERSISTENT":
   881  		return strings.EqualFold(option.String, "DEFAULT")
   882  	case "STATS_SAMPLE_PAGES":
   883  		return strings.EqualFold(option.String, "DEFAULT")
   884  	default:
   885  		return false
   886  	}
   887  }
   888  
   889  func (c *CreateTableEntity) diffOptions(alterTable *sqlparser.AlterTable,
   890  	t1Options sqlparser.TableOptions,
   891  	t2Options sqlparser.TableOptions,
   892  	hints *DiffHints,
   893  ) error {
   894  	t1OptionsMap := map[string]*sqlparser.TableOption{}
   895  	t2OptionsMap := map[string]*sqlparser.TableOption{}
   896  	for _, option := range t1Options {
   897  		t1OptionsMap[option.Name] = option
   898  	}
   899  	for _, option := range t2Options {
   900  		t2OptionsMap[option.Name] = option
   901  	}
   902  	alterTableOptions := sqlparser.TableOptions{}
   903  	// dropped options
   904  	for _, t1Option := range t1Options {
   905  		if _, ok := t2OptionsMap[t1Option.Name]; !ok {
   906  			// option exists in t1 but not in t2, hence it is dropped
   907  			var tableOption *sqlparser.TableOption
   908  			switch strings.ToUpper(t1Option.Name) {
   909  			case "AUTO_INCREMENT":
   910  				// skip
   911  			case "AUTOEXTEND_SIZE":
   912  				// skip
   913  			case "AVG_ROW_LENGTH":
   914  				// skip. MyISAM only, not interesting
   915  			case "CHARSET":
   916  				switch hints.TableCharsetCollateStrategy {
   917  				case TableCharsetCollateStrict:
   918  					tableOption = &sqlparser.TableOption{String: ""}
   919  					// in all other strategies we ignore the charset
   920  				}
   921  			case "CHECKSUM":
   922  				tableOption = &sqlparser.TableOption{Value: sqlparser.NewIntLiteral("0")}
   923  			case "COLLATE":
   924  				// skip. the default collation is applied per CHARSET
   925  			case "COMMENT":
   926  				tableOption = &sqlparser.TableOption{Value: sqlparser.NewStrLiteral("")}
   927  			case "COMPRESSION":
   928  				tableOption = &sqlparser.TableOption{Value: sqlparser.NewStrLiteral("")}
   929  			case "CONNECTION":
   930  				tableOption = &sqlparser.TableOption{Value: sqlparser.NewStrLiteral("")}
   931  			case "DATA DIRECTORY":
   932  				tableOption = &sqlparser.TableOption{Value: sqlparser.NewStrLiteral("")}
   933  			case "DELAY_KEY_WRITE":
   934  				tableOption = &sqlparser.TableOption{Value: sqlparser.NewIntLiteral("0")}
   935  			case "ENCRYPTION":
   936  				tableOption = &sqlparser.TableOption{Value: sqlparser.NewStrLiteral("N")}
   937  			case "ENGINE":
   938  				// skip
   939  			case "ENGINE_ATTRIBUTE":
   940  				// skip
   941  			case "INDEX DIRECTORY":
   942  				tableOption = &sqlparser.TableOption{Value: sqlparser.NewStrLiteral("")}
   943  			case "INSERT_METHOD":
   944  				// MyISAM only. skip
   945  			case "KEY_BLOCK_SIZE":
   946  				tableOption = &sqlparser.TableOption{Value: sqlparser.NewIntLiteral("0")}
   947  			case "MAX_ROWS":
   948  				tableOption = &sqlparser.TableOption{Value: sqlparser.NewIntLiteral("0")}
   949  			case "MIN_ROWS":
   950  				tableOption = &sqlparser.TableOption{Value: sqlparser.NewIntLiteral("0")}
   951  			case "PACK_KEYS":
   952  				tableOption = &sqlparser.TableOption{String: "DEFAULT"}
   953  			case "PASSWORD":
   954  				// unused option. skip
   955  			case "ROW_FORMAT":
   956  				tableOption = &sqlparser.TableOption{String: "DEFAULT"}
   957  			case "SECONDARY_ENGINE_ATTRIBUTE":
   958  				// unused option. skip
   959  			case "STATS_AUTO_RECALC":
   960  				tableOption = &sqlparser.TableOption{String: "DEFAULT"}
   961  			case "STATS_PERSISTENT":
   962  				tableOption = &sqlparser.TableOption{String: "DEFAULT"}
   963  			case "STATS_SAMPLE_PAGES":
   964  				tableOption = &sqlparser.TableOption{String: "DEFAULT"}
   965  			case "TABLESPACE":
   966  				// not supporting the change, skip
   967  			case "UNION":
   968  				// MyISAM/MERGE only. Skip
   969  			default:
   970  				return &UnsupportedTableOptionError{Table: c.Name(), Option: strings.ToUpper(t1Option.Name)}
   971  			}
   972  			if tableOption != nil {
   973  				tableOption.Name = t1Option.Name
   974  				alterTableOptions = append(alterTableOptions, tableOption)
   975  			}
   976  		}
   977  
   978  	}
   979  	// changed options
   980  	for _, t2Option := range t2Options {
   981  		if t1Option, ok := t1OptionsMap[t2Option.Name]; ok {
   982  			options1 := sqlparser.TableOptions{t1Option}
   983  			options2 := sqlparser.TableOptions{t2Option}
   984  			if !sqlparser.Equals.TableOptions(options1, options2) {
   985  				// options are different.
   986  				// However, we don't automatically apply these changes. It depends on the option!
   987  				switch strings.ToUpper(t1Option.Name) {
   988  				case "CHARSET", "COLLATE":
   989  					switch hints.TableCharsetCollateStrategy {
   990  					case TableCharsetCollateStrict:
   991  						alterTableOptions = append(alterTableOptions, t2Option)
   992  					case TableCharsetCollateIgnoreEmpty:
   993  						if t1Option.String != "" && t2Option.String != "" {
   994  							alterTableOptions = append(alterTableOptions, t2Option)
   995  						}
   996  						// if one is empty, we ignore
   997  					case TableCharsetCollateIgnoreAlways:
   998  						// ignore always
   999  					}
  1000  				case "AUTO_INCREMENT":
  1001  					switch hints.AutoIncrementStrategy {
  1002  					case AutoIncrementApplyAlways:
  1003  						alterTableOptions = append(alterTableOptions, t2Option)
  1004  					case AutoIncrementApplyHigher:
  1005  						option1AutoIncrement, err := strconv.ParseInt(t1Option.Value.Val, 10, 64)
  1006  						if err != nil {
  1007  							return err
  1008  						}
  1009  						option2AutoIncrement, err := strconv.ParseInt(t2Option.Value.Val, 10, 64)
  1010  						if err != nil {
  1011  							return err
  1012  						}
  1013  						if option2AutoIncrement > option1AutoIncrement {
  1014  							// never decrease AUTO_INCREMENT. Only increase
  1015  							alterTableOptions = append(alterTableOptions, t2Option)
  1016  						}
  1017  					case AutoIncrementIgnore:
  1018  						// do not apply
  1019  					}
  1020  				default:
  1021  					// Apply the new options
  1022  					alterTableOptions = append(alterTableOptions, t2Option)
  1023  				}
  1024  			}
  1025  		}
  1026  	}
  1027  	// added options
  1028  	for _, t2Option := range t2Options {
  1029  		if _, ok := t1OptionsMap[t2Option.Name]; !ok {
  1030  			switch strings.ToUpper(t2Option.Name) {
  1031  			case "CHARSET", "COLLATE":
  1032  				switch hints.TableCharsetCollateStrategy {
  1033  				case TableCharsetCollateStrict:
  1034  					alterTableOptions = append(alterTableOptions, t2Option)
  1035  					// in all other strategies we ignore the charset
  1036  				}
  1037  			case "AUTO_INCREMENT":
  1038  				switch hints.AutoIncrementStrategy {
  1039  				case AutoIncrementApplyAlways, AutoIncrementApplyHigher:
  1040  					alterTableOptions = append(alterTableOptions, t2Option)
  1041  				case AutoIncrementIgnore:
  1042  					// do not apply
  1043  				}
  1044  			default:
  1045  				alterTableOptions = append(alterTableOptions, t2Option)
  1046  			}
  1047  		}
  1048  	}
  1049  
  1050  	if len(alterTableOptions) > 0 {
  1051  		alterTable.AlterOptions = append(alterTable.AlterOptions, alterTableOptions)
  1052  	}
  1053  	return nil
  1054  }
  1055  
  1056  // rangePartitionsAddedRemoved returns true when:
  1057  // - both table partitions are RANGE type
  1058  // - there is exactly one consequitive non-empty shared sequence of partitions (same names, same range values, in same order)
  1059  // - table1 may have non-empty list of partitions _preceding_ this sequence, and table2 may not
  1060  // - table2 may have non-empty list of partitions _following_ this sequence, and table1 may not
  1061  func (c *CreateTableEntity) isRangePartitionsRotation(
  1062  	t1Partitions *sqlparser.PartitionOption,
  1063  	t2Partitions *sqlparser.PartitionOption,
  1064  ) (bool, []*sqlparser.PartitionSpec, error) {
  1065  	// Validate that both tables have range partitioning
  1066  	if t1Partitions.Type != t2Partitions.Type {
  1067  		return false, nil, nil
  1068  	}
  1069  	if t1Partitions.Type != sqlparser.RangeType {
  1070  		return false, nil, nil
  1071  	}
  1072  	definitions1 := t1Partitions.Definitions
  1073  	definitions2 := t2Partitions.Definitions
  1074  	// there has to be a non-empty shared list, therefore both definitions must be non-empty:
  1075  	if len(definitions1) == 0 {
  1076  		return false, nil, nil
  1077  	}
  1078  	if len(definitions2) == 0 {
  1079  		return false, nil, nil
  1080  	}
  1081  	var droppedPartitions1 []*sqlparser.PartitionDefinition
  1082  	// It's OK for prefix of t1 partitions to be nonexistent in t2 (as they may have been rotated away in t2)
  1083  	for len(definitions1) > 0 && !sqlparser.Equals.RefOfPartitionDefinition(definitions1[0], definitions2[0]) {
  1084  		droppedPartitions1 = append(droppedPartitions1, definitions1[0])
  1085  		definitions1 = definitions1[1:]
  1086  	}
  1087  	if len(definitions1) == 0 {
  1088  		// We've exhaused definition1 trying to find a shared partition with definitions2. Nothing found.
  1089  		// so there is no shared sequence between the two tables.
  1090  		return false, nil, nil
  1091  	}
  1092  	if len(definitions1) > len(definitions2) {
  1093  		return false, nil, nil
  1094  	}
  1095  	// To save computation, and because we've already shown that sqlparser.EqualsRefOfPartitionDefinition(definitions1[0], definitions2[0]), nil,
  1096  	// we can skip one element
  1097  	definitions1 = definitions1[1:]
  1098  	definitions2 = definitions2[1:]
  1099  	// Now let's ensure that whatever is remaining in definitions1 is an exact match for a prefix of definitions2
  1100  	// It's ok if we end up with leftover elements in definition2
  1101  	for len(definitions1) > 0 {
  1102  		if !sqlparser.Equals.RefOfPartitionDefinition(definitions1[0], definitions2[0]) {
  1103  			return false, nil, nil
  1104  		}
  1105  		definitions1 = definitions1[1:]
  1106  		definitions2 = definitions2[1:]
  1107  	}
  1108  	addedPartitions2 := definitions2
  1109  	partitionSpecs := make([]*sqlparser.PartitionSpec, 0, len(droppedPartitions1)+len(addedPartitions2))
  1110  	for _, p := range droppedPartitions1 {
  1111  		partitionSpec := &sqlparser.PartitionSpec{
  1112  			Action: sqlparser.DropAction,
  1113  			Names:  []sqlparser.IdentifierCI{p.Name},
  1114  		}
  1115  		partitionSpecs = append(partitionSpecs, partitionSpec)
  1116  	}
  1117  	for _, p := range addedPartitions2 {
  1118  		partitionSpec := &sqlparser.PartitionSpec{
  1119  			Action:      sqlparser.AddAction,
  1120  			Definitions: []*sqlparser.PartitionDefinition{p},
  1121  		}
  1122  		partitionSpecs = append(partitionSpecs, partitionSpec)
  1123  	}
  1124  	return true, partitionSpecs, nil
  1125  }
  1126  
  1127  func (c *CreateTableEntity) diffPartitions(alterTable *sqlparser.AlterTable,
  1128  	t1Partitions *sqlparser.PartitionOption,
  1129  	t2Partitions *sqlparser.PartitionOption,
  1130  	hints *DiffHints,
  1131  ) (partitionSpecs []*sqlparser.PartitionSpec, err error) {
  1132  	switch {
  1133  	case t1Partitions == nil && t2Partitions == nil:
  1134  		return nil, nil
  1135  	case t1Partitions == nil:
  1136  		// add partitioning
  1137  		alterTable.PartitionOption = t2Partitions
  1138  	case t2Partitions == nil:
  1139  		// remove partitioning
  1140  		partitionSpec := &sqlparser.PartitionSpec{
  1141  			Action: sqlparser.RemoveAction,
  1142  			IsAll:  true,
  1143  		}
  1144  		alterTable.PartitionSpec = partitionSpec
  1145  	case sqlparser.Equals.RefOfPartitionOption(t1Partitions, t2Partitions):
  1146  		// identical partitioning
  1147  		return nil, nil
  1148  	default:
  1149  		// partitioning was changed
  1150  		// For most cases, we produce a complete re-partitioing schema: we don't try and figure out the minimal
  1151  		// needed change. For example, maybe the minimal change is to REORGANIZE a specific partition and split
  1152  		// into two, thus unaffecting the rest of the partitions. But we don't evaluate that, we just set a
  1153  		// complete new ALTER TABLE ... PARTITION BY statement.
  1154  		// The idea is that it doesn't matter: we're not looking to do optimal in-place ALTERs, we run
  1155  		// Online DDL alters, where we create a new table anyway. Thus, the optimization is meaningless.
  1156  
  1157  		// Having said that, we _do_ analyze the scenario of a RANGE partitioning rotation of partitions:
  1158  		// where zero or more partitions may have been dropped from the earlier range, and zero or more
  1159  		// partitions have been added with a later range:
  1160  		isRotation, partitionSpecs, err := c.isRangePartitionsRotation(t1Partitions, t2Partitions)
  1161  		if err != nil {
  1162  			return nil, err
  1163  		}
  1164  		if isRotation {
  1165  			switch hints.RangeRotationStrategy {
  1166  			case RangeRotationIgnore:
  1167  				return nil, nil
  1168  			case RangeRotationDistinctStatements:
  1169  				return partitionSpecs, nil
  1170  			case RangeRotationFullSpec:
  1171  				// proceed to return a full rebuild
  1172  			}
  1173  		}
  1174  		alterTable.PartitionOption = t2Partitions
  1175  	}
  1176  	return nil, nil
  1177  }
  1178  
  1179  func (c *CreateTableEntity) diffConstraints(alterTable *sqlparser.AlterTable,
  1180  	t1Constraints []*sqlparser.ConstraintDefinition,
  1181  	t2Constraints []*sqlparser.ConstraintDefinition,
  1182  	hints *DiffHints,
  1183  ) {
  1184  	normalizeConstraintName := func(constraint *sqlparser.ConstraintDefinition) string {
  1185  		switch hints.ConstraintNamesStrategy {
  1186  		case ConstraintNamesIgnoreVitess:
  1187  			return ExtractConstraintOriginalName(constraint.Name.String())
  1188  		case ConstraintNamesIgnoreAll:
  1189  			return sqlparser.CanonicalString(constraint.Details)
  1190  		case ConstraintNamesStrict:
  1191  			return constraint.Name.String()
  1192  		default:
  1193  			// should never get here; but while here, let's assume strict.
  1194  			return constraint.Name.String()
  1195  		}
  1196  	}
  1197  	t1ConstraintsMap := map[string]*sqlparser.ConstraintDefinition{}
  1198  	t2ConstraintsMap := map[string]*sqlparser.ConstraintDefinition{}
  1199  	for _, constraint := range t1Constraints {
  1200  		t1ConstraintsMap[normalizeConstraintName(constraint)] = constraint
  1201  	}
  1202  	for _, constraint := range t2Constraints {
  1203  		t2ConstraintsMap[normalizeConstraintName(constraint)] = constraint
  1204  	}
  1205  
  1206  	dropConstraintStatement := func(constraint *sqlparser.ConstraintDefinition) *sqlparser.DropKey {
  1207  		if _, fk := constraint.Details.(*sqlparser.ForeignKeyDefinition); fk {
  1208  			return &sqlparser.DropKey{Name: constraint.Name, Type: sqlparser.ForeignKeyType}
  1209  		}
  1210  		return &sqlparser.DropKey{Name: constraint.Name, Type: sqlparser.CheckKeyType}
  1211  	}
  1212  
  1213  	// evaluate dropped constraints
  1214  	//
  1215  	for _, t1Constraint := range t1Constraints {
  1216  		if _, ok := t2ConstraintsMap[normalizeConstraintName(t1Constraint)]; !ok {
  1217  			// constraint exists in t1 but not in t2, hence it is dropped
  1218  			dropConstraint := dropConstraintStatement(t1Constraint)
  1219  			alterTable.AlterOptions = append(alterTable.AlterOptions, dropConstraint)
  1220  		}
  1221  	}
  1222  
  1223  	for _, t2Constraint := range t2Constraints {
  1224  		normalizedT2ConstraintName := normalizeConstraintName(t2Constraint)
  1225  		// evaluate modified & added constraints:
  1226  		//
  1227  		if t1Constraint, ok := t1ConstraintsMap[normalizedT2ConstraintName]; ok {
  1228  			// constraint exists in both tables
  1229  			// check diff between before/after columns:
  1230  			if !sqlparser.Equals.ConstraintInfo(t2Constraint.Details, t1Constraint.Details) {
  1231  				// constraints with same name have different definition.
  1232  				// First we check if this is only the enforced setting that changed which can
  1233  				// be directly altered.
  1234  				check1Details, ok1 := t1Constraint.Details.(*sqlparser.CheckConstraintDefinition)
  1235  				check2Details, ok2 := t2Constraint.Details.(*sqlparser.CheckConstraintDefinition)
  1236  				if ok1 && ok2 && sqlparser.Equals.Expr(check1Details.Expr, check2Details.Expr) {
  1237  					// We have the same expression, so we have a different Enforced here
  1238  					alterConstraint := &sqlparser.AlterCheck{
  1239  						Name:     t2Constraint.Name,
  1240  						Enforced: check2Details.Enforced,
  1241  					}
  1242  					alterTable.AlterOptions = append(alterTable.AlterOptions, alterConstraint)
  1243  					continue
  1244  				}
  1245  
  1246  				// There's another change, so we need to drop and add.
  1247  				dropConstraint := dropConstraintStatement(t1Constraint)
  1248  				addConstraint := &sqlparser.AddConstraintDefinition{
  1249  					ConstraintDefinition: t2Constraint,
  1250  				}
  1251  				alterTable.AlterOptions = append(alterTable.AlterOptions, dropConstraint)
  1252  				alterTable.AlterOptions = append(alterTable.AlterOptions, addConstraint)
  1253  			}
  1254  		} else {
  1255  			// constraint exists in t2 but not in t1, hence it is added
  1256  			addConstraint := &sqlparser.AddConstraintDefinition{
  1257  				ConstraintDefinition: t2Constraint,
  1258  			}
  1259  			alterTable.AlterOptions = append(alterTable.AlterOptions, addConstraint)
  1260  		}
  1261  	}
  1262  }
  1263  
  1264  func (c *CreateTableEntity) diffKeys(alterTable *sqlparser.AlterTable,
  1265  	t1Keys []*sqlparser.IndexDefinition,
  1266  	t2Keys []*sqlparser.IndexDefinition,
  1267  	hints *DiffHints,
  1268  ) (superfluousFulltextKeys []*sqlparser.AddIndexDefinition) {
  1269  	t1KeysMap := map[string]*sqlparser.IndexDefinition{}
  1270  	t2KeysMap := map[string]*sqlparser.IndexDefinition{}
  1271  	for _, key := range t1Keys {
  1272  		t1KeysMap[key.Info.Name.String()] = key
  1273  	}
  1274  	for _, key := range t2Keys {
  1275  		t2KeysMap[key.Info.Name.String()] = key
  1276  	}
  1277  
  1278  	dropKeyStatement := func(info *sqlparser.IndexInfo) *sqlparser.DropKey {
  1279  		dropKey := &sqlparser.DropKey{}
  1280  		if strings.EqualFold(info.Type, sqlparser.PrimaryKeyTypeStr) {
  1281  			dropKey.Type = sqlparser.PrimaryKeyType
  1282  		} else {
  1283  			dropKey.Type = sqlparser.NormalKeyType
  1284  			dropKey.Name = info.Name
  1285  		}
  1286  		return dropKey
  1287  	}
  1288  
  1289  	// evaluate dropped keys
  1290  	//
  1291  	for _, t1Key := range t1Keys {
  1292  		if _, ok := t2KeysMap[t1Key.Info.Name.String()]; !ok {
  1293  			// column exists in t1 but not in t2, hence it is dropped
  1294  			dropKey := dropKeyStatement(t1Key.Info)
  1295  			alterTable.AlterOptions = append(alterTable.AlterOptions, dropKey)
  1296  		}
  1297  	}
  1298  
  1299  	addedFulltextKeys := 0
  1300  	for _, t2Key := range t2Keys {
  1301  		t2KeyName := t2Key.Info.Name.String()
  1302  		// evaluate modified & added keys:
  1303  		//
  1304  		if t1Key, ok := t1KeysMap[t2KeyName]; ok {
  1305  			// key exists in both tables
  1306  			// check diff between before/after columns:
  1307  			if !sqlparser.Equals.RefOfIndexDefinition(t2Key, t1Key) {
  1308  				indexVisibilityChange, newVisibility := indexOnlyVisibilityChange(t1Key, t2Key)
  1309  				if indexVisibilityChange {
  1310  					alterTable.AlterOptions = append(alterTable.AlterOptions, &sqlparser.AlterIndex{
  1311  						Name:      t2Key.Info.Name,
  1312  						Invisible: newVisibility,
  1313  					})
  1314  					continue
  1315  				}
  1316  
  1317  				// For other changes, we're going to drop and create.
  1318  				dropKey := dropKeyStatement(t1Key.Info)
  1319  				addKey := &sqlparser.AddIndexDefinition{
  1320  					IndexDefinition: t2Key,
  1321  				}
  1322  				alterTable.AlterOptions = append(alterTable.AlterOptions, dropKey)
  1323  				alterTable.AlterOptions = append(alterTable.AlterOptions, addKey)
  1324  			}
  1325  		} else {
  1326  			// key exists in t2 but not in t1, hence it is added
  1327  			addKey := &sqlparser.AddIndexDefinition{
  1328  				IndexDefinition: t2Key,
  1329  			}
  1330  			addedAsSuperfluousStatement := false
  1331  			if t2Key.Info.Fulltext {
  1332  				if addedFulltextKeys > 0 && hints.FullTextKeyStrategy == FullTextKeyDistinctStatements {
  1333  					// Special case: MySQL does not support multiple ADD FULLTEXT KEY statements in a single ALTER
  1334  					superfluousFulltextKeys = append(superfluousFulltextKeys, addKey)
  1335  					addedAsSuperfluousStatement = true
  1336  				}
  1337  				addedFulltextKeys++
  1338  			}
  1339  			if !addedAsSuperfluousStatement {
  1340  				alterTable.AlterOptions = append(alterTable.AlterOptions, addKey)
  1341  			}
  1342  		}
  1343  	}
  1344  	return superfluousFulltextKeys
  1345  }
  1346  
  1347  // indexOnlyVisibilityChange checks whether the change on an index is only
  1348  // a visibility change. In that case we can use `ALTER INDEX`.
  1349  // Returns if this is a visibility only change and if true, whether
  1350  // the new visibility is invisible or not.
  1351  func indexOnlyVisibilityChange(t1Key, t2Key *sqlparser.IndexDefinition) (bool, bool) {
  1352  	t1KeyCopy := sqlparser.CloneRefOfIndexDefinition(t1Key)
  1353  	t2KeyCopy := sqlparser.CloneRefOfIndexDefinition(t2Key)
  1354  	t1KeyKeptOptions := make([]*sqlparser.IndexOption, 0, len(t1KeyCopy.Options))
  1355  	t2KeyInvisible := false
  1356  	for _, opt := range t1KeyCopy.Options {
  1357  		if strings.EqualFold(opt.Name, "invisible") {
  1358  			continue
  1359  		}
  1360  		t1KeyKeptOptions = append(t1KeyKeptOptions, opt)
  1361  	}
  1362  	t1KeyCopy.Options = t1KeyKeptOptions
  1363  	t2KeyKeptOptions := make([]*sqlparser.IndexOption, 0, len(t2KeyCopy.Options))
  1364  	for _, opt := range t2KeyCopy.Options {
  1365  		if strings.EqualFold(opt.Name, "invisible") {
  1366  			t2KeyInvisible = true
  1367  			continue
  1368  		}
  1369  		t2KeyKeptOptions = append(t2KeyKeptOptions, opt)
  1370  	}
  1371  	t2KeyCopy.Options = t2KeyKeptOptions
  1372  	if sqlparser.Equals.RefOfIndexDefinition(t2KeyCopy, t1KeyCopy) {
  1373  		return true, t2KeyInvisible
  1374  	}
  1375  	return false, false
  1376  }
  1377  
  1378  // evaluateColumnReordering produces a minimal reordering set of columns. To elaborate:
  1379  // The function receives two sets of columns. the two must be permutations of one another. Specifically,
  1380  // these are the columns shared between the from&to tables.
  1381  // The function uses longest-common-subsequence (lcs) algorithm to compute which columns should not be moved.
  1382  // any column not in the lcs need to be reordered.
  1383  // The function a map of column names that need to be reordered, and the index into which they are reordered.
  1384  func evaluateColumnReordering(t1SharedColumns, t2SharedColumns []*sqlparser.ColumnDefinition) map[string]int {
  1385  	minimalColumnReordering := map[string]int{}
  1386  
  1387  	t1SharedColNames := make([]interface{}, 0, len(t1SharedColumns))
  1388  	for _, col := range t1SharedColumns {
  1389  		t1SharedColNames = append(t1SharedColNames, col.Name.Lowered())
  1390  	}
  1391  	t2SharedColNames := make([]interface{}, 0, len(t2SharedColumns))
  1392  	for _, col := range t2SharedColumns {
  1393  		t2SharedColNames = append(t2SharedColNames, col.Name.Lowered())
  1394  	}
  1395  
  1396  	lcs := golcs.New(t1SharedColNames, t2SharedColNames)
  1397  	lcsNames := map[string]bool{}
  1398  	for _, v := range lcs.Values() {
  1399  		lcsNames[v.(string)] = true
  1400  	}
  1401  	for i, t2Col := range t2SharedColumns {
  1402  		t2ColName := t2Col.Name.Lowered()
  1403  		// see if this column is in the longest common subsequence. If so, no need to reorder it. If not, it must be reordered.
  1404  		if _, ok := lcsNames[t2ColName]; !ok {
  1405  			minimalColumnReordering[t2ColName] = i
  1406  		}
  1407  	}
  1408  
  1409  	return minimalColumnReordering
  1410  }
  1411  
  1412  // Diff compares this table statement with another table statement, and sees what it takes to
  1413  // change this table to look like the other table.
  1414  // It returns an AlterTable statement if changes are found, or nil if not.
  1415  // the other table may be of different name; its name is ignored.
  1416  func (c *CreateTableEntity) diffColumns(alterTable *sqlparser.AlterTable,
  1417  	t1Columns []*sqlparser.ColumnDefinition,
  1418  	t2Columns []*sqlparser.ColumnDefinition,
  1419  	hints *DiffHints,
  1420  	tableCharsetChanged bool,
  1421  ) {
  1422  	getColumnsMap := func(cols []*sqlparser.ColumnDefinition) map[string]*columnDetails {
  1423  		var prevCol *columnDetails
  1424  		m := map[string]*columnDetails{}
  1425  		for _, col := range cols {
  1426  			colDetails := &columnDetails{
  1427  				col:     col,
  1428  				prevCol: prevCol,
  1429  			}
  1430  			if prevCol != nil {
  1431  				prevCol.nextCol = colDetails
  1432  			}
  1433  			prevCol = colDetails
  1434  			m[col.Name.Lowered()] = colDetails
  1435  		}
  1436  		return m
  1437  	}
  1438  	// map columns by names for easy access
  1439  	t1ColumnsMap := getColumnsMap(t1Columns)
  1440  	t2ColumnsMap := getColumnsMap(t2Columns)
  1441  
  1442  	// For purpose of column reordering detection, we maintain a list of
  1443  	// shared columns, by order of appearance in t1
  1444  	var t1SharedColumns []*sqlparser.ColumnDefinition
  1445  
  1446  	var dropColumns []*sqlparser.DropColumn
  1447  	// evaluate dropped columns
  1448  	//
  1449  	for _, t1Col := range t1Columns {
  1450  		if _, ok := t2ColumnsMap[t1Col.Name.Lowered()]; ok {
  1451  			t1SharedColumns = append(t1SharedColumns, t1Col)
  1452  		} else {
  1453  			// column exists in t1 but not in t2, hence it is dropped
  1454  			dropColumn := &sqlparser.DropColumn{
  1455  				Name: getColName(&t1Col.Name),
  1456  			}
  1457  			dropColumns = append(dropColumns, dropColumn)
  1458  		}
  1459  	}
  1460  
  1461  	// For purpose of column reordering detection, we maintain a list of
  1462  	// shared columns, by order of appearance in t2
  1463  	var t2SharedColumns []*sqlparser.ColumnDefinition
  1464  	for _, t2Col := range t2Columns {
  1465  		if _, ok := t1ColumnsMap[t2Col.Name.Lowered()]; ok {
  1466  			// column exists in both tables
  1467  			t2SharedColumns = append(t2SharedColumns, t2Col)
  1468  		}
  1469  	}
  1470  
  1471  	// evaluate modified columns
  1472  	//
  1473  	var modifyColumns []*sqlparser.ModifyColumn
  1474  	columnReordering := evaluateColumnReordering(t1SharedColumns, t2SharedColumns)
  1475  	for _, t2Col := range t2SharedColumns {
  1476  		t2ColName := t2Col.Name.Lowered()
  1477  		// we know that column exists in both tables
  1478  		t1Col := t1ColumnsMap[t2ColName]
  1479  		t1ColEntity := NewColumnDefinitionEntity(t1Col.col)
  1480  		t2ColEntity := NewColumnDefinitionEntity(t2Col)
  1481  
  1482  		// check diff between before/after columns:
  1483  		modifyColumnDiff := t1ColEntity.ColumnDiff(t2ColEntity, hints)
  1484  		if modifyColumnDiff == nil {
  1485  			// even if there's no apparent change, there can still be implicit changes
  1486  			// it is possible that the table charset is changed. the column may be some col1 TEXT NOT NULL, possibly in both varsions 1 and 2,
  1487  			// but implicitly the column has changed its characters set. So we need to explicitly ass a MODIFY COLUMN statement, so that
  1488  			// MySQL rebuilds it.
  1489  			if tableCharsetChanged && t2ColEntity.IsTextual() && t2Col.Type.Charset.Name == "" {
  1490  				modifyColumnDiff = NewModifyColumnDiffByDefinition(t2Col)
  1491  			}
  1492  		}
  1493  		// It is also possible that a column is reordered. Whether the column definition has
  1494  		// or hasn't changed, if a column is reordered then that's a change of its own!
  1495  		if columnReorderIndex, ok := columnReordering[t2ColName]; ok {
  1496  			// seems like we previously evaluated that this column should be reordered
  1497  			if modifyColumnDiff == nil {
  1498  				// create column change
  1499  				modifyColumnDiff = NewModifyColumnDiffByDefinition(t2Col)
  1500  			}
  1501  			if columnReorderIndex == 0 {
  1502  				modifyColumnDiff.modifyColumn.First = true
  1503  			} else {
  1504  				modifyColumnDiff.modifyColumn.After = getColName(&t2SharedColumns[columnReorderIndex-1].Name)
  1505  			}
  1506  		}
  1507  		if modifyColumnDiff != nil {
  1508  			// column definition or ordering has changed
  1509  			modifyColumns = append(modifyColumns, modifyColumnDiff.modifyColumn)
  1510  		}
  1511  	}
  1512  	// Evaluate added columns
  1513  	//
  1514  	// Every added column is obviously a diff. But on top of that, we are also interested to know
  1515  	// if the column is added somewhere in between existing columns rather than appended to the
  1516  	// end of existing columns list.
  1517  	var addColumns []*sqlparser.AddColumns
  1518  	expectAppendIndex := len(t2SharedColumns)
  1519  	for t2ColIndex, t2Col := range t2Columns {
  1520  		if _, ok := t1ColumnsMap[t2Col.Name.Lowered()]; !ok {
  1521  			// column exists in t2 but not in t1, hence it is added
  1522  			addColumn := &sqlparser.AddColumns{
  1523  				Columns: []*sqlparser.ColumnDefinition{t2Col},
  1524  			}
  1525  			if t2ColIndex < expectAppendIndex {
  1526  				// This column is added somewhere in between existing columns, not appended at end of column list
  1527  				if t2ColIndex == 0 {
  1528  					addColumn.First = true
  1529  				} else {
  1530  					addColumn.After = getColName(&t2Columns[t2ColIndex-1].Name)
  1531  				}
  1532  			}
  1533  			expectAppendIndex++
  1534  			addColumns = append(addColumns, addColumn)
  1535  		}
  1536  	}
  1537  	dropColumns, addColumns, renameColumns := heuristicallyDetectColumnRenames(dropColumns, addColumns, t1ColumnsMap, t2ColumnsMap, hints)
  1538  	for _, c := range dropColumns {
  1539  		alterTable.AlterOptions = append(alterTable.AlterOptions, c)
  1540  	}
  1541  	for _, c := range modifyColumns {
  1542  		alterTable.AlterOptions = append(alterTable.AlterOptions, c)
  1543  	}
  1544  	for _, c := range renameColumns {
  1545  		alterTable.AlterOptions = append(alterTable.AlterOptions, c)
  1546  	}
  1547  	for _, c := range addColumns {
  1548  		alterTable.AlterOptions = append(alterTable.AlterOptions, c)
  1549  	}
  1550  }
  1551  
  1552  func heuristicallyDetectColumnRenames(
  1553  	dropColumns []*sqlparser.DropColumn,
  1554  	addColumns []*sqlparser.AddColumns,
  1555  	t1ColumnsMap map[string]*columnDetails,
  1556  	t2ColumnsMap map[string]*columnDetails,
  1557  	hints *DiffHints,
  1558  ) ([]*sqlparser.DropColumn, []*sqlparser.AddColumns, []*sqlparser.RenameColumn) {
  1559  	var renameColumns []*sqlparser.RenameColumn
  1560  	findRenamedColumn := func() bool {
  1561  		// What we're doing next is to try and identify a column RENAME.
  1562  		// We do so by cross-referencing dropped and added columns.
  1563  		// The check is heuristic, and looks like this:
  1564  		// We consider a column renamed iff:
  1565  		// - the DROP and ADD column definitions are identical other than the column name, and
  1566  		// - the DROPped and ADDded column are both FIRST, or they come AFTER the same column, and
  1567  		// - the DROPped and ADDded column are both last, or they come before the same column
  1568  		// This v1 chcek therefore cannot handle a case where two successive columns are renamed.
  1569  		// the problem is complex, and with successive renamed, or drops and adds, it can be
  1570  		// impossible to tell apart different scenarios.
  1571  		// At any case, once we heuristically decide that we found a RENAME, we cancel the DROP,
  1572  		// cancel the ADD, and inject a RENAME in place of both.
  1573  
  1574  		// findRenamedColumn cross-references dropped and added columns to find a single renamed column. If such is found:
  1575  		// we remove the entry from DROPped columns, remove the entry from ADDed columns, add an entry for RENAMEd columns,
  1576  		// and return 'true'.
  1577  		// Successive calls to this function will then find the next heuristic RENAMEs.
  1578  		// the function returns 'false' if it is unable to heuristically find a RENAME.
  1579  		for iDrop, dropCol1 := range dropColumns {
  1580  			for iAdd, addCol2 := range addColumns {
  1581  				col1Details := t1ColumnsMap[dropCol1.Name.Name.Lowered()]
  1582  				if !col1Details.identicalOtherThanName(addCol2.Columns[0]) {
  1583  					continue
  1584  				}
  1585  				// columns look alike, other than their names, which we know are different.
  1586  				// are these two columns otherwise appear to be in same position?
  1587  				col2Details := t2ColumnsMap[addCol2.Columns[0].Name.Lowered()]
  1588  				if col1Details.prevColName() == col2Details.prevColName() && col1Details.nextColName() == col2Details.nextColName() {
  1589  					dropColumns = append(dropColumns[0:iDrop], dropColumns[iDrop+1:]...)
  1590  					addColumns = append(addColumns[0:iAdd], addColumns[iAdd+1:]...)
  1591  					renameColumn := &sqlparser.RenameColumn{
  1592  						OldName: dropCol1.Name,
  1593  						NewName: getColName(&addCol2.Columns[0].Name),
  1594  					}
  1595  					renameColumns = append(renameColumns, renameColumn)
  1596  					return true
  1597  				}
  1598  			}
  1599  		}
  1600  		return false
  1601  	}
  1602  	switch hints.ColumnRenameStrategy {
  1603  	case ColumnRenameAssumeDifferent:
  1604  		// do nothing
  1605  	case ColumnRenameHeuristicStatement:
  1606  		for findRenamedColumn() {
  1607  			// Iteratively detect all RENAMEs
  1608  		}
  1609  	}
  1610  	return dropColumns, addColumns, renameColumns
  1611  }
  1612  
  1613  // primaryKeyColumns returns the columns covered by an existing PRIMARY KEY, or nil if there isn't
  1614  // a PRIMARY KEY
  1615  func (c *CreateTableEntity) primaryKeyColumns() []*sqlparser.IndexColumn {
  1616  	for _, existingIndex := range c.CreateTable.TableSpec.Indexes {
  1617  		if existingIndex.Info.Primary {
  1618  			return existingIndex.Columns
  1619  		}
  1620  	}
  1621  	return nil
  1622  }
  1623  
  1624  // Create implements Entity interface
  1625  func (c *CreateTableEntity) Create() EntityDiff {
  1626  	return &CreateTableEntityDiff{to: c, createTable: c.CreateTable}
  1627  }
  1628  
  1629  // Drop implements Entity interface
  1630  func (c *CreateTableEntity) Drop() EntityDiff {
  1631  	dropTable := &sqlparser.DropTable{
  1632  		FromTables: []sqlparser.TableName{c.Table},
  1633  	}
  1634  	return &DropTableEntityDiff{from: c, dropTable: dropTable}
  1635  }
  1636  
  1637  func sortAlterOptions(diff *AlterTableEntityDiff) {
  1638  	optionOrder := func(opt sqlparser.AlterOption) int {
  1639  		switch opt.(type) {
  1640  		case *sqlparser.DropKey:
  1641  			return 1
  1642  		case *sqlparser.DropColumn:
  1643  			return 2
  1644  		case *sqlparser.ModifyColumn:
  1645  			return 3
  1646  		case *sqlparser.RenameColumn:
  1647  			return 4
  1648  		case *sqlparser.AddColumns:
  1649  			return 5
  1650  		case *sqlparser.AddIndexDefinition:
  1651  			return 6
  1652  		case *sqlparser.AddConstraintDefinition:
  1653  			return 7
  1654  		case sqlparser.TableOptions, *sqlparser.TableOptions:
  1655  			return 8
  1656  		default:
  1657  			return math.MaxInt
  1658  		}
  1659  	}
  1660  	opts := diff.alterTable.AlterOptions
  1661  	sort.SliceStable(opts, func(i, j int) bool {
  1662  		return optionOrder(opts[i]) < optionOrder(opts[j])
  1663  	})
  1664  }
  1665  
  1666  // apply attempts to apply an ALTER TABLE diff onto this entity's table definition.
  1667  // supported modifications are only those created by schemadiff's Diff() function.
  1668  func (c *CreateTableEntity) apply(diff *AlterTableEntityDiff) error {
  1669  	sortAlterOptions(diff)
  1670  	// Apply partitioning changes:
  1671  	if spec := diff.alterTable.PartitionSpec; spec != nil {
  1672  		switch {
  1673  		case spec.Action == sqlparser.RemoveAction && spec.IsAll:
  1674  			// Remove partitioning
  1675  			c.TableSpec.PartitionOption = nil
  1676  		case spec.Action == sqlparser.DropAction && len(spec.Names) > 0:
  1677  			for _, dropPartitionName := range spec.Names {
  1678  				// Drop partitions
  1679  				if c.TableSpec.PartitionOption == nil {
  1680  					return &ApplyPartitionNotFoundError{Table: c.Name(), Partition: dropPartitionName.String()}
  1681  				}
  1682  				partitionFound := false
  1683  				for i, p := range c.TableSpec.PartitionOption.Definitions {
  1684  					if strings.EqualFold(p.Name.String(), dropPartitionName.String()) {
  1685  						c.TableSpec.PartitionOption.Definitions = append(
  1686  							c.TableSpec.PartitionOption.Definitions[0:i],
  1687  							c.TableSpec.PartitionOption.Definitions[i+1:]...,
  1688  						)
  1689  						partitionFound = true
  1690  						break
  1691  					}
  1692  				}
  1693  				if !partitionFound {
  1694  					return &ApplyPartitionNotFoundError{Table: c.Name(), Partition: dropPartitionName.String()}
  1695  				}
  1696  			}
  1697  		case spec.Action == sqlparser.AddAction && len(spec.Definitions) == 1:
  1698  			// Add one partition
  1699  			if c.TableSpec.PartitionOption == nil {
  1700  				return &ApplyNoPartitionsError{Table: c.Name()}
  1701  			}
  1702  			if len(c.TableSpec.PartitionOption.Definitions) == 0 {
  1703  				return &ApplyNoPartitionsError{Table: c.Name()}
  1704  			}
  1705  			for _, p := range c.TableSpec.PartitionOption.Definitions {
  1706  				if strings.EqualFold(p.Name.String(), spec.Definitions[0].Name.String()) {
  1707  					return &ApplyDuplicatePartitionError{Table: c.Name(), Partition: spec.Definitions[0].Name.String()}
  1708  				}
  1709  			}
  1710  			c.TableSpec.PartitionOption.Definitions = append(
  1711  				c.TableSpec.PartitionOption.Definitions,
  1712  				spec.Definitions[0],
  1713  			)
  1714  		default:
  1715  			return &UnsupportedApplyOperationError{Statement: sqlparser.CanonicalString(spec)}
  1716  		}
  1717  	}
  1718  	if diff.alterTable.PartitionOption != nil {
  1719  		// Specify new spec:
  1720  		c.CreateTable.TableSpec.PartitionOption = diff.alterTable.PartitionOption
  1721  	}
  1722  	// reorderColumn attempts to reorder column that is right now in position 'colIndex',
  1723  	// based on its FIRST or AFTER specs (if any)
  1724  	reorderColumn := func(colIndex int, first bool, after *sqlparser.ColName) error {
  1725  		var newCols []*sqlparser.ColumnDefinition // nil
  1726  		col := c.TableSpec.Columns[colIndex]
  1727  		switch {
  1728  		case first:
  1729  			newCols = append(newCols, col)
  1730  			newCols = append(newCols, c.TableSpec.Columns[0:colIndex]...)
  1731  			newCols = append(newCols, c.TableSpec.Columns[colIndex+1:]...)
  1732  		case after != nil:
  1733  			afterColFound := false
  1734  			// look for the AFTER column; it has to exist!
  1735  			for a, afterCol := range c.TableSpec.Columns {
  1736  				if strings.EqualFold(afterCol.Name.String(), after.Name.String()) {
  1737  					if colIndex < a {
  1738  						// moving column i to the right
  1739  						newCols = append(newCols, c.TableSpec.Columns[0:colIndex]...)
  1740  						newCols = append(newCols, c.TableSpec.Columns[colIndex+1:a+1]...)
  1741  						newCols = append(newCols, col)
  1742  						newCols = append(newCols, c.TableSpec.Columns[a+1:]...)
  1743  					} else {
  1744  						// moving column i to the left
  1745  						newCols = append(newCols, c.TableSpec.Columns[0:a+1]...)
  1746  						newCols = append(newCols, col)
  1747  						newCols = append(newCols, c.TableSpec.Columns[a+1:colIndex]...)
  1748  						newCols = append(newCols, c.TableSpec.Columns[colIndex+1:]...)
  1749  					}
  1750  					afterColFound = true
  1751  					break
  1752  				}
  1753  			}
  1754  			if !afterColFound {
  1755  				return &ApplyColumnAfterNotFoundError{Table: c.Name(), Column: col.Name.String(), AfterColumn: after.Name.String()}
  1756  			}
  1757  		default:
  1758  			// no change in position
  1759  		}
  1760  
  1761  		if newCols != nil {
  1762  			c.TableSpec.Columns = newCols
  1763  		}
  1764  		return nil
  1765  	}
  1766  
  1767  	columnExists := map[string]bool{}
  1768  	for _, col := range c.CreateTable.TableSpec.Columns {
  1769  		columnExists[col.Name.Lowered()] = true
  1770  	}
  1771  
  1772  	// apply a single AlterOption; only supported types are those generated by Diff()
  1773  	applyAlterOption := func(opt sqlparser.AlterOption) error {
  1774  		switch opt := opt.(type) {
  1775  		case *sqlparser.DropKey:
  1776  			// applies to either indexes or FK constraints
  1777  			// we expect the named key to be found
  1778  			found := false
  1779  			switch opt.Type {
  1780  			case sqlparser.PrimaryKeyType:
  1781  				for i, idx := range c.TableSpec.Indexes {
  1782  					if strings.EqualFold(idx.Info.Type, sqlparser.PrimaryKeyTypeStr) {
  1783  						found = true
  1784  						c.TableSpec.Indexes = append(c.TableSpec.Indexes[0:i], c.TableSpec.Indexes[i+1:]...)
  1785  						break
  1786  					}
  1787  				}
  1788  			case sqlparser.NormalKeyType:
  1789  				for i, index := range c.TableSpec.Indexes {
  1790  					if strings.EqualFold(index.Info.Name.String(), opt.Name.String()) {
  1791  						found = true
  1792  						c.TableSpec.Indexes = append(c.TableSpec.Indexes[0:i], c.TableSpec.Indexes[i+1:]...)
  1793  						break
  1794  					}
  1795  				}
  1796  			case sqlparser.ForeignKeyType, sqlparser.CheckKeyType:
  1797  				for i, constraint := range c.TableSpec.Constraints {
  1798  					if strings.EqualFold(constraint.Name.String(), opt.Name.String()) {
  1799  						found = true
  1800  						c.TableSpec.Constraints = append(c.TableSpec.Constraints[0:i], c.TableSpec.Constraints[i+1:]...)
  1801  						break
  1802  					}
  1803  				}
  1804  			default:
  1805  				return &UnsupportedApplyOperationError{Statement: sqlparser.CanonicalString(opt)}
  1806  			}
  1807  			if !found {
  1808  				return &ApplyKeyNotFoundError{Table: c.Name(), Key: opt.Name.String()}
  1809  			}
  1810  
  1811  			// Now, if this is a normal key being dropped, let's validate it does not leave any foreign key constraint uncovered
  1812  			switch opt.Type {
  1813  			case sqlparser.PrimaryKeyType, sqlparser.NormalKeyType:
  1814  				for _, cs := range c.CreateTable.TableSpec.Constraints {
  1815  					fk, ok := cs.Details.(*sqlparser.ForeignKeyDefinition)
  1816  					if !ok {
  1817  						continue
  1818  					}
  1819  					if !c.columnsCoveredByInOrderIndex(fk.Source) {
  1820  						return &IndexNeededByForeignKeyError{Table: c.Name(), Key: opt.Name.String()}
  1821  					}
  1822  				}
  1823  			}
  1824  
  1825  		case *sqlparser.AddIndexDefinition:
  1826  			// validate no existing key by same name
  1827  			keyName := opt.IndexDefinition.Info.Name.String()
  1828  			for _, index := range c.TableSpec.Indexes {
  1829  				if strings.EqualFold(index.Info.Name.String(), keyName) {
  1830  					return &ApplyDuplicateKeyError{Table: c.Name(), Key: keyName}
  1831  				}
  1832  			}
  1833  			for colName := range getKeyColumnNames(opt.IndexDefinition) {
  1834  				if !columnExists[colName] {
  1835  					return &InvalidColumnInKeyError{Table: c.Name(), Column: colName, Key: keyName}
  1836  				}
  1837  			}
  1838  			c.TableSpec.Indexes = append(c.TableSpec.Indexes, opt.IndexDefinition)
  1839  		case *sqlparser.AddConstraintDefinition:
  1840  			// validate no existing constraint by same name
  1841  			for _, cs := range c.TableSpec.Constraints {
  1842  				if strings.EqualFold(cs.Name.String(), opt.ConstraintDefinition.Name.String()) {
  1843  					return &ApplyDuplicateConstraintError{Table: c.Name(), Constraint: cs.Name.String()}
  1844  				}
  1845  			}
  1846  			c.TableSpec.Constraints = append(c.TableSpec.Constraints, opt.ConstraintDefinition)
  1847  		case *sqlparser.AlterCheck:
  1848  			// we expect the constraint to exist
  1849  			found := false
  1850  			for _, constraint := range c.TableSpec.Constraints {
  1851  				checkDetails, ok := constraint.Details.(*sqlparser.CheckConstraintDefinition)
  1852  				if ok && strings.EqualFold(constraint.Name.String(), opt.Name.String()) {
  1853  					found = true
  1854  					checkDetails.Enforced = opt.Enforced
  1855  					break
  1856  				}
  1857  			}
  1858  			if !found {
  1859  				return &ApplyConstraintNotFoundError{Table: c.Name(), Constraint: opt.Name.String()}
  1860  			}
  1861  		case *sqlparser.DropColumn:
  1862  			// we expect the column to exist
  1863  			found := false
  1864  			for i, col := range c.TableSpec.Columns {
  1865  				if strings.EqualFold(col.Name.String(), opt.Name.Name.String()) {
  1866  					found = true
  1867  					c.TableSpec.Columns = append(c.TableSpec.Columns[0:i], c.TableSpec.Columns[i+1:]...)
  1868  					delete(columnExists, col.Name.Lowered())
  1869  					break
  1870  				}
  1871  			}
  1872  			if !found {
  1873  				return &ApplyColumnNotFoundError{Table: c.Name(), Column: opt.Name.Name.String()}
  1874  			}
  1875  		case *sqlparser.AddColumns:
  1876  			if len(opt.Columns) != 1 {
  1877  				// our Diff only ever generates a single column per AlterOption
  1878  				return &UnsupportedApplyOperationError{Statement: sqlparser.CanonicalString(opt)}
  1879  			}
  1880  			// validate no column by same name
  1881  			addedCol := opt.Columns[0]
  1882  			for _, col := range c.TableSpec.Columns {
  1883  				if strings.EqualFold(col.Name.String(), addedCol.Name.String()) {
  1884  					return &ApplyDuplicateColumnError{Table: c.Name(), Column: addedCol.Name.String()}
  1885  				}
  1886  			}
  1887  			// if this column has the PRIMARY KEY option, verify there isn't already a PRIMARY KEY
  1888  			if addedCol.Type.Options.KeyOpt == sqlparser.ColKeyPrimary {
  1889  				if cols := c.primaryKeyColumns(); cols != nil {
  1890  					return &DuplicateKeyNameError{Table: c.Name(), Key: "PRIMARY"}
  1891  				}
  1892  			}
  1893  			c.TableSpec.Columns = append(c.TableSpec.Columns, addedCol)
  1894  			// see if we need to position it anywhere other than end of table
  1895  			if err := reorderColumn(len(c.TableSpec.Columns)-1, opt.First, opt.After); err != nil {
  1896  				return err
  1897  			}
  1898  			columnExists[addedCol.Name.Lowered()] = true
  1899  		case *sqlparser.ModifyColumn:
  1900  			// we expect the column to exist
  1901  			found := false
  1902  			for i, col := range c.TableSpec.Columns {
  1903  				if strings.EqualFold(col.Name.String(), opt.NewColDefinition.Name.String()) {
  1904  					found = true
  1905  					// redefine. see if we need to position it anywhere other than end of table
  1906  					c.TableSpec.Columns[i] = opt.NewColDefinition
  1907  					if err := reorderColumn(i, opt.First, opt.After); err != nil {
  1908  						return err
  1909  					}
  1910  					break
  1911  				}
  1912  			}
  1913  			if !found {
  1914  				return &ApplyColumnNotFoundError{Table: c.Name(), Column: opt.NewColDefinition.Name.String()}
  1915  			}
  1916  			// if this column has the PRIMARY KEY option:
  1917  			// - validate there isn't already a PRIMARY KEY for other columns
  1918  			// - if there isn't any PRIMARY KEY, create one
  1919  			// - if there exists a PRIMARY KEY for exactly this column, noop
  1920  			if opt.NewColDefinition.Type.Options.KeyOpt == sqlparser.ColKeyPrimary {
  1921  				cols := c.primaryKeyColumns()
  1922  				if cols == nil {
  1923  					// add primary key
  1924  					c.CreateTable.TableSpec.Indexes = append([]*sqlparser.IndexDefinition{newPrimaryKeyIndexDefinitionSingleColumn(opt.NewColDefinition.Name)}, c.CreateTable.TableSpec.Indexes...)
  1925  				} else {
  1926  					if len(cols) == 1 && strings.EqualFold(cols[0].Column.String(), opt.NewColDefinition.Name.String()) {
  1927  						// existing PK is exactly this column. Nothing to do
  1928  					} else {
  1929  						return &DuplicateKeyNameError{Table: c.Name(), Key: "PRIMARY"}
  1930  					}
  1931  				}
  1932  			}
  1933  			opt.NewColDefinition.Type.Options.KeyOpt = sqlparser.ColKeyNone
  1934  		case *sqlparser.RenameColumn:
  1935  			// we expect the column to exist
  1936  			found := false
  1937  			for i, col := range c.TableSpec.Columns {
  1938  				if strings.EqualFold(col.Name.String(), opt.OldName.Name.String()) {
  1939  					found = true
  1940  					// redefine. see if we need to position it anywhere other than end of table
  1941  					c.TableSpec.Columns[i].Name = opt.NewName.Name
  1942  					delete(columnExists, opt.OldName.Name.Lowered())
  1943  					columnExists[opt.NewName.Name.Lowered()] = true
  1944  					break
  1945  				}
  1946  			}
  1947  			if !found {
  1948  				return &ApplyColumnNotFoundError{Table: c.Name(), Column: opt.OldName.Name.String()}
  1949  			}
  1950  		case *sqlparser.AlterColumn:
  1951  			// we expect the column to exist
  1952  			found := false
  1953  			for _, col := range c.TableSpec.Columns {
  1954  				if strings.EqualFold(col.Name.String(), opt.Column.Name.String()) {
  1955  					found = true
  1956  					if opt.DropDefault {
  1957  						col.Type.Options.Default = nil
  1958  					} else if opt.DefaultVal != nil {
  1959  						col.Type.Options.Default = opt.DefaultVal
  1960  					}
  1961  					col.Type.Options.Invisible = opt.Invisible
  1962  					break
  1963  				}
  1964  			}
  1965  			if !found {
  1966  				return &ApplyColumnNotFoundError{Table: c.Name(), Column: opt.Column.Name.String()}
  1967  			}
  1968  		case *sqlparser.AlterIndex:
  1969  			// we expect the index to exist
  1970  			found := false
  1971  			for _, idx := range c.TableSpec.Indexes {
  1972  				if strings.EqualFold(idx.Info.Name.String(), opt.Name.String()) {
  1973  					found = true
  1974  					if opt.Invisible {
  1975  						idx.Options = append(idx.Options, &sqlparser.IndexOption{Name: "invisible"})
  1976  					} else {
  1977  						keptOptions := make([]*sqlparser.IndexOption, 0, len(idx.Options))
  1978  						for _, idxOpt := range idx.Options {
  1979  							if strings.EqualFold(idxOpt.Name, "invisible") {
  1980  								continue
  1981  							}
  1982  							keptOptions = append(keptOptions, idxOpt)
  1983  						}
  1984  						idx.Options = keptOptions
  1985  					}
  1986  					break
  1987  				}
  1988  			}
  1989  			if !found {
  1990  				return &ApplyKeyNotFoundError{Table: c.Name(), Key: opt.Name.String()}
  1991  			}
  1992  		case sqlparser.TableOptions:
  1993  			// Apply table options. Options that have their DEFAULT value are actually removed.
  1994  			for _, option := range opt {
  1995  				func() {
  1996  					for i, existingOption := range c.TableSpec.Options {
  1997  						if strings.EqualFold(option.Name, existingOption.Name) {
  1998  							if isDefaultTableOptionValue(option) {
  1999  								// remove the option
  2000  								c.TableSpec.Options = append(c.TableSpec.Options[0:i], c.TableSpec.Options[i+1:]...)
  2001  							} else {
  2002  								c.TableSpec.Options[i] = option
  2003  							}
  2004  							// option found. No need for further iteration.
  2005  							return
  2006  						}
  2007  					}
  2008  					// option not found. We add it
  2009  					c.TableSpec.Options = append(c.TableSpec.Options, option)
  2010  				}()
  2011  			}
  2012  		case sqlparser.AlgorithmValue:
  2013  			// silently ignore. This has an operational effect on the MySQL engine, but has no semantical effect.
  2014  		default:
  2015  			return &UnsupportedApplyOperationError{Statement: sqlparser.CanonicalString(opt)}
  2016  		}
  2017  		return nil
  2018  	}
  2019  	for _, alterOption := range diff.alterTable.AlterOptions {
  2020  		if err := applyAlterOption(alterOption); err != nil {
  2021  			return err
  2022  		}
  2023  	}
  2024  	if err := c.postApplyNormalize(); err != nil {
  2025  		return err
  2026  	}
  2027  	if err := c.validate(); err != nil {
  2028  		return err
  2029  	}
  2030  	return nil
  2031  }
  2032  
  2033  // Apply attempts to apply given ALTER TABLE diff onto the table defined by this entity.
  2034  // This entity is unmodified. If successful, a new CREATE TABLE entity is returned.
  2035  func (c *CreateTableEntity) Apply(diff EntityDiff) (Entity, error) {
  2036  	dup := c.Clone().(*CreateTableEntity)
  2037  	for diff != nil {
  2038  		alterDiff, ok := diff.(*AlterTableEntityDiff)
  2039  		if !ok {
  2040  			return nil, ErrEntityTypeMismatch
  2041  		}
  2042  		if !diff.IsEmpty() {
  2043  			if err := dup.apply(alterDiff); err != nil {
  2044  				return nil, err
  2045  			}
  2046  		}
  2047  		diff = diff.SubsequentDiff()
  2048  	}
  2049  	// Always normalize after an Apply to get consistent AST structures.
  2050  	dup.normalize()
  2051  	return dup, nil
  2052  }
  2053  
  2054  // postApplyNormalize runs at the end of apply() and to reorganize/edit things that
  2055  // a MySQL will do implicitly:
  2056  //   - edit or remove keys if referenced columns are dropped
  2057  //   - drop check constraints for a single specific column if that column
  2058  //     is the only referenced column in that check constraint.
  2059  //   - add implicit keys for foreign key constraint, if needed
  2060  func (c *CreateTableEntity) postApplyNormalize() error {
  2061  	// reduce or remove keys based on existing column list
  2062  	// (a column may have been removed)postApplyNormalize
  2063  	columnExists := map[string]bool{}
  2064  	for _, col := range c.CreateTable.TableSpec.Columns {
  2065  		columnExists[col.Name.Lowered()] = true
  2066  	}
  2067  	var nonEmptyIndexes []*sqlparser.IndexDefinition
  2068  
  2069  	keyHasNonExistentColumns := func(keyCol *sqlparser.IndexColumn) bool {
  2070  		if keyCol.Column.Lowered() != "" {
  2071  			if !columnExists[keyCol.Column.Lowered()] {
  2072  				return true
  2073  			}
  2074  		}
  2075  		return false
  2076  	}
  2077  	for _, key := range c.CreateTable.TableSpec.Indexes {
  2078  		var existingKeyColumns []*sqlparser.IndexColumn
  2079  		for _, keyCol := range key.Columns {
  2080  			if !keyHasNonExistentColumns(keyCol) {
  2081  				existingKeyColumns = append(existingKeyColumns, keyCol)
  2082  			}
  2083  		}
  2084  		if len(existingKeyColumns) > 0 {
  2085  			key.Columns = existingKeyColumns
  2086  			nonEmptyIndexes = append(nonEmptyIndexes, key)
  2087  		}
  2088  	}
  2089  	c.CreateTable.TableSpec.Indexes = nonEmptyIndexes
  2090  
  2091  	var keptConstraints []*sqlparser.ConstraintDefinition
  2092  	for _, constraint := range c.CreateTable.TableSpec.Constraints {
  2093  		check, ok := constraint.Details.(*sqlparser.CheckConstraintDefinition)
  2094  		if !ok {
  2095  			keptConstraints = append(keptConstraints, constraint)
  2096  			continue
  2097  		}
  2098  		var referencedColumns []string
  2099  		err := sqlparser.Walk(func(node sqlparser.SQLNode) (kontinue bool, err error) {
  2100  			switch node := node.(type) {
  2101  			case *sqlparser.ColName:
  2102  				referencedColumns = append(referencedColumns, node.Name.String())
  2103  			}
  2104  			return true, nil
  2105  		}, check.Expr)
  2106  		if err != nil {
  2107  			return err
  2108  		}
  2109  		if len(referencedColumns) != 1 {
  2110  			keptConstraints = append(keptConstraints, constraint)
  2111  			continue
  2112  		}
  2113  
  2114  		referencedColumn := referencedColumns[0]
  2115  		if columnExists[strings.ToLower(referencedColumn)] {
  2116  			keptConstraints = append(keptConstraints, constraint)
  2117  		}
  2118  	}
  2119  	c.CreateTable.TableSpec.Constraints = keptConstraints
  2120  
  2121  	c.normalizePrimaryKeyColumns()
  2122  	c.normalizeForeignKeyIndexes()
  2123  	c.normalizeKeys()
  2124  
  2125  	return nil
  2126  }
  2127  
  2128  func getNodeColumns(node sqlparser.SQLNode) (colNames map[string]bool) {
  2129  	colNames = map[string]bool{}
  2130  	if node != nil {
  2131  		_ = sqlparser.Walk(func(node sqlparser.SQLNode) (kontinue bool, err error) {
  2132  			switch node := node.(type) {
  2133  			case *sqlparser.ColName:
  2134  				colNames[node.Name.Lowered()] = true
  2135  			}
  2136  			return true, nil
  2137  		}, node)
  2138  	}
  2139  	return colNames
  2140  }
  2141  
  2142  func getKeyColumnNames(key *sqlparser.IndexDefinition) (colNames map[string]bool) {
  2143  	colNames = map[string]bool{}
  2144  	for _, col := range key.Columns {
  2145  		if colName := col.Column.Lowered(); colName != "" {
  2146  			colNames[colName] = true
  2147  		}
  2148  		for name := range getNodeColumns(col.Expression) {
  2149  			colNames[name] = true
  2150  		}
  2151  	}
  2152  	return colNames
  2153  }
  2154  
  2155  // indexCoversColumnsInOrder checks if the given index covers the given columns in order and in prefix.
  2156  // the index must either covers the exact list of columns or continue to cover additional columns beyond.
  2157  // Used for validating indexes covering foreign keys.
  2158  func indexCoversColumnsInOrder(index *sqlparser.IndexDefinition, columns sqlparser.Columns) bool {
  2159  	if len(columns) == 0 {
  2160  		return false
  2161  	}
  2162  	if len(index.Columns) < len(columns) {
  2163  		// obviously the index doesn't cover the required columns
  2164  		return false
  2165  	}
  2166  	for i, col := range columns {
  2167  		// the index must cover same columns, in order, wih possibly more columns covered than requested.
  2168  		indexCol := index.Columns[i]
  2169  		if !strings.EqualFold(col.String(), indexCol.Column.String()) {
  2170  			return false
  2171  		}
  2172  	}
  2173  	return true
  2174  }
  2175  
  2176  // indexesCoveringForeignKeyColumns returns a list of indexes that cover a given list of coumns, in-oder and in prefix.
  2177  // Used for validating indexes covering foreign keys.
  2178  func (c *CreateTableEntity) indexesCoveringForeignKeyColumns(columns sqlparser.Columns) (indexes []*sqlparser.IndexDefinition) {
  2179  	for _, index := range c.CreateTable.TableSpec.Indexes {
  2180  		if indexCoversColumnsInOrder(index, columns) {
  2181  			indexes = append(indexes, index)
  2182  		}
  2183  	}
  2184  	return indexes
  2185  }
  2186  
  2187  // columnsCoveredByInOrderIndex returns 'true' when there is at least one index that covers the given
  2188  // list of columns in-order and in-prefix.
  2189  func (c *CreateTableEntity) columnsCoveredByInOrderIndex(columns sqlparser.Columns) bool {
  2190  	return len(c.indexesCoveringForeignKeyColumns(columns)) > 0
  2191  }
  2192  
  2193  func (c *CreateTableEntity) validateDuplicateKeyNameError() error {
  2194  	keyNames := map[string]bool{}
  2195  	for _, key := range c.CreateTable.TableSpec.Indexes {
  2196  		name := key.Info.Name
  2197  		if _, ok := keyNames[name.Lowered()]; ok {
  2198  			return &DuplicateKeyNameError{Table: c.Name(), Key: name.String()}
  2199  		}
  2200  		keyNames[name.Lowered()] = true
  2201  	}
  2202  	return nil
  2203  }
  2204  
  2205  // validate checks that the table structure is valid:
  2206  // - all columns referenced by keys exist
  2207  func (c *CreateTableEntity) validate() error {
  2208  	columnExists := map[string]bool{}
  2209  	for _, col := range c.CreateTable.TableSpec.Columns {
  2210  		colName := col.Name.Lowered()
  2211  		if columnExists[colName] {
  2212  			return &ApplyDuplicateColumnError{Table: c.Name(), Column: col.Name.String()}
  2213  		}
  2214  		columnExists[colName] = true
  2215  	}
  2216  	// validate all columns used by foreign key constraints do in fact exist,
  2217  	// and that there exists an index over those columns
  2218  	for _, cs := range c.CreateTable.TableSpec.Constraints {
  2219  		fk, ok := cs.Details.(*sqlparser.ForeignKeyDefinition)
  2220  		if !ok {
  2221  			continue
  2222  		}
  2223  		if len(fk.Source) != len(fk.ReferenceDefinition.ReferencedColumns) {
  2224  			return &ForeignKeyColumnCountMismatchError{Table: c.Name(), Constraint: cs.Name.String(), ColumnCount: len(fk.Source), ReferencedTable: fk.ReferenceDefinition.ReferencedTable.Name.String(), ReferencedColumnCount: len(fk.ReferenceDefinition.ReferencedColumns)}
  2225  		}
  2226  		for _, col := range fk.Source {
  2227  			if !columnExists[col.Lowered()] {
  2228  				return &InvalidColumnInForeignKeyConstraintError{Table: c.Name(), Constraint: cs.Name.String(), Column: col.String()}
  2229  			}
  2230  		}
  2231  	}
  2232  	// validate all columns referenced by indexes do in fact exist
  2233  	for _, key := range c.CreateTable.TableSpec.Indexes {
  2234  		for colName := range getKeyColumnNames(key) {
  2235  			if !columnExists[colName] {
  2236  				return &InvalidColumnInKeyError{Table: c.Name(), Column: colName, Key: key.Info.Name.String()}
  2237  			}
  2238  		}
  2239  	}
  2240  	// validate all columns referenced by generated columns do in fact exist
  2241  	for _, col := range c.CreateTable.TableSpec.Columns {
  2242  		if col.Type.Options != nil && col.Type.Options.As != nil {
  2243  			var referencedColumns []string
  2244  			err := sqlparser.Walk(func(node sqlparser.SQLNode) (kontinue bool, err error) {
  2245  				switch node := node.(type) {
  2246  				case *sqlparser.ColName:
  2247  					referencedColumns = append(referencedColumns, node.Name.String())
  2248  				}
  2249  				return true, nil
  2250  			}, col.Type.Options.As)
  2251  			if err != nil {
  2252  				return err
  2253  			}
  2254  			for _, referencedColName := range referencedColumns {
  2255  				if !columnExists[strings.ToLower(referencedColName)] {
  2256  					return &InvalidColumnInGeneratedColumnError{Table: c.Name(), Column: referencedColName, GeneratedColumn: col.Name.String()}
  2257  				}
  2258  			}
  2259  		}
  2260  	}
  2261  	// validate all columns referenced by functional indexes do in fact exist
  2262  	for _, idx := range c.CreateTable.TableSpec.Indexes {
  2263  		for _, idxCol := range idx.Columns {
  2264  			var referencedColumns []string
  2265  			err := sqlparser.Walk(func(node sqlparser.SQLNode) (kontinue bool, err error) {
  2266  				switch node := node.(type) {
  2267  				case *sqlparser.ColName:
  2268  					referencedColumns = append(referencedColumns, node.Name.String())
  2269  				}
  2270  				return true, nil
  2271  			}, idxCol.Expression)
  2272  			if err != nil {
  2273  				return err
  2274  			}
  2275  			for _, referencedColName := range referencedColumns {
  2276  				if !columnExists[strings.ToLower(referencedColName)] {
  2277  					return &InvalidColumnInKeyError{Table: c.Name(), Column: referencedColName, Key: idx.Info.Name.String()}
  2278  				}
  2279  			}
  2280  		}
  2281  	}
  2282  	// validate all columns referenced by constraint checks do in fact exist
  2283  	for _, cs := range c.CreateTable.TableSpec.Constraints {
  2284  		check, ok := cs.Details.(*sqlparser.CheckConstraintDefinition)
  2285  		if !ok {
  2286  			continue
  2287  		}
  2288  		var referencedColumns []string
  2289  		err := sqlparser.Walk(func(node sqlparser.SQLNode) (kontinue bool, err error) {
  2290  			switch node := node.(type) {
  2291  			case *sqlparser.ColName:
  2292  				referencedColumns = append(referencedColumns, node.Name.String())
  2293  			}
  2294  			return true, nil
  2295  		}, check.Expr)
  2296  		if err != nil {
  2297  			return err
  2298  		}
  2299  		for _, referencedColName := range referencedColumns {
  2300  			if !columnExists[strings.ToLower(referencedColName)] {
  2301  				return &InvalidColumnInCheckConstraintError{Table: c.Name(), Constraint: cs.Name.String(), Column: referencedColName}
  2302  			}
  2303  		}
  2304  	}
  2305  	// validate no two keys have same name
  2306  	if err := c.validateDuplicateKeyNameError(); err != nil {
  2307  		return err
  2308  	}
  2309  
  2310  	if partition := c.CreateTable.TableSpec.PartitionOption; partition != nil {
  2311  		// validate no two partitions have same name
  2312  		partitionExists := map[string]bool{}
  2313  		for _, p := range partition.Definitions {
  2314  			if partitionExists[p.Name.Lowered()] {
  2315  				return &ApplyDuplicatePartitionError{Table: c.Name(), Partition: p.Name.String()}
  2316  			}
  2317  			partitionExists[p.Name.Lowered()] = true
  2318  		}
  2319  		// validate columns referenced by partitions do in fact exist
  2320  		// also, validate that all unique keys include partitioned columns
  2321  		var partitionColNames []string
  2322  		err := sqlparser.Walk(func(node sqlparser.SQLNode) (kontinue bool, err error) {
  2323  			switch node := node.(type) {
  2324  			case *sqlparser.ColName:
  2325  				partitionColNames = append(partitionColNames, node.Name.String())
  2326  			}
  2327  			return true, nil
  2328  		}, partition.Expr)
  2329  		if err != nil {
  2330  			return err
  2331  		}
  2332  
  2333  		for _, partitionColName := range partitionColNames {
  2334  			// Validate columns exists in table:
  2335  			if !columnExists[strings.ToLower(partitionColName)] {
  2336  				return &InvalidColumnInPartitionError{Table: c.Name(), Column: partitionColName}
  2337  			}
  2338  
  2339  			// Validate all unique keys include this column:
  2340  			for _, key := range c.CreateTable.TableSpec.Indexes {
  2341  				if !key.Info.Unique {
  2342  					continue
  2343  				}
  2344  				colFound := false
  2345  				for _, col := range key.Columns {
  2346  					if strings.EqualFold(col.Column.String(), partitionColName) {
  2347  						colFound = true
  2348  						break
  2349  					}
  2350  				}
  2351  				if !colFound {
  2352  					return &MissingPartitionColumnInUniqueKeyError{Table: c.Name(), Column: partitionColName, UniqueKey: key.Info.Name.String()}
  2353  				}
  2354  			}
  2355  		}
  2356  	}
  2357  	return nil
  2358  }
  2359  
  2360  // identicalOtherThanName returns true when this CREATE TABLE and the given one, are identical
  2361  // other than in table's name. We assume both have been normalized.
  2362  func (c *CreateTableEntity) identicalOtherThanName(other *CreateTableEntity) bool {
  2363  	if other == nil {
  2364  		return false
  2365  	}
  2366  	return sqlparser.Equals.RefOfTableSpec(c.TableSpec, other.TableSpec) &&
  2367  		sqlparser.Equals.RefOfParsedComments(c.Comments, other.Comments)
  2368  }