diff options
author | James Moger <james.moger@gmail.com> | 2012-01-11 09:20:51 -0500 |
---|---|---|
committer | James Moger <james.moger@gmail.com> | 2012-01-11 09:20:51 -0500 |
commit | 2e077918649d398dce0948cb3feeb61b925ee8a4 (patch) | |
tree | 2488329364248fb08e346314ba53399d9230bf64 /src | |
parent | 28d2cf5b30ba18f20db54ed9447bc19cb0e4e1b0 (diff) | |
download | iciql-2e077918649d398dce0948cb3feeb61b925ee8a4.tar.gz iciql-2e077918649d398dce0948cb3feeb61b925ee8a4.zip |
Generate SELECT T0.* type statementsv0.7.8
* Fixed negative rollover bug in the AS counter.
* Replaced the non-threadsafe AS counter with an AtomicInteger.
* Added an optional alias parameter to Query.toSQL() and
QueryWhere.toSQL() to force SELECT T0.* select lists
* Fixed bug with Query.select(Z z) which assumed that z is always an
anonymous inner class.
Diffstat (limited to 'src')
-rw-r--r-- | src/com/iciql/Constants.java | 6 | ||||
-rw-r--r-- | src/com/iciql/Query.java | 72 | ||||
-rw-r--r-- | src/com/iciql/QueryWhere.java | 32 | ||||
-rw-r--r-- | src/com/iciql/SelectTable.java | 3 | ||||
-rw-r--r-- | src/com/iciql/TableDefinition.java | 30 | ||||
-rw-r--r-- | src/com/iciql/util/Utils.java | 13 |
6 files changed, 130 insertions, 26 deletions
diff --git a/src/com/iciql/Constants.java b/src/com/iciql/Constants.java index 85a6738..5fd1dec 100644 --- a/src/com/iciql/Constants.java +++ b/src/com/iciql/Constants.java @@ -25,14 +25,14 @@ public class Constants { // The build script extracts this exact line so be careful editing it
// and only use A-Z a-z 0-9 .-_ in the string.
- public static final String VERSION = "0.7.7";
+ public static final String VERSION = "0.7.8";
// The build script extracts this exact line so be careful editing it
// and only use A-Z a-z 0-9 .-_ in the string.
- public static final String VERSION_DATE = "2012-01-05";
+ public static final String VERSION_DATE = "2012-01-11";
// The build script extracts this exact line so be careful editing it
// and only use A-Z a-z 0-9 .-_ in the string.
- public static final String API_CURRENT = "11";
+ public static final String API_CURRENT = "12";
}
diff --git a/src/com/iciql/Query.java b/src/com/iciql/Query.java index e656c0d..fb193a0 100644 --- a/src/com/iciql/Query.java +++ b/src/com/iciql/Query.java @@ -126,7 +126,7 @@ public class Query<T> { public String toSQL() {
return toSQL(false);
}
-
+
/**
* toSQL returns a static string version of the query with runtime variables
* properly encoded. This method is also useful when combined with the where
@@ -136,10 +136,55 @@ public class Query<T> { * @param distinct
* if true SELECT DISTINCT is used for the query
* @return the sql query as plain text
- */
+ */
public String toSQL(boolean distinct) {
- SQLStatement stat = getSelectStatement(distinct);
- stat.appendSQL("*");
+ return toSQL(distinct, null);
+ }
+
+ /**
+ * toSQL returns a static string version of the query with runtime variables
+ * properly encoded. This method is also useful when combined with the where
+ * clause methods like isParameter() or atLeastParameter() which allows
+ * iciql to generate re-usable parameterized string statements.
+ *
+ * @param distinct
+ * if true SELECT DISTINCT is used for the query
+ * @param k
+ * k is used to select only the columns of the specified alias
+ * for an inner join statement. An example of a generated
+ * statement is: SELECT DISTINCT t1.* FROM sometable AS t1 INNER
+ * JOIN othertable AS t2 ON t1.id = t2.id WHERE t2.flag = true
+ * without the alias parameter the statement would start with
+ * SELECT DISTINCT * FROM...
+ * @return the sql query as plain text
+ */
+ public <K> String toSQL(boolean distinct, K k) {
+ SQLStatement stat = new SQLStatement(getDb());
+ stat.appendSQL("SELECT ");
+ if (distinct) {
+ stat.appendSQL("DISTINCT ");
+ }
+ if (k != null) {
+ SelectTable<?> sel = getSelectTable(k);
+ if (sel == null) {
+ // unknown alias, use wildcard
+ IciqlLogger.warn("Alias {0} is not defined in the statement!", k.getClass());
+ stat.appendSQL("*");
+ } else if (isJoin()) {
+ // join query, use AS alias
+ String as = sel.getAs();
+ stat.appendSQL(as + ".*");
+ } else {
+ // schema.table.*
+ String schema = sel.getAliasDefinition().schemaName;
+ String table = sel.getAliasDefinition().tableName;
+ String as = getDb().getDialect().prepareTableName(schema, table);
+ stat.appendSQL(as + ".*");
+ }
+ } else {
+ // alias unspecified, use wildcard
+ stat.appendSQL("*");
+ }
appendFromWhere(stat);
return stat.toSQL().trim();
}
@@ -289,7 +334,11 @@ public class Query<T> { if (Utils.isSimpleType(clazz)) {
return selectSimple((X) x, distinct);
}
- clazz = clazz.getSuperclass();
+ Class<?> enclosingClass = clazz.getEnclosingClass();
+ if (enclosingClass != null) {
+ // anonymous inner class
+ clazz = clazz.getSuperclass();
+ }
return select((Class<X>) clazz, (X) x, distinct);
}
@@ -794,6 +843,19 @@ public class Query<T> { return !joins.isEmpty();
}
+ SelectTable<?> getSelectTable(Object alias) {
+ if (from.getAlias() == alias) {
+ return from;
+ } else {
+ for (SelectTable<?> join : joins) {
+ if (join.getAlias() == alias) {
+ return join;
+ }
+ }
+ }
+ return null;
+ }
+
/**
* This method returns a mapped Object field by its reference.
*
diff --git a/src/com/iciql/QueryWhere.java b/src/com/iciql/QueryWhere.java index 7503ea1..31228c9 100644 --- a/src/com/iciql/QueryWhere.java +++ b/src/com/iciql/QueryWhere.java @@ -252,7 +252,7 @@ public class QueryWhere<T> { * @return the sql query as plain text
*/
public String toSQL() {
- return this.toSQL(false);
+ return query.toSQL(false);
}
/**
@@ -266,14 +266,28 @@ public class QueryWhere<T> { * @return the sql query as plain text
*/
public String toSQL(boolean distinct) {
- SQLStatement stat = new SQLStatement(query.getDb());
- if (distinct) {
- stat.appendSQL("SELECT DISTINCT *");
- } else {
- stat.appendSQL("SELECT *");
- }
- query.appendFromWhere(stat);
- return stat.toSQL().trim();
+ return query.toSQL(distinct);
+ }
+
+ /**
+ * toSQL returns a static string version of the query with runtime variables
+ * properly encoded. This method is also useful when combined with the where
+ * clause methods like isParameter() or atLeastParameter() which allows
+ * iciql to generate re-usable parameterized string statements.
+ *
+ * @param distinct
+ * if true SELECT DISTINCT is used for the query
+ * @param k
+ * k is used to select only the columns of the specified alias
+ * for an inner join statement. An example of a generated
+ * statement is: SELECT DISTINCT t1.* FROM sometable AS t1 INNER
+ * JOIN othertable AS t2 ON t1.id = t2.id WHERE t2.flag = true
+ * without the alias parameter the statement would start with
+ * SELECT DISTINCT * FROM...
+ * @return the sql query as plain text
+ */
+ public <K> String toSQL(boolean distinct, K k) {
+ return query.toSQL(distinct, k);
}
public <X, Z> List<X> select(Z x) {
diff --git a/src/com/iciql/SelectTable.java b/src/com/iciql/SelectTable.java index 7c5017c..37b42c4 100644 --- a/src/com/iciql/SelectTable.java +++ b/src/com/iciql/SelectTable.java @@ -30,7 +30,6 @@ import com.iciql.util.Utils; class SelectTable<T> {
- private static int asCounter;
private Query<T> query;
private Class<T> clazz;
private T current;
@@ -47,7 +46,7 @@ class SelectTable<T> { this.outerJoin = outerJoin;
aliasDef = (TableDefinition<T>) db.getTableDefinition(alias.getClass());
clazz = Utils.getClass(alias);
- as = "T" + asCounter++;
+ as = "T" + Utils.nextAsCount();
}
T getAlias() {
diff --git a/src/com/iciql/TableDefinition.java b/src/com/iciql/TableDefinition.java index b85b941..1d9a98a 100644 --- a/src/com/iciql/TableDefinition.java +++ b/src/com/iciql/TableDefinition.java @@ -418,16 +418,16 @@ public class TableDefinition<T> { "Can not explicitly reference a primitive boolean if there are multiple boolean fields in your model class!");
}
}
-
+
void checkMultipleEnums(Object o) {
- if (o == null) {
- return;
- }
+ if (o == null) {
+ return;
+ }
Class<?> clazz = o.getClass();
if (!clazz.isEnum()) {
return;
}
-
+
int fieldCount = 0;
for (FieldDefinition fieldDef : fields) {
Class<?> targetType = fieldDef.field.getType();
@@ -435,10 +435,11 @@ public class TableDefinition<T> { fieldCount++;
}
}
-
+
if (fieldCount > 1) {
throw new IciqlException(
- "Can not explicitly reference {0} because there are {1} {0} fields in your model class!", clazz.getSimpleName(), fieldCount);
+ "Can not explicitly reference {0} because there are {1} {0} fields in your model class!",
+ clazz.getSimpleName(), fieldCount);
}
}
@@ -820,10 +821,25 @@ public class TableDefinition<T> { }
<Y, X> void appendSelectList(SQLStatement stat, Query<Y> query, X x) {
+ // select t0.col1, t0.col2, t0.col3...
+ // select table1.col1, table1.col2, table1.col3...
+ String selectDot = "";
+ SelectTable<?> sel = query.getSelectTable(x);
+ if (sel != null) {
+ if (query.isJoin()) {
+ selectDot = sel.getAs() + ".";
+ } else {
+ String sn = sel.getAliasDefinition().schemaName;
+ String tn = sel.getAliasDefinition().tableName;
+ selectDot = query.getDb().getDialect().prepareTableName(sn, tn) + ".";
+ }
+ }
+
for (int i = 0; i < fields.size(); i++) {
if (i > 0) {
stat.appendSQL(", ");
}
+ stat.appendSQL(selectDot);
FieldDefinition def = fields.get(i);
if (def.isPrimitive) {
Object obj = def.getValue(x);
diff --git a/src/com/iciql/util/Utils.java b/src/com/iciql/util/Utils.java index 44792c7..77110b8 100644 --- a/src/com/iciql/util/Utils.java +++ b/src/com/iciql/util/Utils.java @@ -35,6 +35,7 @@ import java.util.HashSet; import java.util.IdentityHashMap;
import java.util.Map;
import java.util.UUID;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import com.iciql.Iciql.EnumId;
@@ -47,10 +48,22 @@ import com.iciql.IciqlException; public class Utils {
public static final AtomicLong COUNTER = new AtomicLong(0);
+
+ public static final AtomicInteger AS_COUNTER = new AtomicInteger(0);
private static final boolean MAKE_ACCESSIBLE = true;
private static final int BUFFER_BLOCK_SIZE = 4 * 1024;
+
+ public static synchronized int nextAsCount() {
+ // prevent negative values and use a threadsafe counter
+ int count = AS_COUNTER.incrementAndGet();
+ if (count == Integer.MAX_VALUE) {
+ count = 0;
+ AS_COUNTER.set(count);
+ }
+ return count;
+ }
@SuppressWarnings("unchecked")
public static <X> Class<X> getClass(X x) {
|