/* 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" #includeint 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 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 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 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 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 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 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 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