github.com/dolthub/go-mysql-server@v0.18.0/sql/rowexec/ddl.go (about)

     1  // Copyright 2023 Dolthub, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package rowexec
    16  
    17  import (
    18  	"bufio"
    19  	"fmt"
    20  	"io"
    21  	"os"
    22  	"strings"
    23  	"time"
    24  
    25  	"github.com/dolthub/vitess/go/mysql"
    26  	"github.com/sirupsen/logrus"
    27  
    28  	"github.com/dolthub/go-mysql-server/internal/similartext"
    29  	"github.com/dolthub/go-mysql-server/sql"
    30  	"github.com/dolthub/go-mysql-server/sql/fulltext"
    31  	"github.com/dolthub/go-mysql-server/sql/mysql_db"
    32  	"github.com/dolthub/go-mysql-server/sql/plan"
    33  	"github.com/dolthub/go-mysql-server/sql/types"
    34  )
    35  
    36  func (b *BaseBuilder) buildAlterAutoIncrement(ctx *sql.Context, n *plan.AlterAutoIncrement, row sql.Row) (sql.RowIter, error) {
    37  	err := b.executeAlterAutoInc(ctx, n)
    38  	if err != nil {
    39  		return nil, err
    40  	}
    41  
    42  	return sql.RowsToRowIter(), nil
    43  }
    44  
    45  func (b *BaseBuilder) buildDropTrigger(ctx *sql.Context, n *plan.DropTrigger, row sql.Row) (sql.RowIter, error) {
    46  	triggerDb, ok := n.Db.(sql.TriggerDatabase)
    47  	if !ok {
    48  		if n.IfExists {
    49  			return rowIterWithOkResultWithZeroRowsAffected(), nil
    50  		} else {
    51  			return nil, sql.ErrTriggerDoesNotExist.New(n.TriggerName)
    52  		}
    53  	}
    54  	err := triggerDb.DropTrigger(ctx, n.TriggerName)
    55  	if n.IfExists && sql.ErrTriggerDoesNotExist.Is(err) {
    56  		return rowIterWithOkResultWithZeroRowsAffected(), nil
    57  	} else if err != nil {
    58  		return nil, err
    59  	}
    60  	return rowIterWithOkResultWithZeroRowsAffected(), nil
    61  }
    62  
    63  func (b *BaseBuilder) buildLoadData(ctx *sql.Context, n *plan.LoadData, row sql.Row) (sql.RowIter, error) {
    64  	var reader io.ReadCloser
    65  	var err error
    66  
    67  	if n.Local {
    68  		_, localInfile, ok := sql.SystemVariables.GetGlobal("local_infile")
    69  		if !ok {
    70  			return nil, fmt.Errorf("error: local_infile variable was not found")
    71  		}
    72  
    73  		if localInfile.(int8) == 0 {
    74  			return nil, fmt.Errorf("local_infile needs to be set to 1 to use LOCAL")
    75  		}
    76  
    77  		reader, err = ctx.LoadInfile(n.File)
    78  		if err != nil {
    79  			return nil, err
    80  		}
    81  	} else {
    82  		_, secureFileDir, ok := sql.SystemVariables.GetGlobal("secure_file_priv")
    83  		if !ok {
    84  			return nil, fmt.Errorf("error: secure_file_priv variable was not found")
    85  		}
    86  
    87  		if err = isUnderSecureFileDir(secureFileDir, n.File); err != nil {
    88  			return nil, sql.ErrLoadDataCannotOpen.New(err.Error())
    89  		}
    90  		file, fileErr := os.Open(n.File)
    91  		if fileErr != nil {
    92  			return nil, sql.ErrLoadDataCannotOpen.New(fileErr.Error())
    93  		}
    94  		reader = file
    95  	}
    96  
    97  	scanner := bufio.NewScanner(reader)
    98  
    99  	// Set the split function for lines.
   100  	scanner.Split(n.SplitLines)
   101  
   102  	// Skip through the lines that need to be ignored.
   103  	for n.IgnoreNum > 0 && scanner.Scan() {
   104  		scanner.Text()
   105  		n.IgnoreNum--
   106  	}
   107  
   108  	if scanner.Err() != nil {
   109  		reader.Close()
   110  		return nil, scanner.Err()
   111  	}
   112  
   113  	sch := n.Schema()
   114  	source := sch[0].Source // Schema will always have at least one column
   115  	columnNames := n.ColumnNames
   116  	if len(columnNames) == 0 {
   117  		columnNames = make([]string, len(sch))
   118  		for i, col := range sch {
   119  			columnNames[i] = col.Name
   120  		}
   121  	}
   122  	fieldToColumnMap := make([]int, len(columnNames))
   123  	for fieldIndex, columnName := range columnNames {
   124  		fieldToColumnMap[fieldIndex] = sch.IndexOf(columnName, source)
   125  	}
   126  
   127  	return &loadDataIter{
   128  		destSch:          n.DestSch,
   129  		reader:           reader,
   130  		scanner:          scanner,
   131  		columnCount:      len(n.ColumnNames), // Needs to be the original column count
   132  		fieldToColumnMap: fieldToColumnMap,
   133  
   134  		fieldsTerminatedBy:  n.FieldsTerminatedBy,
   135  		fieldsEnclosedBy:    n.FieldsEnclosedBy,
   136  		fieldsEnclosedByOpt: n.FieldsEnclosedByOpt,
   137  		fieldsEscapedBy:     n.FieldsEscapedBy,
   138  
   139  		linesTerminatedBy: n.LinesTerminatedBy,
   140  		linesStartingBy:   n.LinesStartingBy,
   141  	}, nil
   142  }
   143  
   144  func (b *BaseBuilder) buildDropConstraint(ctx *sql.Context, n *plan.DropConstraint, row sql.Row) (sql.RowIter, error) {
   145  	// DropConstraint should be replaced by another node type (DropForeignKey, DropCheck, etc.) during analysis,
   146  	// so this is an error
   147  	return nil, fmt.Errorf("%T does not have an execution iterator, this is a bug", n)
   148  }
   149  
   150  func (b *BaseBuilder) buildCreateView(ctx *sql.Context, n *plan.CreateView, row sql.Row) (sql.RowIter, error) {
   151  	registry := ctx.GetViewRegistry()
   152  	if n.IsReplace {
   153  		if dropper, ok := n.Database().(sql.ViewDatabase); ok {
   154  			err := dropper.DropView(ctx, n.Name)
   155  			if err != nil && !sql.ErrViewDoesNotExist.Is(err) {
   156  				return sql.RowsToRowIter(), err
   157  			}
   158  		} else {
   159  			err := registry.Delete(n.Database().Name(), n.Name)
   160  			if err != nil && !sql.ErrViewDoesNotExist.Is(err) {
   161  				return sql.RowsToRowIter(), err
   162  			}
   163  		}
   164  	}
   165  	names, err := n.Database().GetTableNames(ctx)
   166  	if err != nil {
   167  		return nil, err
   168  	}
   169  	for _, name := range names {
   170  		if strings.ToLower(name) == strings.ToLower(n.Name) {
   171  			return nil, sql.ErrTableAlreadyExists.New(n)
   172  		}
   173  	}
   174  
   175  	// TODO: isUpdatable should be defined at CREATE VIEW time
   176  	// isUpdatable := GetIsUpdatableFromCreateView(cv)
   177  	creator, ok := n.Database().(sql.ViewDatabase)
   178  	if ok {
   179  		return rowIterWithOkResultWithZeroRowsAffected(), creator.CreateView(ctx, n.Name, n.Definition.TextDefinition, n.CreateViewString)
   180  	} else {
   181  		return rowIterWithOkResultWithZeroRowsAffected(), registry.Register(n.Database().Name(), n.View())
   182  	}
   183  }
   184  
   185  func (b *BaseBuilder) buildCreateCheck(ctx *sql.Context, n *plan.CreateCheck, row sql.Row) (sql.RowIter, error) {
   186  	err := b.executeCreateCheck(ctx, n)
   187  	if err != nil {
   188  		return nil, err
   189  	}
   190  	return rowIterWithOkResultWithZeroRowsAffected(), nil
   191  }
   192  
   193  func (b *BaseBuilder) buildAlterDefaultSet(ctx *sql.Context, n *plan.AlterDefaultSet, row sql.Row) (sql.RowIter, error) {
   194  	// Grab the table fresh from the database.
   195  	table, err := getTableFromDatabase(ctx, n.Database(), n.Table)
   196  	if err != nil {
   197  		return nil, err
   198  	}
   199  
   200  	alterable, ok := table.(sql.AlterableTable)
   201  	if !ok {
   202  		return nil, sql.ErrAlterTableNotSupported.New(n.Table)
   203  	}
   204  
   205  	if err != nil {
   206  		return nil, err
   207  	}
   208  	loweredColName := strings.ToLower(n.ColumnName)
   209  	var col *sql.Column
   210  	for _, schCol := range alterable.Schema() {
   211  		if strings.ToLower(schCol.Name) == loweredColName {
   212  			col = schCol
   213  			break
   214  		}
   215  	}
   216  	if col == nil {
   217  		return nil, sql.ErrTableColumnNotFound.New(n.Table, n.ColumnName)
   218  	}
   219  	newCol := &(*col)
   220  	newCol.Default = n.Default
   221  	return rowIterWithOkResultWithZeroRowsAffected(), alterable.ModifyColumn(ctx, n.ColumnName, newCol, nil)
   222  }
   223  
   224  func (b *BaseBuilder) buildDropCheck(ctx *sql.Context, n *plan.DropCheck, row sql.Row) (sql.RowIter, error) {
   225  	err := b.executeDropCheck(ctx, n)
   226  	if err != nil {
   227  		return nil, err
   228  	}
   229  	return sql.RowsToRowIter(), nil
   230  }
   231  
   232  func (b *BaseBuilder) buildRenameTable(ctx *sql.Context, n *plan.RenameTable, row sql.Row) (sql.RowIter, error) {
   233  	return n.RowIter(ctx, row)
   234  }
   235  
   236  func (b *BaseBuilder) buildModifyColumn(ctx *sql.Context, n *plan.ModifyColumn, row sql.Row) (sql.RowIter, error) {
   237  	tbl, err := getTableFromDatabase(ctx, n.Database(), n.Table)
   238  	if err != nil {
   239  		return nil, err
   240  	}
   241  
   242  	alterable, ok := tbl.(sql.AlterableTable)
   243  	if !ok {
   244  		return nil, sql.ErrAlterTableNotSupported.New(tbl.Name())
   245  	}
   246  
   247  	if err := n.ValidateDefaultPosition(n.TargetSchema()); err != nil {
   248  		return nil, err
   249  	}
   250  	// MySQL assigns the column's type (which contains the collation) at column creation/modification. If a column has
   251  	// an invalid collation, then one has not been assigned at this point, so we assign it the table's collation. This
   252  	// does not create a reference to the table's collation, which may change at any point, and therefore will have no
   253  	// relation to this column after assignment.
   254  	if collatedType, ok := n.NewColumn().Type.(sql.TypeWithCollation); ok && collatedType.Collation() == sql.Collation_Unspecified {
   255  		n.NewColumn().Type, err = collatedType.WithNewCollation(alterable.Collation())
   256  		if err != nil {
   257  			return nil, err
   258  		}
   259  	}
   260  	for _, col := range n.TargetSchema() {
   261  		if collatedType, ok := col.Type.(sql.TypeWithCollation); ok && collatedType.Collation() == sql.Collation_Unspecified {
   262  			col.Type, err = collatedType.WithNewCollation(alterable.Collation())
   263  			if err != nil {
   264  				return nil, err
   265  			}
   266  		}
   267  	}
   268  
   269  	return &modifyColumnIter{
   270  		m:         n,
   271  		alterable: alterable,
   272  	}, nil
   273  }
   274  
   275  func (b *BaseBuilder) buildSingleDropView(ctx *sql.Context, n *plan.SingleDropView, row sql.Row) (sql.RowIter, error) {
   276  	return sql.RowsToRowIter(), nil
   277  }
   278  
   279  func (b *BaseBuilder) buildCreateIndex(ctx *sql.Context, n *plan.CreateIndex, row sql.Row) (sql.RowIter, error) {
   280  	table, ok := n.Table.(*plan.ResolvedTable)
   281  	if !ok {
   282  		return nil, plan.ErrNotIndexable.New()
   283  	}
   284  
   285  	indexable, err := getIndexableTable(table.Table)
   286  	if err != nil {
   287  		return nil, err
   288  	}
   289  
   290  	var driver sql.IndexDriver
   291  	if n.Driver == "" {
   292  		driver = ctx.GetIndexRegistry().DefaultIndexDriver()
   293  	} else {
   294  		driver = ctx.GetIndexRegistry().IndexDriver(n.Driver)
   295  	}
   296  
   297  	if driver == nil {
   298  		return nil, plan.ErrInvalidIndexDriver.New(n.Driver)
   299  	}
   300  
   301  	columns, exprs, err := GetColumnsAndPrepareExpressions(n.Exprs)
   302  	if err != nil {
   303  		return nil, err
   304  	}
   305  
   306  	for _, e := range exprs {
   307  		if types.IsBlobType(e.Type()) || types.IsJSON(e.Type()) {
   308  			return nil, plan.ErrExprTypeNotIndexable.New(e, e.Type())
   309  		}
   310  	}
   311  
   312  	if ch := getChecksumable(table.Table); ch != nil {
   313  		n.Config[sql.ChecksumKey], err = ch.Checksum()
   314  		if err != nil {
   315  			return nil, err
   316  		}
   317  	}
   318  
   319  	index, err := driver.Create(
   320  		n.CurrentDatabase,
   321  		table.Name(),
   322  		n.Name,
   323  		exprs,
   324  		n.Config,
   325  	)
   326  	if err != nil {
   327  		return nil, err
   328  	}
   329  
   330  	iter, err := indexable.IndexKeyValues(ctx, columns)
   331  	if err != nil {
   332  		return nil, err
   333  	}
   334  
   335  	iter = &EvalPartitionKeyValueIter{
   336  		columns: columns,
   337  		exprs:   exprs,
   338  		iter:    iter,
   339  	}
   340  
   341  	created, ready, err := ctx.GetIndexRegistry().AddIndex(index)
   342  	if err != nil {
   343  		return nil, err
   344  	}
   345  
   346  	log := logrus.WithFields(logrus.Fields{
   347  		"id":     index.ID(),
   348  		"driver": index.Driver(),
   349  	})
   350  
   351  	createIndex := func() {
   352  		createIndex(ctx, log, driver, index, iter, created, ready)
   353  	}
   354  
   355  	log.Info("starting to save the index")
   356  
   357  	createIndex()
   358  
   359  	return sql.RowsToRowIter(), nil
   360  }
   361  
   362  func (b *BaseBuilder) buildDeclareCondition(ctx *sql.Context, n *plan.DeclareCondition, row sql.Row) (sql.RowIter, error) {
   363  	return sql.RowsToRowIter(), nil
   364  }
   365  
   366  func (b *BaseBuilder) buildCreateDB(ctx *sql.Context, n *plan.CreateDB, row sql.Row) (sql.RowIter, error) {
   367  	exists := n.Catalog.HasDatabase(ctx, n.DbName)
   368  	rows := []sql.Row{{types.OkResult{RowsAffected: 1}}}
   369  
   370  	if exists {
   371  		if n.IfNotExists && ctx != nil && ctx.Session != nil {
   372  			ctx.Session.Warn(&sql.Warning{
   373  				Level:   "Note",
   374  				Code:    mysql.ERDbCreateExists,
   375  				Message: fmt.Sprintf("Can't create database %s; database exists ", n.DbName),
   376  			})
   377  
   378  			return sql.RowsToRowIter(rows...), nil
   379  		} else {
   380  			return nil, sql.ErrDatabaseExists.New(n.DbName)
   381  		}
   382  	}
   383  
   384  	collation := n.Collation
   385  	if collation == sql.Collation_Unspecified {
   386  		collation = sql.Collation_Default
   387  	}
   388  	err := n.Catalog.CreateDatabase(ctx, n.DbName, collation)
   389  	if err != nil {
   390  		return nil, err
   391  	}
   392  
   393  	return sql.RowsToRowIter(rows...), nil
   394  }
   395  
   396  func (b *BaseBuilder) buildAlterDefaultDrop(ctx *sql.Context, n *plan.AlterDefaultDrop, row sql.Row) (sql.RowIter, error) {
   397  	table, ok, err := n.Db.GetTableInsensitive(ctx, getTableName(n.Table))
   398  	if err != nil {
   399  		return nil, err
   400  	}
   401  	if !ok {
   402  		return nil, sql.ErrTableNotFound.New(n.Table)
   403  	}
   404  
   405  	alterable, ok := table.(sql.AlterableTable)
   406  	loweredColName := strings.ToLower(n.ColumnName)
   407  	var col *sql.Column
   408  	for _, schCol := range alterable.Schema() {
   409  		if strings.ToLower(schCol.Name) == loweredColName {
   410  			col = schCol
   411  			break
   412  		}
   413  	}
   414  
   415  	if col == nil {
   416  		return nil, sql.ErrTableColumnNotFound.New(getTableName(n.Table), n.ColumnName)
   417  	}
   418  	newCol := &(*col)
   419  	newCol.Default = nil
   420  	return rowIterWithOkResultWithZeroRowsAffected(), alterable.ModifyColumn(ctx, n.ColumnName, newCol, nil)
   421  }
   422  
   423  func (b *BaseBuilder) buildDropView(ctx *sql.Context, n *plan.DropView, row sql.Row) (sql.RowIter, error) {
   424  	for _, child := range n.Children() {
   425  		drop, ok := child.(*plan.SingleDropView)
   426  		if !ok {
   427  			return sql.RowsToRowIter(), plan.ErrDropViewChild.New()
   428  		}
   429  
   430  		if dropper, ok := drop.Database().(sql.ViewDatabase); ok {
   431  			err := dropper.DropView(ctx, drop.ViewName)
   432  			if err != nil {
   433  				allowedError := n.IfExists && sql.ErrViewDoesNotExist.Is(err)
   434  				if !allowedError {
   435  					return sql.RowsToRowIter(), err
   436  				}
   437  			}
   438  		} else {
   439  			err := ctx.GetViewRegistry().Delete(drop.Database().Name(), drop.ViewName)
   440  			allowedError := n.IfExists && sql.ErrViewDoesNotExist.Is(err)
   441  			if !allowedError {
   442  				return sql.RowsToRowIter(), err
   443  			}
   444  		}
   445  	}
   446  
   447  	return sql.RowsToRowIter(), nil
   448  }
   449  
   450  func (b *BaseBuilder) buildAlterUser(ctx *sql.Context, a *plan.AlterUser, _ sql.Row) (sql.RowIter, error) {
   451  	mysqlDb, ok := a.MySQLDb.(*mysql_db.MySQLDb)
   452  	if !ok {
   453  		return nil, sql.ErrDatabaseNotFound.New("mysql")
   454  	}
   455  	editor := mysqlDb.Editor()
   456  	defer editor.Close()
   457  
   458  	user := a.User
   459  	// replace empty host with any host
   460  	if user.UserName.Host == "" {
   461  		user.UserName.Host = "%"
   462  	}
   463  
   464  	userPk := mysql_db.UserPrimaryKey{
   465  		Host: user.UserName.Host,
   466  		User: user.UserName.Name,
   467  	}
   468  	previousUserEntry, ok := editor.GetUser(userPk)
   469  	if !ok {
   470  		if a.IfExists {
   471  			return sql.RowsToRowIter(sql.Row{types.NewOkResult(0)}), nil
   472  		}
   473  		return nil, sql.ErrUserAlterFailure.New(user.UserName.String("'"))
   474  	}
   475  
   476  	plugin := "mysql_native_password"
   477  	password := ""
   478  	if user.Auth1 != nil {
   479  		plugin = user.Auth1.Plugin()
   480  		password = user.Auth1.Password()
   481  	}
   482  	if plugin != "mysql_native_password" {
   483  		if err := mysqlDb.VerifyPlugin(plugin); err != nil {
   484  			return nil, sql.ErrUserAlterFailure.New(err)
   485  		}
   486  	}
   487  
   488  	previousUserEntry.Plugin = plugin
   489  	previousUserEntry.Password = password
   490  	previousUserEntry.PasswordLastChanged = time.Now().UTC()
   491  	editor.PutUser(previousUserEntry)
   492  
   493  	if err := mysqlDb.Persist(ctx, editor); err != nil {
   494  		return nil, err
   495  	}
   496  
   497  	return sql.RowsToRowIter(sql.Row{types.NewOkResult(0)}), nil
   498  }
   499  
   500  func (b *BaseBuilder) buildCreateUser(ctx *sql.Context, n *plan.CreateUser, _ sql.Row) (sql.RowIter, error) {
   501  	mysqlDb, ok := n.MySQLDb.(*mysql_db.MySQLDb)
   502  	if !ok {
   503  		return nil, sql.ErrDatabaseNotFound.New("mysql")
   504  	}
   505  
   506  	editor := mysqlDb.Editor()
   507  	defer editor.Close()
   508  
   509  	for _, user := range n.Users {
   510  		// replace empty host with any host
   511  		if user.UserName.Host == "" {
   512  			user.UserName.Host = "%"
   513  		}
   514  
   515  		userPk := mysql_db.UserPrimaryKey{
   516  			Host: user.UserName.Host,
   517  			User: user.UserName.Name,
   518  		}
   519  		_, ok := editor.GetUser(userPk)
   520  		if ok {
   521  			if n.IfNotExists {
   522  				continue
   523  			}
   524  			return nil, sql.ErrUserCreationFailure.New(user.UserName.String("'"))
   525  		}
   526  
   527  		plugin := "mysql_native_password"
   528  		password := ""
   529  		if user.Auth1 != nil {
   530  			plugin = user.Auth1.Plugin()
   531  			password = user.Auth1.Password()
   532  		}
   533  		if plugin != "mysql_native_password" {
   534  			if err := mysqlDb.VerifyPlugin(plugin); err != nil {
   535  				return nil, sql.ErrUserCreationFailure.New(err)
   536  			}
   537  		}
   538  
   539  		// TODO: attributes should probably not be nil, but setting it to &n.Attribute causes unexpected behavior
   540  		// TODO: validate all of the data
   541  		editor.PutUser(&mysql_db.User{
   542  			User:                user.UserName.Name,
   543  			Host:                user.UserName.Host,
   544  			PrivilegeSet:        mysql_db.NewPrivilegeSet(),
   545  			Plugin:              plugin,
   546  			Password:            password,
   547  			PasswordLastChanged: time.Now().UTC(),
   548  			Locked:              false,
   549  			Attributes:          nil,
   550  			IsRole:              false,
   551  			Identity:            user.Identity,
   552  		})
   553  	}
   554  	if err := mysqlDb.Persist(ctx, editor); err != nil {
   555  		return nil, err
   556  	}
   557  	return rowIterWithOkResultWithZeroRowsAffected(), nil
   558  }
   559  
   560  func (b *BaseBuilder) buildAlterPK(ctx *sql.Context, n *plan.AlterPK, row sql.Row) (sql.RowIter, error) {
   561  	// We need to get the current table from the database because this statement could be one clause in an alter table
   562  	// statement and the table may have changed since the analysis phase
   563  	table, err := getTableFromDatabase(ctx, n.Database(), n.Table)
   564  	if err != nil {
   565  		return nil, err
   566  	}
   567  
   568  	// TODO: these validation checks belong in the analysis phase, not here
   569  	pkAlterable, ok := table.(sql.PrimaryKeyAlterableTable)
   570  	if !ok {
   571  		return nil, plan.ErrNotPrimaryKeyAlterable.New(n.Table)
   572  	}
   573  	if err != nil {
   574  		return nil, err
   575  	}
   576  
   577  	switch n.Action {
   578  	case plan.PrimaryKeyAction_Create:
   579  		if plan.HasPrimaryKeys(pkAlterable) {
   580  			return sql.RowsToRowIter(), sql.ErrMultiplePrimaryKeysDefined.New()
   581  		}
   582  
   583  		for _, c := range n.Columns {
   584  			if !pkAlterable.Schema().Contains(c.Name, pkAlterable.Name()) {
   585  				return sql.RowsToRowIter(), sql.ErrKeyColumnDoesNotExist.New(c.Name)
   586  			}
   587  		}
   588  
   589  		return &createPkIter{
   590  			targetSchema: n.TargetSchema(),
   591  			columns:      n.Columns,
   592  			pkAlterable:  pkAlterable,
   593  			db:           n.Database(),
   594  		}, nil
   595  	case plan.PrimaryKeyAction_Drop:
   596  		return &dropPkIter{
   597  			targetSchema: n.TargetSchema(),
   598  			pkAlterable:  pkAlterable,
   599  			db:           n.Database(),
   600  		}, nil
   601  	default:
   602  		panic("unreachable")
   603  	}
   604  }
   605  
   606  func (b *BaseBuilder) buildDropIndex(ctx *sql.Context, n *plan.DropIndex, row sql.Row) (sql.RowIter, error) {
   607  	db, err := n.Catalog.Database(ctx, n.CurrentDatabase)
   608  	if err != nil {
   609  		return nil, err
   610  	}
   611  
   612  	nn, ok := n.Table.(sql.Nameable)
   613  	if !ok {
   614  		return nil, plan.ErrTableNotNameable.New()
   615  	}
   616  
   617  	table, ok, err := db.GetTableInsensitive(ctx, nn.Name())
   618  
   619  	if err != nil {
   620  		return nil, err
   621  	}
   622  
   623  	if !ok {
   624  		tableNames, err := db.GetTableNames(ctx)
   625  
   626  		if err != nil {
   627  			return nil, err
   628  		}
   629  
   630  		similar := similartext.Find(tableNames, nn.Name())
   631  		return nil, sql.ErrTableNotFound.New(nn.Name() + similar)
   632  	}
   633  
   634  	index := ctx.GetIndexRegistry().Index(db.Name(), n.Name)
   635  	if index == nil {
   636  		return nil, plan.ErrIndexNotFound.New(n.Name, nn.Name(), db.Name())
   637  	}
   638  	ctx.GetIndexRegistry().ReleaseIndex(index)
   639  
   640  	if !ctx.GetIndexRegistry().CanRemoveIndex(index) {
   641  		return nil, plan.ErrIndexNotAvailable.New(n.Name)
   642  	}
   643  
   644  	done, err := ctx.GetIndexRegistry().DeleteIndex(db.Name(), n.Name, true)
   645  	if err != nil {
   646  		return nil, err
   647  	}
   648  
   649  	driver := ctx.GetIndexRegistry().IndexDriver(index.Driver())
   650  	if driver == nil {
   651  		return nil, plan.ErrInvalidIndexDriver.New(index.Driver())
   652  	}
   653  
   654  	<-done
   655  
   656  	partitions, err := table.Partitions(ctx)
   657  	if err != nil {
   658  		return nil, err
   659  	}
   660  
   661  	if err := driver.Delete(index, partitions); err != nil {
   662  		return nil, err
   663  	}
   664  
   665  	return sql.RowsToRowIter(), nil
   666  }
   667  
   668  func (b *BaseBuilder) buildDropProcedure(ctx *sql.Context, n *plan.DropProcedure, row sql.Row) (sql.RowIter, error) {
   669  	procDb, ok := n.Db.(sql.StoredProcedureDatabase)
   670  	if !ok {
   671  		if n.IfExists {
   672  			return rowIterWithOkResultWithZeroRowsAffected(), nil
   673  		} else {
   674  			return nil, sql.ErrStoredProceduresNotSupported.New(n.ProcedureName)
   675  		}
   676  	}
   677  	err := procDb.DropStoredProcedure(ctx, n.ProcedureName)
   678  	if n.IfExists && sql.ErrStoredProcedureDoesNotExist.Is(err) {
   679  		return rowIterWithOkResultWithZeroRowsAffected(), nil
   680  	} else if err != nil {
   681  		return nil, err
   682  	}
   683  	return rowIterWithOkResultWithZeroRowsAffected(), nil
   684  }
   685  
   686  func (b *BaseBuilder) buildDropDB(ctx *sql.Context, n *plan.DropDB, row sql.Row) (sql.RowIter, error) {
   687  	exists := n.Catalog.HasDatabase(ctx, n.DbName)
   688  	if !exists {
   689  		if n.IfExists && ctx != nil && ctx.Session != nil {
   690  			ctx.Session.Warn(&sql.Warning{
   691  				Level:   "Note",
   692  				Code:    mysql.ERDbDropExists,
   693  				Message: fmt.Sprintf("Can't drop database %s; database doesn't exist ", n.DbName),
   694  			})
   695  
   696  			rows := []sql.Row{{types.OkResult{RowsAffected: 0}}}
   697  
   698  			return sql.RowsToRowIter(rows...), nil
   699  		} else {
   700  			return nil, sql.ErrDatabaseNotFound.New(n.DbName)
   701  		}
   702  	}
   703  
   704  	// make sure to notify the EventSchedulerStatus before dropping the database
   705  	if n.EventScheduler != nil {
   706  		n.EventScheduler.RemoveSchemaEvents(n.DbName)
   707  	}
   708  
   709  	err := n.Catalog.RemoveDatabase(ctx, n.DbName)
   710  	if err != nil {
   711  		return nil, err
   712  	}
   713  
   714  	// Unsets the current database. Database name is case-insensitive.
   715  	if strings.ToLower(ctx.GetCurrentDatabase()) == strings.ToLower(n.DbName) {
   716  		ctx.SetCurrentDatabase("")
   717  	}
   718  
   719  	rows := []sql.Row{{types.OkResult{RowsAffected: 1}}}
   720  
   721  	return sql.RowsToRowIter(rows...), nil
   722  }
   723  
   724  func (b *BaseBuilder) buildRenameColumn(ctx *sql.Context, n *plan.RenameColumn, row sql.Row) (sql.RowIter, error) {
   725  	tbl, err := getTableFromDatabase(ctx, n.Database(), n.Table)
   726  	if err != nil {
   727  		return nil, err
   728  	}
   729  
   730  	alterable, ok := tbl.(sql.AlterableTable)
   731  	if !ok {
   732  		return nil, sql.ErrAlterTableNotSupported.New(tbl.Name())
   733  	}
   734  
   735  	idx := n.TargetSchema().IndexOf(n.ColumnName, tbl.Name())
   736  	if idx < 0 {
   737  		return nil, sql.ErrTableColumnNotFound.New(tbl.Name(), n.ColumnName)
   738  	}
   739  
   740  	nc := *n.TargetSchema()[idx]
   741  	nc.Name = n.NewColumnName
   742  	col := &nc
   743  
   744  	if err := updateDefaultsOnColumnRename(ctx, alterable, n.TargetSchema(), strings.ToLower(n.ColumnName), n.NewColumnName); err != nil {
   745  		return nil, err
   746  	}
   747  
   748  	// Update the foreign key columns as well
   749  	if fkTable, ok := alterable.(sql.ForeignKeyTable); ok {
   750  		parentFks, err := fkTable.GetReferencedForeignKeys(ctx)
   751  		if err != nil {
   752  			return nil, err
   753  		}
   754  		fks, err := fkTable.GetDeclaredForeignKeys(ctx)
   755  		if err != nil {
   756  			return nil, err
   757  		}
   758  		if len(parentFks) > 0 || len(fks) > 0 {
   759  			err = handleFkColumnRename(ctx, fkTable, n.Db, n.ColumnName, n.NewColumnName)
   760  			if err != nil {
   761  				return nil, err
   762  			}
   763  		}
   764  	}
   765  
   766  	return rowIterWithOkResultWithZeroRowsAffected(), alterable.ModifyColumn(ctx, n.ColumnName, col, nil)
   767  }
   768  
   769  func (b *BaseBuilder) buildAddColumn(ctx *sql.Context, n *plan.AddColumn, row sql.Row) (sql.RowIter, error) {
   770  	table, err := getTableFromDatabase(ctx, n.Database(), n.Table)
   771  	if err != nil {
   772  		return nil, err
   773  	}
   774  
   775  	alterable, ok := table.(sql.AlterableTable)
   776  	if !ok {
   777  		return nil, sql.ErrAlterTableNotSupported.New(table.Name())
   778  	}
   779  
   780  	tbl := alterable.(sql.Table)
   781  	tblSch := n.TargetSchema()
   782  	if n.Order() != nil && !n.Order().First {
   783  		idx := tblSch.IndexOf(n.Order().AfterColumn, tbl.Name())
   784  		if idx < 0 {
   785  			return nil, sql.ErrTableColumnNotFound.New(tbl.Name(), n.Order().AfterColumn)
   786  		}
   787  	}
   788  
   789  	if err := n.ValidateDefaultPosition(tblSch); err != nil {
   790  		return nil, err
   791  	}
   792  	// MySQL assigns the column's type (which contains the collation) at column creation/modification. If a column has
   793  	// an invalid collation, then one has not been assigned at this point, so we assign it the table's collation. This
   794  	// does not create a reference to the table's collation, which may change at any point, and therefore will have no
   795  	// relation to this column after assignment.
   796  	if collatedType, ok := n.Column().Type.(sql.TypeWithCollation); ok && collatedType.Collation() == sql.Collation_Unspecified {
   797  		n.Column().Type, err = collatedType.WithNewCollation(alterable.Collation())
   798  		if err != nil {
   799  			return nil, err
   800  		}
   801  	}
   802  	for _, col := range n.TargetSchema() {
   803  		if collatedType, ok := col.Type.(sql.TypeWithCollation); ok && collatedType.Collation() == sql.Collation_Unspecified {
   804  			col.Type, err = collatedType.WithNewCollation(alterable.Collation())
   805  			if err != nil {
   806  				return nil, err
   807  			}
   808  		}
   809  	}
   810  
   811  	return &addColumnIter{
   812  		a:         n,
   813  		alterable: alterable,
   814  		b:         b,
   815  	}, nil
   816  }
   817  
   818  func (b *BaseBuilder) buildAlterDB(ctx *sql.Context, n *plan.AlterDB, row sql.Row) (sql.RowIter, error) {
   819  	dbName := n.Database(ctx)
   820  
   821  	if !n.Catalog.HasDatabase(ctx, dbName) {
   822  		return nil, sql.ErrDatabaseNotFound.New(dbName)
   823  	}
   824  	db, err := n.Catalog.Database(ctx, dbName)
   825  	if err != nil {
   826  		return nil, err
   827  	}
   828  	collatedDb, ok := db.(sql.CollatedDatabase)
   829  	if !ok {
   830  		return nil, sql.ErrDatabaseCollationsNotSupported.New(dbName)
   831  	}
   832  
   833  	collation := n.Collation
   834  	if collation == sql.Collation_Unspecified {
   835  		collation = sql.Collation_Default
   836  	}
   837  	if err = collatedDb.SetCollation(ctx, collation); err != nil {
   838  		return nil, err
   839  	}
   840  
   841  	rows := []sql.Row{{types.OkResult{RowsAffected: 1}}}
   842  	return sql.RowsToRowIter(rows...), nil
   843  }
   844  
   845  func (b *BaseBuilder) buildCreateTable(ctx *sql.Context, n *plan.CreateTable, row sql.Row) (sql.RowIter, error) {
   846  	var err error
   847  
   848  	// If it's set to Invalid, then no collation has been explicitly defined
   849  	if n.Collation == sql.Collation_Unspecified {
   850  		n.Collation = plan.GetDatabaseCollation(ctx, n.Db)
   851  		// Need to set each type's collation to the correct type as well
   852  		for _, col := range n.CreateSchema.Schema {
   853  			if collatedType, ok := col.Type.(sql.TypeWithCollation); ok && collatedType.Collation() == sql.Collation_Unspecified {
   854  				col.Type, err = collatedType.WithNewCollation(n.Collation)
   855  				if err != nil {
   856  					return nil, err
   857  				}
   858  			}
   859  		}
   860  	}
   861  
   862  	err = n.ValidateDefaultPosition()
   863  	if err != nil {
   864  		return sql.RowsToRowIter(), err
   865  	}
   866  
   867  	maybePrivDb := n.Db
   868  	if privDb, ok := maybePrivDb.(mysql_db.PrivilegedDatabase); ok {
   869  		maybePrivDb = privDb.Unwrap()
   870  	}
   871  
   872  	if n.Temporary() == plan.IsTempTable {
   873  		creatable, ok := maybePrivDb.(sql.TemporaryTableCreator)
   874  		if !ok {
   875  			return sql.RowsToRowIter(), sql.ErrTemporaryTableNotSupported.New()
   876  		}
   877  		err = creatable.CreateTemporaryTable(ctx, n.Name(), n.CreateSchema, n.Collation)
   878  	} else {
   879  		switch creatable := maybePrivDb.(type) {
   880  		case sql.IndexedTableCreator:
   881  			var pkIdxDef sql.IndexDef
   882  			var hasPkIdxDef bool
   883  			for _, idxDef := range n.IdxDefs {
   884  				if idxDef.Constraint == sql.IndexConstraint_Primary {
   885  					hasPkIdxDef = true
   886  					pkIdxDef = sql.IndexDef{
   887  						Name:       idxDef.IndexName,
   888  						Columns:    idxDef.Columns,
   889  						Constraint: idxDef.Constraint,
   890  						Storage:    idxDef.Using,
   891  						Comment:    idxDef.Comment,
   892  					}
   893  				}
   894  			}
   895  			if hasPkIdxDef {
   896  				err = creatable.CreateIndexedTable(ctx, n.Name(), n.CreateSchema, pkIdxDef, n.Collation)
   897  				if sql.ErrUnsupportedIndexPrefix.Is(err) {
   898  					return sql.RowsToRowIter(), err
   899  				}
   900  			} else {
   901  				creatable, ok := maybePrivDb.(sql.TableCreator)
   902  				if !ok {
   903  					return sql.RowsToRowIter(), sql.ErrCreateTableNotSupported.New(n.Db.Name())
   904  				}
   905  				err = creatable.CreateTable(ctx, n.Name(), n.CreateSchema, n.Collation, n.Comment)
   906  			}
   907  		case sql.TableCreator:
   908  			err = creatable.CreateTable(ctx, n.Name(), n.CreateSchema, n.Collation, n.Comment)
   909  		default:
   910  			return sql.RowsToRowIter(), sql.ErrCreateTableNotSupported.New(n.Db.Name())
   911  		}
   912  	}
   913  
   914  	if err != nil && !(sql.ErrTableAlreadyExists.Is(err) && (n.IfNotExists() == plan.IfNotExists)) {
   915  		return sql.RowsToRowIter(), err
   916  	}
   917  
   918  	if vdb, vok := n.Db.(sql.ViewDatabase); vok {
   919  		_, ok, err := vdb.GetViewDefinition(ctx, n.Name())
   920  		if err != nil {
   921  			return nil, err
   922  		}
   923  		if ok {
   924  			return nil, sql.ErrTableAlreadyExists.New(n.Name())
   925  		}
   926  	}
   927  
   928  	//TODO: in the event that foreign keys or indexes aren't supported, you'll be left with a created table and no foreign keys/indexes
   929  	//this also means that if a foreign key or index fails, you'll only have what was declared up to the failure
   930  	tableNode, ok, err := n.Db.GetTableInsensitive(ctx, n.Name())
   931  	if err != nil {
   932  		return sql.RowsToRowIter(), err
   933  	}
   934  	if !ok {
   935  		return sql.RowsToRowIter(), sql.ErrTableCreatedNotFound.New()
   936  	}
   937  
   938  	var nonPrimaryIdxes []*plan.IndexDefinition
   939  	for _, def := range n.IdxDefs {
   940  		if def.Constraint != sql.IndexConstraint_Primary {
   941  			nonPrimaryIdxes = append(nonPrimaryIdxes, def)
   942  		}
   943  	}
   944  
   945  	if len(nonPrimaryIdxes) > 0 {
   946  		err = createIndexesForCreateTable(ctx, n.Db, tableNode, nonPrimaryIdxes)
   947  		if err != nil {
   948  			return sql.RowsToRowIter(), err
   949  		}
   950  	}
   951  
   952  	if len(n.FkDefs) > 0 {
   953  		err = n.CreateForeignKeys(ctx, tableNode)
   954  		if err != nil {
   955  			return sql.RowsToRowIter(), err
   956  		}
   957  	}
   958  
   959  	if len(n.Checks()) > 0 {
   960  		err = n.CreateChecks(ctx, tableNode)
   961  		if err != nil {
   962  			return sql.RowsToRowIter(), err
   963  		}
   964  	}
   965  
   966  	return rowIterWithOkResultWithZeroRowsAffected(), nil
   967  }
   968  
   969  func createIndexesForCreateTable(ctx *sql.Context, db sql.Database, tableNode sql.Table, idxes []*plan.IndexDefinition) (err error) {
   970  	idxAlterable, ok := tableNode.(sql.IndexAlterableTable)
   971  	if !ok {
   972  		return plan.ErrNotIndexable.New()
   973  	}
   974  
   975  	indexMap := make(map[string]struct{})
   976  	fulltextIndexes := make([]sql.IndexDef, 0, len(idxes))
   977  	for _, idxDef := range idxes {
   978  		indexName := idxDef.IndexName
   979  		// If the name is empty, we create a new name using the columns provided while appending an ascending integer
   980  		// until we get a non-colliding name if the original name (or each preceding name) already exists.
   981  		if indexName == "" {
   982  			indexName = strings.Join(idxDef.ColumnNames(), "")
   983  			if _, ok = indexMap[strings.ToLower(indexName)]; ok {
   984  				for i := 0; true; i++ {
   985  					newIndexName := fmt.Sprintf("%s_%d", indexName, i)
   986  					if _, ok = indexMap[strings.ToLower(newIndexName)]; !ok {
   987  						indexName = newIndexName
   988  						break
   989  					}
   990  				}
   991  			}
   992  		} else if _, ok = indexMap[strings.ToLower(idxDef.IndexName)]; ok {
   993  			return sql.ErrIndexIDAlreadyRegistered.New(idxDef.IndexName)
   994  		}
   995  		// We'll create the Full-Text indexes after all others
   996  		if idxDef.Constraint == sql.IndexConstraint_Fulltext {
   997  			otherDef := idxDef.AsIndexDef()
   998  			otherDef.Name = indexName
   999  			fulltextIndexes = append(fulltextIndexes, otherDef)
  1000  			continue
  1001  		}
  1002  		err := idxAlterable.CreateIndex(ctx, sql.IndexDef{
  1003  			Name:       indexName,
  1004  			Columns:    idxDef.Columns,
  1005  			Constraint: idxDef.Constraint,
  1006  			Storage:    idxDef.Using,
  1007  			Comment:    idxDef.Comment,
  1008  		})
  1009  		if err != nil {
  1010  			return err
  1011  		}
  1012  		indexMap[strings.ToLower(indexName)] = struct{}{}
  1013  	}
  1014  
  1015  	// Evaluate our Full-Text indexes now
  1016  	if len(fulltextIndexes) > 0 {
  1017  		database, ok := db.(fulltext.Database)
  1018  		if !ok {
  1019  			if privDb, ok := db.(mysql_db.PrivilegedDatabase); ok {
  1020  				if database, ok = privDb.Unwrap().(fulltext.Database); !ok {
  1021  					return sql.ErrCreateTableNotSupported.New(db.Name())
  1022  				}
  1023  			} else {
  1024  				return sql.ErrCreateTableNotSupported.New(db.Name())
  1025  			}
  1026  		}
  1027  		if err = fulltext.CreateFulltextIndexes(ctx, database, idxAlterable, nil, fulltextIndexes...); err != nil {
  1028  			return err
  1029  		}
  1030  	}
  1031  
  1032  	return nil
  1033  }
  1034  
  1035  func (b *BaseBuilder) buildCreateProcedure(ctx *sql.Context, n *plan.CreateProcedure, row sql.Row) (sql.RowIter, error) {
  1036  	sqlMode := sql.LoadSqlMode(ctx)
  1037  	return &createProcedureIter{
  1038  		spd: sql.StoredProcedureDetails{
  1039  			Name:            n.Name,
  1040  			CreateStatement: n.CreateProcedureString,
  1041  			CreatedAt:       n.CreatedAt,
  1042  			ModifiedAt:      n.ModifiedAt,
  1043  			SqlMode:         sqlMode.String(),
  1044  		},
  1045  		db: n.Database(),
  1046  	}, nil
  1047  }
  1048  
  1049  func (b *BaseBuilder) buildCreateTrigger(ctx *sql.Context, n *plan.CreateTrigger, row sql.Row) (sql.RowIter, error) {
  1050  	sqlMode := sql.LoadSqlMode(ctx)
  1051  	return &createTriggerIter{
  1052  		definition: sql.TriggerDefinition{
  1053  			Name:            n.TriggerName,
  1054  			CreateStatement: n.CreateTriggerString,
  1055  			CreatedAt:       n.CreatedAt,
  1056  			SqlMode:         sqlMode.String(),
  1057  		},
  1058  		db: n.Database(),
  1059  	}, nil
  1060  }
  1061  
  1062  func (b *BaseBuilder) buildDropColumn(ctx *sql.Context, n *plan.DropColumn, row sql.Row) (sql.RowIter, error) {
  1063  	tbl, err := getTableFromDatabase(ctx, n.Database(), n.Table)
  1064  	if err != nil {
  1065  		return nil, err
  1066  	}
  1067  
  1068  	err = n.Validate(ctx, tbl)
  1069  	if err != nil {
  1070  		return nil, err
  1071  	}
  1072  
  1073  	alterable, ok := tbl.(sql.AlterableTable)
  1074  	if !ok {
  1075  		return nil, sql.ErrAlterTableNotSupported.New(tbl.Name())
  1076  	}
  1077  
  1078  	return &dropColumnIter{
  1079  		d:         n,
  1080  		alterable: alterable,
  1081  	}, nil
  1082  }
  1083  
  1084  func (b *BaseBuilder) buildAlterTableCollation(ctx *sql.Context, n *plan.AlterTableCollation, row sql.Row) (sql.RowIter, error) {
  1085  	tbl, err := getTableFromDatabase(ctx, n.Database(), n.Table)
  1086  	if err != nil {
  1087  		return nil, err
  1088  	}
  1089  
  1090  	alterable, ok := tbl.(sql.CollationAlterableTable)
  1091  	if !ok {
  1092  		return nil, sql.ErrAlterTableCollationNotSupported.New(tbl.Name())
  1093  	}
  1094  
  1095  	return rowIterWithOkResultWithZeroRowsAffected(), alterable.ModifyDefaultCollation(ctx, n.Collation)
  1096  }
  1097  
  1098  func (b *BaseBuilder) buildCreateForeignKey(ctx *sql.Context, n *plan.CreateForeignKey, row sql.Row) (sql.RowIter, error) {
  1099  	if n.FkDef.OnUpdate == sql.ForeignKeyReferentialAction_SetDefault || n.FkDef.OnDelete == sql.ForeignKeyReferentialAction_SetDefault {
  1100  		return nil, sql.ErrForeignKeySetDefault.New()
  1101  	}
  1102  	db, err := n.DbProvider.Database(ctx, n.FkDef.Database)
  1103  	if err != nil {
  1104  		return nil, err
  1105  	}
  1106  	tbl, ok, err := db.GetTableInsensitive(ctx, n.FkDef.Table)
  1107  	if err != nil {
  1108  		return nil, err
  1109  	}
  1110  	if !ok {
  1111  		return nil, sql.ErrTableNotFound.New(n.FkDef.Table)
  1112  	}
  1113  
  1114  	refDb, err := n.DbProvider.Database(ctx, n.FkDef.ParentDatabase)
  1115  	if err != nil {
  1116  		return nil, err
  1117  	}
  1118  	refTbl, ok, err := refDb.GetTableInsensitive(ctx, n.FkDef.ParentTable)
  1119  	if err != nil {
  1120  		return nil, err
  1121  	}
  1122  	if !ok {
  1123  		return nil, sql.ErrTableNotFound.New(n.FkDef.ParentTable)
  1124  	}
  1125  
  1126  	fkTbl, ok := tbl.(sql.ForeignKeyTable)
  1127  	if !ok {
  1128  		return nil, sql.ErrNoForeignKeySupport.New(n.FkDef.Table)
  1129  	}
  1130  	refFkTbl, ok := refTbl.(sql.ForeignKeyTable)
  1131  	if !ok {
  1132  		return nil, sql.ErrNoForeignKeySupport.New(n.FkDef.ParentTable)
  1133  	}
  1134  
  1135  	fkChecks, err := ctx.GetSessionVariable(ctx, "foreign_key_checks")
  1136  	if err != nil {
  1137  		return nil, err
  1138  	}
  1139  
  1140  	err = plan.ResolveForeignKey(ctx, fkTbl, refFkTbl, *n.FkDef, true, fkChecks.(int8) == 1, true)
  1141  	if err != nil {
  1142  		return nil, err
  1143  	}
  1144  
  1145  	return rowIterWithOkResultWithZeroRowsAffected(), nil
  1146  }
  1147  
  1148  func rowIterWithOkResultWithZeroRowsAffected() sql.RowIter {
  1149  	return sql.RowsToRowIter(sql.NewRow(types.NewOkResult(0)))
  1150  }