Search in sources :

Example 1 with PersistableIdMapping

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

the class QueryToSQLMapper method processParameterExpression.

/**
 * Method to process a parameter expression.
 * The optional argument controls whether we should create this as a parameter or as a literal (i.e the param value is known etc).
 * If the parameter doesn't have its value defined then returns ParameterLiteral otherwise we get an XXXLiteral of the (declared) type of the parameter
 * @param expr The ParameterExpression
 * @param asLiteral Whether to create a SQLLiteral rather than a parameter literal
 * @return The processed expression
 */
protected Object processParameterExpression(ParameterExpression expr, boolean asLiteral) {
    if (compileComponent == CompilationComponent.ORDERING || compileComponent == CompilationComponent.RESULT) {
        // All JDBC drivers I know don't allow parameters in the order-by, or update clause
        // Note that we also don't allow parameters in result clause since SQLStatement squashes all SELECT expression to a String so losing info about params
        asLiteral = true;
    } else if (compileComponent == CompilationComponent.UPDATE && processingCase && !storeMgr.getDatastoreAdapter().supportsOption(DatastoreAdapter.PARAMETER_IN_CASE_IN_UPDATE_CLAUSE)) {
        // This database doesn't support parameters within a CASE expression in the UPDATE clause, so process as a literal
        asLiteral = true;
    }
    if (expr.getPosition() >= 0) {
        if (paramNameByPosition == null) {
            paramNameByPosition = new HashMap<>();
        }
        paramNameByPosition.put(Integer.valueOf(expr.getPosition()), expr.getId());
    }
    // Find the parameter value if supplied
    Object paramValue = null;
    boolean paramValueSet = false;
    if (parameters != null && parameters.size() > 0) {
        // Check if the parameter has a value
        if (parameters.containsKey(expr.getId())) {
            // Named parameter
            paramValue = parameters.get(expr.getId());
            paramValueSet = true;
        } else if (parameterValueByName != null && parameterValueByName.containsKey(expr.getId())) {
            // Positional parameter, but already encountered
            paramValue = parameterValueByName.get(expr.getId());
            paramValueSet = true;
        } else {
            // Positional parameter, not yet encountered
            int position = positionalParamNumber;
            if (positionalParamNumber < 0) {
                position = 0;
            }
            if (parameters.containsKey(Integer.valueOf(position))) {
                paramValue = parameters.get(Integer.valueOf(position));
                paramValueSet = true;
                positionalParamNumber = position + 1;
                if (parameterValueByName == null) {
                    parameterValueByName = new HashMap<>();
                }
                parameterValueByName.put(expr.getId(), paramValue);
            }
        }
    }
    // Find the type to use for the parameter
    JavaTypeMapping m = paramMappingForName.get(expr.getId());
    if (m == null) {
        // Try to determine from provided parameter value or from symbol table (declared type)
        if (paramValue != null) {
            if (!storeMgr.getMetaDataManager().isClassPersistable(paramValue.getClass().getName()) && !paramValue.getClass().isArray() && !paramValue.getClass().isInterface() && !Collection.class.isAssignableFrom(paramValue.getClass()) && !Map.class.isAssignableFrom(paramValue.getClass()) && !storeMgr.getNucleusContext().getTypeManager().isSupportedSecondClassType(paramValue.getClass().getName())) {
                // Test for this being the "id" of a persistable object
                // Persistable/array/interface/collection/map/simple cannot be an object "id"
                String className = storeMgr.getClassNameForObjectID(paramValue, clr, ec);
                if (className != null) {
                    // Identity for persistable class
                    AbstractClassMetaData cmd = storeMgr.getMetaDataManager().getMetaDataForClass(className, clr);
                    if (cmd.getIdentityType() == IdentityType.APPLICATION) {
                        Class cls = clr.classForName(className);
                        m = exprFactory.getMappingForType(cls, false);
                        m = new PersistableIdMapping((PersistableMapping) m);
                    }
                }
            }
            if (m == null) {
                // Use the type of the input parameter value
                try {
                    m = exprFactory.getMappingForType(paramValue.getClass(), false);
                    if (m instanceof TypeConverterMapping && expr.getSymbol().getValueType() != null && expr.getSymbol().getValueType() != m.getJavaType()) {
                        // This is because if we have a parameter of type "ZoneInfo" it needs to use TimeZone since we have the TypeConverter for that
                        try {
                            m = exprFactory.getMappingForType(expr.getSymbol().getValueType(), false);
                        } catch (NucleusUserException nue) {
                        }
                    }
                } catch (NucleusUserException nue) {
                    // Maybe it needs a TypeConverter so try with the (declared) symbol type of this parameter
                    m = exprFactory.getMappingForType(expr.getSymbol().getValueType(), false);
                }
            }
            if (expr.getSymbol() != null && expr.getSymbol().getValueType() != null) {
                if (!QueryUtils.queryParameterTypesAreCompatible(expr.getSymbol().getValueType(), paramValue.getClass())) {
                    throw new QueryCompilerSyntaxException(Localiser.msg("021118", expr.getId(), expr.getSymbol().getValueType().getName(), paramValue.getClass().getName()));
                }
                if (expr.getSymbol().getValueType() != paramValue.getClass()) {
                    // Mark as not precompilable since the supplied type implies a subclass of the declared type
                    setNotPrecompilable();
                }
            }
        } else if (expr.getSymbol() != null && expr.getSymbol().getValueType() != null) {
            Class valueType = expr.getSymbol().getValueType();
            if (!paramValueSet) {
                if (valueType.isInterface()) {
                    // Special case where we have an interface parameter (not set), and don't know the type, so we pick the first implementation just to get something that works
                    // This is recompiled when the parameter is provided so is just for use in "compile()"
                    String[] implNames = storeMgr.getMetaDataManager().getClassesImplementingInterface(valueType.getName(), clr);
                    if (implNames != null && implNames.length > 0) {
                        valueType = clr.classForName(implNames[0]);
                        setNotPrecompilable();
                    }
                }
            }
            // Use the declared type of the parameter (explicit params)
            m = exprFactory.getMappingForType(valueType, false);
        }
    }
    if (asLiteral && m != null && !m.representableAsStringLiteralInStatement()) {
        // Must keep this as a parameter since its String form is no good in statements
        asLiteral = false;
    }
    if (asLiteral) {
        // Parameter being represented as a literal (for whatever reason), so no longer precompilable
        if (isPrecompilable()) {
            NucleusLogger.QUERY.debug("Parameter " + expr + " is being resolved as a literal, so the query is no longer precompilable");
        }
        setNotPrecompilable();
    } else if (paramValue == null && expr.getSymbol() != null) {
        if (isPrecompilable()) {
            NucleusLogger.QUERY.debug("Parameter " + expr + " is set to null so this has to be resolved as a NullLiteral, and the query is no longer precompilable");
        }
        setNotPrecompilable();
    }
    // Create the SQLExpression for this parameter, either as value-literal or as parameter-literal
    SQLExpression sqlExpr = null;
    if (paramValueSet && paramValue == null && options.contains(OPTION_NULL_PARAM_USE_IS_NULL)) {
        // Value is set to null, but we enforce a NullLiteral for the case of null comparisons e.g we don't want "field = ?", but instead "field IS NULL"
        sqlExpr = exprFactory.newLiteral(stmt, null, null);
    } else if (asLiteral) {
        // Create a value-literal as requested
        sqlExpr = exprFactory.newLiteral(stmt, m, paramValue);
    } else {
        // Create a parameter-literal with it tied to the parameter name for later replacement in the statement
        sqlExpr = exprFactory.newLiteralParameter(stmt, m, paramValue, expr.getId());
        if (sqlExpr instanceof ParameterLiteral) {
            ((ParameterLiteral) sqlExpr).setName(expr.getId());
        }
        if (expressionForParameter == null) {
            expressionForParameter = new HashMap<>();
        }
        expressionForParameter.put(expr.getId(), sqlExpr);
        paramMappingForName.put(expr.getId(), m);
    }
    stack.push(sqlExpr);
    return sqlExpr;
}
Also used : ParameterLiteral(org.datanucleus.store.rdbms.sql.expression.ParameterLiteral) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) HashMap(java.util.HashMap) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) PersistableIdMapping(org.datanucleus.store.rdbms.mapping.java.PersistableIdMapping) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) PersistableMapping(org.datanucleus.store.rdbms.mapping.java.PersistableMapping) TypeConverterMapping(org.datanucleus.store.rdbms.mapping.java.TypeConverterMapping) QueryCompilerSyntaxException(org.datanucleus.store.query.QueryCompilerSyntaxException) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) FetchPlanForClass(org.datanucleus.FetchPlanForClass) Map(java.util.Map) HashMap(java.util.HashMap)

Example 2 with PersistableIdMapping

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

the class SQLStatementHelper method applyParametersToStatement.

/**
 * Convenience method to apply parameter values to the provided statement.
 * @param ps The prepared statement
 * @param ec ExecutionContext
 * @param parameters The parameters
 * @param paramNameByPosition Optional map of parameter names keyed by the position
 * @param paramValuesByName Value of parameter keyed by name (or position)
 */
public static void applyParametersToStatement(PreparedStatement ps, ExecutionContext ec, List<SQLStatementParameter> parameters, Map<Integer, String> paramNameByPosition, Map paramValuesByName) {
    if (parameters != null) {
        int num = 1;
        Map<String, Integer> paramNumberByName = null;
        int nextParamNumber = 0;
        Iterator<SQLStatementParameter> i = parameters.iterator();
        while (i.hasNext()) {
            SQLStatementParameter param = i.next();
            JavaTypeMapping mapping = param.getMapping();
            RDBMSStoreManager storeMgr = mapping.getStoreManager();
            // Find the overall parameter value for this parameter
            Object value = null;
            if (paramNumberByName != null) {
                // Parameters are numbered but the query has named, so use lookup
                Integer position = paramNumberByName.get("" + param.getName());
                if (position == null) {
                    value = paramValuesByName.get(Integer.valueOf(nextParamNumber));
                    paramNumberByName.put(param.getName(), nextParamNumber);
                    nextParamNumber++;
                } else {
                    value = paramValuesByName.get(position);
                }
            } else {
                if (paramValuesByName.containsKey(param.getName())) {
                    // Named parameter has value in the input map
                    value = paramValuesByName.get(param.getName());
                } else {
                    // Named parameter doesn't have value, so maybe using numbered input params
                    if (paramNameByPosition != null) {
                        int paramPosition = -1;
                        Set<String> paramNamesEncountered = new HashSet<>();
                        for (Map.Entry<Integer, String> entry : paramNameByPosition.entrySet()) {
                            String paramName = entry.getValue();
                            if (!paramNamesEncountered.contains(paramName)) {
                                paramPosition++;
                                paramNamesEncountered.add(paramName);
                            }
                            if (paramName.equals(param.getName())) {
                                value = paramValuesByName.get(paramPosition);
                                break;
                            }
                        }
                        paramNamesEncountered.clear();
                        paramNamesEncountered = null;
                    } else {
                        try {
                            value = paramValuesByName.get(Integer.valueOf(param.getName()));
                        } catch (NumberFormatException nfe) {
                            value = paramValuesByName.get(Integer.valueOf(nextParamNumber));
                            paramNumberByName = new HashMap<>();
                            paramNumberByName.put(param.getName(), Integer.valueOf(nextParamNumber));
                            nextParamNumber++;
                        }
                    }
                }
            }
            AbstractClassMetaData cmd = ec.getMetaDataManager().getMetaDataForClass(mapping.getType(), ec.getClassLoaderResolver());
            if (param.getColumnNumber() >= 0 && cmd != null) {
                // Apply the value for this column of the mapping
                Object colValue = null;
                if (value != null) {
                    if (cmd.getIdentityType() == IdentityType.DATASTORE) {
                        colValue = mapping.getValueForDatastoreMapping(ec.getNucleusContext(), param.getColumnNumber(), value);
                    } else if (cmd.getIdentityType() == IdentityType.APPLICATION) {
                        colValue = getValueForPrimaryKeyIndexOfObjectUsingReflection(value, param.getColumnNumber(), cmd, storeMgr, ec.getClassLoaderResolver());
                    }
                }
                mapping.getDatastoreMapping(param.getColumnNumber()).setObject(ps, num, colValue);
            } else {
                // Apply the value as a whole
                if (ec.getApiAdapter().isPersistable(value)) {
                    if (!ec.getApiAdapter().isPersistent(value) && !ec.getApiAdapter().isDetached(value)) {
                        // Transient persistable object passed in as query parameter! We cannot simply use mapping.setObject since it will PERSIST the object
                        // See also JDO TCK Assertion ID: A14.6.2-44 "Comparisons between persistent and non-persistent instances return not equal"
                        boolean supported = false;
                        if (!supported) {
                            // Transient persistable object, so don't use (use null instead) since would cause its persistence
                            NucleusLogger.QUERY.warn("Attempt to use transient object as parameter in query. Not supported, so using NULL for parameter value");
                            mapping.setObject(ec, ps, MappingHelper.getMappingIndices(num, mapping), null);
                        }
                    } else if (ec.getApiAdapter().isDetached(value)) {
                        // Detached, so avoid re-attaching
                        Object id = ec.getApiAdapter().getIdForObject(value);
                        PersistableIdMapping idMapping = new PersistableIdMapping((PersistableMapping) mapping);
                        idMapping.setObject(ec, ps, MappingHelper.getMappingIndices(num, idMapping), id);
                    } else {
                        mapping.setObject(ec, ps, MappingHelper.getMappingIndices(num, mapping), value);
                    }
                } else {
                    if (mapping.getNumberOfDatastoreMappings() == 1) {
                        // Set whole object and only 1 column
                        mapping.setObject(ec, ps, MappingHelper.getMappingIndices(num, mapping), value);
                    } else if (mapping.getNumberOfDatastoreMappings() > 1 && param.getColumnNumber() == (mapping.getNumberOfDatastoreMappings() - 1)) {
                        // Set whole object and this is the last parameter entry for it, so set now
                        mapping.setObject(ec, ps, MappingHelper.getMappingIndices(num - mapping.getNumberOfDatastoreMappings() + 1, mapping), value);
                    }
                }
            }
            num++;
        }
    }
}
Also used : JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) HashMap(java.util.HashMap) PersistableIdMapping(org.datanucleus.store.rdbms.mapping.java.PersistableIdMapping) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) PersistableMapping(org.datanucleus.store.rdbms.mapping.java.PersistableMapping) Map(java.util.Map) HashMap(java.util.HashMap) HashSet(java.util.HashSet)

Example 3 with PersistableIdMapping

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

the class ObjectExpression method eq.

/**
 * Equals operator. Called when the query contains "obj == value" where "obj" is this object.
 * @param expr The expression we compare with (the right-hand-side in the query)
 * @return Boolean expression representing the comparison.
 */
public BooleanExpression eq(SQLExpression expr) {
    addSubexpressionsToRelatedExpression(expr);
    // TODO Implement checks
    if (mapping instanceof PersistableIdMapping) {
        // Special Case : OID comparison ("id == val")
        if (expr instanceof StringLiteral) {
            String oidString = (String) ((StringLiteral) expr).getValue();
            if (oidString != null) {
                AbstractClassMetaData cmd = stmt.getRDBMSManager().getMetaDataManager().getMetaDataForClass(mapping.getType(), stmt.getQueryGenerator().getClassLoaderResolver());
                if (cmd.getIdentityType() == IdentityType.DATASTORE) {
                    try {
                        Object id = stmt.getRDBMSManager().getNucleusContext().getIdentityManager().getDatastoreId(oidString);
                        if (id == null) {
                        // TODO Implement this comparison with the key value
                        }
                    } catch (IllegalArgumentException iae) {
                        NucleusLogger.QUERY.info("Attempted comparison of " + this + " and " + expr + " where the former is a datastore-identity and the latter is of incorrect form (" + oidString + ")");
                        SQLExpressionFactory exprFactory = stmt.getSQLExpressionFactory();
                        JavaTypeMapping m = exprFactory.getMappingForType(boolean.class, true);
                        return exprFactory.newLiteral(stmt, m, false).eq(exprFactory.newLiteral(stmt, m, true));
                    }
                } else if (cmd.getIdentityType() == IdentityType.APPLICATION) {
                // TODO Implement comparison with PK field(s)
                }
            }
        }
    }
    if (mapping instanceof ReferenceMapping && expr.mapping instanceof PersistableMapping) {
        return processComparisonOfImplementationWithReference(this, expr, false);
    } else if (mapping instanceof PersistableMapping && expr.mapping instanceof ReferenceMapping) {
        return processComparisonOfImplementationWithReference(expr, this, false);
    }
    BooleanExpression bExpr = null;
    if (isParameter() || expr.isParameter()) {
        if (subExprs != null && subExprs.size() > 1) {
            for (int i = 0; i < subExprs.size(); i++) {
                BooleanExpression subexpr = subExprs.getExpression(i).eq(((ObjectExpression) expr).subExprs.getExpression(i));
                bExpr = (bExpr == null ? subexpr : bExpr.and(subexpr));
            }
            return bExpr;
        }
        // Comparison with parameter, so just give boolean compare
        return new BooleanExpression(this, Expression.OP_EQ, expr);
    } else if (expr instanceof NullLiteral) {
        if (subExprs != null) {
            for (int i = 0; i < subExprs.size(); i++) {
                BooleanExpression subexpr = expr.eq(subExprs.getExpression(i));
                bExpr = (bExpr == null ? subexpr : bExpr.and(subexpr));
            }
        }
        return bExpr;
    } else if (literalIsValidForSimpleComparison(expr)) {
        if (subExprs != null && subExprs.size() > 1) {
            // More than 1 value to compare with a simple literal!
            return super.eq(expr);
        }
        // Just do a direct comparison with the basic literals
        return new BooleanExpression(this, Expression.OP_EQ, expr);
    } else if (expr instanceof ObjectExpression) {
        return ExpressionUtils.getEqualityExpressionForObjectExpressions(this, (ObjectExpression) expr, true);
    } else {
        if (subExprs == null) {
            // ObjectExpression for a function call
            return new BooleanExpression(this, Expression.OP_EQ, expr);
        }
        return super.eq(expr);
    }
}
Also used : JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) PersistableIdMapping(org.datanucleus.store.rdbms.mapping.java.PersistableIdMapping) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) PersistableMapping(org.datanucleus.store.rdbms.mapping.java.PersistableMapping) ReferenceMapping(org.datanucleus.store.rdbms.mapping.java.ReferenceMapping)

Example 4 with PersistableIdMapping

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

the class RDBMSStoreHelper method getClassNameForIdUsingDiscriminator.

/**
 * Utility that does a discriminator candidate query for the specified candidate and subclasses
 * and returns the class name of the instance that has the specified identity (if any).
 * @param storeMgr RDBMS StoreManager
 * @param ec execution context
 * @param id The id
 * @param cmd Metadata for the root candidate class
 * @return Name of the class with this identity (or null if none found)
 */
public static String getClassNameForIdUsingDiscriminator(RDBMSStoreManager storeMgr, ExecutionContext ec, Object id, AbstractClassMetaData cmd) {
    // Check for input error
    if (cmd == null || id == null) {
        return null;
    }
    SQLExpressionFactory exprFactory = storeMgr.getSQLExpressionFactory();
    ClassLoaderResolver clr = ec.getClassLoaderResolver();
    DatastoreClass primaryTable = storeMgr.getDatastoreClass(cmd.getFullClassName(), clr);
    // Form the query to find which one of these classes has the instance with this id
    DiscriminatorStatementGenerator stmtGen = new DiscriminatorStatementGenerator(storeMgr, clr, clr.classForName(cmd.getFullClassName()), true, null, null);
    stmtGen.setOption(SelectStatementGenerator.OPTION_RESTRICT_DISCRIM);
    SelectStatement sqlStmt = stmtGen.getStatement(ec);
    // Select the discriminator
    JavaTypeMapping discrimMapping = primaryTable.getSurrogateMapping(SurrogateColumnType.DISCRIMINATOR, true);
    SQLTable discrimSqlTbl = SQLStatementHelper.getSQLTableForMappingOfTable(sqlStmt, sqlStmt.getPrimaryTable(), discrimMapping);
    sqlStmt.select(discrimSqlTbl, discrimMapping, null);
    // Restrict to this id
    JavaTypeMapping idMapping = primaryTable.getIdMapping();
    JavaTypeMapping idParamMapping = new PersistableIdMapping((PersistableMapping) idMapping);
    SQLExpression sqlFldExpr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), idMapping);
    SQLExpression sqlFldVal = exprFactory.newLiteralParameter(sqlStmt, idParamMapping, id, "ID");
    sqlStmt.whereAnd(sqlFldExpr.eq(sqlFldVal), true);
    // Perform the query
    try {
        ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec);
        SQLController sqlControl = storeMgr.getSQLController();
        if (ec.getSerializeReadForClass(cmd.getFullClassName())) {
            sqlStmt.addExtension(SQLStatement.EXTENSION_LOCK_FOR_UPDATE, true);
        }
        try {
            PreparedStatement ps = SQLStatementHelper.getPreparedStatementForSQLStatement(sqlStmt, ec, mconn, null, null);
            String statement = sqlStmt.getSQLText().toSQL();
            try {
                ResultSet rs = sqlControl.executeStatementQuery(ec, mconn, statement, ps);
                try {
                    while (rs.next()) {
                        DiscriminatorMetaData dismd = discrimMapping.getTable().getDiscriminatorMetaData();
                        return RDBMSQueryUtils.getClassNameFromDiscriminatorResultSetRow(discrimMapping, dismd, rs, ec);
                    }
                } finally {
                    rs.close();
                }
            } finally {
                sqlControl.closeStatement(mconn, ps);
            }
        } finally {
            mconn.release();
        }
    } catch (SQLException sqe) {
        NucleusLogger.DATASTORE.error("Exception thrown on querying of discriminator for id", sqe);
        throw new NucleusDataStoreException(sqe.toString(), sqe);
    }
    return null;
}
Also used : SQLExpressionFactory(org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) SQLException(java.sql.SQLException) ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) PreparedStatement(java.sql.PreparedStatement) PersistableIdMapping(org.datanucleus.store.rdbms.mapping.java.PersistableIdMapping) DiscriminatorMetaData(org.datanucleus.metadata.DiscriminatorMetaData) SelectStatement(org.datanucleus.store.rdbms.sql.SelectStatement) NucleusDataStoreException(org.datanucleus.exceptions.NucleusDataStoreException) DiscriminatorStatementGenerator(org.datanucleus.store.rdbms.sql.DiscriminatorStatementGenerator) SQLTable(org.datanucleus.store.rdbms.sql.SQLTable) ResultSet(java.sql.ResultSet) ManagedConnection(org.datanucleus.store.connection.ManagedConnection) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass)

Example 5 with PersistableIdMapping

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

the class RDBMSStoreHelper method getClassNameForIdUsingUnion.

/**
 * Utility that does a union candidate query for the specified candidate(s) and subclasses
 * and returns the class name of the instance that has the specified identity (if any).
 * @param storeMgr RDBMS StoreManager
 * @param ec execution context
 * @param id The id
 * @param rootCmds Metadata for the classes at the root
 * @return Name of the class with this identity (or null if none found)
 */
public static String getClassNameForIdUsingUnion(RDBMSStoreManager storeMgr, ExecutionContext ec, Object id, List<AbstractClassMetaData> rootCmds) {
    // Check for input error
    if (rootCmds == null || rootCmds.isEmpty() || id == null) {
        return null;
    }
    SQLExpressionFactory exprFactory = storeMgr.getSQLExpressionFactory();
    ClassLoaderResolver clr = ec.getClassLoaderResolver();
    // Form a query UNIONing all possible root candidates (and their subclasses)
    Iterator<AbstractClassMetaData> rootCmdIter = rootCmds.iterator();
    // Metadata for sample class in the tree so we can check if needs locking
    AbstractClassMetaData sampleCmd = null;
    SelectStatement sqlStmtMain = null;
    while (rootCmdIter.hasNext()) {
        AbstractClassMetaData rootCmd = rootCmdIter.next();
        DatastoreClass rootTbl = storeMgr.getDatastoreClass(rootCmd.getFullClassName(), clr);
        InheritanceMetaData rootInhmd = rootCmd.getBaseAbstractClassMetaData().getInheritanceMetaData();
        if (rootInhmd.getStrategy() == InheritanceStrategy.COMPLETE_TABLE) {
            // COMPLETE TABLE so use one branch of UNION for each possible class
            if (rootTbl != null) {
                UnionStatementGenerator stmtGen = new UnionStatementGenerator(storeMgr, clr, clr.classForName(rootCmd.getFullClassName()), false, null, null);
                stmtGen.setOption(SelectStatementGenerator.OPTION_SELECT_DN_TYPE);
                if (sqlStmtMain == null) {
                    sampleCmd = rootCmd;
                    sqlStmtMain = stmtGen.getStatement(ec);
                    // WHERE (object id) = ?
                    JavaTypeMapping idMapping = sqlStmtMain.getPrimaryTable().getTable().getIdMapping();
                    JavaTypeMapping idParamMapping = new PersistableIdMapping((PersistableMapping) idMapping);
                    SQLExpression fieldExpr = exprFactory.newExpression(sqlStmtMain, sqlStmtMain.getPrimaryTable(), idMapping);
                    SQLExpression fieldVal = exprFactory.newLiteralParameter(sqlStmtMain, idParamMapping, id, "ID");
                    sqlStmtMain.whereAnd(fieldExpr.eq(fieldVal), true);
                } else {
                    SelectStatement sqlStmt = stmtGen.getStatement(ec);
                    // WHERE (object id) = ?
                    JavaTypeMapping idMapping = sqlStmt.getPrimaryTable().getTable().getIdMapping();
                    JavaTypeMapping idParamMapping = new PersistableIdMapping((PersistableMapping) idMapping);
                    SQLExpression fieldExpr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), idMapping);
                    SQLExpression fieldVal = exprFactory.newLiteralParameter(sqlStmt, idParamMapping, id, "ID");
                    sqlStmt.whereAnd(fieldExpr.eq(fieldVal), true);
                    sqlStmtMain.union(sqlStmt);
                }
            }
            Collection<String> rootSubclassNames = storeMgr.getSubClassesForClass(rootCmd.getFullClassName(), true, clr);
            for (String rootSubclassName : rootSubclassNames) {
                AbstractClassMetaData rootSubclassCmd = storeMgr.getMetaDataManager().getMetaDataForClass(rootSubclassName, clr);
                DatastoreClass rootSubclassTbl = storeMgr.getDatastoreClass(rootSubclassCmd.getFullClassName(), clr);
                if (rootSubclassTbl != null) {
                    UnionStatementGenerator stmtGen = new UnionStatementGenerator(storeMgr, clr, clr.classForName(rootSubclassCmd.getFullClassName()), false, null, null);
                    stmtGen.setOption(SelectStatementGenerator.OPTION_SELECT_DN_TYPE);
                    if (sqlStmtMain == null) {
                        sampleCmd = rootSubclassCmd;
                        sqlStmtMain = stmtGen.getStatement(ec);
                        // WHERE (object id) = ?
                        JavaTypeMapping idMapping = sqlStmtMain.getPrimaryTable().getTable().getIdMapping();
                        JavaTypeMapping idParamMapping = new PersistableIdMapping((PersistableMapping) idMapping);
                        SQLExpression fieldExpr = exprFactory.newExpression(sqlStmtMain, sqlStmtMain.getPrimaryTable(), idMapping);
                        SQLExpression fieldVal = exprFactory.newLiteralParameter(sqlStmtMain, idParamMapping, id, "ID");
                        sqlStmtMain.whereAnd(fieldExpr.eq(fieldVal), true);
                    } else {
                        SelectStatement sqlStmt = stmtGen.getStatement(ec);
                        // WHERE (object id) = ?
                        JavaTypeMapping idMapping = sqlStmt.getPrimaryTable().getTable().getIdMapping();
                        JavaTypeMapping idParamMapping = new PersistableIdMapping((PersistableMapping) idMapping);
                        SQLExpression fieldExpr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), idMapping);
                        SQLExpression fieldVal = exprFactory.newLiteralParameter(sqlStmt, idParamMapping, id, "ID");
                        sqlStmt.whereAnd(fieldExpr.eq(fieldVal), true);
                        sqlStmtMain.union(sqlStmt);
                    }
                }
            }
            continue;
        }
        if (rootTbl == null) {
            // Class must be using "subclass-table" (no table of its own) so find where it is
            AbstractClassMetaData[] subcmds = storeMgr.getClassesManagingTableForClass(rootCmd, clr);
            if (subcmds == null || subcmds.length == 0) {
            // No table for this class so ignore
            } else {
                for (int i = 0; i < subcmds.length; i++) {
                    UnionStatementGenerator stmtGen = new UnionStatementGenerator(storeMgr, clr, clr.classForName(subcmds[i].getFullClassName()), true, null, null);
                    stmtGen.setOption(SelectStatementGenerator.OPTION_SELECT_DN_TYPE);
                    if (sqlStmtMain == null) {
                        sampleCmd = subcmds[i];
                        sqlStmtMain = stmtGen.getStatement(ec);
                        // WHERE (object id) = ?
                        JavaTypeMapping idMapping = sqlStmtMain.getPrimaryTable().getTable().getIdMapping();
                        JavaTypeMapping idParamMapping = new PersistableIdMapping((PersistableMapping) idMapping);
                        SQLExpression fieldExpr = exprFactory.newExpression(sqlStmtMain, sqlStmtMain.getPrimaryTable(), idMapping);
                        SQLExpression fieldVal = exprFactory.newLiteralParameter(sqlStmtMain, idParamMapping, id, "ID");
                        sqlStmtMain.whereAnd(fieldExpr.eq(fieldVal), true);
                    } else {
                        SelectStatement sqlStmt = stmtGen.getStatement(ec);
                        // WHERE (object id) = ?
                        JavaTypeMapping idMapping = sqlStmt.getPrimaryTable().getTable().getIdMapping();
                        JavaTypeMapping idParamMapping = new PersistableIdMapping((PersistableMapping) idMapping);
                        SQLExpression fieldExpr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), idMapping);
                        SQLExpression fieldVal = exprFactory.newLiteralParameter(sqlStmt, idParamMapping, id, "ID");
                        sqlStmt.whereAnd(fieldExpr.eq(fieldVal), true);
                        sqlStmtMain.union(sqlStmt);
                    }
                }
            }
        } else {
            UnionStatementGenerator stmtGen = new UnionStatementGenerator(storeMgr, clr, clr.classForName(rootCmd.getFullClassName()), true, null, null);
            stmtGen.setOption(SelectStatementGenerator.OPTION_SELECT_DN_TYPE);
            if (sqlStmtMain == null) {
                sampleCmd = rootCmd;
                sqlStmtMain = stmtGen.getStatement(ec);
                // WHERE (object id) = ?
                JavaTypeMapping idMapping = sqlStmtMain.getPrimaryTable().getTable().getIdMapping();
                JavaTypeMapping idParamMapping = new PersistableIdMapping((PersistableMapping) idMapping);
                SQLExpression fieldExpr = exprFactory.newExpression(sqlStmtMain, sqlStmtMain.getPrimaryTable(), idMapping);
                SQLExpression fieldVal = exprFactory.newLiteralParameter(sqlStmtMain, idParamMapping, id, "ID");
                sqlStmtMain.whereAnd(fieldExpr.eq(fieldVal), true);
            } else {
                SelectStatement sqlStmt = stmtGen.getStatement(ec);
                // WHERE (object id) = ?
                JavaTypeMapping idMapping = sqlStmt.getPrimaryTable().getTable().getIdMapping();
                JavaTypeMapping idParamMapping = new PersistableIdMapping((PersistableMapping) idMapping);
                SQLExpression fieldExpr = exprFactory.newExpression(sqlStmt, sqlStmt.getPrimaryTable(), idMapping);
                SQLExpression fieldVal = exprFactory.newLiteralParameter(sqlStmt, idParamMapping, id, "ID");
                sqlStmt.whereAnd(fieldExpr.eq(fieldVal), true);
                sqlStmtMain.union(sqlStmt);
            }
        }
    }
    // Perform the query
    if (sqlStmtMain != null) {
        try {
            ManagedConnection mconn = storeMgr.getConnectionManager().getConnection(ec);
            SQLController sqlControl = storeMgr.getSQLController();
            if (sampleCmd != null && ec.getSerializeReadForClass(sampleCmd.getFullClassName())) {
                sqlStmtMain.addExtension(SQLStatement.EXTENSION_LOCK_FOR_UPDATE, true);
            }
            try {
                PreparedStatement ps = SQLStatementHelper.getPreparedStatementForSQLStatement(sqlStmtMain, ec, mconn, null, null);
                String statement = sqlStmtMain.getSQLText().toSQL();
                try {
                    ResultSet rs = sqlControl.executeStatementQuery(ec, mconn, statement, ps);
                    try {
                        while (rs.next()) {
                            try {
                                return rs.getString(UnionStatementGenerator.DN_TYPE_COLUMN).trim();
                            } catch (SQLException sqle) {
                            }
                        }
                    } finally {
                        rs.close();
                    }
                } finally {
                    sqlControl.closeStatement(mconn, ps);
                }
            } finally {
                mconn.release();
            }
        } catch (SQLException sqe) {
            NucleusLogger.DATASTORE.error("Exception with UNION statement", sqe);
            throw new NucleusDataStoreException(sqe.toString());
        }
    }
    return null;
}
Also used : SQLExpressionFactory(org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory) SQLExpression(org.datanucleus.store.rdbms.sql.expression.SQLExpression) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) SQLException(java.sql.SQLException) ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) PreparedStatement(java.sql.PreparedStatement) PersistableIdMapping(org.datanucleus.store.rdbms.mapping.java.PersistableIdMapping) InheritanceMetaData(org.datanucleus.metadata.InheritanceMetaData) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) UnionStatementGenerator(org.datanucleus.store.rdbms.sql.UnionStatementGenerator) SelectStatement(org.datanucleus.store.rdbms.sql.SelectStatement) NucleusDataStoreException(org.datanucleus.exceptions.NucleusDataStoreException) ResultSet(java.sql.ResultSet) ManagedConnection(org.datanucleus.store.connection.ManagedConnection) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass)

Aggregations

JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)6 PersistableIdMapping (org.datanucleus.store.rdbms.mapping.java.PersistableIdMapping)6 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)4 PersistableMapping (org.datanucleus.store.rdbms.mapping.java.PersistableMapping)4 SQLExpression (org.datanucleus.store.rdbms.sql.expression.SQLExpression)4 DatastoreClass (org.datanucleus.store.rdbms.table.DatastoreClass)3 PreparedStatement (java.sql.PreparedStatement)2 ResultSet (java.sql.ResultSet)2 SQLException (java.sql.SQLException)2 HashMap (java.util.HashMap)2 Map (java.util.Map)2 ClassLoaderResolver (org.datanucleus.ClassLoaderResolver)2 NucleusDataStoreException (org.datanucleus.exceptions.NucleusDataStoreException)2 NucleusUserException (org.datanucleus.exceptions.NucleusUserException)2 ManagedConnection (org.datanucleus.store.connection.ManagedConnection)2 RDBMSStoreManager (org.datanucleus.store.rdbms.RDBMSStoreManager)2 ReferenceMapping (org.datanucleus.store.rdbms.mapping.java.ReferenceMapping)2 SelectStatement (org.datanucleus.store.rdbms.sql.SelectStatement)2 SQLExpressionFactory (org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory)2 HashSet (java.util.HashSet)1