From d95e16170d063c0b74d04e6636e8fddbfa120689 Mon Sep 17 00:00:00 2001 From: James Moger Date: Tue, 16 Aug 2011 15:32:56 -0400 Subject: Finished MySQL dialect; v5.0.51b 100% tested. Added Db.dropTable(T) --- src/com/iciql/Db.java | 42 +++++++++++++++++++++++++++------ src/com/iciql/IciqlException.java | 18 ++++++++++---- src/com/iciql/SQLDialect.java | 16 +++++++++++++ src/com/iciql/SQLDialectDefault.java | 11 ++++++++- src/com/iciql/SQLDialectDerby.java | 10 +++++++- src/com/iciql/SQLDialectMySQL.java | 41 ++++++++++++++++++++++++-------- src/com/iciql/TableDefinition.java | 3 ++- src/com/iciql/TableInspector.java | 6 ++--- src/com/iciql/build/Build.java | 10 +++++--- src/com/iciql/util/StatementLogger.java | 25 ++++++++++++++++---- 10 files changed, 147 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/com/iciql/Db.java b/src/com/iciql/Db.java index bb087e4..09c26a1 100644 --- a/src/com/iciql/Db.java +++ b/src/com/iciql/Db.java @@ -38,6 +38,7 @@ import com.iciql.DbUpgrader.DefaultDbUpgrader; import com.iciql.Iciql.IQTable; import com.iciql.Iciql.IQVersion; import com.iciql.util.JdbcUtils; +import com.iciql.util.StatementLogger; import com.iciql.util.StringUtils; import com.iciql.util.Utils; import com.iciql.util.WeakIdentityHashMap; @@ -180,7 +181,10 @@ public class Db { public void insert(T t) { Class clazz = t.getClass(); - define(clazz).createTableIfRequired(this).insert(this, t, false); + long rc = define(clazz).createTableIfRequired(this).insert(this, t, false); + if (rc == 0) { + throw new IciqlException("Failed to insert {0}. Affected rowcount == 0.", t); + } } public long insertAndGetKey(T t) { @@ -235,6 +239,26 @@ public class Db { return Query.from(this, alias); } + @SuppressWarnings("unchecked") + public int dropTable(Class modelClass) { + TableDefinition def = (TableDefinition) define(modelClass); + SQLStatement stat = new SQLStatement(this); + getDialect().prepareDropTable(stat, def); + StatementLogger.drop(stat.getSQL()); + int rc = 0; + try { + rc = stat.executeUpdate(); + } catch (IciqlException e) { + if (e.getIciqlCode() != IciqlException.CODE_SCHEMA_NOT_FOUND + && e.getIciqlCode() != IciqlException.CODE_TABLE_NOT_FOUND) { + throw e; + } + } + // remove this model class from the table definition cache + classMap.remove(modelClass); + return rc; + } + @SuppressWarnings("unchecked") public List buildObjects(Class modelClass, ResultSet rs) { List result = new ArrayList(); @@ -259,14 +283,18 @@ public class Db { IQVersion model = dbUpgrader.getClass().getAnnotation(IQVersion.class); if (model.value() > 0) { DbVersion v = new DbVersion(); - DbVersion dbVersion = // (SCHEMA="" && TABLE="") == DATABASE - from(v).where(v.schemaName).is("").and(v.tableName).is("").selectFirst(); + DbVersion dbVersion = from(v).where(v.schemaName).is("").and(v.tableName).is("") + .selectFirst(); if (dbVersion == null) { // database has no version registration, but model specifies // version: insert DbVersion entry and return. DbVersion newDb = new DbVersion(model.value()); - insert(newDb); + // database is an older version than the model + boolean success = dbUpgrader.upgradeDatabase(this, 0, newDb.version); + if (success) { + insert(newDb); + } } else { // database has a version registration: // check to see if upgrade is required. @@ -293,8 +321,8 @@ public class Db { // table is using iciql version tracking. DbVersion v = new DbVersion(); String schema = StringUtils.isNullOrEmpty(model.schemaName) ? "" : model.schemaName; - DbVersion dbVersion = from(v).where(v.schemaName).like(schema).and(v.tableName) - .like(model.tableName).selectFirst(); + DbVersion dbVersion = from(v).where(v.schemaName).is(schema).and(v.tableName) + .is(model.tableName).selectFirst(); if (dbVersion == null) { // table has no version registration, but model specifies // version: insert DbVersion entry @@ -348,7 +376,7 @@ public class Db { upgradeChecked.clear(); } - SQLDialect getDialect() { + public SQLDialect getDialect() { return dialect; } diff --git a/src/com/iciql/IciqlException.java b/src/com/iciql/IciqlException.java index 7d6f152..524d184 100644 --- a/src/com/iciql/IciqlException.java +++ b/src/com/iciql/IciqlException.java @@ -27,9 +27,10 @@ public class IciqlException extends RuntimeException { public static final int CODE_UNMAPPED_FIELD = 1; public static final int CODE_DUPLICATE_KEY = 2; - public static final int CODE_TABLE_NOT_FOUND = 3; - public static final int CODE_TABLE_ALREADY_EXISTS = 4; - public static final int CODE_INDEX_ALREADY_EXISTS = 5; + public static final int CODE_SCHEMA_NOT_FOUND = 3; + public static final int CODE_TABLE_NOT_FOUND = 4; + public static final int CODE_TABLE_ALREADY_EXISTS = 5; + public static final int CODE_INDEX_ALREADY_EXISTS = 6; private static final String TOKEN_UNMAPPED_FIELD = "\\? (=|\\>|\\<|\\<\\>|!=|\\>=|\\<=|LIKE|BETWEEN) \\?"; @@ -95,8 +96,17 @@ public class IciqlException extends RuntimeException { // http://developer.mimer.com/documentation/html_92/Mimer_SQL_Mobile_DocSet/App_Return_Codes2.html SQLException s = (SQLException) t; String state = s.getSQLState(); - if ("23505".equals(state)) { + if ("23000".equals(state)) { + // MySQL iciqlCode = CODE_DUPLICATE_KEY; + } else if ("23505".equals(state)) { + iciqlCode = CODE_DUPLICATE_KEY; + } else if ("42000".equals(state)) { + // MySQL + iciqlCode = CODE_DUPLICATE_KEY; + } else if ("42Y07".equals(state)) { + // Derby + iciqlCode = CODE_SCHEMA_NOT_FOUND; } else if ("42X05".equals(state)) { // Derby iciqlCode = CODE_TABLE_NOT_FOUND; diff --git a/src/com/iciql/SQLDialect.java b/src/com/iciql/SQLDialect.java index 97d9fe9..6e6be25 100644 --- a/src/com/iciql/SQLDialect.java +++ b/src/com/iciql/SQLDialect.java @@ -35,6 +35,14 @@ public interface SQLDialect { */ void configureDialect(String databaseName, DatabaseMetaData data); + /** + * Allows a dialect to substitute an SQL type. + * + * @param sqlType + * @return the dialect-safe type + */ + String convertSqlType(String sqlType); + /** * Returns a properly formatted table name for the dialect. * @@ -63,6 +71,14 @@ public interface SQLDialect { */ void prepareCreateTable(SQLStatement stat, TableDefinition def); + /** + * Get the DROP TABLE statement. + * + * @param stat + * @param def + */ + void prepareDropTable(SQLStatement stat, TableDefinition def); + /** * Get the CREATE INDEX statement. * diff --git a/src/com/iciql/SQLDialectDefault.java b/src/com/iciql/SQLDialectDefault.java index 69502c3..0b611e0 100644 --- a/src/com/iciql/SQLDialectDefault.java +++ b/src/com/iciql/SQLDialectDefault.java @@ -57,7 +57,8 @@ public class SQLDialectDefault implements SQLDialect { * @param sqlType * @return the SQL type or a preferred alternative */ - protected String convertSqlType(String sqlType) { + @Override + public String convertSqlType(String sqlType) { return sqlType; } @@ -94,6 +95,14 @@ public class SQLDialectDefault implements SQLDialect { return name; } + @Override + public void prepareDropTable(SQLStatement stat, TableDefinition def) { + StatementBuilder buff = new StatementBuilder("DROP TABLE IF EXISTS " + + prepareTableName(def.schemaName, def.tableName)); + stat.setSQL(buff.toString()); + return; + } + @Override public void prepareCreateTable(SQLStatement stat, TableDefinition def) { StatementBuilder buff; diff --git a/src/com/iciql/SQLDialectDerby.java b/src/com/iciql/SQLDialectDerby.java index 42f8cfd..019c285 100644 --- a/src/com/iciql/SQLDialectDerby.java +++ b/src/com/iciql/SQLDialectDerby.java @@ -33,7 +33,7 @@ public class SQLDialectDerby extends SQLDialectDefault { } @Override - protected String convertSqlType(String sqlType) { + public String convertSqlType(String sqlType) { if ("TINYINT".equals(sqlType)) { // Derby does not have a TINYINT/BYTE type return "SMALLINT"; @@ -81,6 +81,14 @@ public class SQLDialectDerby extends SQLDialectDefault { return false; } + @Override + public void prepareDropTable(SQLStatement stat, TableDefinition def) { + StatementBuilder buff = new StatementBuilder("DROP TABLE " + + prepareTableName(def.schemaName, def.tableName)); + stat.setSQL(buff.toString()); + return; + } + @Override public void prepareCreateIndex(SQLStatement stat, String schema, String table, IndexDefinition index) { StatementBuilder buff = new StatementBuilder(); diff --git a/src/com/iciql/SQLDialectMySQL.java b/src/com/iciql/SQLDialectMySQL.java index a6c1218..1c1674a 100644 --- a/src/com/iciql/SQLDialectMySQL.java +++ b/src/com/iciql/SQLDialectMySQL.java @@ -16,6 +16,7 @@ package com.iciql; +import com.iciql.TableDefinition.FieldDefinition; import com.iciql.TableDefinition.IndexDefinition; import com.iciql.util.StatementBuilder; @@ -25,7 +26,7 @@ import com.iciql.util.StatementBuilder; public class SQLDialectMySQL extends SQLDialectDefault { @Override - protected String convertSqlType(String sqlType) { + public String convertSqlType(String sqlType) { if (sqlType.equals("CLOB")) { return "TEXT"; } @@ -75,16 +76,36 @@ public class SQLDialectMySQL extends SQLDialectDefault { buff.append(prepareColumnName(col)); } buff.append(") "); + stat.setSQL(buff.toString().trim()); + } - // USING - switch (index.type) { - case HASH: - buff.append("USING HASH"); - break; - case UNIQUE_HASH: - buff.append("USING HASH"); - break; + @Override + public void prepareMerge(SQLStatement stat, String schemaName, String tableName, + TableDefinition def, Object obj) { + StatementBuilder buff = new StatementBuilder("INSERT INTO "); + buff.append(prepareTableName(schemaName, tableName)).append(" ("); + buff.resetCount(); + for (FieldDefinition field : def.fields) { + buff.appendExceptFirst(", "); + buff.append(field.columnName); } - stat.setSQL(buff.toString().trim()); + buff.resetCount(); + buff.append(") VALUES ("); + for (FieldDefinition field : def.fields) { + buff.appendExceptFirst(", "); + buff.append('?'); + Object value = def.getValue(obj, field); + stat.addParameter(value); + } + buff.append(") ON DUPLICATE KEY UPDATE "); + buff.resetCount(); + for (FieldDefinition field : def.fields) { + buff.appendExceptFirst(", "); + buff.append(field.columnName); + buff.append("=VALUES("); + buff.append(field.columnName); + buff.append(')'); + } + stat.setSQL(buff.toString()); } } \ No newline at end of file diff --git a/src/com/iciql/TableDefinition.java b/src/com/iciql/TableDefinition.java index 4d9fec2..251f098 100644 --- a/src/com/iciql/TableDefinition.java +++ b/src/com/iciql/TableDefinition.java @@ -573,7 +573,8 @@ public class TableDefinition { try { stat.executeUpdate(); } catch (IciqlException e) { - if (e.getIciqlCode() != IciqlException.CODE_INDEX_ALREADY_EXISTS) { + if (e.getIciqlCode() != IciqlException.CODE_INDEX_ALREADY_EXISTS + && e.getIciqlCode() != IciqlException.CODE_DUPLICATE_KEY) { throw e; } } diff --git a/src/com/iciql/TableInspector.java b/src/com/iciql/TableInspector.java index dc28956..093055c 100644 --- a/src/com/iciql/TableInspector.java +++ b/src/com/iciql/TableInspector.java @@ -433,13 +433,13 @@ public class TableInspector { if (!isNullOrEmpty(schema)) { if (isNullOrEmpty(def.schemaName)) { remarks.add(consider(table, "SCHEMA", - format("@{0}(name={1})", IQSchema.class.getSimpleName(), schema))); + format("@{0}(\"{1}\")", IQSchema.class.getSimpleName(), schema))); } else if (!schema.equalsIgnoreCase(def.schemaName)) { remarks.add(error( table, "SCHEMA", - format("@{0}(name={1}) != {2}", IQSchema.class.getSimpleName(), def.schemaName, - schema)).throwError(throwError)); + format("@{0}(\"{1}\") != {2}", IQSchema.class.getSimpleName(), def.schemaName, schema)) + .throwError(throwError)); } } diff --git a/src/com/iciql/build/Build.java b/src/com/iciql/build/Build.java index 0102739..8dfd7df 100644 --- a/src/com/iciql/build/Build.java +++ b/src/com/iciql/build/Build.java @@ -58,6 +58,7 @@ public class Build { downloadFromApache(MavenObject.H2, BuildType.COMPILETIME); downloadFromApache(MavenObject.HSQLDB, BuildType.RUNTIME); downloadFromApache(MavenObject.DERBY, BuildType.RUNTIME); + downloadFromApache(MavenObject.MYSQL, BuildType.RUNTIME); downloadFromApache(MavenObject.JCOMMANDER, BuildType.RUNTIME); downloadFromApache(MavenObject.JCOMMANDER, BuildType.COMPILETIME); downloadFromApache(MavenObject.MARKDOWNPAPERS, BuildType.RUNTIME); @@ -170,9 +171,9 @@ public class Build { "219a3540f3b27d7cc3b1d91d6ea046cd8723290e", "0bb50eec177acf0e94d58e0cf07262fe5164331d", "c7adc475ca40c288c93054e0f4fe58f3a98c0cb5"); - public static final MavenObject H2 = new MavenObject("com/h2database", "h2", "1.3.159", - "dd89f939661eb5593909584e1c243db0c25de130", "4d953bf765e8a13c7e06ca51165438338966c698", - "4c79ed03f994820a1a873150c8a9f13c667784d3"); + public static final MavenObject H2 = new MavenObject("com/h2database", "h2", "1.3.158", + "4bac13427caeb32ef6e93b70101e61f370c7b5e2", "6bb165156a0831879fa7797df6e18bdcd4421f2d", + "446d3f58c44992534cb54f67134532d95961904a"); public static final MavenObject HSQLDB = new MavenObject("org/hsqldb", "hsqldb", "2.2.4", "6a6e040b07f5ee409fc825f1c5e5b574b1fa1428", "", ""); @@ -180,6 +181,9 @@ public class Build { public static final MavenObject DERBY = new MavenObject("org/apache/derby", "derby", "10.8.1.2", "2f8717d96eafe3eef3de445ba653f142d54ddab1", "", ""); + public static final MavenObject MYSQL = new MavenObject("mysql", "mysql-connector-java", "5.1.15", + "0fbc80454d27cc65f3addfa516707e9f8e60c3eb", "", ""); + public static final MavenObject JUNIT = new MavenObject("junit", "junit", "4.8.2", "c94f54227b08100974c36170dcb53329435fe5ad", "", ""); diff --git a/src/com/iciql/util/StatementLogger.java b/src/com/iciql/util/StatementLogger.java index 0504c98..b11a5f9 100644 --- a/src/com/iciql/util/StatementLogger.java +++ b/src/com/iciql/util/StatementLogger.java @@ -22,6 +22,8 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicLong; +import com.iciql.IciqlException; + /** * Utility class to optionally log generated statements to StatementListeners.
* Statement logging is disabled by default. @@ -35,7 +37,7 @@ public class StatementLogger { * Enumeration of the different statement types that are logged. */ public enum StatementType { - STAT, TOTAL, CREATE, INSERT, UPDATE, MERGE, DELETE, SELECT; + STAT, TOTAL, CREATE, INSERT, UPDATE, MERGE, DELETE, SELECT, DROP; } /** @@ -61,19 +63,20 @@ public class StatementLogger { private static final AtomicLong UPDATE_COUNT = new AtomicLong(); private static final AtomicLong MERGE_COUNT = new AtomicLong(); private static final AtomicLong DELETE_COUNT = new AtomicLong(); + private static final AtomicLong DROP_COUNT = new AtomicLong(); /** * Activates the Console Logger. */ public static void activateConsoleLogger() { - LISTENERS.add(CONSOLE); + registerListener(CONSOLE); } /** * Deactivates the Console Logger. */ public static void deactivateConsoleLogger() { - LISTENERS.remove(CONSOLE); + unregisterListener(CONSOLE); } /** @@ -91,7 +94,9 @@ public class StatementLogger { * @param listener */ public static void unregisterListener(StatementListener listener) { - LISTENERS.remove(listener); + if (!LISTENERS.remove(listener)) { + throw new IciqlException("Failed to remove statement listener {0}", listener); + } } public static void create(String statement) { @@ -124,6 +129,11 @@ public class StatementLogger { logStatement(StatementType.SELECT, statement); } + public static void drop(String statement) { + DROP_COUNT.incrementAndGet(); + logStatement(StatementType.DROP, statement); + } + private static void logStatement(final StatementType type, final String statement) { for (final StatementListener listener : LISTENERS) { EXEC.execute(new Runnable() { @@ -158,9 +168,13 @@ public class StatementLogger { return SELECT_COUNT.longValue(); } + public static long getDropCount() { + return DROP_COUNT.longValue(); + } + public static long getTotalCount() { return getCreateCount() + getInsertCount() + getUpdateCount() + getDeleteCount() + getMergeCount() - + getSelectCount(); + + getSelectCount() + getDropCount(); } public static void logStats() { @@ -172,6 +186,7 @@ public class StatementLogger { logStat(StatementType.MERGE, getMergeCount()); logStat(StatementType.DELETE, getDeleteCount()); logStat(StatementType.SELECT, getSelectCount()); + logStat(StatementType.DROP, getDropCount()); logStatement(StatementType.STAT, "========================"); logStat(StatementType.TOTAL, getTotalCount()); } -- cgit v1.2.3