github.com/dolthub/go-mysql-server@v0.18.0/sql/plan/ddl.go (about) 1 // Copyright 2020-2021 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 plan 16 17 import ( 18 "fmt" 19 "strings" 20 21 "github.com/dolthub/go-mysql-server/sql/transform" 22 23 "github.com/dolthub/go-mysql-server/sql" 24 "github.com/dolthub/go-mysql-server/sql/types" 25 ) 26 27 type IfNotExistsOption bool 28 29 const ( 30 IfNotExists IfNotExistsOption = true 31 IfNotExistsAbsent IfNotExistsOption = false 32 ) 33 34 type TempTableOption bool 35 36 const ( 37 IsTempTable TempTableOption = true 38 IsTempTableAbsent TempTableOption = false 39 ) 40 41 // Ddl nodes have a reference to a database, but no children and a nil schema. 42 type ddlNode struct { 43 Db sql.Database 44 } 45 46 // Resolved implements the Resolvable interface. 47 func (c *ddlNode) Resolved() bool { 48 _, ok := c.Db.(sql.UnresolvedDatabase) 49 return !ok 50 } 51 52 // Database implements the sql.Databaser interface. 53 func (c *ddlNode) Database() sql.Database { 54 return c.Db 55 } 56 57 // Schema implements the Node interface. 58 func (*ddlNode) Schema() sql.Schema { 59 return types.OkResultSchema 60 } 61 62 // Children implements the Node interface. 63 func (c *ddlNode) Children() []sql.Node { return nil } 64 65 type IndexDefinition struct { 66 IndexName string 67 Using sql.IndexUsing 68 Constraint sql.IndexConstraint 69 Columns []sql.IndexColumn 70 Comment string 71 } 72 73 func (i *IndexDefinition) String() string { 74 return i.IndexName 75 } 76 77 func (i *IndexDefinition) IsSpatial() bool { 78 return i.Constraint == sql.IndexConstraint_Spatial 79 } 80 81 func (i *IndexDefinition) IsUnique() bool { 82 return i.Constraint == sql.IndexConstraint_Unique 83 } 84 85 func (i *IndexDefinition) IsFullText() bool { 86 return i.Constraint == sql.IndexConstraint_Fulltext 87 } 88 89 // ColumnNames returns each column's name without the length property. 90 func (i *IndexDefinition) ColumnNames() []string { 91 colNames := make([]string, len(i.Columns)) 92 for i, col := range i.Columns { 93 colNames[i] = col.Name 94 } 95 return colNames 96 } 97 98 // AsIndexDef returns the IndexDefinition as the other form. 99 func (i *IndexDefinition) AsIndexDef() sql.IndexDef { 100 //TODO: We should get rid of this IndexDefinition and just use the SQL package one 101 cols := make([]sql.IndexColumn, len(i.Columns)) 102 copy(cols, i.Columns) 103 return sql.IndexDef{ 104 Name: i.IndexName, 105 Columns: cols, 106 Constraint: i.Constraint, 107 Storage: i.Using, 108 Comment: i.Comment, 109 } 110 } 111 112 // TableSpec is a node describing the schema of a table. 113 type TableSpec struct { 114 Schema sql.PrimaryKeySchema 115 FkDefs []*sql.ForeignKeyConstraint 116 ChDefs []*sql.CheckConstraint 117 IdxDefs []*IndexDefinition 118 Collation sql.CollationID 119 Comment string 120 } 121 122 func (c *TableSpec) WithSchema(schema sql.PrimaryKeySchema) *TableSpec { 123 nc := *c 124 nc.Schema = schema 125 return &nc 126 } 127 128 func (c *TableSpec) WithForeignKeys(fkDefs []*sql.ForeignKeyConstraint) *TableSpec { 129 nc := *c 130 nc.FkDefs = fkDefs 131 return &nc 132 } 133 134 func (c *TableSpec) WithCheckConstraints(chDefs []*sql.CheckConstraint) *TableSpec { 135 nc := *c 136 nc.ChDefs = chDefs 137 return &nc 138 } 139 140 func (c *TableSpec) WithIndices(idxDefs []*IndexDefinition) *TableSpec { 141 nc := *c 142 nc.IdxDefs = idxDefs 143 return &nc 144 } 145 146 // CreateTable is a node describing the creation of some table. 147 type CreateTable struct { 148 ddlNode 149 name string 150 CreateSchema sql.PrimaryKeySchema 151 ifNotExists IfNotExistsOption 152 FkDefs []*sql.ForeignKeyConstraint 153 fkParentTbls []sql.ForeignKeyTable 154 checks sql.CheckConstraints 155 IdxDefs []*IndexDefinition 156 Collation sql.CollationID 157 Comment string 158 like sql.Node 159 temporary TempTableOption 160 selectNode sql.Node 161 } 162 163 var _ sql.Databaser = (*CreateTable)(nil) 164 var _ sql.Node = (*CreateTable)(nil) 165 var _ sql.Expressioner = (*CreateTable)(nil) 166 var _ sql.SchemaTarget = (*CreateTable)(nil) 167 var _ sql.CheckConstraintNode = (*CreateTable)(nil) 168 var _ sql.CollationCoercible = (*CreateTable)(nil) 169 170 // NewCreateTable creates a new CreateTable node 171 func NewCreateTable(db sql.Database, name string, ifn IfNotExistsOption, temp TempTableOption, tableSpec *TableSpec) *CreateTable { 172 for _, s := range tableSpec.Schema.Schema { 173 s.Source = name 174 } 175 176 return &CreateTable{ 177 ddlNode: ddlNode{db}, 178 name: name, 179 CreateSchema: tableSpec.Schema, 180 FkDefs: tableSpec.FkDefs, 181 checks: tableSpec.ChDefs, 182 IdxDefs: tableSpec.IdxDefs, 183 Collation: tableSpec.Collation, 184 Comment: tableSpec.Comment, 185 ifNotExists: ifn, 186 temporary: temp, 187 } 188 } 189 190 // NewCreateTableSelect create a new CreateTable node for CREATE TABLE [AS] SELECT 191 func NewCreateTableSelect(db sql.Database, name string, selectNode sql.Node, tableSpec *TableSpec, ifn IfNotExistsOption, temp TempTableOption) *CreateTable { 192 for _, s := range tableSpec.Schema.Schema { 193 s.Source = name 194 } 195 196 return &CreateTable{ 197 ddlNode: ddlNode{Db: db}, 198 CreateSchema: tableSpec.Schema, 199 FkDefs: tableSpec.FkDefs, 200 checks: tableSpec.ChDefs, 201 IdxDefs: tableSpec.IdxDefs, 202 name: name, 203 selectNode: selectNode, 204 ifNotExists: ifn, 205 temporary: temp, 206 } 207 } 208 209 func (c *CreateTable) Checks() sql.CheckConstraints { 210 return c.checks 211 } 212 213 func (c *CreateTable) WithChecks(checks sql.CheckConstraints) sql.Node { 214 ret := *c 215 ret.checks = checks 216 return &ret 217 } 218 219 // WithTargetSchema implements the sql.TargetSchema interface. 220 func (c *CreateTable) WithTargetSchema(schema sql.Schema) (sql.Node, error) { 221 return nil, fmt.Errorf("unable to set target schema without primary key info") 222 } 223 224 // TargetSchema implements the sql.TargetSchema interface. 225 func (c *CreateTable) TargetSchema() sql.Schema { 226 return c.CreateSchema.Schema 227 } 228 229 // WithDatabase implements the sql.Databaser interface. 230 func (c *CreateTable) WithDatabase(db sql.Database) (sql.Node, error) { 231 nc := *c 232 nc.Db = db 233 return &nc, nil 234 } 235 236 // Schema implements the sql.Node interface. 237 func (c *CreateTable) Schema() sql.Schema { 238 return types.OkResultSchema 239 } 240 241 func (c *CreateTable) PkSchema() sql.PrimaryKeySchema { 242 return c.CreateSchema 243 } 244 245 // Resolved implements the Resolvable interface. 246 func (c *CreateTable) Resolved() bool { 247 if !c.ddlNode.Resolved() || !c.CreateSchema.Schema.Resolved() { 248 return false 249 } 250 251 for _, chDef := range c.checks { 252 if !chDef.Expr.Resolved() { 253 return false 254 } 255 } 256 257 if c.like != nil { 258 if !c.like.Resolved() { 259 return false 260 } 261 } 262 263 return true 264 } 265 266 func (c *CreateTable) IsReadOnly() bool { 267 return false 268 } 269 270 // ForeignKeys returns any foreign keys that will be declared on this table. 271 func (c *CreateTable) ForeignKeys() []*sql.ForeignKeyConstraint { 272 return c.FkDefs 273 } 274 275 // WithParentForeignKeyTables adds the tables that are referenced in each foreign key. The table indices is assumed 276 // to match the foreign key indices in their respective slices. 277 func (c *CreateTable) WithParentForeignKeyTables(refTbls []sql.ForeignKeyTable) (*CreateTable, error) { 278 if len(c.FkDefs) != len(refTbls) { 279 return nil, fmt.Errorf("table `%s` defines `%d` foreign keys but found `%d` referenced tables", 280 c.name, len(c.FkDefs), len(refTbls)) 281 } 282 nc := *c 283 nc.fkParentTbls = refTbls 284 return &nc, nil 285 } 286 287 func (c *CreateTable) CreateForeignKeys(ctx *sql.Context, tableNode sql.Table) error { 288 fkTbl, ok := tableNode.(sql.ForeignKeyTable) 289 if !ok { 290 return sql.ErrNoForeignKeySupport.New(c.name) 291 } 292 293 fkChecks, err := ctx.GetSessionVariable(ctx, "foreign_key_checks") 294 if err != nil { 295 return err 296 } 297 298 for i, fkDef := range c.FkDefs { 299 if fkDef.OnUpdate == sql.ForeignKeyReferentialAction_SetDefault || fkDef.OnDelete == sql.ForeignKeyReferentialAction_SetDefault { 300 return sql.ErrForeignKeySetDefault.New() 301 } 302 303 if fkChecks.(int8) == 1 { 304 fkParentTbl := c.fkParentTbls[i] 305 // If a foreign key is self-referential then the analyzer uses a nil since the table does not yet exist 306 if fkParentTbl == nil { 307 fkParentTbl = fkTbl 308 } 309 // If foreign_key_checks are true, then the referenced tables will be populated 310 err = ResolveForeignKey(ctx, fkTbl, fkParentTbl, *fkDef, true, true, true) 311 if err != nil { 312 return err 313 } 314 } else { 315 // If foreign_key_checks are true, then the referenced tables will be populated 316 err = ResolveForeignKey(ctx, fkTbl, nil, *fkDef, true, false, false) 317 if err != nil { 318 return err 319 } 320 } 321 } 322 323 return nil 324 } 325 326 func (c *CreateTable) CreateChecks(ctx *sql.Context, tableNode sql.Table) error { 327 chAlterable, ok := tableNode.(sql.CheckAlterableTable) 328 if !ok { 329 return ErrNoCheckConstraintSupport.New(c.name) 330 } 331 332 for _, ch := range c.checks { 333 check, err := NewCheckDefinition(ctx, ch) 334 if err != nil { 335 return err 336 } 337 err = chAlterable.CreateCheck(ctx, check) 338 if err != nil { 339 return err 340 } 341 } 342 343 return nil 344 } 345 346 // Children implements the Node interface. 347 func (c *CreateTable) Children() []sql.Node { 348 if c.like != nil { 349 return []sql.Node{c.like} 350 } else if c.selectNode != nil { 351 return []sql.Node{c.selectNode} 352 } 353 return nil 354 } 355 356 // WithChildren implements the Node interface. 357 func (c CreateTable) WithChildren(children ...sql.Node) (sql.Node, error) { 358 if len(children) == 0 { 359 return &c, nil 360 } else if len(children) == 1 { 361 child := children[0] 362 363 if c.like != nil { 364 c.like = child 365 } else { 366 c.selectNode = child 367 } 368 369 return &c, nil 370 } else { 371 return nil, sql.ErrInvalidChildrenNumber.New(c, len(children), 1) 372 } 373 } 374 375 // CheckPrivileges implements the interface sql.Node. 376 func (c *CreateTable) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool { 377 priv := sql.PrivilegeType_Create 378 if c.temporary == IsTempTable { 379 priv = sql.PrivilegeType_CreateTempTable 380 } 381 subject := sql.PrivilegeCheckSubject{Database: CheckPrivilegeNameForDatabase(c.Db)} 382 return opChecker.UserHasPrivileges(ctx, sql.NewPrivilegedOperation(subject, priv)) 383 } 384 385 // CollationCoercibility implements the interface sql.CollationCoercible. 386 func (*CreateTable) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 387 return sql.Collation_binary, 7 388 } 389 390 func (c *CreateTable) String() string { 391 ifNotExists := "" 392 if c.ifNotExists { 393 ifNotExists = "if not exists " 394 } 395 return fmt.Sprintf("Create table %s%s", ifNotExists, c.name) 396 } 397 398 func (c *CreateTable) DebugString() string { 399 ifNotExists := "" 400 if c.ifNotExists { 401 ifNotExists = "if not exists " 402 } 403 p := sql.NewTreePrinter() 404 405 if c.selectNode != nil { 406 p.WriteNode("Create table %s%s as", ifNotExists, c.name) 407 p.WriteChildren(sql.DebugString(c.selectNode)) 408 return p.String() 409 } 410 411 p.WriteNode("Create table %s%s", ifNotExists, c.name) 412 413 var children []string 414 children = append(children, c.schemaDebugString()) 415 416 if len(c.FkDefs) > 0 { 417 children = append(children, c.foreignKeysDebugString()) 418 } 419 if len(c.IdxDefs) > 0 { 420 children = append(children, c.indexesDebugString()) 421 } 422 if len(c.checks) > 0 { 423 children = append(children, c.checkConstraintsDebugString()) 424 } 425 426 p.WriteChildren(children...) 427 return p.String() 428 } 429 430 func (c *CreateTable) foreignKeysDebugString() string { 431 p := sql.NewTreePrinter() 432 p.WriteNode("ForeignKeys") 433 var children []string 434 for _, def := range c.FkDefs { 435 children = append(children, sql.DebugString(def)) 436 } 437 p.WriteChildren(children...) 438 return p.String() 439 } 440 441 func (c *CreateTable) indexesDebugString() string { 442 p := sql.NewTreePrinter() 443 p.WriteNode("Indexes") 444 var children []string 445 for _, def := range c.IdxDefs { 446 children = append(children, sql.DebugString(def)) 447 } 448 p.WriteChildren(children...) 449 return p.String() 450 } 451 452 func (c *CreateTable) checkConstraintsDebugString() string { 453 p := sql.NewTreePrinter() 454 p.WriteNode("CheckConstraints") 455 var children []string 456 for _, def := range c.checks { 457 children = append(children, sql.DebugString(def)) 458 } 459 p.WriteChildren(children...) 460 return p.String() 461 } 462 463 func (c *CreateTable) schemaDebugString() string { 464 p := sql.NewTreePrinter() 465 p.WriteNode("Columns") 466 var children []string 467 for _, col := range c.CreateSchema.Schema { 468 children = append(children, sql.DebugString(col)) 469 } 470 p.WriteChildren(children...) 471 return p.String() 472 } 473 474 func (c *CreateTable) Expressions() []sql.Expression { 475 exprs := transform.WrappedColumnDefaults(c.CreateSchema.Schema) 476 477 for _, ch := range c.checks { 478 exprs = append(exprs, ch.Expr) 479 } 480 481 return exprs 482 } 483 484 func (c *CreateTable) Like() sql.Node { 485 return c.like 486 } 487 488 func (c *CreateTable) Select() sql.Node { 489 return c.selectNode 490 } 491 492 func (c *CreateTable) TableSpec() *TableSpec { 493 tableSpec := TableSpec{} 494 495 ret := tableSpec.WithSchema(c.CreateSchema) 496 ret = ret.WithForeignKeys(c.FkDefs) 497 ret = ret.WithIndices(c.IdxDefs) 498 ret = ret.WithCheckConstraints(c.checks) 499 ret.Collation = c.Collation 500 ret.Comment = c.Comment 501 502 return ret 503 } 504 505 func (c *CreateTable) Name() string { 506 return c.name 507 } 508 509 func (c *CreateTable) IfNotExists() IfNotExistsOption { 510 return c.ifNotExists 511 } 512 513 func (c *CreateTable) Temporary() TempTableOption { 514 return c.temporary 515 } 516 517 func (c CreateTable) WithExpressions(exprs ...sql.Expression) (sql.Node, error) { 518 schemaLen := len(c.CreateSchema.Schema) 519 length := schemaLen + len(c.checks) 520 if len(exprs) != length { 521 return nil, sql.ErrInvalidChildrenNumber.New(c, len(exprs), length) 522 } 523 524 nc := c 525 526 // Make sure to make a deep copy of any slices here so we aren't modifying the original pointer 527 ns, err := transform.SchemaWithDefaults(c.CreateSchema.Schema, exprs[:schemaLen]) 528 if err != nil { 529 return nil, err 530 } 531 532 nc.CreateSchema = sql.NewPrimaryKeySchema(ns, c.CreateSchema.PkOrdinals...) 533 534 ncd, err := c.checks.FromExpressions(exprs[schemaLen:]) 535 if err != nil { 536 return nil, err 537 } 538 539 nc.checks = ncd 540 return &nc, nil 541 } 542 543 func (c *CreateTable) ValidateDefaultPosition() error { 544 colsAfterThis := make(map[string]*sql.Column) 545 for i := len(c.CreateSchema.Schema) - 1; i >= 0; i-- { 546 col := c.CreateSchema.Schema[i] 547 colsAfterThis[col.Name] = col 548 if err := inspectDefaultForInvalidColumns(col, colsAfterThis); err != nil { 549 return err 550 } 551 } 552 553 return nil 554 } 555 556 // DropTable is a node describing dropping one or more tables 557 type DropTable struct { 558 Tables []sql.Node 559 ifExists bool 560 TriggerNames []string 561 } 562 563 var _ sql.Node = (*DropTable)(nil) 564 var _ sql.CollationCoercible = (*DropTable)(nil) 565 566 // NewDropTable creates a new DropTable node 567 func NewDropTable(tbls []sql.Node, ifExists bool) *DropTable { 568 return &DropTable{ 569 Tables: tbls, 570 ifExists: ifExists, 571 } 572 } 573 574 // WithTriggers returns this node but with the given triggers. 575 func (d *DropTable) WithTriggers(triggers []string) sql.Node { 576 nd := *d 577 nd.TriggerNames = triggers 578 return &nd 579 } 580 581 // TableNames returns the names of the tables to drop. 582 func (d *DropTable) TableNames() ([]string, error) { 583 tblNames := make([]string, len(d.Tables)) 584 for i, t := range d.Tables { 585 // either *ResolvedTable OR *UnresolvedTable here 586 if uTable, ok := t.(*UnresolvedTable); ok { 587 tblNames[i] = uTable.Name() 588 } else if rTable, ok := t.(*ResolvedTable); ok { 589 tblNames[i] = rTable.Name() 590 } else { 591 return []string{}, sql.ErrInvalidType.New(t) 592 } 593 } 594 return tblNames, nil 595 } 596 597 // IfExists returns ifExists variable. 598 func (d *DropTable) IfExists() bool { 599 return d.ifExists 600 } 601 602 // Children implements the Node interface. 603 func (d *DropTable) Children() []sql.Node { 604 return d.Tables 605 } 606 607 // Resolved implements the sql.Expression interface. 608 func (d *DropTable) Resolved() bool { 609 for _, table := range d.Tables { 610 if !table.Resolved() { 611 return false 612 } 613 } 614 615 return true 616 } 617 618 func (d *DropTable) IsReadOnly() bool { 619 return false 620 } 621 622 // Schema implements the sql.Expression interface. 623 func (d *DropTable) Schema() sql.Schema { 624 return types.OkResultSchema 625 } 626 627 // WithChildren implements the Node interface. 628 func (d *DropTable) WithChildren(children ...sql.Node) (sql.Node, error) { 629 // Number of children can be smaller than original as the non-existent 630 // tables get filtered out in some cases 631 var newChildren = make([]sql.Node, len(children)) 632 copy(newChildren, children) 633 nd := *d 634 nd.Tables = newChildren 635 return &nd, nil 636 } 637 638 // CheckPrivileges implements the interface sql.Node. 639 func (d *DropTable) CheckPrivileges(ctx *sql.Context, opChecker sql.PrivilegedOperationChecker) bool { 640 for _, tbl := range d.Tables { 641 subject := sql.PrivilegeCheckSubject{ 642 Database: CheckPrivilegeNameForDatabase(GetDatabase(tbl)), 643 Table: getTableName(tbl), 644 } 645 646 if !opChecker.UserHasPrivileges(ctx, sql.NewPrivilegedOperation(subject, sql.PrivilegeType_Drop)) { 647 return false 648 } 649 } 650 return true 651 } 652 653 // CollationCoercibility implements the interface sql.CollationCoercible. 654 func (*DropTable) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 655 return sql.Collation_binary, 7 656 } 657 658 // String implements the sql.Node interface. 659 func (d *DropTable) String() string { 660 ifExists := "" 661 tblNames, _ := d.TableNames() 662 names := strings.Join(tblNames, ", ") 663 if d.ifExists { 664 ifExists = "if exists " 665 } 666 return fmt.Sprintf("Drop table %s%s", ifExists, names) 667 }