package org.postgresforest.tool.tests;

import java.io.*;
import java.sql.*;
import junit.framework.*;

import org.postgresforest.tool.Logger;
import org.postgresforest.tool.lib.Config;
import org.postgresforest.tool.lib.Database;
import org.postgresforest.tool.lib.Instance;
import org.postgresforest.tool.lib.Table;
import org.postgresforest.tool.lib.GSCdata;
import org.postgresforest.tool.lib.PartitionUtils;
import org.postgresforest.tool.lib.ForestToolException;

/*
 * 試験内容
 * - 多重化テーブルをパーティション１化
 *   INSERT 1000件後、多重化テーブルに戻す
 *   1000件あることを確認
 * - 整合性チェック
 * - 多重化テーブルの削除
 *
 * - 多重化テーブルへのインデックス付与
 * - パーティション１テーブルへのインデックス付与
 * - パーティション２テーブルへのインデックス付与
 * - 多重化テーブルからのインデックス削除
 * - パーティション１テーブルからのインデックス削除
 * - パーティション２テーブルからのインデックス削除
 */
public class TestTable3 extends ForestToolTestCase {
	public void setUp()
	{
	}

	public void tearDown()
	{
	}

	public void testInitialize001()
	{
		GSCdata gsc = null;

		dropdb("gsctest", "9998");
		dropdb("testdb", "9998");
		dropdb("testdb", "9999");

		try {
			gsc = GSCdata.initialize("localhost", "9998", "gsctest",
									 user, pass);
			assertTrue(gsc!=null);

			Instance ins = gsc.registerInstance("localhost", "9999");
			ins.setStatus(1);

			Database d = gsc.createDatabase("testdb");

			assertTrue( d!=null );
			
			gsc.close();
		}
		catch (ForestToolException e)
		{
			System.out.println(e.getMessage());
			fail();
		}
	}

	/*
	 * INTEGERで3分割。
	 * パーティションテーブル１に1000件をINSERT。
	 * 多重化テーブルに戻しても同じ件数が存在することを確認。
	 */
	public void testPart501()
	{
		GSCdata gsc = null;

		/*
		 * パーティション１テーブル作成
		 */
		try {
			gsc = new GSCdata("localhost", "9998", "gsctest",
							  user, pass);
			assertTrue(gsc!=null);

			Database d = gsc.getDatabase("testdb");

			Table t = d.createTable("CREATE TABLE t501 ( uid INTEGER  PRIMARY KEY, name TEXT NOT NULL );");

			String[] pk = { "uid" };

			assertTrue( gsc.validate(GSCdata.VALIDATE_RECORD_COUNT) );

			assertTrue( t.part(pk, 2, null) );

			gsc.close();
		}
		catch (ForestToolException e)
		{
			System.out.println(e.getMessage());
			fail();
		}

		/*
		 * 1000件INSERT
		 */
		try {
			Connection con = DriverManager.getConnection("jdbc:postgresforest:GSC=//localhost:9998/gsctest@testdb",
														 user, pass);
			con.setAutoCommit(false);

			Statement stmt = con.createStatement();

			for (int i=0 ; i<1000 ; i++)
			{
				stmt.executeUpdate("INSERT INTO t501 VALUES ( " + i + ", '" + i + "');");
			}

			con.commit();
			con.close();
		}
		catch (Exception e)
		{
			System.out.println(e.getMessage());
			fail();
		}

		/*
		 * 1000件あるか確認
		 */
		try {
			Class.forName("org.postgresforest.Driver");

			Connection con = DriverManager.getConnection("jdbc:postgresforest:GSC=//localhost:9998/gsctest@testdb",
														 user, pass);
			con.setAutoCommit(false);

			Statement stmt = con.createStatement();

			ResultSet rs = stmt.executeQuery("SELECT count(*) FROM t501");

			assertTrue( rs.next() );
			assertTrue( rs.getInt(1)==1000 );

			con.commit();
			con.close();
		}
		catch (Exception e)
		{
			System.out.println(e.getMessage());
			fail();
		}

		/*
		 * パーティションテーブルの整合性を確認
		 */
		try {
			gsc = new GSCdata("localhost", "9998", "gsctest",
							  user, pass);
			assertTrue(gsc!=null);

			assertTrue( gsc.validate(GSCdata.VALIDATE_RECORD_COUNT) );

			gsc.close();
		}
		catch (Exception e)
		{
			System.out.println(e.getMessage());
			fail();
		}


		/*
		 * パーティション1を持っているインスタンスを取得
		 */
		try {
			gsc = new GSCdata("localhost", "9998", "gsctest",
							  user, pass);
			assertTrue(gsc!=null);

			Database d = gsc.getDatabase("testdb");

			Table t = d.getTable("t501");

			int[] instanceIds = t.getInstanceIds(1);

			assertTrue( instanceIds.length==2 );
			assertTrue( instanceIds[0]==0 );
			assertTrue( instanceIds[1]==1 );

			gsc.close();
		}
		catch (Exception e)
		{
			System.out.println(e.getMessage());
			fail();
		}

		/*
		 * 多重化テーブルに戻す
		 */
		try {
			gsc = new GSCdata("localhost", "9998", "gsctest",
							  user, pass);
			assertTrue(gsc!=null);

			Database d = gsc.getDatabase("testdb");

			Table t = d.getTable("t501");

			assertTrue( t.unpart() );

			gsc.close();
		}
		catch (ForestToolException e)
		{
			System.out.println(e.getMessage());
			fail();
		}

		/*
		 * 1000件あるか確認
		 */
		try {
			Connection con = DriverManager.getConnection("jdbc:postgresforest:GSC=//localhost:9998/gsctest@testdb",
														 user, pass);
			con.setAutoCommit(false);

			Statement stmt = con.createStatement();

			ResultSet rs = stmt.executeQuery("SELECT count(*) FROM t501");

			assertTrue( rs.next() );
			assertTrue( rs.getInt(1)==1000 );

			con.commit();
			con.close();
		}
		catch (Exception e)
		{
			System.out.println(e.getMessage());
			fail();
		}
	}

	/*
	 * 整合性を確認する
	 */
	public void testValidate001()
	{
		GSCdata gsc = null;

		/*
		 * 整合性確認
		 */
		try {
			gsc = new GSCdata("localhost", "9998", "gsctest",
							  user, pass);
			assertTrue(gsc!=null);

			assertTrue( gsc.validate(GSCdata.VALIDATE_RECORD_COUNT) );

			gsc.close();
		}
		catch (ForestToolException e)
		{
			System.out.println(e.getMessage());
			fail();
		}
	}

	public void testDropTable001()
	{
		GSCdata gsc = null;

		try {
			gsc = new GSCdata("localhost", "9998", "gsctest",
							  user, pass);
			assertTrue(gsc!=null);

			Database d = gsc.getDatabase("testdb");

			assertTrue( d.dropTable("t501") );

			gsc.close();
		}
		catch (ForestToolException e)
		{
			System.out.println(e.getMessage());
			fail();
		}

	}

	/*
	 * 多重化テーブルにCREATE INDEXでインデックスを追加
	 */
	public void testCreateIndex001()
	{
		GSCdata gsc = null;

		initializeGSC();

		/*
		 * 二台構成で多重化テーブル作成
		 */
		try {
			gsc = new GSCdata("localhost", "9998", "gsctest",
							  user, pass);
			assertTrue(gsc!=null);

			gsc.registerInstance("localhost", "9999");

			Database d = gsc.createDatabase("testdb");

			Table t = d.createTable("CREATE TABLE t501 ( uid INTEGER  PRIMARY KEY, name TEXT NOT NULL );");

			gsc.close();
		}
		catch (ForestToolException e)
		{
			System.out.println(e.getMessage());
			fail();
		}

		/*
		 * インデックスを作成
		 */
		try {
			gsc = new GSCdata("localhost", "9998", "gsctest",
							  user, pass);
			assertTrue(gsc!=null);

			Database d = gsc.getDatabase("testdb");

			Table t = d.getTable("t501");

			boolean rc;
			rc = t.createIndex("CREATE INDEX t501_name_idx ON t501(name)");

			assertTrue( rc==true );

			gsc.close();
		}
		catch (ForestToolException e)
		{
			System.out.println(e.getMessage());
			fail();
		}
	}

	/*
	 * パーティション１テーブルにCREATE INDEXでインデックスを追加
	 */
	public void testCreateIndex002()
	{
		GSCdata gsc = null;

		/*
		 * 二台構成で多重化テーブル作成
		 */
		try {
			gsc = new GSCdata("localhost", "9998", "gsctest",
							  user, pass);
			assertTrue(gsc!=null);

			Database d = gsc.getDatabase("testdb");

			Table t = d.createTable("CREATE TABLE t502 ( uid INTEGER  PRIMARY KEY, name TEXT NOT NULL );");

			String[] pk = { "uid" };
			assertTrue( t.part(pk, 2, null) );

			gsc.close();
		}
		catch (ForestToolException e)
		{
			System.out.println(e.getMessage());
			fail();
		}

		/*
		 * インデックスを作成
		 */
		try {
			gsc = new GSCdata("localhost", "9998", "gsctest",
							  user, pass);
			assertTrue(gsc!=null);

			Database d = gsc.getDatabase("testdb");

			Table t = d.getTable("t502");

			boolean rc;
			rc = t.createIndex("CREATE INDEX t502_name_idx ON t502(name)");

			assertTrue( rc==true );

			gsc.close();
		}
		catch (ForestToolException e)
		{
			System.out.println(e.getMessage());
			fail();
		}
	}

	/*
	 * パーティション２テーブルにCREATE INDEXでインデックスを追加
	 */
	public void testCreateIndex003()
	{
		GSCdata gsc = null;

		/*
		 * 二台構成で多重化テーブル作成
		 */
		try {
			gsc = new GSCdata("localhost", "9998", "gsctest",
							  user, pass);
			assertTrue(gsc!=null);

			Database d = gsc.getDatabase("testdb");

			Table t = d.createTable("CREATE TABLE t503 ( uid INTEGER  PRIMARY KEY, name TEXT NOT NULL );");

			String[] pk = { "uid" };

			assertTrue( t.part(pk, 2, null) );
			assertTrue( t.dropPart(0, 0) );
			assertTrue( t.dropPart(1, 1) );

			gsc.close();
		}
		catch (ForestToolException e)
		{
			System.out.println(e.getMessage());
			fail();
		}

		/*
		 * インデックスを作成
		 */
		try {
			gsc = new GSCdata("localhost", "9998", "gsctest",
							  user, pass);
			assertTrue(gsc!=null);

			Database d = gsc.getDatabase("testdb");

			Table t = d.getTable("t503");

			boolean rc;
			rc = t.createIndex("CREATE INDEX t503_name_idx ON t503(name)");

			assertTrue( rc==true );

			gsc.close();
		}
		catch (ForestToolException e)
		{
			System.out.println(e.getMessage());
			fail();
		}
	}

	/*
	 * パーティション２テーブルにCREATE INDEX USING HASHでインデックスを追加
	 */
	public void testCreateIndex004()
	{
		GSCdata gsc = null;

		/*
		 * 二台構成で多重化テーブル作成
		 */
		try {
			gsc = new GSCdata("localhost", "9998", "gsctest",
							  user, pass);
			assertTrue(gsc!=null);

			Database d = gsc.getDatabase("testdb");

			Table t = d.createTable("CREATE TABLE t504 ( uid INTEGER  PRIMARY KEY, name TEXT NOT NULL );");

			String[] pk = { "uid" };

			assertTrue( t.part(pk, 2, null) );
			assertTrue( t.dropPart(0, 1) );
			assertTrue( t.dropPart(1, 0) );

			gsc.close();
		}
		catch (ForestToolException e)
		{
			System.out.println(e.getMessage());
			fail();
		}

		/*
		 * インデックスを作成
		 */
		try {
			gsc = new GSCdata("localhost", "9998", "gsctest",
							  user, pass);
			assertTrue(gsc!=null);

			Database d = gsc.getDatabase("testdb");

			Table t = d.getTable("t504");

			boolean rc;
			rc = t.createIndex("CREATE INDEX t504_name_idx ON t504 USING hash (name)");

			assertTrue( rc==true );

			gsc.close();
		}
		catch (ForestToolException e)
		{
			System.out.println(e.getMessage());
			fail();
		}
	}

	public void testGetIndexNames001()
	{
		GSCdata gsc = null;

		/*
		 * インデックス名を取得する
		 */
		try {
			gsc = new GSCdata("localhost", "9998", "gsctest",
							  user, pass);
			assertTrue(gsc!=null);

			Database d = gsc.getDatabase("testdb");

			Table t = d.getTable("t504");

			String[] indexes = t.getIndexNames();

			Logger.debug("indexes : " + indexes.length);

			assertTrue( indexes.length==1 );
			assertTrue( indexes[0].equals("t504_name_idx") );

			gsc.close();
		}
		catch (ForestToolException e)
		{
			System.out.println(e.getMessage());
			fail();
		}
	}

	public void testDropIndex001()
	{
		GSCdata gsc = null;

		/*
		 * 多重化テーブルのインデックスを削除
		 */
		try {
			gsc = new GSCdata("localhost", "9998", "gsctest",
							  user, pass);
			assertTrue(gsc!=null);

			Database d = gsc.getDatabase("testdb");
			Table t = d.getTable("t501");

			assertTrue( t.dropIndex("t501_name_idx") );

			gsc.close();
		}
		catch (ForestToolException e)
		{
			System.out.println(e.getMessage());
			fail();
		}
	}

	public void testDropIndex002()
	{
		GSCdata gsc = null;

		/*
		 * パーティション１テーブルのインデックスを削除
		 */
		try {
			gsc = new GSCdata("localhost", "9998", "gsctest",
							  user, pass);
			assertTrue(gsc!=null);

			Database d = gsc.getDatabase("testdb");
			Table t = d.getTable("t502");

			assertTrue( t.dropIndex("t502_name_idx") );

			gsc.close();
		}
		catch (ForestToolException e)
		{
			System.out.println(e.getMessage());
			fail();
		}
	}

	public void testDropIndex003()
	{
		GSCdata gsc = null;

		/*
		 * パーティション２テーブルのインデックスを削除
		 */
		try {
			gsc = new GSCdata("localhost", "9998", "gsctest",
							  user, pass);
			assertTrue(gsc!=null);

			Database d = gsc.getDatabase("testdb");
			Table t = d.getTable("t503");

			assertTrue( t.dropIndex("t503_name_idx") );

			gsc.close();
		}
		catch (ForestToolException e)
		{
			System.out.println(e.getMessage());
			fail();
		}
	}

	public void testDropIndex004()
	{
		GSCdata gsc = null;

		/*
		 * パーティション２テーブルのHASHインデックスを削除
		 */
		try {
			gsc = new GSCdata("localhost", "9998", "gsctest",
							  user, pass);
			assertTrue(gsc!=null);

			Database d = gsc.getDatabase("testdb");
			Table t = d.getTable("t504");

			assertTrue( t.dropIndex("t504_name_idx") );

			gsc.close();
		}
		catch (ForestToolException e)
		{
			System.out.println(e.getMessage());
			fail();
		}
	}

	public static void main(String[] args)
	{
		Logger.setLevel(Logger.LOG_DEBUG);

		try {
			Class.forName("org.postgresql.Driver");
			Class.forName("org.postgresforest.Driver");
		}
		catch (Exception e)
		{
			System.out.println(e.getMessage());
			fail();
		}

		junit.textui.TestRunner.run(TestTable3.class);
	}
}
