From e9c05f115bad5d88f1ad44f544ba8b469971293b Mon Sep 17 00:00:00 2001 From: "Brian S. O'Neill" Date: Sun, 22 Apr 2007 01:09:36 +0000 Subject: Added primary key verification. --- .../carbonado/repo/sleepycat/BDBStorage.java | 147 +++++++++++++++++++-- 1 file changed, 136 insertions(+), 11 deletions(-) (limited to 'src/main/java/com/amazon/carbonado/repo/sleepycat') diff --git a/src/main/java/com/amazon/carbonado/repo/sleepycat/BDBStorage.java b/src/main/java/com/amazon/carbonado/repo/sleepycat/BDBStorage.java index 82ba789..d42b89f 100644 --- a/src/main/java/com/amazon/carbonado/repo/sleepycat/BDBStorage.java +++ b/src/main/java/com/amazon/carbonado/repo/sleepycat/BDBStorage.java @@ -24,6 +24,8 @@ import java.util.Map; import org.apache.commons.logging.LogFactory; +import org.cojen.classfile.TypeDesc; + import com.amazon.carbonado.Cursor; import com.amazon.carbonado.FetchException; import com.amazon.carbonado.IsolationLevel; @@ -447,16 +449,8 @@ abstract class BDBStorage implements Storage, Storag throw toRepositoryException(e); } - StorableIndex pkIndex; - - if (!isPrimaryEmpty && primaryInfo != null - && primaryInfo.getIndexNameDescriptor() != null) { - - // Entries already exist, so primary key format is locked in. - pkIndex = StorableIndex.parseNameDescriptor - (primaryInfo.getIndexNameDescriptor(), info); - // TODO: Verify index types match and throw error if not. - } else { + StorableIndex desiredPkIndex; + { // In order to select the best index for the primary key, allow all // indexes to be considered. StorableIndexSet indexSet = new StorableIndexSet(); @@ -466,7 +460,30 @@ abstract class BDBStorage implements Storage, Storag indexSet.reduce(Direction.ASCENDING); - pkIndex = indexSet.findPrimaryKeyIndex(info); + desiredPkIndex = indexSet.findPrimaryKeyIndex(info); + } + + StorableIndex pkIndex; + + if (!isPrimaryEmpty && primaryInfo != null + && primaryInfo.getIndexNameDescriptor() != null) + { + // Entries already exist, so primary key format is locked in. + try { + pkIndex = verifyPrimaryKey(info, desiredPkIndex, + primaryInfo.getIndexNameDescriptor(), + primaryInfo.getIndexTypeDescriptor()); + } catch (SupportException e) { + try { + db_close(primaryDatabase); + } catch (Exception e2) { + // Don't care. + } + throw e; + } + } else { + pkIndex = desiredPkIndex; + if (primaryInfo != null) { if (!pkIndex.getNameDescriptor().equals(primaryInfo.getIndexNameDescriptor()) || !pkIndex.getTypeDescriptor().equals(primaryInfo.getIndexTypeDescriptor())) { @@ -832,6 +849,114 @@ abstract class BDBStorage implements Storage, Storag } } + private StorableIndex verifyPrimaryKey(StorableInfo info, + StorableIndex desiredPkIndex, + String nameDescriptor, + String typeDescriptor) + throws SupportException + { + StorableIndex pkIndex; + try { + pkIndex = StorableIndex.parseNameDescriptor(nameDescriptor, info); + } catch (IllegalArgumentException e) { + throw new SupportException + ("Existing primary key apparently refers to properties which " + + "no longer exist. Primary key cannot change if Storage<" + + info.getStorableType().getName() + "> is not empty. " + + "Primary key name descriptor: " + nameDescriptor + ", error: " + + e.getMessage()); + } + + if (!nameDescriptor.equals(desiredPkIndex.getNameDescriptor())) { + throw new SupportException + (buildIndexMismatchMessage(info, pkIndex, desiredPkIndex, null, false)); + } + + if (!typeDescriptor.equals(desiredPkIndex.getTypeDescriptor())) { + throw new SupportException + (buildIndexMismatchMessage(info, pkIndex, desiredPkIndex, typeDescriptor, true)); + } + + return pkIndex; + } + + private String buildIndexMismatchMessage(StorableInfo info, + StorableIndex pkIndex, + StorableIndex desiredPkIndex, + String typeDescriptor, + boolean showDesiredType) + { + StringBuilder message = new StringBuilder(); + message.append("Cannot change primary key if Storage<" + info.getStorableType().getName() + + "> is not empty. Primary key was "); + appendIndexDecl(message, pkIndex, typeDescriptor, false); + message.append(", but new specification is "); + appendIndexDecl(message, desiredPkIndex, null, showDesiredType); + return message.toString(); + } + + private void appendIndexDecl(StringBuilder buf, StorableIndex index, + String typeDescriptor, boolean showDesiredType) + { + buf.append('['); + int count = index.getPropertyCount(); + + TypeDesc[] types = null; + boolean[] nullable = null; + + if (typeDescriptor != null) { + System.out.println(typeDescriptor); + types = new TypeDesc[count]; + nullable = new boolean[count]; + + try { + for (int i=0; i 0) { + buf.append(", "); + } + if (types != null) { + if (nullable[i]) { + buf.append("@Nullable "); + } + buf.append(types[i].getFullName()); + buf.append(' '); + } else if (showDesiredType) { + if (index.getProperty(i).isNullable()) { + buf.append("@Nullable "); + } + buf.append(TypeDesc.forClass(index.getProperty(i).getType()).getFullName()); + buf.append(' '); + } + buf.append(index.getPropertyDirection(i).toCharacter()); + buf.append(index.getProperty(i).getName()); + } + + buf.append(']'); + } + // Note: BDBStorage could just implement the RawSupport interface, but // then these hidden methods would be public. A simple cast of Storage to // RawSupport would expose them. -- cgit v1.2.3