Microsoft Knowledge Base Email Alertz

(229884) - When you use OLE DB with databases that support very large numeric types (for example, Oracle's NUMBER data type which supports up to 38 digits), OLE DB returns DBTYPE_VARNUMERIC as the column's data type. These large numbers can be stored and...

Search KbAlertz

Advanced Search

Receive Microsoft Knowledge Base articles by E-Mail?

Every night we scan the Microsoft Knowledge Base. If technologies you're interested in are updated, we'll send you an e-mail. You only get one e-mail a day, and only when new articles are added.

Click here to create a
FREE account
Already have an account?
[Click here to Login]











Microsoft Knowledge Base Article

This article contents is Microsoft Copyrighted material.
©2005-©2007 Microsoft Corporation. All rights reserved. Terms of Use | Trademarks

Article ID: 229884 - Last Review: August 30, 2004 - Revision: 2.2

How To Use OLE DB DBTYPE_VARNUMERIC

This article was previously published under Q229884

SUMMARY

When you use OLE DB with databases that support very large numeric types (for example, Oracle's NUMBER data type which supports up to 38 digits), OLE DB returns DBTYPE_VARNUMERIC as the column's data type. These large numbers can be stored and retrieved by using the OLE DB DB_VARNUMERIC structure, which is provided in the Oledb.h header file.

MORE INFORMATION

The DB_VARNUMERIC structure is declared as follows:
typedef struct  tagDB_VARNUMERIC
    {
    BYTE precision;
    SBYTE scale;
    BYTE sign;
    BYTE val[ 1 ];
    }	DB_VARNUMERIC;
				
The DB_VARNUMERIC structure member variable val[1] does not provide sufficient memory to hold a large number. To use this structure, declare a BYTE array with the appropriate size, and cast the array as a DB_VARNUMERIC structure to access the data members.

The following code illustrates how to retrieve these numbers and store them in a C double:
#define UNICODE
#define _UNICODE
#define DBINITCONSTANTS
#define INITGUID
#define NUMROWS_CHUNK 5

#include <windows.h>
#include <stdio.h>
#include <oledb.h>
#include <oledberr.h>

#include <stddef.h>
#include <math.h>

void main()
{
	IDBInitialize * pIDBInitialize;
	IRowset * pIRowset;
	IDBCreateSession * pIDBCreateSession;
	IDBCreateCommand * pIDBCreateCommand;
	ICommandText * pICommandText;
	ICommandProperties * pICommandProperties;
	IAccessor * pIAccessor;
	HACCESSOR hAccessor;
	IColumnsInfo * pIColumnsInfo;
	ULONG cColumns;
	DBCOLUMNINFO * prgInfo;
	OLECHAR * pStringsBuffer;
	IMalloc * pIMalloc;
	HRESULT hr;
	CLSID clsid;
	const ULONG nProps = 3;
	IDBProperties * pIDBProperties;
	DBPROP InitProperties[ nProps ];
	DBPROPSET rgInitPropSet;
	LPCTSTR wSQLString = OLESTR( "SELECT * FROM myTable" );
	LONG cRowsAffected;
	ULONG cRowsObtained;
	HROW rghRows;
	HROW * prghRows = & rghRows;
	ULONG cCmdPropertySets = 1;
	DBPROPSET rgCmdPropSet;
	DBBINDSTATUS DBBindStatus[2];
	DBBINDING DBBindings[1];
	BYTE * buffer;
	const ULONG nCmdProps = 2;
	DBPROP CmdProperties[ nCmdProps ];

	VariantInit( &InitProperties[ 0 ].vValue );
	InitProperties[ 0 ].dwPropertyID = DBPROP_INIT_DATASOURCE;
	InitProperties[ 0 ].dwOptions = DBPROPOPTIONS_REQUIRED;
	InitProperties[ 0 ].colid = DB_NULLID;
	InitProperties[ 0 ].vValue.vt = VT_BSTR;
	InitProperties[ 0 ].vValue.bstrVal = SysAllocString( OLESTR( "myServer" ) );

	VariantInit( &InitProperties[ 1 ].vValue );
	InitProperties[ 1 ].dwPropertyID = DBPROP_AUTH_USERID;
	InitProperties[ 1 ].dwOptions = DBPROPOPTIONS_REQUIRED;
	InitProperties[ 1 ].colid = DB_NULLID;
	InitProperties[ 1 ].vValue.vt = VT_BSTR;
	InitProperties[ 1 ].vValue.bstrVal = SysAllocString( OLESTR( "myUID" ) );

	VariantInit( &InitProperties[ 2 ].vValue );
	InitProperties[ 2 ].dwPropertyID = DBPROP_AUTH_PASSWORD;
	InitProperties[ 2 ].dwOptions = DBPROPOPTIONS_REQUIRED;
	InitProperties[ 2 ].colid = DB_NULLID;
	InitProperties[ 2 ].vValue.vt = VT_BSTR;
	InitProperties[ 2 ].vValue.bstrVal = SysAllocString( OLESTR( "myPWD" ) );

	rgInitPropSet.guidPropertySet = DBPROPSET_DBINIT;
	rgInitPropSet.cProperties = nProps;
	rgInitPropSet.rgProperties = InitProperties;

	CmdProperties[ 0 ].dwPropertyID = DBPROP_CANFETCHBACKWARDS;
	CmdProperties[ 0 ].dwOptions = DBPROPOPTIONS_REQUIRED;
	CmdProperties[ 0 ].dwStatus = DBPROPSTATUS_OK;
	CmdProperties[ 0 ].colid = DB_NULLID;
	CmdProperties[ 0 ].vValue.vt = VT_BOOL;
	CmdProperties[ 0 ].vValue.boolVal = VARIANT_TRUE;

	CmdProperties[ 1 ].dwPropertyID = DBPROP_SERVERCURSOR;
	CmdProperties[ 1 ].dwOptions = DBPROPOPTIONS_REQUIRED;
	CmdProperties[ 1 ].dwStatus = DBPROPSTATUS_OK;
	CmdProperties[ 1 ].colid = DB_NULLID;
	CmdProperties[ 1 ].vValue.vt = VT_BOOL;
	CmdProperties[ 1 ].vValue.boolVal = VARIANT_FALSE;

	rgCmdPropSet.guidPropertySet = DBPROPSET_ROWSET;
	rgCmdPropSet.cProperties = nCmdProps;
	rgCmdPropSet.rgProperties = CmdProperties;

	CoInitialize( NULL );

	hr = CLSIDFromProgID( L"MSDAORA", & clsid );

	
	hr = CoCreateInstance(clsid,
                               NULL,
                               CLSCTX_INPROC_SERVER,
                               IID_IDBInitialize,
                               ( void ** ) & pIDBInitialize );


	hr = CoGetMalloc( MEMCTX_TASK, & pIMalloc );

	pIDBInitialize->QueryInterface( IID_IDBProperties,
		( void ** ) & pIDBProperties );

	hr = pIDBProperties->SetProperties( 1, & rgInitPropSet );

	pIDBProperties->Release();

	SysFreeString( InitProperties[0].vValue.bstrVal );
	SysFreeString( InitProperties[1].vValue.bstrVal );
	SysFreeString( InitProperties[2].vValue.bstrVal );

	hr = pIDBInitialize->Initialize();

	hr = pIDBInitialize->QueryInterface( IID_IDBCreateSession,
		( void ** ) & pIDBCreateSession );

	hr = pIDBCreateSession->CreateSession( NULL,
			IID_IDBCreateCommand, ( IUnknown ** ) & pIDBCreateCommand );

	pIDBCreateSession->Release();

	hr = pIDBCreateCommand->CreateCommand( NULL,
			IID_ICommandText, ( IUnknown ** ) & pICommandText );

	pIDBCreateCommand->Release();

	hr = pICommandText->SetCommandText( DBGUID_DBSQL, wSQLString );

	hr = pICommandText->QueryInterface( IID_ICommandProperties,
			( void ** ) & pICommandProperties );

	hr = pICommandProperties->SetProperties( cCmdPropertySets, & rgCmdPropSet );

	pICommandProperties->Release();

	hr = pICommandText->Execute( NULL, IID_IRowset, NULL,
			& cRowsAffected, ( IUnknown ** ) & pIRowset );

	pICommandText->Release();

	pIRowset->QueryInterface( IID_IColumnsInfo, ( void ** ) & pIColumnsInfo );

	hr = pIColumnsInfo->GetColumnInfo( & cColumns, & prgInfo, & pStringsBuffer );

	// for the purposes of this example the table contains 1 column of type NUMBER
	// prgInfo[0].wType will be DBTYPE_VARNUMERIC == 139

	DBBindings[0].iOrdinal = prgInfo[0].iOrdinal;
	DBBindings[0].obValue = 0;
	DBBindings[0].obLength = 0;
	DBBindings[0].obStatus = 0;
	DBBindings[0].pTypeInfo = NULL;
	DBBindings[0].pObject = NULL;
	DBBindings[0].pBindExt = NULL;
	DBBindings[0].dwPart = DBPART_VALUE;
	DBBindings[0].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
	DBBindings[0].eParamIO = DBPARAMIO_NOTPARAM;
	DBBindings[0].cbMaxLen = prgInfo[0].ulColumnSize;
	DBBindings[0].dwFlags = prgInfo[0].dwFlags;
	DBBindings[0].wType = prgInfo[0].wType;
	DBBindings[0].bPrecision = prgInfo[0].bPrecision;
	DBBindings[0].bScale = prgInfo[0].bScale;

	// add 3 bytes for precision, scale, and sign
	buffer = new BYTE[ prgInfo[0].ulColumnSize + 3 ];
	ULONG valbufferlen = ( ULONG ) prgInfo[0].ulColumnSize;

	memset( buffer, 0, prgInfo[0].ulColumnSize + 3 );

	hr = pIRowset->QueryInterface( IID_IAccessor, ( void ** ) & pIAccessor );

	hr = pIAccessor->CreateAccessor( DBACCESSOR_ROWDATA, 
                                          1, 
                                          DBBindings, 
                                          prgInfo[0].ulColumnSize, 
                                          & hAccessor, 
                                          DBBindStatus );

	while( DB_S_ENDOFROWSET != pIRowset->GetNextRows( NULL, 0, 1, & cRowsObtained, & prghRows ) )
	{

		hr = pIRowset->GetData( rghRows, hAccessor, buffer );

		int prec = ( int ) ( ( DB_VARNUMERIC * ) buffer )->precision;
		int scale = ( int ) ( ( DB_VARNUMERIC * ) buffer )->scale;
		int sign = ( ( int ) ( ( DB_VARNUMERIC * ) buffer )->sign > 0 ) ? 1 : -1;

		//the following code will move the data bytes of the DB_VARNUMERIC to a double
		double dValue = 0;
		BYTE hi, lo;
		double multiplier = 1;
		double adjust = 1;

		for( ULONG i = 0, j = 0 ; i < valbufferlen ; i++, j+=2 )
		{
			hi = lo = ( ( DB_VARNUMERIC * ) buffer )->val[ i ];

			lo <<= 4;
			lo >>= 4;

			dValue += ( ( ( ULONG ) lo ) * multiplier );

			multiplier *= 16;

			hi >>= 4;

			dValue += ( ( ( ULONG ) hi ) * multiplier );

			multiplier *= 16;

		}

		for( int k = 0 ; k < scale ; k++ )
			adjust *= 10;

		adjust *= sign;

		dValue /= adjust;

		printf( "%f\n", dValue );

		memset( buffer, 0, prgInfo[0].ulColumnSize + 3 );
	}

	pIAccessor->ReleaseAccessor( hAccessor, NULL );

	pIAccessor->Release();

	pIMalloc->Free( pStringsBuffer );

	pIMalloc->Free( prgInfo );

	pIMalloc->Release();

	pIRowset->Release();

	pIColumnsInfo->Release();

	delete buffer;

	if( pIDBInitialize )
		if( SUCCEEDED( pIDBInitialize->Uninitialize() ) )
			pIDBInitialize->Release();
		else
			printf( "Uninitialize failed.\n Something didn't get released.\n" );
} 
				

APPLIES TO
  • Microsoft Data Access Components 1.5
  • Microsoft Data Access Components 2.0
  • Microsoft Data Access Components 2.1
  • Microsoft Data Access Components 2.5
  • Microsoft Data Access Components 2.6
  • Microsoft Data Access Components 2.7
Keywords: 
kbhowto kboracle KB229884
       

Community Feedback System

Very often, it takes hours to solve a problem. Very often, you've looked high and low, and have tried a lot of solutions. When you finally found it, chances are, it was because someone else helped you. Here's your chance to give back. Use our community feedback tool to let others know what worked for you and what didn't.

Please also understand that the community feedback system is not warranted to be correct, it's simply a system that we've built to let people try and help each other. If something in a feedback response doesn't make sense to you, or you're not comfortable making changes that the feedback talks about (like registry edits), please consult a professional.

Thank you for using kbAlertz.com Feedback System.

-- Scott Cate