You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by rh...@apache.org on 2012/05/02 17:55:32 UTC

svn commit: r1333087 - in /db/derby/code/branches/10.8: ./ java/client/org/apache/derby/client/net/ java/engine/org/apache/derby/impl/store/raw/data/ java/testing/org/apache/derbyTesting/functionTests/tests/lang/

Author: rhillegas
Date: Wed May  2 15:55:32 2012
New Revision: 1333087

URL: http://svn.apache.org/viewvc?rev=1333087&view=rev
Log:
DERBY-5679: Ported 1330877 and 1331484 from trunk to 10.8 branch.

Modified:
    db/derby/code/branches/10.8/   (props changed)
    db/derby/code/branches/10.8/java/client/org/apache/derby/client/net/NetCursor.java   (props changed)
    db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/store/raw/data/StoredPage.java
    db/derby/code/branches/10.8/java/testing/org/apache/derbyTesting/functionTests/tests/lang/AlterTableTest.java

Propchange: db/derby/code/branches/10.8/
------------------------------------------------------------------------------
  Merged /db/derby/code/trunk:r1330877,1331484

Propchange: db/derby/code/branches/10.8/java/client/org/apache/derby/client/net/NetCursor.java
------------------------------------------------------------------------------
  Merged /db/derby/code/trunk/java/client/org/apache/derby/client/net/NetCursor.java:r1330877,1331484

Modified: db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/store/raw/data/StoredPage.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/store/raw/data/StoredPage.java?rev=1333087&r1=1333086&r2=1333087&view=diff
==============================================================================
--- db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/store/raw/data/StoredPage.java (original)
+++ db/derby/code/branches/10.8/java/engine/org/apache/derby/impl/store/raw/data/StoredPage.java Wed May  2 15:55:32 2012
@@ -327,10 +327,15 @@ public class StoredPage extends CachedPa
      *     COLUMN_LONG   - this is a known long column, therefore we will 
      *                     store part of the column on the current page and 
      *                     overflow the rest if necessary.
+     *     COLUMN_CREATE_NULL   - the column was recently added.
+     *                  it doesn't actually exist in the on-disk row yet.
+     *                  we will need to put a null in it as soon as possible.
+     *                  see DERBY-5679.
      **/
     protected static final int COLUMN_NONE  = 0;
     protected static final int COLUMN_FIRST = 1;
     protected static final int COLUMN_LONG  = 2;
+    protected static final int COLUMN_CREATE_NULL  = 3;
 
 
     /**
@@ -3968,12 +3973,14 @@ public class StoredPage extends CachedPa
                     else 
                     {
                         // this is an update that is increasing the number of 
-                        // columns but not providing any value, strange ...
-
+                        // columns but not providing any value. this can happen
+                        // if you are updating a new column after using
+                        // ALTER TABLE to add a couple new columns.
+                        // see DERBY-5679.
                         spaceAvailable = 
                             logColumn(
                                 null, 0, out, spaceAvailable, 
-                                columnFlag, overflowThreshold);
+                                COLUMN_CREATE_NULL, overflowThreshold);
                     }
 
                 } 
@@ -6177,7 +6184,7 @@ public class StoredPage extends CachedPa
             }
         }
 
-        if (column == null)
+        if ( (column == null) && (columnFlag != COLUMN_CREATE_NULL))
         {
             fieldStatus  = StoredFieldHeader.setNonexistent(fieldStatus);
             headerLength =
@@ -6300,11 +6307,28 @@ public class StoredPage extends CachedPa
             }
         
         } 
+        else if ( columnFlag == COLUMN_CREATE_NULL )
+        {
+            //
+            // This block handles the case when a couple columns have been added
+            // recently and now one of the later columns is being updated. Newly added columns
+            // which appear in the row before the updated column don't actually have
+            // any values yet. We stuff NULLs into those newly added columns here.
+            // This fixes DERBY-5679.
+            //
+            fieldStatus = StoredFieldHeader.setNull(fieldStatus, true);
+
+            // header is written with 0 length here.
+            headerLength = 
+                StoredFieldHeader.write(
+                    logicalDataOut, fieldStatus, 
+                    fieldDataLength, slotFieldSize);
+        }
         else if (column instanceof DataValueDescriptor)
         {
             DataValueDescriptor sColumn = (DataValueDescriptor) column;
 
-            boolean isNull = sColumn.isNull();
+            boolean isNull = (columnFlag == COLUMN_CREATE_NULL) || sColumn.isNull();
             if (isNull) 
             {
                 fieldStatus = StoredFieldHeader.setNull(fieldStatus, true);

Modified: db/derby/code/branches/10.8/java/testing/org/apache/derbyTesting/functionTests/tests/lang/AlterTableTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.8/java/testing/org/apache/derbyTesting/functionTests/tests/lang/AlterTableTest.java?rev=1333087&r1=1333086&r2=1333087&view=diff
==============================================================================
--- db/derby/code/branches/10.8/java/testing/org/apache/derbyTesting/functionTests/tests/lang/AlterTableTest.java (original)
+++ db/derby/code/branches/10.8/java/testing/org/apache/derbyTesting/functionTests/tests/lang/AlterTableTest.java Wed May  2 15:55:32 2012
@@ -29,10 +29,9 @@ import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLWarning;
 import java.sql.Connection;
-
-
 import java.sql.DatabaseMetaData;
 import java.sql.SQLException;
+import java.util.Arrays;
 import junit.framework.Test;
 import junit.framework.TestSuite;
 import org.apache.derbyTesting.functionTests.util.TestInputStream;
@@ -3729,4 +3728,217 @@ public final class AlterTableTest extend
         s.execute("alter table \"\"\"\".\"\"\"\" " +
                   "alter column \"\"\"\" set increment by 2");
     }
+    
+    /**
+     * Verify that rollback works properly if a column with a null default
+     * is added and then the table is updated. See DERBY-5679.
+     */
+    public void test_5679() throws Exception
+    {
+        Statement s = createStatement();
+        ResultSet   rs;
+
+        String[][]  rowBefore = new String[][]{ { "before", null, "before" }  };
+        String[][]  rowAfter = new String[][]{ { "after", "after", "after" }  };
+
+        // create a table, insert a row, add two columns, then update one of the columns
+        s.execute( "create table t_5679(name1 varchar(10))" );
+        s.execute( "insert into t_5679(name1) values('before')" );
+        s.execute( "alter table t_5679 add column str1 varchar(10)" );
+        s.execute( "alter table t_5679 add column str2 varchar(10)" );
+        s.execute( "update t_5679 set str2 = 'before'" );
+
+        rs = s.executeQuery( "select * from t_5679" );
+        JDBC.assertFullResultSet( rs, rowBefore );
+
+        // now update the row and rollback
+        setAutoCommit( false );
+        s.execute( "update t_5679 set name1='after', str1='after', str2='after'" );
+        rs = s.executeQuery( "select * from t_5679" );
+        JDBC.assertFullResultSet( rs, rowAfter );
+        rollback();
+        setAutoCommit( true );
+
+        // all columns of the row should have reverted
+        rs = s.executeQuery( "select * from t_5679" );
+        JDBC.assertFullResultSet( rs, rowBefore );
+
+        s.execute( "drop table t_5679" );
+    }
+    
+    /**
+     * More tests for DERBY-5679. Verify with a lot of columns.
+     */
+    public void test_5679_manyColumns() throws Exception
+    {
+        Statement s = createStatement();
+        ResultSet   rs;
+
+        // create a table, insert a row, add two columns, then update one of the columns
+        s.execute( "create table t_5679_1( keyCol int )" );
+        s.execute( "insert into t_5679_1( keyCol ) values( 1 )" );
+
+        // now add a lot of columns
+        for ( int i = 1; i < 100; i++ )
+        {
+            s.execute( "alter table t_5679_1 add column a_" + i + " int" );
+        }
+        s.execute( "update t_5679_1 set a_50 = 50" );
+
+        String[]    rawBeforeRow = new String[ 100 ];
+        rawBeforeRow[ 0 ] = "1";
+        rawBeforeRow[ 50 ] = "50";
+        String[][]  beforeRow = new String[][] { rawBeforeRow };
+
+        String[]    rawAfterRow = new String[ 100 ];
+        rawAfterRow[ 0 ] = "1";
+        rawAfterRow[ 49 ] = "490";
+        rawAfterRow[ 50 ] = "500";
+        rawAfterRow[ 51 ] = "510";
+        String[][]  afterRow = new String[][] { rawAfterRow };
+
+        rs = s.executeQuery( "select * from t_5679_1" );
+        JDBC.assertFullResultSet( rs, beforeRow );
+
+        // now update the row and rollback
+        setAutoCommit( false );
+        s.execute( "update t_5679_1 set a_49 = 490, a_50 = 500, a_51 = 510" );
+        rs = s.executeQuery( "select * from t_5679_1" );
+        JDBC.assertFullResultSet( rs, afterRow );
+        rollback();
+        setAutoCommit( true );
+
+        // all columns of the row should have reverted
+        rs = s.executeQuery( "select * from t_5679_1" );
+        JDBC.assertFullResultSet( rs, beforeRow );
+
+        s.execute( "drop table t_5679_1" );
+    }
+    
+    /**
+     * More tests for DERBY-5679. Verify with long rows.
+     */
+    public void test_5679_longRows() throws Exception
+    {
+        Connection conn = getConnection();
+        PreparedStatement ps;
+        ResultSet   rs;
+
+        // verify that the default page size of 4096 bytes is in effect
+        ps = conn.prepareStatement( "values syscs_util.syscs_get_database_property( 'derby.storage.pageSize' )" );
+        rs = ps.executeQuery();
+        rs.next();
+        assertNull( rs.getString( 1 ) );
+        rs.close();
+        ps.close();
+
+        final   int LONG = 1050;
+        final   int SHORT = 500;
+        final   int PAGE_SIZE = 4096;
+
+        byte[]  a_0 = makeBytes( 0, LONG );
+        byte[]  a_1 = makeBytes( 1, LONG );
+        byte[]  a_2 = makeBytes( 2, LONG );
+        byte[]  a_4 = makeBytes( 4, LONG );
+
+        // create a table, insert a row, add two columns, then update one of the columns
+        conn.prepareStatement
+            (
+             "create table t_5679_2( a_0 varchar( " + LONG + " ) for bit data," +
+             " a_1 varchar( " + LONG + " ) for bit data," +
+             " a_2 varchar( " + LONG + " ) for bit data)" )
+            .execute();
+        ps = conn.prepareStatement( "insert into t_5679_2( a_0, a_1, a_2 ) values ( ?, ?, ? )" );
+        ps.setBytes( 1, a_0 );
+        ps.setBytes( 2, a_1 );
+        ps.setBytes( 3, a_2 );
+        ps.executeUpdate();
+        ps.close();
+
+        // now add 2 columns. the second column will spill onto the second page if it is
+        // stuffed with a long value
+        conn.prepareStatement( "alter table t_5679_2 add column a_3 varchar( " + SHORT + " ) for bit data" ).execute();
+        conn.prepareStatement( "alter table t_5679_2 add column a_4 varchar( " + LONG + " ) for bit data" ).execute();
+
+        assertTrue( LONG + LONG + LONG + SHORT < PAGE_SIZE );
+        assertTrue( LONG + LONG + LONG + LONG > PAGE_SIZE );
+        
+        // now stuff the second newly added column with a large value which
+        // spills onto the next page
+        ps = conn.prepareStatement( "update t_5679_2 set a_4 = ?" );
+        ps.setBytes( 1, a_4 );
+        ps.executeUpdate();
+        ps.close();
+
+
+        byte[]  after_0 = makeBytes( 100, LONG );
+        byte[]  after_1 = makeBytes( 101, LONG );
+        byte[]  after_2 = makeBytes( 102, LONG );
+        byte[]  after_3 = makeBytes( 103, SHORT );
+        byte[]  after_4 = makeBytes( 104, LONG );
+        
+        byte[][]    beforeRow = new byte[][] { a_0, a_1, a_2, null, a_4 };
+        byte[][]    afterRow = new byte[][] { after_0, after_1, after_2, after_3, after_4 };
+
+        vetBytes_5679( conn, beforeRow );
+
+        // now update the row and rollback. columns a_0 through a_3 should stay on
+        // the first page and a_4 should stay on the second page
+        conn.setAutoCommit( false );
+        ps = conn.prepareStatement( "update t_5679_2 set a_0 = ?, a_1 = ?, a_2 = ?, a_3 = ?, a_4 = ?" );
+        ps.setBytes( 1, after_0 );
+        ps.setBytes( 2, after_1 );
+        ps.setBytes( 3, after_2 );
+        ps.setBytes( 4, after_3 );
+        ps.setBytes( 5, after_4 );
+        ps.executeUpdate();
+        vetBytes_5679( conn, afterRow );
+        rollback();
+        conn.setAutoCommit( true );
+
+        // all columns of the row should have reverted
+        vetBytes_5679( conn, beforeRow );
+
+        conn.prepareStatement( "drop table t_5679_2" ).execute();
+    }
+    private byte[]  makeBytes( int seed, int length )
+    {
+        byte[]  result = new byte[ length ];
+
+        Arrays.fill( result, (byte) seed );
+
+        return result;
+    }
+    private void    vetBytes_5679( Connection conn, byte[][] expected ) throws Exception
+    {
+        PreparedStatement   ps = conn.prepareStatement( "select * from t_5679_2" );
+        ResultSet   rs = ps.executeQuery();
+
+        rs.next();
+
+        for ( int i = 0; i < expected.length; i++ )
+        {
+            assertBytes( expected[ i ] , rs.getBytes( i + 1 ) );
+        }
+
+        rs.close();
+        ps.close();
+    }
+    private void    assertBytes( byte[] expected, byte[] actual ) throws Exception
+    {
+        if ( expected == null )
+        {
+            assertNull( actual );
+            return;
+        }
+        else { assertNotNull( actual ); }
+
+        assertEquals( expected.length, actual.length );
+
+        for ( int i = 0; i < expected.length; i++ )
+        {
+            assertEquals( expected[ i ], actual[ i ] );
+        }
+    }
+    
 }