diff options
| author | Brian S. O'Neill <bronee@gmail.com> | 2008-05-11 01:33:53 +0000 | 
|---|---|---|
| committer | Brian S. O'Neill <bronee@gmail.com> | 2008-05-11 01:33:53 +0000 | 
| commit | 1a384d409db2f070730384c6f83083233044673a (patch) | |
| tree | 81ba4b49afdfe61a9b663523db9070eaf6fce26c /src/test/java/com/amazon | |
| parent | c8bec73cfa29e97bcb7085aea6bfac293933f1fc (diff) | |
Added JDBC tests which use H2.
Diffstat (limited to 'src/test/java/com/amazon')
3 files changed, 889 insertions, 0 deletions
diff --git a/src/test/java/com/amazon/carbonado/repo/jdbc/DerbySchemaResolver.java b/src/test/java/com/amazon/carbonado/repo/jdbc/DerbySchemaResolver.java new file mode 100644 index 0000000..76f7cdf --- /dev/null +++ b/src/test/java/com/amazon/carbonado/repo/jdbc/DerbySchemaResolver.java @@ -0,0 +1,256 @@ +/*
 + * Copyright 2008 Amazon Technologies, Inc. or its affiliates.
 + * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
 + * of Amazon Technologies, Inc. or its affiliates.  All rights reserved.
 + *
 + * Licensed under the Apache License, Version 2.0 (the "License");
 + * you may not use this file except in compliance with the License.
 + * You may obtain a copy of the License at
 + *
 + *     http://www.apache.org/licenses/LICENSE-2.0
 + *
 + * Unless required by applicable law or agreed to in writing, software
 + * distributed under the License is distributed on an "AS IS" BASIS,
 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 + * See the License for the specific language governing permissions and
 + * limitations under the License.
 + */
 +
 +package com.amazon.carbonado.repo.jdbc;
 +
 +import java.util.ArrayList;
 +import java.util.List;
 +
 +import java.sql.Connection;
 +import java.sql.ResultSet;
 +import java.sql.SQLException;
 +import java.sql.Statement;
 +
 +import org.joda.time.DateTime;
 +
 +import com.amazon.carbonado.Repository;
 +import com.amazon.carbonado.RepositoryBuilder;
 +import com.amazon.carbonado.RepositoryException;
 +import com.amazon.carbonado.Storable;
 +
 +import com.amazon.carbonado.lob.Blob;
 +import com.amazon.carbonado.lob.Clob;
 +
 +import com.amazon.carbonado.info.OrderedProperty;
 +import com.amazon.carbonado.info.StorableIndex;
 +import com.amazon.carbonado.info.StorableInfo;
 +import com.amazon.carbonado.info.StorableKey;
 +import com.amazon.carbonado.info.StorableProperty;
 +
 +/**
 + * Creates tables as needed automatically for the Derby database.
 + *
 + * @author Brian S O'Neill
 + */
 +public class DerbySchemaResolver implements SchemaResolver {
 +    public <S extends Storable> boolean resolve(StorableInfo<S> info,
 +                                                Connection con, String catalog, String schema)
 +        throws SQLException
 +    {
 +        // Create the table, keys, indexes and sequences.
 +        
 +        StringBuilder b = new StringBuilder();
 +        b.append("CREATE TABLE ");
 +
 +        String tableName;
 +        if (info.getAliasCount() > 0) {
 +            tableName = info.getAlias(0);
 +        } else {
 +            tableName = info.getName();
 +        }
 +        if (needsQuotes(tableName)) {
 +            tableName = '"' + tableName + '"';
 +        }
 +        b.append(tableName);
 +        b.append(" (");
 +
 +        int i = 0;
 +        for (StorableProperty<S> property : info.getAllProperties().values()) {
 +            if (property.isJoin() || property.isDerived()) {
 +                continue;
 +            }
 +
 +            if (i++ > 0) {
 +                b.append(", ");
 +            }
 +
 +            if (property.getAliasCount() > 0) {
 +                b.append(property.getAlias(0));
 +            } else {
 +                b.append(property.getName());
 +            }
 +            b.append(' ');
 +
 +            Class type = property.getType();
 +            String typeName;
 +            if (type == String.class) {
 +                typeName = "VARCHAR(255)";
 +            } else if (type == int.class || type == Integer.class) {
 +                typeName = "INT";
 +            } else if (type == long.class || type == Long.class) {
 +                typeName = "BIGINT";
 +            } else if (type == float.class || type == Float.class) {
 +                typeName = "REAL";
 +            } else if (type == double.class || type == Double.class) {
 +                typeName = "DOUBLE";
 +            } else if (type == short.class || type == Short.class) {
 +                typeName = "SMALLINT";
 +            } else if (type == byte.class || type == Byte.class) {
 +                typeName = "TINYINT";
 +            } else if (type == char.class || type == Character.class) {
 +                typeName = "CHAR(1)";
 +            } else if (type == boolean.class || type == Boolean.class) {
 +                typeName = "BOOLEAN";
 +            } else if (type == DateTime.class) {
 +                typeName = "TIMESTAMP";
 +            } else if (type == byte[].class) {
 +                typeName = "BINARY";
 +            } else if (type == Blob.class) {
 +                typeName = "BLOB";
 +            } else if (type == Clob.class) {
 +                typeName = "CLOB";
 +            } else {
 +                return false;
 +            }
 +
 +            b.append(typeName);
 +
 +            if (!property.isNullable()) {
 +                b.append(" NOT NULL");
 +            }
 +        }
 +
 +        b.append(')');
 +        String createTable = b.toString();
 +
 +        b = new StringBuilder();
 +        b.append("ALTER TABLE ");
 +        b.append(tableName);
 +        b.append(" ADD PRIMARY KEY (");
 +
 +        i = 0;
 +        for (StorableProperty<S> property : info.getPrimaryKeyProperties().values()) {
 +            if (i++ > 0) {
 +                b.append(", ");
 +            }
 +
 +            if (property.getAliasCount() > 0) {
 +                b.append(property.getAlias(0));
 +            } else {
 +                b.append(property.getName());
 +            }
 +        }
 +
 +        b.append(')');
 +        String createPrimaryKey = b.toString();
 +
 +        int indexCount = 0;
 +
 +        List<String> createAltKeys = new ArrayList<String>();
 +
 +        for (StorableKey<S> key : info.getAlternateKeys()) {
 +            b = new StringBuilder();
 +            b.append("CREATE UNIQUE INDEX ");
 +            b.append(tableName);
 +            b.append('_');
 +            b.append(Integer.valueOf(++indexCount));
 +            b.append(" ON ");
 +            b.append(tableName);
 +            b.append(" (");
 +
 +            i = 0;
 +            for (OrderedProperty<S> op : key.getProperties()) {
 +                StorableProperty<S> property = op.getChainedProperty().getPrimeProperty();
 +                if (property.isDerived()) {
 +                    continue;
 +                }
 +
 +                if (i++ > 0) {
 +                    b.append(", ");
 +                }
 +
 +                if (property.getAliasCount() > 0) {
 +                    b.append(property.getAlias(0));
 +                } else {
 +                    b.append(property.getName());
 +                }
 +            }
 +
 +            if (i > 0) {
 +                b.append(')');
 +                createAltKeys.add(b.toString());
 +            }
 +        }
 +
 +        List<String> createIndexes = new ArrayList<String>();
 +
 +        for (StorableIndex<S> index : info.getIndexes()) {
 +            b = new StringBuilder();
 +            b.append("CREATE INDEX ");
 +            b.append(tableName);
 +            b.append('_');
 +            b.append(Integer.valueOf(++indexCount));
 +            b.append(" ON ");
 +            b.append(tableName);
 +            b.append(" (");
 +
 +            i = 0;
 +            for (StorableProperty<S> property : index.getProperties()) {
 +                if (property.isDerived()) {
 +                    continue;
 +                }
 +
 +                if (i++ > 0) {
 +                    b.append(", ");
 +                }
 +
 +                if (property.getAliasCount() > 0) {
 +                    b.append(property.getAlias(0));
 +                } else {
 +                    b.append(property.getName());
 +                }
 +            }
 +
 +            if (i > 0) {
 +                b.append(')');
 +                createIndexes.add(b.toString());
 +            }
 +        }
 +
 +        Statement st = con.createStatement();
 +        try {
 +            st.executeUpdate(createTable);
 +
 +            st.executeUpdate(createPrimaryKey);
 +
 +            for (String createAltKey : createAltKeys) {
 +                st.executeUpdate(createAltKey);
 +            }
 +
 +            for (String createIndex : createIndexes) {
 +                st.executeUpdate(createIndex);
 +            }
 +        } finally {
 +            st.close();
 +        }
 +
 +        return true;
 +    }
 +
 +    private boolean needsQuotes(String str) {
 +        if (!Character.isUnicodeIdentifierStart(str.charAt(0))) {
 +            return true;
 +        }
 +        for (int i=1; i<str.length(); i++) {
 +            if (!Character.isUnicodeIdentifierPart(str.charAt(i))) {
 +                return true;
 +            }
 +        }
 +        return false;
 +    }
 +}
 diff --git a/src/test/java/com/amazon/carbonado/repo/jdbc/H2SchemaResolver.java b/src/test/java/com/amazon/carbonado/repo/jdbc/H2SchemaResolver.java new file mode 100644 index 0000000..8eddb5b --- /dev/null +++ b/src/test/java/com/amazon/carbonado/repo/jdbc/H2SchemaResolver.java @@ -0,0 +1,267 @@ +/*
 + * Copyright 2008 Amazon Technologies, Inc. or its affiliates.
 + * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
 + * of Amazon Technologies, Inc. or its affiliates.  All rights reserved.
 + *
 + * Licensed under the Apache License, Version 2.0 (the "License");
 + * you may not use this file except in compliance with the License.
 + * You may obtain a copy of the License at
 + *
 + *     http://www.apache.org/licenses/LICENSE-2.0
 + *
 + * Unless required by applicable law or agreed to in writing, software
 + * distributed under the License is distributed on an "AS IS" BASIS,
 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 + * See the License for the specific language governing permissions and
 + * limitations under the License.
 + */
 +
 +package com.amazon.carbonado.repo.jdbc;
 +
 +import java.util.ArrayList;
 +import java.util.List;
 +
 +import java.sql.Connection;
 +import java.sql.ResultSet;
 +import java.sql.SQLException;
 +import java.sql.Statement;
 +
 +import org.joda.time.DateTime;
 +
 +import com.amazon.carbonado.Repository;
 +import com.amazon.carbonado.RepositoryBuilder;
 +import com.amazon.carbonado.RepositoryException;
 +import com.amazon.carbonado.Storable;
 +
 +import com.amazon.carbonado.lob.Blob;
 +import com.amazon.carbonado.lob.Clob;
 +
 +import com.amazon.carbonado.info.OrderedProperty;
 +import com.amazon.carbonado.info.StorableIndex;
 +import com.amazon.carbonado.info.StorableInfo;
 +import com.amazon.carbonado.info.StorableKey;
 +import com.amazon.carbonado.info.StorableProperty;
 +
 +/**
 + * Creates tables as needed automatically for the H2 database.
 + *
 + * @author Brian S O'Neill
 + */
 +public class H2SchemaResolver implements SchemaResolver {
 +    public <S extends Storable> boolean resolve(StorableInfo<S> info,
 +                                                Connection con, String catalog, String schema)
 +        throws SQLException
 +    {
 +        // Create the table, keys, indexes and sequences.
 +        List<String> sequenceNames = new ArrayList<String>();
 +        
 +        StringBuilder b = new StringBuilder();
 +        b.append("CREATE TABLE ");
 +
 +        String tableName;
 +        if (info.getAliasCount() > 0) {
 +            tableName = info.getAlias(0);
 +        } else {
 +            tableName = info.getName();
 +        }
 +        if (needsQuotes(tableName)) {
 +            tableName = '"' + tableName + '"';
 +        }
 +        b.append(tableName);
 +        b.append(" (");
 +
 +        int i = 0;
 +        for (StorableProperty<S> property : info.getAllProperties().values()) {
 +            if (property.isJoin() || property.isDerived()) {
 +                continue;
 +            }
 +
 +            if (i++ > 0) {
 +                b.append(", ");
 +            }
 +
 +            if (property.getAliasCount() > 0) {
 +                b.append(property.getAlias(0));
 +            } else {
 +                b.append(property.getName());
 +            }
 +            b.append(' ');
 +
 +            Class type = property.getType();
 +            String typeName;
 +            if (type == String.class) {
 +                typeName = "VARCHAR";
 +            } else if (type == int.class || type == Integer.class) {
 +                typeName = "INT";
 +            } else if (type == long.class || type == Long.class) {
 +                typeName = "BIGINT";
 +            } else if (type == float.class || type == Float.class) {
 +                typeName = "REAL";
 +            } else if (type == double.class || type == Double.class) {
 +                typeName = "DOUBLE";
 +            } else if (type == short.class || type == Short.class) {
 +                typeName = "SMALLINT";
 +            } else if (type == byte.class || type == Byte.class) {
 +                typeName = "TINYINT";
 +            } else if (type == char.class || type == Character.class) {
 +                typeName = "CHAR(1)";
 +            } else if (type == boolean.class || type == Boolean.class) {
 +                typeName = "BOOLEAN";
 +            } else if (type == DateTime.class) {
 +                typeName = "TIMESTAMP";
 +            } else if (type == byte[].class) {
 +                typeName = "BINARY";
 +            } else if (type == Blob.class) {
 +                typeName = "BLOB";
 +            } else if (type == Clob.class) {
 +                typeName = "CLOB";
 +            } else {
 +                return false;
 +            }
 +
 +            b.append(typeName);
 +
 +            if (property.isNullable()) {
 +                b.append(" NULL");
 +            } else {
 +                b.append(" NOT NULL");
 +            }
 +
 +            if (property.getSequenceName() != null) {
 +                sequenceNames.add(property.getSequenceName());
 +            }
 +        }
 +
 +        b.append(')');
 +        String createTable = b.toString();
 +
 +        b = new StringBuilder();
 +        b.append("ALTER TABLE ");
 +        b.append(tableName);
 +        b.append(" ADD PRIMARY KEY (");
 +
 +        i = 0;
 +        for (StorableProperty<S> property : info.getPrimaryKeyProperties().values()) {
 +            if (i++ > 0) {
 +                b.append(", ");
 +            }
 +
 +            if (property.getAliasCount() > 0) {
 +                b.append(property.getAlias(0));
 +            } else {
 +                b.append(property.getName());
 +            }
 +        }
 +
 +        b.append(')');
 +        String createPrimaryKey = b.toString();
 +
 +        int indexCount = 0;
 +
 +        List<String> createAltKeys = new ArrayList<String>();
 +
 +        for (StorableKey<S> key : info.getAlternateKeys()) {
 +            b = new StringBuilder();
 +            b.append("CREATE UNIQUE INDEX ");
 +            b.append(tableName);
 +            b.append('_');
 +            b.append(Integer.valueOf(++indexCount));
 +            b.append(" ON ");
 +            b.append(tableName);
 +            b.append(" (");
 +
 +            i = 0;
 +            for (OrderedProperty<S> op : key.getProperties()) {
 +                StorableProperty<S> property = op.getChainedProperty().getPrimeProperty();
 +                if (property.isDerived()) {
 +                    continue;
 +                }
 +
 +                if (i++ > 0) {
 +                    b.append(", ");
 +                }
 +
 +                if (property.getAliasCount() > 0) {
 +                    b.append(property.getAlias(0));
 +                } else {
 +                    b.append(property.getName());
 +                }
 +            }
 +
 +            if (i > 0) {
 +                b.append(')');
 +                createAltKeys.add(b.toString());
 +            }
 +        }
 +
 +        List<String> createIndexes = new ArrayList<String>();
 +
 +        for (StorableIndex<S> index : info.getIndexes()) {
 +            b = new StringBuilder();
 +            b.append("CREATE INDEX ");
 +            b.append(tableName);
 +            b.append('_');
 +            b.append(Integer.valueOf(++indexCount));
 +            b.append(" ON ");
 +            b.append(tableName);
 +            b.append(" (");
 +
 +            i = 0;
 +            for (StorableProperty<S> property : index.getProperties()) {
 +                if (property.isDerived()) {
 +                    continue;
 +                }
 +
 +                if (i++ > 0) {
 +                    b.append(", ");
 +                }
 +
 +                if (property.getAliasCount() > 0) {
 +                    b.append(property.getAlias(0));
 +                } else {
 +                    b.append(property.getName());
 +                }
 +            }
 +
 +            if (i > 0) {
 +                b.append(')');
 +                createIndexes.add(b.toString());
 +            }
 +        }
 +
 +        Statement st = con.createStatement();
 +        try {
 +            st.executeUpdate(createTable);
 +
 +            st.executeUpdate(createPrimaryKey);
 +
 +            for (String createAltKey : createAltKeys) {
 +                st.executeUpdate(createAltKey);
 +            }
 +
 +            for (String createIndex : createIndexes) {
 +                st.executeUpdate(createIndex);
 +            }
 +
 +            for (String sequenceName : sequenceNames) {
 +                st.executeUpdate("CREATE SEQUENCE IF NOT EXISTS " + sequenceName);
 +            }
 +        } finally {
 +            st.close();
 +        }
 +
 +        return true;
 +    }
 +
 +    private boolean needsQuotes(String str) {
 +        if (!Character.isUnicodeIdentifierStart(str.charAt(0))) {
 +            return true;
 +        }
 +        for (int i=1; i<str.length(); i++) {
 +            if (!Character.isUnicodeIdentifierPart(str.charAt(i))) {
 +                return true;
 +            }
 +        }
 +        return false;
 +    }
 +}
 diff --git a/src/test/java/com/amazon/carbonado/repo/jdbc/TestH2.java b/src/test/java/com/amazon/carbonado/repo/jdbc/TestH2.java new file mode 100644 index 0000000..2682f53 --- /dev/null +++ b/src/test/java/com/amazon/carbonado/repo/jdbc/TestH2.java @@ -0,0 +1,366 @@ +/*
 + * Copyright 2008 Amazon Technologies, Inc. or its affiliates.
 + * Amazon, Amazon.com and Carbonado are trademarks or registered trademarks
 + * of Amazon Technologies, Inc. or its affiliates.  All rights reserved.
 + *
 + * Licensed under the Apache License, Version 2.0 (the "License");
 + * you may not use this file except in compliance with the License.
 + * You may obtain a copy of the License at
 + *
 + *     http://www.apache.org/licenses/LICENSE-2.0
 + *
 + * Unless required by applicable law or agreed to in writing, software
 + * distributed under the License is distributed on an "AS IS" BASIS,
 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 + * See the License for the specific language governing permissions and
 + * limitations under the License.
 + */
 +
 +package com.amazon.carbonado.repo.jdbc;
 +
 +import java.io.*;
 +
 +import java.sql.DriverManager;
 +
 +import junit.framework.TestSuite;
 +
 +import org.apache.commons.dbcp.BasicDataSource;
 +
 +import com.amazon.carbonado.*;
 +
 +import com.amazon.carbonado.lob.*;
 +
 +import com.amazon.carbonado.repo.indexed.IndexedRepositoryBuilder;
 +
 +import com.amazon.carbonado.TestUtilities;
 +
 +import com.amazon.carbonado.stored.StorableWithLobs;
 +
 +/**
 + * 
 + *
 + * @author Brian S O'Neill
 + */
 +public class TestH2 extends com.amazon.carbonado.TestStorables {
 +    public static void main(String[] args) {
 +        junit.textui.TestRunner.run(suite());
 +    }
 +
 +    public static TestSuite suite() {
 +        TestSuite suite = new TestSuite();
 +        suite.addTestSuite(TestH2.class);
 +        return suite;
 +    }
 +
 +    public TestH2(String name) {
 +        super(name);
 +    }
 +
 +    @Override
 +    public void test_derivedJoinIndex() throws Exception {
 +        // Needs to use custom indexing for this test to work.
 +        IndexedRepositoryBuilder builder = new IndexedRepositoryBuilder();
 +        builder.setWrappedRepository(jdbcBuilder(true));
 +        Repository repo = builder.build();
 +        test_derivedJoinIndex(repo);
 +    }
 +
 +    @Override
 +    protected Repository buildRepository(boolean isMaster) throws RepositoryException {
 +        return jdbcBuilder(isMaster).build();
 +    }
 +
 +    // Override because H2 does not fully support LOBs.
 +    @Override
 +    public void test_lobInsert() throws Exception {
 +        Storage<StorableWithLobs> storage = getRepository().storageFor(StorableWithLobs.class);
 +
 +        // Test null insert
 +        {
 +            StorableWithLobs lobs = storage.prepare();
 +            lobs.insert();
 +            assertEquals(null, lobs.getBlobValue());
 +            assertEquals(null, lobs.getClobValue());
 +            lobs.load();
 +            assertEquals(null, lobs.getBlobValue());
 +            assertEquals(null, lobs.getClobValue());
 +        }
 +
 +        // Test content insert
 +        int id;
 +        {
 +            StorableWithLobs lobs = storage.prepare();
 +            lobs.setBlobValue(new ByteArrayBlob("hello".getBytes()));
 +            lobs.setClobValue(new StringClob("world"));
 +            lobs.insert();
 +            assertEquals("hello", lobs.getBlobValue().asString());
 +            assertEquals("world", lobs.getClobValue().asString());
 +            lobs.load();
 +            assertEquals("hello", lobs.getBlobValue().asString());
 +            assertEquals("world", lobs.getClobValue().asString());
 +            id = lobs.getId();
 +        }
 +
 +        // Test insert failure
 +        {
 +            StorableWithLobs lobs = storage.prepare();
 +            lobs.setId(id);
 +
 +            Blob newBlob = new ByteArrayBlob("blob insert should fail".getBytes());
 +            Clob newClob = new StringClob("clob insert should fail");
 +
 +            lobs.setBlobValue(newBlob);
 +            lobs.setClobValue(newClob);
 +
 +            try {
 +                lobs.insert();
 +                fail();
 +            } catch (UniqueConstraintException e) {
 +            }
 +
 +            assertTrue(newBlob == lobs.getBlobValue());
 +            assertTrue(newClob == lobs.getClobValue());
 +        }
 +    }
 +
 +    // Override because H2 does not fully support LOBs.
 +    @Override
 +    public void test_lobUpdate() throws Exception {
 +        Storage<StorableWithLobs> storage = getRepository().storageFor(StorableWithLobs.class);
 +
 +        // Test null replaces null
 +        {
 +            StorableWithLobs lobs = storage.prepare();
 +            lobs.insert();
 +
 +            lobs.setBlobValue(null);
 +            lobs.setClobValue(null);
 +
 +            lobs.update();
 +
 +            assertEquals(null, lobs.getBlobValue());
 +            assertEquals(null, lobs.getClobValue());
 +
 +            lobs.load();
 +            assertEquals(null, lobs.getBlobValue());
 +            assertEquals(null, lobs.getClobValue());
 +        }
 +
 +        // Test null replaces content and verify content deleted
 +        {
 +            StorableWithLobs lobs = storage.prepare();
 +            lobs.setBlobValue(new ByteArrayBlob("hello".getBytes()));
 +            lobs.setClobValue(new StringClob("world!!!"));
 +            lobs.insert();
 +
 +            Blob blob = lobs.getBlobValue();
 +            Clob clob = lobs.getClobValue();
 +
 +            assertEquals(5, blob.getLength());
 +            assertEquals(8, clob.getLength());
 +
 +            lobs.setBlobValue(null);
 +
 +            lobs.update();
 +
 +            assertNull(lobs.getBlobValue());
 +            assertEquals(clob.asString(), lobs.getClobValue().asString());
 +
 +            lobs.load();
 +
 +            assertNull(lobs.getBlobValue());
 +            assertEquals(clob.asString(), lobs.getClobValue().asString());
 +
 +            lobs.setClobValue(null);
 +
 +            lobs.update();
 +
 +            assertNull(lobs.getBlobValue());
 +            assertNull(lobs.getClobValue());
 +
 +            lobs.load();
 +
 +            assertNull(lobs.getBlobValue());
 +            assertNull(lobs.getClobValue());
 +        }
 +
 +        // Test content replaces null
 +        {
 +            StorableWithLobs lobs = storage.prepare();
 +            lobs.insert();
 +
 +            lobs.setBlobValue(new ByteArrayBlob("hello".getBytes()));
 +            lobs.setClobValue(new StringClob("world"));
 +
 +            assertTrue(lobs.getBlobValue() instanceof ByteArrayBlob);
 +            assertTrue(lobs.getClobValue() instanceof StringClob);
 +
 +            lobs.update();
 +
 +            assertEquals("hello", lobs.getBlobValue().asString());
 +            assertEquals("world", lobs.getClobValue().asString());
 +
 +            assertFalse(lobs.getBlobValue() instanceof ByteArrayBlob);
 +            assertFalse(lobs.getClobValue() instanceof StringClob);
 +
 +            lobs.load();
 +
 +            assertEquals("hello", lobs.getBlobValue().asString());
 +            assertEquals("world", lobs.getClobValue().asString());
 +
 +            assertFalse(lobs.getBlobValue() instanceof ByteArrayBlob);
 +            assertFalse(lobs.getClobValue() instanceof StringClob);
 +        }
 +
 +        // Test content replaces content of same length
 +        {
 +            StorableWithLobs lobs = storage.prepare();
 +            lobs.setBlobValue(new ByteArrayBlob("hello".getBytes()));
 +            lobs.setClobValue(new StringClob("world?"));
 +            lobs.insert();
 +
 +            Blob blob = lobs.getBlobValue();
 +            Clob clob = lobs.getClobValue();
 +
 +            lobs.setBlobValue(new ByteArrayBlob("12345".getBytes()));
 +            lobs.update();
 +
 +            assertEquals(5, lobs.getBlobValue().getLength());
 +            assertEquals(6, lobs.getClobValue().getLength());
 +
 +            assertEquals("12345", lobs.getBlobValue().asString());
 +            assertEquals("world?", lobs.getClobValue().asString());
 +
 +            assertTrue(blob.asString().equals(lobs.getBlobValue().asString()));
 +            assertTrue(clob.asString().equals(lobs.getClobValue().asString()));
 +
 +            lobs.setClobValue(new StringClob("123456"));
 +            lobs.update();
 +
 +            assertEquals(5, lobs.getBlobValue().getLength());
 +            assertEquals(6, lobs.getClobValue().getLength());
 +
 +            assertEquals("12345", lobs.getBlobValue().asString());
 +            assertEquals("123456", lobs.getClobValue().asString());
 +
 +            assertTrue(blob.asString().equals(lobs.getBlobValue().asString()));
 +            assertTrue(clob.asString().equals(lobs.getClobValue().asString()));
 +        }
 +
 +        // Test content replaces content of longer length
 +        {
 +            StorableWithLobs lobs = storage.prepare();
 +            lobs.setBlobValue(new ByteArrayBlob("hello".getBytes()));
 +            lobs.setClobValue(new StringClob("world?"));
 +            lobs.insert();
 +
 +            Blob blob = lobs.getBlobValue();
 +            Clob clob = lobs.getClobValue();
 +
 +            lobs.setBlobValue(new ByteArrayBlob("123".getBytes()));
 +            lobs.update();
 +
 +            assertEquals(3, lobs.getBlobValue().getLength());
 +            assertEquals(6, lobs.getClobValue().getLength());
 +
 +            assertEquals("123", lobs.getBlobValue().asString());
 +            assertEquals("world?", lobs.getClobValue().asString());
 +
 +            assertTrue(blob.asString().equals(lobs.getBlobValue().asString()));
 +            assertTrue(clob.asString().equals(lobs.getClobValue().asString()));
 +
 +            lobs.setClobValue(new StringClob("12"));
 +            lobs.update();
 +
 +            assertEquals(3, lobs.getBlobValue().getLength());
 +            assertEquals(2, lobs.getClobValue().getLength());
 +
 +            assertEquals("123", lobs.getBlobValue().asString());
 +            assertEquals("12", lobs.getClobValue().asString());
 +
 +            assertTrue(blob.asString().equals(lobs.getBlobValue().asString()));
 +            assertTrue(clob.asString().equals(lobs.getClobValue().asString()));
 +        }
 +
 +        // Test content replaces content of shorter length
 +        {
 +            StorableWithLobs lobs = storage.prepare();
 +            lobs.setBlobValue(new ByteArrayBlob("hello".getBytes()));
 +            lobs.setClobValue(new StringClob("world?"));
 +            lobs.insert();
 +
 +            Blob blob = lobs.getBlobValue();
 +            Clob clob = lobs.getClobValue();
 +
 +            lobs.setBlobValue(new ByteArrayBlob("123456789".getBytes()));
 +            lobs.update();
 +
 +            assertEquals(9, lobs.getBlobValue().getLength());
 +            assertEquals(6, lobs.getClobValue().getLength());
 +
 +            assertEquals("123456789", lobs.getBlobValue().asString());
 +            assertEquals("world?", lobs.getClobValue().asString());
 +
 +            assertTrue(blob.asString().equals(lobs.getBlobValue().asString()));
 +            assertTrue(clob.asString().equals(lobs.getClobValue().asString()));
 +
 +            lobs.setClobValue(new StringClob("1234567890"));
 +            lobs.update();
 +
 +            assertEquals(9, lobs.getBlobValue().getLength());
 +            assertEquals(10, lobs.getClobValue().getLength());
 +
 +            assertEquals("123456789", lobs.getBlobValue().asString());
 +            assertEquals("1234567890", lobs.getClobValue().asString());
 +
 +            assertTrue(blob.asString().equals(lobs.getBlobValue().asString()));
 +            assertTrue(clob.asString().equals(lobs.getClobValue().asString()));
 +        }
 +
 +        // Test update failure
 +        {
 +            StorableWithLobs lobs = storage.prepare();
 +            lobs.setId(10000);
 +
 +            Blob newBlob = new ByteArrayBlob("blob update should fail".getBytes());
 +            Clob newClob = new StringClob("clob update should fail");
 +
 +            lobs.setBlobValue(newBlob);
 +            lobs.setClobValue(newClob);
 +
 +            try {
 +                lobs.update();
 +                fail();
 +            } catch (PersistNoneException e) {
 +            }
 +
 +            assertTrue(newBlob == lobs.getBlobValue());
 +            assertTrue(newClob == lobs.getClobValue());
 +        }
 +    }
 +
 +    @Override
 +    public void test_insertLobBig() throws Exception {
 +	// Not a useful test.
 +    }
 +
 +    private RepositoryBuilder jdbcBuilder(boolean isMaster) throws RepositoryException {
 +        JDBCRepositoryBuilder builder = new JDBCRepositoryBuilder();
 +        builder.setName("jdbc");
 +        builder.setAutoVersioningEnabled(true, null);
 +        builder.setMaster(isMaster);
 +        BasicDataSource ds = new BasicDataSource();
 +        builder.setDataSource(ds);
 +
 +        builder.setSchemaResolver(new H2SchemaResolver());
 +
 +        File dir = new File(TestUtilities.makeTestDirectory("jdbc"), "/h2");
 +        String url = "jdbc:h2:" + dir.getPath();
 +        ds.setDriverClassName("org.h2.Driver");
 +        ds.setUrl(url);
 +        ds.setUsername("sa");
 +        ds.setPassword("");
 +
 +        return builder;
 +    }
 +}
  | 
