summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.classpath1
-rw-r--r--README.markdown4
-rw-r--r--docs/00_index.mkd2
-rw-r--r--docs/01_model_classes.mkd6
-rw-r--r--docs/02_table_versioning.mkd10
-rw-r--r--docs/05_releases.mkd12
-rw-r--r--src/com/iciql/Db.java25
-rw-r--r--src/com/iciql/DbVersion.java2
-rw-r--r--src/com/iciql/Define.java7
-rw-r--r--src/com/iciql/Iciql.java24
-rw-r--r--src/com/iciql/IciqlException.java91
-rw-r--r--src/com/iciql/ModelUtils.java16
-rw-r--r--src/com/iciql/Query.java36
-rw-r--r--src/com/iciql/QueryBetween.java4
-rw-r--r--src/com/iciql/SQLDialect.java25
-rw-r--r--src/com/iciql/SQLDialectDefault.java107
-rw-r--r--src/com/iciql/SQLDialectH2.java9
-rw-r--r--src/com/iciql/SQLDialectHSQL.java68
-rw-r--r--src/com/iciql/SQLDialectMySQL.java46
-rw-r--r--src/com/iciql/SQLStatement.java16
-rw-r--r--src/com/iciql/TableDefinition.java117
-rw-r--r--src/com/iciql/TableInspector.java32
-rw-r--r--src/com/iciql/ValidationRemark.java14
-rw-r--r--src/com/iciql/build/Build.java5
-rw-r--r--src/com/iciql/util/Utils.java22
-rw-r--r--tests/com/iciql/test/StatementLoggerTest.java39
26 files changed, 471 insertions, 269 deletions
diff --git a/.classpath b/.classpath
index 7e65762..c52fc50 100644
--- a/.classpath
+++ b/.classpath
@@ -29,5 +29,6 @@
<attribute name="javadoc_location" value="jar:platform:/resource/iciql/ext/slf4j-api-1.6.1-javadoc.jar!/"/>
</attributes>
</classpathentry>
+ <classpathentry kind="lib" path="ext/hsqldb-2.2.4.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
diff --git a/README.markdown b/README.markdown
index 416bba2..dc8b761 100644
--- a/README.markdown
+++ b/README.markdown
@@ -17,8 +17,8 @@ iciql **is not**...
Supported Databases
-------
-- [H2](http://h2database.com)
-- [MySQL](http://mysql.com)
+- [H2 1.3+](http://h2database.com)
+- [HSQLDB 2.2+](http://hsqldb.org)
- Support for others is planned and should only require creating a simple "dialect" class.
License
diff --git a/docs/00_index.mkd b/docs/00_index.mkd
index 70048e7..1377db1 100644
--- a/docs/00_index.mkd
+++ b/docs/00_index.mkd
@@ -36,7 +36,7 @@ select * from products
</table>
### Supported Databases
-[H2](http://h2database.com), [MySQL](http://mysql.com)
+[H2 1.3+](http://h2database.com), [HSQLDB 2.2+](http://hsqldb.org)
Support for others is planned and should only require creating a simple "dialect" class.
diff --git a/docs/01_model_classes.mkd b/docs/01_model_classes.mkd
index bdddd80..658ff2b 100644
--- a/docs/01_model_classes.mkd
+++ b/docs/01_model_classes.mkd
@@ -17,7 +17,7 @@ The following data types can be used for all iciql expressions.
<table>
<tr><th colspan="2">All Databases</th></tr>
<tr><td>java.lang.String</td>
-<td>VARCHAR *(length > 0)* or TEXT *(length == 0)*</td></tr>
+<td>VARCHAR *(length > 0)* or CLOB *(length == 0)*</td></tr>
<tr><td>java.lang.Boolean</td>
<td>BIT</td></tr>
@@ -41,7 +41,7 @@ The following data types can be used for all iciql expressions.
<td>DOUBLE</td></tr>
<tr><td>java.math.BigDecimal</td>
-<td>DECIMAL</td></tr>
+<td>DECIMAL *(length == 0)* or DECIMAL(length,scale) *(length > 0)*</td></tr>
<tr><td>java.sql.Date</td>
<td>DATE</td></tr>
@@ -56,7 +56,7 @@ The following data types can be used for all iciql expressions.
<td>TIMESTAMP</td></tr>
<tr><td>java.lang.Enum.name()<br/>*default type*</td>
-<td>VARCHAR *(length > 0)* or TEXT *(length == 0)*<br/>*EnumType.NAME*</td></tr>
+<td>VARCHAR *(length > 0)* or CLOB *(length == 0)*<br/>*EnumType.NAME*</td></tr>
<tr><td>java.lang.Enum.ordinal()</td>
<td>INT<br/>*EnumType.ORDINAL*</td></tr>
diff --git a/docs/02_table_versioning.mkd b/docs/02_table_versioning.mkd
index 12cdf6c..29942fe 100644
--- a/docs/02_table_versioning.mkd
+++ b/docs/02_table_versioning.mkd
@@ -8,22 +8,22 @@ AND/OR<br/>
Your `com.iciql.DbUpgrader` implementation must specify the `IQVersion(version)` annotation
### How does it work?
-If you choose to use versioning, iciql will maintain a table within your database named *_iq_versions* which is defined as:
+If you choose to use versioning, iciql will maintain a table within your database named *iq_versions* which is defined as:
- CREATE TABLE _IQ_VERSIONS(SCHEMANAME VARCHAR(255) NOT NULL, TABLENAME VARCHAR(255) NOT NULL, VERSION INT NOT NULL)
+ CREATE TABLE IQ_VERSIONS(SCHEMANAME VARCHAR(255) NOT NULL, TABLENAME VARCHAR(255) NOT NULL, VERSION INT NOT NULL)
This database table is automatically created if and only if at least one of your model classes specifies a *version* > 0.
-When you generate a statement, iciql will compare the annotated version field of your model class to its last known value in the *_iq_versions* table. If *_iq_versions* lags behind the model annotation, iciql will immediately call the registered `com.iciql.DbUpgrader` implementation before generating and executing the current statement.
+When you generate a statement, iciql will compare the annotated version field of your model class to its last known value in the *iq_versions* table. If *iq_versions* lags behind the model annotation, iciql will immediately call the registered `com.iciql.DbUpgrader` implementation before generating and executing the current statement.
When an upgrade scenario is identified, the current version and the annotated version information is passed to either:
- `DbUpgrader.upgradeDatabase(db, fromVersion, toVersion)`
- `DbUpgrader.upgradeTable(db, schema, table, fromVersion, toVersion)`
-both of which allow for non-linear upgrades. If the upgrade method call is successful and returns *true*, iciql will update the *_iq_versions* table with the annotated version number.
+both of which allow for non-linear upgrades. If the upgrade method call is successful and returns *true*, iciql will update the *iq_versions* table with the annotated version number.
The actual upgrade procedure is beyond the scope of iciql and is your responsibility to implement. This is simply a mechanism to automatically identify when an upgrade is necessary.
**NOTE:**<br/>
-The database entry of the *_iq_versions* table is specified as SCHEMANAME='' and TABLENAME=''. \ No newline at end of file
+The database entry of the *iq_versions* table is specified as SCHEMANAME='' and TABLENAME=''. \ No newline at end of file
diff --git a/docs/05_releases.mkd b/docs/05_releases.mkd
index 7fb0113..c999062 100644
--- a/docs/05_releases.mkd
+++ b/docs/05_releases.mkd
@@ -7,9 +7,17 @@
**%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%*
- api change release (API v4)
+- DECIMAL(length, scale) support
+- unspecified length String fields are now CLOB instead of TEXT. dialects can intercept this and convert to another type. e.g. MySQL dialect can change CLOB to TEXT.
+- Boolean now maps to BOOLEAN instead of BIT
+- expressions on unmapped fields will throw an IciqlException
+- improved exception reporting
- moved dialects back to main package
-- refined dialect loading for pooled connections
-- added a MySQL dialect
+- improved automatic dialect determination on pooled connections
+- moved create table and create index statement generation into dialects
+- added HSQL dialect. HSQL fails 4 unit tests, 2 of which are unimplemented merge, 1 has been filed as a bug in HSQL.
+- added MySQL dialect. Untested.
+- renamed <b>_ iq_versions</b> table to *iq_versions* since leading _ character is troublesome for some databases.
- @IQColumn(allowNull=true) -> @IQColumn(nullable=true)
- All columns are assumed NULLABLE unless explicitly set *@IQColumn(nullable = false)*
- allow using objects to assign default values<br/>
diff --git a/src/com/iciql/Db.java b/src/com/iciql/Db.java
index c7801c2..a8c0b12 100644
--- a/src/com/iciql/Db.java
+++ b/src/com/iciql/Db.java
@@ -73,6 +73,7 @@ public class Db {
// 2. DatabaseMetaData.getDatabaseProductName()
DIALECTS.put("H2", SQLDialectH2.class);
DIALECTS.put("MySQL", SQLDialectMySQL.class);
+ DIALECTS.put("HSQL Database Engine", SQLDialectHSQL.class);
}
private Db(Connection conn) {
@@ -83,7 +84,7 @@ public class Db {
data = conn.getMetaData();
databaseName = data.getDatabaseProductName();
} catch (SQLException s) {
- throw new IciqlException("Failed to retrieve database metadata!", s);
+ throw new IciqlException(s, "failed to retrieve database metadata!");
}
dialect = getDialect(databaseName, conn.getClass().getName());
dialect.configureDialect(databaseName, data);
@@ -140,7 +141,7 @@ public class Db {
Connection conn = JdbcUtils.getConnection(null, url, user, password);
return new Db(conn);
} catch (SQLException e) {
- throw convert(e);
+ throw new IciqlException(e);
}
}
@@ -156,7 +157,7 @@ public class Db {
try {
return new Db(ds.getConnection());
} catch (SQLException e) {
- throw convert(e);
+ throw new IciqlException(e);
}
}
@@ -172,14 +173,10 @@ public class Db {
Connection conn = JdbcUtils.getConnection(null, url, prop);
return new Db(conn);
} catch (SQLException e) {
- throw convert(e);
+ throw new IciqlException(e);
}
}
- private static Error convert(Exception e) {
- return new Error(e);
- }
-
public <T> void insert(T t) {
Class<?> clazz = t.getClass();
define(clazz).createTableIfRequired(this).insert(this, t, false);
@@ -191,18 +188,15 @@ public class Db {
}
/**
- * Merge usually INSERTS if the record does not exist or UPDATES the record
- * if it does exist. Not all databases support MERGE and the syntax varies
- * with the database.
+ * Merge INSERTS if the record does not exist or UPDATES the record if it
+ * does exist. Not all databases support MERGE and the syntax varies with
+ * the database.
*
* If the dialect does not support merge an IciqlException will be thrown.
*
* @param t
*/
public <T> void merge(T t) {
- if (!getDialect().supportsMerge()) {
- throw new IciqlException("Merge is not supported by this SQL dialect");
- }
Class<?> clazz = t.getClass();
define(clazz).createTableIfRequired(this).merge(this, t);
}
@@ -383,13 +377,14 @@ public class Db {
}
PreparedStatement prepare(String sql, boolean returnGeneratedKeys) {
+ IciqlException.checkUnmappedField(sql);
try {
if (returnGeneratedKeys) {
return conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
}
return conn.prepareStatement(sql);
} catch (SQLException e) {
- throw new IciqlException(e);
+ throw IciqlException.fromSQL(sql, e);
}
}
diff --git a/src/com/iciql/DbVersion.java b/src/com/iciql/DbVersion.java
index 8ccf66f..6270e14 100644
--- a/src/com/iciql/DbVersion.java
+++ b/src/com/iciql/DbVersion.java
@@ -23,7 +23,7 @@ import com.iciql.Iciql.IQTable;
/**
* A system table to track database and table versions.
*/
-@IQTable(name = "_iq_versions", primaryKey = { "schemaName", "tableName"}, memoryTable = true)
+@IQTable(name = "iq_versions", primaryKey = { "schemaName", "tableName" }, memoryTable = true)
public class DbVersion {
@IQColumn(length = 255)
diff --git a/src/com/iciql/Define.java b/src/com/iciql/Define.java
index d7b42ba..5e969e1 100644
--- a/src/com/iciql/Define.java
+++ b/src/com/iciql/Define.java
@@ -61,7 +61,12 @@ public class Define {
public static void length(Object column, int length) {
checkInDefine();
- currentTableDefinition.setMaxLength(column, length);
+ currentTableDefinition.setLength(column, length);
+ }
+
+ public static void scale(Object column, int scale) {
+ checkInDefine();
+ currentTableDefinition.setScale(column, scale);
}
public static void tableName(String tableName) {
diff --git a/src/com/iciql/Iciql.java b/src/com/iciql/Iciql.java
index 40c412a..33b954b 100644
--- a/src/com/iciql/Iciql.java
+++ b/src/com/iciql/Iciql.java
@@ -40,7 +40,7 @@ import java.lang.annotation.Target;
* </tr>
* <tr>
* <td>java.lang.String</td>
- * <td>VARCHAR (length > 0) or TEXT (length == 0)</td>
+ * <td>VARCHAR (length > 0) or CLOB (length == 0)</td>
* </tr>
* <tr>
* <td>java.lang.Boolean</td>
@@ -72,7 +72,7 @@ import java.lang.annotation.Target;
* </tr>
* <tr>
* <td>java.math.BigDecimal</td>
- * <td>DECIMAL</td>
+ * <td>DECIMAL (length == 0)<br/>DECIMAL(length, scale) (length > 0)</td>
* </tr>
* <tr>
* <td>java.sql.Date</td>
@@ -92,7 +92,7 @@ import java.lang.annotation.Target;
* </tr>
* <tr>
* <td>java.lang.Enum.name()</td>
- * <td>VARCHAR (length > 0) or TEXT (length == 0)<br/>
+ * <td>VARCHAR (length > 0) or CLOB (length == 0)<br/>
* EnumType.NAME</td>
* </tr>
* <tr>
@@ -391,9 +391,12 @@ public interface Iciql {
boolean autoIncrement() default false;
/**
- * If larger than zero, it is used during the CREATE TABLE phase. It may
- * also be used to prevent database exceptions on INSERT and UPDATE
- * statements (see trim).
+ * Length is used to define the length of a VARCHAR column or to define
+ * the precision of a DECIMAL(precision, scale) expression.
+ * <p>
+ * If larger than zero, it is used during the CREATE TABLE phase. For
+ * string values it may also be used to prevent database exceptions on
+ * INSERT and UPDATE statements (see trim).
* <p>
* Any length set in define() may override this annotation setting if
* the model class is not annotated with IQTable. Default: 0.
@@ -401,6 +404,15 @@ public interface Iciql {
int length() default 0;
/**
+ * Scale is used during the CREATE TABLE phase to define the scale of a
+ * DECIMAL(precision, scale) expression.
+ * <p>
+ * Any scale set in define() may override this annotation setting if
+ * the model class is not annotated with IQTable. Default: 0.
+ */
+ int scale() default 0;
+
+ /**
* If true, iciql will automatically trim the string if it exceeds
* length (value.substring(0, length)). Default: false.
*/
diff --git a/src/com/iciql/IciqlException.java b/src/com/iciql/IciqlException.java
index 1e2a890..6e55c79 100644
--- a/src/com/iciql/IciqlException.java
+++ b/src/com/iciql/IciqlException.java
@@ -16,30 +16,109 @@
package com.iciql;
+import java.sql.SQLException;
import java.text.MessageFormat;
+import java.util.regex.Pattern;
/**
* Iciql wraps all exceptions with this class.
*/
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_INDEX_ALREADY_EXISTS = 4;
+
+ private static final String TOKEN_UNMAPPED_FIELD = "\\? (=|\\>|\\<|!=|\\>=|\\<=|LIKE|BETWEEN) \\?";
+
private static final long serialVersionUID = 1L;
+ private String sql;
+
+ private int iciqlCode;
+
+ public IciqlException(Throwable t) {
+ super(t.getMessage(), t);
+ configureCode(t);
+ }
+
public IciqlException(String message, Object... parameters) {
super(parameters.length > 0 ? MessageFormat.format(message, parameters) : message);
-
}
public IciqlException(Throwable t, String message, Object... parameters) {
super(parameters.length > 0 ? MessageFormat.format(message, parameters) : message, t);
-
+ configureCode(t);
+ }
+
+ public static void checkUnmappedField(String sql) {
+ if (Pattern.compile(IciqlException.TOKEN_UNMAPPED_FIELD).matcher(sql).find()) {
+ IciqlException e = new IciqlException("unmapped field in statement!");
+ e.sql = sql;
+ e.iciqlCode = CODE_UNMAPPED_FIELD;
+ throw e;
+ }
+ }
+
+ public static IciqlException fromSQL(String sql, Throwable t) {
+ if (Pattern.compile(TOKEN_UNMAPPED_FIELD).matcher(sql).find()) {
+ IciqlException e = new IciqlException(t, "unmapped field in statement!");
+ e.sql = sql;
+ e.iciqlCode = CODE_UNMAPPED_FIELD;
+ return e;
+ } else {
+ IciqlException e = new IciqlException(t, t.getMessage());
+ e.sql = sql;
+ return e;
+ }
+ }
+
+ public void setSQL(String sql) {
+ this.sql = sql;
}
- public IciqlException(Throwable t) {
- super(t);
+ public String getSQL() {
+ return sql;
}
- public IciqlException(String message, Throwable t) {
- super(message, t);
+ public int getIciqlCode() {
+ return iciqlCode;
+ }
+
+ private void configureCode(Throwable t) {
+ if (t == null) {
+ return;
+ }
+ if (t instanceof SQLException) {
+ // 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)) {
+ iciqlCode = CODE_DUPLICATE_KEY;
+ } else if ("42501".equals(state)) {
+ iciqlCode = CODE_TABLE_NOT_FOUND;
+ } else if ("42S02".equals(state)) {
+ iciqlCode = CODE_TABLE_NOT_FOUND;
+ } else if ("42504".equals(state)) {
+ iciqlCode = CODE_INDEX_ALREADY_EXISTS;
+ } else if ("42S11".equals(state)) {
+ iciqlCode = CODE_INDEX_ALREADY_EXISTS;
+ }
+ }
}
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(getClass().getName());
+ String message = getLocalizedMessage();
+ if (message != null) {
+ sb.append(": ").append(message);
+ }
+ if (sql != null) {
+ sb.append('\n').append(sql);
+ }
+ return sb.toString();
+ }
}
diff --git a/src/com/iciql/ModelUtils.java b/src/com/iciql/ModelUtils.java
index 2e42a7d..441bca7 100644
--- a/src/com/iciql/ModelUtils.java
+++ b/src/com/iciql/ModelUtils.java
@@ -49,7 +49,7 @@ class ModelUtils {
static {
Map<Class<?>, String> m = SUPPORTED_TYPES;
m.put(String.class, "VARCHAR");
- m.put(Boolean.class, "BIT");
+ m.put(Boolean.class, "BOOLEAN");
m.put(Byte.class, "TINYINT");
m.put(Short.class, "SMALLINT");
m.put(Integer.class, "INT");
@@ -100,8 +100,8 @@ class ModelUtils {
m.put("NCLOB", "VARCHAR");
// logic
- m.put("BOOL", "BIT");
- m.put("BOOLEAN", "BIT");
+ m.put("BIT", "BOOLEAN");
+ m.put("BOOL", "BOOLEAN");
// numeric
m.put("BYTE", "TINYINT");
@@ -159,19 +159,11 @@ class ModelUtils {
return "INT";
case NAME:
default:
- if (fieldDef.maxLength <= 0) {
- return "TEXT";
- }
return "VARCHAR";
}
}
if (SUPPORTED_TYPES.containsKey(fieldClass)) {
- String type = SUPPORTED_TYPES.get(fieldClass);
- if (type.equals("VARCHAR") && fieldDef.maxLength <= 0) {
- // unspecified length strings are TEXT, not VARCHAR
- return "TEXT";
- }
- return type;
+ return SUPPORTED_TYPES.get(fieldClass);
}
if (!strictTypeMapping) {
return "VARCHAR";
diff --git a/src/com/iciql/Query.java b/src/com/iciql/Query.java
index 2e58fe5..5c2d225 100644
--- a/src/com/iciql/Query.java
+++ b/src/com/iciql/Query.java
@@ -83,7 +83,7 @@ public class Query<T> {
long value = rs.getLong(1);
return value;
} catch (SQLException e) {
- throw new IciqlException(e);
+ throw IciqlException.fromSQL(stat.getSQL(), e);
} finally {
JdbcUtils.closeSilently(rs, true);
}
@@ -128,7 +128,7 @@ public class Query<T> {
result.add(item);
}
} catch (SQLException e) {
- throw new IciqlException(e);
+ throw IciqlException.fromSQL(stat.getSQL(), e);
} finally {
JdbcUtils.closeSilently(rs, true);
}
@@ -204,7 +204,7 @@ public class Query<T> {
result.add(row);
}
} catch (SQLException e) {
- throw new IciqlException(e);
+ throw IciqlException.fromSQL(stat.getSQL(), e);
} finally {
JdbcUtils.closeSilently(rs, true);
}
@@ -220,26 +220,20 @@ public class Query<T> {
List<X> result = Utils.newArrayList();
try {
while (rs.next()) {
- try {
- X value;
- Object o = rs.getObject(1);
- // Convert CLOB and BLOB now because we close the resultset
- if (Clob.class.isAssignableFrom(o.getClass())) {
- value = (X) Utils.convert(o, String.class);
- } else if (Blob.class.isAssignableFrom(o.getClass())) {
- value = (X) Utils.convert(o, byte[].class);
- } else {
- value = (X) o;
- }
- result.add(value);
- } catch (IciqlException e) {
- throw e;
- } catch (Exception e) {
- throw new IciqlException(e);
+ X value;
+ Object o = rs.getObject(1);
+ // Convert CLOB and BLOB now because we close the resultset
+ if (Clob.class.isAssignableFrom(o.getClass())) {
+ value = (X) Utils.convert(o, String.class);
+ } else if (Blob.class.isAssignableFrom(o.getClass())) {
+ value = (X) Utils.convert(o, byte[].class);
+ } else {
+ value = (X) o;
}
+ result.add(value);
}
- } catch (SQLException e) {
- throw new IciqlException(e);
+ } catch (Exception e) {
+ throw IciqlException.fromSQL(stat.getSQL(), e);
} finally {
JdbcUtils.closeSilently(rs, true);
}
diff --git a/src/com/iciql/QueryBetween.java b/src/com/iciql/QueryBetween.java
index de09515..8628f40 100644
--- a/src/com/iciql/QueryBetween.java
+++ b/src/com/iciql/QueryBetween.java
@@ -18,6 +18,10 @@ package com.iciql;
/**
* This class represents a "between y and z" condition.
+ * @param <T>
+ * the return type of the query
+ * @param <A>
+ * the incomplete condition data type
*/
public class QueryBetween<T, A> {
diff --git a/src/com/iciql/SQLDialect.java b/src/com/iciql/SQLDialect.java
index 3ca2c4c..7821c3f 100644
--- a/src/com/iciql/SQLDialect.java
+++ b/src/com/iciql/SQLDialect.java
@@ -56,6 +56,14 @@ public interface SQLDialect {
String prepareColumnName(String name);
/**
+ * Get the CREATE TABLE statement.
+ *
+ * @param stat
+ * @param def
+ */
+ <T> void prepareCreateTable(SQLStatement stat, TableDefinition<T> def);
+
+ /**
* Get the CREATE INDEX statement.
*
* @param schemaName
@@ -66,8 +74,8 @@ public interface SQLDialect {
* the index definition
* @return the SQL statement
*/
- String prepareCreateIndex(String schemaName, String tableName, IndexDefinition index);
-
+ void prepareCreateIndex(SQLStatement stat, String schemaName, String tableName, IndexDefinition index);
+
/**
* Get a MERGE or REPLACE INTO statement.
*
@@ -78,7 +86,8 @@ public interface SQLDialect {
* @param index
* the index definition
*/
- <T> void prepareMerge(SQLStatement stat, String schemaName, String tableName, TableDefinition<T> def, Object obj);
+ <T> void prepareMerge(SQLStatement stat, String schemaName, String tableName, TableDefinition<T> def,
+ Object obj);
/**
* Append "LIMIT limit" to the SQL statement.
@@ -106,18 +115,12 @@ public interface SQLDialect {
* @return true if they are
*/
boolean supportsMemoryTables();
-
- /**
- * Whether merge is a supported function.
- *
- * @return true if they are
- */
- boolean supportsMerge();
-
+
/**
* Whether LIMIT/OFFSET notation is supported.
*
* @return true if they are
*/
boolean supportsLimitOffset();
+
}
diff --git a/src/com/iciql/SQLDialectDefault.java b/src/com/iciql/SQLDialectDefault.java
index 760a1f4..3fd2067 100644
--- a/src/com/iciql/SQLDialectDefault.java
+++ b/src/com/iciql/SQLDialectDefault.java
@@ -20,7 +20,9 @@ package com.iciql;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
+import com.iciql.TableDefinition.FieldDefinition;
import com.iciql.TableDefinition.IndexDefinition;
+import com.iciql.util.StatementBuilder;
import com.iciql.util.StringUtils;
/**
@@ -49,13 +51,18 @@ public class SQLDialectDefault implements SQLDialect {
}
}
- @Override
- public boolean supportsMemoryTables() {
- return false;
+ /**
+ * Allows subclasses to change the type of a column for a CREATE statement.
+ *
+ * @param sqlType
+ * @return the SQL type or a preferred alternative
+ */
+ protected String convertSqlType(String sqlType) {
+ return sqlType;
}
@Override
- public boolean supportsMerge() {
+ public boolean supportsMemoryTables() {
return false;
}
@@ -78,12 +85,100 @@ public class SQLDialectDefault implements SQLDialect {
}
@Override
- public String prepareCreateIndex(String schemaName, String tableName, IndexDefinition index) {
+ public <T> void prepareCreateTable(SQLStatement stat, TableDefinition<T> def) {
+ StatementBuilder buff;
+ if (def.memoryTable && supportsMemoryTables()) {
+ buff = new StatementBuilder("CREATE MEMORY TABLE IF NOT EXISTS ");
+ } else {
+ buff = new StatementBuilder("CREATE TABLE IF NOT EXISTS ");
+ }
+
+ buff.append(prepareTableName(def.schemaName, def.tableName)).append('(');
+
+ boolean hasIdentityColumn = false;
+ for (FieldDefinition field : def.fields) {
+ buff.appendExceptFirst(", ");
+ buff.append(prepareColumnName(field.columnName)).append(' ');
+ String dataType = field.dataType;
+ if (dataType.equals("VARCHAR")) {
+ // check to see if we should use VARCHAR or CLOB
+ if (field.length <= 0) {
+ dataType = "CLOB";
+ }
+ buff.append(convertSqlType(dataType));
+ if (field.length > 0) {
+ buff.append('(').append(field.length).append(')');
+ }
+ } else if (dataType.equals("DECIMAL")) {
+ // DECIMAL(precision,scale)
+ buff.append(convertSqlType(dataType));
+ if (field.length > 0) {
+ buff.append('(').append(field.length);
+ if (field.scale > 0) {
+ buff.append(',').append(field.scale);
+ }
+ buff.append(')');
+ }
+ } else {
+ // other
+ buff.append(convertSqlType(dataType));
+ }
+
+ hasIdentityColumn |= prepareColumnDefinition(buff, field.isAutoIncrement, field.isPrimaryKey);
+
+ if (!field.nullable) {
+ buff.append(" NOT NULL");
+ }
+
+ // default values
+ if (!field.isAutoIncrement && !field.isPrimaryKey) {
+ String dv = field.defaultValue;
+ if (!StringUtils.isNullOrEmpty(dv)) {
+ if (ModelUtils.isProperlyFormattedDefaultValue(dv)
+ && ModelUtils.isValidDefaultValue(field.field.getType(), dv)) {
+ buff.append(" DEFAULT " + dv);
+ }
+ }
+ }
+ }
+
+ // if table does not have identity column then specify primary key
+ if (!hasIdentityColumn) {
+ if (def.primaryKeyColumnNames != null && def.primaryKeyColumnNames.size() > 0) {
+ buff.append(", PRIMARY KEY(");
+ buff.resetCount();
+ for (String n : def.primaryKeyColumnNames) {
+ buff.appendExceptFirst(", ");
+ buff.append(prepareColumnName(n));
+ }
+ buff.append(')');
+ }
+ }
+ buff.append(')');
+ stat.setSQL(buff.toString());
+ }
+
+ protected boolean prepareColumnDefinition(StatementBuilder buff, boolean isAutoIncrement,
+ boolean isPrimaryKey) {
+ boolean isIdentity = false;
+ if (isAutoIncrement && isPrimaryKey) {
+ buff.append(" IDENTITY");
+ isIdentity = true;
+ } else if (isAutoIncrement) {
+ buff.append(" AUTO_INCREMENT");
+ }
+ return isIdentity;
+ }
+
+ @Override
+ public void prepareCreateIndex(SQLStatement stat, String schemaName, String tableName,
+ IndexDefinition index) {
throw new IciqlException("Dialect does not support index creation!");
}
@Override
- public <T> void prepareMerge(SQLStatement stat, String schemaName, String tableName, TableDefinition<T> def, Object obj) {
+ public <T> void prepareMerge(SQLStatement stat, String schemaName, String tableName,
+ TableDefinition<T> def, Object obj) {
throw new IciqlException("Dialect does not support merge statements!");
}
diff --git a/src/com/iciql/SQLDialectH2.java b/src/com/iciql/SQLDialectH2.java
index c65c277..80786f9 100644
--- a/src/com/iciql/SQLDialectH2.java
+++ b/src/com/iciql/SQLDialectH2.java
@@ -31,12 +31,7 @@ public class SQLDialectH2 extends SQLDialectDefault {
}
@Override
- public boolean supportsMerge() {
- return true;
- }
-
- @Override
- public String prepareCreateIndex(String schema, String table, IndexDefinition index) {
+ public void prepareCreateIndex(SQLStatement stat, String schema, String table, IndexDefinition index) {
StatementBuilder buff = new StatementBuilder();
buff.append("CREATE ");
switch (index.type) {
@@ -62,7 +57,7 @@ public class SQLDialectH2 extends SQLDialectDefault {
buff.append(col);
}
buff.append(")");
- return buff.toString();
+ stat.setSQL(buff.toString());
}
@Override
diff --git a/src/com/iciql/SQLDialectHSQL.java b/src/com/iciql/SQLDialectHSQL.java
new file mode 100644
index 0000000..e617758
--- /dev/null
+++ b/src/com/iciql/SQLDialectHSQL.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2011 James Moger.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.iciql;
+
+import com.iciql.TableDefinition.IndexDefinition;
+import com.iciql.util.StatementBuilder;
+
+/**
+ * HyperSQL database dialect.
+ */
+public class SQLDialectHSQL extends SQLDialectDefault {
+
+ @Override
+ public boolean supportsMemoryTables() {
+ return true;
+ }
+
+ @Override
+ protected boolean prepareColumnDefinition(StatementBuilder buff, boolean isAutoIncrement, boolean isPrimaryKey) {
+ boolean isIdentity = false;
+ if (isAutoIncrement && isPrimaryKey) {
+ buff.append(" IDENTITY");
+ isIdentity = true;
+ }
+ return isIdentity;
+ }
+
+ @Override
+ public void prepareCreateIndex(SQLStatement stat, String schema, String table, IndexDefinition index) {
+ StatementBuilder buff = new StatementBuilder();
+ buff.append("CREATE ");
+ switch (index.type) {
+ case STANDARD:
+ break;
+ case UNIQUE:
+ buff.append("UNIQUE ");
+ break;
+ case UNIQUE_HASH:
+ buff.append("UNIQUE ");
+ break;
+ }
+ buff.append("INDEX ");
+ buff.append(index.indexName);
+ buff.append(" ON ");
+ buff.append(table);
+ buff.append("(");
+ for (String col : index.columnNames) {
+ buff.appendExceptFirst(", ");
+ buff.append(col);
+ }
+ buff.append(")");
+ stat.setSQL(buff.toString());
+ }
+} \ No newline at end of file
diff --git a/src/com/iciql/SQLDialectMySQL.java b/src/com/iciql/SQLDialectMySQL.java
index 837d77b..2593e0a 100644
--- a/src/com/iciql/SQLDialectMySQL.java
+++ b/src/com/iciql/SQLDialectMySQL.java
@@ -16,7 +16,6 @@
package com.iciql;
-import com.iciql.TableDefinition.FieldDefinition;
import com.iciql.TableDefinition.IndexDefinition;
import com.iciql.util.StatementBuilder;
@@ -26,13 +25,16 @@ import com.iciql.util.StatementBuilder;
public class SQLDialectMySQL extends SQLDialectDefault {
@Override
- public boolean supportsMemoryTables() {
- return false;
+ protected String convertSqlType(String sqlType) {
+ if (sqlType.equals("CLOB")) {
+ return "TEXT";
+ }
+ return sqlType;
}
-
+
@Override
- public boolean supportsMerge() {
- return true;
+ public boolean supportsMemoryTables() {
+ return false;
}
@Override
@@ -41,7 +43,15 @@ public class SQLDialectMySQL extends SQLDialectDefault {
}
@Override
- public String prepareCreateIndex(String schema, String table, IndexDefinition index) {
+ protected boolean prepareColumnDefinition(StatementBuilder buff, boolean isAutoIncrement, boolean isPrimaryKey) {
+ if (isAutoIncrement) {
+ buff.append(" AUTO_INCREMENT");
+ }
+ return false;
+ }
+
+ @Override
+ public void prepareCreateIndex(SQLStatement stat, String schema, String table, IndexDefinition index) {
StatementBuilder buff = new StatementBuilder();
buff.append("CREATE ");
switch (index.type) {
@@ -74,26 +84,6 @@ public class SQLDialectMySQL extends SQLDialectDefault {
buff.append("USING HASH");
break;
}
- return buff.toString().trim();
- }
-
- @Override
- public <T> void prepareMerge(SQLStatement stat, String schemaName, String tableName, TableDefinition<T> def, Object obj) {
- StatementBuilder buff = new StatementBuilder("REPLACE INTO ");
- buff.append(prepareTableName(schemaName, tableName)).append('(');
- for (FieldDefinition field : def.fields) {
- buff.appendExceptFirst(", ");
- buff.append(prepareColumnName(field.columnName));
- }
- buff.append(") VALUES(");
- buff.resetCount();
- for (FieldDefinition field : def.fields) {
- buff.appendExceptFirst(", ");
- buff.append('?');
- Object value = def.getValue(obj, field);
- stat.addParameter(value);
- }
- buff.append(')');
- stat.setSQL(buff.toString());
+ stat.setSQL(buff.toString().trim());
}
} \ No newline at end of file
diff --git a/src/com/iciql/SQLStatement.java b/src/com/iciql/SQLStatement.java
index 49c7627..4962502 100644
--- a/src/com/iciql/SQLStatement.java
+++ b/src/com/iciql/SQLStatement.java
@@ -52,7 +52,7 @@ public class SQLStatement {
public SQLStatement appendTable(String schema, String table) {
return appendSQL(db.getDialect().prepareTableName(schema, table));
}
-
+
public SQLStatement appendColumn(String column) {
return appendSQL(db.getDialect().prepareColumnName(column));
}
@@ -63,7 +63,7 @@ public class SQLStatement {
}
return sql;
}
-
+
public SQLStatement addParameter(Object o) {
params.add(o);
return this;
@@ -73,7 +73,7 @@ public class SQLStatement {
try {
return prepare(false).executeQuery();
} catch (SQLException e) {
- throw new IciqlException(e);
+ throw IciqlException.fromSQL(getSQL(), e);
}
}
@@ -83,7 +83,7 @@ public class SQLStatement {
ps = prepare(false);
return ps.executeUpdate();
} catch (SQLException e) {
- throw new IciqlException(e);
+ throw IciqlException.fromSQL(getSQL(), e);
} finally {
JdbcUtils.closeSilently(ps);
}
@@ -102,17 +102,19 @@ public class SQLStatement {
JdbcUtils.closeSilently(rs);
return identity;
} catch (SQLException e) {
- throw new IciqlException(e);
+ throw IciqlException.fromSQL(getSQL(), e);
} finally {
JdbcUtils.closeSilently(ps);
}
}
- private static void setValue(PreparedStatement prep, int parameterIndex, Object x) {
+ private void setValue(PreparedStatement prep, int parameterIndex, Object x) {
try {
prep.setObject(parameterIndex, x);
} catch (SQLException e) {
- throw new IciqlException(e);
+ IciqlException ix = new IciqlException(e, "error setting parameter {0} as {1}", parameterIndex, x.getClass().getSimpleName());
+ ix.setSQL(getSQL());
+ throw ix;
}
}
diff --git a/src/com/iciql/TableDefinition.java b/src/com/iciql/TableDefinition.java
index c08a032..571ab1f 100644
--- a/src/com/iciql/TableDefinition.java
+++ b/src/com/iciql/TableDefinition.java
@@ -71,10 +71,11 @@ public class TableDefinition<T> {
String columnName;
Field field;
String dataType;
- int maxLength;
+ int length;
+ int scale;
boolean isPrimaryKey;
boolean isAutoIncrement;
- boolean trimString;
+ boolean trim;
boolean nullable;
String defaultValue;
EnumType enumType;
@@ -125,13 +126,14 @@ public class TableDefinition<T> {
String schemaName;
String tableName;
int tableVersion;
- private boolean createTableIfRequired = true;
+ List<String> primaryKeyColumnNames;
+ boolean memoryTable;
+
+ private boolean createTableIfRequired = true;
private Class<T> clazz;
private IdentityHashMap<Object, FieldDefinition> fieldMap = Utils.newIdentityHashMap();
-
- private List<String> primaryKeyColumnNames;
private ArrayList<IndexDefinition> indexes = Utils.newArrayList();
- private boolean memoryTable;
+
TableDefinition(Class<T> clazz) {
this.clazz = clazz;
@@ -242,10 +244,17 @@ public class TableDefinition<T> {
}
}
- public void setMaxLength(Object column, int maxLength) {
+ public void setLength(Object column, int length) {
+ FieldDefinition def = fieldMap.get(column);
+ if (def != null) {
+ def.length = length;
+ }
+ }
+
+ public void setScale(Object column, int scale) {
FieldDefinition def = fieldMap.get(column);
if (def != null) {
- def.maxLength = maxLength;
+ def.scale = scale;
}
}
@@ -273,8 +282,9 @@ public class TableDefinition<T> {
String columnName = f.getName();
boolean isAutoIncrement = false;
boolean isPrimaryKey = false;
- int maxLength = 0;
- boolean trimString = false;
+ int length = 0;
+ int scale = 0;
+ boolean trim = false;
boolean nullable = true;
EnumType enumType = null;
String defaultValue = "";
@@ -301,8 +311,9 @@ public class TableDefinition<T> {
}
isAutoIncrement = col.autoIncrement();
isPrimaryKey = col.primaryKey();
- maxLength = col.length();
- trimString = col.trim();
+ length = col.length();
+ scale = col.scale();
+ trim = col.trim();
nullable = col.nullable();
// try using default object
@@ -321,7 +332,7 @@ public class TableDefinition<T> {
}
}
} catch (IllegalAccessException e) {
- throw new IciqlException(e, "Failed to get default object for {0}", columnName);
+ throw new IciqlException(e, "failed to get default object for {0}", columnName);
}
// annotation overrides
@@ -338,8 +349,9 @@ public class TableDefinition<T> {
fieldDef.columnName = columnName;
fieldDef.isAutoIncrement = isAutoIncrement;
fieldDef.isPrimaryKey = isPrimaryKey;
- fieldDef.maxLength = maxLength;
- fieldDef.trimString = trimString;
+ fieldDef.length = length;
+ fieldDef.scale = scale;
+ fieldDef.trim = trim;
fieldDef.nullable = nullable;
fieldDef.defaultValue = defaultValue;
fieldDef.enumType = enumType;
@@ -372,9 +384,9 @@ public class TableDefinition<T> {
Enum<?> iqenum = (Enum<?>) value;
switch (field.enumType) {
case NAME:
- if (field.trimString && field.maxLength > 0) {
- if (iqenum.name().length() > field.maxLength) {
- return iqenum.name().substring(0, field.maxLength);
+ if (field.trim && field.length > 0) {
+ if (iqenum.name().length() > field.length) {
+ return iqenum.name().substring(0, field.length);
}
}
return iqenum.name();
@@ -388,12 +400,13 @@ public class TableDefinition<T> {
return enumid.enumId();
}
}
- if (field.trimString && field.maxLength > 0) {
+
+ if (field.trim && field.length > 0) {
if (value instanceof String) {
// clip strings
String s = (String) value;
- if (s.length() > field.maxLength) {
- return s.substring(0, field.maxLength);
+ if (s.length() > field.length) {
+ return s.substring(0, field.length);
}
return s;
}
@@ -514,65 +527,23 @@ public class TableDefinition<T> {
db.upgradeTable(this);
return this;
}
- SQLDialect dialect = db.getDialect();
SQLStatement stat = new SQLStatement(db);
- StatementBuilder buff;
- if (memoryTable && dialect.supportsMemoryTables()) {
- buff = new StatementBuilder("CREATE MEMORY TABLE IF NOT EXISTS ");
- } else {
- buff = new StatementBuilder("CREATE TABLE IF NOT EXISTS ");
- }
-
- buff.append(dialect.prepareTableName(schemaName, tableName)).append('(');
-
- for (FieldDefinition field : fields) {
- buff.appendExceptFirst(", ");
- buff.append(dialect.prepareColumnName(field.columnName)).append(' ').append(field.dataType);
- if (field.maxLength > 0) {
- buff.append('(').append(field.maxLength).append(')');
- }
-
- if (field.isAutoIncrement) {
- buff.append(" AUTO_INCREMENT");
- }
-
- if (!field.nullable) {
- buff.append(" NOT NULL");
- }
-
- // default values
- if (!field.isAutoIncrement && !field.isPrimaryKey) {
- String dv = field.defaultValue;
- if (!StringUtils.isNullOrEmpty(dv)) {
- if (ModelUtils.isProperlyFormattedDefaultValue(dv)
- && ModelUtils.isValidDefaultValue(field.field.getType(), dv)) {
- buff.append(" DEFAULT " + dv);
- }
- }
- }
- }
-
- // primary key
- if (primaryKeyColumnNames != null && primaryKeyColumnNames.size() > 0) {
- buff.append(", PRIMARY KEY(");
- buff.resetCount();
- for (String n : primaryKeyColumnNames) {
- buff.appendExceptFirst(", ");
- buff.append(n);
- }
- buff.append(')');
- }
- buff.append(')');
- stat.setSQL(buff.toString());
+ db.getDialect().prepareCreateTable(stat, this);
StatementLogger.create(stat.getSQL());
stat.executeUpdate();
// create indexes
for (IndexDefinition index : indexes) {
- String sql = db.getDialect().prepareCreateIndex(schemaName, tableName, index);
- stat.setSQL(sql);
+ stat = new SQLStatement(db);
+ db.getDialect().prepareCreateIndex(stat, schemaName, tableName, index);
StatementLogger.create(stat.getSQL());
- stat.executeUpdate();
+ try {
+ stat.executeUpdate();
+ } catch (IciqlException e) {
+ if (e.getIciqlCode() != IciqlException.CODE_INDEX_ALREADY_EXISTS) {
+ throw e;
+ }
+ }
}
// tables are created using IF NOT EXISTS
diff --git a/src/com/iciql/TableInspector.java b/src/com/iciql/TableInspector.java
index a5b6dee..e682f2f 100644
--- a/src/com/iciql/TableInspector.java
+++ b/src/com/iciql/TableInspector.java
@@ -118,9 +118,12 @@ public class TableInspector {
indexes = Utils.newHashMap();
while (rs.next()) {
IndexInspector info = new IndexInspector(rs);
- if (info.type.equals(IndexType.UNIQUE) && info.name.toLowerCase().startsWith("primary")) {
- // skip primary key indexes
- continue;
+ if (info.type.equals(IndexType.UNIQUE)) {
+ String name = info.name.toLowerCase();
+ if (name.startsWith("primary") || name.startsWith("sys_idx_sys_pk")) {
+ // skip primary key indexes
+ continue;
+ }
}
if (indexes.containsKey(info.name)) {
indexes.get(info.name).addColumn(rs);
@@ -140,7 +143,20 @@ public class TableInspector {
col.clazz = ModelUtils.getClassForSqlType(col.type, dateTimeClass);
col.size = rs.getInt("COLUMN_SIZE");
col.nullable = rs.getInt("NULLABLE") == DatabaseMetaData.columnNullable;
- col.isAutoIncrement = rs.getBoolean("IS_AUTOINCREMENT");
+ try {
+ Object autoIncrement = rs.getObject("IS_AUTOINCREMENT");
+ if (autoIncrement instanceof Boolean) {
+ col.isAutoIncrement = (Boolean) autoIncrement;
+ } else if (autoIncrement instanceof String) {
+ String val = autoIncrement.toString().toLowerCase();
+ col.isAutoIncrement = val.equals("true") | val.equals("yes");
+ } else if (autoIncrement instanceof Number) {
+ Number n = (Number) autoIncrement;
+ col.isAutoIncrement = n.intValue() > 0;
+ }
+ } catch (SQLException s) {
+ throw s;
+ }
if (primaryKeys.size() == 1) {
if (col.name.equalsIgnoreCase(primaryKeys.get(0))) {
col.isPrimaryKey = true;
@@ -499,14 +515,14 @@ public class TableInspector {
// string types
if (fieldClass == String.class) {
- if ((fieldDef.maxLength != col.size) && (col.size < Integer.MAX_VALUE)) {
+ if ((fieldDef.length != col.size) && (col.size < Integer.MAX_VALUE)) {
remarks.add(warn(
table,
col,
format("{0}.length={1}, ColumnMaxLength={2}", IQColumn.class.getSimpleName(),
- fieldDef.maxLength, col.size)));
+ fieldDef.length, col.size)));
}
- if (fieldDef.maxLength > 0 && !fieldDef.trimString) {
+ if (fieldDef.length > 0 && !fieldDef.trim) {
remarks.add(consider(table, col, format("{0}.trim=true will prevent IciqlExceptions on"
+ " INSERT or UPDATE, but will clip data!", IQColumn.class.getSimpleName())));
}
@@ -687,7 +703,7 @@ public class TableInspector {
}
}
- void addEnum(String parameter, Enum value) {
+ void addEnum(String parameter, Enum<?> value) {
appendExceptFirst(", ");
if (!StringUtils.isNullOrEmpty(parameter)) {
append(parameter);
diff --git a/src/com/iciql/ValidationRemark.java b/src/com/iciql/ValidationRemark.java
index a68bf21..33320ab 100644
--- a/src/com/iciql/ValidationRemark.java
+++ b/src/com/iciql/ValidationRemark.java
@@ -35,11 +35,11 @@ public class ValidationRemark {
CONSIDER, WARN, ERROR;
}
- private Level level;
- private String table;
- private String fieldType;
- private String fieldName;
- private String message;
+ public final Level level;
+ public final String table;
+ public final String fieldType;
+ public final String fieldName;
+ public final String message;
private ValidationRemark(Level level, String table, String type, String message) {
this.level = level;
@@ -104,10 +104,6 @@ public class ValidationRemark {
return level.equals(Level.ERROR);
}
- public Level getLevel() {
- return level;
- }
-
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(StringUtils.pad(level.name(), 9, " ", true));
diff --git a/src/com/iciql/build/Build.java b/src/com/iciql/build/Build.java
index 5963d16..cc3895c 100644
--- a/src/com/iciql/build/Build.java
+++ b/src/com/iciql/build/Build.java
@@ -56,6 +56,7 @@ public class Build {
public static void compiletime() {
downloadFromApache(MavenObject.H2, BuildType.RUNTIME);
downloadFromApache(MavenObject.H2, BuildType.COMPILETIME);
+ downloadFromApache(MavenObject.HSQLDB, BuildType.RUNTIME);
downloadFromApache(MavenObject.JCOMMANDER, BuildType.RUNTIME);
downloadFromApache(MavenObject.JCOMMANDER, BuildType.COMPILETIME);
downloadFromApache(MavenObject.MARKDOWNPAPERS, BuildType.RUNTIME);
@@ -172,6 +173,10 @@ public class Build {
"4bac13427caeb32ef6e93b70101e61f370c7b5e2", "6bb165156a0831879fa7797df6e18bdcd4421f2d",
"446d3f58c44992534cb54f67134532d95961904a");
+ public static final MavenObject HSQLDB = new MavenObject("org/hsqldb", "hsqldb", "2.2.4",
+ "6a6e040b07f5ee409fc825f1c5e5b574b1fa1428", "",
+ "");
+
public static final MavenObject JUNIT = new MavenObject("junit", "junit", "4.8.2",
"c94f54227b08100974c36170dcb53329435fe5ad", "", "");
diff --git a/src/com/iciql/util/Utils.java b/src/com/iciql/util/Utils.java
index fa794cf..6f9746d 100644
--- a/src/com/iciql/util/Utils.java
+++ b/src/com/iciql/util/Utils.java
@@ -116,7 +116,7 @@ public class Utils {
}
}
}
- throw new IciqlException("Missing default constructor? Exception trying to create " + clazz.getName() + ": " + e, e);
+ throw new IciqlException(e, "Missing default constructor? Exception trying to instantiate {0}: {1}", clazz.getName(), e.getMessage());
}
}
};
@@ -190,7 +190,7 @@ public class Utils {
}
}
}
- throw new IciqlException("Exception trying to create " + clazz.getName() + ": " + e, e);
+ throw new IciqlException(e, "Missing default constructor?! Exception trying to instantiate {0}: {1}", clazz.getName(), e.getMessage());
}
}
@@ -220,18 +220,28 @@ public class Utils {
Reader r = c.getCharacterStream();
return readStringAndClose(r, -1);
} catch (Exception e) {
- throw new IciqlException("Error converting CLOB to String: " + e.toString(), e);
+ throw new IciqlException(e, "error converting CLOB to String: ", e.toString());
}
}
return o.toString();
}
- // convert from number to boolean
if (Boolean.class.isAssignableFrom(targetType) || boolean.class.isAssignableFrom(targetType)) {
+ // convert from number to boolean
if (Number.class.isAssignableFrom(currentType)) {
Number n = (Number) o;
return n.intValue() > 0;
}
+ // convert from string to boolean
+ if (String.class.isAssignableFrom(currentType)) {
+ String s = o.toString().toLowerCase();
+ float f = 0f;
+ try {
+ f = Float.parseFloat(s);
+ } catch (Exception e) {
+ }
+ return f > 0 || s.equals("true") || s.equals("yes");
+ }
}
// convert from boolean to number
@@ -271,7 +281,7 @@ public class Utils {
InputStream is = b.getBinaryStream();
return readBlobAndClose(is, -1);
} catch (Exception e) {
- throw new IciqlException("Error converting BLOB to byte[]: " + e.toString(), e);
+ throw new IciqlException(e, "error converting BLOB to byte[]: ", e.toString());
}
}
}
@@ -315,7 +325,7 @@ public class Utils {
Reader r = c.getCharacterStream();
name = readStringAndClose(r, -1);
} catch (Exception e) {
- throw new IciqlException("Error converting CLOB to String: " + e.toString(), e);
+ throw new IciqlException(e, "error converting CLOB to String: ", e.toString());
}
// find name match
diff --git a/tests/com/iciql/test/StatementLoggerTest.java b/tests/com/iciql/test/StatementLoggerTest.java
deleted file mode 100644
index 212faf2..0000000
--- a/tests/com/iciql/test/StatementLoggerTest.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2011 James Moger.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.iciql.test;
-
-import org.junit.Test;
-
-import com.iciql.Db;
-import com.iciql.test.models.Product;
-import com.iciql.util.StatementLogger;
-
-/**
- * Tests the statement logger.
- */
-public class StatementLoggerTest {
-
- @Test
- public void testStatementLogger() {
- StatementLogger.activateConsoleLogger();
- Db db = Db.open("jdbc:h2:mem:", "sa", "sa");
- db.insertAll(Product.getList());
- db.close();
- StatementLogger.logStats();
- StatementLogger.deactivateConsoleLogger();
- }
-}