/*
 * PostgresForest Sequence Implementation
 *
 * Copyright(C) NTT DATA Corp., Ltd. 2006
 */
import java.sql.*;

/*
 * NOTE:
 * Before you use this sequence class, you need to create a sequence table
 * in your PostgresForest user database, and insert a sequence entry.
 *
 * Sequence table structure
 * ------------------------
 *
 * CREATE TABLE seq (
 *     seqname varchar(16) primary key,
 *     seqval integer not null default 0
 * );
 * 
 * Initialize your sequence
 * ------------------------
 *
 * INSERT INTO seq VALUES ( 'myseq', 0 );
 */
public class Sequence {
    private Connection con = null;
    private String relname = null;
    
    public Sequence(Connection con, String relname)
    {
		this.con = con;
		this.relname = relname;
    }
    
    private void checkAutocommit() throws Exception
    {
		if ( con.getAutoCommit()==true )
		{
			throw new Exception("Sequence must be used under autocommit=false.");
		}
    }
    
	/**
	 * nextval() increments a value of the sequence and return it.
	 *
	 * @param String seqname Sequence name
	 *
	 * @return int a sequence value
	 */
    public int nextval(String seqname) throws Exception
    {
		checkAutocommit();
		int seqval = 0;
		SQLException ex = null;
	
		Statement stmt = con.createStatement();
		
		ResultSet rs = null;

		try {
			rs = stmt.executeQuery("SELECT seqval FROM " + relname + " WHERE seqname='" + seqname + "' FOR UPDATE NOWAIT");
		
			if ( rs!=null && rs.next() )
			{
				seqval = rs.getInt(1);
			}

			rs.close();
			rs = null;
			
			int rc = stmt.executeUpdate("UPDATE " + relname + " SET seqval = seqval+1 WHERE seqname='" + seqname + "'");
		
			seqval = seqval + 1;
		
			stmt.close();
			stmt = null;
		}
		catch (SQLException e)
		{
			System.out.println("MESSAGE: " + e.getMessage());
			System.out.println("SQLState: " + e.getSQLState());
			ex = e;
		}		

		try {
			if ( rs!=null )
				rs.close();
			if ( stmt!=null )
				stmt.close();
		}
		catch (SQLException e)
		{
			throw e;
		}

		if ( ex!=null )
			throw ex;

		return seqval;
    }
    
	/**
	 * currval() returns a current value of the sequence.
	 *
	 * @param String seqname Sequence name
	 *
	 * @return int a sequence value
	 */
    public int currval(String seqname) throws Exception
    {
		checkAutocommit();
		int seqval = 0;
		
		Statement stmt = con.createStatement();
		
		ResultSet rs = stmt.executeQuery("SELECT seqval FROM " + relname + " WHERE seqname='" + seqname + "'");
		
		if ( rs!=null && rs.next() )
		{
			seqval = rs.getInt(1);
		}

		rs.close();
		stmt.close();
		
		return seqval;
    }

	/**
	 * setval() sets a new value for the sequence.
	 *
	 * @param String seqname Sequence name
	 * @param int seqval a new value of the sequence
	 *
	 * @return int a new value of the sequence
	 */
    public int setval(String seqname, int seqval) throws Exception
    {
		checkAutocommit();

		Statement stmt = con.createStatement();
		
		ResultSet rs = stmt.executeQuery("SELECT seqval FROM " + relname + " WHERE seqname='" + seqname + "' FOR UPDATE NOWAIT");
		
		rs.close();
		
		int rc = stmt.executeUpdate("UPDATE " + relname + " SET seqval = " + seqval + " WHERE seqname='" + seqname + "'");
	
		stmt.close();
		
		return seqval;
    }
}
