]> source.dussan.org Git - iciql.git/commitdiff
Finished MySQL dialect; v5.0.51b 100% tested. Added Db.dropTable(T)
authorJames Moger <james.moger@gmail.com>
Tue, 16 Aug 2011 19:32:56 +0000 (15:32 -0400)
committerJames Moger <james.moger@gmail.com>
Tue, 16 Aug 2011 19:32:56 +0000 (15:32 -0400)
25 files changed:
.classpath
README.markdown
docs/00_index.mkd
docs/03_performance.mkd
docs/05_releases.mkd
src/com/iciql/Db.java
src/com/iciql/IciqlException.java
src/com/iciql/SQLDialect.java
src/com/iciql/SQLDialectDefault.java
src/com/iciql/SQLDialectDerby.java
src/com/iciql/SQLDialectMySQL.java
src/com/iciql/TableDefinition.java
src/com/iciql/TableInspector.java
src/com/iciql/build/Build.java
src/com/iciql/util/StatementLogger.java
tests/com/iciql/test/AnnotationsTest.java
tests/com/iciql/test/ClobTest.java
tests/com/iciql/test/IciqlSuite.java
tests/com/iciql/test/ModelsTest.java
tests/com/iciql/test/SamplesTest.java
tests/com/iciql/test/UUIDTest.java
tests/com/iciql/test/UpgradesTest.java [new file with mode: 0644]
tests/com/iciql/test/models/PrimitivesModel.java
tests/com/iciql/test/models/ProductAnnotationOnly.java
tests/com/iciql/test/models/SupportedTypes.java

index 1d41ba727df4704bf21b253082ffe039571aff43..136c2015ec8beec37db47d26ed7bf0714bf0bb02 100644 (file)
@@ -26,6 +26,7 @@
        </classpathentry>\r
        <classpathentry kind="lib" path="ext/hsqldb-2.2.4.jar"/>\r
        <classpathentry kind="lib" path="ext/derby-10.8.1.2.jar"/>\r
+       <classpathentry kind="lib" path="ext/mysql-connector-java-5.1.15.jar"/>\r
        <classpathentry kind="lib" path="ext/h2-1.3.159.jar" sourcepath="ext/h2-1.3.159-sources.jar">\r
                <attributes>\r
                        <attribute name="javadoc_location" value="jar:platform:/resource/iciql/ext/h2-1.3.159-javadoc.jar!/"/>\r
index 6c4f5e2292addd71a07d4fc4adf78e45f630108e..28aa424dffa7b46cfd9931cc21c011c6a298515f 100644 (file)
@@ -20,12 +20,9 @@ Supported Databases (Unit-Tested)
 - [H2](http://h2database.com) 1.3.159\r
 - [HSQLDB](http://hsqldb.org) 2.2.4\r
 - [Derby](http://db.apache.org/derby) 10.7.1.1 & 10.8.1.2\r
+- [MySQL](http://mysql.com) 5.0.51b\r
 \r
-Partially Supported Databases (not Unit-Tested)\r
--------\r
-- [MySQL](http://mysql.com)\r
-\r
-Support for others is planned and may only require creating a simple "dialect" class.\r
+Support for others is possible and may only require creating a simple "dialect" class.\r
 \r
 License\r
 -------\r
index b3e8cbfded5f3d27a5b2d081b310f381da4d314d..daf9c426746c80836e4761135eb879960cd79649 100644 (file)
@@ -39,11 +39,9 @@ select * from products
 - [H2](http://h2database.com) 1.3.159\r
 - [HSQLDB](http://hsqldb.org) 2.2.4 \r
 - [Derby](http://db.apache.org/derby) 10.7.1.1 & 10.8.1.2\r
+- [MySQL](http://mysql.com) 5.0.51b\r
 \r
-### Partially Supported Databases (not Unit-Tested)\r
-- [MySQL](http://mysql.com)\r
-\r
-Support for others is planned and may only require creating a simple "dialect" class.\r
+Support for others is possible and may only require creating a simple "dialect" class.\r
 \r
 ### Java Runtime Requirement\r
 \r
index a8922b71eaa705506e675d30556afcc9cfcf34f1..7df050aa0fb57c2adb5c54718c94f1e17906dcb6 100644 (file)
@@ -9,7 +9,7 @@ Performance of iciql statement generation is not currently benchmarked.
 \r
 ### iciql+database performance comparison\r
 \r
-The following data was generated by running the iciql test suite. The suite is almost completely single-threaded.  All databases are run in embedded *memory-only* mode through a JDBC connection.  Since the suite is running in memory-only mode, disk IO bottlenecks should be removed from the equation and the results should be measuring raw statement processing.\r
+The following data was generated by running the iciql test suite. The suite is almost completely single-threaded.  All Java databases are run in embedded *memory-only* mode through a JDBC connection.\r
 \r
 <pre>\r
 %DBPERFORMANCE%\r
index 91ef18f46bbc77c1668783057d74677d319415cd..8e0dfd6c5e15450b276a61c9bcf39403912569ad 100644 (file)
@@ -6,13 +6,18 @@
 \r
 **%VERSION%** ([zip](http://code.google.com/p/iciql/downloads/detail?name=%ZIP%)|[jar](http://code.google.com/p/iciql/downloads/detail?name=%JAR%)) &nbsp; *released %BUILDDATE%*\r
 \r
-- Disabled 2 concurrency unit tests since I believe they are flawed and do not yield reproducible results\r
+- Finished MySQL dialect implementation.  MySQL 5.0.51b passes 100% of tests.\r
+- Added Db.dropTable(T) method\r
+\r
+### Older Releases\r
+\r
+**0.6.6** &nbsp; *released 2011-08-15*\r
+\r
+- Disabled two concurrency unit tests since I believe they are flawed and do not yield reproducible results\r
 - Added Derby database dialect.  Derby 10.7.1.1 and 10.8.1.2 pass 100% of tests.\r
 - Implemented HSQL MERGE syntax.  HSQL 2.2.4 fails 1 test which is a known [bug in HSQL](https://sourceforge.net/tracker/?func=detail&aid=3390047&group_id=23316&atid=378131)\r
 - Updated to H2 1.3.159\r
 \r
-### Older Releases\r
-\r
 **0.6.5** &nbsp; *released 2011-08-12*\r
 \r
 - fixed failure of db.delete(PrimitiveModel) and db.update(PrimitiveModel)\r
index bb087e476da1a6b08ebccab00d3e997706d8f0d0..09c26a1e10fc6c83354736cb2225968b7bdc9756 100644 (file)
@@ -38,6 +38,7 @@ import com.iciql.DbUpgrader.DefaultDbUpgrader;
 import com.iciql.Iciql.IQTable;\r
 import com.iciql.Iciql.IQVersion;\r
 import com.iciql.util.JdbcUtils;\r
+import com.iciql.util.StatementLogger;\r
 import com.iciql.util.StringUtils;\r
 import com.iciql.util.Utils;\r
 import com.iciql.util.WeakIdentityHashMap;\r
@@ -180,7 +181,10 @@ public class Db {
 \r
        public <T> void insert(T t) {\r
                Class<?> clazz = t.getClass();\r
-               define(clazz).createTableIfRequired(this).insert(this, t, false);\r
+               long rc = define(clazz).createTableIfRequired(this).insert(this, t, false);\r
+               if (rc == 0) {\r
+                       throw new IciqlException("Failed to insert {0}.  Affected rowcount == 0.", t);\r
+               }\r
        }\r
 \r
        public <T> long insertAndGetKey(T t) {\r
@@ -235,6 +239,26 @@ public class Db {
                return Query.from(this, alias);\r
        }\r
 \r
+       @SuppressWarnings("unchecked")\r
+       public <T> int dropTable(Class<? extends T> modelClass) {\r
+               TableDefinition<T> def = (TableDefinition<T>) define(modelClass);\r
+               SQLStatement stat = new SQLStatement(this);\r
+               getDialect().prepareDropTable(stat, def);\r
+               StatementLogger.drop(stat.getSQL());\r
+               int rc = 0;\r
+               try {\r
+                       rc = stat.executeUpdate();\r
+               } catch (IciqlException e) {\r
+                       if (e.getIciqlCode() != IciqlException.CODE_SCHEMA_NOT_FOUND\r
+                                       && e.getIciqlCode() != IciqlException.CODE_TABLE_NOT_FOUND) {\r
+                               throw e;\r
+                       }\r
+               }\r
+               // remove this model class from the table definition cache\r
+               classMap.remove(modelClass);\r
+               return rc;\r
+       }\r
+\r
        @SuppressWarnings("unchecked")\r
        public <T> List<T> buildObjects(Class<? extends T> modelClass, ResultSet rs) {\r
                List<T> result = new ArrayList<T>();\r
@@ -259,14 +283,18 @@ public class Db {
                        IQVersion model = dbUpgrader.getClass().getAnnotation(IQVersion.class);\r
                        if (model.value() > 0) {\r
                                DbVersion v = new DbVersion();\r
-                               DbVersion dbVersion =\r
                                // (SCHEMA="" && TABLE="") == DATABASE\r
-                               from(v).where(v.schemaName).is("").and(v.tableName).is("").selectFirst();\r
+                               DbVersion dbVersion = from(v).where(v.schemaName).is("").and(v.tableName).is("")\r
+                                               .selectFirst();\r
                                if (dbVersion == null) {\r
                                        // database has no version registration, but model specifies\r
                                        // version: insert DbVersion entry and return.\r
                                        DbVersion newDb = new DbVersion(model.value());\r
-                                       insert(newDb);\r
+                                       // database is an older version than the model\r
+                                       boolean success = dbUpgrader.upgradeDatabase(this, 0, newDb.version);\r
+                                       if (success) {\r
+                                               insert(newDb);\r
+                                       }\r
                                } else {\r
                                        // database has a version registration:\r
                                        // check to see if upgrade is required.\r
@@ -293,8 +321,8 @@ public class Db {
                                // table is using iciql version tracking.\r
                                DbVersion v = new DbVersion();\r
                                String schema = StringUtils.isNullOrEmpty(model.schemaName) ? "" : model.schemaName;\r
-                               DbVersion dbVersion = from(v).where(v.schemaName).like(schema).and(v.tableName)\r
-                                               .like(model.tableName).selectFirst();\r
+                               DbVersion dbVersion = from(v).where(v.schemaName).is(schema).and(v.tableName)\r
+                                               .is(model.tableName).selectFirst();\r
                                if (dbVersion == null) {\r
                                        // table has no version registration, but model specifies\r
                                        // version: insert DbVersion entry\r
@@ -348,7 +376,7 @@ public class Db {
                upgradeChecked.clear();\r
        }\r
 \r
-       SQLDialect getDialect() {\r
+       public SQLDialect getDialect() {\r
                return dialect;\r
        }\r
 \r
index 7d6f152fd0d62a12624e1dde2d404ca908126a24..524d1848a42f9ea5778bdbc973a106f61ac5ec68 100644 (file)
@@ -27,9 +27,10 @@ public class IciqlException extends RuntimeException {
 \r
        public static final int CODE_UNMAPPED_FIELD = 1;\r
        public static final int CODE_DUPLICATE_KEY = 2;\r
-       public static final int CODE_TABLE_NOT_FOUND = 3;\r
-       public static final int CODE_TABLE_ALREADY_EXISTS = 4;\r
-       public static final int CODE_INDEX_ALREADY_EXISTS = 5;\r
+       public static final int CODE_SCHEMA_NOT_FOUND = 3;\r
+       public static final int CODE_TABLE_NOT_FOUND = 4;\r
+       public static final int CODE_TABLE_ALREADY_EXISTS = 5;\r
+       public static final int CODE_INDEX_ALREADY_EXISTS = 6;\r
 \r
        private static final String TOKEN_UNMAPPED_FIELD = "\\? (=|\\>|\\<|\\<\\>|!=|\\>=|\\<=|LIKE|BETWEEN) \\?";\r
 \r
@@ -95,8 +96,17 @@ public class IciqlException extends RuntimeException {
                        // http://developer.mimer.com/documentation/html_92/Mimer_SQL_Mobile_DocSet/App_Return_Codes2.html\r
                        SQLException s = (SQLException) t;\r
                        String state = s.getSQLState();\r
-                       if ("23505".equals(state)) {\r
+                       if ("23000".equals(state)) {\r
+                               // MySQL\r
                                iciqlCode = CODE_DUPLICATE_KEY;\r
+                       } else if ("23505".equals(state)) {\r
+                               iciqlCode = CODE_DUPLICATE_KEY;\r
+                       } else if ("42000".equals(state)) {\r
+                               // MySQL\r
+                               iciqlCode = CODE_DUPLICATE_KEY;\r
+                       } else if ("42Y07".equals(state)) {\r
+                               // Derby\r
+                               iciqlCode = CODE_SCHEMA_NOT_FOUND;\r
                        } else if ("42X05".equals(state)) {\r
                                // Derby\r
                                iciqlCode = CODE_TABLE_NOT_FOUND;\r
index 97d9fe9597a1432770f2af6c4a70615ebf1dc7cd..6e6be25c4dcce2e52018fef79ad01a0785336725 100644 (file)
@@ -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 {
         */
        <T> void prepareCreateTable(SQLStatement stat, TableDefinition<T> def);
 
+       /**
+        * Get the DROP TABLE statement.
+        * 
+        * @param stat
+        * @param def
+        */
+       <T> void prepareDropTable(SQLStatement stat, TableDefinition<T> def);
+
        /**
         * Get the CREATE INDEX statement.
         * 
index 69502c3ef318ae3722c8cff40456e1c2f316279f..0b611e0a90b43f5448d772cf4dd9ada6ac831912 100644 (file)
@@ -57,7 +57,8 @@ public class SQLDialectDefault implements SQLDialect {
         * @param sqlType\r
         * @return the SQL type or a preferred alternative\r
         */\r
-       protected String convertSqlType(String sqlType) {\r
+       @Override\r
+       public String convertSqlType(String sqlType) {\r
                return sqlType;\r
        }\r
 \r
@@ -94,6 +95,14 @@ public class SQLDialectDefault implements SQLDialect {
                return name;\r
        }\r
 \r
+       @Override\r
+       public <T> void prepareDropTable(SQLStatement stat, TableDefinition<T> def) {\r
+               StatementBuilder buff = new StatementBuilder("DROP TABLE IF EXISTS "\r
+                               + prepareTableName(def.schemaName, def.tableName));\r
+               stat.setSQL(buff.toString());\r
+               return;\r
+       }\r
+\r
        @Override\r
        public <T> void prepareCreateTable(SQLStatement stat, TableDefinition<T> def) {\r
                StatementBuilder buff;\r
index 42f8cfda344ceb1814731c881e2eb096f405bfd3..019c285cf7dc05e8b5b64f6eefc5153ac6bd77df 100644 (file)
@@ -33,7 +33,7 @@ public class SQLDialectDerby extends SQLDialectDefault {
        }\r
 \r
        @Override\r
-       protected String convertSqlType(String sqlType) {\r
+       public String convertSqlType(String sqlType) {\r
                if ("TINYINT".equals(sqlType)) {\r
                        // Derby does not have a TINYINT/BYTE type\r
                        return "SMALLINT";\r
@@ -81,6 +81,14 @@ public class SQLDialectDerby extends SQLDialectDefault {
                return false;\r
        }\r
 \r
+       @Override\r
+       public <T> void prepareDropTable(SQLStatement stat, TableDefinition<T> def) {\r
+               StatementBuilder buff = new StatementBuilder("DROP TABLE "\r
+                               + prepareTableName(def.schemaName, def.tableName));\r
+               stat.setSQL(buff.toString());\r
+               return;\r
+       }\r
+\r
        @Override\r
        public void prepareCreateIndex(SQLStatement stat, String schema, String table, IndexDefinition index) {\r
                StatementBuilder buff = new StatementBuilder();\r
index a6c12183924c6dfcb2323c6b197a824d4462c617..1c1674ac88ce82f2208d083df1ad52c03702df1b 100644 (file)
@@ -16,6 +16,7 @@
 \r
 package com.iciql;\r
 \r
+import com.iciql.TableDefinition.FieldDefinition;\r
 import com.iciql.TableDefinition.IndexDefinition;\r
 import com.iciql.util.StatementBuilder;\r
 \r
@@ -25,7 +26,7 @@ import com.iciql.util.StatementBuilder;
 public class SQLDialectMySQL extends SQLDialectDefault {\r
 \r
        @Override\r
-       protected String convertSqlType(String sqlType) {\r
+       public String convertSqlType(String sqlType) {\r
                if (sqlType.equals("CLOB")) {\r
                        return "TEXT";\r
                }\r
@@ -75,16 +76,36 @@ public class SQLDialectMySQL extends SQLDialectDefault {
                        buff.append(prepareColumnName(col));\r
                }\r
                buff.append(") ");\r
+               stat.setSQL(buff.toString().trim());\r
+       }\r
 \r
-               // USING\r
-               switch (index.type) {\r
-               case HASH:\r
-                       buff.append("USING HASH");\r
-                       break;\r
-               case UNIQUE_HASH:\r
-                       buff.append("USING HASH");\r
-                       break;\r
+       @Override\r
+       public <T> void prepareMerge(SQLStatement stat, String schemaName, String tableName,\r
+                       TableDefinition<T> def, Object obj) {\r
+               StatementBuilder buff = new StatementBuilder("INSERT INTO ");\r
+               buff.append(prepareTableName(schemaName, tableName)).append(" (");\r
+               buff.resetCount();\r
+               for (FieldDefinition field : def.fields) {\r
+                       buff.appendExceptFirst(", ");\r
+                       buff.append(field.columnName);\r
                }\r
-               stat.setSQL(buff.toString().trim());\r
+               buff.resetCount();\r
+               buff.append(") VALUES (");\r
+               for (FieldDefinition field : def.fields) {\r
+                       buff.appendExceptFirst(", ");\r
+                       buff.append('?');\r
+                       Object value = def.getValue(obj, field);\r
+                       stat.addParameter(value);\r
+               }\r
+               buff.append(") ON DUPLICATE KEY UPDATE ");\r
+               buff.resetCount();\r
+               for (FieldDefinition field : def.fields) {\r
+                       buff.appendExceptFirst(", ");\r
+                       buff.append(field.columnName);\r
+                       buff.append("=VALUES(");\r
+                       buff.append(field.columnName);\r
+                       buff.append(')');\r
+               }\r
+               stat.setSQL(buff.toString());\r
        }\r
 }
\ No newline at end of file
index 4d9fec224a5c47b77f0d6fb4fae62473f48bd450..251f0989171d61e866d64f158abf98eede9f12e1 100644 (file)
@@ -573,7 +573,8 @@ public class TableDefinition<T> {
                        try {\r
                                stat.executeUpdate();\r
                        } catch (IciqlException e) {\r
-                               if (e.getIciqlCode() != IciqlException.CODE_INDEX_ALREADY_EXISTS) {\r
+                               if (e.getIciqlCode() != IciqlException.CODE_INDEX_ALREADY_EXISTS\r
+                                               && e.getIciqlCode() != IciqlException.CODE_DUPLICATE_KEY) {\r
                                        throw e;\r
                                }\r
                        }\r
index dc289565868d372bd8ce9496e2e4e1c5a7abf6f9..093055c4d783d8b581e0399c9d1782aff8fff4c1 100644 (file)
@@ -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));
                        }
                }
 
index 010273929872fb010dc5b0031d94b405d7bce9f4..8dfd7df4f9afd24ca66f3cb740aeaf9f61908bdc 100644 (file)
@@ -58,6 +58,7 @@ public class Build {
                downloadFromApache(MavenObject.H2, BuildType.COMPILETIME);\r
                downloadFromApache(MavenObject.HSQLDB, BuildType.RUNTIME);\r
                downloadFromApache(MavenObject.DERBY, BuildType.RUNTIME);\r
+               downloadFromApache(MavenObject.MYSQL, BuildType.RUNTIME);\r
                downloadFromApache(MavenObject.JCOMMANDER, BuildType.RUNTIME);\r
                downloadFromApache(MavenObject.JCOMMANDER, BuildType.COMPILETIME);\r
                downloadFromApache(MavenObject.MARKDOWNPAPERS, BuildType.RUNTIME);\r
@@ -170,9 +171,9 @@ public class Build {
                                "219a3540f3b27d7cc3b1d91d6ea046cd8723290e", "0bb50eec177acf0e94d58e0cf07262fe5164331d",\r
                                "c7adc475ca40c288c93054e0f4fe58f3a98c0cb5");\r
 \r
-               public static final MavenObject H2 = new MavenObject("com/h2database", "h2", "1.3.159",\r
-                               "dd89f939661eb5593909584e1c243db0c25de130", "4d953bf765e8a13c7e06ca51165438338966c698",\r
-                               "4c79ed03f994820a1a873150c8a9f13c667784d3");\r
+               public static final MavenObject H2 = new MavenObject("com/h2database", "h2", "1.3.158",\r
+                               "4bac13427caeb32ef6e93b70101e61f370c7b5e2", "6bb165156a0831879fa7797df6e18bdcd4421f2d",\r
+                               "446d3f58c44992534cb54f67134532d95961904a");\r
 \r
                public static final MavenObject HSQLDB = new MavenObject("org/hsqldb", "hsqldb", "2.2.4",\r
                                "6a6e040b07f5ee409fc825f1c5e5b574b1fa1428", "", "");\r
@@ -180,6 +181,9 @@ public class Build {
                public static final MavenObject DERBY = new MavenObject("org/apache/derby", "derby", "10.8.1.2",\r
                                "2f8717d96eafe3eef3de445ba653f142d54ddab1", "", "");\r
 \r
+               public static final MavenObject MYSQL = new MavenObject("mysql", "mysql-connector-java", "5.1.15",\r
+                               "0fbc80454d27cc65f3addfa516707e9f8e60c3eb", "", "");\r
+\r
                public static final MavenObject JUNIT = new MavenObject("junit", "junit", "4.8.2",\r
                                "c94f54227b08100974c36170dcb53329435fe5ad", "", "");\r
 \r
index 0504c98126a9979b65e302c35629eb2b8862eb38..b11a5f9765e521c2d48232ca62fe626ef9273a28 100644 (file)
@@ -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.<br>
  * 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());
        }
index 7e4e91888126600e760db5203a68ea72dde9ce70..4f50d61f7ea4a3e110fc255d1536a1ffc24eba11 100644 (file)
@@ -69,30 +69,24 @@ public class AnnotationsTest {
                // test indexes are created, and columns are in the right order
                DatabaseMetaData meta = db.getConnection().getMetaData();
                boolean isH2 = meta.getDatabaseProductName().equals("H2");
-               boolean isDerby = meta.getDatabaseProductName().equals("Apache Derby");
-               ResultSet rs;
-               if (isDerby) {
-                       // Derby defaults to USERNAME schema
-                       rs = meta.getIndexInfo(null, "SA", "ANNOTATEDPRODUCT", false, true);
-               } else {
-                       // H2, HSQL default to PUBLIC schema
-                       rs = meta.getIndexInfo(null, "PUBLIC", "ANNOTATEDPRODUCT", false, true);
-               }
+               String schema = IciqlSuite.getDefaultSchema(db);
+               ResultSet rs = meta.getIndexInfo(null, schema, "ANNOTATEDPRODUCT", false, true);
+
                // first index is primary key index
                // H2 gives this a testable name.
                assertTrue(rs.next());
                if (isH2) {
-                       assertStartsWith(rs.getString("INDEX_NAME"), "PRIMARY_KEY");
+                       assertStartsWith(rs.getString("INDEX_NAME").toUpperCase(), "PRIMARY_KEY");
                }
                assertTrue(rs.next());
-               assertStartsWith(rs.getString("INDEX_NAME"), "ANNOTATEDPRODUCT_0");
-               assertStartsWith(rs.getString("COLUMN_NAME"), "NAME");
+               assertStartsWith(rs.getString("INDEX_NAME").toUpperCase(), "ANNOTATEDPRODUCT_0");
+               assertStartsWith(rs.getString("COLUMN_NAME").toUpperCase(), "NAME");
                assertTrue(rs.next());
-               assertStartsWith(rs.getString("INDEX_NAME"), "ANNOTATEDPRODUCT_0");
-               assertStartsWith(rs.getString("COLUMN_NAME"), "CAT");
+               assertStartsWith(rs.getString("INDEX_NAME").toUpperCase(), "ANNOTATEDPRODUCT_0");
+               assertStartsWith(rs.getString("COLUMN_NAME").toUpperCase(), "CAT");
                assertTrue(rs.next());
-               assertStartsWith(rs.getString("INDEX_NAME"), "NAMEIDX");
-               assertStartsWith(rs.getString("COLUMN_NAME"), "NAME");
+               assertStartsWith(rs.getString("INDEX_NAME").toUpperCase(), "NAMEIDX");
+               assertStartsWith(rs.getString("COLUMN_NAME").toUpperCase(), "NAME");
                assertFalse(rs.next());
        }
 
index 3b32dcbcc831cdf5835efed57ab1040dc290264d..49cee7273a3c6bbd55a36d0053b9c688c3df5e14 100644 (file)
@@ -42,12 +42,14 @@ public class ClobTest {
                db.executeUpdate(MessageFormat.format(create, "VARCHAR(255)"));
                db.insertAll(StringRecord.getList());
                testSimpleUpdate(db, "VARCHAR fail");
+               db.executeUpdate("DROP TABLE CLOB_TEST");
                db.close();
 
                db = IciqlSuite.openNewDb();
-               db.executeUpdate(MessageFormat.format(create, "CLOB"));
+               db.executeUpdate(MessageFormat.format(create, db.getDialect().convertSqlType("CLOB")));
                db.insertAll(StringRecord.getList());
                testSimpleUpdate(db, "CLOB fail because of single quote artifacts");
+               db.executeUpdate("DROP TABLE CLOB_TEST");
                db.close();
        }
 
index b91f3a4c6b850f9c54303b10bf233125701ce124..0389d807dab4aa3cc73b43906af7ab3ababf4515 100644 (file)
@@ -40,6 +40,20 @@ import com.beust.jcommander.ParameterException;
 import com.beust.jcommander.Parameters;\r
 import com.iciql.Constants;\r
 import com.iciql.Db;\r
+import com.iciql.test.models.BooleanModel;\r
+import com.iciql.test.models.ComplexObject;\r
+import com.iciql.test.models.Customer;\r
+import com.iciql.test.models.DefaultValuesModel;\r
+import com.iciql.test.models.EnumModels.EnumIdModel;\r
+import com.iciql.test.models.EnumModels.EnumOrdinalModel;\r
+import com.iciql.test.models.EnumModels.EnumStringModel;\r
+import com.iciql.test.models.Order;\r
+import com.iciql.test.models.PrimitivesModel;\r
+import com.iciql.test.models.Product;\r
+import com.iciql.test.models.ProductAnnotationOnly;\r
+import com.iciql.test.models.ProductInheritedAnnotation;\r
+import com.iciql.test.models.ProductMixedAnnotation;\r
+import com.iciql.test.models.SupportedTypes;\r
 import com.iciql.util.StatementLogger;\r
 import com.iciql.util.StatementLogger.StatementListener;\r
 import com.iciql.util.StatementLogger.StatementType;\r
@@ -58,12 +72,13 @@ import com.iciql.util.StringUtils;
 @RunWith(Suite.class)\r
 @SuiteClasses({ AliasMapTest.class, AnnotationsTest.class, BooleanModelTest.class, ClobTest.class,\r
                ConcurrencyTest.class, EnumsTest.class, ModelsTest.class, PrimitivesTest.class,\r
-               RuntimeQueryTest.class, SamplesTest.class, UpdateTest.class, UUIDTest.class })\r
+               RuntimeQueryTest.class, SamplesTest.class, UpdateTest.class, UpgradesTest.class, UUIDTest.class })\r
 public class IciqlSuite {\r
 \r
-       private static final TestDb[] TEST_DBS = { new TestDb("H2", "jdbc:h2:mem:db{0,number,000}"),\r
-                       new TestDb("HSQL", "jdbc:hsqldb:mem:db{0,number,000}"),\r
-                       new TestDb("Derby", "jdbc:derby:memory:db{0,number,000};create=true") };\r
+       private static final TestDb[] TEST_DBS = { new TestDb("H2 (embedded)", "jdbc:h2:mem:db{0,number,000}"),\r
+                       new TestDb("HSQL (embedded)", "jdbc:hsqldb:mem:db{0,number,000}"),\r
+                       new TestDb("Derby (embedded)", "jdbc:derby:memory:db{0,number,000};create=true"),\r
+                       new TestDb("MySQL (tcp/myisam)", "jdbc:mysql://localhost:3306/iciql") };\r
 \r
        private static final TestDb DEFAULT_TEST_DB = TEST_DBS[0];\r
 \r
@@ -82,6 +97,13 @@ public class IciqlSuite {
                                value.startsWith(startsWith));\r
        }\r
 \r
+       public static boolean equivalentTo(double expected, double actual) {\r
+               if (Double.compare(expected, actual) == 0) {\r
+                       return true;\r
+               }\r
+               return Math.abs(expected - actual) <= 0.000001d;\r
+       }\r
+\r
        /**\r
         * Increment the database counter, open and create a new database.\r
         * \r
@@ -93,7 +115,25 @@ public class IciqlSuite {
                        testUrl = DEFAULT_TEST_DB.url;\r
                }\r
                testUrl = MessageFormat.format(testUrl, openCount.incrementAndGet());\r
-               return Db.open(testUrl, username, password);\r
+               Db db = Db.open(testUrl, username, password);\r
+\r
+               // drop tables\r
+               db.dropTable(BooleanModel.class);\r
+               db.dropTable(ComplexObject.class);\r
+               db.dropTable(Customer.class);\r
+               db.dropTable(DefaultValuesModel.class);\r
+               db.dropTable(EnumIdModel.class);\r
+               db.dropTable(EnumOrdinalModel.class);\r
+               db.dropTable(EnumStringModel.class);\r
+               db.dropTable(Order.class);\r
+               db.dropTable(PrimitivesModel.class);\r
+               db.dropTable(Product.class);\r
+               db.dropTable(ProductAnnotationOnly.class);\r
+               db.dropTable(ProductInheritedAnnotation.class);\r
+               db.dropTable(ProductMixedAnnotation.class);\r
+               db.dropTable(SupportedTypes.class);\r
+\r
+               return db;\r
        }\r
 \r
        /**\r
@@ -110,6 +150,15 @@ public class IciqlSuite {
                return Db.open(testUrl, username, password);\r
        }\r
 \r
+       /**\r
+        * Drops all tables from the current database.\r
+        * \r
+        * @return the current database\r
+        */\r
+       public static void dropAllTables(Db db) {\r
+\r
+       }\r
+\r
        /**\r
         * Returns the name of the underlying database engine for the Db object.\r
         * \r
@@ -145,6 +194,16 @@ public class IciqlSuite {
                return IciqlSuite.getDatabaseEngineName(db).equals("H2");\r
        }\r
 \r
+       /**\r
+        * Returns true if the underlying database engine is MySQL.\r
+        * \r
+        * @param db\r
+        * @return true if underlying database engine is MySQL\r
+        */\r
+       public static boolean isMySQL(Db db) {\r
+               return IciqlSuite.getDatabaseEngineName(db).equals("MySQL");\r
+       }\r
+\r
        /**\r
         * Gets the default schema of the underlying database engine.\r
         * \r
@@ -155,7 +214,11 @@ public class IciqlSuite {
                if (isDerby(db)) {\r
                        // Derby sets default schema name to username\r
                        return username.toUpperCase();\r
+               } else if (isMySQL(db)) {\r
+                       // MySQL does not have schemas\r
+                       return null;\r
                }\r
+\r
                return "PUBLIC";\r
        }\r
 \r
@@ -206,8 +269,8 @@ public class IciqlSuite {
 \r
                SuiteClasses suiteClasses = IciqlSuite.class.getAnnotation(SuiteClasses.class);\r
                long quickestDatabase = Long.MAX_VALUE;\r
-               String dividerMajor = buildDivider('*', 70);\r
-               String dividerMinor = buildDivider('-', 70);\r
+               String dividerMajor = buildDivider('*', 79);\r
+               String dividerMinor = buildDivider('-', 79);\r
 \r
                // Header\r
                out.println(dividerMajor);\r
@@ -225,7 +288,7 @@ public class IciqlSuite {
                showProperty("available processors", "" + Runtime.getRuntime().availableProcessors());\r
                showProperty(\r
                                "available memory",\r
-                               MessageFormat.format("{0,number,#.0} GB", ((double) Runtime.getRuntime().maxMemory())\r
+                               MessageFormat.format("{0,number,0.0} GB", ((double) Runtime.getRuntime().maxMemory())\r
                                                / (1024 * 1024)));\r
                out.println();\r
 \r
@@ -246,32 +309,42 @@ public class IciqlSuite {
                                statementWriter.append("\n\n");\r
                        }\r
 \r
-                       System.setProperty("iciql.url", testDb.url);\r
-                       Result result = JUnitCore.runClasses(suiteClasses.value());\r
-                       testDb.runtime = result.getRunTime();\r
-                       if (testDb.runtime < quickestDatabase) {\r
-                               quickestDatabase = testDb.runtime;\r
-                       }\r
-                       testDb.statements = StatementLogger.getTotalCount() - lastCount;\r
-                       // reset total count for next database\r
-                       lastCount = StatementLogger.getTotalCount();\r
-\r
-                       out.println(MessageFormat.format(\r
-                                       "{0} tests ({1} failures, {2} ignores)  {3} statements in {4,number,0.000} secs",\r
-                                       result.getRunCount(), result.getFailureCount(), result.getIgnoreCount(),\r
-                                       testDb.statements, result.getRunTime() / 1000f));\r
-\r
-                       if (result.getFailureCount() == 0) {\r
-                               out.println();\r
+                       if (testDb.getVersion().equals("OFFLINE")) {\r
+                               // Database not available\r
+                               out.println("Skipping.  Could not find " + testDb.url);\r
                        } else {\r
-                               for (Failure failure : result.getFailures()) {\r
-                                       out.println(MessageFormat.format("\n  + {0}\n    {1}\n", failure.getTestHeader(),\r
-                                                       failure.getMessage()));\r
+                               // Test database\r
+                               System.setProperty("iciql.url", testDb.url);\r
+                               Result result = JUnitCore.runClasses(suiteClasses.value());\r
+                               testDb.runtime = result.getRunTime();\r
+                               if (testDb.runtime < quickestDatabase) {\r
+                                       quickestDatabase = testDb.runtime;\r
+                               }\r
+                               testDb.statements = StatementLogger.getTotalCount() - lastCount;\r
+                               // reset total count for next database\r
+                               lastCount = StatementLogger.getTotalCount();\r
+\r
+                               out.println(MessageFormat.format(\r
+                                               "{0} tests ({1} failures, {2} ignores)  {3} statements in {4,number,0.000} secs",\r
+                                               result.getRunCount(), result.getFailureCount(), result.getIgnoreCount(),\r
+                                               testDb.statements, result.getRunTime() / 1000f));\r
+\r
+                               if (result.getFailureCount() == 0) {\r
+                                       out.println();\r
+                                       out.println("  100% successful test suite run.");\r
+                                       out.println();\r
+                               } else {\r
+                                       for (Failure failure : result.getFailures()) {\r
+                                               out.println(MessageFormat.format("\n  + {0}\n    {1}", failure.getTestHeader(),\r
+                                                               failure.getMessage()));\r
+                                       }\r
+                                       out.println();\r
                                }\r
                        }\r
                }\r
 \r
                // Display runtime results sorted by performance leader\r
+               out.println();\r
                out.println(dividerMajor);\r
                out.println(MessageFormat.format("{0} {1} ({2}) test suite performance results", Constants.NAME,\r
                                Constants.VERSION, Constants.VERSION_DATE));\r
@@ -281,6 +354,12 @@ public class IciqlSuite {
 \r
                        @Override\r
                        public int compare(TestDb o1, TestDb o2) {\r
+                               if (o1.runtime == 0) {\r
+                                       return 1;\r
+                               }\r
+                               if (o2.runtime == 0) {\r
+                                       return -1;\r
+                               }\r
                                if (o1.runtime == o2.runtime) {\r
                                        return 0;\r
                                }\r
@@ -292,11 +371,11 @@ public class IciqlSuite {
                });\r
                for (TestDb testDb : dbs) {\r
                        out.println(MessageFormat.format(\r
-                                       "{0} {1}  {2,number,0.0} stats/sec  {3,number,0.000} secs  ({4,number,#.0}x)",\r
-                                       StringUtils.pad(testDb.name, 6, " ", true),\r
-                                       StringUtils.pad(testDb.getVersion(), 22, " ", true),\r
-                                       ((double) testDb.statements)/ (testDb.runtime/1000d), testDb.runtime / 1000f,\r
-                                       ((double) testDb.runtime) / quickestDatabase));\r
+                                       "{0} {1}  {2,number,0} stats/sec  {3,number,0.000} secs  ({4,number,0.0}x)",\r
+                                       StringUtils.pad(testDb.name, 20, " ", true),\r
+                                       StringUtils.pad(testDb.getVersion(), 22, " ", true), ((double) testDb.statements)\r
+                                                       / (testDb.runtime / 1000d), testDb.runtime / 1000f, ((double) testDb.runtime)\r
+                                                       / quickestDatabase));\r
                }\r
 \r
                // close PrintStream and restore System.err\r
@@ -362,8 +441,8 @@ public class IciqlSuite {
                                        version = db.getConnection().getMetaData().getDatabaseProductVersion();\r
                                        db.close();\r
                                        return version;\r
-                               } catch (SQLException s) {\r
-                                       version = "";\r
+                               } catch (Throwable t) {\r
+                                       version = "OFFLINE";\r
                                }\r
                        }\r
                        return version;\r
index 9bbf450d53492230021a1c3529bedd7e80fc518c..d2e02fab5f8f58700d24e30e5cbcb95c0a0a61ca 100644 (file)
@@ -23,7 +23,6 @@ import static org.junit.Assert.assertTrue;
 import java.sql.SQLException;
 import java.text.MessageFormat;
 import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
 
 import org.junit.After;
 import org.junit.Before;
@@ -33,15 +32,12 @@ import org.junit.rules.ErrorCollector;
 
 import com.iciql.Db;
 import com.iciql.DbInspector;
-import com.iciql.DbUpgrader;
-import com.iciql.DbVersion;
-import com.iciql.Iciql.IQVersion;
 import com.iciql.ValidationRemark;
 import com.iciql.test.models.Product;
 import com.iciql.test.models.ProductAnnotationOnly;
 import com.iciql.test.models.ProductMixedAnnotation;
 import com.iciql.test.models.SupportedTypes;
-import com.iciql.test.models.SupportedTypes.SupportedTypes2;
+import com.iciql.util.StringUtils;
 
 /**
  * Test that the mapping between classes and tables is done correctly.
@@ -72,13 +68,9 @@ public class ModelsTest {
 
        @Test
        public void testValidateModels() {
-               boolean isH2 = IciqlSuite.isH2(db);
-               boolean isDerby = IciqlSuite.isDerby(db);
                String schemaName = IciqlSuite.getDefaultSchema(db);
-
                DbInspector inspector = new DbInspector(db);
-               validateModel(inspector, schemaName, new Product(), 3);
-               validateModel(inspector, schemaName, new ProductAnnotationOnly(), (isH2 || isDerby) ? 2 : 3);
+               validateModel(inspector, schemaName, new ProductAnnotationOnly(), 2);
                validateModel(inspector, schemaName, new ProductMixedAnnotation(), 4);
        }
 
@@ -95,8 +87,14 @@ public class ModelsTest {
                                errorCollector.addError(new SQLException(remark.toString()));
                        }
                }
-               assertTrue(remarks.get(0).message.equals(MessageFormat.format("@IQSchema(name={0})", schemaName)));
-               assertEquals(sb.toString(), expected, remarks.size());
+
+               if (StringUtils.isNullOrEmpty(schemaName)) {
+                       // no schema expected
+                       assertEquals(sb.toString(), expected - 1, remarks.size());
+               } else {
+                       assertEquals(sb.toString(), expected, remarks.size());
+                       assertEquals(MessageFormat.format("@IQSchema(\"{0}\")", schemaName), remarks.get(0).message);
+               }
        }
 
        @Test
@@ -133,65 +131,4 @@ public class ModelsTest {
                        assertEquals(1489, models.get(0).length());
                }
        }
-
-       @Test
-       public void testDatabaseUpgrade() {
-               // insert a database version record
-               db.insert(new DbVersion(1));
-
-               TestDbUpgrader dbUpgrader = new TestDbUpgrader();
-               db.setDbUpgrader(dbUpgrader);
-
-               List<SupportedTypes> original = SupportedTypes.createList();
-               db.insertAll(original);
-
-               assertEquals(1, dbUpgrader.oldVersion.get());
-               assertEquals(2, dbUpgrader.newVersion.get());
-       }
-
-       @Test
-       public void testTableUpgrade() {
-               Db db = IciqlSuite.openNewDb();
-
-               // insert first, this will create version record automatically
-               List<SupportedTypes> original = SupportedTypes.createList();
-               db.insertAll(original);
-
-               // reset the dbUpgrader (clears the update check cache)
-               TestDbUpgrader dbUpgrader = new TestDbUpgrader();
-               db.setDbUpgrader(dbUpgrader);
-
-               SupportedTypes2 s2 = new SupportedTypes2();
-
-               List<SupportedTypes2> types = db.from(s2).select();
-               assertEquals(10, types.size());
-               assertEquals(1, dbUpgrader.oldVersion.get());
-               assertEquals(2, dbUpgrader.newVersion.get());
-               db.close();
-       }
-
-       /**
-        * A sample database upgrader class.
-        */
-       @IQVersion(2)
-       class TestDbUpgrader implements DbUpgrader {
-               final AtomicInteger oldVersion = new AtomicInteger(0);
-               final AtomicInteger newVersion = new AtomicInteger(0);
-
-               public boolean upgradeTable(Db db, String schema, String table, int fromVersion, int toVersion) {
-                       // just claims success on upgrade request
-                       oldVersion.set(fromVersion);
-                       newVersion.set(toVersion);
-                       return true;
-               }
-
-               public boolean upgradeDatabase(Db db, int fromVersion, int toVersion) {
-                       // just claims success on upgrade request
-                       oldVersion.set(fromVersion);
-                       newVersion.set(toVersion);
-                       return true;
-               }
-
-       }
-
 }
index f16672af6d9e2e874686ccf6ba046d8481f939a9..17c2151b2feaf35c7b8d9aa497a8e27311c914ac 100644 (file)
@@ -91,6 +91,7 @@ public class SamplesTest {
                TestReverse check = db.from(new TestReverse()).selectFirst();\r
                assertEquals(t.name, check.name);\r
                assertEquals(t.id, check.id);\r
+               db.executeUpdate("DROP TABLE testreverse");\r
        }\r
 \r
        @Test\r
@@ -238,7 +239,8 @@ public class SamplesTest {
        public void testIsNull() {\r
                Product p = new Product();\r
                String sql = db.from(p).whereTrue(isNull(p.productName)).getSQL();\r
-               assertEquals("SELECT * FROM Product WHERE (productName IS NULL)", sql);\r
+               assertEquals("SELECT * FROM Product WHERE (" + db.getDialect().prepareColumnName("productName")\r
+                               + " IS NULL)", sql);\r
        }\r
 \r
        @Test\r
@@ -258,11 +260,13 @@ public class SamplesTest {
        public void testOrAndNot() {\r
                Product p = new Product();\r
                String sql = db.from(p).whereTrue(not(isNull(p.productName))).getSQL();\r
-               assertEquals("SELECT * FROM Product WHERE (NOT productName IS NULL)", sql);\r
+               String productName = db.getDialect().prepareColumnName("productName");\r
+               assertEquals("SELECT * FROM Product WHERE (NOT " + productName + " IS NULL)", sql);\r
                sql = db.from(p).whereTrue(not(isNull(p.productName))).getSQL();\r
-               assertEquals("SELECT * FROM Product WHERE (NOT productName IS NULL)", sql);\r
+               assertEquals("SELECT * FROM Product WHERE (NOT " + productName + " IS NULL)", sql);\r
                sql = db.from(p).whereTrue(db.test(p.productId).is(1)).getSQL();\r
-               assertEquals("SELECT * FROM Product WHERE ((productId = ?))", sql);\r
+               String productId = db.getDialect().prepareColumnName("productId");\r
+               assertEquals("SELECT * FROM Product WHERE ((" + productId + " = ?))", sql);\r
        }\r
 \r
        @Test\r
@@ -316,8 +320,24 @@ public class SamplesTest {
                                .lessThan(java.sql.Timestamp.valueOf("2005-05-05 05:05:05")).and(co.name).is("hello")\r
                                .and(co.time).lessThan(java.sql.Time.valueOf("23:23:23")).and(co.value)\r
                                .is(new BigDecimal("1")).getSQL();\r
-               assertEquals("SELECT * FROM ComplexObject WHERE id = ? AND amount = ? "\r
-                               + "AND birthday < ? AND created < ? AND name = ? AND time < ? AND value = ?", sql);\r
+\r
+               StringBuilder sb = new StringBuilder();\r
+               sb.append("SELECT * FROM ComplexObject WHERE ");\r
+               sb.append(db.getDialect().prepareColumnName("id"));\r
+               sb.append(" = ? AND ");\r
+               sb.append(db.getDialect().prepareColumnName("amount"));\r
+               sb.append(" = ? AND ");\r
+               sb.append(db.getDialect().prepareColumnName("birthday"));\r
+               sb.append(" < ? AND ");\r
+               sb.append(db.getDialect().prepareColumnName("created"));\r
+               sb.append(" < ? AND ");\r
+               sb.append(db.getDialect().prepareColumnName("name"));\r
+               sb.append(" = ? AND ");\r
+               sb.append(db.getDialect().prepareColumnName("time"));\r
+               sb.append(" < ? AND ");\r
+               sb.append(db.getDialect().prepareColumnName("value"));\r
+               sb.append(" = ?");\r
+               assertEquals(sb.toString(), sql);\r
 \r
                long count = db.from(co).where(co.id).is(1).and(co.amount).is(1L).and(co.birthday)\r
                                .lessThan(new java.util.Date()).and(co.created)\r
@@ -340,7 +360,14 @@ public class SamplesTest {
                                return co.id == x && co.name.equals(name) && co.name.equals("hello");\r
                        }\r
                }).getSQL();\r
-               assertEquals("SELECT * FROM ComplexObject WHERE id=? AND ?=name AND 'hello'=name", sql);\r
+               StringBuilder sb = new StringBuilder();\r
+               sb.append("SELECT * FROM ComplexObject WHERE ");\r
+               sb.append(db.getDialect().prepareColumnName("id"));\r
+               sb.append("=? AND ?=");\r
+               sb.append(db.getDialect().prepareColumnName("name"));\r
+               sb.append(" AND 'hello'=");\r
+               sb.append(db.getDialect().prepareColumnName("name"));\r
+               assertEquals(sb.toString(), sql);\r
 \r
                long count = db.from(co).where(new Filter() {\r
                        public boolean where() {\r
index bc3bd12311b0b7dfdc60cb14966893cc573beaf8..9b88cb806f2df4fbf6f358359437734ddb162d8c 100644 (file)
@@ -24,6 +24,7 @@ import java.util.List;
 import java.util.UUID;
 
 import org.junit.After;
+import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -52,10 +53,9 @@ public class UUIDTest {
 
        @Test
        public void testUUIDs() throws Exception {
-               if (!IciqlSuite.isH2(db)) {
-                       // do not test non-H2 databases
-                       return;
-               }
+               // do not test non-H2 databases
+               Assume.assumeTrue(IciqlSuite.isH2(db));
+
                List<UUIDRecord> originals = UUIDRecord.getList();
                db.insertAll(originals);
                UUIDRecord u = new UUIDRecord();
diff --git a/tests/com/iciql/test/UpgradesTest.java b/tests/com/iciql/test/UpgradesTest.java
new file mode 100644 (file)
index 0000000..d4c15e1
--- /dev/null
@@ -0,0 +1,134 @@
+/*\r
+ * Copyright 2011 James Moger.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+package com.iciql.test;\r
+\r
+import static org.junit.Assert.assertEquals;\r
+\r
+import java.util.List;\r
+import java.util.concurrent.atomic.AtomicInteger;\r
+\r
+import org.junit.Test;\r
+\r
+import com.iciql.Db;\r
+import com.iciql.DbUpgrader;\r
+import com.iciql.Iciql.IQVersion;\r
+import com.iciql.test.models.Product;\r
+import com.iciql.test.models.SupportedTypes;\r
+import com.iciql.test.models.SupportedTypes.SupportedTypes2;\r
+\r
+/**\r
+ * Tests the database and table upgrade functions.\r
+ * \r
+ */\r
+public class UpgradesTest {\r
+\r
+       @Test\r
+       public void testDatabaseUpgrade() {\r
+               Db db = IciqlSuite.openNewDb();\r
+\r
+               List<Product> products = Product.getList();\r
+\r
+               // set the v1 upgrader and insert a record.\r
+               // this will trigger the upgrade.\r
+               V1DbUpgrader v1 = new V1DbUpgrader();\r
+               db.setDbUpgrader(v1);\r
+               db.insert(products.get(0));\r
+\r
+               // confirm that upgrade occurred\r
+               assertEquals(0, v1.oldVersion.get());\r
+               assertEquals(1, v1.newVersion.get());\r
+\r
+               // open a second connection to the database\r
+               // and then apply the v2 upgrade.\r
+               // For H2 its important to keep the first connection\r
+               // alive so that the database is not destroyed.\r
+               Db db2 = IciqlSuite.openCurrentDb();\r
+\r
+               // set the v2 upgrader and insert a record.\r
+               // this will trigger the upgrade.\r
+               V2DbUpgrader v2 = new V2DbUpgrader();\r
+               db2.setDbUpgrader(v2);\r
+               db2.insert(products.get(1));\r
+\r
+               // confirm that upgrade occurred\r
+               assertEquals(1, v2.oldVersion.get());\r
+               assertEquals(2, v2.newVersion.get());\r
+\r
+               db.executeUpdate("DROP TABLE iq_versions");\r
+               db.close();\r
+               db2.close();\r
+       }\r
+\r
+       @Test\r
+       public void testTableUpgrade() {\r
+               Db db = IciqlSuite.openNewDb();\r
+\r
+               // insert first, this will create version record automatically\r
+               List<SupportedTypes> original = SupportedTypes.createList();\r
+               db.insertAll(original);\r
+\r
+               // reset the dbUpgrader (clears the update check cache)\r
+               V2DbUpgrader dbUpgrader = new V2DbUpgrader();\r
+               db.setDbUpgrader(dbUpgrader);\r
+\r
+               SupportedTypes2 s2 = new SupportedTypes2();\r
+\r
+               List<SupportedTypes2> types = db.from(s2).select();\r
+               assertEquals(10, types.size());\r
+               assertEquals(1, dbUpgrader.oldVersion.get());\r
+               assertEquals(2, dbUpgrader.newVersion.get());\r
+               db.executeUpdate("DROP TABLE iq_versions");\r
+               db.close();\r
+       }\r
+\r
+       /**\r
+        * A sample database upgrader class.\r
+        */\r
+       class BaseDbUpgrader implements DbUpgrader {\r
+               final AtomicInteger oldVersion = new AtomicInteger(0);\r
+               final AtomicInteger newVersion = new AtomicInteger(0);\r
+\r
+               public boolean upgradeTable(Db db, String schema, String table, int fromVersion, int toVersion) {\r
+                       // just claims success on upgrade request\r
+                       oldVersion.set(fromVersion);\r
+                       newVersion.set(toVersion);\r
+                       return true;\r
+               }\r
+\r
+               public boolean upgradeDatabase(Db db, int fromVersion, int toVersion) {\r
+                       // just claims success on upgrade request\r
+                       oldVersion.set(fromVersion);\r
+                       newVersion.set(toVersion);\r
+                       return true;\r
+               }\r
+       }\r
+\r
+       /**\r
+        * A sample V1 database upgrader class.\r
+        */\r
+       @IQVersion(1)\r
+       class V1DbUpgrader extends BaseDbUpgrader {\r
+       }\r
+\r
+       /**\r
+        * A sample V2 database upgrader class.\r
+        */\r
+       @IQVersion(2)\r
+       class V2DbUpgrader extends BaseDbUpgrader {\r
+       }\r
+\r
+}\r
index 0affd28f9693644336983864bbc7837016a28ec2..44e8b9b78e9d4c8a869c69983345abcf60c7c8fc 100644 (file)
@@ -21,6 +21,7 @@ import java.util.Random;
 \r
 import com.iciql.Iciql.IQColumn;\r
 import com.iciql.Iciql.IQTable;\r
+import com.iciql.test.IciqlSuite;\r
 \r
 /**\r
  * Primitive types model.\r
@@ -67,8 +68,8 @@ public class PrimitivesModel {
                same &= myShort == p.myShort;\r
                same &= myByte == p.myByte;\r
                same &= myBoolean == p.myBoolean;\r
-               same &= myDouble == p.myDouble;\r
-               same &= myFloat == p.myFloat;\r
+               same &= IciqlSuite.equivalentTo(myDouble, p.myDouble);\r
+               same &= IciqlSuite.equivalentTo(myFloat, p.myFloat);\r
                return same;\r
        }\r
 \r
index 80bf0a1630084569c4cd2d2d685d70a0e88c6507..e4de22db2f1d5c0612a4be7fe2fa39b95eb1079c 100644 (file)
@@ -34,12 +34,9 @@ import com.iciql.Iciql.IndexType;
 @IQIndexes({ @IQIndex({ "name", "cat" }), @IQIndex(name = "nameidx", type = IndexType.HASH, value = "name") })
 public class ProductAnnotationOnly {
 
-       @IQColumn(autoIncrement = true)
-       public Integer autoIncrement;
-
        public String unmappedField;
 
-       @IQColumn(name = "id")
+       @IQColumn(name = "id", autoIncrement = true)
        public Integer productId;
 
        @IQColumn(name = "cat", length = 15, trim = true)
index 596af74a94d26e7ce25f1392d96c0e2eabd095d6..1aaa83342ef493ed4058c49f1adc0654869a33e0 100644 (file)
@@ -32,6 +32,7 @@ import com.iciql.Iciql.IQIndexes;
 import com.iciql.Iciql.IQTable;
 import com.iciql.Iciql.IQVersion;
 import com.iciql.Iciql.IndexType;
+import com.iciql.test.IciqlSuite;
 import com.iciql.test.models.EnumModels.Tree;
 import com.iciql.util.Utils;
 
@@ -166,8 +167,8 @@ public class SupportedTypes {
                same &= myShort.equals(s.myShort);
                same &= myInteger.equals(s.myInteger);
                same &= myLong.equals(s.myLong);
-               same &= myFloat.equals(s.myFloat);
-               same &= myDouble.equals(s.myDouble);
+               same &= IciqlSuite.equivalentTo(myFloat, s.myFloat);
+               same &= IciqlSuite.equivalentTo(myDouble, s.myDouble);
                same &= myBigDecimal.compareTo(s.myBigDecimal) == 0;
                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                same &= df.format(myUtilDate).equals(df.format(s.myUtilDate));