Search in sources :

Example 11 with AbstractClassMetaData

use of org.datanucleus.metadata.AbstractClassMetaData in project datanucleus-rdbms by datanucleus.

the class SQLQuery method compileInternal.

/**
 * Verify the elements of the query and provide a hint to the query to prepare and optimize an execution plan.
 */
public void compileInternal(Map parameterValues) {
    if (isCompiled) {
        return;
    }
    // Default to using the users SQL direct with no substitution of params etc
    compiledSQL = inputSQL;
    if (candidateClass != null && getType() == QueryType.SELECT) {
        // Perform any sanity checking of input for SELECT queries
        RDBMSStoreManager storeMgr = (RDBMSStoreManager) getStoreManager();
        ClassLoaderResolver clr = ec.getClassLoaderResolver();
        AbstractClassMetaData cmd = ec.getMetaDataManager().getMetaDataForClass(candidateClass, clr);
        if (cmd == null) {
            throw new ClassNotPersistableException(candidateClass.getName());
        }
        if (cmd.getPersistableSuperclass() != null) {
        // throw new PersistentSuperclassNotAllowedException(candidateClass.getName());
        }
        if (getResultClass() == null) {
            // Check the presence of the required columns (id, version, discriminator) in the candidate class
            // Skip "SELECT "
            String selections = stripComments(compiledSQL.trim()).substring(7);
            int fromStart = selections.indexOf("FROM");
            if (fromStart == -1) {
                fromStart = selections.indexOf("from");
            }
            selections = selections.substring(0, fromStart).trim();
            String[] selectedColumns = StringUtils.split(selections, ",");
            if (selectedColumns == null || selectedColumns.length == 0) {
                throw new NucleusUserException(Localiser.msg("059003", compiledSQL));
            }
            if (selectedColumns.length == 1 && selectedColumns[0].trim().equals("*")) {
            // SQL Query using * so just end the checking since all possible columns will be selected
            } else {
                // Generate id column field information for later checking the id is present
                DatastoreClass table = storeMgr.getDatastoreClass(candidateClass.getName(), clr);
                PersistableMapping idMapping = (PersistableMapping) table.getIdMapping();
                String[] idColNames = new String[idMapping.getNumberOfDatastoreMappings()];
                boolean[] idColMissing = new boolean[idMapping.getNumberOfDatastoreMappings()];
                for (int i = 0; i < idMapping.getNumberOfDatastoreMappings(); i++) {
                    idColNames[i] = idMapping.getDatastoreMapping(i).getColumn().getIdentifier().toString();
                    idColMissing[i] = true;
                }
                // Generate discriminator/version information for later checking they are present
                JavaTypeMapping discrimMapping = table.getSurrogateMapping(SurrogateColumnType.DISCRIMINATOR, false);
                String discriminatorColName = (discrimMapping != null) ? discrimMapping.getDatastoreMapping(0).getColumn().getIdentifier().toString() : null;
                JavaTypeMapping versionMapping = table.getSurrogateMapping(SurrogateColumnType.VERSION, false);
                String versionColName = (versionMapping != null) ? versionMapping.getDatastoreMapping(0).getColumn().getIdentifier().toString() : null;
                boolean discrimMissing = (discriminatorColName != null);
                boolean versionMissing = (versionColName != null);
                // Go through the selected fields and check the existence of id, version, discriminator cols
                DatastoreAdapter dba = storeMgr.getDatastoreAdapter();
                final AbstractClassMetaData candidateCmd = ec.getMetaDataManager().getMetaDataForClass(candidateClass, clr);
                for (int i = 0; i < selectedColumns.length; i++) {
                    String colName = selectedColumns[i].trim();
                    if (colName.indexOf(" AS ") > 0) {
                        // Allow for user specification of "XX.YY AS ZZ"
                        colName = colName.substring(colName.indexOf(" AS ") + 4).trim();
                    } else if (colName.indexOf(" as ") > 0) {
                        // Allow for user specification of "XX.YY as ZZ"
                        colName = colName.substring(colName.indexOf(" as ") + 4).trim();
                    }
                    if (candidateCmd.getIdentityType() == IdentityType.DATASTORE) {
                        // Check for existence of id column, allowing for any RDBMS using quoted identifiers
                        if (SQLQuery.columnNamesAreTheSame(dba, idColNames[0], colName)) {
                            idColMissing[0] = false;
                        }
                    } else if (candidateCmd.getIdentityType() == IdentityType.APPLICATION) {
                        for (int j = 0; j < idColNames.length; j++) {
                            // Check for existence of id column, allowing for any RDBMS using quoted identifiers
                            if (SQLQuery.columnNamesAreTheSame(dba, idColNames[j], colName)) {
                                idColMissing[j] = false;
                            }
                        }
                    }
                    if (discrimMissing && SQLQuery.columnNamesAreTheSame(dba, discriminatorColName, colName)) {
                        discrimMissing = false;
                    } else if (versionMissing && SQLQuery.columnNamesAreTheSame(dba, versionColName, colName)) {
                        versionMissing = false;
                    }
                }
                if (discrimMissing) {
                    throw new NucleusUserException(Localiser.msg("059014", compiledSQL, candidateClass.getName(), discriminatorColName));
                }
                if (versionMissing) {
                    throw new NucleusUserException(Localiser.msg("059015", compiledSQL, candidateClass.getName(), versionColName));
                }
                for (int i = 0; i < idColMissing.length; i++) {
                    if (idColMissing[i]) {
                        throw new NucleusUserException(Localiser.msg("059013", compiledSQL, candidateClass.getName(), idColNames[i]));
                    }
                }
            }
        }
    }
    if (NucleusLogger.QUERY.isDebugEnabled()) {
        NucleusLogger.QUERY.debug(Localiser.msg("059012", compiledSQL));
    }
    isCompiled = true;
}
Also used : JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) PersistableMapping(org.datanucleus.store.rdbms.mapping.java.PersistableMapping) DatastoreAdapter(org.datanucleus.store.rdbms.adapter.DatastoreAdapter) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) ClassNotPersistableException(org.datanucleus.exceptions.ClassNotPersistableException)

Example 12 with AbstractClassMetaData

use of org.datanucleus.metadata.AbstractClassMetaData 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("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().getNumberOfDatastoreMappings() != 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.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 13 with AbstractClassMetaData

use of org.datanucleus.metadata.AbstractClassMetaData in project datanucleus-rdbms by datanucleus.

the class JDOQLQuery method performExecute.

protected Object performExecute(Map parameters) {
    if (statementReturnsEmpty) {
        return Collections.EMPTY_LIST;
    }
    boolean inMemory = evaluateInMemory();
    if (candidateCollection != null) {
        // Supplied collection of instances, so evaluate in-memory
        if (candidateCollection.isEmpty()) {
            return Collections.EMPTY_LIST;
        } else if (inMemory) {
            return new JDOQLInMemoryEvaluator(this, new ArrayList(candidateCollection), compilation, parameters, clr).execute(true, true, true, true, true);
        }
    } else if (type == QueryType.SELECT) {
        // Query results are cached, so return those
        List<Object> cachedResults = getQueryManager().getQueryResult(this, parameters);
        if (cachedResults != null) {
            return new CandidateIdsQueryResult(this, cachedResults);
        }
    }
    Object results = null;
    RDBMSStoreManager storeMgr = (RDBMSStoreManager) getStoreManager();
    ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec);
    try {
        // Execute the query
        long startTime = System.currentTimeMillis();
        if (NucleusLogger.QUERY.isDebugEnabled()) {
            NucleusLogger.QUERY.debug(Localiser.msg("021046", getLanguage(), getSingleStringQuery(), null));
        }
        AbstractClassMetaData acmd = ec.getMetaDataManager().getMetaDataForClass(candidateClass, clr);
        SQLController sqlControl = storeMgr.getSQLController();
        PreparedStatement ps = null;
        try {
            if (type == QueryType.SELECT) {
                // Create PreparedStatement and apply parameters, result settings etc
                ps = RDBMSQueryUtils.getPreparedStatementForQuery(mconn, datastoreCompilation.getSQL(), this);
                SQLStatementHelper.applyParametersToStatement(ps, ec, datastoreCompilation.getStatementParameters(), datastoreCompilation.getParameterNameByPosition(), parameters);
                RDBMSQueryUtils.prepareStatementForExecution(ps, this, true);
                registerTask(ps);
                ResultSet rs = null;
                try {
                    rs = sqlControl.executeStatementQuery(ec, mconn, toString(), ps);
                } finally {
                    deregisterTask();
                }
                AbstractRDBMSQueryResult qr = null;
                try {
                    if (inMemory) {
                        // IN-MEMORY EVALUATION
                        ResultObjectFactory rof = new PersistentClassROF(ec, rs, ignoreCache, datastoreCompilation.getResultDefinitionForClass(), acmd, candidateClass);
                        // Just instantiate the candidates for later in-memory processing
                        // TODO Use a queryResult rather than an ArrayList so we load when required
                        List candidates = new ArrayList();
                        while (rs.next()) {
                            candidates.add(rof.getObject());
                        }
                        // Perform in-memory filter/result/order etc
                        results = new JDOQLInMemoryEvaluator(this, candidates, compilation, parameters, clr).execute(true, true, true, true, true);
                    } else {
                        // IN-DATASTORE EVALUATION
                        ResultObjectFactory rof = null;
                        if (result != null) {
                            // Each result row is of a result type
                            rof = new ResultClassROF(ec, rs, ignoreCache, resultClass, datastoreCompilation.getResultDefinition());
                        } else if (resultClass != null && resultClass != candidateClass) {
                            rof = new ResultClassROF(ec, rs, ignoreCache, resultClass, datastoreCompilation.getResultDefinitionForClass());
                        } else {
                            // Each result row is a candidate object
                            rof = new PersistentClassROF(ec, rs, ignoreCache, datastoreCompilation.getResultDefinitionForClass(), acmd, candidateClass);
                        }
                        // Create the required type of QueryResult
                        qr = RDBMSQueryUtils.getQueryResultForQuery(this, rof, rs, getResultDistinct() ? null : candidateCollection);
                        // Register any bulk loaded member resultSets that need loading
                        Map<String, IteratorStatement> scoIterStmts = datastoreCompilation.getSCOIteratorStatements();
                        if (scoIterStmts != null) {
                            Iterator<Map.Entry<String, IteratorStatement>> scoStmtIter = scoIterStmts.entrySet().iterator();
                            while (scoStmtIter.hasNext()) {
                                Map.Entry<String, IteratorStatement> stmtIterEntry = scoStmtIter.next();
                                IteratorStatement iterStmt = stmtIterEntry.getValue();
                                String iterStmtSQL = iterStmt.getSelectStatement().getSQLText().toSQL();
                                NucleusLogger.DATASTORE_RETRIEVE.debug("JDOQL Bulk-Fetch of " + iterStmt.getBackingStore().getOwnerMemberMetaData().getFullFieldName());
                                try {
                                    PreparedStatement psSco = sqlControl.getStatementForQuery(mconn, iterStmtSQL);
                                    if (datastoreCompilation.getStatementParameters() != null) {
                                        BulkFetchHandler.applyParametersToStatement(ec, psSco, datastoreCompilation, iterStmt.getSelectStatement(), parameters);
                                    }
                                    ResultSet rsSCO = sqlControl.executeStatementQuery(ec, mconn, iterStmtSQL, psSco);
                                    qr.registerMemberBulkResultSet(iterStmt, rsSCO);
                                } catch (SQLException e) {
                                    throw new NucleusDataStoreException(Localiser.msg("056006", iterStmtSQL), e);
                                }
                            }
                        }
                        // Initialise the QueryResult for use
                        qr.initialise();
                        // Add hooks for closing query resources
                        final QueryResult qr1 = qr;
                        final ManagedConnection mconn1 = mconn;
                        ManagedConnectionResourceListener listener = new ManagedConnectionResourceListener() {

                            public void transactionFlushed() {
                            }

                            public void transactionPreClose() {
                                // Tx : disconnect query from ManagedConnection (read in unread rows etc)
                                qr1.disconnect();
                            }

                            public void managedConnectionPreClose() {
                                if (!ec.getTransaction().isActive()) {
                                    // Non-Tx : disconnect query from ManagedConnection (read in unread rows etc)
                                    qr1.disconnect();
                                }
                            }

                            public void managedConnectionPostClose() {
                            }

                            public void resourcePostClose() {
                                mconn1.removeListener(this);
                            }
                        };
                        mconn.addListener(listener);
                        qr.addConnectionListener(listener);
                        results = qr;
                    }
                } finally {
                    if (qr == null) {
                        rs.close();
                    }
                }
            } else if (type == QueryType.BULK_UPDATE || type == QueryType.BULK_DELETE) {
                long bulkResult = 0;
                List<StatementCompilation> stmtCompilations = datastoreCompilation.getStatementCompilations();
                Iterator<StatementCompilation> stmtCompileIter = stmtCompilations.iterator();
                while (stmtCompileIter.hasNext()) {
                    StatementCompilation stmtCompile = stmtCompileIter.next();
                    ps = sqlControl.getStatementForUpdate(mconn, stmtCompile.getSQL(), false);
                    SQLStatementHelper.applyParametersToStatement(ps, ec, datastoreCompilation.getStatementParameters(), datastoreCompilation.getParameterNameByPosition(), parameters);
                    RDBMSQueryUtils.prepareStatementForExecution(ps, this, false);
                    int[] execResults = sqlControl.executeStatementUpdate(ec, mconn, toString(), ps, true);
                    if (stmtCompile.useInCount()) {
                        bulkResult += execResults[0];
                    }
                }
                try {
                    // Evict all objects of this type from the cache
                    ec.getNucleusContext().getLevel2Cache().evictAll(candidateClass, subclasses);
                } catch (UnsupportedOperationException uoe) {
                // Do nothing
                }
                results = bulkResult;
            }
        } catch (SQLException sqle) {
            if (storeMgr.getDatastoreAdapter().isStatementCancel(sqle)) {
                throw new QueryInterruptedException("Query has been interrupted", sqle);
            } else if (storeMgr.getDatastoreAdapter().isStatementTimeout(sqle)) {
                throw new QueryTimeoutException("Query has been timed out", sqle);
            }
            throw new NucleusException(Localiser.msg("021042", datastoreCompilation.getSQL()), sqle);
        }
        if (NucleusLogger.QUERY.isDebugEnabled()) {
            NucleusLogger.QUERY.debug(Localiser.msg("021074", getLanguage(), "" + (System.currentTimeMillis() - startTime)));
        }
        return results;
    } finally {
        mconn.release();
    }
}
Also used : SQLException(java.sql.SQLException) ArrayList(java.util.ArrayList) IteratorStatement(org.datanucleus.store.rdbms.scostore.IteratorStatement) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) SQLController(org.datanucleus.store.rdbms.SQLController) NucleusDataStoreException(org.datanucleus.exceptions.NucleusDataStoreException) QueryTimeoutException(org.datanucleus.store.query.QueryTimeoutException) QueryResult(org.datanucleus.store.query.QueryResult) CandidateIdsQueryResult(org.datanucleus.store.query.CandidateIdsQueryResult) ResultSet(java.sql.ResultSet) Iterator(java.util.Iterator) List(java.util.List) ArrayList(java.util.ArrayList) ManagedConnection(org.datanucleus.store.connection.ManagedConnection) CandidateIdsQueryResult(org.datanucleus.store.query.CandidateIdsQueryResult) QueryInterruptedException(org.datanucleus.store.query.QueryInterruptedException) StatementCompilation(org.datanucleus.store.rdbms.query.RDBMSQueryCompilation.StatementCompilation) JDOQLInMemoryEvaluator(org.datanucleus.query.inmemory.JDOQLInMemoryEvaluator) PreparedStatement(java.sql.PreparedStatement) ManagedConnectionResourceListener(org.datanucleus.store.connection.ManagedConnectionResourceListener) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) NucleusException(org.datanucleus.exceptions.NucleusException) Map(java.util.Map) HashMap(java.util.HashMap)

Example 14 with AbstractClassMetaData

use of org.datanucleus.metadata.AbstractClassMetaData 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;
    }
    // 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().getNumberOfDatastoreMappings() != 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 (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)

Example 15 with AbstractClassMetaData

use of org.datanucleus.metadata.AbstractClassMetaData in project datanucleus-rdbms by datanucleus.

the class QueryToSQLMapper method processVariableExpression.

/* (non-Javadoc)
     * @see org.datanucleus.query.evaluator.AbstractExpressionEvaluator#processVariableExpression(org.datanucleus.query.expression.VariableExpression)
     */
@Override
protected Object processVariableExpression(VariableExpression expr) {
    String varName = expr.getId();
    Symbol varSym = expr.getSymbol();
    if (varSym != null) {
        // Use name from symbol if possible
        varName = varSym.getQualifiedName();
    }
    if (hasSQLTableMappingForAlias(varName)) {
        // Variable already found
        SQLTableMapping tblMapping = getSQLTableMappingForAlias(varName);
        SQLExpression sqlExpr = exprFactory.newExpression(tblMapping.table.getSQLStatement(), tblMapping.table, tblMapping.mapping);
        stack.push(sqlExpr);
        return sqlExpr;
    } else if (compilation.getCompilationForSubquery(varName) != null) {
        // Subquery variable
        QueryCompilation subCompilation = compilation.getCompilationForSubquery(varName);
        AbstractClassMetaData subCmd = ec.getMetaDataManager().getMetaDataForClass(subCompilation.getCandidateClass(), ec.getClassLoaderResolver());
        // Create subquery statement, using any provided alias if possible
        String subAlias = null;
        if (subCompilation.getCandidateAlias() != null && !subCompilation.getCandidateAlias().equals(candidateAlias)) {
            subAlias = subCompilation.getCandidateAlias();
        }
        StatementResultMapping subqueryResultMapping = new StatementResultMapping();
        // TODO Fix "avg(something)" arg - not essential but is a hack right now
        SQLStatement subStmt = RDBMSQueryUtils.getStatementForCandidates(storeMgr, stmt, subCmd, null, ec, subCompilation.getCandidateClass(), true, "avg(something)", subAlias, null, null);
        QueryToSQLMapper sqlMapper = new QueryToSQLMapper(subStmt, subCompilation, parameters, null, subqueryResultMapping, subCmd, true, fetchPlan, ec, importsDefinition, options, extensionsByName);
        sqlMapper.setDefaultJoinType(defaultJoinType);
        sqlMapper.setDefaultJoinTypeFilter(defaultJoinTypeFilter);
        sqlMapper.setParentMapper(this);
        sqlMapper.compile();
        if (subqueryResultMapping.getNumberOfResultExpressions() > 1) {
            throw new NucleusUserException("Number of result expressions in subquery should be 1");
        }
        SQLExpression subExpr = null;
        // TODO Cater for subquery select of its own candidate
        if (subqueryResultMapping.getNumberOfResultExpressions() == 0) {
            subExpr = new org.datanucleus.store.rdbms.sql.expression.SubqueryExpression(stmt, subStmt);
        } else {
            JavaTypeMapping subMapping = ((StatementMappingIndex) subqueryResultMapping.getMappingForResultExpression(0)).getMapping();
            if (subMapping instanceof TemporalMapping) {
                subExpr = new TemporalSubqueryExpression(stmt, subStmt);
            } else if (subMapping instanceof StringMapping) {
                subExpr = new StringSubqueryExpression(stmt, subStmt);
            } else {
                subExpr = new NumericSubqueryExpression(stmt, subStmt);
            }
            if (subExpr.getJavaTypeMapping() == null) {
                subExpr.setJavaTypeMapping(subMapping);
            }
        }
        stack.push(subExpr);
        return subExpr;
    } else if (stmt.getParentStatement() != null && parentMapper != null && parentMapper.candidateAlias != null && parentMapper.candidateAlias.equals(varName)) {
        // Variable in subquery linking back to parent query
        SQLExpression varExpr = exprFactory.newExpression(stmt.getParentStatement(), stmt.getParentStatement().getPrimaryTable(), stmt.getParentStatement().getPrimaryTable().getTable().getIdMapping());
        stack.push(varExpr);
        return varExpr;
    } else {
        // Variable never met before, so return as UnboundExpression - process later if needing binding
        NucleusLogger.QUERY.debug("QueryToSQL.processVariable (unbound) variable=" + varName + " is not yet bound so returning UnboundExpression");
        UnboundExpression unbExpr = new UnboundExpression(stmt, varName);
        stack.push(unbExpr);
        return unbExpr;
    }
}
Also used : SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) Symbol(org.datanucleus.query.compiler.Symbol) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) UnboundExpression(org.datanucleus.store.rdbms.sql.expression.UnboundExpression) StringMapping(org.datanucleus.store.rdbms.mapping.java.StringMapping) SQLStatement(org.datanucleus.store.rdbms.sql.SQLStatement) NumericSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.NumericSubqueryExpression) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) BooleanSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.BooleanSubqueryExpression) NumericSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.NumericSubqueryExpression) StringSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.StringSubqueryExpression) SubqueryExpression(org.datanucleus.query.expression.SubqueryExpression) TemporalSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.TemporalSubqueryExpression) TemporalSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.TemporalSubqueryExpression) StringSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.StringSubqueryExpression) QueryCompilation(org.datanucleus.query.compiler.QueryCompilation) TemporalMapping(org.datanucleus.store.rdbms.mapping.java.TemporalMapping)

Aggregations

AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)204 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)90 JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)69 ClassLoaderResolver (org.datanucleus.ClassLoaderResolver)59 DatastoreClass (org.datanucleus.store.rdbms.table.DatastoreClass)55 NucleusUserException (org.datanucleus.exceptions.NucleusUserException)42 RDBMSStoreManager (org.datanucleus.store.rdbms.RDBMSStoreManager)42 NucleusException (org.datanucleus.exceptions.NucleusException)37 MetaDataManager (org.datanucleus.metadata.MetaDataManager)37 ArrayList (java.util.ArrayList)31 SQLExpression (org.datanucleus.store.rdbms.sql.expression.SQLExpression)26 SQLTable (org.datanucleus.store.rdbms.sql.SQLTable)23 SQLExpressionFactory (org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory)22 ClassLoaderResolverImpl (org.datanucleus.ClassLoaderResolverImpl)19 MapTable (org.datanucleus.store.rdbms.table.MapTable)18 List (java.util.List)16 ObjectProvider (org.datanucleus.state.ObjectProvider)16 PersistableMapping (org.datanucleus.store.rdbms.mapping.java.PersistableMapping)16 SelectStatement (org.datanucleus.store.rdbms.sql.SelectStatement)16 Iterator (java.util.Iterator)15