Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/**********************************************************************
Copyright (c) 2009 Andy Jefferson and others. All rights reserved.
Licensed 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.
Contributors:
...
**********************************************************************/
package org.datanucleus.store.rdbms.query;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import org.datanucleus.ExecutionContext;
import org.datanucleus.FetchPlanForClass;
import org.datanucleus.exceptions.NucleusDataStoreException;
import org.datanucleus.exceptions.NucleusException;
import org.datanucleus.exceptions.NucleusUserException;
import org.datanucleus.metadata.AbstractClassMetaData;
import org.datanucleus.metadata.AbstractMemberMetaData;
import org.datanucleus.metadata.InheritanceStrategy;
import org.datanucleus.metadata.QueryLanguage;
import org.datanucleus.metadata.RelationType;
import org.datanucleus.store.StoreManager;
import org.datanucleus.store.connection.ManagedConnection;
import org.datanucleus.store.connection.ManagedConnectionResourceListener;
import org.datanucleus.store.rdbms.mapping.java.AbstractContainerMapping;
import org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping;
import org.datanucleus.store.query.AbstractJPQLQuery;
import org.datanucleus.store.query.CandidateIdsQueryResult;
import org.datanucleus.store.query.QueryInterruptedException;
import org.datanucleus.store.query.QueryManager;
import org.datanucleus.store.query.QueryResult;
import org.datanucleus.store.query.QueryTimeoutException;
import org.datanucleus.store.query.QueryUtils;
import org.datanucleus.store.query.expression.Expression;
import org.datanucleus.store.query.inmemory.JPQLInMemoryEvaluator;
import org.datanucleus.store.rdbms.RDBMSPropertyNames;
import org.datanucleus.store.rdbms.RDBMSStoreManager;
import org.datanucleus.store.rdbms.SQLController;
import org.datanucleus.store.rdbms.adapter.DatastoreAdapter;
import org.datanucleus.store.rdbms.query.RDBMSQueryCompilation.StatementCompilation;
import org.datanucleus.store.rdbms.scostore.IteratorStatement;
import org.datanucleus.store.rdbms.sql.DeleteStatement;
import org.datanucleus.store.rdbms.sql.InsertStatement;
import org.datanucleus.store.rdbms.sql.SQLStatement;
import org.datanucleus.store.rdbms.sql.SQLStatementHelper;
import org.datanucleus.store.rdbms.sql.SQLTable;
import org.datanucleus.store.rdbms.sql.SQLJoin.JoinType;
import org.datanucleus.store.rdbms.sql.SelectStatement;
import org.datanucleus.store.rdbms.sql.SelectStatementGenerator;
import org.datanucleus.store.rdbms.sql.UpdateStatement;
import org.datanucleus.store.rdbms.sql.expression.ColumnExpression;
import org.datanucleus.store.rdbms.sql.expression.SQLExpression;
import org.datanucleus.store.rdbms.table.DatastoreClass;
import org.datanucleus.store.schema.table.SurrogateColumnType;
import org.datanucleus.store.types.SCOUtils;
import org.datanucleus.util.ClassUtils;
import org.datanucleus.util.Localiser;
import org.datanucleus.util.NucleusLogger;
import org.datanucleus.util.StringUtils;
/**
* RDBMS representation of a JPQL query for use by DataNucleus.
* The query can be specified via method calls, or via a single-string form.
* This implementation uses the generic query compilation in "org.datanucleus.query".
* There are the following main ways of running a query here
*
*
Totally in the datastore (no candidate collection specified, and no in-memory eval).
*
Totally in-memory (candidate collection specified, and in-memory eval)
*
Retrieve candidates from datastore (no candidate collection), and evaluate in-memory
*
*/
public class JPQLQuery extends AbstractJPQLQuery
{
private static final long serialVersionUID = -3735379324740714088L;
/** Extension for whether to convert "== ?" with null parameter to "IS NULL". Defaults to false to comply with JPA spec 4.11. */
public static final String EXTENSION_USE_IS_NULL_WHEN_EQUALS_NULL_PARAM = "datanucleus.query.useIsNullWhenEqualsNullParameter".toLowerCase();
/** Extension to add NOWAIT when using FOR UPDATE (when supported). */
public static final String EXTENSION_FOR_UPDATE_NOWAIT = "datanucleus.query.forUpdateNowait".toLowerCase();
/** Extension to not apply a discriminator restriction on the candidate of the query. */
public static final String EXTENSION_CANDIDATE_DONT_RESTRICT_DISCRIMINATOR = "datanucleus.query.dontRestrictDiscriminator".toLowerCase();
/** Extension to include soft-deleted objects in any results. */
public static final String EXTENSION_INCLUDE_SOFT_DELETES = "datanucleus.query.includeSoftDeletes".toLowerCase();
/** Extension to define the JOIN TYPE to use when navigating single-valued relations, when part of the filter. */
public static final String EXTENSION_NAVIGATION_JOIN_TYPE_FILTER = "datanucleus.query.jpql.navigationJoinTypeForFilter".toLowerCase();
/** Extension to define the JOIN TYPE to use when navigating single-valued relations. */
public static final String EXTENSION_NAVIGATION_JOIN_TYPE = "datanucleus.query.jpql.navigationJoinType".toLowerCase();
/** The compilation of the query for this datastore. Not applicable if totally in-memory. */
protected transient RDBMSQueryCompilation datastoreCompilation;
boolean statementReturnsEmpty = false;
/**
* Constructs a new query instance that uses the given object manager.
* @param storeMgr StoreManager for this query
* @param ec execution context
*/
public JPQLQuery(StoreManager storeMgr, ExecutionContext ec)
{
this(storeMgr, ec, (JPQLQuery) null);
}
/**
* Constructs a new query instance having the same criteria as the given query.
* @param storeMgr StoreManager for this query
* @param ec execution context
* @param q The query from which to copy criteria.
*/
public JPQLQuery(StoreManager storeMgr, ExecutionContext ec, JPQLQuery q)
{
super(storeMgr, ec, q);
}
/**
* Constructor for a JPQL query where the query is specified using the "Single-String" format.
* @param storeMgr StoreManager for this query
* @param ec The ExecutionContext
* @param query The single-string query form
*/
public JPQLQuery(StoreManager storeMgr, ExecutionContext ec, String query)
{
super(storeMgr, ec, query);
}
@Override
public void setImplicitParameter(int position, Object value)
{
if (datastoreCompilation != null && !datastoreCompilation.isPrecompilable())
{
// Force recompile since parameter value set and not compilable without parameter values
datastoreCompilation = null;
}
super.setImplicitParameter(position, value);
}
@Override
public void setImplicitParameter(String name, Object value)
{
if (datastoreCompilation != null && !datastoreCompilation.isPrecompilable())
{
// Force recompile since parameter value set and not compilable without parameter values
datastoreCompilation = null;
}
super.setImplicitParameter(name, value);
}
/**
* Utility to remove any previous compilation of this Query.
*/
protected void discardCompiled()
{
super.discardCompiled();
datastoreCompilation = null;
}
/**
* Method to return if the query is compiled.
* @return Whether it is compiled
*/
protected boolean isCompiled()
{
if (candidateCollection != null)
{
// Don't need datastore compilation here since evaluating in-memory
return compilation != null;
}
// Need both to be present to say "compiled"
if (compilation == null || datastoreCompilation == null)
{
return false;
}
if (!datastoreCompilation.isPrecompilable())
{
NucleusLogger.GENERAL.info("Query compiled but not precompilable so ditching datastore compilation");
datastoreCompilation = null;
return false;
}
return true;
}
/**
* Method to get key for query cache
* @return The cache key
*/
protected String getQueryCacheKey()
{
if (getSerializeRead() != null && getSerializeRead())
{
return super.getQueryCacheKey() + " FOR UPDATE";
}
return super.getQueryCacheKey();
}
/**
* Method to compile the JPQL query.
* Uses the superclass to compile the generic query populating the "compilation", and then generates
* the datastore-specific "datastoreCompilation".
* @param parameterValues Map of param values keyed by param name (if available at compile time)
*/
protected synchronized void compileInternal(Map parameterValues)
{
if (isCompiled())
{
return;
}
if (getExtension(EXTENSION_INCLUDE_SOFT_DELETES) != null)
{
// If using an extension that can change the datastore query then evict any existing compilation
QueryManager qm = getQueryManager();
qm.removeQueryCompilation(QueryLanguage.JPQL.name(), getQueryCacheKey());
}
// Compile the generic query expressions
super.compileInternal(parameterValues);
boolean inMemory = evaluateInMemory();
if (candidateCollection != null)
{
// Everything done in-memory so just return now (don't need datastore compilation)
// TODO Maybe apply the result class checks ?
return;
}
if (candidateClass == null || candidateClassName == null)
{
candidateClass = compilation.getCandidateClass();
candidateClassName = candidateClass.getName();
}
// Create the SQL statement, and its result/parameter definitions
RDBMSStoreManager storeMgr = (RDBMSStoreManager)getStoreManager();
QueryManager qm = getQueryManager();
String datastoreKey = storeMgr.getQueryCacheKey();
String queryCacheKey = getQueryCacheKey();
if (useCaching() && queryCacheKey != null)
{
// Check if we have any parameters set to null, since this can invalidate a datastore compilation
// e.g " field == :val" can be "COL IS NULL" or "COL = "
boolean nullParameter = false;
if (parameterValues != null)
{
Iterator iter = parameterValues.values().iterator();
while (iter.hasNext())
{
Object val = iter.next();
if (val == null)
{
nullParameter = true;
break;
}
}
}
if (!nullParameter)
{
// Allowing caching so try to find compiled (datastore) query
datastoreCompilation = (RDBMSQueryCompilation)qm.getDatastoreQueryCompilation(datastoreKey, getLanguage(), queryCacheKey);
if (datastoreCompilation != null)
{
// Cached compilation exists for this datastore so reuse it
return;
}
}
}
// No cached compilation for this query in this datastore so compile it
AbstractClassMetaData acmd = getCandidateClassMetaData();
if (type == QueryType.BULK_INSERT)
{
datastoreCompilation = new RDBMSQueryCompilation();
compileQueryInsert(parameterValues, acmd);
}
else if (type == QueryType.BULK_UPDATE)
{
datastoreCompilation = new RDBMSQueryCompilation();
compileQueryUpdate(parameterValues, acmd);
}
else if (type == QueryType.BULK_DELETE)
{
datastoreCompilation = new RDBMSQueryCompilation();
compileQueryDelete(parameterValues, acmd);
}
else
{
datastoreCompilation = new RDBMSQueryCompilation();
if (inMemory)
{
// Generate statement to just retrieve all candidate objects for later processing
compileQueryToRetrieveCandidates(parameterValues, acmd);
}
else
{
// Generate statement to perform the full query in the datastore
compileQueryFull(parameterValues, acmd);
if (result != null)
{
StatementResultMapping resultMapping = datastoreCompilation.getResultDefinition();
for (int i=0;i 1)
{
// Invalid number of result expressions
throw new NucleusUserException(Localiser.msg("021201", resultClass.getName()));
}
Object stmtMap = resultMapping.getMappingForResultExpression(0);
// TODO Handle StatementNewObjectMapping
StatementMappingIndex idx = (StatementMappingIndex)stmtMap;
Class exprType = idx.getMapping().getJavaType();
boolean typeConsistent = false;
if (exprType == resultClass)
{
typeConsistent = true;
}
else if (exprType.isPrimitive())
{
Class resultClassPrimitive = ClassUtils.getPrimitiveTypeForType(resultClass);
if (resultClassPrimitive == exprType)
{
typeConsistent = true;
}
}
if (!typeConsistent)
{
// Inconsistent expression type not matching the result class type
throw new NucleusUserException(Localiser.msg("021202", resultClass.getName(), exprType));
}
}
else if (QueryUtils.resultClassIsUserType(resultClass.getName()))
{
// Check for valid constructor (either using param types, or using default ctr)
Class[] ctrTypes = new Class[resultMapping.getNumberOfResultExpressions()];
for (int i=0;i 0)
{
hasParams = true;
}
if (!datastoreCompilation.isPrecompilable() || (datastoreCompilation.getSQL().indexOf('?') < 0 && hasParams))
{
// Some parameters had their clauses evaluated during compilation so the query didn't gain any parameters, so don't cache it
NucleusLogger.QUERY.debug(Localiser.msg("021075"));
}
else
{
if (!statementReturnsEmpty && useCaching() && queryCacheKey != null)
{
qm.addDatastoreQueryCompilation(datastoreKey, getLanguage(), queryCacheKey, datastoreCompilation);
}
}
}
}
/**
* Convenience accessor for the SQL to invoke in the datastore for this query.
* @return The SQL.
*/
public String getSQL()
{
if (datastoreCompilation != null)
{
return datastoreCompilation.getSQL();
}
return null;
}
protected Object performExecute(Map parameters)
{
if (statementReturnsEmpty)
{
return Collections.EMPTY_LIST;
}
if (candidateCollection != null)
{
// Supplied collection of instances, so evaluate in-memory
if (candidateCollection.isEmpty())
{
return Collections.EMPTY_LIST;
}
List candidates = new ArrayList(candidateCollection);
return new JPQLInMemoryEvaluator(this, candidates, compilation, parameters, clr).execute(true, true, true, true, true);
}
else if (type == QueryType.SELECT)
{
// Query results are cached, so return those
List