static HB_ERRCODE odbcGoTo( SQLBASEAREAP pArea, HB_ULONG ulRecNo ) { SQLHSTMT hStmt; SQLRETURN res; SQLLEN iLen; PHB_ITEM pArray, pItem; LPFIELD pField; HB_USHORT ui; /* No pArea->pSDDData for DBCreate() area... * though pArea->fFetched == HB_TRUE for them */ hStmt = pArea->pSDDData ? ( ( SDDDATA * ) pArea->pSDDData )->hStmt : NULL; while( ulRecNo > pArea->ulRecCount && ! pArea->fFetched ) { if( ! SQL_SUCCEEDED( SQLFetch( hStmt ) ) ) { pArea->fFetched = HB_TRUE; break; } pArray = hb_itemArrayNew( pArea->area.uiFieldCount ); pItem = NULL; for( ui = 1; ui <= pArea->area.uiFieldCount; ui++ ) { iLen = SQL_NULL_DATA; res = 0; pField = pArea->area.lpFields + ui - 1; switch( pField->uiType ) { case HB_FT_STRING: if( pField->uiType & HB_FF_BINARY ) { char buffer[ 1 ]; iLen = 0; if( SQL_SUCCEEDED( res = SQLGetData( hStmt, ui, SQL_C_BINARY, buffer, 0, &iLen ) ) ) { if( iLen >= 0 ) { char * val = ( char * ) hb_xgrab( iLen + 1 ); if( SQL_SUCCEEDED( res = SQLGetData( hStmt, ui, SQL_C_BINARY, val, iLen + 1, &iLen ) ) ) pItem = hb_itemPutCLPtr( pItem, val, ( HB_SIZE ) iLen ); else hb_xfree( val ); } } } else { O_HB_CHAR buffer[ 1 ]; #if defined( UNICODE ) SQLSMALLINT iTargetType = SQL_C_WCHAR; #else SQLSMALLINT iTargetType = SQL_C_CHAR; #endif iLen = 0; if( SQL_SUCCEEDED( res = SQLGetData( hStmt, ui, iTargetType, buffer, 0, &iLen ) ) ) { if( iLen >= 0 ) { O_HB_CHAR * val = ( O_HB_CHAR * ) hb_xgrab( iLen + sizeof( O_HB_CHAR ) ); if( SQL_SUCCEEDED( res = SQLGetData( hStmt, ui, iTargetType, val, iLen + sizeof( O_HB_CHAR ), &iLen ) ) ) { #if defined( UNICODE ) iLen >>= 1; #endif pItem = O_HB_ITEMPUTSTRLEN( pItem, val, ( HB_SIZE ) iLen ); } hb_xfree( val ); } } } break; case HB_FT_INTEGER: #if ODBCVER >= 0x0300 if( pField->uiTypeExtended == ( HB_USHORT ) SQL_BIGINT ) { HB_I64 val = 0; /* NOTE: SQL_C_SBIGINT not available before ODBC 3.0 */ if( SQL_SUCCEEDED( res = SQLGetData( hStmt, ui, SQL_C_SBIGINT, &val, sizeof( val ), &iLen ) ) ) pItem = hb_itemPutNIntLen( pItem, val, pField->uiLen ); } else #endif { SQLINTEGER val = 0; if( SQL_SUCCEEDED( res = SQLGetData( hStmt, ui, SQL_C_LONG, &val, sizeof( val ), &iLen ) ) ) pItem = hb_itemPutNLLen( pItem, val, pField->uiLen ); } break; case HB_FT_LONG: if( pField->uiDec == 0 && pField->uiLen < 10 ) { SQLINTEGER val = 0; if( SQL_SUCCEEDED( res = SQLGetData( hStmt, ui, SQL_C_LONG, &val, sizeof( val ), &iLen ) ) ) pItem = hb_itemPutNLLen( pItem, val, pField->uiLen ); } else { double val = 0.0; if( SQL_SUCCEEDED( res = SQLGetData( hStmt, ui, SQL_C_DOUBLE, &val, sizeof( val ), &iLen ) ) ) pItem = hb_itemPutNDLen( pItem, val, pField->uiLen, pField->uiDec ); } break; case HB_FT_DOUBLE: { double val = 0.0; if( SQL_SUCCEEDED( res = SQLGetData( hStmt, ui, SQL_C_DOUBLE, &val, sizeof( val ), &iLen ) ) ) pItem = hb_itemPutNDLen( pItem, val, pField->uiLen, pField->uiDec ); break; } case HB_FT_LOGICAL: { unsigned char val = 0; if( SQL_SUCCEEDED( res = SQLGetData( hStmt, ui, SQL_C_BIT, &val, sizeof( val ), &iLen ) ) ) pItem = hb_itemPutL( pItem, val != 0 ); break; } case HB_FT_DATE: { DATE_STRUCT val = { 0, 0, 0 }; if( SQL_SUCCEEDED( res = SQLGetData( hStmt, ui, SQL_C_DATE, &val, sizeof( val ), &iLen ) ) ) pItem = hb_itemPutD( pItem, val.year, val.month, val.day ); break; } case HB_FT_TIME: { TIME_STRUCT val = { 0, 0, 0 }; if( SQL_SUCCEEDED( res = SQLGetData( hStmt, ui, SQL_C_TIME, &val, sizeof( val ), &iLen ) ) ) pItem = hb_itemPutTDT( pItem, 0, hb_timeEncode( val.hour, val.minute, val.second, 0 ) ); break; } case HB_FT_TIMESTAMP: { TIMESTAMP_STRUCT val = { 0, 0, 0, 0, 0, 0, 0 }; if( SQL_SUCCEEDED( res = SQLGetData( hStmt, ui, SQL_C_TIMESTAMP, &val, sizeof( val ), &iLen ) ) ) pItem = hb_itemPutTDT( pItem, hb_dateEncode( val.year, val.month, val.day ), hb_timeEncode( val.hour, val.minute, val.second, val.fraction / 1000000 ) ); break; } } /* TODO: check SQL_SUCCEEDED( res ) */ /* TODO: check for SQL_NO_TOTAL. What does this mean? */ HB_SYMBOL_UNUSED( res ); if( pItem ) { /* NULL -> NIL */ if( iLen == SQL_NULL_DATA ) hb_itemClear( pItem ); else hb_arraySetForward( pArray, ui, pItem ); } } if( pItem ) hb_itemRelease( pItem ); if( pArea->ulRecCount + 1 >= pArea->ulRecMax ) { pArea->pRow = ( void ** ) hb_xrealloc( pArea->pRow, ( pArea->ulRecMax + SQLDD_ROWSET_RESIZE ) * sizeof( void * ) ); pArea->pRowFlags = ( HB_BYTE * ) hb_xrealloc( pArea->pRowFlags, ( pArea->ulRecMax + SQLDD_ROWSET_RESIZE ) * sizeof( HB_BYTE ) ); pArea->ulRecMax += SQLDD_ROWSET_RESIZE; } pArea->ulRecCount++; pArea->pRow[ pArea->ulRecCount ] = pArray; pArea->pRowFlags[ pArea->ulRecCount ] = SQLDD_FLAG_CACHED; }
static HB_ERRCODE odbcOpen( SQLBASEAREAP pArea ) { SDDCONN * pSDDConn = ( SDDCONN * ) pArea->pConnection->pSDDConn; SDDDATA * pSDDData; void * hQuery; SQLHSTMT hStmt; SQLSMALLINT iNameLen; PHB_ITEM pItemEof, pItem; HB_BOOL bError; HB_USHORT uiFields, uiIndex; HB_ERRCODE errCode; char * szError; pArea->pSDDData = memset( hb_xgrab( sizeof( SDDDATA ) ), 0, sizeof( SDDDATA ) ); pSDDData = ( SDDDATA * ) pArea->pSDDData; #if ODBCVER >= 0x0300 if( ! SQL_SUCCEEDED( SQLAllocHandle( SQL_HANDLE_STMT, pSDDConn->hConn, &hStmt ) ) ) #else if( ! SQL_SUCCEEDED( SQLAllocStmt( pSDDConn->hConn, &hStmt ) ) ) #endif { szError = odbcGetError( pSDDConn->hEnv, pSDDConn->hConn, SQL_NULL_HSTMT, &errCode ); hb_errRT_ODBCDD( EG_OPEN, ESQLDD_STMTALLOC, szError, pArea->szQuery, errCode ); hb_xfree( szError ); return HB_FAILURE; } pItem = hb_itemPutC( NULL, pArea->szQuery ); if( ! SQL_SUCCEEDED( SQLExecDirect( hStmt, ( SQLTCHAR * ) O_HB_ITEMGETSTR( pItem, &hQuery, NULL ), ( SQLINTEGER ) hb_itemGetCLen( pItem ) ) ) ) { hb_strfree( hQuery ); hb_itemRelease( pItem ); szError = odbcGetError( pSDDConn->hEnv, pSDDConn->hConn, hStmt, &errCode ); #if ODBCVER >= 0x0300 SQLFreeHandle( SQL_HANDLE_STMT, hStmt ); #else SQLFreeStmt( hStmt, SQL_DROP ); #endif hb_errRT_ODBCDD( EG_OPEN, ESQLDD_INVALIDQUERY, szError, pArea->szQuery, errCode ); hb_xfree( szError ); return HB_FAILURE; } else { hb_strfree( hQuery ); hb_itemRelease( pItem ); } if( ! SQL_SUCCEEDED( SQLNumResultCols( hStmt, &iNameLen ) ) ) { szError = odbcGetError( pSDDConn->hEnv, pSDDConn->hConn, hStmt, &errCode ); #if ODBCVER >= 0x0300 SQLFreeHandle( SQL_HANDLE_STMT, hStmt ); #else SQLFreeStmt( hStmt, SQL_DROP ); #endif hb_errRT_ODBCDD( EG_OPEN, ESQLDD_STMTDESCR + 1000, szError, pArea->szQuery, errCode ); hb_xfree( szError ); return HB_FAILURE; } uiFields = ( HB_USHORT ) iNameLen; SELF_SETFIELDEXTENT( ( AREAP ) pArea, uiFields ); pItemEof = hb_itemArrayNew( uiFields ); #if 0 HB_TRACE( HB_TR_ALWAYS, ( "fieldcount=%d", iNameLen ) ); #endif errCode = 0; bError = HB_FALSE; for( uiIndex = 0; uiIndex < uiFields; uiIndex++ ) { DBFIELDINFO pFieldInfo; PHB_ITEM pName; SQLTCHAR cName[ 256 ]; SQLULEN uiSize; SQLSMALLINT iDataType, iDec, iNull; if( ! SQL_SUCCEEDED( SQLDescribeCol( hStmt, ( SQLSMALLINT ) uiIndex + 1, ( SQLTCHAR * ) cName, HB_SIZEOFARRAY( cName ), &iNameLen, &iDataType, &uiSize, &iDec, &iNull ) ) ) { hb_itemRelease( pItemEof ); szError = odbcGetError( pSDDConn->hEnv, pSDDConn->hConn, hStmt, NULL ); #if ODBCVER >= 0x0300 SQLFreeHandle( SQL_HANDLE_STMT, hStmt ); #else SQLFreeStmt( hStmt, SQL_DROP ); #endif hb_errRT_ODBCDD( EG_OPEN, ESQLDD_STMTDESCR + 1001, szError, pArea->szQuery, 0 ); hb_xfree( szError ); return HB_FAILURE; } pName = O_HB_ITEMPUTSTRLEN( NULL, ( O_HB_CHAR * ) cName, iNameLen ); pFieldInfo.atomName = hb_itemGetCPtr( pName ); /* We do mapping of many SQL types to one Harbour field type here, so, we need store real SQL type in uiTypeExtended. SQL types are signed, so, HB_USHORT type casting is a little hacky. We need to remember use this casting also in expressions like this: if( pField->uiTypeExtended == ( HB_USHORT ) SQL_BIGINT ) or introduce our own unsigned SQL types. [Mindaugas] */ pFieldInfo.uiTypeExtended = ( HB_USHORT ) iDataType; pFieldInfo.uiLen = ( HB_USHORT ) uiSize; pFieldInfo.uiDec = iDec; #if 0 HB_TRACE( HB_TR_ALWAYS, ( "field: name=%s type=%d len=%d dec=%d null=%d", pFieldInfo.atomName, iDataType, uiSize, iDec, iNull ) ); #endif switch( iDataType ) { case SQL_CHAR: case SQL_VARCHAR: case SQL_LONGVARCHAR: case SQL_WCHAR: case SQL_WVARCHAR: case SQL_WLONGVARCHAR: pFieldInfo.uiType = HB_FT_STRING; break; case SQL_VARBINARY: case SQL_LONGVARBINARY: pFieldInfo.uiType = HB_FT_STRING; pFieldInfo.uiFlags = HB_FF_BINARY; break; case SQL_TINYINT: case SQL_SMALLINT: case SQL_INTEGER: case SQL_BIGINT: pFieldInfo.uiType = HB_FT_INTEGER; break; case SQL_DECIMAL: case SQL_NUMERIC: pFieldInfo.uiType = HB_FT_LONG; break; case SQL_REAL: case SQL_FLOAT: case SQL_DOUBLE: pFieldInfo.uiType = HB_FT_DOUBLE; break; case SQL_BIT: pFieldInfo.uiType = HB_FT_LOGICAL; break; case SQL_DATE: #if ODBCVER >= 0x0300 case SQL_TYPE_DATE: #endif pFieldInfo.uiType = HB_FT_DATE; break; case SQL_TIME: #if ODBCVER >= 0x0300 case SQL_TYPE_TIME: #endif pFieldInfo.uiType = HB_FT_DATE; break; /* SQL_DATETIME = SQL_DATE = 9 */ case SQL_TIMESTAMP: #if ODBCVER >= 0x0300 case SQL_TYPE_TIMESTAMP: #endif pFieldInfo.uiType = HB_FT_TIMESTAMP; break; default: #if 0 HB_TRACE( HB_TR_ALWAYS, ( "new sql type=%d", iDataType ) ); #endif bError = HB_TRUE; errCode = ( HB_ERRCODE ) iDataType; pFieldInfo.uiType = 0; pFieldInfo.uiType = HB_FT_STRING; break; } if( ! bError ) { switch( pFieldInfo.uiType ) { case HB_FT_STRING: { char * pStr; pStr = ( char * ) hb_xgrab( ( HB_SIZE ) pFieldInfo.uiLen + 1 ); memset( pStr, ' ', pFieldInfo.uiLen ); pStr[ pFieldInfo.uiLen ] = '\0'; pItem = hb_itemPutCL( NULL, pStr, pFieldInfo.uiLen ); hb_xfree( pStr ); break; } case HB_FT_MEMO: pItem = hb_itemPutC( NULL, NULL ); break; case HB_FT_INTEGER: pItem = hb_itemPutNI( NULL, 0 ); break; case HB_FT_LONG: if( pFieldInfo.uiDec == 0 ) pItem = hb_itemPutNLLen( NULL, 0, pFieldInfo.uiLen ); else pItem = hb_itemPutNDLen( NULL, 0.0, pFieldInfo.uiLen, pFieldInfo.uiDec ); break; case HB_FT_DOUBLE: pItem = hb_itemPutNDLen( NULL, 0.0, pFieldInfo.uiLen, pFieldInfo.uiDec ); break; case HB_FT_LOGICAL: pItem = hb_itemPutL( NULL, HB_FALSE ); break; case HB_FT_DATE: pItem = hb_itemPutDL( NULL, 0 ); break; case HB_FT_TIME: pItem = hb_itemPutTDT( NULL, 0, 0 ); break; case HB_FT_TIMESTAMP: pItem = hb_itemPutTDT( NULL, 0, 0 ); break; default: pItem = hb_itemNew( NULL ); bError = HB_TRUE; break; } hb_arraySetForward( pItemEof, uiIndex + 1, pItem ); hb_itemRelease( pItem ); if( ! bError ) bError = ( SELF_ADDFIELD( ( AREAP ) pArea, &pFieldInfo ) == HB_FAILURE ); } hb_itemRelease( pName ); if( bError ) break; } if( bError ) { hb_itemRelease( pItemEof ); #if ODBCVER >= 0x0300 SQLFreeHandle( SQL_HANDLE_STMT, hStmt ); #else SQLFreeStmt( hStmt, SQL_DROP ); #endif hb_errRT_ODBCDD( EG_CORRUPTION, ESQLDD_INVALIDFIELD, "Invalid field type", pArea->szQuery, errCode ); return HB_FAILURE; } pArea->ulRecCount = 0; pArea->ulRecMax = SQLDD_ROWSET_INIT; pArea->pRow = ( void ** ) hb_xgrab( SQLDD_ROWSET_INIT * sizeof( void * ) ); memset( pArea->pRow, 0, SQLDD_ROWSET_INIT * sizeof( void * ) ); pArea->pRowFlags = ( HB_BYTE * ) hb_xgrab( SQLDD_ROWSET_INIT * sizeof( HB_BYTE ) ); memset( pArea->pRowFlags, 0, SQLDD_ROWSET_INIT * sizeof( HB_BYTE ) ); pArea->pRow[ 0 ] = pItemEof; pArea->pRowFlags[ 0 ] = SQLDD_FLAG_CACHED; pSDDData->hStmt = hStmt; return HB_SUCCESS; }