OPENJPA-612 Add support for calculating update value in QueryImpl.updateInMemory

Help comitting patch provided by Fay Wang

git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@660825 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Catalina Wei 2008-05-28 06:08:41 +00:00
parent c1e5f27724
commit dbbd1236f2
6 changed files with 1312 additions and 1171 deletions

View File

@ -35,10 +35,12 @@ import org.apache.openjpa.jdbc.kernel.exps.GetColumn;
import org.apache.openjpa.jdbc.kernel.exps.JDBCExpressionFactory;
import org.apache.openjpa.jdbc.kernel.exps.JDBCStringContains;
import org.apache.openjpa.jdbc.kernel.exps.JDBCWildcardMatch;
import org.apache.openjpa.jdbc.kernel.exps.PCPath;
import org.apache.openjpa.jdbc.kernel.exps.QueryExpressionsState;
import org.apache.openjpa.jdbc.kernel.exps.SQLEmbed;
import org.apache.openjpa.jdbc.kernel.exps.SQLExpression;
import org.apache.openjpa.jdbc.kernel.exps.SQLValue;
import org.apache.openjpa.jdbc.kernel.exps.Val;
import org.apache.openjpa.jdbc.meta.ClassMapping;
import org.apache.openjpa.jdbc.meta.FieldMapping;
import org.apache.openjpa.jdbc.meta.strats.VerticalClassStrategy;
@ -50,18 +52,24 @@ import org.apache.openjpa.jdbc.sql.SQLExceptions;
import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.jdbc.sql.Union;
import org.apache.openjpa.kernel.ExpressionStoreQuery;
import org.apache.openjpa.kernel.Filters;
import org.apache.openjpa.kernel.OpenJPAStateManager;
import org.apache.openjpa.kernel.OrderingMergedResultObjectProvider;
import org.apache.openjpa.kernel.QueryHints;
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;
import org.apache.openjpa.kernel.exps.Literal;
import org.apache.openjpa.kernel.exps.QueryExpressions;
import org.apache.openjpa.lib.rop.MergedResultObjectProvider;
import org.apache.openjpa.lib.rop.RangeResultObjectProvider;
import org.apache.openjpa.lib.rop.ResultObjectProvider;
import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.meta.JavaTypes;
import org.apache.openjpa.meta.ValueMetaData;
import org.apache.openjpa.util.UnsupportedException;
import org.apache.openjpa.util.UserException;
import serp.util.Numbers;
@ -671,4 +679,105 @@ public class JDBCStoreQuery
throws SQLException {
return sql.prepareStatement(conn);
}
public Object evaluate(Object value, Object ob, Object[] params,
OpenJPAStateManager sm) {
if (value instanceof org.apache.openjpa.jdbc.kernel.exps.Math) {
org.apache.openjpa.jdbc.kernel.exps.Math mathVal =
(org.apache.openjpa.jdbc.kernel.exps.Math) value;
Val value1 = mathVal.getVal1();
Object val1 = getValue(value1, ob, params, sm);
Class c1 = value1.getType();
Val value2 = mathVal.getVal2();
Object val2 = getValue(value2, ob, params, sm);
Class c2 = value2.getType();
String op = mathVal.getOperation();
if (op.equals(org.apache.openjpa.jdbc.kernel.exps.Math.ADD))
return Filters.add(val1, c1, val2, c2);
else if (op.equals(
org.apache.openjpa.jdbc.kernel.exps.Math.SUBTRACT))
return Filters.subtract(val1, c1, val2, c2);
else if (op.equals(
org.apache.openjpa.jdbc.kernel.exps.Math.MULTIPLY))
return Filters.multiply(val1, c1, val2, c2);
else if (op.equals(
org.apache.openjpa.jdbc.kernel.exps.Math.DIVIDE))
return Filters.divide(val1, c1, val2, c2);
else if (op.equals(org.apache.openjpa.jdbc.kernel.exps.Math.MOD))
return Filters.mod(val1, c1, val2, c2);
throw new UnsupportedException();
}
throw new UnsupportedException();
}
private Object getValue(Object ob, FieldMapping fmd,
OpenJPAStateManager sm) {
int i = fmd.getIndex();
switch (fmd.getDeclaredTypeCode()) {
case JavaTypes.BOOLEAN:
return sm.fetchBooleanField(i);
case JavaTypes.BYTE:
return sm.fetchByteField(i);
case JavaTypes.CHAR:
return sm.fetchCharField(i);
case JavaTypes.DOUBLE:
return sm.fetchDoubleField(i);
case JavaTypes.FLOAT:
return sm.fetchFloatField(i);
case JavaTypes.INT:
return sm.fetchIntField(i);
case JavaTypes.LONG:
return sm.fetchLongField(i);
case JavaTypes.SHORT:
return sm.fetchShortField(i);
case JavaTypes.STRING:
return sm.fetchStringField(i);
case JavaTypes.DATE:
case JavaTypes.NUMBER:
case JavaTypes.BOOLEAN_OBJ:
case JavaTypes.BYTE_OBJ:
case JavaTypes.CHAR_OBJ:
case JavaTypes.DOUBLE_OBJ:
case JavaTypes.FLOAT_OBJ:
case JavaTypes.INT_OBJ:
case JavaTypes.LONG_OBJ:
case JavaTypes.SHORT_OBJ:
case JavaTypes.BIGDECIMAL:
case JavaTypes.BIGINTEGER:
case JavaTypes.LOCALE:
case JavaTypes.OBJECT:
case JavaTypes.OID:
return sm.fetchObjectField(i);
default:
throw new UnsupportedException();
}
}
private Object eval(Object ob, Object value, Object[] params,
OpenJPAStateManager sm) {
Object val = null;
if (value instanceof Literal)
val = ((Literal) value).getValue();
else if (value instanceof Constant)
val = ((Constant) value).getValue(params);
else
val = evaluate(value, ob, params, sm);
return val;
}
private Object getValue(Object value, Object ob, Object[] params,
OpenJPAStateManager sm) {
if (value instanceof org.apache.openjpa.jdbc.kernel.exps.Math)
return evaluate(value, ob, params, sm);
else if (value instanceof PCPath) {
FieldMapping fm = (FieldMapping)((PCPath)value).last();
return getValue(ob, fm, sm);
} else
return eval(ob, value, params, sm);
}
}

View File

@ -33,7 +33,7 @@ import org.apache.openjpa.meta.ClassMetaData;
*
* @author Abe White
*/
class Math
public class Math
extends AbstractVal {
public static final String ADD = "+";
@ -57,6 +57,18 @@ class Math
_op = op;
}
public Val getVal1() {
return _val1;
}
public Val getVal2() {
return _val2;
}
public String getOperation() {
return _op;
}
public ClassMetaData getMetaData() {
return _meta;
}

View File

@ -1,184 +1,190 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.openjpa.kernel;
import java.util.Map;
import org.apache.commons.collections.map.LinkedMap;
import org.apache.openjpa.kernel.exps.AggregateListener;
import org.apache.openjpa.kernel.exps.FilterListener;
import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.util.InternalException;
/**
* Abstract {@link StoreQuery} that implements most methods as no-ops.
*
* @author Abe White
* @since 0.4.0
*/
public abstract class AbstractStoreQuery
implements StoreQuery {
protected QueryContext ctx = null;
public QueryContext getContext() {
return ctx;
}
public void setContext(QueryContext ctx) {
this.ctx = ctx;
}
public boolean setQuery(Object query) {
return false;
}
public FilterListener getFilterListener(String tag) {
return null;
}
public AggregateListener getAggregateListener(String tag) {
return null;
}
public Object newCompilationKey() {
return null;
}
public Object newCompilation() {
return null;
}
public void populateFromCompilation(Object comp) {
}
public void invalidateCompilation() {
}
public boolean supportsDataStoreExecution() {
return false;
}
public boolean supportsInMemoryExecution() {
return false;
}
public Executor newInMemoryExecutor(ClassMetaData meta, boolean subs) {
throw new InternalException();
}
public Executor newDataStoreExecutor(ClassMetaData meta, boolean subs) {
throw new InternalException();
}
public boolean supportsAbstractExecutors() {
return false;
}
public boolean requiresCandidateType() {
return true;
}
public boolean requiresParameterDeclarations() {
return true;
}
public boolean supportsParameterDeclarations() {
return true;
}
/**
* Abstract {@link Executor} that implements most methods as no-ops.
*/
public static abstract class AbstractExecutor
implements Executor {
public Number executeDelete(StoreQuery q, Object[] params) {
return q.getContext().deleteInMemory(q, this, params);
}
public Number executeUpdate(StoreQuery q, Object[] params) {
return q.getContext().updateInMemory(q, this, params);
}
public String[] getDataStoreActions(StoreQuery q, Object[] params,
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;
}
public boolean[] getAscending(StoreQuery q) {
return EMPTY_BOOLEANS;
}
public boolean isPacking(StoreQuery q) {
return false;
}
public String getAlias(StoreQuery q) {
return null;
}
public String[] getProjectionAliases(StoreQuery q) {
return EMPTY_STRINGS;
}
public Class[] getProjectionTypes(StoreQuery q) {
return EMPTY_CLASSES;
}
public ClassMetaData[] getAccessPathMetaDatas(StoreQuery q) {
return EMPTY_METAS;
}
public int getOperation(StoreQuery q) {
return OP_SELECT;
}
public boolean isAggregate(StoreQuery q) {
return false;
}
public boolean hasGrouping(StoreQuery q) {
return false;
}
public LinkedMap getParameterTypes(StoreQuery q) {
return EMPTY_PARAMS;
}
public Class getResultClass(StoreQuery q) {
return null;
}
public Map getUpdates(StoreQuery q) {
return null;
}
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.openjpa.kernel;
import java.util.Map;
import org.apache.commons.collections.map.LinkedMap;
import org.apache.openjpa.kernel.exps.AggregateListener;
import org.apache.openjpa.kernel.exps.FilterListener;
import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.util.InternalException;
import org.apache.openjpa.util.UnsupportedException;
/**
* Abstract {@link StoreQuery} that implements most methods as no-ops.
*
* @author Abe White
* @since 0.4.0
*/
public abstract class AbstractStoreQuery
implements StoreQuery {
protected QueryContext ctx = null;
public QueryContext getContext() {
return ctx;
}
public void setContext(QueryContext ctx) {
this.ctx = ctx;
}
public boolean setQuery(Object query) {
return false;
}
public FilterListener getFilterListener(String tag) {
return null;
}
public AggregateListener getAggregateListener(String tag) {
return null;
}
public Object newCompilationKey() {
return null;
}
public Object newCompilation() {
return null;
}
public void populateFromCompilation(Object comp) {
}
public void invalidateCompilation() {
}
public boolean supportsDataStoreExecution() {
return false;
}
public boolean supportsInMemoryExecution() {
return false;
}
public Executor newInMemoryExecutor(ClassMetaData meta, boolean subs) {
throw new InternalException();
}
public Executor newDataStoreExecutor(ClassMetaData meta, boolean subs) {
throw new InternalException();
}
public boolean supportsAbstractExecutors() {
return false;
}
public boolean requiresCandidateType() {
return true;
}
public boolean requiresParameterDeclarations() {
return true;
}
public boolean supportsParameterDeclarations() {
return true;
}
public Object evaluate(Object value, Object ob, Object[] params,
OpenJPAStateManager sm) {
throw new UnsupportedException();
}
/**
* Abstract {@link Executor} that implements most methods as no-ops.
*/
public static abstract class AbstractExecutor
implements Executor {
public Number executeDelete(StoreQuery q, Object[] params) {
return q.getContext().deleteInMemory(q, this, params);
}
public Number executeUpdate(StoreQuery q, Object[] params) {
return q.getContext().updateInMemory(q, this, params);
}
public String[] getDataStoreActions(StoreQuery q, Object[] params,
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;
}
public boolean[] getAscending(StoreQuery q) {
return EMPTY_BOOLEANS;
}
public boolean isPacking(StoreQuery q) {
return false;
}
public String getAlias(StoreQuery q) {
return null;
}
public String[] getProjectionAliases(StoreQuery q) {
return EMPTY_STRINGS;
}
public Class[] getProjectionTypes(StoreQuery q) {
return EMPTY_CLASSES;
}
public ClassMetaData[] getAccessPathMetaDatas(StoreQuery q) {
return EMPTY_METAS;
}
public int getOperation(StoreQuery q) {
return OP_SELECT;
}
public boolean isAggregate(StoreQuery q) {
return false;
}
public boolean hasGrouping(StoreQuery q) {
return false;
}
public LinkedMap getParameterTypes(StoreQuery q) {
return EMPTY_PARAMS;
}
public Class getResultClass(StoreQuery q) {
return null;
}
public Map getUpdates(StoreQuery q) {
return null;
}
}
}

View File

@ -1048,7 +1048,7 @@ public class QueryImpl
int size = 0;
for (Iterator i = ((Collection) o).iterator(); i.hasNext(); size++)
updateInMemory(i.next(), params);
updateInMemory(i.next(), params, q);
return Numbers.valueOf(size);
} catch (OpenJPAException ke) {
throw ke;
@ -1063,12 +1063,13 @@ public class QueryImpl
* @param ob the persistent instance to change
* @param params the parameters passed to the query
*/
private void updateInMemory(Object ob, Object[] params) {
private void updateInMemory(Object ob, Object[] params, StoreQuery q) {
for (Iterator it = getUpdates().entrySet().iterator();
it.hasNext();) {
Map.Entry e = (Map.Entry) it.next();
Path path = (Path) e.getKey();
FieldMetaData fmd = (FieldMetaData) path.last();
OpenJPAStateManager sm = _broker.getStateManager(ob);
Object val;
Object value = e.getValue();
@ -1080,10 +1081,13 @@ public class QueryImpl
} else if (value instanceof Constant) {
val = ((Constant) value).getValue(params);
} else {
throw new UserException(_loc.get("only-update-primitives"));
try {
val = q.evaluate(value, ob, params, sm);
} catch (UnsupportedException e1) {
throw new UserException(_loc.get("fail-to-get-update-value"));
}
}
OpenJPAStateManager sm = _broker.getStateManager(ob);
int i = fmd.getIndex();
PersistenceCapable into = ImplHelper.toPersistenceCapable(ob,
_broker.getConfiguration());

View File

@ -1,322 +1,325 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.openjpa.kernel;
import java.io.Serializable;
import java.util.Iterator;
import java.util.Map;
import org.apache.commons.collections.map.LinkedMap;
import org.apache.openjpa.kernel.exps.AggregateListener;
import org.apache.openjpa.kernel.exps.Constant;
import org.apache.openjpa.kernel.exps.FilterListener;
import org.apache.openjpa.lib.rop.ResultObjectProvider;
import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.meta.FieldMetaData;
/**
* Component that executes queries against the datastore. For
* expression-based queries, consider subclassing
* {@link ExpressionStoreManagerQuery}.
*
* @author Abe White
* @since 0.4.0
*/
public interface StoreQuery
extends QueryOperations, Serializable {
// linkedmap doesn't allow a size of 0, so use 1
public static final LinkedMap EMPTY_PARAMS = new LinkedMap(1, 1F);
public static final ClassMetaData[] EMPTY_METAS = new ClassMetaData[0];
public static final String[] EMPTY_STRINGS = new String[0];
public static final Object[] EMPTY_OBJECTS = new Object[0];
public static final Class[] EMPTY_CLASSES = new Class[0];
public static final boolean[] EMPTY_BOOLEANS = new boolean[0];
/**
* Return the query context that has been set.
*/
public QueryContext getContext();
/**
* Set the current query context. This will be called before use.
*/
public void setContext(QueryContext ctx);
/**
* This is invoked when the user or a facade creates a new query with
* an object that the system does not recognize. Return true if
* the object is recognized by the store, false otherwise.
*/
public boolean setQuery(Object query);
/**
* Return the standard filter listener for the given tag, or null.
*/
public FilterListener getFilterListener(String tag);
/**
* Return the standard filter listener for the given tag, or null.
*/
public AggregateListener getAggregateListener(String tag);
/**
* Create a new key for caching compiled query information. May be null.
*/
public Object newCompilationKey();
/**
* Create a new compilation for this query. May be null.
*/
public Object newCompilation();
/**
* Populate internal data from compilation.
*/
public void populateFromCompilation(Object comp);
/**
* Invalidate any internal compilation state.
*/
public void invalidateCompilation();
/**
* True if this query supports datastore execution, false if it
* can only run in memory.
*/
public boolean supportsDataStoreExecution();
/**
* True if this query supports in-memory execution, false if it
* can only run against the datastore.
*/
public boolean supportsInMemoryExecution();
/**
* Return an executor for in-memory execution of this query.
* Executors must be cachable and thread safe. If this class returns
* true from {@link #supportsAbstractExecutors}, the given metadata
* will always be for the candidate class of this query, or possibly
* null if the candidate class is not itself persistence capable (like
* an interface or abstract base class). Otherwise, the given type will
* be a mapped class.
*
* @param subs whether to include dependent mapped subclasses in the
* results; independent subclasses should never be included
*/
public Executor newInMemoryExecutor(ClassMetaData meta, boolean subs);
/**
* Return an executor for datastore execution of this query.
* Executors must be cachable and thread safe. If this class returns
* true from {@link #supportsAbstractExecutors}, the given metadata
* will always be for the candidate class of this query, or possibly
* null if the candidate class is not itself persistence capable (like
* an interface or abstract base class). Otherwise, the given type will
* be a mapped class.
*
* @param subs whether to include dependent mapped subclasses in the
* results; independent subclasses should never be included
*/
public Executor newDataStoreExecutor(ClassMetaData meta, boolean subs);
/**
* Return true if this query supports execution against abstract or
* interface types. Returns false by default, meaning we will only
* request executors for persistent classes. In this case, we will
* automatically combine the results of the executors for all
* implementing classes if we execute a query for an interface for
* abstract type.
*/
public boolean supportsAbstractExecutors();
/**
* Whether this query requires a candidate class.
*/
public boolean requiresCandidateType();
/**
* Whether this query requires parameters to be declared.
*/
public boolean requiresParameterDeclarations();
/**
* Whether this query supports declared parameters.
*/
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
* {@link #executeQuery} method will be called before other methods,
* though this is not guaranteed.
*
* @author Marc Prud'hommeaux
*/
public static interface Executor {
/**
* Return the result of executing this query with the given parameter
* values. If this query is a projection and this executor does not
* pack results itself, each element of the returned result object
* provider should be an object array containing the projection values.
*
* @param lrs true if the query result should be treated as a
* large result set, assuming the query is not an
* aggregate and does not have grouping
* @see #isPacking
*/
public ResultObjectProvider executeQuery(StoreQuery q, Object[] params,
Range range);
/**
* Deleted the objects that result from the execution of the
* query, retuning the number of objects that were deleted.
*/
public Number executeDelete(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, Object[] 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,
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 <code>orderIndex</code>th ordering
* expression in {@link Query#getOrderingClauses} from the
* given result object. The result object will be an object from
* the result object provider returned from {@link #executeQuery}.
* This method is used when several result lists have to be merged
* in memory. If this exeuctor's parent query supports executors on
* abstract or interface classes, this method will not be used.
*
* @see StoreQuery#supportsAbstractExecutors
*/
public Object getOrderingValue(StoreQuery q, Object[] params,
Object resultObject, int orderIndex);
/**
* Return the ordering direction for all ordering clauses, or empty
* array if none.
*/
public boolean[] getAscending(StoreQuery q);
/**
* Return true if this executor packs projections into the result
* class itself. Executors for query languages that allow projections
* without result clauses must return true and perform the result
* packing themselves.
*/
public boolean isPacking(StoreQuery q);
/**
* If this is not a projection but the candidate results are placed
* into a result class with an alias, return that alias.
*/
public String getAlias(StoreQuery q);
/**
* Return the alias for each projection element, or empty array
* if not a projection.
*/
public String[] getProjectionAliases(StoreQuery q);
/**
* Return the expected types of the projections used by this query,
* or an empty array if not a projection.
*/
public Class[] getProjectionTypes(StoreQuery q);
/**
* Return an array of all persistent classes used in this query, or
* empty array if unknown.
*/
public ClassMetaData[] getAccessPathMetaDatas(StoreQuery q);
/**
* Returns the operation this executor is meant to execute.
*
* @see QueryOperations
*/
public int getOperation(StoreQuery q);
/**
* Return true if the compiled query is an aggregate.
*/
public boolean isAggregate(StoreQuery q);
/**
* Whether the compiled query has grouping.
*/
public boolean hasGrouping(StoreQuery q);
/**
* Return a map of parameter names to types. The returned
* {@link Map#entrySet}'s {@link Iterator} must return values in the
* order in which they were declared or used.
*/
public LinkedMap getParameterTypes(StoreQuery q);
/**
* Returns the result class, if any.
*/
public Class getResultClass(StoreQuery q);
/**
* Return a map of {@link FieldMetaData} to update
* {@link Constant}s, in cases where this query is for a bulk update.
*/
public Map getUpdates (StoreQuery q);
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.openjpa.kernel;
import java.io.Serializable;
import java.util.Iterator;
import java.util.Map;
import org.apache.commons.collections.map.LinkedMap;
import org.apache.openjpa.kernel.exps.AggregateListener;
import org.apache.openjpa.kernel.exps.Constant;
import org.apache.openjpa.kernel.exps.FilterListener;
import org.apache.openjpa.lib.rop.ResultObjectProvider;
import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.meta.FieldMetaData;
/**
* Component that executes queries against the datastore. For
* expression-based queries, consider subclassing
* {@link ExpressionStoreManagerQuery}.
*
* @author Abe White
* @since 0.4.0
*/
public interface StoreQuery
extends QueryOperations, Serializable {
// linkedmap doesn't allow a size of 0, so use 1
public static final LinkedMap EMPTY_PARAMS = new LinkedMap(1, 1F);
public static final ClassMetaData[] EMPTY_METAS = new ClassMetaData[0];
public static final String[] EMPTY_STRINGS = new String[0];
public static final Object[] EMPTY_OBJECTS = new Object[0];
public static final Class[] EMPTY_CLASSES = new Class[0];
public static final boolean[] EMPTY_BOOLEANS = new boolean[0];
/**
* Return the query context that has been set.
*/
public QueryContext getContext();
/**
* Set the current query context. This will be called before use.
*/
public void setContext(QueryContext ctx);
/**
* This is invoked when the user or a facade creates a new query with
* an object that the system does not recognize. Return true if
* the object is recognized by the store, false otherwise.
*/
public boolean setQuery(Object query);
/**
* Return the standard filter listener for the given tag, or null.
*/
public FilterListener getFilterListener(String tag);
/**
* Return the standard filter listener for the given tag, or null.
*/
public AggregateListener getAggregateListener(String tag);
/**
* Create a new key for caching compiled query information. May be null.
*/
public Object newCompilationKey();
/**
* Create a new compilation for this query. May be null.
*/
public Object newCompilation();
/**
* Populate internal data from compilation.
*/
public void populateFromCompilation(Object comp);
/**
* Invalidate any internal compilation state.
*/
public void invalidateCompilation();
/**
* True if this query supports datastore execution, false if it
* can only run in memory.
*/
public boolean supportsDataStoreExecution();
/**
* True if this query supports in-memory execution, false if it
* can only run against the datastore.
*/
public boolean supportsInMemoryExecution();
/**
* Return an executor for in-memory execution of this query.
* Executors must be cachable and thread safe. If this class returns
* true from {@link #supportsAbstractExecutors}, the given metadata
* will always be for the candidate class of this query, or possibly
* null if the candidate class is not itself persistence capable (like
* an interface or abstract base class). Otherwise, the given type will
* be a mapped class.
*
* @param subs whether to include dependent mapped subclasses in the
* results; independent subclasses should never be included
*/
public Executor newInMemoryExecutor(ClassMetaData meta, boolean subs);
/**
* Return an executor for datastore execution of this query.
* Executors must be cachable and thread safe. If this class returns
* true from {@link #supportsAbstractExecutors}, the given metadata
* will always be for the candidate class of this query, or possibly
* null if the candidate class is not itself persistence capable (like
* an interface or abstract base class). Otherwise, the given type will
* be a mapped class.
*
* @param subs whether to include dependent mapped subclasses in the
* results; independent subclasses should never be included
*/
public Executor newDataStoreExecutor(ClassMetaData meta, boolean subs);
/**
* Return true if this query supports execution against abstract or
* interface types. Returns false by default, meaning we will only
* request executors for persistent classes. In this case, we will
* automatically combine the results of the executors for all
* implementing classes if we execute a query for an interface for
* abstract type.
*/
public boolean supportsAbstractExecutors();
/**
* Whether this query requires a candidate class.
*/
public boolean requiresCandidateType();
/**
* Whether this query requires parameters to be declared.
*/
public boolean requiresParameterDeclarations();
/**
* Whether this query supports declared parameters.
*/
public boolean supportsParameterDeclarations();
public Object evaluate(Object value, Object ob, Object[] params,
OpenJPAStateManager sm);
/**
* 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
* {@link #executeQuery} method will be called before other methods,
* though this is not guaranteed.
*
* @author Marc Prud'hommeaux
*/
public static interface Executor {
/**
* Return the result of executing this query with the given parameter
* values. If this query is a projection and this executor does not
* pack results itself, each element of the returned result object
* provider should be an object array containing the projection values.
*
* @param lrs true if the query result should be treated as a
* large result set, assuming the query is not an
* aggregate and does not have grouping
* @see #isPacking
*/
public ResultObjectProvider executeQuery(StoreQuery q, Object[] params,
Range range);
/**
* Deleted the objects that result from the execution of the
* query, retuning the number of objects that were deleted.
*/
public Number executeDelete(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, Object[] 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,
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 <code>orderIndex</code>th ordering
* expression in {@link Query#getOrderingClauses} from the
* given result object. The result object will be an object from
* the result object provider returned from {@link #executeQuery}.
* This method is used when several result lists have to be merged
* in memory. If this exeuctor's parent query supports executors on
* abstract or interface classes, this method will not be used.
*
* @see StoreQuery#supportsAbstractExecutors
*/
public Object getOrderingValue(StoreQuery q, Object[] params,
Object resultObject, int orderIndex);
/**
* Return the ordering direction for all ordering clauses, or empty
* array if none.
*/
public boolean[] getAscending(StoreQuery q);
/**
* Return true if this executor packs projections into the result
* class itself. Executors for query languages that allow projections
* without result clauses must return true and perform the result
* packing themselves.
*/
public boolean isPacking(StoreQuery q);
/**
* If this is not a projection but the candidate results are placed
* into a result class with an alias, return that alias.
*/
public String getAlias(StoreQuery q);
/**
* Return the alias for each projection element, or empty array
* if not a projection.
*/
public String[] getProjectionAliases(StoreQuery q);
/**
* Return the expected types of the projections used by this query,
* or an empty array if not a projection.
*/
public Class[] getProjectionTypes(StoreQuery q);
/**
* Return an array of all persistent classes used in this query, or
* empty array if unknown.
*/
public ClassMetaData[] getAccessPathMetaDatas(StoreQuery q);
/**
* Returns the operation this executor is meant to execute.
*
* @see QueryOperations
*/
public int getOperation(StoreQuery q);
/**
* Return true if the compiled query is an aggregate.
*/
public boolean isAggregate(StoreQuery q);
/**
* Whether the compiled query has grouping.
*/
public boolean hasGrouping(StoreQuery q);
/**
* Return a map of parameter names to types. The returned
* {@link Map#entrySet}'s {@link Iterator} must return values in the
* order in which they were declared or used.
*/
public LinkedMap getParameterTypes(StoreQuery q);
/**
* Returns the result class, if any.
*/
public Class getResultClass(StoreQuery q);
/**
* Return a map of {@link FieldMetaData} to update
* {@link Constant}s, in cases where this query is for a bulk update.
*/
public Map getUpdates (StoreQuery q);
}
}