package org.postgresforest.tool.lib;

import java.sql.*;
import java.util.ArrayList;

import org.postgresforest.tool.ArrayUtil;
import org.postgresforest.tool.Logger;
import org.postgresforest.vm.Hash_I;

public class PartitionUtils {
	public static String buildPartitionName(String relname, int part)
	{
		return partName(relname, part);
	}

	private static String partSuffix(int part)
	{
		return "_" + ( part<10 ? "0" : "" ) + part;
	}

	private static String partName(String relname, int part)
	{
		return relname + partSuffix(part);
	}

	/**
	 * 検索用のUNION ALL VIEWの定義用DDL文を作成する。
	 * 現在パーティション１のみ対応。
	 *
	 * @param partCount パーティション数
	 * @param relname テーブル名（論理名）
	 *
	 * @return String DDL文文字列（CREATE VIEW文）
	 */
	public static String buildUnionAllViewDef(int partCount, String relname)
	{
		int[] partNum = new int[partCount];
		for (int i=0 ; i<partCount ; i++)
			partNum[i] = i;

		return buildUnionAllViewDef(partNum, relname);
	}

	/**
	 * 検索用のUNION ALL VIEWの定義用DDL文を作成する。
	 * 指定した番号のパーティションをUNION ALLするVIEW定義を生成する。
	 *
	 * @param partNum パーティション番号の配列
	 * @param relname テーブル名（論理名）
	 *
	 * @return String DDL文文字列（CREATE VIEW文）
	 */
	public static String buildUnionAllViewDef(int[] partNum, String relname)
	{
		String def = "CREATE VIEW " + relname + " AS (\n";

		for (int i=0 ; i<partNum.length ; i++)
		{
			if ( i>0 )
				def = def + "    UNION ALL\n";

			def = def + "  ( SELECT * FROM " + partName(relname,partNum[i]) + " )\n";
		}

		def = def + ");\n";

		return def;
	}

	/**
	 * パーティションテーブルに対するUPDATE文書き換え用のRULE定義用DDL文を作成する。
	 * 現在パーティション１のみ対応。
	 *
	 * @param partCount パーティション数
	 * @param relname テーブル名（論理名）
	 * @param pkeys 主キー配列
	 * @param cols 属性名配列
	 *
	 * @return String DDL文文字列（CREATE RULE文）
	 */
	public static String buildUpdateRuleDef(int partCount,
											String relname,
											String[] pkeys,
											String[] cols)
	{
		String def = "";

		/*
		 * CREATE RULE ?_upd AS ON UPDATE TO ? DO INSTEAD ( UPDATE ...; UPDATE ... )
		 */
		def = def + "CREATE RULE " + relname + "_upd AS ON UPDATE TO " + relname + " DO INSTEAD (\n";

		for (int i=0 ; i<partCount ; i++)
		{
			def = def + "    UPDATE " + partName(relname,i) + " SET " + buildSetClauseForRule(cols);
			def = def + " WHERE " + buildWhereClauseForRule(relname, pkeys, i) + ";\n";
		}
		def = def + ");\n";

		return def;
	}

	public static String buildUpdateRuleDef(int[] partNum,
											String relname,
											String[] pkeys,
											String[] cols)
	{
		String def = "";

		/*
		 * CREATE RULE ?_upd AS ON UPDATE TO ? DO INSTEAD ( UPDATE ...; UPDATE ... )
		 */
		def = def + "CREATE RULE " + relname + "_upd AS ON UPDATE TO " + relname + " DO INSTEAD (\n";

		for (int i=0 ; i<partNum.length ; i++)
		{
			def = def + "    UPDATE " + partName(relname,partNum[i]) + " SET " + buildSetClauseForRule(cols);
			def = def + " WHERE " + buildWhereClauseForRule(relname, pkeys, i) + ";\n";
		}
		def = def + ");\n";

		return def;
	}

	/**
	 * パーティションテーブルに対するDELETE文書き換え用のRULE定義用DDL文を作成する。
	 * 現在パーティション１のみ対応。
	 *
	 * @param partCount パーティション数
	 * @param relname テーブル名（論理名）
	 * @param pkeys 主キー配列
	 *
	 * @return String DDL文文字列（CREATE RULE文）
	 */
    public static String buildDeleteRuleDef(int partCount,
											String relname,
											String[] pkeys)
    {
		String def = "";

		/*
		 * CREATE RULE ?_del AS ON DELETE TO ? DO INSTEAD(?)
		 */
		def = def + "CREATE RULE " + relname + "_del AS ON DELETE TO " + relname + " DO INSTEAD (\n";

		for (int i=0 ; i<partCount ; i++)
		{
			def = def + "    DELETE FROM " + partName(relname,i);
			def = def + " WHERE " + buildWhereClauseForRule(relname, pkeys, i) + ";\n";
		}
		def = def + ");\n";

		return def;
    }

    public static String buildDeleteRuleDef(int[] partNum,
											String relname,
											String[] pkeys)
    {
		String def = "";

		/*
		 * CREATE RULE ?_del AS ON DELETE TO ? DO INSTEAD(?)
		 */
		def = def + "CREATE RULE " + relname + "_del AS ON DELETE TO " + relname + " DO INSTEAD (\n";

		for (int i=0 ; i<partNum.length ; i++)
		{
			def = def + "    DELETE FROM " + partName(relname,partNum[i]);
			def = def + " WHERE " + buildWhereClauseForRule(relname, pkeys, i) + ";\n";
		}
		def = def + ");\n";

		return def;
    }

	/**
	 * パーティション作成用DDLを生成する
	 *
	 * @param partCount パーティション数
	 * @param relname パーティション化対象のテーブル名
	 *
	 * @return String パーティション作成用DDL文（CREATE TABLE ... ( LIKE ... )文）
	 */
	public static String buildPartitionDefs(int partCount,
											String relname,
											String[] partKeys,
											String hashName)
	{
		String def = "";

		for (int i=0 ; i<partCount ; i++)
		{
			def = def + "CREATE TABLE " + partName(relname,i) + " AS SELECT * FROM " + relname;
			if ( partKeys.length<=2 )
			{
				/*
				 * FIXME: default hash name
				 */
				if ( hashName==null || hashName.equals("null") )
					hashName = "org.postgresforest.vm.Hash01";

				def = def + " WHERE postgresforest.getpartnum('" + hashName + "'," + partCount + ",";

				if ( partKeys.length==1 )
					def = def + partKeys[0];
				else if ( partKeys.length==2 )
					def = def + partKeys[0] + "," + partKeys[1];

				def = def + ") = " + i + ";\n";
			}
			else
			{
				def = def + " LIMIT 0;\n";
			}
		}

		return def;
	}

	private static String buildSetClauseForRule(String[] cols)
	{
		String def = "";

		/*
		 * 'col1=NEW.col1,col2=NEW.col2,...'
		 */
		for (int i=0 ; i<cols.length ; i++)
		{
			if ( i>0 )
				def = def + ",";

			def = def + cols[i] + "=NEW." + cols[i];
		}

		return def;
	}

	private static String buildWhereClauseForRule(String relname, String[] pkeys, int part)
	{
		String buf = "";

		/*
		 * '( pk=OLD.pk OR ( pk IS NULL AND OLD.pk IS NULL ) )'
		 */
		for (int i=0 ; i<pkeys.length ; i++)
		{
			if ( 0<i )
				buf = buf + " AND ";

			String pkey = pkeys[i];

			buf = buf + "(" + pkey + "=OLD." + pkey + " OR ( " + pkey + " IS NULL AND OLD." + pkey + " IS NULL ) )";
		}

		return buf;
	}

	/**
	 * 多重化テーブルに作成されていたインデックス定義の情報を元に、
	 * パーティションテーブル用のインデックス定義用DDLを生成する。
	 *
	 * @param partCount パーティション数
	 * @param relname パーティション化するテーブル名
	 * @param indexDefs （多重化テーブル時の）インデックス定義用DDLの配列
	 *
	 * @return String[] パーティションテーブル用インデックス定義DDLの配列（インデックス数xパーティション数）
	 */
	public static String[] buildIndexDefs(int partCount, String relname, String[] indexDefs)
	{
		ArrayList a = new ArrayList();

		for (int j=0 ; j<partCount ; j++)
		{
			for (int i=0 ; i<indexDefs.length ; i++)
			{
				SqlTokenizer t = new SqlTokenizer(indexDefs[i]);
				String indexDef = "";
				boolean  indexName = false;
				
				while ( t.hasMoreToken() )
				{
					String token = t.nextToken();

					if ( token.equalsIgnoreCase(relname) )
					{
						indexDef = indexDef + partName(token, j);
					}
					else if ( indexName && t.ttype!=SqlTokenizer.TT_SPACE )
					{
						indexDef = indexDef + token + partSuffix(j);
						indexName = false;
					}
					else
					{
						indexDef = indexDef + token;
					}

					Logger.debug("buildIndexDefs: token=" + token + ",type=" + t.ttype);

					if ( token.equalsIgnoreCase("INDEX") )
						indexName = true;
				}

				a.add(indexDef);
				Logger.debug("buildIndexDefs: " + indexDef);
			}
		}

		return ArrayUtil.array2stringarray(a);
	}

	/**
	 * 多重化テーブルに作成されていた制約の定義の情報を元に、
	 * パーティションテーブル用の制約定義用DDLを生成する。
	 *
	 * @param partCount パーティション数
	 * @param relname パーティション化するテーブル名
	 * @param indexDefs （多重化テーブル時の）制約定義用DDLの配列
	 *
	 * @return String[] パーティションテーブル用制約定義DDLの配列（制約数xパーティション数）
	 */
	public static String[] buildConstraintDefs(int partCount, String relname, String[] conDefs)
	{
		ArrayList a = new ArrayList();

		relname = TableUtils.getSchemaName(relname) + "." + TableUtils.getTableName(relname);

		for (int j=0 ; j<partCount ; j++)
		{
			for (int i=0 ; i<conDefs.length ; i++)
			{
				SqlTokenizer t = new SqlTokenizer(conDefs[i]);
				String conDef = "";
				boolean conname = false;

				while ( t.hasMoreToken() )
				{
					String token = t.nextToken();

					if ( token.equalsIgnoreCase(relname) )
					{
						conDef = conDef + partName(token, j);
					}
					else if ( t.ttype!=SqlTokenizer.TT_SPACE && conname==true )
					{
						conDef = conDef + token + partSuffix(j);
						conname = false;
					}
					else
					{
						conDef = conDef + token;
					}

					if ( token.equalsIgnoreCase("CONSTRAINT") )
						conname = true;
				}

				a.add(conDef);
				Logger.debug("buildConstraintDefs: " + conDef);
			}
		}

		return ArrayUtil.array2stringarray(a);
	}

	/**
	 * ALTER TABLE/INDEX文をパーティション対応に書き換える。
	 *
	 * @param relname テーブル名
	 * @param partCount パーティション数
	 * @param partNum 対象となるパーティション番号の配列
	 * @param sql ALTER文
	 *
	 * @return String[] パーティション用に書き換えられたSQL文（複数可）
	 */
	public static String[] rewriteAlter(String relname, int partCount, int[] partNum, String sql)
	{
		SqlTokenizer t = new SqlTokenizer(sql);
		String token = null;

		/*
		 * ATLER文かどうかをチェック
		 */
		boolean isAlter = false;

		while ( t.hasMoreToken() )
		{
			token = t.nextToken();
			if ( t.ttype==SqlTokenizer.TT_WORD )
			{
				if ( token.equalsIgnoreCase("alter") )
					isAlter = true;
				break;
			}
		}
		if ( !isAlter )
			return null;

		/*
		 * ALTER TABLE/INDEXを判別
		 */
		boolean isAlterTable = false;
		boolean isAlterIndex = false;

		while ( t.hasMoreToken() )
		{
			token = t.nextToken();
			if ( t.ttype==SqlTokenizer.TT_WORD )
			{
				if ( token.equalsIgnoreCase("table") )
					isAlterTable = true;
				else if ( token.equalsIgnoreCase("index") )
					isAlterIndex = true;

				break;
			}
		}

		if ( isAlterTable )
			return rewriteAlterTable(relname, partCount, partNum, sql);
		else if ( isAlterIndex )
			return rewriteAlterIndex(relname, partCount, partNum, sql);

		return null;
	}

	private static String[] rewriteAlterIndex(String relname, int partCount, int[] partNum, String sql)
	{
		/*
		 * FIXME:
		 * 行末に ';' が無いと、SqlTokenizerがステートメントの終端を
		 * 判断できないため。
		 */
		SqlTokenizer t = new SqlTokenizer(sql + ";");

		String indexName = null;
		String newName = null;
		boolean isRename = false;
		int word = 0;
		String newSql = "";

		Logger.debug("rewriteAlterIndex: " + sql);

		/*
		 * まず、'ALTER INDEX indname ...' というSQL文を、
		 * 'ALTER INDEX indname_?? ...' と書き換える。
		 *
		 * その後、'_??' の部分をパーティションごとに書き換える。
		 */
		while ( t.hasMoreToken() )
		{
			String token = t.nextToken();

			if ( t.ttype==SqlTokenizer.TT_WORD )
			{
				word++;

				Logger.debug("rewriteAlterIndex: " + word + ",token=" + token + ",type=" + t.ttype);

				if ( word==3 )
				{
					indexName = token;

					newSql = newSql + indexName + "_??";
				}
				else if ( word==4 && token.equalsIgnoreCase("rename") )
				{
					isRename = true;
					newSql = newSql + token;

					Logger.debug("rewriteAlterIndex: rename command detected.");
				}
				else if ( word==6 && isRename )
				{
					newName = token;

					newSql = newSql + newName + "_??";

					Logger.debug("rewriteAlterIndex: newName=" + newName);
				}
				else
				{
					newSql = newSql + token;
				}
			}
			else
			{
				newSql = newSql + token;
			}

			//			Logger.debug("" + word + ": " + token + ", " + t.ttype);
		}

		Logger.debug("rewriteAlterIndex: word=" + word);
		Logger.debug("rewriteAlterIndex: " + sql + " -> " + newSql);

		/*
		 * リライトされたSQLの '_??' に実際のパーティション番号を入れる
		 */
		ArrayList a = new ArrayList();

		for (int i=0 ; i<partNum.length ; i++)
		{
			String tmpSql = newSql.replaceAll(indexName + "_\\?\\?", indexName + partSuffix(partNum[i]));

			if ( isRename )
				tmpSql = tmpSql.replaceAll(newName + "_\\?\\?", newName + partSuffix(partNum[i]));

			//			Logger.debug("   : " + tmpSql);

			a.add(tmpSql);
		}

		return ArrayUtil.array2stringarray(a);
	}

	/*
	 * ALTER TABLE文をパーティションに対応して書き換える。
	 */
	private static String[] rewriteAlterTable(String relname, int partCount, int[] partNum, String sql)
	{
		SqlTokenizer t = new SqlTokenizer(sql);
		String newSql = "";

		String relName = null;
		String newName = null; // ALTER TABLE ta RENAME TO newName;
		String indName = null; // ALTER TABLE ta CLUSTER ON indName;
		int word = 0;

		boolean isRename  = false;
		boolean isCluster = false;
		boolean withOnly = false;

		while ( t.hasMoreToken() )
		{
			String token = t.nextToken();

			if ( t.ttype==SqlTokenizer.TT_WORD )
			{
				word++;

				if ( word==3 && token.equalsIgnoreCase("only") )
				{
					withOnly = true;
					word--;
				}
				else if ( word==3 )
				{
					relName = token;
					newSql = newSql + relName + "_??";
				}
				else if ( word==4 && token.equalsIgnoreCase("rename") )
				{
					isRename = true;
					newSql = newSql + token;
				}
				else if ( word==4 && token.equalsIgnoreCase("cluster") )
				{
					isCluster = true;
					newSql = newSql + token;
				}
				else if ( word==6 && isRename )
				{
					newName = token;
					newSql = newSql + token + "_??";
				}
				else if ( word==6 && isCluster )
				{
					indName = token;
					newSql = newSql + token + "_??";
				}
				else
				{
					newSql = newSql + token;
				}
			}
			else
			{
				newSql = newSql + token;
			}

			//			Logger.debug("" + word + ": " + token + ", " + t.ttype);
		}
		
		Logger.debug("rewriteAlterTable: " + sql + " -> " + newSql);

		/*
		 * リライトされたSQLの '_??' に実際のパーティション番号を入れる
		 */
		ArrayList a = new ArrayList();

		/*
		 * VIEW名も変更する
		 */
		if ( isRename )
		{
			a.add("-- rename to " + newName + ";");
			a.add("ALTER TABLE " + relname + " RENAME TO " + newName + ";");
		}

		for (int i=0 ; i<partNum.length ; i++)
		{
			String tmpSql = newSql.replaceFirst(relName + "_\\?\\?", relName + partSuffix(partNum[i]));

			if ( isRename )
				tmpSql = tmpSql.replaceFirst(newName + "_\\?\\?", newName + partSuffix(partNum[i]));
			if ( isCluster )
				tmpSql = tmpSql.replaceFirst(indName + "_\\?\\?", indName + partSuffix(partNum[i]));

			Logger.debug("   : " + tmpSql);

			a.add(tmpSql);
		}

		return ArrayUtil.array2stringarray(a);
	}




	/* ----------------------------------------------------------------------------
	 * 以下、PL/Javaから呼び出す関数
	 * ----------------------------------------------------------------------------
	 */

	/**
	 * パーティションキーにできる型かどうかを確認する
	 *
	 * @return boolean パーティション化のキーにできる型のオブジェクトならtrue
	 */
	private static boolean _checkType(Object o)
	{
		if ( o instanceof Integer ||
			 o instanceof String ||
			 o instanceof java.sql.Date ||
			 o instanceof java.sql.Time ||
			 o instanceof java.sql.Timestamp )
			return true;

		return false;
	}

	/**
	 * 指定したクラス名のパーティション化関数をインスタンス化して取得する。
	 *
	 * @param hashName パーティション化関数のクラス名
	 *
	 * @return Hash_I パーティション化関数のHash_Iオブジェクト
	 */
	private static Hash_I _getHash(String hashName)
	{
		Hash_I h = null;

		try {
			h = (Hash_I)Class.forName(hashName).newInstance();
		}
		catch (Exception e) {
			System.out.println(e.getMessage());
		}
		return h;
	}

	public static void _append(Hash_I h, Object o)
	{
		if ( o instanceof Integer )
			h.addCol( ((Integer)o).intValue() );
		else
			h.addCol(o.toString());
	}

	public static Hash_I _init(String hashName, Integer partCount)
	{
		Hash_I h = _getHash(hashName);

		if ( h==null )
			return null;

		h.setPartNum(partCount.intValue());
		h.clearCol();

		return h;
	}

	public static Integer _getpartnum(String hashName, Integer partCount, Object col1)
	{
		Hash_I h = _init(hashName, partCount);
			
		if ( _checkType(col1) )
			_append(h, col1);
		else
			return null;

		return new Integer(h.getNodeNo());
	}

	public static Integer _getpartnum(String hashName, Integer partCount, Object col1, Object col2)
	{
		Hash_I h = _init(hashName, partCount);
			
		if ( _checkType(col1) &&
			 _checkType(col2) )
		{
			_append(h, col1);
			_append(h, col2);
		}
		else
			return null;

		return new Integer(h.getNodeNo());
	}

	/* ----------------------------------------------------------------------------
	 * 以下、PL/Javaから呼び出すインターフェース
	 * ----------------------------------------------------------------------------
	 */

	/* ----------------------------------------------------------------------------
	 * パーティションキーのカラムが1つの場合
	 * ----------------------------------------------------------------------------
	 */
	public static Integer getpartnum(String hashName, Integer partCount, Integer col1)
	{
		return _getpartnum(hashName, partCount, col1);
	}

	public static Integer getpartnum(String hashName, Integer partCount, String col1)
	{
		return _getpartnum(hashName, partCount, col1);
	}

	public static Integer getpartnum(String hashName, Integer partCount, java.sql.Date col1)
	{
		return _getpartnum(hashName, partCount, col1);
	}

	public static Integer getpartnum(String hashName, Integer partCount, java.sql.Time col1)
	{
		return _getpartnum(hashName, partCount, col1);
	}

	public static Integer getpartnum(String hashName, Integer partCount, java.sql.Timestamp col1)
	{
		return _getpartnum(hashName, partCount, col1);
	}

	/* ----------------------------------------------------------------------------
	 * パーティションキーのカラムが2つの場合
	 * ----------------------------------------------------------------------------
	 */

	/*
	 * Integer, [ Integer | String | Date | Time | Timestamp ]
	 */
	public static Integer getpartnum(String hashName, Integer partCount, Integer col1, Integer col2)
	{
		return _getpartnum(hashName, partCount, col1, col2);
	}

	public static Integer getpartnum(String hashName, Integer partCount, Integer col1, String col2)
	{
		return _getpartnum(hashName, partCount, col1, col2);
	}

	public static Integer getpartnum(String hashName, Integer partCount, Integer col1, java.sql.Date col2)
	{
		return _getpartnum(hashName, partCount, col1, col2);
	}

	public static Integer getpartnum(String hashName, Integer partCount, Integer col1, java.sql.Time col2)
	{
		return _getpartnum(hashName, partCount, col1, col2);
	}

	public static Integer getpartnum(String hashName, Integer partCount, Integer col1, java.sql.Timestamp col2)
	{
		return _getpartnum(hashName, partCount, col1, col2);
	}

	/*
	 * String, [ Integer | String | Date | Time | Timestamp ]
	 */
	public static Integer getpartnum(String hashName, Integer partCount, String col1, Integer col2)
	{
		return _getpartnum(hashName, partCount, col1, col2);
	}

	public static Integer getpartnum(String hashName, Integer partCount, String col1, String col2)
	{
		return _getpartnum(hashName, partCount, col1, col2);
	}

	public static Integer getpartnum(String hashName, Integer partCount, String col1, java.sql.Date col2)
	{
		return _getpartnum(hashName, partCount, col1, col2);
	}

	public static Integer getpartnum(String hashName, Integer partCount, String col1, java.sql.Time col2)
	{
		return _getpartnum(hashName, partCount, col1, col2);
	}

	public static Integer getpartnum(String hashName, Integer partCount, String col1, java.sql.Timestamp col2)
	{
		return _getpartnum(hashName, partCount, col1, col2);
	}

	/*
	 * Date, [ Integer | String | Date | Time | Timestamp ]
	 */
	public static Integer getpartnum(String hashName, Integer partCount, Date col1, Integer col2)
	{
		return _getpartnum(hashName, partCount, col1, col2);
	}

	public static Integer getpartnum(String hashName, Integer partCount, Date col1, String col2)
	{
		return _getpartnum(hashName, partCount, col1, col2);
	}

	public static Integer getpartnum(String hashName, Integer partCount, Date col1, java.sql.Date col2)
	{
		return _getpartnum(hashName, partCount, col1, col2);
	}

	public static Integer getpartnum(String hashName, Integer partCount, Date col1, java.sql.Time col2)
	{
		return _getpartnum(hashName, partCount, col1, col2);
	}

	public static Integer getpartnum(String hashName, Integer partCount, Date col1, java.sql.Timestamp col2)
	{
		return _getpartnum(hashName, partCount, col1, col2);
	}

	/*
	 * Time, [ Integer | String | Date | Time | Timestamp ]
	 */
	public static Integer getpartnum(String hashName, Integer partCount, java.sql.Time col1, Integer col2)
	{
		return _getpartnum(hashName, partCount, col1, col2);
	}

	public static Integer getpartnum(String hashName, Integer partCount, java.sql.Time col1, String col2)
	{
		return _getpartnum(hashName, partCount, col1, col2);
	}

	public static Integer getpartnum(String hashName, Integer partCount, java.sql.Time col1, java.sql.Date col2)
	{
		return _getpartnum(hashName, partCount, col1, col2);
	}

	public static Integer getpartnum(String hashName, Integer partCount, java.sql.Time col1, java.sql.Time col2)
	{
		return _getpartnum(hashName, partCount, col1, col2);
	}

	public static Integer getpartnum(String hashName, Integer partCount, java.sql.Time col1, java.sql.Timestamp col2)
	{
		return _getpartnum(hashName, partCount, col1, col2);
	}

	/*
	 * Timestamp, [ Integer | String | Date | Time | Timestamp ]
	 */
	public static Integer getpartnum(String hashName, Integer partCount, java.sql.Timestamp col1, Integer col2)
	{
		return _getpartnum(hashName, partCount, col1, col2);
	}

	public static Integer getpartnum(String hashName, Integer partCount, java.sql.Timestamp col1, String col2)
	{
		return _getpartnum(hashName, partCount, col1, col2);
	}

	public static Integer getpartnum(String hashName, Integer partCount, java.sql.Timestamp col1, java.sql.Date col2)
	{
		return _getpartnum(hashName, partCount, col1, col2);
	}

	public static Integer getpartnum(String hashName, Integer partCount, java.sql.Timestamp col1, java.sql.Time col2)
	{
		return _getpartnum(hashName, partCount, col1, col2);
	}

	public static Integer getpartnum(String hashName, Integer partCount, java.sql.Timestamp col1, java.sql.Timestamp col2)
	{
		return _getpartnum(hashName, partCount, col1, col2);
	}
}
