提交 08ef0d6f authored 作者: Thomas Mueller's avatar Thomas Mueller

The Lucene fulltext search ignored transaction rollback. Fixed using a trigger on rollback.

上级 8926f35e
...@@ -364,7 +364,7 @@ public class FullText { ...@@ -364,7 +364,7 @@ public class FullText {
case Types.ARRAY: case Types.ARRAY:
case DataType.TYPE_DATALINK: case DataType.TYPE_DATALINK:
case Types.DISTINCT: case Types.DISTINCT:
throw new SQLException("FULLTEXT", "Unsupported column data type: " + type); throw throwException("Unsupported column data type: " + type);
default: default:
return ""; return "";
} }
...@@ -462,7 +462,7 @@ public class FullText { ...@@ -462,7 +462,7 @@ public class FullText {
case Types.ARRAY: case Types.ARRAY:
case DataType.TYPE_DATALINK: case DataType.TYPE_DATALINK:
case Types.DISTINCT: case Types.DISTINCT:
throw new SQLException("FULLTEXT", "Unsupported key data type: " + type); throw throwException("Unsupported key data type: " + type);
default: default:
return ""; return "";
} }
...@@ -506,7 +506,7 @@ public class FullText { ...@@ -506,7 +506,7 @@ public class FullText {
} }
} }
if (found < 0) { if (found < 0) {
throw new SQLException("FULLTEXT", "Column not found: " + key); throw throwException("Column not found: " + key);
} }
index[i] = found; index[i] = found;
} }
...@@ -823,7 +823,7 @@ public class FullText { ...@@ -823,7 +823,7 @@ public class FullText {
} }
} }
if (keyList.size() == 0) { if (keyList.size() == 0) {
throw new SQLException("No primary key for table " + tableName); throw throwException("No primary key for table " + tableName);
} }
ArrayList<String> indexList = New.arrayList(); ArrayList<String> indexList = New.arrayList();
PreparedStatement prep = conn.prepareStatement( PreparedStatement prep = conn.prepareStatement(
...@@ -1017,4 +1017,15 @@ public class FullText { ...@@ -1017,4 +1017,15 @@ public class FullText {
FullTextSettings.closeAll(); FullTextSettings.closeAll();
} }
/**
* Throw a SQLException with the given message.
*
* @param message the message
* @return never returns normally
* @throws SQLException the exception
*/
protected static SQLException throwException(String message) throws SQLException {
throw new SQLException(message, "FULLTEXT");
}
} }
...@@ -217,7 +217,7 @@ public class FullTextLucene extends FullText { ...@@ -217,7 +217,7 @@ public class FullTextLucene extends FullText {
* @return the converted SQL exception * @return the converted SQL exception
*/ */
protected static SQLException convertException(Exception e) { protected static SQLException convertException(Exception e) {
SQLException e2 = new SQLException("FULLTEXT", "Error while indexing document"); SQLException e2 = new SQLException("Error while indexing document", "FULLTEXT");
e2.initCause(e); e2.initCause(e);
return e2; return e2;
} }
...@@ -234,8 +234,9 @@ public class FullTextLucene extends FullText { ...@@ -234,8 +234,9 @@ public class FullTextLucene extends FullText {
String trigger = StringUtils.quoteIdentifier(schema) + "." + StringUtils.quoteIdentifier(TRIGGER_PREFIX + table); String trigger = StringUtils.quoteIdentifier(schema) + "." + StringUtils.quoteIdentifier(TRIGGER_PREFIX + table);
stat.execute("DROP TRIGGER IF EXISTS " + trigger); stat.execute("DROP TRIGGER IF EXISTS " + trigger);
StringBuilder buff = new StringBuilder("CREATE TRIGGER IF NOT EXISTS "); StringBuilder buff = new StringBuilder("CREATE TRIGGER IF NOT EXISTS ");
// unlike the native fulltext search, the trigger is also called on rollback
buff.append(trigger). buff.append(trigger).
append(" AFTER INSERT, UPDATE, DELETE ON "). append(" AFTER INSERT, UPDATE, DELETE, ROLLBACK ON ").
append(StringUtils.quoteIdentifier(schema)). append(StringUtils.quoteIdentifier(schema)).
append('.'). append('.').
append(StringUtils.quoteIdentifier(table)). append(StringUtils.quoteIdentifier(table)).
...@@ -282,7 +283,7 @@ public class FullTextLucene extends FullText { ...@@ -282,7 +283,7 @@ public class FullTextLucene extends FullText {
rs.next(); rs.next();
String path = rs.getString(1); String path = rs.getString(1);
if (path == null) { if (path == null) {
throw new SQLException("FULLTEXT", "Fulltext search for in-memory databases is not supported."); throw throwException("Fulltext search for in-memory databases is not supported.");
} }
rs.close(); rs.close();
return path; return path;
...@@ -463,7 +464,7 @@ public class FullTextLucene extends FullText { ...@@ -463,7 +464,7 @@ public class FullTextLucene extends FullText {
} }
} }
if (keyList.size() == 0) { if (keyList.size() == 0) {
throw new SQLException("No primary key for table " + tableName); throw throwException("No primary key for table " + tableName);
} }
ArrayList<String> indexList = New.arrayList(); ArrayList<String> indexList = New.arrayList();
PreparedStatement prep = conn.prepareStatement( PreparedStatement prep = conn.prepareStatement(
......
...@@ -139,7 +139,7 @@ public class FullTextSettings { ...@@ -139,7 +139,7 @@ public class FullTextSettings {
rs.next(); rs.next();
String path = rs.getString(1); String path = rs.getString(1);
if ("MEM:UNNAMED".equals(path)) { if ("MEM:UNNAMED".equals(path)) {
throw new SQLException("FULLTEXT", "Fulltext search for private (unnamed) in-memory databases is not supported."); throw FullText.throwException("Fulltext search for private (unnamed) in-memory databases is not supported.");
} }
rs.close(); rs.close();
return path; return path;
......
...@@ -33,6 +33,8 @@ public class TestFullText extends TestBase { ...@@ -33,6 +33,8 @@ public class TestFullText extends TestBase {
} }
public void test() throws Exception { public void test() throws Exception {
testTransaction(false);
testTransaction(true);
testCreateDrop(); testCreateDrop();
if (config.memory) { if (config.memory) {
return; return;
...@@ -62,6 +64,38 @@ public class TestFullText extends TestBase { ...@@ -62,6 +64,38 @@ public class TestFullText extends TestBase {
deleteDb("fullTextReopen"); deleteDb("fullTextReopen");
} }
private void testTransaction(boolean lucene) throws SQLException {
if (config.memory) {
return;
}
String prefix = lucene ? "FTL" : "FT";
deleteDb("fullTextTransaction");
FileSystem.getInstance(baseDir).deleteRecursive(baseDir + "/fullTextTransaction", false);
Connection conn = getConnection("fullTextTransaction");
Statement stat = conn.createStatement();
String className = lucene ? "FullTextLucene" : "FullText";
stat.execute("CREATE ALIAS IF NOT EXISTS " + prefix + "_INIT FOR \"org.h2.fulltext." + className + ".init\"");
stat.execute("CALL " + prefix + "_INIT()");
stat.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR)");
stat.execute("INSERT INTO TEST VALUES(1, 'Hello World')");
stat.execute("CALL " + prefix + "_CREATE_INDEX('PUBLIC', 'TEST', NULL)");
stat.execute("UPDATE TEST SET NAME=NULL WHERE ID=1");
stat.execute("UPDATE TEST SET NAME='Hello World' WHERE ID=1");
conn.setAutoCommit(false);
stat.execute("insert into test values(2, 'Hello Moon!')");
conn.rollback();
conn.close();
conn = getConnection("fullTextTransaction");
stat = conn.createStatement();
ResultSet rs = stat.executeQuery("SELECT * FROM " + prefix + "_SEARCH('Hello', 0, 0)");
assertTrue(rs.next());
rs = stat.executeQuery("SELECT * FROM " + prefix + "_SEARCH('Moon', 0, 0)");
assertFalse(rs.next());
FullText.dropAll(conn);
conn.close();
deleteDb("fullTextTransaction");
}
private void testMultiThreaded() throws Exception { private void testMultiThreaded() throws Exception {
deleteDb("fullText"); deleteDb("fullText");
final boolean[] stop = new boolean[1]; final boolean[] stop = new boolean[1];
...@@ -125,6 +159,10 @@ public class TestFullText extends TestBase { ...@@ -125,6 +159,10 @@ public class TestFullText extends TestBase {
stat.execute("CREATE ALIAS IF NOT EXISTS FT_INIT FOR \"org.h2.fulltext.FullText.init\""); stat.execute("CREATE ALIAS IF NOT EXISTS FT_INIT FOR \"org.h2.fulltext.FullText.init\"");
stat.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, DATA CLOB)"); stat.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, DATA CLOB)");
FullText.createIndex(conn, "PUBLIC", "TEST", null); FullText.createIndex(conn, "PUBLIC", "TEST", null);
conn.setAutoCommit(false);
stat.execute("insert into test values(1, 'Hello Moon!')");
conn.rollback();
conn.setAutoCommit(true);
stat.execute("insert into test values(0, 'Hello World!')"); stat.execute("insert into test values(0, 'Hello World!')");
PreparedStatement prep = conn.prepareStatement("insert into test values(1, ?)"); PreparedStatement prep = conn.prepareStatement("insert into test values(1, ?)");
final int length = 1024 * 1024; final int length = 1024 * 1024;
...@@ -145,6 +183,8 @@ public class TestFullText extends TestBase { ...@@ -145,6 +183,8 @@ public class TestFullText extends TestBase {
prep.execute(); prep.execute();
ResultSet rs = stat.executeQuery("SELECT * FROM FT_SEARCH('World', 0, 0)"); ResultSet rs = stat.executeQuery("SELECT * FROM FT_SEARCH('World', 0, 0)");
assertTrue(rs.next()); assertTrue(rs.next());
rs = stat.executeQuery("SELECT * FROM FT_SEARCH('Moon', 0, 0)");
assertFalse(rs.next());
FullText.dropAll(conn); FullText.dropAll(conn);
conn.close(); conn.close();
deleteDb("fullText"); deleteDb("fullText");
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论