/*
 * Copyright (C) 2005 NTT DATA Corporation
 * 
 */
package org.postgresforest.tool.db;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Properties;

import org.postgresforest.tool.bean.ColumnInfo;
import org.postgresforest.tool.bean.ConData;
import org.postgresforest.tool.bean.PriorityInfo;
import org.postgresforest.tool.bean.ServerPartition2Info;
import org.postgresforest.tool.bean.ServerPriorityInfo;
import org.postgresforest.tool.bean.TableInfo;
import org.postgresforest.tool.bean.UserInfo;
import org.postgresforest.tool.util.StringReplaceUtil;
import org.postgresql.jdbc3.Jdbc3Connection;

/**
 * ユーザデータクラス.
 * 
 * ユーザデータデータベースに対するデータアクセス処理を提供する。
 * 
 */
public class UserData extends DbBase {

	public static final String TYPE_TABLE = "TABLE";
	public static final String TYPE_VIEW = "VIEW";

	protected String m_dbName = null;
	protected ArrayList m_dumpList = new ArrayList();
  	
	/** パーティション分割テーブルのSUFFIXフォーマット */
	protected static DecimalFormat m_dcFmt = new DecimalFormat("00");

	//Selectの戻り値(エラー)
	protected static final int SELECT_FAIL = 1;

	/**
	 *　コンストラクタ.
	 *　プロパティ
	 * 
	 */
	public UserData(String dbName, String user, String password) {
		super(user, password);
		m_dbName = dbName;

	}

	/**
	 * コンストラクタ
	 * @param userPassword　ユーザ、パスワードが格納されたプロパティクラス
	 */
	public UserData(Properties userPassword) {
		super();
		m_prop = userPassword;

	}

	/**
	 * DDL実行
	 *
	 * DDLを実行する
	 *  
	 * @param ddl	DDL
	 * @return	true:成功.false:失敗
	 * @throws SQLException
	 */
	public boolean execDdl(String ddl)  {
		String[] ddlList = { ddl };
		return execDdl(ddlList);
	}
	/**
	 * DDL実行
	 * 
	 * DDLを実行する
	 * 
	 * @param ddl	DDLのリスト
	 * @return	true:成功.false:失敗
	 * @throws SQLException
	 */
	public boolean execDdl(String[] ddl) {

		boolean ret = true;
		String connectUrl = "";

		for (Iterator iter = m_Connection.iterator(); iter.hasNext();) {
			Connection con = (Connection) iter.next();

			try {
				connectUrl = ((Jdbc3Connection) con).getURL();

				Statement ps = con.createStatement();
				for (int i = 0; i < ddl.length; i++) {
					ps.execute(ddl[i]);

				}

				ps.close();

			} catch (SQLException e) {
				setErrInfo(connectUrl, e);
				ret = false;
			}

		}

		return ret;

	}

	/**
	 * カラム情報取得
	 * 
	 * メタデータよりカラムの属性情報を取得する
	 * 
	 * @param tableName	テーブル名
	 * @return	カラム情報リスト
	 * @throws SQLException
	 */
	public ArrayList getColumnList(String tableName) throws SQLException {


		return getColumnList(getSelectConnectoin(), tableName);
	}

	/**
	 * カラム情報取得
	 * 
	 * メタデータよりカラムの属性情報を取得する
	 * 
	 * @param tableName	テーブル名
	 * @return	カラム情報リスト
	 * @throws SQLException
	 */
	private ArrayList getColumnList(Connection con, String tableName) throws SQLException {

		ArrayList columnList = new ArrayList();
		String connectUrl = "";


		try {

			connectUrl = ((Jdbc3Connection) con).getURL();

			DatabaseMetaData dataMeta = con.getMetaData();

			ResultSet rs =
				dataMeta.getColumns(
					m_dbName,
					"public",
					tableName.toLowerCase(),
					"");

			PreparedStatement pSelectSmt =
				con.prepareStatement(
					m_sqlResource.getString("select.user.partition.datatype"));
			pSelectSmt.setString(1, tableName.toLowerCase());


			while (rs.next()) {
				ColumnInfo column = new ColumnInfo();
				column.setName(rs.getString("COLUMN_NAME"));
				column.setNumber(rs.getInt("ORDINAL_POSITION"));
				column.setType(rs.getString("TYPE_NAME"));

				pSelectSmt.setString(2, column.getName());
				ResultSet rs2 = pSelectSmt.executeQuery();
				rs2.next();
				column.setTypeDetail(rs2.getString(1));
				column.setNotNull(rs2.getBoolean(2));
				rs2.close();

				columnList.add(column);
			}
			pSelectSmt.close();
		} catch (SQLException e) {
			setErrInfo(connectUrl, e);
			throw e;
		}

		return columnList;
	}

	/**
	 * ユーザ情報取得
	 * 
	 * メタデータよりカラムの属性情報を取得する
	 * 
	 * @param tableName	テーブル名
	 * @return	カラム情報リスト
	 * @throws SQLException
	 */
	public ArrayList getUserList() throws SQLException {

		ArrayList userList = new ArrayList();
		String connectUrl = "";

		Connection con = getSelectConnectoin();

		try {

			connectUrl = ((Jdbc3Connection) con).getURL();

			Statement smt = con.createStatement();
	
			ResultSet rs =
				smt.executeQuery(
					m_sqlResource.getString("select.user.list"));

			while (rs.next()) {
				UserInfo userInfo = new UserInfo();
				userInfo.setName(rs.getString("User name"));
				userInfo.setAttribute(rs.getString("Attributes"));

				userList.add(userInfo);
			}
			smt.close();
		} catch (SQLException e) {
			setErrInfo(connectUrl, e);
			throw e;
		}

		return userList;
	}
	/**
	 * パーティション化テーブルの解除
	 * 
	 * <pre>
	 * 以下の処理を行う
	 * viewから、一時テーブル作成
	 * 実テーブル（xxx_00）の削除（CASCADEで関連view、ruleも削除）
	 * 一時テーブルから、テーブル作成
	 * primaryKeyの設定
	 * </pre>
	 * 
	 * @param tableName	テーブル名
	 * @param partitionCount	パーティション数
	 * @return
	 */
	public boolean releasePartition(String tableName, int partitionCount) {
		boolean ret = true;
		String connectUrl = "";


		ArrayList sqlList = new ArrayList();
		
		//TEMPテーブル名、実テーブル名生成
		String tempTable = tableName + "_temp";
		String logicalTable = tableName + "_" + m_dcFmt.format(0);
		
		//--------------
		///実テーブル作成
		//--------------
		ArrayList conList = null;
		try {
			//制約情報の取得
			conList = getConstraint(getSelectConnectoin(),logicalTable);

			//--------------
			///制約名の変更
			//--------------
			for (int k = 0;k < conList.size(); k++) {
				String conName = ((ConData)conList.get(k)).getName();
				conName = conName.replaceAll(logicalTable.toLowerCase(), tableName.toLowerCase());
				((ConData)conList.get(k)).setName(conName);
				
				String description = ((ConData)conList.get(k)).getDesc();
				description = description.replaceAll(logicalTable.toLowerCase(), tableName.toLowerCase());
				((ConData)conList.get(k)).setDesc(description);
			}

			
			for (Iterator iter = m_Connection.iterator(); iter.hasNext();) {
				Connection con = (Connection) iter.next();
	
					connectUrl = ((Jdbc3Connection) con).getURL();
	
					//実テーブル名生成
					ret = makeLogicalTable( con, logicalTable, tempTable);
					if(ret != true)
						return ret;
	
					
	
			}
		} catch (SQLException e) {
			setErrInfo(connectUrl, e);
			ret = false;
		}
		

		//--------------
		//データ移行
		//--------------
		StringReplaceUtil strUtil =
			new StringReplaceUtil(
				m_sqlResource.getString("insert.user.physicaltable.temp"));
		strUtil.set(1, tableName);
		strUtil.set(2, tableName);
		sqlList.add(strUtil.get());

		//--------------
		//実テーブル削除
		//--------------
		strUtil.reset(m_sqlResource.getString("drop.user.physicaltable"));
		for (int i = 0; i < partitionCount; i++) {
			strUtil.set(1, tableName + "_" + m_dcFmt.format(i));
			sqlList.add(strUtil.get());
		}

		//--------------
		//temp　tableからテーブル作成
		//--------------
		strUtil.reset(m_sqlResource.getString("alter.user.physicaltable"));
		strUtil.set(1, tempTable);
		strUtil.set(2, tableName);
		sqlList.add(strUtil.get());

			
		//--------------
		///制約名の適用
		//--------------
		for (int k = 0;k < conList.size();k++) {
			String sql = makeConstraintSQL(tableName, (ConData)conList.get(k));
			sqlList.add(sql);
		}
		
		//--------------
		//DDL実行
		//--------------
		if (!execSql(sqlList)) {
			ret = false;
		}

		return ret;
	}

		/**
		 * パーティション化テーブルの解除
		 * 
		 * <pre>
		 * 以下の処理を行う
		 * viewから、一時テーブル作成
		 * 実テーブル（xxx_00）の削除（CASCADEで関連view、ruleも削除）
		 * 一時テーブルから、テーブル作成
		 * primaryKeyの設定
		 * </pre>
		 * 
		 * @param tableName	テーブル名
		 * @param partitionCount	パーティション数
		 * @return
		 */
		public boolean releasePartition2(String tableName, int partitionCount,ArrayList servers) {
			boolean ret = true;
			String connectUrl = "";
		
		
			
			
			ArrayList sqlList = new ArrayList();
			
			//TEMPテーブル名、実テーブル名生成
			String tempTable = tableName + "_temp";
			String logicalTable = tableName + "_" + m_dcFmt.format(0);
			
			
			
			//--------------
			///実テーブル作成
			//--------------

			try {

				//制約情報、カラム情報の取得
				ArrayList createTableSqlList = new ArrayList();
			    ArrayList conList = null;
			    for (int i = 0; i < servers.size(); i++) {
					try {
                        conList = getConstraint(getConnectoin(i),logicalTable);
					} catch (SQLException e1) {
					    getConnectoin(i).rollback();
                        continue;
                    }
					if(conList != null && conList.size()> 0 ){
						//実テーブル生成SQL作成
		                ArrayList columnList = getColumnList(getConnectoin(i),logicalTable);
					    createTableSqlList = makePhysicalTableSQL(tempTable,columnList);
					    break;
					}
                    
                }

			    
			    
			    //--------------
				///制約名の変更
				//--------------
				for (int k = 0;k < conList.size(); k++) {
					String conName = ((ConData)conList.get(k)).getName();
					conName = conName.replaceAll(logicalTable.toLowerCase(), tableName.toLowerCase());
					((ConData)conList.get(k)).setName(conName);
					
					String description = ((ConData)conList.get(k)).getDesc();
					description = description.replaceAll(logicalTable.toLowerCase(), tableName.toLowerCase());
					((ConData)conList.get(k)).setDesc(description);
				}
	
				
				for (Iterator iter = m_Connection.iterator(), iterSvr = servers.iterator(); iter.hasNext();) {

				    Connection con = (Connection) iter.next();
					connectUrl = ((Jdbc3Connection) con).getURL();
				    ServerPriorityInfo serverPriorityInfo = (ServerPriorityInfo)iterSvr.next();
			

					sqlList.clear();
					
					//実テーブル生成SQLセット
					sqlList.addAll(createTableSqlList);
					
				
					StringReplaceUtil strUtil =	new StringReplaceUtil("");
	
					//--------------
					//実テーブル削除
					//--------------
						
					strUtil.reset(m_sqlResource.getString("drop.user.physicaltable"));
					for (int i = 0; i < partitionCount; i++) {
						PriorityInfo info = (PriorityInfo) serverPriorityInfo.getPartition(i);
						if(info != null){
							strUtil.set(1, tableName + "_" + m_dcFmt.format(info.getPartitionNo()));
							sqlList.add(strUtil.get());
						}
					}
				
					//--------------
					//temp　tableからテーブル名変更
					//--------------
					strUtil.reset(m_sqlResource.getString("alter.user.physicaltable"));
					strUtil.set(1, tempTable);
					strUtil.set(2, tableName);
					sqlList.add(strUtil.get());
				
						
					//--------------
					///制約名の適用
					//--------------
					for (int k = 0;k < conList.size();k++) {
						String sql = makeConstraintSQL(tableName, (ConData)conList.get(k));
						sqlList.add(sql);
					}
					
					//--------------
					// SQLの実行
					//--------------
					Statement ps = con.createStatement();
					
					for (Iterator iterator = sqlList.iterator(); iterator.hasNext();) {
						String sql = (String) iterator.next();
						ps.execute(sql);
		
					}
					ps.close();
			
				}
			
			} catch (SQLException e) {
				setErrInfo(connectUrl, e);
				ret = false;
			}
	
			return ret;
		}


	/**
	 * パーティションテーブル作成
	 * 
	 * <pre>
	 * 指定されたパーティション情報に基づいて以下の処理を行う。
	 * 実テーブル（xxx_00）の作成
	 * primaryKeyの設定
	 * viewテーブルの作成
	 * 元のテーブルの削除
	 * データ移行
	 * </pre>
	 * 
	 * @param tableInfo パーティションテーブル情報
	 * @param partCount パーティション数
	 * @param dataShift データ移行フラグ
	 * @return
	 * @since 2.0
	 */
	public boolean setPartition(TableInfo tableInfo, int partCount, boolean dataShift, String newHashName, byte[] hashImage) {
		boolean ret = true;
		String connectUrl = "";
		
		String tableName = tableInfo.getName();
		ArrayList serverList = tableInfo.getServer();
		
		//SQLリスト。このリストに実行するSQLをセットして、実行する。
		ArrayList sqlList = new ArrayList();

		//サーバ数を取得
		int serverCount = serverList.size();
		

		//--------------
		///実テーブル作成
		//--------------
		try {
			//制約情報の取得
			ArrayList conList = getConstraint(getSelectConnectoin(),tableName);
		
			for (Iterator iter = m_Connection.iterator(); iter.hasNext();) {
				Connection con = (Connection) iter.next();
	
				connectUrl = ((Jdbc3Connection) con).getURL();

				//実テーブル生成
				for (int i = 0; i < partCount; i++) {
					String logicalTable = tableName + "_" + m_dcFmt.format(i);
					ret = makeLogicalTable( con, tableName, logicalTable);
					if(ret != true)
						return ret;
					
					//制約設定取得
					ArrayList conDataWk = makeConstraint( tableName,logicalTable, conList );
					
					//制約を設定
					ret = setConstraint(con, logicalTable, conDataWk);
					if(ret != true)
						return ret;
				
				}
					
			}
		} catch (SQLException e) {
			setErrInfo(connectUrl, e);
			ret = false;
		}
		
		//--------------
		// データ移行
		//--------------
		if (dataShift) {
			sqlList.addAll( makeShiftDataSQL(tableInfo.getColumn(), partCount, tableName, newHashName, hashImage ));
		}
		
		//--------------
		// 元テーブルドロップ
		//--------------
		StringReplaceUtil dropTableStrUtil =
			new StringReplaceUtil(m_sqlResource.getString("drop.user.table"));
		dropTableStrUtil.set(1, tableName);
		//SQLリストに追加
		sqlList.add(dropTableStrUtil.get());


		//--------------
		// VIEW、RULEの作成
		//--------------
		
		
		//各SQLのパラメータをセットする。

		//RULE用のSet句SQL生成
		StringBuffer ruleSetColumn = makeRuleSet(tableInfo.getColumn());
		
		//RULE用のWhere句SQL生成
		StringBuffer ruleWhereColumn = makeRuleWhere(tableName);
		
		//VIEW用SQLの組み立て
		int[] partCountlist = new int[partCount];
		for (int i = 0; i < partCountlist.length; i++) {
			partCountlist[i] = i;
		}
		sqlList.addAll( makeViewSQL(partCountlist, tableName, ruleSetColumn, ruleWhereColumn) );

		//--------------
		// SQLの実行
		//--------------
		if (!execSql(sqlList)) {
			ret = false;
		}

		return ret;

	}

	/**
	 * @param partCount
	 * @param tableName
	 * @param sqlList
	 * @param createViewStrUtil
	 * @param createUpdateRuleStrUtil
	 * @param createDeleteRuleStrUtil
	 * @param ruleSetColumn
	 * @param ruleWhereColumn
	 */
	protected ArrayList makeViewSQL(int[] partCount, String tableName, StringBuffer ruleSetColumn, StringBuffer ruleWhereColumn) {
		ArrayList sqlList = new ArrayList();
		
		//VIEW,RULE（UPDATE,DELETE）のSQL取得
		StringReplaceUtil createViewStrUtil =
			new StringReplaceUtil(m_sqlResource.getString("create.view"));
		createViewStrUtil.set(1, tableName);

		StringReplaceUtil createUpdateRuleStrUtil =
			new StringReplaceUtil(
				m_sqlResource.getString("create.rule.update"));
		createUpdateRuleStrUtil.set(1, tableName);
		createUpdateRuleStrUtil.set(2, tableName);

		StringReplaceUtil createDeleteRuleStrUtil =
			new StringReplaceUtil(
				m_sqlResource.getString("create.rule.delete"));
		createDeleteRuleStrUtil.set(1, tableName);
		createDeleteRuleStrUtil.set(2, tableName);

	
		//SQL組み立て
		StringBuffer viewSelect = new StringBuffer();
		StringBuffer ruleUpdate = new StringBuffer();
		StringBuffer ruleDelate = new StringBuffer();
		for (int i = 0; i < partCount.length; i++) {
			String logicalTable = tableName + "_" + m_dcFmt.format(partCount[i]);
			StringBuffer viewSelectWk = new StringBuffer();
			viewSelectWk.append("( SELECT  * FROM ");
			viewSelectWk.append(logicalTable);
			viewSelectWk.append(")");
			if (viewSelect.length() != 0) {
				viewSelect.append("UNION ALL");
			}
			viewSelect.append(viewSelectWk);

			ruleUpdate.append("UPDATE ");
			ruleUpdate.append(logicalTable);
			ruleUpdate.append(" SET ");
			ruleUpdate.append(ruleSetColumn);
			ruleUpdate.append(" WHERE ");
			ruleUpdate.append(ruleWhereColumn);
			ruleUpdate.append(";");

			ruleDelate.append("DELETE FROM ");
			ruleDelate.append(logicalTable);
			ruleDelate.append(" WHERE ");
			ruleDelate.append(ruleWhereColumn);
			ruleDelate.append(";");

		}

		//SQL用のパラメータをセットして、SQLリストに追加
		createViewStrUtil.set(2, viewSelect.toString());
		createUpdateRuleStrUtil.set(3, ruleUpdate.toString());
		createDeleteRuleStrUtil.set(3, ruleDelate.toString());

		sqlList.add(createViewStrUtil.get());
		sqlList.add(createUpdateRuleStrUtil.get());
		sqlList.add(createDeleteRuleStrUtil.get());
		
		return sqlList;
	}

	/**
	 * //RULE用のWhere句SQL生成
	 * @param tableName
	 * @param ruleWhereColumn
	 */
	protected StringBuffer makeRuleWhere(String tableName ) {
		StringBuffer ruleWhereColumn = new StringBuffer();
		ArrayList primaryKeyList = getPrimaryKey(tableName);
		for (Iterator iter = primaryKeyList.iterator(); iter.hasNext();) {
			String primaryKey = (String) iter.next();
			StringBuffer ruleWhereWk = new StringBuffer();
			ruleWhereWk.append("(");
			ruleWhereWk.append(primaryKey);
			ruleWhereWk.append(" = ");
			ruleWhereWk.append("old.");
			ruleWhereWk.append(primaryKey);
			ruleWhereWk.append(" OR (");
			ruleWhereWk.append(primaryKey);
			ruleWhereWk.append(" IS NULL");
			ruleWhereWk.append(" AND ");
			ruleWhereWk.append("old.");
			ruleWhereWk.append(primaryKey);
			ruleWhereWk.append(" IS NULL");
			ruleWhereWk.append("))");
			if (ruleWhereColumn.length() != 0) {
				ruleWhereColumn.append(" AND ");
			}
			ruleWhereColumn.append(ruleWhereWk);
		}
		return ruleWhereColumn;
	}

	/**
	 * 
	 * @param columnList
	 * @return
	 */
	protected StringBuffer makeRuleSet(ArrayList columnList) {
		StringBuffer ruleSetColumn = new StringBuffer();
		//RULE用のSet句SQL生成
		
		for (Iterator iter = columnList.iterator(); iter.hasNext();) {
			ColumnInfo columnInfo = (ColumnInfo) iter.next();
			String columnName = columnInfo.getName();
			StringBuffer ruleSetWk = new StringBuffer();
			ruleSetWk.append(columnName);
			ruleSetWk.append(" = ");
			ruleSetWk.append("new.");
			ruleSetWk.append(columnName);
			if (ruleSetColumn.length() != 0) {
				ruleSetColumn.append(",");
			}
			ruleSetColumn.append(ruleSetWk);
		}
		
		return ruleSetColumn;
	}


	
	/**
	 * @param ret
	 * @param tableName
	 * @param con
	 * @param logicalTable
	 * @return
	 * @throws SQLException
	 */
	protected ArrayList getConstraint(  Connection con, String tableName) throws SQLException {


		//--------------
		//テーブルの持つカラムごとの制約取得
		//--------------
		//テーブルの持つカラムごとの制約の配列
		ArrayList conList = new ArrayList();
		//テーブルの持つカラムごとの制約取得
		PreparedStatement smt = con.prepareStatement(
			m_sqlResource.getString("select.extractConstraint"));
		smt.setString(1, tableName.toLowerCase());
		ResultSet rs = smt.executeQuery();
		while (rs.next()) {
			ConData condata = new ConData();
			condata.setName(rs.getString("conname"));
			condata.setCategory(rs.getString("concategory"));
			condata.setAttNum(rs.getString("attnum"));
			condata.setCols(rs.getString("targetcolumn"));
			condata.setDesc(rs.getString("description"));
			conList.add(condata);
		}
		rs.close();
		smt.close();
		
		
		return conList;
	}

	/**
	 * @param ret
	 * @param tableName
	 * @param con
	 * @param logicalTable
	 * @return
	 * @throws SQLException
	 */
	protected ArrayList makeConstraint( String srcTableName, String distTableName, ArrayList conList) throws SQLException {
	
		boolean ret = true;
		ArrayList distConList = new ArrayList();
		//--------------
		///制約名の変更
		//--------------
		for(int k = 0;k < conList.size(); k++)
		{
			ConData orgData = (ConData)conList.get(k);

			ConData conData = new ConData();
			conData.setAttNum(orgData.getAttNum());
			conData.setCategory(orgData.getCategory());
			conData.setCols(orgData.getCols());
			conData.setDesc(orgData.getDesc());
			
			String conName = orgData.getName();
			conName = conName.replaceAll(srcTableName.toLowerCase(), distTableName.toLowerCase());
			
			conData.setName(conName);

			distConList.add(conData);
			
			
		}
		
		return distConList;
	}

	/**
	 * @param ret
	 * @param tableName
	 * @param con
	 * @param logicalTable
	 * @return
	 * @throws SQLException
	 */
	protected boolean setConstraint(  Connection con, String logicalTable, ArrayList conList) throws SQLException {
	
		boolean ret = true;
		
		//--------------
		///制約名の適用
		//--------------
		for(int k = 0;k < conList.size();k++)
		{
			String sql = makeConstraintSQL(logicalTable, (ConData)conList.get(k));
	
			Statement stmt = con.createStatement();
			ResultSet rs = stmt.executeQuery(sql);
	
			while (rs.next()) {
				//結果は1タプル1カラムのみのはず
				//成功すれば 0、失敗すれば1
				if(rs.getInt("ret") == SELECT_FAIL){
					ret = false;
				}
			}
			rs.close();
			stmt.close();
		}
		return ret;
	}

	/**
	 * @param logicalTable
	 * @param conData
	 * @return
	 */
	protected String makeConstraintSQL(String logicalTable, ConData conData) {
		String sql = "select ret from postgresforest.AddaptConstraint(" + 
				"'" + conData.getName() + "'::name, " + 
				conData.getCategory() + "::smallint, " + 
				conData.getAttNum() + "::smallint, " + 
				"'" + conData.getCols() + "'::smallint[], " + 
				"'" + conData.getDesc() + "'::text, " + 
				"'" + logicalTable.toLowerCase() + "'::name" + 
				") AS ret";
		return sql;
	}

	/**
	 * @param logicalTable 
	 * @param columnList カラム情報
	 * @return
	 */
	protected ArrayList makePhysicalTableSQL(String physicalTable, ArrayList columnList) {

		ArrayList sqlList = new ArrayList();
		
		StringReplaceUtil strUtil =
			new StringReplaceUtil(
				m_sqlResource.getString("alter.table.notnull"));

		strUtil.set(1, physicalTable);

		StringBuffer nameList = new StringBuffer();

	    for (Iterator iter = columnList.iterator(); iter.hasNext();) {
            ColumnInfo columnInfo = (ColumnInfo) iter.next();
            
            String columnNmae = columnInfo.getName();
            
            //カラム設定生成
			if (nameList.length() != 0) {
			    nameList.append(",");
			}
			nameList.append(columnNmae);
			nameList.append(" ");
            nameList.append(columnInfo.getTypeDetail());
            
            
            //NOT NULL属性SQL作成
            if(columnInfo.isNotNull()){
				strUtil.set(2, columnNmae);
				sqlList.add(strUtil.get());
            }
            
            
        }

	    //テーブルのCREATE文を先頭に挿入
		strUtil.reset(m_sqlResource.getString("create.user.physicaltable"));
		strUtil.set(1, physicalTable);
		strUtil.set(2, nameList.toString());

		sqlList.add(0, strUtil.get());
		
	    return sqlList;
	}

	
	/**
	 * @param ret
	 * @param tableName
	 * @param con
	 * @param logicalTable
	 * @return
	 * @throws SQLException
	 */
	protected boolean makeLogicalTable(  Connection con, String srcTableName, String distTableName) throws SQLException {
	
		boolean ret = true;
	
	
		//テーブルのカラムのみをコピーする
		//ここで引き継がれるのはカラム定義とNOT NULL制約のみ
		PreparedStatement smt =
			con.prepareStatement(
				m_sqlResource.getString("select.copy.column"));
		smt.setString(1, srcTableName.toLowerCase());
		smt.setString(2, distTableName.toLowerCase());
		ResultSet rs = smt.executeQuery();
		ResultSetMetaData rsmd = rs.getMetaData();
		while (rs.next()) {
			//結果は1タプル1カラムのみのはず
			//成功すれば 0、失敗すれば1
			if(rs.getInt("ret") == SELECT_FAIL){
				ret = false;
			}
		}
		rs.close();
		smt.close();
	
		return ret;
	}

	/**
	 * パーティションテーブル作成
	 * 
	 * <pre>
	 * 指定されたパーティション情報に基づいて以下の処理を行う。
	 * 実テーブル（xxx_00）の作成
	 * primaryKeyの設定
	 * viewテーブルの作成
	 * 元のテーブルの削除
	 * データ移行
	 * </pre>
	 * 
	 * @param tableInfo パーティションテーブル情報
	 * @param partCount パーティション数
	 * @param dataShift データ移行フラグ
	 * @return
	 * @since 2.0
	 */
	public boolean setPartition2(TableInfo tableInfo, int partCount, boolean dataShift, String newHashName, byte[] hashImage) {
		boolean ret = true;
		String connectUrl = "";
		
		
		String tableName = tableInfo.getName();
		ArrayList serverList = tableInfo.getServer();
		
		//SQLリスト。このリストに実行するSQLをセットして、実行する。
		ArrayList sqlDataShift = new ArrayList();
	
		//サーバ数を取得
		int serverCount = serverList.size();
		
		int conIndex = 0;
		//--------------
		///実テーブル作成
		//--------------

		
		try {

			ArrayList conList = getConstraint(getSelectConnectoin(),tableName);

			for (Iterator iter = m_Connection.iterator(); iter.hasNext();) {
				Connection con = (Connection) iter.next();
		
					connectUrl = ((Jdbc3Connection) con).getURL();
		
					ServerPartition2Info svrPartInfo = (ServerPartition2Info) serverList.get(conIndex);
	
					conIndex++;
					
					for (int i = 0; i < partCount; i++) {
		
		
						if( svrPartInfo.getMakeInstance(i).booleanValue() == false ){
							continue;
						}
	
						String logicalTable = tableName + "_" + m_dcFmt.format(i);
						ret = makeLogicalTable( con, tableName, logicalTable);
						if(ret != true)
							return ret;
						
						//制約設定取得
						ArrayList conDataWk = makeConstraint( tableName,logicalTable, conList );
						
						//制約を設定
						ret = setConstraint(con, logicalTable, conDataWk);
						if(ret != true)
							return ret;
						
					}
			}
		} catch (SQLException e) {
			setErrInfo(connectUrl, e);
			ret = false;
		}
		
		
		//--------------
		// 元テーブルドロップ
		//--------------
		StringReplaceUtil dropTableStrUtil =
			new StringReplaceUtil(m_sqlResource.getString("drop.user.table"));
		dropTableStrUtil.set(1, tableName);
	
	
		//--------------
		// VIEW、RULEの作成
		//--------------
		
		
		//各SQLのパラメータをセットする。

		//RULE用のSet句SQL生成
		StringBuffer ruleSetColumn = makeRuleSet(tableInfo.getColumn());
		
		//RULE用のWhere句SQL生成
		StringBuffer ruleWhereColumn = makeRuleWhere(tableName);
		

		
		conIndex = 0;
		//--------------
		///実テーブル作成
		//--------------
		for (Iterator iter = m_Connection.iterator(); iter.hasNext();) {
			Connection con = (Connection) iter.next();
	
			try {
				connectUrl = ((Jdbc3Connection) con).getURL();
	
				ServerPartition2Info svrPartInfo = (ServerPartition2Info) serverList.get(conIndex);

				conIndex++;
				int[] partCountlist = new int[svrPartInfo.getMakeInstanceCount()];
				for (int i = 0,partindex = 0; i < partCount; i++) {
					
					if( svrPartInfo.getMakeInstance(i).booleanValue() == true ){
						partCountlist[partindex++] = i;
					}
			
				}

			
				//VIEW用SQLの組み立て
				ArrayList sqlList = new ArrayList();
				
				//--------------
				// データ移行
				//--------------
				if (partCountlist.length != 0 && dataShift) {
					sqlDataShift = makeShiftDataSQL(partCountlist, tableInfo.getColumn(), partCount, tableName, newHashName, hashImage);
					sqlList.addAll(sqlDataShift);
				}
				sqlList.add(dropTableStrUtil.get());

				//--------------
				// /VIEW作成
				//--------------
				if(partCountlist.length != 0){
				    sqlList.addAll( makeViewSQL(partCountlist, tableName, ruleSetColumn, ruleWhereColumn) );
				}
				
				//--------------
				// SQLの実行
				//--------------
				Statement ps = con.createStatement();
				
				for (Iterator iterator = sqlList.iterator(); iterator.hasNext();) {
					String sql = (String) iterator.next();
					ps.execute(sql);
	
				}
				ps.close();

			} catch (SQLException e) {
				setErrInfo(connectUrl, e);
				ret = false;
			}
		}
		return ret;
	
	}

	/**
	 * 
	 * @param columnList カラム情報
	 * @param partCount
	 * @param tableName
	 * @param sqlList
	 * @return
	 */
	protected ArrayList makeShiftDataSQL(ArrayList columnList, int partCount, String tableName , String hashName, byte[] hashImage) {

		int[] partCountList = new int[partCount];
		for (int i = 0; i < partCountList.length; i++) {
			 partCountList[i] = i;
		}
			
		return makeShiftDataSQL(partCountList,columnList,partCount,tableName,hashName,hashImage);
	}

	/**
	 * 
	 * @param columnList カラム情報
	 * @param partCount
	 * @param tableName
	 * @param sqlList
	 * @return
	 */
	protected ArrayList makeShiftDataSQL(int[] partCountList, ArrayList columnList, int partCount, String tableName , String hashName,byte[] hashImage) {

		ArrayList sqlList = new ArrayList();
		
		//ハッシュ関数名、パーティション数を設定
		StringReplaceUtil strUtil =
			new StringReplaceUtil("postgresforest.getHash('?', '?', ?)");
		if(hashName == null){
			//ハッシュが指定されていなければ、デフォルトのハッシュ関数を指定
			strUtil.set(1, "org.postgresql.vm.Hash01");
		}else{
			strUtil.set(1, hashName);
			strUtil.set(2, hashImage);
		}
		strUtil.set(3, Integer.toString(partCount));
		String sqlPartition = strUtil.get();

		
		//パーティション属性を設定
		for (Iterator iterator = columnList.iterator();
			iterator.hasNext();
			) {

			ColumnInfo columnInfo = (ColumnInfo) iterator.next();

			if (columnInfo.isPartition()) {
				strUtil.reset("postgresforest.setValue(?, ?)");
				strUtil.set(1, sqlPartition);
				strUtil.set(2, columnInfo.getName());
				sqlPartition = strUtil.get();
			}
		}
		
		//パーティションNO取得を設定
		strUtil.reset("postgresforest.getPartitionNo(?)");
		strUtil.set(1, sqlPartition);
		sqlPartition = strUtil.get();

		for (int i = 0; i < partCountList.length; i++) {
			//実テーブル名生成
			String logicalTable = tableName + "_" + m_dcFmt.format(partCountList[i]);
			//テーブルのカラムのみをコピーする
			//ここで引き継がれるのはカラム定義とNOT NULL制約のみ
			strUtil.reset("INSERT INTO ? (select * from ? where ? = ?);");
			strUtil.set(1, logicalTable.toLowerCase());
			strUtil.set(2, tableName.toLowerCase());
			strUtil.set(3, sqlPartition);
			strUtil.set(4, Integer.toString(partCountList[i]));
			sqlList.add(strUtil.get());
		}
		return sqlList;
	}
	
	/**
	 * パーティションテーブル作成
	 * 
	 * <pre>
	 * 指定されたパーティション情報に基づいて以下の処理を行う。
	 * 実テーブル（xxx_00）の作成
	 * primaryKeyの設定
	 * viewテーブルの作成
	 * 元のテーブルの削除
	 * </pre>
	 * 
	 * @param tableInfo パーティションテーブル情報
	 * @param partCount パーティション数
	 * @return
	 * @since 2.0
	 */
	public boolean rePartition(TableInfo tableInfo, int partCount, String newHashName, byte[] hashImage) {
		boolean ret = true;
		String connectUrl = "";
	
		//Selectの戻り値
		final int RetSuccess = 0;
		final int RetFail = 1;
	
		//元のテーブル名、実テーブル名生成
		String tableName = tableInfo.getName();
		String srcTableName = tableName + "_" + m_dcFmt.format(0);
	
		//SQLリスト。このリストに実行するSQLをセットして、実行する。
		ArrayList sqlList = new ArrayList();
	
		//サーバ数を取得
		ArrayList serverList = tableInfo.getServer();
		int serverCount = serverList.size();
		
		//元のパーティション数を取得
		int srcPartCount = tableInfo.getPartCount();
		
		//カラム情報
		ArrayList columnList = tableInfo.getColumn();
		
		//テーブルの総レコード数を取得
		ArrayList recCountList = new ArrayList();
		for (Iterator iter = m_Connection.iterator(); iter.hasNext();) {
			Connection con = (Connection) iter.next();
			try {
				connectUrl = ((Jdbc3Connection) con).getURL();
				recCountList.add(new Long(getRecordCount(tableName)));
			} catch (SQLException e) {
				setErrInfo(connectUrl, e);
				ret = false;
			}
		}
		
		//プライマリーキーを取得する
		ArrayList primaryKeyList = getPrimaryKey(srcTableName);
		
		//----------------------------
		///実テーブル作成
		//----------------------------
		for (Iterator iter = m_Connection.iterator(); iter.hasNext();) {
			Connection con = (Connection) iter.next();
			try {
				connectUrl = ((Jdbc3Connection) con).getURL();
				for (int i = 0; i < partCount; i++) {
					//実テーブル名生成
					String logicalTable = "temp_" + tableName + "_" + m_dcFmt.format(i);
					//テーブルのカラムのみをコピーする
					//ここで引き継がれるのはカラム定義とNOT NULL制約のみ
					PreparedStatement smt =
						con.prepareStatement(
							m_sqlResource.getString("select.copy.column"));
					smt.setString(1, srcTableName.toLowerCase());
					smt.setString(2, logicalTable.toLowerCase());
					ResultSet rs = smt.executeQuery();
					ResultSetMetaData rsmd = rs.getMetaData();
					while (rs.next()) {
						//結果は1タプル1カラムのみのはず
						//成功すれば 0、失敗すれば1
						if(rs.getInt("ret") == RetFail){
							SQLException e = 
								new SQLException(
									"ERROR:postgresforest.CopyColumn() ErrorCode=" + RetFail);
							setErrInfo(connectUrl, e);
							ret = false;
						}
					}
					rs.close();
					smt.close();
				}
			} catch (SQLException e) {
				setErrInfo(connectUrl, e);
				ret = false;
			}
		}
		
		//----------------------------
		//テーブルの持つカラムごとの制約取得
		//----------------------------
		//テーブルの持つカラムごとの制約の配列
		ArrayList conList = new ArrayList();
		try {
			Connection con = getSelectConnectoin();
			connectUrl = ((Jdbc3Connection) con).getURL();
			//テーブルの持つカラムごとの制約取得
			PreparedStatement smt = 
				con.prepareStatement(
					m_sqlResource.getString("select.extractConstraint"));
			smt.setString(1, srcTableName.toLowerCase());
			ResultSet rs = smt.executeQuery();
			while (rs.next()) {
				ConData condata = new ConData();
				condata.setName(rs.getString("conname"));
				condata.setCategory(rs.getString("concategory"));
				condata.setAttNum(rs.getString("attnum"));
				condata.setCols(rs.getString("targetcolumn"));
				condata.setDesc(rs.getString("description"));
				conList.add(condata);
			}
			rs.close();
			smt.close();
		} catch (SQLException e) {
			setErrInfo(connectUrl, e);
			ret = false;
		}
	
		//----------------------------
		// データ移行
		//----------------------------
		//ハッシュ関数名、パーティション数を設定
		StringReplaceUtil strUtil =
			new StringReplaceUtil("postgresforest.getHash('?', '?', ?)");
		if(newHashName == null){
			//ハッシュが指定されていなければ、デフォルトのハッシュ関数を指定
			strUtil.set(1, "org.postgresql.vm.Hash01");
		}else{
			strUtil.set(1, newHashName);
			strUtil.set(2, hashImage);
		}
		strUtil.set(3, Integer.toString(partCount));
		String sqlPartition = strUtil.get();

		//パーティション属性を設定
		for (Iterator iterator = columnList.iterator(); iterator.hasNext();) {
			ColumnInfo columnInfo = (ColumnInfo) iterator.next();
			if (columnInfo.isPartition()) {
				strUtil.reset("postgresforest.setValue(?, ?)");
				strUtil.set(1, sqlPartition);
				strUtil.set(2, columnInfo.getName());
				sqlPartition = strUtil.get();
			}
		}

		//パーティションNO取得を設定
		strUtil.reset("postgresforest.getPartitionNo(?)");
		strUtil.set(1, sqlPartition);
		sqlPartition = strUtil.get();
		for (int i = 0; i < partCount; i++) {
			for (int j = 0; j < srcPartCount; j++) {
				//実テーブル名生成
				String logicalTable = "temp_" + tableName + "_" + m_dcFmt.format(i);
				//実テーブル名生成
				String srcLogicalTable = tableName + "_" + m_dcFmt.format(j);
				//テーブルのカラムのみをコピーする
				//ここで引き継がれるのはカラム定義とNOT NULL制約のみ
				strUtil.reset("INSERT INTO ? (select * from ? where ? = ?);");
				strUtil.set(1, logicalTable.toLowerCase());
				strUtil.set(2, srcLogicalTable.toLowerCase());
				strUtil.set(3, sqlPartition);
				strUtil.set(4, Integer.toString(i));
				sqlList.add(strUtil.get());
			}
		}
		
		//----------------------------
		// SQLの実行
		//----------------------------
		if (!execSql(sqlList)) {
			ret = false;
		}
		//SQLリストをクリア
		sqlList.clear();
		
		//TEMPテーブルの総レコード数を取得
		try {
			int i = 0;
			for (Iterator iter = m_Connection.iterator(); iter.hasNext();) {
				Connection con = (Connection) iter.next();
				connectUrl = ((Jdbc3Connection) con).getURL();
				Long recCount = (Long) recCountList.get(i);
				long count = 0;
				for (int j = 0; j < partCount; j++) {
					//実テーブル名生成
					String logicalTable = "temp_" + tableName + "_" + m_dcFmt.format(j);
					count = count + getRecordCount(logicalTable);
				}
				//総レコード数をチェック
				if (count != recCount.longValue()){
					SQLException e = 
						new SQLException("ERROR:Data Shift");
					setErrInfo(connectUrl, e);
					ret = false;
					throw e;
				}
				i++;
			}
		} catch (SQLException e) {
			setErrInfo(connectUrl, e);
			ret = false;
		}
		
		//----------------------------
		// 元テーブルドロップ
		//----------------------------
		for (int i = 0; i < srcPartCount; i++) {
			//実テーブル名生成
			String logicalTable = tableName + "_" + m_dcFmt.format(i);
			StringReplaceUtil dropTableStrUtil =
				new StringReplaceUtil(m_sqlResource.getString("drop.user.physicaltable"));
			dropTableStrUtil.set(1, logicalTable);
			//SQLリストに追加
			sqlList.add(dropTableStrUtil.get());
		}
		
		//----------------------------
		//temp　tableからテーブル作成
		//----------------------------
		for (int i = 0; i < partCount; i++) {
			//実テーブル名生成
			String logicalTable = tableName + "_" + m_dcFmt.format(i);
			String tempTable = "temp_" + tableName + "_" + m_dcFmt.format(i);
			strUtil.reset(m_sqlResource.getString("alter.user.physicaltable"));
			strUtil.set(1, tempTable);
			strUtil.set(2, logicalTable);
			sqlList.add(strUtil.get());
		}
		
		//----------------------------
		///制約名の適用
		//----------------------------
		for (int i = 0; i < partCount; i++) {
			//実テーブル名生成
			String logicalTable = tableName + "_" + m_dcFmt.format(i);

			///制約名の変更
			for (int k = 0;k < conList.size(); k++) {
				String conName = ((ConData)conList.get(k)).getName();
				conName = conName.replaceAll(srcTableName.toLowerCase(), logicalTable.toLowerCase());
				((ConData)conList.get(k)).setName(conName);
				
				String description = ((ConData)conList.get(k)).getDesc();
				description = description.replaceAll(srcTableName.toLowerCase(), logicalTable.toLowerCase());
				((ConData)conList.get(k)).setDesc(description);
			}
				
			///制約名の適用
			for (int k = 0;k < conList.size();k++) {
				String sql = "select ret from postgresforest.AddaptConstraint(" + 
						"'" + ((ConData)conList.get(k)).getName() + "'::name, " + 
						((ConData)conList.get(k)).getCategory() + "::smallint, " + 
						((ConData)conList.get(k)).getAttNum() + "::smallint, " + 
						"'" + ((ConData)conList.get(k)).getCols() + "'::smallint[], " + 
						"'" + ((ConData)conList.get(k)).getDesc() + "'::text, " + 
						"'" + logicalTable.toLowerCase() + "'::name" + 
						") AS ret";
				sqlList.add(sql);
			}
			
			///制約名の変更
			for (int k = 0;k < conList.size(); k++) {
				String conName = ((ConData)conList.get(k)).getName();
				conName = conName.replaceAll(logicalTable.toLowerCase(), srcTableName.toLowerCase());
				((ConData)conList.get(k)).setName(conName);
				
				String description = ((ConData)conList.get(k)).getDesc();
				description = description.replaceAll(logicalTable.toLowerCase(), srcTableName.toLowerCase());
				((ConData)conList.get(k)).setDesc(description);
			}
		}
		
		//----------------------------
		// VIEW、RULEの作成
		//----------------------------
	
		//VIEW,RULE（UPDATE,DELETE）のSQL取得
		StringReplaceUtil createViewStrUtil =
			new StringReplaceUtil(m_sqlResource.getString("create.view"));
		createViewStrUtil.set(1, tableName);
	
		StringReplaceUtil createUpdateRuleStrUtil =
			new StringReplaceUtil(m_sqlResource.getString("create.rule.update"));
		createUpdateRuleStrUtil.set(1, tableName);
		createUpdateRuleStrUtil.set(2, tableName);
	
		StringReplaceUtil createDeleteRuleStrUtil =
			new StringReplaceUtil(m_sqlResource.getString("create.rule.delete"));
		createDeleteRuleStrUtil.set(1, tableName);
		createDeleteRuleStrUtil.set(2, tableName);
	
		//各SQLのパラメータをセットする。
		StringBuffer ruleSetColumn = new StringBuffer();
		StringBuffer ruleWhereColumn = new StringBuffer();
		for (Iterator iter = columnList.iterator(); iter.hasNext();) {
			ColumnInfo columnInfo = (ColumnInfo) iter.next();
			String columnName = columnInfo.getName();
			StringBuffer ruleSetWk = new StringBuffer();
			ruleSetWk.append(columnName);
			ruleSetWk.append(" = ");
			ruleSetWk.append("new.");
			ruleSetWk.append(columnName);
			if (ruleSetColumn.length() != 0) {
				ruleSetColumn.append(",");
			}
			ruleSetColumn.append(ruleSetWk);
		}
		
		//RULE用のSQL生成
		for (Iterator iter = primaryKeyList.iterator(); iter.hasNext();) {
			String primaryKey = (String) iter.next();
			StringBuffer ruleWhereWk = new StringBuffer();
			ruleWhereWk.append("(");
			ruleWhereWk.append(primaryKey);
			ruleWhereWk.append(" = ");
			ruleWhereWk.append("old.");
			ruleWhereWk.append(primaryKey);
			ruleWhereWk.append(" OR (");
			ruleWhereWk.append(primaryKey);
			ruleWhereWk.append(" IS NULL");
			ruleWhereWk.append(" AND ");
			ruleWhereWk.append("old.");
			ruleWhereWk.append(primaryKey);
			ruleWhereWk.append(" IS NULL");
			ruleWhereWk.append("))");
			if (ruleWhereColumn.length() != 0) {
				ruleWhereColumn.append(" AND ");
			}
			ruleWhereColumn.append(ruleWhereWk);
		}
		
		StringBuffer viewSelect = new StringBuffer();
		StringBuffer ruleUpdate = new StringBuffer();
		StringBuffer ruleDelate = new StringBuffer();
		for (int i = 0; i < partCount; i++) {
			String logicalTable = tableName + "_" + m_dcFmt.format(i);
			StringBuffer viewSelectWk = new StringBuffer();
			viewSelectWk.append("( SELECT  * FROM ");
			viewSelectWk.append(logicalTable);
			viewSelectWk.append(")");
			if (viewSelect.length() != 0) {
				viewSelect.append("UNION ALL");
			}
			viewSelect.append(viewSelectWk);
	
			ruleUpdate.append("UPDATE ");
			ruleUpdate.append(logicalTable);
			ruleUpdate.append(" SET ");
			ruleUpdate.append(ruleSetColumn);
			ruleUpdate.append(" WHERE ");
			ruleUpdate.append(ruleWhereColumn);
			ruleUpdate.append(";");
	
			ruleDelate.append("DELETE FROM ");
			ruleDelate.append(logicalTable);
			ruleDelate.append(" WHERE ");
			ruleDelate.append(ruleWhereColumn);
			ruleDelate.append(";");
	
		}
	
		//SQL用のパラメータをセットして、SQLリストに追加
		createViewStrUtil.set(2, viewSelect.toString());
		createUpdateRuleStrUtil.set(3, ruleUpdate.toString());
		createDeleteRuleStrUtil.set(3, ruleDelate.toString());
	
		sqlList.add(createViewStrUtil.get());
		sqlList.add(createUpdateRuleStrUtil.get());
		sqlList.add(createDeleteRuleStrUtil.get());
	
		//----------------------------
		// SQLの実行
		//----------------------------
		if (!execSql(sqlList)) {
			ret = false;
		}
		
		return ret;
	}

	/* (非 Javadoc)
	 * @see jp.co.nttdata.postgresforest.tool.action.DbBase#addUrl(java.lang.String, java.lang.String, java.lang.String)
	 */
	public void addUrl(String hostName, String portNo) {
		super.addUrl(hostName, portNo, m_dbName);
	}

	/**
	 * @return
	 */
	public String getDbName() {
		return m_dbName;
	}

	/**
	 * @param string
	 */
	public void setDbName(String string) {
		m_dbName = string;
	}
	
	/**
	 * 総レコード数取得
	 * 
	 * 指定されたテーブルの総レコード数を取得します
	 * 
	 * @param tableName	テーブル名
	 * @return	指定したテーブルの総レコード数
	 * @throws SQLException
	 * @since 2.0
	 */
	public long getRecordCount(String tableName) throws SQLException {
		long recordCount = 0;
		String connectUrl = "";

		Connection con = getSelectConnectoin();

		try {

			connectUrl = ((Jdbc3Connection) con).getURL();

			StringReplaceUtil strUtil =
				new StringReplaceUtil(m_sqlResource.getString("select.record.count"));
			strUtil.set(1, tableName);
			Statement ps = con.createStatement();
			ResultSet rs = ps.executeQuery(strUtil.get());
			
			while (rs.next()) {
				recordCount = rs.getLong("RECORD_COUNT");
			}
			rs.close();
			ps.close();

		} catch (SQLException e) {
			setErrInfo(connectUrl, e);
			throw e;
		}

		return recordCount;
	}

	/**
	 * ユーザーデータベースSQL実行
	 * 
	 * ユーザーデータベースにてSQLを実行する。
	 * 
	 * @param sqlList	インサート用SQLリスト
	 * @return	true:成功.false:失敗
	 * @since 2.0
	 */
	public boolean execSql(ArrayList sqlList) {
		boolean ret = true;
		String connectUrl = "";

		//----------------------------
		// SQLの実行
		//----------------------------
		//SQLリストに格納されたSQLを格納順に順次実行する。
		for (Iterator iter = m_Connection.iterator(); iter.hasNext();) {
			Connection con = (Connection) iter.next();
	
			try {
				connectUrl = ((Jdbc3Connection) con).getURL();
	
				Statement ps = con.createStatement();
	
				for (Iterator iterator = sqlList.iterator(); iterator.hasNext();) {
					String sql = (String) iterator.next();
					ps.execute(sql);
	
				}
				ps.close();
	
			} catch (SQLException e) {
				setErrInfo(connectUrl, e);
				ret = false;
			}
	
		}
		return ret;
	}
	
	/**
	 * リストア実行
	 * 
	 * ユーザーデータベースにてpg_restoreを実行する。
	 * 
	 * @param dumpList	ダンプデータリスト
	 * @return	true:成功.false:失敗
	 * @since 2.0
	 */
	public boolean execRestore(String dbName) {
		boolean ret = true;
		String connectUrl = "";
		
		//ユーザID、パスワードを取得
		String user = (String)m_prop.get("user");
		String password = (String)m_prop.get("password");
		
		//----------------------------
		// リストアの実行
		//----------------------------
		for (int i = 0; i < m_servers.size(); i++) {
			Connection con = (Connection) m_Connection.get(i);
			UrlInfo urlInfo = (UrlInfo) m_servers.get(i);
			String dumpData = (String )m_dumpList.get(i);
			try {
				connectUrl = ((Jdbc3Connection) con).getURL();
	
				PreparedStatement smt =
					con.prepareStatement(
						m_sqlResource.getString("select.restore.setuser"));
				smt.setString(1, user);
				smt.setString(2, password);
				smt.execute();
				smt.close();
				
				smt = con.prepareStatement(
					m_sqlResource.getString("select.restore.exec"));
				smt.setString(1, urlInfo.getPortNo());
				smt.setString(2, dbName);
				smt.setString(3, dumpData);
				ResultSet rs = smt.executeQuery();
				while (rs.next()) {
					String retString = rs.getString("ret");
					if (retString.compareTo("") != 0) { 
						Exception e = new Exception(retString);
						setErrInfo(connectUrl, e);
						ret = false;
					}
				}
				rs.close();
				smt.close();
	
			} catch (SQLException e) {
				setErrInfo(connectUrl, e);
				ret = false;
			}
		}
		
		return ret;
	}
	
	/**
	 * ダンプデータ設定。
	 * ダンプデータをダンプデータリストに追加する
	 * @param dumpData　ダンプデータ
	 * @since 2.0
	 */
	public void addDumpData(String dumpData) {
		m_dumpList.add(dumpData);
	}
	
	/**
	 * テーブル名の一覧取得
	 * 
	 * テーブル名の一覧を取得する。
	 * 各接続ごとに、キー、値ともに、テーブル名のHashMapを生成し、
	 * リストに格納して返す
	 * 
	 * @return　テーブル名の一覧
	 * @since 2.0
	 */
	public ArrayList getTableList(){

		ArrayList tableList = new ArrayList();
		String connectUrl = "";
		
		Connection con = getSelectConnectoin();

		try{
			connectUrl = ((Jdbc3Connection) con).getURL();

			PreparedStatement smt =
				con.prepareStatement(
					m_sqlResource.getString("select.table.list"));
			ResultSet rs = smt.executeQuery();
			while (rs.next()) {
				String tableName = rs.getString("NAME");
				//HashMapに登録
				tableList.add(tableName);
			}
			rs.close();
			smt.close();

		} catch (SQLException e) {
			
		}
		
		return tableList;
	}
	
	/**
	 * プライマリキーのカラム名を取得
	 * 
	 * <pre>
	 * メタデータからプライマリキーの情報を取得し、
	 * プライマリキーのカラム名リストを取得する。
	 * </pre>
	 * 
	 * @param tableName テーブル名
	 * @return ArrayList PrimaryKeyのカラム名リスト
	 * @since 2.0
	 */
	private ArrayList getPrimaryKey(Connection con, String tableName) {
		String connectUrl = "";
		
		ArrayList primaryList = new ArrayList();
		
		//--------------
		///PRIMARY KEY
		//--------------
		try {
			connectUrl = ((Jdbc3Connection) con).getURL();

			//メタデータからプライマリキーの情報を取得する		

			DatabaseMetaData databaseMetaData = con.getMetaData();
			ResultSet rsmeta =
				databaseMetaData.getPrimaryKeys(
					null,
					"public",
					tableName.toLowerCase());

			while (rsmeta.next()) {
				//PrimaryKeyのカラム名を取得
				String primartKey = rsmeta.getString("COLUMN_NAME");
			
				//カラム名のリストに追加
				primaryList.add(primartKey);
			}
			rsmeta.close();

		} catch (SQLException e) {
			
		}
	
		return primaryList;
	}
	/**
	 * プライマリキーのカラム名を取得
	 * 
	 * <pre>
	 * メタデータからプライマリキーの情報を取得し、
	 * プライマリキーのカラム名リストを取得する。
	 * </pre>
	 * 
	 * @param tableName テーブル名
	 * @return ArrayList PrimaryKeyのカラム名リスト
	 * @since 2.0
	 */
	public ArrayList getPrimaryKey(String tableName) {
	
		return getPrimaryKey(getSelectConnectoin(), tableName);
	}

    /**
     * DB名の取得
     * @return エラーになった接続
     */
    public ArrayList checkTable(String name, String type) {
    
    	ArrayList errConnectionList = new ArrayList();
    	String[] types = { type };
    
    	for (Iterator iter = m_Connection.iterator(); iter.hasNext();) {
    
    		Connection con = (Connection) iter.next();
    		int objIndex = m_Connection.indexOf(con);
    		try {
    
    			DatabaseMetaData dataMeta = con.getMetaData();
    
    			ResultSet rs =
    				dataMeta.getTables(
    					m_dbName,
    					"public",
    					name.toLowerCase(),
    					types);
    			if (!rs.next()) {
    				errConnectionList.add( getURL(objIndex));
    			}
    
    		} catch (SQLException e) {
    			errConnectionList.add(getURL(objIndex));
    		}
    
    	}
    	return errConnectionList;
    
    }

}
