Search in sources :

Example 1 with SelectStatement

use of org.datanucleus.store.rdbms.sql.SelectStatement in project datanucleus-rdbms by datanucleus.

the class OracleClobRDBMSMapping method updateClobColumn.

/**
 * Convenience method to update the contents of a CLOB column.
 * Oracle requires that a CLOB is initialised with EMPTY_CLOB() and then you retrieve
 * the column and update its CLOB value. Performs a statement
 * <pre>
 * SELECT {clobColumn} FROM TABLE WHERE ID=? FOR UPDATE
 * </pre>
 * and then updates the Clob value returned.
 * @param op ObjectProvider of the object
 * @param table Table storing the CLOB column
 * @param mapping Datastore mapping for the CLOB column
 * @param value The value to store in the CLOB
 * @throws NucleusObjectNotFoundException Thrown if an object is not found
 * @throws NucleusDataStoreException Thrown if an error occurs in datastore communication
 */
@SuppressWarnings("deprecation")
public static void updateClobColumn(ObjectProvider op, Table table, DatastoreMapping mapping, String value) {
    ExecutionContext ec = op.getExecutionContext();
    RDBMSStoreManager storeMgr = table.getStoreManager();
    // Don't support join tables yet
    DatastoreClass classTable = (DatastoreClass) table;
    SQLExpressionFactory exprFactory = storeMgr.getSQLExpressionFactory();
    // Generate "SELECT {clobColumn} FROM TABLE WHERE ID=? FOR UPDATE" statement
    SelectStatement sqlStmt = new SelectStatement(storeMgr, table, null, null);
    sqlStmt.setClassLoaderResolver(ec.getClassLoaderResolver());
    sqlStmt.addExtension(SQLStatement.EXTENSION_LOCK_FOR_UPDATE, true);
    SQLTable blobSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(sqlStmt, sqlStmt.getPrimaryTable(), mapping.getJavaTypeMapping());
    sqlStmt.select(blobSqlTbl, mapping.getColumn(), null);
    StatementClassMapping mappingDefinition = new StatementClassMapping();
    AbstractClassMetaData cmd = op.getClassMetaData();
    int inputParamNum = 1;
    if (cmd.getIdentityType() == IdentityType.DATASTORE) {
        // Datastore identity value for input
        JavaTypeMapping datastoreIdMapping = classTable.getSurrogateMapping(SurrogateColumnType.DATASTORE_ID, false);
        SQLExpression expr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), datastoreIdMapping);
        SQLExpression val = exprFactory.newLiteralParameter(sqlStmt, datastoreIdMapping, null, "ID");
        sqlStmt.whereAnd(expr.eq(val), true);
        StatementMappingIndex datastoreIdx = mappingDefinition.getMappingForMemberPosition(SurrogateColumnType.DATASTORE_ID.getFieldNumber());
        if (datastoreIdx == null) {
            datastoreIdx = new StatementMappingIndex(datastoreIdMapping);
            mappingDefinition.addMappingForMember(SurrogateColumnType.DATASTORE_ID.getFieldNumber(), datastoreIdx);
        }
        datastoreIdx.addParameterOccurrence(new int[] { inputParamNum });
    } else if (cmd.getIdentityType() == IdentityType.APPLICATION) {
        // Application identity value(s) for input
        int[] pkNums = cmd.getPKMemberPositions();
        for (int i = 0; i < pkNums.length; i++) {
            AbstractMemberMetaData mmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(pkNums[i]);
            JavaTypeMapping pkMapping = classTable.getMemberMapping(mmd);
            SQLExpression expr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), pkMapping);
            SQLExpression val = exprFactory.newLiteralParameter(sqlStmt, pkMapping, null, "PK" + i);
            sqlStmt.whereAnd(expr.eq(val), true);
            StatementMappingIndex pkIdx = mappingDefinition.getMappingForMemberPosition(pkNums[i]);
            if (pkIdx == null) {
                pkIdx = new StatementMappingIndex(pkMapping);
                mappingDefinition.addMappingForMember(pkNums[i], pkIdx);
            }
            int[] inputParams = new int[pkMapping.getNumberOfDatastoreMappings()];
            for (int j = 0; j < pkMapping.getNumberOfDatastoreMappings(); j++) {
                inputParams[j] = inputParamNum++;
            }
            pkIdx.addParameterOccurrence(inputParams);
        }
    }
    String textStmt = sqlStmt.getSQLText().toSQL();
    if (op.isEmbedded()) {
        // This mapping is embedded, so navigate back to the real owner since that is the "id" in the table
        ObjectProvider[] embeddedOwners = ec.getOwnersForEmbeddedObjectProvider(op);
        if (embeddedOwners != null) {
            // Just use the first owner
            // TODO Should check if the owner is stored in this table
            op = embeddedOwners[0];
        }
    }
    try {
        ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec);
        SQLController sqlControl = storeMgr.getSQLController();
        try {
            PreparedStatement ps = sqlControl.getStatementForQuery(mconn, textStmt);
            try {
                // Provide the primary key field(s) to the JDBC statement
                if (cmd.getIdentityType() == IdentityType.DATASTORE) {
                    StatementMappingIndex datastoreIdx = mappingDefinition.getMappingForMemberPosition(SurrogateColumnType.DATASTORE_ID.getFieldNumber());
                    for (int i = 0; i < datastoreIdx.getNumberOfParameterOccurrences(); i++) {
                        classTable.getSurrogateMapping(SurrogateColumnType.DATASTORE_ID, false).setObject(ec, ps, datastoreIdx.getParameterPositionsForOccurrence(i), op.getInternalObjectId());
                    }
                } else if (cmd.getIdentityType() == IdentityType.APPLICATION) {
                    op.provideFields(cmd.getPKMemberPositions(), new ParameterSetter(op, ps, mappingDefinition));
                }
                ResultSet rs = sqlControl.executeStatementQuery(ec, mconn, textStmt, ps);
                try {
                    if (!rs.next()) {
                        throw new NucleusObjectNotFoundException("No such database row", op.getInternalObjectId());
                    }
                    DatastoreAdapter dba = storeMgr.getDatastoreAdapter();
                    int jdbcMajorVersion = dba.getDriverMajorVersion();
                    if (dba.getDatastoreDriverName().equalsIgnoreCase(OracleAdapter.OJDBC_DRIVER_NAME) && jdbcMajorVersion < 10) {
                        // Oracle JDBC drivers version 9 and below use some sh*tty Oracle-specific CLOB type
                        // we have to cast to that, face west, pray whilst saying ommmmmmmmmmm
                        oracle.sql.CLOB clob = (oracle.sql.CLOB) rs.getClob(1);
                        if (clob != null) {
                            // Deprecated but what can you do
                            clob.putString(1, value);
                        }
                    } else {
                        // Oracle JDBC drivers 10 and above supposedly use the JDBC standard class for Clobs
                        java.sql.Clob clob = rs.getClob(1);
                        if (clob != null) {
                            clob.setString(1, value);
                        }
                    }
                } finally {
                    rs.close();
                }
            } finally {
                sqlControl.closeStatement(mconn, ps);
            }
        } finally {
            mconn.release();
        }
    } catch (SQLException e) {
        throw new NucleusDataStoreException("Update of CLOB value failed: " + textStmt, e);
    }
}
Also used : SQLExpressionFactory(org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) SQLException(java.sql.SQLException) StatementMappingIndex(org.datanucleus.store.rdbms.query.StatementMappingIndex) ParameterSetter(org.datanucleus.store.rdbms.fieldmanager.ParameterSetter) NucleusObjectNotFoundException(org.datanucleus.exceptions.NucleusObjectNotFoundException) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) SQLController(org.datanucleus.store.rdbms.SQLController) SelectStatement(org.datanucleus.store.rdbms.sql.SelectStatement) NucleusDataStoreException(org.datanucleus.exceptions.NucleusDataStoreException) SQLTable(org.datanucleus.store.rdbms.sql.SQLTable) ResultSet(java.sql.ResultSet) ManagedConnection(org.datanucleus.store.connection.ManagedConnection) PreparedStatement(java.sql.PreparedStatement) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) StatementClassMapping(org.datanucleus.store.rdbms.query.StatementClassMapping) ExecutionContext(org.datanucleus.ExecutionContext) ObjectProvider(org.datanucleus.state.ObjectProvider) DatastoreAdapter(org.datanucleus.store.rdbms.adapter.DatastoreAdapter) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Example 2 with SelectStatement

use of org.datanucleus.store.rdbms.sql.SelectStatement in project datanucleus-rdbms by datanucleus.

the class BulkFetchExistsHandler method getStatementToBulkFetchField.

/**
 * Convenience method to generate a bulk-fetch statement for the specified multi-valued field of the owning query.
 * @param candidateCmd Metadata for the candidate
 * @param parameters Parameters for the query
 * @param mmd Metadata for the multi-valued field
 * @param datastoreCompilation The datastore compilation of the query
 * @param mapperOptions Any options for the query to SQL mapper
 * @return The bulk-fetch statement for retrieving this multi-valued field.
 */
public IteratorStatement getStatementToBulkFetchField(AbstractClassMetaData candidateCmd, AbstractMemberMetaData mmd, Query query, Map parameters, RDBMSQueryCompilation datastoreCompilation, Set<String> mapperOptions) {
    IteratorStatement iterStmt = null;
    ExecutionContext ec = query.getExecutionContext();
    ClassLoaderResolver clr = ec.getClassLoaderResolver();
    RDBMSStoreManager storeMgr = (RDBMSStoreManager) query.getStoreManager();
    Store backingStore = storeMgr.getBackingStoreForField(clr, mmd, null);
    if (backingStore instanceof JoinSetStore || backingStore instanceof JoinListStore || backingStore instanceof JoinArrayStore) {
        // Set/List/array using join-table : Generate an iterator query of the form
        if (backingStore instanceof JoinSetStore) {
            iterStmt = ((JoinSetStore) backingStore).getIteratorStatement(ec, ec.getFetchPlan(), false);
        } else if (backingStore instanceof JoinListStore) {
            iterStmt = ((JoinListStore) backingStore).getIteratorStatement(ec, ec.getFetchPlan(), false, -1, -1);
        } else if (backingStore instanceof JoinArrayStore) {
            iterStmt = ((JoinArrayStore) backingStore).getIteratorStatement(ec, ec.getFetchPlan(), false);
        } else {
            throw new NucleusUserException("We do not support BulkFetch using EXISTS for backingStore = " + backingStore);
        }
        // SELECT ELEM_TBL.COL1, ELEM_TBL.COL2, ... FROM JOIN_TBL INNER_JOIN ELEM_TBL WHERE JOIN_TBL.ELEMENT_ID = ELEM_TBL.ID
        // AND EXISTS (SELECT OWNER_TBL.ID FROM OWNER_TBL WHERE (queryWhereClause) AND JOIN_TBL.OWNER_ID = OWNER_TBL.ID)
        SelectStatement sqlStmt = iterStmt.getSelectStatement();
        JoinTable joinTbl = (JoinTable) sqlStmt.getPrimaryTable().getTable();
        JavaTypeMapping joinOwnerMapping = joinTbl.getOwnerMapping();
        // Generate the EXISTS subquery (based on the JDOQL/JPQL query)
        SelectStatement existsStmt = RDBMSQueryUtils.getStatementForCandidates(storeMgr, sqlStmt, candidateCmd, datastoreCompilation.getResultDefinitionForClass(), ec, query.getCandidateClass(), query.isSubclasses(), query.getResult(), null, null, null);
        Set<String> options = new HashSet<>();
        if (mapperOptions != null) {
            options.addAll(mapperOptions);
        }
        options.add(QueryToSQLMapper.OPTION_SELECT_CANDIDATE_ID_ONLY);
        QueryToSQLMapper sqlMapper = new QueryToSQLMapper(existsStmt, query.getCompilation(), parameters, null, null, candidateCmd, query.isSubclasses(), query.getFetchPlan(), ec, query.getParsedImports(), options, query.getExtensions());
        sqlMapper.compile();
        // Add EXISTS clause on iterator statement so we can restrict to just the owners in this query
        // ORDER BY in EXISTS is forbidden by some RDBMS
        existsStmt.setOrdering(null, null);
        BooleanExpression existsExpr = new BooleanSubqueryExpression(sqlStmt, "EXISTS", existsStmt);
        sqlStmt.whereAnd(existsExpr, true);
        // Join to outer statement so we restrict to collection elements for the query candidates
        SQLExpression joinTblOwnerExpr = sqlStmt.getRDBMSManager().getSQLExpressionFactory().newExpression(sqlStmt, sqlStmt.getPrimaryTable(), joinOwnerMapping);
        SQLExpression existsOwnerExpr = sqlStmt.getRDBMSManager().getSQLExpressionFactory().newExpression(existsStmt, existsStmt.getPrimaryTable(), existsStmt.getPrimaryTable().getTable().getIdMapping());
        existsStmt.whereAnd(joinTblOwnerExpr.eq(existsOwnerExpr), true);
        // Select the owner candidate so we can separate the collection elements out to their owner
        int[] ownerColIndexes = sqlStmt.select(joinTblOwnerExpr, null);
        StatementMappingIndex ownerMapIdx = new StatementMappingIndex(existsStmt.getPrimaryTable().getTable().getIdMapping());
        ownerMapIdx.setColumnPositions(ownerColIndexes);
        iterStmt.setOwnerMapIndex(ownerMapIdx);
    } else if (backingStore instanceof FKSetStore || backingStore instanceof FKListStore || backingStore instanceof FKArrayStore) {
        if (backingStore instanceof FKSetStore) {
            iterStmt = ((FKSetStore) backingStore).getIteratorStatement(ec, ec.getFetchPlan(), false);
        } else if (backingStore instanceof FKListStore) {
            iterStmt = ((FKListStore) backingStore).getIteratorStatement(ec, ec.getFetchPlan(), false, -1, -1);
        } else if (backingStore instanceof FKArrayStore) {
            iterStmt = ((FKArrayStore) backingStore).getIteratorStatement(ec, ec.getFetchPlan(), false);
        } else {
            throw new NucleusUserException("We do not support BulkFetch using EXISTS for backingStore = " + backingStore);
        }
        // Set/List/array using foreign-key : Generate an iterator query of the form
        // SELECT ELEM_TBL.COL1, ELEM_TBL.COL2, ... FROM ELEM_TBL
        // WHERE EXISTS (SELECT OWNER_TBL.ID FROM OWNER_TBL WHERE (queryWhereClause) AND ELEM_TBL.OWNER_ID = OWNER_TBL.ID)
        SelectStatement sqlStmt = iterStmt.getSelectStatement();
        // Generate the EXISTS subquery (based on the JDOQL/JPQL query)
        SelectStatement existsStmt = RDBMSQueryUtils.getStatementForCandidates(storeMgr, sqlStmt, candidateCmd, datastoreCompilation.getResultDefinitionForClass(), ec, query.getCandidateClass(), query.isSubclasses(), query.getResult(), null, null, null);
        Set<String> options = new HashSet<>();
        if (mapperOptions != null) {
            options.addAll(mapperOptions);
        }
        options.add(QueryToSQLMapper.OPTION_SELECT_CANDIDATE_ID_ONLY);
        QueryToSQLMapper sqlMapper = new QueryToSQLMapper(existsStmt, query.getCompilation(), parameters, null, null, candidateCmd, query.isSubclasses(), query.getFetchPlan(), ec, query.getParsedImports(), options, query.getExtensions());
        sqlMapper.compile();
        // Add EXISTS clause on iterator statement so we can restrict to just the owners in this query
        // ORDER BY in EXISTS is forbidden by some RDBMS
        existsStmt.setOrdering(null, null);
        BooleanExpression existsExpr = new BooleanSubqueryExpression(sqlStmt, "EXISTS", existsStmt);
        sqlStmt.whereAnd(existsExpr, true);
        // Join to outer statement so we restrict to collection elements for the query candidates
        SQLExpression elemTblOwnerExpr = sqlStmt.getRDBMSManager().getSQLExpressionFactory().newExpression(sqlStmt, sqlStmt.getPrimaryTable(), ((BaseContainerStore) backingStore).getOwnerMapping());
        SQLExpression existsOwnerExpr = sqlStmt.getRDBMSManager().getSQLExpressionFactory().newExpression(existsStmt, existsStmt.getPrimaryTable(), existsStmt.getPrimaryTable().getTable().getIdMapping());
        existsStmt.whereAnd(elemTblOwnerExpr.eq(existsOwnerExpr), true);
        // Select the owner candidate so we can separate the collection elements out to their owner
        int[] ownerColIndexes = sqlStmt.select(elemTblOwnerExpr, null);
        StatementMappingIndex ownerMapIdx = new StatementMappingIndex(existsStmt.getPrimaryTable().getTable().getIdMapping());
        ownerMapIdx.setColumnPositions(ownerColIndexes);
        iterStmt.setOwnerMapIndex(ownerMapIdx);
    }
    return iterStmt;
}
Also used : JoinArrayStore(org.datanucleus.store.rdbms.scostore.JoinArrayStore) HashSet(java.util.HashSet) Set(java.util.Set) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) IteratorStatement(org.datanucleus.store.rdbms.scostore.IteratorStatement) BaseContainerStore(org.datanucleus.store.rdbms.scostore.BaseContainerStore) JoinArrayStore(org.datanucleus.store.rdbms.scostore.JoinArrayStore) FKArrayStore(org.datanucleus.store.rdbms.scostore.FKArrayStore) JoinSetStore(org.datanucleus.store.rdbms.scostore.JoinSetStore) JoinListStore(org.datanucleus.store.rdbms.scostore.JoinListStore) FKListStore(org.datanucleus.store.rdbms.scostore.FKListStore) FKSetStore(org.datanucleus.store.rdbms.scostore.FKSetStore) Store(org.datanucleus.store.types.scostore.Store) SelectStatement(org.datanucleus.store.rdbms.sql.SelectStatement) JoinSetStore(org.datanucleus.store.rdbms.scostore.JoinSetStore) BooleanExpression(org.datanucleus.store.rdbms.sql.expression.BooleanExpression) FKArrayStore(org.datanucleus.store.rdbms.scostore.FKArrayStore) BaseContainerStore(org.datanucleus.store.rdbms.scostore.BaseContainerStore) HashSet(java.util.HashSet) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) JoinListStore(org.datanucleus.store.rdbms.scostore.JoinListStore) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) ExecutionContext(org.datanucleus.ExecutionContext) BooleanSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.BooleanSubqueryExpression) FKSetStore(org.datanucleus.store.rdbms.scostore.FKSetStore) FKListStore(org.datanucleus.store.rdbms.scostore.FKListStore) JoinTable(org.datanucleus.store.rdbms.table.JoinTable)

Example 3 with SelectStatement

use of org.datanucleus.store.rdbms.sql.SelectStatement in project datanucleus-rdbms by datanucleus.

the class BulkFetchHandler method applyParametersToStatement.

/**
 * Convenience method to apply the passed parameters to the provided bulk-fetch statement.
 * Takes care of applying parameters across any UNIONs of elements.
 * @param ec ExecutionContext
 * @param ps PreparedStatement
 * @param datastoreCompilation The datastore compilation for the query itself
 * @param sqlStmt The bulk-fetch iterator statement
 * @param parameters The map of parameters passed in to the query
 */
public static void applyParametersToStatement(ExecutionContext ec, PreparedStatement ps, RDBMSQueryCompilation datastoreCompilation, SQLStatement sqlStmt, Map parameters) {
    Map<Integer, String> stmtParamNameByPosition = null;
    List<SQLStatementParameter> stmtParams = null;
    if (datastoreCompilation.getStatementParameters() != null) {
        stmtParams = new ArrayList<>();
        stmtParams.addAll(datastoreCompilation.getStatementParameters());
        SelectStatement selectStmt = (SelectStatement) sqlStmt;
        int numUnions = selectStmt.getNumberOfUnions();
        for (int i = 0; i < numUnions; i++) {
            stmtParams.addAll(datastoreCompilation.getStatementParameters());
        }
        if (datastoreCompilation.getParameterNameByPosition() != null && datastoreCompilation.getParameterNameByPosition().size() > 0) {
            // ParameterNameByPosition is only populated with implicit parameters
            stmtParamNameByPosition = new HashMap<>();
            stmtParamNameByPosition.putAll(datastoreCompilation.getParameterNameByPosition());
            int numParams = stmtParamNameByPosition.size();
            for (int i = 0; i < numUnions; i++) {
                Iterator<Map.Entry<Integer, String>> paramEntryIter = datastoreCompilation.getParameterNameByPosition().entrySet().iterator();
                while (paramEntryIter.hasNext()) {
                    Map.Entry<Integer, String> paramEntry = paramEntryIter.next();
                    stmtParamNameByPosition.put(numParams * (i + 1) + paramEntry.getKey(), paramEntry.getValue());
                }
            }
        }
        SQLStatementHelper.applyParametersToStatement(ps, ec, stmtParams, stmtParamNameByPosition, parameters);
    }
}
Also used : SelectStatement(org.datanucleus.store.rdbms.sql.SelectStatement) SQLStatementParameter(org.datanucleus.store.rdbms.sql.SQLStatementParameter) HashMap(java.util.HashMap) Map(java.util.Map)

Example 4 with SelectStatement

use of org.datanucleus.store.rdbms.sql.SelectStatement in project datanucleus-rdbms by datanucleus.

the class JDOQLQuery method compileQueryToRetrieveCandidates.

/**
 * Method to set the statement (and parameter/results definitions) to retrieve all candidates.
 * This is used when we want to evaluate in-memory and so just retrieve all possible candidates
 * first.
 * @param parameters Input parameters (if known)
 * @param candidateCmd Metadata for the candidate class
 */
private void compileQueryToRetrieveCandidates(Map parameters, AbstractClassMetaData candidateCmd) {
    if (type != QueryType.SELECT) {
        return;
    }
    StatementClassMapping resultsDef = new StatementClassMapping();
    datastoreCompilation.setResultDefinitionForClass(resultsDef);
    // Generate statement for candidate(s)
    SelectStatement stmt = null;
    try {
        stmt = RDBMSQueryUtils.getStatementForCandidates((RDBMSStoreManager) getStoreManager(), null, candidateCmd, datastoreCompilation.getResultDefinitionForClass(), ec, candidateClass, subclasses, result, null, null, null);
    } 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", ne);
        statementReturnsEmpty = true;
        return;
    }
    if (stmt.allUnionsForSamePrimaryTable()) {
        // Select fetch-plan fields of candidate class
        SQLStatementHelper.selectFetchPlanOfCandidateInStatement(stmt, datastoreCompilation.getResultDefinitionForClass(), candidateCmd, getFetchPlan(), 1);
    } else {
        // Select id only since tables don't have same mappings or column names
        // TODO complete-table will come through here but maybe ought to be treated differently
        SQLStatementHelper.selectIdentityOfCandidateInStatement(stmt, datastoreCompilation.getResultDefinitionForClass(), candidateCmd);
    }
    datastoreCompilation.addStatement(stmt, stmt.getSQLText().toSQL(), false);
    datastoreCompilation.setStatementParameters(stmt.getSQLText().getParametersForStatement());
}
Also used : SelectStatement(org.datanucleus.store.rdbms.sql.SelectStatement) NucleusException(org.datanucleus.exceptions.NucleusException) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager)

Example 5 with SelectStatement

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

Aggregations

SelectStatement (org.datanucleus.store.rdbms.sql.SelectStatement)49 SQLExpression (org.datanucleus.store.rdbms.sql.expression.SQLExpression)36 SQLExpressionFactory (org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory)31 JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)30 DatastoreClass (org.datanucleus.store.rdbms.table.DatastoreClass)27 ClassLoaderResolver (org.datanucleus.ClassLoaderResolver)25 NucleusException (org.datanucleus.exceptions.NucleusException)25 SQLTable (org.datanucleus.store.rdbms.sql.SQLTable)24 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)19 RDBMSStoreManager (org.datanucleus.store.rdbms.RDBMSStoreManager)19 StatementClassMapping (org.datanucleus.store.rdbms.query.StatementClassMapping)19 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)16 ExecutionContext (org.datanucleus.ExecutionContext)14 StatementMappingIndex (org.datanucleus.store.rdbms.query.StatementMappingIndex)14 UnionStatementGenerator (org.datanucleus.store.rdbms.sql.UnionStatementGenerator)12 DiscriminatorStatementGenerator (org.datanucleus.store.rdbms.sql.DiscriminatorStatementGenerator)11 PreparedStatement (java.sql.PreparedStatement)10 ResultSet (java.sql.ResultSet)10 SQLException (java.sql.SQLException)10 NucleusDataStoreException (org.datanucleus.exceptions.NucleusDataStoreException)10