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