Search in sources :

Example 11 with RDBMSStoreManager

use of org.datanucleus.store.rdbms.RDBMSStoreManager in project datanucleus-rdbms by datanucleus.

the class JDOQLQuery method compileQueryUpdate.

/**
 * Method to compile the query for RDBMS for a bulk update.
 * @param parameterValues The parameter values (if any)
 * @param candidateCmd Meta-data for the candidate class
 */
protected void compileQueryUpdate(Map parameterValues, AbstractClassMetaData candidateCmd) {
    Expression[] updateExprs = compilation.getExprUpdate();
    if (updateExprs == null || updateExprs.length == 0) {
        // Nothing to update
        return;
    }
    // Generate statement for candidate
    RDBMSStoreManager storeMgr = (RDBMSStoreManager) getStoreManager();
    DatastoreClass candidateTbl = storeMgr.getDatastoreClass(candidateCmd.getFullClassName(), clr);
    if (candidateTbl == null) {
        throw new NucleusDataStoreException("Bulk update of " + candidateCmd.getFullClassName() + " not supported since candidate has no table of its own");
    }
    List<BulkTable> tables = new ArrayList<>();
    tables.add(new BulkTable(candidateTbl, true));
    if (candidateTbl.getSuperDatastoreClass() != null) {
        DatastoreClass tbl = candidateTbl;
        while (tbl.getSuperDatastoreClass() != null) {
            tbl = tbl.getSuperDatastoreClass();
            tables.add(new BulkTable(tbl, false));
        }
    }
    List<SQLStatement> stmts = new ArrayList<>();
    List<Boolean> stmtCountFlags = new ArrayList<>();
    for (BulkTable bulkTable : tables) {
        // Generate statement for candidate
        DatastoreClass table = bulkTable.table;
        Map<String, Object> extensions = null;
        if (!storeMgr.getDatastoreAdapter().supportsOption(DatastoreAdapter.UPDATE_DELETE_STATEMENT_ALLOW_TABLE_ALIAS_IN_WHERE_CLAUSE)) {
            extensions = new HashMap<>();
            extensions.put(SQLStatement.EXTENSION_SQL_TABLE_NAMING_STRATEGY, "table-name");
        }
        UpdateStatement stmt = new UpdateStatement(storeMgr, table, null, null, extensions);
        stmt.setClassLoaderResolver(clr);
        stmt.setCandidateClassName(candidateCmd.getFullClassName());
        JavaTypeMapping multitenancyMapping = table.getSurrogateMapping(SurrogateColumnType.MULTITENANCY, false);
        if (multitenancyMapping != null) {
            // Multi-tenancy restriction
            SQLExpression tenantExpr = stmt.getSQLExpressionFactory().newExpression(stmt, stmt.getPrimaryTable(), multitenancyMapping);
            SQLExpression tenantVal = stmt.getSQLExpressionFactory().newLiteral(stmt, multitenancyMapping, ec.getNucleusContext().getMultiTenancyId(ec, candidateCmd));
            stmt.whereAnd(tenantExpr.eq(tenantVal), true);
        }
        // TODO Discriminator restriction?
        JavaTypeMapping softDeleteMapping = table.getSurrogateMapping(SurrogateColumnType.SOFTDELETE, false);
        if (softDeleteMapping != null) {
            // Soft-delete restriction
            SQLExpression softDeleteExpr = stmt.getSQLExpressionFactory().newExpression(stmt, stmt.getPrimaryTable(), softDeleteMapping);
            SQLExpression softDeleteVal = stmt.getSQLExpressionFactory().newLiteral(stmt, softDeleteMapping, Boolean.FALSE);
            stmt.whereAnd(softDeleteExpr.eq(softDeleteVal), true);
        }
        Set<String> options = new HashSet<>();
        if (getBooleanExtensionProperty(EXTENSION_USE_IS_NULL_WHEN_EQUALS_NULL_PARAM, true)) {
            options.add(QueryToSQLMapper.OPTION_NULL_PARAM_USE_IS_NULL);
        }
        QueryToSQLMapper sqlMapper = new QueryToSQLMapper(stmt, compilation, parameterValues, null, null, candidateCmd, subclasses, getFetchPlan(), ec, null, options, extensions);
        setMapperJoinTypes(sqlMapper);
        sqlMapper.compile();
        if (stmt.hasUpdates()) {
            stmts.add(stmt);
            stmtCountFlags.add(bulkTable.useInCount);
            datastoreCompilation.setStatementParameters(stmt.getSQLText().getParametersForStatement());
            datastoreCompilation.setPrecompilable(sqlMapper.isPrecompilable());
        }
    }
    datastoreCompilation.clearStatements();
    Iterator<SQLStatement> stmtIter = stmts.iterator();
    Iterator<Boolean> stmtCountFlagsIter = stmtCountFlags.iterator();
    while (stmtIter.hasNext()) {
        SQLStatement stmt = stmtIter.next();
        Boolean useInCount = stmtCountFlagsIter.next();
        if (stmts.size() == 1) {
            useInCount = true;
        }
        datastoreCompilation.addStatement(stmt, stmt.getSQLText().toSQL(), useInCount);
    }
}
Also used : UpdateStatement(org.datanucleus.store.rdbms.sql.UpdateStatement) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) ArrayList(java.util.ArrayList) SQLStatement(org.datanucleus.store.rdbms.sql.SQLStatement) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) NucleusDataStoreException(org.datanucleus.exceptions.NucleusDataStoreException) Expression(org.datanucleus.query.expression.Expression) BooleanExpression(org.datanucleus.store.rdbms.sql.expression.BooleanExpression) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) HashSet(java.util.HashSet)

Example 12 with RDBMSStoreManager

use of org.datanucleus.store.rdbms.RDBMSStoreManager in project datanucleus-rdbms by datanucleus.

the class JDOQLQuery method compileQueryFull.

/**
 * Method to set the (native) query statement for the compiled query as a whole.
 * @param parameters Input parameters (if known)
 * @param candidateCmd Metadata for the candidate class
 */
private void compileQueryFull(Map parameters, AbstractClassMetaData candidateCmd) {
    if (type != QueryType.SELECT) {
        return;
    }
    long startTime = 0;
    if (NucleusLogger.QUERY.isDebugEnabled()) {
        startTime = System.currentTimeMillis();
        NucleusLogger.QUERY.debug(Localiser.msg("021083", getLanguage(), toString()));
    }
    if (result != null) {
        datastoreCompilation.setResultDefinition(new StatementResultMapping());
    } else {
        datastoreCompilation.setResultDefinitionForClass(new StatementClassMapping());
    }
    // Generate statement for candidate(s)
    SelectStatement stmt = null;
    try {
        boolean includeSoftDeletes = getBooleanExtensionProperty("include-soft-deletes", false);
        Set<String> options = null;
        if (includeSoftDeletes) {
            options = new HashSet<>();
            options.add(SelectStatementGenerator.OPTION_INCLUDE_SOFT_DELETES);
        }
        stmt = RDBMSQueryUtils.getStatementForCandidates((RDBMSStoreManager) getStoreManager(), null, candidateCmd, datastoreCompilation.getResultDefinitionForClass(), ec, candidateClass, subclasses, result, null, null, options);
    } catch (NucleusException ne) {
        // Statement would result in no results, so just catch it and avoid generating the statement
        NucleusLogger.QUERY.warn("Query for candidates of " + candidateClass.getName() + (subclasses ? " and subclasses" : "") + " resulted in no possible candidates : " + StringUtils.getMessageFromRootCauseOfThrowable(ne));
        statementReturnsEmpty = true;
        return;
    }
    // Update the SQLStatement with filter, ordering, result etc
    Set<String> options = new HashSet<>();
    options.add(QueryToSQLMapper.OPTION_BULK_UPDATE_VERSION);
    if (getBooleanExtensionProperty(EXTENSION_USE_IS_NULL_WHEN_EQUALS_NULL_PARAM, true)) {
        options.add(QueryToSQLMapper.OPTION_NULL_PARAM_USE_IS_NULL);
    }
    if (getBooleanExtensionProperty(EXTENSION_NON_DISTINCT_IMPLICIT_JOIN, false)) {
        options.add(QueryToSQLMapper.OPTION_NON_DISTINCT_IMPLICIT_JOINS);
    }
    QueryToSQLMapper sqlMapper = new QueryToSQLMapper(stmt, compilation, parameters, datastoreCompilation.getResultDefinitionForClass(), datastoreCompilation.getResultDefinition(), candidateCmd, subclasses, getFetchPlan(), ec, getParsedImports(), options, extensions);
    setMapperJoinTypes(sqlMapper);
    sqlMapper.compile();
    datastoreCompilation.setParameterNameByPosition(sqlMapper.getParameterNameByPosition());
    datastoreCompilation.setPrecompilable(sqlMapper.isPrecompilable());
    if (!getResultDistinct() && stmt.isDistinct()) {
        setResultDistinct(true);
        compilation.setResultDistinct();
    }
    if (candidateCollection != null) {
        // Restrict to the supplied candidate ids
        BooleanExpression candidateExpr = null;
        Iterator iter = candidateCollection.iterator();
        JavaTypeMapping idMapping = stmt.getPrimaryTable().getTable().getIdMapping();
        while (iter.hasNext()) {
            Object candidate = iter.next();
            SQLExpression idExpr = stmt.getSQLExpressionFactory().newExpression(stmt, stmt.getPrimaryTable(), idMapping);
            SQLExpression idVal = stmt.getSQLExpressionFactory().newLiteral(stmt, idMapping, candidate);
            if (candidateExpr == null) {
                candidateExpr = idExpr.eq(idVal);
            } else {
                candidateExpr = candidateExpr.ior(idExpr.eq(idVal));
            }
        }
        stmt.whereAnd(candidateExpr, true);
    }
    // Apply any range
    if (range != null) {
        long lower = fromInclNo;
        long upper = toExclNo;
        if (fromInclParam != null) {
            if (parameters.containsKey(fromInclParam)) {
                lower = ((Number) parameters.get(fromInclParam)).longValue();
            } else {
                // Must be numbered input so take penultimate
                lower = ((Number) parameters.get(Integer.valueOf(parameters.size() - 2))).longValue();
            }
        }
        if (toExclParam != null) {
            if (parameters.containsKey(toExclParam)) {
                upper = ((Number) parameters.get(toExclParam)).longValue();
            } else {
                // Must be numbered input so take ultimate
                upper = ((Number) parameters.get(Integer.valueOf(parameters.size() - 1))).longValue();
            }
        }
        stmt.setRange(lower, upper - lower);
    }
    // Set any extensions
    boolean useUpdateLock = RDBMSQueryUtils.useUpdateLockForQuery(this);
    stmt.addExtension(SQLStatement.EXTENSION_LOCK_FOR_UPDATE, Boolean.valueOf(useUpdateLock));
    if (getBooleanExtensionProperty(EXTENSION_FOR_UPDATE_NOWAIT, false)) {
        stmt.addExtension(SQLStatement.EXTENSION_LOCK_FOR_UPDATE_NOWAIT, Boolean.TRUE);
    }
    datastoreCompilation.addStatement(stmt, stmt.getSQLText().toSQL(), false);
    datastoreCompilation.setStatementParameters(stmt.getSQLText().getParametersForStatement());
    if (result == null && !(resultClass != null && resultClass != candidateClass)) {
        // Select of candidates, so check for any immediate multi-valued fields that are marked for fetching
        // TODO If the query joins to a 1-1/N-1 and then we have a multi-valued field, we should allow that too
        FetchPlanForClass fpc = getFetchPlan().getFetchPlanForClass(candidateCmd);
        int[] fpMembers = fpc.getMemberNumbers();
        for (int i = 0; i < fpMembers.length; i++) {
            AbstractMemberMetaData fpMmd = candidateCmd.getMetaDataForManagedMemberAtAbsolutePosition(fpMembers[i]);
            RelationType fpRelType = fpMmd.getRelationType(clr);
            if (RelationType.isRelationMultiValued(fpRelType)) {
                if (fpMmd.hasCollection() && SCOUtils.collectionHasSerialisedElements(fpMmd)) {
                // Ignore collections serialised into the owner (retrieved in main query)
                } else if (fpMmd.hasMap() && SCOUtils.mapHasSerialisedKeysAndValues(fpMmd)) {
                // Ignore maps serialised into the owner (retrieved in main query)
                } else if (fpMmd.hasMap()) {
                // Ignore maps for now until we support them
                } else {
                    String multifetchType = getStringExtensionProperty(RDBMSPropertyNames.PROPERTY_RDBMS_QUERY_MULTIVALUED_FETCH, null);
                    if (multifetchType == null) {
                        // Default to bulk-fetch EXISTS, so advise the user of why this is happening and how to turn it off
                        NucleusLogger.QUERY.debug("You have selected field " + fpMmd.getFullFieldName() + " for fetching by this query. We will fetch it using 'EXISTS'." + " To disable this set the query extension/hint '" + RDBMSPropertyNames.PROPERTY_RDBMS_QUERY_MULTIVALUED_FETCH + "' as 'none' or remove the field" + " from the query FetchPlan. If this bulk-fetch generates an invalid or unoptimised query, please report it with a way of reproducing it");
                        multifetchType = "exists";
                    }
                    if (multifetchType.equalsIgnoreCase("exists")) {
                        // Fetch container contents for all candidate owners
                        BulkFetchExistsHandler helper = new BulkFetchExistsHandler();
                        IteratorStatement iterStmt = helper.getStatementToBulkFetchField(candidateCmd, fpMmd, this, parameters, datastoreCompilation, options);
                        if (iterStmt != null) {
                            datastoreCompilation.setSCOIteratorStatement(fpMmd.getFullFieldName(), iterStmt);
                        } else {
                            NucleusLogger.GENERAL.debug("Note that query has field " + fpMmd.getFullFieldName() + " marked in the FetchPlan, yet this is currently not fetched by this query");
                        }
                    } else if (multifetchType.equalsIgnoreCase("join")) {
                        // Fetch container contents for all candidate owners
                        BulkFetchJoinHandler helper = new BulkFetchJoinHandler();
                        IteratorStatement iterStmt = helper.getStatementToBulkFetchField(candidateCmd, fpMmd, this, parameters, datastoreCompilation, options);
                        if (iterStmt != null) {
                            datastoreCompilation.setSCOIteratorStatement(fpMmd.getFullFieldName(), iterStmt);
                        } else {
                            NucleusLogger.GENERAL.debug("Note that query has field " + fpMmd.getFullFieldName() + " marked in the FetchPlan, yet this is currently not fetched by this query");
                        }
                    } else {
                        NucleusLogger.GENERAL.debug("Note that query has field " + fpMmd.getFullFieldName() + " marked in the FetchPlan, yet this is not fetched by this query.");
                    }
                // TODO Continue this bulk fetch process to multivalued fields of this field
                }
            } else if (RelationType.isRelationSingleValued(fpRelType)) {
            // TODO Check for multivalued fields of this 1-1/N-1 field
            }
        }
    }
    if (NucleusLogger.QUERY.isDebugEnabled()) {
        NucleusLogger.QUERY.debug(Localiser.msg("021084", getLanguage(), System.currentTimeMillis() - startTime));
    }
}
Also used : SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) FetchPlanForClass(org.datanucleus.FetchPlanForClass) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) IteratorStatement(org.datanucleus.store.rdbms.scostore.IteratorStatement) SelectStatement(org.datanucleus.store.rdbms.sql.SelectStatement) BooleanExpression(org.datanucleus.store.rdbms.sql.expression.BooleanExpression) RelationType(org.datanucleus.metadata.RelationType) Iterator(java.util.Iterator) HashSet(java.util.HashSet) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) NucleusException(org.datanucleus.exceptions.NucleusException) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Example 13 with RDBMSStoreManager

use of org.datanucleus.store.rdbms.RDBMSStoreManager in project datanucleus-rdbms by datanucleus.

the class JDOQLQuery method processesRangeInDatastoreQuery.

/* (non-Javadoc)
     * @see org.datanucleus.store.query.Query#processesRangeInDatastoreQuery()
     */
@Override
public boolean processesRangeInDatastoreQuery() {
    if (range == null) {
        // No range specified so makes no difference
        return true;
    }
    RDBMSStoreManager storeMgr = (RDBMSStoreManager) getStoreManager();
    DatastoreAdapter dba = storeMgr.getDatastoreAdapter();
    boolean using_limit_where_clause = (dba.getRangeByLimitEndOfStatementClause(fromInclNo, toExclNo, !StringUtils.isWhitespace(ordering)).length() > 0);
    boolean using_rownum = (dba.getRangeByRowNumberColumn().length() > 0) || (dba.getRangeByRowNumberColumn2().length() > 0);
    return using_limit_where_clause || using_rownum;
}
Also used : DatastoreAdapter(org.datanucleus.store.rdbms.adapter.DatastoreAdapter) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager)

Example 14 with RDBMSStoreManager

use of org.datanucleus.store.rdbms.RDBMSStoreManager in project datanucleus-rdbms by datanucleus.

the class JPQLQuery method compileQueryInsert.

/**
 * Method to compile the query for RDBMS for a bulk INSERT.
 * @param parameterValues The parameter values (if any)
 * @param candidateCmd Meta-data for the candidate class
 */
protected void compileQueryInsert(Map parameterValues, AbstractClassMetaData candidateCmd) {
    if (StringUtils.isWhitespace(insertFields) || StringUtils.isWhitespace(insertSelectQuery)) {
        // Nothing to INSERT
        return;
    }
    List<String> fieldNames = new ArrayList<>();
    StringTokenizer fieldTokenizer = new StringTokenizer(insertFields, ",");
    while (fieldTokenizer.hasMoreTokens()) {
        String token = fieldTokenizer.nextToken().trim();
        fieldNames.add(token);
    }
    // Generate statement for candidate and related classes in this inheritance tree
    RDBMSStoreManager storeMgr = (RDBMSStoreManager) getStoreManager();
    DatastoreClass candidateTbl = storeMgr.getDatastoreClass(candidateCmd.getFullClassName(), clr);
    if (candidateTbl == null) {
        // TODO Using subclass-table, so find the table(s) it can be persisted into
        throw new NucleusDataStoreException("Bulk INSERT of " + candidateCmd.getFullClassName() + " not supported since candidate has no table of its own");
    }
    // Find table(s) that need populating with this information
    List<BulkTable> tables = new ArrayList<>();
    tables.add(new BulkTable(candidateTbl, true));
    if (candidateTbl.getSuperDatastoreClass() != null) {
        DatastoreClass tbl = candidateTbl;
        while (tbl.getSuperDatastoreClass() != null) {
            tbl = tbl.getSuperDatastoreClass();
            tables.add(0, new BulkTable(tbl, false));
        }
    }
    if (tables.size() > 1) {
        throw new NucleusUserException("BULK INSERT only currently allows a single table, but this query implies INSERT into " + tables.size() + " tables!");
    }
    List<SQLStatement> stmts = new ArrayList<>();
    List<Boolean> stmtCountFlags = new ArrayList<>();
    for (BulkTable bulkTable : tables) {
        // Generate statement for candidate
        InsertStatement stmt = new InsertStatement(storeMgr, bulkTable.table, null, null, null);
        stmt.setClassLoaderResolver(clr);
        stmt.setCandidateClassName(candidateCmd.getFullClassName());
        // Set columns for this table
        for (String fieldName : fieldNames) {
            AbstractMemberMetaData fieldMmd = candidateCmd.getMetaDataForMember(fieldName);
            if (fieldMmd == null) {
            // No such field
            } else {
                JavaTypeMapping fieldMapping = bulkTable.table.getMemberMapping(fieldMmd);
                if (fieldMapping != null) {
                    SQLExpression fieldExpr = stmt.getSQLExpressionFactory().newExpression(stmt, stmt.getPrimaryTable(), fieldMapping);
                    for (int i = 0; i < fieldExpr.getNumberOfSubExpressions(); i++) {
                        ColumnExpression fieldColExpr = fieldExpr.getSubExpression(i);
                        fieldColExpr.setOmitTableFromString(true);
                    }
                    stmt.addColumn(fieldExpr);
                } else {
                // Not in this table
                }
            }
        }
        // Generate the select query and add it to the InsertStatement
        JPQLQuery selectQuery = new JPQLQuery(storeMgr, ec, insertSelectQuery);
        selectQuery.compile();
        stmt.setSelectStatement((SelectStatement) selectQuery.getDatastoreCompilation().getStatementCompilations().get(0).getStatement());
        selectQuery.closeAll();
        // TODO if we have multiple tables then this will mean only using some of the columns in the selectSQL
        stmts.add(stmt);
        stmtCountFlags.add(bulkTable.useInCount);
        datastoreCompilation.setStatementParameters(stmt.getSQLText().getParametersForStatement());
    }
    datastoreCompilation.clearStatements();
    Iterator<SQLStatement> stmtIter = stmts.iterator();
    Iterator<Boolean> stmtCountFlagsIter = stmtCountFlags.iterator();
    while (stmtIter.hasNext()) {
        SQLStatement stmt = stmtIter.next();
        Boolean useInCount = stmtCountFlagsIter.next();
        if (stmts.size() == 1) {
            useInCount = true;
        }
        datastoreCompilation.addStatement(stmt, stmt.getSQLText().toSQL(), useInCount);
    }
}
Also used : SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) ArrayList(java.util.ArrayList) SQLStatement(org.datanucleus.store.rdbms.sql.SQLStatement) InsertStatement(org.datanucleus.store.rdbms.sql.InsertStatement) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) NucleusDataStoreException(org.datanucleus.exceptions.NucleusDataStoreException) StringTokenizer(java.util.StringTokenizer) ColumnExpression(org.datanucleus.store.rdbms.sql.expression.ColumnExpression) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) AbstractJPQLQuery(org.datanucleus.store.query.AbstractJPQLQuery) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Example 15 with RDBMSStoreManager

use of org.datanucleus.store.rdbms.RDBMSStoreManager 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)

Aggregations

RDBMSStoreManager (org.datanucleus.store.rdbms.RDBMSStoreManager)197 ManagedConnection (org.datanucleus.store.connection.ManagedConnection)84 JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)82 SQLException (java.sql.SQLException)78 Connection (java.sql.Connection)76 HashSet (java.util.HashSet)72 DatabaseMetaData (java.sql.DatabaseMetaData)62 PersistenceManager (javax.jdo.PersistenceManager)61 SQLExpression (org.datanucleus.store.rdbms.sql.expression.SQLExpression)56 JDOPersistenceManager (org.datanucleus.api.jdo.JDOPersistenceManager)55 Transaction (javax.jdo.Transaction)52 ArrayList (java.util.ArrayList)49 SQLExpressionFactory (org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory)49 JDOFatalUserException (javax.jdo.JDOFatalUserException)48 DatastoreClass (org.datanucleus.store.rdbms.table.DatastoreClass)44 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)42 ClassLoaderResolver (org.datanucleus.ClassLoaderResolver)41 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)38 NumericExpression (org.datanucleus.store.rdbms.sql.expression.NumericExpression)28 JDOFatalInternalException (javax.jdo.JDOFatalInternalException)25