Search in sources :

Example 46 with AbstractClassMetaData

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

the class ExpressionUtils method getEqualityExpressionForObjectExpressions.

/**
 * Method to generate an equality/inequality expression between two ObjectExpressions.
 * Either or both of the expressions can be ObjectLiterals.
 * @param expr1 First expression
 * @param expr2 Second expression
 * @param equals Whether it is equality (otherwise inequality)
 * @return The expression
 */
public static BooleanExpression getEqualityExpressionForObjectExpressions(ObjectExpression expr1, ObjectExpression expr2, boolean equals) {
    SQLStatement stmt = expr1.stmt;
    RDBMSStoreManager storeMgr = stmt.getRDBMSManager();
    SQLExpressionFactory exprFactory = storeMgr.getSQLExpressionFactory();
    ClassLoaderResolver clr = stmt.getClassLoaderResolver();
    ApiAdapter api = storeMgr.getApiAdapter();
    if (expr1 instanceof ObjectLiteral && expr2 instanceof ObjectLiteral) {
        // ObjectLiterall == ObjectLiteral
        ObjectLiteral lit1 = (ObjectLiteral) expr1;
        ObjectLiteral lit2 = (ObjectLiteral) expr2;
        return new BooleanLiteral(stmt, expr1.mapping, equals ? lit1.getValue().equals(lit2.getValue()) : !lit1.getValue().equals(lit2.getValue()));
    } else if (expr1 instanceof ObjectLiteral || expr2 instanceof ObjectLiteral) {
        // ObjectExpression == ObjectLiteral, ObjectLiteral == ObjectExpression
        BooleanExpression bExpr = null;
        boolean secondIsLiteral = (expr2 instanceof ObjectLiteral);
        Object value = (!secondIsLiteral ? ((ObjectLiteral) expr1).getValue() : ((ObjectLiteral) expr2).getValue());
        if (IdentityUtils.isDatastoreIdentity(value)) {
            // Object is an OID
            Object valueKey = IdentityUtils.getTargetKeyForDatastoreIdentity(value);
            JavaTypeMapping m = storeMgr.getSQLExpressionFactory().getMappingForType(valueKey.getClass(), false);
            SQLExpression oidLit = exprFactory.newLiteral(stmt, m, valueKey);
            if (equals) {
                return (secondIsLiteral ? expr1.subExprs.getExpression(0).eq(oidLit) : expr2.subExprs.getExpression(0).eq(oidLit));
            }
            return (secondIsLiteral ? expr1.subExprs.getExpression(0).ne(oidLit) : expr2.subExprs.getExpression(0).ne(oidLit));
        } else if (IdentityUtils.isSingleFieldIdentity(value)) {
            // Object is SingleFieldIdentity
            Object valueKey = IdentityUtils.getTargetKeyForSingleFieldIdentity(value);
            // This used to use ((SingleFieldId)value).getTargetClass() for some reason, which contradicts the above datastore id method
            JavaTypeMapping m = storeMgr.getSQLExpressionFactory().getMappingForType(valueKey.getClass(), false);
            SQLExpression oidLit = exprFactory.newLiteral(stmt, m, valueKey);
            if (equals) {
                return (secondIsLiteral ? expr1.subExprs.getExpression(0).eq(oidLit) : expr2.subExprs.getExpression(0).eq(oidLit));
            }
            return (secondIsLiteral ? expr1.subExprs.getExpression(0).ne(oidLit) : expr2.subExprs.getExpression(0).ne(oidLit));
        } else {
            AbstractClassMetaData cmd = storeMgr.getNucleusContext().getMetaDataManager().getMetaDataForClass(value.getClass(), clr);
            if (cmd != null) {
                // Value is a persistable object
                if (cmd.getIdentityType() == IdentityType.APPLICATION) {
                    // Application identity
                    if (api.getIdForObject(value) != null) {
                        // Persistent PC object (FCO)
                        // Cater for composite PKs and parts of PK being PC mappings, and recursion
                        ObjectExpression expr = (secondIsLiteral ? expr1 : expr2);
                        JavaTypeMapping[] pkMappingsApp = new JavaTypeMapping[expr.subExprs.size()];
                        Object[] pkFieldValues = new Object[expr.subExprs.size()];
                        int position = 0;
                        ExecutionContext ec = api.getExecutionContext(value);
                        JavaTypeMapping thisMapping = expr.mapping;
                        if (expr.mapping instanceof ReferenceMapping) {
                            // "InterfaceField == value", so pick an implementation mapping that is castable
                            thisMapping = null;
                            ReferenceMapping refMapping = (ReferenceMapping) expr.mapping;
                            JavaTypeMapping[] implMappings = refMapping.getJavaTypeMapping();
                            for (int i = 0; i < implMappings.length; i++) {
                                Class implType = clr.classForName(implMappings[i].getType());
                                if (implType.isAssignableFrom(value.getClass())) {
                                    thisMapping = implMappings[i];
                                    break;
                                }
                            }
                        }
                        if (thisMapping == null) {
                            // Just return a (1=0) since no implementation castable
                            return exprFactory.newLiteral(stmt, expr1.mapping, false).eq(exprFactory.newLiteral(stmt, expr1.mapping, true));
                        }
                        for (int i = 0; i < cmd.getNoOfPrimaryKeyMembers(); i++) {
                            AbstractMemberMetaData mmd = cmd.getMetaDataForManagedMemberAtAbsolutePosition(cmd.getPKMemberPositions()[i]);
                            Object fieldValue = ExpressionUtils.getValueForMemberOfObject(ec, mmd, value);
                            JavaTypeMapping mapping = ((PersistableMapping) thisMapping).getJavaTypeMapping()[i];
                            if (mapping instanceof PersistableMapping) {
                                position = ExpressionUtils.populatePrimaryKeyMappingsValuesForPCMapping(pkMappingsApp, pkFieldValues, position, (PersistableMapping) mapping, cmd, mmd, fieldValue, storeMgr, clr);
                            } else {
                                pkMappingsApp[position] = mapping;
                                pkFieldValues[position] = fieldValue;
                                position++;
                            }
                        }
                        for (int i = 0; i < expr.subExprs.size(); i++) {
                            SQLExpression source = expr.subExprs.getExpression(i);
                            SQLExpression target = exprFactory.newLiteral(stmt, pkMappingsApp[i], pkFieldValues[i]);
                            BooleanExpression subExpr = (secondIsLiteral ? source.eq(target) : target.eq(source));
                            if (bExpr == null) {
                                bExpr = subExpr;
                            } else {
                                bExpr = bExpr.and(subExpr);
                            }
                        }
                    } else {
                        // PC object with no id (embedded, or transient maybe)
                        if (secondIsLiteral) {
                            for (int i = 0; i < expr1.subExprs.size(); i++) {
                                // Query should return nothing (so just do "(1 = 0)")
                                NucleusLogger.QUERY.warn(Localiser.msg("037003", value));
                                bExpr = exprFactory.newLiteral(stmt, expr1.mapping, false).eq(exprFactory.newLiteral(stmt, expr1.mapping, true));
                            // It is arguable that we should compare the id with null (as below)
                            /*bExpr = expr.eq(new NullLiteral(qs));*/
                            }
                        } else {
                            for (int i = 0; i < expr2.subExprs.size(); i++) {
                                // Query should return nothing (so just do "(1 = 0)")
                                NucleusLogger.QUERY.warn(Localiser.msg("037003", value));
                                bExpr = exprFactory.newLiteral(stmt, expr2.mapping, false).eq(exprFactory.newLiteral(stmt, expr2.mapping, true));
                            // It is arguable that we should compare the id with null (as below)
                            /*bExpr = expr.eq(new NullLiteral(qs));*/
                            }
                        }
                    }
                    // TODO Allow for !equals
                    return bExpr;
                } else if (cmd.getIdentityType() == IdentityType.DATASTORE) {
                    // Datastore identity
                    SQLExpression source = (secondIsLiteral ? expr1.subExprs.getExpression(0) : expr2.subExprs.getExpression(0));
                    JavaTypeMapping mapping = (secondIsLiteral ? expr1.mapping : expr2.mapping);
                    Object objectId = api.getIdForObject(value);
                    if (objectId == null) {
                        // PC object with no id (embedded, or transient maybe)
                        // Query should return nothing (so just do "(1 = 0)")
                        NucleusLogger.QUERY.warn(Localiser.msg("037003", value));
                        // TODO Allow for !equals
                        return exprFactory.newLiteral(stmt, mapping, false).eq(exprFactory.newLiteral(stmt, mapping, true));
                    // It is arguable that we should compare the id with null (as below)
                    /*bExpr = expr.eq(new NullLiteral(qs));*/
                    }
                    Object objectIdKey = IdentityUtils.getTargetKeyForDatastoreIdentity(objectId);
                    JavaTypeMapping m = storeMgr.getSQLExpressionFactory().getMappingForType(objectIdKey.getClass(), false);
                    SQLExpression oidExpr = exprFactory.newLiteral(stmt, m, objectIdKey);
                    if (equals) {
                        return source.eq(oidExpr);
                    }
                    return source.ne(oidExpr);
                }
            } else {
                // No metadata, so we either have an application identity, or any object
                String pcClassName = storeMgr.getClassNameForObjectID(value, clr, null);
                if (pcClassName != null) {
                    // Object is an application identity
                    cmd = storeMgr.getNucleusContext().getMetaDataManager().getMetaDataForClass(pcClassName, clr);
                    return (secondIsLiteral ? ExpressionUtils.getAppIdEqualityExpression(value, expr1, storeMgr, clr, cmd, null, null) : ExpressionUtils.getAppIdEqualityExpression(value, expr2, storeMgr, clr, cmd, null, null));
                // TODO Allow for !equals
                }
                // Value not persistable nor an identity, so return nothing "(1 = 0)"
                return exprFactory.newLiteral(stmt, expr1.mapping, false).eq(exprFactory.newLiteral(stmt, expr1.mapping, true));
            // TODO Allow for !equals
            }
        }
    } else {
        // ObjectExpression == ObjectExpression
        BooleanExpression resultExpr = null;
        for (int i = 0; i < expr1.subExprs.size(); i++) {
            SQLExpression sourceExpr = expr1.subExprs.getExpression(i);
            SQLExpression targetExpr = expr2.subExprs.getExpression(i);
            if (resultExpr == null) {
                resultExpr = sourceExpr.eq(targetExpr);
            } else {
                resultExpr = resultExpr.and(sourceExpr.eq(targetExpr));
            }
        }
        if (!equals) {
            resultExpr = new BooleanExpression(Expression.OP_NOT, resultExpr != null ? resultExpr.encloseInParentheses() : null);
        }
        return resultExpr;
    }
    return null;
}
Also used : ApiAdapter(org.datanucleus.api.ApiAdapter) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) SQLStatement(org.datanucleus.store.rdbms.sql.SQLStatement) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) PersistableMapping(org.datanucleus.store.rdbms.mapping.java.PersistableMapping) ExecutionContext(org.datanucleus.ExecutionContext) ReferenceMapping(org.datanucleus.store.rdbms.mapping.java.ReferenceMapping) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Example 47 with AbstractClassMetaData

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

the class CollectionContainsMethod method containsAsSubquery.

/**
 * Method to return an expression for Collection.contains using a subquery "EXISTS".
 * This is for use when there are "!contains" or "OR" operations in the filter.
 * Creates the following SQL,
 * <ul>
 * <li><b>Collection of NonPC using join table</b>
 * <pre>
 * SELECT 1 FROM JOIN_TBL A0_SUB
 * WHERE A0_SUB.JOIN_OWN_ID = A0.ID AND A0_SUB.JOIN_ELEM_ID = {elemExpr}
 * </pre>
 * </li>
 * <li><b>Collection of PC using join table</b>
 * <pre>
 * SELECT 1 FROM ELEM_TABLE A0_SUB INNER JOIN JOIN_TBL B0 ON ...
 * WHERE B0.JOIN_OWN_ID = A0.ID AND A0_SUB.ID = {elemExpr}
 * </pre>
 * </li>
 * <li><b>Collection of PC using FK</b>
 * <pre>
 * SELECT 1 FROM ELEM_TABLE A0_SUB
 * WHERE A0_SUB.OWN_ID = A0.ID AND A0_SUB.ID = {elemExpr}
 * </pre>
 * </li>
 * </ul>
 * and returns a BooleanSubqueryExpression ("EXISTS (subquery)")
 * @param stmt SQLStatement
 * @param collExpr Collection expression
 * @param elemExpr Expression for the element
 * @return Contains expression
 */
protected SQLExpression containsAsSubquery(SQLStatement stmt, CollectionExpression collExpr, SQLExpression elemExpr) {
    boolean elemIsUnbound = (elemExpr instanceof UnboundExpression);
    String varName = null;
    if (elemIsUnbound) {
        varName = ((UnboundExpression) elemExpr).getVariableName();
        NucleusLogger.QUERY.debug("collection.contains(" + elemExpr + ") binding unbound variable " + varName + " using SUBQUERY");
    }
    RDBMSStoreManager storeMgr = stmt.getRDBMSManager();
    SQLExpressionFactory exprFactory = stmt.getSQLExpressionFactory();
    ClassLoaderResolver clr = stmt.getQueryGenerator().getClassLoaderResolver();
    AbstractMemberMetaData mmd = collExpr.getJavaTypeMapping().getMemberMetaData();
    AbstractClassMetaData elemCmd = mmd.getCollection().getElementClassMetaData(clr);
    CollectionTable joinTbl = (CollectionTable) storeMgr.getTable(mmd);
    String elemType = mmd.getCollection().getElementType();
    if (elemIsUnbound) {
        Class varType = stmt.getQueryGenerator().getTypeOfVariable(varName);
        if (varType != null) {
            elemType = varType.getName();
            elemCmd = storeMgr.getMetaDataManager().getMetaDataForClass(elemType, clr);
        }
    }
    SelectStatement subStmt = null;
    if (joinTbl != null) {
        // JoinTable Collection
        if (elemCmd == null) {
            // Collection<Non-PC>
            subStmt = new SelectStatement(stmt, storeMgr, joinTbl, null, null);
            subStmt.setClassLoaderResolver(clr);
            JavaTypeMapping oneMapping = storeMgr.getMappingManager().getMapping(Integer.class);
            subStmt.select(exprFactory.newLiteral(subStmt, oneMapping, 1), null);
            // Restrict to collection owner
            JavaTypeMapping ownerMapping = ((JoinTable) joinTbl).getOwnerMapping();
            SQLExpression ownerExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), ownerMapping);
            SQLExpression ownerIdExpr = exprFactory.newExpression(stmt, collExpr.getSQLTable(), collExpr.getSQLTable().getTable().getIdMapping());
            subStmt.whereAnd(ownerExpr.eq(ownerIdExpr), true);
            SQLExpression elemIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), joinTbl.getElementMapping());
            if (elemIsUnbound) {
                // Bind the variable in the QueryGenerator
                stmt.getQueryGenerator().bindVariable(varName, null, elemIdExpr.getSQLTable(), elemIdExpr.getJavaTypeMapping());
            } else {
                // Add restrict to element
                addRestrictionOnElement(subStmt, elemIdExpr, elemExpr);
            }
        } else {
            // Collection<PC>
            DatastoreClass elemTbl = storeMgr.getDatastoreClass(elemType, clr);
            subStmt = new SelectStatement(stmt, storeMgr, elemTbl, null, null);
            subStmt.setClassLoaderResolver(clr);
            JavaTypeMapping oneMapping = storeMgr.getMappingManager().getMapping(Integer.class);
            subStmt.select(exprFactory.newLiteral(subStmt, oneMapping, 1), null);
            // Join to join table
            SQLTable joinSqlTbl = subStmt.join(JoinType.INNER_JOIN, subStmt.getPrimaryTable(), elemTbl.getIdMapping(), joinTbl, null, joinTbl.getElementMapping(), null, null, true, null);
            // Restrict to collection owner
            JavaTypeMapping ownerMapping = ((JoinTable) joinTbl).getOwnerMapping();
            SQLExpression ownerExpr = exprFactory.newExpression(subStmt, joinSqlTbl, ownerMapping);
            SQLExpression ownerIdExpr = exprFactory.newExpression(stmt, collExpr.getSQLTable(), collExpr.getSQLTable().getTable().getIdMapping());
            subStmt.whereAnd(ownerExpr.eq(ownerIdExpr), true);
            SQLExpression elemIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), elemTbl.getIdMapping());
            if (elemIsUnbound) {
                // Bind the variable in the QueryGenerator
                stmt.getQueryGenerator().bindVariable(varName, elemCmd, elemIdExpr.getSQLTable(), elemIdExpr.getJavaTypeMapping());
            } else {
                // Add restrict to element
                addRestrictionOnElement(subStmt, elemIdExpr, elemExpr);
            }
        }
    } else {
        // FK Collection
        DatastoreClass elemTbl = storeMgr.getDatastoreClass(mmd.getCollection().getElementType(), clr);
        subStmt = new SelectStatement(stmt, storeMgr, elemTbl, null, null);
        subStmt.setClassLoaderResolver(clr);
        JavaTypeMapping oneMapping = storeMgr.getMappingManager().getMapping(Integer.class);
        subStmt.select(exprFactory.newLiteral(subStmt, oneMapping, 1), null);
        // Restrict to collection owner
        JavaTypeMapping ownerMapping = null;
        if (mmd.getMappedBy() != null) {
            ownerMapping = elemTbl.getMemberMapping(mmd.getRelatedMemberMetaData(clr)[0]);
        } else {
            ownerMapping = elemTbl.getExternalMapping(mmd, MappingType.EXTERNAL_FK);
        }
        SQLExpression ownerExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), ownerMapping);
        SQLExpression ownerIdExpr = exprFactory.newExpression(stmt, collExpr.getSQLTable(), collExpr.getSQLTable().getTable().getIdMapping());
        subStmt.whereAnd(ownerExpr.eq(ownerIdExpr), true);
        if (elemIsUnbound) {
            SQLExpression elemIdExpr = null;
            if (!elemType.equals(mmd.getCollection().getElementType())) {
                // Variable is defined as a subclass of the declared type so add extra join to variable type
                DatastoreClass varTbl = storeMgr.getDatastoreClass(elemType, clr);
                SQLTable varSqlTbl = subStmt.join(JoinType.INNER_JOIN, subStmt.getPrimaryTable(), elemTbl.getIdMapping(), null, varTbl, null, varTbl.getIdMapping(), null, null, null, true, null);
                elemIdExpr = exprFactory.newExpression(subStmt, varSqlTbl, varTbl.getIdMapping());
            } else {
                elemIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), elemTbl.getIdMapping());
            }
            // Bind the variable in the QueryGenerator
            stmt.getQueryGenerator().bindVariable(varName, elemCmd, elemIdExpr.getSQLTable(), elemIdExpr.getJavaTypeMapping());
        } else {
            // Add restrict to element
            SQLExpression elemIdExpr = exprFactory.newExpression(subStmt, subStmt.getPrimaryTable(), elemTbl.getIdMapping());
            addRestrictionOnElement(subStmt, elemIdExpr, elemExpr);
        }
    }
    return new BooleanSubqueryExpression(stmt, "EXISTS", subStmt);
}
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) ClassLoaderResolver(org.datanucleus.ClassLoaderResolver) UnboundExpression(org.datanucleus.store.rdbms.sql.expression.UnboundExpression) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) RDBMSStoreManager(org.datanucleus.store.rdbms.RDBMSStoreManager) SelectStatement(org.datanucleus.store.rdbms.sql.SelectStatement) CollectionTable(org.datanucleus.store.rdbms.table.CollectionTable) BooleanSubqueryExpression(org.datanucleus.store.rdbms.sql.expression.BooleanSubqueryExpression) SQLTable(org.datanucleus.store.rdbms.sql.SQLTable) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) DatastoreClass(org.datanucleus.store.rdbms.table.DatastoreClass) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData) JoinTable(org.datanucleus.store.rdbms.table.JoinTable)

Example 48 with AbstractClassMetaData

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

the class ClassTable method getMetaDataForMember.

/**
 * Acessor for the FieldMetaData for the field with the specified name.
 * Searches the MetaData of all classes managed by this table.
 * Doesn't allow for cases where the table manages subclasses with the same field name.
 * In that case you should use the equivalent method passing FieldMetaData.
 * TODO Support subclasses with fields of the same name
 * TODO Use of this is discouraged since the fieldName is not fully qualified
 * and if a superclass-table inheritance is used we could have 2 fields of that name here.
 * @param memberName the field/property name
 * @return metadata for the member
 */
AbstractMemberMetaData getMetaDataForMember(String memberName) {
    // TODO Dont search "cmd" since it is included in "managedClassMetaData"
    AbstractMemberMetaData mmd = cmd.getMetaDataForMember(memberName);
    if (mmd == null) {
        Iterator<AbstractClassMetaData> iter = managedClassMetaData.iterator();
        while (iter.hasNext()) {
            AbstractClassMetaData theCmd = iter.next();
            final AbstractMemberMetaData foundMmd = theCmd.getMetaDataForMember(memberName);
            if (foundMmd != null) {
                if (mmd != null && (!mmd.toString().equalsIgnoreCase(foundMmd.toString()) || mmd.getType() != foundMmd.getType())) {
                    final String errMsg = "Table " + getIdentifier() + " manages at least 2 subclasses that both define a field \"" + memberName + "\", " + "and the fields' metadata is different or they have different type! That means you can get e.g. wrong fetch results.";
                    NucleusLogger.DATASTORE_SCHEMA.error(errMsg);
                    throw new NucleusException(errMsg).setFatal();
                }
                mmd = foundMmd;
            }
        }
    }
    return mmd;
}
Also used : MacroString(org.datanucleus.util.MacroString) NucleusException(org.datanucleus.exceptions.NucleusException) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData)

Example 49 with AbstractClassMetaData

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

the class ClassTable method getExpectedCandidateKeys.

/**
 * Accessor for the expected candidate keys for this table.
 * @return The expected candidate keys.
 */
protected List<CandidateKey> getExpectedCandidateKeys() {
    assertIsInitialized();
    // The candidate keys required by the basic table
    List<CandidateKey> candidateKeys = super.getExpectedCandidateKeys();
    // Add any constraints required for a FK map
    Iterator<CandidateKey> cks = candidateKeysByMapField.values().iterator();
    while (cks.hasNext()) {
        CandidateKey ck = cks.next();
        candidateKeys.add(ck);
    }
    // Add on any user-required candidate keys for the fields
    Set fieldNumbersSet = memberMappingsMap.keySet();
    Iterator iter = fieldNumbersSet.iterator();
    while (iter.hasNext()) {
        AbstractMemberMetaData fmd = (AbstractMemberMetaData) iter.next();
        JavaTypeMapping fieldMapping = memberMappingsMap.get(fmd);
        if (fieldMapping instanceof EmbeddedPCMapping) {
            // Add indexes for fields of this embedded PC object
            EmbeddedPCMapping embMapping = (EmbeddedPCMapping) fieldMapping;
            for (int i = 0; i < embMapping.getNumberOfJavaTypeMappings(); i++) {
                JavaTypeMapping embFieldMapping = embMapping.getJavaTypeMapping(i);
                UniqueMetaData umd = embFieldMapping.getMemberMetaData().getUniqueMetaData();
                if (umd != null) {
                    CandidateKey ck = TableUtils.getCandidateKeyForField(this, umd, embFieldMapping);
                    if (ck != null) {
                        candidateKeys.add(ck);
                    }
                }
            }
        } else {
            // Add any required candidate key for this field
            UniqueMetaData umd = fmd.getUniqueMetaData();
            if (umd != null) {
                CandidateKey ck = TableUtils.getCandidateKeyForField(this, umd, fieldMapping);
                if (ck != null) {
                    candidateKeys.add(ck);
                }
            }
        }
    }
    // Add on any user-required candidate keys for the class(es) as a whole (composite keys)
    Iterator<AbstractClassMetaData> cmdIter = managedClassMetaData.iterator();
    while (cmdIter.hasNext()) {
        AbstractClassMetaData thisCmd = cmdIter.next();
        List<UniqueMetaData> classCKs = thisCmd.getUniqueMetaData();
        if (classCKs != null) {
            for (UniqueMetaData unimd : classCKs) {
                CandidateKey ck = getCandidateKeyForUniqueMetaData(unimd);
                if (ck != null) {
                    candidateKeys.add(ck);
                }
            }
        }
    }
    if (cmd.getIdentityType() == IdentityType.APPLICATION) {
        // Make sure there is no reuse of PK fields that cause a duplicate index for the PK. Remove it if required
        PrimaryKey pk = getPrimaryKey();
        Iterator<CandidateKey> candidatesIter = candidateKeys.iterator();
        while (candidatesIter.hasNext()) {
            CandidateKey key = candidatesIter.next();
            if (key.getColumnList().equals(pk.getColumnList())) {
                NucleusLogger.DATASTORE_SCHEMA.debug("Candidate key " + key + " is for the same columns as the PrimaryKey so being removed from expected set of candidates. PK is always unique");
                candidatesIter.remove();
            }
        }
    }
    return candidateKeys;
}
Also used : Set(java.util.Set) HashSet(java.util.HashSet) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) EmbeddedPCMapping(org.datanucleus.store.rdbms.mapping.java.EmbeddedPCMapping) PrimaryKey(org.datanucleus.store.rdbms.key.PrimaryKey) UniqueMetaData(org.datanucleus.metadata.UniqueMetaData) CandidateKey(org.datanucleus.store.rdbms.key.CandidateKey) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) Iterator(java.util.Iterator) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData)

Example 50 with AbstractClassMetaData

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

the class ClassTable method initializeFKMapUniqueConstraints.

/**
 * Method to initialise unique constraints for 1-N Map using FK.
 * @param ownerMmd metadata for the field/property with the map in the owner class
 */
private void initializeFKMapUniqueConstraints(AbstractMemberMetaData ownerMmd) {
    // Load "mapped-by"
    AbstractMemberMetaData mfmd = null;
    // Field in our class that maps back to the owner class
    String map_field_name = ownerMmd.getMappedBy();
    if (map_field_name != null) {
        // Bidirectional
        mfmd = cmd.getMetaDataForMember(map_field_name);
        if (mfmd == null) {
            // Field not in primary class so may be in subclass so check all managed classes
            Iterator<AbstractClassMetaData> cmdIter = managedClassMetaData.iterator();
            while (cmdIter.hasNext()) {
                AbstractClassMetaData managedCmd = cmdIter.next();
                mfmd = managedCmd.getMetaDataForMember(map_field_name);
                if (mfmd != null) {
                    break;
                }
            }
        }
        if (mfmd == null) {
            // "mapped-by" refers to a field in our class that doesnt exist!
            throw new NucleusUserException(Localiser.msg("057036", map_field_name, cmd.getFullClassName(), ownerMmd.getFullFieldName()));
        }
        if (ownerMmd.getJoinMetaData() == null) {
            // Load field of key in value
            if (ownerMmd.getKeyMetaData() != null && ownerMmd.getKeyMetaData().getMappedBy() != null) {
                // Key field is stored in the value table
                AbstractMemberMetaData kmd = null;
                String key_field_name = ownerMmd.getKeyMetaData().getMappedBy();
                if (key_field_name != null) {
                    kmd = cmd.getMetaDataForMember(key_field_name);
                }
                if (kmd == null) {
                    // Field not in primary class so may be in subclass so check all managed classes
                    Iterator<AbstractClassMetaData> cmdIter = managedClassMetaData.iterator();
                    while (cmdIter.hasNext()) {
                        AbstractClassMetaData managedCmd = cmdIter.next();
                        kmd = managedCmd.getMetaDataForMember(key_field_name);
                        if (kmd != null) {
                            break;
                        }
                    }
                }
                if (kmd == null) {
                    throw new ClassDefinitionException(Localiser.msg("057007", mfmd.getFullFieldName(), key_field_name));
                }
                JavaTypeMapping ownerMapping = getMemberMapping(map_field_name);
                JavaTypeMapping keyMapping = getMemberMapping(kmd.getName());
                if (dba.supportsOption(DatastoreAdapter.NULLS_IN_CANDIDATE_KEYS) || (!ownerMapping.isNullable() && !keyMapping.isNullable())) {
                    // cannot do this so just omit it.
                    if (keyMapping.getTable() == this && ownerMapping.getTable() == this) {
                        CandidateKey ck = new CandidateKey(this, null);
                        // This HashSet is to avoid duplicate adding of columns.
                        HashSet addedColumns = new HashSet();
                        // Add columns for the owner field
                        int countOwnerFields = ownerMapping.getNumberOfDatastoreMappings();
                        for (int i = 0; i < countOwnerFields; i++) {
                            Column col = ownerMapping.getDatastoreMapping(i).getColumn();
                            addedColumns.add(col);
                            ck.addColumn(col);
                        }
                        // Add columns for the key field
                        int countKeyFields = keyMapping.getNumberOfDatastoreMappings();
                        for (int i = 0; i < countKeyFields; i++) {
                            Column col = keyMapping.getDatastoreMapping(i).getColumn();
                            if (!addedColumns.contains(col)) {
                                addedColumns.add(col);
                                ck.addColumn(col);
                            } else {
                                NucleusLogger.DATASTORE_SCHEMA.warn(Localiser.msg("057041", ownerMmd.getName()));
                            }
                        }
                        if (candidateKeysByMapField.put(mfmd, ck) != null) {
                            // We have multiple "mapped-by" coming to this field so give a warning that this may potentially
                            // cause problems. For example if they have the key field defined here for 2 different relations
                            // so you may get keys/values appearing in the other relation that shouldn't be.
                            // Logged as a WARNING for now.
                            // If there is a situation where this should throw an exception, please update this AND COMMENT WHY.
                            NucleusLogger.DATASTORE_SCHEMA.warn(Localiser.msg("057012", mfmd.getFullFieldName(), ownerMmd.getFullFieldName()));
                        }
                    }
                }
            } else if (ownerMmd.getValueMetaData() != null && ownerMmd.getValueMetaData().getMappedBy() != null) {
                // Value field is stored in the key table
                AbstractMemberMetaData vmd = null;
                String value_field_name = ownerMmd.getValueMetaData().getMappedBy();
                if (value_field_name != null) {
                    vmd = cmd.getMetaDataForMember(value_field_name);
                }
                if (vmd == null) {
                    throw new ClassDefinitionException(Localiser.msg("057008", mfmd));
                }
                JavaTypeMapping ownerMapping = getMemberMapping(map_field_name);
                JavaTypeMapping valueMapping = getMemberMapping(vmd.getName());
                if (dba.supportsOption(DatastoreAdapter.NULLS_IN_CANDIDATE_KEYS) || (!ownerMapping.isNullable() && !valueMapping.isNullable())) {
                    // cannot do this so just omit it.
                    if (valueMapping.getTable() == this && ownerMapping.getTable() == this) {
                        CandidateKey ck = new CandidateKey(this, null);
                        // This HashSet is to avoid duplicate adding of columns.
                        Set<Column> addedColumns = new HashSet<>();
                        // Add columns for the owner field
                        int countOwnerFields = ownerMapping.getNumberOfDatastoreMappings();
                        for (int i = 0; i < countOwnerFields; i++) {
                            Column col = ownerMapping.getDatastoreMapping(i).getColumn();
                            addedColumns.add(col);
                            ck.addColumn(col);
                        }
                        // Add columns for the value field
                        int countValueFields = valueMapping.getNumberOfDatastoreMappings();
                        for (int i = 0; i < countValueFields; i++) {
                            Column col = valueMapping.getDatastoreMapping(i).getColumn();
                            if (!addedColumns.contains(col)) {
                                addedColumns.add(col);
                                ck.addColumn(col);
                            } else {
                                NucleusLogger.DATASTORE_SCHEMA.warn(Localiser.msg("057042", ownerMmd.getName()));
                            }
                        }
                        if (candidateKeysByMapField.put(mfmd, ck) != null) {
                            // We have multiple "mapped-by" coming to this field so give a warning that this may potentially
                            // cause problems. For example if they have the key field defined here for 2 different relations
                            // so you may get keys/values appearing in the other relation that shouldn't be.
                            // Logged as a WARNING for now.
                            // If there is a situation where this should throw an exception, please update this AND COMMENT WHY.
                            NucleusLogger.DATASTORE_SCHEMA.warn(Localiser.msg("057012", mfmd.getFullFieldName(), ownerMmd.getFullFieldName()));
                        }
                    }
                }
            } else {
                // We can only have either the key stored in the value or the value stored in the key but nothing else!
                throw new ClassDefinitionException(Localiser.msg("057009", ownerMmd.getFullFieldName()));
            }
        }
    }
}
Also used : Set(java.util.Set) HashSet(java.util.HashSet) JavaTypeMapping(org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping) NucleusUserException(org.datanucleus.exceptions.NucleusUserException) MacroString(org.datanucleus.util.MacroString) AbstractClassMetaData(org.datanucleus.metadata.AbstractClassMetaData) CandidateKey(org.datanucleus.store.rdbms.key.CandidateKey) ClassDefinitionException(org.datanucleus.store.rdbms.exceptions.ClassDefinitionException) AbstractMemberMetaData(org.datanucleus.metadata.AbstractMemberMetaData) HashSet(java.util.HashSet)

Aggregations

AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)204 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)90 JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)69 ClassLoaderResolver (org.datanucleus.ClassLoaderResolver)59 DatastoreClass (org.datanucleus.store.rdbms.table.DatastoreClass)55 NucleusUserException (org.datanucleus.exceptions.NucleusUserException)42 RDBMSStoreManager (org.datanucleus.store.rdbms.RDBMSStoreManager)42 NucleusException (org.datanucleus.exceptions.NucleusException)37 MetaDataManager (org.datanucleus.metadata.MetaDataManager)37 ArrayList (java.util.ArrayList)31 SQLExpression (org.datanucleus.store.rdbms.sql.expression.SQLExpression)26 SQLTable (org.datanucleus.store.rdbms.sql.SQLTable)23 SQLExpressionFactory (org.datanucleus.store.rdbms.sql.expression.SQLExpressionFactory)22 ClassLoaderResolverImpl (org.datanucleus.ClassLoaderResolverImpl)19 MapTable (org.datanucleus.store.rdbms.table.MapTable)18 List (java.util.List)16 ObjectProvider (org.datanucleus.state.ObjectProvider)16 PersistableMapping (org.datanucleus.store.rdbms.mapping.java.PersistableMapping)16 SelectStatement (org.datanucleus.store.rdbms.sql.SelectStatement)16 Iterator (java.util.Iterator)15