github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/pingcap/tidb/ddl/ddl.go (about)

     1  // Copyright 2013 The ql Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSES/QL-LICENSE file.
     4  
     5  // Copyright 2015 PingCAP, Inc.
     6  //
     7  // Licensed under the Apache License, Version 2.0 (the "License");
     8  // you may not use this file except in compliance with the License.
     9  // You may obtain a copy of the License at
    10  //
    11  //     http://www.apache.org/licenses/LICENSE-2.0
    12  //
    13  // Unless required by applicable law or agreed to in writing, software
    14  // distributed under the License is distributed on an "AS IS" BASIS,
    15  // See the License for the specific language governing permissions and
    16  // limitations under the License.
    17  
    18  package ddl
    19  
    20  import (
    21  	"fmt"
    22  	"strings"
    23  	"sync"
    24  	"time"
    25  
    26  	"github.com/insionng/yougam/libraries/juju/errors"
    27  	"github.com/insionng/yougam/libraries/ngaut/log"
    28  	"github.com/insionng/yougam/libraries/pingcap/tidb/ast"
    29  	"github.com/insionng/yougam/libraries/pingcap/tidb/column"
    30  	"github.com/insionng/yougam/libraries/pingcap/tidb/context"
    31  	"github.com/insionng/yougam/libraries/pingcap/tidb/evaluator"
    32  	"github.com/insionng/yougam/libraries/pingcap/tidb/infoschema"
    33  	"github.com/insionng/yougam/libraries/pingcap/tidb/kv"
    34  	"github.com/insionng/yougam/libraries/pingcap/tidb/meta"
    35  	"github.com/insionng/yougam/libraries/pingcap/tidb/meta/autoid"
    36  	"github.com/insionng/yougam/libraries/pingcap/tidb/model"
    37  	"github.com/insionng/yougam/libraries/pingcap/tidb/mysql"
    38  	"github.com/insionng/yougam/libraries/pingcap/tidb/sessionctx/variable"
    39  	"github.com/insionng/yougam/libraries/pingcap/tidb/table"
    40  	"github.com/insionng/yougam/libraries/pingcap/tidb/terror"
    41  	"github.com/insionng/yougam/libraries/pingcap/tidb/util/charset"
    42  	"github.com/insionng/yougam/libraries/pingcap/tidb/util/types"
    43  	"github.com/insionng/yougam/libraries/twinj/uuid"
    44  )
    45  
    46  var (
    47  	// errWorkerClosed means we have already closed the DDL worker.
    48  	errInvalidWorker = terror.ClassDDL.New(codeInvalidWorker, "invalid worker")
    49  	// errNotOwner means we are not owner and can't handle DDL jobs.
    50  	errNotOwner              = terror.ClassDDL.New(codeNotOwner, "not Owner")
    51  	errInvalidDDLJob         = terror.ClassDDL.New(codeInvalidDDLJob, "invalid ddl job")
    52  	errInvalidBgJob          = terror.ClassDDL.New(codeInvalidBgJob, "invalid background job")
    53  	errInvalidJobFlag        = terror.ClassDDL.New(codeInvalidJobFlag, "invalid job flag")
    54  	errRunMultiSchemaChanges = terror.ClassDDL.New(codeRunMultiSchemaChanges, "can't run multi schema change")
    55  	errWaitReorgTimeout      = terror.ClassDDL.New(codeWaitReorgTimeout, "wait for reorganization timeout")
    56  	errInvalidStoreVer       = terror.ClassDDL.New(codeInvalidStoreVer, "invalid storage current version")
    57  
    58  	// we don't support drop column with index covered now.
    59  	errCantDropColWithIndex = terror.ClassDDL.New(codeCantDropColWithIndex, "can't drop column with index")
    60  	errUnsupportedAddColumn = terror.ClassDDL.New(codeUnsupportedAddColumn, "unsupported add column")
    61  
    62  	// ErrInvalidDBState returns for invalid database state.
    63  	ErrInvalidDBState = terror.ClassDDL.New(codeInvalidDBState, "invalid database state")
    64  	// ErrInvalidTableState returns for invalid Table state.
    65  	ErrInvalidTableState = terror.ClassDDL.New(codeInvalidTableState, "invalid table state")
    66  	// ErrInvalidColumnState returns for invalid column state.
    67  	ErrInvalidColumnState = terror.ClassDDL.New(codeInvalidColumnState, "invalid column state")
    68  	// ErrInvalidIndexState returns for invalid index state.
    69  	ErrInvalidIndexState = terror.ClassDDL.New(codeInvalidIndexState, "invalid index state")
    70  	// ErrInvalidForeignKeyState returns for invalid foreign key state.
    71  	ErrInvalidForeignKeyState = terror.ClassDDL.New(codeInvalidForeignKeyState, "invalid foreign key state")
    72  
    73  	// ErrColumnBadNull returns for a bad null value.
    74  	ErrColumnBadNull = terror.ClassDDL.New(codeBadNull, "column cann't be null")
    75  	// ErrCantRemoveAllFields returns for deleting all columns.
    76  	ErrCantRemoveAllFields = terror.ClassDDL.New(codeCantRemoveAllFields, "can't delete all columns with ALTER TABLE")
    77  	// ErrCantDropFieldOrKey returns for dropping a non-existent field or key.
    78  	ErrCantDropFieldOrKey = terror.ClassDDL.New(codeCantDropFieldOrKey, "can't drop field; check that column/key exists")
    79  	// ErrInvalidOnUpdate returns for invalid ON UPDATE clause.
    80  	ErrInvalidOnUpdate = terror.ClassDDL.New(codeInvalidOnUpdate, "invalid ON UPDATE clause for the column")
    81  )
    82  
    83  // DDL is responsible for updating schema in data store and maintaining in-memory InfoSchema cache.
    84  type DDL interface {
    85  	CreateSchema(ctx context.Context, name model.CIStr, charsetInfo *ast.CharsetOpt) error
    86  	DropSchema(ctx context.Context, schema model.CIStr) error
    87  	CreateTable(ctx context.Context, ident ast.Ident, cols []*ast.ColumnDef,
    88  		constrs []*ast.Constraint, options []*ast.TableOption) error
    89  	DropTable(ctx context.Context, tableIdent ast.Ident) (err error)
    90  	CreateIndex(ctx context.Context, tableIdent ast.Ident, unique bool, indexName model.CIStr,
    91  		columnNames []*ast.IndexColName) error
    92  	DropIndex(ctx context.Context, tableIdent ast.Ident, indexName model.CIStr) error
    93  	GetInformationSchema() infoschema.InfoSchema
    94  	AlterTable(ctx context.Context, tableIdent ast.Ident, spec []*ast.AlterTableSpec) error
    95  	// SetLease will reset the lease time for online DDL change,
    96  	// it's a very dangerous function and you must guarantee that all servers have the same lease time.
    97  	SetLease(lease time.Duration)
    98  	// GetLease returns current schema lease time.
    99  	GetLease() time.Duration
   100  	// Stats returns the DDL statistics.
   101  	Stats() (map[string]interface{}, error)
   102  	// GetScope gets the status variables scope.
   103  	GetScope(status string) variable.ScopeFlag
   104  	// Stop stops DDL worker.
   105  	Stop() error
   106  	// Start starts DDL worker.
   107  	Start() error
   108  }
   109  
   110  type ddl struct {
   111  	m sync.RWMutex
   112  
   113  	infoHandle *infoschema.Handle
   114  	hook       Callback
   115  	store      kv.Storage
   116  	// schema lease seconds.
   117  	lease        time.Duration
   118  	uuid         string
   119  	ddlJobCh     chan struct{}
   120  	ddlJobDoneCh chan struct{}
   121  	// drop database/table job runs in the background.
   122  	bgJobCh chan struct{}
   123  	// reorgDoneCh is for reorganization, if the reorganization job is done,
   124  	// we will use this channel to notify outer.
   125  	// TODO: now we use goroutine to simulate reorganization jobs, later we may
   126  	// use a persistent job list.
   127  	reorgDoneCh chan error
   128  
   129  	quitCh chan struct{}
   130  	wait   sync.WaitGroup
   131  }
   132  
   133  // NewDDL creates a new DDL.
   134  func NewDDL(store kv.Storage, infoHandle *infoschema.Handle, hook Callback, lease time.Duration) DDL {
   135  	return newDDL(store, infoHandle, hook, lease)
   136  }
   137  
   138  func newDDL(store kv.Storage, infoHandle *infoschema.Handle, hook Callback, lease time.Duration) *ddl {
   139  	if hook == nil {
   140  		hook = &BaseCallback{}
   141  	}
   142  
   143  	d := &ddl{
   144  		infoHandle:   infoHandle,
   145  		hook:         hook,
   146  		store:        store,
   147  		lease:        lease,
   148  		uuid:         uuid.NewV4().String(),
   149  		ddlJobCh:     make(chan struct{}, 1),
   150  		ddlJobDoneCh: make(chan struct{}, 1),
   151  		bgJobCh:      make(chan struct{}, 1),
   152  	}
   153  
   154  	d.start()
   155  
   156  	variable.RegisterStatistics(d)
   157  
   158  	return d
   159  }
   160  
   161  func (d *ddl) Stop() error {
   162  	d.m.Lock()
   163  	defer d.m.Unlock()
   164  
   165  	d.close()
   166  
   167  	err := kv.RunInNewTxn(d.store, true, func(txn kv.Transaction) error {
   168  		t := meta.NewMeta(txn)
   169  		owner, err1 := t.GetDDLJobOwner()
   170  		if err1 != nil {
   171  			return errors.Trace(err1)
   172  		}
   173  		if owner == nil || owner.OwnerID != d.uuid {
   174  			return nil
   175  		}
   176  
   177  		// ddl job's owner is me, clean it so other servers can compete for it quickly.
   178  		return t.SetDDLJobOwner(&model.Owner{})
   179  	})
   180  	if err != nil {
   181  		return errors.Trace(err)
   182  	}
   183  
   184  	err = kv.RunInNewTxn(d.store, true, func(txn kv.Transaction) error {
   185  		t := meta.NewMeta(txn)
   186  		owner, err1 := t.GetBgJobOwner()
   187  		if err1 != nil {
   188  			return errors.Trace(err1)
   189  		}
   190  		if owner == nil || owner.OwnerID != d.uuid {
   191  			return nil
   192  		}
   193  
   194  		// background job's owner is me, clean it so other servers can compete for it quickly.
   195  		return t.SetBgJobOwner(&model.Owner{})
   196  	})
   197  
   198  	return errors.Trace(err)
   199  }
   200  
   201  func (d *ddl) Start() error {
   202  	d.m.Lock()
   203  	defer d.m.Unlock()
   204  
   205  	if !d.isClosed() {
   206  		return nil
   207  	}
   208  
   209  	d.start()
   210  
   211  	return nil
   212  }
   213  
   214  func (d *ddl) start() {
   215  	d.quitCh = make(chan struct{})
   216  	d.wait.Add(2)
   217  	go d.onBackgroundWorker()
   218  	go d.onDDLWorker()
   219  	// for every start, we will send a fake job to let worker
   220  	// check owner first and try to find whether a job exists and run.
   221  	asyncNotify(d.ddlJobCh)
   222  	asyncNotify(d.bgJobCh)
   223  }
   224  
   225  func (d *ddl) close() {
   226  	if d.isClosed() {
   227  		return
   228  	}
   229  
   230  	close(d.quitCh)
   231  
   232  	d.wait.Wait()
   233  }
   234  
   235  func (d *ddl) isClosed() bool {
   236  	select {
   237  	case <-d.quitCh:
   238  		return true
   239  	default:
   240  		return false
   241  	}
   242  }
   243  
   244  func (d *ddl) SetLease(lease time.Duration) {
   245  	d.m.Lock()
   246  	defer d.m.Unlock()
   247  
   248  	if lease == d.lease {
   249  		return
   250  	}
   251  
   252  	log.Warnf("[ddl] change schema lease %s -> %s", d.lease, lease)
   253  
   254  	if d.isClosed() {
   255  		// if already closed, just set lease and return
   256  		d.lease = lease
   257  		return
   258  	}
   259  
   260  	// close the running worker and start again
   261  	d.close()
   262  	d.lease = lease
   263  	d.start()
   264  }
   265  
   266  func (d *ddl) GetLease() time.Duration {
   267  	d.m.RLock()
   268  	lease := d.lease
   269  	d.m.RUnlock()
   270  	return lease
   271  }
   272  
   273  func (d *ddl) GetInformationSchema() infoschema.InfoSchema {
   274  	return d.infoHandle.Get()
   275  }
   276  
   277  func (d *ddl) genGlobalID() (int64, error) {
   278  	var globalID int64
   279  	err := kv.RunInNewTxn(d.store, true, func(txn kv.Transaction) error {
   280  		var err error
   281  		globalID, err = meta.NewMeta(txn).GenGlobalID()
   282  		return errors.Trace(err)
   283  	})
   284  
   285  	return globalID, errors.Trace(err)
   286  }
   287  
   288  func (d *ddl) CreateSchema(ctx context.Context, schema model.CIStr, charsetInfo *ast.CharsetOpt) (err error) {
   289  	is := d.GetInformationSchema()
   290  	_, ok := is.SchemaByName(schema)
   291  	if ok {
   292  		return errors.Trace(infoschema.ErrDatabaseExists)
   293  	}
   294  
   295  	schemaID, err := d.genGlobalID()
   296  	if err != nil {
   297  		return errors.Trace(err)
   298  	}
   299  	dbInfo := &model.DBInfo{
   300  		Name: schema,
   301  	}
   302  	if charsetInfo != nil {
   303  		dbInfo.Charset = charsetInfo.Chs
   304  		dbInfo.Collate = charsetInfo.Col
   305  	} else {
   306  		dbInfo.Charset, dbInfo.Collate = getDefaultCharsetAndCollate()
   307  	}
   308  
   309  	job := &model.Job{
   310  		SchemaID: schemaID,
   311  		Type:     model.ActionCreateSchema,
   312  		Args:     []interface{}{dbInfo},
   313  	}
   314  
   315  	err = d.doDDLJob(ctx, job)
   316  	err = d.hook.OnChanged(err)
   317  	return errors.Trace(err)
   318  }
   319  
   320  func (d *ddl) DropSchema(ctx context.Context, schema model.CIStr) (err error) {
   321  	is := d.GetInformationSchema()
   322  	old, ok := is.SchemaByName(schema)
   323  	if !ok {
   324  		return errors.Trace(infoschema.ErrDatabaseNotExists)
   325  	}
   326  
   327  	job := &model.Job{
   328  		SchemaID: old.ID,
   329  		Type:     model.ActionDropSchema,
   330  	}
   331  
   332  	err = d.doDDLJob(ctx, job)
   333  	err = d.hook.OnChanged(err)
   334  	return errors.Trace(err)
   335  }
   336  
   337  func getDefaultCharsetAndCollate() (string, string) {
   338  	// TODO: TableDefaultCharset-->DatabaseDefaultCharset-->SystemDefaultCharset.
   339  	// TODO: change TableOption parser to parse collate.
   340  	// This is a tmp solution.
   341  	return "utf8", "utf8_unicode_ci"
   342  }
   343  
   344  func setColumnFlagWithConstraint(colMap map[string]*column.Col, v *ast.Constraint) {
   345  	switch v.Tp {
   346  	case ast.ConstraintPrimaryKey:
   347  		for _, key := range v.Keys {
   348  			c, ok := colMap[key.Column.Name.L]
   349  			if !ok {
   350  				// TODO: table constraint on unknown column.
   351  				continue
   352  			}
   353  			c.Flag |= mysql.PriKeyFlag
   354  			// Primary key can not be NULL.
   355  			c.Flag |= mysql.NotNullFlag
   356  		}
   357  	case ast.ConstraintUniq, ast.ConstraintUniqIndex, ast.ConstraintUniqKey:
   358  		for i, key := range v.Keys {
   359  			c, ok := colMap[key.Column.Name.L]
   360  			if !ok {
   361  				// TODO: table constraint on unknown column.
   362  				continue
   363  			}
   364  			if i == 0 {
   365  				// Only the first column can be set
   366  				// if unique index has multi columns,
   367  				// the flag should be MultipleKeyFlag.
   368  				// See: https://dev.mysql.com/doc/refman/5.7/en/show-columns.html
   369  				if len(v.Keys) > 1 {
   370  					c.Flag |= mysql.MultipleKeyFlag
   371  				} else {
   372  					c.Flag |= mysql.UniqueKeyFlag
   373  				}
   374  			}
   375  		}
   376  	case ast.ConstraintKey, ast.ConstraintIndex:
   377  		for i, key := range v.Keys {
   378  			c, ok := colMap[key.Column.Name.L]
   379  			if !ok {
   380  				// TODO: table constraint on unknown column.
   381  				continue
   382  			}
   383  			if i == 0 {
   384  				// Only the first column can be set.
   385  				c.Flag |= mysql.MultipleKeyFlag
   386  			}
   387  		}
   388  	}
   389  }
   390  
   391  func (d *ddl) buildColumnsAndConstraints(ctx context.Context, colDefs []*ast.ColumnDef,
   392  	constraints []*ast.Constraint) ([]*column.Col, []*ast.Constraint, error) {
   393  	var cols []*column.Col
   394  	colMap := map[string]*column.Col{}
   395  	for i, colDef := range colDefs {
   396  		col, cts, err := d.buildColumnAndConstraint(ctx, i, colDef)
   397  		if err != nil {
   398  			return nil, nil, errors.Trace(err)
   399  		}
   400  		col.State = model.StatePublic
   401  		constraints = append(constraints, cts...)
   402  		cols = append(cols, col)
   403  		colMap[colDef.Name.Name.L] = col
   404  	}
   405  	// traverse table Constraints and set col.flag
   406  	for _, v := range constraints {
   407  		setColumnFlagWithConstraint(colMap, v)
   408  	}
   409  	return cols, constraints, nil
   410  }
   411  
   412  func (d *ddl) buildColumnAndConstraint(ctx context.Context, offset int,
   413  	colDef *ast.ColumnDef) (*column.Col, []*ast.Constraint, error) {
   414  	// Set charset.
   415  	if len(colDef.Tp.Charset) == 0 {
   416  		switch colDef.Tp.Tp {
   417  		case mysql.TypeString, mysql.TypeVarchar, mysql.TypeVarString, mysql.TypeBlob, mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeLongBlob:
   418  			colDef.Tp.Charset, colDef.Tp.Collate = getDefaultCharsetAndCollate()
   419  		default:
   420  			colDef.Tp.Charset = charset.CharsetBin
   421  			colDef.Tp.Collate = charset.CharsetBin
   422  		}
   423  	}
   424  
   425  	col, cts, err := columnDefToCol(ctx, offset, colDef)
   426  	if err != nil {
   427  		return nil, nil, errors.Trace(err)
   428  	}
   429  
   430  	col.ID, err = d.genGlobalID()
   431  	if err != nil {
   432  		return nil, nil, errors.Trace(err)
   433  	}
   434  
   435  	return col, cts, nil
   436  }
   437  
   438  // columnDefToCol converts ColumnDef to Col and TableConstraints.
   439  func columnDefToCol(ctx context.Context, offset int, colDef *ast.ColumnDef) (*column.Col, []*ast.Constraint, error) {
   440  	constraints := []*ast.Constraint{}
   441  	col := &column.Col{
   442  		ColumnInfo: model.ColumnInfo{
   443  			Offset:    offset,
   444  			Name:      colDef.Name.Name,
   445  			FieldType: *colDef.Tp,
   446  		},
   447  	}
   448  
   449  	// Check and set TimestampFlag and OnUpdateNowFlag.
   450  	if col.Tp == mysql.TypeTimestamp {
   451  		col.Flag |= mysql.TimestampFlag
   452  		col.Flag |= mysql.OnUpdateNowFlag
   453  		col.Flag |= mysql.NotNullFlag
   454  	}
   455  
   456  	// If flen is not assigned, assigned it by type.
   457  	if col.Flen == types.UnspecifiedLength {
   458  		col.Flen = mysql.GetDefaultFieldLength(col.Tp)
   459  	}
   460  	if col.Decimal == types.UnspecifiedLength {
   461  		col.Decimal = mysql.GetDefaultDecimal(col.Tp)
   462  	}
   463  
   464  	setOnUpdateNow := false
   465  	hasDefaultValue := false
   466  	if colDef.Options != nil {
   467  		keys := []*ast.IndexColName{
   468  			{
   469  				Column: colDef.Name,
   470  				Length: colDef.Tp.Flen,
   471  			},
   472  		}
   473  		for _, v := range colDef.Options {
   474  			switch v.Tp {
   475  			case ast.ColumnOptionNotNull:
   476  				col.Flag |= mysql.NotNullFlag
   477  			case ast.ColumnOptionNull:
   478  				col.Flag &= ^uint(mysql.NotNullFlag)
   479  				removeOnUpdateNowFlag(col)
   480  			case ast.ColumnOptionAutoIncrement:
   481  				col.Flag |= mysql.AutoIncrementFlag
   482  			case ast.ColumnOptionPrimaryKey:
   483  				constraint := &ast.Constraint{Tp: ast.ConstraintPrimaryKey, Keys: keys}
   484  				constraints = append(constraints, constraint)
   485  				col.Flag |= mysql.PriKeyFlag
   486  			case ast.ColumnOptionUniq:
   487  				constraint := &ast.Constraint{Tp: ast.ConstraintUniq, Name: colDef.Name.Name.O, Keys: keys}
   488  				constraints = append(constraints, constraint)
   489  				col.Flag |= mysql.UniqueKeyFlag
   490  			case ast.ColumnOptionIndex:
   491  				constraint := &ast.Constraint{Tp: ast.ConstraintIndex, Name: colDef.Name.Name.O, Keys: keys}
   492  				constraints = append(constraints, constraint)
   493  			case ast.ColumnOptionUniqIndex:
   494  				constraint := &ast.Constraint{Tp: ast.ConstraintUniqIndex, Name: colDef.Name.Name.O, Keys: keys}
   495  				constraints = append(constraints, constraint)
   496  				col.Flag |= mysql.UniqueKeyFlag
   497  			case ast.ColumnOptionKey:
   498  				constraint := &ast.Constraint{Tp: ast.ConstraintKey, Name: colDef.Name.Name.O, Keys: keys}
   499  				constraints = append(constraints, constraint)
   500  			case ast.ColumnOptionUniqKey:
   501  				constraint := &ast.Constraint{Tp: ast.ConstraintUniqKey, Name: colDef.Name.Name.O, Keys: keys}
   502  				constraints = append(constraints, constraint)
   503  				col.Flag |= mysql.UniqueKeyFlag
   504  			case ast.ColumnOptionDefaultValue:
   505  				value, err := getDefaultValue(ctx, v, colDef.Tp.Tp, colDef.Tp.Decimal)
   506  				if err != nil {
   507  					return nil, nil, ErrColumnBadNull.Gen("invalid default value - %s", err)
   508  				}
   509  				col.DefaultValue = value
   510  				hasDefaultValue = true
   511  				removeOnUpdateNowFlag(col)
   512  			case ast.ColumnOptionOnUpdate:
   513  				if !evaluator.IsCurrentTimeExpr(v.Expr) {
   514  					return nil, nil, ErrInvalidOnUpdate.Gen("invalid ON UPDATE for - %s", col.Name)
   515  				}
   516  
   517  				col.Flag |= mysql.OnUpdateNowFlag
   518  				setOnUpdateNow = true
   519  			case ast.ColumnOptionComment:
   520  				value, err := evaluator.Eval(ctx, v.Expr)
   521  				if err != nil {
   522  					return nil, nil, errors.Trace(err)
   523  				}
   524  				col.Comment, err = value.ToString()
   525  				if err != nil {
   526  					return nil, nil, errors.Trace(err)
   527  				}
   528  			case ast.ColumnOptionFulltext:
   529  				// Do nothing.
   530  			}
   531  		}
   532  	}
   533  
   534  	setTimestampDefaultValue(col, hasDefaultValue, setOnUpdateNow)
   535  
   536  	// Set `NoDefaultValueFlag` if this field doesn't have a default value and
   537  	// it is `not null` and not an `AUTO_INCREMENT` field or `TIMESTAMP` field.
   538  	setNoDefaultValueFlag(col, hasDefaultValue)
   539  
   540  	err := checkDefaultValue(col, hasDefaultValue)
   541  	if err != nil {
   542  		return nil, nil, errors.Trace(err)
   543  	}
   544  	if col.Charset == charset.CharsetBin {
   545  		col.Flag |= mysql.BinaryFlag
   546  	}
   547  	return col, constraints, nil
   548  }
   549  
   550  func getDefaultValue(ctx context.Context, c *ast.ColumnOption, tp byte, fsp int) (interface{}, error) {
   551  	if tp == mysql.TypeTimestamp || tp == mysql.TypeDatetime {
   552  		vd, err := evaluator.GetTimeValue(ctx, c.Expr, tp, fsp)
   553  		value := vd.GetValue()
   554  		if err != nil {
   555  			return nil, errors.Trace(err)
   556  		}
   557  
   558  		// Value is nil means `default null`.
   559  		if value == nil {
   560  			return nil, nil
   561  		}
   562  
   563  		// If value is mysql.Time, convert it to string.
   564  		if vv, ok := value.(mysql.Time); ok {
   565  			return vv.String(), nil
   566  		}
   567  
   568  		return value, nil
   569  	}
   570  	v, err := evaluator.Eval(ctx, c.Expr)
   571  	if err != nil {
   572  		return nil, errors.Trace(err)
   573  	}
   574  	return v.GetValue(), nil
   575  }
   576  
   577  func removeOnUpdateNowFlag(c *column.Col) {
   578  	// For timestamp Col, if it is set null or default value,
   579  	// OnUpdateNowFlag should be removed.
   580  	if mysql.HasTimestampFlag(c.Flag) {
   581  		c.Flag &= ^uint(mysql.OnUpdateNowFlag)
   582  	}
   583  }
   584  
   585  func setTimestampDefaultValue(c *column.Col, hasDefaultValue bool, setOnUpdateNow bool) {
   586  	if hasDefaultValue {
   587  		return
   588  	}
   589  
   590  	// For timestamp Col, if is not set default value or not set null, use current timestamp.
   591  	if mysql.HasTimestampFlag(c.Flag) && mysql.HasNotNullFlag(c.Flag) {
   592  		if setOnUpdateNow {
   593  			c.DefaultValue = evaluator.ZeroTimestamp
   594  		} else {
   595  			c.DefaultValue = evaluator.CurrentTimestamp
   596  		}
   597  	}
   598  }
   599  
   600  func setNoDefaultValueFlag(c *column.Col, hasDefaultValue bool) {
   601  	if hasDefaultValue {
   602  		return
   603  	}
   604  
   605  	if !mysql.HasNotNullFlag(c.Flag) {
   606  		return
   607  	}
   608  
   609  	// Check if it is an `AUTO_INCREMENT` field or `TIMESTAMP` field.
   610  	if !mysql.HasAutoIncrementFlag(c.Flag) && !mysql.HasTimestampFlag(c.Flag) {
   611  		c.Flag |= mysql.NoDefaultValueFlag
   612  	}
   613  }
   614  
   615  func checkDefaultValue(c *column.Col, hasDefaultValue bool) error {
   616  	if !hasDefaultValue {
   617  		return nil
   618  	}
   619  
   620  	if c.DefaultValue != nil {
   621  		return nil
   622  	}
   623  
   624  	// Set not null but default null is invalid.
   625  	if mysql.HasNotNullFlag(c.Flag) {
   626  		return ErrColumnBadNull.Gen("invalid default value for %s", c.Name)
   627  	}
   628  
   629  	return nil
   630  }
   631  
   632  func checkDuplicateColumn(colDefs []*ast.ColumnDef) error {
   633  	colNames := map[string]bool{}
   634  	for _, colDef := range colDefs {
   635  		nameLower := colDef.Name.Name.O
   636  		if colNames[nameLower] {
   637  			return infoschema.ErrColumnExists.Gen("duplicate column %s", colDef.Name)
   638  		}
   639  		colNames[nameLower] = true
   640  	}
   641  	return nil
   642  }
   643  
   644  func checkDuplicateConstraint(namesMap map[string]bool, name string, foreign bool) error {
   645  	if name == "" {
   646  		return nil
   647  	}
   648  	nameLower := strings.ToLower(name)
   649  	if namesMap[nameLower] {
   650  		if foreign {
   651  			return infoschema.ErrForeignKeyExists.Gen("CREATE TABLE: duplicate foreign key %s", name)
   652  		}
   653  		return infoschema.ErrIndexExists.Gen("CREATE TABLE: duplicate key %s", name)
   654  	}
   655  	namesMap[nameLower] = true
   656  	return nil
   657  }
   658  
   659  func setEmptyConstraintName(namesMap map[string]bool, constr *ast.Constraint, foreign bool) {
   660  	if constr.Name == "" && len(constr.Keys) > 0 {
   661  		colName := constr.Keys[0].Column.Name.L
   662  		constrName := colName
   663  		i := 2
   664  		for namesMap[constrName] {
   665  			// We loop forever until we find constrName that haven't been used.
   666  			if foreign {
   667  				constrName = fmt.Sprintf("fk_%s_%d", colName, i)
   668  			} else {
   669  				constrName = fmt.Sprintf("%s_%d", colName, i)
   670  			}
   671  			i++
   672  		}
   673  		constr.Name = constrName
   674  		namesMap[constrName] = true
   675  	}
   676  }
   677  
   678  func (d *ddl) checkConstraintNames(constraints []*ast.Constraint) error {
   679  	constrNames := map[string]bool{}
   680  	fkNames := map[string]bool{}
   681  
   682  	// Check not empty constraint name whether is duplicated.
   683  	for _, constr := range constraints {
   684  		if constr.Tp == ast.ConstraintForeignKey {
   685  			err := checkDuplicateConstraint(fkNames, constr.Name, true)
   686  			if err != nil {
   687  				return errors.Trace(err)
   688  			}
   689  		} else {
   690  			err := checkDuplicateConstraint(constrNames, constr.Name, false)
   691  			if err != nil {
   692  				return errors.Trace(err)
   693  			}
   694  		}
   695  	}
   696  
   697  	// Set empty constraint names.
   698  	for _, constr := range constraints {
   699  		if constr.Tp == ast.ConstraintForeignKey {
   700  			setEmptyConstraintName(fkNames, constr, true)
   701  		} else {
   702  			setEmptyConstraintName(constrNames, constr, false)
   703  		}
   704  	}
   705  
   706  	return nil
   707  }
   708  
   709  func (d *ddl) buildTableInfo(tableName model.CIStr, cols []*column.Col, constraints []*ast.Constraint) (tbInfo *model.TableInfo, err error) {
   710  	tbInfo = &model.TableInfo{
   711  		Name: tableName,
   712  	}
   713  	tbInfo.ID, err = d.genGlobalID()
   714  	if err != nil {
   715  		return nil, errors.Trace(err)
   716  	}
   717  	for _, v := range cols {
   718  		tbInfo.Columns = append(tbInfo.Columns, &v.ColumnInfo)
   719  	}
   720  	for _, constr := range constraints {
   721  		if constr.Tp == ast.ConstraintForeignKey {
   722  			for _, fk := range tbInfo.ForeignKeys {
   723  				if fk.Name.L == strings.ToLower(constr.Name) {
   724  					return nil, infoschema.ErrForeignKeyExists.Gen("foreign key %s already exists.", constr.Name)
   725  				}
   726  			}
   727  			var fk model.FKInfo
   728  			fk.Name = model.NewCIStr(constr.Name)
   729  			fk.RefTable = constr.Refer.Table.Name
   730  			fk.State = model.StatePublic
   731  			for _, key := range constr.Keys {
   732  				fk.Cols = append(fk.Cols, key.Column.Name)
   733  			}
   734  			for _, key := range constr.Refer.IndexColNames {
   735  				fk.RefCols = append(fk.RefCols, key.Column.Name)
   736  			}
   737  			fk.OnDelete = int(constr.Refer.OnDelete.ReferOpt)
   738  			fk.OnUpdate = int(constr.Refer.OnUpdate.ReferOpt)
   739  			if len(fk.Cols) != len(fk.RefCols) {
   740  				return nil, infoschema.ErrForeignKeyNotMatch.Gen("foreign key not match keys len %d, refkeys len %d .", len(fk.Cols), len(fk.RefCols))
   741  			}
   742  			if len(fk.Cols) == 0 {
   743  				return nil, infoschema.ErrForeignKeyNotMatch.Gen("foreign key should have one key at least.")
   744  			}
   745  			tbInfo.ForeignKeys = append(tbInfo.ForeignKeys, &fk)
   746  			continue
   747  		}
   748  		if constr.Tp == ast.ConstraintPrimaryKey {
   749  			if len(constr.Keys) == 1 {
   750  				key := constr.Keys[0]
   751  				col := column.FindCol(cols, key.Column.Name.O)
   752  				if col == nil {
   753  					return nil, infoschema.ErrColumnNotExists.Gen("no such column: %v", key)
   754  				}
   755  				switch col.Tp {
   756  				case mysql.TypeLong, mysql.TypeLonglong:
   757  					tbInfo.PKIsHandle = true
   758  					// Avoid creating index for PK handle column.
   759  					continue
   760  				}
   761  			}
   762  		}
   763  
   764  		// 1. check if the column is exists
   765  		// 2. add index
   766  		indexColumns := make([]*model.IndexColumn, 0, len(constr.Keys))
   767  		for _, key := range constr.Keys {
   768  			col := column.FindCol(cols, key.Column.Name.O)
   769  			if col == nil {
   770  				return nil, infoschema.ErrColumnNotExists.Gen("no such column: %v", key)
   771  			}
   772  			indexColumns = append(indexColumns, &model.IndexColumn{
   773  				Name:   key.Column.Name,
   774  				Offset: col.Offset,
   775  				Length: key.Length,
   776  			})
   777  		}
   778  		idxInfo := &model.IndexInfo{
   779  			Name:    model.NewCIStr(constr.Name),
   780  			Columns: indexColumns,
   781  			State:   model.StatePublic,
   782  		}
   783  		switch constr.Tp {
   784  		case ast.ConstraintPrimaryKey:
   785  			idxInfo.Unique = true
   786  			idxInfo.Primary = true
   787  			idxInfo.Name = model.NewCIStr(column.PrimaryKeyName)
   788  		case ast.ConstraintUniq, ast.ConstraintUniqKey, ast.ConstraintUniqIndex:
   789  			idxInfo.Unique = true
   790  		}
   791  		if constr.Option != nil {
   792  			idxInfo.Comment = constr.Option.Comment
   793  			idxInfo.Tp = constr.Option.Tp
   794  		} else {
   795  			// Use btree as default index type.
   796  			idxInfo.Tp = model.IndexTypeBtree
   797  		}
   798  		idxInfo.ID, err = d.genGlobalID()
   799  		if err != nil {
   800  			return nil, errors.Trace(err)
   801  		}
   802  		tbInfo.Indices = append(tbInfo.Indices, idxInfo)
   803  	}
   804  	return
   805  }
   806  
   807  func (d *ddl) CreateTable(ctx context.Context, ident ast.Ident, colDefs []*ast.ColumnDef,
   808  	constraints []*ast.Constraint, options []*ast.TableOption) (err error) {
   809  	is := d.GetInformationSchema()
   810  	schema, ok := is.SchemaByName(ident.Schema)
   811  	if !ok {
   812  		return infoschema.ErrDatabaseNotExists.Gen("database %s not exists", ident.Schema)
   813  	}
   814  	if is.TableExists(ident.Schema, ident.Name) {
   815  		return errors.Trace(infoschema.ErrTableExists)
   816  	}
   817  	if err = checkDuplicateColumn(colDefs); err != nil {
   818  		return errors.Trace(err)
   819  	}
   820  
   821  	cols, newConstraints, err := d.buildColumnsAndConstraints(ctx, colDefs, constraints)
   822  	if err != nil {
   823  		return errors.Trace(err)
   824  	}
   825  
   826  	err = d.checkConstraintNames(newConstraints)
   827  	if err != nil {
   828  		return errors.Trace(err)
   829  	}
   830  
   831  	tbInfo, err := d.buildTableInfo(ident.Name, cols, newConstraints)
   832  	if err != nil {
   833  		return errors.Trace(err)
   834  	}
   835  
   836  	job := &model.Job{
   837  		SchemaID: schema.ID,
   838  		TableID:  tbInfo.ID,
   839  		Type:     model.ActionCreateTable,
   840  		Args:     []interface{}{tbInfo},
   841  	}
   842  	// Handle Table Options
   843  
   844  	d.handleTableOptions(options, tbInfo, schema.ID)
   845  	err = d.doDDLJob(ctx, job)
   846  	if err == nil {
   847  		if tbInfo.AutoIncID > 1 {
   848  			// Default tableAutoIncID base is 0.
   849  			// If the first id is expected to greater than 1, we need to do rebase.
   850  			d.handleAutoIncID(tbInfo, schema.ID)
   851  		}
   852  	}
   853  	err = d.hook.OnChanged(err)
   854  	return errors.Trace(err)
   855  }
   856  
   857  // If create table with auto_increment option, we should rebase tableAutoIncID value.
   858  func (d *ddl) handleAutoIncID(tbInfo *model.TableInfo, schemaID int64) error {
   859  	alloc := autoid.NewAllocator(d.store, schemaID)
   860  	tbInfo.State = model.StatePublic
   861  	tb, err := table.TableFromMeta(alloc, tbInfo)
   862  	if err != nil {
   863  		return errors.Trace(err)
   864  	}
   865  	// The operation of the minus 1 to make sure that the current value doesn't be used,
   866  	// the next Alloc operation will get this value.
   867  	// Its behavior is consistent with MySQL.
   868  	if err = tb.RebaseAutoID(tbInfo.AutoIncID-1, false); err != nil {
   869  		return errors.Trace(err)
   870  	}
   871  	return nil
   872  }
   873  
   874  // Add create table options into TableInfo.
   875  func (d *ddl) handleTableOptions(options []*ast.TableOption, tbInfo *model.TableInfo, schemaID int64) {
   876  	for _, op := range options {
   877  		switch op.Tp {
   878  		case ast.TableOptionAutoIncrement:
   879  			tbInfo.AutoIncID = int64(op.UintValue)
   880  		case ast.TableOptionComment:
   881  			tbInfo.Comment = op.StrValue
   882  		case ast.TableOptionCharset:
   883  			tbInfo.Charset = op.StrValue
   884  		case ast.TableOptionCollate:
   885  			tbInfo.Charset = op.StrValue
   886  		}
   887  	}
   888  }
   889  
   890  func (d *ddl) AlterTable(ctx context.Context, ident ast.Ident, specs []*ast.AlterTableSpec) (err error) {
   891  	// now we only allow one schema changes at the same time.
   892  	if len(specs) != 1 {
   893  		return errRunMultiSchemaChanges
   894  	}
   895  
   896  	for _, spec := range specs {
   897  		switch spec.Tp {
   898  		case ast.AlterTableAddColumn:
   899  			err = d.AddColumn(ctx, ident, spec)
   900  		case ast.AlterTableDropColumn:
   901  			err = d.DropColumn(ctx, ident, spec.DropColumn.Name)
   902  		case ast.AlterTableDropIndex:
   903  			err = d.DropIndex(ctx, ident, model.NewCIStr(spec.Name))
   904  		case ast.AlterTableAddConstraint:
   905  			constr := spec.Constraint
   906  			switch spec.Constraint.Tp {
   907  			case ast.ConstraintKey, ast.ConstraintIndex:
   908  				err = d.CreateIndex(ctx, ident, false, model.NewCIStr(constr.Name), spec.Constraint.Keys)
   909  			case ast.ConstraintUniq, ast.ConstraintUniqIndex, ast.ConstraintUniqKey:
   910  				err = d.CreateIndex(ctx, ident, true, model.NewCIStr(constr.Name), spec.Constraint.Keys)
   911  			case ast.ConstraintForeignKey:
   912  				err = d.CreateForeignKey(ctx, ident, model.NewCIStr(constr.Name), spec.Constraint.Keys, spec.Constraint.Refer)
   913  			default:
   914  				// nothing to do now.
   915  			}
   916  		case ast.AlterTableDropForeignKey:
   917  			err = d.DropForeignKey(ctx, ident, model.NewCIStr(spec.Name))
   918  		default:
   919  			// nothing to do now.
   920  		}
   921  
   922  		if err != nil {
   923  			return errors.Trace(err)
   924  		}
   925  	}
   926  
   927  	return nil
   928  }
   929  
   930  func checkColumnConstraint(constraints []*ast.ColumnOption) error {
   931  	for _, constraint := range constraints {
   932  		switch constraint.Tp {
   933  		case ast.ColumnOptionAutoIncrement, ast.ColumnOptionPrimaryKey, ast.ColumnOptionUniq, ast.ColumnOptionUniqKey:
   934  			return errUnsupportedAddColumn.Gen("unsupported add column constraint - %v", constraint.Tp)
   935  		}
   936  	}
   937  
   938  	return nil
   939  }
   940  
   941  // AddColumn will add a new column to the table.
   942  func (d *ddl) AddColumn(ctx context.Context, ti ast.Ident, spec *ast.AlterTableSpec) error {
   943  	// Check whether the added column constraints are supported.
   944  	err := checkColumnConstraint(spec.Column.Options)
   945  	if err != nil {
   946  		return errors.Trace(err)
   947  	}
   948  
   949  	is := d.infoHandle.Get()
   950  	schema, ok := is.SchemaByName(ti.Schema)
   951  	if !ok {
   952  		return errors.Trace(infoschema.ErrDatabaseNotExists)
   953  	}
   954  
   955  	t, err := is.TableByName(ti.Schema, ti.Name)
   956  	if err != nil {
   957  		return errors.Trace(infoschema.ErrTableNotExists)
   958  	}
   959  
   960  	// Check whether added column has existed.
   961  	colName := spec.Column.Name.Name.O
   962  	col := column.FindCol(t.Cols(), colName)
   963  	if col != nil {
   964  		return infoschema.ErrColumnExists.Gen("column %s already exists", colName)
   965  	}
   966  
   967  	// ingore table constraints now, maybe return error later
   968  	// we use length(t.Cols()) as the default offset first, later we will change the
   969  	// column's offset later.
   970  	col, _, err = d.buildColumnAndConstraint(ctx, len(t.Cols()), spec.Column)
   971  	if err != nil {
   972  		return errors.Trace(err)
   973  	}
   974  
   975  	job := &model.Job{
   976  		SchemaID: schema.ID,
   977  		TableID:  t.Meta().ID,
   978  		Type:     model.ActionAddColumn,
   979  		Args:     []interface{}{&col.ColumnInfo, spec.Position, 0},
   980  	}
   981  
   982  	err = d.doDDLJob(ctx, job)
   983  	err = d.hook.OnChanged(err)
   984  	return errors.Trace(err)
   985  }
   986  
   987  // DropColumn will drop a column from the table, now we don't support drop the column with index covered.
   988  func (d *ddl) DropColumn(ctx context.Context, ti ast.Ident, colName model.CIStr) error {
   989  	is := d.infoHandle.Get()
   990  	schema, ok := is.SchemaByName(ti.Schema)
   991  	if !ok {
   992  		return errors.Trace(infoschema.ErrDatabaseNotExists)
   993  	}
   994  
   995  	t, err := is.TableByName(ti.Schema, ti.Name)
   996  	if err != nil {
   997  		return errors.Trace(infoschema.ErrTableNotExists)
   998  	}
   999  
  1000  	// Check whether dropped column has existed.
  1001  	col := column.FindCol(t.Cols(), colName.L)
  1002  	if col == nil {
  1003  		return infoschema.ErrColumnNotExists.Gen("column %s doesn’t exist", colName.L)
  1004  	}
  1005  
  1006  	job := &model.Job{
  1007  		SchemaID: schema.ID,
  1008  		TableID:  t.Meta().ID,
  1009  		Type:     model.ActionDropColumn,
  1010  		Args:     []interface{}{colName},
  1011  	}
  1012  
  1013  	err = d.doDDLJob(ctx, job)
  1014  	err = d.hook.OnChanged(err)
  1015  	return errors.Trace(err)
  1016  }
  1017  
  1018  // DropTable will proceed even if some table in the list does not exists.
  1019  func (d *ddl) DropTable(ctx context.Context, ti ast.Ident) (err error) {
  1020  	is := d.GetInformationSchema()
  1021  	schema, ok := is.SchemaByName(ti.Schema)
  1022  	if !ok {
  1023  		return infoschema.ErrDatabaseNotExists.Gen("database %s not exists", ti.Schema)
  1024  	}
  1025  
  1026  	tb, err := is.TableByName(ti.Schema, ti.Name)
  1027  	if err != nil {
  1028  		return errors.Trace(infoschema.ErrTableNotExists)
  1029  	}
  1030  
  1031  	job := &model.Job{
  1032  		SchemaID: schema.ID,
  1033  		TableID:  tb.Meta().ID,
  1034  		Type:     model.ActionDropTable,
  1035  	}
  1036  
  1037  	err = d.doDDLJob(ctx, job)
  1038  	err = d.hook.OnChanged(err)
  1039  	return errors.Trace(err)
  1040  }
  1041  
  1042  func (d *ddl) CreateIndex(ctx context.Context, ti ast.Ident, unique bool, indexName model.CIStr, idxColNames []*ast.IndexColName) error {
  1043  	is := d.infoHandle.Get()
  1044  	schema, ok := is.SchemaByName(ti.Schema)
  1045  	if !ok {
  1046  		return infoschema.ErrDatabaseNotExists.Gen("database %s not exists", ti.Schema)
  1047  	}
  1048  
  1049  	t, err := is.TableByName(ti.Schema, ti.Name)
  1050  	if err != nil {
  1051  		return errors.Trace(infoschema.ErrTableNotExists)
  1052  	}
  1053  	indexID, err := d.genGlobalID()
  1054  	if err != nil {
  1055  		return errors.Trace(err)
  1056  	}
  1057  
  1058  	job := &model.Job{
  1059  		SchemaID: schema.ID,
  1060  		TableID:  t.Meta().ID,
  1061  		Type:     model.ActionAddIndex,
  1062  		Args:     []interface{}{unique, indexName, indexID, idxColNames},
  1063  	}
  1064  
  1065  	err = d.doDDLJob(ctx, job)
  1066  	err = d.hook.OnChanged(err)
  1067  	return errors.Trace(err)
  1068  }
  1069  
  1070  func (d *ddl) buildFKInfo(fkName model.CIStr, keys []*ast.IndexColName, refer *ast.ReferenceDef) (*model.FKInfo, error) {
  1071  	fkID, err := d.genGlobalID()
  1072  	if err != nil {
  1073  		return nil, errors.Trace(err)
  1074  	}
  1075  
  1076  	var fkInfo model.FKInfo
  1077  	fkInfo.ID = fkID
  1078  	fkInfo.Name = fkName
  1079  	fkInfo.RefTable = refer.Table.Name
  1080  
  1081  	fkInfo.Cols = make([]model.CIStr, len(keys))
  1082  	for i, key := range keys {
  1083  		fkInfo.Cols[i] = key.Column.Name
  1084  	}
  1085  
  1086  	fkInfo.RefCols = make([]model.CIStr, len(refer.IndexColNames))
  1087  	for i, key := range refer.IndexColNames {
  1088  		fkInfo.RefCols[i] = key.Column.Name
  1089  	}
  1090  
  1091  	fkInfo.OnDelete = int(refer.OnDelete.ReferOpt)
  1092  	fkInfo.OnUpdate = int(refer.OnUpdate.ReferOpt)
  1093  
  1094  	return &fkInfo, nil
  1095  
  1096  }
  1097  
  1098  func (d *ddl) CreateForeignKey(ctx context.Context, ti ast.Ident, fkName model.CIStr, keys []*ast.IndexColName, refer *ast.ReferenceDef) error {
  1099  	is := d.infoHandle.Get()
  1100  	schema, ok := is.SchemaByName(ti.Schema)
  1101  	if !ok {
  1102  		return infoschema.ErrDatabaseNotExists.Gen("database %s not exists", ti.Schema)
  1103  	}
  1104  
  1105  	t, err := is.TableByName(ti.Schema, ti.Name)
  1106  	if err != nil {
  1107  		return errors.Trace(infoschema.ErrTableNotExists)
  1108  	}
  1109  
  1110  	fkInfo, err := d.buildFKInfo(fkName, keys, refer)
  1111  	if err != nil {
  1112  		return errors.Trace(err)
  1113  	}
  1114  
  1115  	job := &model.Job{
  1116  		SchemaID: schema.ID,
  1117  		TableID:  t.Meta().ID,
  1118  		Type:     model.ActionAddForeignKey,
  1119  		Args:     []interface{}{fkInfo},
  1120  	}
  1121  
  1122  	err = d.doDDLJob(ctx, job)
  1123  	err = d.hook.OnChanged(err)
  1124  	return errors.Trace(err)
  1125  
  1126  }
  1127  
  1128  func (d *ddl) DropForeignKey(ctx context.Context, ti ast.Ident, fkName model.CIStr) error {
  1129  	is := d.infoHandle.Get()
  1130  	schema, ok := is.SchemaByName(ti.Schema)
  1131  	if !ok {
  1132  		return infoschema.ErrDatabaseNotExists.Gen("database %s not exists", ti.Schema)
  1133  	}
  1134  
  1135  	t, err := is.TableByName(ti.Schema, ti.Name)
  1136  	if err != nil {
  1137  		return errors.Trace(infoschema.ErrTableNotExists)
  1138  	}
  1139  
  1140  	job := &model.Job{
  1141  		SchemaID: schema.ID,
  1142  		TableID:  t.Meta().ID,
  1143  		Type:     model.ActionDropForeignKey,
  1144  		Args:     []interface{}{fkName},
  1145  	}
  1146  
  1147  	err = d.doDDLJob(ctx, job)
  1148  	err = d.hook.OnChanged(err)
  1149  	return errors.Trace(err)
  1150  }
  1151  
  1152  func (d *ddl) DropIndex(ctx context.Context, ti ast.Ident, indexName model.CIStr) error {
  1153  	is := d.infoHandle.Get()
  1154  	schema, ok := is.SchemaByName(ti.Schema)
  1155  	if !ok {
  1156  		return errors.Trace(infoschema.ErrDatabaseNotExists)
  1157  	}
  1158  
  1159  	t, err := is.TableByName(ti.Schema, ti.Name)
  1160  	if err != nil {
  1161  		return errors.Trace(infoschema.ErrTableNotExists)
  1162  	}
  1163  
  1164  	job := &model.Job{
  1165  		SchemaID: schema.ID,
  1166  		TableID:  t.Meta().ID,
  1167  		Type:     model.ActionDropIndex,
  1168  		Args:     []interface{}{indexName},
  1169  	}
  1170  
  1171  	err = d.doDDLJob(ctx, job)
  1172  	err = d.hook.OnChanged(err)
  1173  	return errors.Trace(err)
  1174  }
  1175  
  1176  // findCol finds column in cols by name.
  1177  func findCol(cols []*model.ColumnInfo, name string) *model.ColumnInfo {
  1178  	name = strings.ToLower(name)
  1179  	for _, col := range cols {
  1180  		if col.Name.L == name {
  1181  			return col
  1182  		}
  1183  	}
  1184  
  1185  	return nil
  1186  }
  1187  
  1188  // DDL error codes.
  1189  const (
  1190  	codeInvalidWorker         terror.ErrCode = 1
  1191  	codeNotOwner                             = 2
  1192  	codeInvalidDDLJob                        = 3
  1193  	codeInvalidBgJob                         = 4
  1194  	codeInvalidJobFlag                       = 5
  1195  	codeRunMultiSchemaChanges                = 6
  1196  	codeWaitReorgTimeout                     = 7
  1197  	codeInvalidStoreVer                      = 8
  1198  
  1199  	codeInvalidDBState         = 100
  1200  	codeInvalidTableState      = 101
  1201  	codeInvalidColumnState     = 102
  1202  	codeInvalidIndexState      = 103
  1203  	codeInvalidForeignKeyState = 104
  1204  
  1205  	codeCantDropColWithIndex = 201
  1206  	codeUnsupportedAddColumn = 202
  1207  
  1208  	codeBadNull             = 1048
  1209  	codeCantRemoveAllFields = 1090
  1210  	codeCantDropFieldOrKey  = 1091
  1211  	codeInvalidOnUpdate     = 1294
  1212  )
  1213  
  1214  func init() {
  1215  	ddlMySQLERrCodes := map[terror.ErrCode]uint16{
  1216  		codeBadNull:             mysql.ErrBadNull,
  1217  		codeCantRemoveAllFields: mysql.ErrCantRemoveAllFields,
  1218  		codeCantDropFieldOrKey:  mysql.ErrCantDropFieldOrKey,
  1219  		codeInvalidOnUpdate:     mysql.ErrInvalidOnUpdate,
  1220  	}
  1221  	terror.ErrClassToMySQLCodes[terror.ClassDDL] = ddlMySQLERrCodes
  1222  }