You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by "DOAN DuyHai (JIRA)" <ji...@apache.org> on 2013/12/01 16:28:35 UTC

[jira] [Updated] (CASSANDRA-6426) Lost update in Prepared statement batch when a column is inserted with null value in the same batch just before

     [ https://issues.apache.org/jira/browse/CASSANDRA-6426?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

DOAN DuyHai updated CASSANDRA-6426:
-----------------------------------

    Description: 
{panel:title=Test environment}
Cassandra Server *2.0.3*
Java Driver Core *2.0.0-rc1*
{panel}

While implementing batched prepared statements for Achilles, I ran into a very annoying bug.

{code:title=FailingUnitTest.java|borderStyle=solid}
//Given
Long id = RandomUtils.nextLong();
session.execute("CREATE TABLE test(id bigint, name text,label text, PRIMARY KEY(id))");
PreparedStatement insertPS = session.prepare("INSERT INTO test(id,name,label) VALUES (?,?,?)");
PreparedStatement updatePS = session.prepare("UPDATE test SET label=? WHERE id=?");

// Notice the "label" column is inserted first with null
BoundStatement insertBS = insertPS.bind(id, "myName", null);
// Then "label" is updated to "myLabel"
BoundStatement updateBS = updatePS.bind("myLabel", id);

//When
BatchStatement batch = new BatchStatement();
batch.add(insertBS);
batch.add(updateBS);
session.execute(batch);

//Then
Statement statement = new SimpleStatement("SELECT * from test where id=" + id);
Row row = manager.getNativeSession().execute(statement).one();
// Assertion FAIL, "label" is NULL
assertThat(row.getString("label")).isEqualTo("myLabel");
{code}

 The above code always fails.

 Even if I switch the order of the bound statements, e.g. *updateBS* added to the batch before *insertBS*, the test still fails.

{code:title=WorkingUnitTest.java|borderStyle=solid}
//Given
Long id = RandomUtils.nextLong();
session.execute("CREATE TABLE test(id bigint, name text,label text, PRIMARY KEY(id))");
PreparedStatement insertPS = session.prepare("INSERT INTO test(id,name) VALUES (?,?)");
PreparedStatement updatePS = session.prepare("UPDATE test SET label=? WHERE id=?");

// Notice the "label" column is removed from the insert statement
BoundStatement insertBS = insertPS.bind(id, "myName");
BoundStatement updateBS = updatePS.bind("myLabel", id);

//When
BatchStatement batch = new BatchStatement();
batch.add(updateBS);
batch.add(insertBS);
session.execute(batch);

//Then
Statement statement = new SimpleStatement("SELECT * from test where id=" + id);
Row row = manager.getNativeSession().execute(statement).one();
// Assertion SUCCEEDS here
assertThat(row.getString("label")).isEqualTo("myLabel");
{code}

 Only removing column "label" from the first insert bound statement can make the test succeed. This is pretty annoying. 

 The rationale for inserting null values is that in Achilles I prepare generic insert statements for all entities and setting NULL when the field is not filled at runtime.

 Currently, there is no guarantee for batch of prepared statement to be executed in the order they are declared.


  was:
{panel:title=Test environment}
Cassandra Server *2.0.3*
Java Driver Core *2.0.0-rc1*
{panel}

While implementing batched prepared statements for Achilles, I ran into a very annoying bug.

{code:title=FailingUnitTest.java|borderStyle=solid}
//Given
Long id = RandomUtils.nextLong();
session.execute("CREATE TABLE test(id bigint, name text,label text, PRIMARY KEY(id))");
PreparedStatement insertPS = session.prepare("INSERT INTO test(id,name,label) VALUES (?,?,?)");
PreparedStatement updatePS = session.prepare("UPDATE test SET label=? WHERE id=?");

// Notice the "label" column is inserted first with null
BoundStatement insertBS = insertPS.bind(id, "myName", null);
// Then "label" is updated to "myLabel"
BoundStatement updateBS = updatePS.bind("myLabel", id);

//When
BatchStatement batch = new BatchStatement();
batch.add(updateBS);
batch.add(insertBS);
session.execute(batch);

//Then
Statement statement = new SimpleStatement("SELECT * from test where id=" + id);
Row row = manager.getNativeSession().execute(statement).one();
// Assertion FAIL, "label" is NULL
assertThat(row.getString("label")).isEqualTo("myLabel");
{code}

 The above code always fails.

 Even if I switch the order of the bound statements, e.g. *updateBS* added to the batch before *insertBS*, the test still fails.

{code:title=WorkingUnitTest.java|borderStyle=solid}
//Given
Long id = RandomUtils.nextLong();
session.execute("CREATE TABLE test(id bigint, name text,label text, PRIMARY KEY(id))");
PreparedStatement insertPS = session.prepare("INSERT INTO test(id,name) VALUES (?,?)");
PreparedStatement updatePS = session.prepare("UPDATE test SET label=? WHERE id=?");

// Notice the "label" column is removed from the insert statement
BoundStatement insertBS = insertPS.bind(id, "myName");
BoundStatement updateBS = updatePS.bind("myLabel", id);

//When
BatchStatement batch = new BatchStatement();
batch.add(updateBS);
batch.add(insertBS);
session.execute(batch);

//Then
Statement statement = new SimpleStatement("SELECT * from test where id=" + id);
Row row = manager.getNativeSession().execute(statement).one();
// Assertion SUCCEEDS here
assertThat(row.getString("label")).isEqualTo("myLabel");
{code}

 Only removing column "label" from the first insert bound statement can make the test succeed. This is pretty annoying. 

 The rationale for inserting null values is that in Achilles I prepare generic insert statements for all entities and setting NULL when the field is not filled at runtime.

 Currently, there is no guarantee for batch of prepared statement to be executed in the order they are declared.



> Lost update in Prepared statement batch when a column is inserted with null value in the same batch just before
> ---------------------------------------------------------------------------------------------------------------
>
>                 Key: CASSANDRA-6426
>                 URL: https://issues.apache.org/jira/browse/CASSANDRA-6426
>             Project: Cassandra
>          Issue Type: Bug
>          Components: Core
>         Environment: Cassandra Server 2.0.3
> Java Driver Core 2.0.0-rc1
>            Reporter: DOAN DuyHai
>
> {panel:title=Test environment}
> Cassandra Server *2.0.3*
> Java Driver Core *2.0.0-rc1*
> {panel}
> While implementing batched prepared statements for Achilles, I ran into a very annoying bug.
> {code:title=FailingUnitTest.java|borderStyle=solid}
> //Given
> Long id = RandomUtils.nextLong();
> session.execute("CREATE TABLE test(id bigint, name text,label text, PRIMARY KEY(id))");
> PreparedStatement insertPS = session.prepare("INSERT INTO test(id,name,label) VALUES (?,?,?)");
> PreparedStatement updatePS = session.prepare("UPDATE test SET label=? WHERE id=?");
> // Notice the "label" column is inserted first with null
> BoundStatement insertBS = insertPS.bind(id, "myName", null);
> // Then "label" is updated to "myLabel"
> BoundStatement updateBS = updatePS.bind("myLabel", id);
> //When
> BatchStatement batch = new BatchStatement();
> batch.add(insertBS);
> batch.add(updateBS);
> session.execute(batch);
> //Then
> Statement statement = new SimpleStatement("SELECT * from test where id=" + id);
> Row row = manager.getNativeSession().execute(statement).one();
> // Assertion FAIL, "label" is NULL
> assertThat(row.getString("label")).isEqualTo("myLabel");
> {code}
>  The above code always fails.
>  Even if I switch the order of the bound statements, e.g. *updateBS* added to the batch before *insertBS*, the test still fails.
> {code:title=WorkingUnitTest.java|borderStyle=solid}
> //Given
> Long id = RandomUtils.nextLong();
> session.execute("CREATE TABLE test(id bigint, name text,label text, PRIMARY KEY(id))");
> PreparedStatement insertPS = session.prepare("INSERT INTO test(id,name) VALUES (?,?)");
> PreparedStatement updatePS = session.prepare("UPDATE test SET label=? WHERE id=?");
> // Notice the "label" column is removed from the insert statement
> BoundStatement insertBS = insertPS.bind(id, "myName");
> BoundStatement updateBS = updatePS.bind("myLabel", id);
> //When
> BatchStatement batch = new BatchStatement();
> batch.add(updateBS);
> batch.add(insertBS);
> session.execute(batch);
> //Then
> Statement statement = new SimpleStatement("SELECT * from test where id=" + id);
> Row row = manager.getNativeSession().execute(statement).one();
> // Assertion SUCCEEDS here
> assertThat(row.getString("label")).isEqualTo("myLabel");
> {code}
>  Only removing column "label" from the first insert bound statement can make the test succeed. This is pretty annoying. 
>  The rationale for inserting null values is that in Achilles I prepare generic insert statements for all entities and setting NULL when the field is not filled at runtime.
>  Currently, there is no guarantee for batch of prepared statement to be executed in the order they are declared.



--
This message was sent by Atlassian JIRA
(v6.1#6144)