/*
 * blancoDbTutorial: blancoDbチュートリアル・サンプル
 * 
 * Copyright (C) 2005 tosiki.iga@nifty.ne.jp
 */

package postgresql;

import igapyon.exception.IntegrityConstraintException;
import igapyon.exception.NoRowModifiedException;
import igapyon.query.SimpleTestBlancoDbTable1DeleteInvoker;
import igapyon.query.SimpleTestBlancoDbTable1InsertInvoker;
import igapyon.query.SimpleTestBlancoDbTable1InsertNoNullsInvoker;
import igapyon.query.SimpleTestBlancoDbTable1SelectIterator;
import igapyon.query.SimpleTestBlancoDbTable1SelectUpdatableIterator;
import igapyon.query.SimpleTestBlancoDbTable1UpdateInvoker;
import igapyon.query.TestBlancoDbTable1SelectAllIterator;
import igapyon.row.SimpleTestBlancoDbTable1SelectRow;
import igapyon.row.SimpleTestBlancoDbTable1SelectUpdatableRow;
import igapyon.row.TestBlancoDbTable1SelectAllRow;

import java.io.IOException;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Date;

import junit.framework.TestCase;

/**
 * 注意: このクラスをコンパイルするためには、それまでの手順で自動生成したblancoDbソースコードが必要になります。
 */
public class BlancoDbTest01PostgreSQL extends TestCase {
    /**
     * JDBCドライバ名を指定します。
     */
    public static final String JDBC_DRIVER = "org.postgresql.Driver";

    /**
     * JDBC接続時の文字列を指定します。
     */
    public static final String JDBC_URL = "jdbc:postgresql://localhost:5432/template1";

    /**
     * JDBC接続時のユーザ名を指定します。
     */
    public static final String JDBC_USERNAME = "postgres";

    /**
     * JDBC接続時のパスワードを指定します。
     */
    public static final String JDBC_PASSWORD = "password";

    public void testProcess01() throws Exception {
        Class.forName(JDBC_DRIVER);
        Connection conn = null;
        try {
            conn = DriverManager.getConnection(JDBC_URL, JDBC_USERNAME,
                    JDBC_PASSWORD);
            conn.setAutoCommit(false);

            // まず空の状態にします。
            processDeleteAll(conn);

            processInsert(conn);
            processInsertWithNull(conn);
            processInsertNotNull(conn);

            // ここで一意制約違反の試験
            processInsertPrimaryKeyException(conn);

            // ここでupdateの試験
            processUpdate(conn);

            // ここでdeleteの試験
            processDelete(conn);

            // ここで検索更新の試験も実施すべき。
            processSelectUpdatable(conn);

            processCheckScrollCursor(conn);

            conn.commit();
            System.out.println("全ての処理終了しました.");
        } finally {
            conn.rollback();
            conn.close();
            conn = null;
        }
    }

    public void processDeleteAll(Connection conn) throws SQLException {
        System.out.println("不要なレコードを一括削除します。");
        TestBlancoDbTable1SelectAllIterator iterator = new TestBlancoDbTable1SelectAllIterator(
                conn);
        SimpleTestBlancoDbTable1DeleteInvoker invoker = new SimpleTestBlancoDbTable1DeleteInvoker(
                conn);
        try {
            for (; iterator.next();) {
                TestBlancoDbTable1SelectAllRow row = iterator.getRow();
                invoker.prepareStatement();
                invoker.setInputParameter(row.getColIntNotNull());
                System.out.println("行[" + row.getColIntNotNull() + "]を削除");
                invoker.executeSingleUpdate();
            }
        } finally {
            invoker.close();
            iterator.close();
        }
    }

    public void processInsert(Connection conn) throws SQLException, IOException {
        System.out.println("行の挿入を試みます");
        SimpleTestBlancoDbTable1InsertInvoker invoker = new SimpleTestBlancoDbTable1InsertInvoker(
                conn);
        SimpleTestBlancoDbTable1SelectIterator iterator = new SimpleTestBlancoDbTable1SelectIterator(
                conn);
        try {
            for (int index = 0; index < 10; index++) {
                invoker.setInputParameter(index, new Integer(index + 1),
                        (short) 3, new Short((short) 4), (long) 5, new Long(6),
                        (float) 7.1, new Float(8.2), 9.3, new Double(10.4),
                        new BigDecimal("11"), new BigDecimal("12"),
                        new BigDecimal("13"), new BigDecimal("14"),
                        new BigDecimal("15.2"), new BigDecimal("16.4"), "1",
                        "2", "34", "56", "7890", "1234", "5678", "9012",
                        "3456", "7890", "1234", "5678", "12345678", "12345678",
                        new Date(), new Date());
                invoker.executeSingleUpdate();

            }

            // 挿入の成功をチェックします。
            iterator.setInputParameter(5);
            iterator.next();
            SimpleTestBlancoDbTable1SelectRow row = iterator.getRow();
            assertTrue(row.getColDecimal153Null().compareTo(
                    new BigDecimal("16.4")) == 0);
        } finally {
            iterator.close();
            invoker.close();
        }

    }

    public void processInsertWithNull(Connection conn) throws SQLException {
        System.out.println("行の挿入(NULL許容にはNULLを設定)を試みます");
        SimpleTestBlancoDbTable1InsertInvoker invoker = new SimpleTestBlancoDbTable1InsertInvoker(
                conn);
        SimpleTestBlancoDbTable1SelectIterator iterator = new SimpleTestBlancoDbTable1SelectIterator(
                conn);
        try {
            for (int index = 50; index < 60; index++) {
                invoker.setInputParameter(index, new Integer(index + 1),
                        (short) 3, null, (long) 5, null, (float) 7.1, null,
                        9.3, null, new BigDecimal("11.5"), new BigDecimal(
                                "12.6"), new BigDecimal("13.7"),
                        new BigDecimal("14.8"), new BigDecimal("15.9"), null,
                        "1", null, "34", null, "7890", null, "5678", null,
                        "3456", null, "1234", null, "12345678", null,
                        new Date(), null);
                invoker.executeSingleUpdate();
            }

            // 挿入の成功をチェックします。
            iterator.setInputParameter(55);
            SimpleTestBlancoDbTable1SelectRow row = iterator.getSingleRow();
            assertTrue(row.getColDecimal153NotNull().compareTo(
                    new BigDecimal("15.9")) == 0);
            // NULL項目にはNULLが入っていることを確認。
            assertTrue(row.getColDecimal153Null() == null);
        } finally {
            iterator.close();
            invoker.close();
        }
    }

    public void processInsertNotNull(Connection conn) throws SQLException {
        System.out.println("行の挿入(非NULL項目のみ)を試みます");
        SimpleTestBlancoDbTable1InsertNoNullsInvoker invoker = new SimpleTestBlancoDbTable1InsertNoNullsInvoker(
                conn);
        SimpleTestBlancoDbTable1SelectIterator iterator = new SimpleTestBlancoDbTable1SelectIterator(
                conn);
        try {
            for (int index = 100; index < 110; index++) {
                invoker.setInputParameter(index, (short) 3, (long) 5,
                        (float) 7.1, (double) 9.3, new BigDecimal("11.5"),
                        new BigDecimal("12.6"), new BigDecimal("13.7"), "1",
                        "2", "34", "56", "7890", "12345678", new Date());
                invoker.executeSingleUpdate();
            }

            // 挿入の成功をチェックします。
            iterator.setInputParameter(103);
            SimpleTestBlancoDbTable1SelectRow row = iterator.getSingleRow();
            assertTrue(row.getColDecimal153NotNull().compareTo(
                    new BigDecimal("13.7")) == 0);
            // NULL項目にはNULLが入っていることを確認。
            assertTrue(row.getColDecimal153Null() == null);
        } finally {
            iterator.close();
            invoker.close();
        }
    }

    public void processInsertPrimaryKeyException(Connection conn)
            throws SQLException {
        System.out.println("行の挿入によって一意制約違反が発生することを確認します。");
        SimpleTestBlancoDbTable1InsertNoNullsInvoker invoker = new SimpleTestBlancoDbTable1InsertNoNullsInvoker(
                conn);
        try {
            // PostgreSQLは 例外発生前に こまめなコミットの必要があります。
            conn.commit();
            invoker.setInputParameter(5, (short) 3, (long) 5, (float) 7.1,
                    (double) 9.3, new BigDecimal("11.5"),
                    new BigDecimal("12.6"), new BigDecimal("13.7"), "1", "2",
                    "34", "56", "7890", "12345678", new Date());
            invoker.executeSingleUpdate();
            fail("一意制約違反が発生しませんでした。");
        } catch (IntegrityConstraintException ex) {
            // ここに入るのが成功。
            System.out.println("適切に一意制約違反が発生しました: " + ex.toString());
            // 例外発生時は 直前のコミットポイントまで戻る必要があるのだそうです。
            conn.rollback();
        } catch (SQLException ex) {
            fail("予期せぬ例外が発生しました。:" + ex.toString());
            ex.printStackTrace();
        } finally {
            invoker.close();
        }
    }

    public void processUpdate(Connection conn) throws SQLException {
        System.out.println("行の更新を試みます");
        SimpleTestBlancoDbTable1UpdateInvoker invoker = new SimpleTestBlancoDbTable1UpdateInvoker(
                conn);
        SimpleTestBlancoDbTable1SelectIterator iterator = new SimpleTestBlancoDbTable1SelectIterator(
                conn);
        try {
            invoker.setInputParameter(new Integer(5), (short) 3, new Short(
                    (short) 4), (long) 5, new Long(6), (float) 7.1, new Float(
                    8.2), 9.3, new Double(10.4), new BigDecimal("11"),
                    new BigDecimal("12"), new BigDecimal("13"), new BigDecimal(
                            "14"), new BigDecimal("15.2"), new BigDecimal(
                            "16.4"), "1", "2", "34", "56", "7890", "1234",
                    "5678", "9012", "3456", "7890", "1234", "5678", "12345678",
                    "12345678", new Date(), new Date(), 3);
            invoker.executeSingleUpdate();

            iterator.setInputParameter(4);
            SimpleTestBlancoDbTable1SelectRow row = iterator.getSingleRow();
            assertEquals(row.getColIntNull(), new Integer(5));

            invoker.setInputParameter(null, (short) 3, null, (long) 5, null,
                    (float) 7.1, new Float(8.2), 9.3, null,
                    new BigDecimal("11"), null, new BigDecimal("13"), null,
                    new BigDecimal("15.2"), null, "1", "2", "34", "56", "7890",
                    "1234", "5678", "9012", "3456", "7890", "1234", "5678",
                    "12345678", "12345678", new Date(), new Date(), 4);
            invoker.executeSingleUpdate();

            // iteratorの暗黙の再利用の際には executeQueryを明示的に呼び出す必要があります。
            iterator.setInputParameter(4);
            iterator.executeQuery();
            row = iterator.getSingleRow();
            assertEquals(row.getColIntNull(), null);
        } finally {
            iterator.close();
            invoker.close();
        }
    }

    public void processDelete(Connection conn) throws SQLException {
        System.out.println("行の削除を試みます");
        SimpleTestBlancoDbTable1DeleteInvoker invoker = new SimpleTestBlancoDbTable1DeleteInvoker(
                conn);
        try {
            invoker.setInputParameter(108);
            invoker.executeSingleUpdate();

            // 別の行も試験 こちらは nullベース
            invoker.prepareStatement();
            invoker.setInputParameter(108);
            invoker.executeSingleUpdate();
            fail("NoRowModifiedExceptionが発生しませんでした。");
        } catch (NoRowModifiedException ex) {
            // ここに入るのが成功。
            System.out.println("適切にNoRowModifiedExceptionが発生しました: "
                    + ex.toString());
        } finally {
            invoker.close();
        }
    }

    public void processSelectUpdatable(Connection conn) throws SQLException {
        System.out.println("FOR UPDATEを試験します。");
        SimpleTestBlancoDbTable1SelectUpdatableIterator iterator = new SimpleTestBlancoDbTable1SelectUpdatableIterator(
                conn);
        try {
            // prepareStatementを呼び出し、更新可能である旨を明示的に指定します。
            //iterator.prepareStatement(iterator.getQuery(),
            //		ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE);
            iterator.setInputParameter(2);
            assertTrue(iterator.next());
            SimpleTestBlancoDbTable1SelectUpdatableRow row = iterator.getRow();
            iterator.updateColTimestampNull(new Date());
            iterator.updateColText("ABCあい");
            iterator.updateRow();
        } finally {
            iterator.close();
        }
    }

    public void processCheckScrollCursor(Connection conn) throws SQLException {
        System.out.println("スクロールカーソルを試験します。");
        TestBlancoDbTable1SelectAllIterator iterator = new TestBlancoDbTable1SelectAllIterator(
                conn);
        try {
            iterator.absolute(7);
            TestBlancoDbTable1SelectAllRow row = iterator.getRow();
            assertEquals(row.getColIntNotNull(), 6);

            iterator.absolute(-3);
            row = iterator.getRow();
            assertEquals(row.getColIntNotNull(), 106);
        } finally {
            iterator.close();
        }
    }

}