提交 86462170 authored 作者: Noel Grandin's avatar Noel Grandin

Add support for dropping multiple columns in ALTER TABLE DROP COLUMN...

上级 7014d46a
...@@ -289,12 +289,13 @@ ALTER TABLE TEST ALTER COLUMN NAME SET NULL; ...@@ -289,12 +289,13 @@ ALTER TABLE TEST ALTER COLUMN NAME SET NULL;
" "
"Commands (DDL)","ALTER TABLE DROP COLUMN"," "Commands (DDL)","ALTER TABLE DROP COLUMN","
ALTER TABLE tableName DROP COLUMN [ IF EXISTS ] columnName ALTER TABLE tableName DROP COLUMN [ IF EXISTS ] ( columnName [,...] )
"," ","
Removes a column from a table. Removes column(s) from a table.
This command commits an open transaction in this connection. This command commits an open transaction in this connection.
"," ","
ALTER TABLE TEST DROP COLUMN NAME ALTER TABLE TEST DROP COLUMN NAME
ALTER TABLE TEST DROP COLUMN NAME1, NAME2
" "
"Commands (DDL)","ALTER TABLE DROP CONSTRAINT"," "Commands (DDL)","ALTER TABLE DROP CONSTRAINT","
......
...@@ -27,6 +27,8 @@ Change Log ...@@ -27,6 +27,8 @@ Change Log
<h2>Version 1.4.189 Beta (2015-09-13)</h2> <h2>Version 1.4.189 Beta (2015-09-13)</h2>
<ul> <ul>
<li>Add support for dropping multiple columns in ALTER TABLE DROP COLUMN...
</li>
<li>Fix bug in XA management when doing rollback after prepare. Patch by Stephane Lacoin. <li>Fix bug in XA management when doing rollback after prepare. Patch by Stephane Lacoin.
</li> </li>
<li>MVStore CLOB and BLOB: An exception with the message "Block not found" could be thrown <li>MVStore CLOB and BLOB: An exception with the message "Block not found" could be thrown
......
...@@ -5415,12 +5415,17 @@ public class Parser { ...@@ -5415,12 +5415,17 @@ public class Parser {
AlterTableAlterColumn command = new AlterTableAlterColumn( AlterTableAlterColumn command = new AlterTableAlterColumn(
session, table.getSchema()); session, table.getSchema());
command.setType(CommandInterface.ALTER_TABLE_DROP_COLUMN); command.setType(CommandInterface.ALTER_TABLE_DROP_COLUMN);
String columnName = readColumnIdentifier(); ArrayList<Column> columnsToRemove = New.arrayList();
do {
String columnName = readColumnIdentifier();
if (ifExists && !table.doesColumnExist(columnName)) {
return new NoOperation(session);
}
Column column = table.getColumn(columnName);
columnsToRemove.add(column);
} while (readIf(","));
command.setTable(table); command.setTable(table);
if (ifExists && !table.doesColumnExist(columnName)) { command.setColumnsToRemove(columnsToRemove);
return new NoOperation(session);
}
command.setOldColumn(table.getColumn(columnName));
return command; return command;
} }
} else if (readIf("CHANGE")) { } else if (readIf("CHANGE")) {
......
...@@ -7,7 +7,7 @@ package org.h2.command.ddl; ...@@ -7,7 +7,7 @@ package org.h2.command.ddl;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.command.CommandInterface; import org.h2.command.CommandInterface;
import org.h2.command.Parser; import org.h2.command.Parser;
...@@ -57,6 +57,7 @@ public class AlterTableAlterColumn extends SchemaCommand { ...@@ -57,6 +57,7 @@ public class AlterTableAlterColumn extends SchemaCommand {
private String addAfter; private String addAfter;
private boolean ifNotExists; private boolean ifNotExists;
private ArrayList<Column> columnsToAdd; private ArrayList<Column> columnsToAdd;
private ArrayList<Column> columnsToRemove;
public AlterTableAlterColumn(Session session, Schema schema) { public AlterTableAlterColumn(Session session, Schema schema) {
super(session, schema); super(session, schema);
...@@ -85,7 +86,6 @@ public class AlterTableAlterColumn extends SchemaCommand { ...@@ -85,7 +86,6 @@ public class AlterTableAlterColumn extends SchemaCommand {
session.getUser().checkRight(table, Right.ALL); session.getUser().checkRight(table, Right.ALL);
table.checkSupportAlter(); table.checkSupportAlter();
table.lock(session, true, true); table.lock(session, true, true);
Sequence sequence = oldColumn == null ? null : oldColumn.getSequence();
if (newColumn != null) { if (newColumn != null) {
checkDefaultReferencesTable(newColumn.getDefaultExpression()); checkDefaultReferencesTable(newColumn.getDefaultExpression());
} }
...@@ -116,6 +116,7 @@ public class AlterTableAlterColumn extends SchemaCommand { ...@@ -116,6 +116,7 @@ public class AlterTableAlterColumn extends SchemaCommand {
break; break;
} }
case CommandInterface.ALTER_TABLE_ALTER_COLUMN_DEFAULT: { case CommandInterface.ALTER_TABLE_ALTER_COLUMN_DEFAULT: {
Sequence sequence = oldColumn == null ? null : oldColumn.getSequence();
checkDefaultReferencesTable(defaultExpression); checkDefaultReferencesTable(defaultExpression);
oldColumn.setSequence(null); oldColumn.setSequence(null);
oldColumn.setDefaultExpression(session, defaultExpression); oldColumn.setDefaultExpression(session, defaultExpression);
...@@ -162,11 +163,11 @@ public class AlterTableAlterColumn extends SchemaCommand { ...@@ -162,11 +163,11 @@ public class AlterTableAlterColumn extends SchemaCommand {
break; break;
} }
case CommandInterface.ALTER_TABLE_DROP_COLUMN: { case CommandInterface.ALTER_TABLE_DROP_COLUMN: {
if (table.getColumns().length == 1) { if (table.getColumns().length - columnsToRemove.size() < 1) {
throw DbException.get(ErrorCode.CANNOT_DROP_LAST_COLUMN, throw DbException.get(ErrorCode.CANNOT_DROP_LAST_COLUMN,
oldColumn.getSQL()); columnsToRemove.get(0).getSQL());
} }
table.dropSingleColumnConstraintsAndIndexes(session, oldColumn); table.dropMultipleColumnsConstraintsAndIndexes(session, columnsToRemove);
copyData(); copyData();
break; break;
} }
...@@ -282,8 +283,20 @@ public class AlterTableAlterColumn extends SchemaCommand { ...@@ -282,8 +283,20 @@ public class AlterTableAlterColumn extends SchemaCommand {
newColumns.add(col.getClone()); newColumns.add(col.getClone());
} }
if (type == CommandInterface.ALTER_TABLE_DROP_COLUMN) { if (type == CommandInterface.ALTER_TABLE_DROP_COLUMN) {
int position = oldColumn.getColumnId(); for (Column removeCol : columnsToRemove) {
newColumns.remove(position); Column foundCol = null;
for (Iterator<Column> iter = newColumns.iterator(); iter.hasNext(); ) {
Column newCol = iter.next();
if (newCol.getName() == removeCol.getName()) {
foundCol = newCol;
break;
}
}
if (foundCol == null) {
throw DbException.throwInternalError(removeCol.getCreateSQL());
}
newColumns.remove(foundCol);
}
} else if (type == CommandInterface.ALTER_TABLE_ADD_COLUMN) { } else if (type == CommandInterface.ALTER_TABLE_ADD_COLUMN) {
int position; int position;
if (addBefore != null) { if (addBefore != null) {
...@@ -509,4 +522,8 @@ public class AlterTableAlterColumn extends SchemaCommand { ...@@ -509,4 +522,8 @@ public class AlterTableAlterColumn extends SchemaCommand {
public void setNewColumns(ArrayList<Column> columnsToAdd) { public void setNewColumns(ArrayList<Column> columnsToAdd) {
this.columnsToAdd = columnsToAdd; this.columnsToAdd = columnsToAdd;
} }
public void setColumnsToRemove(ArrayList<Column> columnsToRemove) {
this.columnsToRemove = columnsToRemove;
}
} }
...@@ -9,7 +9,6 @@ import java.util.ArrayList; ...@@ -9,7 +9,6 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.command.Prepared; import org.h2.command.Prepared;
import org.h2.constraint.Constraint; import org.h2.constraint.Constraint;
...@@ -531,49 +530,53 @@ public abstract class Table extends SchemaObjectBase { ...@@ -531,49 +530,53 @@ public abstract class Table extends SchemaObjectBase {
} }
/** /**
* Check that this column is not referenced by a multi-column constraint or * Check that these columns are not referenced by a multi-column constraint or
* multi-column index. If it is, an exception is thrown. Single-column * multi-column index. If it is, an exception is thrown. Single-column
* references and indexes are dropped. * references and indexes are dropped.
* *
* @param session the session * @param session the session
* @param col the column * @param columsToDrop the columns to drop
* @throws DbException if the column is referenced by multi-column * @throws DbException if the column is referenced by multi-column
* constraints or indexes * constraints or indexes
*/ */
public void dropSingleColumnConstraintsAndIndexes(Session session, public void dropMultipleColumnsConstraintsAndIndexes(Session session,
Column col) { ArrayList<Column> columsToDrop) {
ArrayList<Constraint> constraintsToDrop = New.arrayList(); HashSet<Constraint> constraintsToDrop = New.hashSet();
if (constraints != null) { if (constraints != null) {
for (int i = 0, size = constraints.size(); i < size; i++) { for (Column col : columsToDrop) {
Constraint constraint = constraints.get(i); for (int i = 0, size = constraints.size(); i < size; i++) {
HashSet<Column> columns = constraint.getReferencedColumns(this); Constraint constraint = constraints.get(i);
if (!columns.contains(col)) { HashSet<Column> columns = constraint.getReferencedColumns(this);
continue; if (!columns.contains(col)) {
} continue;
if (columns.size() == 1) { }
constraintsToDrop.add(constraint); if (columns.size() == 1) {
} else { constraintsToDrop.add(constraint);
throw DbException.get( } else {
ErrorCode.COLUMN_IS_REFERENCED_1, constraint.getSQL()); throw DbException.get(
ErrorCode.COLUMN_IS_REFERENCED_1, constraint.getSQL());
}
} }
} }
} }
ArrayList<Index> indexesToDrop = New.arrayList(); HashSet<Index> indexesToDrop = New.hashSet();
ArrayList<Index> indexes = getIndexes(); ArrayList<Index> indexes = getIndexes();
if (indexes != null) { if (indexes != null) {
for (int i = 0, size = indexes.size(); i < size; i++) { for (Column col : columsToDrop) {
Index index = indexes.get(i); for (int i = 0, size = indexes.size(); i < size; i++) {
if (index.getCreateSQL() == null) { Index index = indexes.get(i);
continue; if (index.getCreateSQL() == null) {
} continue;
if (index.getColumnIndex(col) < 0) { }
continue; if (index.getColumnIndex(col) < 0) {
} continue;
if (index.getColumns().length == 1) { }
indexesToDrop.add(index); if (index.getColumns().length == 1) {
} else { indexesToDrop.add(index);
throw DbException.get( } else {
ErrorCode.COLUMN_IS_REFERENCED_1, index.getSQL()); throw DbException.get(
ErrorCode.COLUMN_IS_REFERENCED_1, index.getSQL());
}
} }
} }
} }
......
...@@ -10,7 +10,6 @@ import java.sql.DatabaseMetaData; ...@@ -10,7 +10,6 @@ import java.sql.DatabaseMetaData;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.test.TestBase; import org.h2.test.TestBase;
...@@ -38,6 +37,7 @@ public class TestAlter extends TestBase { ...@@ -38,6 +37,7 @@ public class TestAlter extends TestBase {
stat = conn.createStatement(); stat = conn.createStatement();
testAlterTableAlterColumnAsSelfColumn(); testAlterTableAlterColumnAsSelfColumn();
testAlterTableDropColumnWithReferences(); testAlterTableDropColumnWithReferences();
testAlterTableDropMultipleColumns();
testAlterTableAlterColumnWithConstraint(); testAlterTableAlterColumnWithConstraint();
testAlterTableAlterColumn(); testAlterTableAlterColumn();
testAlterTableAddColumnIdentity(); testAlterTableAddColumnIdentity();
...@@ -108,6 +108,17 @@ public class TestAlter extends TestBase { ...@@ -108,6 +108,17 @@ public class TestAlter extends TestBase {
} }
private void testAlterTableDropMultipleColumns() throws SQLException {
stat.execute("create table test(id int, name varchar, name2 varchar)");
stat.execute("alter table test drop column name, name2");
stat.execute("drop table test");
stat.execute("create table test(id int, name varchar, name2 varchar)");
assertThrows(ErrorCode.CANNOT_DROP_LAST_COLUMN, stat).
execute("alter table test drop column id, name, name2");
stat.execute("drop table test");
}
/** /**
* Tests a bug we used to have where altering the name of a column that had * Tests a bug we used to have where altering the name of a column that had
* a check constraint that referenced itself would result in not being able * a check constraint that referenced itself would result in not being able
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论