Search in sources :

Example 1 with CandidateKey

use of org.datanucleus.store.rdbms.key.CandidateKey in project datanucleus-rdbms by datanucleus.

the class TableImpl method getExistingCandidateKeys.

/**
 * Accessor for the candidate keys for this table.
 * @param conn The JDBC Connection
 * @return Map of candidate keys
 * @throws SQLException Thrown when an error occurs in the JDBC call.
 */
private Map<DatastoreIdentifier, CandidateKey> getExistingCandidateKeys(Connection conn) throws SQLException {
    Map<DatastoreIdentifier, CandidateKey> candidateKeysByName = new HashMap<>();
    if (tableExistsInDatastore(conn)) {
        StoreSchemaHandler handler = storeMgr.getSchemaHandler();
        RDBMSTableIndexInfo tableIndexInfo = (RDBMSTableIndexInfo) handler.getSchemaData(conn, RDBMSSchemaHandler.TYPE_INDICES, new Object[] { this });
        IdentifierFactory idFactory = storeMgr.getIdentifierFactory();
        Iterator indexIter = tableIndexInfo.getChildren().iterator();
        while (indexIter.hasNext()) {
            IndexInfo indexInfo = (IndexInfo) indexIter.next();
            boolean isUnique = !((Boolean) indexInfo.getProperty("non_unique")).booleanValue();
            if (isUnique) {
                // No idea of why this was being used, so commented out (H2 v2 fails if enabled)
                // short idxType = ((Short)indexInfo.getProperty("type")).shortValue();
                // if (idxType == DatabaseMetaData.tableIndexStatistic)
                // {
                // // Ignore
                // continue;
                // }
                // Only utilise unique indexes
                String keyName = (String) indexInfo.getProperty("index_name");
                DatastoreIdentifier idxName = idFactory.newIdentifier(IdentifierType.CANDIDATE_KEY, keyName);
                CandidateKey key = candidateKeysByName.get(idxName);
                if (key == null) {
                    key = new CandidateKey(this, null);
                    key.setName(keyName);
                    candidateKeysByName.put(idxName, key);
                }
                // Set the column
                int colSeq = ((Short) indexInfo.getProperty("ordinal_position")).shortValue() - 1;
                DatastoreIdentifier colName = idFactory.newIdentifier(IdentifierType.COLUMN, (String) indexInfo.getProperty("column_name"));
                Column col = columnsByIdentifier.get(colName);
                if (col != null) {
                    key.setColumn(colSeq, col);
                }
            }
        }
    }
    return candidateKeysByName;
}
Also used : HashMap(java.util.HashMap) RDBMSTableIndexInfo(org.datanucleus.store.rdbms.schema.RDBMSTableIndexInfo) StoreSchemaHandler(org.datanucleus.store.schema.StoreSchemaHandler) RDBMSTableIndexInfo(org.datanucleus.store.rdbms.schema.RDBMSTableIndexInfo) IndexInfo(org.datanucleus.store.rdbms.schema.IndexInfo) IdentifierFactory(org.datanucleus.store.rdbms.identifier.IdentifierFactory) CandidateKey(org.datanucleus.store.rdbms.key.CandidateKey) DatastoreIdentifier(org.datanucleus.store.rdbms.identifier.DatastoreIdentifier) Iterator(java.util.Iterator)

Example 2 with CandidateKey

use of org.datanucleus.store.rdbms.key.CandidateKey in project datanucleus-rdbms by datanucleus.

the class TableImpl method getSQLAddCandidateKeyStatements.

/**
 * Get SQL statements to add expected Candidate Keys that are not yet on the
 * table. If the returned Map is empty, the current Candidate Key setup is correct.
 * @param actualCandidateKeysByName Actual Map of candidate keys
 * @return a Map with the SQL statements
 */
protected Map<String, String> getSQLAddCandidateKeyStatements(Map actualCandidateKeysByName) {
    assertIsInitialized();
    Map<String, String> stmtsByCKName = new HashMap<>();
    List<CandidateKey> expectedCandidateKeys = getExpectedCandidateKeys();
    Iterator<CandidateKey> i = expectedCandidateKeys.iterator();
    int n = 1;
    IdentifierFactory idFactory = storeMgr.getIdentifierFactory();
    while (i.hasNext()) {
        CandidateKey ck = i.next();
        if (!actualCandidateKeysByName.containsValue(ck)) {
            // If no name assigned, make one up
            if (ck.getName() == null) {
                // Use the CandidateKeyIdentifier to generate the name
                DatastoreIdentifier ckName;
                do {
                    ckName = idFactory.newCandidateKeyIdentifier(this, n++);
                } while (actualCandidateKeysByName.containsKey(ckName));
                ck.setName(ckName.getName());
            }
            String stmtText = dba.getAddCandidateKeyStatement(ck, idFactory);
            if (stmtText != null) {
                stmtsByCKName.put(ck.getName(), stmtText);
            }
        }
    }
    return stmtsByCKName;
}
Also used : HashMap(java.util.HashMap) DatastoreIdentifier(org.datanucleus.store.rdbms.identifier.DatastoreIdentifier) IdentifierFactory(org.datanucleus.store.rdbms.identifier.IdentifierFactory) CandidateKey(org.datanucleus.store.rdbms.key.CandidateKey)

Example 3 with CandidateKey

use of org.datanucleus.store.rdbms.key.CandidateKey in project datanucleus-rdbms by datanucleus.

the class TableUtils method getCandidateKeyForField.

/**
 * Convenience method to return the candidate key (if any) for a field.
 * @param table The table
 * @param umd The Unique MetaData
 * @param fieldMapping Mapping for the field
 * @return The Candidate Key
 */
public static CandidateKey getCandidateKeyForField(Table table, UniqueMetaData umd, JavaTypeMapping fieldMapping) {
    CandidateKey ck = new CandidateKey(table, umd != null ? umd.getExtensions() : null);
    // Set the key name if required
    if (umd.getName() != null) {
        IdentifierFactory idFactory = table.getStoreManager().getIdentifierFactory();
        DatastoreIdentifier ckId = idFactory.newIdentifier(IdentifierType.CANDIDATE_KEY, umd.getName());
        ck.setName(ckId.toString());
    }
    // Field-level index so use all columns for the field
    int countFields = fieldMapping.getNumberOfColumnMappings();
    for (int j = 0; j < countFields; j++) {
        ck.addColumn(fieldMapping.getColumnMapping(j).getColumn());
    }
    return ck;
}
Also used : DatastoreIdentifier(org.datanucleus.store.rdbms.identifier.DatastoreIdentifier) IdentifierFactory(org.datanucleus.store.rdbms.identifier.IdentifierFactory) CandidateKey(org.datanucleus.store.rdbms.key.CandidateKey)

Example 4 with CandidateKey

use of org.datanucleus.store.rdbms.key.CandidateKey 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.
 */
@Override
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 5 with CandidateKey

use of org.datanucleus.store.rdbms.key.CandidateKey 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.getNumberOfColumnMappings();
                        for (int i = 0; i < countOwnerFields; i++) {
                            Column col = ownerMapping.getColumnMapping(i).getColumn();
                            addedColumns.add(col);
                            ck.addColumn(col);
                        }
                        // Add columns for the key field
                        int countKeyFields = keyMapping.getNumberOfColumnMappings();
                        for (int i = 0; i < countKeyFields; i++) {
                            Column col = keyMapping.getColumnMapping(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.getNumberOfColumnMappings();
                        for (int i = 0; i < countOwnerFields; i++) {
                            Column col = ownerMapping.getColumnMapping(i).getColumn();
                            addedColumns.add(col);
                            ck.addColumn(col);
                        }
                        // Add columns for the value field
                        int countValueFields = valueMapping.getNumberOfColumnMappings();
                        for (int i = 0; i < countValueFields; i++) {
                            Column col = valueMapping.getColumnMapping(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

CandidateKey (org.datanucleus.store.rdbms.key.CandidateKey)9 IdentifierFactory (org.datanucleus.store.rdbms.identifier.IdentifierFactory)5 JavaTypeMapping (org.datanucleus.store.rdbms.mapping.java.JavaTypeMapping)5 NucleusUserException (org.datanucleus.exceptions.NucleusUserException)4 UniqueMetaData (org.datanucleus.metadata.UniqueMetaData)4 DatastoreIdentifier (org.datanucleus.store.rdbms.identifier.DatastoreIdentifier)4 AbstractMemberMetaData (org.datanucleus.metadata.AbstractMemberMetaData)3 HashMap (java.util.HashMap)2 HashSet (java.util.HashSet)2 Iterator (java.util.Iterator)2 Set (java.util.Set)2 AbstractClassMetaData (org.datanucleus.metadata.AbstractClassMetaData)2 MacroString (org.datanucleus.util.MacroString)2 ArrayList (java.util.ArrayList)1 List (java.util.List)1 ClassDefinitionException (org.datanucleus.store.rdbms.exceptions.ClassDefinitionException)1 PrimaryKey (org.datanucleus.store.rdbms.key.PrimaryKey)1 EmbeddedElementPCMapping (org.datanucleus.store.rdbms.mapping.java.EmbeddedElementPCMapping)1 EmbeddedKeyPCMapping (org.datanucleus.store.rdbms.mapping.java.EmbeddedKeyPCMapping)1 EmbeddedPCMapping (org.datanucleus.store.rdbms.mapping.java.EmbeddedPCMapping)1