//+------------------------------------------------------------------------- // // 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 #include #include #define DBINITCONSTANTS #include // oledb data conversion (IDataConvert) interface #include #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& 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& 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 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& 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& 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 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; }