提交 c9e8941a authored 作者: Thomas Mueller's avatar Thomas Mueller

TriggerAdapter: in "before" triggers, values can be changed using the ResultSet.updateX methods.

上级 c34aff38
......@@ -18,7 +18,14 @@ Change Log
<h1>Change Log</h1>
<h2>Next Version (unreleased)</h2>
<ul><li>The script created by SCRIPT DROP did not always work if multiple views
<ul><li>TriggerAdapter: in "before" triggers, values can be changed using the ResultSet.updateX methods.
</li><li>Creating a table with column data type NULL now works (even if not very useful).
</li><li>ALTER TABLE ALTER COLUMN no longer copies the data for widening conversions
(for example if only the precision was increased) unless necessary.
</li><li>Multi-threaded kernel: concurrently running an online backup
and updating the database resulted in a broken (transactionally incorrect)
backup file in some cases.
</li><li>The script created by SCRIPT DROP did not always work if multiple views
existed that depend on each other.
</li><li>MathUtils.getSecureRandom could log a warning to System.err in case
the /dev/random is very slow, and the System.getProperties().toString()
......
......@@ -17,6 +17,33 @@ import org.h2.api.Trigger;
*/
public abstract class TriggerAdapter implements Trigger {
/**
* The schema name.
*/
protected String schemaName;
/**
* The name of the trigger.
*/
protected String triggerName;
/**
* The name of the table.
*/
protected String tableName;
/**
* Whether the fire method is called before or after the operation is
* performed.
*/
protected boolean before;
/**
* The trigger type: INSERT, UPDATE, DELETE, SELECT, or a combination (a bit
* field).
*/
protected int type;
private SimpleResultSet oldResultSet, newResultSet;
private TriggerRowSource oldSource, newSource;
......@@ -33,7 +60,8 @@ public abstract class TriggerAdapter implements Trigger {
* @param tableName the name of the table
* @param before whether the fire method is called before or after the
* operation is performed
* @param type the operation type: INSERT, UPDATE, or DELETE
* @param type the operation type: INSERT, UPDATE, DELETE, SELECT, or a
* combination (this parameter is a bit field)
*/
public void init(Connection conn, String schemaName,
String triggerName, String tableName,
......@@ -52,6 +80,11 @@ public abstract class TriggerAdapter implements Trigger {
oldResultSet.addColumn(column, dataType, precision, scale);
newResultSet.addColumn(column, dataType, precision, scale);
}
this.schemaName = schemaName;
this.triggerName = triggerName;
this.tableName = tableName;
this.before = before;
this.type = type;
}
/**
......@@ -112,6 +145,10 @@ public abstract class TriggerAdapter implements Trigger {
* fire(Connection conn, Object[] oldRow, Object[] newRow) method.
* ResultSet.next does not need to be called (and calling it has no effect;
* it will always return true).
* <p>
* For "before" triggers, the new values of the new row may be changed
* using the ResultSet.updateX methods.
* </p>
*
* @param conn a connection to the database
* @param oldRow the old row, or null if no old row is available (for
......
......@@ -121,19 +121,25 @@ public class TestTriggersConstraints extends TestBase implements Trigger {
stat.execute("drop table if exists test");
stat.execute("create table test(id int)");
stat.execute("create table message(name varchar)");
stat.execute("create trigger test_insert after insert, update, delete on test " +
stat.execute("create trigger test_insert before insert, update, delete on test " +
"for each row call \"" + TestTriggerAdapter.class.getName() + "\"");
stat.execute("insert into test values(1)");
ResultSet rs;
rs = stat.executeQuery("select * from test");
rs.next();
assertEquals(10, rs.getInt(1));
stat.execute("update test set id = 2");
rs = stat.executeQuery("select * from test");
rs.next();
assertEquals(20, rs.getInt(1));
stat.execute("delete from test");
ResultSet rs;
rs = stat.executeQuery("select * from message");
assertTrue(rs.next());
assertEquals("+1;", rs.getString(1));
assertTrue(rs.next());
assertEquals("-1;+2;", rs.getString(1));
assertEquals("-10;+2;", rs.getString(1));
assertTrue(rs.next());
assertEquals("-2;", rs.getString(1));
assertEquals("-20;", rs.getString(1));
assertFalse(rs.next());
stat.execute("drop table test, message");
conn.close();
......@@ -182,6 +188,30 @@ public class TestTriggersConstraints extends TestBase implements Trigger {
if (newRow != null) {
buff.append("+").append(newRow.getString("id")).append(';');
}
if (!"TEST_INSERT".equals(triggerName)) {
throw new RuntimeException("Wrong trigger name: " + triggerName);
}
if (!"TEST".equals(tableName)) {
throw new RuntimeException("Wrong table name: " + tableName);
}
if (!"PUBLIC".equals(schemaName)) {
throw new RuntimeException("Wrong schema name: " + schemaName);
}
if (type != (Trigger.INSERT | Trigger.UPDATE | Trigger.DELETE)) {
throw new RuntimeException("Wrong type: " + type);
}
if (newRow != null) {
if (oldRow == null) {
if (newRow.getInt(1) != 1) {
throw new RuntimeException("Expected: 1 got: " + newRow.getString(1));
}
} else {
if (newRow.getInt(1) != 2) {
throw new RuntimeException("Expected: 2 got: " + newRow.getString(1));
}
}
newRow.updateInt(1, newRow.getInt(1) * 10);
}
conn.createStatement().execute("insert into message values('" + buff.toString() + "')");
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论