Skip to content

Commit

Permalink
Merge pull request #785 from dolthub/fulghum/alter-table
Browse files Browse the repository at this point in the history
`ALTER TABLE` support for `ADD COLUMN`, `DROP COLUMN`, and `RENAME COLUMN`
  • Loading branch information
fulghum authored Oct 1, 2024
2 parents 097c2bc + f088074 commit 057c8c7
Show file tree
Hide file tree
Showing 2 changed files with 166 additions and 6 deletions.
85 changes: 79 additions & 6 deletions server/ast/alter_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
}
87 changes: 87 additions & 0 deletions testing/go/alter_table_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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}},
},
},
},
})
}

0 comments on commit 057c8c7

Please sign in to comment.