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;
}
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;
}
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;
}
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;
}
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()));
}
}
}
}
Aggregations