Search in sources :

Example 1 with QueryManager

use of org.datanucleus.store.query.QueryManager in project datanucleus-rdbms by datanucleus.

the class JDOQLQuery method compileInternal.

/**
 * Method to compile the JDOQL 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(Query.LANGUAGE_JDOQL, getQueryCacheKey());
    }
    // Compile the generic query expressions
    super.compileInternal(parameterValues);
    boolean inMemory = evaluateInMemory();
    if (candidateCollection != null && inMemory) {
        // TODO Maybe apply the result class checks ?
        return;
    }
    // Create the SQL statement, and its result/parameter definitions
    RDBMSStoreManager storeMgr = (RDBMSStoreManager) getStoreManager();
    if (candidateClass == null) {
        throw new NucleusUserException(Localiser.msg("021009", candidateClassName));
    }
    // Make sure any persistence info is loaded
    ec.hasPersistenceInformationForClass(candidateClass);
    if (parameterValues != null) {
        // Check for null values on primitive parameters
        Set paramNames = parameterValues.entrySet();
        Iterator<Map.Entry> iter = paramNames.iterator();
        while (iter.hasNext()) {
            Map.Entry entry = iter.next();
            Object paramName = entry.getKey();
            if (paramName instanceof String) {
                Symbol sym = compilation.getSymbolTable().getSymbol((String) paramName);
                Object value = entry.getValue();
                if (value == null) {
                    // so omit the check for that case
                    if (sym != null && sym.getValueType() != null && sym.getValueType().isPrimitive()) {
                        throw new NucleusUserException(Localiser.msg("021117", paramName, sym.getValueType().getName()));
                    }
                }
            }
        }
    }
    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 = <val>"
        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
                setResultDistinct(compilation.getResultDistinct());
                return;
            }
        }
    }
    // Compile the query for the datastore since not cached
    AbstractClassMetaData acmd = getCandidateClassMetaData();
    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();
        synchronized (datastoreCompilation) {
            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) {
                    // Check existence of invalid selections in the result
                    StatementResultMapping resultMapping = datastoreCompilation.getResultDefinition();
                    for (int i = 0; i < resultMapping.getNumberOfResultExpressions(); i++) {
                        Object stmtMap = resultMapping.getMappingForResultExpression(i);
                        if (stmtMap instanceof StatementMappingIndex) {
                            StatementMappingIndex idx = (StatementMappingIndex) stmtMap;
                            AbstractMemberMetaData mmd = idx.getMapping().getMemberMetaData();
                            if (mmd != null) {
                                if (idx.getMapping() instanceof AbstractContainerMapping && idx.getMapping().getNumberOfColumnMappings() != 1) {
                                    throw new NucleusUserException(Localiser.msg("021213"));
                                }
                            }
                        }
                    }
                    if (resultClass != null) {
                        if (// Don't apply checks when user has specified the default (no result class)
                        !resultClass.getName().equals(Object[].class.getName())) {
                            // Check validity of resultClass for the result (PrivilegedAction since uses reflection)
                            AccessController.doPrivileged(new PrivilegedAction() {

                                public Object run() {
                                    // Check that this class has the necessary constructor/setters/fields to be used
                                    StatementResultMapping resultMapping = datastoreCompilation.getResultDefinition();
                                    if (QueryUtils.resultClassIsSimple(resultClass.getName())) {
                                        if (resultMapping.getNumberOfResultExpressions() > 1) {
                                            // Invalid number of result expressions
                                            throw new NucleusUserException(Localiser.msg("021201", resultClass.getName()));
                                        }
                                        Object stmtMap = resultMapping.getMappingForResultExpression(0);
                                        if (stmtMap instanceof StatementMappingIndex) {
                                            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 {
                                            // TODO Handle StatementNewObjectMapping
                                            throw new NucleusUserException("Don't support result clause of " + result + " with resultClass of " + resultClass.getName());
                                        }
                                    } 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 < ctrTypes.length; i++) {
                                            Object stmtMap = resultMapping.getMappingForResultExpression(i);
                                            if (stmtMap instanceof StatementMappingIndex) {
                                                ctrTypes[i] = ((StatementMappingIndex) stmtMap).getMapping().getJavaType();
                                            } else if (stmtMap instanceof StatementNewObjectMapping) {
                                            // TODO Handle this
                                            }
                                        }
                                        Constructor ctr = ClassUtils.getConstructorWithArguments(resultClass, ctrTypes);
                                        if (ctr == null && !ClassUtils.hasDefaultConstructor(resultClass)) {
                                            // No valid constructor found!
                                            throw new NucleusUserException(Localiser.msg("021205", resultClass.getName()));
                                        } else if (ctr == null) {
                                            // We are using default constructor, so check the types of the result expressions for means of input
                                            for (int i = 0; i < resultMapping.getNumberOfResultExpressions(); i++) {
                                                Object stmtMap = resultMapping.getMappingForResultExpression(i);
                                                if (stmtMap instanceof StatementMappingIndex) {
                                                    StatementMappingIndex mapIdx = (StatementMappingIndex) stmtMap;
                                                    AbstractMemberMetaData mmd = mapIdx.getMapping().getMemberMetaData();
                                                    String fieldName = mapIdx.getColumnAlias();
                                                    Class fieldType = mapIdx.getMapping().getJavaType();
                                                    if (fieldName == null && mmd != null) {
                                                        fieldName = mmd.getName();
                                                    }
                                                    if (fieldName != null) {
                                                        // Check for the field of that name in the result class
                                                        Class resultFieldType = null;
                                                        boolean publicField = true;
                                                        try {
                                                            Field fld = resultClass.getDeclaredField(fieldName);
                                                            resultFieldType = fld.getType();
                                                            // Check the type of the field
                                                            if (!ClassUtils.typesAreCompatible(fieldType, resultFieldType) && !ClassUtils.typesAreCompatible(resultFieldType, fieldType)) {
                                                                throw new NucleusUserException(Localiser.msg("021211", fieldName, fieldType.getName(), resultFieldType.getName()));
                                                            }
                                                            if (!Modifier.isPublic(fld.getModifiers())) {
                                                                publicField = false;
                                                            }
                                                        } catch (NoSuchFieldException nsfe) {
                                                            publicField = false;
                                                        }
                                                        // Check for a public set method
                                                        if (!publicField) {
                                                            Method setMethod = QueryUtils.getPublicSetMethodForFieldOfResultClass(resultClass, fieldName, resultFieldType);
                                                            if (setMethod == null) {
                                                                // No setter, so check for a public put(Object, Object) method
                                                                Method putMethod = QueryUtils.getPublicPutMethodForResultClass(resultClass);
                                                                if (putMethod == null) {
                                                                    throw new NucleusUserException(Localiser.msg("021212", resultClass.getName(), fieldName));
                                                                }
                                                            }
                                                        }
                                                    }
                                                } else if (stmtMap instanceof StatementNewObjectMapping) {
                                                // TODO Handle this
                                                }
                                            }
                                        }
                                    }
                                    return null;
                                }
                            });
                        }
                    }
                }
            }
            boolean hasParams = false;
            if (explicitParameters != null) {
                hasParams = true;
            } else if (parameterValues != null && parameterValues.size() > 0) {
                hasParams = true;
            }
            if (!statementReturnsEmpty && queryCacheKey != null && useCaching()) {
                // TODO Allow caching of queries with subqueries
                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 {
                    qm.addDatastoreQueryCompilation(datastoreKey, getLanguage(), queryCacheKey, datastoreCompilation);
                }
            }
        }
    }
}
Also used : ResultSet(java.sql.ResultSet) Set(java.util.Set) HashSet(java.util.HashSet) Symbol(org.datanucleus.store.query.compiler.Symbol) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) Field(java.lang.reflect.Field) PrivilegedAction(java.security.PrivilegedAction) Iterator(java.util.Iterator) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) Constructor(java.lang.reflect.Constructor) Method(java.lang.reflect.Method) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) AbstractContainerMapping(org.datanucleus.store.rdbms.mapping.java.AbstractContainerMapping) QueryManager(org.datanucleus.store.query.QueryManager) FetchPlanForClass(org.datanucleus.FetchPlanForClass) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) Map(java.util.Map) HashMap(java.util.HashMap) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Example 2 with QueryManager

use of org.datanucleus.store.query.QueryManager in project datanucleus-rdbms by datanucleus.

the class JPQLQuery method compileInternal.

/**
 * 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(Query.LANGUAGE_JPQL, getQueryCacheKey());
    }
    // Compile the generic query expressions
    super.compileInternal(parameterValues);
    boolean inMemory = evaluateInMemory();
    if (candidateCollection != null) {
        // 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 = <val>"
        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 < resultMapping.getNumberOfResultExpressions(); i++) {
                    Object stmtMap = resultMapping.getMappingForResultExpression(i);
                    if (stmtMap instanceof StatementMappingIndex) {
                        StatementMappingIndex idx = (StatementMappingIndex) stmtMap;
                        AbstractMemberMetaData mmd = idx.getMapping().getMemberMetaData();
                        if (mmd != null) {
                            if (idx.getMapping() instanceof AbstractContainerMapping && idx.getMapping().getNumberOfColumnMappings() != 1) {
                                throw new NucleusUserException(Localiser.msg("021213"));
                            }
                        }
                    }
                }
            }
        }
        if (resultClass != null && result != null) {
            // Do as PrivilegedAction since uses reflection
            AccessController.doPrivileged(new PrivilegedAction() {

                public Object run() {
                    // Check that this class has the necessary constructor/setters/fields to be used
                    StatementResultMapping resultMapping = datastoreCompilation.getResultDefinition();
                    if (QueryUtils.resultClassIsSimple(resultClass.getName())) {
                        if (resultMapping.getNumberOfResultExpressions() > 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 < ctrTypes.length; i++) {
                            Object stmtMap = resultMapping.getMappingForResultExpression(i);
                            if (stmtMap instanceof StatementMappingIndex) {
                                ctrTypes[i] = ((StatementMappingIndex) stmtMap).getMapping().getJavaType();
                            } else if (stmtMap instanceof StatementNewObjectMapping) {
                            // TODO Handle this
                            }
                        }
                        Constructor ctr = ClassUtils.getConstructorWithArguments(resultClass, ctrTypes);
                        if (ctr == null && !ClassUtils.hasDefaultConstructor(resultClass)) {
                            // No valid constructor found!
                            throw new NucleusUserException(Localiser.msg("021205", resultClass.getName()));
                        } else if (ctr == null) {
                            // We are using default constructor, so check the types of the result expressions for means of input
                            for (int i = 0; i < resultMapping.getNumberOfResultExpressions(); i++) {
                                Object stmtMap = resultMapping.getMappingForResultExpression(i);
                                if (stmtMap instanceof StatementMappingIndex) {
                                    StatementMappingIndex mapIdx = (StatementMappingIndex) stmtMap;
                                    AbstractMemberMetaData mmd = mapIdx.getMapping().getMemberMetaData();
                                    String fieldName = mapIdx.getColumnAlias();
                                    Class fieldType = mapIdx.getMapping().getJavaType();
                                    if (fieldName == null && mmd != null) {
                                        fieldName = mmd.getName();
                                    }
                                    if (fieldName != null) {
                                        // Check for the field of that name in the result class
                                        Class resultFieldType = null;
                                        boolean publicField = true;
                                        try {
                                            Field fld = resultClass.getDeclaredField(fieldName);
                                            resultFieldType = fld.getType();
                                            // Check the type of the field
                                            if (!ClassUtils.typesAreCompatible(fieldType, resultFieldType) && !ClassUtils.typesAreCompatible(resultFieldType, fieldType)) {
                                                throw new NucleusUserException(Localiser.msg("021211", fieldName, fieldType.getName(), resultFieldType.getName()));
                                            }
                                            if (!Modifier.isPublic(fld.getModifiers())) {
                                                publicField = false;
                                            }
                                        } catch (NoSuchFieldException nsfe) {
                                            publicField = false;
                                        }
                                        // Check for a public set method
                                        if (!publicField) {
                                            Method setMethod = QueryUtils.getPublicSetMethodForFieldOfResultClass(resultClass, fieldName, resultFieldType);
                                            if (setMethod == null) {
                                                // No setter, so check for a public put(Object, Object) method
                                                Method putMethod = QueryUtils.getPublicPutMethodForResultClass(resultClass);
                                                if (putMethod == null) {
                                                    throw new NucleusUserException(Localiser.msg("021212", resultClass.getName(), fieldName));
                                                }
                                            }
                                        }
                                    }
                                } else if (stmtMap instanceof StatementNewObjectMapping) {
                                // TODO Handle this
                                }
                            }
                        }
                    }
                    return null;
                }
            });
        }
        boolean hasParams = false;
        if (explicitParameters != null) {
            hasParams = true;
        } else if (parameterValues != null && parameterValues.size() > 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);
            }
        }
    }
}
Also used : NucleusUserException(org.datanucleus.exceptions.NucleusUserException) Constructor(java.lang.reflect.Constructor) Method(java.lang.reflect.Method) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) Field(java.lang.reflect.Field) PrivilegedAction(java.security.PrivilegedAction) AbstractContainerMapping(org.datanucleus.store.rdbms.mapping.java.AbstractContainerMapping) QueryManager(org.datanucleus.store.query.QueryManager) Iterator(java.util.Iterator) FetchPlanForClass(org.datanucleus.FetchPlanForClass) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Aggregations

Constructor (java.lang.reflect.Constructor)2 Field (java.lang.reflect.Field)2 Method (java.lang.reflect.Method)2 PrivilegedAction (java.security.PrivilegedAction)2 Iterator (java.util.Iterator)2 FetchPlanForClass (org.datanucleus.FetchPlanForClass)2 NucleusUserException (org.datanucleus.exceptions.NucleusUserException)2 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)2 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)2 QueryManager (org.datanucleus.store.query.QueryManager)2 RDBMSStoreManager (org.datanucleus.store.rdbms.RDBMSStoreManager)2 AbstractContainerMapping (org.datanucleus.store.rdbms.mapping.java.AbstractContainerMapping)2 DatastoreClass (org.datanucleus.store.rdbms.table.DatastoreClass)2 ResultSet (java.sql.ResultSet)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 Map (java.util.Map)1 Set (java.util.Set)1 Symbol (org.datanucleus.store.query.compiler.Symbol)1