BUG: Oledb32.dll Truncates Data at the Embedded Null-termination Character if a Column Is Bound to DBTYPE_WSTR (313925)



The information in this article applies to:

  • Microsoft Data Access Components 2.1
  • Microsoft Data Access Components 2.5
  • Microsoft Data Access Components 2.6
  • Microsoft Data Access Components 2.7

This article was previously published under Q313925

SYMPTOMS

When an embedded null-termination character in a varchar column is bound to an OLEDB DBTYPE_WSTR data type, OLE DB Core Services Oledb32.dll truncates the data at the null-termination character.

RESOLUTION

To work around this problem, bind the column that contains a null-termination character to a DBTYPE_BSTR data type that allows embedded nulls.

STATUS

Microsoft has confirmed that this is a bug in the Microsoft products that are listed at the beginning of this article.

MORE INFORMATION

Steps to Reproduce Behavior

Bind a varchar column that has a hexadecimal value of 0x4142430044 in the database table to a DBTYPE_WSTR data type in the application. To do this, follow these steps:
  1. In a SQL server database named PUBS, create a table with a varchar column, as follows:
    CREATE TABLE myTest (col1 varchar (20) NOT NULL)
    					
  2. Insert a record into this table with 0x00 embedded in the data, as follows:
     INSERT INTO testVarchar VALUES (0x4142430044)
    					
  3. In Microsoft Visual C++ version 6.0, create a new Console Application project that contains the following code:
    #define UNICODE
    #define _UNICODE
    #define DBINITCONSTANTS
    #define INITGUID
    #define MAX_LEN 100
    
    #include <windows.h>
    #include <stdio.h>
    #include <oledb.h>
    #include <oledberr.h>
    
    void main()
    {
    IDBInitialize * pIDBInitialize = NULL;
    IDBProperties * pIDBProperties = NULL;
    ICommandText *		pICommandText;
    IRowset *			pIRowset;
    IAccessor *			pIAccessor;
    IDBCreateSession * pIDBCreateSession;
    IDBCreateCommand * pIDBCreateCommand;
    CLSID clsid;
    const ULONG nProps = 1;
    DBPROP InitProperties[ nProps ];
    DBPROPSET rgInitPropSet;
    HRESULT				hr;
    BYTE*				pRowValues;
    HACCESSOR			hAccessor;
    LONG				cRowsAffected;
    DBBINDING *			pDBBindings = NULL;
    ULONG cbRow = 0;
    ULONG cRowsObtained;
    LPOLESTR bSQLString = OLESTR( "select col1 from pubs..myTest" );
    HROW rghRows[ 1 ];
    HROW * pRows = & rghRows[ 0 ];
    ULONG iRow;
    
    	VariantInit( &InitProperties[ 0 ].vValue );
    	InitProperties[ 0 ].dwOptions = DBPROPOPTIONS_REQUIRED;
    	InitProperties[ 0 ].colid = DB_NULLID;
    	InitProperties[ 0 ].dwPropertyID = DBPROP_INIT_PROVIDERSTRING;
    	InitProperties[ 0 ].vValue.vt = VT_BSTR;
    	InitProperties[ 0 ].vValue.bstrVal = 
    	Server=kavi1;database=pubs;uid=sa;pwd=sa;
     
    	rgInitPropSet.guidPropertySet = DBPROPSET_DBINIT;
    	rgInitPropSet.cProperties = nProps;
    	rgInitPropSet.rgProperties = InitProperties;
    
    	CoInitialize( NULL );
    
    	CLSIDFromProgID( L"SQLOLEDB", & clsid );
    
    	hr = CoCreateInstance( clsid, 
    				NULL, 
    				CLSCTX_INPROC_SERVER, 
    				IID_IDBInitialize, 
    				( void ** ) & pIDBInitialize );
    
    	if( pIDBInitialize == NULL )
    	{
    		printf( "CoCreateInstance failed.\n" );
    		return;
    	}
    
    	pIDBInitialize->QueryInterface( IID_IDBProperties,
    		( void ** ) & pIDBProperties );
    
    	hr = pIDBProperties->SetProperties( 1, & rgInitPropSet );
    
    	SysFreeString( InitProperties[ 0 ].vValue.bstrVal );
    
    	pIDBProperties->Release();
    
    	if( FAILED( hr ) )
    	{
    		printf( "Set properties failed.\n" );
    		return;
    	}
    
    	if( FAILED( hr = pIDBInitialize->Initialize() ) )
    	{
    		printf( "Initialize) failed\n" );
    	}
    
    	// Get the db session object
    	if( FAILED( pIDBInitialize->QueryInterface( IID_IDBCreateSession,
    		( void ** ) & pIDBCreateSession ) ) )
    	{
    		printf( "Session Initialization failed.\n" );
    		return;
    	}
    
    	// create the session
    	if( FAILED( pIDBCreateSession->CreateSession( NULL,
    		IID_IDBCreateCommand,
    		( IUnknown ** ) & pIDBCreateCommand ) ) )
    	{
    		printf( "Create session failed.\n" );
    		pIDBCreateSession->Release();
    		return;
    	}
    
    
    	// Create the command object
    	if( FAILED( pIDBCreateCommand->CreateCommand( NULL,
    		IID_ICommandText,
    		( IUnknown ** ) & pICommandText ) ) )
    	{
    		printf( "Create command failed.\n" );
    		return;
    	}
    
    	pIDBCreateCommand->Release();
    
    	// provide the command, language and dialect
    	if( FAILED( pICommandText->SetCommandText( DBGUID_DBSQL, bSQLString ) ) )
    	{
    		printf( "Could not set CommandText\n" );
    		return;
    	}
    
    	if( FAILED( hr = pICommandText->Execute( NULL, 
    		IID_IRowset, 
    		NULL, 
    		& cRowsAffected, 
    		( IUnknown ** ) & pIRowset ) ) )
    	{
    		printf( "Execute failed\n" );
    		return;
    	}
    
    	pDBBindings = new DBBINDING[1];
    
    		pDBBindings[ 0 ].iOrdinal = 1;
    		pDBBindings[ 0 ].obValue = 8;
    		pDBBindings[ 0 ].obLength = 4;
    		pDBBindings[ 0 ].obStatus = 0;
    		pDBBindings[ 0 ].pTypeInfo = NULL;
    		pDBBindings[ 0 ].pObject = NULL;
    		pDBBindings[ 0 ].pBindExt = NULL;
    		pDBBindings[ 0 ].dwPart = DBPART_VALUE | DBPART_STATUS | DBPART_LENGTH;
    		pDBBindings[ 0 ].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
    		pDBBindings[ 0 ].eParamIO = DBPARAMIO_NOTPARAM;
    		pDBBindings[ 0 ].cbMaxLen = MAX_LEN;
    		pDBBindings[ 0 ].dwFlags = 0;
    		pDBBindings[ 0 ].wType = DBTYPE_WSTR;
    		pDBBindings[ 0 ].bPrecision = 0;
    		pDBBindings[ 0 ].bScale = 0;
    
    	pRowValues = new BYTE[ MAX_LEN ];
    	memset( pRowValues, 0, MAX_LEN );
    
    	// create an accessor to fetch the data with
    	hr = pIRowset->QueryInterface( IID_IAccessor, ( void ** ) & pIAccessor);
    
    	if( FAILED( hr ) )
    	{
    		printf( "QI for IAccessor failed\n" );
    		return;
    	}
    
    	if( FAILED( hr = pIAccessor->CreateAccessor( DBACCESSOR_ROWDATA, 
    			1, 
    			pDBBindings, 
    			sizeof( pDBBindings ),
    			& hAccessor,
    			NULL ) ) )
    	{
    		printf( "CreateAccessor() failed\n" );
    		return;
    	}
    
    
    	// process the rows 
    	while( TRUE )
    	{
    		hr = pIRowset->GetNextRows( 0, 0, 10, & cRowsObtained, & pRows );
    
    		// all done, there are no more rows to get
    		if( cRowsObtained == 0 )
    			break;
    
    		// loop over rows obtained, getting data for each
    		for( iRow = 0 ; iRow < cRowsObtained ; iRow++ )
    		{
    			hr = pIRowset->GetData( rghRows[ iRow ], hAccessor, pRowValues );
    			printf("Length of row[%d]:%d\n",iRow+1,*(pRowValues+4));
    			printf("Value of Col1:");
    	
    			for(int byteCnt=0;byteCnt<(*(pRowValues+4))-1;byteCnt++)
    						printf( "%x",(pRowValues+8)[byteCnt]);
    			
    			printf("\n\n");
    		}
    		pIRowset->ReleaseRows( cRowsObtained, rghRows, NULL, NULL, NULL );
    	}
    	pIAccessor->ReleaseAccessor( hAccessor, NULL );
    	pIAccessor->Release();
    	pIRowset->Release();
    	pICommandText->Release();
    	pIDBCreateSession->Release();
    
    	delete [] pDBBindings;
    	delete [] pRowValues;
    	
    	if( pIDBInitialize )
    		if( ! FAILED( hr=pIDBInitialize->Uninitialize() ) )
    			pIDBInitialize->Release();
    		else
    			printf( "Uninitialize failed.\n Something didn't get released.\n" );
    }
    					
  4. Build and run the project. Note that Oledb32.dll truncates the string at the null-termination character, so that the data that is retrieved is as follows:
       Length:6
       Value:41042043
    					
You expect the following results:
         Length:10
         Value:4104204300044
				

Modification Type:MajorLast Reviewed:5/12/2003
Keywords:kbBug kbfix KB313925