Progress商业数据库的访问接口的C++包装

iprogressdb.h:

/*      Written by Wooce                     Date: 2002-04        */

#ifndef _IPROGRESSDB_H
#define _IPROGRESSDB_H

#include "idbbase.h"
#include "idbbasetype.h"
#include "sql_lib.h"
#include "ilist.h"
#include "idatetime.h"

typedef void * tpe_cursor_type;
extern int g_ProgressType[DBType_OTHER+1];

class IProgressConnection;
class IProgressStatement;

//--------------------------IProgressCheckErr-------------------------------------

class IProgressCheckErr
{
public:
	IProgressCheckErr(void) {}
	~IProgressCheckErr(void) {}

	static bool    CheckErr(struct sqlca& SQLca);
	static int		CheckErr(struct sqlca& SQLca,IString & res);
	static void	CheckErrEx(struct sqlca& SQLca);
};

//--------------------------End of IProgressCheckErr-------------------------------


class IProgressEnvironment : public IDBEnvironment
{
public:
	IProgressEnvironment(int mode = 0);	//
	~IProgressEnvironment(void) {}

	ISTDDBConnection* GetConnection(const char * lpszDBName,const char * lpszUser,const char * lpszPassword,const char * ip,const char * port=NULL);
};

//-------------------------------------------------------------------------

class IProgressConnection : public ISTDDBConnection
{
protected:
       	IProgressEnvironment	*	m_pEnv;
	struct sqlca sqlca;
	bool	m_bConnected;
	IString m_strConName;
public:
	//Constructor
	IProgressConnection(IProgressEnvironment * pEnv = NULL);
	//Destructor
	~IProgressConnection(void) {Close();}

        void TranCommit(bool boDistributed);
        void TranRollBack(void);
	struct sqlca *	GetSQLCA(void) {return &sqlca;}

	//Standard Interface
	void	Close(void);
	int		Connect(const char * lpszDBName,const char * lpszUser,const char * lpszPassword,const char * ip,const char * lpszPort=NULL);

	ISTDDBStatement *	GetStatement(const IString & strSQL = "");
	ISTDDBStatement *	GetTableList(const IString & strLikeWild = "");
	bool	IsConnected(void);
	IString	EncodeString(const IString & strSrc);
};

//---------------------------------------------------------------------
class IProgressStatement : public ISTDDBStatement
{
private:
protected:
	IProgressCheckErr Check;
	IProgressConnection   *	m_pConnection;
	int					    m_nInfoCount;
	ISTDColumnInfo	      * m_pInfo;

	IString				    m_strSQL;

	tpe_cursor_type         m_cursor;
	pro_sqlda             * m_pSQLDA;
	dh_i32_t              * m_pIVARPTR;

	IDWORD				    m_dwRowCount;

	void				ClearColInfo(void);
	void				GetColumnInfo(void);
	ISTDField	*		NewField(ISTDColumnInfo & info);

	void		ValueByName(const char * lpszFieldName,ISTDField * param);
	void		ValueByPos(int nPos,ISTDField * param);

	void		ParamByName(const char * lpszParamName,ISTDField * param);
	void		ParamByPos(int nPos,ISTDField * param);
public:
	IProgressStatement(IProgressConnection * pConnection = NULL);
	~IProgressStatement(void) {Close();}

	void		Use(IProgressConnection	* pConnection);
	void		Close(void);

	void		Prepare(const IString & strSQL);
        void            PrepareParam(const IString & strSQL);

	bool		Exec(bool boCommit = false);
	bool		ExecCommit(void);
	bool		ExecAndSelectLastInsert(const IString & strTableName,const IString & strAutoIncField,bool boCommit = false);

	ISTDColumnInfo & GetColumnInfo(int nPos);
	IDWORD		GetRowCount(void);

	bool		Fetch(void);
	IString		InsertID(void);
};


#endif

iprogressdb.cpp:

/*      Written by Wooce                     Date: 2002-04        */

#ifdef _HAS_PROGRESS

	#include "iprogressdb.h"
	#include "iprogresstype.h"
	#include "idbbasetype.h"
	#include "istring.h"
	#include "sql_lib.h"
	#include <ctype.h>

int g_ProgressType[DBType_OTHER+1] =
{							 //						Maximum Internal Length			Type of Program variable
	dnu_TPE_DT_ERR,			 //
	dnu_TPE_DT_TINYINT,		 // TinyInt                 1 byte							char
	dnu_TPE_DT_SMALLINT,	 // SmallInt				2 bytes							short
	0,						 // Unsigned int						                    unsigned
	dnu_TPE_DT_INTEGER,		 // INTEGER 				4/2/1 Byte						int/long/short
	dnu_TPE_DT_BIGINT,		 // LONGLONG                Fix size:						sizeof(long long)
	dnu_TPE_DT_REAL,		 // FLOAT                   sizeof(float)                                       float
	dnu_TPE_DT_FLOAT,		 // DOUBLE                  sizeof(double)					double
	dnu_TPE_DT_NUMERIC,		 // NUMBER
	dnu_TPE_DT_NUMERIC,		 // VARNUM
	0,						 // LONG                    2^31-1 Byte						char[n]
	dnu_TPE_DT_CHAR,		 // CHAR
	dnu_TPE_DT_VARCHAR,				 // VARCHAR2
	dnu_TPE_DT_VARCHAR,		 // CHARZ
	dnu_TPE_DT_LVC,			 // Nullterminated STRING Null Terminated STRING			char[n+1]
	dnu_TPE_DT_VARCHAR,		 // VARCHAR												    char[n+sizeof(short int)]
	dnu_TPE_DT_VARCHAR,		 // LONG VARCHAR											char[n+sizeof(int)]
	dnu_TPE_DT_BINARY,		 // RAW					    2000 Byte					    unsigned char[n]
	dnu_TPE_DT_BINARY,		 // LONG RAW				2^31-1 Byte						unsigned char[n]
	dnu_TPE_DT_VARBINARY,	 // VARRAW												    unsigned char[n+sizeof(short int)]
	dnu_TPE_DT_LVB,			 // LONG VARRAW											    unsigned char[n+sizeof(int)]
	0,						 // DATETIME
	dnu_TPE_DT_DATE,		 // DATE
	dnu_TPE_DT_TIME,		 // TIME
	dnu_TPE_DT_TIMESTAMP,	 // TIMESTAMP
	dnu_TPE_DT_LVB,			 // Character LOB			~4000
	dnu_TPE_DT_LVB,			 // Binary LOB			    ~4000
	0,
	0,
	0x7fffffff
};

//-----------------------------------------------------------

bool IProgressCheckErr::CheckErr(struct sqlca& pSQLCA)
{
	if( pSQLCA.sqlcode<0 )
		return true;
	else
		return false;
}

int IProgressCheckErr::CheckErr(struct sqlca& pSQLCA,IString & res)
{
	if( pSQLCA.sqlcode<0 )
	{
		res.Format("Progress : Error - (%d) %s",pSQLCA.sqlcode,pSQLCA.sqlerrm);
		return pSQLCA.sqlcode;
	} else
	{
		res = "Progress : NORMAL";
		return NORMAL;
	}
}

void IProgressCheckErr::CheckErrEx(struct sqlca& pSQLCA)
{
	IString res;
	int retcode = CheckErr(pSQLCA,res);
	if(retcode!=NORMAL)
		throw(ISTDDBException(ERR_SQL_ERR,"%s",res.CConstStr()));
}

//-----------------------------------------------------------

IProgressEnvironment::IProgressEnvironment(int mode)
{
	for(int i=0;i<DBType_OTHER+1;i++)
		m_DBType[i] = g_ProgressType[i];
}

ISTDDBConnection* IProgressEnvironment::GetConnection(const char * lpszDBName,const char * lpszUser,const char * lpszPassword,const char * ip,const char * port)
{
	IDBConnection con(new IProgressConnection(this));
	if(con.Get() == NULL)
		throw(ISTDDBException(MEMNOTENOUGH,"GetConnetion:no mem"));
	con->Connect(lpszDBName,lpszUser,lpszPassword,ip,port);
	return con.Release();
}

//-------------------------------------------------------------------------

IProgressConnection::IProgressConnection(IProgressEnvironment * pEnv)
: ISTDDBConnection(DB_SUPPORT_NOSELECT_ROWCOUNT|DB_SUPPORT_TRANSACTION),
m_pEnv(pEnv),m_bConnected(false)
{
}

void IProgressConnection::Close(void)
{
	if(m_bConnected)
	{
		struct sqlca ca;
		tpe_sql_disconnect(SQL_DISCONNECT_CONNECTION,(char *)m_strConName.CConstStr(),&ca);
		m_bConnected = false;
	}
}

void IProgressConnection::TranCommit(bool boDistributed)
{
	if(m_pEnv == NULL)
		throw(ISTDDBException(ERR_PROGRESS_ERROR,"Commit:not init env"));
	struct sqlca ca;
	tpe_tm_end_trans(tpe_get_curtmhdl(),&ca);
	IProgressCheckErr::CheckErrEx(ca);
}

void IProgressConnection::TranRollBack(void)
{
	if(m_pEnv == NULL)
		throw(ISTDDBException(ERR_PROGRESS_ERROR,"Rollback:not init env"));
	struct sqlca ca;
	tpe_tm_mark_abort(tpe_get_curtmhdl(),&ca);
	IProgressCheckErr::CheckErrEx(ca);
	tpe_tm_end_trans(tpe_get_curtmhdl(),&ca);
	IProgressCheckErr::CheckErrEx(ca);
}

int IProgressConnection::Connect(const char * lpszDBName,const char * lpszUser,const char * lpszPassword,const char * ip,const char * lpszPort)
{
	if( IsConnected() )
		Close();
	IString connectStr;
	connectStr.Format("progress:T:%s:%s:%s",ip,lpszPort,lpszDBName);
	struct sqlca ca;
	m_strConName = connectStr;
	IDateTime dt;
	dt.SetCurTime();
	m_strConName += IntToStr( (long long)dt.GetTime() );
	tpe_sqlconnect(connectStr.CConstStr(),m_strConName.CConstStr(),lpszUser,lpszPassword,(dh_char_t *)0,&ca); 
	IProgressCheckErr::CheckErrEx(ca);
	m_bConnected = true;
	return NORMAL;
}

bool IProgressConnection::IsConnected(void)
{
	if(!m_bConnected)
		return false;
	struct sqlca ca;
	tpe_sql_chk_connection(&ca);
	if(ca.sqlcode < 0)
		return false;
	else
		return true;
}

ISTDDBStatement * IProgressConnection::GetStatement(const IString & strSQL)
{
	IDBStatement statement(new IProgressStatement(this));
	if(statement.Get() == NULL)
		throw(ISTDDBException(MEMNOTENOUGH,"GetStatement:no mem"));
	if(!strSQL.IsEmpty())
		statement->Prepare(strSQL);
	return statement.Release();
}

ISTDDBStatement * IProgressConnection::GetTableList(const IString & strLikeWild)
{
	IString strSQL;
	if(strLikeWild.IsEmpty())
		strSQL = "select tbl from sysprogress.systables";
	else
		strSQL.Format("select tbl from sysprogress.systables where tbl like '%s'",EncodeString(strLikeWild).CConstStr());
	IDBStatement statement(new IProgressStatement(this));
	if(statement.Get() == NULL)
		throw(ISTDDBException(MEMNOTENOUGH,"GetStatement:no mem"));
	statement->Exec(strSQL);
	return statement.Release();
}

IString IProgressConnection::EncodeString(const IString & strSrc)
{
	IString res;
	for(const unsigned char * tp = (const unsigned char *)strSrc.CConstStr();*tp!='\0';tp++)
	{
		if(*tp == '\'')	res += (char)'\'';
		res += (char)(*tp);
	}
	return res;
}

//---------------------------------------------------------------------
IProgressStatement::IProgressStatement(IProgressConnection * pConnection)
: ISTDDBStatement(),m_pConnection(pConnection),m_nInfoCount(0),
m_pInfo(NULL),m_cursor(NULL),m_dwRowCount(0),m_pSQLDA(NULL),m_pIVARPTR(NULL)
{
}

void IProgressStatement::ClearColInfo(void)
{
	if(m_nInfoCount > 0 && m_pInfo!=NULL)
		delete []m_pInfo;
	if(m_pIVARPTR!=NULL)
		delete m_pIVARPTR;
	m_nInfoCount = 0;
	m_pInfo = NULL;
}

//  be called in destructor and Prepare(const IString & strSQL) function
void IProgressStatement::Close(void)
{
	if(m_pConnection == NULL)
		return;
	ClearColInfo();
	struct sqlca ca;
	struct sqlca * pSQLCA = &ca;
	tpe_sqlclose(tpe_get_curtmhdl(),tpe_get_curdbhdl(),(tpe_cursor_type)m_cursor,pSQLCA);	//关闭光标
	if( m_pSQLDA!=NULL )
		PRO_SQLDA_Deallocate(m_pSQLDA);
	m_dwRowCount = 0;
	ISTDDBStatement::Close();
}

void IProgressStatement::Use(IProgressConnection * pConnection)
{
	Close();
	m_pConnection = pConnection;
}

void IProgressStatement::Prepare(const IString & strSQL)
{
	if(m_pConnection == NULL)
		throw(ISTDDBException(ERR_PROGRESS_ERROR,"Prepare:not init env"));
	Close();
	m_strSQL = strSQL;
	m_strSQL.LTrim();
	struct sqlca *pSQLCA = m_pConnection->GetSQLCA();
	dh_char_t *sqlcmd = (char *)strSQL.CConstStr();
	static tpe_uuid__t tpe_uuid = {0x3cad7190, 0x4b97, 0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
	tpe_set_cursor(tpe_get_curtmhdl(),tpe_get_curdbhdl(),(tpe_cursor_type *)&m_cursor,&tpe_uuid,1,sqlcmd,pSQLCA);
	Check.CheckErrEx(*pSQLCA);
	tpe_set_cursorname(m_cursor,NULL,pSQLCA);
	Check.CheckErrEx(*pSQLCA);
	tpe_sqlprepare(tpe_get_curtmhdl(),tpe_get_curdbhdl(),(tpe_cursor_type)m_cursor, pSQLCA);
	PrepareParam(m_strSQL);
}

void IProgressStatement::PrepareParam(const IString & strSQL)
{
	int nParamCount = 0,i;
	ClearParams();

	if(strSQL.Find(':') >= 0)
	{
		const char * tp = strSQL.CConstStr();
		nParamCount = 0;
		while(*tp!='\0')	//Count the number
		{
			if(*tp==':') nParamCount++;
			else if(*tp=='\'')
			{
				tp++;
				while((*tp!='\'' || *(tp-1)=='\\') && *tp!='\0') tp++;
				if(*tp=='\0') break;
			}
			tp ++;
		}
		if(nParamCount>0)
		{
			struct sqlca ca;
			struct sqlca* SQLCAPTR = &ca;
			if( m_pSQLDA==NULL )
				m_pSQLDA = PRO_SQLDA_Allocate(3,20);
			if( m_pSQLDA==NULL )
				throw ISTDDBException(MEMNOTENOUGH,"GetColumnInfo:no mem");
			for(;;)
			{
				dh_u32_t desiredCols;
				tpe_sqldescribe_param(tpe_get_curtmhdl(),tpe_get_curdbhdl(),(tpe_cursor_type)m_cursor,m_pSQLDA,&ca);
				PRO_SQLDA_Get_DA_Attribute_dh_u32_t(m_pSQLDA,PRO_SQLDA_DA_ATTR_DESIREDCOLS,&desiredCols,SQLCAPTR);
				if( desiredCols>0 )
				{
					PRO_SQLDA_Deallocate(m_pSQLDA);
					m_pSQLDA = PRO_SQLDA_Allocate(desiredCols,20);
					if( m_pSQLDA==NULL )
						throw ISTDDBException(MEMNOTENOUGH,"GetColumnInfo:no mem");
					continue;
				}
				break;
			}                        
			dh_u32_t numCols;
			PRO_SQLDA_Get_DA_Attribute_dh_u32_t(m_pSQLDA,PRO_SQLDA_DA_ATTR_ACTUALCOLS,&numCols,&ca);
			if( numCols!=nParamCount )	   //手工代码检出的param数目和tpe_sqldescribe_param不同? 
				throw ISTDDBException(ERR_PROGRESS_ERROR,"Error with getting input params of sql statement:%s",strSQL.CConstStr());
			m_nParamCount = nParamCount;
			m_ppParams = new ISTDField * [nParamCount];
			if(m_ppParams ==NULL)
				throw(ISTDDBException(MEMNOTENOUGH,"Prepare statement Param:no mem"));

			for(i=0;i<nParamCount;i++) m_ppParams[i] = NULL;

			tp = strSQL.CConstStr();
			i = 0;
			while(*tp!='\0')	//Count the number
			{
				if(*tp==':')
				{
					int len =0;
					tp++;
					while(*tp!='\0' && strchr(" ;,:\t\n\r()",*tp)==NULL)
					{
						len++; tp++;
					}
					m_ppParams[i] = NewParam();
					ParamByPos(i,m_ppParams[i]);
					m_ppParams[i++]->SetFieldName(IString(tp-len,len));
					if(*tp=='\0') break;
				} else if(*tp=='\'')
				{
					tp++;
					while((*tp!='\'' || *(tp-1)=='\\') && *tp!='\0') tp++;
					if(*tp=='\0') break;
				}
				tp ++;
			}
		}
	}
}

void IProgressStatement::ParamByName(const char * lpszParamName,ISTDField * param)
{
	if(m_pConnection == NULL || m_strSQL.IsEmpty())
		throw(ISTDDBException(ERR_PROGRESS_ERROR,"Param:not init env or prepare sql"));
	for( int i=0;i<m_nParamCount;i++ )
		if( m_ppParams[i++]->GetFieldName().ICompare(lpszParamName)==0 )
		{
			ParamByPos(i,param);
			return;
		}
	throw ISTDDBException(ERR_PROGRESS_ERROR,"not exists this param in dynamic sql statement:%s",lpszParamName);
}

void IProgressStatement::ParamByPos(int nPos,ISTDField * param)
{
	if(m_pConnection == NULL || m_strSQL.IsEmpty())
		throw(ISTDDBException(ERR_PROGRESS_ERROR,"Param:not init env or prepare sql"));
	struct sqlca ca;
	PRO_SQLDA_Set_Col_Attribute_void_p(m_pSQLDA,PRO_SQLDA_COL_ATTR_VARPTR,nPos+1,param->GetOriginalAddress(),&ca);
	PRO_SQLDA_Set_Col_Attribute_dh_u32_t(m_pSQLDA,PRO_SQLDA_COL_ATTR_LENGTH,nPos+1,param->GetElementLen()+1,&ca);	  // maybe no need?
}

bool IProgressStatement::ExecCommit(void)
{
	return Exec(true);
}

// exec a sql statement
bool IProgressStatement::Exec(bool boCommit)
{
	if(m_pConnection == NULL || m_strSQL.IsEmpty())
		throw(ISTDDBException(ERR_PROGRESS_ERROR,"Exec:not init env or prepare sql"));
	if(!m_pConnection->IsConnected())
		throw(ISTDDBException(ERR_SQL_ERR,"Exec:not init env or prepare sql"));
	ClearColInfo();
	ClearValues();
	struct sqlca *pSQLca = m_pConnection->GetSQLCA();

	if( m_strSQL.INCompare("select",6)==0 )
	{
		tpe_sqlopen(tpe_get_curtmhdl(),tpe_get_curdbhdl(),(tpe_cursor_type)m_cursor, (struct sqlda *)0, pSQLca);
		Check.CheckErrEx(*pSQLca);
		GetColumnInfo();
		PrepareValue();
	} else
	{
		m_dwRowCount = 0;
		tpe_sqlexecute(tpe_get_curtmhdl(),tpe_get_curdbhdl(),(tpe_cursor_type)m_cursor,(struct sqlda *)0,pSQLca);
		Check.CheckErrEx(*pSQLca);
		/*if( pSQLca->sqlcode==SQL_NOT_FOUND )
			throw ISTDDBException(ERR_SQL_ERR,"Exec: Requested row not found!"); */
		m_dwRowCount += (IDWORD)pSQLca->sqlerrd[2];		 //affected rows
		if( boCommit )
		{
			struct sqlca ca;
			tpe_tm_end_trans(tpe_get_curtmhdl(),&ca);
			Check.CheckErrEx(ca);
		}
	}
	return true;
}

void IProgressStatement::GetColumnInfo(void)
{
	if( m_cursor==NULL )
		throw(ISTDDBException(ERR_PROGRESS_ERROR,"GetColumnInfo:no cursor"));

	struct sqlca *SQLCAPTR = m_pConnection->GetSQLCA();
	//    allocate SQLDA for tpe_sqldescribe output
	if( m_pSQLDA==NULL )
		m_pSQLDA = PRO_SQLDA_Allocate(3,20);
	if( m_pSQLDA==NULL )
		throw ISTDDBException(MEMNOTENOUGH,"GetColumnInfo:no mem");
	for(;;)
	{
		dh_u32_t desiredCols;
		tpe_sqldescribe(tpe_get_curtmhdl(),tpe_get_curdbhdl(),(tpe_cursor_type)m_cursor,m_pSQLDA,SQLCAPTR);
		PRO_SQLDA_Get_DA_Attribute_dh_u32_t(m_pSQLDA,PRO_SQLDA_DA_ATTR_DESIREDCOLS,&desiredCols,SQLCAPTR);
		if( desiredCols>0 )
		{
			PRO_SQLDA_Deallocate(m_pSQLDA);
			m_pSQLDA = PRO_SQLDA_Allocate(desiredCols,20);
			if( m_pSQLDA==NULL )
				throw ISTDDBException(MEMNOTENOUGH,"GetColumnInfo:no mem");
			continue;
		}
		break;
	}
	Check.CheckErrEx(*SQLCAPTR);
	dh_u32_t numCols;
	PRO_SQLDA_Get_DA_Attribute_dh_u32_t(m_pSQLDA,PRO_SQLDA_DA_ATTR_ACTUALCOLS,&numCols,SQLCAPTR);
	Check.CheckErrEx(*SQLCAPTR);
	m_nInfoCount = numCols;
	if(m_nInfoCount <= 0)
		return;
	m_nColCount = m_nInfoCount;
	m_pInfo = new ISTDColumnInfo[m_nInfoCount];
	if(m_pInfo == NULL)
		throw(ISTDDBException(MEMNOTENOUGH,"GetColumnInfo:no mem"));
	dh_i16_t nmsize;
	PRO_SQLDA_Get_DA_Attribute_dh_i16_t(m_pSQLDA,PRO_SQLDA_DA_ATTR_VARNMSIZE,&nmsize,SQLCAPTR);
	Check.CheckErrEx(*SQLCAPTR);
	dh_char_t *col_name = new dh_char_t[nmsize];
	if(col_name == NULL)
		throw(ISTDDBException(MEMNOTENOUGH,"GetColumnInfo:no mem"));
	IAuto_Ptr<dh_char_t> autoColName(col_name);
	m_pIVARPTR = new dh_i32_t[m_nInfoCount];
	if(m_pIVARPTR == NULL)
		throw(ISTDDBException(MEMNOTENOUGH,"GetColumnInfo:no mem"));
	for(int i=0;i<m_nInfoCount;i++)
	{
		//length
		dh_u32_t col_length;
		PRO_SQLDA_Get_Col_Attribute_dh_u32_t(m_pSQLDA,PRO_SQLDA_COL_ATTR_LENGTH,i+1,&col_length,SQLCAPTR);
		m_pInfo[i].m_dwElementLen = col_length;	//if character data,  col_length includes space for the trailing 0 character
		//type
		dh_i32_t col_type;
		PRO_SQLDA_Get_Col_Attribute_dh_i32_t(m_pSQLDA,PRO_SQLDA_COL_ATTR_DATATYPE,i+1,&col_type,SQLCAPTR);
		int j;
		switch(col_type)
		{
		case dnu_TPE_DT_INTEGER:
			j = DBType_INTEGER; break;
		case dnu_TPE_DT_SMALLINT:
			j = DBType_SMALLINT; break;
		case dnu_TPE_DT_TINYINT:
		case dnu_TPE_DT_BIT:
			j = DBType_TINYINT; break;

		case dnu_TPE_DT_BIGINT:
			j = DBType_LONGLONG; break;

		case dnu_TPE_DT_NUMERIC:
			j = DBType_DECIMAL; break;

		case dnu_TPE_DT_REAL:
			j = DBType_FLOAT;break;
		case dnu_TPE_DT_FLOAT:
			j = DBType_DOUBLE; break;

		case dnu_TPE_DT_CHAR:
			j = DBType_CHAR; break;
		case dnu_TPE_DT_VARCHAR:
			j = DBType_VARCHAR; break;

		case dnu_TPE_DT_TIMESTAMP:
			j = DBType_TIMESTAMP; break;
		case dnu_TPE_DT_DATE:
			j = DBType_DATE; break;
		case dnu_TPE_DT_TIME:
			j = DBType_TIME; break;

		case dnu_TPE_DT_BINARY:
			j = DBType_BINARY; break;
		case dnu_TPE_DT_VARBINARY:
			j = DBType_VARBINARY; break;
		case dnu_TPE_DT_LVB:
			j = DBType_LONGVARBINARY; break;

		default:
			j = DBType_NTSTRING; break;
		}
		m_pInfo[i].m_nType = (DBSTDTYPE)j;
		//Name
		PRO_SQLDA_Get_Col_Attribute_dh_char_t_p(m_pSQLDA,PRO_SQLDA_COL_ATTR_VARNAME,i+1,&col_name,SQLCAPTR);
		m_pInfo[i].m_strName = col_name;
		//Flags
		dh_u32_t flags;
		PRO_SQLDA_Get_Col_Attribute_dh_u32_t(m_pSQLDA,PRO_SQLDA_COL_ATTR_FLAGS,i+1,&flags,SQLCAPTR);
		if( flags!=P_SQL_NO_NULLS )
			m_pInfo[i].m_nFlags = (DB_COLUMN_FLAGS)(m_pInfo[i].m_nFlags | DB_COLUMN_CANNULL);
		dh_u32_t odbcflags;
		PRO_SQLDA_Get_Col_Attribute_dh_u32_t(m_pSQLDA,PRO_SQLDA_COL_ATTR_ODBCFLAGS,i+1,&odbcflags,SQLCAPTR);
		/*  deprecated
		if( odbcflags&ITEM_AUTO )
			m_pInfo[i].m_nFlags = (DB_COLUMN_FLAGS)(m_pInfo[i].m_nFlags | DB_COLUMN_AUTO_INCREMENT);
			*/
		if( !(odbcflags&ITEM_SIGN) )
			m_pInfo[i].m_nFlags = (DB_COLUMN_FLAGS)(m_pInfo[i].m_nFlags | DB_COLUMN_UNSIGNED);
		PRO_SQLDA_Set_Col_Attribute_dh_i32_t_p(m_pSQLDA,PRO_SQLDA_COL_ATTR_IVARPTR,i+1,&(m_pIVARPTR[i]),SQLCAPTR);
	}
	autoColName.Release();
}

ISTDColumnInfo & IProgressStatement::GetColumnInfo(int nPos)
{
	if(m_pConnection == NULL || !m_pConnection->IsConnected())
		throw(ISTDDBException(ERR_PROGRESS_ERROR,"GetColumnInfo:Not Init"));
	if(m_pInfo == NULL)
		GetColumnInfo();
	if(m_pInfo==NULL || nPos >= m_nColCount)
		throw(ISTDDBException(ERR_PROGRESS_ERROR,"GetColumnInfo:Out of range"));
	return m_pInfo[nPos];
}

//  can only get the affected row count of UPDATE,INSERT,DELETE, if you need to get the row count of the SELECT result,please use "select count(*)"
IDWORD IProgressStatement::GetRowCount(void)
{
	return m_dwRowCount;
}

// it's called in PrepareValue() in ISTDDBStatement
void IProgressStatement::ValueByPos(int nPos,ISTDField * param)
{
	if(m_pConnection == NULL)
		throw(ISTDDBException(ERR_PROGRESS_ERROR,"ValueByPos:Not Init"));
	struct sqlca *ca = m_pConnection->GetSQLCA();
	void *p = (void *)param->GetOriginalAddress();
	PRO_SQLDA_Set_Col_Attribute_void_p(m_pSQLDA,PRO_SQLDA_COL_ATTR_VARPTR,nPos+1,p,ca);
	Check.CheckErrEx(*ca);
}

void IProgressStatement::ValueByName(const char * lpszFieldName,ISTDField * param)
{
	if(m_pConnection == NULL)
		throw(ISTDDBException(ERR_PROGRESS_ERROR,"ValueByName:Not Init"));
	if(m_nInfoCount<0)
		GetColumnInfo();
	for(int i = 0;i<m_nInfoCount;i++)
		if(m_pInfo[i].m_strName.ICompare(lpszFieldName)==0)
		{
			ValueByPos(i,param);
			return;
		}
}

bool IProgressStatement::Fetch(void)
{
	if(m_pConnection == NULL)
		throw(ISTDDBException(ERR_PROGRESS_ERROR,"Fetch:Not Init"));
	if(m_nColCount==0)
		return false;
	if(m_nColCount > 0 && m_pInfo == NULL)
		GetColumnInfo();
	if(m_ppFields==NULL)
		return false;

	struct sqlca *pSQLCA = m_pConnection->GetSQLCA();
	tpe_sqlfetch(tpe_get_curtmhdl(),tpe_get_curdbhdl(),(tpe_cursor_type)m_cursor,m_pSQLDA,pSQLCA);
	if( Check.CheckErr(*pSQLCA) )
	{
		if(!m_pConnection->IsConnected())
			throw(ISTDDBException(ERR_SQL_ERR,"Fetch: Not Connect"));
	}
	if( pSQLCA->sqlcode==SQL_NOT_FOUND )
	{
		return false;
	}
	for(int j=0;j<m_nColCount;j++)
		if(m_ppFields[j]!=NULL)
		{
			dh_i32_t* ivar;
			PRO_SQLDA_Get_Col_Attribute_dh_i32_t_p(m_pSQLDA,PRO_SQLDA_COL_ATTR_IVARPTR,j+1,&ivar,pSQLCA);
			if( *ivar<0 )	//NULL Column
			{
				m_ppFields[j]->AssignString("");           
				m_ppFields[j]->SetNULL();
			} else
				if( *ivar==0 )	 //Column data ok!
			{
				m_ppFields[j]->SetNormal();
				dh_u32_t length;
				PRO_SQLDA_Get_Col_Attribute_dh_u32_t(m_pSQLDA,PRO_SQLDA_COL_ATTR_LENGTH,j+1,&length,pSQLCA);
				m_ppFields[j]->SetFieldLen(length + 1);			  // ?
			} else
				throw ISTDDBException(ERR_SQL_ERR,"No room to hold column data!");
		}
	return true;
}

//  Get the id generated from the previous INSERT operation 
//  Progress don't have the corresponding function
IString IProgressStatement::InsertID(void)
{
	if(m_pConnection == NULL)
		throw(ISTDDBException(ERR_PROGRESS_ERROR,"Fetch:Not Init"));
	struct sqlca ca;   // output of sqlfetchrid
	tpe_sqlfetchrid(tpe_get_curtmhdl(),tpe_get_curdbhdl(),(tpe_cursor_type)m_cursor,m_pSQLDA,m_pSQLDA,&ca);
	return "";
}

bool IProgressStatement::ExecAndSelectLastInsert(const IString & strTableName,const IString & /*strAutoIncField*/,bool boCommit)
{
	if(m_pConnection == NULL)
		throw(ISTDDBException(ERR_PROGRESS_ERROR,"Insert ID:not init"));
	/*if(m_strSQL.INCompare("insert ",7) != 0)
		return false;
	Exec(boCommit);
	IString strSQL;
	LONGLONG nID = (m_pConnection->GetHandle());
	if(nID == 0)
		return false;
	strSQL.Format("select * from %s where %s=%ld",
				  strTableName.CConstStr(),
				  strAutoIncField.CConstStr(),
				  nID);
	Prepare(strSQL);
	Exec(boCommit); */
	return true;
}

//  new an ISTDField object to adopt on column from the sql result
ISTDField * IProgressStatement::NewField(ISTDColumnInfo & info)
{
	ISTDField * tp = NULL;
	switch(info.m_nType)
	{
	case DBType_ROWID:
		tp = new IDBString(20); break;
	case DBType_TINYINT:
		tp = new IDBTinyInt();  break;
	case DBType_SMALLINT:
		tp = new IDBSmallInt();  break;
	case DBType_UNSIGNEDINT:
	case DBType_INTEGER:
		tp = new IDBInteger();  break;
	case DBType_LONGLONG:
		tp = new IDBLongLong(); break;
	case DBType_FLOAT:
		tp = new IDBFloat(); break;
	case DBType_DOUBLE:
		tp = new IDBDouble();
		break;
	case DBType_DECIMAL:
	case DBType_VARDECIMAL:
		tp = new IProgressDecimal(); break;
	case DBType_NTSTRING:
	case DBType_LONGCHAR:
	case DBType_CHAR:
	case DBType_CHARZ:
		tp = new IDBString(info.m_dwElementLen); break;
	case DBType_VARCHAR:
	case DBType_LONGVARCHAR:
		tp = new IDBVarStreamField(info.m_dwElementLen); break;		   // should not use IDBVarChar, for IDBVarChar use the first short int to contain the length, while Progress just return the flat string
	case DBType_BINARY:
	case DBType_VARBINARY:
		tp = new IProgressBinary(); break;
	case DBType_LONGVARBINARY:
		tp = new IDBLongVarBinary(info.m_dwElementLen); break;				 //  ?
	case DBType_DATETIME:
		tp = new IProgressTimeStamp(); break;
	case DBType_TIME:
		tp = new IProgressTime(); break;
	case DBType_DATE:
		tp = new IProgressDate(); break;
	case DBType_TIMESTAMP:
		tp = new IProgressTimeStamp(); break;
	case DBType_CLOB:
	case DBType_BLOB:
	case DBType_FILE:
	case DBType_OBJECT:
	default:
		break;
	}
	if(tp!=NULL)
	{
		tp->SetFieldName(info.m_strName);
		tp->SetFlags(info.m_nFlags);
	} else
		throw(ISTDDBException(MEMNOTENOUGH,"New Field:no mem"));
	return tp;
}

#endif


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值