diff --git a/server/ast/alter_table.go b/server/ast/alter_table.go index 0c2634a2b1..560f3ac8c0 100644 --- a/server/ast/alter_table.go +++ b/server/ast/alter_table.go @@ -70,17 +70,25 @@ func nodeAlterTableCmds( vitessDdlCmds := make([]*vitess.DDL, 0, len(node)) for _, cmd := range node { + var err error + var statement *vitess.DDL switch cmd := cmd.(type) { case *tree.AlterTableAddConstraint: - statement, err := nodeAlterTableAddConstraint(cmd, tableName, ifExists) - if err != nil { - return nil, err - } - vitessDdlCmds = append(vitessDdlCmds, statement) - + statement, err = nodeAlterTableAddConstraint(cmd, tableName, ifExists) + case *tree.AlterTableAddColumn: + statement, err = nodeAlterTableAddColumn(cmd, tableName, ifExists) + case *tree.AlterTableDropColumn: + statement, err = nodeAlterTableDropColumn(cmd, tableName, ifExists) + case *tree.AlterTableRenameColumn: + statement, err = nodeAlterTableRenameColumn(cmd, tableName, ifExists) default: return nil, fmt.Errorf("ALTER TABLE with unsupported command type %T", cmd) } + + if err != nil { + return nil, err + } + vitessDdlCmds = append(vitessDdlCmds, statement) } return vitessDdlCmds, nil @@ -124,3 +132,68 @@ func nodeAlterTableAddConstraint( "definition type %T", node) } } + +// nodeAlterTableAddColumn converts a tree.AlterTableAddColumn instance into an equivalent vitess.DDL instance. +func nodeAlterTableAddColumn(node *tree.AlterTableAddColumn, tableName vitess.TableName, ifExists bool) (*vitess.DDL, error) { + if node.IfNotExists { + return nil, fmt.Errorf("IF NOT EXISTS on a column in an ADD COLUMN statement is not supported yet") + } + + vitessColumnDef, err := nodeColumnTableDef(node.ColumnDef) + if err != nil { + return nil, err + } + + return &vitess.DDL{ + Action: "alter", + ColumnAction: "add", + Table: tableName, + IfExists: ifExists, + Column: vitessColumnDef.Name, + TableSpec: &vitess.TableSpec{ + Columns: []*vitess.ColumnDefinition{ + { + Name: vitessColumnDef.Name, + Type: vitessColumnDef.Type, + }, + }, + }, + }, nil +} + +// nodeAlterTableDropColumn converts a tree.AlterTableDropColumn instance into an equivalent vitess.DDL instance. +func nodeAlterTableDropColumn(node *tree.AlterTableDropColumn, tableName vitess.TableName, ifExists bool) (*vitess.DDL, error) { + if node.IfExists { + return nil, fmt.Errorf("IF EXISTS on a column in a DROP COLUMN statement is not supported yet") + } + + switch node.DropBehavior { + case tree.DropDefault: + case tree.DropRestrict: + return nil, fmt.Errorf("ALTER TABLE DROP COLUMN does not support RESTRICT option") + case tree.DropCascade: + return nil, fmt.Errorf("ALTER TABLE DROP COLUMN does not support CASCADE option") + default: + return nil, fmt.Errorf("ALTER TABLE with unsupported drop behavior %v", node.DropBehavior) + } + + return &vitess.DDL{ + Action: "alter", + ColumnAction: "drop", + Table: tableName, + IfExists: ifExists, + Column: vitess.NewColIdent(node.Column.String()), + }, nil +} + +// nodeAlterTableRenameColumn converts a tree.AlterTableRenameColumn instance into an equivalent vitess.DDL instance. +func nodeAlterTableRenameColumn(node *tree.AlterTableRenameColumn, tableName vitess.TableName, ifExists bool) (*vitess.DDL, error) { + return &vitess.DDL{ + Action: "alter", + ColumnAction: "rename", + Table: tableName, + IfExists: ifExists, + Column: vitess.NewColIdent(node.Column.String()), + ToColumn: vitess.NewColIdent(node.NewName.String()), + }, nil +} diff --git a/testing/go/alter_table_test.go b/testing/go/alter_table_test.go index 87165959af..b5858fc3ca 100644 --- a/testing/go/alter_table_test.go +++ b/testing/go/alter_table_test.go @@ -110,3 +110,90 @@ func TestAlterTableAddPrimaryKey(t *testing.T) { }, }) } + +func TestAlterTableAddColumn(t *testing.T) { + RunScripts(t, []ScriptTest{ + { + Name: "Add Column", + SetUpScript: []string{ + "CREATE TABLE test1 (a INT, b INT);", + "INSERT INTO test1 VALUES (1, 1);", + }, + Assertions: []ScriptTestAssertion{ + { + Query: "ALTER TABLE test1 ADD COLUMN c INT NOT NULL DEFAULT 42;", + Expected: []sql.Row{}, + }, + { + Query: "select * from test1;", + Expected: []sql.Row{{1, 1, 42}}, + }, + }, + }, + }) +} + +func TestAlterTableDropColumn(t *testing.T) { + RunScripts(t, []ScriptTest{ + { + Name: "Drop Column", + SetUpScript: []string{ + "CREATE TABLE test1 (a INT, b INT, c INT, d INT);", + "INSERT INTO test1 VALUES (1, 2, 3, 4);", + }, + Assertions: []ScriptTestAssertion{ + { + Query: "ALTER TABLE test1 DROP COLUMN c;", + Expected: []sql.Row{}, + }, + { + Query: "select * from test1;", + Expected: []sql.Row{{1, 2, 4}}, + }, + { + Query: "ALTER TABLE test1 DROP COLUMN d;", + Expected: []sql.Row{}, + }, + { + Query: "select * from test1;", + Expected: []sql.Row{{1, 2}}, + }, + { + // TODO: Skipped until we support conditional execution on existence of column + Skip: true, + Query: "ALTER TABLE test1 DROP COLUMN IF EXISTS zzz;", + Expected: []sql.Row{}, + }, + { + // TODO: Even though we're setting IF EXISTS, this query still fails with an + // error about the table not existing. + Skip: true, + Query: "ALTER TABLE IF EXISTS doesNotExist DROP COLUMN z;", + Expected: []sql.Row{}, + }, + }, + }, + }) +} + +func TestAlterTableRenameColumn(t *testing.T) { + RunScripts(t, []ScriptTest{ + { + Name: "Rename Column", + SetUpScript: []string{ + "CREATE TABLE test1 (a INT, b INT, c INT, d INT);", + "INSERT INTO test1 VALUES (1, 2, 3, 4);", + }, + Assertions: []ScriptTestAssertion{ + { + Query: "ALTER TABLE test1 RENAME COLUMN c to jjj;", + Expected: []sql.Row{}, + }, + { + Query: "select * from test1 where jjj=3;", + Expected: []sql.Row{{1, 2, 3, 4}}, + }, + }, + }, + }) +}