Bug #2318 Problem inserting and reselecting large blobs
Submitted: 8 Jan 2004 6:46 Modified: 8 Jan 2004 7:56
Reporter: uwe schaefer Email Updates:
Status: Can't repeat Impact on me:
None 
Category:Connector / J Severity:S2 (Serious)
Version:3.0.9 OS:JDK1.4.2 on win2000
Assigned to: Mark Matthews CPU Architecture:Any

[8 Jan 2004 6:46] uwe schaefer
Description:
i´m having trouble storing a blob of more than 16mb into the database.
server is 4.0.16 on linux, driver is 3.0.9 or snaptshots from 
Jan 6. ´04 or Jan 8. ´04

show variables;

gives a max_allowed_packet value of 512mb

table looks like this:

mysql> describe bintest;

| Field | Type       | Null | Key | Default | Extra          |
+-------+------------+------+-----+---------+----------------+
| uid   | bigint(20) |      | PRI | NULL    | auto_increment |
| data  | longblob   | YES  |     | NULL    |                |

I have a simple unit test that inserts one blob into the DB an the reselects it back, in order to compare the result to the Array previously inserted.

The comparison shows an offset of 1 in the data, if the array is larger than 15mb (otherwise, everything works as expected) like this:

first array:  -39 -41 36 -119 -14 31 36 66 -47 -56 -93 102 -25 -121 -125
47
second array: 0 -39 -41 36 -119 -14 31 36 66 -47 -56 -93 102 -25 -121 -125

How to repeat:
Use this TestCase to reproduce:

package tests;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import junit.framework.TestCase;
import org.gjt.mm.mysql.Driver;
public class MaxSizeTest extends TestCase
{
  private static final String URL = "jdbc:mysql://someServer/connectorjtest?user=someUser&password=somePassword";
  public MaxSizeTest(String arg0)
  {
    super(arg0);
  }
  public static void main(String[] args)
  {
    junit.textui.TestRunner.run(MaxSizeTest.class);
  }
  protected void setUp() throws Exception
  {
    super.setUp();
    Class.forName(Driver.class.getName());
    java.sql.Driver d = DriverManager.getDriver(URL);
    System.err.println("Testing Driver " + d.getMajorVersion() + "." + d.getMinorVersion());
  }
  protected void tearDown() throws Exception
  {
    super.tearDown();
  }
  public void testAll() throws Exception
  {
    testArray(TestBlob.bin);
  }
  private void testArray(byte[] bs) throws Exception
  {
    System.err.println("query test with " + bs.length + " bytes");
    Connection c = DriverManager.getConnection(URL);
    //
    java.sql.PreparedStatement s = c.prepareStatement("DELETE FROM bintest;");
    s.execute();
    //
    s = c.prepareStatement("INSERT INTO bintest VALUES (?,?);");
    long id = System.currentTimeMillis();
    s.setLong(1, id);
    s.setBytes(2, bs);
    //
    s.execute();
    //
    ResultSet rs = c.prepareStatement("SELECT * FROM bintest WHERE uid=" + id).executeQuery();
    if (rs.next())
    {
      long l = rs.getLong(1);
      assertEquals(l, id);
      byte[] b = rs.getBytes(2);
      assertEquals(b.length, bs.length);
      // compare arrays
      for (int i = 0; i < b.length; i++)
      {
        if (b[i] != bs[i])
        {
          System.err.println("byte: " + i);
          doFail(b, bs);
        }
      }
    }
    else
      fail();
  }
  private void doFail(byte[] b, byte[] bs)
  {
    printStart("first array:  ", bs);
    printStart("second array: ", b);
    fail();
  }
  private void printStart(String string, byte[] b)
  {
    System.err.print(string);
    for (int i = 0; i < 16; i++)
    {
      byte c = b[i];
      System.err.print(String.valueOf((int) c) + " ");
    }
    System.err.println("");
  }
  static class TestBlob
  {
    public static byte[] bin = new byte[1024 * 1024 * 16];
    static {
      System.err.println("preparing array");
      fillArray(bin);
      System.err.println("preparing array done");
    }
    private static void fillArray(byte[] array)
    {
      for (int i = 0; i < array.length; i++)
      {
        array[i] = (byte) (Math.random() * 256);
      }
    }
  }
}

Suggested fix:
the fact, that this only happens if the array is near to 16m lets us suspect something around packet chunking or something like that.
[8 Jan 2004 7:56] Mark Matthews
The exact same testcase run with the nightly snapshots works for me. (Pretty much the same testcase is in testsuite.simple.BlobTest as well).

Are you _absolutely_ sure your application is not picking up an older version of Connector/J which _did_ have this bug?
[8 Jan 2004 10:14] uwe schaefer
Almost sorry to say: Yes I am. There is no other driver in the classpath.
Apart from the jdk-stuff (unmodified) only 
junit.jar and 
mysql-connector-java-3.0-nightly-20040108-bin.jar
are part of the game. 

BUT after double checking any parameter that could cause this trouble i found that i am talking to a 4.0.5 instead of 4.0.16.

might this be the solution ? (not that easy to get rid of it, otherwise i´d have tested already)
[9 Jan 2004 1:50] uwe schaefer
Hi

I just ran this test against a 5.0a server and saw it working. so obviously this is not a particular driver problem.

of course, i don´t want to use an alpha state server in our development environment, so here is the question:

is this a known issue ? and if so: can anyone tell if i could safely use a 4.0.whatever ?

thanks a lot.