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

package sql2k;

import igapyon.exception.IntegrityConstraintException;
import igapyon.exception.NoRowModifiedException;
import igapyon.query.SimpleTestBlancoDbTable1ColumnColBinary100NotNullIterator;
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.SimpleTestBlancoDbTable1ColumnColBinary100NotNullRow;
import igapyon.row.SimpleTestBlancoDbTable1SelectRow;
import igapyon.row.SimpleTestBlancoDbTable1SelectUpdatableRow;
import igapyon.row.TestBlancoDbTable1SelectAllRow;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
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 BlancoDbTest01Sql2k extends TestCase {
    /**
     * JDBCドライバ名を指定します。
     */
    public static final String JDBC_DRIVER = "com.microsoft.jdbc.sqlserver.SQLServerDriver";

    /**
     * JDBC接続時の文字列を指定します。 <br>
     * ポイント: SelectMethod=cursor の指定は必須です。
     */
    public static final String JDBC_URL = "jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=Northwind;SelectMethod=cursor";

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

    /**
     * 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 (int deleteCount = 0; iterator.next(); deleteCount++) {
                TestBlancoDbTable1SelectAllRow row = iterator.getRow();
                invoker.prepareStatement();
                invoker.setInputParameter(row.getColIntNotNull());
                invoker.executeSingleUpdate();

                if (deleteCount % 1000 == 999) {
                    conn.commit();
                    System.out.println("" + (deleteCount + 1)
                            + "件 削除処理されました。コミットします。");
                }
            }
        } 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);
        SimpleTestBlancoDbTable1ColumnColBinary100NotNullIterator iteratorCol = new SimpleTestBlancoDbTable1ColumnColBinary100NotNullIterator(
                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"), false,
                        new Boolean(true), new ByteArrayInputStream("ABC123"
                                .getBytes()), 6, new ByteArrayInputStream(
                                "DEF456".getBytes()), 6,
                        new ByteArrayInputStream("GHI789".getBytes()), 6,
                        new ByteArrayInputStream("JKL012".getBytes()), 6, "1",
                        "2", "34", "56", "7890", "1234", "5678", "9012",
                        "3456", "7890", "1234", "5678", "12345678", "12345678",
                        "colNVarchar255Null", new StringReader("ABC"), 3,
                        new Date(), new Date());
                invoker.executeSingleUpdate();

            }

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

            iteratorCol.setInputParameter(5);
            assertTrue(iteratorCol.next());
            SimpleTestBlancoDbTable1ColumnColBinary100NotNullRow rowBinary = iteratorCol
                    .getRow();
            InputStream inStream = rowBinary.getColBinary100NotNull();
            for (;;) {
                int iRead = inStream.read();
                if (iRead < 0)
                    break;
            }
        } finally {
            iteratorCol.close();
            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++) {
                InputStream inStream1 = new ByteArrayInputStream("ABC123"
                        .getBytes());
                InputStream inStream3 = new ByteArrayInputStream("GHI789"
                        .getBytes());
                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,
                        false, null, inStream1, 6, null, 0, inStream3, 6, null,
                        0, "1", null, "34", null, "7890", null, "5678", null,
                        "3456", null, "1234", null, "12345678", "12345678",
                        null, null, 0, 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++) {
                InputStream inStream1 = new ByteArrayInputStream("ABC123"
                        .getBytes());
                InputStream inStream2 = new ByteArrayInputStream("DEF456"
                        .getBytes());
                InputStream inStream3 = new ByteArrayInputStream("GHI789"
                        .getBytes());
                InputStream inStream4 = new ByteArrayInputStream("JKL012"
                        .getBytes());
                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"), false,
                        inStream1, 6, inStream3, 6, "1", "2", "34", "56",
                        "7890", "12345678", "colNVarchar255Null", 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 {
            InputStream inStream1 = new ByteArrayInputStream("ABC123"
                    .getBytes());
            InputStream inStream2 = new ByteArrayInputStream("DEF456"
                    .getBytes());
            InputStream inStream3 = new ByteArrayInputStream("GHI789"
                    .getBytes());
            InputStream inStream4 = new ByteArrayInputStream("JKL012"
                    .getBytes());
            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"), false,
                    inStream1, 6, inStream3, 6, "1", "2", "34", "56", "7890",
                    "12345678", "colNVarchar255Null", new Date());
            invoker.executeSingleUpdate();
            fail("一意制約違反が発生しませんでした。");
        } catch (IntegrityConstraintException ex) {
            // ここに入るのが成功。
            System.out.println("適切に一意制約違反が発生しました: " + ex.toString());
        } catch (SQLException ex) {
            ex.printStackTrace();
            // ここに入ってくる場合の例として、生成後ソースコードのIntegrityConstraintException
            // を利用せずに、誤って blanco.db配下のIntegrityConstraintExceptionを閲覧してしまっているという可能性があります。
            fail("予期せぬ例外が発生しました。:" + " SQLState[" + ex.getSQLState() + "] "
                    + ex.toString());
        } finally {
            invoker.close();
        }
    }

    public void processUpdate(Connection conn) throws SQLException {
        System.out.println("行の更新を試みます");
        SimpleTestBlancoDbTable1UpdateInvoker invoker = new SimpleTestBlancoDbTable1UpdateInvoker(
                conn);
        SimpleTestBlancoDbTable1SelectIterator iterator = new SimpleTestBlancoDbTable1SelectIterator(
                conn);
        try {
            InputStream inStream1 = new ByteArrayInputStream("ABC123"
                    .getBytes());
            InputStream inStream2 = new ByteArrayInputStream("DEF456"
                    .getBytes());
            InputStream inStream3 = new ByteArrayInputStream("GHI789"
                    .getBytes());
            InputStream inStream4 = new ByteArrayInputStream("JKL012"
                    .getBytes());
            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"), false, new Boolean(true), inStream1, 6,
                    inStream2, 6, inStream3, 6, inStream4, 6, "1", "2", "34",
                    "56", "7890", "1234", "5678", "9012", "3456", "7890",
                    "1234", "5678", "12345678", "12345678",
                    "colNVarchar255Null", new StringReader("あいうえ"), 4,
                    new Date(), new Date(), 3);
            invoker.executeSingleUpdate();

            // 別の行も試験 こちらは nullベース
            inStream1 = new ByteArrayInputStream("ABC123".getBytes());
            inStream2 = new ByteArrayInputStream("DEF456".getBytes());
            inStream3 = new ByteArrayInputStream("GHI789".getBytes());
            inStream4 = new ByteArrayInputStream("JKL012".getBytes());
            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, false, new Boolean(true),
                    inStream1, 6, null, 0, inStream3, 6, null, 0, "1", "2",
                    "34", "56", "7890", "1234", "5678", "9012", "3456", "7890",
                    "1234", "5678", "12345678", "12345678",
                    "colNVarchar255Null", new StringReader("AB"), 2,
                    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.updateColDatetimeNull(new Date());
            iterator.updateColBinary100Null(new ByteArrayInputStream("ABC123"
                    .getBytes()), 6);
            iterator.updateColNtext(new StringReader("ABCあい"), 5);
            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();
        }
    }

}