Search in sources :

Example 11 with AbstractMemberMetaData

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

the class AbstractRDBMSQueryResult method registerMemberBulkResultSet.

public void registerMemberBulkResultSet(IteratorStatement iterStmt, ResultSet rs) {
    if (bulkLoadedValueByMemberNumber == null) {
        bulkLoadedValueByMemberNumber = new HashMap<>();
    }
    try {
        ExecutionContext ec = query.getExecutionContext();
        AbstractMemberMetaData mmd = iterStmt.getBackingStore().getOwnerMemberMetaData();
        if (mmd.hasCollection() || mmd.hasArray()) {
            ElementContainerStore backingStore = (ElementContainerStore) iterStmt.getBackingStore();
            if (backingStore.isElementsAreEmbedded() || backingStore.isElementsAreSerialised()) {
                int[] param = new int[backingStore.getElementMapping().getNumberOfDatastoreMappings()];
                for (int i = 0; i < param.length; ++i) {
                    param[i] = i + 1;
                }
                if (backingStore.getElementMapping() instanceof SerialisedPCMapping || backingStore.getElementMapping() instanceof SerialisedReferenceMapping || backingStore.getElementMapping() instanceof EmbeddedElementPCMapping) {
                    // Element = Serialised
                    while (rs.next()) {
                        Object owner = iterStmt.getOwnerMapIndex().getMapping().getObject(ec, rs, iterStmt.getOwnerMapIndex().getColumnPositions());
                        Object element = backingStore.getElementMapping().getObject(ec, rs, param, ec.findObjectProvider(owner), backingStore.getOwnerMemberMetaData().getAbsoluteFieldNumber());
                        addOwnerMemberValue(mmd, owner, element);
                    }
                } else {
                    // Element = Non-PC
                    while (rs.next()) {
                        Object owner = iterStmt.getOwnerMapIndex().getMapping().getObject(ec, rs, iterStmt.getOwnerMapIndex().getColumnPositions());
                        Object element = backingStore.getElementMapping().getObject(ec, rs, param);
                        addOwnerMemberValue(mmd, owner, element);
                    }
                }
            } else if (backingStore.getElementMapping() instanceof ReferenceMapping) {
                // Element is Reference (interface/Object) so just use elementMapping
                int[] param = new int[backingStore.getElementMapping().getNumberOfDatastoreMappings()];
                for (int i = 0; i < param.length; ++i) {
                    param[i] = i + 1;
                }
                while (rs.next()) {
                    Object owner = iterStmt.getOwnerMapIndex().getMapping().getObject(ec, rs, iterStmt.getOwnerMapIndex().getColumnPositions());
                    Object element = backingStore.getElementMapping().getObject(ec, rs, param);
                    addOwnerMemberValue(mmd, owner, element);
                }
            } else {
                String elementType = mmd.hasCollection() ? backingStore.getOwnerMemberMetaData().getCollection().getElementType() : backingStore.getOwnerMemberMetaData().getArray().getElementType();
                ResultObjectFactory<E> scoROF = new PersistentClassROF(ec, rs, query.getIgnoreCache(), iterStmt.getStatementClassMapping(), backingStore.getElementClassMetaData(), ec.getClassLoaderResolver().classForName(elementType));
                while (rs.next()) {
                    Object owner = iterStmt.getOwnerMapIndex().getMapping().getObject(ec, rs, iterStmt.getOwnerMapIndex().getColumnPositions());
                    Object element = scoROF.getObject();
                    addOwnerMemberValue(mmd, owner, element);
                }
            }
        } else if (mmd.hasMap()) {
        // TODO Cater for maps
        }
    } catch (SQLException sqle) {
        NucleusLogger.DATASTORE.error("Exception thrown processing bulk loaded field " + iterStmt.getBackingStore().getOwnerMemberMetaData().getFullFieldName(), sqle);
    } finally {
        // Close the ResultSet (and its Statement)
        try {
            Statement stmt = null;
            try {
                stmt = rs.getStatement();
                // Close the result set
                rs.close();
            } catch (SQLException e) {
                NucleusLogger.DATASTORE.error(Localiser.msg("052605", e));
            } finally {
                try {
                    if (stmt != null) {
                        // Close the original statement
                        stmt.close();
                    }
                } catch (SQLException e) {
                // Do nothing
                }
            }
        } finally {
            rs = null;
        }
    }
}
Also used : SerialisedReferenceMapping(org.datanucleus.store.rdbms.mapping.java.SerialisedReferenceMapping) SQLException(java.sql.SQLException) Statement(java.sql.Statement) IteratorStatement(org.datanucleus.store.rdbms.scostore.IteratorStatement) ElementContainerStore(org.datanucleus.store.rdbms.scostore.ElementContainerStore) EmbeddedElementPCMapping(org.datanucleus.store.rdbms.mapping.java.EmbeddedElementPCMapping) ExecutionContext(org.datanucleus.ExecutionContext) SerialisedReferenceMapping(org.datanucleus.store.rdbms.mapping.java.SerialisedReferenceMapping) ReferenceMapping(org.datanucleus.store.rdbms.mapping.java.ReferenceMapping) SerialisedPCMapping(org.datanucleus.store.rdbms.mapping.java.SerialisedPCMapping) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Example 12 with AbstractMemberMetaData

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

the class JDOQLQuery method compileInternal.

/**
 * Method to compile the JDOQL query.
 * Uses the superclass to compile the generic query populating the "compilation", and then generates
 * the datastore-specific "datastoreCompilation".
 * @param parameterValues Map of param values keyed by param name (if available at compile time)
 */
protected synchronized void compileInternal(Map parameterValues) {
    if (isCompiled()) {
        return;
    }
    if (getExtension("include-soft-deletes") != null) {
        // If using an extension that can change the datastore query then evict any existing compilation
        QueryManager qm = getQueryManager();
        qm.removeQueryCompilation(Query.LANGUAGE_JDOQL, getQueryCacheKey());
    }
    // Compile the generic query expressions
    super.compileInternal(parameterValues);
    boolean inMemory = evaluateInMemory();
    if (candidateCollection != null && inMemory) {
        // TODO Maybe apply the result class checks ?
        return;
    }
    // Create the SQL statement, and its result/parameter definitions
    RDBMSStoreManager storeMgr = (RDBMSStoreManager) getStoreManager();
    if (candidateClass == null) {
        throw new NucleusUserException(Localiser.msg("021009", candidateClassName));
    }
    // Make sure any persistence info is loaded
    ec.hasPersistenceInformationForClass(candidateClass);
    if (parameterValues != null) {
        // Check for null values on primitive parameters
        Set paramNames = parameterValues.entrySet();
        Iterator<Map.Entry> iter = paramNames.iterator();
        while (iter.hasNext()) {
            Map.Entry entry = iter.next();
            Object paramName = entry.getKey();
            if (paramName instanceof String) {
                Symbol sym = compilation.getSymbolTable().getSymbol((String) paramName);
                Object value = entry.getValue();
                if (value == null) {
                    // so omit the check for that case
                    if (sym != null && sym.getValueType() != null && sym.getValueType().isPrimitive()) {
                        throw new NucleusUserException(Localiser.msg("021117", paramName, sym.getValueType().getName()));
                    }
                }
            }
        }
    }
    QueryManager qm = getQueryManager();
    String datastoreKey = storeMgr.getQueryCacheKey();
    String queryCacheKey = getQueryCacheKey();
    if (useCaching() && queryCacheKey != null) {
        // Check if we have any parameters set to null, since this can invalidate a datastore compilation
        // e.g " field == :val" can be "COL IS NULL" or "COL = <val>"
        boolean nullParameter = false;
        if (parameterValues != null) {
            Iterator iter = parameterValues.values().iterator();
            while (iter.hasNext()) {
                Object val = iter.next();
                if (val == null) {
                    nullParameter = true;
                    break;
                }
            }
        }
        if (!nullParameter) {
            // Allowing caching so try to find compiled (datastore) query
            datastoreCompilation = (RDBMSQueryCompilation) qm.getDatastoreQueryCompilation(datastoreKey, getLanguage(), queryCacheKey);
            if (datastoreCompilation != null) {
                // Cached compilation exists for this datastore so reuse it
                setResultDistinct(compilation.getResultDistinct());
                return;
            }
        }
    }
    // Compile the query for the datastore since not cached
    AbstractClassMetaData acmd = getCandidateClassMetaData();
    if (type == QueryType.BULK_UPDATE) {
        datastoreCompilation = new RDBMSQueryCompilation();
        compileQueryUpdate(parameterValues, acmd);
    } else if (type == QueryType.BULK_DELETE) {
        datastoreCompilation = new RDBMSQueryCompilation();
        compileQueryDelete(parameterValues, acmd);
    } else {
        datastoreCompilation = new RDBMSQueryCompilation();
        synchronized (datastoreCompilation) {
            if (inMemory) {
                // Generate statement to just retrieve all candidate objects for later processing
                compileQueryToRetrieveCandidates(parameterValues, acmd);
            } else {
                // Generate statement to perform the full query in the datastore
                compileQueryFull(parameterValues, acmd);
                if (result != null) {
                    // Check existence of invalid selections in the result
                    StatementResultMapping resultMapping = datastoreCompilation.getResultDefinition();
                    for (int i = 0; i < resultMapping.getNumberOfResultExpressions(); i++) {
                        Object stmtMap = resultMapping.getMappingForResultExpression(i);
                        if (stmtMap instanceof StatementMappingIndex) {
                            StatementMappingIndex idx = (StatementMappingIndex) stmtMap;
                            AbstractMemberMetaData mmd = idx.getMapping().getMemberMetaData();
                            if (mmd != null) {
                                if (idx.getMapping() instanceof AbstractContainerMapping && idx.getMapping().getNumberOfDatastoreMappings() != 1) {
                                    throw new NucleusUserException(Localiser.msg("021213"));
                                }
                            }
                        }
                    }
                    if (resultClass != null) {
                        if (// Don't apply checks when user has specified the default (no result class)
                        !resultClass.getName().equals(Object[].class.getName())) {
                            // Check validity of resultClass for the result (PrivilegedAction since uses reflection)
                            AccessController.doPrivileged(new PrivilegedAction() {

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

Example 13 with AbstractMemberMetaData

use of org.datanucleus.metadata.AbstractMemberMetaData 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 14 with AbstractMemberMetaData

use of org.datanucleus.metadata.AbstractMemberMetaData 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 AbstractMemberMetaData

use of org.datanucleus.metadata.AbstractMemberMetaData 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

AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)267 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)89 ClassLoaderResolver (org.datanucleus.ClassLoaderResolver)84 JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)82 DatastoreClass (org.datanucleus.store.rdbms.table.DatastoreClass)59 ClassMetaData (org.datanucleus.metadata.ClassMetaData)55 NucleusUserException (org.datanucleus.exceptions.NucleusUserException)50 NucleusException (org.datanucleus.exceptions.NucleusException)41 MetaDataManager (org.datanucleus.metadata.MetaDataManager)40 RDBMSStoreManager (org.datanucleus.store.rdbms.RDBMSStoreManager)38 SQLExpression (org.datanucleus.store.rdbms.sql.expression.SQLExpression)35 RelationType (org.datanucleus.metadata.RelationType)33 NucleusContext (org.datanucleus.NucleusContext)32 PersistenceNucleusContextImpl (org.datanucleus.PersistenceNucleusContextImpl)32 JPAMetaDataManager (org.datanucleus.api.jpa.metadata.JPAMetaDataManager)29 SQLExpressionFactory (org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory)28 ColumnMetaData (org.datanucleus.metadata.ColumnMetaData)27 ExecutionContext (org.datanucleus.ExecutionContext)26 ObjectProvider (org.datanucleus.state.ObjectProvider)25 ArrayList (java.util.ArrayList)24