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 orderIndexth 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}".