org.h2.tools.TriggerAdapter Maven / Gradle / Ivy
/*
* Copyright 2004-2019 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (https://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.tools;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.h2.api.Trigger;
/**
* An adapter for the trigger interface that allows to use the ResultSet
* interface instead of a row array.
*/
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;
/**
* This method is called by the database engine once when initializing the
* trigger. It is called when the trigger is created, as well as when the
* database is opened. The default implementation initialized the result
* sets.
*
* @param conn a connection to the database
* @param schemaName the name of the schema
* @param triggerName the name of the trigger used in the CREATE TRIGGER
* statement
* @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, DELETE, SELECT, or a
* combination (this parameter is a bit field)
*/
@Override
public void init(Connection conn, String schemaName,
String triggerName, String tableName,
boolean before, int type) throws SQLException {
ResultSet rs = conn.getMetaData().getColumns(
null, schemaName, tableName, null);
oldSource = new TriggerRowSource();
newSource = new TriggerRowSource();
oldResultSet = new SimpleResultSet(oldSource);
newResultSet = new SimpleResultSet(newSource);
while (rs.next()) {
String column = rs.getString("COLUMN_NAME");
int dataType = rs.getInt("DATA_TYPE");
int precision = rs.getInt("COLUMN_SIZE");
int scale = rs.getInt("DECIMAL_DIGITS");
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;
}
/**
* A row source that allows to set the next row.
*/
static class TriggerRowSource implements SimpleRowSource {
private Object[] row;
void setRow(Object[] row) {
this.row = row;
}
@Override
public Object[] readRow() {
return row;
}
@Override
public void close() {
// ignore
}
@Override
public void reset() {
// ignore
}
}
/**
* This method is called for each triggered action. The method is called
* immediately when the operation occurred (before it is committed). A
* transaction rollback will also rollback the operations that were done
* within the trigger, if the operations occurred within the same database.
* If the trigger changes state outside the database, a rollback trigger
* should be used.
*
* The row arrays contain all columns of the table, in the same order
* as defined in the table.
*
*
* The default implementation calls the fire method with the ResultSet
* parameters.
*
*
* @param conn a connection to the database
* @param oldRow the old row, or null if no old row is available (for
* INSERT)
* @param newRow the new row, or null if no new row is available (for
* DELETE)
* @throws SQLException if the operation must be undone
*/
@Override
public void fire(Connection conn, Object[] oldRow, Object[] newRow)
throws SQLException {
fire(conn, wrap(oldResultSet, oldSource, oldRow),
wrap(newResultSet, newSource, newRow));
}
/**
* This method is called for each triggered action by the default
* 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).
*
* For "before" triggers, the new values of the new row may be changed
* using the ResultSet.updateX methods.
*
*
* @param conn a connection to the database
* @param oldRow the old row, or null if no old row is available (for
* INSERT)
* @param newRow the new row, or null if no new row is available (for
* DELETE)
* @throws SQLException if the operation must be undone
*/
public abstract void fire(Connection conn, ResultSet oldRow,
ResultSet newRow) throws SQLException;
private static SimpleResultSet wrap(SimpleResultSet rs,
TriggerRowSource source, Object[] row) throws SQLException {
if (row == null) {
return null;
}
source.setRow(row);
rs.next();
return rs;
}
/**
* This method is called when the database is closed.
* If the method throws an exception, it will be logged, but
* closing the database will continue.
* The default implementation does nothing.
*/
@Override
public void remove() throws SQLException {
// do nothing by default
}
/**
* This method is called when the trigger is dropped.
* The default implementation does nothing.
*/
@Override
public void close() throws SQLException {
// do nothing by default
}
}