📄 odbcrecordset.cpp
字号:
/*************************************************************************
FILE : ODBCRecordset.cpp
Author : Stefan Tchekanov (stefant@iname.com)
Description: CODBCRecordset and CDBField classes implementation
Created By : Stefan Tchekanov
Copyright(c) 1998,1999,2000
Stefan Tchekanov (stefant@iname.com)
This code may be used in compiled form in any way you desire. This
file may be redistributed unmodified by any means PROVIDING it is
not sold for profit without the authors written consent, and
providing that this notice and the authors name is included. If
the source code in this file is used in any commercial application
then a simple email to the author would be nice.
This file is provided "as is" with no expressed or implied warranty.
The author accepts no liability if it causes any damage.
*************************************************************************/
/* # Revisions # */
/*************************************************************************
REVISION ON 12.09.2000 15:27:22 By Stefan Tchekanov
Comments : The field names in DoFieldExchange() are made to be quoted
in square brackets - [FieldName]. This is the way the class
wizard passes field names in DoFieldExchange() implementations.
*************************************************************************/
/*************************************************************************
REVISION ON 09.06.2000 21:46:00 By Stefan Tchekanov
Comments : 1. Added CDBField::operator =( const char );
2. Removed (!IsEOF()) && (!IsBOF()) from the ASSERT in
CODBCRecordset::Field( int nField ) to be able to
add records on empty recordsets
*************************************************************************/
////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "ODBCRecordset.h"
////////////////////////////////////////////////////////////////
//
// CODBCRecordset class
//
////////////////////////////////////////////////////////////////
CODBCRecordset::CODBCRecordset( CDatabase* pDatabase /*= NULL*/ ) :
CRecordset( pDatabase )
{
m_fields = NULL;
m_AllocatedFields = 0;
}
////////////////////////////////////////////////////////////////
CODBCRecordset::~CODBCRecordset() {
Clear();
}
////////////////////////////////////////////////////////////////
// Frees all the allocated memory
void CODBCRecordset::Clear() {
if( m_fields != NULL )
delete[] m_fields;
m_fields = NULL;
m_AllocatedFields = 0;
}
////////////////////////////////////////////////////////////////
// Open the recordset
// lpszSQL is a SQL statement that returns recordset
// e.g. SELECT * FROM tablename
// nOpentype is CRecordset open type, see CRecordset::Open()
// dwOptions is CRecordset options, see CRecordset::Open()
BOOL CODBCRecordset::Open( LPCTSTR lpszSQL,
UINT nOpenType, /*=AFX_DB_USE_DEFAULT_TYPE*/
DWORD dwOptions /*= 0*/ )
{
// Allocate the maximum possible field info storage
// This is managed by CRecordset class
m_nFields = 255;
m_bNotLoadedFieldsMap = true;
BOOL nRes = CRecordset::Open(
nOpenType,
lpszSQL,
dwOptions );
return nRes;
}
////////////////////////////////////////////////////////////////
// Called by Move() to load info about all the fields
void CODBCRecordset::LoadFieldNamesMap()
{
m_mapNameIdx.RemoveAll();
int nFields = m_nFields = GetODBCFieldCount();
// Smart storage reallocation for the fields buffer
if( m_AllocatedFields < nFields ) {
Clear();
m_fields = new CDBField[ m_nFields ];
m_AllocatedFields = m_nFields;
}
// Load field names map
CODBCFieldInfo fi;
CString cName;
for( int i = 0; i < nFields; i++ ) {
// Clear the previously allocated storage object
m_fields[i].Clear();
// Determine the field type and initialize the data buffer
GetODBCFieldInfo( i, fi );
AllocDataBuffer( m_fields[i], fi );
// Set the field name
fi.m_strName.MakeUpper();
cName = fi.m_strName;
// Make different field names for the fields with
// equal names.
int fldCount = 1;
while( GetFieldID( cName ) != -1 ) {
fldCount++;
cName.Format( "%s%d", fi.m_strName, fldCount );
}
m_fields[i].m_cName = cName;
m_mapNameIdx.SetAt( cName, (void*)i );
}
}
////////////////////////////////////////////////////////////////
// Overloaded so all the fields be loaded when needed
void CODBCRecordset::Move( long nRows, WORD wFetchType /*= SQL_FETCH_RELATIVE*/ )
{
if( m_bNotLoadedFieldsMap )
{
LoadFieldNamesMap();
m_bNotLoadedFieldsMap = false;
}
CRecordset::Move( nRows, wFetchType );
}
////////////////////////////////////////////////////////////////
// Get the field ID by name
// GetFieldIndexByName() works, but is case sensitive
int CODBCRecordset::GetFieldID( LPCTSTR szName )
{
void* idx = (void*)-1;
CString cName( szName );
cName.MakeUpper();
if( ! m_mapNameIdx.Lookup( cName, idx ) )
return -1;
return (int)idx;
}
CString CODBCRecordset::GetFieldName( int nField )
{
// The field ID is invalid
ASSERT( nField >= 0 );
ASSERT( nField < GetODBCFieldCount() );
CString cName;
void* idx;
POSITION pos = m_mapNameIdx.GetStartPosition();
while( pos != NULL ) {
m_mapNameIdx.GetNextAssoc( pos, cName, idx );
if( (int)idx == nField )
return cName;
}
cName.Empty();
return cName;
}
////////////////////////////////////////////////////////////////
void CODBCRecordset::DoFieldExchange( CFieldExchange* pFX )
{
pFX->SetFieldType( CFieldExchange::outputColumn );
CString cFieldName;
for( UINT i = 0; i < m_nFields; i++ )
{
cFieldName.Format( "[%s]", GetFieldName(i) );
switch( m_fields[i].m_dwType )
{
case DBVT_NULL:
break;
case DBVT_BOOL:
RFX_Bool( pFX, cFieldName, m_fields[i].m_boolVal );
break;
case DBVT_UCHAR:
RFX_Byte( pFX, cFieldName, m_fields[i].m_chVal );
break;
case DBVT_SHORT:
// CDBVariant::m_iVal is of type short
// RFX_Int() requires parameter of type int.
// Class wizard maps int variable in this case
// but CDBVariand does not have int member.
m_fields[i].m_dwType = DBVT_LONG;
RFX_Long( pFX, cFieldName, m_fields[i].m_lVal );
break;
case DBVT_LONG:
RFX_Long( pFX, cFieldName, m_fields[i].m_lVal );
break;
case DBVT_SINGLE:
RFX_Single( pFX, cFieldName, m_fields[i].m_fltVal );
break;
case DBVT_DOUBLE:
RFX_Double( pFX, cFieldName, m_fields[i].m_dblVal );
break;
case DBVT_DATE:
RFX_Date( pFX, cFieldName, *m_fields[i].m_pdate );
break;
case DBVT_STRING:
{
CODBCFieldInfo fi;
GetODBCFieldInfo( i, fi );
RFX_Text( pFX, cFieldName, *m_fields[i].m_pstring, fi.m_nPrecision );
break;
}
case DBVT_BINARY:
RFX_LongBinary( pFX, cFieldName, *(m_fields[i].m_pbinary) );
break;
default:
// Unknown datatype
ASSERT( FALSE );
}
m_fields[i].SetNull( FALSE != IsFieldStatusNull( i ) );
}
}
////////////////////////////////////////////////////////////////
short CODBCRecordset::GetCFieldType( short nSQLType )
{
short nFieldType = 0;
switch( nSQLType )
{
case SQL_BIT:
nFieldType = SQL_C_BIT;
break;
case SQL_TINYINT:
nFieldType = SQL_C_UTINYINT;
break;
case SQL_SMALLINT:
nFieldType = SQL_C_SSHORT;
break;
case SQL_INTEGER:
nFieldType = SQL_C_SLONG;
break;
case SQL_REAL:
nFieldType = SQL_C_FLOAT;
break;
case SQL_FLOAT:
case SQL_DOUBLE:
nFieldType = SQL_C_DOUBLE;
break;
case SQL_DATE:
case SQL_TIME:
case SQL_TIMESTAMP:
nFieldType = SQL_C_TIMESTAMP;
break;
case SQL_NUMERIC:
case SQL_DECIMAL:
case SQL_BIGINT:
case SQL_CHAR:
case SQL_VARCHAR:
nFieldType = SQL_C_CHAR;
break;
// SQL_LONGVARCHAR moved here.
// Its default value is SQL_C_CHAR
case SQL_LONGVARCHAR:
case SQL_BINARY:
case SQL_VARBINARY:
case SQL_LONGVARBINARY:
nFieldType = SQL_C_BINARY;
break;
default:
// Unknown data type
ASSERT( FALSE );
}
return nFieldType;
}
////////////////////////////////////////////////////////////////
void CODBCRecordset::AllocDataBuffer( CDBVariant& varValue, CODBCFieldInfo& fi )
{
int nFieldType = GetCFieldType( fi.m_nSQLType );
switch( nFieldType )
{
case SQL_C_BIT:
varValue.m_dwType = DBVT_BOOL;
break;
case SQL_C_UTINYINT:
varValue.m_dwType = DBVT_UCHAR;
break;
case SQL_C_SSHORT:
varValue.m_dwType = DBVT_SHORT;
break;
case SQL_C_SLONG:
varValue.m_dwType = DBVT_LONG;
break;
case SQL_C_FLOAT:
varValue.m_dwType = DBVT_SINGLE;
break;
case SQL_C_DOUBLE:
varValue.m_dwType = DBVT_DOUBLE;
break;
case SQL_C_TIMESTAMP:
varValue.m_pdate = new TIMESTAMP_STRUCT;
varValue.m_dwType = DBVT_DATE;
break;
case SQL_C_CHAR:
varValue.m_pstring = new CString;
varValue.m_dwType = DBVT_STRING;
break;
case SQL_C_BINARY:
varValue.m_pbinary = new CLongBinary;
varValue.m_dwType = DBVT_BINARY;
break;
default:
// Unknown data type
ASSERT( FALSE );
}
}
////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////
//
// CDBField implementation
//
////////////////////////////////////////////////////////////////
void BinaryToString( CString& cStr, const CLongBinary& bin, bool bExpand )
{
int nSize = min( (int)bin.m_dwDataLength, cStr.GetLength() );
if( bExpand )
nSize = bin.m_dwDataLength;
if( nSize < 1 ) {
cStr.Empty();
return;
}
void* p = ::GlobalLock( bin.m_hData );
if( p == NULL )
::AfxThrowMemoryException();
char* pStr = cStr.GetBuffer( nSize );
memcpy( pStr, p, nSize );
cStr.ReleaseBuffer( nSize );
::GlobalUnlock( bin.m_hData );
}
////////////////////////////////////////////////////////////////
CDBField::CDBField() {
m_bIsNull = true;
}
////////////////////////////////////////////////////////////////
CDBField::CDBField( const CDBField& dbv ) {
m_bIsNull = true;
}
////////////////////////////////////////////////////////////////
CDBField::~CDBField() {
}
////////////////////////////////////////////////////////////////
bool CDBField::AsBool() const
{
if( IsNull() )
return false;
CString cValue;
switch( m_dwType ) {
case DBVT_NULL:
return false;
case DBVT_BOOL:
return (m_boolVal == TRUE);
case DBVT_UCHAR:
return (m_chVal == 'T' || m_chVal == '1');
case DBVT_SHORT:
return (m_iVal != 0);
case DBVT_LONG:
return (m_lVal != 0);
case DBVT_SINGLE:
return (m_fltVal != 0.0);
case DBVT_DOUBLE:
return (m_dblVal != 0.0);
case DBVT_DATE:
// Cannot convert date to bool
ASSERT( FALSE );
break;
case DBVT_STRING:
ASSERT( m_pstring != NULL );
if( m_pstring->GetLength() < 1 )
return false;
return ((*m_pstring)[0] == 'T' || (*m_pstring)[0] == '1');
case DBVT_BINARY:
// Cannot convert long binary to bool
ASSERT( FALSE );
break;
}
// Undefined data type
ASSERT( FALSE );
return false;
}
unsigned char CDBField::AsChar() const
{
if( IsNull() )
return ' ';
switch( m_dwType ) {
case DBVT_NULL:
return ' ';
case DBVT_BOOL:
return (m_boolVal) ? 'T' : 'F';
case DBVT_UCHAR:
return m_chVal;
case DBVT_SHORT:
return (unsigned char)m_iVal;
case DBVT_LONG:
return (unsigned char)m_lVal;
case DBVT_SINGLE:
return (unsigned char)m_fltVal;
case DBVT_DOUBLE:
return (unsigned char)m_dblVal;
case DBVT_DATE:
// Cannot convert date to unsigned char
ASSERT( FALSE );
break;
case DBVT_STRING:
ASSERT( m_pstring != NULL );
if( m_pstring->GetLength() < 1 )
return ' ';
return (unsigned char)((*m_pstring)[0]);
case DBVT_BINARY:
// Cannot convert long binary to unsigned char
ASSERT( FALSE );
break;
}
// Undefined data type
ASSERT( FALSE );
return ' ';
}
short CDBField::AsShort() const
{
if( IsNull() )
return 0;
switch( m_dwType ) {
case DBVT_NULL:
return 0;
case DBVT_BOOL:
return m_boolVal ? 1 : 0;
case DBVT_UCHAR:
return (short)m_chVal;
case DBVT_SHORT:
return m_iVal;
case DBVT_LONG:
return (short)m_lVal;
case DBVT_SINGLE:
return (short)m_fltVal;
case DBVT_DOUBLE:
return (short)m_dblVal;
case DBVT_DATE:
// Cannot convert date to short
ASSERT( FALSE );
break;
case DBVT_STRING:
ASSERT( m_pstring != NULL );
return (short)atoi( *m_pstring );
case DBVT_BINARY:
// Cannot conver long binary to short
ASSERT( FALSE );
break;
}
// Undefined data type
ASSERT( FALSE );
return 0;
}
int CDBField::AsInt() const
{
return AsLong();
}
long CDBField::AsLong() const
{
if( IsNull() )
return 0;
switch( m_dwType ) {
case DBVT_NULL:
return 0;
case DBVT_BOOL:
return m_boolVal ? 1 : 0;
case DBVT_UCHAR:
return (long)m_chVal;
case DBVT_SHORT:
return (long)m_iVal;
case DBVT_LONG:
return m_lVal;
case DBVT_SINGLE:
return (long)m_fltVal;
case DBVT_DOUBLE:
return (long)m_dblVal;
case DBVT_DATE:
// Cannot convert date to long
ASSERT( FALSE );
break;
case DBVT_STRING:
ASSERT( m_pstring != NULL );
return atol( *m_pstring );
case DBVT_BINARY:
// Cannot conver long binary to long
ASSERT( FALSE );
break;
}
// Undefined data type
ASSERT( FALSE );
return 0;
}
float CDBField::AsFloat() const
{
if( IsNull() )
return 0.0;
switch( m_dwType ) {
case DBVT_NULL:
return 0.0;
case DBVT_BOOL:
return (float)(m_boolVal ? 1.0 : 0.0);
case DBVT_UCHAR:
return (float)m_chVal;
case DBVT_SHORT:
return (float)m_iVal;
case DBVT_LONG:
return (float)m_lVal;
case DBVT_SINGLE:
return m_fltVal;
case DBVT_DOUBLE:
return (float)m_dblVal;
case DBVT_DATE:
// Cannot convert date to float
ASSERT( FALSE );
break;
case DBVT_STRING:
ASSERT( m_pstring != NULL );
return (float)atof( *m_pstring );
case DBVT_BINARY:
// Cannot conver long binary to float
ASSERT( FALSE );
break;
}
// Undefined data type
ASSERT( FALSE );
return 0.0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -