diff options
author | Eike Stepper | 2013-03-06 07:50:54 +0000 |
---|---|---|
committer | Eike Stepper | 2013-03-07 13:44:28 +0000 |
commit | 16aa130826e48bc33f5dbd7888f75face530e90d (patch) | |
tree | 3622a3d46bbde50557b7430641104e08f1fb51f6 | |
parent | 81a23a1e6238318f5fc18c97c0ef64b3ed51b3df (diff) | |
download | cdo-16aa130826e48bc33f5dbd7888f75face530e90d.tar.gz cdo-16aa130826e48bc33f5dbd7888f75face530e90d.tar.xz cdo-16aa130826e48bc33f5dbd7888f75face530e90d.zip |
[401763] Make CDO Server more robust against data dictionary changes
https://bugs.eclipse.org/bugs/show_bug.cgi?id=401763
32 files changed, 1245 insertions, 685 deletions
diff --git a/plugins/org.eclipse.net4j.db.h2/src/org/eclipse/net4j/db/h2/H2Adapter.java b/plugins/org.eclipse.net4j.db.h2/src/org/eclipse/net4j/db/h2/H2Adapter.java index 2557dc94fc..5ffb0e4566 100644 --- a/plugins/org.eclipse.net4j.db.h2/src/org/eclipse/net4j/db/h2/H2Adapter.java +++ b/plugins/org.eclipse.net4j.db.h2/src/org/eclipse/net4j/db/h2/H2Adapter.java @@ -13,8 +13,11 @@ package org.eclipse.net4j.db.h2; import org.eclipse.net4j.db.DBType; import org.eclipse.net4j.db.IDBAdapter; import org.eclipse.net4j.db.ddl.IDBField; +import org.eclipse.net4j.db.ddl.IDBIndex.Type; +import org.eclipse.net4j.db.ddl.IDBTable; import org.eclipse.net4j.spi.db.DBAdapter; +import java.sql.Connection; import java.sql.SQLException; /** @@ -66,6 +69,17 @@ public class H2Adapter extends DBAdapter } @Override + protected boolean isPrimaryKeyShadow(Connection connection, IDBTable table, String name, Type type, IDBField[] fields) + { + if (!name.toUpperCase().startsWith("PRIMARY_KEY")) + { + return false; + } + + return super.isPrimaryKeyShadow(connection, table, name, type, fields); + } + + @Override public boolean isDuplicateKeyException(SQLException ex) { String sqlState = ex.getSQLState(); diff --git a/plugins/org.eclipse.net4j.db.mysql/src/org/eclipse/net4j/db/mysql/MYSQLAdapter.java b/plugins/org.eclipse.net4j.db.mysql/src/org/eclipse/net4j/db/mysql/MYSQLAdapter.java index 670d37af34..afb275b38f 100644 --- a/plugins/org.eclipse.net4j.db.mysql/src/org/eclipse/net4j/db/mysql/MYSQLAdapter.java +++ b/plugins/org.eclipse.net4j.db.mysql/src/org/eclipse/net4j/db/mysql/MYSQLAdapter.java @@ -13,6 +13,7 @@ package org.eclipse.net4j.db.mysql; import org.eclipse.net4j.db.DBType; import org.eclipse.net4j.db.IDBAdapter; import org.eclipse.net4j.db.ddl.IDBField; +import org.eclipse.net4j.db.ddl.IDBIndex; import org.eclipse.net4j.spi.db.DBAdapter; import java.sql.SQLException; @@ -103,6 +104,14 @@ public class MYSQLAdapter extends DBAdapter } @Override + protected void dropPrimaryKey(IDBIndex index, StringBuilder builder) + { + builder.append("ALTER TABLE "); //$NON-NLS-1$ + builder.append(index.getTable()); + builder.append(" DROP PRIMARY KEY"); //$NON-NLS-1$ + } + + @Override protected void addIndexField(StringBuilder builder, IDBField field) { super.addIndexField(builder, field); diff --git a/plugins/org.eclipse.net4j.db.tests/src/org/eclipse/net4j/db/tests/AbstractDBTest.java b/plugins/org.eclipse.net4j.db.tests/src/org/eclipse/net4j/db/tests/AbstractDBTest.java index 8e3820cbb3..03c3403baa 100644 --- a/plugins/org.eclipse.net4j.db.tests/src/org/eclipse/net4j/db/tests/AbstractDBTest.java +++ b/plugins/org.eclipse.net4j.db.tests/src/org/eclipse/net4j/db/tests/AbstractDBTest.java @@ -118,99 +118,106 @@ public abstract class AbstractDBTest extends AbstractOMTest public void testSchemaEmpty() throws Exception { - IDBSchema schema = DBUtil.readSchema(SCHEMA_NAME, getConnection()); + IDBSchema schema = DBUtil.readSchema(adapter, getConnection(), SCHEMA_NAME); assertEquals(true, schema.isEmpty()); } public void testSchemaCreation() throws Exception { IDBDatabase database = DBUtil.openDatabase(adapter, connectionProvider, SCHEMA_NAME); - assertEquals(true, database.getSchema().isLocked()); - assertEquals(true, database.getSchema().isEmpty()); + IDBSchema schema = database.getSchema(); + assertEquals(true, schema.isLocked()); + assertEquals(true, schema.isEmpty()); IDBSchemaTransaction schemaTransaction = database.openSchemaTransaction(); - assertEquals(false, schemaTransaction.getSchema().isLocked()); - assertEquals(true, schemaTransaction.getSchema().isEmpty()); - assertEquals(database.getSchema(), schemaTransaction.getSchema()); - - IDBTable table1 = schemaTransaction.getSchema().addTable("table1"); - IDBField field11 = table1.addField("field1", DBType.INTEGER); - IDBField field12 = table1.addField("field2", DBType.VARCHAR, 64); - IDBField field13 = table1.addField("field3", DBType.BOOLEAN); - IDBIndex index11 = table1.addIndex("index1", IDBIndex.Type.PRIMARY_KEY, field11, field12); - IDBIndex index12 = table1.addIndex("index2", IDBIndex.Type.UNIQUE, field11, field12); - IDBIndex index13 = table1.addIndex("index3", IDBIndex.Type.NON_UNIQUE, field12); - - IDBTable table2 = schemaTransaction.getSchema().addTable("table2"); - IDBField field21 = table2.addField("field1", DBType.INTEGER); - IDBField field22 = table2.addField("field2", DBType.VARCHAR, 64); - IDBField field23 = table2.addField("field3", DBType.BOOLEAN); - IDBIndex index21 = table2.addIndex("index1", IDBIndex.Type.PRIMARY_KEY, field21, field22); - IDBIndex index22 = table2.addIndex("index2", IDBIndex.Type.UNIQUE, field21, field22); - IDBIndex index23 = table2.addIndex("index3", IDBIndex.Type.NON_UNIQUE, field22); + IDBSchema workingCopy = schemaTransaction.getSchema(); + assertEquals(false, workingCopy.isLocked()); + assertEquals(true, workingCopy.isEmpty()); + assertEquals(schema, workingCopy); + + IDBTable table1 = workingCopy.addTable("table1"); + IDBField field11 = table1.addField("field11", DBType.INTEGER, true); + IDBField field12 = table1.addField("field12", DBType.VARCHAR, 64, true); + IDBField field13 = table1.addField("field13", DBType.BOOLEAN); + IDBIndex index11 = table1.addIndex("index11", IDBIndex.Type.PRIMARY_KEY, field11, field12); + IDBIndex index12 = table1.addIndex("index12", IDBIndex.Type.UNIQUE, field11, field12); + IDBIndex index13 = table1.addIndex("index13", IDBIndex.Type.NON_UNIQUE, field12); + + IDBTable table2 = workingCopy.addTable("table2"); + IDBField field21 = table2.addField("field21", DBType.INTEGER, true); + IDBField field22 = table2.addField("field22", DBType.VARCHAR, 64, true); + IDBField field23 = table2.addField("field23", DBType.BOOLEAN); + IDBIndex index21 = table2.addIndex("index21", IDBIndex.Type.PRIMARY_KEY, field21, field22); + IDBIndex index22 = table2.addIndex("index22", IDBIndex.Type.UNIQUE, field21, field22); + IDBIndex index23 = table2.addIndex("index23", IDBIndex.Type.NON_UNIQUE, field22); schemaTransaction.commit(); - assertEquals(true, database.getSchema().isLocked()); - assertEquals(false, database.getSchema().isEmpty()); - assertEquals(2, database.getSchema().getTables().length); - - assertEquals(table1, database.getSchema().getTables()[0]); - assertEquals(table1.getFieldCount(), database.getSchema().getTables()[0].getFieldCount()); - assertEquals(field11, database.getSchema().getTables()[0].getField(0)); - assertEquals(field12, database.getSchema().getTables()[0].getField(1)); - assertEquals(field13, database.getSchema().getTables()[0].getField(2)); - assertEquals(table1.getIndexCount(), database.getSchema().getTables()[0].getIndexCount()); - assertEquals(index11, database.getSchema().getTables()[0].getIndex(0)); - assertEquals(index11.getType(), database.getSchema().getTables()[0].getIndex(0).getType()); - assertEquals(index12, database.getSchema().getTables()[0].getIndex(1)); - assertEquals(index12.getType(), database.getSchema().getTables()[0].getIndex(1).getType()); - assertEquals(index13, database.getSchema().getTables()[0].getIndex(2)); - assertEquals(index13.getType(), database.getSchema().getTables()[0].getIndex(2).getType()); - - assertEquals(table2, database.getSchema().getTables()[1]); - assertEquals(table2.getFieldCount(), database.getSchema().getTables()[1].getFieldCount()); - assertEquals(field21, database.getSchema().getTables()[1].getField(0)); - assertEquals(field22, database.getSchema().getTables()[1].getField(1)); - assertEquals(field23, database.getSchema().getTables()[1].getField(2)); - assertEquals(table2.getIndexCount(), database.getSchema().getTables()[1].getIndexCount()); - assertEquals(index21, database.getSchema().getTables()[1].getIndex(0)); - assertEquals(index21.getType(), database.getSchema().getTables()[1].getIndex(0).getType()); - assertEquals(index22, database.getSchema().getTables()[1].getIndex(1)); - assertEquals(index22.getType(), database.getSchema().getTables()[1].getIndex(1).getType()); - assertEquals(index23, database.getSchema().getTables()[1].getIndex(2)); - assertEquals(index23.getType(), database.getSchema().getTables()[1].getIndex(2).getType()); + assertEquals(true, schema.isLocked()); + assertEquals(false, schema.isEmpty()); + assertEquals(2, schema.getTables().length); + + assertEquals(table1, schema.getTables()[0]); + assertEquals(table1.getFieldCount(), schema.getTables()[0].getFieldCount()); + assertEquals(field11, schema.getTables()[0].getField(0)); + assertEquals(field12, schema.getTables()[0].getField(1)); + assertEquals(field13, schema.getTables()[0].getField(2)); + assertEquals(table1.getIndexCount(), schema.getTables()[0].getIndexCount()); + assertEquals(index11, schema.getTables()[0].getIndex(0)); + assertEquals(index11.getType(), schema.getTables()[0].getIndex(0).getType()); + assertEquals(index12, schema.getTables()[0].getIndex(1)); + assertEquals(index12.getType(), schema.getTables()[0].getIndex(1).getType()); + assertEquals(index13, schema.getTables()[0].getIndex(2)); + assertEquals(index13.getType(), schema.getTables()[0].getIndex(2).getType()); + + assertEquals(table2, schema.getTables()[1]); + assertEquals(table2.getFieldCount(), schema.getTables()[1].getFieldCount()); + assertEquals(field21, schema.getTables()[1].getField(0)); + assertEquals(field22, schema.getTables()[1].getField(1)); + assertEquals(field23, schema.getTables()[1].getField(2)); + assertEquals(table2.getIndexCount(), schema.getTables()[1].getIndexCount()); + assertEquals(index21, schema.getTables()[1].getIndex(0)); + assertEquals(index21.getType(), schema.getTables()[1].getIndex(0).getType()); + assertEquals(index22, schema.getTables()[1].getIndex(1)); + assertEquals(index22.getType(), schema.getTables()[1].getIndex(1).getType()); + assertEquals(index23, schema.getTables()[1].getIndex(2)); + assertEquals(index23.getType(), schema.getTables()[1].getIndex(2).getType()); } public void testSchemaAddition() throws Exception { // Init database IDBDatabase database = DBUtil.openDatabase(adapter, connectionProvider, SCHEMA_NAME); + IDBSchema schema = database.getSchema(); + IDBSchemaTransaction schemaTransaction = database.openSchemaTransaction(); + IDBSchema workingCopy = schemaTransaction.getSchema(); - IDBTable table1 = schemaTransaction.getSchema().addTable("table1"); - IDBField field11 = table1.addField("field1", DBType.INTEGER); - IDBField field12 = table1.addField("field2", DBType.VARCHAR, 64); - IDBField field13 = table1.addField("field3", DBType.BOOLEAN); - IDBIndex index11 = table1.addIndex("index1", IDBIndex.Type.PRIMARY_KEY, field11, field12); - IDBIndex index12 = table1.addIndex("index2", IDBIndex.Type.UNIQUE, field11, field12); - IDBIndex index13 = table1.addIndex("index3", IDBIndex.Type.NON_UNIQUE, field12); + IDBTable table1 = workingCopy.addTable("table1"); + IDBField field11 = table1.addField("field11", DBType.INTEGER, true); + IDBField field12 = table1.addField("field12", DBType.VARCHAR, 64, true); + IDBField field13 = table1.addField("field13", DBType.BOOLEAN); + IDBIndex index11 = table1.addIndex("index11", IDBIndex.Type.PRIMARY_KEY, field11, field12); + IDBIndex index12 = table1.addIndex("index12", IDBIndex.Type.UNIQUE, field11, field12); + IDBIndex index13 = table1.addIndex("index13", IDBIndex.Type.NON_UNIQUE, field12); schemaTransaction.commit(); - assertEquals(1, database.getSchema().getTables().length); + assertEquals(1, schema.getTables().length); // Reload database - database = DBUtil.openDatabase(adapter, connectionProvider, SCHEMA_NAME); - assertEquals(true, database.getSchema().isLocked()); - assertEquals(false, database.getSchema().isEmpty()); - assertEquals(1, database.getSchema().getTables().length); - - IDBTable table = database.getSchema().getTable("table1"); - field11 = table.getField("field1"); - field12 = table.getField("field2"); - field13 = table.getField("field3"); - index11 = table.getIndex("index1"); - index12 = table.getIndex("index2"); - index13 = table.getIndex("index3"); + IDBDatabase database2 = DBUtil.openDatabase(adapter, connectionProvider, SCHEMA_NAME); + IDBSchema schema2 = database2.getSchema(); + DBUtil.dump(schema2); + assertEquals(true, schema2.isLocked()); + assertEquals(false, schema2.isEmpty()); + assertEquals(1, schema2.getTables().length); + + IDBTable table = schema2.getTable("table1"); + field11 = table.getField("field11"); + field12 = table.getField("field12"); + field13 = table.getField("field13"); + index11 = table.getIndex("index11"); + index12 = table.getIndex("index12"); + index13 = table.getIndex("index13"); assertNotNull(field11); assertNotNull(field12); assertNotNull(field13); @@ -218,50 +225,62 @@ public abstract class AbstractDBTest extends AbstractOMTest assertNotNull(index12); assertNotNull(index13); - schemaTransaction = database.openSchemaTransaction(); - assertEquals(true, database.getSchema().isLocked()); - assertEquals(false, database.getSchema().isEmpty()); - assertEquals(1, database.getSchema().getTables().length); - - IDBTable table2 = schemaTransaction.getSchema().addTable("table2"); - IDBField field21 = table2.addField("field1", DBType.INTEGER); - IDBField field22 = table2.addField("field2", DBType.VARCHAR, 64); - IDBField field23 = table2.addField("field3", DBType.BOOLEAN); - IDBIndex index21 = table2.addIndex("index1", IDBIndex.Type.PRIMARY_KEY, field21, field22); - IDBIndex index22 = table2.addIndex("index2", IDBIndex.Type.UNIQUE, field21, field22); - IDBIndex index23 = table2.addIndex("index3", IDBIndex.Type.NON_UNIQUE, field22); - - IDBSchemaDelta schemaDelta = schemaTransaction.getSchemaDelta(); - - schemaTransaction.commit(); - assertEquals(true, database.getSchema().isLocked()); - assertEquals(false, database.getSchema().isEmpty()); - assertEquals(2, database.getSchema().getTables().length); - - assertEquals(table1, database.getSchema().getTables()[0]); - assertEquals(table1.getFieldCount(), database.getSchema().getTables()[0].getFieldCount()); - assertEquals(field11, database.getSchema().getTables()[0].getField(0)); - assertEquals(field12, database.getSchema().getTables()[0].getField(1)); - assertEquals(field13, database.getSchema().getTables()[0].getField(2)); - assertEquals(table1.getIndexCount(), database.getSchema().getTables()[0].getIndexCount()); - assertEquals(index11, database.getSchema().getTables()[0].getIndex(0)); - assertEquals(index11.getType(), database.getSchema().getTables()[0].getIndex(0).getType()); - assertEquals(index12, database.getSchema().getTables()[0].getIndex(1)); - assertEquals(index12.getType(), database.getSchema().getTables()[0].getIndex(1).getType()); - assertEquals(index13, database.getSchema().getTables()[0].getIndex(2)); - assertEquals(index13.getType(), database.getSchema().getTables()[0].getIndex(2).getType()); - - assertEquals(table2, database.getSchema().getTables()[1]); - assertEquals(table2.getFieldCount(), database.getSchema().getTables()[1].getFieldCount()); - assertEquals(field21, database.getSchema().getTables()[1].getField(0)); - assertEquals(field22, database.getSchema().getTables()[1].getField(1)); - assertEquals(field23, database.getSchema().getTables()[1].getField(2)); - assertEquals(table2.getIndexCount(), database.getSchema().getTables()[1].getIndexCount()); - assertEquals(index21, database.getSchema().getTables()[1].getIndex(0)); - assertEquals(index21.getType(), database.getSchema().getTables()[1].getIndex(0).getType()); - assertEquals(index22, database.getSchema().getTables()[1].getIndex(1)); - assertEquals(index22.getType(), database.getSchema().getTables()[1].getIndex(1).getType()); - assertEquals(index23, database.getSchema().getTables()[1].getIndex(2)); - assertEquals(index23.getType(), database.getSchema().getTables()[1].getIndex(2).getType()); + schemaTransaction = database2.openSchemaTransaction(); + workingCopy = schemaTransaction.getSchema(); + assertEquals(true, schema2.isLocked()); + assertEquals(false, schema2.isEmpty()); + assertEquals(1, schema2.getTables().length); + + IDBTable table2 = workingCopy.addTable("table2"); + IDBField field21 = table2.addField("field21", DBType.INTEGER, true); + IDBField field22 = table2.addField("field22", DBType.VARCHAR, 64, true); + IDBField field23 = table2.addField("field23", DBType.BOOLEAN); + IDBIndex index21 = table2.addIndex("index21", IDBIndex.Type.PRIMARY_KEY, field21, field22); + IDBIndex index22 = table2.addIndex("index22", IDBIndex.Type.UNIQUE, field21, field22); + IDBIndex index23 = table2.addIndex("index23", IDBIndex.Type.NON_UNIQUE, field22); + assertEquals(table1, schema2.getTables()[0]); + assertEquals(table1.getFieldCount(), schema2.getTables()[0].getFieldCount()); + assertEquals(field11, schema2.getTables()[0].getField(0)); + assertEquals(field12, schema2.getTables()[0].getField(1)); + assertEquals(field13, schema2.getTables()[0].getField(2)); + assertEquals(table1.getIndexCount(), schema2.getTables()[0].getIndexCount()); + assertEquals(index11, schema2.getTables()[0].getIndex(0)); + assertEquals(index11.getType(), schema2.getTables()[0].getIndex(0).getType()); + assertEquals(index12, schema2.getTables()[0].getIndex(1)); + assertEquals(index12.getType(), schema2.getTables()[0].getIndex(1).getType()); + assertEquals(index13, schema2.getTables()[0].getIndex(2)); + assertEquals(index13.getType(), schema2.getTables()[0].getIndex(2).getType()); + + IDBSchemaDelta delta = schemaTransaction.commit(); + DBUtil.dump(delta); + assertEquals(true, schema2.isLocked()); + assertEquals(false, schema2.isEmpty()); + assertEquals(2, schema2.getTables().length); + + assertEquals(table1, schema2.getTables()[0]); + assertEquals(table1.getFieldCount(), schema2.getTables()[0].getFieldCount()); + assertEquals(field11, schema2.getTables()[0].getField(0)); + assertEquals(field12, schema2.getTables()[0].getField(1)); + assertEquals(field13, schema2.getTables()[0].getField(2)); + assertEquals(table1.getIndexCount(), schema2.getTables()[0].getIndexCount()); + assertEquals(index11, schema2.getTables()[0].getIndex(0)); + assertEquals(index11.getType(), schema2.getTables()[0].getIndex(0).getType()); + assertEquals(index12, schema2.getTables()[0].getIndex(1)); + assertEquals(index12.getType(), schema2.getTables()[0].getIndex(1).getType()); + assertEquals(index13, schema2.getTables()[0].getIndex(2)); + assertEquals(index13.getType(), schema2.getTables()[0].getIndex(2).getType()); + + assertEquals(table2, schema2.getTables()[1]); + assertEquals(table2.getFieldCount(), schema2.getTables()[1].getFieldCount()); + assertEquals(field21, schema2.getTables()[1].getField(0)); + assertEquals(field22, schema2.getTables()[1].getField(1)); + assertEquals(field23, schema2.getTables()[1].getField(2)); + assertEquals(table2.getIndexCount(), schema2.getTables()[1].getIndexCount()); + assertEquals(index21, schema2.getTables()[1].getIndex(0)); + assertEquals(index21.getType(), schema2.getTables()[1].getIndex(0).getType()); + assertEquals(index22, schema2.getTables()[1].getIndex(1)); + assertEquals(index22.getType(), schema2.getTables()[1].getIndex(1).getType()); + assertEquals(index23, schema2.getTables()[1].getIndex(2)); + assertEquals(index23.getType(), schema2.getTables()[1].getIndex(2).getType()); } } diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/DBUtil.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/DBUtil.java index d8b77aa4e9..be29db9291 100644 --- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/DBUtil.java +++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/DBUtil.java @@ -18,6 +18,7 @@ import org.eclipse.net4j.internal.db.DBTransaction; import org.eclipse.net4j.internal.db.DataSourceConnectionProvider; import org.eclipse.net4j.internal.db.bundle.OM; import org.eclipse.net4j.spi.db.DBAdapter; +import org.eclipse.net4j.spi.db.DBNamedElement; import org.eclipse.net4j.spi.db.DBSchema; import org.eclipse.net4j.util.ReflectUtil; import org.eclipse.net4j.util.io.ExtendedDataInput; @@ -29,6 +30,7 @@ import org.eclipse.net4j.util.om.trace.ContextTracer; import javax.sql.DataSource; import java.io.IOException; +import java.io.Writer; import java.sql.Blob; import java.sql.Clob; import java.sql.Connection; @@ -141,10 +143,33 @@ public final class DBUtil /** * @since 4.2 */ - public static IDBDatabase openDatabase(IDBAdapter dbAdapter, IDBConnectionProvider dbConnectionProvider, - String schemaName) + public static String dumpToString(IDBNamedElement namedElement) { - return new DBDatabase((DBAdapter)dbAdapter, dbConnectionProvider, schemaName); + return ((DBNamedElement)namedElement).dumpToString(); + } + + /** + * @since 4.2 + */ + public static void dump(IDBNamedElement namedElement) + { + ((DBNamedElement)namedElement).dump(); + } + + /** + * @since 4.2 + */ + public static void dump(IDBNamedElement namedElement, Writer writer) throws IOException + { + ((DBNamedElement)namedElement).dump(writer); + } + + /** + * @since 4.2 + */ + public static IDBDatabase openDatabase(IDBAdapter adapter, IDBConnectionProvider connectionProvider, String schemaName) + { + return new DBDatabase((DBAdapter)adapter, connectionProvider, schemaName); } public static IDBSchema createSchema(String name) @@ -155,9 +180,17 @@ public final class DBUtil /** * @since 4.2 */ - public static IDBSchema readSchema(String name, Connection connection) + public static IDBSchema readSchema(IDBAdapter adapter, Connection connection, String name) + { + return adapter.readSchema(connection, name); + } + + /** + * @since 4.2 + */ + public static void readSchema(IDBAdapter adapter, Connection connection, IDBSchema schema) { - return new DBSchema(name, connection); + adapter.readSchema(connection, schema); } /** diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/IDBAdapter.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/IDBAdapter.java index b33026448c..00817f0ae1 100644 --- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/IDBAdapter.java +++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/IDBAdapter.java @@ -57,6 +57,16 @@ public interface IDBAdapter /** * @since 4.2 */ + public IDBSchema readSchema(Connection connection, String name); + + /** + * @since 4.2 + */ + public void readSchema(Connection connection, IDBSchema schema); + + /** + * @since 4.2 + */ public void updateSchema(Connection connection, IDBSchema schema, IDBSchemaDelta delta) throws DBException; public Set<IDBTable> createTables(Iterable<? extends IDBTable> tables, Connection connection) throws DBException; diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBDelta.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBDelta.java index 41cc7ab387..caac6a2c4e 100644 --- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBDelta.java +++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBDelta.java @@ -10,12 +10,12 @@ */ package org.eclipse.net4j.db.ddl.delta; -import org.eclipse.net4j.db.IDBElement; +import org.eclipse.net4j.db.IDBNamedElement; import org.eclipse.net4j.db.ddl.IDBSchema; import org.eclipse.net4j.db.ddl.IDBSchemaElement; +import org.eclipse.net4j.util.container.IContainer; import java.io.Serializable; -import java.util.Map; /** * @since 4.2 @@ -23,25 +23,25 @@ import java.util.Map; * @noextend This interface is not intended to be extended by clients. * @noimplement This interface is not intended to be implemented by clients. */ -public interface IDBDelta extends IDBElement, Serializable +public interface IDBDelta extends IDBNamedElement, IContainer<IDBDelta>, Comparable<IDBDelta>, Serializable { - public IDBDelta getParent(); + public DeltaType getDeltaType(); - public String getName(); + public IDBDelta getParent(); public ChangeKind getChangeKind(); - public <T> IDBPropertyDelta<T> getPropertyDelta(String name); - - public <T> T getPropertyValue(String name); - - public <T> T getPropertyValue(String name, boolean old); - - public Map<String, IDBPropertyDelta<?>> getPropertyDeltas(); - public void accept(IDBDeltaVisitor visitor); - public IDBSchemaElement getElement(IDBSchema schema); + public IDBSchemaElement getSchemaElement(IDBSchema schema); + + /** + * @author Eike Stepper + */ + public enum DeltaType + { + SCHEMA, TABLE, FIELD, INDEX, INDEX_FIELD, PROPERTY + } /** * @author Eike Stepper diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBDeltaVisitor.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBDeltaVisitor.java index 5efb7475fb..217a47129a 100644 --- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBDeltaVisitor.java +++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBDeltaVisitor.java @@ -10,12 +10,6 @@ */ package org.eclipse.net4j.db.ddl.delta; -import org.eclipse.net4j.db.DBType; -import org.eclipse.net4j.db.ddl.IDBField; -import org.eclipse.net4j.db.ddl.IDBIndex; -import org.eclipse.net4j.db.ddl.IDBIndexField; -import org.eclipse.net4j.db.ddl.IDBSchema; -import org.eclipse.net4j.db.ddl.IDBTable; import org.eclipse.net4j.db.ddl.delta.IDBDelta.ChangeKind; /** @@ -24,15 +18,17 @@ import org.eclipse.net4j.db.ddl.delta.IDBDelta.ChangeKind; */ public interface IDBDeltaVisitor { - public void visit(IDBSchemaDelta schemaDelta); + public void visit(IDBSchemaDelta delta); - public void visit(IDBTableDelta tableDelta); + public void visit(IDBTableDelta delta); - public void visit(IDBFieldDelta fieldDelta); + public void visit(IDBFieldDelta delta); - public void visit(IDBIndexDelta indexDelta); + public void visit(IDBIndexDelta delta); - public void visit(IDBIndexFieldDelta indexFieldDelta); + public void visit(IDBIndexFieldDelta delta); + + public void visit(IDBPropertyDelta<?> delta); /** * @author Eike Stepper @@ -227,114 +223,43 @@ public interface IDBDeltaVisitor { visitDefault(delta); } - } - - /** - * @author Eike Stepper - */ - public static class Applier extends IDBDeltaVisitor.Default - { - private final IDBSchema schema; - - public Applier(IDBSchema schema) - { - this.schema = schema; - } - - public final IDBSchema getSchema() - { - return schema; - } - - @Override - protected void added(IDBTableDelta delta) - { - String name = delta.getName(); - schema.addTable(name); - } - - @Override - protected void removed(IDBTableDelta delta) - { - IDBTable table = delta.getElement(schema); - table.remove(); - } - - @Override - protected void changed(IDBTableDelta delta) - { - } - - @Override - protected void added(IDBFieldDelta delta) - { - String name = delta.getName(); - DBType type = delta.getPropertyValue(IDBFieldDelta.TYPE_PROPERTY); - int precision = delta.getPropertyValue(IDBFieldDelta.PRECISION_PROPERTY); - int scale = delta.getPropertyValue(IDBFieldDelta.SCALE_PROPERTY); - boolean notNull = delta.getPropertyValue(IDBFieldDelta.NOT_NULL_PROPERTY); - - IDBTable table = delta.getParent().getElement(schema); - table.addField(name, type, precision, scale, notNull); - } - - @Override - protected void removed(IDBFieldDelta delta) - { - IDBField field = delta.getElement(schema); - field.remove(); - } - @Override - protected void changed(IDBFieldDelta delta) - { - } - - @Override - protected void added(IDBIndexDelta delta) + public void visit(IDBPropertyDelta<?> delta) { - String name = delta.getName(); - IDBIndex.Type type = delta.getPropertyValue(IDBIndexDelta.TYPE_PROPERTY); + ChangeKind changeKind = delta.getChangeKind(); + switch (changeKind) + { + case ADDED: + added(delta); + break; - IDBTable table = delta.getParent().getElement(schema); - table.addIndex(name, type); - } + case REMOVED: + removed(delta); + break; - @Override - protected void removed(IDBIndexDelta delta) - { - IDBIndex index = delta.getElement(schema); - index.remove(); - } + case CHANGED: + changed(delta); + break; - @Override - protected void changed(IDBIndexDelta delta) - { + default: + throw new IllegalStateException("Illegal change kind: " + changeKind); + } } - @Override - protected void added(IDBIndexFieldDelta delta) + protected void added(IDBPropertyDelta<?> delta) { - IDBIndexDelta parent = delta.getParent(); - IDBTable table = parent.getParent().getElement(schema); - - String name = delta.getName(); - IDBField field = table.getField(name); + visitDefault(delta); - IDBIndex index = parent.getElement(schema); - index.addIndexField(field); } - @Override - protected void removed(IDBIndexFieldDelta delta) + protected void removed(IDBPropertyDelta<?> delta) { - IDBIndexField indexField = delta.getElement(schema); - indexField.remove(); + visitDefault(delta); } - @Override - protected void changed(IDBIndexFieldDelta delta) + protected void changed(IDBPropertyDelta<?> delta) { + visitDefault(delta); } } } diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBTableElementDelta.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBDeltaWithPosition.java index eaeeac8e3d..d0f54fd1a3 100644 --- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBTableElementDelta.java +++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBDeltaWithPosition.java @@ -16,17 +16,9 @@ package org.eclipse.net4j.db.ddl.delta; * @noextend This interface is not intended to be extended by clients. * @noimplement This interface is not intended to be implemented by clients. */ -public interface IDBTableElementDelta extends IDBDelta, Comparable<IDBTableElementDelta> +public interface IDBDeltaWithPosition extends IDBDeltaWithProperties { - public IDBTableDelta getParent(); + public static final String POSITION_PROPERTY = "position"; - public Type getTableElementType(); - - /** - * @author Eike Stepper - */ - public enum Type - { - FIELD, INDEX - } + public int getPosition(); } diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBDeltaWithProperties.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBDeltaWithProperties.java new file mode 100644 index 0000000000..382afc7be8 --- /dev/null +++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBDeltaWithProperties.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2004 - 2012 Eike Stepper (Berlin, Germany) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + */ +package org.eclipse.net4j.db.ddl.delta; + +import java.util.Map; + +/** + * @since 4.2 + * @author Eike Stepper + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IDBDeltaWithProperties extends IDBDelta +{ + public <T> IDBPropertyDelta<T> getPropertyDelta(String name); + + public <T> T getPropertyValue(String name); + + public <T> T getPropertyValue(String name, boolean old); + + public Map<String, IDBPropertyDelta<?>> getPropertyDeltas(); + + public IDBPropertyDelta<?>[] getPropertyDeltasSortedByName(); +} diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBFieldDelta.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBFieldDelta.java index 2877d68480..1d66e0543f 100644 --- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBFieldDelta.java +++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBFieldDelta.java @@ -19,7 +19,7 @@ import org.eclipse.net4j.db.ddl.IDBSchema; * @noextend This interface is not intended to be extended by clients. * @noimplement This interface is not intended to be implemented by clients. */ -public interface IDBFieldDelta extends IDBTableElementDelta +public interface IDBFieldDelta extends IDBDeltaWithPosition { public static final String TYPE_PROPERTY = "type"; @@ -29,7 +29,7 @@ public interface IDBFieldDelta extends IDBTableElementDelta public static final String NOT_NULL_PROPERTY = "notNull"; - public static final String POSITION_PROPERTY = "position"; + public IDBTableDelta getParent(); - public IDBField getElement(IDBSchema schema); + public IDBField getSchemaElement(IDBSchema schema); } diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBIndexDelta.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBIndexDelta.java index def7c19ac3..0e81804731 100644 --- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBIndexDelta.java +++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBIndexDelta.java @@ -12,7 +12,6 @@ package org.eclipse.net4j.db.ddl.delta; import org.eclipse.net4j.db.ddl.IDBIndex; import org.eclipse.net4j.db.ddl.IDBSchema; -import org.eclipse.net4j.util.container.IContainer; import java.util.Map; @@ -22,13 +21,15 @@ import java.util.Map; * @noextend This interface is not intended to be extended by clients. * @noimplement This interface is not intended to be implemented by clients. */ -public interface IDBIndexDelta extends IDBTableElementDelta, IContainer<IDBIndexFieldDelta> +public interface IDBIndexDelta extends IDBDeltaWithProperties { public static final String TYPE_PROPERTY = "type"; - public IDBIndexFieldDelta[] getIndexFieldDeltasSortedByPosition(); + public IDBTableDelta getParent(); public Map<String, IDBIndexFieldDelta> getIndexFieldDeltas(); - public IDBIndex getElement(IDBSchema schema); + public IDBIndexFieldDelta[] getIndexFieldDeltasSortedByPosition(); + + public IDBIndex getSchemaElement(IDBSchema schema); } diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBIndexFieldDelta.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBIndexFieldDelta.java index 79bc4afd42..da5aec3211 100644 --- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBIndexFieldDelta.java +++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBIndexFieldDelta.java @@ -19,11 +19,9 @@ import org.eclipse.net4j.db.ddl.IDBSchema; * @noextend This interface is not intended to be extended by clients. * @noimplement This interface is not intended to be implemented by clients. */ -public interface IDBIndexFieldDelta extends IDBDelta, Comparable<IDBIndexFieldDelta> +public interface IDBIndexFieldDelta extends IDBDeltaWithPosition { - public static final String POSITION_PROPERTY = "position"; - public IDBIndexDelta getParent(); - public IDBIndexField getElement(IDBSchema schema); + public IDBIndexField getSchemaElement(IDBSchema schema); } diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBPropertyDelta.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBPropertyDelta.java index 7a209b7e23..39d15aefd5 100644 --- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBPropertyDelta.java +++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBPropertyDelta.java @@ -10,10 +10,6 @@ */ package org.eclipse.net4j.db.ddl.delta; -import org.eclipse.net4j.db.IDBElement; -import org.eclipse.net4j.db.ddl.delta.IDBDelta.ChangeKind; - -import java.io.Serializable; /** * @since 4.2 @@ -21,12 +17,8 @@ import java.io.Serializable; * @noextend This interface is not intended to be extended by clients. * @noimplement This interface is not intended to be implemented by clients. */ -public interface IDBPropertyDelta<T> extends IDBElement, Serializable +public interface IDBPropertyDelta<T> extends IDBDelta { - public String getName(); - - public ChangeKind getChangeKind(); - public IDBPropertyDelta.Type getType(); public T getValue(); diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBSchemaDelta.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBSchemaDelta.java index 261cce398e..cdb8daf61d 100644 --- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBSchemaDelta.java +++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBSchemaDelta.java @@ -11,7 +11,6 @@ package org.eclipse.net4j.db.ddl.delta; import org.eclipse.net4j.db.ddl.IDBSchema; -import org.eclipse.net4j.util.container.IContainer; import java.util.Map; @@ -21,11 +20,13 @@ import java.util.Map; * @noextend This interface is not intended to be extended by clients. * @noimplement This interface is not intended to be implemented by clients. */ -public interface IDBSchemaDelta extends IDBDelta, IContainer<IDBTableDelta>, Comparable<IDBSchemaDelta> +public interface IDBSchemaDelta extends IDBDelta { public Map<String, IDBTableDelta> getTableDeltas(); - public IDBSchema getElement(IDBSchema schema); + public IDBTableDelta[] getTableDeltasSortedByName(); + + public IDBSchema getSchemaElement(IDBSchema schema); public void applyTo(IDBSchema schema); } diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBTableDelta.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBTableDelta.java index ae169e8ac5..9457142c69 100644 --- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBTableDelta.java +++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/db/ddl/delta/IDBTableDelta.java @@ -12,7 +12,6 @@ package org.eclipse.net4j.db.ddl.delta; import org.eclipse.net4j.db.ddl.IDBSchema; import org.eclipse.net4j.db.ddl.IDBTable; -import org.eclipse.net4j.util.container.IContainer; import java.util.Map; @@ -22,15 +21,17 @@ import java.util.Map; * @noextend This interface is not intended to be extended by clients. * @noimplement This interface is not intended to be implemented by clients. */ -public interface IDBTableDelta extends IDBDelta, IContainer<IDBTableElementDelta>, Comparable<IDBTableDelta> +public interface IDBTableDelta extends IDBDelta { public IDBSchemaDelta getParent(); - public IDBFieldDelta[] getFieldDeltasSortedByPosition(); - public Map<String, IDBFieldDelta> getFieldDeltas(); public Map<String, IDBIndexDelta> getIndexDeltas(); - public IDBTable getElement(IDBSchema schema); + public IDBFieldDelta[] getFieldDeltasSortedByPosition(); + + public IDBIndexDelta[] getIndexDeltasSortedByName(); + + public IDBTable getSchemaElement(IDBSchema schema); } diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBDatabase.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBDatabase.java index ded98ac7a4..ed44f62b30 100644 --- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBDatabase.java +++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/DBDatabase.java @@ -27,8 +27,6 @@ import java.sql.SQLException; */ public final class DBDatabase extends SetContainer<IDBTransaction> implements IDBDatabase { - // private final Set<DBTransaction> transactions = new HashSet<DBTransaction>(); - private DBAdapter adapter; private IDBConnectionProvider connectionProvider; @@ -39,7 +37,7 @@ public final class DBDatabase extends SetContainer<IDBTransaction> implements ID private int statementCacheCapacity = DEFAULT_STATEMENT_CACHE_CAPACITY; - public DBDatabase(DBAdapter adapter, IDBConnectionProvider dbConnectionProvider, final String schemaName) + public DBDatabase(final DBAdapter adapter, IDBConnectionProvider dbConnectionProvider, final String schemaName) { super(IDBTransaction.class); this.adapter = adapter; @@ -49,7 +47,7 @@ public final class DBDatabase extends SetContainer<IDBTransaction> implements ID { public DBSchema run(Connection connection) throws SQLException { - return (DBSchema)DBUtil.readSchema(schemaName, connection); + return (DBSchema)adapter.readSchema(connection, schemaName); } }); diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/DBField.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/DBField.java index 2ceca70b62..c9f563a14f 100644 --- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/DBField.java +++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/DBField.java @@ -14,12 +14,20 @@ import org.eclipse.net4j.db.DBType; import org.eclipse.net4j.db.ddl.IDBField; import org.eclipse.net4j.db.ddl.IDBSchema; import org.eclipse.net4j.spi.db.DBSchemaElement; +import org.eclipse.net4j.util.StringUtil; + +import java.io.IOException; +import java.io.Writer; /** * @author Eike Stepper */ public class DBField extends DBSchemaElement implements IDBField { + public static final int DEFAULT_BOOLEAN_PRECISION = 1; + + public static final int DEFAULT_INTEGER_PRECISION = 10; + public static final int DEFAULT_DECIMAL_PRECISION = 5; public static final int DEFAULT_PRECISION = 0; @@ -89,6 +97,12 @@ public class DBField extends DBSchemaElement implements IDBField { switch (type) { + case BOOLEAN: + return DEFAULT_BOOLEAN_PRECISION; + + case INTEGER: + return DEFAULT_INTEGER_PRECISION; + case CHAR: return DEFAULT_CHAR_LENGTH; @@ -180,6 +194,25 @@ public class DBField extends DBSchemaElement implements IDBField return "(" + getPrecision() + ")"; //$NON-NLS-1$ //$NON-NLS-2$ } - return "(" + getPrecision() + ", " + scale + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + return "(" + getPrecision() + ", " + getScale() + ")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } + + @Override + public void dump(Writer writer) throws IOException + { + writer.append(" FIELD "); + writer.append(getName()); + writer.append(" (position="); + writer.append(String.valueOf(getPosition())); + writer.append(", type="); + writer.append(getType().toString()); + writer.append(", precision="); + writer.append(String.valueOf(getPrecision())); + writer.append(", scale="); + writer.append(String.valueOf(getScale())); + writer.append(", notNull="); + writer.append(String.valueOf(isNotNull())); + writer.append(")"); + writer.append(StringUtil.NL); } } diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/DBIndex.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/DBIndex.java index 046f11d37e..89f537e73e 100644 --- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/DBIndex.java +++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/DBIndex.java @@ -16,7 +16,10 @@ import org.eclipse.net4j.db.ddl.IDBIndex; import org.eclipse.net4j.db.ddl.IDBIndexField; import org.eclipse.net4j.spi.db.DBSchema; import org.eclipse.net4j.spi.db.DBSchemaElement; +import org.eclipse.net4j.util.StringUtil; +import java.io.IOException; +import java.io.Writer; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -96,6 +99,11 @@ public class DBIndex extends DBSchemaElement implements IDBIndex { table.getSchema().assertUnlocked(); + if (!field.isNotNull()) + { + throw new DBException("Index field is nullable: " + field); //$NON-NLS-1$ + } + if (field.getTable() != table) { throw new DBException("Index field is from different table: " + field); //$NON-NLS-1$ @@ -192,4 +200,19 @@ public class DBIndex extends DBSchemaElement implements IDBIndex { table.removeIndex(this); } + + @Override + public void dump(Writer writer) throws IOException + { + writer.append(" INDEX "); + writer.append(getName()); + writer.append(" (type="); + writer.append(String.valueOf(getType())); + writer.append(")"); + writer.append(StringUtil.NL); + for (DBIndexField indexField : indexFields) + { + indexField.dump(writer); + } + } } diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/DBIndexField.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/DBIndexField.java index 7137160554..b74b902113 100644 --- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/DBIndexField.java +++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/DBIndexField.java @@ -13,6 +13,10 @@ package org.eclipse.net4j.internal.db.ddl; import org.eclipse.net4j.db.ddl.IDBIndexField; import org.eclipse.net4j.db.ddl.IDBSchema; import org.eclipse.net4j.spi.db.DBSchemaElement; +import org.eclipse.net4j.util.StringUtil; + +import java.io.IOException; +import java.io.Writer; /** * @author Eike Stepper @@ -77,4 +81,15 @@ public class DBIndexField extends DBSchemaElement implements IDBIndexField { index.removeIndexField(this); } + + @Override + public void dump(Writer writer) throws IOException + { + writer.append(" FIELD "); + writer.append(getName()); + writer.append(" (position="); + writer.append(String.valueOf(getPosition())); + writer.append(")"); + writer.append(StringUtil.NL); + } } diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/DBTable.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/DBTable.java index 35dfd9bb66..0d0f2184fe 100644 --- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/DBTable.java +++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/DBTable.java @@ -18,7 +18,10 @@ import org.eclipse.net4j.db.ddl.IDBIndex.Type; import org.eclipse.net4j.db.ddl.IDBTable; import org.eclipse.net4j.spi.db.DBSchema; import org.eclipse.net4j.spi.db.DBSchemaElement; +import org.eclipse.net4j.util.StringUtil; +import java.io.IOException; +import java.io.Writer; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -153,6 +156,17 @@ public class DBTable extends DBSchemaElement implements IDBTable throw new DBException("Index exists: " + name); //$NON-NLS-1$ } + if (type == Type.PRIMARY_KEY) + { + for (DBIndex index : getIndices()) + { + if (index.getType() == Type.PRIMARY_KEY) + { + throw new DBException("Primary key exists: " + index); //$NON-NLS-1$ + } + } + } + DBIndex index = new DBIndex(this, name, type, fields, position); indices.add(index); return index; @@ -246,4 +260,22 @@ public class DBTable extends DBSchemaElement implements IDBTable builder.append(")"); //$NON-NLS-1$ return builder.toString(); } + + @Override + public void dump(Writer writer) throws IOException + { + writer.append(" TABLE "); + writer.append(getName()); + writer.append(StringUtil.NL); + + for (DBField field : fields) + { + field.dump(writer); + } + + for (DBIndex index : indices) + { + index.dump(writer); + } + } } diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBDelta.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBDelta.java index f704072134..639b070d4a 100644 --- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBDelta.java +++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBDelta.java @@ -12,28 +12,32 @@ package org.eclipse.net4j.internal.db.ddl.delta; import org.eclipse.net4j.db.ddl.IDBSchemaElement; import org.eclipse.net4j.db.ddl.delta.IDBDelta; -import org.eclipse.net4j.db.ddl.delta.IDBFieldDelta; -import org.eclipse.net4j.db.ddl.delta.IDBPropertyDelta; +import org.eclipse.net4j.db.ddl.delta.IDBDeltaVisitor; +import org.eclipse.net4j.db.ddl.delta.IDBDeltaWithPosition; import org.eclipse.net4j.spi.db.DBNamedElement; import org.eclipse.net4j.spi.db.DBSchemaElement; +import org.eclipse.net4j.util.StringUtil; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.Map; +import java.io.IOException; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; /** * @author Eike Stepper */ public abstract class DBDelta extends DBNamedElement implements IDBDelta { + private static final IDBDelta[] NO_ELEMENTS = {}; + private static final long serialVersionUID = 1L; private DBDelta parent; private ChangeKind changeKind; - private Map<String, IDBPropertyDelta<?>> propertyDeltas = new HashMap<String, IDBPropertyDelta<?>>(); + private transient IDBDelta[] elements; public DBDelta(DBDelta parent, String name, ChangeKind changeKind) { @@ -59,44 +63,105 @@ public abstract class DBDelta extends DBNamedElement implements IDBDelta return changeKind; } - public <T> DBPropertyDelta<T> getPropertyDelta(String name) + public final int compareTo(IDBDelta delta2) { - name = name(name); + int result = getDeltaType().compareTo(delta2.getDeltaType()); + if (result == 0) + { + if (this instanceof IDBDeltaWithPosition && delta2 instanceof IDBDeltaWithPosition) + { + IDBDeltaWithPosition withPosition1 = (IDBDeltaWithPosition)this; + IDBDeltaWithPosition withPosition2 = (IDBDeltaWithPosition)delta2; + return withPosition1.getPosition() - withPosition2.getPosition(); + } + + result = getName().compareTo(delta2.getName()); + } - @SuppressWarnings("unchecked") - DBPropertyDelta<T> propertyDelta = (DBPropertyDelta<T>)propertyDeltas.get(name); - return propertyDelta; + return result; } - public <T> T getPropertyValue(String name) + public final void accept(IDBDeltaVisitor visitor) { - return getPropertyValue(name, false); + doAccept(visitor); + + IDBDelta[] deltas = getElements(); + for (IDBDelta delta : deltas) + { + delta.accept(visitor); + } } - public <T> T getPropertyValue(String name, boolean old) + protected abstract void doAccept(IDBDeltaVisitor visitor); + + public final boolean isEmpty() { - IDBPropertyDelta<T> propertyDelta = getPropertyDelta(name); - if (propertyDelta == null) + return getElements().length == 0; + } + + public final IDBDelta[] getElements() + { + if (elements == null) { - return null; + List<IDBDelta> deltas = new ArrayList<IDBDelta>(); + collectElements(deltas); + + if (deltas.isEmpty()) + { + elements = NO_ELEMENTS; + } + else + { + elements = deltas.toArray(new IDBDelta[deltas.size()]); + Arrays.sort(elements); + } } - if (old) + return elements; + } + + protected final void resetElements() + { + elements = null; + } + + protected abstract void collectElements(List<IDBDelta> elements); + + @Override + public void dump(Writer writer) throws IOException + { + int level = getLevel(); + for (int i = 0; i < level; i++) { - return propertyDelta.getOldValue(); + writer.append(" "); } - return propertyDelta.getValue(); + writer.append(getChangeKind().toString()); + writer.append(" "); + writer.append(getDeltaType().toString()); + writer.append(" "); + writer.append(getName()); + dumpAdditionalProperties(writer); + writer.append(StringUtil.NL); + + for (IDBDelta delta : getElements()) + { + ((DBDelta)delta).dump(writer); + } } - public final Map<String, IDBPropertyDelta<?>> getPropertyDeltas() + protected void dumpAdditionalProperties(Writer writer) throws IOException { - return Collections.unmodifiableMap(propertyDeltas); } - public final void addPropertyDelta(IDBPropertyDelta<?> propertyDelta) + private int getLevel() { - propertyDeltas.put(propertyDelta.getName(), propertyDelta); + if (parent == null) + { + return 0; + } + + return parent.getLevel() + 1; } public static String getName(IDBSchemaElement element, IDBSchemaElement oldElement) @@ -140,28 +205,4 @@ public abstract class DBDelta extends DBNamedElement implements IDBDelta { public void compare(T element, T oldElement); } - - /** - * @author Eike Stepper - */ - public static final class PositionComparator implements Comparator<IDBDelta> - { - public int compare(IDBDelta delta1, IDBDelta delta2) - { - int v1 = getValue(delta1); - int v2 = getValue(delta2); - return v2 - v1; - } - - private Integer getValue(IDBDelta delta) - { - Integer value = delta.getPropertyValue(IDBFieldDelta.POSITION_PROPERTY); - if (value == null) - { - return 0; - } - - return value; - } - } } diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBTableElementDelta.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBDeltaWithPosition.java index 6991d5e078..8e93cd8b54 100644 --- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBTableElementDelta.java +++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBDeltaWithPosition.java @@ -10,16 +10,16 @@ */ package org.eclipse.net4j.internal.db.ddl.delta; -import org.eclipse.net4j.db.ddl.delta.IDBTableElementDelta; +import org.eclipse.net4j.db.ddl.delta.IDBDeltaWithPosition; /** * @author Eike Stepper */ -public abstract class DBTableElementDelta extends DBDelta implements IDBTableElementDelta +public abstract class DBDeltaWithPosition extends DBDeltaWithProperties implements IDBDeltaWithPosition { private static final long serialVersionUID = 1L; - public DBTableElementDelta(DBDelta parent, String name, ChangeKind changeKind) + public DBDeltaWithPosition(DBDelta parent, String name, ChangeKind changeKind) { super(parent, name, changeKind); } @@ -27,24 +27,18 @@ public abstract class DBTableElementDelta extends DBDelta implements IDBTableEle /** * Constructor for deserialization. */ - protected DBTableElementDelta() + protected DBDeltaWithPosition() { } - @Override - public DBTableDelta getParent() + public int getPosition() { - return (DBTableDelta)super.getParent(); - } - - public int compareTo(IDBTableElementDelta o) - { - int result = getTableElementType().compareTo(o.getTableElementType()); - if (result == 0) + Integer value = getPropertyValue(POSITION_PROPERTY); + if (value == null) { - result = getName().compareTo(o.getName()); + return 0; } - return result; + return value; } } diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBDeltaWithProperties.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBDeltaWithProperties.java new file mode 100644 index 0000000000..23081ff6d7 --- /dev/null +++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBDeltaWithProperties.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2004 - 2012 Eike Stepper (Berlin, Germany) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Eike Stepper - initial API and implementation + */ +package org.eclipse.net4j.internal.db.ddl.delta; + +import org.eclipse.net4j.db.ddl.delta.IDBDelta; +import org.eclipse.net4j.db.ddl.delta.IDBDeltaWithPosition; +import org.eclipse.net4j.db.ddl.delta.IDBDeltaWithProperties; +import org.eclipse.net4j.db.ddl.delta.IDBPropertyDelta; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author Eike Stepper + */ +public abstract class DBDeltaWithProperties extends DBDelta implements IDBDeltaWithProperties +{ + private static final long serialVersionUID = 1L; + + private Map<String, IDBPropertyDelta<?>> propertyDeltas = new HashMap<String, IDBPropertyDelta<?>>(); + + public DBDeltaWithProperties(DBDelta parent, String name, ChangeKind changeKind) + { + super(parent, name, changeKind); + } + + /** + * Constructor for deserialization. + */ + protected DBDeltaWithProperties() + { + } + + public <T> DBPropertyDelta<T> getPropertyDelta(String name) + { + name = name(name); + + @SuppressWarnings("unchecked") + DBPropertyDelta<T> propertyDelta = (DBPropertyDelta<T>)propertyDeltas.get(name); + return propertyDelta; + } + + public <T> T getPropertyValue(String name) + { + return getPropertyValue(name, false); + } + + public <T> T getPropertyValue(String name, boolean old) + { + IDBPropertyDelta<T> propertyDelta = getPropertyDelta(name); + if (propertyDelta == null) + { + return null; + } + + if (old) + { + return propertyDelta.getOldValue(); + } + + return propertyDelta.getValue(); + } + + public final Map<String, IDBPropertyDelta<?>> getPropertyDeltas() + { + return Collections.unmodifiableMap(propertyDeltas); + } + + public IDBPropertyDelta<?>[] getPropertyDeltasSortedByName() + { + DBPropertyDelta<?>[] result = propertyDeltas.values().toArray(new DBPropertyDelta[propertyDeltas.size()]); + Arrays.sort(result); + return result; + } + + public final void addPropertyDelta(IDBPropertyDelta<?> propertyDelta) + { + String name = propertyDelta.getName(); + propertyDeltas.put(name, propertyDelta); + resetElements(); + + if (IDBDeltaWithPosition.POSITION_PROPERTY.equals(name)) + { + DBDelta parent = getParent(); + if (parent != null) + { + parent.resetElements(); + } + } + } + + @Override + protected void collectElements(List<IDBDelta> elements) + { + elements.addAll(propertyDeltas.values()); + } +} diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBFieldDelta.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBFieldDelta.java index 36c613e2b5..685acdfdd1 100644 --- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBFieldDelta.java +++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBFieldDelta.java @@ -24,7 +24,7 @@ import java.text.MessageFormat; /** * @author Eike Stepper */ -public final class DBFieldDelta extends DBTableElementDelta implements IDBFieldDelta +public final class DBFieldDelta extends DBDeltaWithPosition implements IDBFieldDelta { private static final long serialVersionUID = 1L; @@ -41,14 +41,14 @@ public final class DBFieldDelta extends DBTableElementDelta implements IDBFieldD DBType oldType = oldField == null ? null : oldField.getType(); if (!ObjectUtil.equals(type, oldType)) { - addPropertyDelta(new DBPropertyDelta<DBType>(TYPE_PROPERTY, IDBPropertyDelta.Type.STRING, type, oldType)); + addPropertyDelta(new DBPropertyDelta<DBType>(this, TYPE_PROPERTY, IDBPropertyDelta.Type.STRING, type, oldType)); } Integer precision = field == null ? null : field.getPrecision(); Integer oldPrecision = oldField == null ? null : oldField.getPrecision(); if (!ObjectUtil.equals(precision, oldPrecision)) { - addPropertyDelta(new DBPropertyDelta<Integer>(PRECISION_PROPERTY, IDBPropertyDelta.Type.INTEGER, precision, + addPropertyDelta(new DBPropertyDelta<Integer>(this, PRECISION_PROPERTY, IDBPropertyDelta.Type.INTEGER, precision, oldPrecision)); } @@ -56,22 +56,23 @@ public final class DBFieldDelta extends DBTableElementDelta implements IDBFieldD Integer oldScale = oldField == null ? null : oldField.getScale(); if (!ObjectUtil.equals(scale, oldScale)) { - addPropertyDelta(new DBPropertyDelta<Integer>(SCALE_PROPERTY, IDBPropertyDelta.Type.INTEGER, scale, oldScale)); + addPropertyDelta(new DBPropertyDelta<Integer>(this, SCALE_PROPERTY, IDBPropertyDelta.Type.INTEGER, scale, + oldScale)); } Boolean notNull = field == null ? null : field.isNotNull(); Boolean oldNotNull = oldField == null ? null : oldField.isNotNull(); if (!ObjectUtil.equals(notNull, oldNotNull)) { - addPropertyDelta(new DBPropertyDelta<Boolean>(NOT_NULL_PROPERTY, IDBPropertyDelta.Type.BOOLEAN, notNull, + addPropertyDelta(new DBPropertyDelta<Boolean>(this, NOT_NULL_PROPERTY, IDBPropertyDelta.Type.BOOLEAN, notNull, oldNotNull)); } - Integer position = oldField == null ? null : field.getPosition(); + Integer position = field == null ? null : field.getPosition(); Integer oldPosition = oldField == null ? null : oldField.getPosition(); if (!ObjectUtil.equals(position, oldPosition)) { - addPropertyDelta(new DBPropertyDelta<Integer>(POSITION_PROPERTY, IDBPropertyDelta.Type.INTEGER, position, + addPropertyDelta(new DBPropertyDelta<Integer>(this, POSITION_PROPERTY, IDBPropertyDelta.Type.INTEGER, position, oldPosition)); } } @@ -83,19 +84,20 @@ public final class DBFieldDelta extends DBTableElementDelta implements IDBFieldD { } - public Type getTableElementType() + public DeltaType getDeltaType() { - return Type.FIELD; + return DeltaType.FIELD; } - public void accept(IDBDeltaVisitor visitor) + @Override + public DBTableDelta getParent() { - visitor.visit(this); + return (DBTableDelta)super.getParent(); } - public DBField getElement(IDBSchema schema) + public DBField getSchemaElement(IDBSchema schema) { - DBTable table = getParent().getElement(schema); + DBTable table = getParent().getSchemaElement(schema); if (table == null) { return null; @@ -110,4 +112,10 @@ public final class DBFieldDelta extends DBTableElementDelta implements IDBFieldD return MessageFormat.format("DBFieldDelta[name={0}, kind={1}, propertyDeltas={2}]", getName(), getChangeKind(), getPropertyDeltas().values()); } + + @Override + protected void doAccept(IDBDeltaVisitor visitor) + { + visitor.visit(this); + } } diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBIndexDelta.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBIndexDelta.java index 44a285edba..2ba9c0f9c5 100644 --- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBIndexDelta.java +++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBIndexDelta.java @@ -13,6 +13,7 @@ package org.eclipse.net4j.internal.db.ddl.delta; import org.eclipse.net4j.db.ddl.IDBIndex; import org.eclipse.net4j.db.ddl.IDBIndexField; import org.eclipse.net4j.db.ddl.IDBSchema; +import org.eclipse.net4j.db.ddl.delta.IDBDelta; import org.eclipse.net4j.db.ddl.delta.IDBDeltaVisitor; import org.eclipse.net4j.db.ddl.delta.IDBIndexDelta; import org.eclipse.net4j.db.ddl.delta.IDBIndexFieldDelta; @@ -26,19 +27,16 @@ import java.text.MessageFormat; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; /** * @author Eike Stepper */ -public final class DBIndexDelta extends DBTableElementDelta implements IDBIndexDelta +public final class DBIndexDelta extends DBDeltaWithProperties implements IDBIndexDelta { private static final long serialVersionUID = 1L; - private IDBIndex.Type type; - - private IDBIndex.Type oldType; - private Map<String, IDBIndexFieldDelta> indexFieldDeltas = new HashMap<String, IDBIndexFieldDelta>(); public DBIndexDelta(DBDelta parent, String name, ChangeKind changeKind) @@ -54,7 +52,8 @@ public final class DBIndexDelta extends DBTableElementDelta implements IDBIndexD IDBIndex.Type oldType = oldIndex == null ? null : oldIndex.getType(); if (!ObjectUtil.equals(type, oldType)) { - addPropertyDelta(new DBPropertyDelta<IDBIndex.Type>(TYPE_PROPERTY, IDBPropertyDelta.Type.STRING, type, oldType)); + addPropertyDelta(new DBPropertyDelta<IDBIndex.Type>(this, TYPE_PROPERTY, IDBPropertyDelta.Type.STRING, type, + oldType)); } IDBIndexField[] indexFields = index == null ? DBIndex.NO_INDEX_FIELDS : index.getIndexFields(); @@ -65,7 +64,10 @@ public final class DBIndexDelta extends DBTableElementDelta implements IDBIndexD { DBIndexFieldDelta indexFieldDelta = new DBIndexFieldDelta(DBIndexDelta.this, (DBIndexField)indexField, (DBIndexField)oldIndexField); - addIndexFieldDelta(indexFieldDelta); + if (!indexFieldDelta.isEmpty()) + { + addIndexFieldDelta(indexFieldDelta); + } } }); } @@ -77,82 +79,63 @@ public final class DBIndexDelta extends DBTableElementDelta implements IDBIndexD { } - public Type getTableElementType() - { - return Type.INDEX; - } - - public IDBIndex.Type getType() + public DeltaType getDeltaType() { - return type; + return DeltaType.INDEX; } - public void setType(IDBIndex.Type type) - { - this.type = type; - } - - public IDBIndex.Type getOldType() + @Override + public DBTableDelta getParent() { - return oldType; + return (DBTableDelta)super.getParent(); } - public void setOldType(IDBIndex.Type oldType) + public Map<String, IDBIndexFieldDelta> getIndexFieldDeltas() { - this.oldType = oldType; + return Collections.unmodifiableMap(indexFieldDeltas); } public DBIndexFieldDelta[] getIndexFieldDeltasSortedByPosition() { DBIndexFieldDelta[] result = indexFieldDeltas.values().toArray(new DBIndexFieldDelta[indexFieldDeltas.size()]); - Arrays.sort(result, new PositionComparator()); + Arrays.sort(result); return result; } - public Map<String, IDBIndexFieldDelta> getIndexFieldDeltas() + public DBIndex getSchemaElement(IDBSchema schema) { - return Collections.unmodifiableMap(indexFieldDeltas); - } + DBTable table = getParent().getSchemaElement(schema); + if (table == null) + { + return null; + } - public boolean isEmpty() - { - return indexFieldDeltas.isEmpty(); + return table.getIndex(getName()); } - public DBIndexFieldDelta[] getElements() + @Override + public String toString() { - return getIndexFieldDeltasSortedByPosition(); + return MessageFormat.format("DBIndexDelta[name={0}, kind={1}, propertyDeltas={2}, indexFieldDeltas={3}]", + getName(), getChangeKind(), getPropertyDeltas().values(), indexFieldDeltas.values()); } public void addIndexFieldDelta(DBIndexFieldDelta indexFieldDelta) { indexFieldDeltas.put(indexFieldDelta.getName(), indexFieldDelta); + resetElements(); } - public void accept(IDBDeltaVisitor visitor) + @Override + protected void doAccept(IDBDeltaVisitor visitor) { visitor.visit(this); - for (IDBIndexFieldDelta indexFieldDelta : getIndexFieldDeltasSortedByPosition()) - { - indexFieldDelta.accept(visitor); - } - } - - public DBIndex getElement(IDBSchema schema) - { - DBTable table = getParent().getElement(schema); - if (table == null) - { - return null; - } - - return table.getIndex(getName()); } @Override - public String toString() + protected void collectElements(List<IDBDelta> elements) { - return MessageFormat.format("DBIndexDelta[name={0}, kind={1}, propertyDeltas={2}, indexFieldDeltas={3}]", - getName(), getChangeKind(), getPropertyDeltas().values(), indexFieldDeltas.values()); + elements.addAll(indexFieldDeltas.values()); + super.collectElements(elements); } } diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBIndexFieldDelta.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBIndexFieldDelta.java index aef40665ae..3afebddd83 100644 --- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBIndexFieldDelta.java +++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBIndexFieldDelta.java @@ -23,7 +23,7 @@ import java.text.MessageFormat; /** * @author Eike Stepper */ -public final class DBIndexFieldDelta extends DBDelta implements IDBIndexFieldDelta +public final class DBIndexFieldDelta extends DBDeltaWithPosition implements IDBIndexFieldDelta { private static final long serialVersionUID = 1L; @@ -40,7 +40,7 @@ public final class DBIndexFieldDelta extends DBDelta implements IDBIndexFieldDel Integer oldPosition = oldIndexField == null ? null : oldIndexField.getPosition(); if (!ObjectUtil.equals(position, oldPosition)) { - addPropertyDelta(new DBPropertyDelta<Integer>(POSITION_PROPERTY, IDBPropertyDelta.Type.INTEGER, position, + addPropertyDelta(new DBPropertyDelta<Integer>(this, POSITION_PROPERTY, IDBPropertyDelta.Type.INTEGER, position, oldPosition)); } } @@ -52,25 +52,20 @@ public final class DBIndexFieldDelta extends DBDelta implements IDBIndexFieldDel { } - @Override - public DBIndexDelta getParent() - { - return (DBIndexDelta)super.getParent(); - } - - public int compareTo(IDBIndexFieldDelta o) + public DeltaType getDeltaType() { - return getName().compareTo(o.getName()); + return DeltaType.INDEX_FIELD; } - public void accept(IDBDeltaVisitor visitor) + @Override + public DBIndexDelta getParent() { - visitor.visit(this); + return (DBIndexDelta)super.getParent(); } - public DBIndexField getElement(IDBSchema schema) + public DBIndexField getSchemaElement(IDBSchema schema) { - DBIndex index = getParent().getElement(schema); + DBIndex index = getParent().getSchemaElement(schema); if (index == null) { return null; @@ -85,4 +80,10 @@ public final class DBIndexFieldDelta extends DBDelta implements IDBIndexFieldDel return MessageFormat.format("DBIndexFieldDelta[name={0}, kind={1}, propertyDeltas={2}]", getName(), getChangeKind(), getPropertyDeltas().values()); } + + @Override + protected void doAccept(IDBDeltaVisitor visitor) + { + visitor.visit(this); + } } diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBPropertyDelta.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBPropertyDelta.java index 08f961a8e8..aa1b8a0bf1 100644 --- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBPropertyDelta.java +++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBPropertyDelta.java @@ -10,16 +10,21 @@ */ package org.eclipse.net4j.internal.db.ddl.delta; -import org.eclipse.net4j.db.ddl.delta.IDBDelta.ChangeKind; +import org.eclipse.net4j.db.ddl.IDBSchema; +import org.eclipse.net4j.db.ddl.IDBSchemaElement; +import org.eclipse.net4j.db.ddl.delta.IDBDelta; +import org.eclipse.net4j.db.ddl.delta.IDBDeltaVisitor; import org.eclipse.net4j.db.ddl.delta.IDBPropertyDelta; -import org.eclipse.net4j.spi.db.DBNamedElement; +import java.io.IOException; +import java.io.Writer; import java.text.MessageFormat; +import java.util.List; /** * @author Eike Stepper */ -public final class DBPropertyDelta<T> extends DBNamedElement implements IDBPropertyDelta<T> +public final class DBPropertyDelta<T> extends DBDelta implements IDBPropertyDelta<T> { private static final long serialVersionUID = 1L; @@ -29,9 +34,9 @@ public final class DBPropertyDelta<T> extends DBNamedElement implements IDBPrope private T oldValue; - public DBPropertyDelta(String name, Type type, T value, T oldValue) + public DBPropertyDelta(DBDelta parent, String name, Type type, T value, T oldValue) { - super(name); + super(parent, name, DBDelta.getChangeKind(value, oldValue)); this.type = type; this.value = value; this.oldValue = oldValue; @@ -44,9 +49,14 @@ public final class DBPropertyDelta<T> extends DBNamedElement implements IDBPrope { } - public ChangeKind getChangeKind() + public DeltaType getDeltaType() { - return DBDelta.getChangeKind(value, oldValue); + return DeltaType.PROPERTY; + } + + public IDBSchemaElement getSchemaElement(IDBSchema schema) + { + return null; } public Type getType() @@ -70,4 +80,38 @@ public final class DBPropertyDelta<T> extends DBNamedElement implements IDBPrope return MessageFormat.format("DBPropertyDelta[name={0}, kind={1}, type={2}, value={3}, oldValue={4}]", getName(), getChangeKind(), getType(), getValue(), getOldValue()); } + + @Override + protected void doAccept(IDBDeltaVisitor visitor) + { + visitor.visit(this); + } + + @Override + protected void collectElements(List<IDBDelta> elements) + { + // Do nothing + } + + @Override + protected void dumpAdditionalProperties(Writer writer) throws IOException + { + writer.append(" (type="); + writer.append(getType().toString()); + writer.append(", value="); + writer.append(toString(getValue())); + writer.append(", oldValue="); + writer.append(toString(getOldValue())); + writer.append(")"); + } + + private static CharSequence toString(Object object) + { + if (object == null) + { + return "null"; + } + + return object.toString(); + } } diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBSchemaDelta.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBSchemaDelta.java index 93defc4a6b..279694f3e0 100644 --- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBSchemaDelta.java +++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBSchemaDelta.java @@ -10,9 +10,17 @@ */ package org.eclipse.net4j.internal.db.ddl.delta; +import org.eclipse.net4j.db.DBType; +import org.eclipse.net4j.db.ddl.IDBField; +import org.eclipse.net4j.db.ddl.IDBIndex; +import org.eclipse.net4j.db.ddl.IDBIndexField; import org.eclipse.net4j.db.ddl.IDBSchema; import org.eclipse.net4j.db.ddl.IDBTable; +import org.eclipse.net4j.db.ddl.delta.IDBDelta; import org.eclipse.net4j.db.ddl.delta.IDBDeltaVisitor; +import org.eclipse.net4j.db.ddl.delta.IDBFieldDelta; +import org.eclipse.net4j.db.ddl.delta.IDBIndexDelta; +import org.eclipse.net4j.db.ddl.delta.IDBIndexFieldDelta; import org.eclipse.net4j.db.ddl.delta.IDBSchemaDelta; import org.eclipse.net4j.db.ddl.delta.IDBTableDelta; import org.eclipse.net4j.internal.db.ddl.DBTable; @@ -22,6 +30,7 @@ import java.text.MessageFormat; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; /** @@ -49,7 +58,10 @@ public final class DBSchemaDelta extends DBDelta implements IDBSchemaDelta public void compare(IDBTable table, IDBTable oldTable) { DBTableDelta tableDelta = new DBTableDelta(DBSchemaDelta.this, (DBTable)table, (DBTable)oldTable); - addTableDelta(tableDelta); + if (!tableDelta.isEmpty()) + { + addTableDelta(tableDelta); + } } }); } @@ -61,50 +73,37 @@ public final class DBSchemaDelta extends DBDelta implements IDBSchemaDelta { } - public Map<String, IDBTableDelta> getTableDeltas() - { - return Collections.unmodifiableMap(tableDeltas); - } - - public boolean isEmpty() + public DeltaType getDeltaType() { - return tableDeltas.isEmpty(); + return DeltaType.SCHEMA; } - public DBTableDelta[] getElements() + public Map<String, IDBTableDelta> getTableDeltas() { - DBTableDelta[] elements = tableDeltas.values().toArray(new DBTableDelta[tableDeltas.size()]); - Arrays.sort(elements); - return elements; + return Collections.unmodifiableMap(tableDeltas); } - public int compareTo(IDBSchemaDelta o) + public IDBTableDelta[] getTableDeltasSortedByName() { - return getName().compareTo(o.getName()); + IDBTableDelta[] result = tableDeltas.values().toArray(new IDBTableDelta[tableDeltas.size()]); + Arrays.sort(result); + return result; } public void addTableDelta(IDBTableDelta tableDelta) { tableDeltas.put(tableDelta.getName(), tableDelta); + resetElements(); } - public void accept(IDBDeltaVisitor visitor) - { - visitor.visit(this); - for (DBTableDelta tableDelta : getElements()) - { - tableDelta.accept(visitor); - } - } - - public DBSchema getElement(IDBSchema schema) + public DBSchema getSchemaElement(IDBSchema schema) { return (DBSchema)schema; } public void applyTo(IDBSchema schema) { - IDBDeltaVisitor visitor = new IDBDeltaVisitor.Applier(schema); + IDBDeltaVisitor visitor = new DBSchemaDelta.Applier(schema); accept(visitor); } @@ -114,4 +113,125 @@ public final class DBSchemaDelta extends DBDelta implements IDBSchemaDelta return MessageFormat.format("DBSchemaDelta[name={0}, kind={1}, tableDeltas={2}]", getName(), getChangeKind(), tableDeltas.values()); } + + @Override + protected void doAccept(IDBDeltaVisitor visitor) + { + visitor.visit(this); + } + + @Override + protected void collectElements(List<IDBDelta> elements) + { + elements.addAll(tableDeltas.values()); + } + + /** + * @author Eike Stepper + */ + public static class Applier extends IDBDeltaVisitor.Default + { + private final IDBSchema schema; + + public Applier(IDBSchema schema) + { + this.schema = schema; + } + + public final IDBSchema getSchema() + { + return schema; + } + + @Override + public void added(IDBTableDelta delta) + { + String name = delta.getName(); + schema.addTable(name); + } + + @Override + public void removed(IDBTableDelta delta) + { + IDBTable table = delta.getSchemaElement(schema); + table.remove(); + } + + @Override + public void changed(IDBTableDelta delta) + { + } + + @Override + public void added(IDBFieldDelta delta) + { + String name = delta.getName(); + DBType type = delta.getPropertyValue(IDBFieldDelta.TYPE_PROPERTY); + int precision = delta.getPropertyValue(IDBFieldDelta.PRECISION_PROPERTY); + int scale = delta.getPropertyValue(IDBFieldDelta.SCALE_PROPERTY); + boolean notNull = delta.getPropertyValue(IDBFieldDelta.NOT_NULL_PROPERTY); + + IDBTable table = delta.getParent().getSchemaElement(schema); + table.addField(name, type, precision, scale, notNull); + } + + @Override + public void removed(IDBFieldDelta delta) + { + IDBField field = delta.getSchemaElement(schema); + field.remove(); + } + + @Override + public void changed(IDBFieldDelta delta) + { + } + + @Override + public void added(IDBIndexDelta delta) + { + String name = delta.getName(); + IDBIndex.Type type = delta.getPropertyValue(IDBIndexDelta.TYPE_PROPERTY); + + IDBTable table = delta.getParent().getSchemaElement(schema); + table.addIndex(name, type); + } + + @Override + public void removed(IDBIndexDelta delta) + { + IDBIndex index = delta.getSchemaElement(schema); + index.remove(); + } + + @Override + public void changed(IDBIndexDelta delta) + { + } + + @Override + public void added(IDBIndexFieldDelta delta) + { + IDBIndexDelta parent = delta.getParent(); + IDBTable table = parent.getParent().getSchemaElement(schema); + + String name = delta.getName(); + IDBField field = table.getField(name); + + IDBIndex index = parent.getSchemaElement(schema); + index.addIndexField(field); + } + + @Override + public void removed(IDBIndexFieldDelta delta) + { + IDBIndexField indexField = delta.getSchemaElement(schema); + indexField.remove(); + } + + @Override + public void changed(IDBIndexFieldDelta delta) + { + } + } } diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBTableDelta.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBTableDelta.java index b63375fdfa..286064240a 100644 --- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBTableDelta.java +++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/internal/db/ddl/delta/DBTableDelta.java @@ -13,6 +13,7 @@ package org.eclipse.net4j.internal.db.ddl.delta; import org.eclipse.net4j.db.ddl.IDBField; import org.eclipse.net4j.db.ddl.IDBIndex; import org.eclipse.net4j.db.ddl.IDBSchema; +import org.eclipse.net4j.db.ddl.delta.IDBDelta; import org.eclipse.net4j.db.ddl.delta.IDBDeltaVisitor; import org.eclipse.net4j.db.ddl.delta.IDBFieldDelta; import org.eclipse.net4j.db.ddl.delta.IDBIndexDelta; @@ -25,6 +26,7 @@ import java.text.MessageFormat; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; /** @@ -45,16 +47,19 @@ public final class DBTableDelta extends DBDelta implements IDBTableDelta public DBTableDelta(DBSchemaDelta parent, DBTable table, DBTable oldTable) { - this(parent, table.getName(), oldTable == null ? ChangeKind.ADDED : ChangeKind.CHANGED); + this(parent, getName(table, oldTable), getChangeKind(table, oldTable)); - IDBField[] fields = table.getFields(); + IDBField[] fields = table == null ? DBTable.NO_FIELDS : table.getFields(); IDBField[] oldFields = oldTable == null ? DBTable.NO_FIELDS : oldTable.getFields(); compare(fields, oldFields, new SchemaElementComparator<IDBField>() { public void compare(IDBField field, IDBField oldField) { DBFieldDelta fieldDelta = new DBFieldDelta(DBTableDelta.this, (DBField)field, (DBField)oldField); - addFieldDelta(fieldDelta); + if (!fieldDelta.isEmpty()) + { + addFieldDelta(fieldDelta); + } } }); @@ -65,7 +70,10 @@ public final class DBTableDelta extends DBDelta implements IDBTableDelta public void compare(IDBIndex index, IDBIndex oldIndex) { DBIndexDelta indexDelta = new DBIndexDelta(DBTableDelta.this, (DBIndex)index, (DBIndex)oldIndex); - addIndexDelta(indexDelta); + if (!indexDelta.isEmpty()) + { + addIndexDelta(indexDelta); + } } }); } @@ -77,17 +85,15 @@ public final class DBTableDelta extends DBDelta implements IDBTableDelta { } - @Override - public DBSchemaDelta getParent() + public DeltaType getDeltaType() { - return (DBSchemaDelta)super.getParent(); + return DeltaType.TABLE; } - public DBFieldDelta[] getFieldDeltasSortedByPosition() + @Override + public DBSchemaDelta getParent() { - DBFieldDelta[] result = fieldDeltas.values().toArray(new DBFieldDelta[fieldDeltas.size()]); - Arrays.sort(result, new PositionComparator()); - return result; + return (DBSchemaDelta)super.getParent(); } public Map<String, IDBFieldDelta> getFieldDeltas() @@ -100,69 +106,54 @@ public final class DBTableDelta extends DBDelta implements IDBTableDelta return Collections.unmodifiableMap(indexDeltas); } - public boolean isEmpty() + public DBFieldDelta[] getFieldDeltasSortedByPosition() { - return fieldDeltas.isEmpty() && indexDeltas.isEmpty(); + DBFieldDelta[] result = fieldDeltas.values().toArray(new DBFieldDelta[fieldDeltas.size()]); + Arrays.sort(result); + return result; } - public DBTableElementDelta[] getElements() + public DBIndexDelta[] getIndexDeltasSortedByName() { - DBTableElementDelta[] elements = new DBTableElementDelta[fieldDeltas.size() + indexDeltas.size()]; - int i = 0; - - for (IDBFieldDelta fieldDelta : getFieldDeltasSortedByPosition()) - { - elements[i++] = (DBTableElementDelta)fieldDelta; - } - - for (IDBIndexDelta indexDelta : indexDeltas.values()) - { - elements[i++] = (DBTableElementDelta)indexDelta; - } + DBIndexDelta[] result = indexDeltas.values().toArray(new DBIndexDelta[indexDeltas.size()]); + Arrays.sort(result); + return result; + } - Arrays.sort(elements); - return elements; + public DBTable getSchemaElement(IDBSchema schema) + { + return (DBTable)schema.getTable(getName()); } - public int compareTo(IDBTableDelta o) + @Override + public String toString() { - return getName().compareTo(o.getName()); + return MessageFormat.format("DBTableDelta[name={0}, kind={1}, fieldDeltas={2}, indexDeltas={3}]", getName(), + getChangeKind(), fieldDeltas.values(), indexDeltas.values()); } public void addFieldDelta(IDBFieldDelta fieldDelta) { fieldDeltas.put(fieldDelta.getName(), fieldDelta); + resetElements(); } public void addIndexDelta(IDBIndexDelta indexDelta) { indexDeltas.put(indexDelta.getName(), indexDelta); + resetElements(); } - public void accept(IDBDeltaVisitor visitor) + @Override + protected void doAccept(IDBDeltaVisitor visitor) { visitor.visit(this); - - for (IDBFieldDelta fieldDelta : getFieldDeltasSortedByPosition()) - { - fieldDelta.accept(visitor); - } - - for (IDBIndexDelta indexDelta : indexDeltas.values()) - { - indexDelta.accept(visitor); - } - } - - public DBTable getElement(IDBSchema schema) - { - return (DBTable)schema.getTable(getName()); } @Override - public String toString() + protected void collectElements(List<IDBDelta> elements) { - return MessageFormat.format("DBTableDelta[name={0}, kind={1}, fieldDeltas={2}, indexDeltas={3}]", getName(), - getChangeKind(), fieldDeltas.values(), indexDeltas.values()); + elements.addAll(fieldDeltas.values()); + elements.addAll(indexDeltas.values()); } } diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/spi/db/DBAdapter.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/spi/db/DBAdapter.java index 46e468011d..5c88775b04 100644 --- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/spi/db/DBAdapter.java +++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/spi/db/DBAdapter.java @@ -32,6 +32,7 @@ import javax.sql.DataSource; import java.io.IOException; import java.sql.Connection; +import java.sql.DatabaseMetaData; import java.sql.Driver; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -39,7 +40,9 @@ import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -132,6 +135,189 @@ public abstract class DBAdapter implements IDBAdapter /** * @since 4.2 */ + public IDBSchema readSchema(Connection connection, String name) + { + DBSchema schema = new DBSchema(name); + readSchema(connection, schema); + return schema; + } + + /** + * @since 4.2 + */ + public void readSchema(Connection connection, IDBSchema schema) + { + try + { + String schemaName = schema.getName(); + + DatabaseMetaData metaData = connection.getMetaData(); + ResultSet tables = metaData.getTables(null, schemaName, null, new String[] { "TABLE" }); + while (tables.next()) + { + String tableName = tables.getString(3); + + IDBTable table = schema.addTable(tableName); + readFields(connection, table); + readIndices(connection, metaData, table, schemaName); + } + } + catch (SQLException ex) + { + throw new DBException(ex); + } + } + + /** + * @since 4.2 + */ + protected void readFields(Connection connection, IDBTable table) throws SQLException + { + Statement statement = null; + ResultSet resultSet = null; + + try + { + statement = connection.createStatement(); + resultSet = statement.executeQuery("SELECT * FROM " + table); + ResultSetMetaData metaData = resultSet.getMetaData(); + + for (int i = 0; i < metaData.getColumnCount(); i++) + { + int column = i + 1; + + String name = metaData.getColumnName(column); + DBType type = DBType.getTypeByCode(metaData.getColumnType(column)); + int precision = metaData.getPrecision(column); + int scale = metaData.getScale(column); + boolean notNull = metaData.isNullable(column) == ResultSetMetaData.columnNoNulls; + + table.addField(name, type, precision, scale, notNull); + } + } + finally + { + DBUtil.close(resultSet); + DBUtil.close(statement); + } + } + + /** + * @since 4.2 + */ + protected void readIndices(Connection connection, DatabaseMetaData metaData, IDBTable table, String schemaName) + throws SQLException + { + String tableName = table.getName(); + + ResultSet primaryKeys = metaData.getPrimaryKeys(null, schemaName, tableName); + readIndices(connection, primaryKeys, table, 6, 0, 4, 5); + + ResultSet indexInfo = metaData.getIndexInfo(null, schemaName, tableName, false, false); + readIndices(connection, indexInfo, table, 6, 4, 9, 8); + } + + /** + * @since 4.2 + */ + protected void readIndices(Connection connection, ResultSet resultSet, IDBTable table, int indexNameColumn, + int indexTypeColumn, int fieldNameColumn, int fieldPositionColumn) throws SQLException + { + try + { + String indexName = null; + IDBIndex.Type indexType = null; + List<FieldInfo> fieldInfos = new ArrayList<FieldInfo>(); + + while (resultSet.next()) + { + String name = resultSet.getString(indexNameColumn); + if (indexName != null && !indexName.equals(name)) + { + addIndex(connection, table, indexName, indexType, fieldInfos); + fieldInfos.clear(); + } + + indexName = name; + + if (indexTypeColumn == 0) + { + indexType = IDBIndex.Type.PRIMARY_KEY; + } + else + { + boolean nonUnique = resultSet.getBoolean(indexTypeColumn); + indexType = nonUnique ? IDBIndex.Type.NON_UNIQUE : IDBIndex.Type.UNIQUE; + } + + FieldInfo fieldInfo = new FieldInfo(); + fieldInfo.name = resultSet.getString(fieldNameColumn); + fieldInfo.position = resultSet.getShort(fieldPositionColumn); + fieldInfos.add(fieldInfo); + } + + if (indexName != null) + { + addIndex(connection, table, indexName, indexType, fieldInfos); + } + } + finally + { + DBUtil.close(resultSet); + } + } + + /** + * @since 4.2 + */ + protected void addIndex(Connection connection, IDBTable table, String name, IDBIndex.Type type, + List<FieldInfo> fieldInfos) + { + IDBField[] fields = new IDBField[fieldInfos.size()]; + + Collections.sort(fieldInfos); + for (int i = 0; i < fieldInfos.size(); i++) + { + FieldInfo fieldInfo = fieldInfos.get(i); + IDBField field = table.getField(fieldInfo.name); + if (field == null) + { + throw new IllegalStateException("Field not found: " + fieldInfo.name); + } + + fields[i] = field; + } + + if (!isPrimaryKeyShadow(connection, table, name, type, fields)) + { + table.addIndex(name, type, fields); + } + } + + /** + * @since 4.2 + */ + protected boolean isPrimaryKeyShadow(Connection connection, IDBTable table, String name, IDBIndex.Type type, + IDBField[] fields) + { + if (type != IDBIndex.Type.UNIQUE) + { + return false; + } + + IDBIndex primaryKey = table.getPrimaryKeyIndex(); + if (primaryKey == null) + { + return false; + } + + IDBField[] primaryKeyFields = primaryKey.getFields(); + return Arrays.equals(primaryKeyFields, fields); + } + + /** + * @since 4.2 + */ public void updateSchema(final Connection connection, final IDBSchema schema, IDBSchemaDelta delta) throws DBException { @@ -144,7 +330,7 @@ public abstract class DBAdapter implements IDBAdapter @Override public void visit(IDBTableDelta delta) { - IDBTable table = delta.getElement(schema); + IDBTable table = delta.getSchemaElement(schema); ChangeKind changeKind = delta.getChangeKind(); switch (changeKind) { @@ -168,7 +354,7 @@ public abstract class DBAdapter implements IDBAdapter @Override public void visit(IDBIndexDelta delta) { - IDBIndex element = delta.getElement(schema); + IDBIndex element = delta.getSchemaElement(schema); ChangeKind changeKind = delta.getChangeKind(); switch (changeKind) { @@ -232,11 +418,39 @@ public abstract class DBAdapter implements IDBAdapter */ protected void createIndex(Connection connection, IDBIndex index, IDBIndexDelta delta) { - IDBTable table = index.getTable(); - StringBuilder builder = new StringBuilder(); + if (index.getType() == IDBIndex.Type.PRIMARY_KEY) + { + createPrimaryKey(index, builder); + } + else + { + createIndex(index, builder); + } + + createIndexFields(index, builder); + DBUtil.execute(connection, builder); + } + + /** + * @since 4.2 + */ + protected void createPrimaryKey(IDBIndex index, StringBuilder builder) + { + builder.append("ALTER TABLE "); //$NON-NLS-1$ + builder.append(index.getTable()); + builder.append(" ADD CONSTRAINT "); //$NON-NLS-1$ + builder.append(index); + builder.append(" PRIMARY KEY"); //$NON-NLS-1$ + } + + /** + * @since 4.2 + */ + protected void createIndex(IDBIndex index, StringBuilder builder) + { builder.append("CREATE "); //$NON-NLS-1$ - if (index.getType() == IDBIndex.Type.UNIQUE || index.getType() == IDBIndex.Type.PRIMARY_KEY) + if (index.getType() == IDBIndex.Type.UNIQUE) { builder.append("UNIQUE "); //$NON-NLS-1$ } @@ -244,8 +458,16 @@ public abstract class DBAdapter implements IDBAdapter builder.append("INDEX "); //$NON-NLS-1$ builder.append(index); builder.append(" ON "); //$NON-NLS-1$ - builder.append(table); + builder.append(index.getTable()); + } + + /** + * @since 4.2 + */ + protected void createIndexFields(IDBIndex index, StringBuilder builder) + { builder.append(" ("); //$NON-NLS-1$ + IDBField[] fields = index.getFields(); for (int i = 0; i < fields.length; i++) { @@ -258,6 +480,22 @@ public abstract class DBAdapter implements IDBAdapter } builder.append(")"); //$NON-NLS-1$ + } + + /** + * @since 4.2 + */ + protected void dropIndex(Connection connection, IDBIndex index, IDBIndexDelta delta) + { + StringBuilder builder = new StringBuilder(); + if (index.getType() == IDBIndex.Type.PRIMARY_KEY) + { + dropPrimaryKey(index, builder); + } + else + { + dropIndex(index, builder); + } DBUtil.execute(connection, builder); } @@ -265,7 +503,18 @@ public abstract class DBAdapter implements IDBAdapter /** * @since 4.2 */ - protected void dropIndex(Connection connection, IDBIndex index, IDBIndexDelta delta) + protected void dropPrimaryKey(IDBIndex index, StringBuilder builder) + { + builder.append("ALTER TABLE "); //$NON-NLS-1$ + builder.append(index.getTable()); + builder.append(" DROP CONSTRAINT "); //$NON-NLS-1$ + builder.append(index); + } + + /** + * @since 4.2 + */ + protected void dropIndex(IDBIndex index, StringBuilder builder) { } @@ -476,19 +725,7 @@ public abstract class DBAdapter implements IDBAdapter builder.append(index); builder.append(" ON "); //$NON-NLS-1$ builder.append(table); - builder.append(" ("); //$NON-NLS-1$ - IDBField[] fields = index.getFields(); - for (int i = 0; i < fields.length; i++) - { - if (i != 0) - { - builder.append(", "); //$NON-NLS-1$ - } - - addIndexField(builder, fields[i]); - } - - builder.append(")"); //$NON-NLS-1$ + createIndexFields(index, builder); String sql = builder.toString(); if (TRACER.isEnabled()) { @@ -805,4 +1042,20 @@ public abstract class DBAdapter implements IDBAdapter { return type == DBType.VARCHAR ? 32672 : IDBField.DEFAULT; } + + /** + * @since 4.2 + * @author Eike Stepper + */ + protected static final class FieldInfo implements Comparable<FieldInfo> + { + public String name; + + public int position; + + public int compareTo(FieldInfo o) + { + return position - o.position; + } + } } diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/spi/db/DBNamedElement.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/spi/db/DBNamedElement.java index 1fd49c81a4..80c52b94c1 100644 --- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/spi/db/DBNamedElement.java +++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/spi/db/DBNamedElement.java @@ -12,6 +12,12 @@ package org.eclipse.net4j.spi.db; import org.eclipse.net4j.db.IDBNamedElement; import org.eclipse.net4j.db.ddl.IDBSchemaElement; +import org.eclipse.net4j.util.io.IORuntimeException; + +import java.io.CharArrayWriter; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.Writer; /** * @author Eike Stepper @@ -75,6 +81,36 @@ public abstract class DBNamedElement extends DBElement implements IDBNamedElemen return name; } + public String dumpToString() + { + try + { + CharArrayWriter writer = new CharArrayWriter(); + dump(writer); + return writer.toString(); + } + catch (IOException ex) + { + throw new IORuntimeException(ex); + } + } + + public final void dump() + { + try + { + OutputStreamWriter writer = new OutputStreamWriter(System.out); + dump(writer); + writer.flush(); + } + catch (IOException ex) + { + throw new IORuntimeException(ex); + } + } + + public abstract void dump(Writer writer) throws IOException; + public static String name(String name) { return name.toUpperCase().intern(); diff --git a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/spi/db/DBSchema.java b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/spi/db/DBSchema.java index e4e666b670..9019857a06 100644 --- a/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/spi/db/DBSchema.java +++ b/plugins/org.eclipse.net4j.db/src/org/eclipse/net4j/spi/db/DBSchema.java @@ -11,7 +11,6 @@ package org.eclipse.net4j.spi.db; import org.eclipse.net4j.db.DBException; -import org.eclipse.net4j.db.DBType; import org.eclipse.net4j.db.DBUtil; import org.eclipse.net4j.db.IDBAdapter; import org.eclipse.net4j.db.IDBConnectionProvider; @@ -25,21 +24,16 @@ import org.eclipse.net4j.internal.db.ddl.DBField; import org.eclipse.net4j.internal.db.ddl.DBIndex; import org.eclipse.net4j.internal.db.ddl.DBTable; import org.eclipse.net4j.internal.db.ddl.delta.DBSchemaDelta; +import org.eclipse.net4j.util.StringUtil; import javax.sql.DataSource; +import java.io.IOException; import java.io.PrintStream; +import java.io.Writer; import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Set; @@ -71,39 +65,6 @@ public class DBSchema extends DBSchemaElement implements IDBSchema /** * @since 4.2 */ - public DBSchema(String name, Connection connection) - { - this(name); - Statement statement = null; - - try - { - statement = connection.createStatement(); - DatabaseMetaData metaData = connection.getMetaData(); - - ResultSet tables = metaData.getTables(null, getName(), null, new String[] { "TABLE" }); - while (tables.next()) - { - String tableName = tables.getString(3); - - IDBTable table = addTable(tableName); - readFields(table, statement); - readIndices(table, metaData, getName()); - } - } - catch (SQLException ex) - { - throw new DBException(ex); - } - finally - { - DBUtil.close(statement); - } - } - - /** - * @since 4.2 - */ public DBSchema(IDBSchema source) { super(source.getName()); @@ -114,7 +75,8 @@ public class DBSchema extends DBSchemaElement implements IDBSchema for (IDBField sourceField : sourceTable.getFields()) { - table.addField(sourceField.getName(), sourceField.getType(), sourceField.getScale(), sourceField.isNotNull()); + table.addField(sourceField.getName(), sourceField.getType(), sourceField.getPrecision(), + sourceField.getScale(), sourceField.isNotNull()); } for (IDBIndex sourceIndex : sourceTable.getIndices()) @@ -369,124 +331,15 @@ public class DBSchema extends DBSchemaElement implements IDBSchema return "I" + System.currentTimeMillis() + "_" + ++indexCounter; } - private void readFields(IDBTable table, Statement statement) throws SQLException - { - ResultSet resultSet = null; - - try - { - resultSet = statement.executeQuery("SELECT * FROM " + table); - ResultSetMetaData metaData = resultSet.getMetaData(); - - for (int i = 0; i < metaData.getColumnCount(); i++) - { - int column = i + 1; - - String name = metaData.getColumnName(column); - DBType type = DBType.getTypeByCode(metaData.getColumnType(column)); - int precision = metaData.getPrecision(column); - int scale = metaData.getScale(column); - boolean notNull = metaData.isNullable(column) == ResultSetMetaData.columnNoNulls; - - table.addField(name, type, precision, scale, notNull); - } - } - finally - { - DBUtil.close(resultSet); - } - } - - private void readIndices(IDBTable table, DatabaseMetaData metaData, String schemaName) throws SQLException - { - String tableName = table.getName(); - - ResultSet primaryKeys = metaData.getPrimaryKeys(null, schemaName, tableName); - readIndices(table, primaryKeys, 6, 0, 4, 5); - - ResultSet indexInfo = metaData.getIndexInfo(null, schemaName, tableName, false, false); - readIndices(table, indexInfo, 6, 4, 9, 8); - } - - private void readIndices(IDBTable table, ResultSet resultSet, int indexNameColumn, int indexTypeColumn, - int fieldNameColumn, int fieldPositionColumn) throws SQLException + @Override + public void dump(Writer writer) throws IOException { - try - { - String indexName = null; - IDBIndex.Type indexType = null; - List<FieldInfo> fieldInfos = new ArrayList<FieldInfo>(); - - while (resultSet.next()) - { - String name = resultSet.getString(indexNameColumn); - if (indexName != null && !indexName.equals(name)) - { - addIndex(table, indexName, indexType, fieldInfos); - fieldInfos.clear(); - } - - indexName = name; - - if (indexTypeColumn == 0) - { - indexType = IDBIndex.Type.PRIMARY_KEY; - } - else - { - boolean nonUnique = resultSet.getBoolean(indexTypeColumn); - indexType = nonUnique ? IDBIndex.Type.NON_UNIQUE : IDBIndex.Type.UNIQUE; - } - - FieldInfo fieldInfo = new FieldInfo(); - fieldInfo.name = resultSet.getString(fieldNameColumn); - fieldInfo.position = resultSet.getShort(fieldPositionColumn); - fieldInfos.add(fieldInfo); - } - - if (indexName != null) - { - addIndex(table, indexName, indexType, fieldInfos); - } - } - finally - { - DBUtil.close(resultSet); - } - } - - private void addIndex(IDBTable table, String name, IDBIndex.Type type, List<FieldInfo> fieldInfos) - { - IDBField[] fields = new IDBField[fieldInfos.size()]; - - Collections.sort(fieldInfos); - for (int i = 0; i < fieldInfos.size(); i++) - { - FieldInfo fieldInfo = fieldInfos.get(i); - IDBField field = table.getField(fieldInfo.name); - if (field == null) - { - throw new IllegalStateException("Field not found: " + fieldInfo.name); - } - - fields[i] = field; - } - - table.addIndex(name, type, fields); - } - - /** - * @author Eike Stepper - */ - private static final class FieldInfo implements Comparable<FieldInfo> - { - public String name; - - public int position; - - public int compareTo(FieldInfo o) + writer.append("SCHEMA "); + writer.append(getName()); + writer.append(StringUtil.NL); + for (DBTable table : tables.values()) { - return o.position - position; + table.dump(writer); } } } |