/*
* Copyright (c) 2004, 2005, 2006 TADA AB - Taby Sweden
* Distributed under the terms shown in the file COPYRIGHT
* found in the root folder of this project or at
* http://eng.tada.se/osprojects/COPYRIGHT.html
*/
package org.postgresql.pljava.internal;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.postgresql.pljava.jdbc.TriggerResultSet;
/**
* The <code>TriggerData</code> correspons to the internal PostgreSQL <code>TriggerData</code>.
*
* @author Thomas Hallgren
*/
public class TriggerData extends JavaWrapper implements org.postgresql.pljava.TriggerData
{
private Relation m_relation;
private TriggerResultSet m_old = null;
private TriggerResultSet m_new = null;
private Tuple m_newTuple;
private Tuple m_triggerTuple;
TriggerData(long pointer)
{
super(pointer);
}
/**
* Returns the ResultSet that represents the new row. This ResultSet will
* be null for delete triggers and for triggers that was fired for
* statement. <br>
* The returned set will be updateable and positioned on a
* valid row.
*
* @return An updateable <code>ResultSet</code> containing one row or
* <code>null</code>.
* @throws SQLException
* if the contained native buffer has gone stale.
*/
public ResultSet getNew() throws SQLException
{
if (m_new != null)
return m_new;
if (this.isFiredByDelete() || this.isFiredForStatement())
return null;
// PostgreSQL uses the trigger tuple as the new tuple for inserts.
//
Tuple tuple =
this.isFiredByInsert()
? this.getTriggerTuple()
: this.getNewTuple();
// Triggers fired after will always have a read-only row
//
m_new = new TriggerResultSet(this.getRelation().getTupleDesc(), tuple, this.isFiredAfter());
return m_new;
}
/**
* Returns the ResultSet that represents the old row. This ResultSet will
* be null for insert triggers and for triggers that was fired for
* statement. <br>
* The returned set will be read-only and positioned on a
* valid row.
*
* @return A read-only <code>ResultSet</code> containing one row or
* <code>null</code>.
* @throws SQLException
* if the contained native buffer has gone stale.
*/
public ResultSet getOld() throws SQLException
{
if (m_old != null)
return m_old;
if (this.isFiredByInsert() || this.isFiredForStatement())
return null;
m_old = new TriggerResultSet(this.getRelation().getTupleDesc(), this.getTriggerTuple(), true);
return m_old;
}
/**
* Commits the changes made on the <code>ResultSet</code> representing
* <code>new</code> and returns the native pointer of new tuple. This
* method is called automatically by the trigger handler and should not
* be called in any other way.
*
* @return The modified tuple, or if no modifications have been made, the
* original tuple.
*/
public long getTriggerReturnTuple() throws SQLException
{
if(this.isFiredForStatement() || this.isFiredAfter())
//
// Only triggers fired before each row can have a return
// value.
//
return 0;
if (m_new != null)
{
Object[] changes = m_new.getChangeIndexesAndValues();
if (changes != null)
{
Tuple original = (Tuple)changes[0];
int[] indexes = (int[])changes[1];
Object[] values = (Object[])changes[2];
return this.getRelation().modifyTuple(original, indexes, values).getNativePointer();
}
}
// Return the original tuple.
//
return (this.isFiredByUpdate() ? this.getNewTuple() : this.getTriggerTuple()).getNativePointer();
}
public String getTableName()
throws SQLException
{
return this.getRelation().getName();
}
public String getSchemaName() throws SQLException {
return this.getRelation().getSchema();
}
/**
* Returns a descriptor for the Tuples exposed by this trigger.
*
* @throws SQLException
* if the contained native buffer has gone stale.
*/
public Relation getRelation()
throws SQLException
{
if(m_relation == null)
{
synchronized(Backend.THREADLOCK)
{
m_relation = _getRelation(this.getNativePointer());
}
}
return m_relation;
}
/**
* Returns a <code>Tuple</code> reflecting the row for which the trigger
* was fired. This is the row being inserted, updated, or deleted. If this
* trigger was fired for an <code>
* INSERT</code> or <code>DELETE</code>
* then this is what you should return to from the method if you don't want
* to replace the row with a different one (in the case of <code>INSERT
* </code>)
* or skip the operation.
*
* @throws SQLException
* if the contained native buffer has gone stale.
*/
public Tuple getTriggerTuple()
throws SQLException
{
if(m_triggerTuple == null)
{
synchronized(Backend.THREADLOCK)
{
m_triggerTuple = _getTriggerTuple(this.getNativePointer());
}
}
return m_triggerTuple;
}
/**
* Returns a <code>Tuple</code> reflecting the new version of the row, if
* the trigger was fired for an <code>UPDATE</code>, and <code>null</code>
* if it is for an <code>INSERT</code> or a <code>DELETE</code>. This
* is what you have to return from the function if the event is an <code>UPDATE</code>
* and you don't want to replace this row by a different one or skip the
* operation.
*
* @throws SQLException
* if the contained native buffer has gone stale.
*/
public Tuple getNewTuple()
throws SQLException
{
if(m_newTuple == null)
{
synchronized(Backend.THREADLOCK)
{
m_newTuple = _getNewTuple(this.getNativePointer());
}
}
return m_newTuple;
}
/**
* Returns the arguments for this trigger (as declared in the <code>CREATE TRIGGER</code>
* statement. If the trigger has no arguments, this method will return an
* array with size 0.
*
* @throws SQLException
* if the contained native buffer has gone stale.
*/
public String[] getArguments()
throws SQLException
{
synchronized(Backend.THREADLOCK)
{
return _getArguments(this.getNativePointer());
}
}
/**
* Returns the name of the trigger (as declared in the <code>CREATE TRIGGER</code>
* statement).
*
* @throws SQLException
* if the contained native buffer has gone stale.
*/
public String getName()
throws SQLException
{
synchronized(Backend.THREADLOCK)
{
return _getName(this.getNativePointer());
}
}
/**
* Returns <code>true</code> if the trigger was fired after the statement
* or row action that it is associated with.
*
* @throws SQLException
* if the contained native buffer has gone stale.
*/
public boolean isFiredAfter()
throws SQLException
{
synchronized(Backend.THREADLOCK)
{
return _isFiredAfter(this.getNativePointer());
}
}
/**
* Returns <code>true</code> if the trigger was fired before the
* statement or row action that it is associated with.
*
* @throws SQLException
* if the contained native buffer has gone stale.
*/
public boolean isFiredBefore()
throws SQLException
{
synchronized(Backend.THREADLOCK)
{
return _isFiredBefore(this.getNativePointer());
}
}
/**
* Returns <code>true</code> if this trigger is fired once for each row
* (as opposed to once for the entire statement).
*
* @throws SQLException
* if the contained native buffer has gone stale.
*/
public boolean isFiredForEachRow()
throws SQLException
{
synchronized(Backend.THREADLOCK)
{
return _isFiredForEachRow(this.getNativePointer());
}
}
/**
* Returns <code>true</code> if this trigger is fired once for the entire
* statement (as opposed to once for each row).
*
* @throws SQLException
* if the contained native buffer has gone stale.
*/
public boolean isFiredForStatement()
throws SQLException
{
synchronized(Backend.THREADLOCK)
{
return _isFiredForStatement(this.getNativePointer());
}
}
/**
* Returns <code>true</code> if this trigger was fired by a <code>DELETE</code>.
*
* @throws SQLException
* if the contained native buffer has gone stale.
*/
public boolean isFiredByDelete()
throws SQLException
{
synchronized(Backend.THREADLOCK)
{
return _isFiredByDelete(this.getNativePointer());
}
}
/**
* Returns <code>true</code> if this trigger was fired by an <code>INSERT</code>.
*
* @throws SQLException
* if the contained native buffer has gone stale.
*/
public boolean isFiredByInsert()
throws SQLException
{
synchronized(Backend.THREADLOCK)
{
return _isFiredByInsert(this.getNativePointer());
}
}
/**
* Returns <code>true</code> if this trigger was fired by an <code>UPDATE</code>.
*
* @throws SQLException
* if the contained native buffer has gone stale.
*/
public boolean isFiredByUpdate()
throws SQLException
{
synchronized(Backend.THREADLOCK)
{
return _isFiredByUpdate(this.getNativePointer());
}
}
protected native void _free(long pointer);
private static native Relation _getRelation(long pointer) throws SQLException;
private static native Tuple _getTriggerTuple(long pointer) throws SQLException;
private static native Tuple _getNewTuple(long pointer) throws SQLException;
private static native String[] _getArguments(long pointer) throws SQLException;
private static native String _getName(long pointer) throws SQLException;
private static native boolean _isFiredAfter(long pointer) throws SQLException;
private static native boolean _isFiredBefore(long pointer) throws SQLException;
private static native boolean _isFiredForEachRow(long pointer) throws SQLException;
private static native boolean _isFiredForStatement(long pointer) throws SQLException;
private static native boolean _isFiredByDelete(long pointer) throws SQLException;
private static native boolean _isFiredByInsert(long pointer) throws SQLException;
private static native boolean _isFiredByUpdate(long pointer) throws SQLException;
}