diff --git a/pom.xml b/pom.xml index 9795d39b..812669c1 100644 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,7 @@ 1.8 1.2.2 28.1-jre - 2.5.0-fixed + 2.5.1 2.5.0 2.29.1 9.4.29.v20200521 diff --git a/src/main/java/org/qortal/repository/hsqldb/HSQLDBATRepository.java b/src/main/java/org/qortal/repository/hsqldb/HSQLDBATRepository.java index 833137a2..bc26ab78 100644 --- a/src/main/java/org/qortal/repository/hsqldb/HSQLDBATRepository.java +++ b/src/main/java/org/qortal/repository/hsqldb/HSQLDBATRepository.java @@ -269,9 +269,10 @@ public class HSQLDBATRepository implements ATRepository { String sql = "SELECT height, created_when, state_data, state_hash, fees, is_initial " + "FROM ATStates " + "WHERE AT_address = ? " - + "ORDER BY height DESC " - + "LIMIT 1 " - + "USING INDEX"; + // AT_address then height so the compound primary key is used as an index + // Both must be the same direction also + + "ORDER BY AT_address DESC, height DESC " + + "LIMIT 1 "; try (ResultSet resultSet = this.repository.checkedExecute(sql, atAddress)) { if (resultSet == null) @@ -307,7 +308,9 @@ public class HSQLDBATRepository implements ATRepository { sql.append(minimumFinalHeight); } - sql.append( "ORDER BY height DESC " + // AT_address then height so the compound primary key is used as an index + // Both must be the same direction also + sql.append( "ORDER BY AT_address DESC, height DESC " + "LIMIT 1 " + ") AS FinalATStates " + "WHERE code_hash = ? "); diff --git a/src/test/java/org/qortal/test/RepositoryTests.java b/src/test/java/org/qortal/test/RepositoryTests.java index 7b20bbd9..be9ff50f 100644 --- a/src/test/java/org/qortal/test/RepositoryTests.java +++ b/src/test/java/org/qortal/test/RepositoryTests.java @@ -13,6 +13,7 @@ import org.qortal.test.common.Common; import static org.junit.Assert.*; +import java.sql.ResultSet; import java.sql.SQLException; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; @@ -180,6 +181,44 @@ public class RepositoryTests extends Common { } } + /** Test HSQLDB bug-fix for INSERT INTO...ON DUPLICATE KEY UPDATE... bug */ + @Test + public void testOnDuplicateKeyUpdateBugFix() throws SQLException, DataException { + ResultSet resultSet; + + try (final HSQLDBRepository hsqldb = (HSQLDBRepository) RepositoryManager.getRepository()) { + hsqldb.prepareStatement("DROP TABLE IF EXISTS bugtest").execute(); + hsqldb.prepareStatement("CREATE TABLE bugtest (id INT NOT NULL, counter INT NOT NULL, PRIMARY KEY(id))").execute(); + + hsqldb.prepareStatement("INSERT INTO bugtest (id, counter) VALUES (1, 1) ON DUPLICATE KEY UPDATE counter = counter + 1").execute(); + resultSet = hsqldb.checkedExecute("SELECT counter FROM bugtest WHERE id = 1"); + assertNotNull(resultSet); + assertEquals(1, resultSet.getInt(1)); + + hsqldb.prepareStatement("INSERT INTO bugtest (id, counter) VALUES (1, 100) ON DUPLICATE KEY UPDATE counter = counter + 1").execute(); + resultSet = hsqldb.checkedExecute("SELECT counter FROM bugtest WHERE id = 1"); + assertNotNull(resultSet); + assertEquals(2, resultSet.getInt(1)); + } + } + + /** Test HSQLDB bug-fix for "General Error" in non-fully-qualified columns inside LATERAL() */ + @Test + public void testOnLateralGeneralError() throws SQLException, DataException { + try (final HSQLDBRepository hsqldb = (HSQLDBRepository) RepositoryManager.getRepository()) { + hsqldb.prepareStatement("DROP TABLE IF EXISTS tableA").execute(); + hsqldb.prepareStatement("DROP TABLE IF EXISTS tableB").execute(); + hsqldb.prepareStatement("DROP TABLE IF EXISTS tableC").execute(); + + hsqldb.prepareStatement("CREATE TABLE tableA (col1 INT)").execute(); + hsqldb.prepareStatement("CREATE TABLE tableB (col1 INT)").execute(); + hsqldb.prepareStatement("CREATE TABLE tableC (col2 INT, PRIMARY KEY (col2))").execute(); + + // Prior to bug-fix this would throw a General Error SQL Exception + hsqldb.prepareStatement("SELECT col3 FROM tableA JOIN tableB USING (col1) CROSS JOIN LATERAL(SELECT col2 FROM tableC WHERE col2 = col1) AS tableC (col3)").execute(); + } + } + public static void hsqldbSleep(int millis) throws SQLException { System.out.println(String.format("HSQLDB sleep() thread ID: %s", Thread.currentThread().getId()));