package my.test.mvstore.bugs;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import org.junit.Assert;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
public class TestMVSecondaryIndex {
protected static Connection conn;
protected static Statement stmt;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
conn = DriverManager.getConnection("jdbc:h2:tcp://localhost:9092/mydb", "sa", "");
stmt = conn.createStatement();
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
if (stmt != null)
stmt.close();
if (conn != null)
conn.close();
}
@Test
public void testRegularTable() throws Exception {
run(null); //all tests pass
}
@Test
public void testMVTable() throws Exception {
run("org.h2.mvstore.db.MVTableEngine");
}
private void run(String engine) throws Exception {
stmt.executeUpdate("DROP TABLE IF EXISTS TestMVSecondaryIndex");
String sql = "CREATE TABLE IF NOT EXISTS TestMVSecondaryIndex(id int not null PRIMARY KEY, name varchar(20))";
if (engine != null)
sql += " ENGINE \"" + engine + "\"";
stmt.executeUpdate(sql);
stmt.executeUpdate("CREATE INDEX IF NOT EXISTS idx_name ON TestMVSecondaryIndex(name)");
stmt.executeUpdate("insert into TestMVSecondaryIndex(id, name) values(-1, 'a')");
stmt.executeUpdate("insert into TestMVSecondaryIndex(id, name) values(-2, 'a')");
stmt.executeUpdate("insert into TestMVSecondaryIndex(id, name) values(1, 'b')");
stmt.executeUpdate("insert into TestMVSecondaryIndex(id, name) values(2, 'b')");
count(2, "name='b'");
count(2, "name='a'"); //MVTable failed
}
private void count(int expected, String where) throws Exception {
ResultSet rs = stmt.executeQuery("select count(*) from TestMVSecondaryIndex where " + where);
rs.next();
Assert.assertEquals(expected, rs.getInt(1));
rs.close();
}
}
/*
[MVStore] Can not find the records from the secondary index if the value of primary key is negative and the type of index condition is EQUAL
H2 Version: svn trunk
Test:
==========================================
package my.test.mvstore.bugs;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import org.junit.Assert;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
public class TestMVSecondaryIndex {
protected static Connection conn;
protected static Statement stmt;
@BeforeClass
public static void setUpBeforeClass() throws Exception {
conn = DriverManager.getConnection("jdbc:h2:tcp://localhost:9092/mydb", "sa", "");
stmt = conn.createStatement();
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
if (stmt != null)
stmt.close();
if (conn != null)
conn.close();
}
@Test
public void testRegularTable() throws Exception {
run(null); //all tests pass
}
@Test
public void testMVTable() throws Exception {
run("org.h2.mvstore.db.MVTableEngine");
}
private void run(String engine) throws Exception {
stmt.executeUpdate("DROP TABLE IF EXISTS TestMVSecondaryIndex");
String sql = "CREATE TABLE IF NOT EXISTS TestMVSecondaryIndex(id int not null PRIMARY KEY, name varchar(20))";
if (engine != null)
sql += " ENGINE \"" + engine + "\"";
stmt.executeUpdate(sql);
stmt.executeUpdate("CREATE INDEX IF NOT EXISTS idx_name ON TestMVSecondaryIndex(name)");
stmt.executeUpdate("insert into TestMVSecondaryIndex(id, name) values(-1, 'a')");
stmt.executeUpdate("insert into TestMVSecondaryIndex(id, name) values(-2, 'a')");
stmt.executeUpdate("insert into TestMVSecondaryIndex(id, name) values(1, 'b')");
stmt.executeUpdate("insert into TestMVSecondaryIndex(id, name) values(2, 'b')");
count(2, "name='b'");
count(2, "name='a'"); //MVTable failed
}
private void count(int expected, String where) throws Exception {
ResultSet rs = stmt.executeQuery("select count(*) from TestMVSecondaryIndex where " + where);
rs.next();
Assert.assertEquals(expected, rs.getInt(1));
rs.close();
}
}
Analyze:
===============
The org.h2.mvstore.db.MVSecondaryIndex.find(Session, SearchRow, SearchRow) method using 0 as the key If the parameter 'first' is not null,
then ['a', 0] > ['a', -1]
Fix:
===============
Using Long.MIN_VALUE as the key may be better
*/