提交 03ef250f authored 作者: noelgrandin's avatar noelgrandin

Contribution from Steve McLeod steve.mcleod@gmail.com

Modify ALTER TABLE ADD to support adding multiple columns in one command.
上级 51fef277
......@@ -211,8 +211,9 @@ ALTER SEQUENCE SEQ_ID RESTART WITH 1000
"
"Commands (DDL)","ALTER TABLE ADD","
ALTER TABLE tableName ADD [ IF NOT EXISTS ] name dataType [ DEFAULT expression ]
[ [ NOT ] NULL ] [ AUTO_INCREMENT | IDENTITY ] [ BEFORE columnName ]
ALTER TABLE tableName ADD [ COLUMN ]
{ [ IF NOT EXISTS ] columnDefinition [ BEFORE columnName ]
| ( { columnDefinition } [,...] ) }
","
Adds a new column to a table.
This command commits an open transaction.
......
......@@ -18,7 +18,8 @@ Change Log
<h1>Change Log</h1>
<h2>Next Version (unreleased)</h2>
<ul><li>Issue 380: ALTER TABLE ADD FOREIGN KEY with an explicit index didn't verify
<ul><li>ALTER TABLE ADD can now add more than one column at a time.
</li><li>Issue 380: ALTER TABLE ADD FOREIGN KEY with an explicit index didn't verify
the index can be used, which would lead to a NullPointerException later on.
</li><li>The wrong kind of exception (NullPointerException) was thrown in a UNION query
with an incorrect ORDER BY expression.
......
......@@ -4948,19 +4948,37 @@ public class Parser {
private AlterTableAlterColumn parseAlterTableAddColumn(Table table) {
readIf("COLUMN");
boolean ifNotExists = readIfNoExists();
Schema schema = table.getSchema();
AlterTableAlterColumn command = new AlterTableAlterColumn(session, schema);
command.setIfNotExists(ifNotExists);
command.setType(CommandInterface.ALTER_TABLE_ADD_COLUMN);
command.setTable(table);
String columnName = readColumnIdentifier();
Column column = parseColumnForTable(columnName, true);
command.setNewColumn(column);
if (readIf("BEFORE")) {
command.setAddBefore(readColumnIdentifier());
ArrayList<Column> columnsToAdd = New.arrayList();
boolean b = readIf("(");
if (b) {
command.setIfNotExists(false);
do{
String columnName = readColumnIdentifier();
Column column = parseColumnForTable(columnName, true);
columnsToAdd.add(column);
} while (readIf(","));
read(")");
command.setNewColumns(columnsToAdd);
} else {
boolean ifNotExists = readIfNoExists();
command.setIfNotExists(ifNotExists);
String columnName = readColumnIdentifier();
Column column = parseColumnForTable(columnName, true);
columnsToAdd.add(column);
if (readIf("BEFORE")) {
command.setAddBefore(readColumnIdentifier());
}
}
command.setNewColumns(columnsToAdd);
return command;
}
private int parseAction() {
......
......@@ -55,6 +55,7 @@ public class AlterTableAlterColumn extends SchemaCommand {
private Expression newSelectivity;
private String addBefore;
private boolean ifNotExists;
private ArrayList<Column> columnsToAdd;
public AlterTableAlterColumn(Session session, Schema schema) {
super(session, schema);
......@@ -82,81 +83,89 @@ public class AlterTableAlterColumn extends SchemaCommand {
if (newColumn != null) {
checkDefaultReferencesTable(newColumn.getDefaultExpression());
}
switch (type) {
case CommandInterface.ALTER_TABLE_ALTER_COLUMN_NOT_NULL: {
if (!oldColumn.isNullable()) {
// no change
break;
if (columnsToAdd != null) {
for (Column column : columnsToAdd) {
checkDefaultReferencesTable(column.getDefaultExpression());
}
checkNoNullValues();
oldColumn.setNullable(false);
db.update(session, table);
break;
}
case CommandInterface.ALTER_TABLE_ALTER_COLUMN_NULL: {
if (oldColumn.isNullable()) {
// no change
switch (type) {
case CommandInterface.ALTER_TABLE_ALTER_COLUMN_NOT_NULL: {
if (!oldColumn.isNullable()) {
// no change
break;
}
checkNoNullValues();
oldColumn.setNullable(false);
db.update(session, table);
break;
}
checkNullable();
oldColumn.setNullable(true);
db.update(session, table);
break;
}
case CommandInterface.ALTER_TABLE_ALTER_COLUMN_DEFAULT: {
checkDefaultReferencesTable(defaultExpression);
oldColumn.setSequence(null);
oldColumn.setDefaultExpression(session, defaultExpression);
removeSequence(sequence);
db.update(session, table);
break;
}
case CommandInterface.ALTER_TABLE_ALTER_COLUMN_CHANGE_TYPE: {
// if the change is only increasing the precision, then we don't
// need to copy the table because the length is only a constraint,
// and does not affect the storage structure.
if (oldColumn.isWideningConversion(newColumn)) {
convertAutoIncrementColumn(newColumn);
oldColumn.copy(newColumn);
case CommandInterface.ALTER_TABLE_ALTER_COLUMN_NULL: {
if (oldColumn.isNullable()) {
// no change
break;
}
checkNullable();
oldColumn.setNullable(true);
db.update(session, table);
} else {
break;
}
case CommandInterface.ALTER_TABLE_ALTER_COLUMN_DEFAULT: {
checkDefaultReferencesTable(defaultExpression);
oldColumn.setSequence(null);
oldColumn.setDefaultExpression(session, null);
oldColumn.setConvertNullToDefault(false);
if (oldColumn.isNullable() && !newColumn.isNullable()) {
checkNoNullValues();
} else if (!oldColumn.isNullable() && newColumn.isNullable()) {
checkNullable();
oldColumn.setDefaultExpression(session, defaultExpression);
removeSequence(sequence);
db.update(session, table);
break;
}
case CommandInterface.ALTER_TABLE_ALTER_COLUMN_CHANGE_TYPE: {
// if the change is only increasing the precision, then we don't
// need to copy the table because the length is only a constraint,
// and does not affect the storage structure.
if (oldColumn.isWideningConversion(newColumn)) {
convertAutoIncrementColumn(newColumn);
oldColumn.copy(newColumn);
db.update(session, table);
} else {
oldColumn.setSequence(null);
oldColumn.setDefaultExpression(session, null);
oldColumn.setConvertNullToDefault(false);
if (oldColumn.isNullable() && !newColumn.isNullable()) {
checkNoNullValues();
} else if (!oldColumn.isNullable() && newColumn.isNullable()) {
checkNullable();
}
convertAutoIncrementColumn(newColumn);
copyData();
}
break;
}
case CommandInterface.ALTER_TABLE_ADD_COLUMN: {
// ifNotExists only supported for single column add
if (ifNotExists && columnsToAdd.size() == 1 && table.doesColumnExist(columnsToAdd.get(0).getName())) {
break;
}
for (Column column : columnsToAdd) {
convertAutoIncrementColumn(column);
}
convertAutoIncrementColumn(newColumn);
copyData();
break;
}
break;
}
case CommandInterface.ALTER_TABLE_ADD_COLUMN: {
if (ifNotExists && table.doesColumnExist(newColumn.getName())) {
case CommandInterface.ALTER_TABLE_DROP_COLUMN: {
if (table.getColumns().length == 1) {
throw DbException.get(ErrorCode.CANNOT_DROP_LAST_COLUMN, oldColumn.getSQL());
}
table.dropSingleColumnConstraintsAndIndexes(session, oldColumn);
copyData();
break;
}
convertAutoIncrementColumn(newColumn);
copyData();
break;
}
case CommandInterface.ALTER_TABLE_DROP_COLUMN: {
if (table.getColumns().length == 1) {
throw DbException.get(ErrorCode.CANNOT_DROP_LAST_COLUMN, oldColumn.getSQL());
case CommandInterface.ALTER_TABLE_ALTER_COLUMN_SELECTIVITY: {
int value = newSelectivity.optimize(session).getValue(session).getInt();
oldColumn.setSelectivity(value);
db.update(session, table);
break;
}
table.dropSingleColumnConstraintsAndIndexes(session, oldColumn);
copyData();
break;
}
case CommandInterface.ALTER_TABLE_ALTER_COLUMN_SELECTIVITY: {
int value = newSelectivity.optimize(session).getValue(session).getInt();
oldColumn.setSelectivity(value);
db.update(session, table);
break;
}
default:
DbException.throwInternalError("type=" + type);
default:
DbException.throwInternalError("type=" + type);
}
return 0;
}
......@@ -266,7 +275,9 @@ public class AlterTableAlterColumn extends SchemaCommand {
} else {
position = table.getColumn(addBefore).getColumnId();
}
newColumns.add(position, newColumn);
for (Column column : columnsToAdd) {
newColumns.add(position++, column);
}
} else if (type == CommandInterface.ALTER_TABLE_ALTER_COLUMN_CHANGE_TYPE) {
int position = oldColumn.getColumnId();
newColumns.remove(position);
......@@ -298,7 +309,7 @@ public class AlterTableAlterColumn extends SchemaCommand {
if (columnList.length() > 0) {
columnList.append(", ");
}
if (type == CommandInterface.ALTER_TABLE_ADD_COLUMN && nc == newColumn) {
if (type == CommandInterface.ALTER_TABLE_ADD_COLUMN && columnsToAdd.contains(nc)) {
Expression def = nc.getDefaultExpression();
columnList.append(def == null ? "NULL" : def.getSQL());
} else {
......@@ -470,4 +481,7 @@ public class AlterTableAlterColumn extends SchemaCommand {
this.ifNotExists = ifNotExists;
}
public void setNewColumns(ArrayList<Column> columnsToAdd) {
this.columnsToAdd = columnsToAdd;
}
}
......@@ -40,6 +40,7 @@ public class TestAlter extends TestBase {
testAlterTableAlterColumn();
testAlterTableDropIdentityColumn();
testAlterTableAddColumnIfNotExists();
testAlterTableAddMultipleColumns();
testAlterTableAlterColumn2();
conn.close();
deleteDb("alter");
......@@ -136,6 +137,15 @@ public class TestAlter extends TestBase {
stat.execute("drop table t");
}
private void testAlterTableAddMultipleColumns() throws SQLException {
stat.execute("create table t(x varchar) as select 'x'");
stat.execute("alter table t add (y int, z varchar)");
stat.execute("drop table t");
stat.execute("create table t(x varchar) as select 'x'");
stat.execute("alter table t add (y int)");
stat.execute("drop table t");
}
private void testAlterTableAlterColumn2() throws SQLException {
// ensure that increasing a VARCHAR columns length takes effect because
// we optimize this case
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论