1442 lines
44 KiB
C++
1442 lines
44 KiB
C++
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1998 - 2000.
|
||
|
//
|
||
|
// File: odbvarnt.cxx
|
||
|
//
|
||
|
// Contents: Helper class for PROPVARIANTs, OLE-DB variant types and
|
||
|
// Automation variant types in tables
|
||
|
//
|
||
|
// Classes: COLEDBVariant - derives from CTableVariant
|
||
|
//
|
||
|
// Functions:
|
||
|
//
|
||
|
// History: 09 Jan 1998 VikasMan Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
#include "pch.cxx"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#include <bigtable.hxx>
|
||
|
#include <odbvarnt.hxx>
|
||
|
|
||
|
#include <initguid.h>
|
||
|
#define DBINITCONSTANTS
|
||
|
#include <msdadc.h> // oledb data conversion (IDataConvert) interface
|
||
|
#include <msdaguid.h>
|
||
|
|
||
|
#include "tabledbg.hxx"
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: COLEDBVariant::OLEDBConvert, public.
|
||
|
//
|
||
|
// Synopsis: Data conversion routine, which uses the OLEDB data
|
||
|
// conversion library (MSDADC.DLL) to do the conversion.
|
||
|
//
|
||
|
// Arguments: [pbDstBuf] -- the Destination data buffer
|
||
|
// [cbDstBuf] -- the size of Dst. buffer
|
||
|
// [vtDst] -- the Destination type.
|
||
|
// [rPool] -- pool to use for destination buffers
|
||
|
// [rcbDstLength] -- size of destination data
|
||
|
// [xDataConvert] -- the OLEDB IDataConvert interface
|
||
|
// [bPrecision] -- The precision of the output data in bytes,
|
||
|
// if applicable. This argument is used when
|
||
|
// converting to DBTYPE_NUMERIC data only.
|
||
|
// [bScale] -- The scale of the output data in bytes,
|
||
|
// if applicable. This argument is used when
|
||
|
// converting to DBTYPE_NUMERIC data only.
|
||
|
//
|
||
|
// Returns: DBSTATUS_S_OK if conversion is successful,
|
||
|
// else other DBSTATUS values.
|
||
|
//
|
||
|
// Notes: pbDstBuf should have (enough) memory allocated, else
|
||
|
// truncation can happen.
|
||
|
//
|
||
|
// This routine is subdivided into 3 parts:
|
||
|
// - It checks first if we are dealing with Automation Vars.
|
||
|
// - Then it calls CTableVaraint::CopyOrCoerce to the job
|
||
|
// - If unsuccessful, it uses the OLE-DB library
|
||
|
//
|
||
|
// History: 09 Jan 1998 VikasMan Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
DBSTATUS COLEDBVariant::OLEDBConvert(
|
||
|
BYTE * pbDstBuf,
|
||
|
DBLENGTH cbDstBuf,
|
||
|
VARTYPE vtDst,
|
||
|
PVarAllocator & rPool,
|
||
|
DBLENGTH & rcbDstLength,
|
||
|
XInterface<IDataConvert>& xDataConvert,
|
||
|
BOOL fExtTypes, /* = TRUE */
|
||
|
BYTE bPrecision, /* = 0 */
|
||
|
BYTE bScale /* = 0 */ ) const
|
||
|
{
|
||
|
void* pbSrcBuf;
|
||
|
ULONG cbSrcSize;
|
||
|
DBTYPE dbtypeSrc, dbtypeDst;
|
||
|
DBLENGTH cbDstBufNeeded;
|
||
|
DBSTATUS DstStatus = DBSTATUS_E_CANTCONVERTVALUE;
|
||
|
|
||
|
// Check if fExtTypes is false and we are dealing with automation variants
|
||
|
if ( VT_VARIANT == vtDst || DBTYPE_PROPVARIANT == vtDst )
|
||
|
{
|
||
|
Win4Assert(cbDstBuf == sizeof PROPVARIANT);
|
||
|
|
||
|
rcbDstLength = sizeof (PROPVARIANT);
|
||
|
if ( ! IsArray( vt) &&
|
||
|
( fExtTypes || DBTYPE_PROPVARIANT == vtDst ||
|
||
|
VT_BSTR == vt || (IsSimpleOAType( vt ) && ! IsVector( vt )) ) )
|
||
|
{
|
||
|
Copy( (CTableVariant*) pbDstBuf, rPool, (USHORT) VarDataSize() );
|
||
|
DstStatus = DBSTATUS_S_OK;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DstStatus = _CopyToOAVariant( (VARIANT *) pbDstBuf, rPool );
|
||
|
}
|
||
|
|
||
|
if ( VT_EMPTY == vt )
|
||
|
DstStatus = DBSTATUS_S_ISNULL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// try converting using CTableVariant's CopyOrCoerce
|
||
|
DstStatus = CopyOrCoerce( pbDstBuf,
|
||
|
cbDstBuf,
|
||
|
vtDst,
|
||
|
rcbDstLength,
|
||
|
rPool );
|
||
|
}
|
||
|
|
||
|
if ( DBStatusOK( DstStatus ))
|
||
|
{
|
||
|
// we are done here
|
||
|
return DstStatus;
|
||
|
}
|
||
|
|
||
|
if (DBTYPE_HCHAPTER == vtDst)
|
||
|
{
|
||
|
if (VT_I4 == vt || VT_UI4 == vt)
|
||
|
{
|
||
|
* (ULONG *) pbDstBuf = lVal;
|
||
|
DstStatus = DBSTATUS_S_OK;
|
||
|
}
|
||
|
|
||
|
return DstStatus;
|
||
|
}
|
||
|
|
||
|
// WORKAROUND: The following switch stmt is needed only until
|
||
|
// OLEDB library supports VT_FILETIME. Once it does that,
|
||
|
// we can get rid of this.
|
||
|
|
||
|
switch ( vtDst )
|
||
|
{
|
||
|
case VT_DATE:
|
||
|
// allow coercions from I8, UI8, R8, and FILETIME
|
||
|
|
||
|
if (VT_I8 == vt || VT_UI8 == vt)
|
||
|
{
|
||
|
* (LONGLONG *) pbDstBuf = hVal.QuadPart;
|
||
|
}
|
||
|
else if (VT_R8 == vt)
|
||
|
{
|
||
|
* (DATE *) pbDstBuf = dblVal;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DstStatus = _StoreDate(pbDstBuf, cbDstBuf, vtDst);
|
||
|
}
|
||
|
rcbDstLength = sizeof (DATE);
|
||
|
break;
|
||
|
|
||
|
case VT_FILETIME:
|
||
|
// allow coercions from I8, UI8, and DATE
|
||
|
|
||
|
if (VT_I8 == vt || VT_UI8 == vt)
|
||
|
{
|
||
|
* (LONGLONG *) pbDstBuf = hVal.QuadPart;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DstStatus = _StoreDate(pbDstBuf, cbDstBuf, vtDst);
|
||
|
}
|
||
|
rcbDstLength = sizeof (FILETIME);
|
||
|
break;
|
||
|
|
||
|
case DBTYPE_DBDATE:
|
||
|
DstStatus = _StoreDate(pbDstBuf, cbDstBuf, vtDst);
|
||
|
rcbDstLength = sizeof (DBDATE);
|
||
|
break;
|
||
|
|
||
|
case DBTYPE_DBTIME:
|
||
|
DstStatus = _StoreDate(pbDstBuf, cbDstBuf, vtDst);
|
||
|
rcbDstLength = sizeof (DBTIME);
|
||
|
break;
|
||
|
|
||
|
case DBTYPE_DBTIMESTAMP:
|
||
|
DstStatus = _StoreDate(pbDstBuf, cbDstBuf, vtDst);
|
||
|
rcbDstLength = sizeof (DBTIMESTAMP);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if ( DBStatusOK( DstStatus ))
|
||
|
{
|
||
|
// we are done here
|
||
|
return DstStatus;
|
||
|
}
|
||
|
|
||
|
tbDebugOut(( DEB_ITRACE, "COLEDBVaraint::OLEDBConvert - Using OLEDB library for conversion\n" ));
|
||
|
|
||
|
// this looks like a job for ole-db
|
||
|
|
||
|
// check if we have the IDataConvert interface
|
||
|
if ( xDataConvert.IsNull( ) )
|
||
|
{
|
||
|
// let's get it then
|
||
|
if ( !_GetIDataConvert( xDataConvert ) )
|
||
|
{
|
||
|
// for some reason we could not get the IDataConvert interface
|
||
|
return DBSTATUS_E_CANTCONVERTVALUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// get the source data pointer
|
||
|
pbSrcBuf = _GetDataPointer();
|
||
|
if ( 0 == pbSrcBuf )
|
||
|
{
|
||
|
tbDebugOut(( DEB_ERROR, "OLEDBConvert - _GetDataPointer returned NULL\n" ));
|
||
|
|
||
|
return DBSTATUS_E_CANTCONVERTVALUE;
|
||
|
}
|
||
|
|
||
|
// get the source data size
|
||
|
cbSrcSize = VarDataSize();
|
||
|
|
||
|
// get the OLEDB source type
|
||
|
SCODE sc = _GetOLEDBType( vt, dbtypeSrc );
|
||
|
if ( S_OK != sc )
|
||
|
{
|
||
|
// can't use the OLEDB Conversion library
|
||
|
tbDebugOut(( DEB_ERROR,
|
||
|
"OLEDBConvert - _GetOLEDBType returned error 0x%x for type %x\n",
|
||
|
sc, vt ));
|
||
|
return DBSTATUS_E_CANTCONVERTVALUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
// the destination type has to be an OLE-DB type
|
||
|
dbtypeDst = vtDst;
|
||
|
|
||
|
// get the needed Destination size
|
||
|
sc = xDataConvert->GetConversionSize( dbtypeSrc,
|
||
|
dbtypeDst,
|
||
|
0,
|
||
|
&cbDstBufNeeded,
|
||
|
pbSrcBuf );
|
||
|
|
||
|
if ( sc != S_OK )
|
||
|
{
|
||
|
tbDebugOut(( DEB_ITRACE,
|
||
|
"OLEDBConvert - GetConversionSize returned error 0x%x\n",
|
||
|
sc ));
|
||
|
return DBSTATUS_E_CANTCONVERTVALUE;
|
||
|
}
|
||
|
|
||
|
BYTE* pbDest = 0;
|
||
|
|
||
|
// we need to allocate memory if ...
|
||
|
|
||
|
if ( ( IsLPWSTR( dbtypeDst ) ) ||
|
||
|
( IsLPSTR( dbtypeDst ) ) ||
|
||
|
( (DBTYPE_BYREF | DBTYPE_WSTR) == dbtypeDst ) ||
|
||
|
( (DBTYPE_BYREF | DBTYPE_STR) == dbtypeDst )
|
||
|
)
|
||
|
{
|
||
|
// If we hit this assert, then we got a few things to think about
|
||
|
|
||
|
Win4Assert( !(IsLPWSTR( dbtypeDst ) || IsLPSTR( dbtypeDst )) );
|
||
|
|
||
|
pbDest = (BYTE*) rPool.Allocate( (ULONG) cbDstBufNeeded );
|
||
|
}
|
||
|
else if ( DBTYPE_BSTR == dbtypeDst )
|
||
|
{
|
||
|
pbDest = (BYTE*) rPool.AllocBSTR( (ULONG) cbDstBufNeeded );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// bogus assert
|
||
|
// Win4Assert ( (dbtypeDst & DBTYPE_BYREF) == 0 );
|
||
|
|
||
|
// memory is already allocated
|
||
|
// use the size which is less
|
||
|
// if cbDstBuf is less than cbDstBufNeeded, truncation might happen
|
||
|
cbDstBufNeeded = ( cbDstBufNeeded < cbDstBuf ? cbDstBufNeeded : cbDstBuf );
|
||
|
}
|
||
|
|
||
|
// do the conversion
|
||
|
sc = xDataConvert->DataConvert( dbtypeSrc,
|
||
|
dbtypeDst,
|
||
|
cbSrcSize,
|
||
|
&rcbDstLength,
|
||
|
pbSrcBuf,
|
||
|
pbDest ? (void*)&pbDest : pbDstBuf,
|
||
|
cbDstBufNeeded,
|
||
|
DstStatus,
|
||
|
&DstStatus,
|
||
|
bPrecision,
|
||
|
bScale,
|
||
|
DBDATACONVERT_DEFAULT);
|
||
|
|
||
|
if ( sc != S_OK )
|
||
|
{
|
||
|
tbDebugOut(( DEB_ITRACE,
|
||
|
"OLEDBConvert - DataConvert returned error 0x%x\n",
|
||
|
sc ));
|
||
|
return DBSTATUS_E_CANTCONVERTVALUE;
|
||
|
}
|
||
|
|
||
|
// if memory was allocated, put that ptr in pbDstBuf
|
||
|
if ( pbDest )
|
||
|
{
|
||
|
*((BYTE**)(pbDstBuf)) = pbDest;
|
||
|
}
|
||
|
|
||
|
return DstStatus;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: COLEDBVariant::GetDstLength, public.
|
||
|
//
|
||
|
// Synopsis: Returns the length required after the conversion without
|
||
|
// actually doing the conversion.
|
||
|
//
|
||
|
// History: 10-12-98 DanLeg Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
DBSTATUS COLEDBVariant::GetDstLength(
|
||
|
XInterface<IDataConvert>& xDataConvert,
|
||
|
DBTYPE dbtypeDst,
|
||
|
DBLENGTH & rcbDstLen )
|
||
|
{
|
||
|
SCODE sc = S_OK;
|
||
|
DBTYPE dbtypeSrc;
|
||
|
DBSTATUS DstStatus = DBSTATUS_S_OK;
|
||
|
|
||
|
sc = _GetOLEDBType( vt, dbtypeSrc );
|
||
|
|
||
|
if ( S_OK == sc )
|
||
|
{
|
||
|
if ( xDataConvert.IsNull( ) )
|
||
|
{
|
||
|
if ( !_GetIDataConvert( xDataConvert ) )
|
||
|
sc = S_FALSE;
|
||
|
}
|
||
|
|
||
|
if ( S_OK == sc )
|
||
|
{
|
||
|
void * pbSrcBuf = _GetDataPointer();
|
||
|
sc = xDataConvert->GetConversionSize( dbtypeSrc,
|
||
|
dbtypeDst,
|
||
|
0,
|
||
|
&rcbDstLen,
|
||
|
pbSrcBuf );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( S_OK != sc )
|
||
|
{
|
||
|
tbDebugOut(( DEB_ITRACE,
|
||
|
"OLEDBConvert - GetConversionSize returned error 0x%x\n",
|
||
|
sc ));
|
||
|
DstStatus = DBSTATUS_E_CANTCONVERTVALUE;
|
||
|
}
|
||
|
|
||
|
return DstStatus;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Method: COLEDBVariant::_GetOLEDBType, private.
|
||
|
//
|
||
|
// Synopsis: Returns the OLEDB type equivalent of Variant type.
|
||
|
//
|
||
|
// Arguments: [vt] -- the source varaint type.
|
||
|
// [dbtype] -- the equivalent oledb type.
|
||
|
//
|
||
|
// Returns: S_OK if equivalent OLE DB type exists,
|
||
|
// else S_FALSE.
|
||
|
//
|
||
|
// Notes: Does not handle vectors
|
||
|
//
|
||
|
// History: 09 Jan 1998 VikasMan Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
inline SCODE COLEDBVariant::_GetOLEDBType( VARTYPE vt, DBTYPE& dbtype ) const
|
||
|
{
|
||
|
SCODE sc = S_OK;
|
||
|
|
||
|
switch ( vt & ~VT_BYREF )
|
||
|
{
|
||
|
case VT_I1:
|
||
|
case VT_UI1:
|
||
|
case VT_I2:
|
||
|
case VT_UI2:
|
||
|
case VT_I4:
|
||
|
case VT_UI4:
|
||
|
case VT_I8:
|
||
|
case VT_UI8:
|
||
|
case VT_R4:
|
||
|
case VT_R8:
|
||
|
case VT_CY:
|
||
|
case VT_DATE:
|
||
|
case VT_BSTR:
|
||
|
case VT_FILETIME: // WORKAROUND: Waiting on OLE DB Conv lib to handle this case - 01.12.98
|
||
|
case VT_BOOL:
|
||
|
case VT_ERROR:
|
||
|
case VT_CLSID:
|
||
|
case VT_VARIANT:
|
||
|
case VT_DECIMAL:
|
||
|
|
||
|
case VT_VECTOR | VT_I1:
|
||
|
case VT_VECTOR | VT_UI1:
|
||
|
case VT_VECTOR | VT_I2:
|
||
|
case VT_VECTOR | VT_UI2:
|
||
|
case VT_VECTOR | VT_I4:
|
||
|
case VT_VECTOR | VT_UI4:
|
||
|
case VT_VECTOR | VT_I8:
|
||
|
case VT_VECTOR | VT_UI8:
|
||
|
case VT_VECTOR | VT_R4:
|
||
|
case VT_VECTOR | VT_R8:
|
||
|
case VT_VECTOR | VT_CY:
|
||
|
case VT_VECTOR | VT_DATE:
|
||
|
case VT_VECTOR | VT_BSTR:
|
||
|
case VT_VECTOR | VT_FILETIME: // WORKAROUND: Waiting on OLE DB Conv lib to handle this case - 01.12.98
|
||
|
case VT_VECTOR | VT_BOOL:
|
||
|
case VT_VECTOR | VT_ERROR:
|
||
|
case VT_VECTOR | VT_CLSID:
|
||
|
case VT_VECTOR | VT_VARIANT:
|
||
|
|
||
|
case VT_ARRAY | VT_I1:
|
||
|
case VT_ARRAY | VT_UI1:
|
||
|
case VT_ARRAY | VT_I2:
|
||
|
case VT_ARRAY | VT_UI2:
|
||
|
case VT_ARRAY | VT_I4:
|
||
|
case VT_ARRAY | VT_UI4:
|
||
|
case VT_ARRAY | VT_I8:
|
||
|
case VT_ARRAY | VT_UI8:
|
||
|
case VT_ARRAY | VT_R4:
|
||
|
case VT_ARRAY | VT_R8:
|
||
|
case VT_ARRAY | VT_CY:
|
||
|
case VT_ARRAY | VT_DATE:
|
||
|
case VT_ARRAY | VT_BSTR:
|
||
|
case VT_ARRAY | VT_BOOL:
|
||
|
case VT_ARRAY | VT_VARIANT:
|
||
|
case VT_ARRAY | VT_DECIMAL:
|
||
|
|
||
|
// In all the above cases, the DBTYPE has same value as
|
||
|
// VARIANT type
|
||
|
case DBTYPE_NUMERIC:
|
||
|
case DBTYPE_DBDATE:
|
||
|
case DBTYPE_DBTIME:
|
||
|
case DBTYPE_DBTIMESTAMP:
|
||
|
case DBTYPE_HCHAPTER:
|
||
|
case DBTYPE_BYTES:
|
||
|
case DBTYPE_VARNUMERIC:
|
||
|
// The above are OLEDB types only. So no conversion needed.
|
||
|
dbtype = vt;
|
||
|
break;
|
||
|
|
||
|
case VT_LPSTR:
|
||
|
case DBTYPE_STR:
|
||
|
dbtype = DBTYPE_STR;
|
||
|
break;
|
||
|
|
||
|
case VT_LPWSTR:
|
||
|
case DBTYPE_WSTR:
|
||
|
dbtype = DBTYPE_WSTR;
|
||
|
break;
|
||
|
|
||
|
case VT_BLOB:
|
||
|
dbtype = VT_VECTOR | VT_UI1;
|
||
|
break;
|
||
|
|
||
|
case VT_INT:
|
||
|
dbtype = VT_I4;
|
||
|
break;
|
||
|
|
||
|
case VT_UINT:
|
||
|
dbtype = VT_UI4;
|
||
|
break;
|
||
|
|
||
|
case VT_ARRAY | VT_INT:
|
||
|
dbtype = VT_ARRAY | VT_I4;
|
||
|
break;
|
||
|
|
||
|
case VT_ARRAY | VT_UINT:
|
||
|
dbtype = VT_ARRAY | VT_UI4;
|
||
|
break;
|
||
|
|
||
|
// SPECDEVIATION: What about VT_CF ??? (handled partially in base class)
|
||
|
|
||
|
default:
|
||
|
// default case: all types for which there is no equivalent
|
||
|
// OLE DB type - VT_CF, VT_BLOBOBJECT,
|
||
|
// VT_STREAM, VT_STREAMED_OBJECT, VT_STORAGE, VT_STORED_OBJECT,
|
||
|
// VT_DISPATCH, VT_UNKNOWN,
|
||
|
sc = S_FALSE;
|
||
|
break;
|
||
|
}
|
||
|
return sc;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: COLEDBVariant::_GetDataPointer, private
|
||
|
//
|
||
|
// Synopsis: Depending on the type of vt, returns the data pointer
|
||
|
//
|
||
|
// Arguments: -none-
|
||
|
//
|
||
|
// Returns: Returns the pointer to data in the PropVariant
|
||
|
//
|
||
|
// History: 09 Jan 1998 VikasMan Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
inline void* COLEDBVariant::_GetDataPointer() const
|
||
|
{
|
||
|
if (vt & VT_VECTOR)
|
||
|
return (void*)&cal;
|
||
|
|
||
|
if (vt & VT_ARRAY)
|
||
|
return (void*) parray;
|
||
|
|
||
|
void* pDataPtr = 0;
|
||
|
|
||
|
switch ( vt )
|
||
|
{
|
||
|
case VT_LPSTR:
|
||
|
case VT_LPWSTR:
|
||
|
case VT_CLSID:
|
||
|
case VT_CF:
|
||
|
// all pointer values
|
||
|
pDataPtr = (void*) pszVal;
|
||
|
break;
|
||
|
|
||
|
case VT_BSTR:
|
||
|
// need address of bstr ptr
|
||
|
pDataPtr = (void*) &bstrVal;
|
||
|
break;
|
||
|
|
||
|
case VT_BLOB:
|
||
|
case VT_BLOB_OBJECT:
|
||
|
pDataPtr = (void*) &blob;
|
||
|
break;
|
||
|
|
||
|
case VT_DECIMAL:
|
||
|
pDataPtr = (void*) this;
|
||
|
break;
|
||
|
|
||
|
// cases which we do not handle
|
||
|
case VT_EMPTY:
|
||
|
case VT_NULL:
|
||
|
case VT_ILLEGAL:
|
||
|
case VT_STREAM:
|
||
|
case VT_STREAMED_OBJECT:
|
||
|
case VT_STORAGE:
|
||
|
case VT_STORED_OBJECT:
|
||
|
case VT_DISPATCH:
|
||
|
case VT_VARIANT:
|
||
|
case VT_UNKNOWN:
|
||
|
case VT_VOID:
|
||
|
pDataPtr = 0;
|
||
|
break;
|
||
|
|
||
|
// Rest of the stuff
|
||
|
default:
|
||
|
pDataPtr = (void*) &bVal;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return pDataPtr;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: COLEDBVariant::_CopyToOAVariant, private
|
||
|
//
|
||
|
// Synopsis: Copy table data between a table variant structure and
|
||
|
// an Ole automation variant. Automation variants have a
|
||
|
// restricted set of usable types and vectors must be converted
|
||
|
// to safearrays.
|
||
|
//
|
||
|
// Arguments: [pDest] -- pointer to destination variant
|
||
|
// [rPool] -- pool to use for destination buffers
|
||
|
//
|
||
|
// Returns: status for copy
|
||
|
//
|
||
|
// History: 09 Jan 1998 VikasMan Created
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
DBSTATUS COLEDBVariant::_CopyToOAVariant( VARIANT * pDest,
|
||
|
PVarAllocator & rPool) const
|
||
|
{
|
||
|
DBSTATUS DstStatus = DBSTATUS_S_OK;
|
||
|
|
||
|
switch (vt)
|
||
|
{
|
||
|
case VT_LPSTR:
|
||
|
case VT_LPWSTR:
|
||
|
{
|
||
|
DBLENGTH ulTemp;
|
||
|
pDest->vt = VT_BSTR;
|
||
|
DstStatus = _StoreString( (BYTE *)&(pDest->bstrVal),
|
||
|
sizeof (BSTR),
|
||
|
VT_BSTR,
|
||
|
ulTemp,
|
||
|
rPool);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
case VT_I8:
|
||
|
case VT_UI8:
|
||
|
DstStatus = _StoreDecimal( &(pDest->decVal) );
|
||
|
pDest->vt = VT_DECIMAL;
|
||
|
break;
|
||
|
|
||
|
case VT_I1:
|
||
|
DstStatus = _StoreIntegerSignedToUnSigned( VT_UI1, &(pDest->bVal) );
|
||
|
pDest->vt = VT_UI1;
|
||
|
break;
|
||
|
|
||
|
case VT_UI2:
|
||
|
if (uiVal <= SHRT_MAX)
|
||
|
{
|
||
|
DstStatus = _StoreIntegerUnSignedToSigned( VT_I2, (BYTE*)&(pDest->iVal) );
|
||
|
pDest->vt = VT_I2;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DstStatus = _StoreIntegerUnSignedToSigned( VT_I4, (BYTE*)&(pDest->lVal) );
|
||
|
pDest->vt = VT_I4;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case VT_UI4:
|
||
|
if (ulVal <= LONG_MAX)
|
||
|
{
|
||
|
DstStatus = _StoreIntegerUnSignedToSigned( VT_I4, (BYTE*)&(pDest->lVal) );
|
||
|
pDest->vt = VT_I4;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DstStatus = _StoreDecimal( &(pDest->decVal) );
|
||
|
pDest->vt = VT_DECIMAL;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case VT_FILETIME:
|
||
|
DstStatus = _StoreDate( (BYTE*)&(pDest->date),
|
||
|
sizeof pDest->date,
|
||
|
VT_DATE );
|
||
|
pDest->vt = VT_DATE;
|
||
|
break;
|
||
|
|
||
|
case (VT_VECTOR | VT_I2):
|
||
|
case (VT_VECTOR | VT_I4):
|
||
|
case (VT_VECTOR | VT_R4):
|
||
|
case (VT_VECTOR | VT_R8):
|
||
|
case (VT_VECTOR | VT_CY):
|
||
|
case (VT_VECTOR | VT_DATE):
|
||
|
case (VT_VECTOR | VT_ERROR):
|
||
|
case (VT_VECTOR | VT_BOOL):
|
||
|
case (VT_VECTOR | VT_UI1):
|
||
|
case (VT_VECTOR | VT_DECIMAL):
|
||
|
Win4Assert( IsSimpleOAType(vt & VT_TYPEMASK));
|
||
|
Win4Assert( CanBeVectorType(vt & VT_TYPEMASK));
|
||
|
DstStatus = _StoreSimpleTypeArray( &(pDest->parray));
|
||
|
pDest->vt = (vt & VT_TYPEMASK) | VT_ARRAY;
|
||
|
break;
|
||
|
|
||
|
case (VT_VECTOR | VT_UI4): // could step thru to see if I4 is big enough
|
||
|
case (VT_VECTOR | VT_I8):
|
||
|
case (VT_VECTOR | VT_UI8):
|
||
|
Win4Assert( !IsOAType(vt & VT_TYPEMASK));
|
||
|
Win4Assert( CanBeVectorType(vt & VT_TYPEMASK));
|
||
|
DstStatus = _StoreDecimalArray( &(pDest->parray));
|
||
|
pDest->vt = VT_DECIMAL | VT_ARRAY;
|
||
|
break;
|
||
|
|
||
|
case (VT_VECTOR | VT_UI2): // could step thru to detect if I2 is big enough
|
||
|
Win4Assert( !IsOAType(vt & VT_TYPEMASK));
|
||
|
Win4Assert( CanBeVectorType(vt & VT_TYPEMASK));
|
||
|
DstStatus = _StoreIntegerArray( VT_I4, &(pDest->parray));
|
||
|
pDest->vt = VT_I4 | VT_ARRAY;
|
||
|
break;
|
||
|
|
||
|
case (VT_VECTOR | VT_I1): // should step thru to detect if UI1 is big enough
|
||
|
Win4Assert( !IsOAType(vt & VT_TYPEMASK));
|
||
|
Win4Assert( CanBeVectorType(vt & VT_TYPEMASK));
|
||
|
DstStatus = _StoreIntegerArray( VT_UI1, &(pDest->parray));
|
||
|
pDest->vt = VT_UI1 | VT_ARRAY;
|
||
|
break;
|
||
|
|
||
|
case (VT_VECTOR | VT_LPSTR): // byref/vector mutually exclusive
|
||
|
Win4Assert( !IsOAType(vt & VT_TYPEMASK));
|
||
|
Win4Assert( CanBeVectorType(vt & VT_TYPEMASK));
|
||
|
DstStatus = _StoreLPSTRArray( &(pDest->parray), rPool );
|
||
|
pDest->vt = VT_BSTR | VT_ARRAY;
|
||
|
break;
|
||
|
|
||
|
case (VT_VECTOR | VT_LPWSTR):
|
||
|
Win4Assert( !IsOAType(vt & VT_TYPEMASK));
|
||
|
Win4Assert( CanBeVectorType(vt & VT_TYPEMASK));
|
||
|
DstStatus = _StoreLPWSTRArray( &(pDest->parray), rPool );
|
||
|
pDest->vt = VT_BSTR | VT_ARRAY;
|
||
|
break;
|
||
|
|
||
|
case (VT_VECTOR | VT_BSTR):
|
||
|
Win4Assert( IsOAType(vt & VT_TYPEMASK));
|
||
|
Win4Assert( CanBeVectorType(vt & VT_TYPEMASK));
|
||
|
DstStatus = _StoreBSTRArray( &(pDest->parray), rPool );
|
||
|
pDest->vt = VT_BSTR | VT_ARRAY;
|
||
|
break;
|
||
|
|
||
|
case (VT_VECTOR | VT_VARIANT):
|
||
|
Win4Assert( IsOAType(vt & VT_TYPEMASK));
|
||
|
Win4Assert( CanBeVectorType(vt & VT_TYPEMASK));
|
||
|
DstStatus = _StoreVariantArray( &(pDest->parray), rPool );
|
||
|
pDest->vt = VT_VARIANT | VT_ARRAY;
|
||
|
break;
|
||
|
|
||
|
case (VT_VECTOR | VT_FILETIME):
|
||
|
Win4Assert( !IsOAType(vt & VT_TYPEMASK));
|
||
|
Win4Assert( CanBeVectorType(vt & VT_TYPEMASK));
|
||
|
DstStatus = _StoreDateArray( &(pDest->parray) );
|
||
|
pDest->vt = VT_DATE | VT_ARRAY;
|
||
|
break;
|
||
|
|
||
|
case VT_ARRAY | VT_I1:
|
||
|
case VT_ARRAY | VT_UI1:
|
||
|
case VT_ARRAY | VT_I2:
|
||
|
case VT_ARRAY | VT_UI2:
|
||
|
case VT_ARRAY | VT_I4:
|
||
|
case VT_ARRAY | VT_INT:
|
||
|
case VT_ARRAY | VT_UI4:
|
||
|
case VT_ARRAY | VT_UINT:
|
||
|
case VT_ARRAY | VT_ERROR:
|
||
|
case VT_ARRAY | VT_I8:
|
||
|
case VT_ARRAY | VT_UI8:
|
||
|
case VT_ARRAY | VT_R4:
|
||
|
case VT_ARRAY | VT_R8:
|
||
|
case VT_ARRAY | VT_CY:
|
||
|
case VT_ARRAY | VT_DATE:
|
||
|
case VT_ARRAY | VT_BSTR:
|
||
|
case VT_ARRAY | VT_BOOL:
|
||
|
case VT_ARRAY | VT_VARIANT:
|
||
|
case VT_ARRAY | VT_DECIMAL:
|
||
|
{
|
||
|
SAFEARRAY * psa = 0;
|
||
|
SCODE sc = SafeArrayCopy( parray, &psa );
|
||
|
Win4Assert( E_INVALIDARG != sc );
|
||
|
Win4Assert( E_OUTOFMEMORY == sc || psa != 0 );
|
||
|
if (S_OK != sc)
|
||
|
{
|
||
|
THROW(CException(E_OUTOFMEMORY));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pDest->vt = vt;
|
||
|
pDest->parray = psa;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case VT_CLSID: // no equivalent in OA variant
|
||
|
case VT_CF: // no equivalent in OA variant
|
||
|
default:
|
||
|
Win4Assert( !(VT_ARRAY & vt) ); // should be handled elsewhere
|
||
|
Win4Assert( !IsOAType(vt) ); // should be handled elsewhere
|
||
|
Win4Assert(CanBeVectorType(vt & VT_TYPEMASK) || !(VT_VECTOR & vt));
|
||
|
tbDebugOut(( DEB_WARN, "COLEDBVariant::CopyToOAVariant - bad variant type %d \n", vt ));
|
||
|
|
||
|
DstStatus = DBSTATUS_E_CANTCONVERTVALUE;
|
||
|
}
|
||
|
|
||
|
if ( !StatusSuccess(DstStatus) ||
|
||
|
(DBSTATUS_S_ISNULL == DstStatus && pDest->vt != VT_NULL) )
|
||
|
pDest->vt = VT_EMPTY;
|
||
|
|
||
|
return DstStatus;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: COLEDBVariant::_StoreSimpleTypeArray, private
|
||
|
//
|
||
|
// Synopsis: Copy vector of simple OA types to safearray of same type
|
||
|
//
|
||
|
// Arguments: [pbDstBuf] -- destination buffer
|
||
|
//
|
||
|
// Returns: status for copy
|
||
|
//
|
||
|
// Notes: None of the simple types require memory allocation.
|
||
|
// Throws if safearray itself cannot be alloc'd
|
||
|
//
|
||
|
// History: 09 Apr 1997 EmilyB Created
|
||
|
// 09 Jan 1998 VikasMan Moved from CTableVariant class
|
||
|
// to here
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
DBSTATUS COLEDBVariant::_StoreSimpleTypeArray(SAFEARRAY ** pbDstBuf) const
|
||
|
{
|
||
|
if ( 0 == caul.cElems )
|
||
|
return DBSTATUS_S_ISNULL;
|
||
|
|
||
|
// CLEANCODE - add to PVarAllocator?
|
||
|
SAFEARRAY *sa = SafeArrayCreateVector(vt & VT_TYPEMASK, 0, caul.cElems);
|
||
|
if (0 == sa)
|
||
|
THROW(CException(E_OUTOFMEMORY));
|
||
|
XSafeArray xsa(sa);
|
||
|
|
||
|
USHORT cbSize, cbAlign, rgFlags;
|
||
|
VartypeInfo(vt & VT_TYPEMASK, cbSize, cbAlign, rgFlags);
|
||
|
BYTE * pBase = (BYTE *)&(caul.pElems[0]);
|
||
|
for (LONG lElem = 0; lElem < (LONG)(caul.cElems); lElem++)
|
||
|
{
|
||
|
SCODE sc = SafeArrayPutElement(xsa.Get(), &lElem, pBase + (cbSize * lElem));
|
||
|
Win4Assert ( SUCCEEDED(sc) );
|
||
|
}
|
||
|
|
||
|
*pbDstBuf = xsa.Acquire();
|
||
|
|
||
|
return DBSTATUS_S_OK;
|
||
|
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: COLEDBVariant::_StoreDecimalArray, private
|
||
|
//
|
||
|
// Synopsis: Copy vector to decimal safearray
|
||
|
//
|
||
|
// Arguments: [pbDstBuf] -- destination buffer
|
||
|
//
|
||
|
// Returns: status for copy
|
||
|
//
|
||
|
// Notes: Expects the 'this' data type to be VT_UI4|VT_VECTOR,
|
||
|
// VT_I8|VT_VECTOR, or VT_UI8|VT_VECTOR.
|
||
|
//
|
||
|
// History: 09 Apr 1997 EmilyB Created
|
||
|
// 09 Jan 1998 VikasMan Moved from CTableVariant class
|
||
|
// to here
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
DBSTATUS COLEDBVariant::_StoreDecimalArray( SAFEARRAY ** pbDstBuf ) const
|
||
|
{
|
||
|
if ( 0 == caul.cElems )
|
||
|
return DBSTATUS_S_ISNULL;
|
||
|
|
||
|
DBSTATUS dbStatus = DBSTATUS_S_OK; // status of last conversion
|
||
|
DBSTATUS dbStatusRet = DBSTATUS_S_OK; // error code of last conversion,
|
||
|
// or if no errors, DBSTATUS_S code
|
||
|
// of last item with any trouble converting.
|
||
|
|
||
|
// CLEANCODE - add to PVarAllocator?
|
||
|
SAFEARRAY * sa = SafeArrayCreateVector(VT_DECIMAL, 0, caul.cElems);
|
||
|
if (0 == sa)
|
||
|
THROW(CException(E_OUTOFMEMORY));
|
||
|
XSafeArray xsa(sa);
|
||
|
|
||
|
for (LONG lElem = 0; lElem < (LONG)caul.cElems && StatusSuccess(dbStatus); lElem++)
|
||
|
{
|
||
|
DECIMAL dec;
|
||
|
dbStatus = _StoreDecimal( &dec, lElem);
|
||
|
if (DBSTATUS_S_OK != dbStatus)
|
||
|
dbStatusRet = dbStatus; // save last non-zero status
|
||
|
SCODE sc = SafeArrayPutElement(xsa.Get(), &lElem, &dec);
|
||
|
Win4Assert ( SUCCEEDED(sc) );
|
||
|
}
|
||
|
if (StatusSuccess(dbStatus))
|
||
|
{
|
||
|
*pbDstBuf = xsa.Acquire();
|
||
|
}
|
||
|
return dbStatusRet;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: COLEDBVariant::_StoreIntegerArray, private
|
||
|
//
|
||
|
// Synopsis: Copy vector of integers to safearray of integers
|
||
|
//
|
||
|
// Arguments: [vtDst] -- destination safearray type
|
||
|
// [pbDstBuf] -- destination buffer
|
||
|
//
|
||
|
// Returns: status for copy
|
||
|
//
|
||
|
// Notes: Expects the 'this' data type to be an int type | VT_VECTOR.
|
||
|
//
|
||
|
// History: 09 Apr 1997 EmilyB Created
|
||
|
// 09 Jan 1998 VikasMan Moved from CTableVariant class
|
||
|
// to here
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
DBSTATUS COLEDBVariant::_StoreIntegerArray(VARTYPE vtDst,
|
||
|
SAFEARRAY ** pbDstBuf) const
|
||
|
{
|
||
|
if ( 0 == caul.cElems )
|
||
|
return DBSTATUS_S_ISNULL;
|
||
|
|
||
|
DBSTATUS dbStatus = DBSTATUS_S_OK;
|
||
|
DBSTATUS dbStatusRet = DBSTATUS_S_OK; // error code of last conversion,
|
||
|
// or if no errors, DBSTATUS_S code
|
||
|
// of last item with any trouble converting.
|
||
|
|
||
|
// CLEANCODE - add to PVarAllocator?
|
||
|
SAFEARRAY * sa = SafeArrayCreateVector(vtDst, 0, caul.cElems);
|
||
|
if (0 == sa)
|
||
|
THROW(CException(E_OUTOFMEMORY));
|
||
|
XSafeArray xsa(sa);
|
||
|
|
||
|
for (LONG lElem = 0; lElem < (LONG)caul.cElems && StatusSuccess(dbStatus); lElem++)
|
||
|
{
|
||
|
LONGLONG iInt; // size of longest int - to use as buffer
|
||
|
dbStatus = _StoreInteger( vtDst, (BYTE *)&iInt, lElem);
|
||
|
if (DBSTATUS_S_OK != dbStatus)
|
||
|
dbStatusRet = dbStatus; // save last non-zero status
|
||
|
SCODE sc = SafeArrayPutElement(xsa.Get(), &lElem, &iInt);
|
||
|
Win4Assert ( SUCCEEDED(sc) );
|
||
|
}
|
||
|
if (StatusSuccess(dbStatus))
|
||
|
{
|
||
|
*pbDstBuf = xsa.Acquire();
|
||
|
}
|
||
|
return dbStatusRet;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: COLEDBVariant::_StoreLPSTRArray, private
|
||
|
//
|
||
|
// Synopsis: Copy LPSTR vector to safearray
|
||
|
//
|
||
|
// Arguments: [pbDstBuf] -- destination buffer
|
||
|
// [rPool] -- pool to use for destination buffers
|
||
|
//
|
||
|
// Returns: status for copy
|
||
|
//
|
||
|
// History: 09 Apr 1997 EmilyB Created
|
||
|
// 09 Jan 1998 VikasMan Moved from CTableVariant class
|
||
|
// to here
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
DBSTATUS COLEDBVariant::_StoreLPSTRArray(
|
||
|
SAFEARRAY ** pbDstBuf,
|
||
|
PVarAllocator & rPool) const
|
||
|
{
|
||
|
if ( 0 == calpstr.cElems )
|
||
|
return DBSTATUS_S_ISNULL;
|
||
|
|
||
|
DBSTATUS dbStatus = DBSTATUS_S_OK;
|
||
|
|
||
|
// CLEANCODE - add to PVarAllocator?
|
||
|
|
||
|
SAFEARRAY * sa = SafeArrayCreateVector(VT_BSTR, 0, calpstr.cElems);
|
||
|
if (0 == sa)
|
||
|
THROW(CException(E_OUTOFMEMORY));
|
||
|
|
||
|
XSafeArray xsa(sa);
|
||
|
|
||
|
for (LONG lElem = 0; lElem < (LONG)(calpstr).cElems && StatusSuccess(dbStatus); lElem++)
|
||
|
{
|
||
|
int cwc = MultiByteToWideChar(ulCoercionCodePage,0,
|
||
|
calpstr.pElems[lElem],-1,0,0);
|
||
|
if (0 == cwc)
|
||
|
{
|
||
|
dbStatus = DBSTATUS_E_CANTCONVERTVALUE; // something odd...
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
XArray<WCHAR> wcsDest( cwc );
|
||
|
MultiByteToWideChar(ulCoercionCodePage, 0,
|
||
|
calpstr.pElems[lElem], -1, wcsDest.Get(), cwc);
|
||
|
|
||
|
BSTR bstrDest = (BSTR) rPool.CopyBSTR((cwc-1)*sizeof (OLECHAR),
|
||
|
wcsDest.Get());
|
||
|
|
||
|
SCODE sc = SafeArrayPutElement(xsa.Get(), &lElem, (void *)rPool.PointerToOffset(bstrDest));
|
||
|
rPool.FreeBSTR(bstrDest);
|
||
|
|
||
|
if (E_OUTOFMEMORY == sc)
|
||
|
THROW(CException(E_OUTOFMEMORY));
|
||
|
Win4Assert ( SUCCEEDED(sc) );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (StatusSuccess(dbStatus))
|
||
|
{
|
||
|
*pbDstBuf = xsa.Acquire();
|
||
|
}
|
||
|
|
||
|
|
||
|
return dbStatus;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: COLEDBVariant::_StoreLPWSTRArray, private
|
||
|
//
|
||
|
// Synopsis: Copy LPWSTR vector to safearray
|
||
|
//
|
||
|
// Arguments: [pbDstBuf] -- destination buffer
|
||
|
// [rPool] -- pool to use for destination buffers
|
||
|
//
|
||
|
// Returns: status for copy
|
||
|
//
|
||
|
// History: 09 Apr 1997 EmilyB Created
|
||
|
// 09 Jan 1998 VikasMan Moved from CTableVariant class
|
||
|
// to here
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
DBSTATUS COLEDBVariant::_StoreLPWSTRArray(
|
||
|
SAFEARRAY ** pbDstBuf,
|
||
|
PVarAllocator & rPool) const
|
||
|
{
|
||
|
if ( 0 == calpwstr.cElems )
|
||
|
return DBSTATUS_S_ISNULL;
|
||
|
|
||
|
// CLEANCODE - add to PVarAllocator?
|
||
|
SAFEARRAY * sa = SafeArrayCreateVector(VT_BSTR, 0, calpwstr.cElems);
|
||
|
if (0 == sa)
|
||
|
THROW(CException(E_OUTOFMEMORY));
|
||
|
|
||
|
XSafeArray xsa(sa);
|
||
|
|
||
|
for (LONG lElem = 0; lElem < (LONG)(calpwstr.cElems); lElem++)
|
||
|
{
|
||
|
BSTR bstrDest = (BSTR) rPool.CopyBSTR( wcslen(calpwstr.pElems[lElem]) * sizeof(WCHAR),
|
||
|
calpwstr.pElems[lElem] );
|
||
|
SCODE sc = SafeArrayPutElement(xsa.Get(), &lElem, (void *)rPool.PointerToOffset(bstrDest));
|
||
|
rPool.FreeBSTR(bstrDest);
|
||
|
|
||
|
if (E_OUTOFMEMORY == sc)
|
||
|
THROW(CException(E_OUTOFMEMORY));
|
||
|
Win4Assert ( SUCCEEDED(sc) );
|
||
|
}
|
||
|
|
||
|
*pbDstBuf = xsa.Acquire();
|
||
|
return DBSTATUS_S_OK;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: COLEDBVariant::_StoreBSTRArray, private
|
||
|
//
|
||
|
// Synopsis: Copy BSTR vector to safearray
|
||
|
//
|
||
|
// Arguments: [pbDstBuf] -- destination buffer
|
||
|
// [rPool] -- pool to use for destination buffers
|
||
|
//
|
||
|
// Returns: status for copy
|
||
|
//
|
||
|
// Notes: Expects the 'this' data type to be VT_BSTR | VT_VECTOR.
|
||
|
//
|
||
|
// History: 09 Apr 1997 EmilyB Created
|
||
|
// 09 Jan 1998 VikasMan Moved from CTableVariant class
|
||
|
// to here
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
DBSTATUS COLEDBVariant::_StoreBSTRArray(
|
||
|
SAFEARRAY ** pbDstBuf,
|
||
|
PVarAllocator & rPool) const
|
||
|
{
|
||
|
if ( 0 == cabstr.cElems )
|
||
|
return DBSTATUS_S_ISNULL;
|
||
|
|
||
|
// CLEANCODE - add to PVarAllocator?
|
||
|
SAFEARRAY * sa = SafeArrayCreateVector(VT_BSTR, 0, cabstr.cElems);
|
||
|
if (0 == sa)
|
||
|
THROW(CException(E_OUTOFMEMORY));
|
||
|
|
||
|
XSafeArray xsa(sa);
|
||
|
|
||
|
for (LONG lElem = 0; lElem < (LONG)cabstr.cElems; lElem++)
|
||
|
{
|
||
|
SCODE sc = SafeArrayPutElement(xsa.Get(), &lElem, cabstr.pElems[lElem]);
|
||
|
if (E_OUTOFMEMORY == sc)
|
||
|
THROW(CException(E_OUTOFMEMORY));
|
||
|
Win4Assert ( SUCCEEDED(sc) );
|
||
|
}
|
||
|
|
||
|
*pbDstBuf = xsa.Acquire();
|
||
|
|
||
|
return DBSTATUS_S_OK;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: COLEDBVariant::_StoreVariantArray, private
|
||
|
//
|
||
|
// Synopsis: Copy variant vector to safearray
|
||
|
//
|
||
|
// Arguments: [pbDstBuf] -- destination buffer
|
||
|
// [rPool] -- pool to use for destination buffers
|
||
|
//
|
||
|
// Returns: status for copy
|
||
|
//
|
||
|
// Notes: Expects the 'this' data type to be VT_VARIANT | VT_VECTOR.
|
||
|
//
|
||
|
// History: 09 Apr 1997 EmilyB Created
|
||
|
// 09 Jan 1998 VikasMan Moved from CTableVariant class
|
||
|
// to here
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
DBSTATUS COLEDBVariant::_StoreVariantArray(
|
||
|
SAFEARRAY ** pbDstBuf,
|
||
|
PVarAllocator & rPool) const
|
||
|
{
|
||
|
if ( 0 == capropvar.cElems )
|
||
|
return DBSTATUS_S_ISNULL;
|
||
|
|
||
|
DBSTATUS dbStatus = DBSTATUS_S_OK;
|
||
|
DBSTATUS dbStatusRet = DBSTATUS_S_OK; // error code of last conversion,
|
||
|
// or if no errors, DBSTATUS_S code
|
||
|
// of last item with any trouble converting.
|
||
|
|
||
|
Win4Assert(vt == (VT_VECTOR | VT_VARIANT));
|
||
|
|
||
|
// CLEANCODE - add to PVarAllocator?
|
||
|
SAFEARRAY * sa = SafeArrayCreateVector(VT_VARIANT, 0, capropvar.cElems);
|
||
|
if (0 == sa)
|
||
|
THROW(CException(E_OUTOFMEMORY));
|
||
|
XSafeArray xsa(sa);
|
||
|
|
||
|
for (LONG lElem = 0; lElem < (LONG)(capropvar.cElems) && StatusSuccess(dbStatus); lElem++)
|
||
|
{
|
||
|
COLEDBVariant tblVariant;
|
||
|
if (IsOAType(capropvar.pElems[lElem].vt))
|
||
|
{
|
||
|
((CTableVariant &)capropvar.pElems[lElem]).Copy(&tblVariant,
|
||
|
rPool,
|
||
|
(USHORT)((CTableVariant &)capropvar.pElems[lElem]).VarDataSize(),
|
||
|
0);
|
||
|
}
|
||
|
else // convert variant to an OA type
|
||
|
{
|
||
|
dbStatus = ((COLEDBVariant &)capropvar.pElems[lElem])._CopyToOAVariant( (VARIANT *)&tblVariant, rPool);
|
||
|
if (DBSTATUS_S_OK != dbStatus)
|
||
|
dbStatusRet = dbStatus; // save last non-zero status
|
||
|
|
||
|
}
|
||
|
SCODE sc = SafeArrayPutElement(xsa.Get(), &lElem, (PROPVARIANT *)&tblVariant);
|
||
|
if (E_OUTOFMEMORY == sc)
|
||
|
THROW(CException(E_OUTOFMEMORY));
|
||
|
Win4Assert ( SUCCEEDED(sc) );
|
||
|
}
|
||
|
|
||
|
*pbDstBuf = xsa.Acquire();
|
||
|
return dbStatusRet;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: COLEDBVariant::_StoreDateArray, private
|
||
|
//
|
||
|
// Synopsis: Copy date vector to safearray of dates
|
||
|
//
|
||
|
// Arguments: [pbDstBuf] -- destination buffer
|
||
|
//
|
||
|
// Returns: status for copy
|
||
|
//
|
||
|
// Notes: Expects the 'this' data type to be VT_DATE | VT_VECTOR.
|
||
|
//
|
||
|
// History: 09 Apr 1997 EmilyB Created
|
||
|
// 09 Jan 1998 VikasMan Moved from CTableVariant class
|
||
|
// to here
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
DBSTATUS COLEDBVariant::_StoreDateArray(SAFEARRAY ** pbDstBuf) const
|
||
|
{
|
||
|
if ( 0 == caul.cElems )
|
||
|
return DBSTATUS_S_ISNULL;
|
||
|
|
||
|
DBSTATUS dbStatus = DBSTATUS_S_OK;
|
||
|
DBSTATUS dbStatusRet = DBSTATUS_S_OK; // error code of last conversion,
|
||
|
// or if no errors, DBSTATUS_S code
|
||
|
// of last item with any trouble converting.
|
||
|
|
||
|
// CLEANCODE - add to PVarAllocator?
|
||
|
SAFEARRAY * sa = SafeArrayCreateVector(VT_DATE, 0, caul.cElems);
|
||
|
if (0 == sa)
|
||
|
THROW(CException(E_OUTOFMEMORY));
|
||
|
XSafeArray xsa(sa);
|
||
|
|
||
|
|
||
|
for (LONG lElem = 0; lElem < (LONG)(caul.cElems) && StatusSuccess(dbStatus); lElem++)
|
||
|
{
|
||
|
DATE date;
|
||
|
dbStatus = _StoreDate( (BYTE *)&date, sizeof(date), VT_DATE, lElem);
|
||
|
if (DBSTATUS_S_OK != dbStatus)
|
||
|
dbStatusRet = dbStatus; // save last non-zero status
|
||
|
|
||
|
SCODE sc = SafeArrayPutElement(xsa.Get(), &lElem, &date);
|
||
|
Win4Assert ( SUCCEEDED(sc) );
|
||
|
}
|
||
|
if (StatusSuccess(dbStatus))
|
||
|
{
|
||
|
*pbDstBuf = xsa.Acquire();
|
||
|
}
|
||
|
return dbStatusRet;
|
||
|
}
|
||
|
|
||
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: COLEDBVariant::_StoreDate, private
|
||
|
//
|
||
|
// Synopsis: Copy variant date/time data, coerce if possible
|
||
|
//
|
||
|
// Arguments: [pbDstBuf] -- destination buffer
|
||
|
// [cbDstBuf] -- size of destination buffer
|
||
|
// [vtDst] -- data type of the dest
|
||
|
// [lElem] -- element of vector to convert
|
||
|
//
|
||
|
// Returns: status for copy
|
||
|
//
|
||
|
// Notes: Expects the 'this' data type to be either VT_FILETIME or
|
||
|
// VT_DATE. Expects the vtDst to be VT_FILETIME, VT_DATE,
|
||
|
// DBTYPE_DBDATE, DBTYPE_DBTIME or DBTYPE_DBTIMESTAMP.
|
||
|
//
|
||
|
// History: 31 Jan 1997 AlanW Created
|
||
|
// 13 Jan 1998 VikasMan Moved from CTableVariant class
|
||
|
// to here
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
DBSTATUS COLEDBVariant::_StoreDate(
|
||
|
BYTE * pbDstBuf,
|
||
|
DBLENGTH cbDstBuf,
|
||
|
VARTYPE vtDst,
|
||
|
LONG lElem) const
|
||
|
{
|
||
|
DBSTATUS DstStatus = DBSTATUS_S_OK;
|
||
|
SYSTEMTIME stUTC;
|
||
|
|
||
|
//
|
||
|
// Convert the input date into a common form: GMT SYSTEMTIME.
|
||
|
//
|
||
|
if (VT_DATE == vt)
|
||
|
{
|
||
|
if (! VariantTimeToSystemTime(date, &stUTC) )
|
||
|
return DBSTATUS_E_DATAOVERFLOW;
|
||
|
}
|
||
|
else if ((VT_DATE|VT_VECTOR)== vt)
|
||
|
{
|
||
|
if (! VariantTimeToSystemTime(cadate.pElems[lElem], &stUTC) )
|
||
|
return DBSTATUS_E_DATAOVERFLOW;
|
||
|
}
|
||
|
else if (VT_FILETIME == vt)
|
||
|
{
|
||
|
// do not do local time conversion
|
||
|
if (! FileTimeToSystemTime((LPFILETIME) &hVal.QuadPart, &stUTC) )
|
||
|
return DBSTATUS_E_DATAOVERFLOW;
|
||
|
}
|
||
|
else if ((VT_FILETIME|VT_VECTOR) == vt)
|
||
|
{
|
||
|
// do not do local time conversion
|
||
|
if (! FileTimeToSystemTime(&cafiletime.pElems[lElem], &stUTC) )
|
||
|
return DBSTATUS_E_DATAOVERFLOW;
|
||
|
}
|
||
|
else
|
||
|
return DBSTATUS_E_CANTCONVERTVALUE;
|
||
|
|
||
|
switch (vtDst)
|
||
|
{
|
||
|
case VT_DATE:
|
||
|
DATE dosDate;
|
||
|
if (! SystemTimeToVariantTime(&stUTC, &dosDate) )
|
||
|
return DBSTATUS_E_DATAOVERFLOW;
|
||
|
|
||
|
Win4Assert( cbDstBuf >= sizeof DATE );
|
||
|
RtlCopyMemory(pbDstBuf, &dosDate, sizeof DATE);
|
||
|
break;
|
||
|
|
||
|
case VT_FILETIME:
|
||
|
FILETIME ftUTC;
|
||
|
if (! SystemTimeToFileTime(&stUTC, &ftUTC) )
|
||
|
return DBSTATUS_E_DATAOVERFLOW;
|
||
|
|
||
|
Win4Assert( cbDstBuf >= sizeof FILETIME );
|
||
|
RtlCopyMemory(pbDstBuf, &ftUTC, sizeof FILETIME);
|
||
|
break;
|
||
|
|
||
|
case DBTYPE_DBTIMESTAMP:
|
||
|
{
|
||
|
// does not use local time
|
||
|
DBTIMESTAMP dbUTC;
|
||
|
dbUTC.year = stUTC.wYear;
|
||
|
dbUTC.month = stUTC.wMonth;
|
||
|
dbUTC.day = stUTC.wDay;
|
||
|
dbUTC.hour = stUTC.wHour;
|
||
|
dbUTC.minute = stUTC.wMinute;
|
||
|
dbUTC.second = stUTC.wSecond;
|
||
|
dbUTC.fraction = stUTC.wMilliseconds * 1000000;
|
||
|
|
||
|
Win4Assert( cbDstBuf >= sizeof dbUTC );
|
||
|
RtlCopyMemory(pbDstBuf, &dbUTC, sizeof dbUTC);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case DBTYPE_DBDATE:
|
||
|
{
|
||
|
DBDATE dbUTC;
|
||
|
dbUTC.year = stUTC.wYear;
|
||
|
dbUTC.month = stUTC.wMonth;
|
||
|
dbUTC.day = stUTC.wDay;
|
||
|
|
||
|
Win4Assert( cbDstBuf >= sizeof dbUTC );
|
||
|
RtlCopyMemory(pbDstBuf, &dbUTC, sizeof dbUTC);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case DBTYPE_DBTIME:
|
||
|
{
|
||
|
DBTIME dbUTC;
|
||
|
dbUTC.hour = stUTC.wHour;
|
||
|
dbUTC.minute = stUTC.wMinute;
|
||
|
dbUTC.second = stUTC.wSecond;
|
||
|
|
||
|
Win4Assert( cbDstBuf >= sizeof dbUTC );
|
||
|
RtlCopyMemory(pbDstBuf, &dbUTC, sizeof dbUTC);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
DstStatus = DBSTATUS_E_CANTCONVERTVALUE;
|
||
|
tbDebugOut(( DEB_WARN,
|
||
|
"_StoreDate - Unexpected dest storage type %4x\n",
|
||
|
vtDst));
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return DstStatus;
|
||
|
} //_StoreDate
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: COLEDBVariant::CanConvertType, static public
|
||
|
//
|
||
|
// Synopsis: Indicate whether a type conversion is valid. Uses the OLEDB
|
||
|
// Data Conversion Library.
|
||
|
//
|
||
|
// Arguments: [wFromType] -- source type
|
||
|
// [wToType] -- destination type
|
||
|
// [xDataConvert] -- OLEDB IDataConvert interface pointer
|
||
|
//
|
||
|
// Returns: TRUE if the conversion is available, FALSE otherwise.
|
||
|
//
|
||
|
// History: 13 Jan 98 VikasMan Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
BOOL COLEDBVariant::CanConvertType(
|
||
|
DBTYPE wFromType,
|
||
|
DBTYPE wToType,
|
||
|
XInterface<IDataConvert>& xDataConvert)
|
||
|
{
|
||
|
if ( xDataConvert.IsNull( ) )
|
||
|
{
|
||
|
// use COLEDBVariant's helper function to get the IDataConvert ptr
|
||
|
if ( !_GetIDataConvert( xDataConvert ) )
|
||
|
{
|
||
|
// bail out
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SCODE sc = xDataConvert->CanConvert( wFromType, wToType );
|
||
|
if ( sc != S_OK && sc != S_FALSE )
|
||
|
{
|
||
|
QUIETTHROW(CException(sc)); // bad type
|
||
|
}
|
||
|
|
||
|
return ( sc == S_OK );
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: COLEDBVariant::_GetIDataConvert, static private
|
||
|
//
|
||
|
// Synopsis: Gets the IDataConvert interface
|
||
|
//
|
||
|
// Arguments: [xDataConvert] -- OLEDB IDataConvert interface pointer
|
||
|
//
|
||
|
// Returns: TRUE if the successful, else FALSE
|
||
|
//
|
||
|
// Notes: Make sure thet xDataConvert is null before calling this func.
|
||
|
//
|
||
|
// History: 13 Jan 98 VikasMan Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
inline
|
||
|
BOOL COLEDBVariant::_GetIDataConvert( XInterface<IDataConvert>& xDataConvert )
|
||
|
{
|
||
|
Win4Assert( xDataConvert.IsNull( ) );
|
||
|
|
||
|
SCODE sc = CoCreateInstance( CLSID_OLEDB_CONVERSIONLIBRARY,
|
||
|
NULL,
|
||
|
CLSCTX_SERVER,
|
||
|
IID_IDataConvert,
|
||
|
xDataConvert.GetQIPointer( ) );
|
||
|
|
||
|
if ( FAILED(sc) )
|
||
|
{
|
||
|
// for some reason we could not get the IDataConvert interface
|
||
|
tbDebugOut(( DEB_ERROR,
|
||
|
"_GetIDataConvert - Couldn't get IDataConvert interface %x\n", sc ));
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// Set the OLEDB ver to 2.00
|
||
|
|
||
|
XInterface<IDCInfo> xIDCInfo;
|
||
|
DCINFO rgInfo[] = {{DCINFOTYPE_VERSION, {VT_UI4, 0, 0, 0, 0x0200}}};
|
||
|
|
||
|
sc = xDataConvert->QueryInterface( IID_IDCInfo, xIDCInfo.GetQIPointer( ) );
|
||
|
if ( SUCCEEDED(sc) )
|
||
|
{
|
||
|
sc = xIDCInfo->SetInfo( NUMELEM(rgInfo), rgInfo );
|
||
|
}
|
||
|
|
||
|
if ( FAILED(sc) )
|
||
|
{
|
||
|
tbDebugOut(( DEB_ERROR,
|
||
|
"_GetIDataConvert - Can't set OLEDB ver to 2.0. Error: 0x%x\n",
|
||
|
sc));
|
||
|
Win4Assert( ! "Failed to set OLEDB conversion library version!" );
|
||
|
xDataConvert.Free();
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|