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 }