Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

6636 lines
178 KiB

  1. // This is a part of the Active Template Library.
  2. // Copyright (C) 1996-2001 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Active Template Library Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Active Template Library product.
  10. // ATLDBCLI.H : ATL consumer code for OLEDB
  11. #ifndef __ATLDBCLI_H__
  12. #define __ATLDBCLI_H__
  13. #pragma once
  14. #ifndef __cplusplus
  15. #error ATL requires C++ compilation (use a .cpp suffix)
  16. #endif
  17. #ifndef __ATLBASE_H__
  18. #include <atlbase.h>
  19. #endif
  20. #include <atlbase.inl>
  21. #include <atlsimpstr.h>
  22. #if 0
  23. #ifndef __ATLCOM_H__
  24. #include <atlcom.h>
  25. #endif
  26. #endif
  27. #ifndef __oledb_h__
  28. #include <oledb.h>
  29. #endif // __oledb_h__
  30. #include <oledberr.h>
  31. #include <msdaguid.h>
  32. #include <msdasc.h>
  33. #pragma warning(push)
  34. //REVIEW: remove this pragma once 113526 is resolved
  35. #pragma warning(disable: 4244)
  36. #ifndef _CPPUNWIND
  37. #pragma warning(disable: 4702) // unreachable code
  38. #endif
  39. namespace ATL
  40. {
  41. #define DEFINE_OLEDB_TYPE_FUNCTION(ctype, oledbtype) \
  42. inline DBTYPE _GetOleDBType(ctype&) throw ()\
  43. { \
  44. return oledbtype; \
  45. }
  46. inline DBTYPE _GetOleDBType(BYTE[]) throw ()
  47. {
  48. return DBTYPE_BYTES;
  49. }
  50. inline DBTYPE _GetOleDBType(CHAR[]) throw ()
  51. {
  52. return DBTYPE_STR;
  53. }
  54. inline DBTYPE _GetOleDBType(WCHAR[]) throw()
  55. {
  56. return DBTYPE_WSTR;
  57. }
  58. DEFINE_OLEDB_TYPE_FUNCTION(const WCHAR*, DBTYPE_WSTR | DBTYPE_BYREF)
  59. DEFINE_OLEDB_TYPE_FUNCTION(const CHAR*, DBTYPE_STR | DBTYPE_BYREF)
  60. DEFINE_OLEDB_TYPE_FUNCTION(CComBSTR, DBTYPE_BSTR)
  61. //DEFINE_OLEDB_TYPE_FUNCTION(__int8, DBTYPE_I1)
  62. //DEFINE_OLEDB_TYPE_FUNCTION(__int16, DBTYPE_I2)
  63. //DEFINE_OLEDB_TYPE_FUNCTION(__int32, DBTYPE_I4)
  64. DEFINE_OLEDB_TYPE_FUNCTION(__int64, DBTYPE_I8)
  65. //DEFINE_OLEDB_TYPE_FUNCTION(unsigned __int8, DBTYPE_UI1)
  66. //DEFINE_OLEDB_TYPE_FUNCTION(unsigned __int16, DBTYPE_UI2)
  67. //DEFINE_OLEDB_TYPE_FUNCTION(unsigned __int32, DBTYPE_UI4)
  68. DEFINE_OLEDB_TYPE_FUNCTION(unsigned __int64, DBTYPE_UI8)
  69. DEFINE_OLEDB_TYPE_FUNCTION(signed char ,DBTYPE_I1)
  70. DEFINE_OLEDB_TYPE_FUNCTION(SHORT ,DBTYPE_I2) // DBTYPE_BOOL
  71. DEFINE_OLEDB_TYPE_FUNCTION(int ,DBTYPE_I4)
  72. DEFINE_OLEDB_TYPE_FUNCTION(LONG ,DBTYPE_I4) // DBTYPE_ERROR (SCODE)
  73. DEFINE_OLEDB_TYPE_FUNCTION(LARGE_INTEGER ,DBTYPE_I8) // DBTYPE_CY
  74. DEFINE_OLEDB_TYPE_FUNCTION(CURRENCY ,DBTYPE_CY) // DBTYPE_CY
  75. DEFINE_OLEDB_TYPE_FUNCTION(BYTE ,DBTYPE_UI1)
  76. DEFINE_OLEDB_TYPE_FUNCTION(unsigned short ,DBTYPE_UI2)
  77. DEFINE_OLEDB_TYPE_FUNCTION(unsigned int ,DBTYPE_UI4)
  78. DEFINE_OLEDB_TYPE_FUNCTION(unsigned long ,DBTYPE_UI4)
  79. DEFINE_OLEDB_TYPE_FUNCTION(ULARGE_INTEGER ,DBTYPE_UI8)
  80. DEFINE_OLEDB_TYPE_FUNCTION(float ,DBTYPE_R4)
  81. DEFINE_OLEDB_TYPE_FUNCTION(double ,DBTYPE_R8) // DBTYPE_DATE
  82. DEFINE_OLEDB_TYPE_FUNCTION(DECIMAL ,DBTYPE_DECIMAL)
  83. DEFINE_OLEDB_TYPE_FUNCTION(DB_NUMERIC ,DBTYPE_NUMERIC)
  84. DEFINE_OLEDB_TYPE_FUNCTION(VARIANT ,DBTYPE_VARIANT)
  85. DEFINE_OLEDB_TYPE_FUNCTION(IDispatch* ,DBTYPE_IDISPATCH)
  86. DEFINE_OLEDB_TYPE_FUNCTION(IUnknown* ,DBTYPE_IUNKNOWN)
  87. DEFINE_OLEDB_TYPE_FUNCTION(GUID ,DBTYPE_GUID)
  88. DEFINE_OLEDB_TYPE_FUNCTION(SAFEARRAY* ,DBTYPE_ARRAY)
  89. DEFINE_OLEDB_TYPE_FUNCTION(DBVECTOR ,DBTYPE_VECTOR)
  90. DEFINE_OLEDB_TYPE_FUNCTION(DBDATE ,DBTYPE_DBDATE)
  91. DEFINE_OLEDB_TYPE_FUNCTION(DBTIME ,DBTYPE_DBTIME)
  92. DEFINE_OLEDB_TYPE_FUNCTION(DBTIMESTAMP ,DBTYPE_DBTIMESTAMP)
  93. DEFINE_OLEDB_TYPE_FUNCTION(FILETIME ,DBTYPE_FILETIME)
  94. DEFINE_OLEDB_TYPE_FUNCTION(PROPVARIANT ,DBTYPE_PROPVARIANT)
  95. DEFINE_OLEDB_TYPE_FUNCTION(DB_VARNUMERIC ,DBTYPE_VARNUMERIC)
  96. // Internal structure containing the accessor handle and a flag
  97. // indicating whether the data for the accessor is automatically
  98. // retrieved
  99. struct _ATL_ACCESSOR_INFO
  100. {
  101. HACCESSOR hAccessor;
  102. bool bAutoAccessor;
  103. };
  104. class _CNoOutputColumns
  105. {
  106. public:
  107. static bool HasOutputColumns() throw ()
  108. {
  109. return false;
  110. }
  111. static ULONG _GetNumAccessors() throw ()
  112. {
  113. return 0;
  114. }
  115. static HRESULT _GetBindEntries(LPOLESTR*, DBORDINAL*, DBBINDING*, ULONG, bool*, BYTE* pBuffer = NULL, bool bClearOnly = false) throw ()
  116. {
  117. bClearOnly;
  118. pBuffer;
  119. return E_FAIL;
  120. }
  121. };
  122. class _CNoParameters
  123. {
  124. public:
  125. static bool HasParameters() throw ()
  126. {
  127. return false;
  128. }
  129. static HRESULT _GetParamEntries(LPOLESTR*, DBORDINAL*, DBBINDING*, BYTE* pBuffer = NULL, bool bClearOnly = false) throw ()
  130. {
  131. bClearOnly;
  132. pBuffer;
  133. return E_FAIL;
  134. }
  135. };
  136. class _CNoCommand
  137. {
  138. public:
  139. static HRESULT GetDefaultCommand(LPCWSTR* /*ppszCommand*/) throw ()
  140. {
  141. return S_OK;
  142. }
  143. };
  144. typedef _CNoOutputColumns _OutputColumnsClass;
  145. typedef _CNoParameters _ParamClass;
  146. typedef _CNoCommand _CommandClass;
  147. #define BEGIN_ACCESSOR_MAP(x, num) \
  148. public: \
  149. typedef x _classtype; \
  150. typedef x _OutputColumnsClass; \
  151. static ULONG _GetNumAccessors() throw()\
  152. { \
  153. return num; \
  154. } \
  155. static bool HasOutputColumns() throw () { return true; } \
  156. /* If pBindings == NULL means we only return the column number */ \
  157. /* If pBuffer != NULL then it points to the accessor buffer and */ \
  158. /* we release any appropriate memory e.g. BSTR's or interface pointers */ \
  159. inline static HRESULT _GetBindEntries(LPOLESTR* pColumnNames, \
  160. DBORDINAL* pColumns, \
  161. DBBINDING *pBinding, \
  162. ULONG nAccessor, \
  163. bool* pAuto, \
  164. BYTE* pBuffer = NULL, \
  165. bool bClearOnly = false) throw() \
  166. { \
  167. ATLASSERT(pColumns != NULL); \
  168. DBPARAMIO eParamIO = DBPARAMIO_NOTPARAM; \
  169. DBORDINAL nColumns = 0; \
  170. pBuffer;\
  171. #define BEGIN_ACCESSOR(num, bAuto) \
  172. if (nAccessor == num) \
  173. { \
  174. if (pBinding != NULL) \
  175. *pAuto = bAuto;
  176. #define END_ACCESSOR() \
  177. } \
  178. else
  179. #define END_ACCESSOR_MAP() \
  180. ; \
  181. *pColumns = nColumns; \
  182. return S_OK; \
  183. }
  184. #define BEGIN_COLUMN_MAP(x) \
  185. BEGIN_ACCESSOR_MAP(x, 1) \
  186. BEGIN_ACCESSOR(0, true)
  187. #define END_COLUMN_MAP() \
  188. END_ACCESSOR() \
  189. END_ACCESSOR_MAP()
  190. #define offsetbuf(m) offsetof(_classtype, m)
  191. #define _OLEDB_TYPE(data) ATL::_GetOleDBType(((_classtype*)0)->data)
  192. #define _SIZE_TYPE(data) sizeof(((_classtype*)0)->data)
  193. #define _COLUMN_ENTRY_CODE(nOrdinal, wType, nLength, nPrecision, nScale, dataOffset, lengthOffset, statusOffset) \
  194. if (pBuffer != NULL) \
  195. { \
  196. if (!bClearOnly) \
  197. ATL::CAccessorBase::FreeType(wType, pBuffer + dataOffset); \
  198. memset(pBuffer + dataOffset, 0, nLength); \
  199. } \
  200. else if (pBinding != NULL) \
  201. { \
  202. ATLASSERT( pColumnNames != NULL ); \
  203. *pColumnNames = NULL; \
  204. ATL::CAccessorBase::Bind(pBinding, nOrdinal, wType, nLength, nPrecision, nScale, eParamIO, \
  205. dataOffset, lengthOffset, statusOffset); \
  206. pColumnNames++; \
  207. pBinding++; \
  208. } \
  209. nColumns++;
  210. #define _COLUMN_NAME_CODE(pszName, wType, nLength, nPrecision, nScale, dataOffset, lengthOffset, statusOffset) \
  211. if (pBuffer != NULL) \
  212. { \
  213. if (!bClearOnly) \
  214. ATL::CAccessorBase::FreeType(wType, pBuffer + dataOffset); \
  215. memset(pBuffer + dataOffset, 0, nLength); \
  216. } \
  217. else if (pBinding != NULL) \
  218. { \
  219. ATLASSERT( pColumnNames != NULL ); \
  220. *pColumnNames = pszName; \
  221. ATL::CAccessorBase::Bind(pBinding, 0, wType, nLength, nPrecision, nScale, eParamIO, \
  222. dataOffset, lengthOffset, statusOffset); \
  223. pColumnNames++; \
  224. pBinding++; \
  225. } \
  226. nColumns++;
  227. ///////////////////////////////////////////////////////////////////////////
  228. // the following tweleve macros are used for binding column by the column ordinal number
  229. #define COLUMN_ENTRY_EX(nOrdinal, wType, nLength, nPrecision, nScale, data, length, status) \
  230. _COLUMN_ENTRY_CODE(nOrdinal, wType, nLength, nPrecision, nScale, offsetbuf(data), offsetbuf(length), offsetbuf(status))
  231. #define COLUMN_ENTRY_TYPE(nOrdinal, wType, data) \
  232. COLUMN_ENTRY_TYPE_SIZE(nOrdinal, wType, _SIZE_TYPE(data), data)
  233. #define COLUMN_ENTRY_TYPE_SIZE(nOrdinal, wType, nLength, data) \
  234. _COLUMN_ENTRY_CODE(nOrdinal, wType, nLength, 0, 0, offsetbuf(data), 0, 0)
  235. #define COLUMN_ENTRY_TYPE_STATUS(nOrdinal, wType, status, data) \
  236. _COLUMN_ENTRY_CODE(nOrdinal, wType, _SIZE_TYPE(data), 0, 0, offsetbuf(data), 0, offsetbuf(status))
  237. #define COLUMN_ENTRY_TYPE_PS(nOrdinal, wType, nPrecision, nScale, data) \
  238. _COLUMN_ENTRY_CODE(nOrdinal, wType, _SIZE_TYPE(data), nPrecision, nScale, offsetbuf(data), 0, 0)
  239. // Standard macros where type and size is worked out
  240. #define COLUMN_ENTRY(nOrdinal, data) \
  241. COLUMN_ENTRY_TYPE(nOrdinal, _OLEDB_TYPE(data), data)
  242. #define COLUMN_ENTRY_LENGTH(nOrdinal, data, length) \
  243. _COLUMN_ENTRY_CODE(nOrdinal, _OLEDB_TYPE(data), _SIZE_TYPE(data), 0, 0, offsetbuf(data), offsetbuf(length), 0)
  244. #define COLUMN_ENTRY_STATUS(nOrdinal, data, status) \
  245. _COLUMN_ENTRY_CODE(nOrdinal, _OLEDB_TYPE(data), _SIZE_TYPE(data), 0, 0, offsetbuf(data), 0, offsetbuf(status))
  246. #define COLUMN_ENTRY_LENGTH_STATUS(nOrdinal, data, length, status) \
  247. _COLUMN_ENTRY_CODE(nOrdinal, _OLEDB_TYPE(data), _SIZE_TYPE(data), 0, 0, offsetbuf(data), offsetbuf(length), offsetbuf(status))
  248. // Follow macros are used if precision and scale need to be specified
  249. #define COLUMN_ENTRY_PS(nOrdinal, nPrecision, nScale, data) \
  250. _COLUMN_ENTRY_CODE(nOrdinal, _OLEDB_TYPE(data), _SIZE_TYPE(data), nPrecision, nScale, offsetbuf(data), 0, 0)
  251. #define COLUMN_ENTRY_PS_LENGTH(nOrdinal, nPrecision, nScale, data, length) \
  252. _COLUMN_ENTRY_CODE(nOrdinal, _OLEDB_TYPE(data), _SIZE_TYPE(data), nPrecision, nScale, offsetbuf(data), offsetbuf(length), 0)
  253. #define COLUMN_ENTRY_PS_STATUS(nOrdinal, nPrecision, nScale, data, status) \
  254. _COLUMN_ENTRY_CODE(nOrdinal, _OLEDB_TYPE(data), _SIZE_TYPE(data), nPrecision, nScale, offsetbuf(data), 0, offsetbuf(status))
  255. #define COLUMN_ENTRY_PS_LENGTH_STATUS(nOrdinal, nPrecision, nScale, data, length, status) \
  256. _COLUMN_ENTRY_CODE(nOrdinal, _OLEDB_TYPE(data), _SIZE_TYPE(data), nPrecision, nScale, offsetbuf(data), offsetbuf(length), offsetbuf(status))
  257. ///////////////////////////////////////////////////////////////////////////
  258. // the following tweleve macros are used for binding column by the column name
  259. #define COLUMN_NAME_EX(pszName, wType, nLength, nPrecision, nScale, data, length, status) \
  260. _COLUMN_NAME_CODE(pszName, wType, nLength, nPrecision, nScale, offsetbuf(data), offsetbuf(length), offsetbuf(status))
  261. #define COLUMN_NAME_TYPE(pszName, wType, data) \
  262. COLUMN_NAME_TYPE_SIZE(pszName, wType, _SIZE_TYPE(data), data)
  263. #define COLUMN_NAME_TYPE_SIZE(pszName, wType, nLength, data) \
  264. _COLUMN_NAME_CODE(pszName, wType, nLength, 0, 0, offsetbuf(data), 0, 0)
  265. #define COLUMN_NAME_TYPE_STATUS(pszName, wType, status, data) \
  266. _COLUMN_NAME_CODE(pszName, wType, _SIZE_TYPE(data), 0, 0, offsetbuf(data), 0, offsetbuf(status))
  267. #define COLUMN_NAME_TYPE_PS(pszName, wType, nPrecision, nScale, data) \
  268. _COLUMN_NAME_CODE(pszName, wType, _SIZE_TYPE(data), nPrecision, nScale, offsetbuf(data), 0, 0)
  269. // Standard macros where type and size is worked out
  270. #define COLUMN_NAME(pszName, data) \
  271. COLUMN_NAME_TYPE(pszName, _OLEDB_TYPE(data), data)
  272. #define COLUMN_NAME_LENGTH(pszName, data, length) \
  273. _COLUMN_NAME_CODE(pszName, _OLEDB_TYPE(data), _SIZE_TYPE(data), 0, 0, offsetbuf(data), offsetbuf(length), 0)
  274. #define COLUMN_NAME_STATUS(pszName, data, status) \
  275. _COLUMN_NAME_CODE(pszName, _OLEDB_TYPE(data), _SIZE_TYPE(data), 0, 0, offsetbuf(data), 0, offsetbuf(status))
  276. #define COLUMN_NAME_LENGTH_STATUS(pszName, data, length, status) \
  277. _COLUMN_NAME_CODE(pszName, _OLEDB_TYPE(data), _SIZE_TYPE(data), 0, 0, offsetbuf(data), offsetbuf(length), offsetbuf(status))
  278. // Follow macros are used if precision and scale need to be specified
  279. #define COLUMN_NAME_PS(pszName, nPrecision, nScale, data) \
  280. _COLUMN_NAME_CODE(pszName, _OLEDB_TYPE(data), _SIZE_TYPE(data), nPrecision, nScale, offsetbuf(data), 0, 0)
  281. #define COLUMN_NAME_PS_LENGTH(pszName, nPrecision, nScale, data, length) \
  282. _COLUMN_NAME_CODE(pszName, _OLEDB_TYPE(data), _SIZE_TYPE(data), nPrecision, nScale, offsetbuf(data), offsetbuf(length), 0)
  283. #define COLUMN_NAME_PS_STATUS(pszName, nPrecision, nScale, data, status) \
  284. _COLUMN_NAME_CODE(pszName, _OLEDB_TYPE(data), _SIZE_TYPE(data), nPrecision, nScale, offsetbuf(data), 0, offsetbuf(status))
  285. #define COLUMN_NAME_PS_LENGTH_STATUS(pszName, nPrecision, nScale, data, length, status) \
  286. _COLUMN_NAME_CODE(pszName, _OLEDB_TYPE(data), _SIZE_TYPE(data), nPrecision, nScale, offsetbuf(data), offsetbuf(length), offsetbuf(status))
  287. #define BOOKMARK_ENTRY(variable) \
  288. COLUMN_ENTRY_TYPE_SIZE(0, DBTYPE_BYTES, _SIZE_TYPE(variable##.m_rgBuffer), variable##.m_rgBuffer)
  289. #define _BLOB_ENTRY_CODE(nOrdinal, IID, flags, dataOffset, lengthOffset, statusOffset) \
  290. if (pBuffer != NULL) \
  291. { \
  292. if (!bClearOnly) \
  293. ATL::CAccessorBase::FreeType(DBTYPE_IUNKNOWN, pBuffer + dataOffset); \
  294. memset(pBuffer + dataOffset, 0, sizeof(IUnknown*)); \
  295. } \
  296. else if (pBinding != NULL) \
  297. { \
  298. ATLASSERT( pColumnNames != NULL ); \
  299. DBOBJECT* pObject = NULL; \
  300. ATLTRY(pObject = new DBOBJECT); \
  301. if (pObject == NULL) \
  302. return E_OUTOFMEMORY; \
  303. pObject->dwFlags = flags; \
  304. pObject->iid = IID; \
  305. *pColumnNames = NULL; \
  306. ATL::CAccessorBase::Bind(pBinding, nOrdinal, DBTYPE_IUNKNOWN, sizeof(IUnknown*), 0, 0, eParamIO, \
  307. dataOffset, lengthOffset, statusOffset, pObject); \
  308. pColumnNames++; \
  309. pBinding++; \
  310. } \
  311. nColumns++;
  312. #define _BLOB_NAME_CODE(pszName, IID, flags, dataOffset, lengthOffset, statusOffset) \
  313. if (pBuffer != NULL) \
  314. { \
  315. if (!bClearOnly) \
  316. ATL::CAccessorBase::FreeType(DBTYPE_IUNKNOWN, pBuffer + dataOffset); \
  317. memset(pBuffer + dataOffset, 0, sizeof(IUnknown*)); \
  318. } \
  319. else if (pBinding != NULL) \
  320. { \
  321. ATLASSERT( pColumnNames != NULL ); \
  322. DBOBJECT* pObject = NULL; \
  323. ATLTRY(pObject = new DBOBJECT); \
  324. if (pObject == NULL) \
  325. return E_OUTOFMEMORY; \
  326. pObject->dwFlags = flags; \
  327. pObject->iid = IID; \
  328. *pColumnNames = pszName; \
  329. ATL::CAccessorBase::Bind(pBinding, 0, DBTYPE_IUNKNOWN, sizeof(IUnknown*), 0, 0, eParamIO, \
  330. dataOffset, lengthOffset, statusOffset, pObject); \
  331. pColumnNames++; \
  332. pBinding++; \
  333. } \
  334. nColumns++;
  335. #define BLOB_ENTRY(nOrdinal, IID, flags, data) \
  336. _BLOB_ENTRY_CODE(nOrdinal, IID, flags, offsetbuf(data), 0, 0);
  337. #define BLOB_ENTRY_STATUS(nOrdinal, IID, flags, data, status) \
  338. _BLOB_ENTRY_CODE(nOrdinal, IID, flags, offsetbuf(data), 0, offsetbuf(status));
  339. #define BLOB_ENTRY_LENGTH(nOrdinal, IID, flags, data, length) \
  340. _BLOB_ENTRY_CODE(nOrdinal, IID, flags, offsetbuf(data), offsetbuf(length), 0);
  341. #define BLOB_ENTRY_LENGTH_STATUS(nOrdinal, IID, flags, data, length, status) \
  342. _BLOB_ENTRY_CODE(nOrdinal, IID, flags, offsetbuf(data), offsetbuf(length), offsetbuf(status));
  343. #define BLOB_NAME(pszName, IID, flags, data) \
  344. _BLOB_NAME_CODE(pszName, IID, flags, offsetbuf(data), 0, 0);
  345. #define BLOB_NAME_STATUS(pszName, IID, flags, data, status) \
  346. _BLOB_NAME_CODE(pszName, IID, flags, offsetbuf(data), 0, offsetbuf(status));
  347. #define BLOB_NAME_LENGTH(pszName, IID, flags, data, length) \
  348. _BLOB_NAME_CODE(pszName, IID, flags, offsetbuf(data), offsetbuf(length), 0);
  349. #define BLOB_NAME_LENGTH_STATUS(pszName, IID, flags, data, length, status) \
  350. _BLOB_NAME_CODE(pszName, IID, flags, offsetbuf(data), offsetbuf(length), offsetbuf(status));
  351. #define BEGIN_PARAM_MAP(x) \
  352. public: \
  353. typedef x _classtype; \
  354. typedef x _ParamClass; \
  355. static bool HasParameters() throw () { return true; } \
  356. static HRESULT _GetParamEntries(LPOLESTR* pColumnNames, \
  357. DBORDINAL* pColumns, \
  358. DBBINDING *pBinding, \
  359. BYTE* pBuffer = NULL, \
  360. bool bClearOnly = false) throw () \
  361. { \
  362. ATLASSERT(pColumns != NULL); \
  363. DBPARAMIO eParamIO = DBPARAMIO_INPUT; \
  364. int nColumns = 0; \
  365. pBuffer;
  366. #define END_PARAM_MAP() \
  367. *pColumns = nColumns; \
  368. return S_OK; \
  369. }
  370. #define SET_PARAM_TYPE(type) \
  371. eParamIO = type;
  372. #ifdef _UNICODE
  373. #define DEFINE_COMMAND(x, szCommand) \
  374. typedef x _CommandClass; \
  375. static HRESULT GetDefaultCommand(LPCWSTR* ppwszCommand) throw () \
  376. { \
  377. *ppwszCommand = szCommand; \
  378. return S_OK; \
  379. }
  380. #else // !_UNICODE
  381. #define DEFINE_COMMAND(x, szCommand) \
  382. typedef x _CommandClass; \
  383. static HRESULT GetDefaultCommand(LPCWSTR* ppwszCommand) throw () \
  384. { \
  385. static CA2WEX<sizeof(szCommand)> szCmd(szCommand); \
  386. *ppwszCommand = szCmd; \
  387. return S_OK; \
  388. }
  389. #endif // !_UNICODE
  390. //mikeguo #pragma deprecated("DEFINE_COMMAND") // Use DEFINE_COMMAND_EX instead!
  391. #define DEFINE_COMMAND_EX(x, wszCommand) \
  392. typedef x _CommandClass; \
  393. static HRESULT GetDefaultCommand(LPCWSTR* ppwszCommand) throw () \
  394. { \
  395. *ppwszCommand = wszCommand; \
  396. return S_OK; \
  397. }
  398. ///////////////////////////////////////////////////////////////////////////
  399. // class CDBErrorInfo
  400. class CDBErrorInfo
  401. {
  402. public:
  403. // Use to get the number of error record when you want to explicitly check that
  404. // the passed interface set the error information
  405. HRESULT GetErrorRecords(IUnknown* pUnk, const IID& iid, ULONG* pcRecords) throw()
  406. {
  407. CComPtr<ISupportErrorInfo> spSupportErrorInfo;
  408. HRESULT hr = pUnk->QueryInterface(&spSupportErrorInfo);
  409. if (FAILED(hr))
  410. return hr;
  411. hr = spSupportErrorInfo->InterfaceSupportsErrorInfo(iid);
  412. if (FAILED(hr))
  413. return hr;
  414. return GetErrorRecords(pcRecords);
  415. }
  416. // Use to get the number of error records
  417. HRESULT GetErrorRecords(ULONG* pcRecords) throw ()
  418. {
  419. ATLASSERT(pcRecords != NULL);
  420. HRESULT hr;
  421. m_spErrorInfo.Release();
  422. m_spErrorRecords.Release();
  423. hr = ::GetErrorInfo(0, &m_spErrorInfo);
  424. if (hr == S_FALSE)
  425. return E_FAIL;
  426. hr = m_spErrorInfo->QueryInterface(__uuidof(IErrorRecords), (void**)&m_spErrorRecords);
  427. if (FAILED(hr))
  428. {
  429. // Well we got the IErrorInfo so we'll just treat that as
  430. // the one record
  431. *pcRecords = 1;
  432. return S_OK;
  433. }
  434. return m_spErrorRecords->GetRecordCount(pcRecords);
  435. }
  436. // Get the error information for the passed record number. GetErrorRecords must
  437. // be called before this function is called.
  438. HRESULT GetAllErrorInfo(ULONG ulRecordNum, LCID lcid, BSTR* pbstrDescription,
  439. BSTR* pbstrSource = NULL, GUID* pguid = NULL, DWORD* pdwHelpContext = NULL,
  440. BSTR* pbstrHelpFile = NULL) const throw()
  441. {
  442. CComPtr<IErrorInfo> spErrorInfo;
  443. // If we have the IErrorRecords interface pointer then use it, otherwise
  444. // we'll just default to the IErrorInfo we have already retrieved in the call
  445. // to GetErrorRecords
  446. if (m_spErrorRecords != NULL)
  447. {
  448. HRESULT hr = m_spErrorRecords->GetErrorInfo(ulRecordNum, lcid, &spErrorInfo);
  449. if (FAILED(hr))
  450. return hr;
  451. }
  452. else
  453. {
  454. ATLASSERT(m_spErrorInfo != NULL);
  455. spErrorInfo = m_spErrorInfo;
  456. }
  457. if (pbstrDescription != NULL)
  458. spErrorInfo->GetDescription(pbstrDescription);
  459. if (pguid != NULL)
  460. spErrorInfo->GetGUID(pguid);
  461. if (pdwHelpContext != NULL)
  462. spErrorInfo->GetHelpContext(pdwHelpContext);
  463. if (pbstrHelpFile != NULL)
  464. spErrorInfo->GetHelpFile(pbstrHelpFile);
  465. if (pbstrSource != NULL)
  466. spErrorInfo->GetSource(pbstrSource);
  467. return S_OK;
  468. }
  469. // Get the error information for the passed record number
  470. HRESULT GetBasicErrorInfo(ULONG ulRecordNum, ERRORINFO* pErrorInfo) const throw ()
  471. {
  472. return m_spErrorRecords->GetBasicErrorInfo(ulRecordNum, pErrorInfo);
  473. }
  474. // Get the custom error object for the passed record number
  475. HRESULT GetCustomErrorObject(ULONG ulRecordNum, REFIID riid, IUnknown** ppObject) const throw ()
  476. {
  477. return m_spErrorRecords->GetCustomErrorObject(ulRecordNum, riid, ppObject);
  478. }
  479. // Get the IErrorInfo interface for the passed record number
  480. HRESULT GetErrorInfo(ULONG ulRecordNum, LCID lcid, IErrorInfo** ppErrorInfo) const throw ()
  481. {
  482. return m_spErrorRecords->GetErrorInfo(ulRecordNum, lcid, ppErrorInfo);
  483. }
  484. // Get the error parameters for the passed record number
  485. HRESULT GetErrorParameters(ULONG ulRecordNum, DISPPARAMS* pdispparams) const throw ()
  486. {
  487. return m_spErrorRecords->GetErrorParameters(ulRecordNum, pdispparams);
  488. }
  489. // Implementation
  490. CComPtr<IErrorInfo> m_spErrorInfo;
  491. CComPtr<IErrorRecords> m_spErrorRecords;
  492. };
  493. #ifdef _DEBUG
  494. inline void AtlTraceErrorRecords(HRESULT hrErr = S_OK)
  495. {
  496. CDBErrorInfo ErrorInfo;
  497. ULONG cRecords;
  498. HRESULT hr;
  499. ULONG i;
  500. CComBSTR bstrDesc, bstrHelpFile, bstrSource;
  501. GUID guid;
  502. DWORD dwHelpContext;
  503. WCHAR wszGuid[40];
  504. USES_CONVERSION;
  505. // If the user passed in an HRESULT then trace it
  506. if (hrErr != S_OK)
  507. ATLTRACE(atlTraceDBClient, 0, _T("OLE DB Error Record dump for hr = 0x%x\n"), hrErr);
  508. LCID lcLocale = GetSystemDefaultLCID();
  509. hr = ErrorInfo.GetErrorRecords(&cRecords);
  510. if (FAILED(hr) && ErrorInfo.m_spErrorInfo == NULL)
  511. {
  512. ATLTRACE(atlTraceDBClient, 0, _T("No OLE DB Error Information found: hr = 0x%x\n"), hr);
  513. }
  514. else
  515. {
  516. for (i = 0; i < cRecords; i++)
  517. {
  518. hr = ErrorInfo.GetAllErrorInfo(i, lcLocale, &bstrDesc, &bstrSource, &guid,
  519. &dwHelpContext, &bstrHelpFile);
  520. if (FAILED(hr))
  521. {
  522. ATLTRACE(atlTraceDBClient, 0,
  523. _T("OLE DB Error Record dump retrieval failed: hr = 0x%x\n"), hr);
  524. return;
  525. }
  526. StringFromGUID2(guid, wszGuid, sizeof(wszGuid) / sizeof(WCHAR));
  527. ATLTRACE(atlTraceDBClient, 0,
  528. _T("Row #: %4d Source: \"%s\" Description: \"%s\" Help File: \"%s\" Help Context: %4d GUID: %s\n"),
  529. i, OLE2T(bstrSource), OLE2T(bstrDesc), OLE2T(bstrHelpFile), dwHelpContext, OLE2T(wszGuid));
  530. bstrSource.Empty();
  531. bstrDesc.Empty();
  532. bstrHelpFile.Empty();
  533. }
  534. ATLTRACE(atlTraceDBClient, 0, _T("OLE DB Error Record dump end\n"));
  535. }
  536. }
  537. #else
  538. inline void AtlTraceErrorRecords(HRESULT hrErr = S_OK) throw() { hrErr; }
  539. #endif
  540. ///////////////////////////////////////////////////////////////////////////
  541. // class CDBPropSet
  542. class CDBPropSet : public tagDBPROPSET
  543. {
  544. public:
  545. CDBPropSet()
  546. {
  547. rgProperties = NULL;
  548. cProperties = 0;
  549. }
  550. CDBPropSet(const GUID& guid)
  551. {
  552. rgProperties = NULL;
  553. cProperties = 0;
  554. guidPropertySet = guid;
  555. }
  556. CDBPropSet(const CDBPropSet& propset)
  557. {
  558. InternalCopy(propset);
  559. }
  560. ~CDBPropSet()
  561. {
  562. for (ULONG i = 0; i < cProperties; i++)
  563. VariantClear(&rgProperties[i].vValue);
  564. CoTaskMemFree(rgProperties);
  565. }
  566. CDBPropSet& operator=(CDBPropSet& propset) throw()
  567. {
  568. this->~CDBPropSet();
  569. InternalCopy(propset);
  570. return *this;
  571. }
  572. // Set the GUID of the property set this class represents.
  573. // Use if you didn't pass the GUID to the constructor.
  574. void SetGUID(const GUID& guid) throw()
  575. {
  576. guidPropertySet = guid;
  577. }
  578. // Add the passed property to the property set
  579. bool AddProperty(DWORD dwPropertyID, const VARIANT& var, DBPROPOPTIONS propoptions = DBPROPOPTIONS_REQUIRED) throw()
  580. {
  581. HRESULT hr;
  582. if (!Add(propoptions))
  583. return false;
  584. rgProperties[cProperties].dwPropertyID = dwPropertyID;
  585. hr = ::VariantCopy(&(rgProperties[cProperties].vValue), const_cast<VARIANT*>(&var));
  586. if (FAILED(hr))
  587. return false;
  588. cProperties++;
  589. return true;
  590. }
  591. // Add the passed property to the property set
  592. bool AddProperty(DWORD dwPropertyID, LPCSTR szValue, DBPROPOPTIONS propoptions = DBPROPOPTIONS_REQUIRED) throw()
  593. {
  594. USES_CONVERSION;
  595. if (!Add(propoptions))
  596. return false;
  597. rgProperties[cProperties].dwPropertyID = dwPropertyID;
  598. rgProperties[cProperties].vValue.vt = VT_BSTR;
  599. rgProperties[cProperties].vValue.bstrVal = SysAllocString(A2COLE(szValue));
  600. if (rgProperties[cProperties].vValue.bstrVal == NULL)
  601. return false;
  602. cProperties++;
  603. return true;
  604. }
  605. // Add the passed property to the property set
  606. bool AddProperty(DWORD dwPropertyID, LPCWSTR szValue, DBPROPOPTIONS propoptions = DBPROPOPTIONS_REQUIRED) throw()
  607. {
  608. USES_CONVERSION;
  609. if (!Add(propoptions))
  610. return false;
  611. rgProperties[cProperties].dwPropertyID = dwPropertyID;
  612. rgProperties[cProperties].vValue.vt = VT_BSTR;
  613. rgProperties[cProperties].vValue.bstrVal = SysAllocString(W2COLE(szValue));
  614. if (rgProperties[cProperties].vValue.bstrVal == NULL)
  615. return false;
  616. cProperties++;
  617. return true;
  618. }
  619. // Add the passed property to the property set
  620. bool AddProperty(DWORD dwPropertyID, bool bValue, DBPROPOPTIONS propoptions = DBPROPOPTIONS_REQUIRED) throw()
  621. {
  622. if (!Add(propoptions))
  623. return false;
  624. rgProperties[cProperties].dwPropertyID = dwPropertyID;
  625. rgProperties[cProperties].vValue.vt = VT_BOOL;
  626. rgProperties[cProperties].vValue.boolVal = (bValue) ? ATL_VARIANT_TRUE : ATL_VARIANT_FALSE;
  627. cProperties++;
  628. return true;
  629. }
  630. // Add the passed property to the property set
  631. bool AddProperty(DWORD dwPropertyID, BYTE bValue, DBPROPOPTIONS propoptions = DBPROPOPTIONS_REQUIRED)
  632. {
  633. if (!Add(propoptions))
  634. return false;
  635. rgProperties[cProperties].dwPropertyID = dwPropertyID;
  636. rgProperties[cProperties].vValue.vt = VT_UI1;
  637. rgProperties[cProperties].vValue.bVal = bValue;
  638. cProperties++;
  639. return true;
  640. }
  641. // Add the passed property to the property set
  642. bool AddProperty(DWORD dwPropertyID, short nValue, DBPROPOPTIONS propoptions = DBPROPOPTIONS_REQUIRED)
  643. {
  644. if (!Add(propoptions))
  645. return false;
  646. rgProperties[cProperties].dwPropertyID = dwPropertyID;
  647. rgProperties[cProperties].vValue.vt = VT_I2;
  648. rgProperties[cProperties].vValue.iVal = nValue;
  649. cProperties++;
  650. return true;
  651. }
  652. // Add the passed property to the property set
  653. bool AddProperty(DWORD dwPropertyID, long nValue, DBPROPOPTIONS propoptions = DBPROPOPTIONS_REQUIRED)
  654. {
  655. if (!Add(propoptions))
  656. return false;
  657. rgProperties[cProperties].dwPropertyID = dwPropertyID;
  658. rgProperties[cProperties].vValue.vt = VT_I4;
  659. rgProperties[cProperties].vValue.lVal = nValue;
  660. cProperties++;
  661. return true;
  662. }
  663. // Add the passed property to the property set
  664. bool AddProperty(DWORD dwPropertyID, float fltValue, DBPROPOPTIONS propoptions = DBPROPOPTIONS_REQUIRED)
  665. {
  666. if (!Add(propoptions))
  667. return false;
  668. rgProperties[cProperties].dwPropertyID = dwPropertyID;
  669. rgProperties[cProperties].vValue.vt = VT_R4;
  670. rgProperties[cProperties].vValue.fltVal = fltValue;
  671. cProperties++;
  672. return true;
  673. }
  674. // Add the passed property to the property set
  675. bool AddProperty(DWORD dwPropertyID, double dblValue, DBPROPOPTIONS propoptions = DBPROPOPTIONS_REQUIRED) throw()
  676. {
  677. if (!Add(propoptions))
  678. return false;
  679. rgProperties[cProperties].dwPropertyID = dwPropertyID;
  680. rgProperties[cProperties].vValue.vt = VT_R8;
  681. rgProperties[cProperties].vValue.dblVal = dblValue;
  682. cProperties++;
  683. return true;
  684. }
  685. // Add the passed property to the property set
  686. bool AddProperty(DWORD dwPropertyID, CY cyValue, DBPROPOPTIONS propoptions = DBPROPOPTIONS_REQUIRED) throw()
  687. {
  688. if (!Add(propoptions))
  689. return false;
  690. rgProperties[cProperties].dwPropertyID = dwPropertyID;
  691. rgProperties[cProperties].vValue.vt = VT_CY;
  692. rgProperties[cProperties].vValue.cyVal = cyValue;
  693. cProperties++;
  694. return true;
  695. }
  696. // Implementation
  697. // Create memory to add a new property
  698. bool Add(DBPROPOPTIONS propoptions = DBPROPOPTIONS_REQUIRED) throw()
  699. {
  700. DBPROP* rgTemp = (DBPROP*)CoTaskMemRealloc(rgProperties, (cProperties + 1) * sizeof(DBPROP));
  701. if (rgTemp == NULL)
  702. return false;
  703. rgProperties = rgTemp;
  704. rgProperties[cProperties].dwOptions = propoptions;
  705. rgProperties[cProperties].colid = DB_NULLID;
  706. rgProperties[cProperties].vValue.vt = VT_EMPTY;
  707. return true;
  708. }
  709. // Copies in the passed value now it this value been cleared
  710. void InternalCopy(const CDBPropSet& propset) throw()
  711. {
  712. cProperties = propset.cProperties;
  713. guidPropertySet = propset.guidPropertySet;
  714. rgProperties = (DBPROP*)CoTaskMemAlloc(cProperties * sizeof(DBPROP));
  715. if (rgProperties != NULL)
  716. {
  717. for (ULONG i = 0; i < cProperties; i++)
  718. {
  719. rgProperties[i].dwPropertyID = propset.rgProperties[i].dwPropertyID;
  720. if( propset.rgProperties[i].dwOptions == DBPROPOPTIONS_OPTIONAL )
  721. rgProperties[i].dwOptions = DBPROPOPTIONS_OPTIONAL;
  722. else
  723. rgProperties[i].dwOptions = DBPROPOPTIONS_REQUIRED;
  724. rgProperties[i].colid = DB_NULLID;
  725. rgProperties[i].vValue.vt = VT_EMPTY;
  726. VariantCopy(&rgProperties[i].vValue, &propset.rgProperties[i].vValue);
  727. }
  728. }
  729. else
  730. {
  731. // The memory allocation failed so set the count
  732. // of properties to zero
  733. cProperties = 0;
  734. }
  735. }
  736. };
  737. ///////////////////////////////////////////////////////////////////////////
  738. // class CDBPropIDSet
  739. class CDBPropIDSet : public tagDBPROPIDSET
  740. {
  741. // Constructors and Destructors
  742. public:
  743. CDBPropIDSet()
  744. {
  745. rgPropertyIDs = NULL;
  746. cPropertyIDs = 0;
  747. }
  748. CDBPropIDSet(const GUID& guid)
  749. {
  750. rgPropertyIDs = NULL;
  751. cPropertyIDs = 0;
  752. guidPropertySet = guid;
  753. }
  754. CDBPropIDSet(const CDBPropIDSet& propidset)
  755. {
  756. InternalCopy(propidset);
  757. }
  758. ~CDBPropIDSet()
  759. {
  760. free(rgPropertyIDs);
  761. }
  762. CDBPropIDSet& operator=(CDBPropIDSet& propset) throw()
  763. {
  764. this->~CDBPropIDSet();
  765. InternalCopy(propset);
  766. return *this;
  767. }
  768. // Set the GUID of the property ID set
  769. void SetGUID(const GUID& guid) throw()
  770. {
  771. guidPropertySet = guid;
  772. }
  773. // Add a property ID to the set
  774. bool AddPropertyID(DBPROPID propid) throw()
  775. {
  776. if (!Add())
  777. return false;
  778. rgPropertyIDs[cPropertyIDs] = propid;
  779. cPropertyIDs++;
  780. return true;
  781. }
  782. // Implementation
  783. bool Add() throw()
  784. {
  785. DBPROPID* pTempID = (DBPROPID*)realloc(rgPropertyIDs, (cPropertyIDs + 1) * sizeof(DBPROPID));
  786. if (pTempID == NULL)
  787. return false;
  788. rgPropertyIDs = pTempID;
  789. return true;
  790. }
  791. void InternalCopy(const CDBPropIDSet& propidset) throw()
  792. {
  793. cPropertyIDs = propidset.cPropertyIDs;
  794. guidPropertySet = propidset.guidPropertySet;
  795. rgPropertyIDs = NULL;
  796. ATLTRY(rgPropertyIDs = (DBPROPID*)malloc(cPropertyIDs * sizeof(DBPROPID)));
  797. if (rgPropertyIDs != NULL)
  798. {
  799. for (ULONG i = 0; i < cPropertyIDs; i++)
  800. rgPropertyIDs[i] = propidset.rgPropertyIDs[i];
  801. }
  802. else
  803. {
  804. // The memory allocation failed so set the count
  805. // of properties to zero
  806. cPropertyIDs = 0;
  807. }
  808. }
  809. };
  810. ///////////////////////////////////////////////////////////////////////////
  811. // class CBookmarkBase
  812. class ATL_NO_VTABLE CBookmarkBase
  813. {
  814. public:
  815. virtual DBLENGTH GetSize() const = 0;
  816. virtual BYTE* GetBuffer() const = 0;
  817. };
  818. ///////////////////////////////////////////////////////////////////////////
  819. // class CBookmark
  820. template <DBLENGTH nSize = 0>
  821. class CBookmark : public CBookmarkBase
  822. {
  823. public:
  824. virtual DBLENGTH GetSize() const throw() { return nSize; }
  825. virtual BYTE* GetBuffer() const throw() { return (BYTE*)m_rgBuffer; }
  826. // Implementation
  827. BYTE m_rgBuffer[nSize];
  828. };
  829. // Size of 0 means that the memory for the bookmark will be allocated
  830. // at run time.
  831. template <>
  832. class CBookmark<0> : public CBookmarkBase
  833. {
  834. public:
  835. CBookmark()
  836. {
  837. m_nSize = 0;
  838. m_pBuffer = NULL;
  839. }
  840. CBookmark(DBLENGTH nSize)
  841. {
  842. m_pBuffer = NULL;
  843. ATLTRY(m_pBuffer = new BYTE[nSize]);
  844. m_nSize = (m_pBuffer == NULL) ? 0 : nSize;
  845. }
  846. ~CBookmark()
  847. {
  848. delete [] m_pBuffer;
  849. }
  850. CBookmark& operator=(const CBookmark& bookmark) throw()
  851. {
  852. SetBookmark(bookmark.GetSize(), bookmark.GetBuffer());
  853. return *this;
  854. }
  855. virtual DBLENGTH GetSize() const throw() { return m_nSize; }
  856. virtual BYTE* GetBuffer() const throw() { return m_pBuffer; }
  857. // Sets the bookmark to the passed value
  858. HRESULT SetBookmark(DBLENGTH nSize, BYTE* pBuffer) throw()
  859. {
  860. ATLASSERT(pBuffer != NULL);
  861. delete [] m_pBuffer;
  862. m_pBuffer = NULL;
  863. ATLTRY(m_pBuffer = new BYTE[nSize]);
  864. if (m_pBuffer != NULL)
  865. {
  866. memcpy(m_pBuffer, pBuffer, nSize);
  867. m_nSize = nSize;
  868. return S_OK;
  869. }
  870. else
  871. {
  872. m_nSize = 0;
  873. return E_OUTOFMEMORY;
  874. }
  875. }
  876. DBLENGTH m_nSize;
  877. BYTE* m_pBuffer;
  878. };
  879. ///////////////////////////////////////////////////////////////////////////
  880. // class CAccessorBase
  881. class CAccessorBase
  882. {
  883. public:
  884. CAccessorBase()
  885. {
  886. m_pAccessorInfo = NULL;
  887. m_nAccessors = 0;
  888. m_pBuffer = NULL;
  889. }
  890. void Close() throw()
  891. {
  892. // If Close is called then ReleaseAccessors must have been
  893. // called first
  894. ATLASSERT(m_nAccessors == 0);
  895. ATLASSERT(m_pAccessorInfo == NULL);
  896. }
  897. // Get the number of accessors that have been created
  898. ULONG GetNumAccessors() const throw() { return m_nAccessors; }
  899. // Get the handle of the passed accessor (offset from 0)
  900. HACCESSOR GetHAccessor(ULONG nAccessor) const throw()
  901. {
  902. ATLASSERT(nAccessor<m_nAccessors);
  903. return m_pAccessorInfo[nAccessor].hAccessor;
  904. };
  905. // Called during Close to release the accessor information
  906. HRESULT ReleaseAccessors(IUnknown* pUnk) throw()
  907. {
  908. ATLASSERT(pUnk != NULL);
  909. HRESULT hr = S_OK;
  910. if (m_nAccessors > 0)
  911. {
  912. CComPtr<IAccessor> spAccessor;
  913. hr = pUnk->QueryInterface(__uuidof(IAccessor), (void**)&spAccessor);
  914. if (SUCCEEDED(hr))
  915. {
  916. ATLASSERT(m_pAccessorInfo != NULL);
  917. for (ULONG i = 0; i < m_nAccessors; i++)
  918. spAccessor->ReleaseAccessor(m_pAccessorInfo[i].hAccessor, NULL);
  919. }
  920. m_nAccessors = 0;
  921. delete [] m_pAccessorInfo;
  922. m_pAccessorInfo = NULL;
  923. }
  924. return hr;
  925. }
  926. // Returns true or false depending upon whether data should be
  927. // automatically retrieved for the passed accessor.
  928. bool IsAutoAccessor(ULONG nAccessor) const throw()
  929. {
  930. ATLASSERT(nAccessor < m_nAccessors);
  931. ATLASSERT(m_pAccessorInfo != NULL);
  932. return m_pAccessorInfo[nAccessor].bAutoAccessor;
  933. }
  934. // Implementation
  935. // Used by the rowset class to find out where to place the data
  936. BYTE* GetBuffer() const throw()
  937. {
  938. return m_pBuffer;
  939. }
  940. // Set the buffer that is used to retrieve the data
  941. void SetBuffer(BYTE* pBuffer) throw()
  942. {
  943. m_pBuffer = pBuffer;
  944. }
  945. bool NoBindOnNullRowset() const throw()
  946. {
  947. return false;
  948. }
  949. // Allocate internal memory for the passed number of accessors
  950. HRESULT AllocateAccessorMemory(int nAccessors) throw()
  951. {
  952. // Can't be called twice without calling ReleaseAccessors first
  953. ATLASSERT(m_pAccessorInfo == NULL);
  954. m_nAccessors = nAccessors;
  955. m_pAccessorInfo = NULL;
  956. ATLTRY(m_pAccessorInfo = new _ATL_ACCESSOR_INFO[nAccessors]);
  957. if (m_pAccessorInfo == NULL)
  958. return E_OUTOFMEMORY;
  959. else
  960. return S_OK;
  961. }
  962. // BindParameters will be overriden if parameters are used
  963. HRESULT BindParameters(HACCESSOR*, ICommand*, void**) throw() { return S_OK; }
  964. // Create an accessor for the passed binding information. The created accessor is
  965. // returned through the pHAccessor parameter.
  966. static HRESULT BindEntries(DBBINDING* pBindings, DBORDINAL nColumns, HACCESSOR* pHAccessor,
  967. DBLENGTH nSize, IAccessor* pAccessor) throw()
  968. {
  969. ATLASSERT(pBindings != NULL);
  970. ATLASSERT(pHAccessor != NULL);
  971. ATLASSERT(pAccessor != NULL);
  972. HRESULT hr;
  973. DBORDINAL i;
  974. DWORD dwAccessorFlags = (pBindings->eParamIO == DBPARAMIO_NOTPARAM) ?
  975. DBACCESSOR_ROWDATA : DBACCESSOR_PARAMETERDATA;
  976. #ifdef _DEBUG
  977. // In debug builds we will retrieve the status flags and trace out
  978. // any errors that may occur.
  979. CAutoVectorPtr<DBBINDSTATUS> spStatus;
  980. hr = pAccessor->CreateAccessor(dwAccessorFlags, nColumns,
  981. pBindings, nSize, pHAccessor, spStatus);
  982. if (FAILED(hr) && (DBBINDSTATUS*)spStatus)
  983. {
  984. for (i=0; i<nColumns; i++)
  985. {
  986. if (spStatus[i] != DBBINDSTATUS_OK)
  987. ATLTRACE(atlTraceDBClient, 0, _T("Binding entry %d failed. Status: %d\n"), i, spStatus[i]);
  988. }
  989. }
  990. #else
  991. hr = pAccessor->CreateAccessor(dwAccessorFlags, nColumns,
  992. pBindings, nSize, pHAccessor, NULL);
  993. #endif
  994. for (i=0; i<nColumns; i++)
  995. delete pBindings[i].pObject;
  996. return hr;
  997. }
  998. // Set up the binding structure pointed to by pBindings based upon
  999. // the other passed parameters.
  1000. static void Bind(DBBINDING* pBinding, DBORDINAL nOrdinal, DBTYPE wType,
  1001. DBLENGTH nLength, BYTE nPrecision, BYTE nScale, DBPARAMIO eParamIO,
  1002. DBBYTEOFFSET nDataOffset, DBBYTEOFFSET nLengthOffset = NULL, DBBYTEOFFSET nStatusOffset = NULL,
  1003. DBOBJECT* pdbobject = NULL) throw()
  1004. {
  1005. ATLASSERT(pBinding != NULL);
  1006. // If we are getting a pointer to the data then let the provider
  1007. // own the memory
  1008. if (wType & DBTYPE_BYREF)
  1009. pBinding->dwMemOwner = DBMEMOWNER_PROVIDEROWNED;
  1010. else
  1011. pBinding->dwMemOwner = DBMEMOWNER_CLIENTOWNED;
  1012. pBinding->pObject = pdbobject;
  1013. pBinding->eParamIO = eParamIO;
  1014. pBinding->iOrdinal = nOrdinal;
  1015. pBinding->wType = wType;
  1016. pBinding->bPrecision = nPrecision;
  1017. pBinding->bScale = nScale;
  1018. pBinding->dwFlags = 0;
  1019. pBinding->obValue = nDataOffset;
  1020. pBinding->obLength = 0;
  1021. pBinding->obStatus = 0;
  1022. pBinding->pTypeInfo = NULL;
  1023. pBinding->pBindExt = NULL;
  1024. pBinding->cbMaxLen = nLength;
  1025. pBinding->dwPart = DBPART_VALUE;
  1026. if (nLengthOffset != NULL)
  1027. {
  1028. pBinding->dwPart |= DBPART_LENGTH;
  1029. pBinding->obLength = nLengthOffset;
  1030. }
  1031. if (nStatusOffset != NULL)
  1032. {
  1033. pBinding->dwPart |= DBPART_STATUS;
  1034. pBinding->obStatus = nStatusOffset;
  1035. }
  1036. }
  1037. // Free memory if appropriate
  1038. static inline void FreeType(DBTYPE wType, BYTE* pValue, IRowset* pRowset = NULL) throw()
  1039. {
  1040. if (pValue == NULL || *pValue == NULL)
  1041. return;
  1042. if( wType & DBTYPE_ARRAY )
  1043. {
  1044. SAFEARRAY** ppSafeArray = (SAFEARRAY**)pValue;
  1045. if( ppSafeArray != NULL )
  1046. SafeArrayDestroy(*ppSafeArray);
  1047. }
  1048. else
  1049. {
  1050. switch (wType)
  1051. {
  1052. case DBTYPE_BSTR:
  1053. SysFreeString(*((BSTR*)pValue));
  1054. break;
  1055. case DBTYPE_VARIANT:
  1056. VariantClear((VARIANT*)pValue);
  1057. break;
  1058. case DBTYPE_IUNKNOWN:
  1059. case DBTYPE_IDISPATCH:
  1060. (*(IUnknown**)pValue)->Release();
  1061. break;
  1062. case DBTYPE_HCHAPTER:
  1063. CComQIPtr<IChapteredRowset> spChapteredRowset = pRowset;
  1064. if (spChapteredRowset != NULL)
  1065. spChapteredRowset->ReleaseChapter(*(HCHAPTER*)pValue, NULL);
  1066. break;
  1067. }
  1068. }
  1069. if ((wType & DBTYPE_VECTOR) && ~(wType & DBTYPE_BYREF))
  1070. CoTaskMemFree(((DBVECTOR*)pValue)->ptr);
  1071. }
  1072. void FreeRecordMemory(IRowset* /*pRowset*/) throw()
  1073. {
  1074. }
  1075. _ATL_ACCESSOR_INFO* m_pAccessorInfo;
  1076. ULONG m_nAccessors;
  1077. BYTE* m_pBuffer;
  1078. };
  1079. class CXMLAccessor;
  1080. ///////////////////////////////////////////////////////////////////////////
  1081. // class CRowset
  1082. template <class TAccessor = CAccessorBase>
  1083. class CRowset
  1084. {
  1085. // Constructors and Destructors
  1086. public:
  1087. CRowset()
  1088. {
  1089. m_pXMLAccessor = NULL;
  1090. m_pAccessor = NULL;
  1091. m_hRow = NULL;
  1092. }
  1093. CRowset(IRowset* pRowset)
  1094. {
  1095. m_pXMLAccessor = NULL;
  1096. m_pAccessor = NULL;
  1097. m_hRow = NULL;
  1098. m_spRowset = pRowset;
  1099. }
  1100. ~CRowset()
  1101. {
  1102. Close();
  1103. }
  1104. HRESULT GetXMLColumnInfo( CSimpleStringW& strOutput ) throw()
  1105. {
  1106. ATLASSERT(m_spRowset != NULL);
  1107. HRESULT hr;
  1108. if( m_pXMLAccessor == NULL )
  1109. {
  1110. ATLTRY(m_pXMLAccessor = new CXMLAccessor);
  1111. if( m_pXMLAccessor == NULL )
  1112. return E_OUTOFMEMORY;
  1113. hr = m_pXMLAccessor->BindColumns( m_spRowset );
  1114. if( FAILED(hr) )
  1115. {
  1116. delete m_pXMLAccessor;
  1117. m_pXMLAccessor = NULL;
  1118. return hr;
  1119. }
  1120. }
  1121. ATLASSERT( m_pXMLAccessor != NULL );
  1122. return m_pXMLAccessor->GetXMLColumnData( strOutput );
  1123. }
  1124. HRESULT GetXMLRow( CSimpleStringW& strOutput, bool bAppend = false ) throw()
  1125. {
  1126. ATLASSERT(m_spRowset != NULL);
  1127. ATLASSERT(m_hRow != NULL);
  1128. HRESULT hr;
  1129. if( m_pXMLAccessor == NULL )
  1130. {
  1131. ATLTRY(m_pXMLAccessor = new CXMLAccessor);
  1132. if( m_pXMLAccessor == NULL )
  1133. return E_OUTOFMEMORY;
  1134. hr = m_pXMLAccessor->BindColumns( m_spRowset );
  1135. if( FAILED(hr) )
  1136. {
  1137. delete m_pXMLAccessor;
  1138. m_pXMLAccessor = NULL;
  1139. return hr;
  1140. }
  1141. }
  1142. ATLASSERT( m_pXMLAccessor != NULL );
  1143. hr = m_spRowset->GetData(m_hRow, m_pXMLAccessor->GetHAccessor(0), m_pXMLAccessor->GetBuffer());
  1144. if( FAILED(hr) )
  1145. return hr;
  1146. hr = m_pXMLAccessor->GetXMLRowData( strOutput, bAppend );
  1147. m_pXMLAccessor->FreeRecordMemory( GetInterface() );
  1148. return hr;
  1149. }
  1150. // Release any retrieved row handles and then release the rowset
  1151. void Close() throw()
  1152. {
  1153. if( m_pXMLAccessor != NULL )
  1154. {
  1155. if (m_spRowset != NULL)
  1156. m_pXMLAccessor->ReleaseAccessors( m_spRowset );
  1157. delete m_pXMLAccessor;
  1158. m_pXMLAccessor = NULL;
  1159. }
  1160. if (m_spRowset != NULL)
  1161. {
  1162. m_pAccessor->FreeRecordMemory(m_spRowset);
  1163. ReleaseRows();
  1164. m_spRowset.Release();
  1165. m_spRowsetChange.Release();
  1166. }
  1167. }
  1168. // Addref the current row
  1169. HRESULT AddRefRows() throw()
  1170. {
  1171. ATLASSERT(m_spRowset != NULL);
  1172. return m_spRowset->AddRefRows(1, &m_hRow, NULL, NULL);
  1173. }
  1174. // Release the current row
  1175. HRESULT ReleaseRows() throw()
  1176. {
  1177. ATLASSERT(m_spRowset != NULL);
  1178. HRESULT hr = S_OK;
  1179. if (m_hRow != NULL)
  1180. {
  1181. hr = m_spRowset->ReleaseRows(1, &m_hRow, NULL, NULL, NULL);
  1182. m_hRow = NULL;
  1183. }
  1184. return hr;
  1185. }
  1186. CRowset<>* GetRowsetBase() throw()
  1187. {
  1188. return (CRowset<>*)this;
  1189. }
  1190. // Compare two bookmarks with each other
  1191. HRESULT Compare(const CBookmarkBase& bookmark1, const CBookmarkBase& bookmark2, DBCOMPARE* pComparison) const throw()
  1192. {
  1193. ATLASSERT(m_spRowset != NULL);
  1194. CComPtr<IRowsetLocate> spLocate;
  1195. HRESULT hr = m_spRowset.QueryInterface(&spLocate);
  1196. if (FAILED(hr))
  1197. return hr;
  1198. return spLocate->Compare(NULL, bookmark1.GetSize(), bookmark1.GetBuffer(),
  1199. bookmark2.GetSize(), bookmark2.GetBuffer(), pComparison);
  1200. }
  1201. // Compare the passed hRow with the current row
  1202. HRESULT IsSameRow(HROW hRow) const throw()
  1203. {
  1204. ATLASSERT(m_spRowset != NULL);
  1205. if (m_hRow == hRow)
  1206. return S_OK;
  1207. CComPtr<IRowsetIdentity> spRowsetIdentity;
  1208. HRESULT hr = m_spRowset.QueryInterface(&spRowsetIdentity);
  1209. if (FAILED(hr))
  1210. return hr;
  1211. return spRowsetIdentity->IsSameRow(m_hRow, hRow);
  1212. }
  1213. // Move to the previous record
  1214. HRESULT MovePrev() throw()
  1215. {
  1216. // the following line of code may fail if the DBPROP_CANFETCHBACKWARDS and/or
  1217. // DBPROP_CANSCROLLBACKWARDS properties have not been set.
  1218. return MoveNext(-2);
  1219. }
  1220. // Move to the next record
  1221. HRESULT MoveNext() throw()
  1222. {
  1223. return MoveNext(0);
  1224. }
  1225. // Move lSkip records forward or backward
  1226. HRESULT MoveNext(LONG lSkip, bool bForward = true) throw()
  1227. {
  1228. HRESULT hr;
  1229. DBCOUNTITEM ulRowsFetched = 0;
  1230. // Check the data was opened successfully and the accessor
  1231. // has been set.
  1232. ATLASSERT(m_spRowset != NULL);
  1233. ATLASSERT(m_pAccessor != NULL);
  1234. m_pAccessor->FreeRecordMemory(m_spRowset);
  1235. // Release a row if one is already around
  1236. ReleaseRows();
  1237. // Get the row handle
  1238. HROW* phRow = &m_hRow;
  1239. hr = m_spRowset->GetNextRows(NULL, lSkip, (bForward) ? 1 : -1, &ulRowsFetched, &phRow);
  1240. if (hr != S_OK)
  1241. return hr;
  1242. // Get the data
  1243. hr = GetData();
  1244. if (FAILED(hr))
  1245. {
  1246. ATLTRACE(atlTraceDBClient, 0, _T("GetData failed - HRESULT = 0x%X\n"),hr);
  1247. ReleaseRows();
  1248. }
  1249. return hr;
  1250. }
  1251. // Move to the first record
  1252. HRESULT MoveFirst() throw()
  1253. {
  1254. HRESULT hr;
  1255. // Check the data was opened successfully and the accessor
  1256. // has been set.
  1257. ATLASSERT(m_spRowset != NULL);
  1258. ATLASSERT(m_pAccessor != NULL);
  1259. m_pAccessor->FreeRecordMemory(m_spRowset);
  1260. // Release a row if one is already around
  1261. ReleaseRows();
  1262. // the call to RestartPosition may fail if the DBPROP_CANFETCHBACKWARDS and/or
  1263. // DBPROP_CANSCROLLBACKWARDS properties have not been set.
  1264. hr = m_spRowset->RestartPosition(NULL);
  1265. if (FAILED(hr))
  1266. return hr;
  1267. // Get the data
  1268. return MoveNext();
  1269. }
  1270. // Move to the last record
  1271. HRESULT MoveLast() throw()
  1272. {
  1273. // Check the data was opened successfully and the accessor
  1274. // has been set.
  1275. ATLASSERT(m_spRowset != NULL);
  1276. ATLASSERT(m_pAccessor != NULL);
  1277. // Release a row if one is already around
  1278. m_pAccessor->FreeRecordMemory(m_spRowset);
  1279. ReleaseRows();
  1280. HRESULT hr;
  1281. DBCOUNTITEM ulRowsFetched = 0;
  1282. HROW* phRow = &m_hRow;
  1283. // Restart the rowset position and then move backwards
  1284. // the call to RestartPosition may fail if the DBPROP_CANFETCHBACKWARDS and/or
  1285. // DBPROP_CANSCROLLBACKWARDS properties have not been set.
  1286. m_spRowset->RestartPosition(NULL);
  1287. hr = m_spRowset->GetNextRows(NULL, -1, 1, &ulRowsFetched, &phRow);
  1288. if (hr != S_OK)
  1289. return hr;
  1290. // Get the data
  1291. hr = GetData();
  1292. if (FAILED(hr))
  1293. {
  1294. ATLTRACE(atlTraceDBClient, 0, _T("GetData from MoveLast failed - HRESULT = 0x%X\n"),hr);
  1295. ReleaseRows();
  1296. }
  1297. return S_OK;
  1298. }
  1299. // Move to the passed bookmark
  1300. HRESULT MoveToBookmark(const CBookmarkBase& bookmark, LONG lSkip = 0) throw()
  1301. {
  1302. // Check the data was opened successfully and the accessor
  1303. // has been set.
  1304. ATLASSERT(m_spRowset != NULL);
  1305. ATLASSERT(m_pAccessor != NULL);
  1306. CComPtr<IRowsetLocate> spLocate;
  1307. HRESULT hr = m_spRowset.QueryInterface(&spLocate);
  1308. if (FAILED(hr))
  1309. return hr;
  1310. m_pAccessor->FreeRecordMemory(m_spRowset);
  1311. // Release a row if one is already around
  1312. ReleaseRows();
  1313. DBCOUNTITEM ulRowsFetched = 0;
  1314. HROW* phRow = &m_hRow;
  1315. hr = spLocate->GetRowsAt(NULL, NULL, bookmark.GetSize(), bookmark.GetBuffer(),
  1316. lSkip, 1, &ulRowsFetched, &phRow);
  1317. // Note we're not using SUCCEEDED here, because we could get DB_S_ENDOFROWSET
  1318. if (hr != S_OK)
  1319. return hr;
  1320. // Get the data
  1321. hr = GetData();
  1322. if (FAILED(hr))
  1323. {
  1324. ATLTRACE(atlTraceDBClient, 0, _T("GetData from Bookmark failed - HRESULT = 0x%X\n"),hr);
  1325. ReleaseRows();
  1326. }
  1327. return S_OK;
  1328. }
  1329. // Get the data for the current record
  1330. HRESULT GetData() throw()
  1331. {
  1332. HRESULT hr = S_OK;
  1333. ATLASSERT(m_pAccessor != NULL);
  1334. ULONG nAccessors = m_pAccessor->GetNumAccessors();
  1335. for (ULONG i=0; i<nAccessors; i++)
  1336. {
  1337. if (m_pAccessor->IsAutoAccessor(i))
  1338. {
  1339. hr = GetData(i);
  1340. if (FAILED(hr))
  1341. return hr;
  1342. }
  1343. }
  1344. return hr;
  1345. }
  1346. // Get the data for the passed accessor. Use for a non-auto accessor
  1347. HRESULT GetData(int nAccessor) throw()
  1348. {
  1349. ATLASSERT(m_spRowset != NULL);
  1350. ATLASSERT(m_pAccessor != NULL);
  1351. ATLASSERT(m_hRow != NULL);
  1352. // Note that we are using the specified buffer if it has been set,
  1353. // otherwise we use the accessor for the data.
  1354. return m_spRowset->GetData(m_hRow, m_pAccessor->GetHAccessor(nAccessor), m_pAccessor->GetBuffer());
  1355. }
  1356. // Get the data for the passed accessor. Use for a non-auto accessor
  1357. HRESULT GetDataHere(int nAccessor, void* pBuffer) throw()
  1358. {
  1359. ATLASSERT(m_spRowset != NULL);
  1360. ATLASSERT(m_pAccessor != NULL);
  1361. ATLASSERT(m_hRow != NULL);
  1362. // Note that we are using the specified buffer if it has been set,
  1363. // otherwise we use the accessor for the data.
  1364. return m_spRowset->GetData(m_hRow, m_pAccessor->GetHAccessor(nAccessor), pBuffer);
  1365. }
  1366. HRESULT GetDataHere(void* pBuffer) throw()
  1367. {
  1368. HRESULT hr = S_OK;
  1369. ULONG nAccessors = m_pAccessor->GetNumAccessors();
  1370. for (ULONG i=0; i<nAccessors; i++)
  1371. {
  1372. hr = GetDataHere(i, pBuffer);
  1373. if (FAILED(hr))
  1374. return hr;
  1375. }
  1376. return hr;
  1377. }
  1378. // Insert the current record
  1379. HRESULT Insert(int nAccessor = 0, bool bGetHRow = false) throw()
  1380. {
  1381. ATLASSERT(m_pAccessor != NULL);
  1382. HRESULT hr;
  1383. if (m_spRowsetChange != NULL)
  1384. {
  1385. HROW* pHRow;
  1386. if (bGetHRow)
  1387. {
  1388. ReleaseRows();
  1389. pHRow = &m_hRow;
  1390. }
  1391. else
  1392. pHRow = NULL;
  1393. hr = m_spRowsetChange->InsertRow(NULL, m_pAccessor->GetHAccessor(nAccessor),
  1394. m_pAccessor->GetBuffer(), pHRow);
  1395. }
  1396. else
  1397. hr = E_NOINTERFACE;
  1398. return hr;
  1399. }
  1400. // Delete the current record
  1401. HRESULT Delete() const throw()
  1402. {
  1403. ATLASSERT(m_pAccessor != NULL);
  1404. HRESULT hr;
  1405. if (m_spRowsetChange != NULL)
  1406. hr = m_spRowsetChange->DeleteRows(NULL, 1, &m_hRow, NULL);
  1407. else
  1408. hr = E_NOINTERFACE;
  1409. return hr;
  1410. }
  1411. // Update the current record
  1412. HRESULT SetData() const throw()
  1413. {
  1414. ATLASSERT(m_pAccessor != NULL);
  1415. HRESULT hr = S_OK;
  1416. ULONG nAccessors = m_pAccessor->GetNumAccessors();
  1417. for (ULONG i=0; i<nAccessors; i++)
  1418. {
  1419. hr = SetData(i);
  1420. if (FAILED(hr))
  1421. return hr;
  1422. }
  1423. return hr;
  1424. }
  1425. // Update the current record with the data in the passed accessor
  1426. HRESULT SetData(int nAccessor) const throw()
  1427. {
  1428. ATLASSERT(m_pAccessor != NULL);
  1429. HRESULT hr;
  1430. if (m_spRowsetChange != NULL)
  1431. {
  1432. hr = m_spRowsetChange->SetData(m_hRow, m_pAccessor->GetHAccessor(nAccessor),
  1433. m_pAccessor->GetBuffer());
  1434. }
  1435. else
  1436. hr = E_NOINTERFACE;
  1437. return hr;
  1438. }
  1439. // Get the data most recently fetched from or transmitted to the data source.
  1440. // Does not get values based on pending changes.
  1441. HRESULT GetOriginalData() throw()
  1442. {
  1443. ATLASSERT(m_spRowset != NULL);
  1444. ATLASSERT(m_pAccessor != NULL);
  1445. HRESULT hr = S_OK;
  1446. CComPtr<IRowsetUpdate> spRowsetUpdate;
  1447. hr = m_spRowset->QueryInterface(&spRowsetUpdate);
  1448. if (FAILED(hr))
  1449. return hr;
  1450. ULONG nAccessors = m_pAccessor->GetNumAccessors();
  1451. for (ULONG i = 0; i < nAccessors; i++)
  1452. {
  1453. hr = spRowsetUpdate->GetOriginalData(m_hRow, m_pAccessor->GetHAccessor(i), m_pAccessor->GetBuffer());
  1454. if (FAILED(hr))
  1455. return hr;
  1456. }
  1457. return hr;
  1458. }
  1459. // Get the status of the current row
  1460. HRESULT GetRowStatus(DBPENDINGSTATUS* pStatus) const throw()
  1461. {
  1462. ATLASSERT(m_spRowset != NULL);
  1463. ATLASSERT(pStatus != NULL);
  1464. CComPtr<IRowsetUpdate> spRowsetUpdate;
  1465. HRESULT hr = m_spRowset->QueryInterface(&spRowsetUpdate);
  1466. if (FAILED(hr))
  1467. return hr;
  1468. return spRowsetUpdate->GetRowStatus(NULL, 1, &m_hRow, pStatus);
  1469. }
  1470. // Undo any changes made to the current row since it was last fetched or Update
  1471. // was called for it
  1472. HRESULT Undo(DBCOUNTITEM* pcRows = NULL, HROW* phRow = NULL, DBROWSTATUS* pStatus = NULL) throw()
  1473. {
  1474. ATLASSERT(m_spRowset != NULL);
  1475. CComPtr<IRowsetUpdate> spRowsetUpdate;
  1476. HRESULT hr = m_spRowset->QueryInterface(&spRowsetUpdate);
  1477. if (FAILED(hr))
  1478. return hr;
  1479. CComHeapPtr<HROW> sprgRows;
  1480. CComHeapPtr<DBROWSTATUS> spRowStatus;
  1481. if (phRow != NULL)
  1482. hr = spRowsetUpdate->Undo(NULL, 1, &m_hRow, pcRows, &sprgRows, &spRowStatus);
  1483. else
  1484. hr = spRowsetUpdate->Undo(NULL, 1, &m_hRow, pcRows, NULL, &spRowStatus);
  1485. if (phRow != NULL && sprgRows != NULL)
  1486. *phRow = *sprgRows;
  1487. if (pStatus != NULL && spRowStatus != NULL)
  1488. *pStatus = *spRowStatus;
  1489. return hr;
  1490. }
  1491. // Transmits any pending changes made to a row since it was last fetched or Update was
  1492. // called for it. Also see SetData.
  1493. HRESULT Update(DBCOUNTITEM* pcRows = NULL, HROW* phRow = NULL, DBROWSTATUS* pStatus = NULL) throw()
  1494. {
  1495. ATLASSERT(m_spRowset != NULL);
  1496. CComPtr<IRowsetUpdate> spRowsetUpdate;
  1497. HRESULT hr = m_spRowset->QueryInterface(&spRowsetUpdate);
  1498. if (FAILED(hr))
  1499. return hr;
  1500. CComHeapPtr<HROW> sprgRows;
  1501. CComHeapPtr<DBROWSTATUS> spRowStatus;
  1502. if (phRow != NULL)
  1503. hr = spRowsetUpdate->Update(NULL, 1, &m_hRow, pcRows, &sprgRows, &spRowStatus);
  1504. else
  1505. hr = spRowsetUpdate->Update(NULL, 1, &m_hRow, pcRows, NULL, &spRowStatus);
  1506. if (phRow != NULL && sprgRows != NULL)
  1507. *phRow = *sprgRows;
  1508. if (pStatus != NULL && spRowStatus != NULL)
  1509. *pStatus = *spRowStatus;
  1510. return hr;
  1511. }
  1512. // Transmits any pending changes to all rows made since it was last fetched or Update was
  1513. // alled for it. Differs from Update in that it will do every row (even if we don't hold
  1514. // the handle for it).
  1515. HRESULT UpdateAll(DBCOUNTITEM* pcRows = NULL, HROW** pphRow = NULL, DBROWSTATUS** ppStatus = NULL) throw()
  1516. {
  1517. ATLASSERT(m_spRowset != NULL);
  1518. CComPtr<IRowsetUpdate> spRowsetUpdate;
  1519. HRESULT hr = m_spRowset->QueryInterface(&spRowsetUpdate);
  1520. if (FAILED(hr))
  1521. return hr;
  1522. // Create some temporary variables to help with debugging.
  1523. DBCOUNTITEM cRowsReturned = 0;
  1524. CComHeapPtr<HROW> sprgRows;
  1525. CComHeapPtr<DBROWSTATUS> spRowStatus;
  1526. // Passing zero for the 2nd parameter tells the provider to update ALL pending rows.
  1527. // The 3rd parameter, prghRows is ignored.
  1528. hr = spRowsetUpdate->Update(NULL, 0, NULL, &cRowsReturned, &sprgRows, &spRowStatus);
  1529. // NOTE, the user must CoTaskMemFree *pphRow and *ppStatus after return, if they
  1530. // are non-NULL. Otherwise, we'll CoTaskMemFree if they are NULL.
  1531. if (pcRows != NULL)
  1532. *pcRows = cRowsReturned;
  1533. if (pphRow != NULL)
  1534. *pphRow = sprgRows.Detach();
  1535. if (ppStatus != NULL)
  1536. *ppStatus = spRowStatus.Detach();
  1537. return hr;
  1538. }
  1539. // Get the approximate position of the row corresponding to the passed bookmark
  1540. HRESULT GetApproximatePosition(const CBookmarkBase* pBookmark, DBCOUNTITEM* pPosition, DBCOUNTITEM* pcRows) throw()
  1541. {
  1542. ATLASSERT(m_spRowset != NULL);
  1543. CComPtr<IRowsetScroll> spRowsetScroll;
  1544. HRESULT hr = m_spRowset->QueryInterface(&spRowsetScroll);
  1545. if (SUCCEEDED(hr))
  1546. {
  1547. if (pBookmark != NULL)
  1548. hr = spRowsetScroll->GetApproximatePosition(NULL, pBookmark->GetSize(), pBookmark->GetBuffer(),
  1549. pPosition, pcRows);
  1550. else
  1551. hr = spRowsetScroll->GetApproximatePosition(NULL, 0, NULL, pPosition, pcRows);
  1552. }
  1553. return hr;
  1554. }
  1555. // Move to a fractional position in the rowset
  1556. HRESULT MoveToRatio(DBCOUNTITEM nNumerator, DBCOUNTITEM nDenominator, bool bForward = true) throw()
  1557. {
  1558. ATLASSERT(m_spRowset != NULL);
  1559. DBCOUNTITEM nRowsFetched;
  1560. CComPtr<IRowsetScroll> spRowsetScroll;
  1561. HRESULT hr = m_spRowset->QueryInterface(&spRowsetScroll);
  1562. if (FAILED(hr))
  1563. return hr;
  1564. m_pAccessor->FreeRecordMemory(m_spRowset);
  1565. ReleaseRows();
  1566. HROW* phRow = &m_hRow;
  1567. hr = spRowsetScroll->GetRowsAtRatio(NULL, NULL, nNumerator, nDenominator, (bForward) ? 1 : -1,
  1568. &nRowsFetched, &phRow);
  1569. // Note we're not using SUCCEEDED here, because we could get DB_S_ENDOFROWSET
  1570. if (hr == S_OK)
  1571. hr = GetData();
  1572. return hr;
  1573. }
  1574. HRESULT FindNextRow(DBCOMPAREOP op, BYTE* pData, DBTYPE wType, DBLENGTH nLength,
  1575. BYTE bPrecision, BYTE bScale, BOOL bSkipCurrent = TRUE, CBookmarkBase* pBookmark = NULL) throw()
  1576. {
  1577. ATLASSERT(m_spRowset != NULL);
  1578. DBBINDING binding;
  1579. HRESULT hr;
  1580. HACCESSOR hAccessor;
  1581. DBCOUNTITEM ulRowsFetched = 0;
  1582. HROW* phRow = &m_hRow;
  1583. DBLENGTH cbBookmark;
  1584. BYTE* pBookmarkBuffer;
  1585. CComQIPtr<IAccessor, &__uuidof(IAccessor)> spAccessor(m_spRowset);
  1586. CComQIPtr<IRowsetFind, &__uuidof(IRowsetFind)> spRowsetFind(m_spRowset);
  1587. if (spAccessor == NULL || spRowsetFind == NULL)
  1588. return E_NOINTERFACE;
  1589. TAccessor::Bind(&binding, 1, wType, nLength, bPrecision, bScale, DBPARAMIO_NOTPARAM, 0);
  1590. hr = CAccessorBase::BindEntries(&binding, 1, &hAccessor, nLength, spAccessor);
  1591. if (FAILED(hr))
  1592. return hr;
  1593. if (pBookmark == NULL)
  1594. {
  1595. cbBookmark = 0;
  1596. pBookmarkBuffer = NULL;
  1597. }
  1598. else
  1599. {
  1600. cbBookmark = pBookmark->GetSize();
  1601. pBookmarkBuffer = pBookmark->GetBuffer();
  1602. }
  1603. hr = spRowsetFind->FindNextRow(DB_NULL_HCHAPTER, hAccessor, pData, op, cbBookmark, pBookmarkBuffer,
  1604. bSkipCurrent, 1, &ulRowsFetched, &phRow);
  1605. // Note we're not using SUCCEEDED here, because we could get DB_S_ENDOFROWSET
  1606. if (hr != S_OK)
  1607. return hr;
  1608. // Get the data
  1609. hr = GetData();
  1610. spAccessor->ReleaseAccessor(hAccessor, NULL);
  1611. if (FAILED(hr))
  1612. {
  1613. ATLTRACE(_T("ATL: GetData from FindNextRows failed - HRESULT = 0x%X\n"),hr);
  1614. ReleaseRows();
  1615. }
  1616. return S_OK;
  1617. }
  1618. // Implementation
  1619. static const IID& GetIID() throw()
  1620. {
  1621. return __uuidof(IRowset);
  1622. }
  1623. IRowset* GetInterface() const throw()
  1624. {
  1625. return m_spRowset;
  1626. }
  1627. IRowset** GetInterfacePtr() throw()
  1628. {
  1629. return &m_spRowset;
  1630. }
  1631. void SetupOptionalRowsetInterfaces() throw()
  1632. {
  1633. // Cache IRowsetChange if available
  1634. if (m_spRowset != NULL)
  1635. m_spRowset->QueryInterface(&m_spRowsetChange);
  1636. }
  1637. HRESULT BindFinished() const throw()
  1638. {
  1639. return S_OK;
  1640. }
  1641. void SetAccessor(TAccessor* pAccessor) throw()
  1642. {
  1643. m_pAccessor = pAccessor;
  1644. }
  1645. CComPtr<IRowset> m_spRowset;
  1646. CComPtr<IRowsetChange> m_spRowsetChange;
  1647. TAccessor* m_pAccessor;
  1648. HROW m_hRow;
  1649. CXMLAccessor* m_pXMLAccessor;
  1650. };
  1651. ///////////////////////////////////////////////////////////////////////////
  1652. // class CBulkRowset
  1653. template <class TAccessor>
  1654. class CBulkRowset : public CRowset<TAccessor>
  1655. {
  1656. public:
  1657. CBulkRowset()
  1658. {
  1659. // Default the number of rows to bulk fetch to 10
  1660. m_nRows = 10;
  1661. m_hr = S_OK;
  1662. m_phRow = NULL;
  1663. }
  1664. ~CBulkRowset()
  1665. {
  1666. Close();
  1667. }
  1668. void Close() throw()
  1669. {
  1670. if (m_spRowset != NULL)
  1671. {
  1672. m_pAccessor->FreeRecordMemory(m_spRowset);
  1673. ReleaseRows();
  1674. }
  1675. CRowset<TAccessor>::Close();
  1676. delete [] m_phRow;
  1677. m_phRow = NULL;
  1678. m_hr = S_OK;
  1679. }
  1680. // Set the number of row handles that will be retrieved in each
  1681. // bulk row fetch. The default is 10 and this function must be called
  1682. // before Open if you wish to change it.
  1683. void SetRows(DBROWCOUNT nRows) throw()
  1684. {
  1685. if (nRows == 0)
  1686. nRows = 10;
  1687. if (nRows != m_nRows)
  1688. {
  1689. // This function must be called before the memory is allocated
  1690. // during binding or between a Close() and a Open()
  1691. delete m_phRow;
  1692. m_phRow = NULL;
  1693. m_nRows = nRows;
  1694. }
  1695. }
  1696. // AddRef all the currently retrieved row handles
  1697. HRESULT AddRefRows() throw()
  1698. {
  1699. ATLASSERT(m_spRowset != NULL);
  1700. return m_spRowset->AddRefRows(m_nCurrentRows, m_phRow, NULL, NULL);
  1701. }
  1702. // Release all the currently retrieved row handles
  1703. HRESULT ReleaseRows() throw()
  1704. {
  1705. ATLASSERT(m_spRowset != NULL);
  1706. // We're going to Release the rows so reset the current row position
  1707. m_nCurrentRow = 0;
  1708. m_hRow = NULL;
  1709. DBCOUNTITEM nCurrentRows = m_nCurrentRows;
  1710. m_nCurrentRows = 0;
  1711. return m_spRowset->ReleaseRows(nCurrentRows, m_phRow, NULL, NULL, NULL);
  1712. }
  1713. // Move to the first record
  1714. HRESULT MoveFirst() throw()
  1715. {
  1716. ATLASSERT(m_spRowset != NULL);
  1717. m_hr = S_OK;
  1718. m_pAccessor->FreeRecordMemory(m_spRowset);
  1719. ReleaseRows();
  1720. // the following line of code may fail if the DBPROP_CANFETCHBACKWARDS and/or
  1721. // DBPROP_CANSCROLLBACKWARDS properties have not been set.
  1722. HRESULT hr = m_spRowset->RestartPosition(NULL);
  1723. if (FAILED(hr))
  1724. return hr;
  1725. // Get the data
  1726. return MoveNext(0);
  1727. }
  1728. // Move to the last record
  1729. HRESULT MoveLast() throw()
  1730. {
  1731. m_hr = S_OK;
  1732. m_pAccessor->FreeRecordMemory(m_spRowset);
  1733. ReleaseRows();
  1734. m_hr = S_OK;
  1735. // the following line of code may fail if the DBPROP_CANFETCHBACKWARDS and/or
  1736. // DBPROP_CANSCROLLBACKWARDS properties have not been set.
  1737. return CRowset<TAccessor>::MoveLast();
  1738. }
  1739. // Move to the next record
  1740. HRESULT MoveNext() throw()
  1741. {
  1742. return MoveNext(0);
  1743. }
  1744. // Move to the previous record
  1745. HRESULT MovePrev() throw()
  1746. {
  1747. // the following line of code may fail if the DBPROP_CANFETCHBACKWARDS and/or
  1748. // DBPROP_CANSCROLLBACKWARDS properties have not been set.
  1749. return MoveNext(-2);
  1750. }
  1751. // Move lSkip records forward or backward
  1752. HRESULT MoveNext(DBROWOFFSET lSkip, bool bForward = true) throw()
  1753. {
  1754. ATLASSERT(m_spRowset != NULL);
  1755. ATLASSERT(m_phRow != NULL);
  1756. m_pAccessor->FreeRecordMemory(m_spRowset);
  1757. // Calculate the record index in the buffer
  1758. DBROWOFFSET nNewRow = m_nCurrentRow + lSkip + (bForward ? 1 : -1);
  1759. bool bFetchNewRows = false;
  1760. // Is the row in the buffer?
  1761. // else adjust the skip value
  1762. if (m_nCurrentRows == 0)
  1763. {
  1764. //lSkip = 0;
  1765. bFetchNewRows = true;
  1766. }
  1767. else if (nNewRow >= (DBROWOFFSET)m_nCurrentRows)
  1768. {
  1769. bFetchNewRows = true;
  1770. lSkip = nNewRow - m_nCurrentRows + (bForward ? 0 : (2 - m_nRows));
  1771. }
  1772. else if (nNewRow < 0)
  1773. {
  1774. lSkip = nNewRow - (m_nCurrentRows - m_nCurrentRow) + (bForward ? 0 : (2 - m_nRows));
  1775. bFetchNewRows = true;
  1776. }
  1777. if (bFetchNewRows)
  1778. {
  1779. nNewRow = 0;
  1780. // If we've reached the end of the buffer and we had a non S_OK HRESULT from
  1781. // the last call to GetNextRows then return that HRESULT now.
  1782. if (m_hr != S_OK && m_hr != DB_S_ROWLIMITEXCEEDED)
  1783. return m_hr;
  1784. // We've finished with these rows so we need some more
  1785. // First release any HROWs that we have
  1786. ReleaseRows();
  1787. // the following line of code may fail if the DBPROP_CANFETCHBACKWARDS and/or
  1788. // DBPROP_CANSCROLLBACKWARDS properties have not been set and the lSkip offset is negative.
  1789. m_hr = m_spRowset->GetNextRows(NULL, lSkip, m_nRows, &m_nCurrentRows, &m_phRow);
  1790. // If we have an error HRESULT or we haven't retrieved any rows then return
  1791. // the HRESULT now.
  1792. if (FAILED(m_hr) || m_nCurrentRows == 0)
  1793. return m_hr;
  1794. if (!bForward)
  1795. nNewRow = m_nCurrentRows - 1;
  1796. }
  1797. // Get the data for the current row
  1798. m_hRow = m_phRow[m_nCurrentRow = nNewRow];
  1799. return GetData();
  1800. }
  1801. // Move to the passed bookmark
  1802. HRESULT MoveToBookmark(const CBookmarkBase& bookmark, DBCOUNTITEM lSkip = 0) throw()
  1803. {
  1804. ATLASSERT(m_spRowset != NULL);
  1805. CComPtr<IRowsetLocate> spLocate;
  1806. HRESULT hr = m_spRowset->QueryInterface(&spLocate);
  1807. if (FAILED(hr))
  1808. return hr;
  1809. m_pAccessor->FreeRecordMemory(m_spRowset);
  1810. ReleaseRows();
  1811. m_hr = spLocate->GetRowsAt(NULL, NULL, bookmark.GetSize(), bookmark.GetBuffer(),
  1812. lSkip, m_nRows, &m_nCurrentRows, &m_phRow);
  1813. if( (m_hr != S_OK || m_nCurrentRows == 0 ) && m_hr != DB_S_ENDOFROWSET)
  1814. return m_hr;
  1815. // Get the data
  1816. m_hRow = m_phRow[m_nCurrentRow];
  1817. return GetData();
  1818. }
  1819. // Move to a fractional position in the rowset
  1820. HRESULT MoveToRatio(DBCOUNTITEM nNumerator, DBCOUNTITEM nDenominator) throw()
  1821. {
  1822. ATLASSERT(m_spRowset != NULL);
  1823. CComPtr<IRowsetScroll> spRowsetScroll;
  1824. HRESULT hr = m_spRowset->QueryInterface(&spRowsetScroll);
  1825. if (FAILED(hr))
  1826. return hr;
  1827. m_pAccessor->FreeRecordMemory(m_spRowset);
  1828. ReleaseRows();
  1829. m_hr = spRowsetScroll->GetRowsAtRatio(NULL, NULL, nNumerator, nDenominator, m_nRows, &m_nCurrentRows, &m_phRow);
  1830. if (m_hr != S_OK || m_nCurrentRows == 0)
  1831. return m_hr;
  1832. // Get the data
  1833. m_hRow = m_phRow[m_nCurrentRow];
  1834. return GetData();
  1835. }
  1836. // Insert the current record
  1837. HRESULT Insert(int nAccessor = 0, bool bGetHRow = false) throw()
  1838. {
  1839. ReleaseRows();
  1840. return CRowset< TAccessor >::Insert(nAccessor, bGetHRow);
  1841. }
  1842. // Implementation
  1843. HRESULT BindFinished() throw()
  1844. {
  1845. // No rows in the buffer yet
  1846. m_nCurrentRows = 0;
  1847. // Cause MoveNext to automatically perform a new bulk fetch the first time
  1848. m_nCurrentRow = 0;
  1849. m_hr = S_OK;
  1850. // Do not allocate if the buffer has been allocated by a previous call to BindFinished.
  1851. if (m_phRow == NULL)
  1852. {
  1853. ATLTRY(m_phRow = new HROW[m_nRows]);
  1854. if (m_phRow == NULL)
  1855. return E_OUTOFMEMORY;
  1856. }
  1857. return S_OK;
  1858. }
  1859. HRESULT m_hr; // HRESULT to return from MoveNext at end of buffer
  1860. HROW* m_phRow; // Pointer to array of HROWs for each row in buffer
  1861. DBROWCOUNT m_nRows; // Number of rows that will fit in the buffer
  1862. DBCOUNTITEM m_nCurrentRows; // Number of rows currently in the buffer
  1863. DBCOUNTITEM m_nCurrentRow;
  1864. };
  1865. ///////////////////////////////////////////////////////////////////////////
  1866. // class CArrayRowset
  1867. //
  1868. // Allows you to access a rowset with an array syntax. TAccessor must be a
  1869. // CAccessor<> type class
  1870. template <class TAccessor>
  1871. class CArrayRowset :
  1872. public CVirtualBuffer<TAccessor>,
  1873. protected CBulkRowset<TAccessor>
  1874. {
  1875. public:
  1876. CArrayRowset(int nMax = 100000) : CVirtualBuffer<TAccessor>(nMax)
  1877. {
  1878. m_nRowsRead = 0;
  1879. }
  1880. TAccessor& operator[](int nRow)
  1881. {
  1882. ATLASSERT(nRow >= 0);
  1883. HRESULT hr = S_OK;
  1884. TAccessor* pCurrent = m_pBase + m_nRowsRead;
  1885. // Retrieve the row if we haven't retrieved it already
  1886. while ((ULONG)nRow >= m_nRowsRead)
  1887. {
  1888. // REVIEW: This will change
  1889. m_pAccessor->SetBuffer((BYTE*)pCurrent + sizeof(CAccessorBase));
  1890. __try
  1891. {
  1892. // Get the row
  1893. hr = MoveNext();
  1894. if (hr != S_OK)
  1895. break;
  1896. }
  1897. __except(Except(GetExceptionInformation()))
  1898. {
  1899. }
  1900. m_nRowsRead++;
  1901. pCurrent++;
  1902. }
  1903. if(hr != S_OK)
  1904. {
  1905. ATLASSERT(hr != DB_S_ENDOFROWSET); // if you're getting this assertion, then
  1906. // most likely you are trying to access an
  1907. // out of bounds element of CArrayRowset
  1908. // (ex. table[100].data where table has only
  1909. // 50 records)
  1910. AtlThrow(hr);
  1911. }
  1912. return *(m_pBase + nRow);
  1913. }
  1914. HRESULT Snapshot() throw()
  1915. {
  1916. ATLASSERT(m_nRowsRead == 0);
  1917. ATLASSERT(m_spRowset != NULL);
  1918. HRESULT hr = MoveFirst();
  1919. if (FAILED(hr))
  1920. return hr;
  1921. do
  1922. {
  1923. Write(*(TAccessor*)m_pAccessor->GetBuffer());
  1924. m_nRowsRead++;
  1925. hr = MoveNext();
  1926. } while (SUCCEEDED(hr) && hr != DB_S_ENDOFROWSET);
  1927. return (hr == DB_S_ENDOFROWSET) ? S_OK : hr;
  1928. }
  1929. ULONG m_nRowsRead;
  1930. };
  1931. // Used when you don't need any parameters or output columns
  1932. class CNoAccessor
  1933. {
  1934. public:
  1935. // We don't need any typedef's here as the default
  1936. // global typedef is not to have any parameters and
  1937. // output columns.
  1938. HRESULT BindColumns(IUnknown*) throw() { return S_OK; }
  1939. HRESULT BindParameters(HACCESSOR*, ICommand*, void**) throw() { return S_OK; }
  1940. void Close() throw() { }
  1941. HRESULT ReleaseAccessors(IUnknown*) throw() { return S_OK; }
  1942. void FreeRecordMemory(IRowset* /*pRowset*/) throw() { }
  1943. void FreeRecordMemory(int /*nAccessor*/, IRowset* /*pRowset*/) throw() { }
  1944. HRESULT GetColumnInfo(IRowset*, DBORDINAL*, DBCOLUMNINFO**) throw() { return E_FAIL; }
  1945. ULONG GetNumAccessors() const throw() { return 0; }
  1946. bool IsAutoAccessor(ULONG /*nAccessor*/) const throw() { return false; }
  1947. HACCESSOR GetHAccessor(ULONG /*nAccessor*/) const throw() { return NULL; }
  1948. BYTE* GetBuffer() const throw() { ATLASSERT(FALSE); return NULL; }
  1949. static void Bind(DBBINDING*, DBORDINAL, DBTYPE, DBLENGTH, BYTE, BYTE, DBPARAMIO,
  1950. DBBYTEOFFSET, DBBYTEOFFSET = NULL, DBBYTEOFFSET = NULL, DBOBJECT* = NULL) throw()
  1951. { ATLASSERT(FALSE); }
  1952. bool NoBindOnNullRowset() const throw() { return false; }
  1953. };
  1954. // Used when a rowset will not be returned from the command
  1955. template <class TAccessor = CAccessorBase>
  1956. class CNoRowset
  1957. {
  1958. public:
  1959. HRESULT BindFinished() throw() { return S_OK; }
  1960. void Close() throw() { }
  1961. static const IID& GetIID() throw() { return IID_NULL; }
  1962. IRowset* GetInterface() const throw() { return NULL; }
  1963. IRowset** GetInterfacePtr() throw() { return NULL; }
  1964. void SetAccessor(void*) throw() { }
  1965. void SetupOptionalRowsetInterfaces() throw() { }
  1966. };
  1967. // Used with SQL Server 2000, a rowset will not be returned from the command, but instead
  1968. // we get an ISequentialStream object and use it to read the data.
  1969. template <class TAccessor = CAccessorBase>
  1970. class CStreamRowset
  1971. {
  1972. public:
  1973. // Constructors & destructors
  1974. CStreamRowset()
  1975. {
  1976. m_spStream = NULL;
  1977. }
  1978. ~CStreamRowset()
  1979. {
  1980. Close();
  1981. }
  1982. // Methods
  1983. void Close()
  1984. {
  1985. if (m_spStream != NULL)
  1986. m_spStream.Release();
  1987. }
  1988. // Implementation
  1989. static const IID& GetIID()
  1990. {
  1991. return IID_ISequentialStream;
  1992. }
  1993. ISequentialStream* GetInterface() const
  1994. {
  1995. return m_spStream;
  1996. }
  1997. ISequentialStream** GetInterfacePtr()
  1998. {
  1999. return &m_spStream;
  2000. }
  2001. HRESULT BindFinished() throw() { return S_OK; }
  2002. void SetAccessor(void*) throw() { }
  2003. void SetupOptionalRowsetInterfaces() throw() { }
  2004. CComPtr<ISequentialStream> m_spStream;
  2005. };
  2006. ///////////////////////////////////////////////////////////////////////////
  2007. // class CAccessor
  2008. // T is the class that contains the data that will be accessed.
  2009. template <class T>
  2010. class CAccessor :
  2011. public CAccessorBase,
  2012. public T
  2013. {
  2014. public:
  2015. // Implementation
  2016. // Free's any columns in the current record that need to be freed.
  2017. // E.g. Calls SysFreeString on any BSTR's and Release on any interfaces.
  2018. void FreeRecordMemory(int nAccessor, IRowset* /* pRowset */) throw()
  2019. {
  2020. nAccessor;
  2021. __if_exists(_GetBindEntries)
  2022. {
  2023. DBORDINAL nColumns;
  2024. // Passing in m_pBuffer tells the column entry maps to free the
  2025. // memory for the types if appropriate
  2026. _GetBindEntries(NULL, &nColumns, NULL, nAccessor, NULL, m_pBuffer);
  2027. }
  2028. }
  2029. void FreeRecordMemory(IRowset* pRowset) throw()
  2030. {
  2031. for (ULONG i = 0; i < GetNumAccessors(); i++)
  2032. FreeRecordMemory(i, pRowset);
  2033. }
  2034. HRESULT GetColumnInfo(IRowset*, DBORDINAL*, DBCOLUMNINFO**) throw() { return E_FAIL; }
  2035. void ClearRecordMemory() throw()
  2036. {
  2037. __if_exists(_GetBindEntries)
  2038. {
  2039. for (ULONG i = 0; i < _OutputColumnsClass::_GetNumAccessors(); i++)
  2040. {
  2041. DBORDINAL nColumns;
  2042. _GetBindEntries(NULL, &nColumns, NULL, i, NULL, m_pBuffer, true);
  2043. }
  2044. }
  2045. }
  2046. HRESULT BindColumns(IUnknown* pUnk) throw()
  2047. {
  2048. HRESULT hr;
  2049. ULONG nAccessors;
  2050. DBLENGTH nSize;
  2051. nAccessors = _OutputColumnsClass::_GetNumAccessors();
  2052. SetBuffer((BYTE*)(T*)this);
  2053. ClearRecordMemory();
  2054. nSize = sizeof(T);
  2055. hr = BindAccessors(nAccessors, nSize, pUnk);
  2056. return hr;
  2057. }
  2058. HRESULT BindAccessors(ULONG nAccessors, DBLENGTH nSize, IUnknown* pUnk) throw()
  2059. {
  2060. ATLASSERT(pUnk != NULL);
  2061. HRESULT hr;
  2062. CComPtr<IAccessor> spAccessor;
  2063. hr = pUnk->QueryInterface(&spAccessor);
  2064. if (SUCCEEDED(hr))
  2065. {
  2066. // Allocate the accessor memory if we haven't done so yet
  2067. if (m_pAccessorInfo == NULL)
  2068. {
  2069. hr = AllocateAccessorMemory(nAccessors);
  2070. if (FAILED(hr))
  2071. return hr;
  2072. }
  2073. for (ULONG i=0; i<nAccessors && SUCCEEDED(hr); i++)
  2074. hr = BindAccessor(spAccessor, i, nSize);
  2075. }
  2076. return hr;
  2077. }
  2078. HRESULT BindAccessor(IAccessor* pAccessor, ULONG nAccessor, DBLENGTH nSize) throw()
  2079. {
  2080. CAutoVectorPtr<DBBINDING> spBindings;
  2081. CAutoVectorPtr<LPOLESTR> spColumnNames;
  2082. DBORDINAL nColumns;
  2083. bool bAuto = false;
  2084. HRESULT hr;
  2085. CComHeapPtr<DBCOLUMNINFO> spColumnInfo;
  2086. DBORDINAL nColumnInfoCount = 0;
  2087. CComHeapPtr<OLECHAR> spStringsBuffer;
  2088. // First time just get the number of entries by passing in &nColumns
  2089. _OutputColumnsClass::_GetBindEntries(NULL, &nColumns, NULL, nAccessor, NULL);
  2090. // Allocate the binding structures
  2091. if( !spBindings.Allocate(nColumns) )
  2092. return E_OUTOFMEMORY;
  2093. for( ULONG i = 0; i < nColumns; i++ )
  2094. spBindings[i].pObject = NULL;
  2095. // Allocate the column names strings array
  2096. if( !spColumnNames.Allocate(nColumns) )
  2097. return E_OUTOFMEMORY;
  2098. // Now get the bind entries
  2099. hr = _OutputColumnsClass::_GetBindEntries(spColumnNames, &nColumns, spBindings, nAccessor, &bAuto);
  2100. if (SUCCEEDED(hr))
  2101. {
  2102. // translate the columns names to oridinals if necessary
  2103. for( ULONG i = 0; i < nColumns; i++ )
  2104. if( spColumnNames[i] != NULL ) // if a column name was given, translate it to oridinal
  2105. {
  2106. // if necessary, get the column information
  2107. if( spColumnInfo == NULL )
  2108. {
  2109. if( FAILED( GetColumnNames( pAccessor, &spColumnInfo, &spStringsBuffer, &nColumnInfoCount ) ) )
  2110. {
  2111. ATLASSERT( FALSE ); // unable to get columns information
  2112. return E_FAIL;
  2113. }
  2114. }
  2115. if( ! GetOridinalColumnNo(spColumnNames[i], spBindings[i].iOrdinal, spColumnInfo, nColumnInfoCount ) )
  2116. {
  2117. ATLASSERT(FALSE); // unable to match column name to an oridinal !!!
  2118. return E_FAIL;
  2119. }
  2120. }
  2121. m_pAccessorInfo[nAccessor].bAutoAccessor = bAuto;
  2122. hr = BindEntries(spBindings, nColumns, &m_pAccessorInfo[nAccessor].hAccessor, nSize, pAccessor);
  2123. }
  2124. else
  2125. {
  2126. // free any DBBINDING::pObject's
  2127. for( ULONG i = 0; i < nColumns; i++ )
  2128. delete spBindings[i].pObject;
  2129. }
  2130. return hr;
  2131. }
  2132. HRESULT BindParameters(HACCESSOR* pHAccessor, ICommand* pCommand, void** ppParameterBuffer) throw()
  2133. {
  2134. HRESULT hr = S_OK;
  2135. // In the static accessor case, the parameter buffer will be T plus the size of CAccessorBase
  2136. *ppParameterBuffer = static_cast<T*>(this);
  2137. // Only bind the parameters if we haven't already done it
  2138. if (*pHAccessor == NULL)
  2139. {
  2140. DBORDINAL nColumns = 0;
  2141. CAutoVectorPtr<DBBINDING> spBinding;
  2142. CAutoVectorPtr<LPOLESTR> spColumnNames;
  2143. CComHeapPtr<DBPARAMINFO> spParameterInfo;
  2144. DB_UPARAMS nParameterInfoCount = 0;
  2145. CComHeapPtr<OLECHAR> spStringsBuffer;
  2146. _ParamClass::_GetParamEntries(NULL, &nColumns, NULL);
  2147. // Allocate the DBPARAMINFO array
  2148. if( !spBinding.Allocate(nColumns) )
  2149. return E_OUTOFMEMORY;
  2150. // Allocate the column names strings array
  2151. if( !spColumnNames.Allocate(nColumns) )
  2152. return E_OUTOFMEMORY;
  2153. hr = _ParamClass::_GetParamEntries(spColumnNames, &nColumns, spBinding);
  2154. if (SUCCEEDED(hr))
  2155. {
  2156. // translate the columns names to oridinals if necessary
  2157. for( ULONG i = 0; i < nColumns; i++ )
  2158. if( spColumnNames[i] != NULL ) // if a column name was given, translate it to oridinal
  2159. {
  2160. // if necessary, get the column information
  2161. if( spParameterInfo == NULL )
  2162. {
  2163. if( FAILED( GetParameterNames( pCommand, &spParameterInfo, &spStringsBuffer, &nParameterInfoCount ) ) )
  2164. {
  2165. ATLASSERT( FALSE ); // unable to get columns information
  2166. return E_FAIL;
  2167. }
  2168. }
  2169. if( ! GetOridinalParameterNo(spColumnNames[i], spBinding[i].iOrdinal, spParameterInfo, nParameterInfoCount ) )
  2170. {
  2171. ATLASSERT(FALSE); // unable to match parameter name to an oridinal !!!
  2172. return E_FAIL;
  2173. }
  2174. }
  2175. // Get the IAccessor from the passed ICommand
  2176. ATLASSERT(pCommand != NULL);
  2177. CComPtr<IAccessor> spAccessor;
  2178. hr = pCommand->QueryInterface(&spAccessor);
  2179. if (SUCCEEDED(hr))
  2180. {
  2181. hr = BindEntries(spBinding, nColumns, pHAccessor, sizeof(T), spAccessor);
  2182. }
  2183. }
  2184. }
  2185. return hr;
  2186. }
  2187. protected:
  2188. bool GetOridinalColumnNo(LPCOLESTR pOleColumnName, DBORDINAL& nColumn, DBCOLUMNINFO* pColumnInfo, DBORDINAL nColumns ) throw()
  2189. {
  2190. ATLASSERT(pOleColumnName != NULL);
  2191. ATLASSERT(pColumnInfo != NULL);
  2192. if( pOleColumnName == NULL || pColumnInfo == NULL )
  2193. return false;
  2194. // Search through the columns trying to find a match
  2195. for (ULONG i = 0; i < nColumns; i++)
  2196. {
  2197. if (pColumnInfo[i].pwszName != NULL && wcscmp(pColumnInfo[i].pwszName, pOleColumnName) == 0)
  2198. {
  2199. nColumn = pColumnInfo[i].iOrdinal;
  2200. return true;
  2201. }
  2202. }
  2203. return false; // Not Found
  2204. }
  2205. HRESULT GetColumnNames( IAccessor* pAccessor, DBCOLUMNINFO** ppColumnInfo, OLECHAR** ppStringsBuffer, DBORDINAL* pnColumns ) throw()
  2206. {
  2207. ATLASSERT( ppColumnInfo != NULL );
  2208. ATLASSERT( ppStringsBuffer != NULL );
  2209. ATLASSERT( pnColumns != NULL );
  2210. ATLASSERT( pAccessor != NULL );
  2211. if( ppColumnInfo == NULL || ppStringsBuffer == NULL || pnColumns == NULL || pAccessor == NULL )
  2212. return E_FAIL;
  2213. CComPtr<IColumnsInfo> spColumnsInfo;
  2214. HRESULT hr = pAccessor->QueryInterface(&spColumnsInfo);
  2215. if (FAILED(hr))
  2216. return hr;
  2217. hr = spColumnsInfo->GetColumnInfo(pnColumns, ppColumnInfo, ppStringsBuffer);
  2218. if (FAILED(hr))
  2219. return hr;
  2220. return S_OK;
  2221. }
  2222. bool GetOridinalParameterNo(LPCOLESTR pOleParameterName, DB_UPARAMS& nParameter, DBPARAMINFO* pParameterInfo, DB_UPARAMS nParameters ) throw()
  2223. {
  2224. ATLASSERT(pOleParameterName != NULL);
  2225. ATLASSERT(pParameterInfo != NULL);
  2226. if( pOleParameterName == NULL || pParameterInfo == NULL )
  2227. return false;
  2228. // Search through the columns trying to find a match
  2229. for (ULONG i = 0; i < nParameters; i++)
  2230. {
  2231. if (pParameterInfo[i].pwszName != NULL && wcscmp(pParameterInfo[i].pwszName, pOleParameterName) == 0)
  2232. {
  2233. nParameter = pParameterInfo[i].iOrdinal;
  2234. return true;
  2235. }
  2236. }
  2237. return false; // Not Found
  2238. }
  2239. HRESULT GetParameterNames( ICommand* pCmd, DBPARAMINFO** ppParameterInfo, OLECHAR** ppStringsBuffer, DB_UPARAMS* pnParameters ) throw()
  2240. {
  2241. ATLASSERT( ppParameterInfo != NULL );
  2242. ATLASSERT( ppStringsBuffer != NULL );
  2243. ATLASSERT( pnParameters != NULL );
  2244. ATLASSERT( pCmd != NULL );
  2245. if( ppParameterInfo == NULL || ppStringsBuffer == NULL || pnParameters == NULL || pCmd == NULL )
  2246. return E_FAIL;
  2247. CComPtr<ICommandWithParameters> spCommandWithParameters;
  2248. HRESULT hr = pCmd->QueryInterface(&spCommandWithParameters);
  2249. if (FAILED(hr))
  2250. return hr;
  2251. hr = spCommandWithParameters->GetParameterInfo(pnParameters, ppParameterInfo, ppStringsBuffer);
  2252. if (FAILED(hr))
  2253. return hr;
  2254. return S_OK;
  2255. }
  2256. };
  2257. enum DBBLOBHANDLINGENUM
  2258. {
  2259. DBBLOBHANDLING_DEFAULT,
  2260. DBBLOBHANDLING_NOSTREAMS,
  2261. DBBLOBHANDLING_SKIP
  2262. };
  2263. ///////////////////////////////////////////////////////////////////////////
  2264. // CDynamicAccessor
  2265. class CDynamicAccessor :
  2266. public CAccessorBase
  2267. {
  2268. public:
  2269. CDynamicAccessor( DBBLOBHANDLINGENUM eBlobHandling = DBBLOBHANDLING_DEFAULT, DBLENGTH nBlobSize = 8000 )
  2270. {
  2271. ATLASSERT( eBlobHandling == DBBLOBHANDLING_DEFAULT ||
  2272. eBlobHandling == DBBLOBHANDLING_NOSTREAMS ||
  2273. eBlobHandling == DBBLOBHANDLING_SKIP );
  2274. m_nColumns = 0;
  2275. m_pColumnInfo = NULL;
  2276. m_pStringsBuffer = NULL;
  2277. m_eBlobHandling = eBlobHandling;
  2278. m_nBlobSize = nBlobSize;
  2279. m_pfClientOwnedMemRef = NULL;
  2280. };
  2281. ~CDynamicAccessor()
  2282. {
  2283. Close();
  2284. }
  2285. bool SetBlobHandling( DBBLOBHANDLINGENUM eBlobHandling )
  2286. {
  2287. switch( eBlobHandling )
  2288. {
  2289. case DBBLOBHANDLING_DEFAULT:
  2290. case DBBLOBHANDLING_NOSTREAMS:
  2291. case DBBLOBHANDLING_SKIP:
  2292. m_eBlobHandling = eBlobHandling;
  2293. return true;
  2294. default:
  2295. ATLASSERT( FALSE ); // invalid blob handling mode!!!
  2296. return false;
  2297. }
  2298. }
  2299. const DBBLOBHANDLINGENUM GetBlobHandling() const
  2300. {
  2301. return m_eBlobHandling;
  2302. }
  2303. void SetBlobSizeLimit( DBLENGTH nBlobSize )
  2304. {
  2305. m_nBlobSize = nBlobSize;
  2306. }
  2307. const DBLENGTH GetBlobSizeLimit() const
  2308. {
  2309. return m_nBlobSize;
  2310. }
  2311. // void FreeRecordMemory(int , IRowset* ) throw() {}
  2312. void Close() throw()
  2313. {
  2314. CoTaskMemFree(m_pColumnInfo);
  2315. m_pColumnInfo = NULL;
  2316. // Free the memory for the string buffer returned by IColumnsInfo::GetColumnInfo,
  2317. // if necessary
  2318. CoTaskMemFree(m_pStringsBuffer);
  2319. m_pStringsBuffer = NULL;
  2320. delete [] m_pBuffer;
  2321. m_pBuffer = NULL;
  2322. delete [] m_pfClientOwnedMemRef;
  2323. m_pfClientOwnedMemRef = NULL;
  2324. m_nColumns = 0;
  2325. CAccessorBase::Close();
  2326. }
  2327. bool GetColumnType(DBORDINAL nColumn, DBTYPE* pType) const throw()
  2328. {
  2329. if (TranslateColumnNo(nColumn))
  2330. {
  2331. *pType = m_pColumnInfo[nColumn].wType;
  2332. return true;
  2333. }
  2334. else
  2335. return false;
  2336. }
  2337. bool GetColumnFlags(DBORDINAL nColumn, DBCOLUMNFLAGS* pFlags) const throw()
  2338. {
  2339. if (TranslateColumnNo(nColumn))
  2340. {
  2341. *pFlags = m_pColumnInfo[nColumn].dwFlags;
  2342. return true;
  2343. }
  2344. else
  2345. return false;
  2346. }
  2347. bool GetOrdinal(const CHAR* pColumnName, DBORDINAL* pOrdinal) const throw()
  2348. {
  2349. ATLASSERT(pColumnName != NULL);
  2350. DBORDINAL nColumn;
  2351. if (GetInternalColumnNo(pColumnName, &nColumn))
  2352. {
  2353. *pOrdinal = m_pColumnInfo[nColumn].iOrdinal;
  2354. return true;
  2355. }
  2356. else
  2357. return false;
  2358. }
  2359. bool GetOrdinal(const WCHAR* pColumnName, DBORDINAL* pOrdinal) const throw()
  2360. {
  2361. ATLASSERT(pColumnName != NULL);
  2362. DBORDINAL nColumn;
  2363. if (GetInternalColumnNo(pColumnName, &nColumn))
  2364. {
  2365. *pOrdinal = m_pColumnInfo[nColumn].iOrdinal;
  2366. return true;
  2367. }
  2368. else
  2369. return false;
  2370. }
  2371. void* GetValue(DBORDINAL nColumn) const throw()
  2372. {
  2373. if (TranslateColumnNo(nColumn))
  2374. return _GetDataPtr(nColumn);
  2375. else
  2376. return NULL;
  2377. }
  2378. void* GetValue(const CHAR* pColumnName) const throw()
  2379. {
  2380. ATLASSERT(pColumnName != NULL);
  2381. DBORDINAL nColumn;
  2382. if (GetInternalColumnNo(pColumnName, &nColumn))
  2383. return _GetDataPtr(nColumn);
  2384. else
  2385. return NULL; // Not Found
  2386. }
  2387. void* GetValue(const WCHAR* pColumnName) const throw()
  2388. {
  2389. ATLASSERT(pColumnName != NULL);
  2390. DBORDINAL nColumn;
  2391. if (GetInternalColumnNo(pColumnName, &nColumn))
  2392. return _GetDataPtr(nColumn);
  2393. else
  2394. return NULL; // Not Found
  2395. }
  2396. template <class ctype>
  2397. void _GetValue(DBORDINAL nColumn, ctype* pData) const throw()
  2398. {
  2399. ATLASSERT(pData != NULL);
  2400. ATLASSERT(m_pColumnInfo[nColumn].ulColumnSize == sizeof(ctype));
  2401. ctype* pBuffer = (ctype*)_GetDataPtr(nColumn);
  2402. *pData = *pBuffer;
  2403. }
  2404. template <class ctype>
  2405. void _SetValue(DBORDINAL nColumn, const ctype& data) throw()
  2406. {
  2407. ATLASSERT(m_pColumnInfo[nColumn].ulColumnSize == sizeof(ctype));
  2408. ctype* pBuffer = (ctype*)_GetDataPtr(nColumn);
  2409. *pBuffer = (ctype)data;
  2410. }
  2411. template <class ctype>
  2412. bool GetValue(DBORDINAL nColumn, ctype* pData) const throw()
  2413. {
  2414. if (TranslateColumnNo(nColumn))
  2415. {
  2416. _GetValue(nColumn, pData);
  2417. return true;
  2418. }
  2419. return false;
  2420. }
  2421. template <class ctype>
  2422. bool SetValue(DBORDINAL nColumn, const ctype& data) throw()
  2423. {
  2424. if (TranslateColumnNo(nColumn))
  2425. {
  2426. _SetValue(nColumn, data);
  2427. return true;
  2428. }
  2429. return false;
  2430. }
  2431. template <class ctype>
  2432. bool GetValue(const CHAR *pColumnName, ctype* pData) const throw()
  2433. {
  2434. ATLASSERT(pColumnName != NULL);
  2435. DBORDINAL nColumn;
  2436. if (GetInternalColumnNo(pColumnName, &nColumn))
  2437. {
  2438. _GetValue(nColumn, pData);
  2439. return true;
  2440. }
  2441. return false;
  2442. }
  2443. template <class ctype>
  2444. bool GetValue(const WCHAR *pColumnName, ctype* pData) const throw()
  2445. {
  2446. ATLASSERT(pColumnName != NULL);
  2447. DBORDINAL nColumn;
  2448. if (GetInternalColumnNo(pColumnName, &nColumn))
  2449. {
  2450. _GetValue(nColumn, pData);
  2451. return true;
  2452. }
  2453. return false;
  2454. }
  2455. template <class ctype>
  2456. bool SetValue(const CHAR *pColumnName, const ctype& data) throw()
  2457. {
  2458. ATLASSERT(pColumnName != NULL);
  2459. DBORDINAL nColumn;
  2460. if (GetInternalColumnNo(pColumnName, &nColumn))
  2461. {
  2462. _SetValue(nColumn, data);
  2463. return true;
  2464. }
  2465. return false;
  2466. }
  2467. template <class ctype>
  2468. bool SetValue(const WCHAR *pColumnName, const ctype& data) throw()
  2469. {
  2470. ATLASSERT(pColumnName != NULL);
  2471. DBORDINAL nColumn;
  2472. if (GetInternalColumnNo(pColumnName, &nColumn))
  2473. {
  2474. _SetValue(nColumn, data);
  2475. return true;
  2476. }
  2477. return false;
  2478. }
  2479. bool GetLength(DBORDINAL nColumn, DBLENGTH* pLength) const throw()
  2480. {
  2481. ATLASSERT(pLength != NULL);
  2482. if (TranslateColumnNo(nColumn))
  2483. {
  2484. DBBYTEOFFSET nOffset = (DBBYTEOFFSET)(ULONG_PTR)m_pColumnInfo[nColumn].pTypeInfo;
  2485. IncrementAndAlignOffset( nOffset, m_pColumnInfo[nColumn].ulColumnSize, __alignof(DBLENGTH) );
  2486. *pLength = *(DBLENGTH*)( m_pBuffer + nOffset );
  2487. return true;
  2488. }
  2489. else
  2490. return false;
  2491. }
  2492. bool SetLength(DBORDINAL nColumn, DBLENGTH nLength) throw()
  2493. {
  2494. if (TranslateColumnNo(nColumn))
  2495. {
  2496. DBBYTEOFFSET nOffset = (DBBYTEOFFSET)(ULONG_PTR)m_pColumnInfo[nColumn].pTypeInfo;
  2497. IncrementAndAlignOffset( nOffset, m_pColumnInfo[nColumn].ulColumnSize, __alignof(DBLENGTH) );
  2498. *(DBLENGTH*)( m_pBuffer + nOffset ) = nLength;
  2499. return true;
  2500. }
  2501. else
  2502. return false;
  2503. }
  2504. bool GetLength(const CHAR* pColumnName, DBLENGTH* pLength) const throw()
  2505. {
  2506. ATLASSERT(pColumnName != NULL);
  2507. ATLASSERT(pLength != NULL);
  2508. DBORDINAL nColumn;
  2509. if (GetInternalColumnNo(pColumnName, &nColumn))
  2510. {
  2511. DBBYTEOFFSET nOffset = (DBBYTEOFFSET)(ULONG_PTR)m_pColumnInfo[nColumn].pTypeInfo;
  2512. IncrementAndAlignOffset( nOffset, m_pColumnInfo[nColumn].ulColumnSize, __alignof(DBLENGTH) );
  2513. *pLength = *(DBLENGTH*)( m_pBuffer + nOffset );
  2514. return true;
  2515. }
  2516. else
  2517. return false;
  2518. }
  2519. bool GetLength(const WCHAR* pColumnName, DBLENGTH* pLength) const throw()
  2520. {
  2521. ATLASSERT(pColumnName != NULL);
  2522. ATLASSERT(pLength != NULL);
  2523. DBORDINAL nColumn;
  2524. if (GetInternalColumnNo(pColumnName, &nColumn))
  2525. {
  2526. DBBYTEOFFSET nOffset = (DBBYTEOFFSET)(ULONG_PTR)m_pColumnInfo[nColumn].pTypeInfo;
  2527. IncrementAndAlignOffset( nOffset, m_pColumnInfo[nColumn].ulColumnSize, __alignof(DBLENGTH) );
  2528. *pLength = *(DBLENGTH*)( m_pBuffer + nOffset );
  2529. return true;
  2530. }
  2531. else
  2532. return false;
  2533. }
  2534. bool SetLength(const CHAR* pColumnName, DBLENGTH nLength) throw()
  2535. {
  2536. ATLASSERT(pColumnName != NULL);
  2537. DBORDINAL nColumn;
  2538. if (GetInternalColumnNo(pColumnName, &nColumn))
  2539. {
  2540. DBBYTEOFFSET nOffset = (DBBYTEOFFSET)(ULONG_PTR)m_pColumnInfo[nColumn].pTypeInfo;
  2541. IncrementAndAlignOffset( nOffset, m_pColumnInfo[nColumn].ulColumnSize, __alignof(DBLENGTH) );
  2542. *(DBLENGTH*)( m_pBuffer + nOffset ) = nLength;
  2543. return true;
  2544. }
  2545. else
  2546. return false;
  2547. }
  2548. bool SetLength(const WCHAR* pColumnName, DBLENGTH nLength) throw()
  2549. {
  2550. ATLASSERT(pColumnName != NULL);
  2551. DBORDINAL nColumn;
  2552. if (GetInternalColumnNo(pColumnName, &nColumn))
  2553. {
  2554. DBBYTEOFFSET nOffset = (DBBYTEOFFSET)(ULONG_PTR)m_pColumnInfo[nColumn].pTypeInfo;
  2555. IncrementAndAlignOffset( nOffset, m_pColumnInfo[nColumn].ulColumnSize, __alignof(DBLENGTH) );
  2556. *(DBLENGTH*)( m_pBuffer + nOffset ) = nLength;
  2557. return true;
  2558. }
  2559. else
  2560. return false;
  2561. }
  2562. bool GetStatus(DBORDINAL nColumn, DBSTATUS* pStatus) const throw()
  2563. {
  2564. ATLASSERT(pStatus != NULL);
  2565. if (TranslateColumnNo(nColumn))
  2566. {
  2567. DBBYTEOFFSET nOffset = (DBBYTEOFFSET)(ULONG_PTR)m_pColumnInfo[nColumn].pTypeInfo;
  2568. IncrementAndAlignOffset( nOffset, m_pColumnInfo[nColumn].ulColumnSize, __alignof(DBLENGTH) );
  2569. IncrementAndAlignOffset( nOffset, sizeof(DBLENGTH), __alignof(DBSTATUS) );
  2570. *pStatus = *(DBSTATUS*)( m_pBuffer + nOffset );
  2571. return true;
  2572. }
  2573. else
  2574. return false;
  2575. }
  2576. bool SetStatus(DBORDINAL nColumn, DBSTATUS status) throw()
  2577. {
  2578. if (TranslateColumnNo(nColumn))
  2579. {
  2580. DBBYTEOFFSET nOffset = (DBBYTEOFFSET)(ULONG_PTR)m_pColumnInfo[nColumn].pTypeInfo;
  2581. IncrementAndAlignOffset( nOffset, m_pColumnInfo[nColumn].ulColumnSize, __alignof(DBLENGTH) );
  2582. IncrementAndAlignOffset( nOffset, sizeof(DBLENGTH), __alignof(DBSTATUS) );
  2583. *(DBSTATUS*)( m_pBuffer + nOffset ) = status;
  2584. return true;
  2585. }
  2586. else
  2587. return false;
  2588. }
  2589. bool GetStatus(const CHAR* pColumnName, DBSTATUS* pStatus) const throw()
  2590. {
  2591. ATLASSERT(pColumnName != NULL);
  2592. ATLASSERT(pStatus != NULL);
  2593. DBORDINAL nColumn;
  2594. if (GetInternalColumnNo(pColumnName, &nColumn))
  2595. {
  2596. DBBYTEOFFSET nOffset = (DBBYTEOFFSET)(ULONG_PTR)m_pColumnInfo[nColumn].pTypeInfo;
  2597. IncrementAndAlignOffset( nOffset, m_pColumnInfo[nColumn].ulColumnSize, __alignof(DBLENGTH) );
  2598. IncrementAndAlignOffset( nOffset, sizeof(DBLENGTH), __alignof(DBSTATUS) );
  2599. *pStatus = *(DBSTATUS*)( m_pBuffer + nOffset );
  2600. return true;
  2601. }
  2602. else
  2603. return false;
  2604. }
  2605. bool GetStatus(const WCHAR* pColumnName, DBSTATUS* pStatus) const throw()
  2606. {
  2607. ATLASSERT(pColumnName != NULL);
  2608. ATLASSERT(pStatus != NULL);
  2609. DBORDINAL nColumn;
  2610. if (GetInternalColumnNo(pColumnName, &nColumn))
  2611. {
  2612. DBBYTEOFFSET nOffset = (DBBYTEOFFSET)(ULONG_PTR)m_pColumnInfo[nColumn].pTypeInfo;
  2613. IncrementAndAlignOffset( nOffset, m_pColumnInfo[nColumn].ulColumnSize, __alignof(DBLENGTH) );
  2614. IncrementAndAlignOffset( nOffset, sizeof(DBLENGTH), __alignof(DBSTATUS) );
  2615. *pStatus = *(DBSTATUS*)( m_pBuffer + nOffset );
  2616. return true;
  2617. }
  2618. else
  2619. return false;
  2620. }
  2621. bool SetStatus(const CHAR* pColumnName, DBSTATUS status) throw()
  2622. {
  2623. ATLASSERT(pColumnName != NULL);
  2624. DBORDINAL nColumn;
  2625. if (GetInternalColumnNo(pColumnName, &nColumn))
  2626. {
  2627. DBBYTEOFFSET nOffset = (DBBYTEOFFSET)(ULONG_PTR)m_pColumnInfo[nColumn].pTypeInfo;
  2628. IncrementAndAlignOffset( nOffset, m_pColumnInfo[nColumn].ulColumnSize, __alignof(DBLENGTH) );
  2629. IncrementAndAlignOffset( nOffset, sizeof(DBLENGTH), __alignof(DBSTATUS) );
  2630. *(DBSTATUS*)( m_pBuffer + nOffset ) = status;
  2631. return true;
  2632. }
  2633. else
  2634. return false;
  2635. }
  2636. bool SetStatus(const WCHAR* pColumnName, DBSTATUS status) throw()
  2637. {
  2638. ATLASSERT(pColumnName != NULL);
  2639. DBORDINAL nColumn;
  2640. if (GetInternalColumnNo(pColumnName, &nColumn))
  2641. {
  2642. DBBYTEOFFSET nOffset = (DBBYTEOFFSET)(ULONG_PTR)m_pColumnInfo[nColumn].pTypeInfo;
  2643. IncrementAndAlignOffset( nOffset, m_pColumnInfo[nColumn].ulColumnSize, __alignof(DBLENGTH) );
  2644. IncrementAndAlignOffset( nOffset, sizeof(DBLENGTH), __alignof(DBSTATUS) );
  2645. *(DBSTATUS*)( m_pBuffer + nOffset ) = status;
  2646. return true;
  2647. }
  2648. else
  2649. return false;
  2650. }
  2651. // Returns true if a bookmark is available
  2652. HRESULT GetBookmark(CBookmark<>* pBookmark) const throw()
  2653. {
  2654. HRESULT hr;
  2655. if (m_pColumnInfo->iOrdinal == 0)
  2656. hr = pBookmark->SetBookmark(m_pColumnInfo->ulColumnSize, (BYTE*)_GetDataPtr(0));
  2657. else
  2658. hr = E_FAIL;
  2659. return hr;
  2660. }
  2661. DBORDINAL GetColumnCount() const throw()
  2662. {
  2663. return m_nColumns;
  2664. }
  2665. LPOLESTR GetColumnName(DBORDINAL nColumn) const throw()
  2666. {
  2667. if (TranslateColumnNo(nColumn))
  2668. return m_pColumnInfo[nColumn].pwszName;
  2669. else
  2670. return NULL;
  2671. }
  2672. ATL_DEPRECATED HRESULT GetColumnInfo(IRowset* pRowset, DBORDINAL* pColumns, DBCOLUMNINFO** ppColumnInfo);
  2673. HRESULT GetColumnInfo(IRowset* pRowset, DBORDINAL* pColumns, DBCOLUMNINFO** ppColumnInfo, OLECHAR** ppStringsBuffer) throw()
  2674. {
  2675. CComPtr<IColumnsInfo> spColumnsInfo;
  2676. HRESULT hr = pRowset->QueryInterface(&spColumnsInfo);
  2677. if (SUCCEEDED(hr))
  2678. hr = spColumnsInfo->GetColumnInfo(pColumns, ppColumnInfo, ppStringsBuffer);
  2679. return hr;
  2680. }
  2681. HRESULT AddBindEntry(const DBCOLUMNINFO& info) throw()
  2682. {
  2683. DBCOLUMNINFO* pTempInfo = (DBCOLUMNINFO*)CoTaskMemRealloc(m_pColumnInfo, (m_nColumns + 1) * sizeof(DBCOLUMNINFO));
  2684. if (pTempInfo == NULL)
  2685. return E_OUTOFMEMORY;
  2686. m_pColumnInfo = pTempInfo;
  2687. m_pColumnInfo[m_nColumns] = info;
  2688. m_nColumns++;
  2689. return S_OK;
  2690. }
  2691. bool NoBindOnNullRowset() const throw()
  2692. {
  2693. return true;
  2694. }
  2695. // Implementation
  2696. // Free's any columns in the current record that need to be freed.
  2697. // E.g. Calls SysFreeString on any BSTR's and Release on any interfaces.
  2698. void FreeRecordMemory(IRowset* pRowset) throw()
  2699. {
  2700. ULONG i;
  2701. for (i = 0; i < m_nColumns; i++)
  2702. {
  2703. if( m_pfClientOwnedMemRef != NULL && m_pfClientOwnedMemRef[i] == true )
  2704. {
  2705. DBBYTEOFFSET nOffset = (DBBYTEOFFSET)(ULONG_PTR)m_pColumnInfo[i].pTypeInfo;
  2706. IncrementAndAlignOffset( nOffset, m_pColumnInfo[i].ulColumnSize, __alignof(DBLENGTH) );
  2707. IncrementAndAlignOffset( nOffset, sizeof(DBLENGTH), __alignof(DBSTATUS) );
  2708. if( *(DBSTATUS*)( m_pBuffer + nOffset ) != DBSTATUS_S_ISNULL )
  2709. {
  2710. void* pRef = _GetDataPtr(i);
  2711. if( pRef != NULL && *(void**)pRef != NULL )
  2712. CoTaskMemFree( *(void**)_GetDataPtr(i) );
  2713. }
  2714. }
  2715. else if( m_pColumnInfo[i].wType == DBTYPE_IUNKNOWN || m_pColumnInfo[i].wType == DBTYPE_IDISPATCH )
  2716. {
  2717. DBBYTEOFFSET nOffset = (DBBYTEOFFSET)(ULONG_PTR)m_pColumnInfo[i].pTypeInfo;
  2718. IncrementAndAlignOffset( nOffset, m_pColumnInfo[i].ulColumnSize, __alignof(DBLENGTH) );
  2719. IncrementAndAlignOffset( nOffset, sizeof(DBLENGTH), __alignof(DBSTATUS) );
  2720. if( *(DBSTATUS*)( m_pBuffer + nOffset ) == DBSTATUS_S_OK )
  2721. CAccessorBase::FreeType(m_pColumnInfo[i].wType, (BYTE*)_GetDataPtr(i), pRowset);
  2722. }
  2723. else
  2724. {
  2725. CAccessorBase::FreeType(m_pColumnInfo[i].wType, (BYTE*)_GetDataPtr(i), pRowset);
  2726. }
  2727. }
  2728. }
  2729. void ClearRecordMemory() throw()
  2730. {
  2731. for (ULONG i = 0; i < m_nColumns; i++)
  2732. {
  2733. DBLENGTH uLength = m_pColumnInfo[i].ulColumnSize;
  2734. switch (m_pColumnInfo[i].wType)
  2735. {
  2736. case DBTYPE_STR :
  2737. uLength += 1;
  2738. break;
  2739. case DBTYPE_WSTR :
  2740. uLength = (uLength + 1) * 2;
  2741. break;
  2742. }
  2743. memset((BYTE*)_GetDataPtr(i), 0, uLength);
  2744. }
  2745. }
  2746. void* _GetDataPtr(DBORDINAL nColumn) const throw()
  2747. {
  2748. return m_pBuffer + (DBBYTEOFFSET)(ULONG_PTR)m_pColumnInfo[nColumn].pTypeInfo;
  2749. }
  2750. bool GetInternalColumnNo(const CHAR* pColumnName, DBORDINAL* pColumn) const throw()
  2751. {
  2752. ATLASSERT(pColumnName != NULL);
  2753. ATLASSERT(pColumn != NULL);
  2754. USES_CONVERSION;
  2755. ULONG i;
  2756. size_t nSize = (lstrlenA(pColumnName) + 1) * sizeof(OLECHAR);
  2757. OLECHAR* pOleColumnName = A2OLE(pColumnName);
  2758. // Search through the columns trying to find a match
  2759. for (i = 0; i < m_nColumns; i++)
  2760. {
  2761. ATLASSERT(m_pColumnInfo != NULL);
  2762. if (m_pColumnInfo[i].pwszName != NULL &&
  2763. memcmp(m_pColumnInfo[i].pwszName, pOleColumnName, nSize) == 0)
  2764. break;
  2765. }
  2766. if (i < m_nColumns)
  2767. {
  2768. *pColumn = i;
  2769. return true;
  2770. }
  2771. else
  2772. return false; // Not Found
  2773. }
  2774. bool GetInternalColumnNo(const WCHAR* pColumnName, DBORDINAL* pColumn) const throw()
  2775. {
  2776. ATLASSERT(pColumnName != NULL);
  2777. ATLASSERT(pColumn != NULL);
  2778. USES_CONVERSION;
  2779. ULONG i;
  2780. size_t nSize = (wcslen(pColumnName) + 1) * sizeof(OLECHAR);
  2781. LPCOLESTR pOleColumnName = W2COLE(pColumnName);
  2782. // Search through the columns trying to find a match
  2783. for (i = 0; i < m_nColumns; i++)
  2784. {
  2785. ATLASSERT(m_pColumnInfo != NULL);
  2786. if (m_pColumnInfo[i].pwszName != NULL &&
  2787. memcmp(m_pColumnInfo[i].pwszName, pOleColumnName, nSize) == 0)
  2788. break;
  2789. }
  2790. if (i < m_nColumns)
  2791. {
  2792. *pColumn = i;
  2793. return true;
  2794. }
  2795. else
  2796. return false; // Not Found
  2797. }
  2798. // Set up the binding structure pointed to by pBindings based upon
  2799. // the other passed parameters.
  2800. static void BindEx(DBBINDING* pBinding, DBORDINAL nOrdinal, DBTYPE wType,
  2801. DBLENGTH nLength, BYTE nPrecision, BYTE nScale, DBPARAMIO eParamIO,
  2802. DBBYTEOFFSET nDataOffset, DBBYTEOFFSET nLengthOffset, DBBYTEOFFSET nStatusOffset,
  2803. DBOBJECT* pdbobject, DBMEMOWNER dwMemOwner, bool fSkipData = false ) throw()
  2804. {
  2805. ATLASSERT(pBinding != NULL);
  2806. /*
  2807. // If we are getting a pointer to the data then let the provider
  2808. // own the memory
  2809. if (wType & DBTYPE_BYREF)
  2810. pBinding->dwMemOwner = DBMEMOWNER_PROVIDEROWNED;
  2811. else
  2812. pBinding->dwMemOwner = DBMEMOWNER_CLIENTOWNED;
  2813. */
  2814. pBinding->dwMemOwner = dwMemOwner;
  2815. pBinding->pObject = pdbobject;
  2816. pBinding->eParamIO = eParamIO;
  2817. pBinding->iOrdinal = nOrdinal;
  2818. pBinding->wType = wType;
  2819. pBinding->bPrecision = nPrecision;
  2820. pBinding->bScale = nScale;
  2821. pBinding->dwFlags = 0;
  2822. pBinding->obValue = 0;
  2823. pBinding->obLength = 0;
  2824. pBinding->obStatus = 0;
  2825. pBinding->pTypeInfo = NULL;
  2826. pBinding->pBindExt = NULL;
  2827. pBinding->cbMaxLen = nLength;
  2828. pBinding->dwPart = 0;
  2829. if ( ! fSkipData ) // skip column data
  2830. {
  2831. pBinding->dwPart |= DBPART_VALUE;
  2832. pBinding->obValue = nDataOffset;
  2833. }
  2834. if (nLengthOffset != NULL) // skip length
  2835. {
  2836. pBinding->dwPart |= DBPART_LENGTH;
  2837. pBinding->obLength = nLengthOffset;
  2838. }
  2839. if (nStatusOffset != NULL) // skip status
  2840. {
  2841. pBinding->dwPart |= DBPART_STATUS;
  2842. pBinding->obStatus = nStatusOffset;
  2843. }
  2844. }
  2845. HRESULT GetRowsetProperties( IUnknown* pUnk, DBPROPID* prgPropertyIDs, BOOL* pbValues, ULONG nPropCount ) throw()
  2846. {
  2847. ULONG t;
  2848. ATLASSERT(pUnk != NULL);
  2849. ATLASSERT(pbValues != NULL);
  2850. ATLASSERT(prgPropertyIDs != NULL);
  2851. ATLASSERT(nPropCount > 0);
  2852. CComPtr<IRowsetInfo> spRowsetInfo;
  2853. HRESULT hr = pUnk->QueryInterface(&spRowsetInfo);
  2854. for( t = 0; t < nPropCount; t++ )
  2855. pbValues[t] = FALSE;
  2856. if (FAILED(hr))
  2857. ATLASSERT(0); // unable to retrieve IRowsetInfo interface
  2858. else
  2859. {
  2860. DBPROPIDSET rgPropertyIDSets[1];
  2861. ULONG cPropSets = 0;
  2862. CComHeapPtr<DBPROPSET> rgPropSets;
  2863. // Set up the Property ID Set.
  2864. rgPropertyIDSets[0].rgPropertyIDs = prgPropertyIDs;
  2865. rgPropertyIDSets[0].cPropertyIDs = nPropCount;
  2866. rgPropertyIDSets[0].guidPropertySet = DBPROPSET_ROWSET;
  2867. hr = spRowsetInfo->GetProperties( 1, // cPropertyIDSets
  2868. rgPropertyIDSets, // rgPropertyIDSets
  2869. &cPropSets, // pcPropSets
  2870. &rgPropSets ); // prgPropSets
  2871. if( SUCCEEDED(hr) )
  2872. {
  2873. for( t = 0; t < __min(rgPropSets[0].cProperties, nPropCount); t++ )
  2874. pbValues[t] = V_BOOL(&rgPropSets[0].rgProperties[t].vValue);
  2875. if( rgPropSets[0].rgProperties )
  2876. CoTaskMemFree(rgPropSets[0].rgProperties);
  2877. }
  2878. }
  2879. return hr;
  2880. }
  2881. HRESULT BindColumns(IUnknown* pUnk) throw()
  2882. {
  2883. IID iidStreamToUse = __uuidof(ISequentialStream);
  2884. //IID iidPersistToUse;
  2885. bool fIStreamSupportTested = false;
  2886. //bool fIPersistSupportTested = false;
  2887. ATLASSERT(pUnk != NULL);
  2888. CComPtr<IAccessor> spAccessor;
  2889. HRESULT hr = pUnk->QueryInterface(&spAccessor);
  2890. if (FAILED(hr))
  2891. return hr;
  2892. ULONG i;
  2893. DBBYTEOFFSET nOffset = 0, nDataOffset, nLengthOffset, nStatusOffset;
  2894. // If the user hasn't specifed the column information to bind by calling AddBindEntry then
  2895. // we get it ourselves
  2896. if (m_pColumnInfo == NULL)
  2897. {
  2898. CComPtr<IColumnsInfo> spColumnsInfo;
  2899. hr = pUnk->QueryInterface(&spColumnsInfo);
  2900. if (FAILED(hr))
  2901. return hr;
  2902. hr = spColumnsInfo->GetColumnInfo(&m_nColumns, &m_pColumnInfo, &m_pStringsBuffer);
  2903. if (FAILED(hr))
  2904. return hr;
  2905. m_bOverride = false;
  2906. }
  2907. else
  2908. m_bOverride = true;
  2909. DBBINDING* pBinding = NULL;
  2910. ATLTRY( pBinding = new DBBINDING[m_nColumns] );
  2911. if( pBinding == NULL )
  2912. return E_OUTOFMEMORY;
  2913. ATLASSERT(m_pfClientOwnedMemRef == NULL);
  2914. ATLTRY(m_pfClientOwnedMemRef = new bool[m_nColumns]);
  2915. if( m_pfClientOwnedMemRef == NULL )
  2916. {
  2917. delete [] pBinding;
  2918. return E_OUTOFMEMORY;
  2919. }
  2920. #ifdef _DEBUG
  2921. ATLTRACE( "CDynamicAccessor::BindColumns\n" );
  2922. ATLTRACE( "Number of columns: %d\n", m_nColumns );
  2923. ATLTRACE( "Blob Handling Mode: " );
  2924. switch( m_eBlobHandling )
  2925. {
  2926. case DBBLOBHANDLING_DEFAULT:
  2927. ATLTRACE( "DBBLOBHANDLING_DEFAULT\n" );
  2928. break;
  2929. case DBBLOBHANDLING_NOSTREAMS:
  2930. ATLTRACE( "DBBLOBHANDLING_NOSTREAMS\n" );
  2931. break;
  2932. case DBBLOBHANDLING_SKIP:
  2933. ATLTRACE( "DBBLOBHANDLING_SKIP\n" );
  2934. break;
  2935. default:
  2936. ATLTRACE( "IVALID HANDLING MODE!!!\n" );
  2937. }
  2938. #endif
  2939. DBBINDING* pCurrent = pBinding;
  2940. DBOBJECT* pObject;
  2941. for (i = 0; i < m_nColumns; i++)
  2942. {
  2943. // If it's a BLOB or the column size is large enough for us to treat it as
  2944. // a BLOB then we also need to set up the DBOBJECT structure.
  2945. m_pfClientOwnedMemRef[i] = false;
  2946. if (m_pColumnInfo[i].ulColumnSize > m_nBlobSize && m_pColumnInfo[i].wType != DBTYPE_IUNKNOWN )
  2947. {
  2948. if( m_eBlobHandling == DBBLOBHANDLING_SKIP )
  2949. {
  2950. // Calculate the column data offset
  2951. nDataOffset = 0;
  2952. // Calculate the column length offset
  2953. nLengthOffset = AlignAndIncrementOffset( nOffset, sizeof(DBLENGTH), __alignof(DBLENGTH) );
  2954. // Calculate the column status offset
  2955. nStatusOffset = AlignAndIncrementOffset( nOffset, sizeof(DBSTATUS), __alignof(DBSTATUS) );
  2956. #ifdef _DEBUG
  2957. ATLTRACE( "%d. Column ordinal %d: Binding length and status ONLY\n", i, m_pColumnInfo[i].iOrdinal );
  2958. #endif
  2959. BindEx(pCurrent, m_pColumnInfo[i].iOrdinal, m_pColumnInfo[i].wType,
  2960. m_pColumnInfo[i].ulColumnSize, m_pColumnInfo[i].bPrecision, m_pColumnInfo[i].bScale,
  2961. DBPARAMIO_NOTPARAM, nDataOffset, nLengthOffset, nStatusOffset, NULL, DBMEMOWNER_CLIENTOWNED, true );
  2962. pCurrent++;
  2963. }
  2964. else if( m_eBlobHandling == DBBLOBHANDLING_NOSTREAMS )
  2965. {
  2966. // get the value by reference
  2967. m_pColumnInfo[i].wType |= DBTYPE_BYREF;
  2968. m_pColumnInfo[i].ulColumnSize = sizeof(WCHAR*);
  2969. m_pfClientOwnedMemRef[i] = true;
  2970. // Calculate the column data offset
  2971. nDataOffset = AlignAndIncrementOffset( nOffset, m_pColumnInfo[i].ulColumnSize, GetAlignment( m_pColumnInfo[i].wType ) );
  2972. // Calculate the column length offset
  2973. nLengthOffset = AlignAndIncrementOffset( nOffset, sizeof(DBLENGTH), __alignof(DBLENGTH) );
  2974. // Calculate the column status offset
  2975. nStatusOffset = AlignAndIncrementOffset( nOffset, sizeof(DBSTATUS), __alignof(DBSTATUS) );
  2976. #ifdef _DEBUG
  2977. ATLTRACE( "%d. Column ordinal %d: Binding by reference in provider allocated, consumer owned memory\n", i, m_pColumnInfo[i].iOrdinal );
  2978. #endif
  2979. BindEx(pCurrent, m_pColumnInfo[i].iOrdinal, m_pColumnInfo[i].wType,
  2980. m_pColumnInfo[i].ulColumnSize, m_pColumnInfo[i].bPrecision, m_pColumnInfo[i].bScale,
  2981. DBPARAMIO_NOTPARAM, nDataOffset, nLengthOffset, nStatusOffset, NULL, DBMEMOWNER_CLIENTOWNED);
  2982. pCurrent++;
  2983. }
  2984. else // if( m_eBlobHandling == DBBLOBHANDLING_DEFAULT )
  2985. {
  2986. // we will try to bind blobs as streams
  2987. // if we have not tested if the rowset supports streams, do it now
  2988. if( ! fIStreamSupportTested )
  2989. {
  2990. #ifdef _DEBUG
  2991. ATLTRACE( "Testing streams support... " );
  2992. #endif
  2993. DBPROPID rgPropertyIDs[2] = { DBPROP_ISequentialStream, DBPROP_IStream };
  2994. BOOL rgStreamsSupported[2] = {FALSE, FALSE};
  2995. // check if the rowset supports IStream* interfaces
  2996. hr = GetRowsetProperties( pUnk, rgPropertyIDs, rgStreamsSupported, 2 );
  2997. ATLASSERT( SUCCEEDED( hr ) );
  2998. if( rgStreamsSupported[0] )
  2999. {
  3000. iidStreamToUse = __uuidof(ISequentialStream);
  3001. #ifdef _DEBUG
  3002. ATLTRACE( "ISequentialStream is supported\n" );
  3003. #endif
  3004. }
  3005. else if( rgStreamsSupported[1] )
  3006. {
  3007. iidStreamToUse = __uuidof(IStream);
  3008. #ifdef _DEBUG
  3009. ATLTRACE( "IStream is supported\n" );
  3010. #endif
  3011. }
  3012. else
  3013. {
  3014. #ifdef _DEBUG
  3015. ATLTRACE( "neither ISequentialStream nor IStream are supported!\n" );
  3016. #endif
  3017. ATLASSERT(FALSE); // the stream interfaces are not supported!!!
  3018. }
  3019. fIStreamSupportTested = true;
  3020. }
  3021. pObject = NULL;
  3022. ATLTRY(pObject = new DBOBJECT);
  3023. if (pObject == NULL)
  3024. {
  3025. for( ULONG t = 0; t < i; t++ )
  3026. delete pBinding[t].pObject;
  3027. delete [] pBinding;
  3028. delete [] m_pfClientOwnedMemRef;
  3029. m_pfClientOwnedMemRef = NULL;
  3030. return E_OUTOFMEMORY;
  3031. }
  3032. pObject->dwFlags = STGM_READ;
  3033. pObject->iid = iidStreamToUse;
  3034. m_pColumnInfo[i].wType = DBTYPE_IUNKNOWN;
  3035. m_pColumnInfo[i].ulColumnSize = sizeof(IUnknown*);
  3036. // Calculate the column data offset
  3037. nDataOffset = AlignAndIncrementOffset( nOffset, m_pColumnInfo[i].ulColumnSize, GetAlignment( m_pColumnInfo[i].wType ) );
  3038. // Calculate the column length offset
  3039. nLengthOffset = AlignAndIncrementOffset( nOffset, sizeof(DBLENGTH), __alignof(DBLENGTH) );
  3040. // Calculate the column status offset
  3041. nStatusOffset = AlignAndIncrementOffset( nOffset, sizeof(DBSTATUS), __alignof(DBSTATUS) );
  3042. #ifdef _DEBUG
  3043. if( iidStreamToUse == __uuidof(ISequentialStream) )
  3044. ATLTRACE( "%d. Column ordinal %d: Binding as an ISequentialStream object\n", i, m_pColumnInfo[i].iOrdinal );
  3045. else
  3046. ATLTRACE( "%d. Column ordinal %d: Binding as an IStream object\n", i, m_pColumnInfo[i].iOrdinal );
  3047. #endif
  3048. Bind(pCurrent, m_pColumnInfo[i].iOrdinal, m_pColumnInfo[i].wType,
  3049. m_pColumnInfo[i].ulColumnSize, m_pColumnInfo[i].bPrecision, m_pColumnInfo[i].bScale,
  3050. DBPARAMIO_NOTPARAM, nDataOffset, nLengthOffset, nStatusOffset, pObject);
  3051. pCurrent++;
  3052. }
  3053. }
  3054. // else if it's a COM object
  3055. else if( m_pColumnInfo[i].wType == DBTYPE_IUNKNOWN)
  3056. {
  3057. pObject = NULL;
  3058. ATLTRY(pObject = new DBOBJECT);
  3059. if (pObject == NULL)
  3060. {
  3061. for( ULONG t = 0; t < i; t++ )
  3062. delete pBinding[t].pObject;
  3063. delete [] pBinding;
  3064. delete [] m_pfClientOwnedMemRef;
  3065. m_pfClientOwnedMemRef = NULL;
  3066. return E_OUTOFMEMORY;
  3067. }
  3068. pObject->dwFlags = STGM_READ;
  3069. pObject->iid = __uuidof(IUnknown); // iidPersistToUse;
  3070. m_pColumnInfo[i].wType = DBTYPE_IUNKNOWN;
  3071. m_pColumnInfo[i].ulColumnSize = sizeof(IUnknown*);
  3072. // Calculate the column data offset
  3073. nDataOffset = AlignAndIncrementOffset( nOffset, m_pColumnInfo[i].ulColumnSize, GetAlignment( m_pColumnInfo[i].wType ) );
  3074. // Calculate the column length offset
  3075. nLengthOffset = AlignAndIncrementOffset( nOffset, sizeof(DBLENGTH), __alignof(DBLENGTH) );
  3076. // Calculate the column status offset
  3077. nStatusOffset = AlignAndIncrementOffset( nOffset, sizeof(DBSTATUS), __alignof(DBSTATUS) );
  3078. #ifdef _DEBUG
  3079. ATLTRACE( "%d. Column ordinal %d: Binding a COM object\n", i, m_pColumnInfo[i].iOrdinal );
  3080. #endif
  3081. Bind(pCurrent, m_pColumnInfo[i].iOrdinal, m_pColumnInfo[i].wType,
  3082. m_pColumnInfo[i].ulColumnSize, m_pColumnInfo[i].bPrecision, m_pColumnInfo[i].bScale,
  3083. DBPARAMIO_NOTPARAM, nDataOffset, nLengthOffset, nStatusOffset, pObject);
  3084. pCurrent++;
  3085. }
  3086. // else if it's not a BLOB or COM object
  3087. else
  3088. {
  3089. pObject = NULL;
  3090. // Calculate the size needed if it's a string
  3091. // including the NULL terminator.
  3092. if (m_pColumnInfo[i].wType == DBTYPE_STR)
  3093. m_pColumnInfo[i].ulColumnSize += 1;
  3094. if (m_pColumnInfo[i].wType == DBTYPE_WSTR)
  3095. m_pColumnInfo[i].ulColumnSize = m_pColumnInfo[i].ulColumnSize*2 + 2;
  3096. // Calculate the column data offset
  3097. nDataOffset = AlignAndIncrementOffset( nOffset, m_pColumnInfo[i].ulColumnSize, GetAlignment( m_pColumnInfo[i].wType ) );
  3098. // Calculate the column length offset
  3099. nLengthOffset = AlignAndIncrementOffset( nOffset, sizeof(DBLENGTH), __alignof(DBLENGTH) );
  3100. // Calculate the column status offset
  3101. nStatusOffset = AlignAndIncrementOffset( nOffset, sizeof(DBSTATUS), __alignof(DBSTATUS) );
  3102. #ifdef _DEBUG
  3103. ATLTRACE( "%d. Column ordinal %d: Binding as native data type\n", i, m_pColumnInfo[i].iOrdinal );
  3104. #endif
  3105. Bind(pCurrent, m_pColumnInfo[i].iOrdinal, m_pColumnInfo[i].wType,
  3106. m_pColumnInfo[i].ulColumnSize, m_pColumnInfo[i].bPrecision, m_pColumnInfo[i].bScale,
  3107. DBPARAMIO_NOTPARAM, nDataOffset, nLengthOffset, nStatusOffset, pObject);
  3108. pCurrent++;
  3109. }
  3110. // Note that, as we're not using this for anything else, we're using the
  3111. // pTypeInfo element to store the offset to our data.
  3112. m_pColumnInfo[i].pTypeInfo = (ITypeInfo*)(ULONG_PTR)nDataOffset;
  3113. }
  3114. // Allocate the accessor memory if we haven't done so yet
  3115. if (m_pAccessorInfo == NULL)
  3116. {
  3117. hr = AllocateAccessorMemory(1); // We only have one accessor
  3118. if (FAILED(hr))
  3119. {
  3120. for( ULONG t = 0; t < m_nColumns; t++ )
  3121. delete pBinding[t].pObject;
  3122. delete [] pBinding;
  3123. delete [] m_pfClientOwnedMemRef;
  3124. m_pfClientOwnedMemRef = NULL;
  3125. return hr;
  3126. }
  3127. m_pAccessorInfo->bAutoAccessor = true;
  3128. }
  3129. // Allocate enough memory for the data buffer and tell the rowset
  3130. // Note that the rowset will free the memory in its destructor.
  3131. m_pBuffer = NULL;
  3132. ATLTRY(m_pBuffer = new BYTE[nOffset]);
  3133. if (m_pBuffer == NULL)
  3134. {
  3135. for( ULONG t = 0; t < m_nColumns; t++ )
  3136. delete pBinding[t].pObject;
  3137. delete [] pBinding;
  3138. delete [] m_pfClientOwnedMemRef;
  3139. m_pfClientOwnedMemRef = NULL;
  3140. return E_OUTOFMEMORY;
  3141. }
  3142. memset(m_pBuffer, 0, nOffset);
  3143. hr = BindEntries(pBinding, m_nColumns, &m_pAccessorInfo->hAccessor,
  3144. nOffset, spAccessor);
  3145. if( FAILED(hr))
  3146. {
  3147. delete [] m_pfClientOwnedMemRef;
  3148. m_pfClientOwnedMemRef = NULL;
  3149. }
  3150. delete [] pBinding;
  3151. return hr;
  3152. }
  3153. // Translate the column number to the index into the column info array
  3154. bool TranslateColumnNo(DBORDINAL& nColumn) const throw()
  3155. {
  3156. ATLASSERT(m_pColumnInfo != NULL);
  3157. // If the user has overriden the binding then we need to search
  3158. // through the column info for the ordinal number
  3159. if (m_bOverride)
  3160. {
  3161. for (ULONG i = 0; i < m_nColumns; i++)
  3162. {
  3163. if (m_pColumnInfo[i].iOrdinal == nColumn)
  3164. {
  3165. nColumn = i;
  3166. return true;
  3167. }
  3168. }
  3169. return false;
  3170. }
  3171. else
  3172. {
  3173. // Note that m_pColumnInfo->iOrdinal will be zero if have bound
  3174. // a bookmark as the first entry, otherwise it will be 1.
  3175. // If the column is out of range then return false
  3176. if (nColumn > (m_nColumns - 1 + m_pColumnInfo->iOrdinal))
  3177. return false;
  3178. // otherwise translate the column to an index into our internal
  3179. // binding entries array
  3180. nColumn -= m_pColumnInfo->iOrdinal;
  3181. return true;
  3182. }
  3183. }
  3184. static size_t GetAlignment(DBTYPE bType) throw()
  3185. {
  3186. if( bType & DBTYPE_BYREF )
  3187. return __alignof(void*);
  3188. if( bType & DBTYPE_ARRAY )
  3189. return __alignof(SAFEARRAY*);
  3190. if( bType & DBTYPE_VECTOR )
  3191. return __alignof(DBVECTOR);
  3192. switch( bType )
  3193. {
  3194. case DBTYPE_I2:
  3195. return __alignof(signed short);
  3196. break;
  3197. case DBTYPE_I4:
  3198. return __alignof(signed int);
  3199. break;
  3200. case DBTYPE_R4:
  3201. return __alignof(float);
  3202. break;
  3203. case DBTYPE_R8:
  3204. return __alignof(double);
  3205. break;
  3206. case DBTYPE_CY:
  3207. return __alignof(__int64);
  3208. break;
  3209. case DBTYPE_DATE:
  3210. return __alignof(DATE);
  3211. break;
  3212. case DBTYPE_BSTR:
  3213. return __alignof(BSTR*);
  3214. break;
  3215. case DBTYPE_IDISPATCH:
  3216. return __alignof(IDispatch*);
  3217. break;
  3218. case DBTYPE_ERROR:
  3219. return __alignof(SCODE);
  3220. break;
  3221. case DBTYPE_BOOL:
  3222. return __alignof(VARIANT_BOOL);
  3223. break;
  3224. case DBTYPE_VARIANT:
  3225. return __alignof(VARIANT);
  3226. break;
  3227. case DBTYPE_IUNKNOWN:
  3228. return __alignof(IUnknown*);
  3229. break;
  3230. case DBTYPE_DECIMAL:
  3231. return __alignof(DECIMAL);
  3232. break;
  3233. case DBTYPE_UI1:
  3234. return __alignof(unsigned char);
  3235. break;
  3236. case DBTYPE_I1:
  3237. return __alignof(signed char);
  3238. break;
  3239. case DBTYPE_UI2:
  3240. return __alignof(unsigned short);
  3241. break;
  3242. case DBTYPE_UI4:
  3243. return __alignof(unsigned int);
  3244. break;
  3245. case DBTYPE_I8:
  3246. return __alignof(signed char);
  3247. break;
  3248. case DBTYPE_UI8:
  3249. return __alignof(unsigned char);
  3250. break;
  3251. case DBTYPE_GUID:
  3252. return __alignof(GUID);
  3253. break;
  3254. case DBTYPE_BYTES:
  3255. return __alignof(BYTE);
  3256. break;
  3257. case DBTYPE_STR:
  3258. return __alignof(char);
  3259. break;
  3260. case DBTYPE_WSTR:
  3261. return __alignof(short);
  3262. break;
  3263. case DBTYPE_NUMERIC:
  3264. return __alignof(DB_NUMERIC);
  3265. break;
  3266. case DBTYPE_DBDATE:
  3267. return __alignof(DBDATE);
  3268. break;
  3269. case DBTYPE_DBTIME:
  3270. return __alignof(DBTIME);
  3271. break;
  3272. case DBTYPE_DBTIMESTAMP:
  3273. return __alignof(DBTIMESTAMP);
  3274. break;
  3275. default:
  3276. return __alignof(__int64);
  3277. }
  3278. }
  3279. inline static DBBYTEOFFSET AlignAndIncrementOffset( DBBYTEOFFSET& nOffset, DBLENGTH nSize, size_t nAlign ) throw()
  3280. {
  3281. DBBYTEOFFSET nResult;
  3282. nOffset = AtlAlignUp( nOffset, (ULONG)nAlign );
  3283. nResult = nOffset;
  3284. nOffset += nSize;
  3285. return nResult;
  3286. }
  3287. inline static void IncrementAndAlignOffset( DBBYTEOFFSET& nOffset, DBLENGTH nSize, size_t nAlign ) throw()
  3288. {
  3289. nOffset += nSize;
  3290. nOffset = AtlAlignUp( nOffset, (ULONG)nAlign );
  3291. }
  3292. typedef CDynamicAccessor _OutputColumnsClass;
  3293. static bool HasOutputColumns() throw() { return true; }
  3294. DBORDINAL m_nColumns;
  3295. bool* m_pfClientOwnedMemRef;
  3296. DBCOLUMNINFO* m_pColumnInfo;
  3297. OLECHAR* m_pStringsBuffer;
  3298. bool m_bOverride;
  3299. protected:
  3300. DBBLOBHANDLINGENUM m_eBlobHandling;
  3301. DBLENGTH m_nBlobSize;
  3302. };
  3303. template< typename BaseType >
  3304. inline BaseType* strcpyT( BaseType *strDest, const BaseType *strSource )
  3305. {
  3306. return NULL;
  3307. }
  3308. template< typename BaseType >
  3309. inline BaseType* strncpyT( BaseType *strDest, const BaseType *strSource, size_t count )
  3310. {
  3311. return NULL;
  3312. }
  3313. template< typename BaseType >
  3314. inline size_t strlenT( const BaseType *string )
  3315. {
  3316. return NULL;
  3317. }
  3318. template<>
  3319. inline CHAR* strcpyT<CHAR>( CHAR *strDest, const CHAR *strSource )
  3320. {
  3321. return strcpy( strDest, strSource );
  3322. }
  3323. template<>
  3324. inline CHAR* strncpyT<CHAR>( CHAR *strDest, const CHAR *strSource, size_t count )
  3325. {
  3326. return strncpy( strDest, strSource, count );
  3327. }
  3328. template<>
  3329. inline size_t strlenT<CHAR>( const CHAR *string )
  3330. {
  3331. return strlen( string );
  3332. }
  3333. template<>
  3334. inline WCHAR* strcpyT<WCHAR>( WCHAR *strDest, const WCHAR *strSource )
  3335. {
  3336. return wcscpy( strDest, strSource );
  3337. }
  3338. template<>
  3339. inline WCHAR* strncpyT<WCHAR>( WCHAR *strDest, const WCHAR *strSource, size_t count )
  3340. {
  3341. return wcsncpy( strDest, strSource, count );
  3342. }
  3343. template<>
  3344. inline size_t strlenT<WCHAR>( const WCHAR *string )
  3345. {
  3346. return wcslen( string );
  3347. }
  3348. template< typename BaseType, DBTYPEENUM OleDbType >
  3349. class CDynamicStringAccessorT : public CDynamicAccessor
  3350. {
  3351. public:
  3352. explicit CDynamicStringAccessorT(DBLENGTH nBlobSize = 8000)
  3353. : CDynamicAccessor( DBBLOBHANDLING_DEFAULT, nBlobSize )
  3354. {
  3355. }
  3356. HRESULT BindColumns(IUnknown* pUnk) throw()
  3357. {
  3358. ATLASSERT(pUnk != NULL);
  3359. CComPtr<IAccessor> spAccessor;
  3360. HRESULT hr = pUnk->QueryInterface(&spAccessor);
  3361. if (FAILED(hr))
  3362. return hr;
  3363. ULONG i;
  3364. DBBYTEOFFSET nOffset = 0, nDataOffset, nLengthOffset, nStatusOffset;
  3365. DBLENGTH nLength;
  3366. // If the user hasn't specifed the column information to bind by calling AddBindEntry then
  3367. // we get it ourselves
  3368. if (m_pColumnInfo == NULL)
  3369. {
  3370. CComPtr<IColumnsInfo> spColumnsInfo;
  3371. hr = pUnk->QueryInterface(&spColumnsInfo);
  3372. if (FAILED(hr))
  3373. return hr;
  3374. hr = spColumnsInfo->GetColumnInfo(&m_nColumns, &m_pColumnInfo, &m_pStringsBuffer);
  3375. if (FAILED(hr))
  3376. return hr;
  3377. m_bOverride = false;
  3378. }
  3379. else
  3380. m_bOverride = true;
  3381. DBBINDING* pBinding = NULL;
  3382. ATLTRY(pBinding= new DBBINDING[m_nColumns]);
  3383. if (pBinding == NULL)
  3384. return E_OUTOFMEMORY;
  3385. ATLASSERT(m_pfClientOwnedMemRef == NULL);
  3386. ATLTRY(m_pfClientOwnedMemRef = new bool[m_nColumns]);
  3387. if( m_pfClientOwnedMemRef == NULL )
  3388. {
  3389. delete [] pBinding;
  3390. pBinding = NULL;
  3391. return E_OUTOFMEMORY;
  3392. }
  3393. DBBINDING* pCurrent = pBinding;
  3394. for (i = 0; i < m_nColumns; i++)
  3395. {
  3396. m_pfClientOwnedMemRef[i] = false;
  3397. // If it's a IPersist* object or the column size is large enough for us to treat it as
  3398. // a BLOB then we will request references (in client owned memory) to a string
  3399. if (m_pColumnInfo[i].ulColumnSize > m_nBlobSize || m_pColumnInfo[i].wType == DBTYPE_IUNKNOWN)
  3400. {
  3401. m_pColumnInfo[i].wType = OleDbType | DBTYPE_BYREF;
  3402. m_pColumnInfo[i].ulColumnSize = sizeof(BaseType*);
  3403. m_pfClientOwnedMemRef[i] = true;
  3404. }
  3405. else // We're treating everything as a string so add 1 for the NULL byte.
  3406. {
  3407. switch (m_pColumnInfo[i].wType)
  3408. {
  3409. case DBTYPE_BOOL:
  3410. nLength = 2;
  3411. break;
  3412. case DBTYPE_BYTES:
  3413. nLength = m_pColumnInfo[i].ulColumnSize * 2;
  3414. break;
  3415. case DBTYPE_BSTR:
  3416. nLength = m_pColumnInfo[i].ulColumnSize;
  3417. break;
  3418. case DBTYPE_STR:
  3419. nLength = m_pColumnInfo[i].ulColumnSize;
  3420. break;
  3421. case DBTYPE_WSTR:
  3422. nLength = m_pColumnInfo[i].ulColumnSize;
  3423. break;
  3424. case DBTYPE_I1:
  3425. nLength = 5;
  3426. break;
  3427. case DBTYPE_I2:
  3428. nLength = 7;
  3429. break;
  3430. case DBTYPE_I4:
  3431. nLength = 12;
  3432. break;
  3433. case DBTYPE_I8:
  3434. nLength = 22;
  3435. break;
  3436. case DBTYPE_UI1:
  3437. nLength = 4;
  3438. break;
  3439. case DBTYPE_UI2:
  3440. nLength = 6;
  3441. break;
  3442. case DBTYPE_UI4:
  3443. nLength = 11;
  3444. break;
  3445. case DBTYPE_UI8:
  3446. nLength = 21;
  3447. break;
  3448. case DBTYPE_R4:
  3449. nLength = 13;
  3450. break;
  3451. case DBTYPE_R8:
  3452. nLength = 23; // maybe 9
  3453. break;
  3454. case DBTYPE_DECIMAL:
  3455. nLength = 23;
  3456. break;
  3457. case DBTYPE_NUMERIC:
  3458. nLength = 23;
  3459. break;
  3460. case DBTYPE_VARIANT:
  3461. nLength = 20;
  3462. break;
  3463. case DBTYPE_IDISPATCH:
  3464. nLength = 32;
  3465. break;
  3466. case DBTYPE_IUNKNOWN:
  3467. nLength = 32;
  3468. break;
  3469. case DBTYPE_GUID:
  3470. nLength = 32;
  3471. break;
  3472. case DBTYPE_ARRAY:
  3473. nLength = 32;
  3474. break;
  3475. case DBTYPE_VECTOR:
  3476. nLength = 32;
  3477. break;
  3478. case DBTYPE_DBDATE:
  3479. nLength = 32;
  3480. break;
  3481. case DBTYPE_DBTIME:
  3482. nLength = 32;
  3483. break;
  3484. case DBTYPE_DBTIMESTAMP:
  3485. nLength = 20; // was 32
  3486. break;
  3487. case DBTYPE_FILETIME:
  3488. nLength = 32;
  3489. break;
  3490. case DBTYPE_PROPVARIANT:
  3491. nLength = 32;
  3492. break;
  3493. case DBTYPE_VARNUMERIC:
  3494. nLength = 32;
  3495. break;
  3496. case DBTYPE_CY:
  3497. nLength = 32;
  3498. break;
  3499. default:
  3500. ATLASSERT(FALSE); // unhandled column type
  3501. nLength = 32;
  3502. }
  3503. m_pColumnInfo[i].ulColumnSize = (nLength + 1) * sizeof(BaseType);
  3504. m_pColumnInfo[i].wType = OleDbType;
  3505. }
  3506. // Calculate the column data offset
  3507. nDataOffset = AlignAndIncrementOffset( nOffset, m_pColumnInfo[i].ulColumnSize, GetAlignment( OleDbType ) );
  3508. // Calculate the column length offset
  3509. nLengthOffset = AlignAndIncrementOffset( nOffset, sizeof(DBLENGTH), __alignof(DBLENGTH) );
  3510. // Calculate the column status offset
  3511. nStatusOffset = AlignAndIncrementOffset( nOffset, sizeof(DBSTATUS), __alignof(DBSTATUS) );
  3512. BindEx(pCurrent, m_pColumnInfo[i].iOrdinal, m_pColumnInfo[i].wType,
  3513. m_pColumnInfo[i].ulColumnSize, m_pColumnInfo[i].bPrecision, m_pColumnInfo[i].bScale,
  3514. DBPARAMIO_NOTPARAM, nDataOffset, nLengthOffset, nStatusOffset, NULL, DBMEMOWNER_CLIENTOWNED);
  3515. pCurrent++;
  3516. // Note that, as we're not using this for anything else, we're using the
  3517. // pTypeInfo element to store the offset to our data.
  3518. m_pColumnInfo[i].pTypeInfo = (ITypeInfo*)(ULONG_PTR)nDataOffset;
  3519. }
  3520. // Allocate the accessor memory if we haven't done so yet
  3521. if (m_pAccessorInfo == NULL)
  3522. {
  3523. hr = AllocateAccessorMemory(1); // We only have one accessor
  3524. if (FAILED(hr))
  3525. {
  3526. delete [] pBinding;
  3527. delete [] m_pfClientOwnedMemRef;
  3528. m_pfClientOwnedMemRef = NULL;
  3529. return hr;
  3530. }
  3531. m_pAccessorInfo->bAutoAccessor = true;
  3532. }
  3533. // Allocate enough memory for the data buffer and tell the rowset
  3534. // Note that the rowset will free the memory in its destructor.
  3535. m_pBuffer = NULL;
  3536. ATLTRY(m_pBuffer = new BYTE[nOffset]);
  3537. if (m_pBuffer == NULL)
  3538. {
  3539. delete [] pBinding;
  3540. delete [] m_pfClientOwnedMemRef;
  3541. m_pfClientOwnedMemRef = NULL;
  3542. return E_OUTOFMEMORY;
  3543. }
  3544. memset(m_pBuffer, 0, nOffset);
  3545. hr = BindEntries(pBinding, m_nColumns, &m_pAccessorInfo->hAccessor,
  3546. nOffset, spAccessor);
  3547. delete [] pBinding;
  3548. if( FAILED(hr) )
  3549. {
  3550. delete [] m_pfClientOwnedMemRef;
  3551. m_pfClientOwnedMemRef = NULL;
  3552. }
  3553. return hr;
  3554. }
  3555. BaseType* GetString(DBORDINAL nColumn) const throw()
  3556. {
  3557. if (TranslateColumnNo(nColumn))
  3558. {
  3559. if( m_pColumnInfo[nColumn].wType & DBTYPE_BYREF )
  3560. return *(BaseType**)_GetDataPtr(nColumn);
  3561. else
  3562. return (BaseType*)_GetDataPtr(nColumn);
  3563. }
  3564. else
  3565. return NULL;
  3566. }
  3567. BaseType* GetString(const CHAR* pColumnName) const throw()
  3568. {
  3569. ATLASSERT(pColumnName != NULL);
  3570. DBORDINAL nColumn;
  3571. if (GetInternalColumnNo(pColumnName, &nColumn))
  3572. {
  3573. if( m_pColumnInfo[nColumn].wType & DBTYPE_BYREF )
  3574. return *(BaseType**)_GetDataPtr(nColumn);
  3575. else
  3576. return (BaseType*)_GetDataPtr(nColumn);
  3577. }
  3578. else
  3579. return NULL; // Not Found
  3580. }
  3581. BaseType* GetString(const WCHAR* pColumnName) const throw()
  3582. {
  3583. ATLASSERT(pColumnName != NULL);
  3584. DBORDINAL nColumn;
  3585. if (GetInternalColumnNo(pColumnName, &nColumn))
  3586. {
  3587. if( m_pColumnInfo[nColumn].wType & DBTYPE_BYREF )
  3588. return *(BaseType**)_GetDataPtr(nColumn);
  3589. else
  3590. return (BaseType*)_GetDataPtr(nColumn);
  3591. }
  3592. else
  3593. return NULL; // Not Found
  3594. }
  3595. void _SetLength(DBORDINAL nColumn, DBLENGTH nLength ) throw()
  3596. {
  3597. DBBYTEOFFSET nOffset = (DBBYTEOFFSET)(ULONG_PTR)m_pColumnInfo[nColumn].pTypeInfo;
  3598. IncrementAndAlignOffset( nOffset, m_pColumnInfo[nColumn].ulColumnSize, __alignof(DBLENGTH) );
  3599. *(DBLENGTH*)( m_pBuffer + nOffset ) = nLength;
  3600. }
  3601. HRESULT _SetString(DBORDINAL nColumn, BaseType* data) throw()
  3602. {
  3603. DBLENGTH stringLen = (DBLENGTH)strlenT<BaseType>( data );
  3604. if( m_pColumnInfo[nColumn].wType & DBTYPE_BYREF )
  3605. {
  3606. BaseType** pBuffer = (BaseType**)_GetDataPtr(nColumn);
  3607. BaseType* pNewBuffer = (BaseType*)CoTaskMemRealloc( *pBuffer, (stringLen + 1) * sizeof(BaseType) );
  3608. if( pNewBuffer == NULL )
  3609. return E_OUTOFMEMORY;
  3610. *pBuffer = pNewBuffer;
  3611. strcpyT<BaseType>( pNewBuffer, data );
  3612. _SetLength( nColumn, stringLen );
  3613. }
  3614. else
  3615. {
  3616. BaseType* pBuffer = (BaseType*)_GetDataPtr(nColumn);
  3617. if( stringLen >= m_pColumnInfo[nColumn].ulColumnSize )
  3618. {
  3619. strncpyT<BaseType>( pBuffer, data, m_pColumnInfo[nColumn].ulColumnSize - 1 );
  3620. pBuffer[m_pColumnInfo[nColumn].ulColumnSize - 1] = 0;
  3621. _SetLength( nColumn, m_pColumnInfo[nColumn].ulColumnSize - 1 );
  3622. return DBSTATUS_S_TRUNCATED;
  3623. }
  3624. else
  3625. {
  3626. strcpyT<BaseType>( pBuffer, data );
  3627. _SetLength( nColumn, stringLen );
  3628. }
  3629. }
  3630. return S_OK;
  3631. }
  3632. HRESULT SetString(DBORDINAL nColumn, BaseType* data) throw()
  3633. {
  3634. if (TranslateColumnNo(nColumn))
  3635. return _SetString(nColumn, data);
  3636. else
  3637. return DB_S_ERRORSOCCURRED;
  3638. }
  3639. HRESULT SetString(const CHAR* pColumnName, BaseType* data) throw()
  3640. {
  3641. ATLASSERT(pColumnName != NULL);
  3642. DBORDINAL nColumn;
  3643. if (GetInternalColumnNo(pColumnName, &nColumn))
  3644. return _SetString(nColumn, data);
  3645. else
  3646. return DB_S_ERRORSOCCURRED;
  3647. }
  3648. HRESULT SetString(const WCHAR* pColumnName, BaseType* data) throw()
  3649. {
  3650. ATLASSERT(pColumnName != NULL);
  3651. DBORDINAL nColumn;
  3652. if (GetInternalColumnNo(pColumnName, &nColumn))
  3653. return _SetString(nColumn, data);
  3654. else
  3655. return DB_S_ERRORSOCCURRED;
  3656. }
  3657. };
  3658. typedef CDynamicStringAccessorT<CHAR, DBTYPE_STR> CDynamicStringAccessorA;
  3659. typedef CDynamicStringAccessorT<WCHAR, DBTYPE_WSTR> CDynamicStringAccessorW;
  3660. #ifdef _UNICODE
  3661. typedef CDynamicStringAccessorW CDynamicStringAccessor;
  3662. #else
  3663. typedef CDynamicStringAccessorA CDynamicStringAccessor;
  3664. #endif
  3665. class CXMLAccessor : public CDynamicStringAccessorW
  3666. {
  3667. public:
  3668. HRESULT GetXMLColumnData(CSimpleStringW& strOutput) throw()
  3669. {
  3670. _ATLTRY
  3671. {
  3672. strOutput = L"<columninfo>\n";
  3673. DBTYPE wType;
  3674. for (ULONG i=1; i<=m_nColumns; i++)
  3675. {
  3676. strOutput += L"<column type=\"";
  3677. if( !GetColumnType(i, &wType) )
  3678. return E_FAIL;
  3679. wType &= ~DBTYPE_BYREF;
  3680. wType &= ~DBTYPE_ARRAY;
  3681. wType &= ~DBTYPE_VECTOR;
  3682. switch (wType)
  3683. {
  3684. case DBTYPE_BOOL:
  3685. strOutput += L"BOOL";
  3686. break;
  3687. case DBTYPE_STR:
  3688. case DBTYPE_WSTR:
  3689. strOutput += L"STRING";
  3690. break;
  3691. case DBTYPE_I1:
  3692. strOutput += L"I1";
  3693. break;
  3694. case DBTYPE_I2:
  3695. strOutput += L"I2";
  3696. break;
  3697. case DBTYPE_I4:
  3698. strOutput += L"I4";
  3699. break;
  3700. case DBTYPE_I8:
  3701. strOutput += L"I8";
  3702. break;
  3703. case DBTYPE_UI1:
  3704. strOutput += L"UI1";
  3705. break;
  3706. case DBTYPE_UI2:
  3707. strOutput += L"UI2";
  3708. break;
  3709. case DBTYPE_UI4:
  3710. strOutput += L"UI4";
  3711. break;
  3712. case DBTYPE_UI8:
  3713. strOutput += L"UI8";
  3714. break;
  3715. case DBTYPE_R4:
  3716. strOutput += L"R4";
  3717. break;
  3718. case DBTYPE_R8:
  3719. strOutput += L"R8";
  3720. break;
  3721. case DBTYPE_DECIMAL:
  3722. strOutput += L"DECIMAL";
  3723. break;
  3724. case DBTYPE_NUMERIC:
  3725. strOutput += L"NUMERIC";
  3726. break;
  3727. case DBTYPE_VARIANT:
  3728. strOutput += L"VARIANT";
  3729. break;
  3730. case DBTYPE_IDISPATCH:
  3731. strOutput += L"DISPATCH";
  3732. break;
  3733. case DBTYPE_IUNKNOWN:
  3734. strOutput += L"IUNKNOWN";
  3735. break;
  3736. case DBTYPE_GUID:
  3737. strOutput += L"GUID";
  3738. break;
  3739. case DBTYPE_DBDATE:
  3740. strOutput += L"DBDATE";
  3741. break;
  3742. case DBTYPE_DBTIME:
  3743. strOutput += L"DBTIME";
  3744. break;
  3745. case DBTYPE_DBTIMESTAMP:
  3746. strOutput += L"DBTIMESTAMP";
  3747. break;
  3748. case DBTYPE_FILETIME:
  3749. strOutput += L"FILETIME";
  3750. break;
  3751. case DBTYPE_PROPVARIANT:
  3752. strOutput += L"PROPVARIANT";
  3753. break;
  3754. case DBTYPE_VARNUMERIC:
  3755. strOutput += L"VARNUMERIC";
  3756. break;
  3757. }
  3758. strOutput += L"\">";
  3759. strOutput += GetColumnName(i);
  3760. strOutput += L"</column>\n";
  3761. }
  3762. strOutput += L"</columninfo>\n";
  3763. return S_OK;
  3764. }
  3765. _ATLCATCH(e)
  3766. {
  3767. _ATLDELETEEXCEPTION(e)
  3768. return E_FAIL;
  3769. }
  3770. }
  3771. HRESULT GetXMLRowData(CSimpleStringW& strOutput, bool bAppend = false) throw()
  3772. {
  3773. _ATLTRY
  3774. {
  3775. USES_CONVERSION;
  3776. LPOLESTR pszName;
  3777. if (!bAppend)
  3778. strOutput.Empty();
  3779. strOutput += L"<row>";
  3780. for (ULONG i=1; i<=m_nColumns; i++)
  3781. {
  3782. pszName = GetColumnName(i);
  3783. strOutput += L"<";
  3784. strOutput += pszName;
  3785. strOutput += L">";
  3786. DBSTATUS dbStatus=DBSTATUS_S_ISNULL;
  3787. if( !GetStatus(i, &dbStatus) )
  3788. return E_FAIL;
  3789. if (dbStatus!=DBSTATUS_S_ISNULL)
  3790. strOutput += GetString(i);
  3791. strOutput += L"</";
  3792. strOutput += pszName;
  3793. strOutput += L">";
  3794. }
  3795. strOutput += L"</row>";
  3796. return S_OK;
  3797. }
  3798. _ATLCATCH(e)
  3799. {
  3800. _ATLDELETEEXCEPTION(e)
  3801. return E_FAIL;
  3802. }
  3803. }
  3804. };
  3805. // Like CDynamicAccessor but everything is bound as a DBTYPE_VARIANT
  3806. class CDynamicVariantAccessor : public CDynamicAccessor
  3807. {
  3808. public:
  3809. HRESULT BindColumns(IUnknown* pUnk) throw()
  3810. {
  3811. ATLASSERT(pUnk != NULL);
  3812. CComPtr<IAccessor> spAccessor;
  3813. HRESULT hr = pUnk->QueryInterface(&spAccessor);
  3814. if (FAILED(hr))
  3815. return hr;
  3816. ULONG i;
  3817. DBBYTEOFFSET nOffset = 0, nDataOffset, nLengthOffset, nStatusOffset;
  3818. // If the user hasn't specifed the column information to bind by calling AddBindEntry then
  3819. // we get it ourselves
  3820. if (m_pColumnInfo == NULL)
  3821. {
  3822. CComPtr<IColumnsInfo> spColumnsInfo;
  3823. hr = pUnk->QueryInterface(&spColumnsInfo);
  3824. if (FAILED(hr))
  3825. return hr;
  3826. hr = spColumnsInfo->GetColumnInfo(&m_nColumns, &m_pColumnInfo, &m_pStringsBuffer);
  3827. if (FAILED(hr))
  3828. return hr;
  3829. m_bOverride = false;
  3830. }
  3831. else
  3832. m_bOverride = true;
  3833. DBBINDING* pBinding = NULL;
  3834. ATLTRY(pBinding= new DBBINDING[m_nColumns]);
  3835. if (pBinding == NULL)
  3836. return E_OUTOFMEMORY;
  3837. DBBINDING* pCurrent = pBinding;
  3838. DBOBJECT* pObject;
  3839. for (i = 0; i < m_nColumns; i++)
  3840. {
  3841. // If it's a BLOB or the column size is large enough for us to treat it as
  3842. // a BLOB then we also need to set up the DBOBJECT structure.
  3843. if (m_pColumnInfo[i].ulColumnSize > m_nBlobSize || m_pColumnInfo[i].wType == DBTYPE_IUNKNOWN)
  3844. {
  3845. pObject = NULL;
  3846. ATLTRY(pObject = new DBOBJECT);
  3847. if (pObject == NULL)
  3848. {
  3849. for( UINT t = 0; t < i; t++ )
  3850. delete pBinding[t].pObject;
  3851. delete [] pBinding;
  3852. return E_OUTOFMEMORY;
  3853. }
  3854. pObject->dwFlags = STGM_READ;
  3855. pObject->iid = __uuidof(ISequentialStream);
  3856. m_pColumnInfo[i].wType = DBTYPE_IUNKNOWN;
  3857. m_pColumnInfo[i].ulColumnSize = sizeof(IUnknown*);
  3858. }
  3859. else
  3860. pObject = NULL;
  3861. m_pColumnInfo[i].ulColumnSize = sizeof(VARIANT);
  3862. // Calculate the column data offset
  3863. nDataOffset = AlignAndIncrementOffset(nOffset, sizeof(VARIANT), __alignof(VARIANT));
  3864. // Calculate the column length offset
  3865. nLengthOffset = AlignAndIncrementOffset(nOffset, sizeof(DBLENGTH), __alignof(DBLENGTH));
  3866. // Calculate the column status offset
  3867. nStatusOffset = AlignAndIncrementOffset(nOffset, sizeof(DBSTATUS), __alignof(DBSTATUS));
  3868. Bind(pCurrent, m_pColumnInfo[i].iOrdinal, DBTYPE_VARIANT,
  3869. sizeof(VARIANT), m_pColumnInfo[i].bPrecision, m_pColumnInfo[i].bScale,
  3870. DBPARAMIO_NOTPARAM, nDataOffset, nLengthOffset, nStatusOffset, pObject);
  3871. pCurrent++;
  3872. // Note that, as we're not using this for anything else, we're using the
  3873. // pTypeInfo element to store the offset to our data.
  3874. m_pColumnInfo[i].pTypeInfo = (ITypeInfo*)(ULONG_PTR)nDataOffset;
  3875. }
  3876. // Allocate the accessor memory if we haven't done so yet
  3877. if (m_pAccessorInfo == NULL)
  3878. {
  3879. hr = AllocateAccessorMemory(1); // We only have one accessor
  3880. if (FAILED(hr))
  3881. {
  3882. for( UINT t = 0; t < m_nColumns; t++ )
  3883. delete pBinding[t].pObject;
  3884. delete [] pBinding;
  3885. return hr;
  3886. }
  3887. m_pAccessorInfo->bAutoAccessor = true;
  3888. }
  3889. // Allocate enough memory for the data buffer and tell the rowset
  3890. // Note that the rowset will free the memory in its destructor.
  3891. m_pBuffer = NULL;
  3892. ATLTRY(m_pBuffer = new BYTE[nOffset]);
  3893. if (m_pBuffer == NULL)
  3894. {
  3895. for( UINT t = 0; t < m_nColumns; t++ )
  3896. delete pBinding[t].pObject;
  3897. delete [] pBinding;
  3898. return E_OUTOFMEMORY;
  3899. }
  3900. memset(m_pBuffer, 0, nOffset);
  3901. hr = BindEntries(pBinding, m_nColumns, &m_pAccessorInfo->hAccessor,
  3902. nOffset, spAccessor);
  3903. delete [] pBinding;
  3904. return hr;
  3905. }
  3906. };
  3907. ///////////////////////////////////////////////////////////////////////////
  3908. // class CDynamicParameterAccessor
  3909. class CDynamicParameterAccessor : public CDynamicAccessor
  3910. {
  3911. // Constructors and Destructors
  3912. public:
  3913. typedef CDynamicParameterAccessor _ParamClass;
  3914. CDynamicParameterAccessor( DBBLOBHANDLINGENUM eBlobHandling = DBBLOBHANDLING_DEFAULT, DBLENGTH nBlobSize = 8000 )
  3915. : CDynamicAccessor( eBlobHandling, nBlobSize )
  3916. {
  3917. m_pParameterEntry = NULL;
  3918. m_pParameterBuffer = NULL;
  3919. m_ppParamName = NULL;
  3920. m_nParameterBufferSize = 0;
  3921. m_nParams = 0;
  3922. };
  3923. ~CDynamicParameterAccessor()
  3924. {
  3925. delete [] m_pParameterEntry;
  3926. if (m_ppParamName != NULL)
  3927. {
  3928. CoTaskMemFree(*m_ppParamName);
  3929. delete [] m_ppParamName;
  3930. }
  3931. delete m_pParameterBuffer;
  3932. };
  3933. bool GetParamSize(DBORDINAL nParam, DBLENGTH *pLength) const throw()
  3934. {
  3935. ATLASSERT( pLength != NULL );
  3936. if( !TranslateParameterNo( nParam ) )
  3937. return false;
  3938. *pLength = m_pParameterEntry[nParam].cbMaxLen;
  3939. return true;
  3940. }
  3941. bool GetParamIO(DBORDINAL nParam, DBPARAMIO *pParamIO) const throw()
  3942. {
  3943. ATLASSERT( pParamIO != NULL );
  3944. if( !TranslateParameterNo( nParam ) )
  3945. return false;
  3946. *pParamIO = m_pParameterEntry[nParam].eParamIO;
  3947. return true;
  3948. }
  3949. bool GetParamType(DBORDINAL nParam, DBTYPE *pType) const throw()
  3950. {
  3951. ATLASSERT( pType != NULL );
  3952. if( !TranslateParameterNo( nParam ) )
  3953. return false;
  3954. *pType = m_pParameterEntry[nParam].wType;
  3955. return true;
  3956. }
  3957. bool GetParamLength(DBORDINAL nParam, DBLENGTH *pLength)
  3958. {
  3959. ATLASSERT( pLength != NULL );
  3960. DBLENGTH* pBuffer = GetParamLength(nParam);
  3961. if (pBuffer == NULL)
  3962. return false;
  3963. *pLength = *pBuffer;
  3964. return true;
  3965. }
  3966. bool SetParamLength(DBORDINAL nParam, DBLENGTH length)
  3967. {
  3968. DBLENGTH* pBuffer = GetParamLength(nParam);
  3969. if (pBuffer == NULL)
  3970. return false;
  3971. *pBuffer = length;
  3972. return true;
  3973. }
  3974. bool GetParamStatus(DBORDINAL nParam, DBSTATUS *pStatus)
  3975. {
  3976. ATLASSERT( pStatus != NULL );
  3977. DBSTATUS* pBuffer = GetParamStatus(nParam);
  3978. if (pBuffer == NULL)
  3979. return false;
  3980. *pStatus = *pBuffer;
  3981. return true;
  3982. }
  3983. bool SetParamStatus(DBORDINAL nParam, DBSTATUS status)
  3984. {
  3985. DBSTATUS* pBuffer = GetParamStatus(nParam);
  3986. if (pBuffer == NULL)
  3987. return false;
  3988. *pBuffer = status;
  3989. return true;
  3990. }
  3991. template <class ctype>
  3992. bool GetParam(DBORDINAL nParam, ctype* pData) const throw()
  3993. {
  3994. ATLASSERT( pData != NULL );
  3995. ctype* pBuffer = (ctype*)GetParam(nParam);
  3996. if (pBuffer == NULL)
  3997. return false;
  3998. *pData = *pBuffer;
  3999. return true;
  4000. }
  4001. bool GetParamString(DBORDINAL nParam, CSimpleStringA& strOutput ) throw()
  4002. {
  4003. CHAR* pData = (CHAR*)GetParam(nParam);
  4004. if (pData == NULL)
  4005. return false;
  4006. strOutput = pData;
  4007. return true;
  4008. }
  4009. bool GetParamString(DBORDINAL nParam, CSimpleStringW& strOutput ) throw()
  4010. {
  4011. WCHAR* pData = (WCHAR*)GetParam(nParam);
  4012. if (pData == NULL)
  4013. return false;
  4014. strOutput = pData;
  4015. return true;
  4016. }
  4017. bool GetParamString(DBORDINAL nParam, CHAR* pBuffer, size_t* pMaxLen) throw()
  4018. {
  4019. ATLASSERT( pMaxLen != NULL );
  4020. CHAR* pData = (CHAR*)GetParam(nParam);
  4021. if (pData == NULL)
  4022. return false;
  4023. size_t nStrLen = strlen( pData );
  4024. if( pBuffer == NULL )
  4025. {
  4026. *pMaxLen = nStrLen + 1;
  4027. return true;
  4028. }
  4029. if( ( *pMaxLen ) < ( nStrLen + 1 ) )
  4030. {
  4031. return false;
  4032. }
  4033. strcpy( pBuffer, pData );
  4034. return true;
  4035. }
  4036. bool GetParamString(DBORDINAL nParam, WCHAR* pBuffer, size_t* pMaxLen) throw()
  4037. {
  4038. ATLASSERT( pMaxLen != NULL );
  4039. WCHAR* pData = (WCHAR*)GetParam(nParam);
  4040. if (pData == NULL)
  4041. return false;
  4042. size_t nStrLen = wcslen( pData );
  4043. if( pBuffer == NULL )
  4044. {
  4045. *pMaxLen = nStrLen + 1;
  4046. return true;
  4047. }
  4048. if( ( * pMaxLen ) < ( nStrLen + 1 ) )
  4049. {
  4050. return false;
  4051. }
  4052. wcscpy( pBuffer, pData );
  4053. return true;
  4054. }
  4055. template <class ctype>
  4056. bool SetParam(DBORDINAL nParam, const ctype* pData, DBSTATUS status = DBSTATUS_S_OK ) throw()
  4057. {
  4058. ATLASSERT( pData != NULL );
  4059. if( !TranslateParameterNo( nParam ) )
  4060. return false;
  4061. ctype* pBuffer = (ctype*)_GetParam(nParam);
  4062. if (pBuffer == NULL)
  4063. return false;
  4064. *pBuffer = *pData;
  4065. DBSTATUS *pStatus = _GetParamStatus( nParam );
  4066. if( pStatus != NULL )
  4067. *pStatus = status;
  4068. //DBLENGTH *pLength = _GetParamLength( nParam );
  4069. //if( pLength != NULL )
  4070. // *pLength = (DBLENGTH)sizeof(ctype);
  4071. return true;
  4072. }
  4073. bool SetParamString(DBORDINAL nParam, const CHAR* pString, DBSTATUS status = DBSTATUS_S_OK ) throw()
  4074. {
  4075. ATLASSERT( pString != NULL );
  4076. if( !TranslateParameterNo( nParam ) )
  4077. return false;
  4078. CHAR* pBuffer = (CHAR*)_GetParam(nParam);
  4079. if (pBuffer == NULL)
  4080. return false;
  4081. size_t nMaxLen = m_pParameterEntry[nParam].cbMaxLen;
  4082. if( strlen( pString ) >= nMaxLen )
  4083. return false;
  4084. strcpy( pBuffer, pString );
  4085. DBSTATUS *pStatus = _GetParamStatus( nParam );
  4086. if( pStatus != NULL )
  4087. *pStatus = status;
  4088. DBLENGTH *pLength = _GetParamLength( nParam );
  4089. if( pLength != NULL )
  4090. *pLength = (DBLENGTH)(strlen(pBuffer));
  4091. return true;
  4092. }
  4093. bool SetParamString(DBORDINAL nParam, const WCHAR* pString, DBSTATUS status = DBSTATUS_S_OK ) throw()
  4094. {
  4095. ATLASSERT( pString != NULL );
  4096. if( !TranslateParameterNo( nParam ) )
  4097. return false;
  4098. WCHAR* pBuffer = (WCHAR*)_GetParam(nParam);
  4099. if (pBuffer == NULL)
  4100. return false;
  4101. size_t nMaxLen = m_pParameterEntry[nParam].cbMaxLen / 2;
  4102. if( wcslen( pString ) >= nMaxLen )
  4103. return false;
  4104. wcscpy( pBuffer, pString );
  4105. DBSTATUS *pStatus = _GetParamStatus( nParam );
  4106. if( pStatus != NULL )
  4107. *pStatus = status;
  4108. DBLENGTH *pLength = _GetParamLength( nParam );
  4109. if( pLength != NULL )
  4110. *pLength = (DBLENGTH)( sizeof(WCHAR) * wcslen(pBuffer));
  4111. return true;
  4112. }
  4113. template <class ctype>
  4114. bool GetParam(TCHAR* pParamName, ctype* pData) const throw()
  4115. {
  4116. ATLASSERT( pData != NULL );
  4117. DBORDINAL nParam;
  4118. if( !_GetParameterNo( pParamName, nParam ) )
  4119. return NULL;
  4120. ctype* pBuffer = (ctype*)_GetParam(nParam);
  4121. if (pBuffer == NULL)
  4122. return false;
  4123. *pData = *pBuffer;
  4124. return true;
  4125. }
  4126. template <class ctype>
  4127. bool SetParam(TCHAR* pParamName, const ctype* pData, DBSTATUS status = DBSTATUS_S_OK ) throw()
  4128. {
  4129. ATLASSERT( pData != NULL );
  4130. DBORDINAL nParam;
  4131. if( !_GetParameterNo( pParamName, nParam ) )
  4132. return NULL;
  4133. ctype* pBuffer = (ctype*)_GetParam(nParam);
  4134. if (pBuffer == NULL)
  4135. return false;
  4136. *pBuffer = *pData;
  4137. DBSTATUS *pStatus = _GetParamStatus( nParam );
  4138. if( pStatus != NULL )
  4139. *pStatus = status;
  4140. //DBLENGTH *pLength = _GetParamLength( nParam );
  4141. //if( pLength != NULL )
  4142. // *pLength = sizeof(ctype);
  4143. return true;
  4144. }
  4145. void* GetParam(DBORDINAL nParam) const throw()
  4146. {
  4147. if( !TranslateParameterNo( nParam ) )
  4148. return NULL;
  4149. return _GetParam( nParam );
  4150. }
  4151. DBLENGTH* GetParamLength(DBORDINAL nParam) const throw()
  4152. {
  4153. if( !TranslateParameterNo( nParam ) )
  4154. return NULL;
  4155. return _GetParamLength( nParam );
  4156. }
  4157. DBSTATUS* GetParamStatus(DBORDINAL nParam) const throw()
  4158. {
  4159. if( !TranslateParameterNo( nParam ) )
  4160. return NULL;
  4161. return _GetParamStatus( nParam );
  4162. }
  4163. void* GetParam(TCHAR* pParamName) const throw()
  4164. {
  4165. DBORDINAL nParam;
  4166. if( !_GetParameterNo( pParamName, nParam ) )
  4167. return NULL;
  4168. return _GetParam( nParam );
  4169. }
  4170. // Get the number of parameters
  4171. DB_UPARAMS GetParamCount() const throw()
  4172. {
  4173. return m_nParams;
  4174. }
  4175. // Get the parameter name for the passed parameter number
  4176. LPOLESTR GetParamName(DBORDINAL nParam) const throw()
  4177. {
  4178. if( !TranslateParameterNo( nParam ) )
  4179. return NULL;
  4180. return m_ppParamName[nParam];
  4181. }
  4182. bool TranslateParameterNo( DBORDINAL& nParam ) const throw()
  4183. {
  4184. for( DBORDINAL i = 0; i < m_nParams; i++ )
  4185. {
  4186. if( m_pParameterEntry[i].iOrdinal == nParam )
  4187. {
  4188. nParam = i;
  4189. return true;
  4190. }
  4191. }
  4192. return false;
  4193. }
  4194. bool _GetParameterNo( TCHAR* pParamName, DBORDINAL& nParam ) const throw()
  4195. {
  4196. USES_CONVERSION;
  4197. if( pParamName == NULL )
  4198. return false;
  4199. DBORDINAL i;
  4200. size_t nSize = (lstrlen(pParamName) + 1) * sizeof(OLECHAR);
  4201. OLECHAR* pOleParamName = T2OLE(pParamName);
  4202. for (i=0; i<m_nParams; i++)
  4203. {
  4204. if (memcmp(m_ppParamName[i], pOleParamName, nSize) == 0)
  4205. {
  4206. nParam = i;
  4207. return true;
  4208. }
  4209. }
  4210. return false; // Not Found
  4211. }
  4212. void* _GetParam(DBORDINAL nParam) const throw()
  4213. {
  4214. return m_pParameterBuffer + m_pParameterEntry[nParam].obValue;
  4215. }
  4216. DBLENGTH* _GetParamLength(DBORDINAL nParam) const throw()
  4217. {
  4218. if( m_pParameterEntry[nParam].obLength == 0 )
  4219. return NULL;
  4220. else
  4221. return (DBLENGTH*)(m_pParameterBuffer + m_pParameterEntry[nParam].obLength);
  4222. }
  4223. DBSTATUS* _GetParamStatus(DBORDINAL nParam) const throw()
  4224. {
  4225. if( m_pParameterEntry[nParam].obStatus == 0 )
  4226. return NULL;
  4227. else
  4228. return (DBSTATUS*)(m_pParameterBuffer + m_pParameterEntry[nParam].obStatus);
  4229. }
  4230. // Implementation
  4231. HRESULT BindParameters(HACCESSOR* pHAccessor, ICommand* pCommand,
  4232. void** ppParameterBuffer, bool fBindLength = false, bool fBindStatus = false ) throw()
  4233. {
  4234. // If we have already bound the parameters then just return
  4235. // the pointer to the parameter buffer
  4236. if (*pHAccessor != NULL)
  4237. {
  4238. *ppParameterBuffer = m_pParameterBuffer;
  4239. return S_OK;
  4240. }
  4241. CComPtr<IAccessor> spAccessor;
  4242. ATLASSERT(pCommand != NULL);
  4243. HRESULT hr = pCommand->QueryInterface(&spAccessor);
  4244. if (FAILED(hr))
  4245. return hr;
  4246. // Try to bind parameters if available
  4247. CComPtr<ICommandWithParameters> spCommandParameters;
  4248. hr = pCommand->QueryInterface(&spCommandParameters);
  4249. if (FAILED(hr))
  4250. return hr;
  4251. DB_UPARAMS ulParams = 0;
  4252. CComHeapPtr<DBPARAMINFO> spParamInfo;
  4253. LPOLESTR pNamesBuffer;
  4254. // Get Parameter Information
  4255. hr = spCommandParameters->GetParameterInfo(&ulParams, &spParamInfo,
  4256. &pNamesBuffer);
  4257. if (FAILED(hr))
  4258. return hr;
  4259. // Create the parameter information for binding
  4260. hr = AllocateParameterInfo(ulParams);
  4261. if (FAILED(hr))
  4262. {
  4263. CoTaskMemFree(pNamesBuffer);
  4264. return hr;
  4265. }
  4266. DBBYTEOFFSET nOffset = 0;
  4267. DBBYTEOFFSET nDataOffset = 0;
  4268. DBBYTEOFFSET nLengthOffset = 0;
  4269. DBBYTEOFFSET nStatusOffset = 0;
  4270. DBBINDING* pCurrent = m_pParameterEntry;
  4271. for (ULONG l=0; l<ulParams; l++)
  4272. {
  4273. m_pParameterEntry[l].eParamIO = 0;
  4274. if (spParamInfo[l].dwFlags & DBPARAMFLAGS_ISINPUT)
  4275. m_pParameterEntry[l].eParamIO |= DBPARAMIO_INPUT;
  4276. if (spParamInfo[l].dwFlags & DBPARAMFLAGS_ISOUTPUT)
  4277. m_pParameterEntry[l].eParamIO |= DBPARAMIO_OUTPUT;
  4278. // if this is a BLOB, truncate column length to m_nBlobSize (like 8000 bytes)
  4279. if( spParamInfo[l].ulParamSize > m_nBlobSize )
  4280. spParamInfo[l].ulParamSize = m_nBlobSize;
  4281. // if this is a string, recalculate column size in bytes
  4282. DBLENGTH colLength = spParamInfo[l].ulParamSize;
  4283. if (spParamInfo[l].wType == DBTYPE_STR)
  4284. colLength += 1;
  4285. if (spParamInfo[l].wType == DBTYPE_WSTR)
  4286. colLength = colLength*2 + 2;
  4287. // Calculate the column data offset
  4288. nDataOffset = AlignAndIncrementOffset( nOffset, colLength, GetAlignment( spParamInfo[l].wType ) );
  4289. if( fBindLength )
  4290. {
  4291. // Calculate the column length offset
  4292. nLengthOffset = AlignAndIncrementOffset( nOffset, sizeof(DBLENGTH), __alignof(DBLENGTH) );
  4293. }
  4294. if( fBindStatus )
  4295. {
  4296. // Calculate the column status offset
  4297. nStatusOffset = AlignAndIncrementOffset( nOffset, sizeof(DBSTATUS), __alignof(DBSTATUS) );
  4298. }
  4299. Bind(pCurrent, spParamInfo[l].iOrdinal, spParamInfo[l].wType,
  4300. colLength, spParamInfo[l].bPrecision, spParamInfo[l].bScale,
  4301. m_pParameterEntry[l].eParamIO, nDataOffset, nLengthOffset, nStatusOffset );
  4302. pCurrent++;
  4303. m_ppParamName[l] = pNamesBuffer;
  4304. if (pNamesBuffer && *pNamesBuffer)
  4305. {
  4306. // Search for the NULL termination character
  4307. while (*pNamesBuffer++)
  4308. ;
  4309. }
  4310. }
  4311. // Allocate memory for the new buffer
  4312. m_pParameterBuffer = NULL;
  4313. ATLTRY(m_pParameterBuffer = new BYTE[nOffset]);
  4314. if (m_pParameterBuffer == NULL)
  4315. {
  4316. // Note that pNamesBuffer will be freed in the destructor
  4317. // by freeing *m_ppParamName
  4318. return E_OUTOFMEMORY;
  4319. }
  4320. *ppParameterBuffer = m_pParameterBuffer;
  4321. m_nParameterBufferSize = nOffset;
  4322. m_nParams = ulParams;
  4323. BindEntries(m_pParameterEntry, ulParams, pHAccessor, nOffset, spAccessor);
  4324. return S_OK;
  4325. }
  4326. bool HasParameters() const throw()
  4327. {
  4328. return true;
  4329. }
  4330. HRESULT AllocateParameterInfo(DB_UPARAMS nParamEntries) throw()
  4331. {
  4332. // Allocate memory for the bind structures
  4333. m_pParameterEntry = NULL;
  4334. ATLTRY(m_pParameterEntry = new DBBINDING[nParamEntries]);
  4335. if (m_pParameterEntry == NULL)
  4336. return E_OUTOFMEMORY;
  4337. // Allocate memory to store the field names
  4338. m_ppParamName = NULL;
  4339. ATLTRY(m_ppParamName = new OLECHAR*[nParamEntries]);
  4340. if (m_ppParamName == NULL)
  4341. {
  4342. delete [] m_pParameterEntry;
  4343. m_pParameterEntry = NULL;
  4344. return E_OUTOFMEMORY;
  4345. }
  4346. return S_OK;
  4347. }
  4348. // Data Members
  4349. // Number of parameters
  4350. DB_UPARAMS m_nParams;
  4351. // A pointer to the entry structures for each parameter
  4352. DBBINDING* m_pParameterEntry;
  4353. // String names for the parameters
  4354. OLECHAR** m_ppParamName;
  4355. // The size of the buffer where the parameters are stored
  4356. DBLENGTH m_nParameterBufferSize;
  4357. // A pointer to the buffer where the parameters are stored
  4358. BYTE* m_pParameterBuffer;
  4359. };
  4360. ///////////////////////////////////////////////////////////////////////////
  4361. // class CManualAccessor
  4362. class CManualAccessor :
  4363. public CAccessorBase
  4364. {
  4365. public:
  4366. CManualAccessor()
  4367. {
  4368. // By default we don't have any parameters unless CreateParameterAccessor
  4369. // is called
  4370. m_pEntry = NULL;
  4371. m_nParameters = 0;
  4372. m_pParameterEntry = NULL;
  4373. m_nColumns = 0;
  4374. m_pParameterBuffer = NULL;
  4375. }
  4376. ~CManualAccessor()
  4377. {
  4378. delete [] m_pEntry;
  4379. delete [] m_pParameterEntry;
  4380. }
  4381. HRESULT CreateAccessor(int nBindEntries, void* pBuffer, DBLENGTH nBufferSize) throw()
  4382. {
  4383. m_pBuffer = (BYTE*)pBuffer;
  4384. m_nBufferSize = nBufferSize;
  4385. m_nColumns = nBindEntries;
  4386. m_nEntry = 0;
  4387. memset(pBuffer, 0, nBufferSize);
  4388. // If they've previously created some entries then free them
  4389. delete [] m_pEntry;
  4390. m_pEntry = NULL;
  4391. // Allocate memory for the bind structures
  4392. ATLTRY(m_pEntry = new DBBINDING[nBindEntries]);
  4393. if (m_pEntry == NULL)
  4394. return E_OUTOFMEMORY;
  4395. else
  4396. return S_OK;
  4397. }
  4398. HRESULT CreateParameterAccessor(int nBindEntries, void* pBuffer, DBLENGTH nBufferSize) throw()
  4399. {
  4400. // Should be called only once. But, if you really insist on doing this...
  4401. if (m_pParameterEntry != NULL)
  4402. {
  4403. delete [] m_pParameterEntry;
  4404. m_pParameterEntry = NULL;
  4405. }
  4406. m_pParameterBuffer = (BYTE*)pBuffer;
  4407. m_nParameterBufferSize = nBufferSize;
  4408. m_nParameters = nBindEntries;
  4409. m_nCurrentParameter = 0;
  4410. // Allocate memory for the bind structures
  4411. ATLTRY(m_pParameterEntry = new DBBINDING[nBindEntries]);
  4412. if (m_pParameterEntry == NULL)
  4413. return E_OUTOFMEMORY;
  4414. else
  4415. return S_OK;
  4416. }
  4417. void AddBindEntry(DBORDINAL nOrdinal, DBTYPE wType, DBLENGTH nColumnSize,
  4418. void* pData, void* pLength = NULL, void* pStatus = NULL) throw()
  4419. {
  4420. ATLASSERT(m_nEntry < m_nColumns);
  4421. DBBYTEOFFSET nLengthOffset, nStatusOffset;
  4422. if (pStatus != NULL)
  4423. nStatusOffset = (BYTE*)pStatus - m_pBuffer;
  4424. else
  4425. nStatusOffset = 0;
  4426. if (pLength != NULL)
  4427. nLengthOffset = (BYTE*)pLength - m_pBuffer;
  4428. else
  4429. nLengthOffset = 0;
  4430. Bind(m_pEntry+m_nEntry, nOrdinal, wType, nColumnSize, 0, 0, DBPARAMIO_NOTPARAM,
  4431. (BYTE*)pData - m_pBuffer, nLengthOffset, nStatusOffset);
  4432. m_nEntry++;
  4433. }
  4434. void AddParameterEntry(DBORDINAL nOrdinal, DBTYPE wType, DBLENGTH nColumnSize,
  4435. void* pData, void* pLength = NULL, void* pStatus = NULL,
  4436. DBPARAMIO eParamIO = DBPARAMIO_INPUT) throw()
  4437. {
  4438. ATLASSERT(m_nCurrentParameter < m_nParameters);
  4439. DBBYTEOFFSET nLengthOffset, nStatusOffset;
  4440. if (pStatus != NULL)
  4441. nStatusOffset = (BYTE*)pStatus - m_pParameterBuffer;
  4442. else
  4443. nStatusOffset = 0;
  4444. if (pLength != NULL)
  4445. nLengthOffset = (BYTE*)pLength - m_pParameterBuffer;
  4446. else
  4447. nLengthOffset = 0;
  4448. Bind(m_pParameterEntry + m_nCurrentParameter, nOrdinal, wType, nColumnSize, 0, 0,
  4449. eParamIO, (BYTE*)pData - m_pParameterBuffer, nLengthOffset, nStatusOffset);
  4450. m_nCurrentParameter++;
  4451. }
  4452. // Implementation
  4453. // Free's any columns in the current record that need to be freed.
  4454. // E.g. Calls SysFreeString on any BSTR's and Release on any interfaces.
  4455. void FreeRecordMemory(IRowset* pRowset) throw ()
  4456. {
  4457. ULONG i;
  4458. for (i = 0; i < m_nColumns; i++)
  4459. CAccessorBase::FreeType(m_pEntry[i].wType, m_pBuffer + m_pEntry[i].obValue, pRowset);
  4460. }
  4461. void ClearRecordMemory() throw()
  4462. {
  4463. memset(m_pBuffer, 0, m_nBufferSize);
  4464. }
  4465. HRESULT BindColumns(IUnknown* pUnk) throw()
  4466. {
  4467. ATLASSERT(pUnk != NULL);
  4468. CComPtr<IAccessor> spAccessor;
  4469. HRESULT hr = pUnk->QueryInterface(&spAccessor);
  4470. if (FAILED(hr))
  4471. return hr;
  4472. // Allocate the accessor memory if we haven't done so yet
  4473. if (m_pAccessorInfo == NULL)
  4474. {
  4475. hr = AllocateAccessorMemory(1); // We only have one accessor
  4476. if (FAILED(hr))
  4477. return hr;
  4478. m_pAccessorInfo->bAutoAccessor = true;
  4479. }
  4480. return BindEntries(m_pEntry, m_nColumns, &m_pAccessorInfo->hAccessor, m_nBufferSize, spAccessor);
  4481. }
  4482. HRESULT BindParameters(HACCESSOR* pHAccessor, ICommand* pCommand, void** ppParameterBuffer) throw()
  4483. {
  4484. HRESULT hr;
  4485. *ppParameterBuffer = m_pParameterBuffer;
  4486. // Only bind the parameter if we haven't done so yet
  4487. if (*pHAccessor == NULL)
  4488. {
  4489. // Get the IAccessor from the passed IUnknown
  4490. CComPtr<IAccessor> spAccessor;
  4491. ATLASSERT(pCommand != NULL);
  4492. hr = pCommand->QueryInterface(&spAccessor);
  4493. if (SUCCEEDED(hr))
  4494. {
  4495. hr = BindEntries(m_pParameterEntry, m_nParameters, pHAccessor,
  4496. m_nParameterBufferSize, spAccessor);
  4497. }
  4498. }
  4499. else
  4500. hr = S_OK;
  4501. return hr;
  4502. }
  4503. typedef CManualAccessor _ParamClass;
  4504. bool HasParameters() throw() { return (m_nParameters > 0); }
  4505. typedef CManualAccessor _OutputColumnsClass;
  4506. bool HasOutputColumns() throw() { return (m_nColumns > 0); }
  4507. DBORDINAL GetColumnCount() const throw()
  4508. {
  4509. return m_nColumns;
  4510. }
  4511. // The binding structure for the output columns
  4512. DBBINDING* m_pEntry;
  4513. // The number of output columns
  4514. DBORDINAL m_nColumns;
  4515. // The number of the current entry for the output columns
  4516. DBORDINAL m_nEntry;
  4517. // The size of the data buffer for the output columns
  4518. DBLENGTH m_nBufferSize;
  4519. // The number of parameters columns
  4520. DBORDINAL m_nParameters;
  4521. // The number of the parameter column to bind next
  4522. DBORDINAL m_nCurrentParameter;
  4523. // A pointer to the entry structures for each parameter
  4524. DBBINDING* m_pParameterEntry;
  4525. // The size of the buffer where the parameters are stored
  4526. DBLENGTH m_nParameterBufferSize;
  4527. // A pointer to the buffer where the parameters are stored
  4528. BYTE* m_pParameterBuffer;
  4529. };
  4530. class _ATL_COLUMN_PARAM_INFO
  4531. {
  4532. public:
  4533. _ATL_COLUMN_PARAM_INFO()
  4534. {
  4535. m_pParams = NULL;
  4536. m_pBuffer = NULL;
  4537. }
  4538. ~_ATL_COLUMN_PARAM_INFO()
  4539. {
  4540. delete m_pParams;
  4541. }
  4542. BOOL AddBinding(DBBINDING& binding)
  4543. {
  4544. return m_rgBinding.Add(binding);
  4545. }
  4546. CSimpleArray<DBBINDING, CSimpleArrayEqualHelperFalse<DBBINDING> > m_rgBinding; // The binding for each parameter
  4547. DBPARAMS* m_pParams;
  4548. BYTE* m_pBuffer;
  4549. };
  4550. ///////////////////////////////////////////////////////////////////////////
  4551. // CColumnAccessor
  4552. class CColumnAccessor : public CAccessorBase
  4553. {
  4554. public:
  4555. CColumnAccessor()
  4556. {
  4557. m_pParamInfo = NULL;
  4558. }
  4559. ~CColumnAccessor()
  4560. {
  4561. delete m_pParamInfo;
  4562. }
  4563. // pUnk is the interface the accessor will be created upon
  4564. HRESULT CreateAccessor(IUnknown* pUnk, DBORDINAL nOrdinal, DBTYPE wType, DBLENGTH nColumnSize,
  4565. BYTE nPrecision, BYTE nScale, void* pData) throw()
  4566. {
  4567. nPrecision;
  4568. nScale;
  4569. ATLASSERT(pUnk != NULL);
  4570. DBBINDING binding;
  4571. // REVIEW: This will change when we have a separate buffer for each accessor
  4572. Bind(&binding, nOrdinal, wType, nColumnSize, 0, 0, DBPARAMIO_NOTPARAM,
  4573. (BYTE*)pData - m_pBuffer);
  4574. CComPtr<IAccessor> spAccessor;
  4575. HRESULT hr = pUnk->QueryInterface(&spAccessor);
  4576. if (FAILED(hr))
  4577. return hr;
  4578. // Add another accessor info structure
  4579. AddAccessorInfo();
  4580. // REVIEW: I suppose I could add the new accessor at the beginning
  4581. _ATL_ACCESSOR_INFO* pAccessorInfo = m_pAccessorInfo + m_nAccessors - 1;
  4582. pAccessorInfo->bAutoAccessor = true; // Always auto
  4583. // Bind it
  4584. return BindEntries(&binding, 1, &pAccessorInfo->hAccessor, nColumnSize, spAccessor);
  4585. }
  4586. // Bind columns doesn't have to do anything here as we bind each accessor when
  4587. // CreateAccessor is called
  4588. HRESULT BindColumns(IUnknown*) throw()
  4589. {
  4590. return S_OK;
  4591. }
  4592. HRESULT SetParameterBuffer(BYTE* pBuffer) throw()
  4593. {
  4594. // This should only be called once.
  4595. ATLASSERT(m_pParamInfo == NULL);
  4596. ATLTRY(m_pParamInfo = new _ATL_COLUMN_PARAM_INFO);
  4597. if (m_pParamInfo == NULL)
  4598. return E_OUTOFMEMORY;
  4599. m_pParamInfo->m_pBuffer = pBuffer;
  4600. return S_OK;
  4601. }
  4602. HRESULT AddParameter(DBPARAMIO paramio, DBORDINAL nOrdinal, DBTYPE wType, DBLENGTH nColumnSize,
  4603. BYTE /* nPrecision*/, BYTE /* nScale */, void* pData) throw()
  4604. {
  4605. ATLASSERT(m_pParamInfo != NULL);
  4606. DBBINDING binding;
  4607. // REVIEW: This will change when we have a separate buffer for each accessor
  4608. Bind(&binding, nOrdinal, wType, nColumnSize, 0, 0, paramio,
  4609. (BYTE*)pData - m_pParamInfo->m_pBuffer);
  4610. if (m_pParamInfo->AddBinding(binding) == FALSE)
  4611. return E_OUTOFMEMORY;
  4612. return S_OK;
  4613. }
  4614. bool HasOutputColumns() throw()
  4615. {
  4616. // REVIEW: This probably won't always be true
  4617. return true;
  4618. }
  4619. bool HasParameters() const throw()
  4620. {
  4621. return (m_pParamInfo != NULL) ? true : false;
  4622. }
  4623. // Called to bind the parameters created
  4624. HRESULT BindParameters(HACCESSOR* pHAccessor, ICommand* pCommand, void** ppParameterBuffer)
  4625. {
  4626. ATLASSERT(m_pParamInfo != NULL);
  4627. HRESULT hr = S_OK;
  4628. // Only bind the parameters if we haven't already done it
  4629. if (*pHAccessor == NULL)
  4630. {
  4631. // Get the IAccessor from the passed ICommand
  4632. CComPtr<IAccessor> spAccessor;
  4633. ATLASSERT(pCommand != NULL);
  4634. hr = pCommand->QueryInterface(&spAccessor);
  4635. if (SUCCEEDED(hr))
  4636. {
  4637. *ppParameterBuffer = m_pParamInfo->m_pBuffer;
  4638. // REVIEW: size isn't being passed here
  4639. hr = BindEntries(&m_pParamInfo->m_rgBinding[0], m_pParamInfo->m_rgBinding.GetSize(),
  4640. pHAccessor, 4, spAccessor);
  4641. }
  4642. }
  4643. return hr;
  4644. }
  4645. // Implementation
  4646. typedef CColumnAccessor _ParamClass;
  4647. typedef CColumnAccessor _OutputColumnsClass;
  4648. HRESULT AddAccessorInfo() throw()
  4649. {
  4650. _ATL_ACCESSOR_INFO* pAccessorInfo = NULL;
  4651. ATLTRY( pAccessorInfo = new _ATL_ACCESSOR_INFO[m_nAccessors + 1]; )
  4652. if (pAccessorInfo == NULL)
  4653. return E_OUTOFMEMORY;
  4654. // Now copy the current accessor information to the new buffer
  4655. memcpy(pAccessorInfo, m_pAccessorInfo, sizeof(_ATL_ACCESSOR_INFO) * m_nAccessors);
  4656. m_nAccessors++;
  4657. // Now delete the old memory and use the new one
  4658. delete [] m_pAccessorInfo;
  4659. m_pAccessorInfo = pAccessorInfo;
  4660. return S_OK;
  4661. }
  4662. _ATL_COLUMN_PARAM_INFO* m_pParamInfo;
  4663. };
  4664. ///////////////////////////////////////////////////////////////////////////
  4665. // CAccessorRowset
  4666. template <class TAccessor = CNoAccessor, template <typename T> class TRowset = CRowset>
  4667. class CAccessorRowset :
  4668. public TAccessor,
  4669. public TRowset<TAccessor>
  4670. {
  4671. public:
  4672. CAccessorRowset()
  4673. {
  4674. // Give the rowset a pointer to the accessor
  4675. __if_exists(m_nAccessors)
  4676. {
  4677. SetAccessor(this);
  4678. }
  4679. }
  4680. ~CAccessorRowset()
  4681. {
  4682. Close();
  4683. }
  4684. // Used to get the column information from the opened rowset. The user is responsible
  4685. // for freeing the returned column information and string buffer.
  4686. HRESULT GetColumnInfo(DBORDINAL* pulColumns,
  4687. DBCOLUMNINFO** ppColumnInfo, LPOLESTR* ppStrings) const throw()
  4688. {
  4689. if (ppColumnInfo == NULL || pulColumns == NULL || ppStrings == NULL)
  4690. return E_POINTER;
  4691. ATLASSERT(GetInterface() != NULL);
  4692. if (GetInterface() == NULL)
  4693. return E_FAIL;
  4694. CComPtr<IColumnsInfo> spColumns;
  4695. HRESULT hr = GetInterface()->QueryInterface(&spColumns);
  4696. if (SUCCEEDED(hr))
  4697. hr = spColumns->GetColumnInfo(pulColumns, ppColumnInfo, ppStrings);
  4698. return hr;
  4699. }
  4700. // Used to get the column information when overriding the bindings using CDynamicAccessor
  4701. // The user should CoTaskMemFree the column information pointer that is returned.
  4702. HRESULT GetColumnInfo(DBORDINAL* pColumns, DBCOLUMNINFO** ppColumnInfo) throw()
  4703. {
  4704. // If you get a compilation here, then you are most likely calling this function
  4705. // from a class that is not using CDynamicAccessor.
  4706. ATLASSERT(GetInterface() != NULL);
  4707. if (GetInterface() == NULL)
  4708. return E_FAIL;
  4709. return TAccessor::GetColumnInfo(GetInterface(), pColumns, ppColumnInfo);
  4710. }
  4711. // Call to bind the output columns
  4712. HRESULT Bind() throw()
  4713. {
  4714. // Bind should only be called when we've successfully opened the rowset
  4715. ATLASSERT(GetInterface() != NULL);
  4716. if (GetInterface() == NULL)
  4717. return E_FAIL;
  4718. HRESULT hr = TAccessor::BindColumns(GetInterface());
  4719. if (SUCCEEDED(hr))
  4720. hr = BindFinished();
  4721. return hr;
  4722. }
  4723. // Close the opened rowset and release the created accessors for the output columns
  4724. void Close() throw()
  4725. {
  4726. if (GetInterface() != NULL)
  4727. {
  4728. ReleaseAccessors(GetInterface());
  4729. TAccessor::Close();
  4730. TRowset<TAccessor>::Close();
  4731. }
  4732. }
  4733. // Free's any columns in the current record that need to be freed.
  4734. // E.g. Calls SysFreeString on any BSTR's and Release on any interfaces.
  4735. void FreeRecordMemory() throw()
  4736. {
  4737. TAccessor::FreeRecordMemory(m_spRowset);
  4738. }
  4739. void FreeRecordMemory(int nAccessor) throw()
  4740. {
  4741. TAccessor::FreeRecordMemory(nAccessor, m_spRowset);
  4742. }
  4743. };
  4744. ///////////////////////////////////////////////////////////////////////////
  4745. // class CEnumeratorAccessor
  4746. class CEnumeratorAccessor
  4747. {
  4748. public:
  4749. WCHAR m_szName[129];
  4750. WCHAR m_szParseName[129];
  4751. WCHAR m_szDescription[129];
  4752. USHORT m_nType;
  4753. VARIANT_BOOL m_bIsParent;
  4754. // Binding Maps
  4755. BEGIN_COLUMN_MAP(CEnumeratorAccessor)
  4756. COLUMN_ENTRY(1, m_szName)
  4757. COLUMN_ENTRY(2, m_szParseName)
  4758. COLUMN_ENTRY(3, m_szDescription)
  4759. COLUMN_ENTRY(4, m_nType)
  4760. COLUMN_ENTRY(5, m_bIsParent)
  4761. END_COLUMN_MAP()
  4762. };
  4763. ///////////////////////////////////////////////////////////////////////////
  4764. // class CEnumerator
  4765. class CEnumerator : public CAccessorRowset<CAccessor<CEnumeratorAccessor> >
  4766. {
  4767. public:
  4768. HRESULT Open(LPMONIKER pMoniker) throw()
  4769. {
  4770. if (pMoniker == NULL)
  4771. return E_FAIL;
  4772. // Bind the moniker for the sources rowset
  4773. if (FAILED(BindMoniker(pMoniker, 0, __uuidof(ISourcesRowset),
  4774. (void**)&m_spSourcesRowset)))
  4775. return E_FAIL;
  4776. // Enumerate the data sources
  4777. if (FAILED(m_spSourcesRowset->GetSourcesRowset(NULL, __uuidof(IRowset), 0,
  4778. NULL, (IUnknown**)&m_spRowset)))
  4779. return E_FAIL;
  4780. return Bind();
  4781. }
  4782. HRESULT Open(const CEnumerator& enumerator) throw()
  4783. {
  4784. HRESULT hr;
  4785. CComPtr<IMoniker> spMoniker;
  4786. hr = enumerator.GetMoniker(&spMoniker);
  4787. if (FAILED(hr))
  4788. return hr;
  4789. return Open(spMoniker);
  4790. }
  4791. HRESULT Open(const CLSID* pClsid = &CLSID_OLEDB_ENUMERATOR) throw()
  4792. {
  4793. if (pClsid == NULL)
  4794. return E_FAIL;
  4795. HRESULT hr;
  4796. // Create the enumerator
  4797. hr = CoCreateInstance(*pClsid, NULL, CLSCTX_INPROC_SERVER,
  4798. __uuidof(ISourcesRowset), (LPVOID*)&m_spSourcesRowset);
  4799. if (FAILED(hr))
  4800. return hr;
  4801. // Get the rowset so we can enumerate the data sources
  4802. hr = m_spSourcesRowset->GetSourcesRowset(NULL, __uuidof(IRowset), 0,
  4803. NULL, (IUnknown**)&m_spRowset);
  4804. if (FAILED(hr))
  4805. return hr;
  4806. return Bind();
  4807. }
  4808. void Close() throw()
  4809. {
  4810. // Close the rowset pointer
  4811. if (m_spSourcesRowset != NULL)
  4812. m_spSourcesRowset.Release();
  4813. // Close the base class pointers
  4814. CAccessorRowset<CAccessor<CEnumeratorAccessor> >::Close();
  4815. }
  4816. HRESULT GetMoniker(LPMONIKER* ppMoniker) const throw()
  4817. {
  4818. CComPtr<IParseDisplayName> spParse;
  4819. HRESULT hr;
  4820. ULONG chEaten;
  4821. if (ppMoniker == NULL)
  4822. return E_POINTER;
  4823. if (m_spSourcesRowset == NULL)
  4824. return E_FAIL;
  4825. hr = m_spSourcesRowset->QueryInterface(__uuidof(IParseDisplayName), (void**)&spParse);
  4826. if (FAILED(hr))
  4827. return hr;
  4828. hr = spParse->ParseDisplayName(NULL, (LPOLESTR)m_szParseName,
  4829. &chEaten, ppMoniker);
  4830. return hr;
  4831. }
  4832. HRESULT GetMoniker(LPMONIKER* ppMoniker, LPCTSTR lpszDisplayName) const throw()
  4833. {
  4834. USES_CONVERSION;
  4835. CComPtr<IParseDisplayName> spParse;
  4836. HRESULT hr;
  4837. ULONG chEaten;
  4838. if (ppMoniker == NULL || lpszDisplayName == NULL)
  4839. return E_POINTER;
  4840. if (m_spSourcesRowset == NULL)
  4841. return E_FAIL;
  4842. hr = m_spSourcesRowset->QueryInterface(__uuidof(IParseDisplayName), (void**)&spParse);
  4843. if (FAILED(hr))
  4844. return hr;
  4845. hr = spParse->ParseDisplayName(NULL, (LPOLESTR)T2COLE(lpszDisplayName),
  4846. &chEaten, ppMoniker);
  4847. return hr;
  4848. }
  4849. bool Find(TCHAR* szSearchName) throw()
  4850. {
  4851. USES_CONVERSION;
  4852. // Loop through the providers looking for the passed name
  4853. while (MoveNext()==S_OK && lstrcmp(W2T(m_szName), szSearchName))
  4854. ATLTRACE(atlTraceDBClient, 2, _T("%s, %s, %d\n"), m_szName, m_szParseName, m_nType);
  4855. if (lstrcmp(W2T(m_szName), szSearchName))
  4856. return false;
  4857. else
  4858. return true;
  4859. }
  4860. CComPtr<ISourcesRowset> m_spSourcesRowset;
  4861. };
  4862. ///////////////////////////////////////////////////////////////////////////
  4863. // CDataSource
  4864. class CDataSource
  4865. {
  4866. public:
  4867. HRESULT Open(const CLSID& clsid, DBPROPSET* pPropSet = NULL, ULONG nPropertySets=1) throw()
  4868. {
  4869. HRESULT hr;
  4870. m_spInit.Release();
  4871. hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, __uuidof(IDBInitialize),
  4872. (void**)&m_spInit);
  4873. if (FAILED(hr))
  4874. return hr;
  4875. // Initialize the provider
  4876. return OpenWithProperties(pPropSet, nPropertySets);
  4877. }
  4878. HRESULT Open(const CLSID& clsid, LPCTSTR pName, LPCTSTR pUserName = NULL,
  4879. LPCTSTR pPassword = NULL, long nInitMode = 0) throw()
  4880. {
  4881. HRESULT hr;
  4882. m_spInit.Release();
  4883. hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, __uuidof(IDBInitialize),
  4884. (void**)&m_spInit);
  4885. if (FAILED(hr))
  4886. return hr;
  4887. return OpenWithNameUserPassword(pName, pUserName, pPassword, nInitMode);
  4888. }
  4889. HRESULT Open(LPCSTR szProgID, DBPROPSET* pPropSet = NULL, ULONG nPropertySets=1) throw()
  4890. {
  4891. USES_CONVERSION;
  4892. HRESULT hr;
  4893. CLSID clsid;
  4894. hr = CLSIDFromProgID(A2COLE(szProgID), &clsid);
  4895. if (FAILED(hr))
  4896. return hr;
  4897. return Open(clsid, pPropSet, nPropertySets);
  4898. }
  4899. HRESULT Open(LPCWSTR szProgID, LPCTSTR pName, LPCTSTR pUserName = NULL,
  4900. LPCTSTR pPassword = NULL, long nInitMode = 0) throw()
  4901. {
  4902. HRESULT hr;
  4903. CLSID clsid;
  4904. hr = CLSIDFromProgID(szProgID, &clsid);
  4905. if (FAILED(hr))
  4906. return hr;
  4907. return Open(clsid, pName, pUserName, pPassword, nInitMode);
  4908. }
  4909. HRESULT Open(LPCWSTR szProgID, DBPROPSET* pPropSet = NULL, ULONG nPropertySets=1) throw()
  4910. {
  4911. HRESULT hr;
  4912. CLSID clsid;
  4913. hr = CLSIDFromProgID(szProgID, &clsid);
  4914. if (FAILED(hr))
  4915. return hr;
  4916. return Open(clsid, pPropSet, nPropertySets);
  4917. }
  4918. HRESULT Open(LPCSTR szProgID, LPCTSTR pName, LPCTSTR pUserName = NULL,
  4919. LPCTSTR pPassword = NULL, long nInitMode = 0) throw()
  4920. {
  4921. USES_CONVERSION;
  4922. HRESULT hr;
  4923. CLSID clsid;
  4924. hr = CLSIDFromProgID(A2COLE(szProgID), &clsid);
  4925. if (FAILED(hr))
  4926. return hr;
  4927. return Open(clsid, pName, pUserName, pPassword, nInitMode);
  4928. }
  4929. HRESULT Open(const CEnumerator& enumerator, DBPROPSET* pPropSet = NULL, ULONG nPropertySets=1) throw()
  4930. {
  4931. CComPtr<IMoniker> spMoniker;
  4932. HRESULT hr;
  4933. hr = enumerator.GetMoniker(&spMoniker);
  4934. if (FAILED(hr))
  4935. return hr;
  4936. m_spInit.Release();
  4937. // Now bind the moniker
  4938. hr = BindMoniker(spMoniker, 0, __uuidof(IDBInitialize), (void**)&m_spInit);
  4939. if (FAILED(hr))
  4940. return hr;
  4941. return OpenWithProperties(pPropSet, nPropertySets);
  4942. }
  4943. HRESULT Open(const CEnumerator& enumerator, LPCTSTR pName, LPCTSTR pUserName = NULL,
  4944. LPCTSTR pPassword = NULL, long nInitMode = 0) throw()
  4945. {
  4946. CComPtr<IMoniker> spMoniker;
  4947. HRESULT hr;
  4948. hr = enumerator.GetMoniker(&spMoniker);
  4949. if (FAILED(hr))
  4950. return hr;
  4951. m_spInit.Release();
  4952. // Now bind the moniker
  4953. hr = BindMoniker(spMoniker, 0, __uuidof(IDBInitialize), (void**)&m_spInit);
  4954. if (FAILED(hr))
  4955. return hr;
  4956. return OpenWithNameUserPassword(pName, pUserName, pPassword, nInitMode);
  4957. }
  4958. // Invoke the data links dialog and open the selected database
  4959. HRESULT Open(HWND hWnd = GetActiveWindow(), DBPROMPTOPTIONS dwPromptOptions = DBPROMPTOPTIONS_WIZARDSHEET) throw()
  4960. {
  4961. CComPtr<IDBPromptInitialize> spDBInit;
  4962. HRESULT hr = CoCreateInstance(__uuidof(DataLinks), NULL, CLSCTX_INPROC_SERVER,
  4963. __uuidof(IDBPromptInitialize), (void**) &spDBInit);
  4964. if (FAILED(hr))
  4965. return hr;
  4966. CComPtr<IDBProperties> spIDBProperties;
  4967. hr = spDBInit->PromptDataSource(NULL, hWnd, dwPromptOptions, 0, NULL, NULL,
  4968. __uuidof(IDBProperties), (IUnknown**)&spIDBProperties);
  4969. if (hr == S_OK)
  4970. {
  4971. hr = spIDBProperties->QueryInterface(&m_spInit);
  4972. if (SUCCEEDED(hr))
  4973. hr = m_spInit->Initialize();
  4974. }
  4975. return hr;
  4976. }
  4977. // Opens a data source using the service components
  4978. HRESULT OpenWithServiceComponents(const CLSID& clsid, DBPROPSET* pPropSet = NULL, ULONG nPropertySets=1) throw()
  4979. {
  4980. CComPtr<IDataInitialize> spDataInit;
  4981. HRESULT hr;
  4982. hr = CoCreateInstance(__uuidof(MSDAINITIALIZE), NULL, CLSCTX_INPROC_SERVER,
  4983. __uuidof(IDataInitialize), (void**)&spDataInit);
  4984. if (FAILED(hr))
  4985. return hr;
  4986. m_spInit.Release();
  4987. hr = spDataInit->CreateDBInstance(clsid, NULL, CLSCTX_INPROC_SERVER, NULL,
  4988. __uuidof(IDBInitialize), (IUnknown**)&m_spInit);
  4989. if (FAILED(hr))
  4990. return hr;
  4991. // Initialize the provider
  4992. return OpenWithProperties(pPropSet, nPropertySets);
  4993. }
  4994. // Opens a data source using the service components
  4995. HRESULT OpenWithServiceComponents(LPCTSTR szProgID, DBPROPSET* pPropSet = NULL, ULONG nPropertySets=1) throw()
  4996. {
  4997. USES_CONVERSION;
  4998. HRESULT hr;
  4999. CLSID clsid;
  5000. hr = CLSIDFromProgID(T2COLE(szProgID), &clsid);
  5001. if (FAILED(hr))
  5002. return hr;
  5003. return OpenWithServiceComponents(clsid, pPropSet, nPropertySets);
  5004. }
  5005. // Bring up the "Organize Dialog" which allows the user to select a previously created data link
  5006. // file (.UDL file). The selected file will be used to open the datbase.
  5007. HRESULT OpenWithPromptFileName(HWND hWnd = GetActiveWindow(), DBPROMPTOPTIONS dwPromptOptions = DBPROMPTOPTIONS_NONE,
  5008. LPCOLESTR szInitialDirectory = NULL) throw()
  5009. {
  5010. USES_CONVERSION;
  5011. CComPtr<IDBPromptInitialize> spDBInit;
  5012. HRESULT hr = CoCreateInstance(__uuidof(DataLinks), NULL, CLSCTX_INPROC_SERVER,
  5013. __uuidof(IDBPromptInitialize), (void**) &spDBInit);
  5014. if (FAILED(hr))
  5015. return hr;
  5016. CComPtr<IDBProperties> spIDBProperties;
  5017. LPOLESTR szSelected;
  5018. hr = spDBInit->PromptFileName(hWnd, dwPromptOptions, szInitialDirectory, L"*.udl", &szSelected);
  5019. if (hr == S_OK)
  5020. hr = OpenFromFileName(szSelected);
  5021. else if (hr == S_FALSE)
  5022. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_CANCELLED); // The user clicked cancel
  5023. return hr;
  5024. }
  5025. // Open the datasource specified by the passed filename, typically a .UDL file
  5026. HRESULT OpenFromFileName(LPCOLESTR szFileName) throw()
  5027. {
  5028. CComPtr<IDataInitialize> spDataInit;
  5029. CComHeapPtr<OLECHAR> spszInitString;
  5030. HRESULT hr = CoCreateInstance(__uuidof(MSDAINITIALIZE), NULL, CLSCTX_INPROC_SERVER,
  5031. __uuidof(IDataInitialize), (void**)&spDataInit);
  5032. if (FAILED(hr))
  5033. return hr;
  5034. hr = spDataInit->LoadStringFromStorage(szFileName, &spszInitString);
  5035. if (FAILED(hr))
  5036. return hr;
  5037. return OpenFromInitializationString(spszInitString);
  5038. }
  5039. // Open the datasource specified by the passed initialization string
  5040. HRESULT OpenFromInitializationString(LPCOLESTR szInitializationString, bool fPromptForInfo = false) throw()
  5041. {
  5042. CComPtr<IDataInitialize> spDataInit;
  5043. HRESULT hr = CoCreateInstance(__uuidof(MSDAINITIALIZE), NULL, CLSCTX_INPROC_SERVER,
  5044. __uuidof(IDataInitialize), (void**)&spDataInit);
  5045. if (FAILED(hr))
  5046. return hr;
  5047. CComPtr<IDBProperties> spIDBProperties;
  5048. hr = spDataInit->GetDataSource(NULL, CLSCTX_INPROC_SERVER, szInitializationString,
  5049. __uuidof(IDBInitialize), (IUnknown**)&m_spInit);
  5050. if (FAILED(hr))
  5051. return hr;
  5052. if( fPromptForInfo )
  5053. {
  5054. CComPtr<IDBProperties> spIDBProperties;
  5055. hr = m_spInit->QueryInterface( &spIDBProperties );
  5056. DBPROP rgProperties[1];
  5057. DBPROPSET rgPropertySets[1];
  5058. VariantInit(&rgProperties[1].vValue);
  5059. rgProperties[0].dwOptions = DBPROPOPTIONS_REQUIRED;
  5060. rgProperties[0].colid = DB_NULLID;
  5061. rgProperties[0].dwPropertyID = DBPROP_INIT_PROMPT;
  5062. rgProperties[0].vValue.vt = VT_I2;
  5063. rgProperties[0].vValue.lVal = DBPROMPT_COMPLETEREQUIRED;
  5064. rgPropertySets[0].rgProperties = rgProperties;
  5065. rgPropertySets[0].cProperties = 1;
  5066. rgPropertySets[0].guidPropertySet = DBPROPSET_DBINIT;
  5067. hr = spIDBProperties->SetProperties( 1, rgPropertySets );
  5068. if (FAILED(hr))
  5069. return hr;
  5070. }
  5071. return m_spInit->Initialize();
  5072. }
  5073. // Get the initialization string from the currently open data source. The returned string
  5074. // must be CoTaskMemFree'd when finished with.
  5075. HRESULT GetInitializationString(BSTR* pInitializationString, bool bIncludePassword=false) throw()
  5076. {
  5077. // If the datasource isn't open then we're not going to get an init string
  5078. ATLASSERT(m_spInit != NULL);
  5079. CComPtr<IDataInitialize> spDataInit;
  5080. LPOLESTR szInitString;
  5081. HRESULT hr = CoCreateInstance(__uuidof(MSDAINITIALIZE), NULL, CLSCTX_INPROC_SERVER,
  5082. __uuidof(IDataInitialize), (void**)&spDataInit);
  5083. if (FAILED(hr))
  5084. return hr;
  5085. hr = spDataInit->GetInitializationString(m_spInit, bIncludePassword, &szInitString);
  5086. if (SUCCEEDED(hr))
  5087. {
  5088. *pInitializationString = ::SysAllocString(szInitString);
  5089. if (*pInitializationString == NULL && szInitString != NULL)
  5090. hr = E_OUTOFMEMORY;
  5091. CoTaskMemFree(szInitString);
  5092. }
  5093. return hr;
  5094. }
  5095. HRESULT GetProperties(ULONG ulPropIDSets, const DBPROPIDSET* pPropIDSet,
  5096. ULONG* pulPropertySets, DBPROPSET** ppPropsets) const throw()
  5097. {
  5098. CComPtr<IDBProperties> spProperties;
  5099. // Check that we are connected
  5100. ATLASSERT(m_spInit != NULL);
  5101. HRESULT hr = m_spInit->QueryInterface(__uuidof(IDBProperties), (void**)&spProperties);
  5102. if (FAILED(hr))
  5103. return hr;
  5104. hr = spProperties->GetProperties(ulPropIDSets, pPropIDSet, pulPropertySets,
  5105. ppPropsets);
  5106. return hr;
  5107. }
  5108. HRESULT GetProperty(const GUID& guid, DBPROPID propid, VARIANT* pVariant) const throw()
  5109. {
  5110. ATLASSERT(pVariant != NULL);
  5111. CComPtr<IDBProperties> spProperties;
  5112. // Check that we are connected
  5113. ATLASSERT(m_spInit != NULL);
  5114. HRESULT hr = m_spInit->QueryInterface(__uuidof(IDBProperties), (void**)&spProperties);
  5115. if (FAILED(hr))
  5116. return hr;
  5117. CDBPropIDSet set(guid);
  5118. set.AddPropertyID(propid);
  5119. CComHeapPtr<DBPROPSET> spPropSet;
  5120. ULONG ulPropSet = 0;
  5121. hr = spProperties->GetProperties(1, &set, &ulPropSet, &spPropSet);
  5122. if (FAILED(hr))
  5123. return hr;
  5124. ATLASSERT(ulPropSet == 1);
  5125. VariantCopy(pVariant, &(spPropSet->rgProperties[0].vValue));
  5126. VariantClear(&(spPropSet->rgProperties[0].vValue));
  5127. CoTaskMemFree(spPropSet->rgProperties);
  5128. return S_OK;
  5129. }
  5130. void Close() throw()
  5131. {
  5132. m_spInit.Release();
  5133. }
  5134. // Implementation
  5135. HRESULT OpenFromIDBProperties(IDBProperties* pIDBProperties) throw()
  5136. {
  5137. CComPtr<IPersist> spPersist;
  5138. CLSID clsid;
  5139. HRESULT hr;
  5140. hr = pIDBProperties->QueryInterface(__uuidof(IPersist), (void**)&spPersist);
  5141. if (FAILED(hr))
  5142. return hr;
  5143. spPersist->GetClassID(&clsid);
  5144. ULONG ulPropSets=0;
  5145. CDBPropSet* pPropSets=NULL;
  5146. pIDBProperties->GetProperties(0, NULL, &ulPropSets, (DBPROPSET**)&pPropSets);
  5147. hr = Open(clsid, &pPropSets[0], ulPropSets);
  5148. for (ULONG i=0; i < ulPropSets; i++)
  5149. (pPropSets+i)->~CDBPropSet();
  5150. CoTaskMemFree(pPropSets);
  5151. return hr;
  5152. }
  5153. HRESULT OpenWithNameUserPassword(LPCTSTR pName, LPCTSTR pUserName, LPCTSTR pPassword, long nInitMode = 0) throw()
  5154. {
  5155. ATLASSERT(m_spInit != NULL);
  5156. CComPtr<IDBProperties> spProperties;
  5157. HRESULT hr;
  5158. hr = m_spInit->QueryInterface(__uuidof(IDBProperties), (void**)&spProperties);
  5159. if (FAILED(hr))
  5160. return hr;
  5161. // Set connection properties
  5162. CDBPropSet propSet(DBPROPSET_DBINIT);
  5163. // Add Datbase name, User name and Password
  5164. if (pName != NULL)
  5165. propSet.AddProperty(DBPROP_INIT_DATASOURCE, pName);
  5166. if (pUserName != NULL)
  5167. propSet.AddProperty(DBPROP_AUTH_USERID, pUserName);
  5168. if (pPassword != NULL)
  5169. propSet.AddProperty(DBPROP_AUTH_PASSWORD, pPassword);
  5170. if (nInitMode)
  5171. propSet.AddProperty(DBPROP_INIT_MODE, nInitMode);
  5172. hr = spProperties->SetProperties(1, &propSet);
  5173. if (FAILED(hr))
  5174. return hr;
  5175. // Initialize the provider
  5176. return m_spInit->Initialize();
  5177. }
  5178. HRESULT OpenWithProperties(DBPROPSET* pPropSet, ULONG nPropertySets=1) throw()
  5179. {
  5180. ATLASSERT(m_spInit != NULL);
  5181. // Set the properties if there are some to set
  5182. if (pPropSet != NULL)
  5183. {
  5184. CComPtr<IDBProperties> spProperties;
  5185. HRESULT hr;
  5186. hr = m_spInit->QueryInterface(__uuidof(IDBProperties), (void**)&spProperties);
  5187. if (FAILED(hr))
  5188. return hr;
  5189. hr = spProperties->SetProperties(nPropertySets, pPropSet);
  5190. if (FAILED(hr))
  5191. return hr;
  5192. }
  5193. // Initialize the provider
  5194. return m_spInit->Initialize();
  5195. }
  5196. CComPtr<IDBInitialize> m_spInit;
  5197. };
  5198. ///////////////////////////////////////////////////////////////////////////
  5199. // class CSession
  5200. class CSession
  5201. {
  5202. public:
  5203. ~CSession()
  5204. {
  5205. Close();
  5206. }
  5207. // Create a session on the passed datasource
  5208. HRESULT Open(const CDataSource& ds, DBPROPSET *pPropSet = NULL, ULONG ulPropSets = 0) throw()
  5209. {
  5210. CComPtr<IDBCreateSession> spSession;
  5211. // Check we have connected to the database
  5212. ATLASSERT(ds.m_spInit != NULL);
  5213. HRESULT hr = ds.m_spInit->QueryInterface(__uuidof(IDBCreateSession), (void**)&spSession);
  5214. if (FAILED(hr))
  5215. return hr;
  5216. hr = spSession->CreateSession(NULL, __uuidof(IOpenRowset), (IUnknown**)&m_spOpenRowset);
  5217. if( pPropSet != NULL && SUCCEEDED(hr) && m_spOpenRowset != NULL )
  5218. {
  5219. // If the user didn't specify the default parameter, use one
  5220. if (pPropSet != NULL && ulPropSets == 0)
  5221. ulPropSets = 1;
  5222. CComPtr<ISessionProperties> spSessionProperties;
  5223. hr = m_spOpenRowset->QueryInterface(__uuidof(ISessionProperties), (void**)&spSessionProperties);
  5224. if(FAILED(hr))
  5225. return hr;
  5226. hr = spSessionProperties->SetProperties( ulPropSets, pPropSet );
  5227. }
  5228. return hr;
  5229. }
  5230. // Close the session
  5231. void Close() throw()
  5232. {
  5233. m_spOpenRowset.Release();
  5234. }
  5235. // Start a transaction
  5236. HRESULT StartTransaction(ISOLEVEL isoLevel = ISOLATIONLEVEL_READCOMMITTED, ULONG isoFlags = 0,
  5237. ITransactionOptions* pOtherOptions = NULL, ULONG* pulTransactionLevel = NULL) const throw()
  5238. {
  5239. ATLASSERT(m_spOpenRowset != NULL);
  5240. CComPtr<ITransactionLocal> spTransactionLocal;
  5241. HRESULT hr = m_spOpenRowset->QueryInterface(&spTransactionLocal);
  5242. if (SUCCEEDED(hr))
  5243. hr = spTransactionLocal->StartTransaction(isoLevel, isoFlags, pOtherOptions, pulTransactionLevel);
  5244. return hr;
  5245. }
  5246. // Abort the current transaction
  5247. HRESULT Abort(BOID* pboidReason = NULL, BOOL bRetaining = FALSE, BOOL bAsync = FALSE) const throw()
  5248. {
  5249. ATLASSERT(m_spOpenRowset != NULL);
  5250. CComPtr<ITransaction> spTransaction;
  5251. HRESULT hr = m_spOpenRowset->QueryInterface(&spTransaction);
  5252. if (SUCCEEDED(hr))
  5253. hr = spTransaction->Abort(pboidReason, bRetaining, bAsync);
  5254. return hr;
  5255. }
  5256. // Commit the current transaction
  5257. HRESULT Commit(BOOL bRetaining = FALSE, DWORD grfTC = XACTTC_SYNC, DWORD grfRM = 0) const throw()
  5258. {
  5259. ATLASSERT(m_spOpenRowset != NULL);
  5260. CComPtr<ITransaction> spTransaction;
  5261. HRESULT hr = m_spOpenRowset->QueryInterface(&spTransaction);
  5262. if (SUCCEEDED(hr))
  5263. hr = spTransaction->Commit(bRetaining, grfTC, grfRM);
  5264. return hr;
  5265. }
  5266. // Get information for the current transaction
  5267. HRESULT GetTransactionInfo(XACTTRANSINFO* pInfo) const throw()
  5268. {
  5269. ATLASSERT(m_spOpenRowset != NULL);
  5270. CComPtr<ITransaction> spTransaction;
  5271. HRESULT hr = m_spOpenRowset->QueryInterface(&spTransaction);
  5272. if (SUCCEEDED(hr))
  5273. hr = spTransaction->GetTransactionInfo(pInfo);
  5274. return hr;
  5275. }
  5276. // Implementation
  5277. CComPtr<IOpenRowset> m_spOpenRowset;
  5278. };
  5279. ///////////////////////////////////////////////////////////////////////////
  5280. // class CDataConnection
  5281. class CDataConnection
  5282. {
  5283. public:
  5284. CDataConnection()
  5285. {
  5286. }
  5287. CDataConnection(const CDataConnection &ds)
  5288. {
  5289. Copy(ds);
  5290. }
  5291. // for construction a CDataConnection with NULL
  5292. CDataConnection(int i)
  5293. {
  5294. ATLASSERT(i==NULL);
  5295. i;
  5296. }
  5297. CDataConnection& Copy(const CDataConnection &ds) throw()
  5298. {
  5299. m_source.m_spInit = ds.m_source.m_spInit;
  5300. m_session.m_spOpenRowset = ds.m_session.m_spOpenRowset;
  5301. return *this;
  5302. }
  5303. HRESULT Open(LPCOLESTR szInitString) throw()
  5304. {
  5305. HRESULT hr = E_FAIL;
  5306. hr = m_source.OpenFromInitializationString(szInitString);
  5307. if (hr == S_OK)
  5308. {
  5309. hr = m_session.Open(m_source);
  5310. }
  5311. return hr;
  5312. }
  5313. HRESULT OpenNewSession(CSession &session) throw()
  5314. {
  5315. return session.Open(m_source);
  5316. }
  5317. operator const CSession&() throw()
  5318. {
  5319. return m_session;
  5320. }
  5321. operator const CSession*() throw()
  5322. {
  5323. return &m_session;
  5324. }
  5325. operator const CDataSource&() throw()
  5326. {
  5327. return m_source;
  5328. }
  5329. operator const CDataSource*() throw()
  5330. {
  5331. return &m_source;
  5332. }
  5333. CDataConnection& operator=(const CDataConnection &ds) throw()
  5334. {
  5335. return Copy(ds);
  5336. }
  5337. // operator= is used for assignment of NULL to this object.
  5338. // No other integer value can be assigned to this object.
  5339. operator=(int i) throw()
  5340. {
  5341. ATLASSERT(i==NULL);
  5342. if (i == NULL)
  5343. m_session.Close();
  5344. }
  5345. operator BOOL() throw()
  5346. {
  5347. return m_session.m_spOpenRowset != NULL ? TRUE : FALSE;
  5348. }
  5349. operator bool() throw()
  5350. {
  5351. return m_session.m_spOpenRowset != NULL ? true : false;
  5352. }
  5353. void CloseDataSource() throw()
  5354. {
  5355. m_session.Close();
  5356. m_source.Close();
  5357. }
  5358. CSession m_session;
  5359. CDataSource m_source;
  5360. };
  5361. ///////////////////////////////////////////////////////////////////////////
  5362. // CTable
  5363. template <class TAccessor = CNoAccessor, template <typename T> class TRowset = CRowset>
  5364. class CTable : public CAccessorRowset<TAccessor, TRowset>
  5365. {
  5366. public:
  5367. // Open a rowset on the passed name
  5368. HRESULT Open(const CSession& session, LPCWSTR wszTableName, DBPROPSET* pPropSet = NULL,
  5369. ULONG ulPropSets = 0) throw()
  5370. {
  5371. DBID idTable;
  5372. idTable.eKind = DBKIND_NAME;
  5373. idTable.uName.pwszName = (LPOLESTR)wszTableName;
  5374. return Open(session, idTable, pPropSet, ulPropSets);
  5375. }
  5376. HRESULT Open(const CSession& session, LPCSTR szTableName, DBPROPSET* pPropSet = NULL,
  5377. ULONG ulPropSets = 0) throw()
  5378. {
  5379. USES_CONVERSION;
  5380. return Open( session, A2COLE(szTableName), pPropSet, ulPropSets );
  5381. }
  5382. // Open the a rowset on the passed DBID
  5383. HRESULT Open(const CSession& session, DBID& dbid, DBPROPSET* pPropSet = NULL,
  5384. ULONG ulPropSets = 0) throw()
  5385. {
  5386. // Check the session is valid
  5387. ATLASSERT(session.m_spOpenRowset != NULL);
  5388. HRESULT hr;
  5389. // If the user didn't specify the default parameter, use one for
  5390. // backward compatibility
  5391. if (pPropSet != NULL && ulPropSets == 0)
  5392. ulPropSets = 1;
  5393. hr = session.m_spOpenRowset->OpenRowset(NULL, &dbid, NULL, GetIID(),
  5394. ulPropSets, pPropSet, (IUnknown**)GetInterfacePtr());
  5395. if (SUCCEEDED(hr))
  5396. {
  5397. SetupOptionalRowsetInterfaces();
  5398. // If we have output columns then bind
  5399. if (_OutputColumnsClass::HasOutputColumns())
  5400. hr = Bind();
  5401. }
  5402. return hr;
  5403. }
  5404. };
  5405. #if (OLEDBVER < 0x0150)
  5406. #define DBGUID_DEFAULT DBGUID_DBSQL
  5407. #endif
  5408. ///////////////////////////////////////////////////////////////////////////
  5409. // CCommandBase
  5410. class CCommandBase
  5411. {
  5412. public:
  5413. CCommandBase()
  5414. {
  5415. m_hParameterAccessor = NULL;
  5416. }
  5417. ~CCommandBase()
  5418. {
  5419. ReleaseCommand();
  5420. }
  5421. // Create the command
  5422. HRESULT CreateCommand(const CSession& session) throw()
  5423. {
  5424. // Before creating the command, release the old one if necessary.
  5425. ReleaseCommand();
  5426. // Check the session is valid
  5427. ATLASSERT(session.m_spOpenRowset != NULL);
  5428. CComPtr<IDBCreateCommand> spCreateCommand;
  5429. HRESULT hr = session.m_spOpenRowset->QueryInterface(__uuidof(IDBCreateCommand), (void**)&spCreateCommand);
  5430. if (FAILED(hr))
  5431. return hr;
  5432. return spCreateCommand->CreateCommand(NULL, __uuidof(ICommand), (IUnknown**)&m_spCommand);
  5433. }
  5434. // Prepare the command
  5435. HRESULT Prepare(ULONG cExpectedRuns = 0) throw()
  5436. {
  5437. CComPtr<ICommandPrepare> spCommandPrepare;
  5438. HRESULT hr = m_spCommand->QueryInterface(&spCommandPrepare);
  5439. if (SUCCEEDED(hr))
  5440. hr = spCommandPrepare->Prepare(cExpectedRuns);
  5441. return hr;
  5442. }
  5443. // Unprepare the command
  5444. HRESULT Unprepare() throw()
  5445. {
  5446. CComPtr<ICommandPrepare> spCommandPrepare;
  5447. HRESULT hr = m_spCommand->QueryInterface(&spCommandPrepare);
  5448. if (SUCCEEDED(hr))
  5449. hr = spCommandPrepare->Unprepare();
  5450. return hr;
  5451. }
  5452. // Create the command and set the command text
  5453. HRESULT Create(const CSession& session, LPCWSTR wszCommand,
  5454. REFGUID guidCommand = DBGUID_DEFAULT) throw()
  5455. {
  5456. HRESULT hr;
  5457. hr = CreateCommand(session);
  5458. if (SUCCEEDED(hr))
  5459. {
  5460. CComPtr<ICommandText> spCommandText;
  5461. hr = m_spCommand->QueryInterface(&spCommandText);
  5462. if (SUCCEEDED(hr))
  5463. hr = spCommandText->SetCommandText(guidCommand, wszCommand);
  5464. }
  5465. return hr;
  5466. }
  5467. HRESULT Create(const CSession& session, LPCSTR szCommand,
  5468. REFGUID guidCommand = DBGUID_DEFAULT) throw()
  5469. {
  5470. USES_CONVERSION;
  5471. return Create( session, A2COLE(szCommand), guidCommand );
  5472. }
  5473. // Release the command
  5474. void ReleaseCommand() throw()
  5475. {
  5476. // Release the parameter accessor if necessary, before releasing the command
  5477. if (m_hParameterAccessor != NULL && m_spCommand != NULL )
  5478. {
  5479. CComPtr<IAccessor> spAccessor;
  5480. HRESULT hr = m_spCommand->QueryInterface(&spAccessor);
  5481. if (SUCCEEDED(hr))
  5482. {
  5483. spAccessor->ReleaseAccessor(m_hParameterAccessor, NULL); \
  5484. m_hParameterAccessor = NULL;
  5485. }
  5486. }
  5487. m_spCommand.Release();
  5488. }
  5489. // Get the parameter information from the command
  5490. HRESULT GetParameterInfo(DB_UPARAMS* pParams, DBPARAMINFO** ppParamInfo,
  5491. OLECHAR** ppNamesBuffer) throw()
  5492. {
  5493. CComPtr<ICommandWithParameters> spCommandParameters;
  5494. HRESULT hr = m_spCommand->QueryInterface(&spCommandParameters);
  5495. if (SUCCEEDED(hr))
  5496. {
  5497. // Get the parameter information
  5498. hr = spCommandParameters->GetParameterInfo(pParams, ppParamInfo,
  5499. ppNamesBuffer);
  5500. }
  5501. return hr;
  5502. }
  5503. // Set the parameter information for the command
  5504. HRESULT SetParameterInfo(DB_UPARAMS ulParams, const DBORDINAL* pOrdinals,
  5505. const DBPARAMBINDINFO* pParamInfo) throw()
  5506. {
  5507. CComPtr<ICommandWithParameters> spCommandParameters;
  5508. HRESULT hr = m_spCommand->QueryInterface(&spCommandParameters);
  5509. if (SUCCEEDED(hr))
  5510. {
  5511. // Set the parameter information
  5512. hr = spCommandParameters->SetParameterInfo(ulParams, pOrdinals,
  5513. pParamInfo);
  5514. }
  5515. return hr;
  5516. }
  5517. CComPtr<ICommand> m_spCommand;
  5518. HACCESSOR m_hParameterAccessor;
  5519. };
  5520. // Used to turn on multiple result set support in CCommand
  5521. class CMultipleResults
  5522. {
  5523. public:
  5524. bool UseMultipleResults() throw() { return true; }
  5525. IMultipleResults** GetMultiplePtrAddress() throw() { return &m_spMultipleResults.p; }
  5526. IMultipleResults* GetMultiplePtr() throw() { return m_spMultipleResults; }
  5527. CComPtr<IMultipleResults> m_spMultipleResults;
  5528. };
  5529. // Used to turn off multiple result set support in CCommand
  5530. class CNoMultipleResults
  5531. {
  5532. public:
  5533. bool UseMultipleResults() throw() { return false; }
  5534. IMultipleResults** GetMultiplePtrAddress() throw() { return NULL; }
  5535. IMultipleResults* GetMultiplePtr() throw() { return NULL; }
  5536. };
  5537. ///////////////////////////////////////////////////////////////////////////
  5538. // CCommand
  5539. template <class TAccessor = CNoAccessor, template <typename T> class TRowset = CRowset,
  5540. class TMultiple = CNoMultipleResults>
  5541. class CCommand :
  5542. public CAccessorRowset<TAccessor, TRowset>,
  5543. public CCommandBase,
  5544. public TMultiple
  5545. {
  5546. public:
  5547. // Create a command on the session and execute it
  5548. HRESULT Open(const CSession& session, LPCWSTR wszCommand,
  5549. DBPROPSET *pPropSet = NULL, LONG* pRowsAffected = NULL,
  5550. REFGUID guidCommand = DBGUID_DEFAULT, bool bBind = true,
  5551. ULONG ulPropSets = 0) throw()
  5552. {
  5553. HRESULT hr;
  5554. if (wszCommand == NULL)
  5555. {
  5556. hr = _CommandClass::GetDefaultCommand(&wszCommand);
  5557. if (FAILED(hr))
  5558. return hr;
  5559. }
  5560. hr = Create(session, wszCommand, guidCommand);
  5561. if (FAILED(hr))
  5562. return hr;
  5563. return Open(pPropSet, pRowsAffected, bBind, ulPropSets);
  5564. }
  5565. HRESULT Open(const CSession& session, LPCSTR szCommand,
  5566. DBPROPSET *pPropSet = NULL, LONG* pRowsAffected = NULL,
  5567. REFGUID guidCommand = DBGUID_DEFAULT, bool bBind = true,
  5568. ULONG ulPropSets = 0) throw()
  5569. {
  5570. USES_CONVERSION;
  5571. if( szCommand == NULL )
  5572. return Open( session, (LPCWSTR)NULL, pPropSet, pRowsAffected, guidCommand, bBind, ulPropSets );
  5573. else
  5574. return Open( session, A2COLE(szCommand), pPropSet, pRowsAffected, guidCommand, bBind, ulPropSets );
  5575. }
  5576. // this version of Open, takes an INT instead of a string pointer.
  5577. // this is to resolve an ambiguity when calling
  5578. // Open( session, NULL, ... ) or Open( session )
  5579. HRESULT Open(const CSession& session, INT szCommand = NULL,
  5580. DBPROPSET *pPropSet = NULL, LONG* pRowsAffected = NULL,
  5581. REFGUID guidCommand = DBGUID_DEFAULT, bool bBind = true,
  5582. ULONG ulPropSets = 0) throw()
  5583. {
  5584. szCommand;
  5585. ATLASSERT( szCommand == NULL );
  5586. return Open( session, (LPCWSTR)NULL, pPropSet, pRowsAffected, guidCommand, bBind, ulPropSets );
  5587. }
  5588. // Used if you have previously created the command
  5589. HRESULT Open(DBPROPSET *pPropSet = NULL, LONG* pRowsAffected = NULL,
  5590. bool bBind = true, ULONG ulPropSets = 0) throw()
  5591. {
  5592. HRESULT hr;
  5593. DBPARAMS params;
  5594. DBPARAMS *pParams;
  5595. // Bind the parameters if we have some
  5596. if (_ParamClass::HasParameters())
  5597. {
  5598. // Bind the parameters in the accessor if they haven't already been bound
  5599. hr = BindParameters(&m_hParameterAccessor, m_spCommand, &params.pData);
  5600. if (FAILED(hr))
  5601. return hr;
  5602. // Setup the DBPARAMS structure
  5603. params.cParamSets = 1;
  5604. params.hAccessor = m_hParameterAccessor;
  5605. pParams = &params;
  5606. }
  5607. else
  5608. pParams = NULL;
  5609. return ExecuteAndBind(pParams, pPropSet, pRowsAffected, bBind, ulPropSets);
  5610. }
  5611. // Get the next rowset when using multiple result sets
  5612. HRESULT GetNextResult(LONG* pulRowsAffected, bool bBind = true) throw()
  5613. {
  5614. // This function should only be called if CMultipleResults is being
  5615. // used as the third template parameter
  5616. ATLASSERT(GetMultiplePtrAddress() != NULL);
  5617. // If user calls GetNextResult but the interface is not available
  5618. // return E_FAIL.
  5619. if (GetMultiplePtr() == NULL)
  5620. return E_FAIL;
  5621. // Close the existing rowset in preparation for opening the next one
  5622. Close();
  5623. HRESULT hr = GetMultiplePtr()->GetResult(NULL, 0, GetIID(),
  5624. pulRowsAffected, (IUnknown**)GetInterfacePtr());
  5625. if (FAILED(hr))
  5626. return hr;
  5627. if (bBind && GetInterface() != NULL)
  5628. return Bind();
  5629. else
  5630. return hr;
  5631. }
  5632. // Implementation
  5633. HRESULT ExecuteAndBind(DBPARAMS* pParams, DBPROPSET* pPropSet = NULL,
  5634. LONG* pRowsAffected = NULL, bool bBind = true, ULONG ulPropSets = 0) throw()
  5635. {
  5636. HRESULT hr = Execute((IUnknown**)GetInterfacePtr(), pParams, pPropSet,
  5637. pRowsAffected, ulPropSets);
  5638. if (FAILED(hr))
  5639. return hr;
  5640. // Only bind if we have been asked to and we have output columns
  5641. if (bBind && _OutputColumnsClass::HasOutputColumns())
  5642. {
  5643. // for dynamic accessors we don't want to automatically call Bind if we got no rowset in return
  5644. if( NoBindOnNullRowset() && GetInterface() == NULL )
  5645. return hr;
  5646. else
  5647. return Bind();
  5648. }
  5649. else
  5650. return hr;
  5651. }
  5652. HRESULT Execute(IRowset** ppRowset, DBPARAMS* pParams, DBPROPSET *pPropSet,
  5653. LONG* pRowsAffected, ULONG ulPropSets = 0) throw()
  5654. {
  5655. return Execute( (IUnknown**)ppRowset, pParams, pPropSet, pRowsAffected, ulPropSets );
  5656. }
  5657. HRESULT Execute(IUnknown** ppInterface, DBPARAMS* pParams, DBPROPSET *pPropSet,
  5658. LONG* pRowsAffected, ULONG ulPropSets = 0) throw()
  5659. {
  5660. HRESULT hr;
  5661. // Specify the properties if we have some
  5662. if (pPropSet)
  5663. {
  5664. // For backward compatibility, if the default parameter is not
  5665. // specified, then set it to one if a property set exists
  5666. if (ulPropSets == 0)
  5667. ulPropSets = 1;
  5668. CComPtr<ICommandProperties> spCommandProperties;
  5669. hr = m_spCommand->QueryInterface(&spCommandProperties);
  5670. if (FAILED(hr))
  5671. return hr;
  5672. hr = spCommandProperties->SetProperties(ulPropSets, pPropSet);
  5673. if (FAILED(hr))
  5674. return hr;
  5675. }
  5676. // If the user want the rows affected then return it back, otherwise
  5677. // just point to our local variable here.
  5678. LONG nAffected, *pAffected;
  5679. if (pRowsAffected)
  5680. pAffected = pRowsAffected;
  5681. else
  5682. pAffected = &nAffected;
  5683. if (UseMultipleResults())
  5684. {
  5685. hr = m_spCommand->Execute(NULL, __uuidof(IMultipleResults), pParams,
  5686. pAffected, (IUnknown**)GetMultiplePtrAddress());
  5687. if (SUCCEEDED(hr))
  5688. hr = GetNextResult(pAffected, false);
  5689. else
  5690. // If we can't get IMultipleResults then just try to get IRowset
  5691. hr = m_spCommand->Execute(NULL, GetIID(), pParams, pAffected,
  5692. ppInterface);
  5693. }
  5694. else
  5695. {
  5696. hr = m_spCommand->Execute(NULL, GetIID(), pParams, pAffected,
  5697. ppInterface);
  5698. }
  5699. if (SUCCEEDED(hr))
  5700. SetupOptionalRowsetInterfaces();
  5701. return hr;
  5702. }
  5703. };
  5704. // This class can be used to implement the IRowsetNotify interface.
  5705. // It is supplied so that if you only want to implement one of the
  5706. // notifications you don't have to supply empty functions for the
  5707. // other methods.
  5708. class ATL_NO_VTABLE IRowsetNotifyImpl : public IRowsetNotify
  5709. {
  5710. public:
  5711. STDMETHOD(OnFieldChange)(
  5712. /* [in] */ IRowset* /* pRowset */,
  5713. /* [in] */ HROW /* hRow */,
  5714. /* [in] */ DBORDINAL /* cColumns */,
  5715. /* [size_is][in] */ DBORDINAL /* rgColumns*/ [] ,
  5716. /* [in] */ DBREASON /* eReason */,
  5717. /* [in] */ DBEVENTPHASE /* ePhase */,
  5718. /* [in] */ BOOL /* fCantDeny */)
  5719. {
  5720. ATLTRACENOTIMPL(_T("IRowsetNotifyImpl::OnFieldChange"));
  5721. }
  5722. STDMETHOD(OnRowChange)(
  5723. /* [in] */ IRowset* /* pRowset */,
  5724. /* [in] */ DBCOUNTITEM /* cRows */,
  5725. /* [size_is][in] */ const HROW /* rghRows*/ [] ,
  5726. /* [in] */ DBREASON /* eReason */,
  5727. /* [in] */ DBEVENTPHASE /* ePhase */,
  5728. /* [in] */ BOOL /* fCantDeny */)
  5729. {
  5730. ATLTRACENOTIMPL(_T("IRowsetNotifyImpl::OnRowChange"));
  5731. }
  5732. STDMETHOD(OnRowsetChange)(
  5733. /* [in] */ IRowset* /* pRowset */,
  5734. /* [in] */ DBREASON /* eReason */,
  5735. /* [in] */ DBEVENTPHASE /* ePhase */,
  5736. /* [in] */ BOOL /* fCantDeny*/)
  5737. {
  5738. ATLTRACENOTIMPL(_T("IRowsetNotifyImpl::OnRowsetChange"));
  5739. }
  5740. };
  5741. }; //namespace ATL
  5742. #pragma warning(pop)
  5743. #endif // __ATLDBCLI_H__