/*
 * $Source: /usr/local/cvsroot/erserver/erserver/java/src/com/postgres/replic/util/DBProcessor.java,v $
 * $Author: asullivan $ $Revision: 1.1.1.1 $ $Date: 2003/08/26 19:02:27 $
 *
 */

package com.postgres.replic.util;

import java.sql.*;
import com.postgres.util.jdbc.*;
import com.postgres.replic.util.struct.*;
import com.postgres.replic.server.props.*;


public class DBProcessor extends AbstractInitializable {
    private Connection conn;
    private ConnectionPool cPool;
    private boolean isConnectionSame = false;
    private int pstmtUseCount = 0;
    private boolean resetPstmtCache = false;

    protected TableColumnCache  tableColumnCache;
    protected ServerProps serverProps;

    private String errorPrefix;
    private static final int SUCCESS = 1;
    private static final String [] sqls = {
        "set transaction isolation level serializable",  // 0
        "set enable_seqscan to off",                     // 1
        "set enable_indexscan to on",                    // 2
    } ;

    protected int getPstmtUseCount() {
         return pstmtUseCount;
    }

    public void init(Connection conn, ServerProps serverProps)
    throws RservException, Exception {
        this.serverProps = serverProps;

        // This postion is reused only
        pstmtUseCount++;
        if (this.conn != null && conn != null && conn.equals(this.conn)) {
             isConnectionSame = true;
        } else {
             isConnectionSame = false;
        }

        if (pstmtUseCount >= serverProps.getPstmtReuseCount() || !isConnectionSame) {
             resetPstmtCache = true;
             pstmtUseCount = 0; // <== reset pstmtUseCount!
        } else {
             resetPstmtCache = false;
        }
        getLogger().debug("*** DBProcessor::init: pstmtUseCount="+pstmtUseCount +"; isConnectionSame="+isConnectionSame+"; resetPstmtCache="+resetPstmtCache);

        this.conn = conn;
        validate();

        //setInitialized(true);
    }


    protected void setTableColumnCache() throws Exception {
        if (tableColumnCache == null) {
            tableColumnCache = new TableColumnCache(conn, getTableMap(), serverProps);
        }
    }

    protected void resetPstmtCache() throws Exception {
        // If this is not the same connection  - update Pstm cache:
        if (resetPstmtCache) {
             tableColumnCache.resetPstmtCache();
        }
    }

    protected TableMap getTableMap() throws RservException {
         return null;
    }

    protected TableColumnCache getTableColumnCache() {
        return tableColumnCache;
    }


    public void init(ConnectionPool cPool) throws RservException {
        this.cPool = cPool;
        validate();
        //setInitialized(true);
    }

    protected boolean isConnectionSame() {
        return isConnectionSame;
    }

    protected void validate() throws RservException {
        if (conn == null && cPool == null) {
            throw new RservException(errorPrefix + "Either connection or connection pool must be set");
        }
    }

    protected void validateInit() throws RservException {
        if (!initialized()) {
            throw new RservException(errorPrefix + " object is not initialized");
        }
    }

    protected void setErrorPrefix(String errorPrefix) {
        this.errorPrefix = errorPrefix;
    }

    protected String getErrorPrefix() {
        return  errorPrefix == null ? "" : errorPrefix;
    }

    protected Connection getConnection() throws RservException {
        setErrorPrefix("getConnection: ");
        validate() ;
        if (cPool != null && conn == null) {
            conn = cPool.getConnection();
        }
        return conn;
    }

    public void closeConnection() throws RservException {
        setErrorPrefix("closeConnection: ");
        validate() ;
        if (cPool != null && conn != null) {
            cPool.close(conn);
        }
    }

    protected void generalClose(Statement stmt, ResultSet rs) {
        try {
            if (stmt != null) { stmt.close(); }
        } catch (Exception e) { }

        try {
            if (rs != null) { rs.close(); }
        } catch (Exception e) { }
    }

    protected void generalClose(PreparedStatement stmt, ResultSet rs) {
        try {
            if (stmt != null) { stmt.close(); }
        } catch (Exception e) { }

        try {
            if (rs != null) { rs.close(); }
        } catch (Exception e) { }
    }

    public void commit() throws Exception {
        getConnection().commit();
        /*
        Statement stmt = null;
        String sql = "COMMIT";

        try {
            stmt = getConnection().createStatement();
            stmt.executeUpdate(sql);
            getLogger().debug("{TRANSACTION COMMIT}");
        } catch (Exception e) {
            throw new Exception("DBProcessor::commit: " + e.toString());
        } finally {
            generalClose(stmt, null);
        }
        */
    }

    public void rollback() throws Exception {
         getConnection().rollback();
         /*
         Statement stmt = null;
         String sql = "ROLLBACK";

        try {
            stmt = getConnection().createStatement();
            stmt.executeUpdate(sql);
            getLogger().debug("{TRANSACTION ROLLBACK}");
        } catch (Exception e) {
            throw new Exception("DBProcessor::rollback: " + e.toString());
        } finally {
            generalClose(stmt, null);
        }
        */
    }

    public void setDebug(boolean debug) {
        super.setDebug(debug);
        if (getTableColumnCache() != null) {
             getTableColumnCache().setDebug(debug);
        }
    }

    public void setVerbose(boolean verbose) {
        super.setDebug(verbose);
        if (getTableColumnCache() != null) {
             getTableColumnCache().setDebug(verbose);
        }
    }

    public void begin() throws Exception {
       /* Statement stmt = null;
        String sql = "BEGIN";

        try {
            stmt = getConnection().createStatement();
            stmt.executeUpdate(sql);
            getLogger().debug("{TRANSACTION BEGIN}");
        } catch (Exception e) {
            throw new Exception("DBProcessor::begin: " + e.toString());
        } finally {
            generalClose(stmt, null);
        }  */
    }

    public void setTransactionSerializable() throws Exception {
        Statement stmt = null;

        try {
            stmt = getConnection().createStatement();
            stmt.executeUpdate(sqls[0]);
            getLogger().debug("DBProcessor::setTransactionSerializable: sql="+sqls[0]);
        } catch (Exception e) {
            throw new Exception("DBProcessor::setTransactionSerializable: " + e.toString());
        } finally {
            generalClose(stmt, null);
        }
    }

    public void setOptimizerHints() throws Exception {
        Statement stmt = null;

        try {
            stmt = getConnection().createStatement();
            stmt.executeUpdate(sqls[1]);
            getLogger().debug("DBProcessor::setOptimizerHints: sql="+sqls[1]);
            stmt.executeUpdate(sqls[2]);
            getLogger().debug("DBProcessor::setOptimizerHints: sql="+sqls[2]);
        } catch (Exception e) {
            throw new Exception("DBProcessor::setDatabaseHints: " + e.toString());
        } finally {
            generalClose(stmt, null);
        }
    }
}
