Hi Noel & Thomas,
A patch is included, with updated tests and grammar too.
A problem I had with preparing this was with updating the grammar. The
generated railroad diagram just couldn't format the changed grammar
for ALTER TABLE ADD in a nice fashion. So I changed it slightly to
use
"columnDefinition" instead of
"name dataType [ DEFAULT expression ] [ [ NOT ] NULL ]
[ AUTO_INCREMENT | IDENTITY ]"
I hope this is acceptable.
START OF PATCH:
Index: src/docsrc/help/help.csv
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>MacRoman
===================================================================
--- src/docsrc/help/help.csv (revision 4126)
+++ src/docsrc/help/help.csv (revision )
@@ -211,8 +211,9 @@
"
"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.
Index: src/test/org/h2/test/db/TestAlter.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>MacRoman
===================================================================
--- src/test/org/h2/test/db/TestAlter.java (revision 4126)
+++ src/test/org/h2/test/db/TestAlter.java (revision )
@@ -40,6 +40,7 @@
testAlterTableAlterColumn();
testAlterTableDropIdentityColumn();
testAlterTableAddColumnIfNotExists();
+ testAlterTableAddMultipleColumns();
testAlterTableAlterColumn2();
conn.close();
deleteDb("alter");
@@ -133,6 +134,15 @@
stat.execute("create table t(x varchar) as select 'x'");
stat.execute("alter table t add if not exists y int");
stat.execute("select x, y from t");
+ 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");
}
Index: src/main/org/h2/command/Parser.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>MacRoman
===================================================================
--- src/main/org/h2/command/Parser.java (revision 4126)
+++ src/main/org/h2/command/Parser.java (revision )
@@ -4948,19 +4948,37 @@
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);
+ ArrayList<Column> columnsToAdd = New.arrayList();
+
+ boolean b = readIf("(");
+ if (b) {
+ command.setIfNotExists(false);
+ do{
- String columnName = readColumnIdentifier();
- Column column = parseColumnForTable(columnName, true);
+ String columnName = readColumnIdentifier();
+ Column column = parseColumnForTable(columnName,
true);
- command.setNewColumn(column);
+ 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());
- }
+ if (readIf("BEFORE")) {
+ command.setAddBefore(readColumnIdentifier());
+ }
+
+ }
+ command.setNewColumns(columnsToAdd);
return command;
+
}
private int parseAction() {
Index: src/docsrc/html/changelog.html
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- src/docsrc/html/changelog.html (revision 4126)
+++ src/docsrc/html/changelog.html (revision )
@@ -26,6 +26,7 @@
</li><li>CSV tool: new feature to preserve the case sensitivity of
column names
(option caseSensitiveColumnNames).
</li><li>PostgreSQL compatibility: LOG(x) is base 10 in the
PostgreSQL mode.
+</li><li>ALTER TABLE ADD can now add more than one column at a time.
</li></ul>
<h2>Version 1.3.164 (2012-02-03)</h2>
Index: src/main/org/h2/command/ddl/AlterTableAlterColumn.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>MacRoman
===================================================================
--- src/main/org/h2/command/ddl/AlterTableAlterColumn.java (revision
4126)
+++ src/main/org/h2/command/ddl/AlterTableAlterColumn.java (revision )
@@ -55,6 +55,7 @@
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 @@
if (newColumn != null) {
checkDefaultReferencesTable(newColumn.getDefaultExpression());
}
+ if (columnsToAdd != null) {
+ for (Column column : columnsToAdd) {
+
checkDefaultReferencesTable(column.getDefaultExpression());
+ }
+ }
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;
- }
- case CommandInterface.ALTER_TABLE_ALTER_COLUMN_NULL: {
- if (oldColumn.isNullable()) {
- // no change
- 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);
- 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: {
+ case CommandInterface.ALTER_TABLE_ALTER_COLUMN_NOT_NULL:
{
+ if (!oldColumn.isNullable()) {
+ // no change
+ break;
+ }
+ checkNoNullValues();
+ oldColumn.setNullable(false);
+ db.update(session, table);
+ break;
+ }
+ case CommandInterface.ALTER_TABLE_ALTER_COLUMN_NULL: {
+ if (oldColumn.isNullable()) {
+ // no change
+ 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);
+ 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: {
- if (ifNotExists &&
table.doesColumnExist(newColumn.getName())) {
+ // ifNotExists only supported for single column add
+ if (ifNotExists && columnsToAdd.size() == 1 &&
table.doesColumnExist(columnsToAdd.get(0).getName())) {
- break;
- }
+ break;
+ }
- convertAutoIncrementColumn(newColumn);
+ for (Column column : columnsToAdd) {
+ convertAutoIncrementColumn(column);
+ }
- copyData();
- break;
- }
- 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;
- }
- 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);
+ copyData();
+ break;
+ }
+ 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;
+ }
+ 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);
}
return 0;
}
@@ -266,7 +275,9 @@
} 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 @@
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 @@
this.ifNotExists = ifNotExists;
}
+ public void setNewColumns(ArrayList<Column> columnsToAdd) {
+ this.columnsToAdd = columnsToAdd;
+ }
}
END OF PATCH