diff options
author | Jesse Morgan <jesse@jesterpm.net> | 2016-12-17 21:28:53 -0800 |
---|---|---|
committer | Jesse Morgan <jesse@jesterpm.net> | 2016-12-17 21:28:53 -0800 |
commit | 54df2afaa61c6a03cbb4a33c9b90fa572b6d07b8 (patch) | |
tree | 18147b92b969d25ffbe61935fb63035cac820dd0 /db-4.8.30/test/scr024/src/com/sleepycat/persist |
Berkeley DB 4.8 with rust build script for linux.
Diffstat (limited to 'db-4.8.30/test/scr024/src/com/sleepycat/persist')
19 files changed, 17975 insertions, 0 deletions
diff --git a/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/BindingTest.java b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/BindingTest.java new file mode 100644 index 0000000..504014e --- /dev/null +++ b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/BindingTest.java @@ -0,0 +1,2425 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2002-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +package com.sleepycat.persist.test; + +import static com.sleepycat.persist.model.Relationship.MANY_TO_ONE; +import static com.sleepycat.persist.model.Relationship.ONE_TO_MANY; +import static com.sleepycat.persist.model.Relationship.ONE_TO_ONE; + +import java.io.File; +import java.io.FileNotFoundException; +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.TreeSet; + +import junit.framework.TestCase; + +import com.sleepycat.bind.EntryBinding; +import com.sleepycat.compat.DbCompat; +import com.sleepycat.db.DatabaseConfig; +import com.sleepycat.db.DatabaseEntry; +import com.sleepycat.db.DatabaseException; +import com.sleepycat.db.Environment; +import com.sleepycat.db.EnvironmentConfig; +import com.sleepycat.db.ForeignMultiKeyNullifier; +import com.sleepycat.db.SecondaryKeyCreator; +import com.sleepycat.db.SecondaryMultiKeyCreator; +import com.sleepycat.persist.impl.PersistCatalog; +import com.sleepycat.persist.impl.PersistComparator; +import com.sleepycat.persist.impl.PersistEntityBinding; +import com.sleepycat.persist.impl.PersistKeyBinding; +import com.sleepycat.persist.impl.PersistKeyCreator; +import com.sleepycat.persist.impl.SimpleCatalog; +import com.sleepycat.persist.model.AnnotationModel; +import com.sleepycat.persist.model.ClassMetadata; +import com.sleepycat.persist.model.Entity; +import com.sleepycat.persist.model.EntityMetadata; +import com.sleepycat.persist.model.EntityModel; +import com.sleepycat.persist.model.KeyField; +import com.sleepycat.persist.model.Persistent; +import com.sleepycat.persist.model.PersistentProxy; +import com.sleepycat.persist.model.PrimaryKey; +import com.sleepycat.persist.model.PrimaryKeyMetadata; +import com.sleepycat.persist.model.SecondaryKey; +import com.sleepycat.persist.model.SecondaryKeyMetadata; +import com.sleepycat.persist.raw.RawField; +import com.sleepycat.persist.raw.RawObject; +import com.sleepycat.persist.raw.RawType; +import com.sleepycat.util.test.SharedTestUtils; +import com.sleepycat.util.test.TestEnv; + +/** + * @author Mark Hayes + */ +public class BindingTest extends TestCase { + + private static final String STORE_PREFIX = "persist#foo#"; + + private File envHome; + private Environment env; + private EntityModel model; + private PersistCatalog catalog; + private DatabaseEntry keyEntry; + private DatabaseEntry dataEntry; + + @Override + public void setUp() { + envHome = new File(System.getProperty(SharedTestUtils.DEST_DIR)); + SharedTestUtils.emptyDir(envHome); + keyEntry = new DatabaseEntry(); + dataEntry = new DatabaseEntry(); + } + + @Override + public void tearDown() { + if (env != null) { + try { + env.close(); + } catch (Exception e) { + System.out.println("During tearDown: " + e); + } + } + envHome = null; + env = null; + catalog = null; + keyEntry = null; + dataEntry = null; + } + + /** + * @throws FileNotFoundException from DB core. + */ + private void open() + throws FileNotFoundException, DatabaseException { + + EnvironmentConfig envConfig = TestEnv.BDB.getConfig(); + envConfig.setAllowCreate(true); + env = new Environment(envHome, envConfig); + openCatalog(); + } + + private void openCatalog() + throws DatabaseException { + + model = new AnnotationModel(); + model.registerClass(LocalizedTextProxy.class); + model.registerClass(LocaleProxy.class); + + DatabaseConfig dbConfig = new DatabaseConfig(); + dbConfig.setAllowCreate(true); + DbCompat.setTypeBtree(dbConfig); + catalog = new PersistCatalog + (null, env, STORE_PREFIX, STORE_PREFIX + "catalog", dbConfig, + model, null, false /*rawAccess*/, null /*Store*/); + } + + private void close() + throws DatabaseException { + + /* Close/open/close catalog to test checks for class evolution. */ + catalog.close(); + PersistCatalog.expectNoClassChanges = true; + try { + openCatalog(); + } finally { + PersistCatalog.expectNoClassChanges = false; + } + catalog.close(); + catalog = null; + + env.close(); + env = null; + } + + public void testBasic() + throws FileNotFoundException, DatabaseException { + + open(); + + checkEntity(Basic.class, + new Basic(1, "one", 2.2, "three")); + checkEntity(Basic.class, + new Basic(0, null, 0, null)); + checkEntity(Basic.class, + new Basic(-1, "xxx", -2, "xxx")); + + checkMetadata(Basic.class.getName(), new String[][] { + {"id", "long"}, + {"one", "java.lang.String"}, + {"two", "double"}, + {"three", "java.lang.String"}, + }, + 0 /*priKeyIndex*/, null); + + close(); + } + + @Entity + static class Basic implements MyEntity { + + @PrimaryKey + private long id; + private String one; + private double two; + private String three; + + private Basic() { } + + private Basic(long id, String one, double two, String three) { + this.id = id; + this.one = one; + this.two = two; + this.three = three; + } + + public String getBasicOne() { + return one; + } + + public Object getPriKeyObject() { + return id; + } + + public void validate(Object other) { + Basic o = (Basic) other; + TestCase.assertEquals(id, o.id); + TestCase.assertTrue(nullOrEqual(one, o.one)); + TestCase.assertEquals(two, o.two); + TestCase.assertTrue(nullOrEqual(three, o.three)); + if (one == three) { + TestCase.assertSame(o.one, o.three); + } + } + + @Override + public String toString() { + return "" + id + ' ' + one + ' ' + two; + } + } + + public void testSimpleTypes() + throws FileNotFoundException, DatabaseException { + + open(); + + checkEntity(SimpleTypes.class, new SimpleTypes()); + + checkMetadata(SimpleTypes.class.getName(), new String[][] { + {"f0", "boolean"}, + {"f1", "char"}, + {"f2", "byte"}, + {"f3", "short"}, + {"f4", "int"}, + {"f5", "long"}, + {"f6", "float"}, + {"f7", "double"}, + {"f8", "java.lang.String"}, + {"f9", "java.math.BigInteger"}, + //{"f10", "java.math.BigDecimal"}, + {"f11", "java.util.Date"}, + {"f12", "java.lang.Boolean"}, + {"f13", "java.lang.Character"}, + {"f14", "java.lang.Byte"}, + {"f15", "java.lang.Short"}, + {"f16", "java.lang.Integer"}, + {"f17", "java.lang.Long"}, + {"f18", "java.lang.Float"}, + {"f19", "java.lang.Double"}, + }, + 0 /*priKeyIndex*/, null); + + close(); + } + + @Entity + static class SimpleTypes implements MyEntity { + + @PrimaryKey + private final boolean f0 = true; + private final char f1 = 'a'; + private final byte f2 = 123; + private final short f3 = 123; + private final int f4 = 123; + private final long f5 = 123; + private final float f6 = 123.4f; + private final double f7 = 123.4; + private final String f8 = "xxx"; + private final BigInteger f9 = BigInteger.valueOf(123); + //private BigDecimal f10 = BigDecimal.valueOf(123.4); + private final Date f11 = new Date(); + private final Boolean f12 = true; + private final Character f13 = 'a'; + private final Byte f14 = 123; + private final Short f15 = 123; + private final Integer f16 = 123; + private final Long f17 = 123L; + private final Float f18 = 123.4f; + private final Double f19 = 123.4; + + SimpleTypes() { } + + public Object getPriKeyObject() { + return f0; + } + + public void validate(Object other) { + SimpleTypes o = (SimpleTypes) other; + TestCase.assertEquals(f0, o.f0); + TestCase.assertEquals(f1, o.f1); + TestCase.assertEquals(f2, o.f2); + TestCase.assertEquals(f3, o.f3); + TestCase.assertEquals(f4, o.f4); + TestCase.assertEquals(f5, o.f5); + TestCase.assertEquals(f6, o.f6); + TestCase.assertEquals(f7, o.f7); + TestCase.assertEquals(f8, o.f8); + TestCase.assertEquals(f9, o.f9); + //TestCase.assertEquals(f10, o.f10); + TestCase.assertEquals(f11, o.f11); + TestCase.assertEquals(f12, o.f12); + TestCase.assertEquals(f13, o.f13); + TestCase.assertEquals(f14, o.f14); + TestCase.assertEquals(f15, o.f15); + TestCase.assertEquals(f16, o.f16); + TestCase.assertEquals(f17, o.f17); + TestCase.assertEquals(f18, o.f18); + TestCase.assertEquals(f19, o.f19); + } + } + + public void testArrayTypes() + throws FileNotFoundException, DatabaseException { + + open(); + + checkEntity(ArrayTypes.class, new ArrayTypes()); + + checkMetadata(ArrayTypes.class.getName(), new String[][] { + {"id", "int"}, + {"f0", boolean[].class.getName()}, + {"f1", char[].class.getName()}, + {"f2", byte[].class.getName()}, + {"f3", short[].class.getName()}, + {"f4", int[].class.getName()}, + {"f5", long[].class.getName()}, + {"f6", float[].class.getName()}, + {"f7", double[].class.getName()}, + {"f8", String[].class.getName()}, + {"f9", Address[].class.getName()}, + {"f10", boolean[][][].class.getName()}, + {"f11", String[][][].class.getName()}, + }, + 0 /*priKeyIndex*/, null); + + close(); + } + + @Entity + static class ArrayTypes implements MyEntity { + + @PrimaryKey + private final int id = 1; + private final boolean[] f0 = {false, true}; + private final char[] f1 = {'a', 'b'}; + private final byte[] f2 = {1, 2}; + private final short[] f3 = {1, 2}; + private final int[] f4 = {1, 2}; + private final long[] f5 = {1, 2}; + private final float[] f6 = {1.1f, 2.2f}; + private final double[] f7 = {1.1, 2,2}; + private final String[] f8 = {"xxx", null, "yyy"}; + private final Address[] f9 = {new Address("city", "state", 123), + null, + new Address("x", "y", 444)}; + private final boolean[][][] f10 = + { + { + {false, true}, + {false, true}, + }, + null, + { + {false, true}, + {false, true}, + }, + }; + private final String[][][] f11 = + { + { + {"xxx", null, "yyy"}, + null, + {"xxx", null, "yyy"}, + }, + null, + { + {"xxx", null, "yyy"}, + null, + {"xxx", null, "yyy"}, + }, + }; + + ArrayTypes() { } + + public Object getPriKeyObject() { + return id; + } + + public void validate(Object other) { + ArrayTypes o = (ArrayTypes) other; + TestCase.assertEquals(id, o.id); + TestCase.assertTrue(Arrays.equals(f0, o.f0)); + TestCase.assertTrue(Arrays.equals(f1, o.f1)); + TestCase.assertTrue(Arrays.equals(f2, o.f2)); + TestCase.assertTrue(Arrays.equals(f3, o.f3)); + TestCase.assertTrue(Arrays.equals(f4, o.f4)); + TestCase.assertTrue(Arrays.equals(f5, o.f5)); + TestCase.assertTrue(Arrays.equals(f6, o.f6)); + TestCase.assertTrue(Arrays.equals(f7, o.f7)); + TestCase.assertTrue(Arrays.equals(f8, o.f8)); + TestCase.assertTrue(Arrays.deepEquals(f9, o.f9)); + TestCase.assertTrue(Arrays.deepEquals(f10, o.f10)); + TestCase.assertTrue(Arrays.deepEquals(f11, o.f11)); + } + } + + public void testEnumTypes() + throws FileNotFoundException, DatabaseException { + + open(); + + checkEntity(EnumTypes.class, new EnumTypes()); + + checkMetadata(EnumTypes.class.getName(), new String[][] { + {"f0", "int"}, + {"f1", Thread.State.class.getName()}, + {"f2", MyEnum.class.getName()}, + {"f3", Object.class.getName()}, + }, + 0 /*priKeyIndex*/, null); + + close(); + } + + enum MyEnum { ONE, TWO }; + + @Entity + static class EnumTypes implements MyEntity { + + @PrimaryKey + private final int f0 = 1; + private final Thread.State f1 = Thread.State.RUNNABLE; + private final MyEnum f2 = MyEnum.ONE; + private final Object f3 = MyEnum.TWO; + + EnumTypes() { } + + public Object getPriKeyObject() { + return f0; + } + + public void validate(Object other) { + EnumTypes o = (EnumTypes) other; + TestCase.assertEquals(f0, o.f0); + TestCase.assertSame(f1, o.f1); + TestCase.assertSame(f2, o.f2); + TestCase.assertSame(f3, o.f3); + } + } + + public void testProxyTypes() + throws FileNotFoundException, DatabaseException { + + open(); + + checkEntity(ProxyTypes.class, new ProxyTypes()); + + checkMetadata(ProxyTypes.class.getName(), new String[][] { + {"f0", "int"}, + {"f1", Locale.class.getName()}, + {"f2", Set.class.getName()}, + {"f3", Set.class.getName()}, + {"f4", Object.class.getName()}, + {"f5", HashMap.class.getName()}, + {"f6", TreeMap.class.getName()}, + {"f7", List.class.getName()}, + {"f8", LinkedList.class.getName()}, + {"f9", LocalizedText.class.getName()}, + }, + 0 /*priKeyIndex*/, null); + + close(); + } + + @Entity + static class ProxyTypes implements MyEntity { + + @PrimaryKey + private final int f0 = 1; + private final Locale f1 = Locale.getDefault(); + private final Set<Integer> f2 = new HashSet<Integer>(); + private final Set<Integer> f3 = new TreeSet<Integer>(); + private final Object f4 = new HashSet<Address>(); + private final HashMap<String,Integer> f5 = + new HashMap<String,Integer>(); + private final TreeMap<String,Address> f6 = + new TreeMap<String,Address>(); + private final List<Integer> f7 = new ArrayList<Integer>(); + private final LinkedList<Integer> f8 = new LinkedList<Integer>(); + private final LocalizedText f9 = new LocalizedText(f1, "xyz"); + + ProxyTypes() { + f2.add(123); + f2.add(456); + f3.add(456); + f3.add(123); + HashSet<Address> s = (HashSet) f4; + s.add(new Address("city", "state", 11111)); + s.add(new Address("city2", "state2", 22222)); + s.add(new Address("city3", "state3", 33333)); + f5.put("one", 111); + f5.put("two", 222); + f5.put("three", 333); + f6.put("one", new Address("city", "state", 11111)); + f6.put("two", new Address("city2", "state2", 22222)); + f6.put("three", new Address("city3", "state3", 33333)); + f7.add(123); + f7.add(456); + f8.add(123); + f8.add(456); + } + + public Object getPriKeyObject() { + return f0; + } + + public void validate(Object other) { + ProxyTypes o = (ProxyTypes) other; + TestCase.assertEquals(f0, o.f0); + TestCase.assertEquals(f1, o.f1); + TestCase.assertEquals(f2, o.f2); + TestCase.assertEquals(f3, o.f3); + TestCase.assertEquals(f4, o.f4); + TestCase.assertEquals(f5, o.f5); + TestCase.assertEquals(f6, o.f6); + TestCase.assertEquals(f7, o.f7); + TestCase.assertEquals(f8, o.f8); + TestCase.assertEquals(f9, o.f9); + } + } + + @Persistent(proxyFor=Locale.class) + static class LocaleProxy implements PersistentProxy<Locale> { + + String language; + String country; + String variant; + + private LocaleProxy() {} + + public void initializeProxy(Locale object) { + language = object.getLanguage(); + country = object.getCountry(); + variant = object.getVariant(); + } + + public Locale convertProxy() { + return new Locale(language, country, variant); + } + } + + static class LocalizedText { + + Locale locale; + String text; + + LocalizedText(Locale locale, String text) { + this.locale = locale; + this.text = text; + } + + @Override + public boolean equals(Object other) { + LocalizedText o = (LocalizedText) other; + return text.equals(o.text) && + locale.equals(o.locale); + } + } + + @Persistent(proxyFor=LocalizedText.class) + static class LocalizedTextProxy implements PersistentProxy<LocalizedText> { + + Locale locale; + String text; + + private LocalizedTextProxy() {} + + public void initializeProxy(LocalizedText object) { + locale = object.locale; + text = object.text; + } + + public LocalizedText convertProxy() { + return new LocalizedText(locale, text); + } + } + + public void testEmbedded() + throws FileNotFoundException, DatabaseException { + + open(); + + Address a1 = new Address("city", "state", 123); + Address a2 = new Address("Wikieup", "AZ", 85360); + + checkEntity(Embedded.class, + new Embedded("x", a1, a2)); + checkEntity(Embedded.class, + new Embedded("y", a1, null)); + checkEntity(Embedded.class, + new Embedded("", a2, a2)); + + checkMetadata(Embedded.class.getName(), new String[][] { + {"id", "java.lang.String"}, + {"idShadow", "java.lang.String"}, + {"one", Address.class.getName()}, + {"two", Address.class.getName()}, + }, + 0 /*priKeyIndex*/, null); + + checkMetadata(Address.class.getName(), new String[][] { + {"street", "java.lang.String"}, + {"city", "java.lang.String"}, + {"zip", "int"}, + }, + -1 /*priKeyIndex*/, null); + + close(); + } + + @Entity + static class Embedded implements MyEntity { + + @PrimaryKey + private String id; + private String idShadow; + private Address one; + private Address two; + + private Embedded() { } + + private Embedded(String id, Address one, Address two) { + this.id = id; + idShadow = id; + this.one = one; + this.two = two; + } + + public Object getPriKeyObject() { + return id; + } + + public void validate(Object other) { + Embedded o = (Embedded) other; + TestCase.assertEquals(id, o.id); + if (one != null) { + one.validate(o.one); + } else { + assertNull(o.one); + } + if (two != null) { + two.validate(o.two); + } else { + assertNull(o.two); + } + TestCase.assertSame(o.id, o.idShadow); + if (one == two) { + TestCase.assertSame(o.one, o.two); + } + } + + @Override + public String toString() { + return "" + id + ' ' + one + ' ' + two; + } + } + + @Persistent + static class Address { + + private String street; + private String city; + private int zip; + + private Address() {} + + Address(String street, String city, int zip) { + this.street = street; + this.city = city; + this.zip = zip; + } + + void validate(Address o) { + TestCase.assertTrue(nullOrEqual(street, o.street)); + TestCase.assertTrue(nullOrEqual(city, o.city)); + TestCase.assertEquals(zip, o.zip); + } + + @Override + public String toString() { + return "" + street + ' ' + city + ' ' + zip; + } + + @Override + public boolean equals(Object other) { + if (other == null) { + return false; + } + Address o = (Address) other; + return nullOrEqual(street, o.street) && + nullOrEqual(city, o.city) && + nullOrEqual(zip, o.zip); + } + + @Override + public int hashCode() { + return zip; + } + } + + public void testSubclass() + throws FileNotFoundException, DatabaseException { + + open(); + + checkEntity(Basic.class, + new Subclass(-1, "xxx", -2, "xxx", "xxx", true)); + + checkMetadata(Basic.class.getName(), new String[][] { + {"id", "long"}, + {"one", "java.lang.String"}, + {"two", "double"}, + {"three", "java.lang.String"}, + }, + 0 /*priKeyIndex*/, null); + checkMetadata(Subclass.class.getName(), new String[][] { + {"one", "java.lang.String"}, + {"two", "boolean"}, + }, + -1 /*priKeyIndex*/, Basic.class.getName()); + + close(); + } + + @Persistent + static class Subclass extends Basic { + + private String one; + private boolean two; + + private Subclass() { + } + + private Subclass(long id, String one, double two, String three, + String subOne, boolean subTwo) { + super(id, one, two, three); + this.one = subOne; + this.two = subTwo; + } + + @Override + public void validate(Object other) { + super.validate(other); + Subclass o = (Subclass) other; + TestCase.assertTrue(nullOrEqual(one, o.one)); + TestCase.assertEquals(two, o.two); + if (one == getBasicOne()) { + TestCase.assertSame(o.one, o.getBasicOne()); + } + } + } + + public void testSuperclass() + throws FileNotFoundException, DatabaseException { + + open(); + + checkEntity(UseSuperclass.class, + new UseSuperclass(33, "xxx")); + + checkMetadata(Superclass.class.getName(), new String[][] { + {"id", "int"}, + {"one", "java.lang.String"}, + }, + 0 /*priKeyIndex*/, null); + checkMetadata(UseSuperclass.class.getName(), new String[][] { + }, + -1 /*priKeyIndex*/, Superclass.class.getName()); + + close(); + } + + @Persistent + static class Superclass implements MyEntity { + + @PrimaryKey + private int id; + private String one; + + private Superclass() { } + + private Superclass(int id, String one) { + this.id = id; + this.one = one; + } + + public Object getPriKeyObject() { + return id; + } + + public void validate(Object other) { + Superclass o = (Superclass) other; + TestCase.assertEquals(id, o.id); + TestCase.assertTrue(nullOrEqual(one, o.one)); + } + } + + @Entity + static class UseSuperclass extends Superclass { + + private UseSuperclass() { } + + private UseSuperclass(int id, String one) { + super(id, one); + } + } + + public void testAbstract() + throws FileNotFoundException, DatabaseException { + + open(); + + checkEntity(EntityUseAbstract.class, + new EntityUseAbstract(33, "xxx")); + + checkMetadata(Abstract.class.getName(), new String[][] { + {"one", "java.lang.String"}, + }, + -1 /*priKeyIndex*/, null); + checkMetadata(EmbeddedUseAbstract.class.getName(), new String[][] { + {"two", "java.lang.String"}, + }, + -1 /*priKeyIndex*/, Abstract.class.getName()); + checkMetadata(EntityUseAbstract.class.getName(), new String[][] { + {"id", "int"}, + {"f1", EmbeddedUseAbstract.class.getName()}, + {"f2", Abstract.class.getName()}, + {"f3", Object.class.getName()}, + {"f4", Interface.class.getName()}, + {"a1", EmbeddedUseAbstract[].class.getName()}, + {"a2", Abstract[].class.getName()}, + {"a3", Abstract[].class.getName()}, + {"a4", Object[].class.getName()}, + {"a5", Interface[].class.getName()}, + {"a6", Interface[].class.getName()}, + {"a7", Interface[].class.getName()}, + }, + 0 /*priKeyIndex*/, Abstract.class.getName()); + + close(); + } + + @Persistent + static abstract class Abstract implements Interface { + + String one; + + private Abstract() { } + + private Abstract(String one) { + this.one = one; + } + + public void validate(Object other) { + Abstract o = (Abstract) other; + TestCase.assertTrue(nullOrEqual(one, o.one)); + } + + @Override + public boolean equals(Object other) { + Abstract o = (Abstract) other; + return nullOrEqual(one, o.one); + } + } + + interface Interface { + void validate(Object other); + } + + @Persistent + static class EmbeddedUseAbstract extends Abstract { + + private String two; + + private EmbeddedUseAbstract() { } + + private EmbeddedUseAbstract(String one, String two) { + super(one); + this.two = two; + } + + @Override + public void validate(Object other) { + super.validate(other); + EmbeddedUseAbstract o = (EmbeddedUseAbstract) other; + TestCase.assertTrue(nullOrEqual(two, o.two)); + } + + @Override + public boolean equals(Object other) { + if (!super.equals(other)) { + return false; + } + EmbeddedUseAbstract o = (EmbeddedUseAbstract) other; + return nullOrEqual(two, o.two); + } + } + + @Entity + static class EntityUseAbstract extends Abstract implements MyEntity { + + @PrimaryKey + private int id; + + private EmbeddedUseAbstract f1; + private Abstract f2; + private Object f3; + private Interface f4; + private EmbeddedUseAbstract[] a1; + private Abstract[] a2; + private Abstract[] a3; + private Object[] a4; + private Interface[] a5; + private Interface[] a6; + private Interface[] a7; + + private EntityUseAbstract() { } + + private EntityUseAbstract(int id, String one) { + super(one); + this.id = id; + f1 = new EmbeddedUseAbstract(one, one); + f2 = new EmbeddedUseAbstract(one + "x", one + "y"); + f3 = new EmbeddedUseAbstract(null, null); + f4 = new EmbeddedUseAbstract(null, null); + a1 = new EmbeddedUseAbstract[3]; + a2 = new EmbeddedUseAbstract[3]; + a3 = new Abstract[3]; + a4 = new Object[3]; + a5 = new EmbeddedUseAbstract[3]; + a6 = new Abstract[3]; + a7 = new Interface[3]; + for (int i = 0; i < 3; i += 1) { + a1[i] = new EmbeddedUseAbstract("1" + i, null); + a2[i] = new EmbeddedUseAbstract("2" + i, null); + a3[i] = new EmbeddedUseAbstract("3" + i, null); + a4[i] = new EmbeddedUseAbstract("4" + i, null); + a5[i] = new EmbeddedUseAbstract("5" + i, null); + a6[i] = new EmbeddedUseAbstract("6" + i, null); + a7[i] = new EmbeddedUseAbstract("7" + i, null); + } + } + + public Object getPriKeyObject() { + return id; + } + + @Override + public void validate(Object other) { + super.validate(other); + EntityUseAbstract o = (EntityUseAbstract) other; + TestCase.assertEquals(id, o.id); + f1.validate(o.f1); + assertSame(o.one, o.f1.one); + assertSame(o.f1.one, o.f1.two); + f2.validate(o.f2); + ((Abstract) f3).validate(o.f3); + f4.validate(o.f4); + assertTrue(arrayToString(a1) + ' ' + arrayToString(o.a1), + Arrays.equals(a1, o.a1)); + assertTrue(Arrays.equals(a2, o.a2)); + assertTrue(Arrays.equals(a3, o.a3)); + assertTrue(Arrays.equals(a4, o.a4)); + assertTrue(Arrays.equals(a5, o.a5)); + assertTrue(Arrays.equals(a6, o.a6)); + assertTrue(Arrays.equals(a7, o.a7)); + assertSame(EmbeddedUseAbstract.class, f2.getClass()); + assertSame(EmbeddedUseAbstract.class, f3.getClass()); + assertSame(EmbeddedUseAbstract[].class, a1.getClass()); + assertSame(EmbeddedUseAbstract[].class, a2.getClass()); + assertSame(Abstract[].class, a3.getClass()); + assertSame(Object[].class, a4.getClass()); + assertSame(EmbeddedUseAbstract[].class, a5.getClass()); + assertSame(Abstract[].class, a6.getClass()); + assertSame(Interface[].class, a7.getClass()); + } + } + + public void testCompositeKey() + throws FileNotFoundException, DatabaseException { + + open(); + + CompositeKey key = + new CompositeKey(123, 456L, "xyz", BigInteger.valueOf(789), + MyEnum.ONE); + checkEntity(UseCompositeKey.class, + new UseCompositeKey(key, "one")); + + checkMetadata(UseCompositeKey.class.getName(), new String[][] { + {"key", CompositeKey.class.getName()}, + {"one", "java.lang.String"}, + }, + 0 /*priKeyIndex*/, null); + + checkMetadata(CompositeKey.class.getName(), new String[][] { + {"f1", "int"}, + {"f2", "java.lang.Long"}, + {"f3", "java.lang.String"}, + {"f4", "java.math.BigInteger"}, + {"f5", MyEnum.class.getName()}, + }, + -1 /*priKeyIndex*/, null); + + close(); + } + + @Persistent + static class CompositeKey { + @KeyField(3) + private int f1; + @KeyField(2) + private Long f2; + @KeyField(1) + private String f3; + @KeyField(4) + private BigInteger f4; + @KeyField(5) + private MyEnum f5; + + private CompositeKey() {} + + CompositeKey(int f1, Long f2, String f3, BigInteger f4, MyEnum f5) { + this.f1 = f1; + this.f2 = f2; + this.f3 = f3; + this.f4 = f4; + this.f5 = f5; + } + + void validate(CompositeKey o) { + TestCase.assertEquals(f1, o.f1); + TestCase.assertTrue(nullOrEqual(f2, o.f2)); + TestCase.assertTrue(nullOrEqual(f3, o.f3)); + TestCase.assertTrue(nullOrEqual(f4, o.f4)); + TestCase.assertEquals(f5, o.f5); + TestCase.assertTrue(nullOrEqual(f5, o.f5)); + } + + @Override + public boolean equals(Object other) { + CompositeKey o = (CompositeKey) other; + return f1 == o.f1 && + nullOrEqual(f2, o.f2) && + nullOrEqual(f3, o.f3) && + nullOrEqual(f4, o.f4) && + nullOrEqual(f5, o.f5); + } + + @Override + public int hashCode() { + return f1; + } + + @Override + public String toString() { + return "" + f1 + ' ' + f2 + ' ' + f3 + ' ' + f4 + ' ' + f5; + } + } + + @Entity + static class UseCompositeKey implements MyEntity { + + @PrimaryKey + private CompositeKey key; + private String one; + + private UseCompositeKey() { } + + private UseCompositeKey(CompositeKey key, String one) { + this.key = key; + this.one = one; + } + + public Object getPriKeyObject() { + return key; + } + + public void validate(Object other) { + UseCompositeKey o = (UseCompositeKey) other; + TestCase.assertNotNull(key); + TestCase.assertNotNull(o.key); + key.validate(o.key); + TestCase.assertTrue(nullOrEqual(one, o.one)); + } + } + + public void testComparableKey() + throws FileNotFoundException, DatabaseException { + + open(); + + ComparableKey key = new ComparableKey(123, 456); + checkEntity(UseComparableKey.class, + new UseComparableKey(key, "one")); + + checkMetadata(UseComparableKey.class.getName(), new String[][] { + {"key", ComparableKey.class.getName()}, + {"one", "java.lang.String"}, + }, + 0 /*priKeyIndex*/, null); + + checkMetadata(ComparableKey.class.getName(), new String[][] { + {"f1", "int"}, + {"f2", "int"}, + }, + -1 /*priKeyIndex*/, null); + + ClassMetadata classMeta = + model.getClassMetadata(UseComparableKey.class.getName()); + assertNotNull(classMeta); + + PersistKeyBinding binding = new PersistKeyBinding + (catalog, ComparableKey.class.getName(), false); + + PersistComparator comparator = new PersistComparator + (/*ComparableKey.class.getName(), + classMeta.getCompositeKeyFields(),*/ + binding); + + compareKeys(comparator, binding, new ComparableKey(1, 1), + new ComparableKey(1, 1), 0); + compareKeys(comparator, binding, new ComparableKey(1, 2), + new ComparableKey(1, 1), -1); + compareKeys(comparator, binding, new ComparableKey(2, 1), + new ComparableKey(1, 1), -1); + compareKeys(comparator, binding, new ComparableKey(2, 1), + new ComparableKey(3, 1), 1); + + close(); + } + + private void compareKeys(Comparator<byte[]> comparator, + EntryBinding binding, + Object key1, + Object key2, + int expectResult) { + DatabaseEntry entry1 = new DatabaseEntry(); + DatabaseEntry entry2 = new DatabaseEntry(); + binding.objectToEntry(key1, entry1); + binding.objectToEntry(key2, entry2); + int result = comparator.compare(entry1.getData(), entry2.getData()); + assertEquals(expectResult, result); + } + + @Persistent + static class ComparableKey implements Comparable<ComparableKey> { + @KeyField(2) + private int f1; + @KeyField(1) + private int f2; + + private ComparableKey() {} + + ComparableKey(int f1, int f2) { + this.f1 = f1; + this.f2 = f2; + } + + void validate(ComparableKey o) { + TestCase.assertEquals(f1, o.f1); + TestCase.assertEquals(f2, o.f2); + } + + @Override + public boolean equals(Object other) { + ComparableKey o = (ComparableKey) other; + return f1 == o.f1 && f2 == o.f2; + } + + @Override + public int hashCode() { + return f1 + f2; + } + + @Override + public String toString() { + return "" + f1 + ' ' + f2; + } + + /** Compare f1 then f2, in reverse integer order. */ + public int compareTo(ComparableKey o) { + if (f1 != o.f1) { + return o.f1 - f1; + } else { + return o.f2 - f2; + } + } + } + + @Entity + static class UseComparableKey implements MyEntity { + + @PrimaryKey + private ComparableKey key; + private String one; + + private UseComparableKey() { } + + private UseComparableKey(ComparableKey key, String one) { + this.key = key; + this.one = one; + } + + public Object getPriKeyObject() { + return key; + } + + public void validate(Object other) { + UseComparableKey o = (UseComparableKey) other; + TestCase.assertNotNull(key); + TestCase.assertNotNull(o.key); + key.validate(o.key); + TestCase.assertTrue(nullOrEqual(one, o.one)); + } + } + + public void testSecKeys() + throws FileNotFoundException, DatabaseException { + + open(); + + SecKeys obj = new SecKeys(); + checkEntity(SecKeys.class, obj); + + checkMetadata(SecKeys.class.getName(), new String[][] { + {"id", "long"}, + {"f0", "boolean"}, + {"g0", "boolean"}, + {"f1", "char"}, + {"g1", "char"}, + {"f2", "byte"}, + {"g2", "byte"}, + {"f3", "short"}, + {"g3", "short"}, + {"f4", "int"}, + {"g4", "int"}, + {"f5", "long"}, + {"g5", "long"}, + {"f6", "float"}, + {"g6", "float"}, + {"f7", "double"}, + {"g7", "double"}, + {"f8", "java.lang.String"}, + {"g8", "java.lang.String"}, + {"f9", "java.math.BigInteger"}, + {"g9", "java.math.BigInteger"}, + //{"f10", "java.math.BigDecimal"}, + //{"g10", "java.math.BigDecimal"}, + {"f11", "java.util.Date"}, + {"g11", "java.util.Date"}, + {"f12", "java.lang.Boolean"}, + {"g12", "java.lang.Boolean"}, + {"f13", "java.lang.Character"}, + {"g13", "java.lang.Character"}, + {"f14", "java.lang.Byte"}, + {"g14", "java.lang.Byte"}, + {"f15", "java.lang.Short"}, + {"g15", "java.lang.Short"}, + {"f16", "java.lang.Integer"}, + {"g16", "java.lang.Integer"}, + {"f17", "java.lang.Long"}, + {"g17", "java.lang.Long"}, + {"f18", "java.lang.Float"}, + {"g18", "java.lang.Float"}, + {"f19", "java.lang.Double"}, + {"g19", "java.lang.Double"}, + {"f20", CompositeKey.class.getName()}, + {"g20", CompositeKey.class.getName()}, + {"f21", int[].class.getName()}, + {"g21", int[].class.getName()}, + {"f22", Integer[].class.getName()}, + {"g22", Integer[].class.getName()}, + {"f23", Set.class.getName()}, + {"g23", Set.class.getName()}, + {"f24", CompositeKey[].class.getName()}, + {"g24", CompositeKey[].class.getName()}, + {"f25", Set.class.getName()}, + {"g25", Set.class.getName()}, + {"f26", MyEnum.class.getName()}, + {"g26", MyEnum.class.getName()}, + {"f27", MyEnum[].class.getName()}, + {"g27", MyEnum[].class.getName()}, + {"f28", Set.class.getName()}, + {"g28", Set.class.getName()}, + {"f31", "java.util.Date"}, + {"f32", "java.lang.Boolean"}, + {"f33", "java.lang.Character"}, + {"f34", "java.lang.Byte"}, + {"f35", "java.lang.Short"}, + {"f36", "java.lang.Integer"}, + {"f37", "java.lang.Long"}, + {"f38", "java.lang.Float"}, + {"f39", "java.lang.Double"}, + {"f40", CompositeKey.class.getName()}, + }, + 0 /*priKeyIndex*/, null); + + checkSecKey(obj, "f0", obj.f0, Boolean.class); + checkSecKey(obj, "f1", obj.f1, Character.class); + checkSecKey(obj, "f2", obj.f2, Byte.class); + checkSecKey(obj, "f3", obj.f3, Short.class); + checkSecKey(obj, "f4", obj.f4, Integer.class); + checkSecKey(obj, "f5", obj.f5, Long.class); + checkSecKey(obj, "f6", obj.f6, Float.class); + checkSecKey(obj, "f7", obj.f7, Double.class); + checkSecKey(obj, "f8", obj.f8, String.class); + checkSecKey(obj, "f9", obj.f9, BigInteger.class); + //checkSecKey(obj, "f10", obj.f10, BigDecimal.class); + checkSecKey(obj, "f11", obj.f11, Date.class); + checkSecKey(obj, "f12", obj.f12, Boolean.class); + checkSecKey(obj, "f13", obj.f13, Character.class); + checkSecKey(obj, "f14", obj.f14, Byte.class); + checkSecKey(obj, "f15", obj.f15, Short.class); + checkSecKey(obj, "f16", obj.f16, Integer.class); + checkSecKey(obj, "f17", obj.f17, Long.class); + checkSecKey(obj, "f18", obj.f18, Float.class); + checkSecKey(obj, "f19", obj.f19, Double.class); + checkSecKey(obj, "f20", obj.f20, CompositeKey.class); + checkSecKey(obj, "f26", obj.f26, MyEnum.class); + + checkSecMultiKey(obj, "f21", toSet(obj.f21), Integer.class); + checkSecMultiKey(obj, "f22", toSet(obj.f22), Integer.class); + checkSecMultiKey(obj, "f23", toSet(obj.f23), Integer.class); + checkSecMultiKey(obj, "f24", toSet(obj.f24), CompositeKey.class); + checkSecMultiKey(obj, "f25", toSet(obj.f25), CompositeKey.class); + checkSecMultiKey(obj, "f27", toSet(obj.f27), MyEnum.class); + checkSecMultiKey(obj, "f28", toSet(obj.f28), MyEnum.class); + + nullifySecKey(obj, "f8", obj.f8, String.class); + nullifySecKey(obj, "f9", obj.f9, BigInteger.class); + //nullifySecKey(obj, "f10", obj.f10, BigDecimal.class); + nullifySecKey(obj, "f11", obj.f11, Date.class); + nullifySecKey(obj, "f12", obj.f12, Boolean.class); + nullifySecKey(obj, "f13", obj.f13, Character.class); + nullifySecKey(obj, "f14", obj.f14, Byte.class); + nullifySecKey(obj, "f15", obj.f15, Short.class); + nullifySecKey(obj, "f16", obj.f16, Integer.class); + nullifySecKey(obj, "f17", obj.f17, Long.class); + nullifySecKey(obj, "f18", obj.f18, Float.class); + nullifySecKey(obj, "f19", obj.f19, Double.class); + nullifySecKey(obj, "f20", obj.f20, CompositeKey.class); + nullifySecKey(obj, "f26", obj.f26, MyEnum.class); + + nullifySecMultiKey(obj, "f21", obj.f21, Integer.class); + nullifySecMultiKey(obj, "f22", obj.f22, Integer.class); + nullifySecMultiKey(obj, "f23", obj.f23, Integer.class); + nullifySecMultiKey(obj, "f24", obj.f24, CompositeKey.class); + nullifySecMultiKey(obj, "f25", obj.f25, CompositeKey.class); + nullifySecMultiKey(obj, "f27", obj.f27, MyEnum.class); + nullifySecMultiKey(obj, "f28", obj.f28, MyEnum.class); + + nullifySecKey(obj, "f31", obj.f31, Date.class); + nullifySecKey(obj, "f32", obj.f32, Boolean.class); + nullifySecKey(obj, "f33", obj.f33, Character.class); + nullifySecKey(obj, "f34", obj.f34, Byte.class); + nullifySecKey(obj, "f35", obj.f35, Short.class); + nullifySecKey(obj, "f36", obj.f36, Integer.class); + nullifySecKey(obj, "f37", obj.f37, Long.class); + nullifySecKey(obj, "f38", obj.f38, Float.class); + nullifySecKey(obj, "f39", obj.f39, Double.class); + nullifySecKey(obj, "f40", obj.f40, CompositeKey.class); + + close(); + } + + static Set toSet(int[] a) { + Set set = new HashSet(); + for (int i : a) { + set.add(i); + } + return set; + } + + static Set toSet(Object[] a) { + return new HashSet(Arrays.asList(a)); + } + + static Set toSet(Set s) { + return s; + } + + @Entity + static class SecKeys implements MyEntity { + + @PrimaryKey + long id; + + @SecondaryKey(relate=MANY_TO_ONE) + private final boolean f0 = false; + private final boolean g0 = false; + + @SecondaryKey(relate=MANY_TO_ONE) + private final char f1 = '1'; + private final char g1 = '1'; + + @SecondaryKey(relate=MANY_TO_ONE) + private final byte f2 = 2; + private final byte g2 = 2; + + @SecondaryKey(relate=MANY_TO_ONE) + private final short f3 = 3; + private final short g3 = 3; + + @SecondaryKey(relate=MANY_TO_ONE) + private final int f4 = 4; + private final int g4 = 4; + + @SecondaryKey(relate=MANY_TO_ONE) + private final long f5 = 5; + private final long g5 = 5; + + @SecondaryKey(relate=MANY_TO_ONE) + private final float f6 = 6.6f; + private final float g6 = 6.6f; + + @SecondaryKey(relate=MANY_TO_ONE) + private final double f7 = 7.7; + private final double g7 = 7.7; + + @SecondaryKey(relate=MANY_TO_ONE) + private final String f8 = "8"; + private final String g8 = "8"; + + @SecondaryKey(relate=MANY_TO_ONE) + private BigInteger f9; + private BigInteger g9; + + //@SecondaryKey(relate=MANY_TO_ONE) + //private BigDecimal f10; + //private BigDecimal g10; + + @SecondaryKey(relate=MANY_TO_ONE) + private final Date f11 = new Date(11); + private final Date g11 = new Date(11); + + @SecondaryKey(relate=MANY_TO_ONE) + private final Boolean f12 = true; + private final Boolean g12 = true; + + @SecondaryKey(relate=MANY_TO_ONE) + private final Character f13 = '3'; + private final Character g13 = '3'; + + @SecondaryKey(relate=MANY_TO_ONE) + private final Byte f14 = 14; + private final Byte g14 = 14; + + @SecondaryKey(relate=MANY_TO_ONE) + private final Short f15 = 15; + private final Short g15 = 15; + + @SecondaryKey(relate=MANY_TO_ONE) + private final Integer f16 = 16; + private final Integer g16 = 16; + + @SecondaryKey(relate=MANY_TO_ONE) + private final Long f17= 17L; + private final Long g17= 17L; + + @SecondaryKey(relate=MANY_TO_ONE) + private final Float f18 = 18.18f; + private final Float g18 = 18.18f; + + @SecondaryKey(relate=MANY_TO_ONE) + private final Double f19 = 19.19; + private final Double g19 = 19.19; + + @SecondaryKey(relate=MANY_TO_ONE) + private final CompositeKey f20 = + new CompositeKey(20, 20L, "20", BigInteger.valueOf(20), + MyEnum.ONE); + private final CompositeKey g20 = + new CompositeKey(20, 20L, "20", BigInteger.valueOf(20), + MyEnum.TWO); + + private static int[] arrayOfInt = { 100, 101, 102 }; + + private static Integer[] arrayOfInteger = { 100, 101, 102 }; + + private static CompositeKey[] arrayOfCompositeKey = { + new CompositeKey(100, 100L, "100", BigInteger.valueOf(100), + MyEnum.ONE), + new CompositeKey(101, 101L, "101", BigInteger.valueOf(101), + MyEnum.TWO), + new CompositeKey(102, 102L, "102", BigInteger.valueOf(102), + MyEnum.TWO), + }; + + private static MyEnum[] arrayOfEnum = + new MyEnum[] { MyEnum.ONE, MyEnum.TWO }; + + @SecondaryKey(relate=ONE_TO_MANY) + private final int[] f21 = arrayOfInt; + private final int[] g21 = f21; + + @SecondaryKey(relate=ONE_TO_MANY) + private final Integer[] f22 = arrayOfInteger; + private final Integer[] g22 = f22; + + @SecondaryKey(relate=ONE_TO_MANY) + private final Set<Integer> f23 = toSet(arrayOfInteger); + private final Set<Integer> g23 = f23; + + @SecondaryKey(relate=ONE_TO_MANY) + private final CompositeKey[] f24 = arrayOfCompositeKey; + private final CompositeKey[] g24 = f24; + + @SecondaryKey(relate=ONE_TO_MANY) + private final Set<CompositeKey> f25 = toSet(arrayOfCompositeKey); + private final Set<CompositeKey> g25 = f25; + + @SecondaryKey(relate=MANY_TO_ONE) + private final MyEnum f26 = MyEnum.TWO; + private final MyEnum g26 = f26; + + @SecondaryKey(relate=ONE_TO_MANY) + private final MyEnum[] f27 = arrayOfEnum; + private final MyEnum[] g27 = f27; + + @SecondaryKey(relate=ONE_TO_MANY) + private final Set<MyEnum> f28 = toSet(arrayOfEnum); + private final Set<MyEnum> g28 = f28; + + /* Repeated key values to test shared references. */ + + @SecondaryKey(relate=MANY_TO_ONE) + private final Date f31 = f11; + + @SecondaryKey(relate=MANY_TO_ONE) + private final Boolean f32 = f12; + + @SecondaryKey(relate=MANY_TO_ONE) + private final Character f33 = f13; + + @SecondaryKey(relate=MANY_TO_ONE) + private final Byte f34 = f14; + + @SecondaryKey(relate=MANY_TO_ONE) + private final Short f35 = f15; + + @SecondaryKey(relate=MANY_TO_ONE) + private final Integer f36 = f16; + + @SecondaryKey(relate=MANY_TO_ONE) + private final Long f37= f17; + + @SecondaryKey(relate=MANY_TO_ONE) + private final Float f38 = f18; + + @SecondaryKey(relate=MANY_TO_ONE) + private final Double f39 = f19; + + @SecondaryKey(relate=MANY_TO_ONE) + private final CompositeKey f40 = f20; + + public Object getPriKeyObject() { + return id; + } + + public void validate(Object other) { + SecKeys o = (SecKeys) other; + TestCase.assertEquals(id, o.id); + + TestCase.assertEquals(f0, o.f0); + TestCase.assertEquals(f1, o.f1); + TestCase.assertEquals(f2, o.f2); + TestCase.assertEquals(f3, o.f3); + TestCase.assertEquals(f4, o.f4); + TestCase.assertEquals(f5, o.f5); + TestCase.assertEquals(f6, o.f6); + TestCase.assertEquals(f7, o.f7); + TestCase.assertEquals(f8, o.f8); + TestCase.assertEquals(f9, o.f9); + //TestCase.assertEquals(f10, o.f10); + TestCase.assertEquals(f11, o.f11); + TestCase.assertEquals(f12, o.f12); + TestCase.assertEquals(f13, o.f13); + TestCase.assertEquals(f14, o.f14); + TestCase.assertEquals(f15, o.f15); + TestCase.assertEquals(f16, o.f16); + TestCase.assertEquals(f17, o.f17); + TestCase.assertEquals(f18, o.f18); + TestCase.assertEquals(f19, o.f19); + TestCase.assertEquals(f20, o.f20); + TestCase.assertTrue(Arrays.equals(f21, o.f21)); + TestCase.assertTrue(Arrays.equals(f22, o.f22)); + TestCase.assertEquals(f23, o.f23); + TestCase.assertTrue(Arrays.equals(f24, o.f24)); + TestCase.assertEquals(f25, o.f25); + + TestCase.assertEquals(g0, o.g0); + TestCase.assertEquals(g1, o.g1); + TestCase.assertEquals(g2, o.g2); + TestCase.assertEquals(g3, o.g3); + TestCase.assertEquals(g4, o.g4); + TestCase.assertEquals(g5, o.g5); + TestCase.assertEquals(g6, o.g6); + TestCase.assertEquals(g7, o.g7); + TestCase.assertEquals(g8, o.g8); + TestCase.assertEquals(g9, o.g9); + //TestCase.assertEquals(g10, o.g10); + TestCase.assertEquals(g11, o.g11); + TestCase.assertEquals(g12, o.g12); + TestCase.assertEquals(g13, o.g13); + TestCase.assertEquals(g14, o.g14); + TestCase.assertEquals(g15, o.g15); + TestCase.assertEquals(g16, o.g16); + TestCase.assertEquals(g17, o.g17); + TestCase.assertEquals(g18, o.g18); + TestCase.assertEquals(g19, o.g19); + TestCase.assertEquals(g20, o.g20); + TestCase.assertTrue(Arrays.equals(g21, o.g21)); + TestCase.assertTrue(Arrays.equals(g22, o.g22)); + TestCase.assertEquals(g23, o.g23); + TestCase.assertTrue(Arrays.equals(g24, o.g24)); + TestCase.assertEquals(g25, o.g25); + + TestCase.assertEquals(f31, o.f31); + TestCase.assertEquals(f32, o.f32); + TestCase.assertEquals(f33, o.f33); + TestCase.assertEquals(f34, o.f34); + TestCase.assertEquals(f35, o.f35); + TestCase.assertEquals(f36, o.f36); + TestCase.assertEquals(f37, o.f37); + TestCase.assertEquals(f38, o.f38); + TestCase.assertEquals(f39, o.f39); + TestCase.assertEquals(f40, o.f40); + + checkSameIfNonNull(o.f31, o.f11); + checkSameIfNonNull(o.f32, o.f12); + checkSameIfNonNull(o.f33, o.f13); + checkSameIfNonNull(o.f34, o.f14); + checkSameIfNonNull(o.f35, o.f15); + checkSameIfNonNull(o.f36, o.f16); + checkSameIfNonNull(o.f37, o.f17); + checkSameIfNonNull(o.f38, o.f18); + checkSameIfNonNull(o.f39, o.f19); + checkSameIfNonNull(o.f40, o.f20); + } + } + + public void testSecKeyRefToPriKey() + throws FileNotFoundException, DatabaseException { + + open(); + + SecKeyRefToPriKey obj = new SecKeyRefToPriKey(); + checkEntity(SecKeyRefToPriKey.class, obj); + + checkMetadata(SecKeyRefToPriKey.class.getName(), new String[][] { + {"priKey", "java.lang.String"}, + {"secKey1", "java.lang.String"}, + {"secKey2", String[].class.getName()}, + {"secKey3", Set.class.getName()}, + }, + 0 /*priKeyIndex*/, null); + + checkSecKey(obj, "secKey1", obj.secKey1, String.class); + checkSecMultiKey(obj, "secKey2", toSet(obj.secKey2), String.class); + checkSecMultiKey(obj, "secKey3", toSet(obj.secKey3), String.class); + + close(); + } + + @Entity + static class SecKeyRefToPriKey implements MyEntity { + + @PrimaryKey + private final String priKey; + + @SecondaryKey(relate=ONE_TO_ONE) + private final String secKey1; + + @SecondaryKey(relate=ONE_TO_MANY) + private final String[] secKey2; + + @SecondaryKey(relate=ONE_TO_MANY) + private final Set<String> secKey3 = new HashSet<String>(); + + private SecKeyRefToPriKey() { + priKey = "sharedValue"; + secKey1 = priKey; + secKey2 = new String[] { priKey }; + secKey3.add(priKey); + } + + public Object getPriKeyObject() { + return priKey; + } + + public void validate(Object other) { + SecKeyRefToPriKey o = (SecKeyRefToPriKey) other; + TestCase.assertEquals(priKey, o.priKey); + TestCase.assertNotNull(o.secKey1); + TestCase.assertEquals(1, o.secKey2.length); + TestCase.assertEquals(1, o.secKey3.size()); + TestCase.assertSame(o.secKey1, o.priKey); + TestCase.assertSame(o.secKey2[0], o.priKey); + TestCase.assertSame(o.secKey3.iterator().next(), o.priKey); + } + } + + public void testSecKeyInSuperclass() + throws FileNotFoundException, DatabaseException { + + open(); + + SecKeyInSuperclassEntity obj = new SecKeyInSuperclassEntity(); + checkEntity(SecKeyInSuperclassEntity.class, obj); + + checkMetadata(SecKeyInSuperclass.class.getName(), + new String[][] { + {"priKey", "java.lang.String"}, + {"secKey1", String.class.getName()}, + }, + 0/*priKeyIndex*/, null); + + checkMetadata(SecKeyInSuperclassEntity.class.getName(), + new String[][] { + {"secKey2", "java.lang.String"}, + }, + -1 /*priKeyIndex*/, SecKeyInSuperclass.class.getName()); + + checkSecKey + (obj, SecKeyInSuperclassEntity.class, "secKey1", obj.secKey1, + String.class); + checkSecKey + (obj, SecKeyInSuperclassEntity.class, "secKey2", obj.secKey2, + String.class); + + close(); + } + + @Persistent + static class SecKeyInSuperclass implements MyEntity { + + @PrimaryKey + String priKey = "1"; + + @SecondaryKey(relate=ONE_TO_ONE) + String secKey1 = "1"; + + public Object getPriKeyObject() { + return priKey; + } + + public void validate(Object other) { + SecKeyInSuperclass o = (SecKeyInSuperclass) other; + TestCase.assertEquals(secKey1, o.secKey1); + } + } + + @Entity + static class SecKeyInSuperclassEntity extends SecKeyInSuperclass { + + @SecondaryKey(relate=ONE_TO_ONE) + String secKey2 = "2"; + + @Override + public void validate(Object other) { + super.validate(other); + SecKeyInSuperclassEntity o = (SecKeyInSuperclassEntity) other; + TestCase.assertEquals(priKey, o.priKey); + TestCase.assertEquals(secKey2, o.secKey2); + } + } + + public void testSecKeyInSubclass() + throws FileNotFoundException, DatabaseException { + + open(); + + SecKeyInSubclass obj = new SecKeyInSubclass(); + checkEntity(SecKeyInSubclassEntity.class, obj); + + checkMetadata(SecKeyInSubclassEntity.class.getName(), new String[][] { + {"priKey", "java.lang.String"}, + {"secKey1", "java.lang.String"}, + }, + 0 /*priKeyIndex*/, null); + + checkMetadata(SecKeyInSubclass.class.getName(), new String[][] { + {"secKey2", String.class.getName()}, + }, + -1 /*priKeyIndex*/, + SecKeyInSubclassEntity.class.getName()); + + checkSecKey + (obj, SecKeyInSubclassEntity.class, "secKey1", obj.secKey1, + String.class); + checkSecKey + (obj, SecKeyInSubclassEntity.class, "secKey2", obj.secKey2, + String.class); + + close(); + } + + @Entity + static class SecKeyInSubclassEntity implements MyEntity { + + @PrimaryKey + String priKey = "1"; + + @SecondaryKey(relate=ONE_TO_ONE) + String secKey1; + + public Object getPriKeyObject() { + return priKey; + } + + public void validate(Object other) { + SecKeyInSubclassEntity o = (SecKeyInSubclassEntity) other; + TestCase.assertEquals(priKey, o.priKey); + TestCase.assertEquals(secKey1, o.secKey1); + } + } + + @Persistent + static class SecKeyInSubclass extends SecKeyInSubclassEntity { + + @SecondaryKey(relate=ONE_TO_ONE) + String secKey2 = "2"; + + @Override + public void validate(Object other) { + super.validate(other); + SecKeyInSubclass o = (SecKeyInSubclass) other; + TestCase.assertEquals(secKey2, o.secKey2); + } + } + + private static void checkSameIfNonNull(Object o1, Object o2) { + if (o1 != null && o2 != null) { + assertSame(o1, o2); + } + } + + private void checkEntity(Class entityCls, MyEntity entity) { + Object priKey = entity.getPriKeyObject(); + Class keyCls = priKey.getClass(); + DatabaseEntry keyEntry2 = new DatabaseEntry(); + DatabaseEntry dataEntry2 = new DatabaseEntry(); + + /* Write object, read it back and validate (compare) it. */ + PersistEntityBinding entityBinding = + new PersistEntityBinding(catalog, entityCls.getName(), false); + entityBinding.objectToData(entity, dataEntry); + entityBinding.objectToKey(entity, keyEntry); + Object entity2 = entityBinding.entryToObject(keyEntry, dataEntry); + entity.validate(entity2); + + /* Read back the primary key and validate it. */ + PersistKeyBinding keyBinding = + new PersistKeyBinding(catalog, keyCls.getName(), false); + Object priKey2 = keyBinding.entryToObject(keyEntry); + assertEquals(priKey, priKey2); + keyBinding.objectToEntry(priKey2, keyEntry2); + assertEquals(keyEntry, keyEntry2); + + /* Check raw entity binding. */ + PersistEntityBinding rawEntityBinding = + new PersistEntityBinding(catalog, entityCls.getName(), true); + RawObject rawEntity = + (RawObject) rawEntityBinding.entryToObject(keyEntry, dataEntry); + rawEntityBinding.objectToKey(rawEntity, keyEntry2); + rawEntityBinding.objectToData(rawEntity, dataEntry2); + entity2 = entityBinding.entryToObject(keyEntry2, dataEntry2); + entity.validate(entity2); + RawObject rawEntity2 = + (RawObject) rawEntityBinding.entryToObject(keyEntry2, dataEntry2); + assertEquals(rawEntity, rawEntity2); + assertEquals(dataEntry, dataEntry2); + assertEquals(keyEntry, keyEntry2); + + /* Check that raw entity can be converted to a regular entity. */ + entity2 = catalog.convertRawObject(rawEntity, null); + entity.validate(entity2); + + /* Check raw key binding. */ + PersistKeyBinding rawKeyBinding = + new PersistKeyBinding(catalog, keyCls.getName(), true); + Object rawKey = rawKeyBinding.entryToObject(keyEntry); + rawKeyBinding.objectToEntry(rawKey, keyEntry2); + priKey2 = keyBinding.entryToObject(keyEntry2); + assertEquals(priKey, priKey2); + assertEquals(keyEntry, keyEntry2); + } + + private void checkSecKey(MyEntity entity, + String keyName, + Object keyValue, + Class keyCls) + throws DatabaseException { + + checkSecKey(entity, entity.getClass(), keyName, keyValue, keyCls); + } + + private void checkSecKey(MyEntity entity, + Class entityCls, + String keyName, + Object keyValue, + Class keyCls) + throws DatabaseException { + + /* Get entity metadata. */ + EntityMetadata entityMeta = + model.getEntityMetadata(entityCls.getName()); + assertNotNull(entityMeta); + + /* Get secondary key metadata. */ + SecondaryKeyMetadata secKeyMeta = + entityMeta.getSecondaryKeys().get(keyName); + assertNotNull(secKeyMeta); + + /* Create key creator/nullifier. */ + SecondaryKeyCreator keyCreator = new PersistKeyCreator + (catalog, entityMeta, keyCls.getName(), secKeyMeta, + false /*rawAcess*/); + + /* Convert entity to bytes. */ + PersistEntityBinding entityBinding = + new PersistEntityBinding(catalog, entityCls.getName(), false); + entityBinding.objectToData(entity, dataEntry); + entityBinding.objectToKey(entity, keyEntry); + + /* Extract secondary key bytes from entity bytes. */ + DatabaseEntry secKeyEntry = new DatabaseEntry(); + boolean isKeyPresent = keyCreator.createSecondaryKey + (null, keyEntry, dataEntry, secKeyEntry); + assertEquals(keyValue != null, isKeyPresent); + + /* Convert secondary key bytes back to an object. */ + PersistKeyBinding keyBinding = + new PersistKeyBinding(catalog, keyCls.getName(), false); + if (isKeyPresent) { + Object keyValue2 = keyBinding.entryToObject(secKeyEntry); + assertEquals(keyValue, keyValue2); + DatabaseEntry secKeyEntry2 = new DatabaseEntry(); + keyBinding.objectToEntry(keyValue2, secKeyEntry2); + assertEquals(secKeyEntry, secKeyEntry2); + } + } + + private void checkSecMultiKey(MyEntity entity, + String keyName, + Set keyValues, + Class keyCls) + throws DatabaseException { + + /* Get entity metadata. */ + Class entityCls = entity.getClass(); + EntityMetadata entityMeta = + model.getEntityMetadata(entityCls.getName()); + assertNotNull(entityMeta); + + /* Get secondary key metadata. */ + SecondaryKeyMetadata secKeyMeta = + entityMeta.getSecondaryKeys().get(keyName); + assertNotNull(secKeyMeta); + + /* Create key creator/nullifier. */ + SecondaryMultiKeyCreator keyCreator = new PersistKeyCreator + (catalog, entityMeta, keyCls.getName(), secKeyMeta, + false /*rawAcess*/); + + /* Convert entity to bytes. */ + PersistEntityBinding entityBinding = + new PersistEntityBinding(catalog, entityCls.getName(), false); + entityBinding.objectToData(entity, dataEntry); + entityBinding.objectToKey(entity, keyEntry); + + /* Extract secondary key bytes from entity bytes. */ + Set<DatabaseEntry> results = new HashSet<DatabaseEntry>(); + keyCreator.createSecondaryKeys + (null, keyEntry, dataEntry, results); + assertEquals(keyValues.size(), results.size()); + + /* Convert secondary key bytes back to objects. */ + PersistKeyBinding keyBinding = + new PersistKeyBinding(catalog, keyCls.getName(), false); + Set keyValues2 = new HashSet(); + for (DatabaseEntry secKeyEntry : results) { + Object keyValue2 = keyBinding.entryToObject(secKeyEntry); + keyValues2.add(keyValue2); + } + assertEquals(keyValues, keyValues2); + } + + private void nullifySecKey(MyEntity entity, + String keyName, + Object keyValue, + Class keyCls) + throws DatabaseException { + + /* Get entity metadata. */ + Class entityCls = entity.getClass(); + EntityMetadata entityMeta = + model.getEntityMetadata(entityCls.getName()); + assertNotNull(entityMeta); + + /* Get secondary key metadata. */ + SecondaryKeyMetadata secKeyMeta = + entityMeta.getSecondaryKeys().get(keyName); + assertNotNull(secKeyMeta); + + /* Create key creator/nullifier. */ + ForeignMultiKeyNullifier keyNullifier = new PersistKeyCreator + (catalog, entityMeta, keyCls.getName(), secKeyMeta, + false /*rawAcess*/); + + /* Convert entity to bytes. */ + PersistEntityBinding entityBinding = + new PersistEntityBinding(catalog, entityCls.getName(), false); + entityBinding.objectToData(entity, dataEntry); + entityBinding.objectToKey(entity, keyEntry); + + /* Convert secondary key to bytes. */ + PersistKeyBinding keyBinding = + new PersistKeyBinding(catalog, keyCls.getName(), false); + DatabaseEntry secKeyEntry = new DatabaseEntry(); + if (keyValue != null) { + keyBinding.objectToEntry(keyValue, secKeyEntry); + } + + /* Nullify secondary key bytes within entity bytes. */ + boolean isKeyPresent = keyNullifier.nullifyForeignKey + (null, keyEntry, dataEntry, secKeyEntry); + assertEquals(keyValue != null, isKeyPresent); + + /* Convert modified entity bytes back to an entity. */ + Object entity2 = entityBinding.entryToObject(keyEntry, dataEntry); + setFieldToNull(entity, keyName); + entity.validate(entity2); + + /* Do a full check after nullifying it. */ + checkSecKey(entity, keyName, null, keyCls); + } + + private void nullifySecMultiKey(MyEntity entity, + String keyName, + Object keyValue, + Class keyCls) + throws DatabaseException { + + /* Get entity metadata. */ + Class entityCls = entity.getClass(); + EntityMetadata entityMeta = + model.getEntityMetadata(entityCls.getName()); + assertNotNull(entityMeta); + + /* Get secondary key metadata. */ + SecondaryKeyMetadata secKeyMeta = + entityMeta.getSecondaryKeys().get(keyName); + assertNotNull(secKeyMeta); + + /* Create key creator/nullifier. */ + ForeignMultiKeyNullifier keyNullifier = new PersistKeyCreator + (catalog, entityMeta, keyCls.getName(), secKeyMeta, + false /*rawAcess*/); + + /* Convert entity to bytes. */ + PersistEntityBinding entityBinding = + new PersistEntityBinding(catalog, entityCls.getName(), false); + entityBinding.objectToData(entity, dataEntry); + entityBinding.objectToKey(entity, keyEntry); + + /* Get secondary key binding. */ + PersistKeyBinding keyBinding = + new PersistKeyBinding(catalog, keyCls.getName(), false); + DatabaseEntry secKeyEntry = new DatabaseEntry(); + + /* Nullify one key value at a time until all of them are gone. */ + while (true) { + Object fieldObj = getField(entity, keyName); + fieldObj = nullifyFirstElement(fieldObj, keyBinding, secKeyEntry); + if (fieldObj == null) { + break; + } + setField(entity, keyName, fieldObj); + + /* Nullify secondary key bytes within entity bytes. */ + boolean isKeyPresent = keyNullifier.nullifyForeignKey + (null, keyEntry, dataEntry, secKeyEntry); + assertEquals(keyValue != null, isKeyPresent); + + /* Convert modified entity bytes back to an entity. */ + Object entity2 = entityBinding.entryToObject(keyEntry, dataEntry); + entity.validate(entity2); + + /* Do a full check after nullifying it. */ + Set keyValues; + if (fieldObj instanceof Set) { + keyValues = (Set) fieldObj; + } else if (fieldObj instanceof Object[]) { + keyValues = toSet((Object[]) fieldObj); + } else if (fieldObj instanceof int[]) { + keyValues = toSet((int[]) fieldObj); + } else { + throw new IllegalStateException(fieldObj.getClass().getName()); + } + checkSecMultiKey(entity, keyName, keyValues, keyCls); + } + } + + /** + * Nullifies the first element of an array or collection object by removing + * it from the array or collection. Returns the resulting array or + * collection. Also outputs the removed element to the keyEntry using the + * keyBinding. + */ + private Object nullifyFirstElement(Object obj, + EntryBinding keyBinding, + DatabaseEntry keyEntry) { + if (obj instanceof Collection) { + Iterator i = ((Collection) obj).iterator(); + if (i.hasNext()) { + Object elem = i.next(); + i.remove(); + keyBinding.objectToEntry(elem, keyEntry); + return obj; + } else { + return null; + } + } else if (obj instanceof Object[]) { + Object[] a1 = (Object[]) obj; + if (a1.length > 0) { + Object[] a2 = (Object[]) Array.newInstance + (obj.getClass().getComponentType(), a1.length - 1); + System.arraycopy(a1, 1, a2, 0, a2.length); + keyBinding.objectToEntry(a1[0], keyEntry); + return a2; + } else { + return null; + } + } else if (obj instanceof int[]) { + int[] a1 = (int[]) obj; + if (a1.length > 0) { + int[] a2 = new int[a1.length - 1]; + System.arraycopy(a1, 1, a2, 0, a2.length); + keyBinding.objectToEntry(a1[0], keyEntry); + return a2; + } else { + return null; + } + } else { + throw new IllegalStateException(obj.getClass().getName()); + } + } + + private void checkMetadata(String clsName, + String[][] nameTypePairs, + int priKeyIndex, + String superClsName) + throws DatabaseException { + + /* Check metadata/types against the live model. */ + checkMetadata + (catalog, model, clsName, nameTypePairs, priKeyIndex, + superClsName); + + /* + * Open a catalog that uses the stored model. + */ + PersistCatalog storedCatalog = new PersistCatalog + (null, env, STORE_PREFIX, STORE_PREFIX + "catalog", null, null, + null, false /*useCurrentModel*/, null /*Store*/); + EntityModel storedModel = storedCatalog.getResolvedModel(); + + /* Check metadata/types against the stored catalog/model. */ + checkMetadata + (storedCatalog, storedModel, clsName, nameTypePairs, priKeyIndex, + superClsName); + + storedCatalog.close(); + } + + private void checkMetadata(PersistCatalog checkCatalog, + EntityModel checkModel, + String clsName, + String[][] nameTypePairs, + int priKeyIndex, + String superClsName) { + ClassMetadata classMeta = checkModel.getClassMetadata(clsName); + assertNotNull(clsName, classMeta); + + PrimaryKeyMetadata priKeyMeta = classMeta.getPrimaryKey(); + if (priKeyIndex >= 0) { + assertNotNull(priKeyMeta); + String fieldName = nameTypePairs[priKeyIndex][0]; + String fieldType = nameTypePairs[priKeyIndex][1]; + assertEquals(priKeyMeta.getName(), fieldName); + assertEquals(priKeyMeta.getClassName(), fieldType); + assertEquals(priKeyMeta.getDeclaringClassName(), clsName); + assertNull(priKeyMeta.getSequenceName()); + } else { + assertNull(priKeyMeta); + } + + RawType type = checkCatalog.getFormat(clsName); + assertNotNull(type); + assertEquals(clsName, type.getClassName()); + assertEquals(0, type.getVersion()); + assertTrue(!type.isSimple()); + assertTrue(!type.isPrimitive()); + assertTrue(!type.isEnum()); + assertNull(type.getEnumConstants()); + assertTrue(!type.isArray()); + assertEquals(0, type.getDimensions()); + assertNull(type.getComponentType()); + RawType superType = type.getSuperType(); + if (superClsName != null) { + assertNotNull(superType); + assertEquals(superClsName, superType.getClassName()); + } else { + assertNull(superType); + } + + Map<String,RawField> fields = type.getFields(); + assertNotNull(fields); + + int nFields = nameTypePairs.length; + assertEquals(nFields, fields.size()); + + for (String[] pair : nameTypePairs) { + String fieldName = pair[0]; + String fieldType = pair[1]; + Class fieldCls; + try { + fieldCls = SimpleCatalog.classForName(fieldType); + } catch (ClassNotFoundException e) { + fail(e.toString()); + return; /* For compiler */ + } + RawField field = fields.get(fieldName); + assertNotNull(field); + assertEquals(fieldName, field.getName()); + type = field.getType(); + assertNotNull(type); + int dim = getArrayDimensions(fieldType); + while (dim > 0) { + assertEquals(dim, type.getDimensions()); + assertEquals(dim, getArrayDimensions(fieldType)); + assertEquals(true, type.isArray()); + assertEquals(fieldType, type.getClassName()); + assertEquals(0, type.getVersion()); + assertTrue(!type.isSimple()); + assertTrue(!type.isPrimitive()); + assertTrue(!type.isEnum()); + assertNull(type.getEnumConstants()); + fieldType = getArrayComponent(fieldType, dim); + type = type.getComponentType(); + assertNotNull(fieldType, type); + dim -= 1; + } + assertEquals(fieldType, type.getClassName()); + List<String> enums = getEnumConstants(fieldType); + assertEquals(isSimpleType(fieldType), type.isSimple()); + assertEquals(isPrimitiveType(fieldType), type.isPrimitive()); + assertNull(type.getComponentType()); + assertTrue(!type.isArray()); + assertEquals(0, type.getDimensions()); + if (enums != null) { + assertTrue(type.isEnum()); + assertEquals(enums, type.getEnumConstants()); + assertNull(type.getSuperType()); + } else { + assertTrue(!type.isEnum()); + assertNull(type.getEnumConstants()); + } + } + } + + private List<String> getEnumConstants(String clsName) { + if (isPrimitiveType(clsName)) { + return null; + } + Class cls; + try { + cls = Class.forName(clsName); + } catch (ClassNotFoundException e) { + fail(e.toString()); + return null; /* Never happens. */ + } + if (!cls.isEnum()) { + return null; + } + List<String> enums = new ArrayList<String>(); + Object[] vals = cls.getEnumConstants(); + for (Object val : vals) { + enums.add(val.toString()); + } + return enums; + } + + private String getArrayComponent(String clsName, int dim) { + clsName = clsName.substring(1); + if (dim > 1) { + return clsName; + } + if (clsName.charAt(0) == 'L' && + clsName.charAt(clsName.length() - 1) == ';') { + return clsName.substring(1, clsName.length() - 1); + } + if (clsName.length() != 1) { + fail(); + } + switch (clsName.charAt(0)) { + case 'Z': return "boolean"; + case 'B': return "byte"; + case 'C': return "char"; + case 'D': return "double"; + case 'F': return "float"; + case 'I': return "int"; + case 'J': return "long"; + case 'S': return "short"; + default: fail(); + } + return null; /* Should never happen. */ + } + + private static int getArrayDimensions(String clsName) { + int i = 0; + while (clsName.charAt(i) == '[') { + i += 1; + } + return i; + } + + private static boolean isSimpleType(String clsName) { + return isPrimitiveType(clsName) || + clsName.equals("java.lang.Boolean") || + clsName.equals("java.lang.Character") || + clsName.equals("java.lang.Byte") || + clsName.equals("java.lang.Short") || + clsName.equals("java.lang.Integer") || + clsName.equals("java.lang.Long") || + clsName.equals("java.lang.Float") || + clsName.equals("java.lang.Double") || + clsName.equals("java.lang.String") || + clsName.equals("java.math.BigInteger") || + //clsName.equals("java.math.BigDecimal") || + clsName.equals("java.util.Date"); + } + + private static boolean isPrimitiveType(String clsName) { + return clsName.equals("boolean") || + clsName.equals("char") || + clsName.equals("byte") || + clsName.equals("short") || + clsName.equals("int") || + clsName.equals("long") || + clsName.equals("float") || + clsName.equals("double"); + } + + interface MyEntity { + Object getPriKeyObject(); + void validate(Object other); + } + + private static boolean nullOrEqual(Object o1, Object o2) { + return (o1 != null) ? o1.equals(o2) : (o2 == null); + } + + private static String arrayToString(Object[] array) { + StringBuffer buf = new StringBuffer(); + buf.append('['); + for (Object o : array) { + if (o instanceof Object[]) { + buf.append(arrayToString((Object[]) o)); + } else { + buf.append(o); + } + buf.append(','); + } + buf.append(']'); + return buf.toString(); + } + + private void setFieldToNull(Object obj, String fieldName) { + try { + Field field = obj.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + field.set(obj, null); + } catch (NoSuchFieldException e) { + fail(e.toString()); + } catch (IllegalAccessException e) { + fail(e.toString()); + } + } + + private void setField(Object obj, String fieldName, Object fieldValue) { + try { + Field field = obj.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + field.set(obj, fieldValue); + } catch (NoSuchFieldException e) { + throw new IllegalStateException(e.toString()); + } catch (IllegalAccessException e) { + throw new IllegalStateException(e.toString()); + } + } + + private Object getField(Object obj, String fieldName) { + try { + Field field = obj.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + return field.get(obj); + } catch (NoSuchFieldException e) { + throw new IllegalStateException(e.toString()); + } catch (IllegalAccessException e) { + throw new IllegalStateException(e.toString()); + } + } +} diff --git a/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/Enhanced0.java b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/Enhanced0.java new file mode 100644 index 0000000..f29a24c --- /dev/null +++ b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/Enhanced0.java @@ -0,0 +1,36 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2002-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +package com.sleepycat.persist.test; + +import static com.sleepycat.persist.model.Relationship.MANY_TO_ONE; + +import com.sleepycat.persist.model.Entity; +import com.sleepycat.persist.model.PrimaryKey; +import com.sleepycat.persist.model.SecondaryKey; + +/** + * For running ASMifier -- before any enhancements. + */ +@Entity +class Enhanced0 { + + @PrimaryKey + private String f1; + + @SecondaryKey(relate=MANY_TO_ONE) + private int f2; + @SecondaryKey(relate=MANY_TO_ONE) + private String f3; + @SecondaryKey(relate=MANY_TO_ONE) + private String f4; + + private int f5; + private String f6; + private String f7; +} diff --git a/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/Enhanced1.java b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/Enhanced1.java new file mode 100644 index 0000000..2eb93ba --- /dev/null +++ b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/Enhanced1.java @@ -0,0 +1,260 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2002-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +package com.sleepycat.persist.test; + +import static com.sleepycat.persist.model.Relationship.MANY_TO_ONE; + +import com.sleepycat.persist.impl.Enhanced; +import com.sleepycat.persist.impl.EnhancedAccessor; +import com.sleepycat.persist.impl.EntityInput; +import com.sleepycat.persist.impl.EntityOutput; +import com.sleepycat.persist.impl.Format; +import com.sleepycat.persist.model.Entity; +import com.sleepycat.persist.model.PrimaryKey; +import com.sleepycat.persist.model.SecondaryKey; + +/** + * For running ASMifier -- adds minimal enhancements. + */ +@Entity +class Enhanced1 implements Enhanced { + + @PrimaryKey + private String f1; + + @SecondaryKey(relate=MANY_TO_ONE) + private int f2; + @SecondaryKey(relate=MANY_TO_ONE) + private String f3; + @SecondaryKey(relate=MANY_TO_ONE) + private String f4; + + private int f5; + private String f6; + private String f7; + private int f8; + private int f9; + private int f10; + private int f11; + private int f12; + + static { + EnhancedAccessor.registerClass(null, new Enhanced1()); + } + + public Object bdbNewInstance() { + return new Enhanced1(); + } + + public Object bdbNewArray(int len) { + return new Enhanced1[len]; + } + + public boolean bdbIsPriKeyFieldNullOrZero() { + return f1 == null; + } + + public void bdbWritePriKeyField(EntityOutput output, Format format) { + output.writeKeyObject(f1, format); + } + + public void bdbReadPriKeyField(EntityInput input, Format format) { + f1 = (String) input.readKeyObject(format); + } + + public void bdbWriteSecKeyFields(EntityOutput output) { + /* If primary key is an object: */ + output.registerPriKeyObject(f1); + /* Always: */ + output.writeInt(f2); + output.writeObject(f3, null); + output.writeObject(f4, null); + } + + public void bdbReadSecKeyFields(EntityInput input, + int startField, + int endField, + int superLevel) { + /* If primary key is an object: */ + input.registerPriKeyObject(f1); + + if (superLevel <= 0) { + switch (startField) { + case 0: + f2 = input.readInt(); + if (endField == 0) break; + case 1: + f3 = (String) input.readObject(); + if (endField == 1) break; + case 2: + f4 = (String) input.readObject(); + } + } + } + + public void bdbWriteNonKeyFields(EntityOutput output) { + output.writeInt(f5); + output.writeObject(f6, null); + output.writeObject(f7, null); + output.writeInt(f8); + output.writeInt(f9); + output.writeInt(f10); + output.writeInt(f11); + output.writeInt(f12); + } + + public void bdbReadNonKeyFields(EntityInput input, + int startField, + int endField, + int superLevel) { + if (superLevel <= 0) { + switch (startField) { + case 0: + f5 = input.readInt(); + if (endField == 0) break; + case 1: + f6 = (String) input.readObject(); + if (endField == 1) break; + case 2: + f7 = (String) input.readObject(); + if (endField == 2) break; + case 3: + f8 = input.readInt(); + if (endField == 3) break; + case 4: + f9 = input.readInt(); + if (endField == 4) break; + case 5: + f10 = input.readInt(); + if (endField == 5) break; + case 6: + f11 = input.readInt(); + if (endField == 6) break; + case 7: + f12 = input.readInt(); + } + } + } + + public void bdbWriteCompositeKeyFields(EntityOutput output, + Format[] formats) { + } + + public void bdbReadCompositeKeyFields(EntityInput input, + Format[] formats) { + } + + public boolean bdbNullifyKeyField(Object o, + int field, + int superLevel, + boolean isSecField, + Object keyElement) { + if (superLevel > 0) { + return false; + } else if (isSecField) { + switch (field) { + case 1: + if (f3 != null) { + f3 = null; + return true; + } else { + return false; + } + case 2: + if (f4 != null) { + f4 = null; + return true; + } else { + return false; + } + default: + return false; + } + } else { + switch (field) { + case 1: + if (f6 != null) { + f6 = null; + return true; + } else { + return false; + } + case 2: + if (f7 != null) { + f7 = null; + return true; + } else { + return false; + } + default: + return false; + } + } + } + + public Object bdbGetField(Object o, + int field, + int superLevel, + boolean isSecField) { + if (superLevel > 0) { + } else if (isSecField) { + switch (field) { + case 0: + return Integer.valueOf(f2); + case 1: + return f3; + case 2: + return f4; + } + } else { + switch (field) { + case 0: + return Integer.valueOf(f5); + case 1: + return f6; + case 2: + return f7; + } + } + return null; + } + + public void bdbSetField(Object o, + int field, + int superLevel, + boolean isSecField, + Object value) { + if (superLevel > 0) { + } else if (isSecField) { + switch (field) { + case 0: + f2 = ((Integer) value).intValue(); + return; + case 1: + f3 = (String) value; + return; + case 2: + f4 = (String) value; + return; + } + } else { + switch (field) { + case 0: + f5 = ((Integer) value).intValue(); + return; + case 1: + f6 = (String) value; + return; + case 2: + f7 = (String) value; + return; + } + } + } +} diff --git a/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/Enhanced2.java b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/Enhanced2.java new file mode 100644 index 0000000..5cc2e06 --- /dev/null +++ b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/Enhanced2.java @@ -0,0 +1,110 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2002-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +package com.sleepycat.persist.test; + +import com.sleepycat.persist.impl.EnhancedAccessor; +import com.sleepycat.persist.impl.EntityInput; +import com.sleepycat.persist.impl.EntityOutput; +import com.sleepycat.persist.impl.Format; +import com.sleepycat.persist.model.Persistent; + +/** + * For running ASMifier -- entity sublcass. + */ +@Persistent +class Enhanced2 extends Enhanced1 { + + static { + EnhancedAccessor.registerClass(null, new Enhanced2()); + } + + public Object bdbNewInstance() { + return new Enhanced2(); + } + + public Object bdbNewArray(int len) { + return new Enhanced2[len]; + } + + public boolean bdbIsPriKeyFieldNullOrZero() { + return super.bdbIsPriKeyFieldNullOrZero(); + } + + public void bdbWritePriKeyField(EntityOutput output, Format format) { + super.bdbWritePriKeyField(output, format); + } + + public void bdbReadPriKeyField(EntityInput input, Format format) { + super.bdbReadPriKeyField(input, format); + } + + public void bdbWriteSecKeyFields(EntityOutput output) { + super.bdbWriteSecKeyFields(output); + } + + public void bdbReadSecKeyFields(EntityInput input, + int startField, + int endField, + int superLevel) { + if (superLevel != 0) { + super.bdbReadSecKeyFields + (input, startField, endField, superLevel - 1); + } + } + + public void bdbWriteNonKeyFields(EntityOutput output) { + super.bdbWriteNonKeyFields(output); + } + + public void bdbReadNonKeyFields(EntityInput input, + int startField, + int endField, + int superLevel) { + if (superLevel != 0) { + super.bdbReadNonKeyFields + (input, startField, endField, superLevel - 1); + } + } + + public boolean bdbNullifyKeyField(Object o, + int field, + int superLevel, + boolean isSecField, + Object keyElement) { + if (superLevel > 0) { + return super.bdbNullifyKeyField + (o, field, superLevel - 1, isSecField, keyElement); + } else { + return false; + } + } + + public Object bdbGetField(Object o, + int field, + int superLevel, + boolean isSecField) { + if (superLevel > 0) { + return super.bdbGetField + (o, field, superLevel - 1, isSecField); + } else { + return null; + } + } + + public void bdbSetField(Object o, + int field, + int superLevel, + boolean isSecField, + Object value) { + if (superLevel > 0) { + super.bdbSetField + (o, field, superLevel - 1, isSecField, value); + } + } +} diff --git a/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/Enhanced3.java b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/Enhanced3.java new file mode 100644 index 0000000..5b59a29 --- /dev/null +++ b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/Enhanced3.java @@ -0,0 +1,176 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2002-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +package com.sleepycat.persist.test; + +/* +import java.math.BigDecimal; +*/ +import java.math.BigInteger; +import java.util.Date; + +import com.sleepycat.persist.impl.Enhanced; +import com.sleepycat.persist.impl.EnhancedAccessor; +import com.sleepycat.persist.impl.EntityInput; +import com.sleepycat.persist.impl.EntityOutput; +import com.sleepycat.persist.impl.Format; +import com.sleepycat.persist.model.KeyField; +import com.sleepycat.persist.model.Persistent; + +/** + * For running ASMifier -- a composite key class using all simple data types, + * does not follow from previous EnhancedN.java files + */ +@Persistent +class Enhanced3 implements Enhanced { + + enum MyEnum { ONE, TWO }; + + @KeyField(1) boolean z; + @KeyField(2) char c; + @KeyField(3) byte b; + @KeyField(4) short s; + @KeyField(5) int i; + @KeyField(6) long l; + @KeyField(7) float f; + @KeyField(8) double d; + + @KeyField(9) Boolean zw; + @KeyField(10) Character cw; + @KeyField(11) Byte bw; + @KeyField(12) Short sw; + @KeyField(13) Integer iw; + @KeyField(14) Long lw; + @KeyField(15) Float fw; + @KeyField(16) Double dw; + + @KeyField(17) Date date; + @KeyField(18) String str; + @KeyField(19) MyEnum e; + @KeyField(20) BigInteger bigint; + /* + @KeyField(21) BigDecimal bigdec; + */ + + static { + EnhancedAccessor.registerClass(null, new Enhanced3()); + } + + public Object bdbNewInstance() { + return new Enhanced3(); + } + + public Object bdbNewArray(int len) { + return new Enhanced3[len]; + } + + public boolean bdbIsPriKeyFieldNullOrZero() { + return false; + } + + public void bdbWritePriKeyField(EntityOutput output, Format format) { + } + + public void bdbReadPriKeyField(EntityInput input, Format format) { + } + + public void bdbWriteSecKeyFields(EntityOutput output) { + } + + public void bdbReadSecKeyFields(EntityInput input, + int startField, + int endField, + int superLevel) { + } + + public void bdbWriteNonKeyFields(EntityOutput output) { + } + + public void bdbReadNonKeyFields(EntityInput input, + int startField, + int endField, + int superLevel) { + } + + public void bdbWriteCompositeKeyFields(EntityOutput output, + Format[] formats) { + output.writeBoolean(z); + output.writeChar(c); + output.writeByte(b); + output.writeShort(s); + output.writeInt(i); + output.writeLong(l); + output.writeSortedFloat(f); + output.writeSortedDouble(d); + + output.writeBoolean(zw.booleanValue()); + output.writeChar(cw.charValue()); + output.writeByte(bw.byteValue()); + output.writeShort(sw.shortValue()); + output.writeInt(iw.intValue()); + output.writeLong(lw.longValue()); + output.writeSortedFloat(fw.floatValue()); + output.writeSortedDouble(dw.doubleValue()); + + output.writeLong(date.getTime()); + output.writeString(str); + output.writeKeyObject(e, formats[18]); + output.writeBigInteger(bigint); + } + + public void bdbReadCompositeKeyFields(EntityInput input, + Format[] formats) { + z = input.readBoolean(); + c = input.readChar(); + b = input.readByte(); + s = input.readShort(); + i = input.readInt(); + l = input.readLong(); + f = input.readSortedFloat(); + d = input.readSortedDouble(); + + zw = Boolean.valueOf(input.readBoolean()); + cw = Character.valueOf(input.readChar()); + bw = Byte.valueOf(input.readByte()); + sw = Short.valueOf(input.readShort()); + iw = Integer.valueOf(input.readInt()); + lw = Long.valueOf(input.readLong()); + fw = Float.valueOf(input.readSortedFloat()); + dw = Double.valueOf(input.readSortedDouble()); + + date = new Date(input.readLong()); + str = input.readString(); + e = (MyEnum) input.readKeyObject(formats[18]); + bigint = input.readBigInteger(); + } + + public boolean bdbNullifyKeyField(Object o, + int field, + int superLevel, + boolean isSecField, + Object keyElement) { + // Didn't bother with this one. + return false; + } + + public Object bdbGetField(Object o, + int field, + int superLevel, + boolean isSecField) { + // Didn't bother with this one. + return null; + } + + public void bdbSetField(Object o, + int field, + int superLevel, + boolean isSecField, + Object value) { + // Didn't bother with this one. + } +} diff --git a/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/EvolveCase.java b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/EvolveCase.java new file mode 100644 index 0000000..4451efa --- /dev/null +++ b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/EvolveCase.java @@ -0,0 +1,205 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2000-2009 Oracle. All rights reserved. + * + * $Id$ + */ +package com.sleepycat.persist.test; + +import java.util.Iterator; +import java.util.List; + +import junit.framework.TestCase; + +import com.sleepycat.db.DatabaseException; +import com.sleepycat.db.Environment; +import com.sleepycat.persist.EntityStore; +import com.sleepycat.persist.StoreConfig; +import com.sleepycat.persist.evolve.Mutations; +import com.sleepycat.persist.model.ClassMetadata; +import com.sleepycat.persist.model.EntityModel; +import com.sleepycat.persist.model.Persistent; +import com.sleepycat.persist.raw.RawStore; +import com.sleepycat.persist.raw.RawType; + +@Persistent +abstract class EvolveCase { + + static final String STORE_NAME = "foo"; + + transient boolean updated; + + Mutations getMutations() { + return null; + } + + void configure(EntityModel model, StoreConfig config) { + } + + String getStoreOpenException() { + return null; + } + + int getNRecordsExpected() { + return 1; + } + + void checkUnevolvedModel(EntityModel model, Environment env) { + } + + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + } + + /** + * @throws DatabaseException from subclasses. + */ + void writeObjects(EntityStore store) + throws DatabaseException { + } + + /** + * @throws DatabaseException from subclasses. + */ + void readObjects(EntityStore store, boolean doUpdate) + throws DatabaseException { + } + + /** + * @throws DatabaseException from subclasses. + */ + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + } + + /** + * @throws DatabaseException from subclasses. + */ + void copyRawObjects(RawStore rawStore, EntityStore newStore) + throws DatabaseException { + } + + /** + * Checks for equality and prints the entire values rather than + * abbreviated values like TestCase.assertEquals does. + */ + static void checkEquals(Object expected, Object got) { + if ((expected != null) ? (!expected.equals(got)) : (got != null)) { + TestCase.fail("Expected:\n" + expected + "\nBut got:\n" + got); + } + } + + /** + * Asserts than an entity database exists or does not exist. + */ + static void assertDbExists(boolean expectExists, + Environment env, + String entityClassName) { + assertDbExists(expectExists, env, entityClassName, null); + } + + /** + * Checks that an entity class exists or does not exist. + */ + static void checkEntity(boolean exists, + EntityModel model, + Environment env, + String className, + int version, + String secKeyName) { + if (exists) { + TestCase.assertNotNull(model.getEntityMetadata(className)); + ClassMetadata meta = model.getClassMetadata(className); + TestCase.assertNotNull(meta); + TestCase.assertEquals(version, meta.getVersion()); + TestCase.assertTrue(meta.isEntityClass()); + + RawType raw = model.getRawType(className); + TestCase.assertNotNull(raw); + TestCase.assertEquals(version, raw.getVersion()); + } else { + TestCase.assertNull(model.getEntityMetadata(className)); + TestCase.assertNull(model.getClassMetadata(className)); + TestCase.assertNull(model.getRawType(className)); + } + + assertDbExists(exists, env, className); + if (secKeyName != null) { + assertDbExists(exists, env, className, secKeyName); + } + } + + /** + * Checks that a non-entity class exists or does not exist. + */ + static void checkNonEntity(boolean exists, + EntityModel model, + Environment env, + String className, + int version) { + if (exists) { + ClassMetadata meta = model.getClassMetadata(className); + TestCase.assertNotNull(meta); + TestCase.assertEquals(version, meta.getVersion()); + TestCase.assertTrue(!meta.isEntityClass()); + + RawType raw = model.getRawType(className); + TestCase.assertNotNull(raw); + TestCase.assertEquals(version, raw.getVersion()); + } else { + TestCase.assertNull(model.getClassMetadata(className)); + TestCase.assertNull(model.getRawType(className)); + } + + TestCase.assertNull(model.getEntityMetadata(className)); + assertDbExists(false, env, className); + } + + /** + * Asserts than a database expectExists or does not exist. If keyName is + * null, checks an entity database. If keyName is non-null, checks a + * secondary database. + */ + static void assertDbExists(boolean expectExists, + Environment env, + String entityClassName, + String keyName) { + PersistTestUtils.assertDbExists + (expectExists, env, STORE_NAME, entityClassName, keyName); + } + + static void checkVersions(EntityModel model, String name, int version) { + checkVersions(model, new String[] {name}, new int[] {version}); + } + + static void checkVersions(EntityModel model, + String name1, + int version1, + String name2, + int version2) { + checkVersions + (model, new String[] {name1, name2}, + new int[] {version1, version2}); + } + + private static void checkVersions(EntityModel model, + String[] names, + int[] versions) { + List<RawType> all = model.getAllRawTypeVersions(names[0]); + TestCase.assertNotNull(all); + + assert names.length == versions.length; + TestCase.assertEquals(all.toString(), names.length, all.size()); + + Iterator<RawType> iter = all.iterator(); + for (int i = 0; i < names.length; i += 1) { + RawType type = iter.next(); + TestCase.assertEquals(versions[i], type.getVersion()); + TestCase.assertEquals(names[i], type.getClassName()); + } + } +} diff --git a/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/EvolveClasses.java b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/EvolveClasses.java new file mode 100644 index 0000000..058aef3 --- /dev/null +++ b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/EvolveClasses.java @@ -0,0 +1,6818 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2000-2009 Oracle. All rights reserved. + * + * $Id$ + */ +package com.sleepycat.persist.test; + +import static com.sleepycat.persist.model.Relationship.MANY_TO_ONE; +import static com.sleepycat.persist.model.Relationship.ONE_TO_ONE; + +import java.math.BigInteger; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.StringTokenizer; + +import junit.framework.TestCase; + +import com.sleepycat.db.DatabaseException; +import com.sleepycat.db.Environment; +import com.sleepycat.persist.EntityStore; +import com.sleepycat.persist.PrimaryIndex; +import com.sleepycat.persist.SecondaryIndex; +import com.sleepycat.persist.StoreConfig; +import com.sleepycat.persist.evolve.Conversion; +import com.sleepycat.persist.evolve.Converter; +import com.sleepycat.persist.evolve.Deleter; +import com.sleepycat.persist.evolve.EntityConverter; +import com.sleepycat.persist.evolve.Mutations; +import com.sleepycat.persist.evolve.Renamer; +import com.sleepycat.persist.model.Entity; +import com.sleepycat.persist.model.EntityModel; +import com.sleepycat.persist.model.KeyField; +import com.sleepycat.persist.model.Persistent; +import com.sleepycat.persist.model.PersistentProxy; +import com.sleepycat.persist.model.PrimaryKey; +import com.sleepycat.persist.model.SecondaryKey; +import com.sleepycat.persist.raw.RawObject; +import com.sleepycat.persist.raw.RawStore; +import com.sleepycat.persist.raw.RawType; + +/** + * Nested classes are modified versions of classes of the same name in + * EvolveClasses.java.original. See EvolveTestBase.java for the steps that are + * taken to add a new class (test case). + * + * @author Mark Hayes + */ +class EvolveClasses { + + private static final String PREFIX = EvolveClasses.class.getName() + '$'; + private static final String CASECLS = EvolveCase.class.getName(); + + private static RawObject readRaw(RawStore store, + Object key, + Object... classVersionPairs) + throws DatabaseException { + + return readRaw(store, null, key, classVersionPairs); + } + + /** + * Reads a raw object and checks its superclass names and versions. + */ + private static RawObject readRaw(RawStore store, + String entityClsName, + Object key, + Object... classVersionPairs) + throws DatabaseException { + + TestCase.assertNotNull(store); + TestCase.assertNotNull(key); + + if (entityClsName == null) { + entityClsName = (String) classVersionPairs[0]; + } + PrimaryIndex<Object,RawObject> index = + store.getPrimaryIndex(entityClsName); + TestCase.assertNotNull(index); + + RawObject obj = index.get(key); + TestCase.assertNotNull(obj); + + checkRawType(obj.getType(), classVersionPairs); + + RawObject superObj = obj.getSuper(); + for (int i = 2; i < classVersionPairs.length; i += 2) { + Object[] a = new Object[classVersionPairs.length - i]; + System.arraycopy(classVersionPairs, i, a, 0, a.length); + TestCase.assertNotNull(superObj); + checkRawType(superObj.getType(), a); + superObj = superObj.getSuper(); + } + + return obj; + } + + /** + * Reads a raw object and checks its superclass names and versions. + */ + private static void checkRawType(RawType type, + Object... classVersionPairs) { + TestCase.assertNotNull(type); + TestCase.assertNotNull(classVersionPairs); + TestCase.assertTrue(classVersionPairs.length % 2 == 0); + + for (int i = 0; i < classVersionPairs.length; i += 2) { + String clsName = (String) classVersionPairs[i]; + int clsVersion = (Integer) classVersionPairs[i + 1]; + TestCase.assertEquals(clsName, type.getClassName()); + TestCase.assertEquals(clsVersion, type.getVersion()); + type = type.getSuperType(); + } + TestCase.assertNull(type); + } + + /** + * Checks that a raw object contains the specified field values. Does not + * check superclass fields. + */ + private static void checkRawFields(RawObject obj, + Object... nameValuePairs) { + TestCase.assertNotNull(obj); + TestCase.assertNotNull(obj.getValues()); + TestCase.assertNotNull(nameValuePairs); + TestCase.assertTrue(nameValuePairs.length % 2 == 0); + + Map<String,Object> values = obj.getValues(); + TestCase.assertEquals(nameValuePairs.length / 2, values.size()); + + for (int i = 0; i < nameValuePairs.length; i += 2) { + String name = (String) nameValuePairs[i]; + Object value = nameValuePairs[i + 1]; + TestCase.assertEquals(name, value, values.get(name)); + } + } + + private static Map<String,Object> makeValues(Object... nameValuePairs) { + TestCase.assertTrue(nameValuePairs.length % 2 == 0); + Map<String,Object> values = new HashMap<String,Object>(); + for (int i = 0; i < nameValuePairs.length; i += 2) { + values.put((String) nameValuePairs[i], nameValuePairs[i + 1]); + } + return values; + } + + /** + * Disallow removing an entity class when no Deleter mutation is specified. + */ + static class DeletedEntity1_ClassRemoved_NoMutation extends EvolveCase { + + private static final String NAME = + PREFIX + "DeletedEntity1_ClassRemoved"; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DeletedEntity1_ClassRemoved version: 0 Error: java.lang.ClassNotFoundException: com.sleepycat.persist.test.EvolveClasses$DeletedEntity1_ClassRemoved"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, "skey"); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "skey", 88); + } + } + + /** + * Allow removing an entity class when a Deleter mutation is specified. + */ + static class DeletedEntity2_ClassRemoved_WithDeleter extends EvolveCase { + + private static final String NAME = + PREFIX + "DeletedEntity2_ClassRemoved"; + + @Override + int getNRecordsExpected() { + return 0; + } + + @Override + Mutations getMutations() { + Mutations m = new Mutations(); + m.addDeleter(new Deleter(NAME, 0)); + return m; + } + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkEntity(false, model, env, NAME, 0, "skey"); + if (oldTypesExist) { + checkVersions(model, NAME, 0); + } + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + return; + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "skey", 88); + } + } + + /** + * Disallow removing the Entity annotation when no Deleter mutation is + * specified. + */ + static class DeletedEntity3_AnnotRemoved_NoMutation extends EvolveCase { + + private static final String NAME = + DeletedEntity3_AnnotRemoved_NoMutation.class.getName(); + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DeletedEntity3_AnnotRemoved_NoMutation version: 0 Error: java.lang.IllegalArgumentException: Class could not be loaded or is not persistent: com.sleepycat.persist.test.EvolveClasses$DeletedEntity3_AnnotRemoved_NoMutation"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, "skey"); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "skey", 88); + } + } + + /** + * Allow removing the Entity annotation when a Deleter mutation is + * specified. + */ + static class DeletedEntity4_AnnotRemoved_WithDeleter extends EvolveCase { + + private static final String NAME = + DeletedEntity4_AnnotRemoved_WithDeleter.class.getName(); + + @Override + int getNRecordsExpected() { + return 0; + } + + @Override + Mutations getMutations() { + Mutations m = new Mutations(); + m.addDeleter(new Deleter(NAME, 0)); + return m; + } + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkEntity(false, model, env, NAME, 0, "skey"); + if (oldTypesExist) { + checkVersions(model, NAME, 0); + } + } + + @Override + void readObjects(EntityStore store, boolean doUpdate) { + try { + store.getPrimaryIndex + (Integer.class, + DeletedEntity4_AnnotRemoved_WithDeleter.class); + TestCase.fail(); + } catch (Exception e) { + checkEquals + ("java.lang.IllegalArgumentException: Class could not be loaded or is not an entity class: com.sleepycat.persist.test.EvolveClasses$DeletedEntity4_AnnotRemoved_WithDeleter", + e.toString()); + } + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + return; + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "skey", 88); + } + } + + /** + * Disallow changing the Entity annotation to Persistent when no Deleter + * mutation is specified. + */ + @Persistent(version=1) + static class DeletedEntity5_EntityToPersist_NoMutation extends EvolveCase { + + private static final String NAME = + DeletedEntity5_EntityToPersist_NoMutation.class.getName(); + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DeletedEntity5_EntityToPersist_NoMutation version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DeletedEntity5_EntityToPersist_NoMutation version: 1 Error: @Entity switched to/from @Persistent"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, "skey"); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "skey", 88); + } + } + + /** + * Allow changing the Entity annotation to Persistent when a Deleter + * mutation is specified. + */ + @Persistent(version=1) + static class DeletedEntity6_EntityToPersist_WithDeleter extends EvolveCase { + + private static final String NAME = + DeletedEntity6_EntityToPersist_WithDeleter.class.getName(); + private static final String NAME2 = + Embed_DeletedEntity6_EntityToPersist_WithDeleter.class.getName(); + + @Override + int getNRecordsExpected() { + return 0; + } + + @Override + Mutations getMutations() { + Mutations m = new Mutations(); + m.addDeleter(new Deleter(NAME, 0)); + return m; + } + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkNonEntity(true, model, env, NAME, 1); + if (oldTypesExist) { + checkVersions(model, NAME, 1, NAME, 0); + } else { + checkVersions(model, NAME, 1); + } + } + + @Override + void readObjects(EntityStore store, boolean doUpdate) + throws DatabaseException { + + /* Cannot get the primary index for the former entity class. */ + try { + store.getPrimaryIndex + (Integer.class, + DeletedEntity6_EntityToPersist_WithDeleter.class); + TestCase.fail(); + } catch (Exception e) { + checkEquals + ("java.lang.IllegalArgumentException: Class could not be loaded or is not an entity class: com.sleepycat.persist.test.EvolveClasses$DeletedEntity6_EntityToPersist_WithDeleter", + e.toString()); + } + + /* Can embed the now persistent class in another entity class. */ + PrimaryIndex<Long, + Embed_DeletedEntity6_EntityToPersist_WithDeleter> + index = store.getPrimaryIndex + (Long.class, + Embed_DeletedEntity6_EntityToPersist_WithDeleter.class); + + if (doUpdate) { + Embed_DeletedEntity6_EntityToPersist_WithDeleter embed = + new Embed_DeletedEntity6_EntityToPersist_WithDeleter(); + index.put(embed); + embed = index.get(embed.key); + /* This new type should exist only after update. */ + Environment env = store.getEnvironment(); + EntityModel model = store.getModel(); + checkEntity(true, model, env, NAME2, 0, null); + checkVersions(model, NAME2, 0); + } + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + return; + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "skey", 88); + } + } + + @Entity + static class Embed_DeletedEntity6_EntityToPersist_WithDeleter { + + @PrimaryKey + long key = 99; + + DeletedEntity6_EntityToPersist_WithDeleter embedded = + new DeletedEntity6_EntityToPersist_WithDeleter(); + } + + /** + * Disallow removing a Persistent class when no Deleter mutation is + * specified, even when the Entity class that embedded the Persistent class + * is deleted properly (by removing the Entity annotation in this case). + */ + static class DeletedPersist1_ClassRemoved_NoMutation extends EvolveCase { + + private static final String NAME = + PREFIX + "DeletedPersist1_ClassRemoved"; + + private static final String NAME2 = + DeletedPersist1_ClassRemoved_NoMutation.class.getName(); + + @Override + Mutations getMutations() { + Mutations m = new Mutations(); + m.addDeleter(new Deleter(NAME2, 0)); + return m; + } + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DeletedPersist1_ClassRemoved version: 0 Error: java.lang.ClassNotFoundException: com.sleepycat.persist.test.EvolveClasses$DeletedPersist1_ClassRemoved"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkNonEntity(true, model, env, NAME, 0); + checkEntity(true, model, env, NAME2, 0, null); + checkVersions(model, NAME, 0); + checkVersions(model, NAME2, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + + RawType embedType = store.getModel().getRawType(NAME); + checkRawType(embedType, NAME, 0); + + RawObject embed = + new RawObject(embedType, makeValues("f", 123), null); + + RawObject obj = readRaw(store, 99, NAME2, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "embed", embed); + } + } + + /** + * Allow removing a Persistent class when a Deleter mutation is + * specified, and the Entity class that embedded the Persistent class + * is also deleted properly (by removing the Entity annotation in this + * case). + */ + static class DeletedPersist2_ClassRemoved_WithDeleter extends EvolveCase { + + private static final String NAME = + PREFIX + "DeletedPersist2_ClassRemoved"; + private static final String NAME2 = + DeletedPersist2_ClassRemoved_WithDeleter.class.getName(); + + @Override + int getNRecordsExpected() { + return 0; + } + + @Override + Mutations getMutations() { + Mutations m = new Mutations(); + m.addDeleter(new Deleter(NAME, 0)); + m.addDeleter(new Deleter(NAME2, 0)); + return m; + } + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkNonEntity(false, model, env, NAME, 0); + checkEntity(false, model, env, NAME2, 0, null); + if (oldTypesExist) { + checkVersions(model, NAME, 0); + checkVersions(model, NAME2, 0); + } + } + + @Override + void readObjects(EntityStore store, boolean doUpdate) { + try { + store.getPrimaryIndex + (Integer.class, + DeletedPersist2_ClassRemoved_WithDeleter.class); + TestCase.fail(); + } catch (Exception e) { + checkEquals + ("java.lang.IllegalArgumentException: Class could not be loaded or is not an entity class: com.sleepycat.persist.test.EvolveClasses$DeletedPersist2_ClassRemoved_WithDeleter", + e.toString()); + } + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + return; + } + + RawType embedType = store.getModel().getRawType(NAME); + checkRawType(embedType, NAME, 0); + + RawObject embed = + new RawObject(embedType, makeValues("f", 123), null); + + RawObject obj = readRaw(store, 99, NAME2, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "embed", embed); + } + } + + static class DeletedPersist3_AnnotRemoved { + + int f = 123; + } + + /** + * Disallow removing the Persistent annotation when no Deleter mutation is + * specified, even when the Entity class that embedded the Persistent class + * is deleted properly (by removing the Entity annotation in this case). + */ + static class DeletedPersist3_AnnotRemoved_NoMutation extends EvolveCase { + + private static final String NAME = + DeletedPersist3_AnnotRemoved.class.getName(); + private static final String NAME2 = + DeletedPersist3_AnnotRemoved_NoMutation.class.getName(); + + @Override + Mutations getMutations() { + Mutations m = new Mutations(); + m.addDeleter(new Deleter(NAME2, 0)); + return m; + } + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DeletedPersist3_AnnotRemoved version: 0 Error: java.lang.IllegalArgumentException: Class could not be loaded or is not persistent: com.sleepycat.persist.test.EvolveClasses$DeletedPersist3_AnnotRemoved"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkNonEntity(true, model, env, NAME, 0); + checkEntity(true, model, env, NAME2, 0, null); + checkVersions(model, NAME, 0); + checkVersions(model, NAME2, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + + RawType embedType = store.getModel().getRawType(NAME); + checkRawType(embedType, NAME, 0); + + RawObject embed = + new RawObject(embedType, makeValues("f", 123), null); + + RawObject obj = readRaw(store, 99, NAME2, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "embed", embed); + } + } + + static class DeletedPersist4_AnnotRemoved { + + int f = 123; + } + + /** + * Allow removing the Persistent annotation when a Deleter mutation is + * specified, and the Entity class that embedded the Persistent class + * is also be deleted properly (by removing the Entity annotation in this + * case). + */ + static class DeletedPersist4_AnnotRemoved_WithDeleter extends EvolveCase { + + private static final String NAME = + DeletedPersist4_AnnotRemoved.class.getName(); + private static final String NAME2 = + DeletedPersist4_AnnotRemoved_WithDeleter.class.getName(); + + @Override + int getNRecordsExpected() { + return 0; + } + + @Override + Mutations getMutations() { + Mutations m = new Mutations(); + m.addDeleter(new Deleter(NAME, 0)); + m.addDeleter(new Deleter(NAME2, 0)); + return m; + } + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkNonEntity(false, model, env, NAME, 0); + checkEntity(false, model, env, NAME2, 0, null); + if (oldTypesExist) { + checkVersions(model, NAME, 0); + checkVersions(model, NAME2, 0); + } + } + + @Override + void readObjects(EntityStore store, boolean doUpdate) { + try { + store.getPrimaryIndex + (Integer.class, + DeletedPersist4_AnnotRemoved_WithDeleter.class); + TestCase.fail(); + } catch (Exception e) { + checkEquals + ("java.lang.IllegalArgumentException: Class could not be loaded or is not an entity class: com.sleepycat.persist.test.EvolveClasses$DeletedPersist4_AnnotRemoved_WithDeleter", + e.toString()); + } + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + return; + } + + RawType embedType = store.getModel().getRawType(NAME); + checkRawType(embedType, NAME, 0); + + RawObject embed = + new RawObject(embedType, makeValues("f", 123), null); + + RawObject obj = readRaw(store, 99, NAME2, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "embed", embed); + } + } + + @Entity(version=1) + static class DeletedPersist5_PersistToEntity { + + @PrimaryKey + int key = 99; + + int f = 123; + } + + /** + * Disallow changing the Entity annotation to Persistent when no Deleter + * mutation is specified, even when the Entity class that embedded the + * Persistent class is deleted properly (by removing the Entity annotation + * in this case). + */ + static class DeletedPersist5_PersistToEntity_NoMutation + extends EvolveCase { + + private static final String NAME = + DeletedPersist5_PersistToEntity.class.getName(); + private static final String NAME2 = + DeletedPersist5_PersistToEntity_NoMutation.class.getName(); + + @Override + Mutations getMutations() { + Mutations m = new Mutations(); + m.addDeleter(new Deleter(NAME2, 0)); + return m; + } + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DeletedPersist5_PersistToEntity version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DeletedPersist5_PersistToEntity version: 1 Error: @Entity switched to/from @Persistent"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkNonEntity(true, model, env, NAME, 0); + checkEntity(true, model, env, NAME2, 0, null); + checkVersions(model, NAME, 0); + checkVersions(model, NAME2, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + + RawType embedType = store.getModel().getRawType(NAME); + checkRawType(embedType, NAME, 0); + + RawObject embed = + new RawObject(embedType, makeValues("f", 123), null); + + RawObject obj = readRaw(store, 99, NAME2, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "embed", embed); + } + } + + @Entity(version=1) + static class DeletedPersist6_PersistToEntity { + + @PrimaryKey + int key = 99; + + int f = 123; + } + + /** + * Allow changing the Entity annotation to Persistent when a Deleter + * mutation is specified, and the Entity class that embedded the Persistent + * class is also be deleted properly (by removing the Entity annotation in + * this case). + */ + static class DeletedPersist6_PersistToEntity_WithDeleter + extends EvolveCase { + + private static final String NAME = + DeletedPersist6_PersistToEntity.class.getName(); + private static final String NAME2 = + DeletedPersist6_PersistToEntity_WithDeleter.class.getName(); + + @Override + int getNRecordsExpected() { + return 0; + } + + @Override + Mutations getMutations() { + Mutations m = new Mutations(); + m.addDeleter(new Deleter(NAME, 0)); + m.addDeleter(new Deleter(NAME2, 0)); + return m; + } + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkEntity(false, model, env, NAME2, 0, null); + if (oldTypesExist) { + checkVersions(model, NAME, 1, NAME, 0); + checkVersions(model, NAME2, 0); + } else { + checkVersions(model, NAME, 1); + } + } + + @Override + void readObjects(EntityStore store, boolean doUpdate) + throws DatabaseException { + + /* Cannot get the primary index for the former entity class. */ + try { + store.getPrimaryIndex + (Integer.class, + DeletedPersist6_PersistToEntity_WithDeleter.class); + TestCase.fail(); + } catch (Exception e) { + checkEquals + ("java.lang.IllegalArgumentException: Class could not be loaded or is not an entity class: com.sleepycat.persist.test.EvolveClasses$DeletedPersist6_PersistToEntity_WithDeleter", + e.toString()); + } + + /* Can use the primary index of the now entity class. */ + PrimaryIndex<Integer, + DeletedPersist6_PersistToEntity> + index = store.getPrimaryIndex + (Integer.class, + DeletedPersist6_PersistToEntity.class); + + if (doUpdate) { + DeletedPersist6_PersistToEntity obj = + new DeletedPersist6_PersistToEntity(); + index.put(obj); + obj = index.get(obj.key); + /* This new type should exist only after update. */ + Environment env = store.getEnvironment(); + EntityModel model = store.getModel(); + checkEntity(true, model, env, NAME, 1, null); + } + } + + @Override + void copyRawObjects(RawStore rawStore, EntityStore newStore) + throws DatabaseException { + + PrimaryIndex<Integer, + DeletedPersist6_PersistToEntity> + index = newStore.getPrimaryIndex + (Integer.class, + DeletedPersist6_PersistToEntity.class); + RawObject raw = rawStore.getPrimaryIndex(NAME).get(99); + index.put((DeletedPersist6_PersistToEntity) + newStore.getModel().convertRawObject(raw)); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + return; + } + + RawType embedType = store.getModel().getRawType(NAME); + checkRawType(embedType, NAME, 0); + + RawObject embed = + new RawObject(embedType, makeValues("f", 123), null); + + RawObject obj = readRaw(store, 99, NAME2, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "embed", embed); + } + } + + /** + * Disallow renaming an entity class without a Renamer mutation. + */ + @Entity(version=1) + static class RenamedEntity1_NewEntityName_NoMutation + extends EvolveCase { + + private static final String NAME = + PREFIX + "RenamedEntity1_NewEntityName"; + private static final String NAME2 = + RenamedEntity1_NewEntityName_NoMutation.class.getName(); + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + int skey = 88; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$RenamedEntity1_NewEntityName version: 0 Error: java.lang.ClassNotFoundException: com.sleepycat.persist.test.EvolveClasses$RenamedEntity1_NewEntityName"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, "skey"); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "skey", 88); + } + } + + /** + * Allow renaming an entity class with a Renamer mutation. + */ + @Entity(version=1) + static class RenamedEntity2_NewEntityName_WithRenamer + extends EvolveCase { + + private static final String NAME = + PREFIX + "RenamedEntity2_NewEntityName"; + private static final String NAME2 = + RenamedEntity2_NewEntityName_WithRenamer.class.getName(); + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + int skey = 88; + + @Override + Mutations getMutations() { + Mutations m = new Mutations(); + m.addRenamer(new Renamer(NAME, 0, NAME2)); + return m; + } + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkEntity(false, model, env, NAME, 0, null); + checkEntity(true, model, env, NAME2, 1, null); + if (oldTypesExist) { + checkVersions(model, NAME2, 1, NAME, 0); + } else { + checkVersions(model, NAME2, 1); + } + } + + @Override + void readObjects(EntityStore store, boolean doUpdate) + throws DatabaseException { + + PrimaryIndex<Integer,RenamedEntity2_NewEntityName_WithRenamer> + index = store.getPrimaryIndex + (Integer.class, + RenamedEntity2_NewEntityName_WithRenamer.class); + RenamedEntity2_NewEntityName_WithRenamer obj = index.get(key); + TestCase.assertNotNull(obj); + TestCase.assertEquals(99, obj.key); + TestCase.assertEquals(88, obj.skey); + + SecondaryIndex<Integer,Integer, + RenamedEntity2_NewEntityName_WithRenamer> + sindex = store.getSecondaryIndex(index, Integer.class, "skey"); + obj = sindex.get(88); + TestCase.assertNotNull(obj); + TestCase.assertEquals(99, obj.key); + TestCase.assertEquals(88, obj.skey); + + if (doUpdate) { + index.put(obj); + } + } + + @Override + void copyRawObjects(RawStore rawStore, EntityStore newStore) + throws DatabaseException { + + PrimaryIndex<Integer,RenamedEntity2_NewEntityName_WithRenamer> + index = newStore.getPrimaryIndex + (Integer.class, + RenamedEntity2_NewEntityName_WithRenamer.class); + RawObject raw = rawStore.getPrimaryIndex(NAME2).get(99); + index.put((RenamedEntity2_NewEntityName_WithRenamer) + newStore.getModel().convertRawObject(raw)); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + RawObject obj; + if (expectEvolved) { + obj = readRaw(store, 99, NAME2, 1, CASECLS, 0); + } else { + obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + } + checkRawFields(obj, "key", 99, "skey", 88); + } + } + + @Persistent + static class DeleteSuperclass1_BaseClass + extends EvolveCase { + + int f = 123; + } + + /** + * Disallow deleting a superclass from the hierarchy when the superclass + * has persistent fields and no Deleter or Converter is specified. + */ + @Entity + static class DeleteSuperclass1_NoMutation + extends EvolveCase { + + private static final String NAME = + DeleteSuperclass1_BaseClass.class.getName(); + private static final String NAME2 = + DeleteSuperclass1_NoMutation.class.getName(); + + @PrimaryKey + int key = 99; + + int ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DeleteSuperclass1_NoMutation version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DeleteSuperclass1_NoMutation version: 0 Error: When a superclass is removed from the class hierarchy, the superclass or all of its persistent fields must be deleted with a Deleter: com.sleepycat.persist.test.EvolveClasses$DeleteSuperclass1_BaseClass"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkNonEntity(true, model, env, NAME, 0); + checkEntity(true, model, env, NAME2, 0, null); + checkVersions(model, NAME, 0); + checkVersions(model, NAME2, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME2, 0, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", 88); + checkRawFields(obj.getSuper(), "f", 123); + checkRawFields(obj.getSuper().getSuper()); + } + } + + @Persistent + static class DeleteSuperclass2_BaseClass + extends EvolveCase { + + int f; + + @SecondaryKey(relate=ONE_TO_ONE) + int skey; + } + + /** + * Allow deleting a superclass from the hierarchy when the superclass has + * persistent fields and a class Converter is specified. Also check that + * the secondary key field in the deleted base class is handled properly. + */ + @Entity(version=1) + static class DeleteSuperclass2_WithConverter extends EvolveCase { + + private static final String NAME = + DeleteSuperclass2_BaseClass.class.getName(); + private static final String NAME2 = + DeleteSuperclass2_WithConverter.class.getName(); + + @PrimaryKey + int key; + + int ff; + + @SecondaryKey(relate=ONE_TO_ONE) + Integer skey2; + + @SecondaryKey(relate=ONE_TO_ONE) + int skey3; + + @Override + Mutations getMutations() { + Mutations m = new Mutations(); + m.addConverter(new EntityConverter + (NAME2, 0, new MyConversion(), + Collections.singleton("skey"))); + return m; + } + + @SuppressWarnings("serial") + static class MyConversion implements Conversion { + + transient RawType newType; + + public void initialize(EntityModel model) { + newType = model.getRawType(NAME2); + TestCase.assertNotNull(newType); + } + + public Object convert(Object fromValue) { + TestCase.assertNotNull(newType); + RawObject obj = (RawObject) fromValue; + RawObject newSuper = obj.getSuper().getSuper(); + return new RawObject(newType, obj.getValues(), newSuper); + } + + @Override + public boolean equals(Object other) { + return other instanceof MyConversion; + } + } + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkEntity(true, model, env, NAME2, 1, null); + if (oldTypesExist) { + checkVersions(model, NAME2, 1, NAME2, 0); + checkNonEntity(true, model, env, NAME, 0); + checkVersions(model, NAME, 0); + } else { + checkVersions(model, NAME2, 1); + } + } + + @Override + void readObjects(EntityStore store, boolean doUpdate) + throws DatabaseException { + + PrimaryIndex<Integer,DeleteSuperclass2_WithConverter> + index = store.getPrimaryIndex + (Integer.class, + DeleteSuperclass2_WithConverter.class); + DeleteSuperclass2_WithConverter obj = index.get(99); + TestCase.assertNotNull(obj); + TestCase.assertSame + (EvolveCase.class, obj.getClass().getSuperclass()); + TestCase.assertEquals(99, obj.key); + TestCase.assertEquals(88, obj.ff); + TestCase.assertEquals(Integer.valueOf(77), obj.skey2); + TestCase.assertEquals(66, obj.skey3); + if (doUpdate) { + index.put(obj); + } + } + + @Override + void copyRawObjects(RawStore rawStore, EntityStore newStore) + throws DatabaseException { + + PrimaryIndex<Integer,DeleteSuperclass2_WithConverter> + index = newStore.getPrimaryIndex + (Integer.class, + DeleteSuperclass2_WithConverter.class); + RawObject raw = rawStore.getPrimaryIndex(NAME2).get(99); + index.put((DeleteSuperclass2_WithConverter) + newStore.getModel().convertRawObject(raw)); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + RawObject obj; + if (expectEvolved) { + obj = readRaw(store, 99, NAME2, 1, CASECLS, 0); + } else { + obj = readRaw(store, 99, NAME2, 0, NAME, 0, CASECLS, 0); + } + checkRawFields + (obj, "key", 99, "ff", 88, "skey2", 77, "skey3", 66); + if (expectEvolved) { + checkRawFields(obj.getSuper()); + } else { + checkRawFields(obj.getSuper(), "f", 123, "skey", 456); + checkRawFields(obj.getSuper().getSuper()); + } + Environment env = store.getEnvironment(); + assertDbExists(!expectEvolved, env, NAME2, "skey"); + assertDbExists(true, env, NAME2, "skey3"); + } + } + + static class DeleteSuperclass3_BaseClass + extends EvolveCase { + + int f; + + @SecondaryKey(relate=ONE_TO_ONE) + int skey; + } + + /** + * Allow deleting a superclass from the hierarchy when the superclass + * has persistent fields and a class Deleter is specified. Also check that + * the secondary key field in the deleted base class is handled properly. + */ + @Entity(version=1) + static class DeleteSuperclass3_WithDeleter extends EvolveCase { + + private static final String NAME = + DeleteSuperclass3_BaseClass.class.getName(); + private static final String NAME2 = + DeleteSuperclass3_WithDeleter.class.getName(); + + @PrimaryKey + int key; + + int ff; + + @Override + Mutations getMutations() { + Mutations m = new Mutations(); + m.addDeleter(new Deleter(NAME, 0)); + return m; + } + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkEntity(true, model, env, NAME2, 1, null); + if (oldTypesExist) { + checkVersions(model, NAME2, 1, NAME2, 0); + checkNonEntity(false, model, env, NAME, 0); + checkVersions(model, NAME, 0); + } else { + checkVersions(model, NAME2, 1); + } + } + + @Override + void readObjects(EntityStore store, boolean doUpdate) + throws DatabaseException { + + PrimaryIndex<Integer,DeleteSuperclass3_WithDeleter> + index = store.getPrimaryIndex + (Integer.class, + DeleteSuperclass3_WithDeleter.class); + DeleteSuperclass3_WithDeleter obj = index.get(99); + TestCase.assertNotNull(obj); + TestCase.assertSame + (EvolveCase.class, obj.getClass().getSuperclass()); + TestCase.assertEquals(99, obj.key); + TestCase.assertEquals(88, obj.ff); + if (doUpdate) { + index.put(obj); + } + } + + @Override + void copyRawObjects(RawStore rawStore, EntityStore newStore) + throws DatabaseException { + + PrimaryIndex<Integer,DeleteSuperclass3_WithDeleter> + index = newStore.getPrimaryIndex + (Integer.class, + DeleteSuperclass3_WithDeleter.class); + RawObject raw = rawStore.getPrimaryIndex(NAME2).get(99); + index.put((DeleteSuperclass3_WithDeleter) + newStore.getModel().convertRawObject(raw)); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + RawObject obj; + if (expectEvolved) { + obj = readRaw(store, 99, NAME2, 1, CASECLS, 0); + } else { + obj = readRaw(store, 99, NAME2, 0, NAME, 0, CASECLS, 0); + } + checkRawFields(obj, "key", 99, "ff", 88); + if (expectEvolved) { + checkRawFields(obj.getSuper()); + } else { + checkRawFields(obj.getSuper(), "f", 123, "skey", 456); + checkRawFields(obj.getSuper().getSuper()); + } + Environment env = store.getEnvironment(); + assertDbExists(!expectEvolved, env, NAME2, "skey"); + } + } + + @Persistent + static class DeleteSuperclass4_BaseClass + extends EvolveCase { + } + + /** + * Allow deleting a superclass from the hierarchy when the superclass + * has NO persistent fields. No mutations are needed. + */ + @Entity(version=1) + static class DeleteSuperclass4_NoFields extends EvolveCase { + + private static final String NAME = + DeleteSuperclass4_BaseClass.class.getName(); + private static final String NAME2 = + DeleteSuperclass4_NoFields.class.getName(); + + @PrimaryKey + int key = 99; + + int ff; + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkEntity(true, model, env, NAME2, 1, null); + if (oldTypesExist) { + checkVersions(model, NAME2, 1, NAME2, 0); + checkNonEntity(true, model, env, NAME, 0); + checkVersions(model, NAME, 0); + } else { + checkVersions(model, NAME2, 1); + } + } + + @Override + void readObjects(EntityStore store, boolean doUpdate) + throws DatabaseException { + + PrimaryIndex<Integer,DeleteSuperclass4_NoFields> + index = store.getPrimaryIndex + (Integer.class, + DeleteSuperclass4_NoFields.class); + DeleteSuperclass4_NoFields obj = index.get(key); + TestCase.assertNotNull(obj); + TestCase.assertSame + (EvolveCase.class, obj.getClass().getSuperclass()); + TestCase.assertEquals(99, obj.key); + TestCase.assertEquals(88, obj.ff); + if (doUpdate) { + index.put(obj); + } + } + + @Override + void copyRawObjects(RawStore rawStore, EntityStore newStore) + throws DatabaseException { + + PrimaryIndex<Integer,DeleteSuperclass4_NoFields> + index = newStore.getPrimaryIndex + (Integer.class, + DeleteSuperclass4_NoFields.class); + RawObject raw = rawStore.getPrimaryIndex(NAME2).get(99); + index.put((DeleteSuperclass4_NoFields) + newStore.getModel().convertRawObject(raw)); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + RawObject obj; + if (expectEvolved) { + obj = readRaw(store, 99, NAME2, 1, CASECLS, 0); + } else { + obj = readRaw(store, 99, NAME2, 0, NAME, 0, CASECLS, 0); + } + checkRawFields(obj, "key", 99, "ff", 88); + checkRawFields(obj.getSuper()); + if (expectEvolved) { + TestCase.assertNull(obj.getSuper().getSuper()); + } else { + checkRawFields(obj.getSuper().getSuper()); + } + } + } + + @Persistent(version=1) + static class DeleteSuperclass5_Embedded { + + int f; + + @Override + public String toString() { + return "" + f; + } + } + + /** + * Ensure that a superclass at the top of the hierarchy can be deleted. A + * class Deleter is used. + */ + @Entity + static class DeleteSuperclass5_Top + extends EvolveCase { + + private static final String NAME = + DeleteSuperclass5_Top.class.getName(); + private static final String NAME2 = + DeleteSuperclass5_Embedded.class.getName(); + private static final String NAME3 = + PREFIX + "DeleteSuperclass5_Embedded_Base"; + + @PrimaryKey + int key = 99; + + int ff; + + DeleteSuperclass5_Embedded embed = + new DeleteSuperclass5_Embedded(); + + @Override + Mutations getMutations() { + Mutations m = new Mutations(); + m.addDeleter(new Deleter(NAME3, 0)); + return m; + } + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkEntity(true, model, env, NAME, 0, null); + checkNonEntity(true, model, env, NAME2, 1); + checkNonEntity(false, model, env, NAME3, 0); + checkVersions(model, NAME, 0); + if (oldTypesExist) { + checkVersions(model, NAME2, 1, NAME2, 0); + checkVersions(model, NAME3, 0); + } else { + checkVersions(model, NAME2, 1); + } + } + + @Override + void readObjects(EntityStore store, boolean doUpdate) + throws DatabaseException { + + PrimaryIndex<Integer,DeleteSuperclass5_Top> + index = store.getPrimaryIndex + (Integer.class, + DeleteSuperclass5_Top.class); + DeleteSuperclass5_Top obj = index.get(key); + TestCase.assertNotNull(obj); + TestCase.assertNotNull(obj.embed); + TestCase.assertEquals(99, obj.key); + TestCase.assertEquals(88, obj.ff); + TestCase.assertEquals(123, obj.embed.f); + if (doUpdate) { + index.put(obj); + } + } + + @Override + void copyRawObjects(RawStore rawStore, EntityStore newStore) + throws DatabaseException { + + PrimaryIndex<Integer,DeleteSuperclass5_Top> + index = newStore.getPrimaryIndex + (Integer.class, + DeleteSuperclass5_Top.class); + RawObject raw = rawStore.getPrimaryIndex(NAME).get(99); + index.put((DeleteSuperclass5_Top) + newStore.getModel().convertRawObject(raw)); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + RawType embedType = store.getModel().getRawType(NAME2); + RawObject embedSuper = null; + if (!expectEvolved) { + RawType embedSuperType = store.getModel().getRawType(NAME3); + embedSuper = new RawObject + (embedSuperType, makeValues("g", 456), null); + } + RawObject embed = + new RawObject(embedType, makeValues("f", 123), embedSuper); + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", 88, "embed", embed); + } + } + + @Persistent + static class InsertSuperclass1_BaseClass + extends EvolveCase { + + int f = 123; + } + + /** + * Allow inserting a superclass between two existing classes in the + * hierarchy. No mutations are needed. + */ + @Entity(version=1) + static class InsertSuperclass1_Between + extends InsertSuperclass1_BaseClass { + + private static final String NAME = + InsertSuperclass1_BaseClass.class.getName(); + private static final String NAME2 = + InsertSuperclass1_Between.class.getName(); + + @PrimaryKey + int key = 99; + + int ff; + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkNonEntity(true, model, env, NAME, 0); + checkEntity(true, model, env, NAME2, 1, null); + checkVersions(model, NAME, 0); + if (oldTypesExist) { + checkVersions(model, NAME2, 1, NAME2, 0); + } else { + checkVersions(model, NAME2, 1); + } + } + + @Override + void readObjects(EntityStore store, boolean doUpdate) + throws DatabaseException { + + PrimaryIndex<Integer,InsertSuperclass1_Between> + index = store.getPrimaryIndex + (Integer.class, + InsertSuperclass1_Between.class); + InsertSuperclass1_Between obj = index.get(key); + TestCase.assertNotNull(obj); + TestCase.assertSame + (InsertSuperclass1_BaseClass.class, + obj.getClass().getSuperclass()); + TestCase.assertSame + (EvolveCase.class, + obj.getClass().getSuperclass().getSuperclass()); + TestCase.assertEquals(99, obj.key); + TestCase.assertEquals(88, obj.ff); + TestCase.assertEquals(123, obj.f); + if (doUpdate) { + index.put(obj); + } + } + + @Override + void copyRawObjects(RawStore rawStore, EntityStore newStore) + throws DatabaseException { + + PrimaryIndex<Integer,InsertSuperclass1_Between> + index = newStore.getPrimaryIndex + (Integer.class, + InsertSuperclass1_Between.class); + RawObject raw = rawStore.getPrimaryIndex(NAME2).get(99); + index.put((InsertSuperclass1_Between) + newStore.getModel().convertRawObject(raw)); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + RawObject obj; + if (expectEvolved) { + obj = readRaw(store, 99, NAME2, 1, NAME, 0, CASECLS, 0); + } else { + obj = readRaw(store, 99, NAME2, 0, CASECLS, 0); + } + checkRawFields(obj, "key", 99, "ff", 88); + if (expectEvolved) { + if (expectUpdated) { + checkRawFields(obj.getSuper(), "f", 123); + } else { + checkRawFields(obj.getSuper()); + } + checkRawFields(obj.getSuper().getSuper()); + TestCase.assertNull(obj.getSuper().getSuper().getSuper()); + } else { + checkRawFields(obj.getSuper()); + TestCase.assertNull(obj.getSuper().getSuper()); + } + } + } + + @Persistent + static class InsertSuperclass2_Embedded_Base { + + int g = 456; + } + + @Persistent(version=1) + static class InsertSuperclass2_Embedded + extends InsertSuperclass2_Embedded_Base { + + int f; + } + + /** + * Allow inserting a superclass at the top of the hierarchy. No mutations + * are needed. + */ + @Entity + static class InsertSuperclass2_Top + extends EvolveCase { + + private static final String NAME = + InsertSuperclass2_Top.class.getName(); + private static final String NAME2 = + InsertSuperclass2_Embedded.class.getName(); + private static final String NAME3 = + InsertSuperclass2_Embedded_Base.class.getName(); + + @PrimaryKey + int key = 99; + + int ff; + + InsertSuperclass2_Embedded embed = + new InsertSuperclass2_Embedded(); + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkEntity(true, model, env, NAME, 0, null); + checkNonEntity(true, model, env, NAME2, 1); + checkNonEntity(true, model, env, NAME3, 0); + checkVersions(model, NAME, 0); + if (oldTypesExist) { + checkVersions(model, NAME2, 1, NAME2, 0); + } else { + checkVersions(model, NAME2, 1); + } + checkVersions(model, NAME3, 0); + } + + @Override + void readObjects(EntityStore store, boolean doUpdate) + throws DatabaseException { + + PrimaryIndex<Integer,InsertSuperclass2_Top> + index = store.getPrimaryIndex + (Integer.class, + InsertSuperclass2_Top.class); + InsertSuperclass2_Top obj = index.get(key); + TestCase.assertNotNull(obj); + TestCase.assertNotNull(obj.embed); + TestCase.assertEquals(99, obj.key); + TestCase.assertEquals(88, obj.ff); + TestCase.assertEquals(123, obj.embed.f); + TestCase.assertEquals(456, obj.embed.g); + if (doUpdate) { + index.put(obj); + } + } + + @Override + void copyRawObjects(RawStore rawStore, EntityStore newStore) + throws DatabaseException { + + PrimaryIndex<Integer,InsertSuperclass2_Top> + index = newStore.getPrimaryIndex + (Integer.class, + InsertSuperclass2_Top.class); + RawObject raw = rawStore.getPrimaryIndex(NAME).get(99); + index.put((InsertSuperclass2_Top) + newStore.getModel().convertRawObject(raw)); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + RawType embedType = store.getModel().getRawType(NAME2); + RawObject embedSuper = null; + if (expectEvolved) { + RawType embedSuperType = store.getModel().getRawType(NAME3); + Map<String,Object> values = + expectUpdated ? makeValues("g", 456) : makeValues(); + embedSuper = new RawObject(embedSuperType, values, null); + } + RawObject embed = + new RawObject(embedType, makeValues("f", 123), embedSuper); + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", 88, "embed", embed); + } + } + + @Entity(version=1) + static class DisallowNonKeyField_PrimitiveToObject + extends EvolveCase { + + private static final String NAME = + DisallowNonKeyField_PrimitiveToObject.class.getName(); + + @PrimaryKey + int key = 99; + + String ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_PrimitiveToObject version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_PrimitiveToObject version: 1 Error: Old field type: int is not compatible with the new type: java.lang.String for field: ff"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", 88); + } + } + + @Entity(version=1) + static class DisallowNonKeyField_ObjectToPrimitive + extends EvolveCase { + + private static final String NAME = + DisallowNonKeyField_ObjectToPrimitive.class.getName(); + + @PrimaryKey + int key = 99; + + int ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_ObjectToPrimitive version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_ObjectToPrimitive version: 1 Error: Old field type: java.lang.String is not compatible with the new type: int for field: ff"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", "88"); + } + } + + @Persistent + static class MyType { + + @Override + public boolean equals(Object o) { + return o instanceof MyType; + } + } + + @Persistent + static class MySubtype extends MyType { + + @Override + public boolean equals(Object o) { + return o instanceof MySubtype; + } + } + + @Entity(version=1) + static class DisallowNonKeyField_ObjectToSubtype + extends EvolveCase { + + private static final String NAME = + DisallowNonKeyField_ObjectToSubtype.class.getName(); + + @PrimaryKey + int key = 99; + + MySubtype ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_ObjectToSubtype version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_ObjectToSubtype version: 1 Error: Old field type: com.sleepycat.persist.test.EvolveClasses$MyType is not compatible with the new type: com.sleepycat.persist.test.EvolveClasses$MySubtype for field: ff"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawType embedType = store.getModel().getRawType + (MyType.class.getName()); + RawObject embed = new RawObject(embedType, makeValues(), null); + + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", embed); + } + } + + @Entity(version=1) + static class DisallowNonKeyField_ObjectToUnrelatedSimple + extends EvolveCase { + + private static final String NAME = + DisallowNonKeyField_ObjectToUnrelatedSimple.class.getName(); + + @PrimaryKey + int key = 99; + + String ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_ObjectToUnrelatedSimple version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_ObjectToUnrelatedSimple version: 1 Error: Old field type: java.lang.Integer is not compatible with the new type: java.lang.String for field: ff"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", 88); + } + } + + @Entity(version=1) + static class DisallowNonKeyField_ObjectToUnrelatedOther + extends EvolveCase { + + private static final String NAME = + DisallowNonKeyField_ObjectToUnrelatedOther.class.getName(); + + @PrimaryKey + int key = 99; + + MyType ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_ObjectToUnrelatedOther version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_ObjectToUnrelatedOther version: 1 Error: Old field type: java.lang.Integer is not compatible with the new type: com.sleepycat.persist.test.EvolveClasses$MyType for field: ff"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", 88); + } + } + + @Entity(version=1) + static class DisallowNonKeyField_byte2boolean + extends EvolveCase { + + private static final String NAME = + DisallowNonKeyField_byte2boolean.class.getName(); + + @PrimaryKey + int key = 99; + + boolean ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_byte2boolean version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_byte2boolean version: 1 Error: Old field type: byte is not compatible with the new type: boolean for field: ff"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", (byte) 88); + } + } + + @Entity(version=1) + static class DisallowNonKeyField_short2byte + extends EvolveCase { + + private static final String NAME = + DisallowNonKeyField_short2byte.class.getName(); + + @PrimaryKey + int key = 99; + + byte ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_short2byte version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_short2byte version: 1 Error: Old field type: short is not compatible with the new type: byte for field: ff"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", (short) 88); + } + } + + @Entity(version=1) + static class DisallowNonKeyField_int2short + extends EvolveCase { + + private static final String NAME = + DisallowNonKeyField_int2short.class.getName(); + + @PrimaryKey + int key = 99; + + short ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_int2short version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_int2short version: 1 Error: Old field type: int is not compatible with the new type: short for field: ff"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", 88); + } + } + + @Entity(version=1) + static class DisallowNonKeyField_long2int + extends EvolveCase { + + private static final String NAME = + DisallowNonKeyField_long2int.class.getName(); + + @PrimaryKey + int key = 99; + + int ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_long2int version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_long2int version: 1 Error: Old field type: long is not compatible with the new type: int for field: ff"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", (long) 88); + } + } + + @Entity(version=1) + static class DisallowNonKeyField_float2long + extends EvolveCase { + + private static final String NAME = + DisallowNonKeyField_float2long.class.getName(); + + @PrimaryKey + int key = 99; + + long ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_float2long version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_float2long version: 1 Error: Old field type: float is not compatible with the new type: long for field: ff"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", (float) 88); + } + } + + @Entity(version=1) + static class DisallowNonKeyField_double2float + extends EvolveCase { + + private static final String NAME = + DisallowNonKeyField_double2float.class.getName(); + + @PrimaryKey + int key = 99; + + float ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_double2float version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_double2float version: 1 Error: Old field type: double is not compatible with the new type: float for field: ff"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", (double) 88); + } + } + + @Entity(version=1) + static class DisallowNonKeyField_Byte2byte + extends EvolveCase { + + private static final String NAME = + DisallowNonKeyField_Byte2byte.class.getName(); + + @PrimaryKey + int key = 99; + + byte ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_Byte2byte version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_Byte2byte version: 1 Error: Old field type: java.lang.Byte is not compatible with the new type: byte for field: ff"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", (byte) 88); + } + } + + @Entity(version=1) + static class DisallowNonKeyField_Character2char + extends EvolveCase { + + private static final String NAME = + DisallowNonKeyField_Character2char.class.getName(); + + @PrimaryKey + int key = 99; + + char ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_Character2char version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_Character2char version: 1 Error: Old field type: java.lang.Character is not compatible with the new type: char for field: ff"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", (char) 88); + } + } + + @Entity(version=1) + static class DisallowNonKeyField_Short2short + extends EvolveCase { + + private static final String NAME = + DisallowNonKeyField_Short2short.class.getName(); + + @PrimaryKey + int key = 99; + + short ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_Short2short version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_Short2short version: 1 Error: Old field type: java.lang.Short is not compatible with the new type: short for field: ff"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", (short) 88); + } + } + + @Entity(version=1) + static class DisallowNonKeyField_Integer2int + extends EvolveCase { + + private static final String NAME = + DisallowNonKeyField_Integer2int.class.getName(); + + @PrimaryKey + int key = 99; + + int ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_Integer2int version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_Integer2int version: 1 Error: Old field type: java.lang.Integer is not compatible with the new type: int for field: ff"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", 88); + } + } + + @Entity(version=1) + static class DisallowNonKeyField_Long2long + extends EvolveCase { + + private static final String NAME = + DisallowNonKeyField_Long2long.class.getName(); + + @PrimaryKey + int key = 99; + + long ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_Long2long version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_Long2long version: 1 Error: Old field type: java.lang.Long is not compatible with the new type: long for field: ff"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", (long) 88); + } + } + + @Entity(version=1) + static class DisallowNonKeyField_Float2float + extends EvolveCase { + + private static final String NAME = + DisallowNonKeyField_Float2float.class.getName(); + + @PrimaryKey + int key = 99; + + float ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_Float2float version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_Float2float version: 1 Error: Old field type: java.lang.Float is not compatible with the new type: float for field: ff"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", (float) 88); + } + } + + @Entity(version=1) + static class DisallowNonKeyField_Double2double + extends EvolveCase { + + private static final String NAME = + DisallowNonKeyField_Double2double.class.getName(); + + @PrimaryKey + int key = 99; + + double ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_Double2double version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_Double2double version: 1 Error: Old field type: java.lang.Double is not compatible with the new type: double for field: ff"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", (double) 88); + } + } + + @Entity(version=1) + static class DisallowNonKeyField_float2BigInt + extends EvolveCase { + + private static final String NAME = + DisallowNonKeyField_float2BigInt.class.getName(); + + @PrimaryKey + int key = 99; + + BigInteger ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_float2BigInt version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_float2BigInt version: 1 Error: Old field type: float is not compatible with the new type: java.math.BigInteger for field: ff"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", (float) 88); + } + } + + @Entity(version=1) + static class DisallowNonKeyField_BigInt2long + extends EvolveCase { + + private static final String NAME = + DisallowNonKeyField_BigInt2long.class.getName(); + + @PrimaryKey + int key = 99; + + long ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_BigInt2long version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowNonKeyField_BigInt2long version: 1 Error: Old field type: java.math.BigInteger is not compatible with the new type: long for field: ff"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", BigInteger.valueOf(88)); + } + } + + @Entity(version=1) + static class DisallowSecKeyField_byte2short + extends EvolveCase { + + private static final String NAME = + DisallowSecKeyField_byte2short.class.getName(); + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + short ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DisallowSecKeyField_byte2short version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowSecKeyField_byte2short version: 1 Error: Old field type: byte is not compatible with the new type: short for field: ff"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, "ff"); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", (byte) 88); + } + } + + @Entity(version=1) + static class DisallowSecKeyField_char2int + extends EvolveCase { + + private static final String NAME = + DisallowSecKeyField_char2int.class.getName(); + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + int ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DisallowSecKeyField_char2int version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowSecKeyField_char2int version: 1 Error: Old field type: char is not compatible with the new type: int for field: ff"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, "ff"); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", (char) 88); + } + } + + @Entity(version=1) + static class DisallowSecKeyField_short2int + extends EvolveCase { + + private static final String NAME = + DisallowSecKeyField_short2int.class.getName(); + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + int ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DisallowSecKeyField_short2int version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowSecKeyField_short2int version: 1 Error: Old field type: short is not compatible with the new type: int for field: ff"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, "ff"); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", (short) 88); + } + } + + @Entity(version=1) + static class DisallowSecKeyField_int2long + extends EvolveCase { + + private static final String NAME = + DisallowSecKeyField_int2long.class.getName(); + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + long ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DisallowSecKeyField_int2long version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowSecKeyField_int2long version: 1 Error: Old field type: int is not compatible with the new type: long for field: ff"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, "ff"); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", 88); + } + } + + @Entity(version=1) + static class DisallowSecKeyField_long2float + extends EvolveCase { + + private static final String NAME = + DisallowSecKeyField_long2float.class.getName(); + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + float ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DisallowSecKeyField_long2float version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowSecKeyField_long2float version: 1 Error: Old field type: long is not compatible with the new type: float for field: ff"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, "ff"); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", (long) 88); + } + } + + @Entity(version=1) + static class DisallowSecKeyField_float2double + extends EvolveCase { + + private static final String NAME = + DisallowSecKeyField_float2double.class.getName(); + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + double ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DisallowSecKeyField_float2double version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowSecKeyField_float2double version: 1 Error: Old field type: float is not compatible with the new type: double for field: ff"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, "ff"); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", (float) 88); + } + } + + @Entity(version=1) + static class DisallowSecKeyField_Byte2short2 + extends EvolveCase { + + private static final String NAME = + DisallowSecKeyField_Byte2short2.class.getName(); + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + short ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DisallowSecKeyField_Byte2short2 version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowSecKeyField_Byte2short2 version: 1 Error: Old field type: java.lang.Byte is not compatible with the new type: short for field: ff"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, "ff"); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", (byte) 88); + } + } + + @Entity(version=1) + static class DisallowSecKeyField_Character2int + extends EvolveCase { + + private static final String NAME = + DisallowSecKeyField_Character2int.class.getName(); + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + int ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DisallowSecKeyField_Character2int version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowSecKeyField_Character2int version: 1 Error: Old field type: java.lang.Character is not compatible with the new type: int for field: ff"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, "ff"); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", (char) 88); + } + } + + @Entity(version=1) + static class DisallowSecKeyField_Short2int2 + extends EvolveCase { + + private static final String NAME = + DisallowSecKeyField_Short2int2.class.getName(); + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + int ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DisallowSecKeyField_Short2int2 version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowSecKeyField_Short2int2 version: 1 Error: Old field type: java.lang.Short is not compatible with the new type: int for field: ff"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, "ff"); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", (short) 88); + } + } + + @Entity(version=1) + static class DisallowSecKeyField_Integer2long + extends EvolveCase { + + private static final String NAME = + DisallowSecKeyField_Integer2long.class.getName(); + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + long ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DisallowSecKeyField_Integer2long version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowSecKeyField_Integer2long version: 1 Error: Old field type: java.lang.Integer is not compatible with the new type: long for field: ff"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, "ff"); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", 88); + } + } + + @Entity(version=1) + static class DisallowSecKeyField_Long2float2 + extends EvolveCase { + + private static final String NAME = + DisallowSecKeyField_Long2float2.class.getName(); + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + float ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DisallowSecKeyField_Long2float2 version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowSecKeyField_Long2float2 version: 1 Error: Old field type: java.lang.Long is not compatible with the new type: float for field: ff"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, "ff"); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", (long) 88); + } + } + + @Entity(version=1) + static class DisallowSecKeyField_Float2double2 + extends EvolveCase { + + private static final String NAME = + DisallowSecKeyField_Float2double2.class.getName(); + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + double ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DisallowSecKeyField_Float2double2 version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowSecKeyField_Float2double2 version: 1 Error: Old field type: java.lang.Float is not compatible with the new type: double for field: ff"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, "ff"); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", (float) 88); + } + } + + @Entity(version=1) + static class DisallowSecKeyField_int2BigInt + extends EvolveCase { + + private static final String NAME = + DisallowSecKeyField_int2BigInt.class.getName(); + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + BigInteger ff; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: com.sleepycat.persist.test.EvolveClasses$DisallowSecKeyField_int2BigInt version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowSecKeyField_int2BigInt version: 1 Error: Old field type: int is not compatible with the new type: java.math.BigInteger for field: ff"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, "ff"); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "ff", 88); + } + } + + // --- + + @Entity(version=1) + static class DisallowPriKeyField_byte2short + extends EvolveCase { + + private static final String NAME = + DisallowPriKeyField_byte2short.class.getName(); + + @PrimaryKey + short key; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Type may not be changed for a primary key field or composite key class field when evolving class: com.sleepycat.persist.test.EvolveClasses$DisallowPriKeyField_byte2short version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowPriKeyField_byte2short version: 1 Error: Old field type: byte is not compatible with the new type: short for field: key"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, (byte) 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", (byte) 99); + } + } + + @Entity(version=1) + static class DisallowPriKeyField_char2int + extends EvolveCase { + + private static final String NAME = + DisallowPriKeyField_char2int.class.getName(); + + @PrimaryKey + int key; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Type may not be changed for a primary key field or composite key class field when evolving class: com.sleepycat.persist.test.EvolveClasses$DisallowPriKeyField_char2int version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowPriKeyField_char2int version: 1 Error: Old field type: char is not compatible with the new type: int for field: key"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, (char) 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", (char) 99); + } + } + + @Entity(version=1) + static class DisallowPriKeyField_short2int + extends EvolveCase { + + private static final String NAME = + DisallowPriKeyField_short2int.class.getName(); + + @PrimaryKey + int key; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Type may not be changed for a primary key field or composite key class field when evolving class: com.sleepycat.persist.test.EvolveClasses$DisallowPriKeyField_short2int version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowPriKeyField_short2int version: 1 Error: Old field type: short is not compatible with the new type: int for field: key"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, (short) 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", (short) 99); + } + } + + @Entity(version=1) + static class DisallowPriKeyField_int2long + extends EvolveCase { + + private static final String NAME = + DisallowPriKeyField_int2long.class.getName(); + + @PrimaryKey + long key; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Type may not be changed for a primary key field or composite key class field when evolving class: com.sleepycat.persist.test.EvolveClasses$DisallowPriKeyField_int2long version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowPriKeyField_int2long version: 1 Error: Old field type: int is not compatible with the new type: long for field: key"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99); + } + } + + @Entity(version=1) + static class DisallowPriKeyField_long2float + extends EvolveCase { + + private static final String NAME = + DisallowPriKeyField_long2float.class.getName(); + + @PrimaryKey + float key; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Type may not be changed for a primary key field or composite key class field when evolving class: com.sleepycat.persist.test.EvolveClasses$DisallowPriKeyField_long2float version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowPriKeyField_long2float version: 1 Error: Old field type: long is not compatible with the new type: float for field: key"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, (long) 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", (long) 99); + } + } + + @Entity(version=1) + static class DisallowPriKeyField_float2double + extends EvolveCase { + + private static final String NAME = + DisallowPriKeyField_float2double.class.getName(); + + @PrimaryKey + double key; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Type may not be changed for a primary key field or composite key class field when evolving class: com.sleepycat.persist.test.EvolveClasses$DisallowPriKeyField_float2double version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowPriKeyField_float2double version: 1 Error: Old field type: float is not compatible with the new type: double for field: key"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, (float) 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", (float) 99); + } + } + + @Entity(version=1) + static class DisallowPriKeyField_Byte2short2 + extends EvolveCase { + + private static final String NAME = + DisallowPriKeyField_Byte2short2.class.getName(); + + @PrimaryKey + short key; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Type may not be changed for a primary key field or composite key class field when evolving class: com.sleepycat.persist.test.EvolveClasses$DisallowPriKeyField_Byte2short2 version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowPriKeyField_Byte2short2 version: 1 Error: Old field type: java.lang.Byte is not compatible with the new type: short for field: key"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, (byte) 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", (byte) 99); + } + } + + @Entity(version=1) + static class DisallowPriKeyField_Character2int + extends EvolveCase { + + private static final String NAME = + DisallowPriKeyField_Character2int.class.getName(); + + @PrimaryKey + int key; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Type may not be changed for a primary key field or composite key class field when evolving class: com.sleepycat.persist.test.EvolveClasses$DisallowPriKeyField_Character2int version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowPriKeyField_Character2int version: 1 Error: Old field type: java.lang.Character is not compatible with the new type: int for field: key"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, (char) 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", (char) 99); + } + } + + @Entity(version=1) + static class DisallowPriKeyField_Short2int2 + extends EvolveCase { + + private static final String NAME = + DisallowPriKeyField_Short2int2.class.getName(); + + @PrimaryKey + int key; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Type may not be changed for a primary key field or composite key class field when evolving class: com.sleepycat.persist.test.EvolveClasses$DisallowPriKeyField_Short2int2 version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowPriKeyField_Short2int2 version: 1 Error: Old field type: java.lang.Short is not compatible with the new type: int for field: key"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, (short) 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", (short) 99); + } + } + + @Entity(version=1) + static class DisallowPriKeyField_Integer2long + extends EvolveCase { + + private static final String NAME = + DisallowPriKeyField_Integer2long.class.getName(); + + @PrimaryKey + long key; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Type may not be changed for a primary key field or composite key class field when evolving class: com.sleepycat.persist.test.EvolveClasses$DisallowPriKeyField_Integer2long version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowPriKeyField_Integer2long version: 1 Error: Old field type: java.lang.Integer is not compatible with the new type: long for field: key"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99); + } + } + + @Entity(version=1) + static class DisallowPriKeyField_Long2float2 + extends EvolveCase { + + private static final String NAME = + DisallowPriKeyField_Long2float2.class.getName(); + + @PrimaryKey + float key; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Type may not be changed for a primary key field or composite key class field when evolving class: com.sleepycat.persist.test.EvolveClasses$DisallowPriKeyField_Long2float2 version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowPriKeyField_Long2float2 version: 1 Error: Old field type: java.lang.Long is not compatible with the new type: float for field: key"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, (long) 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", (long) 99); + } + } + + @Entity(version=1) + static class DisallowPriKeyField_Float2double2 + extends EvolveCase { + + private static final String NAME = + DisallowPriKeyField_Float2double2.class.getName(); + + @PrimaryKey + double key; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Type may not be changed for a primary key field or composite key class field when evolving class: com.sleepycat.persist.test.EvolveClasses$DisallowPriKeyField_Float2double2 version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowPriKeyField_Float2double2 version: 1 Error: Old field type: java.lang.Float is not compatible with the new type: double for field: key"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, (float) 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", (float) 99); + } + } + + @Entity(version=1) + static class DisallowPriKeyField_Long2BigInt + extends EvolveCase { + + private static final String NAME = + DisallowPriKeyField_Long2BigInt.class.getName(); + + @PrimaryKey + BigInteger key; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Type may not be changed for a primary key field or composite key class field when evolving class: com.sleepycat.persist.test.EvolveClasses$DisallowPriKeyField_Long2BigInt version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowPriKeyField_Long2BigInt version: 1 Error: Old field type: java.lang.Long is not compatible with the new type: java.math.BigInteger for field: key"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawObject obj = readRaw(store, 99L, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99L); + } + } + + @Persistent(version=1) + static class DisallowCompositeKeyField_byte2short_Key { + + @KeyField(1) + int f1 = 1; + + @KeyField(2) + short f2 = 2; + + @KeyField(3) + String f3 = "3"; + } + + @Entity + static class DisallowCompositeKeyField_byte2short + extends EvolveCase { + + private static final String NAME = + DisallowCompositeKeyField_byte2short.class.getName(); + private static final String NAME2 = + DisallowCompositeKeyField_byte2short_Key.class.getName(); + + @PrimaryKey + DisallowCompositeKeyField_byte2short_Key key; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Type may not be changed for a primary key field or composite key class field when evolving class: com.sleepycat.persist.test.EvolveClasses$DisallowCompositeKeyField_byte2short_Key version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowCompositeKeyField_byte2short_Key version: 1 Error: Old field type: byte is not compatible with the new type: short for field: f2"; + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + checkEntity(true, model, env, NAME, 0, null); + checkNonEntity(true, model, env, NAME2, 0); + checkVersions(model, NAME, 0); + checkVersions(model, NAME2, 0); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + if (expectEvolved) { + TestCase.fail(); + } + RawType rawKeyType = store.getModel().getRawType(NAME2); + RawObject rawKey = new RawObject + (rawKeyType, + makeValues("f1", 1, "f2", (byte) 2, "f3", "3"), + null); + + RawObject obj = readRaw(store, rawKey, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", rawKey); + } + } + + @Entity(version=1) + static class AllowPriKeyField_byte2Byte + extends EvolveCase { + + private static final String NAME = + AllowPriKeyField_byte2Byte.class.getName(); + + @PrimaryKey + Byte key = 99; + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkEntity(true, model, env, NAME, 1, null); + if (oldTypesExist) { + checkVersions(model, NAME, 1, NAME, 0); + } else { + checkVersions(model, NAME, 1); + } + } + + @Override + void readObjects(EntityStore store, boolean doUpdate) + throws DatabaseException { + + PrimaryIndex<Byte,AllowPriKeyField_byte2Byte> + index = store.getPrimaryIndex + (Byte.class, + AllowPriKeyField_byte2Byte.class); + AllowPriKeyField_byte2Byte obj = index.get(key); + TestCase.assertNotNull(obj); + TestCase.assertEquals(Byte.valueOf((byte) 99), obj.key); + + if (doUpdate) { + index.put(obj); + } + } + + @Override + void copyRawObjects(RawStore rawStore, EntityStore newStore) + throws DatabaseException { + + PrimaryIndex<Byte,AllowPriKeyField_byte2Byte> + index = newStore.getPrimaryIndex + (Byte.class, + AllowPriKeyField_byte2Byte.class); + RawObject raw = rawStore.getPrimaryIndex(NAME).get((byte) 99); + index.put((AllowPriKeyField_byte2Byte) + newStore.getModel().convertRawObject(raw)); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + RawObject obj; + if (expectEvolved) { + obj = readRaw(store, (byte) 99, NAME, 1, CASECLS, 0); + } else { + obj = readRaw(store, (byte) 99, NAME, 0, CASECLS, 0); + } + checkRawFields(obj, "key", (byte) 99); + } + } + + @Entity(version=1) + static class AllowPriKeyField_Byte2byte2 + extends EvolveCase { + + private static final String NAME = + AllowPriKeyField_Byte2byte2.class.getName(); + + @PrimaryKey + byte key = 99; + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkEntity(true, model, env, NAME, 1, null); + if (oldTypesExist) { + checkVersions(model, NAME, 1, NAME, 0); + } else { + checkVersions(model, NAME, 1); + } + } + + @Override + void readObjects(EntityStore store, boolean doUpdate) + throws DatabaseException { + + PrimaryIndex<Byte,AllowPriKeyField_Byte2byte2> + index = store.getPrimaryIndex + (Byte.class, + AllowPriKeyField_Byte2byte2.class); + AllowPriKeyField_Byte2byte2 obj = index.get(key); + TestCase.assertNotNull(obj); + TestCase.assertEquals((byte) 99, obj.key); + + if (doUpdate) { + index.put(obj); + } + } + + @Override + void copyRawObjects(RawStore rawStore, EntityStore newStore) + throws DatabaseException { + + PrimaryIndex<Byte,AllowPriKeyField_Byte2byte2> + index = newStore.getPrimaryIndex + (Byte.class, + AllowPriKeyField_Byte2byte2.class); + RawObject raw = rawStore.getPrimaryIndex(NAME).get((byte) 99); + index.put((AllowPriKeyField_Byte2byte2) + newStore.getModel().convertRawObject(raw)); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + RawObject obj; + if (expectEvolved) { + obj = readRaw(store, (byte) 99, NAME, 1, CASECLS, 0); + } else { + obj = readRaw(store, (byte) 99, NAME, 0, CASECLS, 0); + } + checkRawFields(obj, "key", (byte) 99); + } + } + + @Persistent(version=1) + static class AllowFieldTypeChanges_Key { + + AllowFieldTypeChanges_Key() { + this(false); + } + + AllowFieldTypeChanges_Key(boolean init) { + if (init) { + f1 = true; + f2 = (byte) 2; + f3 = (short) 3; + f4 = 4; + f5 = 5L; + f6 = 6F; + f7 = 7D; + f8 = (char) 8; + f9 = true; + f10 = (byte) 10; + f11 = (short) 11; + f12 = 12; + f13 = 13L; + f14 = 14F; + f15 = 15D; + f16 = (char) 16; + } + } + + @KeyField(1) + boolean f1; + + @KeyField(2) + byte f2; + + @KeyField(3) + short f3; + + @KeyField(4) + int f4; + + @KeyField(5) + long f5; + + @KeyField(6) + float f6; + + @KeyField(7) + double f7; + + @KeyField(8) + char f8; + + @KeyField(9) + Boolean f9; + + @KeyField(10) + Byte f10; + + @KeyField(11) + Short f11; + + @KeyField(12) + Integer f12; + + @KeyField(13) + Long f13; + + @KeyField(14) + Float f14; + + @KeyField(15) + Double f15; + + @KeyField(16) + Character f16; + } + + @Persistent(version=1) + static class AllowFieldTypeChanges_Base + extends EvolveCase { + + @SecondaryKey(relate=ONE_TO_ONE) + AllowFieldTypeChanges_Key kComposite; + + Integer f_long2Integer; + Long f_String2Long; + } + + /** + * Allow field type changes: automatic widening, supported widening, + * and Converter mutations. Also tests primary and secondary key field + * renaming. + */ + @Entity(version=1) + static class AllowFieldTypeChanges + extends AllowFieldTypeChanges_Base { + + private static final String NAME = + AllowFieldTypeChanges.class.getName(); + private static final String NAME2 = + AllowFieldTypeChanges_Base.class.getName(); + private static final String NAME3 = + AllowFieldTypeChanges_Key.class.getName(); + + @PrimaryKey + Integer pkeyInteger; + + @SecondaryKey(relate=ONE_TO_ONE) + Boolean kBoolean; + + @SecondaryKey(relate=ONE_TO_ONE) + Byte kByte; + + @SecondaryKey(relate=ONE_TO_ONE) + Short kShort; + + @SecondaryKey(relate=ONE_TO_ONE) + Integer kInteger; + + @SecondaryKey(relate=ONE_TO_ONE) + Long kLong; + + @SecondaryKey(relate=ONE_TO_ONE) + Float kFloat; + + @SecondaryKey(relate=ONE_TO_ONE) + Double kDouble; + + @SecondaryKey(relate=ONE_TO_ONE) + Character kCharacter; + + short f01; + int f02; + long f03; + float f04; + double f06; + int f07; + long f08; + float f09; + double f10; + int f11; + long f12; + float f13; + double f14; + long f15; + float f16; + double f17; + float f18; + double f19; + double f20; + + Short f21; + Integer f22; + Long f23; + Float f24; + Double f26; + Integer f27; + Long f28; + Float f29; + Double f30; + Integer f31; + Long f32; + Float f33; + Double f34; + Long f35; + Float f36; + Double f37; + Float f38; + Double f39; + Double f40; + + Short f41; + Integer f42; + Long f43; + Float f44; + Double f46; + Integer f47; + Long f48; + Float f49; + Double f50; + Integer f51; + Long f52; + Float f53; + Double f54; + Long f55; + Float f56; + Double f57; + Float f58; + Double f59; + Double f60; + + BigInteger f70; + BigInteger f71; + BigInteger f72; + BigInteger f73; + BigInteger f74; + BigInteger f75; + BigInteger f76; + BigInteger f77; + BigInteger f78; + BigInteger f79; + + int f_long2int; + long f_String2long; + + @Override + Mutations getMutations() { + Mutations m = new Mutations(); + m.addRenamer(new Renamer(NAME, 0, "pkeyint", "pkeyInteger")); + m.addRenamer(new Renamer(NAME, 0, "kboolean", "kBoolean")); + m.addRenamer(new Renamer(NAME, 0, "kbyte", "kByte")); + m.addRenamer(new Renamer(NAME, 0, "kshort", "kShort")); + m.addRenamer(new Renamer(NAME, 0, "kint", "kInteger")); + m.addRenamer(new Renamer(NAME, 0, "klong", "kLong")); + m.addRenamer(new Renamer(NAME, 0, "kfloat", "kFloat")); + m.addRenamer(new Renamer(NAME, 0, "kdouble", "kDouble")); + m.addRenamer(new Renamer(NAME, 0, "kchar", "kCharacter")); + m.addRenamer(new Renamer(NAME2, 0, "kcomposite", "kComposite")); + + Conversion conv1 = new MyConversion1(); + Conversion conv2 = new MyConversion2(); + + m.addConverter(new Converter(NAME, 0, "f_long2int", conv1)); + m.addConverter(new Converter(NAME, 0, "f_String2long", conv2)); + m.addConverter(new Converter(NAME2, 0, "f_long2Integer", conv1)); + m.addConverter(new Converter(NAME2, 0, "f_String2Long", conv2)); + return m; + } + + @SuppressWarnings("serial") + static class MyConversion1 implements Conversion { + + public void initialize(EntityModel model) {} + + public Object convert(Object o) { + return ((Long) o).intValue(); + } + + @Override + public boolean equals(Object other) { return true; } + } + + @SuppressWarnings("serial") + static class MyConversion2 implements Conversion { + + public void initialize(EntityModel model) {} + + public Object convert(Object o) { + return Long.valueOf((String) o); + } + + @Override + public boolean equals(Object other) { return true; } + } + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkEntity(true, model, env, NAME, 1, null); + checkNonEntity(true, model, env, NAME2, 1); + if (oldTypesExist) { + checkVersions(model, NAME, 1, NAME, 0); + checkVersions(model, NAME2, 1, NAME2, 0); + checkVersions(model, NAME3, 1, NAME3, 0); + } else { + checkVersions(model, NAME, 1); + checkVersions(model, NAME2, 1); + checkVersions(model, NAME3, 1); + } + } + + @Override + void readObjects(EntityStore store, boolean doUpdate) + throws DatabaseException { + + PrimaryIndex<Integer,AllowFieldTypeChanges> + index = store.getPrimaryIndex + (Integer.class, AllowFieldTypeChanges.class); + AllowFieldTypeChanges obj = index.get(99); + checkValues(obj); + checkSecondaries(store, index); + + if (doUpdate) { + index.put(obj); + checkSecondaries(store, index); + } + } + + @Override + void copyRawObjects(RawStore rawStore, EntityStore newStore) + throws DatabaseException { + + PrimaryIndex<Integer,AllowFieldTypeChanges> + index = newStore.getPrimaryIndex + (Integer.class, AllowFieldTypeChanges.class); + RawObject raw = rawStore.getPrimaryIndex(NAME).get(99); + index.put((AllowFieldTypeChanges) + newStore.getModel().convertRawObject(raw)); + } + + private void checkSecondaries(EntityStore store, + PrimaryIndex<Integer, + AllowFieldTypeChanges> + index) + throws DatabaseException { + + checkValues(store.getSecondaryIndex + (index, Boolean.class, "kBoolean").get(true)); + checkValues(store.getSecondaryIndex + (index, Byte.class, "kByte").get((byte) 77)); + checkValues(store.getSecondaryIndex + (index, Short.class, "kShort").get((short) 66)); + checkValues(store.getSecondaryIndex + (index, Integer.class, "kInteger").get(55)); + checkValues(store.getSecondaryIndex + (index, Long.class, "kLong").get((long) 44)); + checkValues(store.getSecondaryIndex + (index, Float.class, "kFloat").get((float) 33)); + checkValues(store.getSecondaryIndex + (index, Double.class, "kDouble").get((double) 22)); + checkValues(store.getSecondaryIndex + (index, Character.class, "kCharacter").get((char) 11)); + checkValues(store.getSecondaryIndex + (index, AllowFieldTypeChanges_Key.class, "kComposite").get + (new AllowFieldTypeChanges_Key(true))); + } + + private void checkValues(AllowFieldTypeChanges obj) { + TestCase.assertNotNull(obj); + TestCase.assertEquals(obj.pkeyInteger, Integer.valueOf(99)); + TestCase.assertEquals(obj.kBoolean, Boolean.valueOf(true)); + TestCase.assertEquals(obj.kByte, Byte.valueOf((byte) 77)); + TestCase.assertEquals(obj.kShort, Short.valueOf((short) 66)); + TestCase.assertEquals(obj.kInteger, Integer.valueOf(55)); + TestCase.assertEquals(obj.kLong, Long.valueOf(44)); + TestCase.assertEquals(obj.kFloat, Float.valueOf(33)); + TestCase.assertEquals(obj.kDouble, Double.valueOf(22)); + TestCase.assertEquals(obj.kCharacter, Character.valueOf((char) 11)); + + AllowFieldTypeChanges_Key embed = obj.kComposite; + TestCase.assertNotNull(embed); + TestCase.assertEquals(embed.f1, true); + TestCase.assertEquals(embed.f2, (byte) 2); + TestCase.assertEquals(embed.f3, (short) 3); + TestCase.assertEquals(embed.f4, 4); + TestCase.assertEquals(embed.f5, 5L); + TestCase.assertEquals(embed.f6, 6F); + TestCase.assertEquals(embed.f7, 7D); + TestCase.assertEquals(embed.f8, (char) 8); + TestCase.assertEquals(embed.f9, Boolean.valueOf(true)); + TestCase.assertEquals(embed.f10, Byte.valueOf((byte) 10)); + TestCase.assertEquals(embed.f11, Short.valueOf((short) 11)); + TestCase.assertEquals(embed.f12, Integer.valueOf(12)); + TestCase.assertEquals(embed.f13, Long.valueOf(13L)); + TestCase.assertEquals(embed.f14, Float.valueOf(14F)); + TestCase.assertEquals(embed.f15, Double.valueOf(15D)); + TestCase.assertEquals(embed.f16, Character.valueOf((char) 16)); + + TestCase.assertEquals(obj.f01, (short) 1); + TestCase.assertEquals(obj.f02, 2); + TestCase.assertEquals(obj.f03, 3); + TestCase.assertEquals(obj.f04, (float) 4); + TestCase.assertEquals(obj.f06, (double) 6); + TestCase.assertEquals(obj.f07, 7); + TestCase.assertEquals(obj.f08, 8); + TestCase.assertEquals(obj.f09, (float) 9); + TestCase.assertEquals(obj.f10, (double) 10); + TestCase.assertEquals(obj.f11, 11); + TestCase.assertEquals(obj.f12, 12); + TestCase.assertEquals(obj.f13, (float) 13); + TestCase.assertEquals(obj.f14, (double) 14); + TestCase.assertEquals(obj.f15, 15L); + TestCase.assertEquals(obj.f16, 16F); + TestCase.assertEquals(obj.f17, 17D); + TestCase.assertEquals(obj.f18, (float) 18); + TestCase.assertEquals(obj.f19, (double) 19); + TestCase.assertEquals(obj.f20, (double) 20); + + TestCase.assertEquals(obj.f21, Short.valueOf((byte) 21)); + TestCase.assertEquals(obj.f22, Integer.valueOf((byte) 22)); + TestCase.assertEquals(obj.f23, Long.valueOf((byte) 23)); + TestCase.assertEquals(obj.f24, Float.valueOf((byte) 24)); + TestCase.assertEquals(obj.f26, Double.valueOf((byte) 26)); + TestCase.assertEquals(obj.f27, Integer.valueOf((short) 27)); + TestCase.assertEquals(obj.f28, Long.valueOf((short) 28)); + TestCase.assertEquals(obj.f29, Float.valueOf((short) 29)); + TestCase.assertEquals(obj.f30, Double.valueOf((short) 30)); + TestCase.assertEquals(obj.f31, Integer.valueOf((char) 31)); + TestCase.assertEquals(obj.f32, Long.valueOf((char) 32)); + TestCase.assertEquals(obj.f33, Float.valueOf((char) 33)); + TestCase.assertEquals(obj.f34, Double.valueOf((char) 34)); + TestCase.assertEquals(obj.f35, Long.valueOf(35)); + TestCase.assertEquals(obj.f36, Float.valueOf(36)); + TestCase.assertEquals(obj.f37, Double.valueOf(37)); + TestCase.assertEquals(obj.f38, Float.valueOf(38)); + TestCase.assertEquals(obj.f39, Double.valueOf(39)); + TestCase.assertEquals(obj.f40, Double.valueOf(40)); + + TestCase.assertEquals(obj.f41, Short.valueOf((byte) 41)); + TestCase.assertEquals(obj.f42, Integer.valueOf((byte) 42)); + TestCase.assertEquals(obj.f43, Long.valueOf((byte) 43)); + TestCase.assertEquals(obj.f44, Float.valueOf((byte) 44)); + TestCase.assertEquals(obj.f46, Double.valueOf((byte) 46)); + TestCase.assertEquals(obj.f47, Integer.valueOf((short) 47)); + TestCase.assertEquals(obj.f48, Long.valueOf((short) 48)); + TestCase.assertEquals(obj.f49, Float.valueOf((short) 49)); + TestCase.assertEquals(obj.f50, Double.valueOf((short) 50)); + TestCase.assertEquals(obj.f51, Integer.valueOf((char) 51)); + TestCase.assertEquals(obj.f52, Long.valueOf((char) 52)); + TestCase.assertEquals(obj.f53, Float.valueOf((char) 53)); + TestCase.assertEquals(obj.f54, Double.valueOf((char) 54)); + TestCase.assertEquals(obj.f55, Long.valueOf(55)); + TestCase.assertEquals(obj.f56, Float.valueOf(56)); + TestCase.assertEquals(obj.f57, Double.valueOf(57)); + TestCase.assertEquals(obj.f58, Float.valueOf(58)); + TestCase.assertEquals(obj.f59, Double.valueOf(59)); + TestCase.assertEquals(obj.f60, Double.valueOf(60)); + + TestCase.assertEquals(obj.f70, BigInteger.valueOf(70)); + TestCase.assertEquals(obj.f71, BigInteger.valueOf(71)); + TestCase.assertEquals(obj.f72, BigInteger.valueOf(72)); + TestCase.assertEquals(obj.f73, BigInteger.valueOf(73)); + TestCase.assertEquals(obj.f74, BigInteger.valueOf(74)); + TestCase.assertEquals(obj.f75, BigInteger.valueOf(75)); + TestCase.assertEquals(obj.f76, BigInteger.valueOf(76)); + TestCase.assertEquals(obj.f77, BigInteger.valueOf(77)); + TestCase.assertEquals(obj.f78, BigInteger.valueOf(78)); + TestCase.assertEquals(obj.f79, BigInteger.valueOf(79)); + + TestCase.assertEquals(obj.f_long2Integer, Integer.valueOf(111)); + TestCase.assertEquals(obj.f_String2Long, Long.valueOf(222)); + TestCase.assertEquals(obj.f_long2int, 333); + TestCase.assertEquals(obj.f_String2long, 444L); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + RawType embedType = store.getModel().getRawType(NAME3); + RawObject embed = new RawObject + (embedType, + makeValues + ("f1", true, + "f2", (byte) 2, + "f3", (short) 3, + "f4", 4, + "f5", 5L, + "f6", 6F, + "f7", 7D, + "f8", (char) 8, + "f9", true, + "f10", (byte) 10, + "f11", (short) 11, + "f12", 12, + "f13", 13L, + "f14", 14F, + "f15", 15D, + "f16", (char) 16), + null); + + RawObject obj; + if (expectEvolved) { + obj = readRaw(store, 99, NAME, 1, NAME2, 1, CASECLS, 0); + checkRawFields(obj, "pkeyInteger", 99, + "kBoolean", true, + "kByte", (byte) 77, + "kShort", (short) 66, + "kInteger", 55, + "kLong", (long) 44, + "kFloat", (float) 33, + "kDouble", (double) 22, + "kCharacter", (char) 11, + + "f01", (short) 1, + "f02", 2, + "f03", (long) 3, + "f04", (float) 4, + "f06", (double) 6, + "f07", 7, + "f08", (long) 8, + "f09", (float) 9, + "f10", (double) 10, + "f11", 11, + "f12", (long) 12, + "f13", (float) 13, + "f14", (double) 14, + "f15", 15L, + "f16", 16F, + "f17", 17D, + "f18", (float) 18, + "f19", (double) 19, + "f20", (double) 20, + + "f21", (short) 21, + "f22", 22, + "f23", (long) 23, + "f24", (float) 24, + "f26", (double) 26, + "f27", 27, + "f28", (long) 28, + "f29", (float) 29, + "f30", (double) 30, + "f31", 31, + "f32", (long) 32, + "f33", (float) 33, + "f34", (double) 34, + "f35", 35L, + "f36", 36F, + "f37", 37D, + "f38", (float) 38, + "f39", (double) 39, + "f40", (double) 40, + + "f41", (short) 41, + "f42", 42, + "f43", (long) 43, + "f44", (float) 44, + "f46", (double) 46, + "f47", 47, + "f48", (long) 48, + "f49", (float) 49, + "f50", (double) 50, + "f51", 51, + "f52", (long) 52, + "f53", (float) 53, + "f54", (double) 54, + "f55", 55L, + "f56", 56F, + "f57", 57D, + "f58", (float) 58, + "f59", (double) 59, + "f60", (double) 60, + + "f70", BigInteger.valueOf(70), + "f71", BigInteger.valueOf(71), + "f72", BigInteger.valueOf(72), + "f73", BigInteger.valueOf(73), + "f74", BigInteger.valueOf(74), + "f75", BigInteger.valueOf(75), + "f76", BigInteger.valueOf(76), + "f77", BigInteger.valueOf(77), + "f78", BigInteger.valueOf(78), + "f79", BigInteger.valueOf(79), + + "f_long2int", 333, + "f_String2long", 444L); + checkRawFields(obj.getSuper(), + "kComposite", embed, + "f_long2Integer", 111, + "f_String2Long", 222L); + } else { + obj = readRaw(store, 99, NAME, 0, NAME2, 0, CASECLS, 0); + checkRawFields(obj, "pkeyint", 99, + "kboolean", true, + "kbyte", (byte) 77, + "kshort", (short) 66, + "kint", 55, + "klong", (long) 44, + "kfloat", (float) 33, + "kdouble", (double) 22, + "kchar", (char) 11, + + "f01", (byte) 1, + "f02", (byte) 2, + "f03", (byte) 3, + "f04", (byte) 4, + "f06", (byte) 6, + "f07", (short) 7, + "f08", (short) 8, + "f09", (short) 9, + "f10", (short) 10, + "f11", (char) 11, + "f12", (char) 12, + "f13", (char) 13, + "f14", (char) 14, + "f15", 15, + "f16", 16, + "f17", 17, + "f18", (long) 18, + "f19", (long) 19, + "f20", (float) 20, + + "f21", (byte) 21, + "f22", (byte) 22, + "f23", (byte) 23, + "f24", (byte) 24, + "f26", (byte) 26, + "f27", (short) 27, + "f28", (short) 28, + "f29", (short) 29, + "f30", (short) 30, + "f31", (char) 31, + "f32", (char) 32, + "f33", (char) 33, + "f34", (char) 34, + "f35", 35, + "f36", 36, + "f37", 37, + "f38", (long) 38, + "f39", (long) 39, + "f40", (float) 40, + + "f41", (byte) 41, + "f42", (byte) 42, + "f43", (byte) 43, + "f44", (byte) 44, + "f46", (byte) 46, + "f47", (short) 47, + "f48", (short) 48, + "f49", (short) 49, + "f50", (short) 50, + "f51", (char) 51, + "f52", (char) 52, + "f53", (char) 53, + "f54", (char) 54, + "f55", 55, + "f56", 56, + "f57", 57, + "f58", (long) 58, + "f59", (long) 59, + "f60", (float) 60, + + "f70", (byte) 70, + "f71", (short) 71, + "f72", (char) 72, + "f73", 73, + "f74", (long) 74, + "f75", (byte) 75, + "f76", (short) 76, + "f77", (char) 77, + "f78", 78, + "f79", (long) 79, + + "f_long2int", 333L, + "f_String2long", "444"); + + checkRawFields(obj.getSuper(), + "kcomposite", embed, + "f_long2Integer", 111L, + "f_String2Long", "222"); + } + Environment env = store.getEnvironment(); + + assertDbExists(expectEvolved, env, NAME, "kBoolean"); + assertDbExists(expectEvolved, env, NAME, "kByte"); + assertDbExists(expectEvolved, env, NAME, "kShort"); + assertDbExists(expectEvolved, env, NAME, "kInteger"); + assertDbExists(expectEvolved, env, NAME, "kLong"); + assertDbExists(expectEvolved, env, NAME, "kFloat"); + assertDbExists(expectEvolved, env, NAME, "kDouble"); + assertDbExists(expectEvolved, env, NAME, "kCharacter"); + assertDbExists(expectEvolved, env, NAME, "kComposite"); + + assertDbExists(!expectEvolved, env, NAME, "kboolean"); + assertDbExists(!expectEvolved, env, NAME, "kbyte"); + assertDbExists(!expectEvolved, env, NAME, "kshort"); + assertDbExists(!expectEvolved, env, NAME, "kint"); + assertDbExists(!expectEvolved, env, NAME, "klong"); + assertDbExists(!expectEvolved, env, NAME, "kfloat"); + assertDbExists(!expectEvolved, env, NAME, "kdouble"); + assertDbExists(!expectEvolved, env, NAME, "kchar"); + assertDbExists(!expectEvolved, env, NAME, "kcomposite"); + } + } + + @SuppressWarnings("serial") + static class ConvertFieldContent_Conversion implements Conversion { + + public void initialize(EntityModel model) { + } + + public Object convert(Object fromValue) { + String s1 = (String) fromValue; + return (new StringBuilder(s1)).reverse().toString(); + } + + @Override + public boolean equals(Object o) { + return o instanceof ConvertFieldContent_Conversion; + } + } + + @Entity(version=1) + static class ConvertFieldContent_Entity + extends EvolveCase { + + private static final String NAME = + ConvertFieldContent_Entity.class.getName(); + + @PrimaryKey + int key = 99; + + String f1; + String f2; + + @Override + Mutations getMutations() { + Mutations m = new Mutations(); + Converter converter = new Converter + (ConvertFieldContent_Entity.class.getName(), 0, + "f1", new ConvertFieldContent_Conversion()); + m.addConverter(converter); + converter = new Converter + (ConvertFieldContent_Entity.class.getName(), 0, + "f2", new ConvertFieldContent_Conversion()); + m.addConverter(converter); + return m; + } + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkEntity(true, model, env, NAME, 1, null); + if (oldTypesExist) { + checkVersions(model, NAME, 1, NAME, 0); + } else { + checkVersions(model, NAME, 1); + } + } + + @Override + void readObjects(EntityStore store, boolean doUpdate) + throws DatabaseException { + + PrimaryIndex<Integer,ConvertFieldContent_Entity> + index = store.getPrimaryIndex + (Integer.class, + ConvertFieldContent_Entity.class); + ConvertFieldContent_Entity obj = index.get(99); + TestCase.assertNotNull(obj); + TestCase.assertEquals(99, obj.key); + TestCase.assertEquals("43210", obj.f1); + TestCase.assertEquals("98765", obj.f2); + + if (doUpdate) { + index.put(obj); + } + } + + @Override + void copyRawObjects(RawStore rawStore, EntityStore newStore) + throws DatabaseException { + + PrimaryIndex<Integer,ConvertFieldContent_Entity> + index = newStore.getPrimaryIndex + (Integer.class, + ConvertFieldContent_Entity.class); + RawObject raw = rawStore.getPrimaryIndex(NAME).get(99); + index.put((ConvertFieldContent_Entity) + newStore.getModel().convertRawObject(raw)); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + RawObject obj = + readRaw(store, 99, NAME, expectEvolved ? 1 : 0, CASECLS, 0); + if (expectEvolved) { + checkRawFields(obj, "key", 99, + "f1", "43210", + "f2", "98765"); + } else { + checkRawFields(obj, "key", 99, + "f1", "01234", + "f2", "56789"); + } + } + } + + @Persistent(version=1) + static class ConvertExample1_Address { + String street; + String city; + String state; + int zipCode; + } + + @SuppressWarnings("serial") + static class ConvertExample1_Conversion implements Conversion { + + public void initialize(EntityModel model) { + } + + public Object convert(Object fromValue) { + return Integer.valueOf((String) fromValue); + } + + @Override + public boolean equals(Object o) { + return o instanceof ConvertExample1_Conversion; + } + } + + @Entity + static class ConvertExample1_Entity + extends EvolveCase { + + private static final String NAME = + ConvertExample1_Entity.class.getName(); + private static final String NAME2 = + ConvertExample1_Address.class.getName(); + + @PrimaryKey + int key = 99; + + ConvertExample1_Address embed; + + @Override + Mutations getMutations() { + Mutations m = new Mutations(); + Converter converter = new Converter + (ConvertExample1_Address.class.getName(), 0, + "zipCode", new ConvertExample1_Conversion()); + m.addConverter(converter); + return m; + } + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + if (oldTypesExist) { + checkVersions(model, NAME2, 1, NAME2, 0); + } else { + checkVersions(model, NAME2, 1); + } + } + + @Override + void readObjects(EntityStore store, boolean doUpdate) + throws DatabaseException { + + PrimaryIndex<Integer,ConvertExample1_Entity> + index = store.getPrimaryIndex + (Integer.class, + ConvertExample1_Entity.class); + ConvertExample1_Entity obj = index.get(99); + TestCase.assertNotNull(obj); + TestCase.assertEquals(99, obj.key); + TestCase.assertNotNull(obj.embed); + TestCase.assertEquals("street", obj.embed.street); + TestCase.assertEquals("city", obj.embed.city); + TestCase.assertEquals("state", obj.embed.state); + TestCase.assertEquals(12345, obj.embed.zipCode); + + if (doUpdate) { + index.put(obj); + } + } + + @Override + void copyRawObjects(RawStore rawStore, EntityStore newStore) + throws DatabaseException { + + PrimaryIndex<Integer,ConvertExample1_Entity> + index = newStore.getPrimaryIndex + (Integer.class, + ConvertExample1_Entity.class); + RawObject raw = rawStore.getPrimaryIndex(NAME).get(99); + index.put((ConvertExample1_Entity) + newStore.getModel().convertRawObject(raw)); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + RawType embedType = store.getModel().getRawType(NAME2); + RawObject embed; + if (expectEvolved) { + embed = new RawObject + (embedType, + makeValues("street", "street", + "city", "city", + "state", "state", + "zipCode", 12345), + null); + } else { + embed = new RawObject + (embedType, + makeValues("street", "street", + "city", "city", + "state", "state", + "zipCode", "12345"), + null); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "embed", embed); + } + } + + @Persistent + static class ConvertExample2_Address { + String street; + String city; + String state; + int zipCode; + } + + @Entity(version=1) + static class ConvertExample2_Person + extends EvolveCase { + + private static final String NAME = + ConvertExample2_Person.class.getName(); + private static final String NAME2 = + ConvertExample2_Address .class.getName(); + + @PrimaryKey + int key; + + ConvertExample2_Address address; + + @Override + Mutations getMutations() { + Mutations m = new Mutations(); + Converter converter = new Converter + (ConvertExample2_Person.class.getName(), 0, + "address", new ConvertExample2_Conversion()); + m.addConverter(converter); + return m; + } + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkEntity(true, model, env, NAME, 1, null); + if (oldTypesExist) { + checkVersions(model, NAME, 1, NAME, 0); + } else { + checkVersions(model, NAME, 1); + } + checkVersions(model, NAME2, 0); + } + + @Override + void readObjects(EntityStore store, boolean doUpdate) + throws DatabaseException { + + PrimaryIndex<Integer,ConvertExample2_Person> + index = store.getPrimaryIndex + (Integer.class, + ConvertExample2_Person.class); + ConvertExample2_Person obj = index.get(99); + TestCase.assertNotNull(obj); + TestCase.assertEquals(99, obj.key); + TestCase.assertNotNull(obj.address); + TestCase.assertEquals("street", obj.address.street); + TestCase.assertEquals("city", obj.address.city); + TestCase.assertEquals("state", obj.address.state); + TestCase.assertEquals(12345, obj.address.zipCode); + + if (doUpdate) { + index.put(obj); + } + } + + @Override + void copyRawObjects(RawStore rawStore, EntityStore newStore) + throws DatabaseException { + + PrimaryIndex<Integer,ConvertExample2_Person> + index = newStore.getPrimaryIndex + (Integer.class, + ConvertExample2_Person.class); + RawObject raw = rawStore.getPrimaryIndex(NAME).get(99); + index.put((ConvertExample2_Person) + newStore.getModel().convertRawObject(raw)); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + Object embed; + if (expectEvolved) { + RawType embedType = store.getModel().getRawType(NAME2); + embed = new RawObject + (embedType, + makeValues("street", "street", + "city", "city", + "state", "state", + "zipCode", 12345), + null); + } else { + embed = "street#city#state#12345"; + } + RawObject obj = readRaw + (store, 99, NAME, expectEvolved ? 1 : 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "address", embed); + } + } + + @SuppressWarnings("serial") + static class ConvertExample2_Conversion implements Conversion { + private transient RawType addressType; + + public void initialize(EntityModel model) { + addressType = model.getRawType + (ConvertExample2_Address.class.getName()); + } + + public Object convert(Object fromValue) { + + String oldAddress = (String) fromValue; + Map<String,Object> addressValues = new HashMap<String,Object>(); + addressValues.put("street", parseAddress(1, oldAddress)); + addressValues.put("city", parseAddress(2, oldAddress)); + addressValues.put("state", parseAddress(3, oldAddress)); + addressValues.put("zipCode", + Integer.valueOf(parseAddress(4, oldAddress))); + + return new RawObject(addressType, addressValues, null); + } + + @Override + public boolean equals(Object o) { + return o instanceof ConvertExample2_Conversion; + } + + private String parseAddress(int fieldNum, String oldAddress) { + StringTokenizer tokens = new StringTokenizer(oldAddress, "#"); + String field = null; + for (int i = 0; i < fieldNum; i += 1) { + field = tokens.nextToken(); + } + return field; + } + } + + @Persistent + static class ConvertExample3_Address { + String street; + String city; + String state; + int zipCode; + } + + @SuppressWarnings("serial") + static class ConvertExample3_Conversion implements Conversion { + private transient RawType newPersonType; + private transient RawType addressType; + + public void initialize(EntityModel model) { + newPersonType = model.getRawType + (ConvertExample3_Person.class.getName()); + addressType = model.getRawType + (ConvertExample3_Address.class.getName()); + } + + public Object convert(Object fromValue) { + + RawObject person = (RawObject) fromValue; + Map<String,Object> personValues = person.getValues(); + Map<String,Object> addressValues = new HashMap<String,Object>(); + RawObject address = new RawObject + (addressType, addressValues, null); + + addressValues.put("street", personValues.remove("street")); + addressValues.put("city", personValues.remove("city")); + addressValues.put("state", personValues.remove("state")); + addressValues.put("zipCode", personValues.remove("zipCode")); + personValues.put("address", address); + + return new RawObject + (newPersonType, personValues, person.getSuper()); + } + + @Override + public boolean equals(Object o) { + return o instanceof ConvertExample3_Conversion; + } + } + + @Entity(version=1) + static class ConvertExample3_Person + extends EvolveCase { + + private static final String NAME = + ConvertExample3_Person.class.getName(); + private static final String NAME2 = + ConvertExample3_Address .class.getName(); + + @PrimaryKey + int key; + + ConvertExample3_Address address; + + @Override + Mutations getMutations() { + Mutations m = new Mutations(); + Converter converter = new Converter + (ConvertExample3_Person.class.getName(), 0, + new ConvertExample3_Conversion()); + m.addConverter(converter); + return m; + } + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkEntity(true, model, env, NAME, 1, null); + if (oldTypesExist) { + checkVersions(model, NAME, 1, NAME, 0); + } else { + checkVersions(model, NAME, 1); + } + checkVersions(model, NAME2, 0); + } + + @Override + void readObjects(EntityStore store, boolean doUpdate) + throws DatabaseException { + + PrimaryIndex<Integer,ConvertExample3_Person> + index = store.getPrimaryIndex + (Integer.class, + ConvertExample3_Person.class); + ConvertExample3_Person obj = index.get(99); + TestCase.assertNotNull(obj); + TestCase.assertEquals(99, obj.key); + TestCase.assertNotNull(obj.address); + TestCase.assertEquals("street", obj.address.street); + TestCase.assertEquals("city", obj.address.city); + TestCase.assertEquals("state", obj.address.state); + TestCase.assertEquals(12345, obj.address.zipCode); + + if (doUpdate) { + index.put(obj); + } + } + + @Override + void copyRawObjects(RawStore rawStore, EntityStore newStore) + throws DatabaseException { + + PrimaryIndex<Integer,ConvertExample3_Person> + index = newStore.getPrimaryIndex + (Integer.class, + ConvertExample3_Person.class); + RawObject raw = rawStore.getPrimaryIndex(NAME).get(99); + index.put((ConvertExample3_Person) + newStore.getModel().convertRawObject(raw)); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + RawObject obj = readRaw + (store, 99, NAME, expectEvolved ? 1 : 0, CASECLS, 0); + if (expectEvolved) { + RawType embedType = store.getModel().getRawType(NAME2); + Object embed = new RawObject + (embedType, + makeValues("street", "street", + "city", "city", + "state", "state", + "zipCode", 12345), + null); + checkRawFields(obj, "key", 99, "address", embed); + } else { + checkRawFields(obj, "key", 99, + "street", "street", + "city", "city", + "state", "state", + "zipCode", 12345); + } + } + } + + @SuppressWarnings("serial") + static class ConvertExample3Reverse_Conversion implements Conversion { + private transient RawType newPersonType; + + public void initialize(EntityModel model) { + newPersonType = model.getRawType + (ConvertExample3Reverse_Person.class.getName()); + } + + public Object convert(Object fromValue) { + + RawObject person = (RawObject) fromValue; + Map<String,Object> personValues = person.getValues(); + RawObject address = (RawObject) personValues.remove("address"); + Map<String,Object> addressValues = address.getValues(); + + personValues.put("street", addressValues.remove("street")); + personValues.put("city", addressValues.remove("city")); + personValues.put("state", addressValues.remove("state")); + personValues.put("zipCode", addressValues.remove("zipCode")); + + return new RawObject + (newPersonType, personValues, person.getSuper()); + } + + @Override + public boolean equals(Object o) { + return o instanceof ConvertExample3Reverse_Conversion; + } + } + + @Entity(version=1) + static class ConvertExample3Reverse_Person + extends EvolveCase { + + private static final String NAME = + ConvertExample3Reverse_Person.class.getName(); + private static final String NAME2 = + PREFIX + "ConvertExample3Reverse_Address"; + + @PrimaryKey + int key; + + String street; + String city; + String state; + int zipCode; + + @Override + Mutations getMutations() { + Mutations m = new Mutations(); + Converter converter = new Converter + (ConvertExample3Reverse_Person.class.getName(), 0, + new ConvertExample3Reverse_Conversion()); + m.addConverter(converter); + m.addDeleter(new Deleter(NAME2, 0)); + return m; + } + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkEntity(true, model, env, NAME, 1, null); + if (oldTypesExist) { + checkVersions(model, NAME, 1, NAME, 0); + checkVersions(model, NAME2, 0); + } else { + checkVersions(model, NAME, 1); + } + } + + @Override + void readObjects(EntityStore store, boolean doUpdate) + throws DatabaseException { + + PrimaryIndex<Integer,ConvertExample3Reverse_Person> + index = store.getPrimaryIndex + (Integer.class, + ConvertExample3Reverse_Person.class); + ConvertExample3Reverse_Person obj = index.get(99); + TestCase.assertNotNull(obj); + TestCase.assertEquals(99, obj.key); + TestCase.assertEquals("street", obj.street); + TestCase.assertEquals("city", obj.city); + TestCase.assertEquals("state", obj.state); + TestCase.assertEquals(12345, obj.zipCode); + + if (doUpdate) { + index.put(obj); + } + } + + @Override + void copyRawObjects(RawStore rawStore, EntityStore newStore) + throws DatabaseException { + + PrimaryIndex<Integer,ConvertExample3Reverse_Person> + index = newStore.getPrimaryIndex + (Integer.class, + ConvertExample3Reverse_Person.class); + RawObject raw = rawStore.getPrimaryIndex(NAME).get(99); + index.put((ConvertExample3Reverse_Person) + newStore.getModel().convertRawObject(raw)); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + RawObject obj = readRaw + (store, 99, NAME, expectEvolved ? 1 : 0, CASECLS, 0); + if (expectEvolved) { + checkRawFields(obj, "key", 99, + "street", "street", + "city", "city", + "state", "state", + "zipCode", 12345); + } else { + RawType embedType = store.getModel().getRawType(NAME2); + Object embed = new RawObject + (embedType, + makeValues("street", "street", + "city", "city", + "state", "state", + "zipCode", 12345), + null); + checkRawFields(obj, "key", 99, "address", embed); + } + } + } + + @Persistent(version=1) + static class ConvertExample4_A extends ConvertExample4_B { + } + + @Persistent(version=1) + static class ConvertExample4_B { + String name; + } + + @SuppressWarnings("serial") + static class Example4_Conversion implements Conversion { + private transient RawType newAType; + private transient RawType newBType; + + public void initialize(EntityModel model) { + newAType = model.getRawType(ConvertExample4_A.class.getName()); + newBType = model.getRawType(ConvertExample4_B.class.getName()); + } + + public Object convert(Object fromValue) { + RawObject oldA = (RawObject) fromValue; + RawObject oldB = oldA.getSuper(); + Map<String,Object> aValues = oldA.getValues(); + Map<String,Object> bValues = oldB.getValues(); + bValues.put("name", aValues.remove("name")); + RawObject newB = new RawObject(newBType, bValues, oldB.getSuper()); + RawObject newA = new RawObject(newAType, aValues, newB); + return newA; + } + + @Override + public boolean equals(Object o) { + return o instanceof Example4_Conversion; + } + } + + @Entity(version=1) + static class ConvertExample4_Entity + extends EvolveCase { + + private static final String NAME = + ConvertExample4_Entity.class.getName(); + private static final String NAME2 = + ConvertExample4_A .class.getName(); + private static final String NAME3 = + ConvertExample4_B .class.getName(); + + @PrimaryKey + int key; + + ConvertExample4_A embed; + + @Override + Mutations getMutations() { + Mutations m = new Mutations(); + Converter converter = new Converter + (ConvertExample4_A.class.getName(), 0, + new Example4_Conversion()); + m.addConverter(converter); + return m; + } + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkEntity(true, model, env, NAME, 1, null); + if (oldTypesExist) { + checkVersions(model, NAME, 1, NAME, 0); + checkVersions(model, NAME2, 1, NAME2, 0); + checkVersions(model, NAME3, 1, NAME3, 0); + } else { + checkVersions(model, NAME, 1); + checkVersions(model, NAME2, 1); + checkVersions(model, NAME3, 1); + } + } + + @Override + void readObjects(EntityStore store, boolean doUpdate) + throws DatabaseException { + + PrimaryIndex<Integer,ConvertExample4_Entity> + index = store.getPrimaryIndex + (Integer.class, + ConvertExample4_Entity.class); + ConvertExample4_Entity obj = index.get(99); + TestCase.assertNotNull(obj); + TestCase.assertEquals(99, obj.key); + TestCase.assertNotNull(obj.embed); + TestCase.assertEquals("name", obj.embed.name); + + if (doUpdate) { + index.put(obj); + } + } + + @Override + void copyRawObjects(RawStore rawStore, EntityStore newStore) + throws DatabaseException { + + PrimaryIndex<Integer,ConvertExample4_Entity> + index = newStore.getPrimaryIndex + (Integer.class, + ConvertExample4_Entity.class); + RawObject raw = rawStore.getPrimaryIndex(NAME).get(99); + index.put((ConvertExample4_Entity) + newStore.getModel().convertRawObject(raw)); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + RawType embedTypeA = store.getModel().getRawType(NAME2); + RawType embedTypeB = store.getModel().getRawType(NAME3); + Object embed; + if (expectEvolved) { + embed = new RawObject(embedTypeA, makeValues(), + new RawObject + (embedTypeB, makeValues("name", "name"), null)); + } else { + embed = new RawObject(embedTypeA, makeValues("name", "name"), + new RawObject + (embedTypeB, makeValues(), null)); + } + RawObject obj = readRaw + (store, 99, NAME, expectEvolved ? 1 : 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "embed", embed); + } + } + + @Persistent(version=1) + static class ConvertExample5_Pet { + String name; + } + + @Persistent + static class ConvertExample5_Cat extends ConvertExample5_Pet { + int finickyLevel; + } + + @Persistent + static class ConvertExample5_Dog extends ConvertExample5_Pet { + double barkVolume; + } + + @SuppressWarnings("serial") + static class ConvertExample5_Conversion implements Conversion { + private transient RawType newPetType; + private transient RawType dogType; + private transient RawType catType; + + public void initialize(EntityModel model) { + newPetType = model.getRawType(ConvertExample5_Pet.class.getName()); + dogType = model.getRawType(ConvertExample5_Dog.class.getName()); + catType = model.getRawType(ConvertExample5_Cat.class.getName()); + } + + public Object convert(Object fromValue) { + RawObject pet = (RawObject) fromValue; + Map<String,Object> petValues = pet.getValues(); + Map<String,Object> subTypeValues = new HashMap<String,Object>(); + Boolean isCat = (Boolean) petValues.remove("isCatNotDog"); + Integer finickyLevel = (Integer) petValues.remove("finickyLevel"); + Double barkVolume = (Double) petValues.remove("barkVolume"); + RawType newSubType; + if (isCat) { + newSubType = catType; + subTypeValues.put("finickyLevel", finickyLevel); + } else { + newSubType = dogType; + subTypeValues.put("barkVolume", barkVolume); + } + RawObject newPet = new RawObject + (newPetType, petValues, pet.getSuper()); + return new RawObject(newSubType, subTypeValues, newPet); + } + + @Override + public boolean equals(Object o) { + return o instanceof ConvertExample5_Conversion; + } + } + + @Entity(version=1) + static class ConvertExample5_Entity + extends EvolveCase { + + private static final String NAME = + ConvertExample5_Entity.class.getName(); + private static final String NAME2 = + ConvertExample5_Pet.class.getName(); + private static final String NAME3 = + ConvertExample5_Cat.class.getName(); + private static final String NAME4 = + ConvertExample5_Dog.class.getName(); + + @PrimaryKey + int key; + + ConvertExample5_Cat cat; + ConvertExample5_Dog dog; + + @Override + Mutations getMutations() { + Mutations m = new Mutations(); + Converter converter = new Converter + (ConvertExample5_Pet.class.getName(), 0, + new ConvertExample5_Conversion()); + m.addConverter(converter); + return m; + } + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkEntity(true, model, env, NAME, 1, null); + if (oldTypesExist) { + checkVersions(model, NAME, 1, NAME, 0); + checkVersions(model, NAME2, 1, NAME2, 0); + } else { + checkVersions(model, NAME, 1); + checkVersions(model, NAME2, 1); + } + checkVersions(model, NAME3, 0); + checkVersions(model, NAME4, 0); + } + + @Override + void readObjects(EntityStore store, boolean doUpdate) + throws DatabaseException { + + PrimaryIndex<Integer,ConvertExample5_Entity> + index = store.getPrimaryIndex + (Integer.class, + ConvertExample5_Entity.class); + ConvertExample5_Entity obj = index.get(99); + TestCase.assertNotNull(obj); + TestCase.assertEquals(99, obj.key); + TestCase.assertNotNull(obj.cat); + TestCase.assertEquals("Jeffry", obj.cat.name); + TestCase.assertEquals(999, obj.cat.finickyLevel); + TestCase.assertNotNull(obj.dog); + TestCase.assertEquals("Nelson", obj.dog.name); + TestCase.assertEquals(0.01, obj.dog.barkVolume); + + if (doUpdate) { + index.put(obj); + } + } + + @Override + void copyRawObjects(RawStore rawStore, EntityStore newStore) + throws DatabaseException { + + PrimaryIndex<Integer,ConvertExample5_Entity> + index = newStore.getPrimaryIndex + (Integer.class, + ConvertExample5_Entity.class); + RawObject raw = rawStore.getPrimaryIndex(NAME).get(99); + index.put((ConvertExample5_Entity) + newStore.getModel().convertRawObject(raw)); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + RawType petType = store.getModel().getRawType(NAME2); + RawObject cat; + RawObject dog; + if (expectEvolved) { + RawType catType = store.getModel().getRawType(NAME3); + RawType dogType = store.getModel().getRawType(NAME4); + cat = new RawObject(catType, makeValues("finickyLevel", 999), + new RawObject(petType, makeValues("name", "Jeffry"), + null)); + dog = new RawObject(dogType, makeValues("barkVolume", 0.01), + new RawObject(petType, makeValues("name", "Nelson"), + null)); + } else { + cat = new RawObject(petType, makeValues("name", "Jeffry", + "isCatNotDog", true, + "finickyLevel", 999, + "barkVolume", 0.0), + null); + dog = new RawObject(petType, makeValues("name", "Nelson", + "isCatNotDog", false, + "finickyLevel", 0, + "barkVolume", 0.01), + null); + } + RawObject obj = readRaw + (store, 99, NAME, expectEvolved ? 1 : 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "cat", cat, "dog", dog); + } + } + + @Persistent(version=1) + static class AllowFieldAddDelete_Embed { + private final String f0 = "0"; + private String f2; + private final int f3 = 3; + private String f4; + private final int f5 = 5; + private final String f8 = "8"; + private final int f9 = 9; + } + + @Persistent(version=1) + static class AllowFieldAddDelete_Base + extends EvolveCase { + + private final String f0 = "0"; + private String f2; + private final int f3 = 3; + private String f4; + private final int f5 = 5; + private final String f8 = "8"; + private final int f9 = 9; + } + + @Entity(version=1) + static class AllowFieldAddDelete + extends AllowFieldAddDelete_Base { + + private static final String NAME = + AllowFieldAddDelete.class.getName(); + private static final String NAME2 = + AllowFieldAddDelete_Base.class.getName(); + private static final String NAME3 = + AllowFieldAddDelete_Embed.class.getName(); + + @PrimaryKey + int key; + + AllowFieldAddDelete_Embed embed; + + private final String f0 = "0"; + private String f2; + private final int f3 = 3; + private String f4; + private final int f5 = 5; + private final String f8 = "8"; + private final int f9 = 9; + + @Override + Mutations getMutations() { + Mutations m = new Mutations(); + for (String name : new String[] {NAME, NAME2, NAME3}) { + m.addDeleter(new Deleter(name, 0, "f1")); + m.addDeleter(new Deleter(name, 0, "f6")); + m.addDeleter(new Deleter(name, 0, "f7")); + } + return m; + } + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkEntity(true, model, env, NAME, 1, null); + if (oldTypesExist) { + checkVersions(model, NAME, 1, NAME, 0); + checkVersions(model, NAME2, 1, NAME2, 0); + checkVersions(model, NAME3, 1, NAME3, 0); + } else { + checkVersions(model, NAME, 1); + checkVersions(model, NAME2, 1); + checkVersions(model, NAME3, 1); + } + } + + @Override + void readObjects(EntityStore store, boolean doUpdate) + throws DatabaseException { + + PrimaryIndex<Integer,AllowFieldAddDelete> + index = store.getPrimaryIndex + (Integer.class, + AllowFieldAddDelete.class); + AllowFieldAddDelete obj = index.get(99); + TestCase.assertNotNull(obj); + TestCase.assertEquals(99, obj.key); + { + AllowFieldAddDelete o = obj; + + TestCase.assertNotNull(o); + TestCase.assertEquals("0", o.f0); + TestCase.assertEquals("2", o.f2); + TestCase.assertEquals(3, o.f3); + TestCase.assertEquals("4", o.f4); + TestCase.assertEquals(5, o.f5); + TestCase.assertEquals("8", o.f8); + TestCase.assertEquals(9, o.f9); + } + { + AllowFieldAddDelete_Base o = obj; + + TestCase.assertNotNull(o); + TestCase.assertEquals("0", o.f0); + TestCase.assertEquals("2", o.f2); + TestCase.assertEquals(3, o.f3); + TestCase.assertEquals("4", o.f4); + TestCase.assertEquals(5, o.f5); + TestCase.assertEquals("8", o.f8); + TestCase.assertEquals(9, o.f9); + } + { + AllowFieldAddDelete_Embed o = obj.embed; + + TestCase.assertNotNull(o); + TestCase.assertEquals("0", o.f0); + TestCase.assertEquals("2", o.f2); + TestCase.assertEquals(3, o.f3); + TestCase.assertEquals("4", o.f4); + TestCase.assertEquals(5, o.f5); + TestCase.assertEquals("8", o.f8); + TestCase.assertEquals(9, o.f9); + } + + if (doUpdate) { + index.put(obj); + } + } + + @Override + void copyRawObjects(RawStore rawStore, EntityStore newStore) + throws DatabaseException { + + PrimaryIndex<Integer,AllowFieldAddDelete> + index = newStore.getPrimaryIndex + (Integer.class, + AllowFieldAddDelete.class); + RawObject raw = rawStore.getPrimaryIndex(NAME).get(99); + index.put((AllowFieldAddDelete) + newStore.getModel().convertRawObject(raw)); + } + + static final Object[] fixedFields0 = { + "f1", 1, + "f2", "2", + "f4", "4", + "f6", 6, + "f7", "7", + }; + + static final Object[] fixedFields1 = { + "f2", "2", + "f4", "4", + }; + + static final Object[] fixedFields2 = { + "f0", "0", + "f2", "2", + "f3", 3, + "f4", "4", + "f5", 5, + "f8", "8", + "f9", 9, + }; + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + RawType baseType = store.getModel().getRawType(NAME2); + RawType embedType = store.getModel().getRawType(NAME3); + + Object[] ff; + if (expectEvolved) { + if (expectUpdated) { + ff = fixedFields2; + } else { + ff = fixedFields1; + } + } else { + ff = fixedFields0; + } + RawObject embed = new RawObject(embedType, makeValues(ff), null); + RawObject obj = readRaw + (store, 99, NAME, expectEvolved ? 1 : 0, + NAME2, expectEvolved ? 1 : 0, + CASECLS, 0); + checkRaw(obj, ff, "key", 99, "embed", embed); + checkRaw(obj.getSuper(), ff); + } + + private void checkRaw(RawObject obj, + Object[] fixedFields, + Object... otherFields) { + Object[] allFields = + new Object[otherFields.length + fixedFields.length]; + System.arraycopy(otherFields, 0, allFields, 0, otherFields.length); + System.arraycopy(fixedFields, 0, allFields, + otherFields.length, fixedFields.length); + checkRawFields(obj, allFields); + } + } + + static class ProxiedClass { + int data; + + ProxiedClass(int data) { + this.data = data; + } + } + + @Persistent(version=1, proxyFor=ProxiedClass.class) + static class ProxiedClass_Proxy implements PersistentProxy<ProxiedClass> { + long data; + + public void initializeProxy(ProxiedClass o) { + data = o.data; + } + + public ProxiedClass convertProxy() { + return new ProxiedClass((int) data); + } + } + + @Entity + static class ProxiedClass_Entity + extends EvolveCase { + + private static final String NAME = + ProxiedClass_Entity.class.getName(); + private static final String NAME2 = + ProxiedClass_Proxy.class.getName(); + + @PrimaryKey + int key; + + ProxiedClass embed; + + @Override + void configure(EntityModel model, StoreConfig config) { + model.registerClass(ProxiedClass_Proxy.class); + } + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + if (oldTypesExist) { + checkVersions(model, NAME2, 1, NAME2, 0); + } else { + checkVersions(model, NAME2, 1); + } + } + + @Override + void readObjects(EntityStore store, boolean doUpdate) + throws DatabaseException { + + PrimaryIndex<Integer,ProxiedClass_Entity> + index = store.getPrimaryIndex + (Integer.class, + ProxiedClass_Entity.class); + ProxiedClass_Entity obj = index.get(99); + TestCase.assertNotNull(obj); + TestCase.assertEquals(99, obj.key); + TestCase.assertNotNull(obj.embed); + TestCase.assertEquals(88, obj.embed.data); + + if (doUpdate) { + index.put(obj); + } + } + + @Override + void copyRawObjects(RawStore rawStore, EntityStore newStore) + throws DatabaseException { + + PrimaryIndex<Integer,ProxiedClass_Entity> + index = newStore.getPrimaryIndex + (Integer.class, + ProxiedClass_Entity.class); + RawObject raw = rawStore.getPrimaryIndex(NAME).get(99); + index.put((ProxiedClass_Entity) + newStore.getModel().convertRawObject(raw)); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + RawType embedType = store.getModel().getRawType(NAME2); + RawObject embed; + if (expectEvolved) { + embed = new RawObject + (embedType, makeValues("data", 88L), null); + } else { + embed = new RawObject + (embedType, makeValues("data", 88), null); + } + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "embed", embed); + } + } + + @Persistent(proxyFor=StringBuffer.class) + static class DisallowChangeProxyFor_Proxy2 + implements PersistentProxy<StringBuffer> { + + String data; + + public void initializeProxy(StringBuffer o) { + data = o.toString(); + } + + public StringBuffer convertProxy() { + return new StringBuffer(data); + } + } + + @Persistent(proxyFor=StringBuilder.class) + static class DisallowChangeProxyFor_Proxy + implements PersistentProxy<StringBuilder> { + + String data; + + public void initializeProxy(StringBuilder o) { + data = o.toString(); + } + + public StringBuilder convertProxy() { + return new StringBuilder(data); + } + } + + @Entity + static class DisallowChangeProxyFor + extends EvolveCase { + + @PrimaryKey + int key; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Error when evolving class: java.lang.StringBuffer version: 0 to class: java.lang.StringBuffer version: 0 Error: The proxy class for this type has been changed from: com.sleepycat.persist.test.EvolveClasses$DisallowChangeProxyFor_Proxy to: com.sleepycat.persist.test.EvolveClasses$DisallowChangeProxyFor_Proxy2"; + } + + @Override + void configure(EntityModel model, StoreConfig config) { + model.registerClass(DisallowChangeProxyFor_Proxy.class); + model.registerClass(DisallowChangeProxyFor_Proxy2.class); + } + } + + @Persistent + static class DisallowDeleteProxyFor_Proxy { + String data; + } + + @Entity + static class DisallowDeleteProxyFor + extends EvolveCase { + + @PrimaryKey + int key; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Mutation is missing to evolve class: java.lang.StringBuffer version: 0 Error: java.lang.IllegalArgumentException: Class could not be loaded or is not persistent: java.lang.StringBuffer"; + } + } + + @Persistent(version=1) + static class ArrayNameChange_Component_Renamed { + + long data; + } + + @Entity + static class ArrayNameChange_Entity + extends EvolveCase { + + private static final String NAME = + ArrayNameChange_Entity.class.getName(); + private static final String NAME2 = + ArrayNameChange_Component_Renamed.class.getName(); + private static final String NAME3 = + PREFIX + "ArrayNameChange_Component"; + + @PrimaryKey + int key; + + ArrayNameChange_Component_Renamed[] embed; + ArrayNameChange_Component_Renamed embed2; + + @Override + Mutations getMutations() { + Mutations m = new Mutations(); + m.addRenamer(new Renamer(NAME3, 0, NAME2)); + return m; + } + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + if (oldTypesExist) { + checkVersions(model, NAME2, 1, NAME3, 0); + } else { + checkVersions(model, NAME2, 1); + } + } + + @Override + void readObjects(EntityStore store, boolean doUpdate) + throws DatabaseException { + + PrimaryIndex<Integer,ArrayNameChange_Entity> + index = store.getPrimaryIndex + (Integer.class, + ArrayNameChange_Entity.class); + ArrayNameChange_Entity obj = index.get(99); + TestCase.assertNotNull(obj); + TestCase.assertEquals(99, obj.key); + TestCase.assertNotNull(obj.embed); + TestCase.assertEquals(1, obj.embed.length); + TestCase.assertEquals(88L, obj.embed[0].data); + TestCase.assertSame(obj.embed2, obj.embed[0]); + + if (doUpdate) { + index.put(obj); + } + } + + @Override + void copyRawObjects(RawStore rawStore, EntityStore newStore) + throws DatabaseException { + + PrimaryIndex<Integer,ArrayNameChange_Entity> + index = newStore.getPrimaryIndex + (Integer.class, + ArrayNameChange_Entity.class); + RawObject raw = rawStore.getPrimaryIndex(NAME).get(99); + index.put((ArrayNameChange_Entity) + newStore.getModel().convertRawObject(raw)); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + String compTypeName = expectEvolved ? NAME2 : NAME3; + String arrayTypeName = "[L" + compTypeName + ';'; + RawType compType = store.getModel().getRawType(compTypeName); + RawType arrayType = store.getModel().getRawType(arrayTypeName); + RawObject embed2; + if (expectEvolved) { + embed2 = new RawObject + (compType, makeValues("data", 88L), null); + } else { + embed2 = new RawObject + (compType, makeValues("data", 88), null); + } + RawObject embed = new RawObject + (arrayType, new Object[] { embed2 }); + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + checkRawFields(obj, "key", 99, "embed", embed, "embed2", embed2); + } + } + + enum AddEnumConstant_Enum { + A, B, C; + } + + @Entity(version=1) + static class AddEnumConstant_Entity + extends EvolveCase { + + private static final String NAME = + AddEnumConstant_Entity.class.getName(); + private static final String NAME2 = + AddEnumConstant_Enum.class.getName(); + + @PrimaryKey + int key; + + AddEnumConstant_Enum e1; + AddEnumConstant_Enum e2; + AddEnumConstant_Enum e3 = AddEnumConstant_Enum.C; + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkEntity(true, model, env, NAME, 1, null); + if (oldTypesExist) { + checkVersions(model, NAME, 1, NAME, 0); + checkVersions(model, NAME2, 0, NAME2, 0); + } else { + checkVersions(model, NAME, 1); + checkVersions(model, NAME2, 0); + } + } + + @Override + void readObjects(EntityStore store, boolean doUpdate) + throws DatabaseException { + + PrimaryIndex<Integer,AddEnumConstant_Entity> + index = store.getPrimaryIndex + (Integer.class, + AddEnumConstant_Entity.class); + AddEnumConstant_Entity obj = index.get(99); + TestCase.assertNotNull(obj); + TestCase.assertEquals(99, obj.key); + TestCase.assertSame(AddEnumConstant_Enum.A, obj.e1); + TestCase.assertSame(AddEnumConstant_Enum.B, obj.e2); + TestCase.assertSame(AddEnumConstant_Enum.C, obj.e3); + + if (doUpdate) { + index.put(obj); + } + } + + @Override + void copyRawObjects(RawStore rawStore, EntityStore newStore) + throws DatabaseException { + + PrimaryIndex<Integer,AddEnumConstant_Entity> + index = newStore.getPrimaryIndex + (Integer.class, + AddEnumConstant_Entity.class); + RawObject raw = rawStore.getPrimaryIndex(NAME).get(99); + index.put((AddEnumConstant_Entity) + newStore.getModel().convertRawObject(raw)); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + RawObject obj = readRaw + (store, 99, NAME, expectEvolved ? 1 : 0, CASECLS, 0); + RawType enumType = store.getModel().getRawType(NAME2); + if (expectUpdated) { + checkRawFields(obj, "key", 99, + "e1", new RawObject(enumType, "A"), + "e2", new RawObject(enumType, "B"), + "e3", new RawObject(enumType, "C")); + } else { + checkRawFields(obj, "key", 99, + "e1", new RawObject(enumType, "A"), + "e2", new RawObject(enumType, "B")); + } + } + } + + enum InsertEnumConstant_Enum { + X, A, Y, B, Z; + } + + @Persistent + static class InsertEnumConstant_KeyClass + implements Comparable<InsertEnumConstant_KeyClass > { + + @KeyField(1) + InsertEnumConstant_Enum key; + + private InsertEnumConstant_KeyClass() {} + + InsertEnumConstant_KeyClass(InsertEnumConstant_Enum key) { + this.key = key; + } + + public int compareTo(InsertEnumConstant_KeyClass o) { + /* Use the natural order, in spite of insertions. */ + return key.compareTo(o.key); + } + } + + @Entity(version=1) + static class InsertEnumConstant_Entity + extends EvolveCase { + + private static final String NAME = + InsertEnumConstant_Entity.class.getName(); + private static final String NAME2 = + InsertEnumConstant_Enum.class.getName(); + private static final String NAME3 = + InsertEnumConstant_KeyClass.class.getName(); + + @PrimaryKey + int key; + + @SecondaryKey(relate=MANY_TO_ONE) + InsertEnumConstant_KeyClass secKey; + + InsertEnumConstant_Enum e1; + InsertEnumConstant_Enum e2; + InsertEnumConstant_Enum e3 = InsertEnumConstant_Enum.X; + InsertEnumConstant_Enum e4 = InsertEnumConstant_Enum.Y; + InsertEnumConstant_Enum e5 = InsertEnumConstant_Enum.Z; + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkEntity(true, model, env, NAME, 1, null); + if (oldTypesExist) { + checkVersions(model, NAME, 1, NAME, 0); + checkVersions(model, NAME2, 0, NAME2, 0); + checkVersions(model, NAME3, 0, NAME3, 0); + } else { + checkVersions(model, NAME, 1); + checkVersions(model, NAME2, 0); + checkVersions(model, NAME3, 0); + } + } + + @Override + void readObjects(EntityStore store, boolean doUpdate) + throws DatabaseException { + + PrimaryIndex<Integer,InsertEnumConstant_Entity> + index = store.getPrimaryIndex + (Integer.class, + InsertEnumConstant_Entity.class); + InsertEnumConstant_Entity obj = index.get(99); + TestCase.assertNotNull(obj); + TestCase.assertEquals(99, obj.key); + if (updated) { + TestCase.assertSame(InsertEnumConstant_Enum.X, obj.secKey.key); + } else { + TestCase.assertSame(InsertEnumConstant_Enum.A, obj.secKey.key); + } + TestCase.assertSame(InsertEnumConstant_Enum.A, obj.e1); + TestCase.assertSame(InsertEnumConstant_Enum.B, obj.e2); + TestCase.assertSame(InsertEnumConstant_Enum.X, obj.e3); + TestCase.assertSame(InsertEnumConstant_Enum.Y, obj.e4); + TestCase.assertSame(InsertEnumConstant_Enum.Z, obj.e5); + + if (doUpdate) { + obj.secKey = + new InsertEnumConstant_KeyClass(InsertEnumConstant_Enum.X); + index.put(obj); + updated = true; + } + } + + @Override + void copyRawObjects(RawStore rawStore, EntityStore newStore) + throws DatabaseException { + + PrimaryIndex<Integer,InsertEnumConstant_Entity> + index = newStore.getPrimaryIndex + (Integer.class, + InsertEnumConstant_Entity.class); + RawObject raw = rawStore.getPrimaryIndex(NAME).get(99); + index.put((InsertEnumConstant_Entity) + newStore.getModel().convertRawObject(raw)); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + RawObject obj = readRaw + (store, 99, NAME, expectEvolved ? 1 : 0, CASECLS, 0); + RawType enumType = store.getModel().getRawType(NAME2); + + Map<String, Object> secKeyFields = new HashMap<String, Object>(); + RawType secKeyType = store.getModel().getRawType(NAME3); + RawObject secKeyObject = + new RawObject(secKeyType, secKeyFields, null /*superObject*/); + + if (expectUpdated) { + secKeyFields.put("key", new RawObject(enumType, "X")); + checkRawFields(obj, "key", 99, + "secKey", secKeyObject, + "e1", new RawObject(enumType, "A"), + "e2", new RawObject(enumType, "B"), + "e3", new RawObject(enumType, "X"), + "e4", new RawObject(enumType, "Y"), + "e5", new RawObject(enumType, "Z")); + } else { + secKeyFields.put("key", new RawObject(enumType, "A")); + checkRawFields(obj, "key", 99, + "secKey", secKeyObject, + "e1", new RawObject(enumType, "A"), + "e2", new RawObject(enumType, "B")); + } + } + } + + enum DeleteEnumConstant_Enum { + A, C; + } + + /** + * Don't allow deleting (or renaming, which appears as a deletion) enum + * values without mutations. + */ + @Entity + static class DeleteEnumConstant_NoMutation + extends EvolveCase { + + @PrimaryKey + int key; + + DeleteEnumConstant_Enum e1; + DeleteEnumConstant_Enum e2; + DeleteEnumConstant_Enum e3; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Incompatible enum type changed detected when evolving class: com.sleepycat.persist.test.EvolveClasses$DeleteEnumConstant_Enum version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DeleteEnumConstant_Enum version: 0 Error: Enum values may not be removed: [B]"; + } + } + + /** + * With a Deleter, deleted enum values are null. Note that version is not + * bumped. + */ + /* Disabled until support for enum deletion is added. + @Entity + static class DeleteEnumConstant_WithDeleter + extends EvolveCase { + + private static final String NAME = + DeleteEnumConstant_WithDeleter.class.getName(); + private static final String NAME2 = + DeleteEnumConstant_Enum.class.getName(); + + @PrimaryKey + int key; + + DeleteEnumConstant_Enum e1; + DeleteEnumConstant_Enum e2; + DeleteEnumConstant_Enum e3; + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkEntity(true, model, env, NAME, 0, null); + checkVersions(model, NAME, 0); + if (oldTypesExist) { + checkVersions(model, NAME2, 0, NAME2, 0); + } else { + checkVersions(model, NAME2, 0); + } + } + + @Override + void readObjects(EntityStore store, boolean doUpdate) + throws DatabaseException { + + PrimaryIndex<Integer,DeleteEnumConstant_WithDeleter> + index = store.getPrimaryIndex + (Integer.class, + DeleteEnumConstant_WithDeleter.class); + DeleteEnumConstant_WithDeleter obj = index.get(99); + TestCase.assertNotNull(obj); + TestCase.assertEquals(99, obj.key); + TestCase.assertSame(DeleteEnumConstant_Enum.A, obj.e1); + TestCase.assertSame(null, obj.e2); + TestCase.assertSame(DeleteEnumConstant_Enum.C, obj.e3); + + if (doUpdate) { + index.put(obj); + } + } + + @Override + void copyRawObjects(RawStore rawStore, EntityStore newStore) + throws DatabaseException { + + PrimaryIndex<Integer,DeleteEnumConstant_WithDeleter> + index = newStore.getPrimaryIndex + (Integer.class, + DeleteEnumConstant_WithDeleter.class); + RawObject raw = rawStore.getPrimaryIndex(NAME).get(99); + index.put((DeleteEnumConstant_WithDeleter) + newStore.getModel().convertRawObject(raw)); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + RawObject obj = readRaw(store, 99, NAME, 0, CASECLS, 0); + RawType enumType = store.getModel().getRawType(NAME2); + if (expectUpdated) { + checkRawFields(obj, "key", 99, + "e1", new RawObject(enumType, "A"), + "e2", null, + "e3", new RawObject(enumType, "C")); + } else { + checkRawFields(obj, "key", 99, + "e1", new RawObject(enumType, "A"), + "e2", new RawObject(enumType, "B"), + "e3", new RawObject(enumType, "C")); + } + } + } + */ + + /** + * A field converter can assign deleted enum values. Version must be + * bumped when a converter is added. + */ + /* Disabled until support for enum deletion is added. + @Entity(version=1) + static class DeleteEnumConstant_WithConverter + extends EvolveCase { + + private static final String NAME = + DeleteEnumConstant_WithConverter.class.getName(); + private static final String NAME2 = + DeleteEnumConstant_Enum.class.getName(); + + @PrimaryKey + int key; + + DeleteEnumConstant_Enum e1; + DeleteEnumConstant_Enum e2; + DeleteEnumConstant_Enum e3; + + @Override + Mutations getMutations() { + Mutations m = new Mutations(); + Conversion c = new MyConversion(); + m.addConverter(new Converter(NAME, 0, "e1", c)); + m.addConverter(new Converter(NAME, 0, "e2", c)); + m.addConverter(new Converter(NAME, 0, "e3", c)); + return m; + } + + @SuppressWarnings("serial") + static class MyConversion implements Conversion { + + transient RawType newType; + + public void initialize(EntityModel model) { + newType = model.getRawType(NAME2); + TestCase.assertNotNull(newType); + } + + public Object convert(Object fromValue) { + TestCase.assertNotNull(newType); + RawObject obj = (RawObject) fromValue; + String val = obj.getEnum(); + TestCase.assertNotNull(val); + if ("B".equals(val)) { + val = "C"; + } + return new RawObject(newType, val); + } + + @Override + public boolean equals(Object other) { + return other instanceof MyConversion; + } + } + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkEntity(true, model, env, NAME, 1, null); + if (oldTypesExist) { + checkVersions(model, NAME, 1, NAME, 0); + checkVersions(model, NAME2, 0, NAME2, 0); + } else { + checkVersions(model, NAME, 1); + checkVersions(model, NAME2, 0); + } + } + + @Override + void readObjects(EntityStore store, boolean doUpdate) + throws DatabaseException { + + PrimaryIndex<Integer,DeleteEnumConstant_WithConverter> + index = store.getPrimaryIndex + (Integer.class, + DeleteEnumConstant_WithConverter.class); + DeleteEnumConstant_WithConverter obj = index.get(99); + TestCase.assertNotNull(obj); + TestCase.assertEquals(99, obj.key); + TestCase.assertSame(DeleteEnumConstant_Enum.A, obj.e1); + TestCase.assertSame(DeleteEnumConstant_Enum.C, obj.e2); + TestCase.assertSame(DeleteEnumConstant_Enum.C, obj.e3); + + if (doUpdate) { + index.put(obj); + } + } + + @Override + void copyRawObjects(RawStore rawStore, EntityStore newStore) + throws DatabaseException { + + PrimaryIndex<Integer,DeleteEnumConstant_WithConverter> + index = newStore.getPrimaryIndex + (Integer.class, + DeleteEnumConstant_WithConverter.class); + RawObject raw = rawStore.getPrimaryIndex(NAME).get(99); + index.put((DeleteEnumConstant_WithConverter) + newStore.getModel().convertRawObject(raw)); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + RawObject obj = readRaw(store, 99, NAME, expectEvolved ? 1 : 0, + CASECLS, 0); + RawType enumType = store.getModel().getRawType(NAME2); + if (expectEvolved) { + checkRawFields(obj, "key", 99, + "e1", new RawObject(enumType, "A"), + "e2", new RawObject(enumType, "C"), + "e3", new RawObject(enumType, "C")); + } else { + checkRawFields(obj, "key", 99, + "e1", new RawObject(enumType, "A"), + "e2", new RawObject(enumType, "B"), + "e3", new RawObject(enumType, "C")); + } + } + } + */ + + @Entity + static class DisallowChangeKeyRelate + extends EvolveCase { + + private static final String NAME = + DisallowChangeKeyRelate.class.getName(); + + @PrimaryKey + int key; + + @SecondaryKey(relate=MANY_TO_ONE) + int skey; + + @Override + public String getStoreOpenException() { + return "com.sleepycat.persist.evolve.IncompatibleClassException: Change detected in the relate attribute (Relationship) of a secondary key when evolving class: com.sleepycat.persist.test.EvolveClasses$DisallowChangeKeyRelate version: 0 to class: com.sleepycat.persist.test.EvolveClasses$DisallowChangeKeyRelate version: 0 Error: Old key: skey relate: ONE_TO_ONE new key: skey relate: MANY_TO_ONE"; + } + } + + @Entity(version=1) + static class AllowChangeKeyMetadata + extends EvolveCase { + + private static final String NAME = + AllowChangeKeyMetadata.class.getName(); + + @PrimaryKey + int key; + + /* + * Combined fields from version 0 and 1: + * addAnnotation = 88; + * dropField = 77; + * dropAnnotation = 66; + * addField = 55; + * renamedField = 44; // was toBeRenamedField + * aa = 33; + * ff = 22; + */ + + int aa; + + @SecondaryKey(relate=ONE_TO_ONE) + int addAnnotation; + + int dropAnnotation; + + @SecondaryKey(relate=ONE_TO_ONE) + Integer addField; + + @SecondaryKey(relate=ONE_TO_ONE) + int renamedField; + + int ff; + + @Override + Mutations getMutations() { + Mutations m = new Mutations(); + m.addDeleter(new Deleter(NAME, 0, "dropField")); + m.addRenamer(new Renamer(NAME, 0, "toBeRenamedField", + "renamedField")); + return m; + } + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkEntity(true, model, env, NAME, 1, null); + if (oldTypesExist) { + checkVersions(model, NAME, 1, NAME, 0); + } else { + checkVersions(model, NAME, 1); + } + } + + @Override + void readObjects(EntityStore store, boolean doUpdate) + throws DatabaseException { + + PrimaryIndex<Integer,AllowChangeKeyMetadata> + index = store.getPrimaryIndex + (Integer.class, + AllowChangeKeyMetadata.class); + AllowChangeKeyMetadata obj = index.get(99); + checkValues(obj); + + checkValues(store.getSecondaryIndex + (index, Integer.class, "addAnnotation").get(88)); + checkValues(store.getSecondaryIndex + (index, Integer.class, "renamedField").get(44)); + if (updated) { + checkValues(store.getSecondaryIndex + (index, Integer.class, "addField").get(55)); + } else { + TestCase.assertNull(store.getSecondaryIndex + (index, Integer.class, "addField").get(55)); + } + + if (doUpdate) { + obj.addField = 55; + index.put(obj); + updated = true; + checkValues(store.getSecondaryIndex + (index, Integer.class, "addAnnotation").get(88)); + checkValues(store.getSecondaryIndex + (index, Integer.class, "addField").get(55)); + } + } + + @Override + void copyRawObjects(RawStore rawStore, EntityStore newStore) + throws DatabaseException { + + PrimaryIndex<Integer,AllowChangeKeyMetadata> + index = newStore.getPrimaryIndex + (Integer.class, + AllowChangeKeyMetadata.class); + RawObject raw = rawStore.getPrimaryIndex(NAME).get(99); + index.put((AllowChangeKeyMetadata) + newStore.getModel().convertRawObject(raw)); + } + + private void checkValues(AllowChangeKeyMetadata obj) { + TestCase.assertNotNull(obj); + TestCase.assertEquals(99, obj.key); + TestCase.assertEquals(88, obj.addAnnotation); + TestCase.assertEquals(66, obj.dropAnnotation); + TestCase.assertEquals(44, obj.renamedField); + TestCase.assertEquals(33, obj.aa); + TestCase.assertEquals(22, obj.ff); + if (updated) { + TestCase.assertEquals(Integer.valueOf(55), obj.addField); + } else { + TestCase.assertNull(obj.addField); + } + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + RawObject obj = readRaw + (store, 99, NAME, expectEvolved ? 1 : 0, CASECLS, 0); + if (expectUpdated) { + checkRawFields(obj, "key", 99, + "addAnnotation", 88, + "dropAnnotation", 66, + "addField", 55, + "renamedField", 44, + "aa", 33, + "ff", 22); + } else if (expectEvolved) { + checkRawFields(obj, "key", 99, + "addAnnotation", 88, + "dropAnnotation", 66, + "renamedField", 44, + "aa", 33, + "ff", 22); + } else { + checkRawFields(obj, "key", 99, + "addAnnotation", 88, + "dropField", 77, + "dropAnnotation", 66, + "toBeRenamedField", 44, + "aa", 33, + "ff", 22); + } + Environment env = store.getEnvironment(); + assertDbExists(expectEvolved, env, NAME, "addAnnotation"); + assertDbExists(expectEvolved, env, NAME, "addField"); + assertDbExists(expectEvolved, env, NAME, "renamedField"); + assertDbExists(!expectEvolved, env, NAME, "toBeRenamedField"); + assertDbExists(!expectEvolved, env, NAME, "dropField"); + assertDbExists(!expectEvolved, env, NAME, "dropAnnotation"); + } + } + + /** + * Same test as AllowChangeKeyMetadata but with the secondary keys in an + * entity subclass. [#16253] + */ + @Persistent(version=1) + static class AllowChangeKeyMetadataInSubclass + extends AllowChangeKeyMetadataEntity { + + private static final String NAME = + AllowChangeKeyMetadataInSubclass.class.getName(); + private static final String NAME2 = + AllowChangeKeyMetadataEntity.class.getName(); + + /* + * Combined fields from version 0 and 1: + * addAnnotation = 88; + * dropField = 77; + * dropAnnotation = 66; + * addField = 55; + * renamedField = 44; // was toBeRenamedField + * aa = 33; + * ff = 22; + */ + + int aa; + + @SecondaryKey(relate=ONE_TO_ONE) + int addAnnotation; + + int dropAnnotation; + + @SecondaryKey(relate=ONE_TO_ONE) + Integer addField; + + @SecondaryKey(relate=ONE_TO_ONE) + int renamedField; + + int ff; + + @Override + void configure(EntityModel model, StoreConfig config) { + model.registerClass(AllowChangeKeyMetadataInSubclass.class); + } + + @Override + Mutations getMutations() { + Mutations m = new Mutations(); + m.addDeleter(new Deleter(NAME, 0, "dropField")); + m.addRenamer(new Renamer(NAME, 0, "toBeRenamedField", + "renamedField")); + return m; + } + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkNonEntity(true, model, env, NAME, 1); + checkEntity(true, model, env, NAME2, 0, null); + if (oldTypesExist) { + checkVersions(model, NAME, 1, NAME, 0); + checkVersions(model, NAME2, 0); + } else { + checkVersions(model, NAME, 1); + checkVersions(model, NAME2, 0); + } + } + + @Override + void readObjects(EntityStore store, boolean doUpdate) + throws DatabaseException { + + PrimaryIndex<Integer,AllowChangeKeyMetadataEntity> + index = store.getPrimaryIndex + (Integer.class, + AllowChangeKeyMetadataEntity.class); + AllowChangeKeyMetadataEntity obj = index.get(99); + checkValues(obj); + + checkValues(store.getSecondaryIndex + (index, Integer.class, "addAnnotation").get(88)); + checkValues(store.getSecondaryIndex + (index, Integer.class, "renamedField").get(44)); + if (updated) { + checkValues(store.getSecondaryIndex + (index, Integer.class, "addField").get(55)); + } else { + TestCase.assertNull(store.getSecondaryIndex + (index, Integer.class, "addField").get(55)); + } + + if (doUpdate) { + ((AllowChangeKeyMetadataInSubclass) obj).addField = 55; + index.put(obj); + updated = true; + checkValues(store.getSecondaryIndex + (index, Integer.class, "addAnnotation").get(88)); + checkValues(store.getSecondaryIndex + (index, Integer.class, "addField").get(55)); + } + } + + @Override + void copyRawObjects(RawStore rawStore, EntityStore newStore) + throws DatabaseException { + + PrimaryIndex<Integer,AllowChangeKeyMetadataEntity> + index = newStore.getPrimaryIndex + (Integer.class, + AllowChangeKeyMetadataEntity.class); + RawObject raw = rawStore.getPrimaryIndex(NAME2).get(99); + index.put((AllowChangeKeyMetadataInSubclass) + newStore.getModel().convertRawObject(raw)); + } + + private void checkValues(AllowChangeKeyMetadataEntity objParam) { + AllowChangeKeyMetadataInSubclass obj = + (AllowChangeKeyMetadataInSubclass) objParam; + TestCase.assertNotNull(obj); + TestCase.assertEquals(99, obj.key); + TestCase.assertEquals(88, obj.addAnnotation); + TestCase.assertEquals(66, obj.dropAnnotation); + TestCase.assertEquals(44, obj.renamedField); + TestCase.assertEquals(33, obj.aa); + TestCase.assertEquals(22, obj.ff); + if (updated) { + TestCase.assertEquals(Integer.valueOf(55), obj.addField); + } else { + TestCase.assertNull(obj.addField); + } + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + RawObject obj = readRaw + (store, NAME2, 99, NAME, expectEvolved ? 1 : 0, + NAME2, 0, CASECLS, 0); + checkRawFields(obj.getSuper(), "key", 99); + if (expectUpdated) { + checkRawFields(obj, + "addAnnotation", 88, + "dropAnnotation", 66, + "addField", 55, + "renamedField", 44, + "aa", 33, + "ff", 22); + } else if (expectEvolved) { + checkRawFields(obj, + "addAnnotation", 88, + "dropAnnotation", 66, + "renamedField", 44, + "aa", 33, + "ff", 22); + } else { + checkRawFields(obj, + "addAnnotation", 88, + "dropField", 77, + "dropAnnotation", 66, + "toBeRenamedField", 44, + "aa", 33, + "ff", 22); + } + Environment env = store.getEnvironment(); + assertDbExists(expectEvolved, env, NAME2, "addAnnotation"); + assertDbExists(expectEvolved, env, NAME2, "addField"); + assertDbExists(expectEvolved, env, NAME2, "renamedField"); + assertDbExists(!expectEvolved, env, NAME2, "toBeRenamedField"); + assertDbExists(!expectEvolved, env, NAME2, "dropField"); + assertDbExists(!expectEvolved, env, NAME2, "dropAnnotation"); + } + } + + @Entity + static class AllowChangeKeyMetadataEntity + extends EvolveCase { + + @PrimaryKey + int key; + } + + /** + * Special case of adding secondaries that caused + * IndexOutOfBoundsException. [#15524] + */ + @Entity(version=1) + static class AllowAddSecondary + extends EvolveCase { + + private static final String NAME = + AllowAddSecondary.class.getName(); + + @PrimaryKey + long key; + + @SecondaryKey(relate=ONE_TO_ONE) + int a; + + @SecondaryKey(relate=ONE_TO_ONE) + int b; + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkEntity(true, model, env, NAME, 1, null); + if (oldTypesExist) { + checkVersions(model, NAME, 1, NAME, 0); + } else { + checkVersions(model, NAME, 1); + } + } + + @Override + void readObjects(EntityStore store, boolean doUpdate) + throws DatabaseException { + + PrimaryIndex<Long,AllowAddSecondary> + index = store.getPrimaryIndex + (Long.class, + AllowAddSecondary.class); + AllowAddSecondary obj = index.get(99L); + checkValues(obj); + + checkValues(store.getSecondaryIndex + (index, Integer.class, "a").get(1)); + if (updated) { + checkValues(store.getSecondaryIndex + (index, Integer.class, "b").get(3)); + TestCase.assertNull(store.getSecondaryIndex + (index, Integer.class, "b").get(2)); + } else { + checkValues(store.getSecondaryIndex + (index, Integer.class, "b").get(2)); + TestCase.assertNull(store.getSecondaryIndex + (index, Integer.class, "b").get(3)); + } + + if (doUpdate) { + obj.b = 3; + index.put(obj); + updated = true; + checkValues(store.getSecondaryIndex + (index, Integer.class, "a").get(1)); + checkValues(store.getSecondaryIndex + (index, Integer.class, "b").get(3)); + } + } + + @Override + void copyRawObjects(RawStore rawStore, EntityStore newStore) + throws DatabaseException { + + PrimaryIndex<Long,AllowAddSecondary> + index = newStore.getPrimaryIndex + (Long.class, + AllowAddSecondary.class); + RawObject raw = rawStore.getPrimaryIndex(NAME).get(99L); + index.put((AllowAddSecondary) + newStore.getModel().convertRawObject(raw)); + } + + private void checkValues(AllowAddSecondary obj) { + TestCase.assertNotNull(obj); + TestCase.assertEquals(99L, obj.key); + TestCase.assertEquals(1, obj.a); + if (updated) { + TestCase.assertEquals(3, obj.b); + } else { + TestCase.assertEquals(2, obj.b); + } + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + RawObject obj = readRaw + (store, 99L, NAME, expectEvolved ? 1 : 0, CASECLS, 0); + if (expectUpdated) { + checkRawFields(obj, "key", 99L, + "a", 1, + "b", 3); + } else { + checkRawFields(obj, "key", 99L, + "a", 1, + "b", 2); + } + Environment env = store.getEnvironment(); + assertDbExists(expectEvolved, env, NAME, "a"); + assertDbExists(expectEvolved, env, NAME, "b"); + } + } + + @Entity(version=1) + static class FieldAddAndConvert + extends EvolveCase { + + private static final String NAME = + FieldAddAndConvert.class.getName(); + + @PrimaryKey + int key; + + private final String f0 = "0"; // new field + private final String f1 = "1"; // converted field + private final String f2 = "2"; // new field + private final String f3 = "3"; // converted field + private final String f4 = "4"; // new field + + @Override + Mutations getMutations() { + Mutations m = new Mutations(); + m.addConverter(new Converter(NAME, 0, "f1", new IntToString())); + m.addConverter(new Converter(NAME, 0, "f3", new IntToString())); + return m; + } + + @SuppressWarnings("serial") + private static class IntToString implements Conversion { + + public void initialize(EntityModel model) { + } + + public Object convert(Object fromValue) { + return fromValue.toString(); + } + + @Override + public boolean equals(Object other) { + return other instanceof IntToString; + } + } + + @Override + void checkEvolvedModel(EntityModel model, + Environment env, + boolean oldTypesExist) { + checkEntity(true, model, env, NAME, 1, null); + if (oldTypesExist) { + checkVersions(model, NAME, 1, NAME, 0); + } else { + checkVersions(model, NAME, 1); + } + } + + @Override + void readObjects(EntityStore store, boolean doUpdate) + throws DatabaseException { + + PrimaryIndex<Integer,FieldAddAndConvert> + index = store.getPrimaryIndex + (Integer.class, + FieldAddAndConvert.class); + FieldAddAndConvert obj = index.get(99); + TestCase.assertNotNull(obj); + TestCase.assertEquals(99, obj.key); + TestCase.assertEquals("0", obj.f0); + TestCase.assertEquals("1", obj.f1); + TestCase.assertEquals("2", obj.f2); + TestCase.assertEquals("3", obj.f3); + TestCase.assertEquals("4", obj.f4); + + if (doUpdate) { + index.put(obj); + } + } + + @Override + void copyRawObjects(RawStore rawStore, EntityStore newStore) + throws DatabaseException { + + PrimaryIndex<Integer,FieldAddAndConvert> + index = newStore.getPrimaryIndex + (Integer.class, + FieldAddAndConvert.class); + RawObject raw = rawStore.getPrimaryIndex(NAME).get(99); + index.put((FieldAddAndConvert) + newStore.getModel().convertRawObject(raw)); + } + + @Override + void readRawObjects(RawStore store, + boolean expectEvolved, + boolean expectUpdated) + throws DatabaseException { + + RawObject obj = readRaw + (store, 99, NAME, expectEvolved ? 1 : 0, CASECLS, 0); + if (expectUpdated) { + checkRawFields(obj, + "key", 99, + "f0", "0", + "f1", "1", + "f2", "2", + "f3", "3", + "f4", "4"); + } else if (expectEvolved) { + checkRawFields(obj, + "key", 99, + "f1", "1", + "f3", "3"); + } else { + checkRawFields(obj, + "key", 99, + "f1", 1, + "f3", 3); + } + } + } +} diff --git a/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/EvolveClasses.java.original b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/EvolveClasses.java.original new file mode 100644 index 0000000..c077920 --- /dev/null +++ b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/EvolveClasses.java.original @@ -0,0 +1,2855 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2000-2009 Oracle. All rights reserved. + * + * $Id$ + */ +package com.sleepycat.persist.test; + +import static com.sleepycat.persist.model.Relationship.MANY_TO_ONE; + +import java.math.BigInteger; + +import junit.framework.TestCase; + +import com.sleepycat.db.Environment; +import com.sleepycat.db.DatabaseException; +import com.sleepycat.persist.EntityStore; +import com.sleepycat.persist.PrimaryIndex; +import com.sleepycat.persist.SecondaryIndex; +import com.sleepycat.persist.StoreConfig; +import com.sleepycat.persist.evolve.Mutations; +import com.sleepycat.persist.model.Entity; +import com.sleepycat.persist.model.EntityModel; +import com.sleepycat.persist.model.KeyField; +import com.sleepycat.persist.model.Persistent; +import com.sleepycat.persist.model.PersistentProxy; +import com.sleepycat.persist.model.PrimaryKey; +import com.sleepycat.persist.model.SecondaryKey; +import com.sleepycat.persist.raw.RawStore; + +import static com.sleepycat.persist.model.Relationship.ONE_TO_ONE; + +/** + * Nested classes are original versions of classes of the same name in + * EvolveClasses.java. See EvolveTestBase.java for the steps that are taken to + * add a new class (test case). + * + * @author Mark Hayes + */ +class EvolveClasses { + + @Entity + static class DeletedEntity1_ClassRemoved extends EvolveCase { + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + int skey = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DeletedEntity1_ClassRemoved> index = + store.getPrimaryIndex + (Integer.class, DeletedEntity1_ClassRemoved.class); + index.put(this); + + SecondaryIndex<Integer,Integer,DeletedEntity1_ClassRemoved> + sindex = store.getSecondaryIndex(index, Integer.class, "skey"); + TestCase.assertNotNull(sindex.get(88)); + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + assertDbExists + (true, env, + DeletedEntity1_ClassRemoved.class.getName()); + assertDbExists + (true, env, + DeletedEntity1_ClassRemoved.class.getName(), "skey"); + } + } + + @Entity + static class DeletedEntity2_ClassRemoved extends EvolveCase { + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + int skey = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DeletedEntity2_ClassRemoved> index = + store.getPrimaryIndex + (Integer.class, DeletedEntity2_ClassRemoved.class); + index.put(this); + + SecondaryIndex<Integer,Integer,DeletedEntity2_ClassRemoved> + sindex = store.getSecondaryIndex(index, Integer.class, "skey"); + TestCase.assertNotNull(sindex.get(88)); + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + assertDbExists + (true, env, + DeletedEntity2_ClassRemoved.class.getName()); + assertDbExists + (true, env, + DeletedEntity2_ClassRemoved.class.getName(), "skey"); + } + } + + @Entity + static class DeletedEntity3_AnnotRemoved_NoMutation extends EvolveCase { + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + int skey = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DeletedEntity3_AnnotRemoved_NoMutation> + index = store.getPrimaryIndex + (Integer.class, + DeletedEntity3_AnnotRemoved_NoMutation.class); + index.put(this); + + SecondaryIndex<Integer,Integer, + DeletedEntity3_AnnotRemoved_NoMutation> + sindex = store.getSecondaryIndex(index, Integer.class, "skey"); + TestCase.assertNotNull(sindex.get(88)); + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + assertDbExists + (true, env, + DeletedEntity3_AnnotRemoved_NoMutation.class.getName()); + assertDbExists + (true, env, + DeletedEntity3_AnnotRemoved_NoMutation.class.getName(), + "skey"); + } + } + + @Entity + static class DeletedEntity4_AnnotRemoved_WithDeleter extends EvolveCase { + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + int skey = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DeletedEntity4_AnnotRemoved_WithDeleter> + index = store.getPrimaryIndex + (Integer.class, + DeletedEntity4_AnnotRemoved_WithDeleter.class); + index.put(this); + + SecondaryIndex<Integer,Integer, + DeletedEntity4_AnnotRemoved_WithDeleter> + sindex = store.getSecondaryIndex(index, Integer.class, "skey"); + TestCase.assertNotNull(sindex.get(88)); + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + assertDbExists + (true, env, + DeletedEntity4_AnnotRemoved_WithDeleter.class.getName()); + assertDbExists + (true, env, + DeletedEntity4_AnnotRemoved_WithDeleter.class.getName(), + "skey"); + } + } + + @Entity + static class DeletedEntity5_EntityToPersist_NoMutation extends EvolveCase { + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + int skey = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DeletedEntity5_EntityToPersist_NoMutation> + index = store.getPrimaryIndex + (Integer.class, + DeletedEntity5_EntityToPersist_NoMutation.class); + index.put(this); + + SecondaryIndex<Integer,Integer, + DeletedEntity5_EntityToPersist_NoMutation> + sindex = store.getSecondaryIndex(index, Integer.class, "skey"); + TestCase.assertNotNull(sindex.get(88)); + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + assertDbExists + (true, env, + DeletedEntity5_EntityToPersist_NoMutation.class.getName()); + assertDbExists + (true, env, + DeletedEntity5_EntityToPersist_NoMutation.class.getName(), + "skey"); + } + } + + @Entity + static class DeletedEntity6_EntityToPersist_WithDeleter extends EvolveCase { + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + int skey = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DeletedEntity6_EntityToPersist_WithDeleter> + index = store.getPrimaryIndex + (Integer.class, + DeletedEntity6_EntityToPersist_WithDeleter.class); + index.put(this); + + SecondaryIndex<Integer,Integer, + DeletedEntity6_EntityToPersist_WithDeleter> + sindex = store.getSecondaryIndex(index, Integer.class, "skey"); + TestCase.assertNotNull(sindex.get(88)); + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + assertDbExists + (true, env, + DeletedEntity6_EntityToPersist_WithDeleter.class.getName()); + assertDbExists + (true, env, + DeletedEntity6_EntityToPersist_WithDeleter.class.getName(), + "skey"); + } + } + + @Persistent + static class DeletedPersist1_ClassRemoved { + + int f = 123; + } + + @Entity + static class DeletedPersist1_ClassRemoved_NoMutation extends EvolveCase { + + @PrimaryKey + int key = 99; + + DeletedPersist1_ClassRemoved embed = + new DeletedPersist1_ClassRemoved(); + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DeletedPersist1_ClassRemoved_NoMutation> + index = store.getPrimaryIndex + (Integer.class, + DeletedPersist1_ClassRemoved_NoMutation.class); + index.put(this); + } + } + + @Persistent + static class DeletedPersist2_ClassRemoved { + + int f = 123; + } + + @Entity + static class DeletedPersist2_ClassRemoved_WithDeleter extends EvolveCase { + + @PrimaryKey + int key = 99; + + DeletedPersist2_ClassRemoved embed = + new DeletedPersist2_ClassRemoved(); + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DeletedPersist2_ClassRemoved_WithDeleter> + index = store.getPrimaryIndex + (Integer.class, + DeletedPersist2_ClassRemoved_WithDeleter.class); + index.put(this); + } + } + + @Persistent + static class DeletedPersist3_AnnotRemoved { + + int f = 123; + } + + @Entity + static class DeletedPersist3_AnnotRemoved_NoMutation extends EvolveCase { + + @PrimaryKey + int key = 99; + + DeletedPersist3_AnnotRemoved embed = + new DeletedPersist3_AnnotRemoved(); + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DeletedPersist3_AnnotRemoved_NoMutation> + index = store.getPrimaryIndex + (Integer.class, + DeletedPersist3_AnnotRemoved_NoMutation.class); + index.put(this); + } + } + + @Persistent + static class DeletedPersist4_AnnotRemoved { + + int f = 123; + } + + @Entity + static class DeletedPersist4_AnnotRemoved_WithDeleter extends EvolveCase { + + @PrimaryKey + int key = 99; + + DeletedPersist4_AnnotRemoved embed = + new DeletedPersist4_AnnotRemoved(); + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DeletedPersist4_AnnotRemoved_WithDeleter> + index = store.getPrimaryIndex + (Integer.class, + DeletedPersist4_AnnotRemoved_WithDeleter.class); + index.put(this); + } + } + + @Persistent + static class DeletedPersist5_PersistToEntity { + + int f = 123; + } + + @Entity + static class DeletedPersist5_PersistToEntity_NoMutation + extends EvolveCase { + + @PrimaryKey + int key = 99; + + DeletedPersist5_PersistToEntity embed = + new DeletedPersist5_PersistToEntity(); + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DeletedPersist5_PersistToEntity_NoMutation> + index = store.getPrimaryIndex + (Integer.class, + DeletedPersist5_PersistToEntity_NoMutation.class); + index.put(this); + } + } + + @Persistent + static class DeletedPersist6_PersistToEntity { + + int f = 123; + } + + @Entity + static class DeletedPersist6_PersistToEntity_WithDeleter + extends EvolveCase { + + @PrimaryKey + int key = 99; + + DeletedPersist6_PersistToEntity embed = + new DeletedPersist6_PersistToEntity(); + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DeletedPersist6_PersistToEntity_WithDeleter> + index = store.getPrimaryIndex + (Integer.class, + DeletedPersist6_PersistToEntity_WithDeleter.class); + index.put(this); + } + } + + @Entity + static class RenamedEntity1_NewEntityName + extends EvolveCase { + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + int skey = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,RenamedEntity1_NewEntityName> + index = store.getPrimaryIndex + (Integer.class, RenamedEntity1_NewEntityName.class); + index.put(this); + + SecondaryIndex<Integer,Integer,RenamedEntity1_NewEntityName> + sindex = store.getSecondaryIndex(index, Integer.class, "skey"); + TestCase.assertNotNull(sindex.get(88)); + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + assertDbExists + (true, env, + RenamedEntity1_NewEntityName.class.getName()); + assertDbExists + (true, env, + RenamedEntity1_NewEntityName.class.getName(), "skey"); + } + } + + @Entity + static class RenamedEntity2_NewEntityName + extends EvolveCase { + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + int skey = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,RenamedEntity2_NewEntityName> + index = store.getPrimaryIndex + (Integer.class, RenamedEntity2_NewEntityName.class); + index.put(this); + + SecondaryIndex<Integer,Integer,RenamedEntity2_NewEntityName> + sindex = store.getSecondaryIndex(index, Integer.class, "skey"); + TestCase.assertNotNull(sindex.get(88)); + } + + @Override + void checkUnevolvedModel(EntityModel model, Environment env) { + assertDbExists + (true, env, + RenamedEntity2_NewEntityName.class.getName()); + assertDbExists + (true, env, + RenamedEntity2_NewEntityName.class.getName(), "skey"); + } + } + + @Persistent + static class DeleteSuperclass1_BaseClass + extends EvolveCase { + + int f = 123; + } + + @Entity + static class DeleteSuperclass1_NoMutation + extends DeleteSuperclass1_BaseClass { + + @PrimaryKey + int key = 99; + + int ff = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DeleteSuperclass1_NoMutation> + index = store.getPrimaryIndex + (Integer.class, + DeleteSuperclass1_NoMutation.class); + index.put(this); + } + } + + @Persistent + static class DeleteSuperclass2_BaseClass + extends EvolveCase { + + int f = 123; + + @SecondaryKey(relate=ONE_TO_ONE) + int skey = 456; + } + + @Entity + static class DeleteSuperclass2_WithConverter + extends DeleteSuperclass2_BaseClass { + + @PrimaryKey + int key = 99; + + int ff = 88; + + @SecondaryKey(relate=ONE_TO_ONE) + int skey2 = 77; + + @SecondaryKey(relate=ONE_TO_ONE) + Integer skey3 = 66; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DeleteSuperclass2_WithConverter> + index = store.getPrimaryIndex + (Integer.class, + DeleteSuperclass2_WithConverter.class); + index.put(this); + } + } + + @Persistent + static class DeleteSuperclass3_BaseClass + extends EvolveCase { + + int f = 123; + + @SecondaryKey(relate=ONE_TO_ONE) + int skey = 456; + } + + @Entity + static class DeleteSuperclass3_WithDeleter + extends DeleteSuperclass3_BaseClass { + + @PrimaryKey + int key = 99; + + int ff = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DeleteSuperclass3_WithDeleter> + index = store.getPrimaryIndex + (Integer.class, + DeleteSuperclass3_WithDeleter.class); + index.put(this); + } + } + + @Persistent + static class DeleteSuperclass4_BaseClass + extends EvolveCase { + } + + @Entity + static class DeleteSuperclass4_NoFields + extends DeleteSuperclass4_BaseClass { + + @PrimaryKey + int key = 99; + + int ff = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DeleteSuperclass4_NoFields> + index = store.getPrimaryIndex + (Integer.class, + DeleteSuperclass4_NoFields.class); + index.put(this); + } + } + + @Persistent + static class DeleteSuperclass5_Embedded_Base { + + int g = 456; + } + + @Persistent + static class DeleteSuperclass5_Embedded + extends DeleteSuperclass5_Embedded_Base { + + int f = 123; + } + + @Entity + static class DeleteSuperclass5_Top + extends EvolveCase { + + @PrimaryKey + int key = 99; + + int ff = 88; + + DeleteSuperclass5_Embedded embed = + new DeleteSuperclass5_Embedded(); + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DeleteSuperclass5_Top> + index = store.getPrimaryIndex + (Integer.class, + DeleteSuperclass5_Top.class); + index.put(this); + } + } + + @Entity + static class InsertSuperclass1_Between + extends EvolveCase { + + @PrimaryKey + int key = 99; + + int ff = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,InsertSuperclass1_Between> + index = store.getPrimaryIndex + (Integer.class, + InsertSuperclass1_Between.class); + index.put(this); + } + } + + @Persistent + static class InsertSuperclass2_Embedded { + + int f = 123; + } + + @Entity + static class InsertSuperclass2_Top + extends EvolveCase { + + @PrimaryKey + int key = 99; + + int ff = 88; + + InsertSuperclass2_Embedded embed = + new InsertSuperclass2_Embedded(); + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,InsertSuperclass2_Top> + index = store.getPrimaryIndex + (Integer.class, + InsertSuperclass2_Top.class); + index.put(this); + } + } + + /* + @Persistent + static class RenameFields1_Base + extends EvolveCase { + + int f = 123; + } + + @Entity + static class RenameFields1 + extends RenameFields1_Base { + + @PrimaryKey + int key = 99; + + int ff = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,RenameFields1> + index = store.getPrimaryIndex + (Integer.class, + RenameFields1.class); + index.put(this); + } + } + */ + + @Entity + static class DisallowNonKeyField_PrimitiveToObject + extends EvolveCase { + + @PrimaryKey + int key = 99; + + int ff = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowNonKeyField_PrimitiveToObject> + index = store.getPrimaryIndex + (Integer.class, + DisallowNonKeyField_PrimitiveToObject.class); + index.put(this); + } + } + + @Entity + static class DisallowNonKeyField_ObjectToPrimitive + extends EvolveCase { + + @PrimaryKey + int key = 99; + + String ff = "88"; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowNonKeyField_ObjectToPrimitive> + index = store.getPrimaryIndex + (Integer.class, + DisallowNonKeyField_ObjectToPrimitive.class); + index.put(this); + } + } + + @Persistent + static class MyType { + + @Override + public boolean equals(Object o) { + return o instanceof MyType; + } + } + + @Persistent + static class MySubtype extends MyType { + + @Override + public boolean equals(Object o) { + return o instanceof MySubtype; + } + } + + @Entity + static class DisallowNonKeyField_ObjectToSubtype + extends EvolveCase { + + @PrimaryKey + int key = 99; + + MyType ff = new MyType(); + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowNonKeyField_ObjectToSubtype> + index = store.getPrimaryIndex + (Integer.class, + DisallowNonKeyField_ObjectToSubtype.class); + index.put(this); + } + } + + @Entity + static class DisallowNonKeyField_ObjectToUnrelatedSimple + extends EvolveCase { + + @PrimaryKey + int key = 99; + + Integer ff = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowNonKeyField_ObjectToUnrelatedSimple> + index = store.getPrimaryIndex + (Integer.class, + DisallowNonKeyField_ObjectToUnrelatedSimple.class); + index.put(this); + } + } + + @Entity + static class DisallowNonKeyField_ObjectToUnrelatedOther + extends EvolveCase { + + @PrimaryKey + int key = 99; + + Integer ff = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowNonKeyField_ObjectToUnrelatedOther> + index = store.getPrimaryIndex + (Integer.class, + DisallowNonKeyField_ObjectToUnrelatedOther.class); + index.put(this); + } + } + + @Entity + static class DisallowNonKeyField_byte2boolean + extends EvolveCase { + + @PrimaryKey + int key = 99; + + byte ff = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowNonKeyField_byte2boolean> + index = store.getPrimaryIndex + (Integer.class, + DisallowNonKeyField_byte2boolean.class); + index.put(this); + } + } + + @Entity + static class DisallowNonKeyField_short2byte + extends EvolveCase { + + @PrimaryKey + int key = 99; + + short ff = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowNonKeyField_short2byte> + index = store.getPrimaryIndex + (Integer.class, + DisallowNonKeyField_short2byte.class); + index.put(this); + } + } + + @Entity + static class DisallowNonKeyField_int2short + extends EvolveCase { + + @PrimaryKey + int key = 99; + + int ff = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowNonKeyField_int2short> + index = store.getPrimaryIndex + (Integer.class, + DisallowNonKeyField_int2short.class); + index.put(this); + } + } + + @Entity + static class DisallowNonKeyField_long2int + extends EvolveCase { + + @PrimaryKey + int key = 99; + + long ff = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowNonKeyField_long2int> + index = store.getPrimaryIndex + (Integer.class, + DisallowNonKeyField_long2int.class); + index.put(this); + } + } + + @Entity + static class DisallowNonKeyField_float2long + extends EvolveCase { + + @PrimaryKey + int key = 99; + + float ff = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowNonKeyField_float2long> + index = store.getPrimaryIndex + (Integer.class, + DisallowNonKeyField_float2long.class); + index.put(this); + } + } + + @Entity + static class DisallowNonKeyField_double2float + extends EvolveCase { + + @PrimaryKey + int key = 99; + + double ff = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowNonKeyField_double2float> + index = store.getPrimaryIndex + (Integer.class, + DisallowNonKeyField_double2float.class); + index.put(this); + } + } + + @Entity + static class DisallowNonKeyField_Byte2byte + extends EvolveCase { + + @PrimaryKey + int key = 99; + + Byte ff = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowNonKeyField_Byte2byte> + index = store.getPrimaryIndex + (Integer.class, + DisallowNonKeyField_Byte2byte.class); + index.put(this); + } + } + + @Entity + static class DisallowNonKeyField_Character2char + extends EvolveCase { + + @PrimaryKey + int key = 99; + + Character ff = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowNonKeyField_Character2char> + index = store.getPrimaryIndex + (Integer.class, + DisallowNonKeyField_Character2char.class); + index.put(this); + } + } + + @Entity + static class DisallowNonKeyField_Short2short + extends EvolveCase { + + @PrimaryKey + int key = 99; + + Short ff = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowNonKeyField_Short2short> + index = store.getPrimaryIndex + (Integer.class, + DisallowNonKeyField_Short2short.class); + index.put(this); + } + } + + @Entity + static class DisallowNonKeyField_Integer2int + extends EvolveCase { + + @PrimaryKey + int key = 99; + + Integer ff = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowNonKeyField_Integer2int> + index = store.getPrimaryIndex + (Integer.class, + DisallowNonKeyField_Integer2int.class); + index.put(this); + } + } + + @Entity + static class DisallowNonKeyField_Long2long + extends EvolveCase { + + @PrimaryKey + int key = 99; + + Long ff = 88L; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowNonKeyField_Long2long> + index = store.getPrimaryIndex + (Integer.class, + DisallowNonKeyField_Long2long.class); + index.put(this); + } + } + + @Entity + static class DisallowNonKeyField_Float2float + extends EvolveCase { + + @PrimaryKey + int key = 99; + + Float ff = 88F; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowNonKeyField_Float2float> + index = store.getPrimaryIndex + (Integer.class, + DisallowNonKeyField_Float2float.class); + index.put(this); + } + } + + @Entity + static class DisallowNonKeyField_Double2double + extends EvolveCase { + + @PrimaryKey + int key = 99; + + Double ff = 88D; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowNonKeyField_Double2double> + index = store.getPrimaryIndex + (Integer.class, + DisallowNonKeyField_Double2double.class); + index.put(this); + } + } + + @Entity + static class DisallowNonKeyField_float2BigInt + extends EvolveCase { + + @PrimaryKey + int key = 99; + + float ff = 88F; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowNonKeyField_float2BigInt> + index = store.getPrimaryIndex + (Integer.class, + DisallowNonKeyField_float2BigInt.class); + index.put(this); + } + } + + @Entity + static class DisallowNonKeyField_BigInt2long + extends EvolveCase { + + @PrimaryKey + int key = 99; + + BigInteger ff = BigInteger.valueOf(88); + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowNonKeyField_BigInt2long> + index = store.getPrimaryIndex + (Integer.class, + DisallowNonKeyField_BigInt2long.class); + index.put(this); + } + } + + @Entity + static class DisallowSecKeyField_byte2short + extends EvolveCase { + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + byte ff = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowSecKeyField_byte2short> + index = store.getPrimaryIndex + (Integer.class, + DisallowSecKeyField_byte2short.class); + index.put(this); + } + } + + @Entity + static class DisallowSecKeyField_char2int + extends EvolveCase { + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + char ff = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowSecKeyField_char2int> + index = store.getPrimaryIndex + (Integer.class, + DisallowSecKeyField_char2int.class); + index.put(this); + } + } + + @Entity + static class DisallowSecKeyField_short2int + extends EvolveCase { + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + short ff = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowSecKeyField_short2int> + index = store.getPrimaryIndex + (Integer.class, + DisallowSecKeyField_short2int.class); + index.put(this); + } + } + + @Entity + static class DisallowSecKeyField_int2long + extends EvolveCase { + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + int ff = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowSecKeyField_int2long> + index = store.getPrimaryIndex + (Integer.class, + DisallowSecKeyField_int2long.class); + index.put(this); + } + } + + @Entity + static class DisallowSecKeyField_long2float + extends EvolveCase { + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + long ff = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowSecKeyField_long2float> + index = store.getPrimaryIndex + (Integer.class, + DisallowSecKeyField_long2float.class); + index.put(this); + } + } + + @Entity + static class DisallowSecKeyField_float2double + extends EvolveCase { + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + float ff = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowSecKeyField_float2double> + index = store.getPrimaryIndex + (Integer.class, + DisallowSecKeyField_float2double.class); + index.put(this); + } + } + + @Entity + static class DisallowSecKeyField_Byte2short2 + extends EvolveCase { + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + Byte ff = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowSecKeyField_Byte2short2> + index = store.getPrimaryIndex + (Integer.class, + DisallowSecKeyField_Byte2short2.class); + index.put(this); + } + } + + @Entity + static class DisallowSecKeyField_Character2int + extends EvolveCase { + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + Character ff = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowSecKeyField_Character2int> + index = store.getPrimaryIndex + (Integer.class, + DisallowSecKeyField_Character2int.class); + index.put(this); + } + } + + @Entity + static class DisallowSecKeyField_Short2int2 + extends EvolveCase { + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + Short ff = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowSecKeyField_Short2int2> + index = store.getPrimaryIndex + (Integer.class, + DisallowSecKeyField_Short2int2.class); + index.put(this); + } + } + + @Entity + static class DisallowSecKeyField_Integer2long + extends EvolveCase { + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + Integer ff = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowSecKeyField_Integer2long> + index = store.getPrimaryIndex + (Integer.class, + DisallowSecKeyField_Integer2long.class); + index.put(this); + } + } + + @Entity + static class DisallowSecKeyField_Long2float2 + extends EvolveCase { + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + Long ff = 88L; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowSecKeyField_Long2float2> + index = store.getPrimaryIndex + (Integer.class, + DisallowSecKeyField_Long2float2.class); + index.put(this); + } + } + + @Entity + static class DisallowSecKeyField_Float2double2 + extends EvolveCase { + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + Float ff = 88F; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowSecKeyField_Float2double2> + index = store.getPrimaryIndex + (Integer.class, + DisallowSecKeyField_Float2double2.class); + index.put(this); + } + } + + @Entity + static class DisallowSecKeyField_int2BigInt + extends EvolveCase { + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + int ff = 88; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowSecKeyField_int2BigInt> + index = store.getPrimaryIndex + (Integer.class, + DisallowSecKeyField_int2BigInt.class); + index.put(this); + } + } + + // -- + + @Entity + static class DisallowPriKeyField_byte2short + extends EvolveCase { + + @PrimaryKey + byte key = 99; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Byte,DisallowPriKeyField_byte2short> + index = store.getPrimaryIndex + (Byte.class, + DisallowPriKeyField_byte2short.class); + index.put(this); + } + } + + @Entity + static class DisallowPriKeyField_char2int + extends EvolveCase { + + @PrimaryKey + char key = 99; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Character,DisallowPriKeyField_char2int> + index = store.getPrimaryIndex + (Character.class, + DisallowPriKeyField_char2int.class); + index.put(this); + } + } + + @Entity + static class DisallowPriKeyField_short2int + extends EvolveCase { + + @PrimaryKey + short key = 99; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Short,DisallowPriKeyField_short2int> + index = store.getPrimaryIndex + (Short.class, + DisallowPriKeyField_short2int.class); + index.put(this); + } + } + + @Entity + static class DisallowPriKeyField_int2long + extends EvolveCase { + + @PrimaryKey + int key = 99; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowPriKeyField_int2long> + index = store.getPrimaryIndex + (Integer.class, + DisallowPriKeyField_int2long.class); + index.put(this); + } + } + + @Entity + static class DisallowPriKeyField_long2float + extends EvolveCase { + + @PrimaryKey + long key = 99; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Long,DisallowPriKeyField_long2float> + index = store.getPrimaryIndex + (Long.class, + DisallowPriKeyField_long2float.class); + index.put(this); + } + } + + @Entity + static class DisallowPriKeyField_float2double + extends EvolveCase { + + @PrimaryKey + float key = 99; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Float,DisallowPriKeyField_float2double> + index = store.getPrimaryIndex + (Float.class, + DisallowPriKeyField_float2double.class); + index.put(this); + } + } + + @Entity + static class DisallowPriKeyField_Byte2short2 + extends EvolveCase { + + @PrimaryKey + Byte key = 99; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Byte,DisallowPriKeyField_Byte2short2> + index = store.getPrimaryIndex + (Byte.class, + DisallowPriKeyField_Byte2short2.class); + index.put(this); + } + } + + @Entity + static class DisallowPriKeyField_Character2int + extends EvolveCase { + + @PrimaryKey + Character key = 99; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Character,DisallowPriKeyField_Character2int> + index = store.getPrimaryIndex + (Character.class, + DisallowPriKeyField_Character2int.class); + index.put(this); + } + } + + @Entity + static class DisallowPriKeyField_Short2int2 + extends EvolveCase { + + @PrimaryKey + Short key = 99; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Short,DisallowPriKeyField_Short2int2> + index = store.getPrimaryIndex + (Short.class, + DisallowPriKeyField_Short2int2.class); + index.put(this); + } + } + + @Entity + static class DisallowPriKeyField_Integer2long + extends EvolveCase { + + @PrimaryKey + Integer key = 99; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowPriKeyField_Integer2long> + index = store.getPrimaryIndex + (Integer.class, + DisallowPriKeyField_Integer2long.class); + index.put(this); + } + } + + @Entity + static class DisallowPriKeyField_Long2float2 + extends EvolveCase { + + @PrimaryKey + Long key = 99L; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Long,DisallowPriKeyField_Long2float2> + index = store.getPrimaryIndex + (Long.class, + DisallowPriKeyField_Long2float2.class); + index.put(this); + } + } + + @Entity + static class DisallowPriKeyField_Float2double2 + extends EvolveCase { + + @PrimaryKey + Float key = 99F; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Float,DisallowPriKeyField_Float2double2> + index = store.getPrimaryIndex + (Float.class, + DisallowPriKeyField_Float2double2.class); + index.put(this); + } + } + + @Entity + static class DisallowPriKeyField_Long2BigInt + extends EvolveCase { + + @PrimaryKey + Long key = 99L; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Long,DisallowPriKeyField_Long2BigInt> + index = store.getPrimaryIndex + (Long.class, + DisallowPriKeyField_Long2BigInt.class); + index.put(this); + } + } + + @Persistent + static class DisallowCompositeKeyField_byte2short_Key { + + @KeyField(1) + int f1 = 1; + + @KeyField(2) + byte f2 = 2; + + @KeyField(3) + String f3 = "3"; + } + + @Entity + static class DisallowCompositeKeyField_byte2short + extends EvolveCase { + + @PrimaryKey + DisallowCompositeKeyField_byte2short_Key key = + new DisallowCompositeKeyField_byte2short_Key(); + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<DisallowCompositeKeyField_byte2short_Key, + DisallowCompositeKeyField_byte2short> + index = store.getPrimaryIndex + (DisallowCompositeKeyField_byte2short_Key.class, + DisallowCompositeKeyField_byte2short.class); + index.put(this); + } + } + + @Entity + static class AllowPriKeyField_byte2Byte + extends EvolveCase { + + @PrimaryKey + byte key = 99; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Byte,AllowPriKeyField_byte2Byte> + index = store.getPrimaryIndex + (Byte.class, AllowPriKeyField_byte2Byte.class); + index.put(this); + } + } + + @Entity + static class AllowPriKeyField_Byte2byte2 + extends EvolveCase { + + @PrimaryKey + Byte key = 99; + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Byte,AllowPriKeyField_Byte2byte2> + index = store.getPrimaryIndex + (Byte.class, AllowPriKeyField_Byte2byte2.class); + index.put(this); + } + } + + @Persistent + static class AllowFieldTypeChanges_Key { + + AllowFieldTypeChanges_Key() { + this(false); + } + + AllowFieldTypeChanges_Key(boolean init) { + if (init) { + f1 = true; + f2 = (byte) 2; + f3 = (short) 3; + f4 = 4; + f5 = 5L; + f6 = 6F; + f7 = 7D; + f8 = (char) 8; + f9 = true; + f10 = (byte) 10; + f11 = (short) 11; + f12 = 12; + f13 = 13L; + f14 = 14F; + f15 = 15D; + f16 = (char) 16; + } + } + + @KeyField(1) + boolean f1; + + @KeyField(2) + byte f2; + + @KeyField(3) + short f3; + + @KeyField(4) + int f4; + + @KeyField(5) + long f5; + + @KeyField(6) + float f6; + + @KeyField(7) + double f7; + + @KeyField(8) + char f8; + + @KeyField(9) + Boolean f9; + + @KeyField(10) + Byte f10; + + @KeyField(11) + Short f11; + + @KeyField(12) + Integer f12; + + @KeyField(13) + Long f13; + + @KeyField(14) + Float f14; + + @KeyField(15) + Double f15; + + @KeyField(16) + Character f16; + } + + @Persistent + static class AllowFieldTypeChanges_Base + extends EvolveCase { + + @SecondaryKey(relate=ONE_TO_ONE) + AllowFieldTypeChanges_Key kcomposite = + new AllowFieldTypeChanges_Key(true); + + long f_long2Integer = 111; + String f_String2Long = "222"; + } + + @Entity + static class AllowFieldTypeChanges + extends AllowFieldTypeChanges_Base { + + @PrimaryKey + int pkeyint = 99; + + @SecondaryKey(relate=ONE_TO_ONE) + boolean kboolean = true; + + @SecondaryKey(relate=ONE_TO_ONE) + byte kbyte = 77; + + @SecondaryKey(relate=ONE_TO_ONE) + short kshort = 66; + + @SecondaryKey(relate=ONE_TO_ONE) + int kint = 55; + + @SecondaryKey(relate=ONE_TO_ONE) + long klong = 44; + + @SecondaryKey(relate=ONE_TO_ONE) + float kfloat = 33; + + @SecondaryKey(relate=ONE_TO_ONE) + double kdouble = 22; + + @SecondaryKey(relate=ONE_TO_ONE) + char kchar = 11; + + byte f01; + byte f02; + byte f03; + byte f04; + byte f06; + short f07; + short f08; + short f09; + short f10; + char f11; + char f12; + char f13; + char f14; + int f15; + int f16; + int f17; + long f18; + long f19; + float f20; + + byte f21; + byte f22; + byte f23; + byte f24; + byte f26; + short f27; + short f28; + short f29; + short f30; + char f31; + char f32; + char f33; + char f34; + int f35; + int f36; + int f37; + long f38; + long f39; + float f40; + + Byte f41; + Byte f42; + Byte f43; + Byte f44; + Byte f46; + Short f47; + Short f48; + Short f49; + Short f50; + Character f51; + Character f52; + Character f53; + Character f54; + Integer f55; + Integer f56; + Integer f57; + Long f58; + Long f59; + Float f60; + + byte f70; + short f71; + char f72; + int f73; + long f74; + Byte f75; + Short f76; + Character f77; + Integer f78; + Long f79; + + long f_long2int = 333; + String f_String2long = "444"; + + private void init() { + f01 = (byte) 1; + f02 = (byte) 2; + f03 = (byte) 3; + f04 = (byte) 4; + f06 = (byte) 6; + f07 = (short) 7; + f08 = (short) 8; + f09 = (short) 9; + f10 = (short) 10; + f11 = (char) 11; + f12 = (char) 12; + f13 = (char) 13; + f14 = (char) 14; + f15 = 15; + f16 = 16; + f17 = 17; + f18 = (long) 18; + f19 = (long) 19; + f20 = (float) 20; + + f21 = (byte) 21; + f22 = (byte) 22; + f23 = (byte) 23; + f24 = (byte) 24; + f26 = (byte) 26; + f27 = (short) 27; + f28 = (short) 28; + f29 = (short) 29; + f30 = (short) 30; + f31 = (char) 31; + f32 = (char) 32; + f33 = (char) 33; + f34 = (char) 34; + f35 = 35; + f36 = 36; + f37 = 37; + f38 = (long) 38; + f39 = (long) 39; + f40 = (float) 40; + + f41 = (byte) 41; + f42 = (byte) 42; + f43 = (byte) 43; + f44 = (byte) 44; + f46 = (byte) 46; + f47 = (short) 47; + f48 = (short) 48; + f49 = (short) 49; + f50 = (short) 50; + f51 = (char) 51; + f52 = (char) 52; + f53 = (char) 53; + f54 = (char) 54; + f55 = 55; + f56 = 56; + f57 = 57; + f58 = (long) 58; + f59 = (long) 59; + f60 = (float) 60; + + f70 = (byte) 70; + f71 = (short) 71; + f72 = (char) 72; + f73 = 73; + f74 = (long) 74; + f75 = (byte) 75; + f76 = (short) 76; + f77 = (char) 77; + f78 = 78; + f79 = (long) 79; + } + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,AllowFieldTypeChanges> + index = store.getPrimaryIndex + (Integer.class, AllowFieldTypeChanges.class); + init(); + index.put(this); + } + } + + @Entity + static class ConvertFieldContent_Entity + extends EvolveCase { + + @PrimaryKey + int key; + + String f1; + String f2; + + private void init() { + key = 99; + f1 = "01234"; + f2 = "56789"; + } + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,ConvertFieldContent_Entity> + index = store.getPrimaryIndex + (Integer.class, ConvertFieldContent_Entity.class); + init(); + index.put(this); + } + } + + @Persistent + static class ConvertExample1_Address { + String street; + String city; + String state; + String zipCode; + } + + @Entity + static class ConvertExample1_Entity + extends EvolveCase { + + @PrimaryKey + int key; + + ConvertExample1_Address embed; + + private void init() { + key = 99; + embed = new ConvertExample1_Address(); + embed.street = "street"; + embed.city = "city"; + embed.state = "state"; + embed.zipCode = "12345"; + } + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,ConvertExample1_Entity> + index = store.getPrimaryIndex + (Integer.class, ConvertExample1_Entity.class); + init(); + index.put(this); + } + } + + @Entity + static class ConvertExample2_Person + extends EvolveCase { + + @PrimaryKey + int key; + + String address; + + private void init() { + key = 99; + address = "street#city#state#12345"; + } + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,ConvertExample2_Person> + index = store.getPrimaryIndex + (Integer.class, ConvertExample2_Person.class); + init(); + index.put(this); + } + } + + @Entity + static class ConvertExample3_Person + extends EvolveCase { + + @PrimaryKey + int key; + + String street; + String city; + String state; + int zipCode; + + private void init() { + key = 99; + street = "street"; + city = "city"; + state = "state"; + zipCode = 12345; + } + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,ConvertExample3_Person> + index = store.getPrimaryIndex + (Integer.class, ConvertExample3_Person.class); + init(); + index.put(this); + } + } + + @Persistent + static class ConvertExample3Reverse_Address { + String street; + String city; + String state; + int zipCode; + } + + @Entity + static class ConvertExample3Reverse_Person + extends EvolveCase { + + @PrimaryKey + int key; + + ConvertExample3Reverse_Address address; + + private void init() { + key = 99; + address = new ConvertExample3Reverse_Address(); + address.street = "street"; + address.city = "city"; + address.state = "state"; + address.zipCode = 12345; + } + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,ConvertExample3Reverse_Person> + index = store.getPrimaryIndex + (Integer.class, ConvertExample3Reverse_Person.class); + init(); + index.put(this); + } + } + + @Persistent + static class ConvertExample4_A extends ConvertExample4_B { + String name; + } + + @Persistent + static class ConvertExample4_B { + } + + @Entity + static class ConvertExample4_Entity + extends EvolveCase { + + @PrimaryKey + int key; + + ConvertExample4_A embed; + + private void init() { + key = 99; + embed = new ConvertExample4_A(); + embed.name = "name"; + } + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,ConvertExample4_Entity> + index = store.getPrimaryIndex + (Integer.class, ConvertExample4_Entity.class); + init(); + index.put(this); + } + } + + @Persistent + static class ConvertExample5_Pet { + String name; + boolean isCatNotDog; + int finickyLevel; + double barkVolume; + } + + @Entity + static class ConvertExample5_Entity + extends EvolveCase { + + @PrimaryKey + int key; + + ConvertExample5_Pet cat; + ConvertExample5_Pet dog; + + private void init() { + key = 99; + cat = new ConvertExample5_Pet(); + cat.name = "Jeffry"; + cat.isCatNotDog = true; + cat.finickyLevel = 999; + dog = new ConvertExample5_Pet(); + dog.name = "Nelson"; + dog.isCatNotDog = false; + dog.barkVolume = 0.01; + } + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,ConvertExample5_Entity> + index = store.getPrimaryIndex + (Integer.class, ConvertExample5_Entity.class); + init(); + index.put(this); + } + } + + @Persistent + static class AllowFieldAddDelete_Embed { + private int f1 = 1; + private String f2 = "2"; + private String f4 = "4"; + private int f6 = 6; + private String f7 = "7"; + } + + @Persistent + static class AllowFieldAddDelete_Base + extends EvolveCase { + + private int f1 = 1; + private String f2 = "2"; + private String f4 = "4"; + private int f6 = 6; + private String f7 = "7"; + } + + @Entity + static class AllowFieldAddDelete + extends AllowFieldAddDelete_Base { + + @PrimaryKey + int key; + + AllowFieldAddDelete_Embed embed; + + private int f1 = 1; + private String f2 = "2"; + private String f4 = "4"; + private int f6 = 6; + private String f7 = "7"; + + private void init() { + key = 99; + embed = new AllowFieldAddDelete_Embed(); + } + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,AllowFieldAddDelete> + index = store.getPrimaryIndex + (Integer.class, AllowFieldAddDelete.class); + init(); + index.put(this); + } + } + + static class ProxiedClass { + int data; + + ProxiedClass(int data) { + this.data = data; + } + } + + @Persistent(proxyFor=ProxiedClass.class) + static class ProxiedClass_Proxy implements PersistentProxy<ProxiedClass> { + int data; + + public void initializeProxy(ProxiedClass o) { + data = o.data; + } + + public ProxiedClass convertProxy() { + return new ProxiedClass(data); + } + } + + @Entity + static class ProxiedClass_Entity + extends EvolveCase { + + @PrimaryKey + int key; + + ProxiedClass embed; + + private void init() { + key = 99; + embed = new ProxiedClass(88); + } + + @Override + void configure(EntityModel model, StoreConfig config) { + model.registerClass(ProxiedClass_Proxy.class); + } + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,ProxiedClass_Entity> + index = store.getPrimaryIndex + (Integer.class, ProxiedClass_Entity.class); + init(); + index.put(this); + } + } + + @Persistent(proxyFor=StringBuffer.class) + static class DisallowChangeProxyFor_Proxy + implements PersistentProxy<StringBuffer> { + + String data; + + public void initializeProxy(StringBuffer o) { + data = o.toString(); + } + + public StringBuffer convertProxy() { + return new StringBuffer(data); + } + } + + @Entity + static class DisallowChangeProxyFor + extends EvolveCase { + + @PrimaryKey + int key; + + private void init() { + key = 99; + } + + @Override + void configure(EntityModel model, StoreConfig config) { + model.registerClass(DisallowChangeProxyFor_Proxy.class); + } + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowChangeProxyFor> + index = store.getPrimaryIndex + (Integer.class, DisallowChangeProxyFor.class); + init(); + index.put(this); + } + } + + @Persistent(proxyFor=StringBuffer.class) + static class DisallowDeleteProxyFor_Proxy + implements PersistentProxy<StringBuffer> { + + String data; + + public void initializeProxy(StringBuffer o) { + data = o.toString(); + } + + public StringBuffer convertProxy() { + return new StringBuffer(data); + } + } + + @Entity + static class DisallowDeleteProxyFor + extends EvolveCase { + + @PrimaryKey + int key; + + private void init() { + key = 99; + } + + @Override + void configure(EntityModel model, StoreConfig config) { + model.registerClass(DisallowDeleteProxyFor_Proxy.class); + } + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowDeleteProxyFor> + index = store.getPrimaryIndex + (Integer.class, DisallowDeleteProxyFor.class); + init(); + index.put(this); + } + } + + @Persistent + static class ArrayNameChange_Component { + + int data; + } + + @Entity + static class ArrayNameChange_Entity + extends EvolveCase { + + @PrimaryKey + int key; + + ArrayNameChange_Component[] embed; + ArrayNameChange_Component embed2; + + private void init() { + key = 99; + embed2 = new ArrayNameChange_Component(); + embed2.data = 88; + embed = new ArrayNameChange_Component[] { embed2 }; + } + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,ArrayNameChange_Entity> + index = store.getPrimaryIndex + (Integer.class, ArrayNameChange_Entity.class); + init(); + index.put(this); + } + } + + enum AddEnumConstant_Enum { + A, B; + } + + @Entity + static class AddEnumConstant_Entity + extends EvolveCase { + + @PrimaryKey + int key; + + AddEnumConstant_Enum e1; + AddEnumConstant_Enum e2; + + private void init() { + key = 99; + e1 = AddEnumConstant_Enum.A; + e2 = AddEnumConstant_Enum.B; + } + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,AddEnumConstant_Entity> + index = store.getPrimaryIndex + (Integer.class, AddEnumConstant_Entity.class); + init(); + index.put(this); + } + } + + enum InsertEnumConstant_Enum { + A, B; + } + + @Persistent + static class InsertEnumConstant_KeyClass + implements Comparable<InsertEnumConstant_KeyClass > { + + @KeyField(1) + InsertEnumConstant_Enum key; + + private InsertEnumConstant_KeyClass() {} + + InsertEnumConstant_KeyClass(InsertEnumConstant_Enum key) { + this.key = key; + } + + public int compareTo(InsertEnumConstant_KeyClass o) { + /* Use the natural order, in spite of insertions. */ + return key.compareTo(o.key); + } + } + + @Entity + static class InsertEnumConstant_Entity + extends EvolveCase { + + @PrimaryKey + int key; + + @SecondaryKey(relate=MANY_TO_ONE) + InsertEnumConstant_KeyClass secKey; + + InsertEnumConstant_Enum e1; + InsertEnumConstant_Enum e2; + + private void init() { + key = 99; + secKey = + new InsertEnumConstant_KeyClass(InsertEnumConstant_Enum.A); + e1 = InsertEnumConstant_Enum.A; + e2 = InsertEnumConstant_Enum.B; + } + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,InsertEnumConstant_Entity> + index = store.getPrimaryIndex + (Integer.class, InsertEnumConstant_Entity.class); + init(); + index.put(this); + } + } + + enum DeleteEnumConstant_Enum { + A, B, C; + } + + @Entity + static class DeleteEnumConstant_NoMutation + extends EvolveCase { + + @PrimaryKey + int key; + + DeleteEnumConstant_Enum e1; + DeleteEnumConstant_Enum e2; + DeleteEnumConstant_Enum e3; + + private void init() { + key = 99; + e1 = DeleteEnumConstant_Enum.A; + e2 = DeleteEnumConstant_Enum.B; + e3 = DeleteEnumConstant_Enum.C; + } + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DeleteEnumConstant_NoMutation> + index = store.getPrimaryIndex + (Integer.class, DeleteEnumConstant_NoMutation.class); + init(); + index.put(this); + } + } + + /* Disabled until support for enum deletion is added. + @Entity + static class DeleteEnumConstant_WithConverter + extends EvolveCase { + + @PrimaryKey + int key; + + DeleteEnumConstant_Enum e1; + DeleteEnumConstant_Enum e2; + DeleteEnumConstant_Enum e3; + + private void init() { + key = 99; + e1 = DeleteEnumConstant_Enum.A; + e2 = DeleteEnumConstant_Enum.B; + e3 = DeleteEnumConstant_Enum.C; + } + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DeleteEnumConstant_WithConverter> + index = store.getPrimaryIndex + (Integer.class, DeleteEnumConstant_WithConverter.class); + init(); + index.put(this); + } + } + */ + + @Entity + static class DisallowChangeKeyRelate + extends EvolveCase { + + @PrimaryKey + int key; + + @SecondaryKey(relate=ONE_TO_ONE) + int skey; + + private void init() { + key = 99; + skey = 88; + } + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,DisallowChangeKeyRelate> + index = store.getPrimaryIndex + (Integer.class, DisallowChangeKeyRelate.class); + init(); + index.put(this); + } + } + + @Entity + static class AllowChangeKeyMetadata + extends EvolveCase { + + @PrimaryKey + int key; + + int aa; + + int addAnnotation; + + @SecondaryKey(relate=ONE_TO_ONE) + int dropField; + + @SecondaryKey(relate=ONE_TO_ONE) + int dropAnnotation; + + @SecondaryKey(relate=ONE_TO_ONE) + int toBeRenamedField; + + int ff; + + private void init() { + key = 99; + addAnnotation = 88; + dropField = 77; + dropAnnotation = 66; + toBeRenamedField = 44; + aa = 33; + ff = 22; + } + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,AllowChangeKeyMetadata> + index = store.getPrimaryIndex + (Integer.class, AllowChangeKeyMetadata.class); + init(); + index.put(this); + } + } + + /** [#16253] */ + @Persistent + static class AllowChangeKeyMetadataInSubclass + extends AllowChangeKeyMetadataEntity { + + int aa; + + int addAnnotation; + + @SecondaryKey(relate=ONE_TO_ONE) + int dropField; + + @SecondaryKey(relate=ONE_TO_ONE) + int dropAnnotation; + + @SecondaryKey(relate=ONE_TO_ONE) + int toBeRenamedField; + + int ff; + + private void init() { + key = 99; + addAnnotation = 88; + dropField = 77; + dropAnnotation = 66; + toBeRenamedField = 44; + aa = 33; + ff = 22; + } + + @Override + void configure(EntityModel model, StoreConfig config) { + model.registerClass(AllowChangeKeyMetadataInSubclass.class); + } + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,AllowChangeKeyMetadataEntity> + index = store.getPrimaryIndex + (Integer.class, AllowChangeKeyMetadataEntity.class); + init(); + index.put(this); + } + } + + @Entity + static class AllowChangeKeyMetadataEntity + extends EvolveCase { + + @PrimaryKey + int key; + } + + /** [#15524] */ + @Entity + static class AllowAddSecondary + extends EvolveCase { + + @PrimaryKey + long key; + + int a; + int b; + + private void init() { + key = 99; + a = 1; + b = 2; + } + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Long,AllowAddSecondary> + index = store.getPrimaryIndex + (Long.class, AllowAddSecondary.class); + init(); + index.put(this); + } + } + + /** [#15797] */ + @Entity + static class FieldAddAndConvert + extends EvolveCase { + + @PrimaryKey + int key; + + private int f1 = 1; + private int f3 = 3; + + private void init() { + key = 99; + } + + @Override + void writeObjects(EntityStore store) + throws DatabaseException { + + PrimaryIndex<Integer,FieldAddAndConvert> + index = store.getPrimaryIndex + (Integer.class, FieldAddAndConvert.class); + init(); + index.put(this); + } + } +} diff --git a/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/EvolveTest.java b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/EvolveTest.java new file mode 100644 index 0000000..c76a63a --- /dev/null +++ b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/EvolveTest.java @@ -0,0 +1,255 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2000-2009 Oracle. All rights reserved. + * + * $Id$ + */ +package com.sleepycat.persist.test; + +import java.io.IOException; + +import junit.framework.Test; + +import com.sleepycat.persist.evolve.EvolveConfig; +import com.sleepycat.persist.evolve.EvolveEvent; +import com.sleepycat.persist.evolve.EvolveListener; +import com.sleepycat.persist.evolve.EvolveStats; +import com.sleepycat.persist.impl.PersistCatalog; +import com.sleepycat.util.test.SharedTestUtils; + +/** + * Runs part two of the EvolveTest. This part is run with the new/updated + * version of EvolveClasses in the classpath. It uses the environment and + * store created by EvolveTestInit. It verifies that it can read/write/evolve + * objects serialized using the old class format, and that it can create new + * objects with the new class format. + * + * @author Mark Hayes + */ +public class EvolveTest extends EvolveTestBase { + + /* Toggle to use listener every other test case. */ + private static boolean useEvolveListener; + + public static Test suite() + throws Exception { + + return getSuite(EvolveTest.class); + } + + private int evolveNRead; + private int evolveNConverted; + + boolean useEvolvedClass() { + return true; + } + + @Override + public void tearDown() { + try { super.tearDown(); } catch (Throwable e) { } + } + + @Override + public void setUp() + throws IOException { + + /* Copy the log files created by EvolveTestInit. */ + envHome = getTestInitHome(true /*evolved*/); + envHome.mkdirs(); + SharedTestUtils.emptyDir(envHome); + SharedTestUtils.copyFiles(getTestInitHome(false /*evolved*/), envHome); + } + + public void testLazyEvolve() + throws Exception { + + openEnv(); + + /* + * Open in raw mode to check unevolved raw object and formats. This + * is possible whether or not we can open the store further below to + * evolve formats without errors. + */ + openRawStore(); + caseObj.checkUnevolvedModel(rawStore.getModel(), env); + caseObj.readRawObjects + (rawStore, false /*expectEvolved*/, false /*expectUpdated*/); + closeRawStore(); + + if (openStoreReadWrite()) { + + /* + * When opening read-write, formats are evolved lazily. Check by + * reading evolved objects. + */ + caseObj.checkEvolvedModel + (store.getModel(), env, true /*oldTypesExist*/); + caseObj.readObjects(store, false /*doUpdate*/); + closeStore(); + + /* + * Read raw objects again to check that the evolved objects are + * returned even though the stored objects were not evolved. + */ + openRawStore(); + caseObj.checkEvolvedModel + (rawStore.getModel(), env, true /*oldTypesExist*/); + caseObj.readRawObjects + (rawStore, true /*expectEvolved*/, false /*expectUpdated*/); + closeRawStore(); + + /* + * Open read-only to ensure that the catalog does not need to + * change (evolve formats) unnecessarily. + */ + PersistCatalog.expectNoClassChanges = true; + try { + openStoreReadOnly(); + } finally { + PersistCatalog.expectNoClassChanges = false; + } + caseObj.checkEvolvedModel + (store.getModel(), env, true /*oldTypesExist*/); + caseObj.readObjects(store, false /*doUpdate*/); + closeStore(); + + /* + * Open read-write to update objects and store them in evolved + * format. + */ + openStoreReadWrite(); + caseObj.checkEvolvedModel + (store.getModel(), env, true /*oldTypesExist*/); + caseObj.readObjects(store, true /*doUpdate*/); + caseObj.checkEvolvedModel + (store.getModel(), env, true /*oldTypesExist*/); + closeStore(); + + /* + * Check raw objects again after the evolved objects were stored. + */ + openRawStore(); + caseObj.checkEvolvedModel + (rawStore.getModel(), env, true /*oldTypesExist*/); + caseObj.readRawObjects + (rawStore, true /*expectEvolved*/, true /*expectUpdated*/); + closeRawStore(); + } + + closeAll(); + } + + public void testEagerEvolve() + throws Exception { + + /* If the store cannot be opened, this test is not appropriate. */ + if (caseObj.getStoreOpenException() != null) { + return; + } + + EvolveConfig config = new EvolveConfig(); + + /* + * Use listener every other time to ensure that the stats are returned + * correctly when no listener is configured. [#17024] + */ + useEvolveListener = !useEvolveListener; + if (useEvolveListener) { + config.setEvolveListener(new EvolveListener() { + public boolean evolveProgress(EvolveEvent event) { + EvolveStats stats = event.getStats(); + evolveNRead = stats.getNRead(); + evolveNConverted = stats.getNConverted(); + return true; + } + }); + } + + openEnv(); + + openStoreReadWrite(); + + /* + * Evolve and expect that the expected number of entities are + * converted. + */ + int nExpected = caseObj.getNRecordsExpected(); + evolveNRead = 0; + evolveNConverted = 0; + PersistCatalog.unevolvedFormatsEncountered = false; + EvolveStats stats = store.evolve(config); + if (nExpected > 0) { + assertTrue(PersistCatalog.unevolvedFormatsEncountered); + } + assertTrue(stats.getNRead() == nExpected); + assertTrue(stats.getNConverted() == nExpected); + assertTrue(stats.getNConverted() >= stats.getNRead()); + if (useEvolveListener) { + assertEquals(evolveNRead, stats.getNRead()); + assertEquals(evolveNConverted, stats.getNConverted()); + } + + /* Evolve again and expect that no entities are converted. */ + evolveNRead = 0; + evolveNConverted = 0; + PersistCatalog.unevolvedFormatsEncountered = false; + stats = store.evolve(config); + assertTrue(!PersistCatalog.unevolvedFormatsEncountered); + assertEquals(0, stats.getNRead()); + assertEquals(0, stats.getNConverted()); + if (useEvolveListener) { + assertTrue(evolveNRead == 0); + assertTrue(evolveNConverted == 0); + } + + /* Ensure that we can read all entities without evolution. */ + PersistCatalog.unevolvedFormatsEncountered = false; + caseObj.readObjects(store, false /*doUpdate*/); + assertTrue(!PersistCatalog.unevolvedFormatsEncountered); + + /* + * When automatic unused type deletion is implemented in the future the + * oldTypesExist parameters below should be changed to false. + */ + + /* Open again and try an update. */ + caseObj.checkEvolvedModel + (store.getModel(), env, true /*oldTypesExist*/); + caseObj.readObjects(store, true /*doUpdate*/); + caseObj.checkEvolvedModel + (store.getModel(), env, true /*oldTypesExist*/); + closeStore(); + + /* Open read-only and double check that everything is OK. */ + openStoreReadOnly(); + caseObj.checkEvolvedModel + (store.getModel(), env, true /*oldTypesExist*/); + caseObj.readObjects(store, false /*doUpdate*/); + caseObj.checkEvolvedModel + (store.getModel(), env, true /*oldTypesExist*/); + closeStore(); + + /* Check raw objects. */ + openRawStore(); + caseObj.checkEvolvedModel + (rawStore.getModel(), env, true /*oldTypesExist*/); + caseObj.readRawObjects + (rawStore, true /*expectEvolved*/, true /*expectUpdated*/); + + /* + * Test copy raw object to new store via convertRawObject. In this + * test we can pass false for oldTypesExist because newStore starts + * with the new/evolved class model. + */ + openNewStore(); + caseObj.copyRawObjects(rawStore, newStore); + caseObj.readObjects(newStore, true /*doUpdate*/); + caseObj.checkEvolvedModel + (newStore.getModel(), env, false /*oldTypesExist*/); + closeNewStore(); + closeRawStore(); + + closeAll(); + } +} diff --git a/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/EvolveTestBase.java b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/EvolveTestBase.java new file mode 100644 index 0000000..7b97dcd --- /dev/null +++ b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/EvolveTestBase.java @@ -0,0 +1,438 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2000-2009 Oracle. All rights reserved. + * + * $Id$ + */ +package com.sleepycat.persist.test; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.Enumeration; + +import junit.framework.TestCase; +import junit.framework.TestSuite; + +import com.sleepycat.db.DatabaseException; +import com.sleepycat.db.Environment; +import com.sleepycat.db.EnvironmentConfig; +import com.sleepycat.persist.EntityStore; +import com.sleepycat.persist.StoreConfig; +import com.sleepycat.persist.model.AnnotationModel; +import com.sleepycat.persist.model.EntityModel; +import com.sleepycat.persist.raw.RawStore; +import com.sleepycat.util.test.TestEnv; + +/** + * Base class for EvolveTest and EvolveTestInit. + * + * @author Mark Hayes + */ +public abstract class EvolveTestBase extends TestCase { + + /* + * When adding a evolve test class, three places need to be changed: + * 1) Add the unmodified class to EvolveClass.java.original. + * 2) Add the modified class to EvolveClass.java. + * 3) Add the class name to the ALL list below as a pair of strings. The + * first string in each pair is the name of the original class, and the + * second string is the name of the evolved class or null if the evolved + * name is the same as the original. The index in the list identifies a + * test case, and the class at that position identifies the old and new + * class to use for the test. + */ + private static final String[] ALL = { +//* + "DeletedEntity1_ClassRemoved", + "DeletedEntity1_ClassRemoved_NoMutation", + "DeletedEntity2_ClassRemoved", + "DeletedEntity2_ClassRemoved_WithDeleter", + "DeletedEntity3_AnnotRemoved_NoMutation", + null, + "DeletedEntity4_AnnotRemoved_WithDeleter", + null, + "DeletedEntity5_EntityToPersist_NoMutation", + null, + "DeletedEntity6_EntityToPersist_WithDeleter", + null, + "DeletedPersist1_ClassRemoved_NoMutation", + null, + "DeletedPersist2_ClassRemoved_WithDeleter", + null, + "DeletedPersist3_AnnotRemoved_NoMutation", + null, + "DeletedPersist4_AnnotRemoved_WithDeleter", + null, + "DeletedPersist5_PersistToEntity_NoMutation", + null, + "DeletedPersist6_PersistToEntity_WithDeleter", + null, + "RenamedEntity1_NewEntityName", + "RenamedEntity1_NewEntityName_NoMutation", + "RenamedEntity2_NewEntityName", + "RenamedEntity2_NewEntityName_WithRenamer", + "DeleteSuperclass1_NoMutation", + null, + "DeleteSuperclass2_WithConverter", + null, + "DeleteSuperclass3_WithDeleter", + null, + "DeleteSuperclass4_NoFields", + null, + "DeleteSuperclass5_Top", + null, + "InsertSuperclass1_Between", + null, + "InsertSuperclass2_Top", + null, + "DisallowNonKeyField_PrimitiveToObject", + null, + "DisallowNonKeyField_ObjectToPrimitive", + null, + "DisallowNonKeyField_ObjectToSubtype", + null, + "DisallowNonKeyField_ObjectToUnrelatedSimple", + null, + "DisallowNonKeyField_ObjectToUnrelatedOther", + null, + "DisallowNonKeyField_byte2boolean", + null, + "DisallowNonKeyField_short2byte", + null, + "DisallowNonKeyField_int2short", + null, + "DisallowNonKeyField_long2int", + null, + "DisallowNonKeyField_float2long", + null, + "DisallowNonKeyField_double2float", + null, + "DisallowNonKeyField_Byte2byte", + null, + "DisallowNonKeyField_Character2char", + null, + "DisallowNonKeyField_Short2short", + null, + "DisallowNonKeyField_Integer2int", + null, + "DisallowNonKeyField_Long2long", + null, + "DisallowNonKeyField_Float2float", + null, + "DisallowNonKeyField_Double2double", + null, + "DisallowNonKeyField_float2BigInt", + null, + "DisallowNonKeyField_BigInt2long", + null, + "DisallowSecKeyField_byte2short", + null, + "DisallowSecKeyField_char2int", + null, + "DisallowSecKeyField_short2int", + null, + "DisallowSecKeyField_int2long", + null, + "DisallowSecKeyField_long2float", + null, + "DisallowSecKeyField_float2double", + null, + "DisallowSecKeyField_Byte2short2", + null, + "DisallowSecKeyField_Character2int", + null, + "DisallowSecKeyField_Short2int2", + null, + "DisallowSecKeyField_Integer2long", + null, + "DisallowSecKeyField_Long2float2", + null, + "DisallowSecKeyField_Float2double2", + null, + "DisallowSecKeyField_int2BigInt", + null, + "DisallowPriKeyField_byte2short", + null, + "DisallowPriKeyField_char2int", + null, + "DisallowPriKeyField_short2int", + null, + "DisallowPriKeyField_int2long", + null, + "DisallowPriKeyField_long2float", + null, + "DisallowPriKeyField_float2double", + null, + "DisallowPriKeyField_Byte2short2", + null, + "DisallowPriKeyField_Character2int", + null, + "DisallowPriKeyField_Short2int2", + null, + "DisallowPriKeyField_Integer2long", + null, + "DisallowPriKeyField_Long2float2", + null, + "DisallowPriKeyField_Float2double2", + null, + "DisallowPriKeyField_Long2BigInt", + null, + "DisallowCompositeKeyField_byte2short", + null, + "AllowPriKeyField_Byte2byte2", + null, + "AllowPriKeyField_byte2Byte", + null, + "AllowFieldTypeChanges", + null, + "ConvertFieldContent_Entity", + null, + "ConvertExample1_Entity", + null, + "ConvertExample2_Person", + null, + "ConvertExample3_Person", + null, + "ConvertExample3Reverse_Person", + null, + "ConvertExample4_Entity", + null, + "ConvertExample5_Entity", + null, + "AllowFieldAddDelete", + null, + "ProxiedClass_Entity", + null, + "DisallowChangeProxyFor", + null, + "DisallowDeleteProxyFor", + null, + "ArrayNameChange_Entity", + null, + "AddEnumConstant_Entity", + null, + "InsertEnumConstant_Entity", + null, + "DeleteEnumConstant_NoMutation", + null, + "DisallowChangeKeyRelate", + null, + "AllowChangeKeyMetadata", + null, + "AllowChangeKeyMetadataInSubclass", + null, + "AllowAddSecondary", + null, + "FieldAddAndConvert", + null, +//*/ + }; + + File envHome; + Environment env; + EntityStore store; + RawStore rawStore; + EntityStore newStore; + String caseClsName; + Class caseCls; + EvolveCase caseObj; + String caseLabel; + + static TestSuite getSuite(Class testClass) + throws Exception { + + TestSuite suite = new TestSuite(); + for (int i = 0; i < ALL.length; i += 2) { + String originalClsName = ALL[i]; + String evolvedClsName = ALL[i + 1]; + if (evolvedClsName == null) { + evolvedClsName = originalClsName; + } + TestSuite baseSuite = new TestSuite(testClass); + Enumeration e = baseSuite.tests(); + while (e.hasMoreElements()) { + EvolveTestBase test = (EvolveTestBase) e.nextElement(); + test.init(originalClsName, evolvedClsName); + suite.addTest(test); + } + } + return suite; + } + + private void init(String originalClsName, + String evolvedClsName) + throws Exception { + + String caseClsName = useEvolvedClass() ? + evolvedClsName : originalClsName; + caseClsName = "com.sleepycat.persist.test.EvolveClasses$" + + caseClsName; + + this.caseClsName = caseClsName; + this.caseCls = Class.forName(caseClsName); + this.caseObj = (EvolveCase) caseCls.newInstance(); + this.caseLabel = evolvedClsName; + } + + abstract boolean useEvolvedClass(); + + File getTestInitHome(boolean evolved) { + return new File + (System.getProperty("testevolvedir"), + (evolved ? "evolved" : "original") + '/' + caseLabel); + } + + @Override + public void tearDown() { + + /* Set test name for reporting; cannot be done in the ctor or setUp. */ + setName(caseLabel + '-' + getName()); + + if (env != null) { + try { + closeAll(); + } catch (Throwable e) { + System.out.println("During tearDown: " + e); + } + } + envHome = null; + env = null; + store = null; + caseCls = null; + caseObj = null; + caseLabel = null; + + /* Do not delete log files so they can be used by 2nd phase of test. */ + } + + /** + * @throws FileNotFoundException from DB core. + */ + void openEnv() + throws FileNotFoundException, DatabaseException { + + EnvironmentConfig config = TestEnv.TXN.getConfig(); + config.setAllowCreate(true); + env = new Environment(envHome, config); + } + + /** + * Returns true if the store was opened successfully. Returns false if the + * store could not be opened because an exception was expected -- this is + * not a test failure but no further tests for an EntityStore may be run. + */ + private boolean openStore(StoreConfig config) + throws Exception { + + config.setTransactional(true); + config.setMutations(caseObj.getMutations()); + + EntityModel model = new AnnotationModel(); + config.setModel(model); + caseObj.configure(model, config); + + String expectException = caseObj.getStoreOpenException(); + try { + store = new EntityStore(env, EvolveCase.STORE_NAME, config); + if (expectException != null) { + fail("Expected: " + expectException); + } + } catch (Exception e) { + if (expectException != null) { + //e.printStackTrace(); + String actualMsg = e.getMessage(); + EvolveCase.checkEquals + (expectException, + e.getClass().getName() + ": " + actualMsg); + return false; + } else { + throw e; + } + } + return true; + } + + boolean openStoreReadOnly() + throws Exception { + + StoreConfig config = new StoreConfig(); + config.setReadOnly(true); + return openStore(config); + } + + boolean openStoreReadWrite() + throws Exception { + + StoreConfig config = new StoreConfig(); + config.setAllowCreate(true); + return openStore(config); + } + + void openRawStore() + throws DatabaseException { + + StoreConfig config = new StoreConfig(); + config.setTransactional(true); + rawStore = new RawStore(env, EvolveCase.STORE_NAME, config); + } + + void closeStore() + throws DatabaseException { + + if (store != null) { + store.close(); + store = null; + } + } + + void openNewStore() + throws Exception { + + StoreConfig config = new StoreConfig(); + config.setAllowCreate(true); + config.setTransactional(true); + + EntityModel model = new AnnotationModel(); + config.setModel(model); + caseObj.configure(model, config); + + newStore = new EntityStore(env, "new", config); + } + + void closeNewStore() + throws DatabaseException { + + if (newStore != null) { + newStore.close(); + newStore = null; + } + } + + void closeRawStore() + throws DatabaseException { + + if (rawStore != null) { + rawStore.close(); + rawStore = null; + } + } + + void closeEnv() + throws DatabaseException { + + if (env != null) { + env.close(); + env = null; + } + } + + void closeAll() + throws DatabaseException { + + closeStore(); + closeRawStore(); + closeNewStore(); + closeEnv(); + } +} diff --git a/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/EvolveTestInit.java b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/EvolveTestInit.java new file mode 100644 index 0000000..06ed2a7 --- /dev/null +++ b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/EvolveTestInit.java @@ -0,0 +1,53 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2000-2009 Oracle. All rights reserved. + * + * $Id$ + */ +package com.sleepycat.persist.test; + +import junit.framework.Test; + +import com.sleepycat.util.test.SharedTestUtils; + +/** + * Runs part one of the EvolveTest. This part is run with the old/original + * version of EvolveClasses in the classpath. It creates a fresh environment + * and store containing instances of the original class. When EvolveTest is + * run, it will read/write/evolve these objects from the store created here. + * + * @author Mark Hayes + */ +public class EvolveTestInit extends EvolveTestBase { + + public static Test suite() + throws Exception { + + return getSuite(EvolveTestInit.class); + } + + @Override + boolean useEvolvedClass() { + return false; + } + + @Override + public void setUp() { + envHome = getTestInitHome(false /*evolved*/); + envHome.mkdirs(); + SharedTestUtils.emptyDir(envHome); + } + + public void testInit() + throws Exception { + + openEnv(); + if (!openStoreReadWrite()) { + fail(); + } + caseObj.writeObjects(store); + caseObj.checkUnevolvedModel(store.getModel(), env); + closeAll(); + } +} diff --git a/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/ForeignKeyTest.java b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/ForeignKeyTest.java new file mode 100644 index 0000000..741452c --- /dev/null +++ b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/ForeignKeyTest.java @@ -0,0 +1,329 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2000-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +package com.sleepycat.persist.test; + +import static com.sleepycat.persist.model.DeleteAction.ABORT; +import static com.sleepycat.persist.model.DeleteAction.CASCADE; +import static com.sleepycat.persist.model.DeleteAction.NULLIFY; +import static com.sleepycat.persist.model.Relationship.ONE_TO_ONE; + +import java.util.Enumeration; + +import junit.framework.Test; +import junit.framework.TestSuite; + +import com.sleepycat.compat.DbCompat; +import com.sleepycat.db.DatabaseException; +import com.sleepycat.db.Transaction; +import com.sleepycat.persist.EntityStore; +import com.sleepycat.persist.PrimaryIndex; +import com.sleepycat.persist.SecondaryIndex; +import com.sleepycat.persist.StoreConfig; +import com.sleepycat.persist.model.DeleteAction; +import com.sleepycat.persist.model.Entity; +import com.sleepycat.persist.model.Persistent; +import com.sleepycat.persist.model.PrimaryKey; +import com.sleepycat.persist.model.SecondaryKey; +import com.sleepycat.util.test.TxnTestCase; + +/** + * @author Mark Hayes + */ +public class ForeignKeyTest extends TxnTestCase { + + private static final DeleteAction[] ACTIONS = { + ABORT, + NULLIFY, + CASCADE, + }; + + private static final String[] ACTION_LABELS = { + "ABORT", + "NULLIFY", + "CASCADE", + }; + + static protected Class<?> testClass = ForeignKeyTest.class; + + public static Test suite() { + TestSuite suite = new TestSuite(); + for (int i = 0; i < ACTIONS.length; i += 1) { + for (int j = 0; j < 2; j++) { + TestSuite txnSuite = txnTestSuite(testClass, null, null); + Enumeration e = txnSuite.tests(); + while (e.hasMoreElements()) { + ForeignKeyTest test = (ForeignKeyTest) e.nextElement(); + test.onDelete = ACTIONS[i]; + test.onDeleteLabel = ACTION_LABELS[i]; + test.useSubclass = (j == 0); + test.useSubclassLabel = + (j == 0) ? "UseSubclass" : "UseBaseclass"; + suite.addTest(test); + } + } + } + return suite; + } + + private EntityStore store; + private PrimaryIndex<String,Entity1> pri1; + private PrimaryIndex<String,Entity2> pri2; + private SecondaryIndex<String,String,Entity1> sec1; + private SecondaryIndex<String,String,Entity2> sec2; + private DeleteAction onDelete; + private String onDeleteLabel; + private boolean useSubclass; + private String useSubclassLabel; + + @Override + public void tearDown() + throws Exception { + + super.tearDown(); + setName(getName() + '-' + onDeleteLabel + "-" + useSubclassLabel); + } + + private void open() + throws DatabaseException { + + StoreConfig config = new StoreConfig(); + config.setAllowCreate(envConfig.getAllowCreate()); + config.setTransactional(envConfig.getTransactional()); + + store = new EntityStore(env, "test", config); + + pri1 = store.getPrimaryIndex(String.class, Entity1.class); + sec1 = store.getSecondaryIndex(pri1, String.class, "sk"); + pri2 = store.getPrimaryIndex(String.class, Entity2.class); + sec2 = store.getSecondaryIndex + (pri2, String.class, "sk_" + onDeleteLabel); + } + + private void close() + throws DatabaseException { + + store.close(); + } + + public void testForeignKeys() + throws Exception { + + open(); + Transaction txn = txnBegin(); + + Entity1 o1 = new Entity1("pk1", "sk1"); + assertNull(pri1.put(txn, o1)); + + assertEquals(o1, pri1.get(txn, "pk1", null)); + assertEquals(o1, sec1.get(txn, "sk1", null)); + + Entity2 o2 = (useSubclass ? + new Entity3("pk2", "pk1", onDelete) : + new Entity2("pk2", "pk1", onDelete)); + assertNull(pri2.put(txn, o2)); + + assertEquals(o2, pri2.get(txn, "pk2", null)); + assertEquals(o2, sec2.get(txn, "pk1", null)); + + txnCommit(txn); + txn = txnBegin(); + + /* + * pri1 contains o1 with primary key "pk1" and index key "sk1". + * + * pri2 contains o2 with primary key "pk2" and foreign key "pk1", + * which is the primary key of pri1. + */ + if (onDelete == ABORT) { + + /* Test that we abort trying to delete a referenced key. */ + + try { + pri1.delete(txn, "pk1"); + fail(); + } catch (DatabaseException expected) { + assertTrue(!DbCompat.NEW_JE_EXCEPTIONS); + txnAbort(txn); + txn = txnBegin(); + } + + /* + * Test that we can put a record into store2 with a null foreign + * key value. + */ + o2 = (useSubclass ? + new Entity3("pk2", null, onDelete) : + new Entity2("pk2", null, onDelete)); + assertNotNull(pri2.put(txn, o2)); + assertEquals(o2, pri2.get(txn, "pk2", null)); + + /* + * The index2 record should have been deleted since the key was set + * to null above. + */ + assertNull(sec2.get(txn, "pk1", null)); + + /* + * Test that now we can delete the record in store1, since it is no + * longer referenced. + */ + assertNotNull(pri1.delete(txn, "pk1")); + assertNull(pri1.get(txn, "pk1", null)); + assertNull(sec1.get(txn, "sk1", null)); + + } else if (onDelete == NULLIFY) { + + /* Delete the referenced key. */ + assertNotNull(pri1.delete(txn, "pk1")); + assertNull(pri1.get(txn, "pk1", null)); + assertNull(sec1.get(txn, "sk1", null)); + + /* + * The store2 record should still exist, but should have an empty + * secondary key since it was nullified. + */ + o2 = pri2.get(txn, "pk2", null); + assertNotNull(o2); + assertEquals("pk2", o2.pk); + assertEquals(null, o2.getSk(onDelete)); + + } else if (onDelete == CASCADE) { + + /* Delete the referenced key. */ + assertNotNull(pri1.delete(txn, "pk1")); + assertNull(pri1.get(txn, "pk1", null)); + assertNull(sec1.get(txn, "sk1", null)); + + /* The store2 record should have deleted also. */ + assertNull(pri2.get(txn, "pk2", null)); + assertNull(sec2.get(txn, "pk1", null)); + + } else { + throw new IllegalStateException(); + } + + /* + * Test that a foreign key value may not be used that is not present in + * the foreign store. "pk2" is not in store1 in this case. + */ + Entity2 o3 = (useSubclass ? + new Entity3("pk3", "pk2", onDelete) : + new Entity2("pk3", "pk2", onDelete)); + try { + pri2.put(txn, o3); + fail(); + } catch (DatabaseException expected) { + assertTrue(!DbCompat.NEW_JE_EXCEPTIONS); + } + + txnAbort(txn); + close(); + } + + @Entity + static class Entity1 { + + @PrimaryKey + String pk; + + @SecondaryKey(relate=ONE_TO_ONE) + String sk; + + private Entity1() {} + + Entity1(String pk, String sk) { + this.pk = pk; + this.sk = sk; + } + + @Override + public boolean equals(Object other) { + Entity1 o = (Entity1) other; + return nullOrEqual(pk, o.pk) && + nullOrEqual(sk, o.sk); + } + } + + @Entity + static class Entity2 { + + @PrimaryKey + String pk; + + @SecondaryKey(relate=ONE_TO_ONE, relatedEntity=Entity1.class, + onRelatedEntityDelete=ABORT) + String sk_ABORT; + + @SecondaryKey(relate=ONE_TO_ONE, relatedEntity=Entity1.class, + onRelatedEntityDelete=CASCADE) + String sk_CASCADE; + + @SecondaryKey(relate=ONE_TO_ONE, relatedEntity=Entity1.class, + onRelatedEntityDelete=NULLIFY) + String sk_NULLIFY; + + private Entity2() {} + + Entity2(String pk, String sk, DeleteAction action) { + this.pk = pk; + switch (action) { + case ABORT: + sk_ABORT = sk; + break; + case CASCADE: + sk_CASCADE = sk; + break; + case NULLIFY: + sk_NULLIFY = sk; + break; + default: + throw new IllegalArgumentException(); + } + } + + String getSk(DeleteAction action) { + switch (action) { + case ABORT: + return sk_ABORT; + case CASCADE: + return sk_CASCADE; + case NULLIFY: + return sk_NULLIFY; + default: + throw new IllegalArgumentException(); + } + } + + @Override + public boolean equals(Object other) { + Entity2 o = (Entity2) other; + return nullOrEqual(pk, o.pk) && + nullOrEqual(sk_ABORT, o.sk_ABORT) && + nullOrEqual(sk_CASCADE, o.sk_CASCADE) && + nullOrEqual(sk_NULLIFY, o.sk_NULLIFY); + } + } + + @Persistent + static class Entity3 extends Entity2 { + Entity3() {} + + Entity3(String pk, String sk, DeleteAction action) { + super(pk, sk, action); + } + } + + static boolean nullOrEqual(Object o1, Object o2) { + if (o1 == null) { + return o2 == null; + } else { + return o1.equals(o2); + } + } +} diff --git a/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/IndexTest.java b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/IndexTest.java new file mode 100644 index 0000000..d4478c5 --- /dev/null +++ b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/IndexTest.java @@ -0,0 +1,874 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2002-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +package com.sleepycat.persist.test; + +import static com.sleepycat.persist.model.Relationship.MANY_TO_MANY; +import static com.sleepycat.persist.model.Relationship.MANY_TO_ONE; +import static com.sleepycat.persist.model.Relationship.ONE_TO_MANY; +import static com.sleepycat.persist.model.Relationship.ONE_TO_ONE; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.SortedMap; +import java.util.SortedSet; +import java.util.TreeMap; +import java.util.TreeSet; + +import junit.framework.Test; + +import com.sleepycat.collections.MapEntryParameter; +import com.sleepycat.db.DatabaseException; +import com.sleepycat.db.Transaction; +import com.sleepycat.persist.EntityCursor; +import com.sleepycat.persist.EntityIndex; +import com.sleepycat.persist.EntityStore; +import com.sleepycat.persist.PrimaryIndex; +import com.sleepycat.persist.SecondaryIndex; +import com.sleepycat.persist.StoreConfig; +import com.sleepycat.persist.model.Entity; +import com.sleepycat.persist.model.PrimaryKey; +import com.sleepycat.persist.model.SecondaryKey; +import com.sleepycat.persist.raw.RawObject; +import com.sleepycat.persist.raw.RawStore; +import com.sleepycat.persist.raw.RawType; +import com.sleepycat.util.test.TxnTestCase; + +/** + * Tests EntityIndex and EntityCursor in all their permutations. + * + * @author Mark Hayes + */ +public class IndexTest extends TxnTestCase { + + private static final int N_RECORDS = 5; + private static final int THREE_TO_ONE = 3; + + static protected Class<?> testClass = IndexTest.class; + + public static Test suite() { + return txnTestSuite(testClass, null, + null); + //new String[] { TxnTestCase.TXN_NULL}); + } + + private EntityStore store; + private PrimaryIndex<Integer,MyEntity> primary; + private SecondaryIndex<Integer,Integer,MyEntity> oneToOne; + private SecondaryIndex<Integer,Integer,MyEntity> manyToOne; + private SecondaryIndex<Integer,Integer,MyEntity> oneToMany; + private SecondaryIndex<Integer,Integer,MyEntity> manyToMany; + private RawStore rawStore; + private RawType entityType; + private PrimaryIndex<Object,RawObject> primaryRaw; + private SecondaryIndex<Object,Object,RawObject> oneToOneRaw; + private SecondaryIndex<Object,Object,RawObject> manyToOneRaw; + private SecondaryIndex<Object,Object,RawObject> oneToManyRaw; + private SecondaryIndex<Object,Object,RawObject> manyToManyRaw; + + /** + * Opens the store. + */ + private void open() + throws DatabaseException { + + StoreConfig config = new StoreConfig(); + config.setAllowCreate(envConfig.getAllowCreate()); + config.setTransactional(envConfig.getTransactional()); + + store = new EntityStore(env, "test", config); + + primary = store.getPrimaryIndex(Integer.class, MyEntity.class); + oneToOne = + store.getSecondaryIndex(primary, Integer.class, "oneToOne"); + manyToOne = + store.getSecondaryIndex(primary, Integer.class, "manyToOne"); + oneToMany = + store.getSecondaryIndex(primary, Integer.class, "oneToMany"); + manyToMany = + store.getSecondaryIndex(primary, Integer.class, "manyToMany"); + + assertNotNull(primary); + assertNotNull(oneToOne); + assertNotNull(manyToOne); + assertNotNull(oneToMany); + assertNotNull(manyToMany); + + rawStore = new RawStore(env, "test", config); + String clsName = MyEntity.class.getName(); + entityType = rawStore.getModel().getRawType(clsName); + assertNotNull(entityType); + + primaryRaw = rawStore.getPrimaryIndex(clsName); + oneToOneRaw = rawStore.getSecondaryIndex(clsName, "oneToOne"); + manyToOneRaw = rawStore.getSecondaryIndex(clsName, "manyToOne"); + oneToManyRaw = rawStore.getSecondaryIndex(clsName, "oneToMany"); + manyToManyRaw = rawStore.getSecondaryIndex(clsName, "manyToMany"); + + assertNotNull(primaryRaw); + assertNotNull(oneToOneRaw); + assertNotNull(manyToOneRaw); + assertNotNull(oneToManyRaw); + assertNotNull(manyToManyRaw); + } + + /** + * Closes the store. + */ + private void close() + throws DatabaseException { + + store.close(); + store = null; + rawStore.close(); + rawStore = null; + } + + @Override + public void setUp() + throws Exception { + + super.setUp(); + } + + /** + * The store must be closed before closing the environment. + */ + @Override + public void tearDown() + throws Exception { + + try { + if (rawStore != null) { + rawStore.close(); + } + } catch (Throwable e) { + System.out.println("During tearDown: " + e); + } + try { + if (store != null) { + store.close(); + } + } catch (Throwable e) { + System.out.println("During tearDown: " + e); + } + store = null; + rawStore = null; + super.tearDown(); + } + + /** + * Primary keys: {0, 1, 2, 3, 4} + */ + public void testPrimary() + throws DatabaseException { + + SortedMap<Integer,SortedSet<Integer>> expected = + new TreeMap<Integer,SortedSet<Integer>>(); + + for (int priKey = 0; priKey < N_RECORDS; priKey += 1) { + SortedSet<Integer> values = new TreeSet<Integer>(); + values.add(priKey); + expected.put(priKey, values); + } + + open(); + addEntities(primary); + checkIndex(primary, expected, keyGetter, entityGetter); + checkIndex(primaryRaw, expected, rawKeyGetter, rawEntityGetter); + + /* Close and reopen, then recheck indices. */ + close(); + open(); + checkIndex(primary, expected, keyGetter, entityGetter); + checkIndex(primaryRaw, expected, rawKeyGetter, rawEntityGetter); + + /* Check primary delete, last key first for variety. */ + for (int priKey = N_RECORDS - 1; priKey >= 0; priKey -= 1) { + boolean useRaw = ((priKey & 1) != 0); + Transaction txn = txnBegin(); + if (useRaw) { + primaryRaw.delete(txn, priKey); + } else { + primary.delete(txn, priKey); + } + txnCommit(txn); + expected.remove(priKey); + checkIndex(primary, expected, keyGetter, entityGetter); + } + checkAllEmpty(); + + /* Check PrimaryIndex put operations. */ + MyEntity e; + Transaction txn = txnBegin(); + /* put() */ + e = primary.put(txn, new MyEntity(1)); + assertNull(e); + e = primary.get(txn, 1, null); + assertEquals(1, e.key); + /* putNoReturn() */ + primary.putNoReturn(txn, new MyEntity(2)); + e = primary.get(txn, 2, null); + assertEquals(2, e.key); + /* putNoOverwrite */ + assertTrue(!primary.putNoOverwrite(txn, new MyEntity(1))); + assertTrue(!primary.putNoOverwrite(txn, new MyEntity(2))); + assertTrue(primary.putNoOverwrite(txn, new MyEntity(3))); + e = primary.get(txn, 3, null); + assertEquals(3, e.key); + txnCommit(txn); + close(); + } + + /** + * { 0:0, 1:-1, 2:-2, 3:-3, 4:-4 } + */ + public void testOneToOne() + throws DatabaseException { + + SortedMap<Integer,SortedSet<Integer>> expected = + new TreeMap<Integer,SortedSet<Integer>>(); + + for (int priKey = 0; priKey < N_RECORDS; priKey += 1) { + SortedSet<Integer> values = new TreeSet<Integer>(); + values.add(priKey); + Integer secKey = (-priKey); + expected.put(secKey, values); + } + + open(); + addEntities(primary); + checkSecondary(oneToOne, oneToOneRaw, expected); + checkDelete(oneToOne, oneToOneRaw, expected); + close(); + } + + /** + * { 0:0, 1:1, 2:2, 3:0, 4:1 } + */ + public void testManyToOne() + throws DatabaseException { + + SortedMap<Integer,SortedSet<Integer>> expected = + new TreeMap<Integer,SortedSet<Integer>>(); + + for (int priKey = 0; priKey < N_RECORDS; priKey += 1) { + Integer secKey = priKey % THREE_TO_ONE; + SortedSet<Integer> values = expected.get(secKey); + if (values == null) { + values = new TreeSet<Integer>(); + expected.put(secKey, values); + } + values.add(priKey); + } + + open(); + addEntities(primary); + checkSecondary(manyToOne, manyToOneRaw, expected); + checkDelete(manyToOne, manyToOneRaw, expected); + close(); + } + + /** + * { 0:{}, 1:{10}, 2:{20,21}, 3:{30,31,32}, 4:{40,41,42,43} + */ + public void testOneToMany() + throws DatabaseException { + + SortedMap<Integer,SortedSet<Integer>> expected = + new TreeMap<Integer,SortedSet<Integer>>(); + + for (int priKey = 0; priKey < N_RECORDS; priKey += 1) { + for (int i = 0; i < priKey; i += 1) { + Integer secKey = (N_RECORDS * priKey) + i; + SortedSet<Integer> values = expected.get(secKey); + if (values == null) { + values = new TreeSet<Integer>(); + expected.put(secKey, values); + } + values.add(priKey); + } + } + + open(); + addEntities(primary); + checkSecondary(oneToMany, oneToManyRaw, expected); + checkDelete(oneToMany, oneToManyRaw, expected); + close(); + } + + /** + * { 0:{}, 1:{0}, 2:{0,1}, 3:{0,1,2}, 4:{0,1,2,3} + */ + public void testManyToMany() + throws DatabaseException { + + SortedMap<Integer,SortedSet<Integer>> expected = + new TreeMap<Integer,SortedSet<Integer>>(); + + for (int priKey = 0; priKey < N_RECORDS; priKey += 1) { + for (int i = 0; i < priKey; i += 1) { + Integer secKey = i; + SortedSet<Integer> values = expected.get(secKey); + if (values == null) { + values = new TreeSet<Integer>(); + expected.put(secKey, values); + } + values.add(priKey); + } + } + + open(); + addEntities(primary); + checkSecondary(manyToMany, manyToManyRaw, expected); + checkDelete(manyToMany, manyToManyRaw, expected); + close(); + } + + private void addEntities(PrimaryIndex<Integer,MyEntity> primary) + throws DatabaseException { + + Transaction txn = txnBegin(); + for (int priKey = 0; priKey < N_RECORDS; priKey += 1) { + MyEntity prev = primary.put(txn, new MyEntity(priKey)); + assertNull(prev); + } + txnCommit(txn); + } + + private void checkDelete(SecondaryIndex<Integer,Integer,MyEntity> index, + SecondaryIndex<Object,Object,RawObject> indexRaw, + SortedMap<Integer,SortedSet<Integer>> expected) + throws DatabaseException { + + SortedMap<Integer,SortedSet<Integer>> expectedSubIndex = + new TreeMap<Integer,SortedSet<Integer>>(); + + while (expected.size() > 0) { + Integer delSecKey = expected.firstKey(); + SortedSet<Integer> deletedPriKeys = expected.remove(delSecKey); + for (SortedSet<Integer> priKeys : expected.values()) { + priKeys.removeAll(deletedPriKeys); + } + Transaction txn = txnBegin(); + boolean deleted = index.delete(txn, delSecKey); + assertEquals(deleted, !deletedPriKeys.isEmpty()); + deleted = index.delete(txn, delSecKey); + assertTrue(!deleted); + assertNull(index.get(txn, delSecKey, null)); + txnCommit(txn); + checkSecondary(index, indexRaw, expected); + } + + /* + * Delete remaining records so that the primary index is empty. Use + * the RawStore for variety. + */ + Transaction txn = txnBegin(); + for (int priKey = 0; priKey < N_RECORDS; priKey += 1) { + primaryRaw.delete(txn, priKey); + } + txnCommit(txn); + checkAllEmpty(); + } + + private void checkSecondary(SecondaryIndex<Integer,Integer,MyEntity> index, + SecondaryIndex<Object,Object,RawObject> + indexRaw, + SortedMap<Integer,SortedSet<Integer>> expected) + throws DatabaseException { + + checkIndex(index, expected, keyGetter, entityGetter); + checkIndex(index.keysIndex(), expected, keyGetter, keyGetter); + + checkIndex(indexRaw, expected, rawKeyGetter, rawEntityGetter); + checkIndex(indexRaw.keysIndex(), expected, rawKeyGetter, rawKeyGetter); + + SortedMap<Integer,SortedSet<Integer>> expectedSubIndex = + new TreeMap<Integer,SortedSet<Integer>>(); + + for (Integer secKey : expected.keySet()) { + expectedSubIndex.clear(); + for (Integer priKey : expected.get(secKey)) { + SortedSet<Integer> values = new TreeSet<Integer>(); + values.add(priKey); + expectedSubIndex.put(priKey, values); + } + checkIndex(index.subIndex(secKey), + expectedSubIndex, + keyGetter, + entityGetter); + checkIndex(indexRaw.subIndex(secKey), + expectedSubIndex, + rawKeyGetter, + rawEntityGetter); + } + } + + private <K,V> void checkIndex(EntityIndex<K,V> index, + SortedMap<Integer,SortedSet<Integer>> + expected, + Getter<K> kGetter, + Getter<V> vGetter) + throws DatabaseException { + + SortedMap<K,V> map = index.sortedMap(); + + Transaction txn = txnBegin(); + for (int i : expected.keySet()) { + K k = kGetter.fromInt(i); + SortedSet<Integer> dups = expected.get(i); + if (dups.isEmpty()) { + + /* EntityIndex */ + V v = index.get(txn, k, null); + assertNull(v); + assertTrue(!index.contains(txn, k, null)); + + /* Map/Collection */ + v = map.get(i); + assertNull(v); + assertTrue(!map.containsKey(i)); + } else { + int j = dups.first(); + + /* EntityIndex */ + V v = index.get(txn, k, null); + assertNotNull(v); + assertEquals(j, vGetter.getKey(v)); + assertTrue(index.contains(txn, k, null)); + + /* Map/Collection */ + v = map.get(i); + assertNotNull(v); + assertEquals(j, vGetter.getKey(v)); + assertTrue(map.containsKey(i)); + assertTrue("" + i + ' ' + j + ' ' + v + ' ' + map, + map.containsValue(v)); + assertTrue(map.keySet().contains(i)); + assertTrue(map.values().contains(v)); + assertTrue + (map.entrySet().contains(new MapEntryParameter(i, v))); + } + } + txnCommit(txn); + + int keysSize = expandKeySize(expected); + int valuesSize = expandValueSize(expected); + + /* EntityIndex.count */ + assertEquals("keysSize=" + keysSize, valuesSize, index.count()); + + /* Map/Collection size */ + assertEquals(valuesSize, map.size()); + assertEquals(valuesSize, map.values().size()); + assertEquals(valuesSize, map.entrySet().size()); + assertEquals(keysSize, map.keySet().size()); + + /* Map/Collection isEmpty */ + assertEquals(valuesSize == 0, map.isEmpty()); + assertEquals(valuesSize == 0, map.values().isEmpty()); + assertEquals(valuesSize == 0, map.entrySet().isEmpty()); + assertEquals(keysSize == 0, map.keySet().isEmpty()); + + txn = txnBeginCursor(); + + /* Unconstrained cursors. */ + checkCursor + (index.keys(txn, null), + map.keySet(), true, + expandKeys(expected), kGetter); + checkCursor + (index.entities(txn, null), + map.values(), false, + expandValues(expected), vGetter); + + /* Range cursors. */ + if (expected.isEmpty()) { + checkOpenRanges(txn, 0, index, expected, kGetter, vGetter); + checkClosedRanges(txn, 0, 1, index, expected, kGetter, vGetter); + } else { + int firstKey = expected.firstKey(); + int lastKey = expected.lastKey(); + for (int i = firstKey - 1; i <= lastKey + 1; i += 1) { + checkOpenRanges(txn, i, index, expected, kGetter, vGetter); + int j = i + 1; + if (j < lastKey + 1) { + checkClosedRanges + (txn, i, j, index, expected, kGetter, vGetter); + } + } + } + + txnCommit(txn); + } + + private <K,V> void checkOpenRanges(Transaction txn, int i, + EntityIndex<K,V> index, + SortedMap<Integer,SortedSet<Integer>> + expected, + Getter<K> kGetter, + Getter<V> vGetter) + throws DatabaseException { + + SortedMap<K,V> map = index.sortedMap(); + SortedMap<Integer,SortedSet<Integer>> rangeExpected; + K k = kGetter.fromInt(i); + K kPlusOne = kGetter.fromInt(i + 1); + + /* Head range exclusive. */ + rangeExpected = expected.headMap(i); + checkCursor + (index.keys(txn, null, false, k, false, null), + map.headMap(k).keySet(), true, + expandKeys(rangeExpected), kGetter); + checkCursor + (index.entities(txn, null, false, k, false, null), + map.headMap(k).values(), false, + expandValues(rangeExpected), vGetter); + + /* Head range inclusive. */ + rangeExpected = expected.headMap(i + 1); + checkCursor + (index.keys(txn, null, false, k, true, null), + map.headMap(kPlusOne).keySet(), true, + expandKeys(rangeExpected), kGetter); + checkCursor + (index.entities(txn, null, false, k, true, null), + map.headMap(kPlusOne).values(), false, + expandValues(rangeExpected), vGetter); + + /* Tail range exclusive. */ + rangeExpected = expected.tailMap(i + 1); + checkCursor + (index.keys(txn, k, false, null, false, null), + map.tailMap(kPlusOne).keySet(), true, + expandKeys(rangeExpected), kGetter); + checkCursor + (index.entities(txn, k, false, null, false, null), + map.tailMap(kPlusOne).values(), false, + expandValues(rangeExpected), vGetter); + + /* Tail range inclusive. */ + rangeExpected = expected.tailMap(i); + checkCursor + (index.keys(txn, k, true, null, false, null), + map.tailMap(k).keySet(), true, + expandKeys(rangeExpected), kGetter); + checkCursor + (index.entities(txn, k, true, null, false, null), + map.tailMap(k).values(), false, + expandValues(rangeExpected), vGetter); + } + + private <K,V> void checkClosedRanges(Transaction txn, int i, int j, + EntityIndex<K,V> index, + SortedMap<Integer,SortedSet<Integer>> + expected, + Getter<K> kGetter, + Getter<V> vGetter) + throws DatabaseException { + + SortedMap<K,V> map = index.sortedMap(); + SortedMap<Integer,SortedSet<Integer>> rangeExpected; + K k = kGetter.fromInt(i); + K kPlusOne = kGetter.fromInt(i + 1); + K l = kGetter.fromInt(j); + K lPlusOne = kGetter.fromInt(j + 1); + + /* Sub range exclusive. */ + rangeExpected = expected.subMap(i + 1, j); + checkCursor + (index.keys(txn, k, false, l, false, null), + map.subMap(kPlusOne, l).keySet(), true, + expandKeys(rangeExpected), kGetter); + checkCursor + (index.entities(txn, k, false, l, false, null), + map.subMap(kPlusOne, l).values(), false, + expandValues(rangeExpected), vGetter); + + /* Sub range inclusive. */ + rangeExpected = expected.subMap(i, j + 1); + checkCursor + (index.keys(txn, k, true, l, true, null), + map.subMap(k, lPlusOne).keySet(), true, + expandKeys(rangeExpected), kGetter); + checkCursor + (index.entities(txn, k, true, l, true, null), + map.subMap(k, lPlusOne).values(), false, + expandValues(rangeExpected), vGetter); + } + + private List<List<Integer>> + expandKeys(SortedMap<Integer,SortedSet<Integer>> map) { + + List<List<Integer>> list = new ArrayList<List<Integer>>(); + for (Integer key : map.keySet()) { + SortedSet<Integer> values = map.get(key); + List<Integer> dups = new ArrayList<Integer>(); + for (int i = 0; i < values.size(); i += 1) { + dups.add(key); + } + list.add(dups); + } + return list; + } + + private List<List<Integer>> + expandValues(SortedMap<Integer,SortedSet<Integer>> map) { + + List<List<Integer>> list = new ArrayList<List<Integer>>(); + for (SortedSet<Integer> values : map.values()) { + list.add(new ArrayList<Integer>(values)); + } + return list; + } + + private int expandKeySize(SortedMap<Integer,SortedSet<Integer>> map) { + + int size = 0; + for (SortedSet<Integer> values : map.values()) { + if (values.size() > 0) { + size += 1; + } + } + return size; + } + + private int expandValueSize(SortedMap<Integer,SortedSet<Integer>> map) { + + int size = 0; + for (SortedSet<Integer> values : map.values()) { + size += values.size(); + } + return size; + } + + private <T> void checkCursor(EntityCursor<T> cursor, + Collection<T> collection, + boolean collectionIsKeySet, + List<List<Integer>> expected, + Getter<T> getter) + throws DatabaseException { + + boolean first; + boolean firstDup; + Iterator<T> iterator = collection.iterator(); + + for (List<Integer> dups : expected) { + for (int i : dups) { + T o = cursor.next(); + assertNotNull(o); + assertEquals(i, getter.getKey(o)); + /* Value iterator over duplicates. */ + if (!collectionIsKeySet) { + assertTrue(iterator.hasNext()); + o = iterator.next(); + assertNotNull(o); + assertEquals(i, getter.getKey(o)); + } + } + } + + first = true; + for (List<Integer> dups : expected) { + firstDup = true; + for (int i : dups) { + T o = first ? cursor.first() + : (firstDup ? cursor.next() : cursor.nextDup()); + assertNotNull(o); + assertEquals(i, getter.getKey(o)); + first = false; + firstDup = false; + } + } + + first = true; + for (List<Integer> dups : expected) { + if (!dups.isEmpty()) { + int i = dups.get(0); + T o = first ? cursor.first() : cursor.nextNoDup(); + assertNotNull(o); + assertEquals(i, getter.getKey(o)); + /* Key iterator over non-duplicates. */ + if (collectionIsKeySet) { + assertTrue(iterator.hasNext()); + o = iterator.next(); + assertNotNull(o); + assertEquals(i, getter.getKey(o)); + } + first = false; + } + } + + List<List<Integer>> reversed = new ArrayList<List<Integer>>(); + for (List<Integer> dups : expected) { + ArrayList<Integer> reversedDups = new ArrayList<Integer>(dups); + Collections.reverse(reversedDups); + reversed.add(reversedDups); + } + Collections.reverse(reversed); + + first = true; + for (List<Integer> dups : reversed) { + for (int i : dups) { + T o = first ? cursor.last() : cursor.prev(); + assertNotNull(o); + assertEquals(i, getter.getKey(o)); + first = false; + } + } + + first = true; + for (List<Integer> dups : reversed) { + firstDup = true; + for (int i : dups) { + T o = first ? cursor.last() + : (firstDup ? cursor.prev() : cursor.prevDup()); + assertNotNull(o); + assertEquals(i, getter.getKey(o)); + first = false; + firstDup = false; + } + } + + first = true; + for (List<Integer> dups : reversed) { + if (!dups.isEmpty()) { + int i = dups.get(0); + T o = first ? cursor.last() : cursor.prevNoDup(); + assertNotNull(o); + assertEquals(i, getter.getKey(o)); + first = false; + } + } + + cursor.close(); + } + + private void checkAllEmpty() + throws DatabaseException { + + checkEmpty(primary); + checkEmpty(oneToOne); + checkEmpty(oneToMany); + checkEmpty(manyToOne); + checkEmpty(manyToMany); + } + + private <K,V> void checkEmpty(EntityIndex<K,V> index) + throws DatabaseException { + + EntityCursor<K> keys = index.keys(); + assertNull(keys.next()); + assertTrue(!keys.iterator().hasNext()); + keys.close(); + EntityCursor<V> entities = index.entities(); + assertNull(entities.next()); + assertTrue(!entities.iterator().hasNext()); + entities.close(); + } + + private interface Getter<T> { + int getKey(T o); + T fromInt(int i); + } + + private static Getter<MyEntity> entityGetter = + new Getter<MyEntity>() { + public int getKey(MyEntity o) { + return o.key; + } + public MyEntity fromInt(int i) { + throw new UnsupportedOperationException(); + } + }; + + private static Getter<Integer> keyGetter = + new Getter<Integer>() { + public int getKey(Integer o) { + return o; + } + public Integer fromInt(int i) { + return Integer.valueOf(i); + } + }; + + private static Getter<RawObject> rawEntityGetter = + new Getter<RawObject>() { + public int getKey(RawObject o) { + Object val = o.getValues().get("key"); + return ((Integer) val).intValue(); + } + public RawObject fromInt(int i) { + throw new UnsupportedOperationException(); + } + }; + + private static Getter<Object> rawKeyGetter = + new Getter<Object>() { + public int getKey(Object o) { + return ((Integer) o).intValue(); + } + public Object fromInt(int i) { + return Integer.valueOf(i); + } + }; + + @Entity + private static class MyEntity { + + @PrimaryKey + private int key; + + @SecondaryKey(relate=ONE_TO_ONE) + private int oneToOne; + + @SecondaryKey(relate=MANY_TO_ONE) + private int manyToOne; + + @SecondaryKey(relate=ONE_TO_MANY) + private Set<Integer> oneToMany = new TreeSet<Integer>(); + + @SecondaryKey(relate=MANY_TO_MANY) + private Set<Integer> manyToMany = new TreeSet<Integer>(); + + private MyEntity() {} + + private MyEntity(int key) { + + /* example keys: {0, 1, 2, 3, 4} */ + this.key = key; + + /* { 0:0, 1:-1, 2:-2, 3:-3, 4:-4 } */ + oneToOne = -key; + + /* { 0:0, 1:1, 2:2, 3:0, 4:1 } */ + manyToOne = key % THREE_TO_ONE; + + /* { 0:{}, 1:{10}, 2:{20,21}, 3:{30,31,32}, 4:{40,41,42,43} */ + for (int i = 0; i < key; i += 1) { + oneToMany.add((N_RECORDS * key) + i); + } + + /* { 0:{}, 1:{0}, 2:{0,1}, 3:{0,1,2}, 4:{0,1,2,3} */ + for (int i = 0; i < key; i += 1) { + manyToMany.add(i); + } + } + + @Override + public String toString() { + return "MyEntity " + key; + } + } +} diff --git a/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/JoinTest.java b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/JoinTest.java new file mode 100644 index 0000000..b77d37d --- /dev/null +++ b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/JoinTest.java @@ -0,0 +1,176 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2002-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +package com.sleepycat.persist.test; + +import static com.sleepycat.persist.model.Relationship.MANY_TO_ONE; + +import java.util.ArrayList; +import java.util.List; + +import junit.framework.Test; + +import com.sleepycat.db.DatabaseException; +import com.sleepycat.db.Transaction; +import com.sleepycat.persist.EntityJoin; +import com.sleepycat.persist.EntityStore; +import com.sleepycat.persist.ForwardCursor; +import com.sleepycat.persist.PrimaryIndex; +import com.sleepycat.persist.SecondaryIndex; +import com.sleepycat.persist.StoreConfig; +import com.sleepycat.persist.model.Entity; +import com.sleepycat.persist.model.PrimaryKey; +import com.sleepycat.persist.model.SecondaryKey; +import com.sleepycat.util.test.TxnTestCase; + +/** + * @author Mark Hayes + */ +public class JoinTest extends TxnTestCase { + + private static final int N_RECORDS = 5; + + static protected Class<?> testClass = JoinTest.class; + + public static Test suite() { + return txnTestSuite(testClass, null, null); + } + + private EntityStore store; + private PrimaryIndex<Integer,MyEntity> primary; + private SecondaryIndex<Integer,Integer,MyEntity> sec1; + private SecondaryIndex<Integer,Integer,MyEntity> sec2; + private SecondaryIndex<Integer,Integer,MyEntity> sec3; + + /** + * Opens the store. + */ + private void open() + throws DatabaseException { + + StoreConfig config = new StoreConfig(); + config.setAllowCreate(envConfig.getAllowCreate()); + config.setTransactional(envConfig.getTransactional()); + + store = new EntityStore(env, "test", config); + + primary = store.getPrimaryIndex(Integer.class, MyEntity.class); + sec1 = store.getSecondaryIndex(primary, Integer.class, "k1"); + sec2 = store.getSecondaryIndex(primary, Integer.class, "k2"); + sec3 = store.getSecondaryIndex(primary, Integer.class, "k3"); + } + + /** + * Closes the store. + */ + private void close() + throws DatabaseException { + + store.close(); + } + + public void testJoin() + throws DatabaseException { + + open(); + + /* + * Primary keys: { 0, 1, 2, 3, 4 } + * Secondary k1: { 0:0, 0:1, 0:2, 0:3, 0:4 } + * Secondary k2: { 0:0, 1:1, 0:2, 1:3, 0:4 } + * Secondary k3: { 0:0, 1:1, 2:2, 0:3, 1:4 } + */ + Transaction txn = txnBegin(); + for (int i = 0; i < N_RECORDS; i += 1) { + MyEntity e = new MyEntity(i, 0, i % 2, i % 3); + boolean ok = primary.putNoOverwrite(txn, e); + assertTrue(ok); + } + txnCommit(txn); + + /* + * k1, k2, k3, -> { primary keys } + * -1 means don't include the key in the join. + */ + doJoin( 0, 0, 0, new int[] { 0 }); + doJoin( 0, 0, 1, new int[] { 4 }); + doJoin( 0, 0, -1, new int[] { 0, 2, 4 }); + doJoin(-1, 1, 1, new int[] { 1 }); + doJoin(-1, 2, 2, new int[] { }); + doJoin(-1, -1, 2, new int[] { 2 }); + + close(); + } + + private void doJoin(int k1, int k2, int k3, int[] expectKeys) + throws DatabaseException { + + List<Integer> expect = new ArrayList<Integer>(); + for (int i : expectKeys) { + expect.add(i); + } + EntityJoin join = new EntityJoin(primary); + if (k1 >= 0) { + join.addCondition(sec1, k1); + } + if (k2 >= 0) { + join.addCondition(sec2, k2); + } + if (k3 >= 0) { + join.addCondition(sec3, k3); + } + List<Integer> found; + Transaction txn = txnBegin(); + + /* Keys */ + found = new ArrayList<Integer>(); + ForwardCursor<Integer> keys = join.keys(txn, null); + for (int i : keys) { + found.add(i); + } + keys.close(); + assertEquals(expect, found); + + /* Entities */ + found = new ArrayList<Integer>(); + ForwardCursor<MyEntity> entities = join.entities(txn, null); + for (MyEntity e : entities) { + found.add(e.id); + } + entities.close(); + assertEquals(expect, found); + + txnCommit(txn); + } + + @Entity + private static class MyEntity { + @PrimaryKey + int id; + @SecondaryKey(relate=MANY_TO_ONE) + int k1; + @SecondaryKey(relate=MANY_TO_ONE) + int k2; + @SecondaryKey(relate=MANY_TO_ONE) + int k3; + + private MyEntity() {} + + MyEntity(int id, int k1, int k2, int k3) { + this.id = id; + this.k1 = k1; + this.k2 = k2; + this.k3 = k3; + } + + @Override + public String toString() { + return "MyEntity " + id + ' ' + k1 + ' ' + k2 + ' ' + k3; + } + } +} diff --git a/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/NegativeTest.java b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/NegativeTest.java new file mode 100644 index 0000000..5503451 --- /dev/null +++ b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/NegativeTest.java @@ -0,0 +1,644 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2002-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +package com.sleepycat.persist.test; + +import static com.sleepycat.persist.model.Relationship.ONE_TO_MANY; +import static com.sleepycat.persist.model.Relationship.ONE_TO_ONE; +import static com.sleepycat.persist.model.DeleteAction.NULLIFY; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collection; + +import junit.framework.Test; + +import com.sleepycat.db.DatabaseException; +import com.sleepycat.persist.EntityStore; +import com.sleepycat.persist.PrimaryIndex; +import com.sleepycat.persist.StoreConfig; +import com.sleepycat.persist.model.AnnotationModel; +import com.sleepycat.persist.model.Entity; +import com.sleepycat.persist.model.KeyField; +import com.sleepycat.persist.model.Persistent; +import com.sleepycat.persist.model.PersistentProxy; +import com.sleepycat.persist.model.PrimaryKey; +import com.sleepycat.persist.model.SecondaryKey; +import com.sleepycat.util.test.TxnTestCase; + +/** + * Negative tests. + * + * @author Mark Hayes + */ +public class NegativeTest extends TxnTestCase { + + static protected Class<?> testClass = NegativeTest.class; + + public static Test suite() { + return txnTestSuite(testClass, null, null); + } + + private EntityStore store; + + private void open() + throws DatabaseException { + + open(null); + } + + private void open(Class<ProxyExtendsEntity> clsToRegister) + throws DatabaseException { + + StoreConfig config = new StoreConfig(); + config.setAllowCreate(envConfig.getAllowCreate()); + config.setTransactional(envConfig.getTransactional()); + + if (clsToRegister != null) { + AnnotationModel model = new AnnotationModel(); + model.registerClass(clsToRegister); + config.setModel(model); + } + + store = new EntityStore(env, "test", config); + } + + private void close() + throws DatabaseException { + + store.close(); + store = null; + } + + @Override + public void setUp() + throws Exception { + + super.setUp(); + } + + @Override + public void tearDown() + throws Exception { + + if (store != null) { + try { + store.close(); + } catch (Throwable e) { + System.out.println("tearDown: " + e); + } + store = null; + } + super.tearDown(); + } + + public void testBadKeyClass1() + throws DatabaseException { + + open(); + try { + store.getPrimaryIndex(BadKeyClass1.class, UseBadKeyClass1.class); + fail(); + } catch (IllegalArgumentException expected) { + assertTrue(expected.getMessage().indexOf("@KeyField") >= 0); + } + close(); + } + + /** Missing @KeyField in composite key class. */ + @Persistent + static class BadKeyClass1 { + + private int f1; + } + + @Entity + static class UseBadKeyClass1 { + + @PrimaryKey + private BadKeyClass1 f1 = new BadKeyClass1(); + + @SecondaryKey(relate=ONE_TO_ONE) + private BadKeyClass1 f2 = new BadKeyClass1(); + } + + public void testBadSequenceKeys() + throws DatabaseException { + + open(); + try { + store.getPrimaryIndex(Boolean.class, BadSequenceKeyEntity1.class); + fail(); + } catch (IllegalArgumentException expected) { + assertTrue(expected.getMessage().indexOf + ("Type not allowed for sequence") >= 0); + } + try { + store.getPrimaryIndex(BadSequenceKeyEntity2.Key.class, + BadSequenceKeyEntity2.class); + fail(); + } catch (IllegalArgumentException expected) { + assertTrue(expected.getMessage().indexOf + ("Type not allowed for sequence") >= 0); + } + try { + store.getPrimaryIndex(BadSequenceKeyEntity3.Key.class, + BadSequenceKeyEntity3.class); + fail(); + } catch (IllegalArgumentException expected) { + assertTrue(expected.getMessage().indexOf + ("A composite key class used with a sequence may contain " + + "only a single integer key field")>= 0); + } + close(); + } + + /** Boolean not allowed for sequence key. */ + @Entity + static class BadSequenceKeyEntity1 { + + @PrimaryKey(sequence="X") + private boolean key; + } + + /** Composite key with non-integer field not allowed for sequence key. */ + @Entity + static class BadSequenceKeyEntity2 { + + @PrimaryKey(sequence="X") + private Key key; + + @Persistent + static class Key { + @KeyField(1) + boolean key; + } + } + + /** Composite key with multiple key fields not allowed for sequence key. */ + @Entity + static class BadSequenceKeyEntity3 { + + @PrimaryKey(sequence="X") + private Key key; + + @Persistent + static class Key { + @KeyField(1) + int key; + @KeyField(2) + int key2; + } + } + + /** + * A proxied object may not current contain a field that references the + * parent proxy. [#15815] + */ + public void testProxyNestedRef() + throws DatabaseException { + + open(); + PrimaryIndex<Integer,ProxyNestedRef> index = store.getPrimaryIndex + (Integer.class, ProxyNestedRef.class); + ProxyNestedRef entity = new ProxyNestedRef(); + entity.list.add(entity.list); + try { + index.put(entity); + fail(); + } catch (IllegalArgumentException expected) { + assertTrue(expected.getMessage().indexOf + ("Cannot embed a reference to a proxied object") >= 0); + } + close(); + } + + @Entity + static class ProxyNestedRef { + + @PrimaryKey + private int key; + + ArrayList<Object> list = new ArrayList<Object>(); + } + + /** + * Disallow primary keys on entity subclasses. [#15757] + */ + public void testEntitySubclassWithPrimaryKey() + throws DatabaseException { + + open(); + PrimaryIndex<Integer,EntitySuperClass> index = store.getPrimaryIndex + (Integer.class, EntitySuperClass.class); + EntitySuperClass e1 = new EntitySuperClass(1, "one"); + index.put(e1); + assertEquals(e1, index.get(1)); + EntitySubClass e2 = new EntitySubClass(2, "two", "foo", 9); + try { + index.put(e2); + fail(); + } catch (IllegalArgumentException e) { + assertTrue(e.getMessage().contains + ("PrimaryKey may not appear on an Entity subclass")); + } + assertEquals(e1, index.get(1)); + close(); + } + + @Entity + static class EntitySuperClass { + + @PrimaryKey + private int x; + + private String y; + + EntitySuperClass(int x, String y) { + assert y != null; + this.x = x; + this.y = y; + } + + private EntitySuperClass() {} + + @Override + public String toString() { + return "x=" + x + " y=" + y; + } + + @Override + public boolean equals(Object other) { + if (other instanceof EntitySuperClass) { + EntitySuperClass o = (EntitySuperClass) other; + return x == o.x && y.equals(o.y); + } else { + return false; + } + } + } + + @Persistent + static class EntitySubClass extends EntitySuperClass { + + @PrimaryKey + private String foo; + + private int z; + + EntitySubClass(int x, String y, String foo, int z) { + super(x, y); + assert foo != null; + this.foo = foo; + this.z = z; + } + + private EntitySubClass() {} + + @Override + public String toString() { + return super.toString() + " z=" + z; + } + + @Override + public boolean equals(Object other) { + if (other instanceof EntitySubClass) { + EntitySubClass o = (EntitySubClass) other; + return super.equals(o) && z == o.z; + } else { + return false; + } + } + } + + /** + * Disallow embedded entity classes and subclasses. [#16077] + */ + public void testEmbeddedEntity() + throws DatabaseException { + + open(); + PrimaryIndex<Integer,EmbeddingEntity> index = store.getPrimaryIndex + (Integer.class, EmbeddingEntity.class); + EmbeddingEntity e1 = new EmbeddingEntity(1, null); + index.put(e1); + assertEquals(e1, index.get(1)); + + EmbeddingEntity e2 = + new EmbeddingEntity(2, new EntitySuperClass(2, "two")); + try { + index.put(e2); + fail(); + } catch (IllegalArgumentException e) { + assertTrue(e.getMessage().contains + ("References to entities are not allowed")); + } + + EmbeddingEntity e3 = new EmbeddingEntity + (3, new EmbeddedEntitySubClass(3, "three", "foo", 9)); + try { + index.put(e3); + fail(); + } catch (IllegalArgumentException e) { + assertTrue(e.toString(), e.getMessage().contains + ("References to entities are not allowed")); + } + + assertEquals(e1, index.get(1)); + close(); + } + + @Entity + static class EmbeddingEntity { + + @PrimaryKey + private int x; + + private EntitySuperClass y; + + EmbeddingEntity(int x, EntitySuperClass y) { + this.x = x; + this.y = y; + } + + private EmbeddingEntity() {} + + @Override + public String toString() { + return "x=" + x + " y=" + y; + } + + @Override + public boolean equals(Object other) { + if (other instanceof EmbeddingEntity) { + EmbeddingEntity o = (EmbeddingEntity) other; + return x == o.x && + ((y == null) ? (o.y == null) : y.equals(o.y)); + } else { + return false; + } + } + } + + @Persistent + static class EmbeddedEntitySubClass extends EntitySuperClass { + + private String foo; + + private int z; + + EmbeddedEntitySubClass(int x, String y, String foo, int z) { + super(x, y); + assert foo != null; + this.foo = foo; + this.z = z; + } + + private EmbeddedEntitySubClass() {} + + @Override + public String toString() { + return super.toString() + " z=" + z; + } + + @Override + public boolean equals(Object other) { + if (other instanceof EmbeddedEntitySubClass) { + EmbeddedEntitySubClass o = (EmbeddedEntitySubClass) other; + return super.equals(o) && z == o.z; + } else { + return false; + } + } + } + + /** + * Disallow SecondaryKey collection with no type parameter. [#15950] + */ + public void testTypelessKeyCollection() + throws DatabaseException { + + open(); + try { + store.getPrimaryIndex + (Integer.class, TypelessKeyCollectionEntity.class); + fail(); + } catch (IllegalArgumentException e) { + assertTrue(e.toString(), e.getMessage().contains + ("Collection typed secondary key field must have a " + + "single generic type argument and a wildcard or type " + + "bound is not allowed")); + } + close(); + } + + @Entity + static class TypelessKeyCollectionEntity { + + @PrimaryKey + private int x; + + @SecondaryKey(relate=ONE_TO_MANY) + private Collection keys = new ArrayList(); + + TypelessKeyCollectionEntity(int x) { + this.x = x; + } + + private TypelessKeyCollectionEntity() {} + } + + /** + * Disallow a persistent proxy that extends an entity. [#15950] + */ + public void testProxyEntity() + throws DatabaseException { + + try { + open(ProxyExtendsEntity.class); + fail(); + } catch (IllegalArgumentException e) { + assertTrue(e.toString(), e.getMessage().contains + ("A proxy may not be an entity")); + } + } + + @Persistent(proxyFor=BigDecimal.class) + static class ProxyExtendsEntity + extends EntitySuperClass + implements PersistentProxy<BigDecimal> { + + private String rep; + + public BigDecimal convertProxy() { + return new BigDecimal(rep); + } + + public void initializeProxy(BigDecimal o) { + rep = o.toString(); + } + } + + /** + * Wrapper type not allowed for nullified foreign key. + */ + public void testBadNullifyKey() + throws DatabaseException { + + open(); + try { + store.getPrimaryIndex(Integer.class, BadNullifyKeyEntity1.class); + fail(); + } catch (IllegalArgumentException expected) { + assertTrue(expected.getMessage().indexOf + ("NULLIFY may not be used with primitive fields") >= 0); + } + close(); + } + + @Entity + static class BadNullifyKeyEntity1 { + + @PrimaryKey + private int key; + + @SecondaryKey(relate=ONE_TO_ONE, + relatedEntity=BadNullifyKeyEntity2.class, + onRelatedEntityDelete=NULLIFY) + private int secKey; // Should be Integer, not int. + } + + @Entity + static class BadNullifyKeyEntity2 { + + @PrimaryKey + private int key; + } + + /** + * @Persistent not allowed on an enum. + */ + public void testPersistentEnum() + throws DatabaseException { + + open(); + try { + store.getPrimaryIndex(Integer.class, PersistentEnumEntity.class); + fail(); + } catch (IllegalArgumentException expected) { + assertTrue(expected.getMessage().indexOf + ("not allowed for enum, interface, or primitive") >= 0); + } + close(); + } + + @Entity + static class PersistentEnumEntity { + + @PrimaryKey + private int key; + + @Persistent + enum MyEnum {X, Y, Z}; + + MyEnum f1; + } + + /** + * Disallow a reference to an interface marked @Persistent. + */ + public void testPersistentInterface() + throws DatabaseException { + + open(); + try { + store.getPrimaryIndex(Integer.class, + PersistentInterfaceEntity1.class); + fail(); + } catch (IllegalArgumentException expected) { + assertTrue(expected.getMessage().indexOf + ("not allowed for enum, interface, or primitive") >= 0); + } + close(); + } + + @Entity + static class PersistentInterfaceEntity1 { + + @PrimaryKey + private int key; + + @SecondaryKey(relate=ONE_TO_ONE, + relatedEntity=PersistentInterfaceEntity2.class) + private int secKey; // Should be Integer, not int. + } + + @Persistent + interface PersistentInterfaceEntity2 { + } + + /** + * Disallow reference to @Persistent inner class. + */ + public void testPersistentInnerClass() + throws DatabaseException { + + open(); + try { + store.getPrimaryIndex(Integer.class, + PersistentInnerClassEntity1.class); + fail(); + } catch (IllegalArgumentException expected) { + assertTrue(expected.getMessage().indexOf + ("Inner classes not allowed") >= 0); + } + close(); + } + + @Entity + static class PersistentInnerClassEntity1 { + + @PrimaryKey + private int key; + + private PersistentInnerClass f; + } + + /* An inner (non-static) class is illegal. */ + @Persistent + class PersistentInnerClass { + + private int x; + } + + /** + * Disallow @Entity inner class. + */ + public void testEntityInnerClass() + throws DatabaseException { + + open(); + try { + store.getPrimaryIndex(Integer.class, + EntityInnerClassEntity.class); + fail(); + } catch (IllegalArgumentException expected) { + assertTrue(expected.getMessage().indexOf + ("Inner classes not allowed") >= 0); + } + close(); + } + + /* An inner (non-static) class is illegal. */ + @Entity + class EntityInnerClassEntity { + + @PrimaryKey + private int key; + } +} diff --git a/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/OperationTest.java b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/OperationTest.java new file mode 100644 index 0000000..4fc81fc --- /dev/null +++ b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/OperationTest.java @@ -0,0 +1,1552 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2002-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +package com.sleepycat.persist.test; + +import static com.sleepycat.persist.model.DeleteAction.CASCADE; +import static com.sleepycat.persist.model.DeleteAction.NULLIFY; +import static com.sleepycat.persist.model.Relationship.MANY_TO_MANY; +import static com.sleepycat.persist.model.Relationship.MANY_TO_ONE; +import static com.sleepycat.persist.model.Relationship.ONE_TO_MANY; +import static com.sleepycat.persist.model.Relationship.ONE_TO_ONE; + +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import junit.framework.Test; + +import com.sleepycat.compat.DbCompat; +import com.sleepycat.db.Database; +import com.sleepycat.db.DatabaseConfig; +import com.sleepycat.db.DatabaseException; +import com.sleepycat.db.StatsConfig; +import com.sleepycat.db.Transaction; +import com.sleepycat.persist.EntityCursor; +import com.sleepycat.persist.EntityIndex; +import com.sleepycat.persist.EntityStore; +import com.sleepycat.persist.PrimaryIndex; +import com.sleepycat.persist.SecondaryIndex; +import com.sleepycat.persist.StoreConfig; +import com.sleepycat.persist.impl.Store; +import com.sleepycat.persist.model.Entity; +import com.sleepycat.persist.model.KeyField; +import com.sleepycat.persist.model.NotPersistent; +import com.sleepycat.persist.model.NotTransient; +import com.sleepycat.persist.model.Persistent; +import com.sleepycat.persist.model.PrimaryKey; +import com.sleepycat.persist.model.SecondaryKey; +import com.sleepycat.persist.raw.RawStore; +import com.sleepycat.util.test.TxnTestCase; + +/** + * Tests misc store and index operations that are not tested by IndexTest. + * + * @author Mark Hayes + */ +public class OperationTest extends TxnTestCase { + + private static final String STORE_NAME = "test"; + + static protected Class<?> testClass = OperationTest.class; + + public static Test suite() { + return txnTestSuite(testClass, null, null); + } + + private EntityStore store; + + private void openReadOnly() + throws DatabaseException { + + StoreConfig config = new StoreConfig(); + config.setReadOnly(true); + open(config); + } + + private void open() + throws DatabaseException { + + open((Class) null); + } + + private void open(Class clsToRegister) + throws DatabaseException { + + StoreConfig config = new StoreConfig(); + config.setAllowCreate(envConfig.getAllowCreate()); + if (clsToRegister != null) { + com.sleepycat.persist.model.EntityModel model = + new com.sleepycat.persist.model.AnnotationModel(); + model.registerClass(clsToRegister); + config.setModel(model); + } + open(config); + } + + private void open(StoreConfig config) + throws DatabaseException { + + config.setTransactional(envConfig.getTransactional()); + store = new EntityStore(env, STORE_NAME, config); + } + + private void close() + throws DatabaseException { + + store.close(); + store = null; + } + + @Override + public void setUp() + throws Exception { + + super.setUp(); + } + + /** + * The store must be closed before closing the environment. + */ + @Override + public void tearDown() + throws Exception { + + try { + if (store != null) { + store.close(); + } + } catch (Throwable e) { + System.out.println("During tearDown: " + e); + } + store = null; + super.tearDown(); + } + + public void testReadOnly() + throws DatabaseException { + + open(); + PrimaryIndex<Integer,SharedSequenceEntity1> priIndex = + store.getPrimaryIndex(Integer.class, SharedSequenceEntity1.class); + Transaction txn = txnBegin(); + SharedSequenceEntity1 e = new SharedSequenceEntity1(); + priIndex.put(txn, e); + assertEquals(1, e.key); + txnCommit(txn); + close(); + + /* + * Check that we can open the store read-only and read the records + * written above. + */ + openReadOnly(); + priIndex = + store.getPrimaryIndex(Integer.class, SharedSequenceEntity1.class); + e = priIndex.get(1); + assertNotNull(e); + close(); + } + + + + public void testUninitializedCursor() + throws DatabaseException { + + open(); + + PrimaryIndex<Integer,MyEntity> priIndex = + store.getPrimaryIndex(Integer.class, MyEntity.class); + + Transaction txn = txnBeginCursor(); + + MyEntity e = new MyEntity(); + e.priKey = 1; + e.secKey = 1; + priIndex.put(txn, e); + + EntityCursor<MyEntity> entities = priIndex.entities(txn, null); + try { + entities.nextDup(); + fail(); + } catch (IllegalStateException expected) {} + try { + entities.prevDup(); + fail(); + } catch (IllegalStateException expected) {} + try { + entities.current(); + fail(); + } catch (IllegalStateException expected) {} + try { + entities.delete(); + fail(); + } catch (IllegalStateException expected) {} + try { + entities.update(e); + fail(); + } catch (IllegalStateException expected) {} + try { + entities.count(); + fail(); + } catch (IllegalStateException expected) {} + + entities.close(); + txnCommit(txn); + close(); + } + + public void testCursorCount() + throws DatabaseException { + + open(); + + PrimaryIndex<Integer,MyEntity> priIndex = + store.getPrimaryIndex(Integer.class, MyEntity.class); + + SecondaryIndex<Integer,Integer,MyEntity> secIndex = + store.getSecondaryIndex(priIndex, Integer.class, "secKey"); + + Transaction txn = txnBeginCursor(); + + MyEntity e = new MyEntity(); + e.priKey = 1; + e.secKey = 1; + priIndex.put(txn, e); + + EntityCursor<MyEntity> cursor = secIndex.entities(txn, null); + cursor.next(); + assertEquals(1, cursor.count()); + cursor.close(); + + e.priKey = 2; + priIndex.put(txn, e); + cursor = secIndex.entities(txn, null); + cursor.next(); + assertEquals(2, cursor.count()); + cursor.close(); + + txnCommit(txn); + close(); + } + + public void testCursorUpdate() + throws DatabaseException { + + open(); + + PrimaryIndex<Integer,MyEntity> priIndex = + store.getPrimaryIndex(Integer.class, MyEntity.class); + + SecondaryIndex<Integer,Integer,MyEntity> secIndex = + store.getSecondaryIndex(priIndex, Integer.class, "secKey"); + + Transaction txn = txnBeginCursor(); + + Integer k; + MyEntity e = new MyEntity(); + e.priKey = 1; + e.secKey = 2; + priIndex.put(txn, e); + + /* update() with primary entity cursor. */ + EntityCursor<MyEntity> entities = priIndex.entities(txn, null); + e = entities.next(); + assertNotNull(e); + assertEquals(1, e.priKey); + assertEquals(Integer.valueOf(2), e.secKey); + e.secKey = null; + assertTrue(entities.update(e)); + e = entities.current(); + assertNotNull(e); + assertEquals(1, e.priKey); + assertEquals(null, e.secKey); + e.secKey = 3; + assertTrue(entities.update(e)); + e = entities.current(); + assertNotNull(e); + assertEquals(1, e.priKey); + assertEquals(Integer.valueOf(3), e.secKey); + entities.close(); + + /* update() with primary keys cursor. */ + EntityCursor<Integer> keys = priIndex.keys(txn, null); + k = keys.next(); + assertNotNull(k); + assertEquals(Integer.valueOf(1), k); + try { + keys.update(2); + fail(); + } catch (UnsupportedOperationException expected) { + } + keys.close(); + + /* update() with secondary entity cursor. */ + entities = secIndex.entities(txn, null); + e = entities.next(); + assertNotNull(e); + assertEquals(1, e.priKey); + assertEquals(Integer.valueOf(3), e.secKey); + try { + entities.update(e); + fail(); + } catch (UnsupportedOperationException expected) { + } catch (IllegalArgumentException expectedForDbCore) { + } + entities.close(); + + /* update() with secondary keys cursor. */ + keys = secIndex.keys(txn, null); + k = keys.next(); + assertNotNull(k); + assertEquals(Integer.valueOf(3), k); + try { + keys.update(k); + fail(); + } catch (UnsupportedOperationException expected) { + } + keys.close(); + + txnCommit(txn); + close(); + } + + public void testCursorDelete() + throws DatabaseException { + + open(); + + PrimaryIndex<Integer,MyEntity> priIndex = + store.getPrimaryIndex(Integer.class, MyEntity.class); + + SecondaryIndex<Integer,Integer,MyEntity> secIndex = + store.getSecondaryIndex(priIndex, Integer.class, "secKey"); + + Transaction txn = txnBeginCursor(); + + /* delete() with primary and secondary entities cursor. */ + + for (EntityIndex index : new EntityIndex[] { priIndex, secIndex }) { + + MyEntity e = new MyEntity(); + e.priKey = 1; + e.secKey = 1; + priIndex.put(txn, e); + e.priKey = 2; + priIndex.put(txn, e); + + EntityCursor<MyEntity> cursor = index.entities(txn, null); + + e = cursor.next(); + assertNotNull(e); + assertEquals(1, e.priKey); + e = cursor.current(); + assertNotNull(e); + assertEquals(1, e.priKey); + assertTrue(cursor.delete()); + assertTrue(!cursor.delete()); + assertNull(cursor.current()); + + e = cursor.next(); + assertNotNull(e); + assertEquals(2, e.priKey); + e = cursor.current(); + assertNotNull(e); + assertEquals(2, e.priKey); + assertTrue(cursor.delete()); + assertTrue(!cursor.delete()); + assertNull(cursor.current()); + + e = cursor.next(); + assertNull(e); + + if (index == priIndex) { + e = new MyEntity(); + e.priKey = 2; + e.secKey = 1; + assertTrue(!cursor.update(e)); + } + + cursor.close(); + } + + /* delete() with primary and secondary keys cursor. */ + + for (EntityIndex index : new EntityIndex[] { priIndex, secIndex }) { + + MyEntity e = new MyEntity(); + e.priKey = 1; + e.secKey = 1; + priIndex.put(txn, e); + e.priKey = 2; + priIndex.put(txn, e); + + EntityCursor<Integer> cursor = index.keys(txn, null); + + Integer k = cursor.next(); + assertNotNull(k); + assertEquals(1, k.intValue()); + k = cursor.current(); + assertNotNull(k); + assertEquals(1, k.intValue()); + assertTrue(cursor.delete()); + assertTrue(!cursor.delete()); + assertNull(cursor.current()); + + int expectKey = (index == priIndex) ? 2 : 1; + k = cursor.next(); + assertNotNull(k); + assertEquals(expectKey, k.intValue()); + k = cursor.current(); + assertNotNull(k); + assertEquals(expectKey, k.intValue()); + assertTrue(cursor.delete()); + assertTrue(!cursor.delete()); + assertNull(cursor.current()); + + k = cursor.next(); + assertNull(k); + + cursor.close(); + } + + txnCommit(txn); + close(); + } + + public void testDeleteFromSubIndex() + throws DatabaseException { + + open(); + + PrimaryIndex<Integer,MyEntity> priIndex = + store.getPrimaryIndex(Integer.class, MyEntity.class); + + SecondaryIndex<Integer,Integer,MyEntity> secIndex = + store.getSecondaryIndex(priIndex, Integer.class, "secKey"); + + Transaction txn = txnBegin(); + MyEntity e = new MyEntity(); + e.secKey = 1; + e.priKey = 1; + priIndex.put(txn, e); + e.priKey = 2; + priIndex.put(txn, e); + e.priKey = 3; + priIndex.put(txn, e); + e.priKey = 4; + priIndex.put(txn, e); + txnCommit(txn); + + EntityIndex<Integer,MyEntity> subIndex = secIndex.subIndex(1); + txn = txnBeginCursor(); + e = subIndex.get(txn, 1, null); + assertEquals(1, e.priKey); + assertEquals(Integer.valueOf(1), e.secKey); + e = subIndex.get(txn, 2, null); + assertEquals(2, e.priKey); + assertEquals(Integer.valueOf(1), e.secKey); + e = subIndex.get(txn, 3, null); + assertEquals(3, e.priKey); + assertEquals(Integer.valueOf(1), e.secKey); + e = subIndex.get(txn, 5, null); + assertNull(e); + + boolean deleted = subIndex.delete(txn, 1); + assertTrue(deleted); + assertNull(subIndex.get(txn, 1, null)); + assertNotNull(subIndex.get(txn, 2, null)); + + EntityCursor<MyEntity> cursor = subIndex.entities(txn, null); + boolean saw4 = false; + for (MyEntity e2 = cursor.first(); e2 != null; e2 = cursor.next()) { + if (e2.priKey == 3) { + cursor.delete(); + } + if (e2.priKey == 4) { + saw4 = true; + } + } + cursor.close(); + assertTrue(saw4); + assertNull(subIndex.get(txn, 1, null)); + assertNull(subIndex.get(txn, 3, null)); + assertNotNull(subIndex.get(txn, 2, null)); + assertNotNull(subIndex.get(txn, 4, null)); + + txnCommit(txn); + close(); + } + + @Entity + static class MyEntity { + + @PrimaryKey + private int priKey; + + @SecondaryKey(relate=MANY_TO_ONE) + private Integer secKey; + + private MyEntity() {} + } + + public void testSharedSequence() + throws DatabaseException { + + open(); + + PrimaryIndex<Integer,SharedSequenceEntity1> priIndex1 = + store.getPrimaryIndex(Integer.class, SharedSequenceEntity1.class); + + PrimaryIndex<Integer,SharedSequenceEntity2> priIndex2 = + store.getPrimaryIndex(Integer.class, SharedSequenceEntity2.class); + + Transaction txn = txnBegin(); + SharedSequenceEntity1 e1 = new SharedSequenceEntity1(); + SharedSequenceEntity2 e2 = new SharedSequenceEntity2(); + priIndex1.put(txn, e1); + assertEquals(1, e1.key); + priIndex2.putNoOverwrite(txn, e2); + assertEquals(Integer.valueOf(2), e2.key); + e1.key = 0; + priIndex1.putNoOverwrite(txn, e1); + assertEquals(3, e1.key); + e2.key = null; + priIndex2.put(txn, e2); + assertEquals(Integer.valueOf(4), e2.key); + txnCommit(txn); + + close(); + } + + @Entity + static class SharedSequenceEntity1 { + + @PrimaryKey(sequence="shared") + private int key; + } + + @Entity + static class SharedSequenceEntity2 { + + @PrimaryKey(sequence="shared") + private Integer key; + } + + public void testSeparateSequence() + throws DatabaseException { + + open(); + + PrimaryIndex<Integer,SeparateSequenceEntity1> priIndex1 = + store.getPrimaryIndex + (Integer.class, SeparateSequenceEntity1.class); + + PrimaryIndex<Integer,SeparateSequenceEntity2> priIndex2 = + store.getPrimaryIndex + (Integer.class, SeparateSequenceEntity2.class); + + Transaction txn = txnBegin(); + SeparateSequenceEntity1 e1 = new SeparateSequenceEntity1(); + SeparateSequenceEntity2 e2 = new SeparateSequenceEntity2(); + priIndex1.put(txn, e1); + assertEquals(1, e1.key); + priIndex2.putNoOverwrite(txn, e2); + assertEquals(Integer.valueOf(1), e2.key); + e1.key = 0; + priIndex1.putNoOverwrite(txn, e1); + assertEquals(2, e1.key); + e2.key = null; + priIndex2.put(txn, e2); + assertEquals(Integer.valueOf(2), e2.key); + txnCommit(txn); + + close(); + } + + @Entity + static class SeparateSequenceEntity1 { + + @PrimaryKey(sequence="seq1") + private int key; + } + + @Entity + static class SeparateSequenceEntity2 { + + @PrimaryKey(sequence="seq2") + private Integer key; + } + + public void testCompositeSequence() + throws DatabaseException { + + open(); + + PrimaryIndex<CompositeSequenceEntity1.Key,CompositeSequenceEntity1> + priIndex1 = + store.getPrimaryIndex + (CompositeSequenceEntity1.Key.class, + CompositeSequenceEntity1.class); + + PrimaryIndex<CompositeSequenceEntity2.Key,CompositeSequenceEntity2> + priIndex2 = + store.getPrimaryIndex + (CompositeSequenceEntity2.Key.class, + CompositeSequenceEntity2.class); + + Transaction txn = txnBegin(); + CompositeSequenceEntity1 e1 = new CompositeSequenceEntity1(); + CompositeSequenceEntity2 e2 = new CompositeSequenceEntity2(); + priIndex1.put(txn, e1); + assertEquals(1, e1.key.key); + priIndex2.putNoOverwrite(txn, e2); + assertEquals(Integer.valueOf(1), e2.key.key); + e1.key = null; + priIndex1.putNoOverwrite(txn, e1); + assertEquals(2, e1.key.key); + e2.key = null; + priIndex2.put(txn, e2); + assertEquals(Integer.valueOf(2), e2.key.key); + txnCommit(txn); + + EntityCursor<CompositeSequenceEntity1> c1 = priIndex1.entities(); + e1 = c1.next(); + assertEquals(2, e1.key.key); + e1 = c1.next(); + assertEquals(1, e1.key.key); + e1 = c1.next(); + assertNull(e1); + c1.close(); + + EntityCursor<CompositeSequenceEntity2> c2 = priIndex2.entities(); + e2 = c2.next(); + assertEquals(Integer.valueOf(2), e2.key.key); + e2 = c2.next(); + assertEquals(Integer.valueOf(1), e2.key.key); + e2 = c2.next(); + assertNull(e2); + c2.close(); + + close(); + } + + @Entity + static class CompositeSequenceEntity1 { + + @Persistent + static class Key implements Comparable<Key> { + + @KeyField(1) + private int key; + + public int compareTo(Key o) { + /* Reverse the natural order. */ + return o.key - key; + } + } + + @PrimaryKey(sequence="seq1") + private Key key; + } + + /** + * Same as CompositeSequenceEntity1 but using Integer rather than int for + * the key type. + */ + @Entity + static class CompositeSequenceEntity2 { + + @Persistent + static class Key implements Comparable<Key> { + + @KeyField(1) + private Integer key; + + public int compareTo(Key o) { + /* Reverse the natural order. */ + return o.key - key; + } + } + + @PrimaryKey(sequence="seq2") + private Key key; + } + + /** + * When opening read-only, secondaries are not opened when the primary is + * opened, causing a different code path to be used for opening + * secondaries. For a RawStore in particular, this caused an unreported + * NullPointerException in JE 3.0.12. No SR was created because the use + * case is very obscure and was discovered by code inspection. + */ + public void testOpenRawStoreReadOnly() + throws DatabaseException { + + open(); + store.getPrimaryIndex(Integer.class, MyEntity.class); + close(); + + StoreConfig config = new StoreConfig(); + config.setReadOnly(true); + config.setTransactional(envConfig.getTransactional()); + RawStore rawStore = new RawStore(env, "test", config); + + String clsName = MyEntity.class.getName(); + rawStore.getSecondaryIndex(clsName, "secKey"); + + rawStore.close(); + } + + /** + * When opening an X_TO_MANY secondary that has a persistent key class, the + * key class was not recognized as being persistent if it was never before + * referenced when getSecondaryIndex was called. This was a bug in JE + * 3.0.12, reported on OTN. [#15103] + */ + public void testToManyKeyClass() + throws DatabaseException { + + open(); + + PrimaryIndex<Integer,ToManyKeyEntity> priIndex = + store.getPrimaryIndex(Integer.class, ToManyKeyEntity.class); + SecondaryIndex<ToManyKey,Integer,ToManyKeyEntity> secIndex = + store.getSecondaryIndex(priIndex, ToManyKey.class, "key2"); + + priIndex.put(new ToManyKeyEntity()); + secIndex.get(new ToManyKey()); + + close(); + } + + /** + * Test a fix for a bug where opening a TO_MANY secondary index would fail + * fail with "IllegalArgumentException: Wrong secondary key class: ..." + * when the store was opened read-only. [#15156] + */ + public void testToManyReadOnly() + throws DatabaseException { + + open(); + PrimaryIndex<Integer,ToManyKeyEntity> priIndex = + store.getPrimaryIndex(Integer.class, ToManyKeyEntity.class); + priIndex.put(new ToManyKeyEntity()); + close(); + + openReadOnly(); + priIndex = store.getPrimaryIndex(Integer.class, ToManyKeyEntity.class); + SecondaryIndex<ToManyKey,Integer,ToManyKeyEntity> secIndex = + store.getSecondaryIndex(priIndex, ToManyKey.class, "key2"); + secIndex.get(new ToManyKey()); + close(); + } + + @Persistent + static class ToManyKey { + + @KeyField(1) + int value = 99; + } + + @Entity + static class ToManyKeyEntity { + + @PrimaryKey + int key = 88; + + @SecondaryKey(relate=ONE_TO_MANY) + Set<ToManyKey> key2; + + ToManyKeyEntity() { + key2 = new HashSet<ToManyKey>(); + key2.add(new ToManyKey()); + } + } + + + + /** + * When Y is opened and X has a key with relatedEntity=Y.class, X should + * be opened automatically. If X is not opened, foreign key constraints + * will not be enforced. [#15358] + */ + public void testAutoOpenRelatedEntity() + throws DatabaseException { + + PrimaryIndex<Integer,RelatedY> priY; + PrimaryIndex<Integer,RelatedX> priX; + + /* Opening X should create (and open) Y and enforce constraints. */ + open(); + priX = store.getPrimaryIndex(Integer.class, RelatedX.class); + PersistTestUtils.assertDbExists + (true, env, STORE_NAME, RelatedY.class.getName(), null); + if (isTransactional) { + /* Constraint enforcement requires transactions. */ + try { + priX.put(new RelatedX()); + fail(); + } catch (DatabaseException e) { + assertTrue + ("" + e.getMessage(), (e.getMessage().indexOf + ("foreign key not allowed: it is not present") >= 0) || + (e.getMessage().indexOf("DB_FOREIGN_CONFLICT") >= 0)); + } + } + priY = store.getPrimaryIndex(Integer.class, RelatedY.class); + priY.put(new RelatedY()); + priX.put(new RelatedX()); + close(); + + /* Delete should cascade even when X is not opened explicitly. */ + open(); + priY = store.getPrimaryIndex(Integer.class, RelatedY.class); + assertEquals(1, priY.count()); + priY.delete(88); + assertEquals(0, priY.count()); + priX = store.getPrimaryIndex(Integer.class, RelatedX.class); + assertEquals(0, priX.count()); /* Failed prior to [#15358] fix. */ + close(); + } + + @Entity + static class RelatedX { + + @PrimaryKey + int key = 99; + + @SecondaryKey(relate=ONE_TO_ONE, + relatedEntity=RelatedY.class, + onRelatedEntityDelete=CASCADE) + int key2 = 88; + + RelatedX() { + } + } + + @Entity + static class RelatedY { + + @PrimaryKey + int key = 88; + + RelatedY() { + } + } + + public void testSecondaryBulkLoad1() + throws DatabaseException { + + doSecondaryBulkLoad(true); + } + + public void testSecondaryBulkLoad2() + throws DatabaseException { + + doSecondaryBulkLoad(false); + } + + private void doSecondaryBulkLoad(boolean closeAndOpenNormally) + throws DatabaseException { + + PrimaryIndex<Integer,RelatedX> priX; + PrimaryIndex<Integer,RelatedY> priY; + SecondaryIndex<Integer,Integer,RelatedX> secX; + + /* Open priX with SecondaryBulkLoad=true. */ + StoreConfig config = new StoreConfig(); + config.setAllowCreate(true); + config.setSecondaryBulkLoad(true); + open(config); + + /* Getting priX should not create the secondary index. */ + priX = store.getPrimaryIndex(Integer.class, RelatedX.class); + PersistTestUtils.assertDbExists + (false, env, STORE_NAME, RelatedX.class.getName(), "key2"); + + /* We can put records that violate the secondary key constraint. */ + priX.put(new RelatedX()); + + if (closeAndOpenNormally) { + /* Open normally and attempt to populate the secondary. */ + close(); + open(); + if (isTransactional && DbCompat.POPULATE_ENFORCES_CONSTRAINTS) { + /* Constraint enforcement requires transactions. */ + try { + /* Before adding the foreign key, constraint is violated. */ + priX = store.getPrimaryIndex(Integer.class, + RelatedX.class); + fail(); + } catch (DatabaseException e) { + assertTrue + (e.toString(), + e.toString().contains("foreign key not allowed")); + } + } + /* Open priX with SecondaryBulkLoad=true. */ + close(); + open(config); + /* Add the foreign key to avoid the constraint error. */ + priY = store.getPrimaryIndex(Integer.class, RelatedY.class); + priY.put(new RelatedY()); + /* Open normally and the secondary will be populated. */ + close(); + open(); + priX = store.getPrimaryIndex(Integer.class, RelatedX.class); + PersistTestUtils.assertDbExists + (true, env, STORE_NAME, RelatedX.class.getName(), "key2"); + secX = store.getSecondaryIndex(priX, Integer.class, "key2"); + } else { + /* Get secondary index explicitly and it will be populated. */ + if (isTransactional && DbCompat.POPULATE_ENFORCES_CONSTRAINTS) { + /* Constraint enforcement requires transactions. */ + try { + /* Before adding the foreign key, constraint is violated. */ + secX = store.getSecondaryIndex(priX, Integer.class, + "key2"); + fail(); + } catch (DatabaseException e) { + assertTrue + (e.toString(), + e.toString().contains("foreign key not allowed")); + } + } + /* Add the foreign key. */ + priY = store.getPrimaryIndex(Integer.class, RelatedY.class); + priY.put(new RelatedY()); + secX = store.getSecondaryIndex(priX, Integer.class, "key2"); + PersistTestUtils.assertDbExists + (true, env, STORE_NAME, RelatedX.class.getName(), "key2"); + } + + RelatedX x = secX.get(88); + assertNotNull(x); + close(); + } + + public void testPersistentFields() + throws DatabaseException { + + open(); + PrimaryIndex<Integer, PersistentFields> pri = + store.getPrimaryIndex(Integer.class, PersistentFields.class); + PersistentFields o1 = new PersistentFields(-1, 1, 2, 3, 4, 5, 6); + assertNull(pri.put(o1)); + PersistentFields o2 = pri.get(-1); + assertNotNull(o2); + assertEquals(0, o2.transient1); + assertEquals(0, o2.transient2); + assertEquals(0, o2.transient3); + assertEquals(4, o2.persistent1); + assertEquals(5, o2.persistent2); + assertEquals(6, o2.persistent3); + close(); + } + + @Entity + static class PersistentFields { + + @PrimaryKey int key; + + transient int transient1; + @NotPersistent int transient2; + @NotPersistent transient int transient3; + + int persistent1; + @NotTransient int persistent2; + @NotTransient transient int persistent3; + + PersistentFields(int k, + int t1, + int t2, + int t3, + int p1, + int p2, + int p3) { + key = k; + transient1 = t1; + transient2 = t2; + transient3 = t3; + persistent1 = p1; + persistent2 = p2; + persistent3 = p3; + } + + private PersistentFields() {} + } + + /** + * When a primary or secondary has a persistent key class, the key class + * was not recognized as being persistent when getPrimaryConfig, + * getSecondaryConfig, or getSubclassIndex was called, if that key class + * was not previously referenced. All three cases are tested by calling + * getSecondaryConfig. This was a bug in JE 3.3.69, reported on OTN. + * [#16407] + */ + public void testKeyClassInitialization() + throws DatabaseException { + + open(); + store.getSecondaryConfig(ToManyKeyEntity.class, "key2"); + close(); + } + + public void testKeyName() + throws DatabaseException { + + open(); + + PrimaryIndex<Long, BookEntity> pri1 = + store.getPrimaryIndex(Long.class, BookEntity.class); + PrimaryIndex<Long, AuthorEntity> pri2 = + store.getPrimaryIndex(Long.class, AuthorEntity.class); + + BookEntity book = new BookEntity(); + pri1.put(book); + AuthorEntity author = new AuthorEntity(); + author.bookIds.add(book.bookId); + pri2.put(author); + + close(); + + open(); + pri1 = store.getPrimaryIndex(Long.class, BookEntity.class); + pri2 = store.getPrimaryIndex(Long.class, AuthorEntity.class); + book = pri1.get(1L); + assertNotNull(book); + author = pri2.get(1L); + assertNotNull(author); + close(); + } + + @Entity + static class AuthorEntity { + + @PrimaryKey(sequence="authorSeq") + long authorId; + + @SecondaryKey(relate=MANY_TO_MANY, relatedEntity=BookEntity.class, + name="bookId", onRelatedEntityDelete=NULLIFY) + Set<Long> bookIds = new HashSet<Long>(); + } + + @Entity + static class BookEntity { + + @PrimaryKey(sequence="bookSeq") + long bookId; + } + + /** + * Checks that we get an appropriate exception when storing an entity + * subclass instance, which contains a secondary key, without registering + * the subclass up front. [#16399] + */ + public void testPutEntitySubclassWithoutRegisterClass() + throws DatabaseException { + + open(); + + final PrimaryIndex<Long, Statement> pri = + store.getPrimaryIndex(Long.class, Statement.class); + + final Transaction txn = txnBegin(); + pri.put(txn, new Statement(1)); + try { + pri.put(txn, new ExtendedStatement(2, null)); + fail(); + } catch (IllegalArgumentException expected) { + assertTrue(expected.toString(), expected.getMessage().contains + ("Entity subclasses defining a secondary key must be " + + "registered by calling EntityModel.registerClass or " + + "EntityStore.getSubclassIndex before storing an instance " + + "of the subclass: " + ExtendedStatement.class.getName())); + } + txnAbort(txn); + + close(); + } + + /** + * Checks that registerClass avoids an exception when storing an entity + * subclass instance, which defines a secondary key. [#16399] + */ + public void testPutEntitySubclassWithRegisterClass() + throws DatabaseException { + + open(ExtendedStatement.class); + + final PrimaryIndex<Long, Statement> pri = + store.getPrimaryIndex(Long.class, Statement.class); + + final Transaction txn = txnBegin(); + pri.put(txn, new Statement(1)); + pri.put(txn, new ExtendedStatement(2, "abc")); + txnCommit(txn); + + final SecondaryIndex<String, Long, ExtendedStatement> sec = + store.getSubclassIndex(pri, ExtendedStatement.class, + String.class, "name"); + + ExtendedStatement o = sec.get("abc"); + assertNotNull(o); + assertEquals(2, o.id); + + close(); + } + + /** + * Same as testPutEntitySubclassWithRegisterClass but store the first + * instance of the subclass after closing and reopening the store, + * *without* calling registerClass. This ensures that a single call to + * registerClass is sufficient and subsequent use of the store does not + * require it. [#16399] + */ + public void testPutEntitySubclassWithRegisterClass2() + throws DatabaseException { + + open(ExtendedStatement.class); + + PrimaryIndex<Long, Statement> pri = + store.getPrimaryIndex(Long.class, Statement.class); + + Transaction txn = txnBegin(); + pri.put(txn, new Statement(1)); + txnCommit(txn); + + close(); + open(); + + pri = store.getPrimaryIndex(Long.class, Statement.class); + + txn = txnBegin(); + pri.put(txn, new ExtendedStatement(2, "abc")); + txnCommit(txn); + + final SecondaryIndex<String, Long, ExtendedStatement> sec = + store.getSubclassIndex(pri, ExtendedStatement.class, + String.class, "name"); + + ExtendedStatement o = sec.get("abc"); + assertNotNull(o); + assertEquals(2, o.id); + + close(); + } + + /** + * Checks that getSubclassIndex can be used instead of registerClass to + * avoid an exception when storing an entity subclass instance, which + * defines a secondary key. [#16399] + */ + public void testPutEntitySubclassWithGetSubclassIndex() + throws DatabaseException { + + open(); + + final PrimaryIndex<Long, Statement> pri = + store.getPrimaryIndex(Long.class, Statement.class); + + final SecondaryIndex<String, Long, ExtendedStatement> sec = + store.getSubclassIndex(pri, ExtendedStatement.class, + String.class, "name"); + + final Transaction txn = txnBegin(); + pri.put(txn, new Statement(1)); + pri.put(txn, new ExtendedStatement(2, "abc")); + txnCommit(txn); + + ExtendedStatement o = sec.get("abc"); + assertNotNull(o); + assertEquals(2, o.id); + + close(); + } + + /** + * Same as testPutEntitySubclassWithGetSubclassIndex2 but store the first + * instance of the subclass after closing and reopening the store, + * *without* calling getSubclassIndex. This ensures that a single call to + * getSubclassIndex is sufficient and subsequent use of the store does not + * require it. [#16399] + */ + public void testPutEntitySubclassWithGetSubclassIndex2() + throws DatabaseException { + + open(); + + PrimaryIndex<Long, Statement> pri = + store.getPrimaryIndex(Long.class, Statement.class); + + SecondaryIndex<String, Long, ExtendedStatement> sec = + store.getSubclassIndex(pri, ExtendedStatement.class, + String.class, "name"); + + Transaction txn = txnBegin(); + pri.put(txn, new Statement(1)); + txnCommit(txn); + + close(); + open(); + + pri = store.getPrimaryIndex(Long.class, Statement.class); + + txn = txnBegin(); + pri.put(txn, new ExtendedStatement(2, "abc")); + txnCommit(txn); + + sec = store.getSubclassIndex(pri, ExtendedStatement.class, + String.class, "name"); + + ExtendedStatement o = sec.get("abc"); + assertNotNull(o); + assertEquals(2, o.id); + + close(); + } + + /** + * Checks that secondary population occurs only once when an index is + * created, not every time it is opened, even when it is empty. This is a + * JE-only test because we don't have a portable way to get stats that + * indicate whether primary reads were performed. [#16399] + */ + + @Entity + static class Statement { + + @PrimaryKey + long id; + + Statement(long id) { + this.id = id; + } + + private Statement() {} + } + + @Persistent + static class ExtendedStatement extends Statement { + + @SecondaryKey(relate=MANY_TO_ONE) + String name; + + ExtendedStatement(long id, String name) { + super(id); + this.name = name; + } + + private ExtendedStatement() {} + } + + public void testCustomCompare() + throws DatabaseException { + + open(); + + PrimaryIndex<ReverseIntKey, CustomCompareEntity> + priIndex = store.getPrimaryIndex + (ReverseIntKey.class, CustomCompareEntity.class); + + SecondaryIndex<ReverseIntKey, ReverseIntKey, CustomCompareEntity> + secIndex1 = store.getSecondaryIndex(priIndex, ReverseIntKey.class, + "secKey1"); + + SecondaryIndex<ReverseIntKey, ReverseIntKey, CustomCompareEntity> + secIndex2 = store.getSecondaryIndex(priIndex, ReverseIntKey.class, + "secKey2"); + + Transaction txn = txnBegin(); + for (int i = 1; i <= 5; i += 1) { + assertTrue(priIndex.putNoOverwrite(txn, + new CustomCompareEntity(i))); + } + txnCommit(txn); + + txn = txnBeginCursor(); + EntityCursor<CustomCompareEntity> c = priIndex.entities(txn, null); + for (int i = 5; i >= 1; i -= 1) { + CustomCompareEntity e = c.next(); + assertNotNull(e); + assertEquals(new ReverseIntKey(i), e.key); + } + c.close(); + txnCommit(txn); + + txn = txnBeginCursor(); + c = secIndex1.entities(txn, null); + for (int i = -1; i >= -5; i -= 1) { + CustomCompareEntity e = c.next(); + assertNotNull(e); + assertEquals(new ReverseIntKey(-i), e.key); + assertEquals(new ReverseIntKey(i), e.secKey1); + } + c.close(); + txnCommit(txn); + + txn = txnBeginCursor(); + c = secIndex2.entities(txn, null); + for (int i = -1; i >= -5; i -= 1) { + CustomCompareEntity e = c.next(); + assertNotNull(e); + assertEquals(new ReverseIntKey(-i), e.key); + assertTrue(e.secKey2.contains(new ReverseIntKey(i))); + } + c.close(); + txnCommit(txn); + + close(); + } + + @Entity + static class CustomCompareEntity { + + @PrimaryKey + private ReverseIntKey key; + + @SecondaryKey(relate=MANY_TO_ONE) + private ReverseIntKey secKey1; + + @SecondaryKey(relate=ONE_TO_MANY) + private Set<ReverseIntKey> secKey2 = new HashSet<ReverseIntKey>(); + + private CustomCompareEntity() {} + + CustomCompareEntity(int i) { + key = new ReverseIntKey(i); + secKey1 = new ReverseIntKey(-i); + secKey2.add(new ReverseIntKey(-i)); + } + } + + @Persistent + static class ReverseIntKey implements Comparable<ReverseIntKey> { + + @KeyField(1) + private int key; + + public int compareTo(ReverseIntKey o) { + /* Reverse the natural order. */ + return o.key - key; + } + + private ReverseIntKey() {} + + ReverseIntKey(int key) { + this.key = key; + } + + @Override + public boolean equals(Object o) { + return key == ((ReverseIntKey) o).key; + } + + @Override + public int hashCode() { + return key; + } + + @Override + public String toString() { + return "Key = " + key; + } + } + + /** + * Ensures that custom comparators are persisted and work correctly during + * recovery. JE recovery uses comparators, so they are serialized and + * stored in the DatabaseImpl. They are deserialized during recovery prior + * to opening the EntityStore and its format catalog. But the formats are + * needed by the comparator, so they are specially created when needed. + * + * In particular we need to ensure that enum key fields work correctly, + * since their formats are not static (like simple type formats are). + * [#17140] + * + * Note that we don't need to actually cause a recovery in order to test + * the deserialization and subsequent use of comparators. The JE + * DatabaseConfig.setBtreeComparator method serializes and deserializes the + * comparator. The comparator is initialized on its first use, just as if + * recovery were run. + */ + public void testStoredComparators() + throws DatabaseException { + + open(); + + PrimaryIndex<StoredComparatorEntity.Key, + StoredComparatorEntity> priIndex = + store.getPrimaryIndex(StoredComparatorEntity.Key.class, + StoredComparatorEntity.class); + + SecondaryIndex<StoredComparatorEntity.MyEnum, + StoredComparatorEntity.Key, + StoredComparatorEntity> secIndex = + store.getSecondaryIndex + (priIndex, StoredComparatorEntity.MyEnum.class, "secKey"); + + final StoredComparatorEntity.Key[] priKeys = + new StoredComparatorEntity.Key[] { + new StoredComparatorEntity.Key + (StoredComparatorEntity.MyEnum.A, 1, + StoredComparatorEntity.MyEnum.A), + new StoredComparatorEntity.Key + (StoredComparatorEntity.MyEnum.A, 1, + StoredComparatorEntity.MyEnum.B), + new StoredComparatorEntity.Key + (StoredComparatorEntity.MyEnum.A, 2, + StoredComparatorEntity.MyEnum.A), + new StoredComparatorEntity.Key + (StoredComparatorEntity.MyEnum.A, 2, + StoredComparatorEntity.MyEnum.B), + new StoredComparatorEntity.Key + (StoredComparatorEntity.MyEnum.B, 1, + StoredComparatorEntity.MyEnum.A), + new StoredComparatorEntity.Key + (StoredComparatorEntity.MyEnum.B, 1, + StoredComparatorEntity.MyEnum.B), + new StoredComparatorEntity.Key + (StoredComparatorEntity.MyEnum.C, 0, + StoredComparatorEntity.MyEnum.C), + }; + + final StoredComparatorEntity.MyEnum[] secKeys = + new StoredComparatorEntity.MyEnum[] { + StoredComparatorEntity.MyEnum.C, + StoredComparatorEntity.MyEnum.B, + StoredComparatorEntity.MyEnum.A, + null, + StoredComparatorEntity.MyEnum.A, + StoredComparatorEntity.MyEnum.B, + StoredComparatorEntity.MyEnum.C, + }; + + assertEquals(priKeys.length, secKeys.length); + final int nEntities = priKeys.length; + + Transaction txn = txnBegin(); + for (int i = 0; i < nEntities; i += 1) { + priIndex.put(txn, + new StoredComparatorEntity(priKeys[i], secKeys[i])); + } + txnCommit(txn); + + txn = txnBeginCursor(); + EntityCursor<StoredComparatorEntity> entities = + priIndex.entities(txn, null); + for (int i = nEntities - 1; i >= 0; i -= 1) { + StoredComparatorEntity e = entities.next(); + assertNotNull(e); + assertEquals(priKeys[i], e.key); + assertEquals(secKeys[i], e.secKey); + } + assertNull(entities.next()); + entities.close(); + txnCommit(txn); + + txn = txnBeginCursor(); + entities = secIndex.entities(txn, null); + for (StoredComparatorEntity.MyEnum myEnum : + EnumSet.allOf(StoredComparatorEntity.MyEnum.class)) { + for (int i = 0; i < nEntities; i += 1) { + if (secKeys[i] == myEnum) { + StoredComparatorEntity e = entities.next(); + assertNotNull(e); + assertEquals(priKeys[i], e.key); + assertEquals(secKeys[i], e.secKey); + } + } + } + assertNull(entities.next()); + entities.close(); + txnCommit(txn); + + close(); + } + + @Entity + static class StoredComparatorEntity { + + enum MyEnum { A, B, C }; + + @Persistent + static class Key implements Comparable<Key> { + + @KeyField(1) + MyEnum f1; + + @KeyField(2) + Integer f2; + + @KeyField(3) + MyEnum f3; + + private Key() {} + + Key(MyEnum f1, Integer f2, MyEnum f3) { + this.f1 = f1; + this.f2 = f2; + this.f3 = f3; + } + + public int compareTo(Key o) { + /* Reverse the natural order. */ + int i = f1.compareTo(o.f1); + if (i != 0) return -i; + i = f2.compareTo(o.f2); + if (i != 0) return -i; + i = f3.compareTo(o.f3); + if (i != 0) return -i; + return 0; + } + + @Override + public boolean equals(Object other) { + if (!(other instanceof Key)) { + return false; + } + Key o = (Key) other; + return f1 == o.f1 && + f2.equals(o.f2) && + f3 == o.f3; + } + + @Override + public int hashCode() { + return f1.ordinal() + f2 + f3.ordinal(); + } + + @Override + public String toString() { + return "[Key " + f1 + ' ' + f2 + ' ' + f3 + ']'; + } + } + + @PrimaryKey + Key key; + + @SecondaryKey(relate=MANY_TO_ONE) + private MyEnum secKey; + + private StoredComparatorEntity() {} + + StoredComparatorEntity(Key key, MyEnum secKey) { + this.key = key; + this.secKey = secKey; + } + + @Override + public String toString() { + return "[pri = " + key + " sec = " + secKey + ']'; + } + } +} diff --git a/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/PersistTestUtils.java b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/PersistTestUtils.java new file mode 100644 index 0000000..354eb19 --- /dev/null +++ b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/PersistTestUtils.java @@ -0,0 +1,49 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2000-2009 Oracle. All rights reserved. + * + * $Id$ + */ +package com.sleepycat.persist.test; + +import junit.framework.TestCase; + +import com.sleepycat.compat.DbCompat; +import com.sleepycat.db.Environment; + +class PersistTestUtils { + + /** + * Asserts than a database expectExists or does not exist. If keyName is + * null, checks an entity database. If keyName is non-null, checks a + * secondary database. + */ + static void assertDbExists(boolean expectExists, + Environment env, + String storeName, + String entityClassName, + String keyName) { + String fileName; + String dbName; + if (DbCompat.SEPARATE_DATABASE_FILES) { + fileName = storeName + '-' + entityClassName; + if (keyName != null) { + fileName += "-" + keyName; + } + dbName = null; + } else { + fileName = null; + dbName = "persist#" + storeName + '#' + entityClassName; + if (keyName != null) { + dbName += "#" + keyName; + } + } + boolean exists = DbCompat.databaseExists(env, fileName, dbName); + if (expectExists != exists) { + TestCase.fail + ((expectExists ? "Does not exist: " : "Does exist: ") + + dbName); + } + } +} diff --git a/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/SequenceTest.java b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/SequenceTest.java new file mode 100644 index 0000000..f228426 --- /dev/null +++ b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/SequenceTest.java @@ -0,0 +1,469 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2002-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +package com.sleepycat.persist.test; + +import java.io.File; + +import com.sleepycat.db.Environment; +import com.sleepycat.db.EnvironmentConfig; +import com.sleepycat.db.util.DualTestCase; +import com.sleepycat.persist.EntityStore; +import com.sleepycat.persist.PrimaryIndex; +import com.sleepycat.persist.StoreConfig; +import com.sleepycat.persist.model.Entity; +import com.sleepycat.persist.model.KeyField; +import com.sleepycat.persist.model.Persistent; +import com.sleepycat.persist.model.PrimaryKey; +import com.sleepycat.util.test.SharedTestUtils; +import com.sleepycat.util.test.TestEnv; + +/** + * @author Mark Hayes + */ +public class SequenceTest extends DualTestCase { + + private File envHome; + private Environment env; + + @Override + public void setUp() + throws Exception { + + super.setUp(); + + envHome = new File(System.getProperty(SharedTestUtils.DEST_DIR)); + SharedTestUtils.emptyDir(envHome); + } + + @Override + public void tearDown() + throws Exception { + + super.tearDown(); + + envHome = null; + env = null; + } + + public void testSequenceKeys() + throws Exception { + + Class[] classes = { + SequenceEntity_Long.class, + SequenceEntity_Integer.class, + SequenceEntity_Short.class, + SequenceEntity_Byte.class, + SequenceEntity_tlong.class, + SequenceEntity_tint.class, + SequenceEntity_tshort.class, + SequenceEntity_tbyte.class, + SequenceEntity_Long_composite.class, + SequenceEntity_Integer_composite.class, + SequenceEntity_Short_composite.class, + SequenceEntity_Byte_composite.class, + SequenceEntity_tlong_composite.class, + SequenceEntity_tint_composite.class, + SequenceEntity_tshort_composite.class, + SequenceEntity_tbyte_composite.class, + }; + + EnvironmentConfig envConfig = TestEnv.TXN.getConfig(); + envConfig.setAllowCreate(true); + env = create(envHome, envConfig); + + StoreConfig storeConfig = new StoreConfig(); + storeConfig.setAllowCreate(true); + storeConfig.setTransactional(true); + EntityStore store = new EntityStore(env, "foo", storeConfig); + + long seq = 0; + + for (int i = 0; i < classes.length; i += 1) { + Class entityCls = classes[i]; + SequenceEntity entity = (SequenceEntity) entityCls.newInstance(); + Class keyCls = entity.getKeyClass(); + + PrimaryIndex<Object,SequenceEntity> index = + store.getPrimaryIndex(keyCls, entityCls); + index.putNoReturn(entity); + seq += 1; + assertEquals(seq, entity.getKey()); + + index.putNoReturn(entity); + assertEquals(seq, entity.getKey()); + + entity.nullifyKey(); + index.putNoReturn(entity); + seq += 1; + assertEquals(seq, entity.getKey()); + } + + store.close(); + close(env); + env = null; + } + + interface SequenceEntity { + Class getKeyClass(); + long getKey(); + void nullifyKey(); + } + + @Entity + static class SequenceEntity_Long implements SequenceEntity { + + @PrimaryKey(sequence="X") + Long priKey; + + public Class getKeyClass() { + return Long.class; + } + + public long getKey() { + return priKey; + } + + public void nullifyKey() { + priKey = null; + } + } + + @Entity + static class SequenceEntity_Integer implements SequenceEntity { + + @PrimaryKey(sequence="X") + Integer priKey; + + public Class getKeyClass() { + return Integer.class; + } + + public long getKey() { + return priKey; + } + + public void nullifyKey() { + priKey = null; + } + } + + @Entity + static class SequenceEntity_Short implements SequenceEntity { + + @PrimaryKey(sequence="X") + Short priKey; + + public Class getKeyClass() { + return Short.class; + } + + public long getKey() { + return priKey; + } + + public void nullifyKey() { + priKey = null; + } + } + + @Entity + static class SequenceEntity_Byte implements SequenceEntity { + + @PrimaryKey(sequence="X") + Byte priKey; + + public Class getKeyClass() { + return Byte.class; + } + + public long getKey() { + return priKey; + } + + public void nullifyKey() { + priKey = null; + } + } + + @Entity + static class SequenceEntity_tlong implements SequenceEntity { + + @PrimaryKey(sequence="X") + long priKey; + + public Class getKeyClass() { + return Long.class; + } + + public long getKey() { + return priKey; + } + + public void nullifyKey() { + priKey = 0; + } + } + + @Entity + static class SequenceEntity_tint implements SequenceEntity { + + @PrimaryKey(sequence="X") + int priKey; + + public Class getKeyClass() { + return Integer.class; + } + + public long getKey() { + return priKey; + } + + public void nullifyKey() { + priKey = 0; + } + } + + @Entity + static class SequenceEntity_tshort implements SequenceEntity { + + @PrimaryKey(sequence="X") + short priKey; + + public Class getKeyClass() { + return Short.class; + } + + public long getKey() { + return priKey; + } + + public void nullifyKey() { + priKey = 0; + } + } + + @Entity + static class SequenceEntity_tbyte implements SequenceEntity { + + @PrimaryKey(sequence="X") + byte priKey; + + public Class getKeyClass() { + return Byte.class; + } + + public long getKey() { + return priKey; + } + + public void nullifyKey() { + priKey = 0; + } + } + + @Entity + static class SequenceEntity_Long_composite implements SequenceEntity { + + @PrimaryKey(sequence="X") + Key priKey; + + @Persistent + static class Key { + @KeyField(1) + Long priKey; + } + + public Class getKeyClass() { + return Key.class; + } + + public long getKey() { + return priKey.priKey; + } + + public void nullifyKey() { + priKey = null; + } + } + + @Entity + static class SequenceEntity_Integer_composite implements SequenceEntity { + + @PrimaryKey(sequence="X") + Key priKey; + + @Persistent + static class Key { + @KeyField(1) + Integer priKey; + } + + public Class getKeyClass() { + return Key.class; + } + + public long getKey() { + return priKey.priKey; + } + + public void nullifyKey() { + priKey = null; + } + } + + @Entity + static class SequenceEntity_Short_composite implements SequenceEntity { + + @PrimaryKey(sequence="X") + Key priKey; + + @Persistent + static class Key { + @KeyField(1) + Short priKey; + } + + public Class getKeyClass() { + return Key.class; + } + + public long getKey() { + return priKey.priKey; + } + + public void nullifyKey() { + priKey = null; + } + } + + @Entity + static class SequenceEntity_Byte_composite implements SequenceEntity { + + @PrimaryKey(sequence="X") + Key priKey; + + @Persistent + static class Key { + @KeyField(1) + Byte priKey; + } + + public Class getKeyClass() { + return Key.class; + } + + public long getKey() { + return priKey.priKey; + } + + public void nullifyKey() { + priKey = null; + } + } + + @Entity + static class SequenceEntity_tlong_composite implements SequenceEntity { + + @PrimaryKey(sequence="X") + Key priKey; + + @Persistent + static class Key { + @KeyField(1) + long priKey; + } + + public Class getKeyClass() { + return Key.class; + } + + public long getKey() { + return priKey.priKey; + } + + public void nullifyKey() { + priKey = null; + } + } + + @Entity + static class SequenceEntity_tint_composite implements SequenceEntity { + + @PrimaryKey(sequence="X") + Key priKey; + + @Persistent + static class Key { + @KeyField(1) + int priKey; + } + + public Class getKeyClass() { + return Key.class; + } + + public long getKey() { + return priKey.priKey; + } + + public void nullifyKey() { + priKey = null; + } + } + + @Entity + static class SequenceEntity_tshort_composite implements SequenceEntity { + + @PrimaryKey(sequence="X") + Key priKey; + + @Persistent + static class Key { + @KeyField(1) + short priKey; + } + + public Class getKeyClass() { + return Key.class; + } + + public long getKey() { + return priKey.priKey; + } + + public void nullifyKey() { + priKey = null; + } + } + + @Entity + static class SequenceEntity_tbyte_composite implements SequenceEntity { + + @PrimaryKey(sequence="X") + Key priKey; + + @Persistent + static class Key { + @KeyField(1) + byte priKey; + } + + public Class getKeyClass() { + return Key.class; + } + + public long getKey() { + return priKey.priKey; + } + + public void nullifyKey() { + priKey = null; + } + } +} diff --git a/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/SubclassIndexTest.java b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/SubclassIndexTest.java new file mode 100644 index 0000000..f1f5dd9 --- /dev/null +++ b/db-4.8.30/test/scr024/src/com/sleepycat/persist/test/SubclassIndexTest.java @@ -0,0 +1,251 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 2002-2009 Oracle. All rights reserved. + * + * $Id$ + */ + +package com.sleepycat.persist.test; + +import static com.sleepycat.persist.model.Relationship.MANY_TO_ONE; + +import java.io.File; + +import com.sleepycat.db.DatabaseException; +import com.sleepycat.db.Environment; +import com.sleepycat.db.EnvironmentConfig; +import com.sleepycat.db.Transaction; +import com.sleepycat.db.util.DualTestCase; +import com.sleepycat.persist.EntityCursor; +import com.sleepycat.persist.EntityStore; +import com.sleepycat.persist.PrimaryIndex; +import com.sleepycat.persist.SecondaryIndex; +import com.sleepycat.persist.StoreConfig; +import com.sleepycat.persist.model.AnnotationModel; +import com.sleepycat.persist.model.Entity; +import com.sleepycat.persist.model.EntityModel; +import com.sleepycat.persist.model.Persistent; +import com.sleepycat.persist.model.PrimaryKey; +import com.sleepycat.persist.model.SecondaryKey; +import com.sleepycat.util.test.SharedTestUtils; +import com.sleepycat.util.test.TestEnv; + +public class SubclassIndexTest extends DualTestCase { + + private File envHome; + private Environment env; + private EntityStore store; + + @Override + public void setUp() + throws Exception { + + super.setUp(); + + envHome = new File(System.getProperty(SharedTestUtils.DEST_DIR)); + SharedTestUtils.emptyDir(envHome); + } + + @Override + public void tearDown() + throws Exception { + + super.tearDown(); + + envHome = null; + env = null; + } + + private void open() + throws DatabaseException { + + EnvironmentConfig envConfig = TestEnv.TXN.getConfig(); + envConfig.setAllowCreate(true); + env = create(envHome, envConfig); + + EntityModel model = new AnnotationModel(); + model.registerClass(Manager.class); + model.registerClass(SalariedManager.class); + + StoreConfig storeConfig = new StoreConfig(); + storeConfig.setModel(model); + storeConfig.setAllowCreate(true); + storeConfig.setTransactional(true); + store = new EntityStore(env, "foo", storeConfig); + } + + private void close() + throws DatabaseException { + + store.close(); + store = null; + close(env); + env = null; + } + + public void testSubclassIndex() + throws DatabaseException { + + open(); + + PrimaryIndex<String, Employee> employeesById = + store.getPrimaryIndex(String.class, Employee.class); + + employeesById.put(new Employee("1")); + employeesById.put(new Manager("2", "a")); + employeesById.put(new Manager("3", "a")); + employeesById.put(new Manager("4", "b")); + + Employee e; + Manager m; + + e = employeesById.get("1"); + assertNotNull(e); + assertTrue(!(e instanceof Manager)); + + /* Ensure DB exists BEFORE calling getSubclassIndex. [#15247] */ + PersistTestUtils.assertDbExists + (true, env, "foo", Employee.class.getName(), "dept"); + + /* Normal use: Subclass index for a key in the subclass. */ + SecondaryIndex<String, String, Manager> managersByDept = + store.getSubclassIndex + (employeesById, Manager.class, String.class, "dept"); + + m = managersByDept.get("a"); + assertNotNull(m); + assertEquals("2", m.id); + + m = managersByDept.get("b"); + assertNotNull(m); + assertEquals("4", m.id); + + Transaction txn = env.beginTransaction(null, null); + EntityCursor<Manager> managers = managersByDept.entities(txn, null); + try { + m = managers.next(); + assertNotNull(m); + assertEquals("2", m.id); + m = managers.next(); + assertNotNull(m); + assertEquals("3", m.id); + m = managers.next(); + assertNotNull(m); + assertEquals("4", m.id); + m = managers.next(); + assertNull(m); + } finally { + managers.close(); + txn.commit(); + } + + /* Getting a subclass index for the entity class is also allowed. */ + store.getSubclassIndex + (employeesById, Employee.class, String.class, "other"); + + /* Getting a subclass index for a base class key is not allowed. */ + try { + store.getSubclassIndex + (employeesById, Manager.class, String.class, "other"); + fail(); + } catch (IllegalArgumentException expected) { + } + + close(); + } + + /** + * Previously this tested that a secondary key database was added only + * AFTER storing the first instance of the subclass that defines the key. + * Now that we require registering the subclass up front, the database is + * created up front also. So this test is somewhat less useful, but still + * nice to have around. [#16399] + */ + public void testAddSecKey() + throws DatabaseException { + + open(); + PrimaryIndex<String, Employee> employeesById = + store.getPrimaryIndex(String.class, Employee.class); + employeesById.put(new Employee("1")); + assertTrue(hasEntityKey("dept")); + close(); + + open(); + employeesById = store.getPrimaryIndex(String.class, Employee.class); + assertTrue(hasEntityKey("dept")); + employeesById.put(new Manager("2", "a")); + assertTrue(hasEntityKey("dept")); + close(); + + open(); + assertTrue(hasEntityKey("dept")); + close(); + + open(); + employeesById = store.getPrimaryIndex(String.class, Employee.class); + assertTrue(hasEntityKey("salary")); + employeesById.put(new SalariedManager("3", "a", "111")); + assertTrue(hasEntityKey("salary")); + close(); + + open(); + assertTrue(hasEntityKey("dept")); + assertTrue(hasEntityKey("salary")); + close(); + } + + private boolean hasEntityKey(String keyName) { + return store.getModel(). + getRawType(Employee.class.getName()). + getEntityMetadata(). + getSecondaryKeys(). + keySet(). + contains(keyName); + } + + @Entity + private static class Employee { + + @PrimaryKey + String id; + + @SecondaryKey(relate=MANY_TO_ONE) + String other; + + Employee(String id) { + this.id = id; + } + + private Employee() {} + } + + @Persistent + private static class Manager extends Employee { + + @SecondaryKey(relate=MANY_TO_ONE) + String dept; + + Manager(String id, String dept) { + super(id); + this.dept = dept; + } + + private Manager() {} + } + + @Persistent + private static class SalariedManager extends Manager { + + @SecondaryKey(relate=MANY_TO_ONE) + String salary; + + SalariedManager(String id, String dept, String salary) { + super(id, dept); + this.salary = salary; + } + + private SalariedManager() {} + } +} |