From 163cc2a22c9662fe79dd8eeacc0fd9fb197a6565 Mon Sep 17 00:00:00 2001
From: "A. Abram White"
Date: Wed, 30 Aug 2006 03:43:16 +0000
Subject: [PATCH] Framework for allowing ranges in query strings to be
specified as parameters (not needed for JPQL, but for others). Also
consolidated some internal query framework APIs.
git-svn-id: https://svn.apache.org/repos/asf/incubator/openjpa/trunk@438338 13f79535-47bb-0310-9956-ffa450edef68
---
.../openjpa/jdbc/kernel/JDBCStoreQuery.java | 53 ++--
.../openjpa/jdbc/kernel/SQLStoreQuery.java | 12 +-
.../apache/openjpa/jdbc/kernel/exps/SubQ.java | 8 +-
.../openjpa/jdbc/kernel/localizer.properties | 11 +-
.../openjpa/ant/ApplicationIdToolTask.java | 94 +++++++
.../datacache/QueryCacheStoreQuery.java | 43 +--
.../openjpa/kernel/AbstractStoreQuery.java | 22 +-
.../openjpa/kernel/DelegatingQuery.java | 8 -
.../openjpa/kernel/ExpressionStoreQuery.java | 84 +++---
.../openjpa/kernel/MethodStoreQuery.java | 15 +-
.../apache/openjpa/kernel/QueryContext.java | 5 -
.../org/apache/openjpa/kernel/QueryImpl.java | 264 ++++--------------
.../openjpa/kernel/SingleFieldManager.java | 9 +-
.../org/apache/openjpa/kernel/StoreQuery.java | 50 ++--
.../apache/openjpa/kernel/exps/Constant.java | 5 +-
.../apache/openjpa/kernel/exps/Literal.java | 2 +-
.../apache/openjpa/kernel/exps/Parameter.java | 2 +-
.../openjpa/kernel/exps/QueryExpressions.java | 18 +-
.../org/apache/openjpa/kernel/exps/SubQ.java | 3 +-
.../apache/openjpa/kernel/exps/Subquery.java | 3 +-
.../kernel/jpql/JPQLExpressionBuilder.java | 16 +-
.../src/main/java/sun/misc/Perf.java | 28 ++
.../openjpa/kernel/exps/localizer.properties | 2 -
.../openjpa/kernel/localizer.properties | 18 +-
.../openjpa/lib/util/concurrent/CondVar.java | 2 +-
.../persistence/jdbc/localizer.properties | 4 +-
26 files changed, 348 insertions(+), 433 deletions(-)
create mode 100755 openjpa-kernel/src/main/java/org/apache/openjpa/ant/ApplicationIdToolTask.java
create mode 100644 openjpa-kernel/src/main/java/sun/misc/Perf.java
diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreQuery.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreQuery.java
index 2cfcbdafe..31ec30b58 100644
--- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreQuery.java
+++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/JDBCStoreQuery.java
@@ -130,10 +130,10 @@ public class JDBCStoreQuery
protected ResultObjectProvider executeQuery(Executor ex,
ClassMetaData base, ClassMetaData[] metas, boolean subclasses,
ExpressionFactory[] facts, QueryExpressions[] exps, Object[] params,
- boolean lrs, long startIdx, long endIdx) {
+ Range range) {
if (metas.length > 1 && exps[0].isAggregate())
- throw new UserException(Localizer.forPackage(JDBCStoreQuery.class)
- .get("mult-mapping-aggregate", Arrays.asList(metas)));
+ throw new UserException(Localizer.forPackage(JDBCStoreQuery.class).
+ get("mult-mapping-aggregate", Arrays.asList(metas)));
ClassMapping[] mappings = (ClassMapping[]) metas;
JDBCFetchConfiguration fetch = (JDBCFetchConfiguration)
@@ -143,12 +143,12 @@ public class JDBCStoreQuery
fetch.addJoins(Arrays.asList(exps[0].fetchPaths));
}
- int eager = calculateEagerMode(exps[0], startIdx, endIdx);
+ int eager = calculateEagerMode(exps[0], range.start, range.end);
int subclassMode = fetch.getSubclassFetchMode((ClassMapping) base);
DBDictionary dict = _store.getDBDictionary();
long start = (mappings.length == 1 && dict.supportsSelectStartIndex)
- ? startIdx : 0L;
- long end = (dict.supportsSelectEndIndex) ? endIdx : Long.MAX_VALUE;
+ ? range.start : 0L;
+ long end = (dict.supportsSelectEndIndex) ? range.end : Long.MAX_VALUE;
// add selects with populate WHERE conditions to list
List sels = new ArrayList(mappings.length);
@@ -165,8 +165,8 @@ public class JDBCStoreQuery
// we might want to use lrs settings if we can't use the range
if (sels.size() > 1)
start = 0L;
- lrs = lrs || (fetch.getFetchBatchSize() >= 0 && (start != startIdx
- || end != endIdx));
+ boolean lrs = range.lrs || (fetch.getFetchBatchSize() >= 0
+ && (start != range.start || end != range.end));
ResultObjectProvider[] rops = null;
ResultObjectProvider rop = null;
@@ -209,9 +209,9 @@ public class JDBCStoreQuery
}
// need to fake result range?
- if ((rops != null && endIdx != Long.MAX_VALUE) || start != startIdx
- || end != endIdx)
- rop = new RangeResultObjectProvider(rop, startIdx, endIdx);
+ if ((rops != null && range.end != Long.MAX_VALUE)
+ || start != range.start || end != range.end)
+ rop = new RangeResultObjectProvider(rop, range.start, range.end);
return rop;
}
@@ -226,7 +226,6 @@ public class JDBCStoreQuery
final BitSet[] paged = (exps[0].projections.length > 0) ? null
: new BitSet[mappings.length];
union.select(new Union.Selector() {
-
public void select(Select sel, int idx) {
BitSet bits = populateSelect(sel, mappings[idx], subclasses,
(JDBCExpressionFactory) facts[idx], exps[idx], params,
@@ -392,11 +391,11 @@ public class JDBCStoreQuery
* or the query is unique, use an eager setting of single. Otherwise use
* an eager mode of multiple.
*/
- private int calculateEagerMode(QueryExpressions exps, long startIdx,
- long endIdx) {
- if (exps.projections.length > 0 || startIdx >= endIdx)
+ private int calculateEagerMode(QueryExpressions exps, long start,
+ long end) {
+ if (exps.projections.length > 0 || start >= end)
return EagerFetchModes.EAGER_NONE;
- if (endIdx - startIdx == 1 || ctx.isUnique())
+ if (end - start == 1 || ctx.isUnique())
return EagerFetchModes.EAGER_JOIN;
return EagerFetchModes.EAGER_PARALLEL;
}
@@ -479,19 +478,13 @@ public class JDBCStoreQuery
count += stmnt.executeUpdate();
} finally {
if (stmnt != null)
- try {
- stmnt.close();
- } catch (SQLException se) {
- }
+ try { stmnt.close(); } catch (SQLException se) {}
}
}
} catch (SQLException se) {
throw SQLExceptions.getStore(se, ctx, _store.getDBDictionary());
} finally {
- try {
- conn.close();
- } catch (SQLException se) {
- }
+ try { conn.close(); } catch (SQLException se) {}
}
return Numbers.valueOf(count);
}
@@ -572,22 +565,22 @@ public class JDBCStoreQuery
protected String[] getDataStoreActions(ClassMetaData base,
ClassMetaData[] metas, boolean subclasses, ExpressionFactory[] facts,
- QueryExpressions[] exps, Object[] params, long startIdx, long endIdx) {
+ QueryExpressions[] exps, Object[] params, Range range) {
ClassMapping[] mappings = (ClassMapping[]) metas;
- JDBCFetchConfiguration fetch = (JDBCFetchConfiguration) ctx
- .getFetchConfiguration();
+ JDBCFetchConfiguration fetch = (JDBCFetchConfiguration) ctx.
+ getFetchConfiguration();
if (exps[0].fetchPaths != null) {
fetch.addFields(Arrays.asList(exps[0].fetchPaths));
fetch.addJoins(Arrays.asList(exps[0].fetchPaths));
}
- int eager = calculateEagerMode(exps[0], startIdx, endIdx);
+ int eager = calculateEagerMode(exps[0], range.start, range.end);
eager = Math.min(eager, JDBCFetchConfiguration.EAGER_JOIN);
int subclassMode = fetch.getSubclassFetchMode((ClassMapping) base);
DBDictionary dict = _store.getDBDictionary();
long start = (mappings.length == 1 && dict.supportsSelectStartIndex)
- ? startIdx : 0L;
- long end = (dict.supportsSelectEndIndex) ? endIdx : Long.MAX_VALUE;
+ ? range.start : 0L;
+ long end = (dict.supportsSelectEndIndex) ? range.end : Long.MAX_VALUE;
// add selects with populate WHERE conditions to list
List sels = new ArrayList(mappings.length);
diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/SQLStoreQuery.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/SQLStoreQuery.java
index eaa628eb4..241b1accd 100644
--- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/SQLStoreQuery.java
+++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/SQLStoreQuery.java
@@ -184,7 +184,7 @@ public class SQLStoreQuery
}
public ResultObjectProvider executeQuery(StoreQuery q,
- Object[] params, boolean lrs, long startIdx, long endIdx) {
+ Object[] params, Range range) {
JDBCStore store = ((SQLStoreQuery) q).getStore();
DBDictionary dict = store.getDBDictionary();
String sql = q.getContext().getQueryString();
@@ -209,11 +209,11 @@ public class SQLStoreQuery
PreparedStatement stmnt = null;
try {
// use the right method depending on sel vs. proc, lrs setting
- if (_select && !lrs)
+ if (_select && !range.lrs)
stmnt = buf.prepareStatement(conn);
else if (_select)
stmnt = buf.prepareStatement(conn, fetch, -1, -1);
- else if (!lrs)
+ else if (!range.lrs)
stmnt = buf.prepareCall(conn);
else
stmnt = buf.prepareCall(conn, fetch, -1, -1);
@@ -240,13 +240,13 @@ public class SQLStoreQuery
throw SQLExceptions.getStore(se, dict);
}
- if (startIdx != 0 || endIdx != Long.MAX_VALUE)
- rop = new RangeResultObjectProvider(rop, startIdx, endIdx);
+ if (range.start != 0 || range.end != Long.MAX_VALUE)
+ rop = new RangeResultObjectProvider(rop, range.start,range.end);
return rop;
}
public String[] getDataStoreActions(StoreQuery q, Object[] params,
- long startIdx, long endIdx) {
+ Range range) {
return new String[]{ q.getContext().getQueryString() };
}
diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/SubQ.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/SubQ.java
index 90e3271e3..f2c99a6cc 100644
--- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/SubQ.java
+++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/SubQ.java
@@ -48,8 +48,6 @@ class SubQ
private Class _type = null;
private ClassMetaData _meta = null;
private QueryExpressions _exps = null;
- private long _startIdx = 0;
- private long _endIdx = Long.MAX_VALUE;
/**
* Constructor. Supply candidate, whether subclasses are included in
@@ -100,11 +98,8 @@ class SubQ
return _alias;
}
- public void setQueryExpressions(QueryExpressions query, long startIdx,
- long endIdx) {
+ public void setQueryExpressions(QueryExpressions query) {
_exps = query;
- _startIdx = startIdx;
- _endIdx = endIdx;
}
public void initialize(Select sel, JDBCStore store, boolean nullTest) {
@@ -180,7 +175,6 @@ class SubQ
_cons.CACHE_NULL, fetch);
_cons.select(store, _candidate, _subs, sel, _exps, params,
fetch, fetch.EAGER_NONE);
- sel.setRange(_startIdx, _endIdx);
if (size)
sql.appendCount(sel, fetch);
diff --git a/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/kernel/localizer.properties b/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/kernel/localizer.properties
index 3879cc8a8..2c23d1e12 100644
--- a/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/kernel/localizer.properties
+++ b/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/kernel/localizer.properties
@@ -22,7 +22,8 @@ update-failed-no-failed-obj: Database operation failed. Update count for SQL \
virtual-mapping: Cannot instantiate virtual mapping "{0}".
press-key-end: Server running. Press enter to stop.
no-server-conf: There is no persistence server configured.
-server-usage: Usage: java org.apache.openjpa.jdbc.kernel.StartPersistenceServer\n\
+server-usage: Usage: \
+ java org.apache.openjpa.jdbc.kernel.StartPersistenceServer\n\
\t[-properties/-p ]\n\
\t[- ]*
cant-lock-on-load: The database is unable to lock this query. Each object \
@@ -42,7 +43,7 @@ batch-not-supported: The update count for the statement was an invalid \
value ({0}). This indicates that your database or JDBC driver does not \
have complete support for executing batch statements. Batch \
functionality should be disabled by including "BatchLimit=0" in \
- your org.apache.openjpa.jdbc.DBDictionary configuration property. Statement: {1}
+ your openjpa.jdbc.DBDictionary configuration property. Statement: {1}
bad-synch-mappings: Invalid SynchronizeMappings operation ("{0}") specified. \
Valid operations are: {1}
make-native-seq: Creating sequence.
@@ -59,7 +60,8 @@ bad-seq-type: This sequence of type "{0}" cannot generate values for \
no-seq-sql: Error instantiating named sequence "{0}": Your database dictionary \
does not support native sequences. To tell the dictionary how to select \
sequence values, use:\n\
- org.apache.openjpa.jdbc.DBDictionary: NextSequenceQuery="SELECT NEXT VALUE FOR \{0\}"\n\
+ openjpa.jdbc.DBDictionary: NextSequenceQuery="SELECT NEXT VALUE \
+ FOR \{0\}"\n\
Where the above string is replaced with the proper SQL for your database.
invalid-seq-sql: No rows returned for sql "{0}". Check your configuration.
insert-seq: Inserting row for this mapping into sequence table.
@@ -72,7 +74,8 @@ seq-usage: Usage: java org.apache.openjpa.jdbc.kernel.TableJDBCSeq\n\
\t[-properties/-p ]\n\
\t[- ]*\n\
\t-action/-a [value]
-clstable-seq-usage: Usage: java org.apache.openjpa.jdbc.kernel.ClassTableJDBCSeq\n\
+clstable-seq-usage: Usage: \
+ java org.apache.openjpa.jdbc.kernel.ClassTableJDBCSeq\n\
\t[-properties/-p ]\n\
\t[- ]*\n\
\t-action/-a \n\
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/ant/ApplicationIdToolTask.java b/openjpa-kernel/src/main/java/org/apache/openjpa/ant/ApplicationIdToolTask.java
new file mode 100755
index 000000000..6290ba900
--- /dev/null
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/ant/ApplicationIdToolTask.java
@@ -0,0 +1,94 @@
+package org.apache.openjpa.ant;
+
+import java.io.IOException;
+
+import org.apache.openjpa.conf.OpenJPAConfiguration;
+import org.apache.openjpa.conf.OpenJPAConfigurationImpl;
+import org.apache.openjpa.enhance.ApplicationIdTool;
+import org.apache.openjpa.lib.ant.AbstractTask;
+import org.apache.openjpa.lib.conf.ConfigurationImpl;
+import org.apache.openjpa.lib.util.CodeFormat;
+import org.apache.openjpa.lib.util.Files;
+
+/**
+ * Executes the application id tool on the specified files. This task
+ * can take the following arguments:
+ *
+ * directory
+ * ignoreErrors
+ * name
+ * suffix
+ * token
+ *
+ * It can also take an embedded codeFormat
element with attributes
+ * for the bean properties of the {@link CodeFormat}.
+ */
+public class ApplicationIdToolTask
+ extends AbstractTask {
+
+ protected ApplicationIdTool.Flags flags = new ApplicationIdTool.Flags();
+ protected String dirName = null;
+
+ /**
+ * Default constructor.
+ */
+ public ApplicationIdToolTask() {
+ flags.format = new CodeFormat();
+ }
+
+ /**
+ * Set the output directory we want the enhancer to write to.
+ */
+ public void setDirectory(String dirName) {
+ this.dirName = dirName;
+ }
+
+ /**
+ * Set whether to ignore errors.
+ */
+ public void setIgnoreErrors(boolean ignoreErrors) {
+ flags.ignoreErrors = ignoreErrors;
+ }
+
+ /**
+ * Set the name of the identity class; with this option you must supply
+ * exactly one class to run on.
+ */
+ public void setName(String name) {
+ flags.name = name;
+ }
+
+ /**
+ * Set a suffix to append to persistent classes to form their identity
+ * class name.
+ */
+ public void setSuffix(String suffix) {
+ flags.suffix = suffix;
+ }
+
+ /**
+ * Set the token to separate stringified primary key field values.
+ */
+ public void setToken(String token) {
+ flags.token = token;
+ }
+
+ /**
+ * Create the embedded code format element.
+ */
+ public Object createCodeFormat() {
+ return flags.format;
+ }
+
+ protected ConfigurationImpl newConfiguration() {
+ return new OpenJPAConfigurationImpl();
+ }
+
+ protected void executeOn(String[] files)
+ throws IOException, ClassNotFoundException {
+ flags.directory = (dirName == null) ? null
+ : Files.getFile(dirName, getClassLoader());
+ ApplicationIdTool.run((OpenJPAConfiguration) getConfiguration(), files,
+ flags, getClassLoader ());
+ }
+}
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/QueryCacheStoreQuery.java b/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/QueryCacheStoreQuery.java
index e2c371f31..ebe7c7259 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/QueryCacheStoreQuery.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/datacache/QueryCacheStoreQuery.java
@@ -293,30 +293,17 @@ public class QueryCacheStoreQuery
}
public ResultObjectProvider executeQuery(StoreQuery q, Object[] params,
- boolean lrs, long startIdx, long endIdx) {
+ Range range) {
QueryCacheStoreQuery cq = (QueryCacheStoreQuery) q;
QueryKey key = QueryKey.newInstance(cq.getContext(),
- _ex.isPacking(q), params, _candidate, _subs, startIdx, endIdx);
+ _ex.isPacking(q), params, _candidate, _subs, range.start,
+ range.end);
List cached = cq.checkCache(key);
if (cached != null)
return new ListResultObjectProvider(cached);
ResultObjectProvider rop = _ex.executeQuery(cq.getDelegate(),
- params, lrs, startIdx, endIdx);
- return cq.wrapResult(rop, key);
- }
-
- public ResultObjectProvider executeQuery(StoreQuery q, Map params,
- boolean lrs, long startIdx, long endIdx) {
- QueryCacheStoreQuery cq = (QueryCacheStoreQuery) q;
- QueryKey key = QueryKey.newInstance(cq.getContext(),
- _ex.isPacking(q), params, _candidate, _subs, startIdx, endIdx);
- List cached = cq.checkCache(key);
- if (cached != null)
- return new ListResultObjectProvider(cached);
-
- ResultObjectProvider rop = _ex.executeQuery(cq.getDelegate(),
- params, lrs, startIdx, endIdx);
+ params, range);
return cq.wrapResult(rop, key);
}
@@ -351,14 +338,6 @@ public class QueryCacheStoreQuery
}
}
- public Number executeDelete(StoreQuery q, Map params) {
- try {
- return _ex.executeDelete(unwrap(q), params);
- } finally {
- clearAccesssPath(q);
- }
- }
-
public Number executeUpdate(StoreQuery q, Object[] params) {
try {
return _ex.executeUpdate(unwrap(q), params);
@@ -367,22 +346,18 @@ public class QueryCacheStoreQuery
}
}
- public Number executeUpdate(StoreQuery q, Map params) {
- try {
- return _ex.executeUpdate(unwrap(q), params);
- } finally {
- clearAccesssPath(q);
- }
- }
-
public String[] getDataStoreActions(StoreQuery q, Object[] params,
- long startIdx, long endIdx) {
+ Range range) {
return EMPTY_STRINGS;
}
public void validate(StoreQuery q) {
_ex.validate(unwrap(q));
}
+
+ public void getRange(StoreQuery q, Object[] params, Range range) {
+ _ex.getRange(q, params, range);
+ }
public Object getOrderingValue(StoreQuery q, Object[] params,
Object resultObject, int orderIndex) {
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractStoreQuery.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractStoreQuery.java
index 8d0a1f523..4b6c43059 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractStoreQuery.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/AbstractStoreQuery.java
@@ -107,39 +107,25 @@ public abstract class AbstractStoreQuery
public static abstract class AbstractExecutor
implements Executor {
- public ResultObjectProvider executeQuery(StoreQuery q, Map params,
- boolean lrs, long startIdx, long endIdx) {
- Object[] arr = q.getContext().toParameterArray
- (q.getContext().getParameterTypes(), params);
- return executeQuery(q, arr, lrs, startIdx, endIdx);
- }
-
public Number executeDelete(StoreQuery q, Object[] params) {
return q.getContext().deleteInMemory(this, params);
}
- public Number executeDelete(StoreQuery q, Map params) {
- return executeDelete(q, q.getContext().toParameterArray
- (q.getContext().getParameterTypes(), params));
- }
-
public Number executeUpdate(StoreQuery q, Object[] params) {
return q.getContext().updateInMemory(this, params);
}
- public Number executeUpdate(StoreQuery q, Map params) {
- return executeUpdate(q, q.getContext().toParameterArray
- (q.getContext().getParameterTypes(), params));
- }
-
public String[] getDataStoreActions(StoreQuery q, Object[] params,
- long startIdx, long endIdx) {
+ Range range) {
return EMPTY_STRINGS;
}
public void validate(StoreQuery q) {
}
+ public void getRange(StoreQuery q, Object[] params, Range range) {
+ }
+
public Object getOrderingValue(StoreQuery q, Object[] params,
Object resultObject, int orderIndex) {
return null;
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingQuery.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingQuery.java
index 6d3256435..529d277ad 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingQuery.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/DelegatingQuery.java
@@ -403,14 +403,6 @@ public class DelegatingQuery
}
}
- public Object[] toParameterArray(LinkedMap paramTypes, Map params) {
- try {
- return _query.toParameterArray(paramTypes, params);
- } catch (RuntimeException re) {
- throw translate(re);
- }
- }
-
public Number deleteInMemory(StoreQuery.Executor ex, Object[] params) {
try {
return _query.deleteInMemory(ex, params);
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ExpressionStoreQuery.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ExpressionStoreQuery.java
index 038f93dcf..e4595fc66 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ExpressionStoreQuery.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/ExpressionStoreQuery.java
@@ -27,6 +27,7 @@ import org.apache.commons.collections.map.LinkedMap;
import org.apache.openjpa.conf.OpenJPAConfiguration;
import org.apache.openjpa.kernel.exps.AbstractExpressionVisitor;
import org.apache.openjpa.kernel.exps.AggregateListener;
+import org.apache.openjpa.kernel.exps.Constant;
import org.apache.openjpa.kernel.exps.ExpressionFactory;
import org.apache.openjpa.kernel.exps.ExpressionParser;
import org.apache.openjpa.kernel.exps.FilterListener;
@@ -177,18 +178,13 @@ public class ExpressionStoreQuery
* each base type
* @param parsed the parsed query values
* @param params parameter values, or empty array
- * @param lrs whether the result will be handled as a potentially
- * large result set, or will be consumed greedily
- * @param startIdx 0-based inclusive index for first result to return
- * from result object provider
- * @param endIdx 0-based exclusive index for last result to return
- * from result object provider, or {@link Long#MAX_VALUE} for no max
+ * @param range result range
* @return a provider for matching objects
*/
protected ResultObjectProvider executeQuery(Executor ex,
ClassMetaData base, ClassMetaData[] types, boolean subclasses,
ExpressionFactory[] facts, QueryExpressions[] parsed, Object[] params,
- boolean lrs, long startIdx, long endIdx) {
+ Range range) {
throw new UnsupportedException();
}
@@ -246,16 +242,12 @@ public class ExpressionStoreQuery
* each base type
* @param parsed the parsed query values
* @param params parameter values, or empty array
- * @param startIdx 0-based inclusive index for first result to return
- * from result object provider
- * @param endIdx 0-based exclusive index for last result to return
- * from result object provider, or {@link Long#MAX_VALUE} for no max
+ * @param range result range
* @return a textual description of the query to execute
*/
protected String[] getDataStoreActions(Executor ex, ClassMetaData base,
ClassMetaData[] types, boolean subclasses, ExpressionFactory[] facts,
- QueryExpressions[] parsed, Object[] params, long startIdx,
- long endIdx) {
+ QueryExpressions[] parsed, Object[] params, Range range) {
return StoreQuery.EMPTY_STRINGS;
}
@@ -328,6 +320,30 @@ public class ExpressionStoreQuery
ValidateGroupingExpressionVisitor.validate(q.getContext(), exps);
}
+ public void getRange(StoreQuery q, Object[] params, Range range) {
+ QueryExpressions exps = assertQueryExpression();
+ if (exps.range.length == 0)
+ return;
+
+ if (exps.range.length == 2
+ && exps.range[0] instanceof Constant
+ && exps.range[1] instanceof Constant) {
+ try {
+ range.start = ((Number) ((Constant) exps.range[0]).
+ getValue(params)).longValue();
+ range.end = ((Number) ((Constant) exps.range[1]).
+ getValue(params)).longValue();
+ return;
+ } catch (ClassCastException cce) {
+ // fall through to exception below
+ } catch (NullPointerException npe) {
+ // fall through to exception below
+ }
+ }
+ throw new UserException(_loc.get("only-range-constants",
+ q.getContext().getQueryString()));
+ }
+
public final Class getResultClass(StoreQuery q) {
return assertQueryExpression().resultClass;
}
@@ -464,7 +480,7 @@ public class ExpressionStoreQuery
_subs = subclasses;
_factory = new InMemoryExpressionFactory();
- _exps = new QueryExpressions[]{
+ _exps = new QueryExpressions[] {
parser.eval(parsed, q, _factory, _meta)
};
if (_exps[0].projections.length == 0)
@@ -488,7 +504,7 @@ public class ExpressionStoreQuery
}
public ResultObjectProvider executeQuery(StoreQuery q,
- Object[] params, boolean lrs, long startIdx, long endIdx) {
+ Object[] params, Range range) {
// execute in memory for candidate collection;
// also execute in memory for transactional extents
Collection coll = q.getContext().getCandidateCollection();
@@ -539,19 +555,13 @@ public class ExpressionStoreQuery
results = _factory.distinct(_exps[0], coll == null, results);
ResultObjectProvider rop = new ListResultObjectProvider(results);
- if (startIdx != 0 || endIdx != Long.MAX_VALUE)
- rop = new RangeResultObjectProvider(rop, startIdx, endIdx);
+ if (range.start != 0 || range.end != Long.MAX_VALUE)
+ rop = new RangeResultObjectProvider(rop, range.start,range.end);
return rop;
}
- public ResultObjectProvider executeQuery(StoreQuery q,
- Map params, boolean lrs, long startIdx, long endIdx) {
- return executeQuery(q, q.getContext().toParameterArray
- (getParameterTypes(q), params), lrs, startIdx, endIdx);
- }
-
public String[] getDataStoreActions(StoreQuery q, Object[] params,
- long startIdx, long endIdx) {
+ Range range) {
// in memory queries have no datastore actions to perform
return StoreQuery.EMPTY_STRINGS;
}
@@ -646,16 +656,10 @@ public class ExpressionStoreQuery
}
public ResultObjectProvider executeQuery(StoreQuery q,
- Object[] params, boolean lrs, long startIdx, long endIdx) {
- lrs = lrs && !isAggregate(q) && !hasGrouping(q);
+ Object[] params, Range range) {
+ range.lrs &= !isAggregate(q) && !hasGrouping(q);
return ((ExpressionStoreQuery) q).executeQuery(this, _meta, _metas,
- _subs, _facts, _exps, params, lrs, startIdx, endIdx);
- }
-
- public ResultObjectProvider executeQuery(StoreQuery q,
- Map params, boolean lrs, long startIdx, long endIdx) {
- return executeQuery(q, q.getContext().toParameterArray
- (getParameterTypes(q), params), lrs, startIdx, endIdx);
+ _subs, _facts, _exps, params, range);
}
public Number executeDelete(StoreQuery q, Object[] params) {
@@ -666,11 +670,6 @@ public class ExpressionStoreQuery
return num;
}
- public Number executeDelete(StoreQuery q, Map params) {
- return executeDelete(q, q.getContext().toParameterArray
- (getParameterTypes(q), params));
- }
-
public Number executeUpdate(StoreQuery q, Object[] params) {
Number num = ((ExpressionStoreQuery) q).executeUpdate(this, _meta,
_metas, _subs, _facts, _exps, params);
@@ -679,15 +678,10 @@ public class ExpressionStoreQuery
return num;
}
- public Number executeUpdate(StoreQuery q, Map params) {
- return executeUpdate(q, q.getContext().toParameterArray
- (getParameterTypes(q), params));
- }
-
public String[] getDataStoreActions(StoreQuery q, Object[] params,
- long startIdx, long endIdx) {
+ Range range) {
return ((ExpressionStoreQuery) q).getDataStoreActions(this, _meta,
- _metas, _subs, _facts, _exps, params, startIdx, endIdx);
+ _metas, _subs, _facts, _exps, params, range);
}
public Object getOrderingValue(StoreQuery q, Object[] params,
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/MethodStoreQuery.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/MethodStoreQuery.java
index f2c209158..efff61628 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/MethodStoreQuery.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/MethodStoreQuery.java
@@ -135,7 +135,7 @@ public class MethodStoreQuery
}
public ResultObjectProvider executeQuery(StoreQuery q,
- Object[] params, boolean lrs, long startIdx, long endIdx) {
+ Object[] params, Range range) {
// convert the parameters into a map
Map paramMap;
if (params.length == 0)
@@ -148,19 +148,14 @@ public class MethodStoreQuery
itr.hasNext(); idx++)
paramMap.put(itr.next(), params[idx]);
}
- return executeQuery(q, paramMap, lrs, startIdx, endIdx);
- }
- public ResultObjectProvider executeQuery(StoreQuery q,
- Map params, boolean lrs, long startIdx, long endIdx) {
FetchConfiguration fetch = q.getContext().getFetchConfiguration();
StoreContext sctx = q.getContext().getStoreContext();
-
ResultObjectProvider rop;
Object[] args;
if (_inMem) {
args = new Object[]{ sctx, _meta, (_subs) ? Boolean.TRUE
- : Boolean.FALSE, null, params, fetch };
+ : Boolean.FALSE, null, paramMap, fetch };
Iterator itr = null;
Collection coll = q.getContext().getCandidateCollection();
@@ -192,12 +187,12 @@ public class MethodStoreQuery
} else {
// datastore
args = new Object[]{ sctx, _meta, (_subs) ? Boolean.TRUE
- : Boolean.FALSE, params, fetch };
+ : Boolean.FALSE, paramMap, fetch };
rop = (ResultObjectProvider) invoke(q, args);
}
- if (startIdx != 0 || endIdx != Long.MAX_VALUE)
- rop = new RangeResultObjectProvider(rop, startIdx, endIdx);
+ if (range.start != 0 || range.end != Long.MAX_VALUE)
+ rop = new RangeResultObjectProvider(rop, range.start,range.end);
return rop;
}
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryContext.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryContext.java
index 1acbed02a..485ef1519 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryContext.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryContext.java
@@ -248,11 +248,6 @@ public interface QueryContext {
*/
public Collection getAggregateListeners();
- /**
- * Helper method to transform the given parameters into an array.
- */
- public Object[] toParameterArray(LinkedMap paramTypes, Map params);
-
/**
* Helper method to delete the objects found by executing a query on
* the given executor.
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java
index e9229c6aa..b3dc2fc93 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/QueryImpl.java
@@ -104,6 +104,7 @@ public class QueryImpl
private Class _resultClass = null;
private transient long _startIdx = 0;
private transient long _endIdx = Long.MAX_VALUE;
+ private transient boolean _rangeSet = false;
// remember the list of all the results we have returned so we
// can free their resources when close or closeAll is called
@@ -486,35 +487,13 @@ public class QueryImpl
}
public long getStartRange() {
- lock();
- try {
- assertOpen();
- if (_startIdx != 0 || _endIdx != Long.MAX_VALUE
- || _compiled != null || _query == null || _broker == null)
- return _startIdx;
-
- // check again after compilation; maybe encoded in string
- compileForCompilation();
- return _startIdx;
- } finally {
- unlock();
- }
+ assertOpen();
+ return _startIdx;
}
public long getEndRange() {
- lock();
- try {
- assertOpen();
- if (_startIdx != 0 || _endIdx != Long.MAX_VALUE
- || _compiled != null || _query == null || _broker == null)
- return _endIdx;
-
- // check again after compilation; maybe encoded in string
- compileForCompilation();
- return _endIdx;
- } finally {
- unlock();
- }
+ assertOpen();
+ return _endIdx;
}
public void setRange(long start, long end) {
@@ -532,6 +511,7 @@ public class QueryImpl
// allowed modification: no read-only check
_startIdx = start;
_endIdx = end;
+ _rangeSet = true;
} finally {
unlock();
}
@@ -703,7 +683,7 @@ public class QueryImpl
else
es[i] = _storeQuery.newDataStoreExecutor(metas[i], true);
}
- return new MergedExecutor(es, this);
+ return new MergedExecutor(es);
} catch (OpenJPAException ke) {
throw ke;
} catch (RuntimeException re) {
@@ -799,16 +779,18 @@ public class QueryImpl
StoreQuery.Executor ex = (isInMemory(operation))
? compileForInMemory(comp) : compileForDataStore(comp);
- assertParameters(ex, params);
+ Object[] arr = (params.isEmpty()) ? StoreQuery.EMPTY_OBJECTS :
+ toParameterArray(ex.getParameterTypes(_storeQuery), params);
+ assertParameters(ex, arr);
if (_log.isTraceEnabled())
logExecution(operation, params);
if (operation == OP_SELECT)
- return execute(ex, params);
+ return execute(ex, arr);
if (operation == OP_DELETE)
- return delete(ex, params);
+ return delete(ex, arr);
if (operation == OP_UPDATE)
- return update(ex, params);
+ return update(ex, arr);
throw new UnsupportedException();
} catch (OpenJPAException ke) {
throw ke;
@@ -847,7 +829,7 @@ public class QueryImpl
return ((Number) execute(OP_UPDATE, params)).longValue();
}
- public Object[] toParameterArray(LinkedMap paramTypes, Map params) {
+ private Object[] toParameterArray(LinkedMap paramTypes, Map params) {
if (params == null || params.isEmpty())
return StoreQuery.EMPTY_OBJECTS;
@@ -940,16 +922,18 @@ public class QueryImpl
private Object execute(StoreQuery.Executor ex, Object[] params)
throws Exception {
// if this is an impossible result range, return null / empty list
- if (_startIdx >= _endIdx)
+ StoreQuery.Range range = new StoreQuery.Range(_startIdx, _endIdx);
+ if (!_rangeSet)
+ ex.getRange(_storeQuery, params, range);
+ if (range.start >= range.end)
return emptyResult(ex);
// execute; if we have a result class or we have only one result
// and so need to remove it from its array, wrap in a packing rop
- boolean lrs = isLRS();
- ResultObjectProvider rop = ex.executeQuery(_storeQuery, params, lrs,
- _startIdx, _endIdx);
+ range.lrs = isLRS(range.start, range.end);
+ ResultObjectProvider rop = ex.executeQuery(_storeQuery, params, range);
try {
- return toResult(ex, rop, lrs);
+ return toResult(ex, rop, range);
} catch (Exception e) {
if (rop != null)
try { rop.close(); } catch (Exception e2) {}
@@ -957,48 +941,6 @@ public class QueryImpl
}
}
- /**
- * Execute the query using the given compilation, executor, and parameter
- * values. All other execute methods delegate to this one or to
- * {@link #execute(StoreQuery.Executor,Object[])} after validation and
- * locking.
- */
- private Object execute(StoreQuery.Executor ex, Map params)
- throws Exception {
- // if this is an impossible result range, return null / empty list
- if (_startIdx >= _endIdx)
- return emptyResult(ex);
-
- // execute; if we have a result class or we have only one result
- // and so need to remove it from its array, wrap in a packing rop
- boolean lrs = isLRS();
- ResultObjectProvider rop = ex.executeQuery(_storeQuery, params, lrs,
- _startIdx, _endIdx);
- try {
- return toResult(ex, rop, lrs);
- } catch (Exception e) {
- if (rop != null)
- try {
- rop.close();
- } catch (Exception e2) {
- }
- throw e;
- }
- }
-
- /**
- * Delete the query using the given executor, and parameter
- * values. All other execute methods delegate to this one or to
- * {@link #delete(StoreQuery.Executor,Object[])} after validation and
- * locking. The return value will be a Number indicating the number of
- * instances deleted.
- */
- private Number delete(StoreQuery.Executor ex, Map params)
- throws Exception {
- assertBulkModify();
- return ex.executeDelete(_storeQuery, params);
- }
-
/**
* Delete the query using the given executor, and parameter
* values. All other execute methods delegate to this one or to
@@ -1008,7 +950,7 @@ public class QueryImpl
*/
private Number delete(StoreQuery.Executor ex, Object[] params)
throws Exception {
- assertBulkModify();
+ assertBulkModify(ex, params);
return ex.executeDelete(_storeQuery, params);
}
@@ -1030,19 +972,6 @@ public class QueryImpl
}
}
- /**
- * Update the query using the given executor and parameter
- * values. All other execute methods delegate to this one or to
- * {@link #update(StoreQuery.Executor,Object[])} after validation and
- * locking. The return value will be a Number indicating the number of
- * instances updated.
- */
- private Number update(StoreQuery.Executor ex, Map params)
- throws Exception {
- assertBulkModify();
- return ex.executeUpdate(_storeQuery, params);
- }
-
/**
* Update the query using the given compilation, executor, and parameter
* values. All other execute methods delegate to this one or to
@@ -1052,7 +981,7 @@ public class QueryImpl
*/
private Number update(StoreQuery.Executor ex, Object[] params)
throws Exception {
- assertBulkModify();
+ assertBulkModify(ex, params);
return ex.executeUpdate(_storeQuery, params);
}
@@ -1086,7 +1015,7 @@ public class QueryImpl
Map.Entry e = (Map.Entry) it.next();
FieldMetaData fmd = (FieldMetaData) e.getKey();
if (!(e.getValue() instanceof Constant))
- throw new UserException(_loc.get("only-update-primitives"));
+ throw new UserException(_loc.get("only-update-constants"));
Constant value = (Constant) e.getValue();
Object val = value.getValue(params);
@@ -1195,8 +1124,8 @@ public class QueryImpl
/**
* Return whether this should be treated as a potential large result set.
*/
- private boolean isLRS() {
- long range = _endIdx - _startIdx;
+ private boolean isLRS(long start, long end) {
+ long range = end - start;
return _fc.getFetchBatchSize() >= 0
&& !(range <= _fc.getFetchBatchSize()
|| (_fc.getFetchBatchSize() == 0 && range <= 50));
@@ -1206,7 +1135,7 @@ public class QueryImpl
* Return the query result for the given result object provider.
*/
protected Object toResult(StoreQuery.Executor ex, ResultObjectProvider rop,
- boolean lrs)
+ StoreQuery.Range range)
throws Exception {
// pack projections if necessary
String[] aliases = ex.getProjectionAliases(_storeQuery);
@@ -1220,13 +1149,13 @@ public class QueryImpl
// if single result, extract it
if (_unique == Boolean.TRUE || (aliases.length > 0
&& !ex.hasGrouping(_storeQuery) && ex.isAggregate(_storeQuery)))
- return singleResult(rop);
+ return singleResult(rop, range);
// now that we've executed the query, we can call isAggregate and
// hasGrouping efficiently
boolean detach = (_broker.getAutoDetach() &
AutoDetach.DETACH_NONTXREAD) > 0 && !_broker.isActive();
- lrs = lrs && !ex.isAggregate(_storeQuery)
+ boolean lrs = range.lrs && !ex.isAggregate(_storeQuery)
&& !ex.hasGrouping(_storeQuery);
ResultList res = (!detach && lrs) ? _fc.newResultList(rop)
: new EagerResultList(rop);
@@ -1281,7 +1210,8 @@ public class QueryImpl
* Extract an expected single result from the given provider. Used when
* the result is an ungrouped aggregate or the unique flag is set to true.
*/
- private Object singleResult(ResultObjectProvider rop)
+ private Object singleResult(ResultObjectProvider rop,
+ StoreQuery.Range range)
throws Exception {
rop.open();
try {
@@ -1293,7 +1223,7 @@ public class QueryImpl
Object single = null;
if (next) {
single = rop.getResultObject();
- if (_endIdx != _startIdx + 1 && rop.next())
+ if (range.end != range.start + 1 && rop.next())
throw new InvalidStateException(_loc.get("not-unique",
_class, _query));
}
@@ -1397,10 +1327,13 @@ public class QueryImpl
assertOpen();
StoreQuery.Executor ex = compileForExecutor();
- assertParameters(ex, params);
Object[] arr = toParameterArray(ex.getParameterTypes(_storeQuery),
params);
- return ex.getDataStoreActions(_storeQuery, arr, _startIdx, _endIdx);
+ assertParameters(ex, arr);
+ StoreQuery.Range range = new StoreQuery.Range(_startIdx, _endIdx);
+ if (!_rangeSet)
+ ex.getRange(_storeQuery, arr, range);
+ return ex.getDataStoreActions(_storeQuery, arr, range);
} catch (OpenJPAException ke) {
throw ke;
} catch (Exception e) {
@@ -1654,44 +1587,16 @@ public class QueryImpl
* Check that we are in a state to be able to perform a bulk operation;
* also flush the current modfications if any elements are currently dirty.
*/
- private void assertBulkModify() {
+ private void assertBulkModify(StoreQuery.Executor ex, Object[] params) {
_broker.assertActiveTransaction();
if (_startIdx != 0 || _endIdx != Long.MAX_VALUE)
throw new UserException(_loc.get("no-modify-range"));
if (_resultClass != null)
throw new UserException(_loc.get("no-modify-resultclass"));
- }
-
- /**
- * Checks that the passed parameters match the declarations.
- */
- private void assertParameters(StoreQuery.Executor ex, Map params) {
- if (!_storeQuery.requiresParameterDeclarations())
- return;
-
- // check that all declared parameters are given compatible values
- LinkedMap paramTypes = ex.getParameterTypes(_storeQuery);
- if (paramTypes != null && !paramTypes.isEmpty()) {
- Map.Entry entry;
- for (Iterator itr = paramTypes.entrySet().iterator();
- itr.hasNext();) {
- entry = (Map.Entry) itr.next();
- if (!params.containsKey(entry.getKey()))
- throw new UserException(_loc.get("unbound-param",
- entry.getKey()));
- if (((Class) entry.getValue()).isPrimitive()
- && params.get(entry.getKey()) == null)
- throw new UserException(_loc.get("null-primitive-param",
- entry.getKey()));
- }
- }
-
- // check that there are no extra params
- int typeCount = (paramTypes == null) ? 0 : paramTypes.size();
- int paramCount = (params == null) ? 0 : params.size();
- if (paramCount > typeCount)
- throw new UserException(_loc.get("extra-params", new Object[]
- { new Integer(typeCount), new Integer(paramCount) }));
+ StoreQuery.Range range = new StoreQuery.Range();
+ ex.getRange(_storeQuery, params, range);
+ if (range.start != 0 || range.end != Long.MAX_VALUE)
+ throw new UserException(_loc.get("no-modify-range"));
}
/**
@@ -1708,7 +1613,7 @@ public class QueryImpl
paramTypes.keySet()));
if (typeCount < params.length)
throw new UserException(_loc.get("extra-params", new Object[]
- { new Integer(typeCount), new Integer(params.length) }));
+ { String.valueOf(typeCount), String.valueOf(params.length) }));
Iterator itr = paramTypes.entrySet().iterator();
Map.Entry entry;
@@ -1761,31 +1666,28 @@ public class QueryImpl
implements StoreQuery.Executor {
private final StoreQuery.Executor[] _executors;
- private final QueryContext _ctx;
- public MergedExecutor(StoreQuery.Executor[] executors,
- QueryContext ctx) {
+ public MergedExecutor(StoreQuery.Executor[] executors) {
_executors = executors;
- _ctx = ctx;
}
public ResultObjectProvider executeQuery(StoreQuery q,
- Object[] params, boolean lrs, long startIdx, long endIdx) {
+ Object[] params, StoreQuery.Range range) {
if (_executors.length == 1)
- return _executors[0].executeQuery(q, params, lrs, startIdx,
- endIdx);
+ return _executors[0].executeQuery(q, params, range);
// use lrs settings if we couldn't take advantage of the start index
// so that hopefully the skip to the start will be efficient
- lrs = lrs || (startIdx > 0
- && _ctx.getFetchConfiguration().getFetchBatchSize() >= 0);
+ StoreQuery.Range ropRange = new StoreQuery.Range(0, range.end);
+ ropRange.lrs = range.lrs || (range.start > 0 && q.getContext().
+ getFetchConfiguration().getFetchBatchSize() >= 0);
// execute the query; we cannot use the lower bound of the result
// range, but we can take advantage of the upper bound
ResultObjectProvider[] rops =
new ResultObjectProvider[_executors.length];
for (int i = 0; i < _executors.length; i++)
- rops[i] = _executors[i].executeQuery(q, params, lrs, 0, endIdx);
+ rops[i] = _executors[i].executeQuery(q, params, ropRange);
boolean[] asc = _executors[0].getAscending(q);
ResultObjectProvider rop;
@@ -1796,41 +1698,9 @@ public class QueryImpl
_executors, q, params);
// if there is a lower bound, wrap in range rop
- if (startIdx != 0)
- rop = new RangeResultObjectProvider(rop, startIdx, endIdx);
- return rop;
- }
-
- public ResultObjectProvider executeQuery(StoreQuery q, Map params,
- boolean lrs, long startIdx, long endIdx) {
- if (_executors.length == 1)
- return _executors[0].executeQuery(q, params, lrs, startIdx,
- endIdx);
-
- // use lrs settings if we couldn't take advantage of the start index
- // so that hopefully the skip to the start will be efficient
- lrs = lrs || (startIdx > 0
- && _ctx.getFetchConfiguration().getFetchBatchSize() >= 0);
-
- // execute the query; we cannot use the lower bound of the result
- // range, but we can take advantage of the upper bound
- ResultObjectProvider[] rops =
- new ResultObjectProvider[_executors.length];
- for (int i = 0; i < _executors.length; i++)
- rops[i] = _executors[i].executeQuery(q, params, lrs, 0, endIdx);
-
- boolean[] asc = _executors[0].getAscending(q);
- ResultObjectProvider rop;
- if (asc.length == 0)
- rop = new MergedResultObjectProvider(rops);
- else
- rop = new OrderingMergedResultObjectProvider(rops, asc,
- _executors, q, _ctx.toParameterArray
- (_executors[0].getParameterTypes(q), params));
-
- // if there is a lower bound, wrap in range rop
- if (startIdx != 0)
- rop = new RangeResultObjectProvider(rop, startIdx, endIdx);
+ if (range.start != 0)
+ rop = new RangeResultObjectProvider(rop, range.start,
+ range.end);
return rop;
}
@@ -1841,13 +1711,6 @@ public class QueryImpl
return Numbers.valueOf(num);
}
- public Number executeDelete(StoreQuery q, Map params) {
- long num = 0;
- for (int i = 0; i < _executors.length; i++)
- num += _executors[i].executeDelete(q, params).longValue();
- return Numbers.valueOf(num);
- }
-
public Number executeUpdate(StoreQuery q, Object[] params) {
long num = 0;
for (int i = 0; i < _executors.length; i++)
@@ -1855,24 +1718,16 @@ public class QueryImpl
return Numbers.valueOf(num);
}
- public Number executeUpdate(StoreQuery q, Map params) {
- long num = 0;
- for (int i = 0; i < _executors.length; i++)
- num += _executors[i].executeUpdate(q, params).longValue();
- return Numbers.valueOf(num);
- }
-
public String[] getDataStoreActions(StoreQuery q, Object[] params,
- long startIdx, long endIdx) {
+ StoreQuery.Range range) {
if (_executors.length == 1)
- return _executors[0].getDataStoreActions(q, params,
- startIdx, endIdx);
+ return _executors[0].getDataStoreActions(q, params, range);
List results = new ArrayList(_executors.length);
+ StoreQuery.Range ropRange = new StoreQuery.Range(0L, range.end);
String[] actions;
for (int i = 0; i < _executors.length; i++) {
- actions = _executors[i].getDataStoreActions(q, params, 0,
- endIdx);
+ actions = _executors[i].getDataStoreActions(q, params,ropRange);
if (actions != null && actions.length > 0)
results.addAll(Arrays.asList(actions));
}
@@ -1883,6 +1738,11 @@ public class QueryImpl
_executors[0].validate(q);
}
+ public void getRange(StoreQuery q, Object[] params,
+ StoreQuery.Range range) {
+ _executors[0].getRange(q, params, range);
+ }
+
public Object getOrderingValue(StoreQuery q, Object[] params,
Object resultObject, int idx) {
// unfortunately, at this point (must be a merged rop containing
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/SingleFieldManager.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/SingleFieldManager.java
index 7c830ad90..46c853a18 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/SingleFieldManager.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/SingleFieldManager.java
@@ -89,9 +89,12 @@ class SingleFieldManager
proxy = checkProxy();
if (proxy == null) {
proxy = (Proxy) _sm.newFieldProxy(field);
- if (objval != null)
- ((Calendar) proxy).setTime(((Calendar) objval).
- getTime());
+ if (objval != null) {
+ Calendar pcal = (Calendar) proxy;
+ Calendar ocal = (Calendar) objval;
+ pcal.setTime(ocal.getTime());
+ pcal.setTimeZone(ocal.getTimeZone());
+ }
ret = true;
}
break;
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreQuery.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreQuery.java
index 46f01cd27..cfa30f534 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreQuery.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StoreQuery.java
@@ -158,6 +158,23 @@ public interface StoreQuery
*/
public boolean supportsParameterDeclarations();
+ /**
+ * A query result range.
+ */
+ public static class Range {
+ public long start = 0L;
+ public long end = Long.MAX_VALUE;
+ public boolean lrs = false;
+
+ public Range() {
+ }
+
+ public Range(long start, long end) {
+ this.start = start;
+ this.end = end;
+ }
+ }
+
/**
* An executor provides a uniform interface to the mechanism for executing
* either an in-memory or datastore query. In the common case, the
@@ -179,17 +196,8 @@ public interface StoreQuery
* aggregate and does not have grouping
* @see #isPacking
*/
- public ResultObjectProvider executeQuery(StoreQuery q,
- Object[] params, boolean lrs, long startIdx, long endIdx);
-
- /**
- * Return the result of executing this query with the given parameter
- * values. Most implementation will use
- * {@link QueryContext#toParameterArray} to transform the parameters
- * into an array and invoke the array version of this method.
- */
- public ResultObjectProvider executeQuery(StoreQuery q, Map params,
- boolean lrs, long startIdx, long endIdx);
+ public ResultObjectProvider executeQuery(StoreQuery q, Object[] params,
+ Range range);
/**
* Deleted the objects that result from the execution of the
@@ -197,36 +205,30 @@ public interface StoreQuery
*/
public Number executeDelete(StoreQuery q, Object[] params);
- /**
- * Deleted the objects that result from the execution of the
- * query, retuning the number of objects that were deleted.
- */
- public Number executeDelete(StoreQuery q, Map params);
-
/**
* Updates the objects that result from the execution of the
* query, retuning the number of objects that were updated.
*/
public Number executeUpdate(StoreQuery q, Object[] params);
- /**
- * Updates the objects that result from the execution of the
- * query, retuning the number of objects that were updated.
- */
- public Number executeUpdate(StoreQuery q, Map params);
-
/**
* Return a description of the commands that will be sent to
* the datastore in order to execute the query.
*/
public String[] getDataStoreActions(StoreQuery q, Object[] params,
- long startIdx, long endIdx);
+ Range range);
/**
* Validate components of query.
*/
public void validate(StoreQuery q);
+ /**
+ * Mutate the given range to set any range information stored in
+ * the query string and/or parameters.
+ */
+ public void getRange(StoreQuery q, Object[] params, Range range);
+
/**
* Extract the value of the orderIndex
th ordering
* expression in {@link Query#getOrderingClauses} from the
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Constant.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Constant.java
index d806453fb..23eafa150 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Constant.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Constant.java
@@ -16,12 +16,11 @@
package org.apache.openjpa.kernel.exps;
/**
- * Interface for any constant value.
+ * Interface for any query constant value.
*
* @author Marc Prud'hommeaux
*/
-public interface Constant
- extends Value {
+public interface Constant {
/**
* Return the value for this constant given the specified parameters.
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Literal.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Literal.java
index 576ddedf2..e9e4972f1 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Literal.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Literal.java
@@ -22,7 +22,7 @@ package org.apache.openjpa.kernel.exps;
* @nojavadoc
*/
public interface Literal
- extends Constant {
+ extends Value, Constant {
public static final int TYPE_UNKNOWN = 0;
public static final int TYPE_NUMBER = 1;
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Parameter.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Parameter.java
index b99ce3c4c..ef8bb04f3 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Parameter.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Parameter.java
@@ -22,7 +22,7 @@ package org.apache.openjpa.kernel.exps;
* @nojavadoc
*/
public interface Parameter
- extends Constant {
+ extends Value, Constant {
/**
* Set the index of this parameter.
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/QueryExpressions.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/QueryExpressions.java
index f9270e253..a8a1ec7bc 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/QueryExpressions.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/QueryExpressions.java
@@ -15,6 +15,8 @@
*/
package org.apache.openjpa.kernel.exps;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.Map;
import org.apache.commons.collections.map.LinkedMap;
@@ -40,8 +42,7 @@ public class QueryExpressions {
/**
* Map of {@link FieldMetaData},{@link Value} for update statements.
*/
- public Map updates = null;
-
+ public Map updates = Collections.EMPTY_MAP;
public int distinct = DISTINCT_AUTO;
public String alias = null;
public Value[] projections = EMPTY_VALUES;
@@ -59,8 +60,12 @@ public class QueryExpressions {
public int operation = QueryOperations.OP_SELECT;
public ClassMetaData[] accessPath = StoreQuery.EMPTY_METAS;
public String[] fetchPaths = StoreQuery.EMPTY_STRINGS;
+ public Value[] range = EMPTY_VALUES;
private Boolean _aggregate = null;
+ /**
+ * Whether this is an aggregate results.
+ */
public boolean isAggregate() {
if (projections.length == 0)
return false;
@@ -70,6 +75,15 @@ public class QueryExpressions {
return _aggregate.booleanValue();
}
+ /**
+ * Add an update.
+ */
+ public void putUpdate(FieldMetaData fmd, Value val) {
+ if (updates == Collections.EMPTY_MAP)
+ updates = new HashMap();
+ updates.put(fmd, val);
+ }
+
/**
* Visitor to determine whether our projections are aggregates.
*/
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/SubQ.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/SubQ.java
index fc58671c8..86666082d 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/SubQ.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/SubQ.java
@@ -42,8 +42,7 @@ class SubQ
return _alias;
}
- public void setQueryExpressions(QueryExpressions q, long startIdx,
- long endIdx) {
+ public void setQueryExpressions(QueryExpressions q) {
}
public Class getType() {
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Subquery.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Subquery.java
index eeffce0f9..f73e58de0 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Subquery.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/exps/Subquery.java
@@ -32,6 +32,5 @@ public interface Subquery
/**
* Set the parsed subquery.
*/
- public void setQueryExpressions(QueryExpressions query, long startIdx,
- long endIdx);
+ public void setQueryExpressions(QueryExpressions query);
}
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java
index 66a3b7429..51d845adf 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/jpql/JPQLExpressionBuilder.java
@@ -444,30 +444,18 @@ class JPQLExpressionBuilder
protected void evalSetClause(QueryExpressions exps) {
// handle SET field = value
JPQLNode[] nodes = root().findChildrenByID(JJTUPDATEITEM);
-
- Map updates = null;
-
for (int i = 0; nodes != null && i < nodes.length; i++) {
- if (updates == null)
- updates = new HashMap();
-
FieldMetaData field = getPath(firstChild(nodes[i])).last();
Value val = getValue(onlyChild(lastChild(nodes[i])));
-
- updates.put(field, val);
+ exps.putUpdate(field, val);
}
-
- if (updates != null)
- exps.updates = updates;
}
private Expression evalWhereClause(QueryExpressions exps) {
// evaluate the WHERE clause
JPQLNode whereNode = root().findChildByID(JJTWHERE, false);
-
if (whereNode == null)
return null;
-
return (Expression) eval(whereNode);
}
@@ -1110,7 +1098,7 @@ class JPQLExpressionBuilder
try {
QueryExpressions subexp = getQueryExpressions();
- subq.setQueryExpressions(subexp, 0, Long.MAX_VALUE);
+ subq.setQueryExpressions(subexp);
return subq;
} finally {
// remove the subquery parse context
diff --git a/openjpa-kernel/src/main/java/sun/misc/Perf.java b/openjpa-kernel/src/main/java/sun/misc/Perf.java
new file mode 100644
index 000000000..309537eb7
--- /dev/null
+++ b/openjpa-kernel/src/main/java/sun/misc/Perf.java
@@ -0,0 +1,28 @@
+package sun.misc;
+
+/**
+ * Compilation stub for pre-1.4.2 JREs. Thanks to it, the whole backport
+ * concurrency package compiles and works with 1.4.2 as well as wih earlier
+ * JREs, and takes advantage of native Perf class when running on 1.4.2 while
+ * seamlessly falling back to System.currentTimeMillis() on previous JREs. This
+ * class should NOT be included in the binary distribution of backport.
+ *
+ * @author Dawid Kurzyniec
+ * @version 1.0
+ */
+public final class Perf {
+
+ private static final Perf perf = new Perf();
+
+ public static Perf getPerf() { return perf; }
+
+ private Perf() {}
+
+ public long highResCounter() {
+ return System.currentTimeMillis();
+ }
+
+ public long highResFrequency() {
+ return 1000L;
+ }
+}
diff --git a/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/exps/localizer.properties b/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/exps/localizer.properties
index c5eb98bab..23d61a7bb 100644
--- a/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/exps/localizer.properties
+++ b/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/exps/localizer.properties
@@ -4,8 +4,6 @@ in-mem-subquery: Subqueries are not supported for queries that execute \
not-comp: The evaluation of the ordering expression of this query produced \
non-comparable values "{0}" and "{1}". Please check that the ordering \
clause is valid.
-bad-wild: The wildcard string "{0}" is invalid.
-bad-regexp: The regular expression string "{0}" is invalid.
agg-in-filter: If you use an aggregate function in a query filter, you must \
make sure to only invoke the aggregate on collections.
parse-error: An error occurred while parsing the query filter "{1}". \
diff --git a/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties b/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties
index 1b00f932f..e0e094935 100644
--- a/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties
+++ b/openjpa-kernel/src/main/resources/org/apache/openjpa/kernel/localizer.properties
@@ -166,7 +166,9 @@ inverse-consistency: An inverse inconsistency in the object model was \
detected while flushing the field "{0}" of the instance with id "{1}" \
in context "{2}".
no-brokerfactory: You did not name the factory class with the required \
- property org.apache.openjpa.BrokerFactory.
+ property openjpa.BrokerFactory. Normally this property defaults \
+ appropriately; have you forgotten to include all the OpenJPA jars in your \
+ classpath?
brokerfactory-excep: There was an error when invoking the static \
getInstance method on the named factory class "{0}". See the \
nested exception for details.
@@ -226,7 +228,7 @@ force-in-mem: This query on type "{0}" must load the entire candidate class \
there are dirty instances that may affect the query''s outcome in the \
cache.
cant-exec-inmem: Queries of this type ("{0}") cannot be executed in-memory. \
- Either set IgnoreCache to true, set the org.apache.openjpa.FlushBeforeQueries \
+ Either set IgnoreCache to true, set the openjpa.FlushBeforeQueries \
property to true, or execute the query before changing any instances in \
the transaction.
executing-query: Executing query: {0}
@@ -269,9 +271,9 @@ bad-method-class: You set the method name of this openjpa.MethodQL query to \
"{1}", but class "{0}" is not a valid class name. Make sure to fully \
qualify the class name or to import its package into this query if the \
class is not in the query candidate class'' package.
-method-not-static: Method "{0}" named in the org.apache.openjpa.MethodQL query must be static.
+method-not-static: Method "{0}" named in the MethodQL query must be static.
no-method: You must set the query filter to the name of the method to execute \
- for this org.apache.openjpa.MethodQL query instance.
+ for this MethodQL query instance.
method-error: There was an error invoking method "{0}" with arguments "{1}".
bad-param-type: The type "{0}" as used in the parameter declarations \
could not be found in the imports.
@@ -295,13 +297,15 @@ bad-inmem-method: Method "{0}(StoreContext, ClassMetaData, boolean, Object, \
true.
bad-datastore-method: Method "{0}(StoreContext, ClassMetaData, boolean, Map, \
FetchConfiguration)" is not declared in type "{1}". Check \
- the method name supplied in your org.apache.openjpa.MethodQL query filter. OpenJPA is \
+ the method name supplied in your MethodQL query filter. OpenJPA is \
attempting to execute this query against the datastore; if you implemented \
the in-memory method instead (a method with the same signature but with an \
Object argument) and want this query to execute in-memory, supplly a \
Collection of candidates to filter.
-only-update-primitives: Bulk update queries when executed in memory \
- may only change the value of primitives and simple Object fields.
+only-update-constants: Bulk update queries when executed in memory \
+ may only update to constant values.
+only-range-constants: Range values must be numeric constants. Illegal query: \
+ {0}
no-savepoint-copy: Unable to copy field "{0}" for savepoint.
savepoint-exists: A savepoint with the name "{0}" already exists. \
Each savepoint name must be unique.
diff --git a/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/concurrent/CondVar.java b/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/concurrent/CondVar.java
index d8316b360..bc01a7a66 100644
--- a/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/concurrent/CondVar.java
+++ b/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/concurrent/CondVar.java
@@ -31,7 +31,7 @@ class CondVar implements Condition, java.io.Serializable {
*/
protected final ExclusiveLock lock;
- /* *
+ /**
* Create a new CondVar that relies on the given mutual exclusion lock.
* @param lock A non-reentrant mutual exclusion lock.
*/
diff --git a/openjpa-persistence-jdbc/src/main/resources/org/apache/openjpa/persistence/jdbc/localizer.properties b/openjpa-persistence-jdbc/src/main/resources/org/apache/openjpa/persistence/jdbc/localizer.properties
index 406215fbf..aac112066 100644
--- a/openjpa-persistence-jdbc/src/main/resources/org/apache/openjpa/persistence/jdbc/localizer.properties
+++ b/openjpa-persistence-jdbc/src/main/resources/org/apache/openjpa/persistence/jdbc/localizer.properties
@@ -16,8 +16,8 @@ bad-second: "{0}" declares a secondary table on columns that do not support \
unique-constraints: Detected declared unique constraints on "{0}". OpenJPA \
does not yet support the @UniqueConstraint annotation.
inconsist-col-attrs: Detected inconsistent values of "unique" on different \
- columns of "{0}". OpenJPA does not yet support different per-column unique \
- values. All columns for this mapping must use the same values.
+ columns of "{0}". OpenJPA does not yet support different per-column \
+ unique values. All columns for this mapping must use the same values.
pk-as-fk: The "usePKasFK" attribute is not yet supported. Mapping your \
OneToOne using JoinColumns that match your id property columns will work.
no-override-name: Missing "name" property on mapping override for "{0}".