#include "Database.h"
#include "Logger.h"
#include "rcdu.h"
#include "syncmanager.h"

#define		MAX_ROWS	1000000

void toLowerCaseSTD(std::string &str)
{
	transform(str.begin(), str.end(), str.begin(), (int(*)(int))tolower);
}

string StringReplace(const string& source, const string search, const string replacement)
{
	string r = source;

	string::size_type pos = 0;

	while ( (pos = r.find(search, pos)) != string::npos ) 
	{
		r.replace( pos, search.size(), replacement );
		pos = pos + replacement.size();		
	}

	return r;
}

CSyncManager::CSyncManager() 
	: m_tblmode(-1)
{

}

CSyncManager::~CSyncManager()
{

}

bool CSyncManager::sync( DataBase &db, RCUDINFOLIST &infolist )
{
	RCUDINFOLIST::iterator i;

	// 2014.06.07 dadamin
	// 형상(9.3) 변경으로 테이블 형태 체크
	if( m_tblmode < 0 && targettblmode(db) == false )
	{
		LOG(LERR, "Unknown table mode.");
		return false;
	}

	_LOG(LINF,"RCDB : %s Type.", m_tblmode == 1 ? "NEW" : "OLD");

	for (i = infolist.begin(); i != infolist.end(); ++i )
	{
#ifdef _DEBUG
		cout << "sync - " << (*i).getInfoService() << "," << (*i).getInfoCaldepth() << endl;
#endif //_DEBUG
		 SYNCDATAMAP data;
		 		
		if((*i).getInfoCaldepth() == 0)
		{
			// sync directory
			if( deloverdepth(db, (*i).getInfoUserseq(), (*i).getInfoTranid(), (*i).getInfoCaldepth() ) == false )
				break;
			if( insertroot( db, (*i).getInfoUserseq(), (*i).getInfoTranid()) == false )
				break;

			// get sync data
			if( getrootsum( db, (*i).getInfoUserseq(), (*i).getInfoTranid(), data ) != 0 )
				break;
		}
		else
		{
			// sync directory
			if( deloverdepth( db, (*i).getInfoUserseq(), (*i).getInfoTranid(), (*i).getInfoCaldepth() ) == false )
				break;
			if( deldeleteddir( db, (*i).getInfoUserseq(), (*i).getInfoTranid(), (*i).getInfoCaldepth() ) == false )
				break;
			if( delnotfouddir( db, (*i).getInfoUserseq(), (*i).getInfoTranid(), (*i).getInfoCaldepth() ) == false )
				break;
			if( insertdir( db, (*i).getInfoUserseq(), (*i).getInfoTranid(), (*i).getInfoCaldepth() ) == false )
				break;

			// get sync data
			if( getdepthsum( db, (*i).getInfoUserseq(), (*i).getInfoTranid(), (*i).getInfoCaldepth(), data ) != 0 )
				break;
		}

		// sync data
		if( syndata(db, data)  == false )
			break;	
	}

	return true;
}

int	CSyncManager::savedata( int64_t userseq, int64_t tranid,  int caldepth, int depth, const char *uri, int64_t length, SYNCDATAMAP &data )
{
	int loop = depth;
	if( depth > caldepth )
		loop = caldepth;
	else if ( depth < 0 )
		loop = 0;

	string path = uri;

	size_t found = 1;
	for ( int i = 0; i <= loop; ++i )
	{
		found = path.find("/", found );
		string s;
		if( found != string::npos ) 
		{
			s = path.substr(0, found);
			found += 1;
		} 
		else
		{
			s = path;
		}

		SYNCDATAMAP::iterator f;

		f = data.find(s);
		if (f != data.end()) 
		{
#ifdef _DEBUG
			cout << "savedata find  : " << i  << "," << s << "," << length << endl;
#endif // _DEBUG
			f->second.addused(length);								
		}
		else 
		{
#ifdef _DEBUG
			cout << "savedata : " << i  << "," << s << "," << length << endl;
#endif // _DEBUG

			CSyncData v;
			v.setUserseq(userseq);
			v.setTranid(tranid);
			v.setdepth(i);
			v.setpath(s.c_str());
			v.addused(length);
			data[s] = v;
		}
	}

	return 0;
}

int CSyncManager::getrootsum( DataBase &db, int64_t userseq, int64_t tranid, SYNCDATAMAP &data )
{
	int r = 0;
	ostringstream sql,t;
	
	t << tranid;
	string strtranid = t.str();
	const char *paramValues[1];

	paramValues[0] = strtranid.c_str();
#ifdef _DEBUG
	cout << "Sum Root Data : " << userseq  << "," << paramValues[0] << endl;
#endif //_DEBUG
		
	string tblname = gettablename(tranid);
	sql << "SELECT SUM(get_content_length) FROM " ;
	sql	<< tblname << " ";
	sql	<< "WHERE sp_svc_tran_id = $1 AND deleted_yn = 'N' AND is_cache = 'N'";
	
#ifdef _DEBUG
	cout << "sum SQL - " << sql.str() << endl;
#endif // _DEBUG

	db.PgDoExecParams(const_cast<char *> (sql.str().c_str()), 1, paramValues);

	if(db.PgResult(DataBase::NOT_CLEAR) < 0)
	{
		LOG(LERR, "Database Error.[%s]", db.GetErrorMessage().c_str());
		return r;
	}

	int64_t sum = 0;
	if(db.GetNoTuples() > 0)
	{
		sum = atoll(db.GetValue(0,0));
	}

	string s = "/" + t.str();
	savedata( userseq, tranid, 0, 0, s.c_str(), sum, data );
	
	db.PgClear();

	return r;
}

int CSyncManager::getsyncdata( DataBase &db, int64_t userseq, int64_t tranid, int caldepth, SYNCDATAMAP &data )
{
#ifdef _DEBUG
	cout << "Sum Total Data : " << userseq  << "," << tranid << "," << caldepth << endl;
#endif //_DEBUG
	string tblname = gettablename(tranid);

	ostringstream sql;	
	sql << "SELECT depth, uri, get_content_length, resource_type FROM "
		<< tblname
		// 2011.07.03 : BD-13와 같이 여러개의 서비스 중인 RC 경우 MAX depth 구할 시 DB 부하가 많이 발생함
		//				이에 따라 통상 depth 500이상 경우 없기 때문에 1000으로 고정시켜 DB 부하를 줄였음
		<< " WHERE depth >= 0 and depth <= 1000 AND uri LIKE $1 ||'%' AND "
		<< "deleted_yn = 'N' AND is_cache = 'N' "
		// 2011.06.30 : LIMIT...OFFSET 사용 시 order by 없을 중복 및 누락 발생할 수 있음(이는 PosgtreSQL 매뉴얼에 나와 있음)
		<< "ORDER BY resource_id "
		<< "LIMIT " << MAX_ROWS << " OFFSET $2";

	int r = 0;
	int64_t offset = 0;
	ostringstream t;

	t  << "/" << tranid;
	string m = t.str();
	while ( true ) 
	{
		int rows = 0;
		t.str("");
		t  <<  offset;

		const char *paramValues[2];
		paramValues[0] = m.c_str();
		paramValues[1] = t.str().c_str();
#ifdef _DEBUG
		cout << "sumdata SQL - " << sql.str() << endl;
		cout << "paramValues - " <<  paramValues[0] << "," << paramValues[1]  << endl;
#endif // _DEBUG

		db.PgDoExecParams( const_cast<char *> (sql.str().c_str()), 2 , paramValues);

		if( db.PgResult(DataBase::NOT_CLEAR) < 0 )
		{
			r = -1;
			LOG(LERR, "sumdata data load fail.[%s]", db.GetErrorMessage().c_str());
			break;
		}

		rows = db.GetNoTuples();

		for( int i = 0; i < rows; ++i )
		{
#ifdef _DEBUG
			cout << "sum date - " << i << "," << db.GetValue(i,0) << "," << db.GetValue(i,1) << "," << db.GetValue(i,2) << endl;
#endif // _DEBUG
			int rtype = atoi(db.GetValue(i,3));
			
			if( rtype == 0 ) // file
				savedata( userseq, tranid, caldepth, atoi(db.GetValue(i,0)) - 1, db.GetValue(i,1), atoll(db.GetValue(i,2)), data ) ;
			else  //dir
				savedata( userseq, tranid, caldepth, atoi(db.GetValue(i,0)) , db.GetValue(i,1), atoll(db.GetValue(i,2)), data ) ;
		}

		db.PgClear();

		if( rows < MAX_ROWS )
			break;

		offset += MAX_ROWS;
	}

	return r;
}

int CSyncManager::getdepthsum( DataBase &db, int64_t userseq, int64_t tranid, int caldepth, SYNCDATAMAP &data )
{
	int r = 0;
#ifdef _DEBUG
	cout << "Sum Depth Data : " << userseq  << "," << tranid << "," << caldepth << endl;
#endif //_DEBUG

	const char *paramValues[3];
	ostringstream t;
	string p1,p2,p3;

	ostringstream sql;
	string tblname = gettablename(tranid);

	for(int d = caldepth; d >=0; --d)
	{	
		sql.str("");
		sql << "SELECT path_name FROM t_dav_use_dir WHERE"
			<< " depth = $1 AND path_name LIKE $2 ||'%'";

		t << d;
		p1 = t.str(); t.str("");
		t << "/" << tranid;
		p2 = t.str(); t.str("");
		paramValues[0] = p1.c_str();
		paramValues[1] = p2.c_str();

#ifdef _DEBUG
		cout << "select dir sql  : " << sql.str() << endl;
		cout << "  param : " << paramValues[0] << "," << paramValues[1]  << endl;
#endif // _DEBUG

		db.PgDoExecParams( const_cast<char *> (sql.str().c_str()), 2 , paramValues);

		if( db.PgResult(DataBase::NOT_CLEAR) < 0 )
		{
			r = -1;
			LOG(LERR, "select dir load fail.[%s][%s]", db.GetErrorMessage().c_str(), paramValues[1]);
			break;
		}

		vector<string> seldata;
		int rows = db.GetNoTuples();
		for( int i = 0; i < rows; ++i )
		{
			seldata.push_back(db.GetValue(i,0));
		}
		db.PgClear();

		if(rows == 0) continue;

		for( int i = 0; i < rows; ++i )
		{
			sql.str("");
			sql << "SELECT SUM(get_content_length) FROM " << tblname;

			if(d == caldepth)
			{
				sql << " WHERE depth >= $1 ";
			}
			else 
			{
				sql << " WHERE (depth = $1 OR depth = $1+1 )";				
			}

			//sql << "AND uri LIKE $2 ||'/%' AND resource_type = 0 ";
			//sql << "AND uri LIKE regexp_replace(lower($2), '(%|_)', '\\\\\\1', 'g') || '%' ";
			//sql << "AND deleted_yn = 'N' AND is_cache = 'N'";

			// BUG 2019-03-14 huibong 지정된 폴더가 아닌 다른 폴더까지 SUM 처리되는 버그 수정 (#32547)
			//                - 폴더 구분자 미사용으로 폴더 용량 계산시 다른 폴더까지 계산됨
			//                - /73/mut 계산시 /73/mut-hd 까지 계산되는 버그 수정
			sql << "AND uri LIKE regexp_replace(lower($2), '(%|_)', '\\\\\\1', 'g') || '/%' ";
			sql << "AND deleted_yn = 'N' AND is_cache = 'N' AND resource_type = 0 ";


			//string s = StringReplace(seldata[i], "_", "\\_");
			paramValues[1] = seldata[i].c_str();
#ifdef _DEBUG
			cout << " dir sum sql  : " << sql.str() << endl;
			cout << "  param : " << paramValues[0] << "," << paramValues[1]  << endl;
#endif // _DEBUG
			db.PgDoExecParams( const_cast<char *> (sql.str().c_str()), 2 , paramValues);

			if( db.PgResult(DataBase::NOT_CLEAR) < 0 )
			{
				r = -1;
				LOG(LERR, "dir sum fail.[%s][%s]", db.GetErrorMessage().c_str(), paramValues[1]);
				break;
			}

			savedata( userseq, tranid, caldepth, d, paramValues[1],atoll(db.GetValue(0,0)), data) ;		
		}
		db.PgClear();

		if( r != 0 )
			break;
	}

	return r;
}

static string stringreplace(const string& source, const string search, const string replacement) 
{
	string r = source;

	string::size_type pos = 0;

	while ( (pos = r.find(search, pos)) != string::npos ) 
	{
		r.replace( pos, search.size(), replacement );
		pos = pos + replacement.size();		
	}

	return r;
}

bool CSyncManager::syndata( DataBase &db, SYNCDATAMAP &data ) 
{
#ifdef _DEBUG
	cout << "syndata : " <<  data.size() << endl;
#endif //_DEBUG

	for( SYNCDATAMAP::iterator i=data.begin(); i!=data.end(); ++i ) 
	{
#ifdef _DEBUG
		cout << "sync (" << i->second.getTranid() << ") : "<< i->second.getpath() << "," << i->second.getused() << endl;
#endif //_DEBUG

		// replace unsafe chars
		string updatepath = stringreplace( i->second.getpath(), "'", "''" );

		ostringstream sql;
		sql << "UPDATE t_dav_use_dir SET dir_used = " << i->second.getused() 
			<< " WHERE depth = "<< i->second.getdepth() << " AND path_name = '" << updatepath << "'";

#ifdef _DEBUG
		cout << "syndata sql : " << sql.str() << endl;
#endif // _DEBUG
		
		db.PgDoExec(const_cast<char *> (sql.str().c_str()));
		if( db.PgResult(DataBase::CLEAR) < 0) 
		{
			cerr << "[error] Update error.[dir_used  - " << i->second.getpath() << "]" << endl;
			LOG(LERR, "Update dir_used failed.[path - %s]", i->second.getpath());
			return false;
		}
		_LOG(LINF, "SYNC DATA - Path : %s, Size : %jd",i->second.getpath(), i->second.getused() );
	}
	return true;
}

bool CSyncManager::deloverdepth(DataBase &db, int64_t userseq, int64_t tranid, int caldepth)
{
#ifdef _DEBUG
	cout << "delete over depth : " << userseq  << "," << tranid << "," << caldepth << endl;
#endif // _DEBUG
	ostringstream sql;

	sql << "DELETE FROM t_dav_use_dir WHERE depth > $1 AND path_name LIKE $2 ||'%'";

	const char *paramValues[2];
	ostringstream t;
	string p1,p2;

	t << caldepth;
	p1 = t.str(); t.str("");
	t << "/" << tranid << "/";
	p2 = t.str(); t.str("");

	paramValues[0] = p1.c_str();
	paramValues[1] = p2.c_str();

#ifdef _DEBUG
	cout << "delete over depth sql  : " << sql.str() << endl;
	cout << "  param : " << paramValues[0] << "," << paramValues[1] << endl;
#endif // _DEBUG

	db.PgDoExecParams(const_cast<char *> (sql.str().c_str()), 2, paramValues);

	if( db.PgResult(DataBase::CLEAR) < 0) 
	{
		cerr << "[error] delete over depth error.[sync root tran id - " << tranid << "]" << endl;
		LOG(LERR, "delete over depth failed.[tran id - %jd]", tranid);
		return false;
	}

	return true;
}

bool CSyncManager::deldeleteddir(DataBase &db, int64_t userseq, int64_t tranid, int caldepth)
{
#ifdef _DEBUG
	cout << "delete deleted dir : " << userseq  << "," << tranid << "," << caldepth << endl;
#endif // _DEBUG

	string tblname = gettablename(tranid);
	ostringstream sql;

	sql << "SELECT uri FROM " << tblname << " WHERE "
		<< "uri IN "
		<< " (SELECT uri FROM " << tblname << " WHERE depth >= 0  AND depth <= $1 "
		<< "  AND uri LIKE $2 ||'%' AND resource_type = 1 AND deleted_yn = 'Y' AND is_cache = 'N') "
		<< "AND deleted_yn = 'Y' "
		<< "AND uri NOT IN "
		<< " (SELECT uri FROM " << tblname << " WHERE uri IN (SELECT uri FROM " << tblname << " WHERE depth >= 0  AND depth <= $1 "
		<< "  AND uri LIKE $2 ||'%' AND resource_type = 1 AND deleted_yn = 'Y' AND is_cache = 'N') AND deleted_yn = 'N') ";

	const char *paramValues[2];
	ostringstream t;
	string p1,p2;

	t << caldepth;
	p1 = t.str(); t.str("");
	t << "/" << tranid;
	p2 = t.str(); t.str("");
	paramValues[0] = p1.c_str();
	paramValues[1] = p2.c_str();

#ifdef _DEBUG
	cout << "deleted dir sel sql  : " << sql.str() << endl;
	cout << "  param : " << paramValues[0] << "," << paramValues[1] << endl;
#endif // _DEBUG

	db.PgDoExecParams( const_cast<char *> (sql.str().c_str()), 2 , paramValues);

	if( db.PgResult(DataBase::NOT_CLEAR) < 0 )
	{
		LOG(LERR, "deleted dir load fail.[%s][%s]", db.GetErrorMessage().c_str(), paramValues[1]);
		return false;
	}

	string strdeldir;
	int rows = db.GetNoTuples();	
	for( int i = 0; i < rows; ++i )
	{
		if(i > 0) strdeldir += ",";
		strdeldir += db.GetValue(i,0);	
	}

	// 2014.06.07 dadamin
	// ANY 함수 사용을 {} 포함된 경우 array 로 인되는 경우 방지
	strdeldir = StringReplace(strdeldir,"{", "\\{");
	strdeldir = StringReplace(strdeldir,"}", "\\}");

	strdeldir = "{" + strdeldir + "}" ;
	db.PgClear();

	if(rows == 0) return true;

	sql.str("");
	sql << "DELETE FROM t_dav_use_dir WHERE path_name = ANY($1)";
	
	paramValues[0] = strdeldir.c_str();
#ifdef _DEBUG
	cout << "delete dir sql  : " << sql.str() << endl;
	cout << "  param : " << paramValues[0]  << endl;
#endif // _DEBUG

	db.PgDoExecParams(const_cast<char *> (sql.str().c_str()), 1, paramValues);

	if( db.PgResult(DataBase::CLEAR) < 0) 
	{
		cerr << "[error] delete dir error.[sync tran id - " << tranid << "]" << endl;
		LOG(LERR, "delete dir failed.[%s][tran id - %jd]", db.GetErrorMessage().c_str(), tranid);
		return false;
	}
	
	return true;
}

bool CSyncManager::delnotfouddir(DataBase &db, int64_t userseq, int64_t tranid, int caldepth)
{
#ifdef _DEBUG
	cout << "delete not found dir : " << userseq  << "," << tranid << "," << caldepth << endl;
#endif // _DEBUG

	string tblname = gettablename(tranid);

	ostringstream sql;

	sql << "SELECT L.path_name FROM t_dav_use_dir L LEFT JOIN " << tblname << " R "
		<< "ON L.path_name = R.uri WHERE L.sp_user_seq = $1 AND L.sp_svc_tran_id = $2 AND R.uri IS NULL ";

	const char *paramValues[2];
	ostringstream t;
	string p1,p2;

	t << userseq;
	p1 = t.str(); t.str("");
	t << tranid;
	p2 = t.str(); t.str("");
	paramValues[0] = p1.c_str();
	paramValues[1] = p2.c_str();

#ifdef _DEBUG
	cout << "deleted not found sel sql  : " << sql.str() << endl;
	cout << "  param : " << paramValues[0] << "," << paramValues[1] << endl;
#endif // _DEBUG

	db.PgDoExecParams( const_cast<char *> (sql.str().c_str()), 2 , paramValues);

	if( db.PgResult(DataBase::NOT_CLEAR) < 0 )
	{
		LOG(LERR, "deleted dir load fail.[%s][%s]", db.GetErrorMessage().c_str(), paramValues[1]);
		return false;
	}

	string strnotfound;
	int rows = db.GetNoTuples();
	for( int i = 0; i < rows; ++i )
	{
		if(i > 0) strnotfound += ",";
		strnotfound += db.GetValue(i,0);
	}
	// 2014.06.07 dadamin
	// ANY 함수 사용을 {} 포함된 경우 array 로 인되는 경우 방지
	strnotfound = StringReplace(strnotfound,"{", "\\{");
	strnotfound = StringReplace(strnotfound,"}", "\\}");

	strnotfound = "{" + strnotfound + "}" ;

	db.PgClear();

	if(rows == 0) return true;

	sql.str("");
	sql << "DELETE FROM t_dav_use_dir WHERE path_name = ANY($1)";

	paramValues[0] = strnotfound.c_str();
#ifdef _DEBUG
	cout << "delete not found sql  : " << sql.str() << endl;
	cout << "  param : " << paramValues[0]  << endl;
#endif // _DEBUG

	db.PgDoExecParams(const_cast<char *> (sql.str().c_str()), 1, paramValues);

	if( db.PgResult(DataBase::CLEAR) < 0) 
	{
		cerr << "[error] delete not found error.[sync tran id - " << tranid << "]" << endl;
		LOG(LERR, "delete not found failed.[%s][tran id - %jd]", db.GetErrorMessage().c_str(), tranid);
		return false;
	}

	return true;
}

bool CSyncManager::insertroot(DataBase &db, int64_t userseq, int64_t tranid)
{
#ifdef _DEBUG
	cout << "insert root : " << userseq  << "," << tranid << endl;
#endif //_DEBUG

	const char *paramValues[3];
	ostringstream t;
	string p1,p2,p3;
	ostringstream sql;

	t << userseq;
	p1 = t.str(); t.str("");
	t << tranid;
	p2 = t.str(); t.str("");
	t << "/" << tranid;
	p3 = t.str(); t.str("");

	paramValues[0] = p1.c_str();
	paramValues[1] = p2.c_str();
	paramValues[2] = p3.c_str();

	sql << "SELECT * FROM t_dav_use_dir "
		<< "WHERE sp_user_seq = $1 AND sp_svc_tran_id = $2 AND depth = 0";

#ifdef _DEBUG
	cout << "select root sql  : " << sql.str() << endl;
	cout << "  param : " << paramValues[0] << "," << paramValues[1] << "," << paramValues[2] << endl;
#endif // _DEBUG

	db.PgDoExecParams(const_cast<char *> (sql.str().c_str()), 2, paramValues);

	int row = db.GetNoTuples();

	if( db.PgResult(DataBase::CLEAR) < 0) 
	{
		cerr << "[error] Select root error.[sync root tran id - " << tranid << "]" << endl;
		LOG(LERR, "Select root failed.[tran id - %jd]", tranid);
		return false;
	}

	if( row > 0 )
		return true;

	sql.str("");
	sql << "INSERT INTO t_dav_use_dir (sp_user_seq, sp_svc_tran_id, depth, path_name)"
		<< " VALUES ($1,$2,0,$3)";

#ifdef _DEBUG
	cout << "insert root sql  : " << sql.str() << endl;
	cout << "  param : " << paramValues[0] << "," << paramValues[1] << "," << paramValues[2] << endl;
#endif // _DEBUG

	db.PgDoExecParams(const_cast<char *> (sql.str().c_str()), 3, paramValues);

	if( db.PgResult(DataBase::CLEAR) < 0) 
	{
		cerr << "[error] Insert root error.[sync root tran id - " << tranid << "]" << endl;
		LOG(LERR, "Insert root failed.[tran id - %jd]", tranid);
		return false;
	}

	return true;
}

bool CSyncManager::insertdir(DataBase &db, int64_t userseq, int64_t tranid, int caldepth)
{
#ifdef _DEBUG
	cout << "insert dir : " << userseq  << "," << tranid << "," << caldepth << endl;
#endif // _DEBUG

	string tblname = gettablename(tranid);

	ostringstream sql;

	sql	<< "SELECT L.uri FROM " << tblname << " L "
		<< "LEFT JOIN t_dav_use_dir R ON L.uri = R.path_name "
		<< "WHERE L.sp_user_seq = $1 AND L.sp_svc_tran_id = $2 "
		<< "AND L.deleted_yn = 'N' and L.is_cache = 'N' AND L.resource_type = 1 AND L.depth >= 0 "
		<< "AND L.depth <= $3 AND R.path_name IS NULL ORDER BY L.uri";

	const char *paramValues[3];
	ostringstream t;
	string p1,p2,p3;

	t << userseq;
	p1 = t.str(); t.str("");
	t << tranid;
	p2 = t.str(); t.str("");
	t << caldepth;
	p3 = t.str(); t.str("");
	
	paramValues[0] = p1.c_str();
	paramValues[1] = p2.c_str();
	paramValues[2] = p3.c_str();

#ifdef _DEBUG
	cout << "insert dir sql  : " << sql.str() << endl;
	cout << "  param : " << paramValues[0] << "," << paramValues[1] << "," << paramValues[2] << endl;
#endif // _DEBUG

	db.PgDoExecParams( const_cast<char *> (sql.str().c_str()), 3 , paramValues);

	if( db.PgResult(DataBase::NOT_CLEAR) < 0 )
	{
		LOG(LERR, "insert dir load fail.[%s][%s]", db.GetErrorMessage().c_str(), paramValues[1]);
		return false;
	}

	string strinserdir;
	int rows = db.GetNoTuples();
	for( int i = 0; i < rows; ++i )
	{
		if(i > 0) strinserdir += ",";
		strinserdir += db.GetValue(i,0);
	}
	// 2014.06.07 dadamin
	// ANY 함수 사용을 {} 포함된 경우 array 로 인되는 경우 방지
	strinserdir = StringReplace(strinserdir,"{", "\\{");
	strinserdir = StringReplace(strinserdir,"}", "\\}");

	strinserdir = "{" + strinserdir + "}" ;
	db.PgClear();

	if(rows == 0) return true;

	sql.str("");
	sql << "INSERT INTO t_dav_use_dir (sp_user_seq, sp_svc_tran_id, depth, path_name) "
		<< "SELECT DISTINCT ON (uri) sp_user_seq, sp_svc_tran_id, depth, uri FROM " << tblname
		<< " WHERE uri = ANY($1)";

	paramValues[0] = strinserdir.c_str();
#ifdef _DEBUG
	cout << "insert dir sql  : " << sql.str() << endl;
	cout << "  param : " << paramValues[0]  << endl;
#endif // _DEBUG

	db.PgDoExecParams(const_cast<char *> (sql.str().c_str()), 1, paramValues);

	if( db.PgResult(DataBase::CLEAR) < 0) 
	{
		cerr << "[error] insert dir error.[sync tran id - " << tranid << "]" << endl;
		LOG(LERR, "insert dir failed.[%s][tran id - %jd]", db.GetErrorMessage().c_str(), tranid);
		return false;
	}

	return true;
}

// 2014.06.07 dadamin
// 형상(9.3) 변경으로 테이블명 수정
bool CSyncManager::targettblmode( DataBase &db )
{
	db.PgDoExec("SELECT *  FROM pg_tables WHERE schemaname =  'public' AND tablename =  't_dav_resource'");
	if (db.PgResult(DataBase::NOT_CLEAR) < 0)
	{
		db.PgClear();
		cerr << "[error] failed Target Table mode." << endl;
		LOG(LERR, "failed Target Table mode.[%s]", db.GetErrorMessage().c_str());
		return false;
	}

	if (db.GetNoTuples() > 0)
	{
		m_tblmode = 0;
	}
	else
	{
		m_tblmode = 1;
	}

	db.PgClear();

	return true;
}

string CSyncManager::gettablename(int64_t tranid)
{
	string r;
	ostringstream tmp;

	switch (m_tblmode)
	{
	case 1:
		tmp << "t_meta_" << tranid;
		break;
	case 0:
	default:
		tmp << "t_dav_resource";
		break;
	}

	r = tmp.str();
	LOG(LDBG, "Working Table Name %s", r.c_str());

	return r;
}
