diff options
author | James Moger <james.moger@gmail.com> | 2011-08-10 09:01:04 -0400 |
---|---|---|
committer | James Moger <james.moger@gmail.com> | 2011-08-10 09:01:04 -0400 |
commit | 1d381026a5d256a59fe41da42c7f4e86bb60f02c (patch) | |
tree | fd6e7a8aa8d8d2b9855d1e8e249798d372f84f3a | |
parent | 01ec38ed904bd24c9075edfc12c2b41c1e13d249 (diff) | |
download | iciql-1d381026a5d256a59fe41da42c7f4e86bb60f02c.tar.gz iciql-1d381026a5d256a59fe41da42c7f4e86bb60f02c.zip |
Dialect refinements.
-rw-r--r-- | src/com/iciql/Db.java | 70 | ||||
-rw-r--r-- | src/com/iciql/SQLDialect.java | 33 | ||||
-rw-r--r-- | src/com/iciql/SQLStatement.java | 4 | ||||
-rw-r--r-- | src/com/iciql/TableDefinition.java | 38 | ||||
-rw-r--r-- | src/com/iciql/TableInspector.java | 11 | ||||
-rw-r--r-- | src/com/iciql/dialect/DefaultSQLDialect.java | 30 | ||||
-rw-r--r-- | src/com/iciql/dialect/H2Dialect.java | 33 | ||||
-rw-r--r-- | src/com/iciql/dialect/MySQLDialect.java | 85 |
8 files changed, 207 insertions, 97 deletions
diff --git a/src/com/iciql/Db.java b/src/com/iciql/Db.java index cae384d..d6f70d1 100644 --- a/src/com/iciql/Db.java +++ b/src/com/iciql/Db.java @@ -18,6 +18,7 @@ package com.iciql;
import java.sql.Connection;
+import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
@@ -69,38 +70,51 @@ public class Db { static {
TOKENS = Collections.synchronizedMap(new WeakIdentityHashMap<Object, Token>());
DIALECTS = Collections.synchronizedMap(new HashMap<String, Class<? extends SQLDialect>>());
- DIALECTS.put("org.h2", H2Dialect.class);
+ // can register by...
+ // 1. Connection class name
+ // 2. DatabaseMetaData.getDatabaseProductName()
+ DIALECTS.put("h2", H2Dialect.class);
}
private Db(Connection conn) {
this.conn = conn;
- dialect = getDialect(conn.getClass().getCanonicalName());
- dialect.configureDialect(conn);
- }
-
- public static void registerDialect(Connection conn, Class<? extends SQLDialect> dialectClass) {
- registerDialect(conn.getClass().getCanonicalName(), dialectClass);
- }
-
- public static void registerDialect(String connClass, Class<? extends SQLDialect> dialectClass) {
- DIALECTS.put(connClass, dialectClass);
+ String databaseName = null;
+ DatabaseMetaData data = null;
+ try {
+ data = conn.getMetaData();
+ databaseName = data.getDatabaseProductName();
+ } catch (SQLException s) {
+ throw new IciqlException("Failed to retrieve database metadata!", s);
+ }
+ dialect = getDialect(databaseName, conn.getClass().getName());
+ dialect.configureDialect(databaseName, data);
}
- SQLDialect getDialect(String clazz) {
- // try dialect by connection class name
- Class<? extends SQLDialect> dialectClass = DIALECTS.get(clazz);
- while (dialectClass == null) {
- // try dialect by registered name
- for (String registeredName : DIALECTS.keySet()) {
- if (clazz.indexOf(registeredName) > -1) {
- dialectClass = DIALECTS.get(registeredName);
- break;
- }
- }
- if (dialectClass == null) {
- // did not find a match, use default
- dialectClass = DefaultSQLDialect.class;
- }
+ /**
+ * Register a new/custom dialect class. You can use this method to replace
+ * any existing dialect or to add a new one.
+ *
+ * @param token
+ * the fully qualified name of the connection class or the
+ * expected result of DatabaseMetaData.getDatabaseProductName()
+ * @param dialectClass
+ * the dialect class to register
+ */
+ public static void registerDialect(String token, Class<? extends SQLDialect> dialectClass) {
+ DIALECTS.put(token, dialectClass);
+ }
+
+ SQLDialect getDialect(String databaseName, String className) {
+ Class<? extends SQLDialect> dialectClass = null;
+ if (DIALECTS.containsKey(className)) {
+ // dialect registered by connection class name
+ dialectClass = DIALECTS.get(className);
+ } else if (DIALECTS.containsKey(databaseName)) {
+ // dialect registered by database name
+ dialectClass = DIALECTS.get(databaseName);
+ } else {
+ // did not find a match, use default
+ dialectClass = DefaultSQLDialect.class;
}
return instance(dialectClass);
}
@@ -268,8 +282,8 @@ public class Db { // table is using iciql version tracking.
DbVersion v = new DbVersion();
String schema = StringUtils.isNullOrEmpty(model.schemaName) ? "" : model.schemaName;
- DbVersion dbVersion = from(v).where(v.schemaName).like(schema).and(v.tableName).like(model.tableName)
- .selectFirst();
+ DbVersion dbVersion = from(v).where(v.schemaName).like(schema).and(v.tableName)
+ .like(model.tableName).selectFirst();
if (dbVersion == null) {
// table has no version registration, but model specifies
// version: insert DbVersion entry
diff --git a/src/com/iciql/SQLDialect.java b/src/com/iciql/SQLDialect.java index 8291e53..3ca2c4c 100644 --- a/src/com/iciql/SQLDialect.java +++ b/src/com/iciql/SQLDialect.java @@ -17,7 +17,7 @@ package com.iciql; -import java.sql.Connection; +import java.sql.DatabaseMetaData; import com.iciql.TableDefinition.IndexDefinition; @@ -28,22 +28,23 @@ import com.iciql.TableDefinition.IndexDefinition; public interface SQLDialect { /** - * Configure the dialect from the database connection. + * Configure the dialect from the database metadata. * - * @param conn + * @param databaseName + * @param data */ - void configureDialect(Connection conn); + void configureDialect(String databaseName, DatabaseMetaData data); /** * Returns a properly formatted table name for the dialect. * - * @param schema + * @param schemaName * the schema name, or null for no schema - * @param table + * @param tableName * the properly formatted table name * @return the SQL snippet */ - String prepareTableName(String schema, String table); + String prepareTableName(String schemaName, String tableName); /** * Returns a properly formatted column name for the dialect. @@ -57,15 +58,27 @@ public interface SQLDialect { /** * Get the CREATE INDEX statement. * - * @param schema + * @param schemaName * the schema name - * @param table + * @param tableName * the table name * @param index * the index definition * @return the SQL statement */ - String prepareCreateIndex(String schema, String table, IndexDefinition index); + String prepareCreateIndex(String schemaName, String tableName, IndexDefinition index); + + /** + * Get a MERGE or REPLACE INTO statement. + * + * @param schemaName + * the schema name + * @param tableName + * the table name + * @param index + * the index definition + */ + <T> void prepareMerge(SQLStatement stat, String schemaName, String tableName, TableDefinition<T> def, Object obj); /** * Append "LIMIT limit" to the SQL statement. diff --git a/src/com/iciql/SQLStatement.java b/src/com/iciql/SQLStatement.java index 3a7c901..49c7627 100644 --- a/src/com/iciql/SQLStatement.java +++ b/src/com/iciql/SQLStatement.java @@ -38,7 +38,7 @@ public class SQLStatement { this.db = db;
}
- void setSQL(String sql) {
+ public void setSQL(String sql) {
this.sql = sql;
buff = new StringBuilder(sql);
}
@@ -64,7 +64,7 @@ public class SQLStatement { return sql;
}
- SQLStatement addParameter(Object o) {
+ public SQLStatement addParameter(Object o) {
params.add(o);
return this;
}
diff --git a/src/com/iciql/TableDefinition.java b/src/com/iciql/TableDefinition.java index eb018bc..5d934a5 100644 --- a/src/com/iciql/TableDefinition.java +++ b/src/com/iciql/TableDefinition.java @@ -67,12 +67,12 @@ public class TableDefinition<T> { * The meta data of a field.
*/
- static class FieldDefinition {
- String columnName;
+ public static class FieldDefinition {
+ public String columnName;
Field field;
String dataType;
int maxLength;
- boolean isPrimaryKey;
+ public boolean isPrimaryKey;
boolean isAutoIncrement;
boolean trimString;
boolean nullable;
@@ -121,12 +121,12 @@ public class TableDefinition<T> { }
}
+ public ArrayList<FieldDefinition> fields = Utils.newArrayList();
String schemaName;
String tableName;
int tableVersion;
private boolean createTableIfRequired = true;
private Class<T> clazz;
- private ArrayList<FieldDefinition> fields = Utils.newArrayList();
private IdentityHashMap<Object, FieldDefinition> fieldMap = Utils.newIdentityHashMap();
private List<String> primaryKeyColumnNames;
@@ -362,7 +362,7 @@ public class TableDefinition<T> { * Optionally truncates strings to the maximum length and converts
* java.lang.Enum types to Strings or Integers.
*/
- private Object getValue(Object obj, FieldDefinition field) {
+ public Object getValue(Object obj, FieldDefinition field) {
Object value = field.getValue(obj);
if (value == null) {
return value;
@@ -434,33 +434,7 @@ public class TableDefinition<T> { + " - no update possible");
}
SQLStatement stat = new SQLStatement(db);
- StatementBuilder buff = new StatementBuilder("MERGE INTO ");
- buff.append(db.getDialect().prepareTableName(schemaName, tableName)).append(" (");
- buff.resetCount();
- for (FieldDefinition field : fields) {
- buff.appendExceptFirst(", ");
- buff.append(db.getDialect().prepareColumnName(field.columnName));
- }
- buff.append(") KEY(");
- buff.resetCount();
- for (FieldDefinition field : fields) {
- if (field.isPrimaryKey) {
- buff.appendExceptFirst(", ");
- buff.append(db.getDialect().prepareColumnName(field.columnName));
- }
- }
- buff.append(") ");
- buff.resetCount();
- buff.append("VALUES (");
- for (FieldDefinition field : fields) {
- buff.appendExceptFirst(", ");
- buff.append('?');
- Object value = getValue(obj, field);
- stat.addParameter(value);
- }
- buff.append(')');
- stat.setSQL(buff.toString());
-
+ db.getDialect().prepareMerge(stat, schemaName, tableName, this, obj);
StatementLogger.merge(stat.getSQL());
stat.executeUpdate();
}
diff --git a/src/com/iciql/TableInspector.java b/src/com/iciql/TableInspector.java index 51b2d69..a5b6dee 100644 --- a/src/com/iciql/TableInspector.java +++ b/src/com/iciql/TableInspector.java @@ -226,16 +226,7 @@ public class TableInspector { ap.addParameter("name", table); if (primaryKeys.size() > 1) { - StatementBuilder pk = new StatementBuilder(); - pk.append("{ "); - for (String key : primaryKeys) { - pk.appendExceptFirst(", "); - pk.append("\""); - pk.append(key); - pk.append("\""); - } - pk.append(" }"); - ap.addParameter("primaryKey", pk.toString()); + ap.addParameter("primaryKey", primaryKeys); } // finish @IQTable annotation diff --git a/src/com/iciql/dialect/DefaultSQLDialect.java b/src/com/iciql/dialect/DefaultSQLDialect.java index 517ae10..f3f222e 100644 --- a/src/com/iciql/dialect/DefaultSQLDialect.java +++ b/src/com/iciql/dialect/DefaultSQLDialect.java @@ -1,12 +1,12 @@ package com.iciql.dialect;
-import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import com.iciql.IciqlException;
import com.iciql.SQLDialect;
import com.iciql.SQLStatement;
+import com.iciql.TableDefinition;
import com.iciql.TableDefinition.IndexDefinition;
import com.iciql.util.StringUtils;
@@ -16,25 +16,20 @@ import com.iciql.util.StringUtils; */
public class DefaultSQLDialect implements SQLDialect {
float databaseVersion;
- String productName;
+ String databaseName;
String productVersion;
@Override
public String toString() {
- return getClass().getName() + ": " + productName + " " + productVersion;
+ return getClass().getName() + ": " + databaseName + " " + productVersion;
}
@Override
- public void configureDialect(Connection conn) {
- loadIdentity(conn);
- }
-
- protected void loadIdentity(Connection conn) {
+ public void configureDialect(String databaseName, DatabaseMetaData data) {
+ this.databaseName = databaseName;
try {
- DatabaseMetaData data = conn.getMetaData();
databaseVersion = Float.parseFloat(data.getDatabaseMajorVersion() + "."
+ data.getDatabaseMinorVersion());
- productName = data.getDatabaseProductName();
productVersion = data.getDatabaseProductVersion();
} catch (SQLException e) {
throw new IciqlException(e);
@@ -57,11 +52,11 @@ public class DefaultSQLDialect implements SQLDialect { }
@Override
- public String prepareTableName(String schema, String table) {
- if (StringUtils.isNullOrEmpty(schema)) {
- return table;
+ public String prepareTableName(String schemaName, String tableName) {
+ if (StringUtils.isNullOrEmpty(schemaName)) {
+ return tableName;
}
- return schema + "." + table;
+ return schemaName + "." + tableName;
}
@Override
@@ -70,11 +65,16 @@ public class DefaultSQLDialect implements SQLDialect { }
@Override
- public String prepareCreateIndex(String schema, String table, IndexDefinition index) {
+ public String prepareCreateIndex(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) {
+ throw new IciqlException("Dialect does not support merge statements!");
+ }
+
+ @Override
public void appendLimit(SQLStatement stat, long limit) {
stat.appendSQL(" LIMIT " + limit);
}
diff --git a/src/com/iciql/dialect/H2Dialect.java b/src/com/iciql/dialect/H2Dialect.java index e0a5035..61babd7 100644 --- a/src/com/iciql/dialect/H2Dialect.java +++ b/src/com/iciql/dialect/H2Dialect.java @@ -1,5 +1,8 @@ package com.iciql.dialect;
+import com.iciql.SQLStatement;
+import com.iciql.TableDefinition;
+import com.iciql.TableDefinition.FieldDefinition;
import com.iciql.TableDefinition.IndexDefinition;
import com.iciql.util.StatementBuilder;
@@ -47,4 +50,34 @@ public class H2Dialect extends DefaultSQLDialect { buff.append(")");
return buff.toString();
}
+
+ @Override
+ public <T> void prepareMerge(SQLStatement stat, String schemaName, String tableName, TableDefinition<T> def, Object obj) {
+ StatementBuilder buff = new StatementBuilder("MERGE INTO ");
+ buff.append(prepareTableName(schemaName, tableName)).append(" (");
+ buff.resetCount();
+ for (FieldDefinition field : def.fields) {
+ buff.appendExceptFirst(", ");
+ buff.append(field.columnName);
+ }
+ buff.append(") KEY(");
+ buff.resetCount();
+ for (FieldDefinition field : def.fields) {
+ if (field.isPrimaryKey) {
+ buff.appendExceptFirst(", ");
+ buff.append(field.columnName);
+ }
+ }
+ buff.append(") ");
+ buff.resetCount();
+ buff.append("VALUES (");
+ for (FieldDefinition field : def.fields) {
+ buff.appendExceptFirst(", ");
+ buff.append('?');
+ Object value = def.getValue(obj, field);
+ stat.addParameter(value);
+ }
+ buff.append(')');
+ stat.setSQL(buff.toString());
+ }
}
\ No newline at end of file diff --git a/src/com/iciql/dialect/MySQLDialect.java b/src/com/iciql/dialect/MySQLDialect.java new file mode 100644 index 0000000..e1ccaf3 --- /dev/null +++ b/src/com/iciql/dialect/MySQLDialect.java @@ -0,0 +1,85 @@ +package com.iciql.dialect;
+
+import com.iciql.SQLStatement;
+import com.iciql.TableDefinition;
+import com.iciql.TableDefinition.FieldDefinition;
+import com.iciql.TableDefinition.IndexDefinition;
+import com.iciql.util.StatementBuilder;
+
+/**
+ * H2 database dialect.
+ */
+public class MySQLDialect extends DefaultSQLDialect {
+
+ @Override
+ public boolean supportsMemoryTables() {
+ return false;
+ }
+
+ @Override
+ public boolean supportsMerge() {
+ return true;
+ }
+
+ @Override
+ public String prepareColumnName(String name) {
+ return "`" + name + "`";
+ }
+
+ @Override
+ public String prepareCreateIndex(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(prepareColumnName(col));
+ }
+ buff.append(") ");
+
+ // USING
+ switch (index.type) {
+ case HASH:
+ buff.append("USING HASH");
+ break;
+ case UNIQUE_HASH:
+ 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());
+ }
+}
\ No newline at end of file |