Search in sources :

Example 21 with JavaTypeMapping

use of org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping in project datanucleus-rdbms by datanucleus.

the class SQLQuery method getResultObjectFactoryForCandidateClass.

/**
 * Method to generate a ResultObjectFactory for converting rows of the provided ResultSet into instances of the candidate class.
 * Populates "stmtMappings".
 * @param rs The ResultSet
 * @return The ResultObjectFactory
 * @throws SQLException Thrown if an error occurs processing the ResultSet
 */
protected ResultObjectFactory getResultObjectFactoryForCandidateClass(ResultSet rs) throws SQLException {
    ClassLoaderResolver clr = ec.getClassLoaderResolver();
    RDBMSStoreManager storeMgr = (RDBMSStoreManager) getStoreManager();
    DatastoreAdapter dba = storeMgr.getDatastoreAdapter();
    // Create an index listing for ALL (fetchable) fields in the result class.
    final AbstractClassMetaData candidateCmd = ec.getMetaDataManager().getMetaDataForClass(candidateClass, clr);
    int fieldCount = candidateCmd.getNoOfManagedMembers() + candidateCmd.getNoOfInheritedManagedMembers();
    // Map of field numbers keyed by the column name
    Map columnFieldNumberMap = new HashMap();
    stmtMappings = new StatementMappingIndex[fieldCount];
    DatastoreClass tbl = storeMgr.getDatastoreClass(candidateClass.getName(), clr);
    for (int fieldNumber = 0; fieldNumber < fieldCount; ++fieldNumber) {
        AbstractMemberMetaData mmd = candidateCmd.getMetaDataForManagedMemberAtAbsolutePosition(fieldNumber);
        String fieldName = mmd.getName();
        Class fieldType = mmd.getType();
        JavaTypeMapping m = null;
        if (mmd.getPersistenceModifier() != FieldPersistenceModifier.NONE) {
            if (tbl != null) {
                // Get the field mapping from the candidate table
                m = tbl.getMemberMapping(mmd);
            } else {
                // Fall back to generating a mapping for this type - does this ever happen?
                m = storeMgr.getMappingManager().getMappingWithDatastoreMapping(fieldType, false, false, clr);
            }
            if (m.includeInFetchStatement()) {
                // Set mapping for this field since it can potentially be returned from a fetch
                String columnName = null;
                if (mmd.getColumnMetaData() != null && mmd.getColumnMetaData().length > 0) {
                    for (int colNum = 0; colNum < mmd.getColumnMetaData().length; colNum++) {
                        columnName = mmd.getColumnMetaData()[colNum].getName();
                        columnFieldNumberMap.put(columnName, Integer.valueOf(fieldNumber));
                    }
                } else {
                    columnName = storeMgr.getIdentifierFactory().newColumnIdentifier(fieldName, ec.getNucleusContext().getTypeManager().isDefaultEmbeddedType(fieldType), FieldRole.ROLE_NONE, false).getName();
                    columnFieldNumberMap.put(columnName, Integer.valueOf(fieldNumber));
                }
            } else {
            // Don't put anything in this position (field has no column in the result set)
            }
        } else {
        // Don't put anything in this position (field has no column in the result set)
        }
        stmtMappings[fieldNumber] = new StatementMappingIndex(m);
    }
    if (columnFieldNumberMap.size() == 0) {
        // None of the fields in the class have columns in the datastore table!
        throw new NucleusUserException(Localiser.msg("059030", candidateClass.getName())).setFatal();
    }
    // Generate id column field information for later checking the id is present
    DatastoreClass table = storeMgr.getDatastoreClass(candidateClass.getName(), clr);
    if (table == null) {
        AbstractClassMetaData[] cmds = storeMgr.getClassesManagingTableForClass(candidateCmd, clr);
        if (cmds != null && cmds.length == 1) {
            table = storeMgr.getDatastoreClass(cmds[0].getFullClassName(), clr);
        } else {
            throw new NucleusUserException("SQL query specified with class " + candidateClass.getName() + " but this doesn't have its own table, or is mapped to multiple tables. Unsupported");
        }
    }
    PersistableMapping idMapping = (PersistableMapping) table.getIdMapping();
    String[] idColNames = new String[idMapping.getNumberOfDatastoreMappings()];
    for (int i = 0; i < idMapping.getNumberOfDatastoreMappings(); i++) {
        idColNames[i] = idMapping.getDatastoreMapping(i).getColumn().getIdentifier().toString();
    }
    // Generate discriminator information for later checking it is present
    JavaTypeMapping discrimMapping = table.getSurrogateMapping(SurrogateColumnType.DISCRIMINATOR, false);
    String discrimColName = discrimMapping != null ? discrimMapping.getDatastoreMapping(0).getColumn().getIdentifier().toString() : null;
    // Generate version information for later checking it is present
    JavaTypeMapping versionMapping = table.getSurrogateMapping(SurrogateColumnType.VERSION, false);
    String versionColName = versionMapping != null ? versionMapping.getDatastoreMapping(0).getColumn().getIdentifier().toString() : null;
    // Go through the fields of the ResultSet and map to the required fields in the candidate
    ResultSetMetaData rsmd = rs.getMetaData();
    // TODO We put nothing in this, so what is it for?!
    HashSet remainingColumnNames = new HashSet(columnFieldNumberMap.size());
    int colCount = rsmd.getColumnCount();
    int[] datastoreIndex = null;
    int[] versionIndex = null;
    int[] discrimIndex = null;
    int[] matchedFieldNumbers = new int[colCount];
    int fieldNumberPosition = 0;
    for (int colNum = 1; colNum <= colCount; ++colNum) {
        String colName = rsmd.getColumnName(colNum);
        // Find the field for this column
        int fieldNumber = -1;
        Integer fieldNum = (Integer) columnFieldNumberMap.get(colName);
        if (fieldNum == null) {
            // Try column name in lowercase
            fieldNum = (Integer) columnFieldNumberMap.get(colName.toLowerCase());
            if (fieldNum == null) {
                // Try column name in UPPERCASE
                fieldNum = (Integer) columnFieldNumberMap.get(colName.toUpperCase());
            }
        }
        if (fieldNum != null) {
            fieldNumber = fieldNum.intValue();
        }
        if (fieldNumber >= 0) {
            int[] exprIndices = null;
            if (stmtMappings[fieldNumber].getColumnPositions() != null) {
                exprIndices = new int[stmtMappings[fieldNumber].getColumnPositions().length + 1];
                for (int i = 0; i < stmtMappings[fieldNumber].getColumnPositions().length; i++) {
                    exprIndices[i] = stmtMappings[fieldNumber].getColumnPositions()[i];
                }
                exprIndices[exprIndices.length - 1] = colNum;
            } else {
                exprIndices = new int[] { colNum };
            }
            stmtMappings[fieldNumber].setColumnPositions(exprIndices);
            remainingColumnNames.remove(colName);
            matchedFieldNumbers[fieldNumberPosition++] = fieldNumber;
        }
        if (discrimColName != null && colName.equals(discrimColName)) {
            // Identify the location of the discriminator column
            discrimIndex = new int[1];
            discrimIndex[0] = colNum;
        }
        if (versionColName != null && colName.equals(versionColName)) {
            // Identify the location of the version column
            versionIndex = new int[1];
            versionIndex[0] = colNum;
        }
        if (candidateCmd.getIdentityType() == IdentityType.DATASTORE) {
            // Check for existence of id column, allowing for any RDBMS using quoted identifiers
            if (columnNamesAreTheSame(dba, idColNames[0], colName)) {
                datastoreIndex = new int[1];
                datastoreIndex[0] = colNum;
            }
        }
    }
    // Set the field numbers found to match what we really have
    int[] fieldNumbers = new int[fieldNumberPosition];
    for (int i = 0; i < fieldNumberPosition; i++) {
        fieldNumbers[i] = matchedFieldNumbers[i];
    }
    StatementClassMapping mappingDefinition = new StatementClassMapping();
    for (int i = 0; i < fieldNumbers.length; i++) {
        mappingDefinition.addMappingForMember(fieldNumbers[i], stmtMappings[fieldNumbers[i]]);
    }
    if (datastoreIndex != null) {
        StatementMappingIndex datastoreMappingIdx = new StatementMappingIndex(table.getSurrogateMapping(SurrogateColumnType.DATASTORE_ID, false));
        datastoreMappingIdx.setColumnPositions(datastoreIndex);
        mappingDefinition.addMappingForMember(SurrogateColumnType.DATASTORE_ID.getFieldNumber(), datastoreMappingIdx);
    }
    if (discrimIndex != null) {
        StatementMappingIndex discrimMappingIdx = new StatementMappingIndex(table.getSurrogateMapping(SurrogateColumnType.DISCRIMINATOR, true));
        discrimMappingIdx.setColumnPositions(discrimIndex);
        mappingDefinition.addMappingForMember(SurrogateColumnType.DISCRIMINATOR.getFieldNumber(), discrimMappingIdx);
    }
    if (versionIndex != null) {
        StatementMappingIndex versionMappingIdx = new StatementMappingIndex(table.getSurrogateMapping(SurrogateColumnType.VERSION, true));
        versionMappingIdx.setColumnPositions(versionIndex);
        mappingDefinition.addMappingForMember(SurrogateColumnType.VERSION.getFieldNumber(), versionMappingIdx);
    }
    return new PersistentClassROF(ec, rs, ignoreCache, mappingDefinition, candidateCmd, getCandidateClass());
}
Also used : HashMap(java.util.HashMap) 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) ResultSetMetaData(java.sql.ResultSetMetaData) PersistableMapping(org.datanucleus.store.rdbms.mapping.java.PersistableMapping) DatastoreAdapter(org.datanucleus.store.rdbms.adapter.DatastoreAdapter) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) HashMap(java.util.HashMap) Map(java.util.Map) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData) HashSet(java.util.HashSet)

Example 22 with JavaTypeMapping

use of org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping 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 23 with JavaTypeMapping

use of org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping 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 24 with JavaTypeMapping

use of org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping 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 25 with JavaTypeMapping

use of org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping 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

JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)230 SQLExpression (org.datanucleus.store.rdbms.sql.expression.SQLExpression)96 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)82 RDBMSStoreManager (org.datanucleus.store.rdbms.RDBMSStoreManager)82 SQLExpressionFactory (org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory)81 DatastoreClass (org.datanucleus.store.rdbms.table.DatastoreClass)76 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)69 ArrayList (java.util.ArrayList)66 NucleusException (org.datanucleus.exceptions.NucleusException)57 ClassLoaderResolver (org.datanucleus.ClassLoaderResolver)50 NucleusUserException (org.datanucleus.exceptions.NucleusUserException)47 NumericExpression (org.datanucleus.store.rdbms.sql.expression.NumericExpression)43 SQLTable (org.datanucleus.store.rdbms.sql.SQLTable)37 PersistableMapping (org.datanucleus.store.rdbms.mapping.java.PersistableMapping)30 SelectStatement (org.datanucleus.store.rdbms.sql.SelectStatement)30 StringExpression (org.datanucleus.store.rdbms.sql.expression.StringExpression)27 List (java.util.List)25 ReferenceMapping (org.datanucleus.store.rdbms.mapping.java.ReferenceMapping)22 StatementMappingIndex (org.datanucleus.store.rdbms.query.StatementMappingIndex)21 StringLiteral (org.datanucleus.store.rdbms.sql.expression.StringLiteral)21