Leaked source code of windows server 2003
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.

5205 lines
167 KiB

  1. //---------------------------------------------------------------------------
  2. // Cursor.cpp : Cursor implementation
  3. //
  4. // Copyright (c) 1996 Microsoft Corporation, All Rights Reserved
  5. // Developed by Sheridan Software Systems, Inc.
  6. //---------------------------------------------------------------------------
  7. #include "stdafx.h"
  8. #include "Notifier.h"
  9. #include "RSColumn.h"
  10. #include "RSSource.h"
  11. #include "CursMain.h"
  12. #include "ColUpdat.h"
  13. #include "CursPos.h"
  14. #include "enumcnpt.h"
  15. #include "CursBase.h"
  16. #include "Cursor.h"
  17. #include "CursMeta.h"
  18. #include "EntryID.h"
  19. #include "Stream.h"
  20. #include "fastguid.h"
  21. #include "resource.h"
  22. #include "NConnPt.h"
  23. #include "NConnPtC.h"
  24. #include "FromVar.h"
  25. #include "timeconv.h"
  26. SZTHISFILE
  27. //=--------------------------------------------------------------------------=
  28. // CVDCursor - Constructor
  29. //
  30. CVDCursor::CVDCursor()
  31. {
  32. m_hAccessor = 0;
  33. m_hVarHelper = 0;
  34. m_ulVarBindings = 0;
  35. m_rghVarAccessors = NULL;
  36. m_rghAdjustAccessors = NULL;
  37. m_pdwAdjustFlags = NULL;
  38. m_ppColumns = NULL;
  39. m_pCursorPosition = NULL;
  40. m_pConnPtContainer = NULL;
  41. #ifdef _DEBUG
  42. g_cVDCursorCreated++;
  43. #endif
  44. }
  45. //=--------------------------------------------------------------------------=
  46. // ~CVDCursor - Destructor
  47. //
  48. CVDCursor::~CVDCursor()
  49. {
  50. DestroyAccessors();
  51. DestroyColumns();
  52. if (m_pCursorPosition->GetSameRowClone())
  53. m_pCursorPosition->ReleaseSameRowClone();
  54. LeaveFamily(); // leave m_pCursorPosition's notification family
  55. if (m_pConnPtContainer)
  56. m_pConnPtContainer->Destroy();
  57. if (m_pCursorPosition)
  58. ((CVDNotifier*)m_pCursorPosition)->Release(); // release associated cursor position object
  59. #ifdef _DEBUG
  60. g_cVDCursorDestroyed++;
  61. #endif
  62. }
  63. //=--------------------------------------------------------------------------=
  64. // GetRowsetColumn - Get rowset column from ordinal
  65. //=--------------------------------------------------------------------------=
  66. // This function retrieves the rowset column with the specified rowset ordinal
  67. //
  68. // Parameters:
  69. // ulOrdinal - [in] rowset ordinal
  70. //
  71. // Output:
  72. // CVDRowsetColumn pointer
  73. //
  74. // Notes:
  75. //
  76. CVDRowsetColumn * CVDCursor::GetRowsetColumn(ULONG ulOrdinal)
  77. {
  78. CVDRowsetColumn * pRowsetColumn = NULL;
  79. ULONG ulColumns = GetCursorMain()->GetColumnsCount();
  80. CVDRowsetColumn * pColumn = GetCursorMain()->InternalGetColumns();
  81. for (ULONG ulCol = 0; ulCol < ulColumns && !pRowsetColumn; ulCol++)
  82. {
  83. if (pColumn->GetOrdinal() == ulOrdinal)
  84. pRowsetColumn = pColumn;
  85. pColumn++;
  86. }
  87. return pRowsetColumn;
  88. }
  89. //=--------------------------------------------------------------------------=
  90. // GetRowsetColumn - Get rowset column from cursor column identifier
  91. //=--------------------------------------------------------------------------=
  92. // This function retrieves the rowset column associated with the specified
  93. // cursor column identifier
  94. //
  95. // Parameters:
  96. // cursorColumnID - [in] a reference to cursor column identifier
  97. //
  98. // Output:
  99. // CVDRowsetColumn pointer
  100. //
  101. // Notes:
  102. //
  103. CVDRowsetColumn * CVDCursor::GetRowsetColumn(CURSOR_DBCOLUMNID& cursorColumnID)
  104. {
  105. CVDRowsetColumn * pRowsetColumn = NULL;
  106. ULONG ulColumns = GetCursorMain()->GetColumnsCount();
  107. CVDRowsetColumn * pColumn = GetCursorMain()->InternalGetColumns();
  108. for (ULONG ulCol = 0; ulCol < ulColumns && !pRowsetColumn; ulCol++)
  109. {
  110. if (IsEqualCursorColumnID(cursorColumnID, pColumn->GetCursorColumnID()))
  111. pRowsetColumn = pColumn;
  112. pColumn++;
  113. }
  114. return pRowsetColumn;
  115. }
  116. //=--------------------------------------------------------------------------=
  117. // GetOrdinal - Get ordinal from cursor column identifier
  118. //=--------------------------------------------------------------------------=
  119. // This function converts a cursor column identifier its ordinal eqivalent
  120. //
  121. // Parameters:
  122. // cursorColumnID - [in] a reference to cursor column identifier
  123. // pulOrdinal - [out] a pointer to memory in which to return ordinal
  124. //
  125. // Output:
  126. // HRESULT - S_OK if successful
  127. // E_FAIL bad cursor column identifier
  128. //
  129. // Notes:
  130. //
  131. HRESULT CVDCursor::GetOrdinal(CURSOR_DBCOLUMNID& cursorColumnID, ULONG * pulOrdinal)
  132. {
  133. HRESULT hr = E_FAIL;
  134. ULONG ulColumns = GetCursorMain()->GetColumnsCount();
  135. CVDRowsetColumn * pColumn = GetCursorMain()->InternalGetColumns();
  136. for (ULONG ulCol = 0; ulCol < ulColumns && FAILED(hr); ulCol++)
  137. {
  138. if (IsEqualCursorColumnID(cursorColumnID, pColumn->GetCursorColumnID()))
  139. {
  140. *pulOrdinal = pColumn->GetOrdinal();
  141. hr = S_OK;
  142. }
  143. pColumn++;
  144. }
  145. return hr;
  146. }
  147. //=--------------------------------------------------------------------------=
  148. // StatusToCursorInfo - Get cursor info from rowset status field
  149. //=--------------------------------------------------------------------------=
  150. // This function converts a rowset status to its cursor information field
  151. // eqivalent
  152. //
  153. // Parameters:
  154. // dwStatus - [in] rowset status
  155. //
  156. // Output:
  157. // DWORD - cursor information
  158. //
  159. // Notes:
  160. // There are more rowset statuses than cursor information values
  161. //
  162. DWORD CVDCursor::StatusToCursorInfo(DBSTATUS dwStatus)
  163. {
  164. DWORD dwCursorInfo = CURSOR_DB_UNKNOWN;
  165. switch (dwStatus)
  166. {
  167. case DBSTATUS_S_OK:
  168. dwCursorInfo = CURSOR_DB_NOINFO;
  169. break;
  170. case DBSTATUS_E_CANTCONVERTVALUE:
  171. dwCursorInfo = CURSOR_DB_CANTCOERCE;
  172. break;
  173. case DBSTATUS_S_ISNULL:
  174. dwCursorInfo = CURSOR_DB_NULL;
  175. break;
  176. case DBSTATUS_S_TRUNCATED:
  177. dwCursorInfo = CURSOR_DB_TRUNCATED;
  178. break;
  179. }
  180. return dwCursorInfo;
  181. }
  182. //=--------------------------------------------------------------------------=
  183. // CursorInfoToStatus - Get rowset status from cursor info field
  184. //=--------------------------------------------------------------------------=
  185. // This function converts a cursor information field to its rowset status
  186. // eqivalent
  187. //
  188. // Parameters:
  189. // dwInfo - [in] rowset status
  190. //
  191. // Output:
  192. // DWORD - cursor information
  193. //
  194. // Notes:
  195. // This function only converts successful cursor information fields for
  196. // the purpose of setting data
  197. //
  198. DBSTATUS CVDCursor::CursorInfoToStatus(DWORD dwCursorInfo)
  199. {
  200. DBSTATUS dwStatus;
  201. switch (dwCursorInfo)
  202. {
  203. case CURSOR_DB_NULL:
  204. dwStatus = DBSTATUS_S_ISNULL;
  205. break;
  206. case CURSOR_DB_EMPTY:
  207. dwStatus = DBSTATUS_S_ISNULL;
  208. break;
  209. case CURSOR_DB_TRUNCATED:
  210. dwStatus = DBSTATUS_S_TRUNCATED;
  211. break;
  212. case CURSOR_DB_NOINFO:
  213. dwStatus = DBSTATUS_S_OK;
  214. break;
  215. }
  216. return dwStatus;
  217. }
  218. //=--------------------------------------------------------------------------=
  219. // ValidateCursorBindParams - Validate cursor column binding parameters
  220. //=--------------------------------------------------------------------------=
  221. // This function makes sure the specified column binding parameters are
  222. // acceptable and then returns a pointer to the corresponding rowset column
  223. //
  224. // Parameters:
  225. // pCursorColumnID - [in] a pointer to column identifier of the
  226. // column to bind
  227. // pCursorBindParams - [in] a pointer to binding structure
  228. // ppRowsetColumn - [out] a pointer to memory in which to return
  229. // a pointer to the rowset column to bind
  230. //
  231. // Output:
  232. // HRESULT - S_OK if successful
  233. // CURSOR_DB_E_BADBINDINFO bad binding information
  234. // CURSOR_DB_E_BADCOLUMNID columnID is not available
  235. //
  236. // Notes:
  237. //
  238. HRESULT CVDCursor::ValidateCursorBindParams(CURSOR_DBCOLUMNID * pCursorColumnID, CURSOR_DBBINDPARAMS * pCursorBindParams,
  239. CVDRowsetColumn ** ppRowsetColumn)
  240. {
  241. ASSERT_POINTER(pCursorColumnID, CURSOR_DBCOLUMNID)
  242. ASSERT_POINTER(pCursorBindParams, CURSOR_DBBINDPARAMS)
  243. ASSERT_POINTER(ppRowsetColumn, CVDRowsetColumn*)
  244. // make sure we have all necessary pointers
  245. if (!pCursorColumnID || !pCursorBindParams || !ppRowsetColumn)
  246. {
  247. VDSetErrorInfo(IDS_ERR_INVALIDARG, IID_ICursorUpdateARow, m_pResourceDLL);
  248. return E_INVALIDARG;
  249. }
  250. // init out parameter
  251. *ppRowsetColumn = NULL;
  252. // make sure column identifier is available
  253. BOOL fColumnIDAvailable = FALSE;
  254. DWORD dwCursorType;
  255. ULONG ulColumns = GetCursorMain()->GetColumnsCount();
  256. CVDRowsetColumn * pColumns = GetCursorMain()->InternalGetColumns();
  257. CVDRowsetColumn * pColumn = pColumns;
  258. // iterate through rowset columns looking for match
  259. for (ULONG ulCol = 0; ulCol < ulColumns && !fColumnIDAvailable; ulCol++)
  260. {
  261. if (IsEqualCursorColumnID(*pCursorColumnID, pColumn->GetCursorColumnID()))
  262. {
  263. dwCursorType = pColumn->GetCursorType();
  264. *ppRowsetColumn = pColumn;
  265. fColumnIDAvailable = TRUE;
  266. }
  267. pColumn++;
  268. }
  269. // get out if not found
  270. if (!fColumnIDAvailable)
  271. {
  272. VDSetErrorInfo(IDS_ERR_BADCOLUMNID, IID_ICursorUpdateARow, m_pResourceDLL);
  273. return CURSOR_DB_E_BADCOLUMNID;
  274. }
  275. // make sure caller supplied a maximum length if a default binding was specified
  276. // for the cursor types CURSOR_DBTYPE_CHARS, CURSOR_DBTYPE_WCHARS or CURSOR_DBTYPE_BYTES
  277. if (pCursorBindParams->cbMaxLen == CURSOR_DB_NOMAXLENGTH &&
  278. pCursorBindParams->dwBinding == CURSOR_DBBINDING_DEFAULT)
  279. {
  280. if (pCursorBindParams->dwDataType == CURSOR_DBTYPE_CHARS ||
  281. pCursorBindParams->dwDataType == CURSOR_DBTYPE_WCHARS ||
  282. pCursorBindParams->dwDataType == CURSOR_DBTYPE_BYTES)
  283. {
  284. VDSetErrorInfo(IDS_ERR_BADCURSORBINDINFO, IID_ICursorUpdateARow, m_pResourceDLL);
  285. return CURSOR_DB_E_BADBINDINFO;
  286. }
  287. }
  288. // check binding bit mask for possible values
  289. if (pCursorBindParams->dwBinding != CURSOR_DBBINDING_DEFAULT &&
  290. pCursorBindParams->dwBinding != CURSOR_DBBINDING_VARIANT &&
  291. pCursorBindParams->dwBinding != CURSOR_DBBINDING_ENTRYID &&
  292. pCursorBindParams->dwBinding != (CURSOR_DBBINDING_VARIANT | CURSOR_DBBINDING_ENTRYID))
  293. {
  294. VDSetErrorInfo(IDS_ERR_BADCURSORBINDINFO, IID_ICursorUpdateARow, m_pResourceDLL);
  295. return CURSOR_DB_E_BADBINDINFO;
  296. }
  297. // check for valid cursor type
  298. if (!IsValidCursorType(pCursorBindParams->dwDataType))
  299. {
  300. VDSetErrorInfo(IDS_ERR_BADCURSORBINDINFO, IID_ICursorUpdateARow, m_pResourceDLL);
  301. return CURSOR_DB_E_BADBINDINFO;
  302. }
  303. // if a variant binding was specified make sure the cursor type is not CURSOR_DBTYPE_CHARS,
  304. // CURSOR_DBTYPE_WCHARS or CURSOR_DBTYPE_BYTES
  305. if (pCursorBindParams->dwBinding & CURSOR_DBBINDING_VARIANT)
  306. {
  307. if (pCursorBindParams->dwDataType == CURSOR_DBTYPE_CHARS ||
  308. pCursorBindParams->dwDataType == CURSOR_DBTYPE_WCHARS ||
  309. pCursorBindParams->dwDataType == CURSOR_DBTYPE_BYTES)
  310. {
  311. VDSetErrorInfo(IDS_ERR_BADCURSORBINDINFO, IID_ICursorUpdateARow, m_pResourceDLL);
  312. return CURSOR_DB_E_BADBINDINFO;
  313. }
  314. }
  315. // if its not a variant binding make sure the cursor type is not CURSOR_DBTYPE_ANYVARIANT
  316. if (!(pCursorBindParams->dwBinding & CURSOR_DBBINDING_VARIANT) &&
  317. pCursorBindParams->dwDataType == CURSOR_DBTYPE_ANYVARIANT)
  318. {
  319. VDSetErrorInfo(IDS_ERR_BADCURSORBINDINFO, IID_ICursorUpdateARow, m_pResourceDLL);
  320. return CURSOR_DB_E_BADBINDINFO;
  321. }
  322. return S_OK;
  323. }
  324. //=--------------------------------------------------------------------------=
  325. // ValidateEntryID - Validate entry identifier
  326. //=--------------------------------------------------------------------------=
  327. // This function makes sure the specified enrty identifier is acceptable,
  328. // if it is, then return rowset column and hRow associated with it
  329. //
  330. // Parameters:
  331. // cbEntryID - [in] the size of the entryID
  332. // pEntryID - [in] a pointer to the entryID
  333. // ppColumn - [out] a pointer to memory in which to return rowset column pointer
  334. // phRow - [out] a pointer to memory in which to return row handle
  335. //
  336. // Output:
  337. // HRESULT - S_OK if successful
  338. // E_INVALIDARG bad parameter
  339. // CURSOR_DB_E_BADENTRYID bad entry identifier
  340. //
  341. HRESULT CVDCursor::ValidateEntryID(ULONG cbEntryID, BYTE * pEntryID, CVDRowsetColumn ** ppColumn, HROW * phRow)
  342. {
  343. ASSERT_POINTER(pEntryID, BYTE)
  344. ASSERT_POINTER(ppColumn, CVDRowsetColumn*)
  345. ASSERT_POINTER(phRow, HROW)
  346. IRowsetLocate * pRowsetLocate = GetRowsetLocate();
  347. // make sure we have a valid rowset locate pointer
  348. if (!pRowsetLocate || !IsRowsetValid())
  349. {
  350. VDSetErrorInfo(IDS_ERR_ROWSETRELEASED, IID_IEntryID, m_pResourceDLL);
  351. return E_FAIL;
  352. }
  353. // make sure we have all necessary pointers
  354. if (!pEntryID || !ppColumn || !phRow)
  355. {
  356. VDSetErrorInfo(IDS_ERR_INVALIDARG, IID_IEntryID, m_pResourceDLL);
  357. return E_INVALIDARG;
  358. }
  359. // init out parameters
  360. *ppColumn = NULL;
  361. *phRow = NULL;
  362. // check length of enrtyID
  363. if (cbEntryID != sizeof(ULONG) + sizeof(ULONG) + GetCursorMain()->GetMaxBookmarkLen())
  364. {
  365. VDSetErrorInfo(IDS_ERR_BADENTRYID, IID_IEntryID, m_pResourceDLL);
  366. return CURSOR_DB_E_BADENTRYID;
  367. }
  368. // extract column ordinal
  369. ULONG ulOrdinal = *(ULONG*)pEntryID;
  370. // make sure column ordinal is okay
  371. BOOL fColumnOrdinalOkay = FALSE;
  372. ULONG ulColumns = GetCursorMain()->GetColumnsCount();
  373. CVDRowsetColumn * pColumn = GetCursorMain()->InternalGetColumns();
  374. // iterate through rowset columns looking for match
  375. for (ULONG ulCol = 0; ulCol < ulColumns && !fColumnOrdinalOkay; ulCol++)
  376. {
  377. if (ulOrdinal == pColumn->GetOrdinal())
  378. fColumnOrdinalOkay = TRUE;
  379. else
  380. pColumn++;
  381. }
  382. // if not found, get out
  383. if (!fColumnOrdinalOkay)
  384. {
  385. VDSetErrorInfo(IDS_ERR_BADENTRYID, IID_IEntryID, m_pResourceDLL);
  386. return CURSOR_DB_E_BADENTRYID;
  387. }
  388. // set column pointer
  389. *ppColumn = pColumn;
  390. // extract row bookmark
  391. ULONG cbBookmark = *(ULONG*)(pEntryID + sizeof(ULONG));
  392. BYTE * pBookmark = (BYTE*)pEntryID + sizeof(ULONG) + sizeof(ULONG);
  393. // attempt to retrieve hRow from bookmark
  394. HRESULT hr = pRowsetLocate->GetRowsByBookmark(0, 1, &cbBookmark, (const BYTE**)&pBookmark, phRow, NULL);
  395. if (FAILED(hr))
  396. VDSetErrorInfo(IDS_ERR_BADENTRYID, IID_IEntryID, m_pResourceDLL);
  397. return hr;
  398. }
  399. //=--------------------------------------------------------------------------=
  400. // QueryEntryIDInterface - Get specified interface for entry identifier
  401. //=--------------------------------------------------------------------------=
  402. // This function attempts to get the requested interface from the specified
  403. // column row
  404. //
  405. // Parameters:
  406. // pColumn - [in] rowset column pointer
  407. // hRow - [in] the row handle
  408. // dwFlags - [in] interface specific flags
  409. // riid - [in] interface identifier requested
  410. // ppUnknown - [out] a pointer to memory in which to return interface pointer
  411. //
  412. // Output:
  413. // HRESULT - S_OK if successful
  414. // E_FAIL error occured
  415. // E_INVALIDARG bad parameter
  416. // E_OUTOFMEMORY not enough memory
  417. // E_NOINTERFACE interface not available
  418. //
  419. HRESULT CVDCursor::QueryEntryIDInterface(CVDRowsetColumn * pColumn, HROW hRow, DWORD dwFlags, REFIID riid,
  420. IUnknown ** ppUnknown)
  421. {
  422. ASSERT_POINTER(pColumn, CVDRowsetColumn)
  423. ASSERT_POINTER(ppUnknown, IUnknown*)
  424. IRowset * pRowset = GetRowset();
  425. IAccessor * pAccessor = GetAccessor();
  426. // make sure we have valid rowset and accessor pointers
  427. if (!pRowset || !pAccessor || !IsRowsetValid())
  428. {
  429. VDSetErrorInfo(IDS_ERR_ROWSETRELEASED, IID_IEntryID, m_pResourceDLL);
  430. return E_FAIL;
  431. }
  432. // make sure we have all necessay pointers
  433. if (!pColumn || !ppUnknown)
  434. {
  435. VDSetErrorInfo(IDS_ERR_INVALIDARG, IID_IEntryID, m_pResourceDLL);
  436. return E_INVALIDARG;
  437. }
  438. // init out parameters
  439. *ppUnknown = NULL;
  440. DBOBJECT object;
  441. DBBINDING binding;
  442. // clear out binding
  443. memset(&binding, 0, sizeof(DBBINDING));
  444. // create interface binding
  445. binding.iOrdinal = pColumn->GetOrdinal();
  446. binding.pObject = &object;
  447. binding.pObject->dwFlags = dwFlags;
  448. binding.pObject->iid = riid;
  449. binding.dwPart = DBPART_VALUE;
  450. binding.dwMemOwner = DBMEMOWNER_CLIENTOWNED;
  451. binding.cbMaxLen = sizeof(IUnknown*);
  452. binding.wType = DBTYPE_IUNKNOWN;
  453. HACCESSOR hAccessor;
  454. // create interface accessor
  455. HRESULT hr = pAccessor->CreateAccessor(DBACCESSOR_ROWDATA, 1, &binding, 0, &hAccessor, NULL);
  456. if (FAILED(hr))
  457. return E_NOINTERFACE;
  458. IUnknown * pUnknown = NULL;
  459. // try to get interface
  460. hr = pRowset->GetData(hRow, hAccessor, &pUnknown);
  461. // release interface accessor
  462. pAccessor->ReleaseAccessor(hAccessor, NULL);
  463. if (FAILED(hr))
  464. return E_NOINTERFACE;
  465. // return pointer
  466. *ppUnknown = pUnknown;
  467. return hr;
  468. }
  469. #ifndef VD_DONT_IMPLEMENT_ISTREAM
  470. //=--------------------------------------------------------------------------=
  471. // CreateEntryIDStream - Create stream for entry identifier
  472. //=--------------------------------------------------------------------------=
  473. // This function retrieves supplied column row's data and create a
  474. // stream containing this data
  475. //
  476. // Parameters:
  477. // pColumn - [in] rowset column pointer
  478. // hRow - [in] the row handle
  479. // ppStream - [out] a pointer to memory in which to return stream pointer
  480. //
  481. // Output:
  482. // HRESULT - S_OK if successful
  483. // E_FAIL error occured
  484. // E_INVALIDARG bad parameter
  485. // E_OUTOFMEMORY not enough memory
  486. //
  487. HRESULT CVDCursor::CreateEntryIDStream(CVDRowsetColumn * pColumn, HROW hRow, IStream ** ppStream)
  488. {
  489. ASSERT_POINTER(pColumn, CVDRowsetColumn)
  490. ASSERT_POINTER(ppStream, IStream*)
  491. IRowset * pRowset = GetRowset();
  492. IAccessor * pAccessor = GetAccessor();
  493. // make sure we have valid rowset and accessor pointers
  494. if (!pRowset || !pAccessor || !IsRowsetValid())
  495. {
  496. VDSetErrorInfo(IDS_ERR_ROWSETRELEASED, IID_IEntryID, m_pResourceDLL);
  497. return E_FAIL;
  498. }
  499. // make sure we have all necessay pointers
  500. if (!pColumn || !ppStream)
  501. {
  502. VDSetErrorInfo(IDS_ERR_INVALIDARG, IID_IEntryID, m_pResourceDLL);
  503. return E_INVALIDARG;
  504. }
  505. // init out parameters
  506. *ppStream = NULL;
  507. DBBINDING binding;
  508. // clear out binding
  509. memset(&binding, 0, sizeof(DBBINDING));
  510. // create length binding
  511. binding.iOrdinal = pColumn->GetOrdinal();
  512. binding.obLength = 0;
  513. binding.dwPart = DBPART_LENGTH;
  514. binding.dwMemOwner = DBMEMOWNER_CLIENTOWNED;
  515. binding.wType = DBTYPE_BYTES;
  516. HACCESSOR hAccessor;
  517. // create length accessor
  518. HRESULT hr = pAccessor->CreateAccessor(DBACCESSOR_ROWDATA, 1, &binding, 0, &hAccessor, NULL);
  519. hr = VDMapRowsetHRtoCursorHR(hr, IDS_ERR_CREATEACCESSORFAILED, IID_IEntryID, pAccessor, IID_IAccessor, m_pResourceDLL);
  520. if (FAILED(hr))
  521. return hr;
  522. ULONG cbData;
  523. // get size of data
  524. hr = pRowset->GetData(hRow, hAccessor, &cbData);
  525. hr = VDMapRowsetHRtoCursorHR(hr, IDS_ERR_GETDATAFAILED, IID_IEntryID, pRowset, IID_IRowset, m_pResourceDLL);
  526. // release length accessor
  527. pAccessor->ReleaseAccessor(hAccessor, NULL);
  528. if (FAILED(hr))
  529. return hr;
  530. // create value binding
  531. binding.iOrdinal = pColumn->GetOrdinal();
  532. binding.obValue = 0;
  533. binding.dwPart = DBPART_VALUE;
  534. binding.dwMemOwner = DBMEMOWNER_CLIENTOWNED;
  535. binding.cbMaxLen = cbData;
  536. binding.wType = DBTYPE_BYTES;
  537. // create value accessor
  538. hr = pAccessor->CreateAccessor(DBACCESSOR_ROWDATA, 1, &binding, 0, &hAccessor, NULL);
  539. hr = VDMapRowsetHRtoCursorHR(hr, IDS_ERR_CREATEACCESSORFAILED, IID_IEntryID, pAccessor, IID_IAccessor, m_pResourceDLL);
  540. if (FAILED(hr))
  541. return hr;
  542. // create data buffer
  543. HGLOBAL hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD, cbData);
  544. if (!hData)
  545. {
  546. // release value accessor
  547. pAccessor->ReleaseAccessor(hAccessor, NULL);
  548. VDSetErrorInfo(IDS_ERR_OUTOFMEMORY, IID_IEntryID, m_pResourceDLL);
  549. return E_OUTOFMEMORY;
  550. }
  551. // get pointer to data buffer
  552. BYTE * pData = (BYTE*)GlobalLock(hData);
  553. // get data value
  554. hr = pRowset->GetData(hRow, hAccessor, pData);
  555. // release pointer to data buffer
  556. GlobalUnlock(hData);
  557. hr = VDMapRowsetHRtoCursorHR(hr, IDS_ERR_GETDATAFAILED, IID_IEntryID, pRowset, IID_IRowset, m_pResourceDLL);
  558. // release value accessor
  559. pAccessor->ReleaseAccessor(hAccessor, NULL);
  560. if (FAILED(hr))
  561. {
  562. GlobalFree(hData);
  563. return hr;
  564. }
  565. // create stream containing data
  566. hr = CreateStreamOnHGlobal(hData, TRUE, ppStream);
  567. if (FAILED(hr))
  568. GlobalFree(hData);
  569. return hr;
  570. }
  571. #endif //VD_DONT_IMPLEMENT_ISTREAM
  572. //=--------------------------------------------------------------------------=
  573. // MakeAdjustments - Make adjustments to fixed length buffer accessor bindings
  574. //=--------------------------------------------------------------------------=
  575. // This function makes adjustments to the fixed length buffer accessor
  576. // bindings, after a call to CreateAccessor fails, to try and make the
  577. // binding more suitable
  578. //
  579. // Parameters:
  580. // ulBindings - [in] number of fixed length buffer bindings
  581. // pBindings - [in] a pointer to fixed length buffer bindings
  582. // pulIndex - [in] a pointer to an array of indices, which
  583. // specify which cursor binding each fixed
  584. // length buffer binding applies
  585. // ulTotalBindings - [in] number of cursor bindings
  586. // prghAdjustAccessors - [out] a pointer to memory in which to return
  587. // a pointer to adjusted fixed length buffer
  588. // accessors
  589. // ppdwAdjustFlags - [out] a pointer to memory in which to return
  590. // a pointer to adjusted fixed length buffer
  591. // accessors flags
  592. // fBefore - [in] a flag which indicated whether this call
  593. // has been made before or after the call
  594. // to CreateAccessor
  595. //
  596. // Output:
  597. // S_OK - if adjustments were made
  598. // E_FAIL - failed to make any adjustments
  599. // E_OUTOFMEMORY - not enough memory
  600. // E_INVALIDARG - bad parameter
  601. //
  602. // Notes:
  603. // Specifically, this function can make the following adjustments...
  604. // (1) Change variant binding byte field -> byte binding (fails in GetData)
  605. // (2) Change variant binding date field -> wide string binding (fails in CreateAccessor)
  606. // (3) Change variant binding memo field -> string binding (fails in CreateAccessor)
  607. //
  608. HRESULT CVDCursor::MakeAdjustments(ULONG ulBindings, DBBINDING * pBindings, ULONG * pulIndex, ULONG ulTotalBindings,
  609. HACCESSOR ** prghAdjustAccessors, DWORD ** ppdwAdjustFlags, BOOL fBefore)
  610. {
  611. ASSERT_POINTER(pBindings, DBBINDING)
  612. ASSERT_POINTER(pulIndex, ULONG)
  613. ASSERT_POINTER(prghAdjustAccessors, HACCESSOR*)
  614. ASSERT_POINTER(ppdwAdjustFlags, DWORD*)
  615. IAccessor * pAccessor = GetAccessor();
  616. // make sure we have a valid accessor pointer
  617. if (!pAccessor || !IsRowsetValid())
  618. {
  619. VDSetErrorInfo(IDS_ERR_ROWSETRELEASED, IID_ICursor, m_pResourceDLL);
  620. return E_FAIL;
  621. }
  622. // make sure we have all necessary pointers
  623. if (!pBindings || !pulIndex || !prghAdjustAccessors || !ppdwAdjustFlags)
  624. return E_INVALIDARG;
  625. BOOL fWeAllocatedMemory = FALSE;
  626. // try to get storage for adjusted accessors and flags
  627. HACCESSOR * rghAdjustAccessors = *prghAdjustAccessors;
  628. DWORD * pdwAdjustFlags = *ppdwAdjustFlags;
  629. // if not supplied, then create storage
  630. if (!rghAdjustAccessors || !pdwAdjustFlags)
  631. {
  632. rghAdjustAccessors = new HACCESSOR[ulTotalBindings];
  633. pdwAdjustFlags = new DWORD[ulTotalBindings];
  634. // make sure we got the requested memory
  635. if (!rghAdjustAccessors || !pdwAdjustFlags)
  636. {
  637. delete [] rghAdjustAccessors;
  638. delete [] pdwAdjustFlags;
  639. VDSetErrorInfo(IDS_ERR_OUTOFMEMORY, IID_ICursor, m_pResourceDLL);
  640. return E_OUTOFMEMORY;
  641. }
  642. // clear adjusted accessors and flags
  643. memset(rghAdjustAccessors, 0, ulTotalBindings * sizeof(HACCESSOR));
  644. memset(pdwAdjustFlags, 0, ulTotalBindings * sizeof(DWORD));
  645. fWeAllocatedMemory = TRUE;
  646. }
  647. // initialize variables
  648. DBBINDING * pBinding = pBindings;
  649. CVDRowsetColumn * pColumn;
  650. DBTYPE wType;
  651. ULONG cbMaxLength;
  652. DBBINDING binding;
  653. HRESULT hr;
  654. HACCESSOR hAccessor;
  655. HRESULT hrAdjust = E_FAIL;
  656. // iterate through fixed length buffer bindings
  657. for (ULONG ulBind = 0; ulBind < ulBindings; ulBind++)
  658. {
  659. // first check for a variant binding, where value is to be returned
  660. if (pBinding->wType == DBTYPE_VARIANT && (pBinding->dwPart & DBPART_VALUE))
  661. {
  662. // get rowset column associated with this binding
  663. pColumn = GetRowsetColumn(pBinding->iOrdinal);
  664. if (pColumn)
  665. {
  666. // get attributes of this column
  667. wType = pColumn->GetType();
  668. cbMaxLength = pColumn->GetMaxLength();
  669. // check for a byte field
  670. if (fBefore && wType == DBTYPE_UI1)
  671. {
  672. // make adjustments to fixed length buffer binding
  673. pBinding->wType = DBTYPE_UI1;
  674. // store associated flag
  675. pdwAdjustFlags[pulIndex[ulBind]] = VD_ADJUST_VARIANT_TO_BYTE;
  676. // we succeeded
  677. hrAdjust = S_OK;
  678. }
  679. // check for a date field
  680. if (!fBefore && wType == DBTYPE_DBTIMESTAMP)
  681. {
  682. // clear binding
  683. memset(&binding, 0, sizeof(DBBINDING));
  684. // create adjusted accessor binding
  685. binding.iOrdinal = pBinding->iOrdinal;
  686. binding.dwPart = DBPART_VALUE;
  687. binding.dwMemOwner = DBMEMOWNER_CLIENTOWNED;
  688. binding.cbMaxLen = 0x7FFFFFFF;
  689. binding.wType = DBTYPE_WSTR;
  690. // try to create adjusted accessor
  691. hr = pAccessor->CreateAccessor(DBACCESSOR_ROWDATA, 1, &binding, 0, &hAccessor, NULL);
  692. if (SUCCEEDED(hr))
  693. {
  694. // make adjustments to fixed length buffer binding
  695. pBinding->obLength = pBinding->obValue;
  696. pBinding->dwPart &= ~DBPART_VALUE;
  697. pBinding->dwPart |= DBPART_LENGTH;
  698. pBinding->wType = DBTYPE_WSTR;
  699. // store adjusted accessor and associated flag
  700. rghAdjustAccessors[pulIndex[ulBind]] = hAccessor;
  701. pdwAdjustFlags[pulIndex[ulBind]] = VD_ADJUST_VARIANT_TO_WSTR;
  702. // we succeeded
  703. hrAdjust = S_OK;
  704. }
  705. }
  706. // check for a memo field
  707. if (!fBefore && wType == DBTYPE_STR && cbMaxLength >= 0x40000000)
  708. {
  709. // clear binding
  710. memset(&binding, 0, sizeof(DBBINDING));
  711. // create adjusted accessor binding
  712. binding.iOrdinal = pBinding->iOrdinal;
  713. binding.dwPart = DBPART_VALUE;
  714. binding.dwMemOwner = DBMEMOWNER_CLIENTOWNED;
  715. binding.cbMaxLen = 0x7FFFFFFF;
  716. binding.wType = DBTYPE_STR;
  717. // try to create adjusted accessor
  718. hr = pAccessor->CreateAccessor(DBACCESSOR_ROWDATA, 1, &binding, 0, &hAccessor, NULL);
  719. if (SUCCEEDED(hr))
  720. {
  721. // make adjustments to fixed length buffer binding
  722. pBinding->obLength = pBinding->obValue;
  723. pBinding->dwPart &= ~DBPART_VALUE;
  724. pBinding->dwPart |= DBPART_LENGTH;
  725. pBinding->wType = DBTYPE_STR;
  726. // store adjusted accessor and associated flag
  727. rghAdjustAccessors[pulIndex[ulBind]] = hAccessor;
  728. pdwAdjustFlags[pulIndex[ulBind]] = VD_ADJUST_VARIANT_TO_STR;
  729. // we succeeded
  730. hrAdjust = S_OK;
  731. }
  732. }
  733. }
  734. }
  735. pBinding++;
  736. }
  737. if (SUCCEEDED(hrAdjust))
  738. {
  739. // if we made any adjustments, return accessors and flags
  740. *prghAdjustAccessors = rghAdjustAccessors;
  741. *ppdwAdjustFlags = pdwAdjustFlags;
  742. }
  743. else if (fWeAllocatedMemory)
  744. {
  745. // destroy allocated memory
  746. delete [] rghAdjustAccessors;
  747. delete [] pdwAdjustFlags;
  748. }
  749. return hrAdjust;
  750. }
  751. //=--------------------------------------------------------------------------=
  752. // ReCreateAccessors - Re-create accessors
  753. //=--------------------------------------------------------------------------=
  754. // This function attempts to recreate accessors based on old and new bindings
  755. //
  756. // Parameters:
  757. // ulNewCursorBindings - [in] the number of new cursor column bindings
  758. // pNewCursorBindings - [in] an array of new cursor column bindings
  759. // dwFlags - [in] a flag that specifies whether to replace the
  760. // existing column bindings or add to them
  761. //
  762. // Output:
  763. // HRESULT - S_OK if successful
  764. // E_OUTOFMEMORY not enough memory to create object
  765. //
  766. // Notes:
  767. //
  768. HRESULT CVDCursor::ReCreateAccessors(ULONG ulNewCursorBindings, CURSOR_DBCOLUMNBINDING * pNewCursorBindings, DWORD dwFlags)
  769. {
  770. IAccessor * pAccessor = GetAccessor();
  771. // make sure we have a valid accessor pointer
  772. if (!pAccessor || !IsRowsetValid())
  773. {
  774. VDSetErrorInfo(IDS_ERR_ROWSETRELEASED, IID_ICursor, m_pResourceDLL);
  775. return E_FAIL;
  776. }
  777. ULONG ulOldCursorBindings = 0;
  778. CURSOR_DBCOLUMNBINDING * pOldCursorBindings = NULL;
  779. // if we're adding bindings include old bindings
  780. if (dwFlags == CURSOR_DBCOLUMNBINDOPTS_ADD)
  781. {
  782. ulOldCursorBindings = m_ulCursorBindings;
  783. pOldCursorBindings = m_pCursorBindings;
  784. }
  785. // get total binding count (sum of old and new)
  786. ULONG ulTotalBindings = ulOldCursorBindings + ulNewCursorBindings;
  787. ULONG * pulIndex = NULL;
  788. DBBINDING * pBindings = NULL;
  789. DBBINDING * pHelperBindings = NULL;
  790. DBBINDING * pVarBindings = NULL;
  791. if (ulTotalBindings)
  792. {
  793. // create storage for new rowset bindings
  794. pulIndex = new ULONG[ulTotalBindings];
  795. pBindings = new DBBINDING[ulTotalBindings];
  796. pHelperBindings = new DBBINDING[ulTotalBindings];
  797. pVarBindings = new DBBINDING[ulTotalBindings];
  798. // make sure we got all requested memory
  799. if (!pulIndex || !pBindings || !pHelperBindings || !pVarBindings)
  800. {
  801. delete [] pulIndex;
  802. delete [] pBindings;
  803. delete [] pHelperBindings;
  804. delete [] pVarBindings;
  805. VDSetErrorInfo(IDS_ERR_OUTOFMEMORY, IID_ICursor, m_pResourceDLL);
  806. return E_OUTOFMEMORY;
  807. }
  808. // clear rowset bindings
  809. memset(pulIndex, 0, ulTotalBindings * sizeof(ULONG));
  810. memset(pBindings, 0, ulTotalBindings * sizeof(DBBINDING));
  811. memset(pHelperBindings, 0, ulTotalBindings * sizeof(DBBINDING));
  812. memset(pVarBindings, 0, ulTotalBindings * sizeof(DBBINDING));
  813. }
  814. // set adjustments to null
  815. HACCESSOR * rghAdjustAccessors = NULL;
  816. DWORD * pdwAdjustFlags = NULL;
  817. HRESULT hr;
  818. WORD wType;
  819. ULONG ulBindings = 0;
  820. ULONG ulHelperBindings = 0;
  821. ULONG ulVarBindings = 0;
  822. ULONG obVarDataInfo = 0;
  823. DBBINDING * pBinding = pBindings;
  824. DBBINDING * pHelperBinding = pHelperBindings;
  825. DBBINDING * pVarBinding = pVarBindings;
  826. CURSOR_DBCOLUMNBINDING * pCursorBinding = pOldCursorBindings;
  827. CVDRowsetColumn * pColumn;
  828. BOOL fEntryIDBinding;
  829. // iterate through cursor bindings and set rowset bindings
  830. for (ULONG ulCol = 0; ulCol < ulTotalBindings; ulCol++)
  831. {
  832. // if necessary, switch to new bindings
  833. if (ulCol == ulOldCursorBindings)
  834. pCursorBinding = pNewCursorBindings;
  835. // get rowset column for this binding
  836. pColumn = GetRowsetColumn(pCursorBinding->columnID);
  837. // get desired rowset datatype
  838. wType = CVDRowsetColumn::CursorTypeToType((CURSOR_DBVARENUM)pCursorBinding->dwDataType);
  839. // set entryID binding flag
  840. fEntryIDBinding = (pCursorBinding->dwBinding & CURSOR_DBBINDING_ENTRYID);
  841. // check for datatypes which require variable length buffer
  842. if (DoesCursorTypeNeedVarData(pCursorBinding->dwDataType))
  843. {
  844. // create fixed length buffer binding
  845. pBinding->iOrdinal = pColumn->GetOrdinal();
  846. pBinding->dwMemOwner = DBMEMOWNER_CLIENTOWNED;
  847. pBinding->wType = wType;
  848. // determine offset to the length part
  849. if (pCursorBinding->obVarDataLen != CURSOR_DB_NOVALUE)
  850. {
  851. pBinding->obLength = pCursorBinding->obVarDataLen;
  852. pBinding->dwPart |= DBPART_LENGTH;
  853. }
  854. // determine offset to the status part
  855. if (pCursorBinding->obInfo != CURSOR_DB_NOVALUE)
  856. {
  857. pBinding->obStatus = pCursorBinding->obInfo;
  858. pBinding->dwPart |= DBPART_STATUS;
  859. }
  860. // BLOBs always require the length part
  861. if (pCursorBinding->dwDataType == CURSOR_DBTYPE_BLOB &&
  862. pCursorBinding->obData != CURSOR_DB_NOVALUE && !fEntryIDBinding)
  863. {
  864. pBinding->obLength = pCursorBinding->obData;
  865. pBinding->dwPart |= DBPART_LENGTH;
  866. }
  867. // bookmark columns require native type
  868. if (!pColumn->GetDataColumn())
  869. pBinding->wType = pColumn->GetType();
  870. // create variable length helper buffer binding
  871. if (!pColumn->GetFixed() && !fEntryIDBinding)
  872. {
  873. // if column contains variable length data, then create binding
  874. pHelperBinding->iOrdinal = pColumn->GetOrdinal();
  875. pHelperBinding->obLength = obVarDataInfo;
  876. pHelperBinding->obStatus = obVarDataInfo + sizeof(ULONG);
  877. pHelperBinding->dwPart = DBPART_LENGTH | DBPART_STATUS;
  878. pHelperBinding->dwMemOwner = DBMEMOWNER_CLIENTOWNED;
  879. pHelperBinding->wType = wType;
  880. }
  881. // always increase offset in helper buffer
  882. obVarDataInfo += sizeof(ULONG) + sizeof(DBSTATUS);
  883. // create variable length buffer binding
  884. pVarBinding->iOrdinal = pColumn->GetOrdinal();
  885. pVarBinding->dwPart = DBPART_VALUE;
  886. pVarBinding->dwMemOwner = DBMEMOWNER_CLIENTOWNED;
  887. pVarBinding->cbMaxLen = pCursorBinding->cbMaxLen;
  888. pVarBinding->wType = wType;
  889. // adjust for no maximum length
  890. if (pVarBinding->cbMaxLen == CURSOR_DB_NOMAXLENGTH)
  891. pVarBinding->cbMaxLen = 0x7FFFFFFF;
  892. }
  893. else // datatype requires only fixed length buffer
  894. {
  895. // create fixed length buffer binding
  896. pBinding->iOrdinal = pColumn->GetOrdinal();
  897. pBinding->dwMemOwner = DBMEMOWNER_CLIENTOWNED;
  898. pBinding->cbMaxLen = pCursorBinding->cbMaxLen;
  899. pBinding->wType = wType;
  900. // determine offset to the value part
  901. if (pCursorBinding->obData != CURSOR_DB_NOVALUE && !fEntryIDBinding)
  902. {
  903. pBinding->obValue = pCursorBinding->obData;
  904. pBinding->dwPart |= DBPART_VALUE;
  905. }
  906. // determine offset to the length part
  907. if (pCursorBinding->obVarDataLen != CURSOR_DB_NOVALUE)
  908. {
  909. pBinding->obLength = pCursorBinding->obVarDataLen;
  910. pBinding->dwPart |= DBPART_LENGTH;
  911. }
  912. // determine offset to the status part
  913. if (pCursorBinding->obInfo != CURSOR_DB_NOVALUE)
  914. {
  915. pBinding->obStatus = pCursorBinding->obInfo;
  916. pBinding->dwPart |= DBPART_STATUS;
  917. }
  918. // BYTES always require the length part
  919. if (pCursorBinding->dwDataType == CURSOR_DBTYPE_BYTES &&
  920. pCursorBinding->obData != CURSOR_DB_NOVALUE && !fEntryIDBinding)
  921. {
  922. pBinding->obLength = pCursorBinding->obData;
  923. pBinding->obValue += sizeof(ULONG);
  924. pBinding->dwPart |= DBPART_LENGTH;
  925. }
  926. // check for variant binding, in which case ask for variant
  927. if (pCursorBinding->dwBinding & CURSOR_DBBINDING_VARIANT)
  928. pBinding->wType = DBTYPE_VARIANT;
  929. }
  930. // if any parts needed, increment fixed buffer binding
  931. if (pBinding->dwPart)
  932. {
  933. pulIndex[ulBindings] = ulCol;
  934. ulBindings++;
  935. pBinding++;
  936. }
  937. // if any parts needed, increment variable buffer helper binding
  938. if (pHelperBinding->dwPart)
  939. {
  940. ulHelperBindings++;
  941. pHelperBinding++;
  942. }
  943. // if any parts needed, increment variable buffer binding count
  944. if (pVarBinding->dwPart)
  945. {
  946. // entryID bindings do not need value part
  947. if (fEntryIDBinding)
  948. pVarBinding->dwPart &= ~DBPART_VALUE;
  949. ulVarBindings++;
  950. }
  951. // however, always increment variable buffer binding
  952. pVarBinding++;
  953. // get next cursor binding
  954. pCursorBinding++;
  955. }
  956. hr = S_OK;
  957. // try to create fixed length buffer accessor
  958. HACCESSOR hAccessor = 0;
  959. if (ulBindings)
  960. {
  961. // make adjustments that can cause failure in GetData
  962. MakeAdjustments(ulBindings, pBindings, pulIndex, ulTotalBindings, &rghAdjustAccessors, &pdwAdjustFlags, TRUE);
  963. hr = pAccessor->CreateAccessor(DBACCESSOR_ROWDATA, ulBindings, pBindings, 0, &hAccessor, NULL);
  964. }
  965. if (FAILED(hr))
  966. {
  967. // make other known adjustments that can cause CreateAccessor to fail
  968. hr = MakeAdjustments(ulBindings, pBindings, pulIndex, ulTotalBindings, &rghAdjustAccessors, &pdwAdjustFlags, FALSE);
  969. if (SUCCEEDED(hr))
  970. hr = pAccessor->CreateAccessor(DBACCESSOR_ROWDATA, ulBindings, pBindings, 0, &hAccessor, NULL);
  971. }
  972. delete [] pulIndex;
  973. delete [] pBindings;
  974. hr = VDMapRowsetHRtoCursorHR(hr, IDS_ERR_CREATEACCESSORFAILED, IID_ICursor, pAccessor, IID_IAccessor, m_pResourceDLL);
  975. if (FAILED(hr))
  976. {
  977. delete [] pHelperBindings;
  978. delete [] pVarBindings;
  979. ReleaseAccessorArray(rghAdjustAccessors);
  980. delete [] rghAdjustAccessors;
  981. delete [] pdwAdjustFlags;
  982. return hr;
  983. }
  984. // try to create variable length buffer accessors helper
  985. HACCESSOR hVarHelper = 0;
  986. if (ulHelperBindings)
  987. hr = pAccessor->CreateAccessor(DBACCESSOR_ROWDATA, ulHelperBindings, pHelperBindings, 0, &hVarHelper, NULL);
  988. delete [] pHelperBindings;
  989. hr = VDMapRowsetHRtoCursorHR(hr, IDS_ERR_CREATEACCESSORFAILED, IID_ICursor, pAccessor, IID_IAccessor, m_pResourceDLL);
  990. if (FAILED(hr))
  991. {
  992. pAccessor->ReleaseAccessor(hAccessor, NULL);
  993. delete [] pVarBindings;
  994. ReleaseAccessorArray(rghAdjustAccessors);
  995. delete [] rghAdjustAccessors;
  996. delete [] pdwAdjustFlags;
  997. return hr;
  998. }
  999. // try to create variable length buffer accessors
  1000. HACCESSOR * rghVarAccessors = NULL;
  1001. if (ulTotalBindings)
  1002. {
  1003. rghVarAccessors = new HACCESSOR[ulTotalBindings];
  1004. if (!rghVarAccessors)
  1005. hr = E_OUTOFMEMORY;
  1006. else
  1007. {
  1008. pVarBinding = pVarBindings;
  1009. memset(rghVarAccessors, 0, ulTotalBindings * sizeof(HACCESSOR));
  1010. // iterate through rowset bindings and create accessor for one which have a part
  1011. for (ULONG ulBind = 0; ulBind < ulTotalBindings && SUCCEEDED(hr); ulBind++)
  1012. {
  1013. if (pVarBinding->dwPart)
  1014. hr = pAccessor->CreateAccessor(DBACCESSOR_ROWDATA, 1, pVarBinding, 0, &rghVarAccessors[ulBind], NULL);
  1015. pVarBinding++;
  1016. }
  1017. }
  1018. }
  1019. delete [] pVarBindings;
  1020. hr = VDMapRowsetHRtoCursorHR(hr, IDS_ERR_CREATEACCESSORFAILED, IID_ICursor, pAccessor, IID_IAccessor, m_pResourceDLL);
  1021. if (FAILED(hr))
  1022. {
  1023. if (rghVarAccessors)
  1024. {
  1025. // iterate through rowset bindings and destroy any created accessors
  1026. for (ULONG ulBind = 0; ulBind < ulTotalBindings; ulBind++)
  1027. {
  1028. if (rghVarAccessors[ulBind])
  1029. pAccessor->ReleaseAccessor(rghVarAccessors[ulBind], NULL);
  1030. }
  1031. delete [] rghVarAccessors;
  1032. }
  1033. pAccessor->ReleaseAccessor(hAccessor, NULL);
  1034. pAccessor->ReleaseAccessor(hVarHelper, NULL);
  1035. ReleaseAccessorArray(rghAdjustAccessors);
  1036. delete [] rghAdjustAccessors;
  1037. delete [] pdwAdjustFlags;
  1038. return hr;
  1039. }
  1040. // destroy old accessors
  1041. DestroyAccessors();
  1042. // store new accessors
  1043. m_hAccessor = hAccessor;
  1044. m_hVarHelper = hVarHelper;
  1045. m_ulVarBindings = ulVarBindings;
  1046. m_rghVarAccessors = rghVarAccessors;
  1047. m_rghAdjustAccessors = rghAdjustAccessors;
  1048. m_pdwAdjustFlags = pdwAdjustFlags;
  1049. return hr;
  1050. }
  1051. //=--------------------------------------------------------------------------=
  1052. // ReleaseAccessorArray - Release all accessors in specified array
  1053. //
  1054. void CVDCursor::ReleaseAccessorArray(HACCESSOR * rghAccessors)
  1055. {
  1056. IAccessor * pAccessor = GetAccessor();
  1057. if (pAccessor && rghAccessors)
  1058. {
  1059. for (ULONG ulBind = 0; ulBind < m_ulCursorBindings; ulBind++)
  1060. {
  1061. if (rghAccessors[ulBind])
  1062. {
  1063. pAccessor->ReleaseAccessor(rghAccessors[ulBind], NULL);
  1064. rghAccessors[ulBind] = NULL;
  1065. }
  1066. }
  1067. }
  1068. }
  1069. //=--------------------------------------------------------------------------=
  1070. // DestroyAccessors - Destroy all rowset accessors
  1071. //
  1072. void CVDCursor::DestroyAccessors()
  1073. {
  1074. IAccessor * pAccessor = GetAccessor();
  1075. if (pAccessor && m_hAccessor)
  1076. {
  1077. pAccessor->ReleaseAccessor(m_hAccessor, NULL);
  1078. m_hAccessor = 0;
  1079. }
  1080. if (pAccessor && m_hVarHelper)
  1081. {
  1082. pAccessor->ReleaseAccessor(m_hVarHelper, NULL);
  1083. m_hVarHelper = 0;
  1084. }
  1085. m_ulVarBindings = 0;
  1086. ReleaseAccessorArray(m_rghVarAccessors);
  1087. delete [] m_rghVarAccessors;
  1088. m_rghVarAccessors = NULL;
  1089. ReleaseAccessorArray(m_rghAdjustAccessors);
  1090. delete [] m_rghAdjustAccessors;
  1091. m_rghAdjustAccessors = NULL;
  1092. delete [] m_pdwAdjustFlags;
  1093. m_pdwAdjustFlags = NULL;
  1094. }
  1095. //=--------------------------------------------------------------------------=
  1096. // ReCreateColumns - Re-create rowset columns associated with current bindings
  1097. //
  1098. HRESULT CVDCursor::ReCreateColumns()
  1099. {
  1100. DestroyColumns();
  1101. if (m_ulCursorBindings)
  1102. {
  1103. m_ppColumns = new CVDRowsetColumn*[m_ulCursorBindings];
  1104. if (!m_ppColumns)
  1105. {
  1106. VDSetErrorInfo(IDS_ERR_OUTOFMEMORY, IID_ICursor, m_pResourceDLL);
  1107. return E_OUTOFMEMORY;
  1108. }
  1109. CURSOR_DBCOLUMNBINDING * pCursorBinding = m_pCursorBindings;
  1110. for (ULONG ulBind = 0; ulBind < m_ulCursorBindings; ulBind++)
  1111. {
  1112. m_ppColumns[ulBind] = GetRowsetColumn(pCursorBinding->columnID);
  1113. pCursorBinding++;
  1114. }
  1115. }
  1116. return S_OK;
  1117. }
  1118. //=--------------------------------------------------------------------------=
  1119. // DestroyColumns - Destroy rowset column pointers
  1120. //
  1121. void CVDCursor::DestroyColumns()
  1122. {
  1123. delete [] m_ppColumns;
  1124. m_ppColumns = NULL;
  1125. }
  1126. //=--------------------------------------------------------------------------=
  1127. // InsertNewRow - Insert a new row and set in cursor position object
  1128. //
  1129. HRESULT CVDCursor::InsertNewRow()
  1130. {
  1131. IRowset * pRowset = GetRowset();
  1132. IAccessor * pAccessor = GetAccessor();
  1133. IRowsetChange * pRowsetChange = GetRowsetChange();
  1134. // make sure we have valid rowset, accessor and change pointers
  1135. if (!pRowset || !pAccessor || !pRowsetChange || !IsRowsetValid())
  1136. {
  1137. VDSetErrorInfo(IDS_ERR_ROWSETRELEASED, IID_ICursorUpdateARow, m_pResourceDLL);
  1138. return E_FAIL;
  1139. }
  1140. HACCESSOR hAccessor;
  1141. // create null accessor
  1142. HRESULT hr = pAccessor->CreateAccessor(DBACCESSOR_ROWDATA, 0, NULL, 0, &hAccessor, NULL);
  1143. hr = VDMapRowsetHRtoCursorHR(hr, IDS_ERR_CREATEACCESSORFAILED, IID_ICursorUpdateARow, pAccessor, IID_IAccessor,
  1144. m_pResourceDLL);
  1145. if (FAILED(hr))
  1146. return hr;
  1147. HROW hRow;
  1148. // insert an empty row using null accessor (set/clear internal insert row flag)
  1149. GetCursorMain()->SetInternalInsertRow(TRUE);
  1150. hr = pRowsetChange->InsertRow(0, hAccessor, NULL, &hRow);
  1151. GetCursorMain()->SetInternalInsertRow(FALSE);
  1152. hr = VDMapRowsetHRtoCursorHR(hr, IDS_ERR_INSERTROWFAILED, IID_ICursorUpdateARow, pRowsetChange, IID_IRowsetChange,
  1153. m_pResourceDLL);
  1154. // release null accessor
  1155. pAccessor->ReleaseAccessor(hAccessor, NULL);
  1156. if (FAILED(hr))
  1157. return hr;
  1158. // set hRow in cursor position object
  1159. hr = m_pCursorPosition->SetAddHRow(hRow);
  1160. // release our reference on hRow
  1161. pRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
  1162. return hr;
  1163. }
  1164. //=--------------------------------------------------------------------------=
  1165. // GetOriginalColumn - Get original column data using same-row clone
  1166. //
  1167. HRESULT CVDCursor::GetOriginalColumn(CVDRowsetColumn * pColumn, CURSOR_DBBINDPARAMS * pBindParams)
  1168. {
  1169. ASSERT_POINTER(pColumn, CVDRowsetColumn)
  1170. ASSERT_POINTER(pBindParams, CURSOR_DBBINDPARAMS)
  1171. // make sure we have all necessary pointers
  1172. if (!pColumn || !pBindParams || !pBindParams->pData)
  1173. {
  1174. VDSetErrorInfo(IDS_ERR_INVALIDARG, IID_ICursorUpdateARow, m_pResourceDLL);
  1175. return E_INVALIDARG;
  1176. }
  1177. // get hRow of the row currently being edited
  1178. HROW hRow = m_pCursorPosition->GetEditRow();
  1179. // see if we already have a same-row clone
  1180. ICursor * pSameRowClone = m_pCursorPosition->GetSameRowClone();
  1181. if (!pSameRowClone)
  1182. {
  1183. // if not, create new same-row clone
  1184. HRESULT hr = Clone(CURSOR_DBCLONEOPTS_SAMEROW, IID_ICursor, (IUnknown**)&pSameRowClone);
  1185. if (FAILED(hr))
  1186. return hr;
  1187. // set same-row clone in cursor position object
  1188. m_pCursorPosition->SetSameRowClone(pSameRowClone);
  1189. }
  1190. CURSOR_DBCOLUMNBINDING columnBinding;
  1191. // set common column binding members
  1192. columnBinding.columnID = pColumn->GetCursorColumnID();
  1193. columnBinding.obData = CURSOR_DB_NOVALUE;
  1194. columnBinding.cbMaxLen = pBindParams->cbMaxLen;
  1195. columnBinding.obVarDataLen = CURSOR_DB_NOVALUE;
  1196. columnBinding.obInfo = CURSOR_DB_NOVALUE;
  1197. columnBinding.dwBinding = CURSOR_DBBINDING_DEFAULT;
  1198. columnBinding.dwDataType = pBindParams->dwDataType;
  1199. // adjust column binding for variable length datatypes
  1200. if (DoesCursorTypeNeedVarData(pBindParams->dwDataType))
  1201. {
  1202. switch (pBindParams->dwDataType)
  1203. {
  1204. case CURSOR_DBTYPE_BLOB:
  1205. columnBinding.dwDataType = CURSOR_DBTYPE_BYTES;
  1206. break;
  1207. case CURSOR_DBTYPE_LPSTR:
  1208. columnBinding.dwDataType = CURSOR_DBTYPE_CHARS;
  1209. break;
  1210. case CURSOR_DBTYPE_LPWSTR:
  1211. columnBinding.dwDataType = CURSOR_DBTYPE_WCHARS;
  1212. break;
  1213. }
  1214. }
  1215. CURSOR_DBFETCHROWS fetchRows;
  1216. // set common fetch rows members
  1217. fetchRows.cRowsRequested = 1;
  1218. fetchRows.dwFlags = CURSOR_DBROWFETCH_DEFAULT;
  1219. fetchRows.pVarData = NULL;
  1220. fetchRows.cbVarData = 0;
  1221. // retrieve length and/or information field if requested
  1222. if (pBindParams->cbVarDataLen != CURSOR_DB_NOVALUE || pBindParams->dwInfo != CURSOR_DB_NOVALUE)
  1223. {
  1224. // set column binding offsets
  1225. if (pBindParams->cbVarDataLen != CURSOR_DB_NOVALUE)
  1226. columnBinding.obVarDataLen = offsetof(CURSOR_DBBINDPARAMS, cbVarDataLen);
  1227. if (pBindParams->dwInfo != CURSOR_DB_NOVALUE)
  1228. columnBinding.obInfo = offsetof(CURSOR_DBBINDPARAMS, dwInfo);
  1229. // set bindings on same-row clone
  1230. HRESULT hr = pSameRowClone->SetBindings(1, &columnBinding, 0, CURSOR_DBCOLUMNBINDOPTS_REPLACE);
  1231. if (FAILED(hr))
  1232. return hr;
  1233. // set fetch rows buffer
  1234. fetchRows.pData = pBindParams;
  1235. // retrieve length and/or information field from same-row clone
  1236. hr = ((CVDCursor*)pSameRowClone)->FillConsumersBuffer(S_OK, &fetchRows, 1, &hRow);
  1237. if (FAILED(hr))
  1238. return hr;
  1239. }
  1240. // set column binding offsets and bind-type
  1241. columnBinding.obData = 0;
  1242. columnBinding.obVarDataLen = CURSOR_DB_NOVALUE;
  1243. columnBinding.obInfo = CURSOR_DB_NOVALUE;
  1244. columnBinding.dwBinding = pBindParams->dwBinding;
  1245. // adjust offsets for variable length datatypes
  1246. if (DoesCursorTypeNeedVarData(pBindParams->dwDataType))
  1247. {
  1248. columnBinding.dwBinding = CURSOR_DBBINDING_DEFAULT;
  1249. if (pBindParams->dwBinding & CURSOR_DBBINDING_VARIANT)
  1250. {
  1251. if (pBindParams->dwDataType == CURSOR_DBTYPE_BLOB)
  1252. columnBinding.obVarDataLen = columnBinding.obData;
  1253. columnBinding.obData += sizeof(CURSOR_DBVARIANT);
  1254. }
  1255. else
  1256. {
  1257. switch (pBindParams->dwDataType)
  1258. {
  1259. case CURSOR_DBTYPE_BLOB:
  1260. columnBinding.obVarDataLen = columnBinding.obData;
  1261. columnBinding.obData += sizeof(ULONG) + sizeof(LPBYTE);
  1262. break;
  1263. case CURSOR_DBTYPE_LPSTR:
  1264. columnBinding.obData += sizeof(LPSTR);
  1265. break;
  1266. case CURSOR_DBTYPE_LPWSTR:
  1267. columnBinding.obData += sizeof(LPWSTR);
  1268. break;
  1269. }
  1270. }
  1271. }
  1272. // set bindings on same-row clone
  1273. HRESULT hr = pSameRowClone->SetBindings(1, &columnBinding, pBindParams->cbMaxLen, CURSOR_DBCOLUMNBINDOPTS_REPLACE);
  1274. if (FAILED(hr))
  1275. return hr;
  1276. // set fetch rows buffer
  1277. fetchRows.pData = pBindParams->pData;
  1278. // retrieve data value from same-row clone
  1279. hr = ((CVDCursor*)pSameRowClone)->FillConsumersBuffer(S_OK, &fetchRows, 1, &hRow);
  1280. if (FAILED(hr))
  1281. return hr;
  1282. // place data pointers in buffer for variable length datatypes
  1283. if (DoesCursorTypeNeedVarData(pBindParams->dwDataType))
  1284. {
  1285. BYTE * pData = (BYTE*)pBindParams->pData;
  1286. // first check for variant binding
  1287. if (pBindParams->dwBinding & CURSOR_DBBINDING_VARIANT)
  1288. {
  1289. CURSOR_BLOB cursorBlob;
  1290. CURSOR_DBVARIANT * pVariant = (CURSOR_DBVARIANT*)pBindParams->pData;
  1291. switch (pBindParams->dwDataType)
  1292. {
  1293. case CURSOR_DBTYPE_BLOB:
  1294. cursorBlob.cbSize = *(ULONG*)pVariant;
  1295. cursorBlob.pBlobData = pData + sizeof(CURSOR_DBVARIANT);
  1296. VariantInit((VARIANT*)pVariant);
  1297. pVariant->vt = CURSOR_DBTYPE_BLOB;
  1298. pVariant->blob = cursorBlob;
  1299. break;
  1300. case CURSOR_DBTYPE_LPSTR:
  1301. VariantInit((VARIANT*)pVariant);
  1302. pVariant->vt = CURSOR_DBTYPE_LPSTR;
  1303. pVariant->pszVal = (LPSTR)(pData + sizeof(CURSOR_DBVARIANT));
  1304. break;
  1305. case CURSOR_DBTYPE_LPWSTR:
  1306. VariantInit((VARIANT*)pVariant);
  1307. pVariant->vt = CURSOR_DBTYPE_LPSTR;
  1308. pVariant->pwszVal = (LPWSTR)(pData + sizeof(CURSOR_DBVARIANT));
  1309. break;
  1310. }
  1311. }
  1312. else // otherwise, default binding
  1313. {
  1314. switch (pBindParams->dwDataType)
  1315. {
  1316. case CURSOR_DBTYPE_BLOB:
  1317. *(LPBYTE*)(pData + sizeof(ULONG)) = pData + sizeof(ULONG) + sizeof(LPBYTE);
  1318. break;
  1319. case CURSOR_DBTYPE_LPSTR:
  1320. *(LPSTR*)pData = (LPSTR)(pData + sizeof(LPSTR));
  1321. break;
  1322. case CURSOR_DBTYPE_LPWSTR:
  1323. *(LPWSTR*)pData = (LPWSTR)(pData + sizeof(LPWSTR));
  1324. break;
  1325. }
  1326. }
  1327. }
  1328. return S_OK;
  1329. }
  1330. //=--------------------------------------------------------------------------=
  1331. // GetModifiedColumn - Get modified column data from column update object
  1332. //
  1333. HRESULT CVDCursor::GetModifiedColumn(CVDColumnUpdate * pColumnUpdate, CURSOR_DBBINDPARAMS * pBindParams)
  1334. {
  1335. ASSERT_POINTER(pColumnUpdate, CVDColumnUpdate)
  1336. ASSERT_POINTER(pBindParams, CURSOR_DBBINDPARAMS)
  1337. // make sure we have all necessary pointers
  1338. if (!pColumnUpdate || !pBindParams || !pBindParams->pData)
  1339. {
  1340. VDSetErrorInfo(IDS_ERR_INVALIDARG, IID_ICursorUpdateARow, m_pResourceDLL);
  1341. return E_INVALIDARG;
  1342. }
  1343. // get source variant
  1344. CURSOR_DBVARIANT varSrc = pColumnUpdate->GetVariant();
  1345. // check for any variant binding
  1346. if (pBindParams->dwDataType == CURSOR_DBTYPE_ANYVARIANT)
  1347. pBindParams->dwDataType = varSrc.vt;
  1348. // determine which type the destination variant should be
  1349. VARTYPE vtDest = (VARTYPE)pBindParams->dwDataType;
  1350. switch (vtDest)
  1351. {
  1352. case CURSOR_DBTYPE_BYTES:
  1353. vtDest = CURSOR_DBTYPE_BLOB;
  1354. break;
  1355. case CURSOR_DBTYPE_CHARS:
  1356. case CURSOR_DBTYPE_WCHARS:
  1357. case CURSOR_DBTYPE_LPSTR:
  1358. case CURSOR_DBTYPE_LPWSTR:
  1359. vtDest = VT_BSTR;
  1360. break;
  1361. }
  1362. HRESULT hr = S_OK;
  1363. CURSOR_DBVARIANT varDest;
  1364. BOOL fVariantCreated = FALSE;
  1365. // init destination variant
  1366. VariantInit((VARIANT*)&varDest);
  1367. // get destination variant
  1368. if (varSrc.vt != vtDest)
  1369. {
  1370. // if the types do not match, then create a variant of the desired type
  1371. hr = VariantChangeType((VARIANT*)&varDest, (VARIANT*)&varSrc, 0, vtDest);
  1372. fVariantCreated = TRUE;
  1373. }
  1374. else
  1375. varDest = varSrc;
  1376. if (FAILED(hr))
  1377. {
  1378. VDSetErrorInfo(IDS_ERR_INVALIDARG, IID_ICursorUpdateARow, m_pResourceDLL);
  1379. return E_INVALIDARG;
  1380. }
  1381. // get pointer to data
  1382. BYTE * pData = (BYTE*)pBindParams->pData;
  1383. // return coerced data
  1384. if (pBindParams->dwBinding & CURSOR_DBBINDING_VARIANT)
  1385. {
  1386. // get pointer to variant data
  1387. CURSOR_DBVARIANT * pVariant = (CURSOR_DBVARIANT*)pData;
  1388. // return variant
  1389. *pVariant = varDest;
  1390. // adjust variant for variable length datatypes
  1391. if (pBindParams->dwDataType == CURSOR_DBTYPE_BLOB)
  1392. {
  1393. pVariant->blob.pBlobData = pData + sizeof(CURSOR_DBVARIANT);
  1394. memcpy(pData + sizeof(CURSOR_DBVARIANT), varDest.blob.pBlobData, varDest.blob.cbSize);
  1395. }
  1396. else if (pBindParams->dwDataType == CURSOR_DBTYPE_LPSTR)
  1397. {
  1398. ULONG cbLength = GET_MBCSLEN_FROMWIDE(varDest.bstrVal);
  1399. MAKE_MBCSPTR_FROMWIDE(psz, varDest.bstrVal);
  1400. pVariant->pszVal = (LPSTR)(pData + sizeof(CURSOR_DBVARIANT));
  1401. memcpy(pData + sizeof(CURSOR_DBVARIANT), psz, min(pBindParams->cbMaxLen, cbLength));
  1402. }
  1403. else if (pBindParams->dwDataType == CURSOR_DBTYPE_LPWSTR)
  1404. {
  1405. ULONG cbLength = (lstrlenW(varDest.bstrVal) + 1) * sizeof(WCHAR);
  1406. pVariant->pwszVal = (LPWSTR)(pData + sizeof(CURSOR_DBVARIANT));
  1407. memcpy(pData + sizeof(CURSOR_DBVARIANT), varDest.bstrVal, min(pBindParams->cbMaxLen, cbLength));
  1408. }
  1409. else if (pBindParams->dwDataType == VT_BSTR)
  1410. {
  1411. pVariant->bstrVal = SysAllocString(pVariant->bstrVal);
  1412. }
  1413. }
  1414. else // otherwise, default binding
  1415. {
  1416. // first check for variable length datatypes
  1417. if (pBindParams->dwDataType == CURSOR_DBTYPE_BYTES)
  1418. {
  1419. *(ULONG*)pData = varDest.blob.cbSize;
  1420. memcpy(pData + sizeof(ULONG), varDest.blob.pBlobData, varDest.blob.cbSize);
  1421. }
  1422. else if (pBindParams->dwDataType == CURSOR_DBTYPE_CHARS)
  1423. {
  1424. ULONG cbLength = GET_MBCSLEN_FROMWIDE(varDest.bstrVal);
  1425. MAKE_MBCSPTR_FROMWIDE(psz, varDest.bstrVal);
  1426. memcpy(pData, psz, min(pBindParams->cbMaxLen, cbLength));
  1427. }
  1428. else if (pBindParams->dwDataType == CURSOR_DBTYPE_WCHARS)
  1429. {
  1430. ULONG cbLength = (lstrlenW(varDest.bstrVal) + 1) * sizeof(WCHAR);
  1431. memcpy(pData, varDest.bstrVal, min(pBindParams->cbMaxLen, cbLength));
  1432. }
  1433. else if (pBindParams->dwDataType == CURSOR_DBTYPE_BLOB)
  1434. {
  1435. *(ULONG*)pData = varDest.blob.cbSize;
  1436. *(LPBYTE*)(pData + sizeof(ULONG)) = pData + sizeof(ULONG) + sizeof(LPBYTE);
  1437. memcpy(pData + sizeof(ULONG) + sizeof(LPBYTE), varDest.blob.pBlobData, varDest.blob.cbSize);
  1438. }
  1439. else if (pBindParams->dwDataType == CURSOR_DBTYPE_LPSTR)
  1440. {
  1441. ULONG cbLength = GET_MBCSLEN_FROMWIDE(varDest.bstrVal);
  1442. MAKE_MBCSPTR_FROMWIDE(psz, varDest.bstrVal);
  1443. *(LPSTR*)pData = (LPSTR)(pData + sizeof(LPSTR));
  1444. memcpy(pData + sizeof(LPSTR), psz, min(pBindParams->cbMaxLen, cbLength));
  1445. }
  1446. else if (pBindParams->dwDataType == CURSOR_DBTYPE_LPWSTR)
  1447. {
  1448. ULONG cbLength = (lstrlenW(varDest.bstrVal) + 1) * sizeof(WCHAR);
  1449. *(LPWSTR*)pData = (LPWSTR)(pData + sizeof(LPWSTR));
  1450. memcpy(pData + sizeof(LPWSTR), varDest.bstrVal, min(pBindParams->cbMaxLen, cbLength));
  1451. }
  1452. else // fixed length datatypes
  1453. {
  1454. ULONG cbLength = CVDCursorBase::GetCursorTypeLength(pBindParams->dwDataType, 0);
  1455. memcpy(pData, &varDest.cyVal, cbLength);
  1456. }
  1457. }
  1458. // if created, destroy variant
  1459. if (fVariantCreated)
  1460. VariantClear((VARIANT*)&varDest);
  1461. return S_OK;
  1462. }
  1463. //=--------------------------------------------------------------------------=
  1464. // Create - Create cursor object
  1465. //=--------------------------------------------------------------------------=
  1466. // This function creates and initializes a new cursor object
  1467. //
  1468. // Parameters:
  1469. // pCursorPosition - [in] backwards pointer to CVDCursorPosition object
  1470. // ppCursor - [out] a pointer in which to return pointer to cursor object
  1471. // pResourceDLL - [in] a pointer which keeps track of resource DLL
  1472. //
  1473. // Output:
  1474. // HRESULT - S_OK if successful
  1475. // E_OUTOFMEMORY not enough memory to create object
  1476. //
  1477. // Notes:
  1478. //
  1479. HRESULT CVDCursor::Create(CVDCursorPosition * pCursorPosition, CVDCursor ** ppCursor, CVDResourceDLL * pResourceDLL)
  1480. {
  1481. ASSERT_POINTER(pCursorPosition, CVDCursorPosition)
  1482. ASSERT_POINTER(ppCursor, CVDCursor*)
  1483. ASSERT_POINTER(pResourceDLL, CVDResourceDLL)
  1484. if (!pCursorPosition || !ppCursor)
  1485. return E_INVALIDARG;
  1486. *ppCursor = NULL;
  1487. CVDCursor * pCursor = new CVDCursor();
  1488. if (!pCursor)
  1489. return E_OUTOFMEMORY;
  1490. // create connection point container
  1491. HRESULT hr = CVDNotifyDBEventsConnPtCont::Create(pCursor, &pCursor->m_pConnPtContainer);
  1492. if (FAILED(hr))
  1493. {
  1494. delete pCursor;
  1495. return hr;
  1496. }
  1497. ((CVDNotifier*)pCursorPosition)->AddRef(); // add reference to associated cursor position object
  1498. pCursor->m_pCursorPosition = pCursorPosition;
  1499. pCursor->m_pResourceDLL = pResourceDLL;
  1500. // add to pCursorPosition's notification family
  1501. pCursor->JoinFamily(pCursorPosition);
  1502. *ppCursor = pCursor;
  1503. return S_OK;
  1504. }
  1505. //=--------------------------------------------------------------------------=
  1506. // IUnknown methods implemented
  1507. //=--------------------------------------------------------------------------=
  1508. //=--------------------------------------------------------------------------=
  1509. // IUnknown QueryInterface
  1510. //
  1511. HRESULT CVDCursor::QueryInterface(REFIID riid, void **ppvObjOut)
  1512. {
  1513. ASSERT_POINTER(ppvObjOut, IUnknown*)
  1514. if (!ppvObjOut)
  1515. return E_INVALIDARG;
  1516. *ppvObjOut = NULL;
  1517. switch (riid.Data1)
  1518. {
  1519. QI_INTERFACE_SUPPORTED_IF(this, ICursorUpdateARow, GetRowsetChange());
  1520. QI_INTERFACE_SUPPORTED_IF(this, ICursorFind, GetRowsetFind());
  1521. QI_INTERFACE_SUPPORTED(this, IEntryID);
  1522. QI_INTERFACE_SUPPORTED(m_pConnPtContainer, IConnectionPointContainer);
  1523. }
  1524. if (NULL == *ppvObjOut)
  1525. return CVDCursorBase::QueryInterface(riid, ppvObjOut);
  1526. CVDNotifier::AddRef();
  1527. return S_OK;
  1528. }
  1529. //=--------------------------------------------------------------------------=
  1530. // IUnknown AddRef (this override is needed to instantiate class)
  1531. //
  1532. ULONG CVDCursor::AddRef(void)
  1533. {
  1534. return CVDNotifier::AddRef();
  1535. }
  1536. //=--------------------------------------------------------------------------=
  1537. // IUnknown Release (this override is needed to instantiate class)
  1538. //
  1539. ULONG CVDCursor::Release(void)
  1540. {
  1541. return CVDNotifier::Release();
  1542. }
  1543. //=--------------------------------------------------------------------------=
  1544. // ICursor methods implemented
  1545. //=--------------------------------------------------------------------------=
  1546. //=--------------------------------------------------------------------------=
  1547. // ICursor GetColumnsCursor
  1548. //=--------------------------------------------------------------------------=
  1549. // Creates a cursor containing information about the current cursor
  1550. //
  1551. // Parameters:
  1552. // riid - [in] the interface ID to which to return a pointer
  1553. // ppvColumnsCursor - [out] a pointer to memory in which to return the
  1554. // interface pointer
  1555. // pcRows - [out] a pointer to memory in which to return the
  1556. // number of rows in the metadata cursor
  1557. //
  1558. // Output:
  1559. // HRESULT - S_OK if successful
  1560. // E_FAIL can't create cursor
  1561. // E_INVALIDARG bad parameter
  1562. // E_OUTOFMEMORY not enough memory
  1563. // E_NOINTERFACE interface not available
  1564. //
  1565. // Notes:
  1566. //
  1567. HRESULT CVDCursor::GetColumnsCursor(REFIID riid, IUnknown **ppvColumnsCursor, ULONG *pcRows)
  1568. {
  1569. ASSERT_POINTER(ppvColumnsCursor, IUnknown*)
  1570. ASSERT_NULL_OR_POINTER(pcRows, ULONG)
  1571. if (!IsRowsetValid())
  1572. {
  1573. VDSetErrorInfo(IDS_ERR_ROWSETRELEASED, IID_ICursor, m_pResourceDLL);
  1574. return E_FAIL;
  1575. }
  1576. if (!ppvColumnsCursor)
  1577. {
  1578. VDSetErrorInfo(IDS_ERR_INVALIDARG, IID_ICursor, m_pResourceDLL);
  1579. return E_INVALIDARG;
  1580. }
  1581. // init out parameters
  1582. *ppvColumnsCursor = NULL;
  1583. if (pcRows)
  1584. *pcRows = 0;
  1585. // make sure caller asked for an available interface
  1586. if (riid != IID_IUnknown && riid != IID_ICursor && riid != IID_ICursorMove && riid != IID_ICursorScroll)
  1587. {
  1588. VDSetErrorInfo(IDS_ERR_NOINTERFACE, IID_ICursor, m_pResourceDLL);
  1589. return E_NOINTERFACE;
  1590. }
  1591. // create metadata cursor
  1592. CVDMetadataCursor * pMetadataCursor;
  1593. ULONG ulColumns = GetCursorMain()->GetColumnsCount();
  1594. CVDRowsetColumn * pColumns = GetCursorMain()->InternalGetColumns();
  1595. ULONG ulMetaColumns = GetCursorMain()->GetMetaColumnsCount();
  1596. CVDRowsetColumn * pMetaColumns = GetCursorMain()->InternalGetMetaColumns();
  1597. if (!GetCursorMain()->IsColumnsRowsetSupported())
  1598. ulMetaColumns -= VD_COLUMNSROWSET_MAX_OPT_COLUMNS;
  1599. HRESULT hr = CVDMetadataCursor::Create(ulColumns,
  1600. pColumns,
  1601. ulMetaColumns,
  1602. pMetaColumns,
  1603. &pMetadataCursor,
  1604. m_pResourceDLL);
  1605. if (FAILED(hr)) // the only reason for failing here is an out of memory condition
  1606. {
  1607. VDSetErrorInfo(IDS_ERR_OUTOFMEMORY, IID_ICursor, m_pResourceDLL);
  1608. return hr;
  1609. }
  1610. *ppvColumnsCursor = (ICursor*)pMetadataCursor;
  1611. if (pcRows)
  1612. *pcRows = ulColumns;
  1613. return S_OK;
  1614. }
  1615. //=--------------------------------------------------------------------------=
  1616. // ICursor SetBindings
  1617. //=--------------------------------------------------------------------------=
  1618. // Replaces the existing column bindings or adds new column bindings to the
  1619. // existing ones
  1620. //
  1621. // Parameters:
  1622. // cCol - [in] the number of columns to bind
  1623. // rgBoundColumns - [in] an array of column bindings, one for each
  1624. // column for which data is to be returned
  1625. // cbRowLength - [in] the number of bytes of inline memory in a
  1626. // single row of data
  1627. // dwFlags - [in] a flag that specifies whether to replace the
  1628. // existing column bindings or add to them
  1629. //
  1630. // Output:
  1631. // HRESULT - S_OK if successful
  1632. // E_INVALIDARG bad parameter
  1633. // E_OUTOFMEMORY not enough memory
  1634. // CURSOR_DB_E_BADBINDINFO bad binding information
  1635. // CURSOR_DB_E_COLUMNUNAVAILABLE columnID is not available
  1636. // CURSOR_DB_E_ROWTOOSHORT cbRowLength was less than the minumum (and not zero)
  1637. //
  1638. // Notes:
  1639. //
  1640. HRESULT CVDCursor::SetBindings(ULONG cCol, CURSOR_DBCOLUMNBINDING rgBoundColumns[], ULONG cbRowLength, DWORD dwFlags)
  1641. {
  1642. ASSERT_NULL_OR_POINTER(rgBoundColumns, CURSOR_DBCOLUMNBINDING)
  1643. if (!IsRowsetValid())
  1644. {
  1645. VDSetErrorInfo(IDS_ERR_ROWSETRELEASED, IID_ICursor, m_pResourceDLL);
  1646. return E_FAIL;
  1647. }
  1648. if (!cCol && dwFlags == CURSOR_DBCOLUMNBINDOPTS_ADD)
  1649. return S_OK;
  1650. if (cCol && !rgBoundColumns)
  1651. {
  1652. VDSetErrorInfo(IDS_ERR_INVALIDARG, IID_ICursor, m_pResourceDLL);
  1653. return E_INVALIDARG;
  1654. }
  1655. if (dwFlags != CURSOR_DBCOLUMNBINDOPTS_REPLACE && dwFlags != CURSOR_DBCOLUMNBINDOPTS_ADD)
  1656. {
  1657. VDSetErrorInfo(IDS_ERR_INVALIDARG, IID_ICursor, m_pResourceDLL);
  1658. return E_INVALIDARG;
  1659. }
  1660. // make sure the bindings are okay
  1661. ULONG ulColumns = GetCursorMain()->GetColumnsCount();
  1662. CVDRowsetColumn * pColumns = GetCursorMain()->InternalGetColumns();
  1663. ULONG cbNewRowLength;
  1664. ULONG cbNewVarRowLength;
  1665. HRESULT hr = ValidateCursorBindings(ulColumns, pColumns, cCol, rgBoundColumns, cbRowLength, dwFlags,
  1666. &cbNewRowLength, &cbNewVarRowLength);
  1667. if (SUCCEEDED(hr))
  1668. {
  1669. // if so, then try to create new accessors
  1670. hr = ReCreateAccessors(cCol, rgBoundColumns, dwFlags);
  1671. if (SUCCEEDED(hr))
  1672. {
  1673. // if all is okay, then set bindings in cursor
  1674. hr = CVDCursorBase::SetBindings(cCol, rgBoundColumns, cbRowLength, dwFlags);
  1675. if (SUCCEEDED(hr))
  1676. {
  1677. // store new row lengths computed during validation
  1678. m_cbRowLength = cbNewRowLength;
  1679. m_cbVarRowLength = cbNewVarRowLength;
  1680. // recreate column pointers
  1681. hr = ReCreateColumns();
  1682. }
  1683. }
  1684. }
  1685. return hr;
  1686. }
  1687. //=--------------------------------------------------------------------------=
  1688. // FilterNewRow - Filter addrow from fetch
  1689. //=--------------------------------------------------------------------------=
  1690. // This function determines if the last row fetch was an addrow, in which case
  1691. // it releases and removes this row from the block of fetched hRows
  1692. //
  1693. // Parameters:
  1694. // pcRowsObtained - [in/out] a pointer to the number of hRows
  1695. // rghRows - [in/out] an array of nRows fetched
  1696. // hr - [in] result of fetch
  1697. //
  1698. // Output:
  1699. // HRESULT - E_FAIL rowset is invalid
  1700. // E_INVALIDARG bad parameter
  1701. // DB_E_BADSTARTPOSITION no rows fetched
  1702. // DB_S_ENDOFROWSET reached end of rowset
  1703. //
  1704. // Notes:
  1705. // This function was added to assist in filtering out of add-rows which
  1706. // appear as part of the underlying rowset, however should not appear as
  1707. // part of the implemeted cursor.
  1708. //
  1709. HRESULT CVDCursor::FilterNewRow(ULONG * pcRowsObtained, HROW * rghRows, HRESULT hr)
  1710. {
  1711. ASSERT_POINTER(pcRowsObtained, ULONG)
  1712. ASSERT_NULL_OR_POINTER(rghRows, HROW)
  1713. IRowset * pRowset = GetRowset();
  1714. // make sure we have a valid rowset pointer
  1715. if (!pRowset || !IsRowsetValid())
  1716. {
  1717. VDSetErrorInfo(IDS_ERR_ROWSETRELEASED, IID_ICursor, m_pResourceDLL);
  1718. return E_FAIL;
  1719. }
  1720. // make sure we have necessary pointers
  1721. if (!pcRowsObtained || *pcRowsObtained && !rghRows)
  1722. return E_INVALIDARG;
  1723. if (*pcRowsObtained == 0)
  1724. return hr;
  1725. // detemine if last row fetched is an addrow
  1726. if (GetCursorMain()->IsSameRowAsNew(rghRows[*pcRowsObtained - 1]))
  1727. {
  1728. // if so, release hRow
  1729. pRowset->ReleaseRows(1, &rghRows[*pcRowsObtained - 1], NULL, NULL, NULL);
  1730. // decrement fetch count
  1731. *pcRowsObtained -= 1;
  1732. // return appropriate result
  1733. return *pcRowsObtained == 0 ? DB_E_BADSTARTPOSITION : DB_S_ENDOFROWSET;
  1734. }
  1735. return hr;
  1736. }
  1737. //=--------------------------------------------------------------------------=
  1738. // ICursor GetNextRows
  1739. //=--------------------------------------------------------------------------=
  1740. // Fetches the specified number of rows starting with the row after the
  1741. // current one
  1742. //
  1743. // Parameters:
  1744. // udlRowsToSkip - [in] the number of rows to skip before fetching
  1745. // pFetchParams - [in, out] a pointer to fetch rows structure
  1746. //
  1747. // Output:
  1748. // HRESULT - S_OK if successful
  1749. // E_FAIL rowset is invalid
  1750. // CURSOR_DB_S_ENDOFCURSOR reached end of the cursor
  1751. //
  1752. // Notes:
  1753. //
  1754. HRESULT CVDCursor::GetNextRows(LARGE_INTEGER udlRowsToSkip, CURSOR_DBFETCHROWS *pFetchParams)
  1755. {
  1756. ASSERT_NULL_OR_POINTER(pFetchParams, CURSOR_DBFETCHROWS)
  1757. if (!IsRowsetValid())
  1758. {
  1759. VDSetErrorInfo(IDS_ERR_ROWSETRELEASED, IID_ICursor, m_pResourceDLL);
  1760. return E_FAIL;
  1761. }
  1762. // return if caller doesn't supply fetch rows structure
  1763. if (!pFetchParams)
  1764. return S_OK;
  1765. // vaildate fetch params (implemented on CVDCursorBase
  1766. HRESULT hr = ValidateFetchParams(pFetchParams, IID_ICursor);
  1767. // return if fetch params are invalid
  1768. if (FAILED(hr))
  1769. return hr;
  1770. // return if caller didn't ask for any rows
  1771. if (!pFetchParams->cRowsRequested)
  1772. return S_OK;
  1773. HRESULT hrFetch;
  1774. IRowset * pRowset = GetRowset();
  1775. // notify other interested parties
  1776. DWORD dwEventWhat = CURSOR_DBEVENT_CURRENT_ROW_CHANGED;
  1777. CURSOR_DBNOTIFYREASON rgReasons[1];
  1778. rgReasons[0].dwReason = CURSOR_DBREASON_MOVE;
  1779. rgReasons[0].arg1 = m_pCursorPosition->m_bmCurrent.GetBookmarkVariant();
  1780. VariantInit((VARIANT*)&rgReasons[0].arg2);
  1781. rgReasons[0].arg2.vt = VT_I8;
  1782. rgReasons[0].arg2.cyVal.Lo = udlRowsToSkip.LowPart;
  1783. rgReasons[0].arg2.cyVal.Hi = udlRowsToSkip.HighPart;
  1784. hrFetch = m_pCursorPosition->NotifyBefore(dwEventWhat, 1, rgReasons);
  1785. // make sure action was not cancelled
  1786. if (hrFetch != S_OK)
  1787. {
  1788. VDSetErrorInfo(IDS_ERR_ACTIONCANCELLED, IID_ICursor, m_pResourceDLL);
  1789. return E_FAIL;
  1790. }
  1791. // make sure that an update is not already in progress
  1792. if (m_pCursorPosition->GetEditMode() != CURSOR_DBEDITMODE_NONE)
  1793. {
  1794. m_pCursorPosition->NotifyFail(dwEventWhat, 1, rgReasons);
  1795. VDSetErrorInfo(IDS_ERR_UPDATEINPROGRESS, IID_ICursor, m_pResourceDLL);
  1796. return CURSOR_DB_E_UPDATEINPROGRESS;
  1797. }
  1798. ULONG cRowsObtained = 0;
  1799. HROW * rghRows = NULL;
  1800. BYTE bSpecialBM;
  1801. ULONG cbBookmark;
  1802. BYTE * pBookmark;
  1803. switch (m_pCursorPosition->m_bmCurrent.GetStatus())
  1804. {
  1805. case VDBOOKMARKSTATUS_BEGINNING:
  1806. cbBookmark = sizeof(BYTE);
  1807. bSpecialBM = DBBMK_FIRST;
  1808. pBookmark = &bSpecialBM;
  1809. break;
  1810. case VDBOOKMARKSTATUS_END:
  1811. m_pCursorPosition->NotifyFail(dwEventWhat, 1, rgReasons);
  1812. return CURSOR_DB_S_ENDOFCURSOR;
  1813. case VDBOOKMARKSTATUS_CURRENT:
  1814. cbBookmark = m_pCursorPosition->m_bmCurrent.GetBookmarkLen();
  1815. pBookmark = m_pCursorPosition->m_bmCurrent.GetBookmark();
  1816. udlRowsToSkip.LowPart++;
  1817. break;
  1818. default:
  1819. m_pCursorPosition->NotifyFail(dwEventWhat, 1, rgReasons);
  1820. ASSERT_(FALSE);
  1821. VDSetErrorInfo(IDS_ERR_INVALIDBMSTATUS, IID_ICursor, m_pResourceDLL);
  1822. return E_FAIL;
  1823. }
  1824. hrFetch = GetRowsetLocate()->GetRowsAt(0, 0, cbBookmark, pBookmark,
  1825. udlRowsToSkip.LowPart,
  1826. pFetchParams->cRowsRequested,
  1827. &cRowsObtained, &rghRows);
  1828. hrFetch = FilterNewRow(&cRowsObtained, rghRows, hrFetch);
  1829. if (S_OK != hrFetch)
  1830. hrFetch = VDMapRowsetHRtoCursorHR(hrFetch, IDS_ERR_GETROWSATFAILED, IID_ICursor, GetRowsetLocate(), IID_IRowsetLocate, m_pResourceDLL);
  1831. if FAILED(hrFetch)
  1832. {
  1833. if (cRowsObtained)
  1834. {
  1835. // release hRows and associated memory
  1836. pRowset->ReleaseRows(cRowsObtained, rghRows, NULL, NULL, NULL);
  1837. g_pMalloc->Free(rghRows);
  1838. }
  1839. m_pCursorPosition->NotifyFail(dwEventWhat, 1, rgReasons);
  1840. return hrFetch;
  1841. }
  1842. if (cRowsObtained)
  1843. {
  1844. HRESULT hrMove = S_OK;
  1845. // if got all rows requested then set current position to last row retrieved
  1846. if (SUCCEEDED(hrFetch) &&
  1847. cRowsObtained == pFetchParams->cRowsRequested)
  1848. hrMove = m_pCursorPosition->SetRowPosition(rghRows[cRowsObtained - 1]);
  1849. // only do this if succeeded
  1850. if (SUCCEEDED(hrMove))
  1851. {
  1852. // fill consumers buffer
  1853. hrFetch = FillConsumersBuffer(hrFetch, pFetchParams, cRowsObtained, rghRows);
  1854. // if got all rows requested then set current position to last row retrieved (internally)
  1855. if (SUCCEEDED(hrFetch) &&
  1856. cRowsObtained == pFetchParams->cRowsRequested)
  1857. m_pCursorPosition->SetCurrentHRow(rghRows[cRowsObtained - 1]);
  1858. }
  1859. // release hRows and associated memory
  1860. pRowset->ReleaseRows(cRowsObtained, rghRows, NULL, NULL, NULL);
  1861. g_pMalloc->Free(rghRows);
  1862. // report failure
  1863. if (FAILED(hrMove))
  1864. {
  1865. cRowsObtained = 0;
  1866. hrFetch = E_FAIL;
  1867. }
  1868. }
  1869. if (SUCCEEDED(hrFetch) &&
  1870. cRowsObtained < pFetchParams->cRowsRequested)
  1871. m_pCursorPosition->SetCurrentRowStatus(VDBOOKMARKSTATUS_END);
  1872. if SUCCEEDED(hrFetch)
  1873. {
  1874. rgReasons[0].arg1 = m_pCursorPosition->m_bmCurrent.GetBookmarkVariant();
  1875. m_pCursorPosition->NotifyAfter(dwEventWhat, 1, rgReasons);
  1876. }
  1877. else
  1878. m_pCursorPosition->NotifyFail(dwEventWhat, 1, rgReasons);
  1879. return hrFetch;
  1880. }
  1881. //=--------------------------------------------------------------------------=
  1882. // UseAdjustments - Use adjustments to fix-up returned data
  1883. //=--------------------------------------------------------------------------=
  1884. // This uses adjustments to fix-up returned data, see MakeAdjustments function
  1885. //
  1886. // Parameters:
  1887. // hRow - [in] row handle
  1888. // pData - [in] a pointer to data
  1889. //
  1890. // Output:
  1891. // S_OK - if successful
  1892. // E_INVALIDARG - bad parameter
  1893. // E_OUTOFMEMORY - not enough memory
  1894. //
  1895. // Notes:
  1896. //
  1897. HRESULT CVDCursor::UseAdjustments(HROW hRow, BYTE * pData)
  1898. {
  1899. ASSERT_POINTER(m_rghAdjustAccessors, HACCESSOR)
  1900. ASSERT_POINTER(m_pdwAdjustFlags, DWORD)
  1901. ASSERT_POINTER(pData, BYTE)
  1902. IRowset * pRowset = GetRowset();
  1903. // make sure we have a valid rowset pointer
  1904. if (!pRowset || !IsRowsetValid())
  1905. {
  1906. VDSetErrorInfo(IDS_ERR_ROWSETRELEASED, IID_ICursor, m_pResourceDLL);
  1907. return E_FAIL;
  1908. }
  1909. // make sure we have all neccessary pointers
  1910. if (!m_rghAdjustAccessors || !m_pdwAdjustFlags || !pData)
  1911. return E_INVALIDARG;
  1912. // iterate through cursor bindings, checking for adjustments
  1913. for (ULONG ulBind = 0; ulBind < m_ulCursorBindings; ulBind++)
  1914. {
  1915. // check for variant binding byte field -> byte binding
  1916. if (m_pdwAdjustFlags[ulBind] == VD_ADJUST_VARIANT_TO_BYTE)
  1917. {
  1918. // get variant pointer
  1919. VARIANT * pVariant = (VARIANT*)(pData + m_pCursorBindings[ulBind].obData);
  1920. // extract byte
  1921. BYTE value = *(BYTE*)pVariant;
  1922. // init byte variant
  1923. VariantInit(pVariant);
  1924. // fix-up returned data
  1925. pVariant->vt = VT_UI1;
  1926. pVariant->bVal = value;
  1927. }
  1928. // check for variant binding date field -> wide string binding
  1929. if (m_pdwAdjustFlags[ulBind] == VD_ADJUST_VARIANT_TO_WSTR)
  1930. {
  1931. // get variant pointer
  1932. VARIANT * pVariant = (VARIANT*)(pData + m_pCursorBindings[ulBind].obData);
  1933. // extract length of string
  1934. ULONG ulLength = *(ULONG*)pVariant;
  1935. // place length field in proper place, if originally requested
  1936. if (m_pCursorBindings[ulBind].obVarDataLen != CURSOR_DB_NOVALUE)
  1937. *(ULONG*)(pData + m_pCursorBindings[ulBind].obVarDataLen) = ulLength;
  1938. // init string variant
  1939. VariantInit(pVariant);
  1940. // create storage for string
  1941. BSTR bstr = SysAllocStringByteLen(NULL, ulLength);
  1942. if (!bstr)
  1943. {
  1944. VDSetErrorInfo(IDS_ERR_OUTOFMEMORY, IID_ICursor, m_pResourceDLL);
  1945. return E_OUTOFMEMORY;
  1946. }
  1947. // clear wide string
  1948. memset(bstr, 0, ulLength);
  1949. HRESULT hr = S_OK;
  1950. // get memo string value
  1951. if (ulLength)
  1952. {
  1953. hr = pRowset->GetData(hRow, m_rghAdjustAccessors[ulBind], bstr);
  1954. // ignore these return values
  1955. if (hr == DB_S_ERRORSOCCURRED || hr == DB_E_ERRORSOCCURRED)
  1956. hr = S_OK;
  1957. }
  1958. if (SUCCEEDED(hr))
  1959. {
  1960. // fix-up returned data
  1961. pVariant->vt = VT_BSTR;
  1962. pVariant->bstrVal = bstr;
  1963. }
  1964. else
  1965. SysFreeString(bstr);
  1966. }
  1967. // check for variant binding memo field -> string binding
  1968. if (m_pdwAdjustFlags[ulBind] == VD_ADJUST_VARIANT_TO_STR)
  1969. {
  1970. // get variant pointer
  1971. VARIANT * pVariant = (VARIANT*)(pData + m_pCursorBindings[ulBind].obData);
  1972. // extract length of string
  1973. ULONG ulLength = *(ULONG*)pVariant;
  1974. // place length field in proper place, if originally requested
  1975. if (m_pCursorBindings[ulBind].obVarDataLen != CURSOR_DB_NOVALUE)
  1976. *(ULONG*)(pData + m_pCursorBindings[ulBind].obVarDataLen) = ulLength;
  1977. // init string variant
  1978. VariantInit(pVariant);
  1979. // create temporary string buffer
  1980. CHAR * pszBuffer = new CHAR[ulLength + 1];
  1981. if (!pszBuffer)
  1982. {
  1983. VDSetErrorInfo(IDS_ERR_OUTOFMEMORY, IID_ICursor, m_pResourceDLL);
  1984. return E_OUTOFMEMORY;
  1985. }
  1986. // clear string buffer
  1987. memset(pszBuffer, 0, ulLength + 1);
  1988. HRESULT hr = S_OK;
  1989. // get memo string value
  1990. if (ulLength)
  1991. {
  1992. hr = pRowset->GetData(hRow, m_rghAdjustAccessors[ulBind], pszBuffer);
  1993. // ignore these return values
  1994. if (hr == DB_S_ERRORSOCCURRED || hr == DB_E_ERRORSOCCURRED)
  1995. hr = S_OK;
  1996. }
  1997. if (SUCCEEDED(hr))
  1998. {
  1999. // fix-up returned data
  2000. pVariant->vt = VT_BSTR;
  2001. pVariant->bstrVal = BSTRFROMANSI(pszBuffer);
  2002. }
  2003. delete [] pszBuffer;
  2004. }
  2005. }
  2006. return S_OK;
  2007. }
  2008. //=--------------------------------------------------------------------------=
  2009. // FillConsumersBuffer
  2010. //=--------------------------------------------------------------------------=
  2011. // Fills the ICursor consumer's buffer with data from the obtained rows.
  2012. // Called from our implementations of GetNextRows, Move, Find, Scroll etc.
  2013. //
  2014. // Notes:
  2015. // End of string characters are inserted into variable length buffer to resolve an
  2016. // apparent difference between ICursor and IRowset. ICursor places an empty string
  2017. // in variable length buffer for NULL data, but this does not seem to be the behavior
  2018. // with IRowset, because it does not touch the variable length buffer in this case.
  2019. //
  2020. // Likewise, all variants are initialized before they are fetched to resolve another
  2021. // apparent difference between ICursor and IRowset. ICursor returns a NULL variant
  2022. // in cases where the underlying data is NULL, however IRowset leaves the variant
  2023. // untouched similar to the above.
  2024. //
  2025. HRESULT CVDCursor::FillConsumersBuffer(HRESULT hrFetch,
  2026. CURSOR_DBFETCHROWS *pFetchParams,
  2027. ULONG cRowsObtained,
  2028. HROW * rghRows)
  2029. {
  2030. HRESULT hr;
  2031. ULONG ulRow;
  2032. ULONG ulBind;
  2033. BYTE * pVarLength = NULL;
  2034. BYTE * pVarHelperData = NULL;
  2035. CURSOR_DBCOLUMNBINDING * pCursorBinding;
  2036. BOOL fEntryIDBinding;
  2037. IRowset * pRowset = GetRowset();
  2038. // if caller requested callee allocated memory, then compute sizes and allocate memory
  2039. if (pFetchParams->dwFlags & CURSOR_DBROWFETCH_CALLEEALLOCATES)
  2040. {
  2041. // allocate inline memory
  2042. pFetchParams->pData = g_pMalloc->Alloc(cRowsObtained * m_cbRowLength);
  2043. if (!pFetchParams->pData)
  2044. {
  2045. VDSetErrorInfo(IDS_ERR_OUTOFMEMORY, IID_ICursor, m_pResourceDLL);
  2046. return E_OUTOFMEMORY;
  2047. }
  2048. // if needed, allocate out-of-line memory
  2049. if (m_ulVarBindings)
  2050. {
  2051. // create variable length data table
  2052. ULONG cbVarHelperData = cRowsObtained * m_ulVarBindings * (sizeof(ULONG) + sizeof(DBSTATUS));
  2053. pVarHelperData = new BYTE[cbVarHelperData];
  2054. if (!pVarHelperData)
  2055. {
  2056. g_pMalloc->Free(pFetchParams->pData);
  2057. pFetchParams->pData = NULL;
  2058. VDSetErrorInfo(IDS_ERR_OUTOFMEMORY, IID_ICursor, m_pResourceDLL);
  2059. return E_OUTOFMEMORY;
  2060. }
  2061. // clear table
  2062. memset(pVarHelperData, 0, cbVarHelperData);
  2063. ULONG cbVarData = 0;
  2064. pVarLength = pVarHelperData;
  2065. // determine necessary size of variable length buffer
  2066. for (ulRow = 0; ulRow < cRowsObtained; ulRow++)
  2067. {
  2068. hr = S_OK;
  2069. // if necessary, get variable length and status information
  2070. if (m_hVarHelper)
  2071. {
  2072. hr = pRowset->GetData(rghRows[ulRow], m_hVarHelper, pVarLength);
  2073. // ignore these errors
  2074. if (hr == DB_S_ERRORSOCCURRED || hr == DB_E_ERRORSOCCURRED)
  2075. hr = S_OK;
  2076. hr = VDMapRowsetHRtoCursorHR(hr, IDS_ERR_GETDATAFAILED, IID_ICursor, pRowset, IID_IRowset,
  2077. m_pResourceDLL);
  2078. }
  2079. if (FAILED(hr))
  2080. {
  2081. g_pMalloc->Free(pFetchParams->pData);
  2082. pFetchParams->pData = NULL;
  2083. delete [] pVarHelperData;
  2084. return hr;
  2085. }
  2086. pCursorBinding = m_pCursorBindings;
  2087. // calculate sizes of data returned in out-of-line memory
  2088. for (ulBind = 0; ulBind < m_ulCursorBindings; ulBind++)
  2089. {
  2090. // set entryID binding flag
  2091. fEntryIDBinding = (pCursorBinding->dwBinding & CURSOR_DBBINDING_ENTRYID);
  2092. if (m_rghVarAccessors[ulBind] || fEntryIDBinding && pCursorBinding->dwDataType == CURSOR_DBTYPE_BLOB)
  2093. {
  2094. // insert length entries for fixed datatypes
  2095. if (m_ppColumns[ulBind]->GetFixed())
  2096. {
  2097. *(ULONG*)pVarLength = m_ppColumns[ulBind]->GetMaxStrLen();
  2098. *(DBSTATUS*)(pVarLength + sizeof(ULONG)) = DBSTATUS_S_OK;
  2099. }
  2100. // insert length entries for entryID bindings
  2101. if (fEntryIDBinding)
  2102. {
  2103. *(ULONG*)pVarLength = sizeof(ULONG) + sizeof(ULONG) + GetCursorMain()->GetMaxBookmarkLen();
  2104. *(DBSTATUS*)(pVarLength + sizeof(ULONG)) = DBSTATUS_S_OK;
  2105. }
  2106. // allow for null-terminator
  2107. if (pCursorBinding->dwDataType == CURSOR_DBTYPE_LPSTR ||
  2108. pCursorBinding->dwDataType == CURSOR_DBTYPE_LPWSTR)
  2109. *((ULONG*)pVarLength) += 1;
  2110. // allow for wide characters
  2111. if (pCursorBinding->dwDataType == CURSOR_DBTYPE_LPWSTR)
  2112. *((ULONG*)pVarLength) *= sizeof(WCHAR);
  2113. cbVarData += *(ULONG*)pVarLength;
  2114. pVarLength += sizeof(ULONG) + sizeof(DBSTATUS);
  2115. }
  2116. pCursorBinding++;
  2117. }
  2118. }
  2119. // now, allocate out-of-line memory
  2120. pFetchParams->pVarData = g_pMalloc->Alloc(cbVarData);
  2121. if (!pFetchParams->pData)
  2122. {
  2123. g_pMalloc->Free(pFetchParams->pData);
  2124. pFetchParams->pData = NULL;
  2125. delete [] pVarHelperData;
  2126. VDSetErrorInfo(IDS_ERR_OUTOFMEMORY, IID_ICursor, m_pResourceDLL);
  2127. return E_OUTOFMEMORY;
  2128. }
  2129. }
  2130. else
  2131. pFetchParams->pVarData = NULL;
  2132. }
  2133. // fetch data
  2134. CURSOR_BLOB cursorBlob;
  2135. BYTE * pData = (BYTE*)pFetchParams->pData;
  2136. BYTE * pVarData = (BYTE*)pFetchParams->pVarData;
  2137. pVarLength = pVarHelperData;
  2138. // iterate through the returned hRows
  2139. for (ulRow = 0; ulRow < cRowsObtained; ulRow++)
  2140. {
  2141. hr = S_OK;
  2142. pCursorBinding = m_pCursorBindings;
  2143. // iterate through bindings and initialize variants
  2144. for (ulBind = 0; ulBind < m_ulCursorBindings; ulBind++)
  2145. {
  2146. if (pCursorBinding->dwBinding & CURSOR_DBBINDING_VARIANT)
  2147. {
  2148. if (pCursorBinding->obData != CURSOR_DB_NOVALUE)
  2149. VariantInit((VARIANT*)(pData + pCursorBinding->obData));
  2150. }
  2151. pCursorBinding++;
  2152. }
  2153. // if necessary get fixed length data
  2154. if (m_hAccessor)
  2155. {
  2156. hr = pRowset->GetData(rghRows[ulRow], m_hAccessor, pData);
  2157. // ignore these return values
  2158. if (hr == DB_S_ERRORSOCCURRED || hr == DB_E_ERRORSOCCURRED)
  2159. hr = S_OK;
  2160. // check to see if need to use adjustments
  2161. if (m_rghAdjustAccessors && SUCCEEDED(hr))
  2162. hr = UseAdjustments(rghRows[ulRow], pData);
  2163. hr = VDMapRowsetHRtoCursorHR(hr, IDS_ERR_GETDATAFAILED, IID_ICursor, pRowset, IID_IRowset, m_pResourceDLL);
  2164. }
  2165. if (FAILED(hr))
  2166. {
  2167. hrFetch = hr;
  2168. pFetchParams->cRowsReturned = 0;
  2169. goto DoneFetchingData;
  2170. }
  2171. pCursorBinding = m_pCursorBindings;
  2172. // if necessary get fixed length entryIDs
  2173. for (ulBind = 0; ulBind < m_ulCursorBindings; ulBind++)
  2174. {
  2175. // set entryID binding flag
  2176. fEntryIDBinding = (pCursorBinding->dwBinding & CURSOR_DBBINDING_ENTRYID);
  2177. if (fEntryIDBinding && pCursorBinding->dwDataType == CURSOR_DBTYPE_BYTES)
  2178. {
  2179. // return entryID length
  2180. *(ULONG*)(pData + pCursorBinding->obData) =
  2181. sizeof(ULONG) + sizeof(ULONG) + GetCursorMain()->GetMaxBookmarkLen();
  2182. // return column ordinal
  2183. *(ULONG*)(pData + pCursorBinding->obData + sizeof(ULONG)) = m_ppColumns[ulBind]->GetOrdinal();
  2184. // return row bookmark
  2185. hr = pRowset->GetData(rghRows[ulRow], GetCursorMain()->GetBookmarkAccessor(),
  2186. pData + pCursorBinding->obData + sizeof(ULONG) + sizeof(ULONG));
  2187. hr = VDMapRowsetHRtoCursorHR(hr, IDS_ERR_GETDATAFAILED, IID_ICursor, pRowset, IID_IRowset,
  2188. m_pResourceDLL);
  2189. if (FAILED(hr))
  2190. {
  2191. hrFetch = hr;
  2192. pFetchParams->cRowsReturned = 0;
  2193. goto DoneFetchingData;
  2194. }
  2195. }
  2196. pCursorBinding++;
  2197. }
  2198. pCursorBinding = m_pCursorBindings;
  2199. // if necessary get variable length data
  2200. if (m_rghVarAccessors)
  2201. {
  2202. for (ulBind = 0; ulBind < m_ulCursorBindings; ulBind++)
  2203. {
  2204. // set entryID binding flag
  2205. fEntryIDBinding = (pCursorBinding->dwBinding & CURSOR_DBBINDING_ENTRYID);
  2206. if (m_rghVarAccessors[ulBind] || fEntryIDBinding && pCursorBinding->dwDataType == CURSOR_DBTYPE_BLOB)
  2207. {
  2208. // place end of string characters in variable length buffer
  2209. if (pCursorBinding->dwDataType == CURSOR_DBTYPE_LPSTR)
  2210. {
  2211. pVarData[0] = 0;
  2212. }
  2213. else if (pCursorBinding->dwDataType == CURSOR_DBTYPE_LPWSTR)
  2214. {
  2215. pVarData[0] = 0;
  2216. pVarData[1] = 0;
  2217. }
  2218. // get data if we have accessor
  2219. if (m_rghVarAccessors[ulBind])
  2220. {
  2221. // get variable length data
  2222. hr = pRowset->GetData(rghRows[ulRow], m_rghVarAccessors[ulBind], pVarData);
  2223. // ignore these return values
  2224. if (hr == DB_S_ERRORSOCCURRED || hr == DB_E_ERRORSOCCURRED)
  2225. hr = S_OK;
  2226. hr = VDMapRowsetHRtoCursorHR(hr, IDS_ERR_GETDATAFAILED, IID_ICursor, pRowset, IID_IRowset,
  2227. m_pResourceDLL);
  2228. }
  2229. else // otherwise, get variable length entryIDs
  2230. {
  2231. // return entryID length
  2232. *(ULONG*)(pData + pCursorBinding->obData) =
  2233. sizeof(ULONG) + sizeof(ULONG) + GetCursorMain()->GetMaxBookmarkLen();
  2234. // return column ordinal
  2235. *(ULONG*)(pVarData) = m_ppColumns[ulBind]->GetOrdinal();
  2236. // return row bookmark
  2237. hr = pRowset->GetData(rghRows[ulRow], GetCursorMain()->GetBookmarkAccessor(),
  2238. pVarData + sizeof(ULONG));
  2239. hr = VDMapRowsetHRtoCursorHR(hr, IDS_ERR_GETDATAFAILED, IID_ICursor, pRowset, IID_IRowset,
  2240. m_pResourceDLL);
  2241. }
  2242. if (FAILED(hr))
  2243. {
  2244. hrFetch = hr;
  2245. pFetchParams->cRowsReturned = 0;
  2246. goto DoneFetchingData;
  2247. }
  2248. // make adjustments in fixed length buffer for default bindings
  2249. if (!(pCursorBinding->dwBinding & CURSOR_DBBINDING_VARIANT))
  2250. {
  2251. switch (pCursorBinding->dwDataType)
  2252. {
  2253. case CURSOR_DBTYPE_BLOB:
  2254. *(LPBYTE*)(pData + pCursorBinding->obData + sizeof(ULONG)) = (LPBYTE)pVarData;
  2255. break;
  2256. case CURSOR_DBTYPE_LPSTR:
  2257. *(LPSTR*)(pData + pCursorBinding->obData) = (LPSTR)pVarData;
  2258. break;
  2259. case CURSOR_DBTYPE_LPWSTR:
  2260. *(LPWSTR*)(pData + pCursorBinding->obData) = (LPWSTR)pVarData;
  2261. break;
  2262. }
  2263. }
  2264. else // make adjustments in fixed length buffer for variant bindings
  2265. {
  2266. CURSOR_DBVARIANT * pVariant = (CURSOR_DBVARIANT*)(pData + pCursorBinding->obData);
  2267. switch (pCursorBinding->dwDataType)
  2268. {
  2269. case CURSOR_DBTYPE_BLOB:
  2270. cursorBlob.cbSize = *(ULONG*)pVariant;
  2271. cursorBlob.pBlobData = (LPBYTE)pVarData;
  2272. VariantInit((VARIANT*)pVariant);
  2273. pVariant->vt = CURSOR_DBTYPE_BLOB;
  2274. pVariant->blob = cursorBlob;
  2275. break;
  2276. case CURSOR_DBTYPE_LPSTR:
  2277. VariantInit((VARIANT*)pVariant);
  2278. pVariant->vt = CURSOR_DBTYPE_LPSTR;
  2279. pVariant->pszVal = (LPSTR)pVarData;
  2280. break;
  2281. case CURSOR_DBTYPE_LPWSTR:
  2282. VariantInit((VARIANT*)pVariant);
  2283. pVariant->vt = CURSOR_DBTYPE_LPSTR;
  2284. pVariant->pwszVal = (LPWSTR)pVarData;
  2285. break;
  2286. }
  2287. }
  2288. if (pVarLength)
  2289. {
  2290. pVarData += *(ULONG*)pVarLength;
  2291. pVarLength += sizeof(ULONG) + sizeof(DBSTATUS);
  2292. }
  2293. else
  2294. {
  2295. if (pCursorBinding->dwDataType == CURSOR_DBTYPE_BLOB)
  2296. pVarData += *(ULONG *) (pData + pCursorBinding->obData);
  2297. else
  2298. pVarData += pCursorBinding->cbMaxLen;
  2299. }
  2300. }
  2301. else
  2302. {
  2303. if (pCursorBinding->dwDataType == CURSOR_DBTYPE_FILETIME)
  2304. {
  2305. VDConvertToFileTime((DBTIMESTAMP*)(pData + pCursorBinding->obData),
  2306. (FILETIME*)(pData + pCursorBinding->obData));
  2307. }
  2308. }
  2309. pCursorBinding++;
  2310. }
  2311. }
  2312. pCursorBinding = m_pCursorBindings;
  2313. // make adjustments for status fields
  2314. for (ulBind = 0; ulBind < m_ulCursorBindings; ulBind++)
  2315. {
  2316. if (pCursorBinding->obInfo != CURSOR_DB_NOVALUE)
  2317. {
  2318. *(DWORD*)(pData + pCursorBinding->obInfo) =
  2319. StatusToCursorInfo(*(DBSTATUS*)(pData + pCursorBinding->obInfo));
  2320. }
  2321. pCursorBinding++;
  2322. }
  2323. // increment returned row count
  2324. pFetchParams->cRowsReturned++;
  2325. pData += m_cbRowLength;
  2326. }
  2327. DoneFetchingData:
  2328. delete [] pVarHelperData;
  2329. // cleanup memory allocations if we did not retrieve any rows
  2330. if (pFetchParams->dwFlags & CURSOR_DBROWFETCH_CALLEEALLOCATES && !pFetchParams->cRowsReturned)
  2331. {
  2332. if (pFetchParams->pData)
  2333. {
  2334. g_pMalloc->Free(pFetchParams->pData);
  2335. pFetchParams->pData = NULL;
  2336. }
  2337. if (pFetchParams->pVarData)
  2338. {
  2339. g_pMalloc->Free(pFetchParams->pVarData);
  2340. pFetchParams->pVarData = NULL;
  2341. }
  2342. }
  2343. return hrFetch;
  2344. }
  2345. //=--------------------------------------------------------------------------=
  2346. // ICursor Requery
  2347. //=--------------------------------------------------------------------------=
  2348. // Repopulates the cursor based on its original definition
  2349. //
  2350. // Parameters:
  2351. // none
  2352. //
  2353. // Output:
  2354. // HRESULT - S_OK if successful
  2355. //
  2356. // Notes:
  2357. //
  2358. HRESULT CVDCursor::Requery(void)
  2359. {
  2360. if (!IsRowsetValid())
  2361. {
  2362. VDSetErrorInfo(IDS_ERR_ROWSETRELEASED, IID_ICursor, m_pResourceDLL);
  2363. return E_FAIL;
  2364. }
  2365. IRowset * pRowset = GetRowset();
  2366. IRowsetResynch * pRowsetResynch = NULL;
  2367. HRESULT hr = pRowset->QueryInterface(IID_IRowsetResynch, (void**)&pRowsetResynch);
  2368. if (SUCCEEDED(hr))
  2369. {
  2370. hr = pRowsetResynch->ResynchRows(0, NULL, NULL, NULL, NULL);
  2371. pRowsetResynch->Release();
  2372. if (FAILED(hr))
  2373. return VDMapRowsetHRtoCursorHR(hr, IDS_ERR_RESYNCHFAILED, IID_ICursor, pRowset, IID_IRowsetResynch, m_pResourceDLL);
  2374. }
  2375. hr = pRowset->RestartPosition(0);
  2376. hr = VDMapRowsetHRtoCursorHR(hr, IDS_ERR_RESTARTPOSFAILED, IID_ICursor, pRowset, IID_IRowset, m_pResourceDLL);
  2377. m_pCursorPosition->PositionToFirstRow();
  2378. return hr;
  2379. }
  2380. //=--------------------------------------------------------------------------=
  2381. // FetchAtBookmark
  2382. //=--------------------------------------------------------------------------=
  2383. // Called from ICursorMove::Move, ICursorScroll::Scroll and ICursorFind::Find
  2384. //
  2385. // Parameters:
  2386. // cbBookmark [in] The length of the bookmark
  2387. // pBookmark [in] A pointer to the bookmarks data
  2388. // dlOffset [in] Offset from the bookmark position
  2389. // pFetchParams [in] A pointer to the CURSOR_DBFETCHROWS structure (optional)
  2390. //
  2391. // Output:
  2392. // HRESULT - S_OK if successful
  2393. //
  2394. // Notes:
  2395. //
  2396. //
  2397. HRESULT CVDCursor::FetchAtBookmark(ULONG cbBookmark,
  2398. void *pBookmark,
  2399. LARGE_INTEGER dlOffset,
  2400. CURSOR_DBFETCHROWS *pFetchParams)
  2401. {
  2402. HRESULT hr = S_OK;
  2403. // vaildate fetch params (implemented on CVDCursorBase
  2404. if (pFetchParams)
  2405. hr = ValidateFetchParams(pFetchParams, IID_ICursorMove);
  2406. // return if fetch params are invalid
  2407. if (FAILED(hr))
  2408. return hr;
  2409. IRowset * pRowset = GetRowset();
  2410. // make sure that an update is not already in progress
  2411. if (m_pCursorPosition->GetEditMode() != CURSOR_DBEDITMODE_NONE)
  2412. {
  2413. VDSetErrorInfo(IDS_ERR_UPDATEINPROGRESS, IID_ICursor, m_pResourceDLL);
  2414. return CURSOR_DB_E_UPDATEINPROGRESS;
  2415. }
  2416. ULONG cRowsObtained = 0;
  2417. HROW * rghRows = NULL;
  2418. HRESULT hrFetch = S_OK;
  2419. BYTE bSpecialBM;
  2420. BOOL fFetchData = TRUE;
  2421. WORD wSpecialBMStatus = 0;
  2422. if (CURSOR_DB_BMK_SIZE == cbBookmark)
  2423. {
  2424. if (memcmp(&CURSOR_DBBMK_BEGINNING, pBookmark, CURSOR_DB_BMK_SIZE) == 0)
  2425. {
  2426. if ((long)dlOffset.LowPart < 0)
  2427. {
  2428. m_pCursorPosition->SetCurrentRowStatus(VDBOOKMARKSTATUS_BEGINNING);
  2429. return CURSOR_DB_S_ENDOFCURSOR;
  2430. }
  2431. bSpecialBM = DBBMK_FIRST;
  2432. pBookmark = &bSpecialBM;
  2433. // make sure we properly handle situation when caller move before the first,
  2434. // and does not fetch any rows
  2435. if ((!pFetchParams || !pFetchParams->cRowsRequested) && (long)dlOffset.LowPart < 1)
  2436. {
  2437. fFetchData = FALSE;
  2438. wSpecialBMStatus = VDBOOKMARKSTATUS_BEGINNING;
  2439. }
  2440. else
  2441. dlOffset.LowPart--;
  2442. }
  2443. else
  2444. if (memcmp(&CURSOR_DBBMK_END, pBookmark, CURSOR_DB_BMK_SIZE) == 0)
  2445. {
  2446. if ((long)dlOffset.LowPart > 0)
  2447. {
  2448. m_pCursorPosition->SetCurrentRowStatus(VDBOOKMARKSTATUS_END);
  2449. return CURSOR_DB_S_ENDOFCURSOR;
  2450. }
  2451. bSpecialBM = DBBMK_LAST;
  2452. pBookmark = &bSpecialBM;
  2453. // make sure we properly handle situation when caller move after the last
  2454. if ((!pFetchParams || !pFetchParams->cRowsRequested) && (long)dlOffset.LowPart > -1)
  2455. {
  2456. fFetchData = FALSE;
  2457. wSpecialBMStatus = VDBOOKMARKSTATUS_END;
  2458. }
  2459. else
  2460. dlOffset.LowPart++;
  2461. }
  2462. else
  2463. if (memcmp(&CURSOR_DBBMK_CURRENT, pBookmark, CURSOR_DB_BMK_SIZE) == 0)
  2464. {
  2465. switch (m_pCursorPosition->m_bmCurrent.GetStatus())
  2466. {
  2467. case VDBOOKMARKSTATUS_BEGINNING:
  2468. cbBookmark = sizeof(BYTE);
  2469. bSpecialBM = DBBMK_FIRST;
  2470. pBookmark = &bSpecialBM;
  2471. dlOffset.LowPart--;
  2472. break;
  2473. case VDBOOKMARKSTATUS_END:
  2474. cbBookmark = sizeof(BYTE);
  2475. bSpecialBM = DBBMK_LAST;
  2476. pBookmark = &bSpecialBM;
  2477. dlOffset.LowPart++;
  2478. break;
  2479. case VDBOOKMARKSTATUS_CURRENT:
  2480. cbBookmark = m_pCursorPosition->m_bmCurrent.GetBookmarkLen();
  2481. pBookmark = m_pCursorPosition->m_bmCurrent.GetBookmark();
  2482. break;
  2483. default:
  2484. ASSERT_(FALSE);
  2485. VDSetErrorInfo(IDS_ERR_INVALIDBMSTATUS, IID_ICursor, m_pResourceDLL);
  2486. return E_FAIL;
  2487. }
  2488. }
  2489. }
  2490. ULONG cRowsToFetch = 1;
  2491. // if caller requested rows, fetch that count
  2492. if (pFetchParams && pFetchParams->cRowsRequested > 0)
  2493. cRowsToFetch = pFetchParams->cRowsRequested;
  2494. if (fFetchData)
  2495. {
  2496. // fetch hRows
  2497. hrFetch = GetRowsetLocate()->GetRowsAt(0, 0, cbBookmark, (const BYTE *)pBookmark,
  2498. dlOffset.LowPart,
  2499. cRowsToFetch,
  2500. &cRowsObtained, &rghRows);
  2501. if (hrFetch == E_UNEXPECTED)
  2502. {
  2503. // set rowset released flag, since original rowset is zombie'd
  2504. m_pCursorPosition->GetRowsetSource()->SetRowsetReleasedFlag();
  2505. }
  2506. hrFetch = FilterNewRow(&cRowsObtained, rghRows, hrFetch);
  2507. // check for before the first or after the last
  2508. if (hrFetch == DB_E_BADSTARTPOSITION)
  2509. {
  2510. if ((long)dlOffset.LowPart < 0)
  2511. wSpecialBMStatus = VDBOOKMARKSTATUS_BEGINNING;
  2512. else
  2513. wSpecialBMStatus = VDBOOKMARKSTATUS_END;
  2514. hrFetch = DB_S_ENDOFROWSET;
  2515. fFetchData = FALSE;
  2516. }
  2517. }
  2518. hrFetch = VDMapRowsetHRtoCursorHR(hrFetch, IDS_ERR_GETROWSATFAILED, IID_ICursorMove, GetRowsetLocate(),
  2519. IID_IRowsetLocate, m_pResourceDLL);
  2520. if (FAILED(hrFetch))
  2521. {
  2522. if (cRowsObtained)
  2523. {
  2524. // release hRows and associated memory
  2525. pRowset->ReleaseRows(cRowsObtained, rghRows, NULL, NULL, NULL);
  2526. g_pMalloc->Free(rghRows);
  2527. }
  2528. return hrFetch;
  2529. }
  2530. if (cRowsObtained)
  2531. {
  2532. HRESULT hrMove = S_OK;
  2533. // if got all rows requested then set current position to last row retrieved
  2534. if (SUCCEEDED(hrFetch) &&
  2535. cRowsObtained == cRowsToFetch)
  2536. hrMove = m_pCursorPosition->SetRowPosition(rghRows[cRowsObtained - 1]);
  2537. // only do this if succeeded
  2538. if (SUCCEEDED(hrMove))
  2539. {
  2540. // fill consumers buffer
  2541. if (pFetchParams && pFetchParams->cRowsRequested > 0)
  2542. hrFetch = FillConsumersBuffer(hrFetch, pFetchParams, cRowsObtained, rghRows);
  2543. // if got all rows requested then set current position to last row retrieved (internally)
  2544. if (SUCCEEDED(hrFetch) &&
  2545. cRowsObtained == cRowsToFetch)
  2546. m_pCursorPosition->SetCurrentHRow(rghRows[cRowsObtained - 1]);
  2547. }
  2548. // release hRows and associated memory
  2549. pRowset->ReleaseRows(cRowsObtained, rghRows, NULL, NULL, NULL);
  2550. g_pMalloc->Free(rghRows);
  2551. // report failure
  2552. if (FAILED(hrMove))
  2553. {
  2554. cRowsObtained = 0;
  2555. hrFetch = E_FAIL;
  2556. }
  2557. }
  2558. else if (wSpecialBMStatus)
  2559. {
  2560. m_pCursorPosition->SetCurrentRowStatus(wSpecialBMStatus);
  2561. hrFetch = CURSOR_DB_S_ENDOFCURSOR;
  2562. }
  2563. if (SUCCEEDED(hrFetch) &&
  2564. cRowsObtained < cRowsToFetch &&
  2565. !wSpecialBMStatus)
  2566. m_pCursorPosition->SetCurrentRowStatus(VDBOOKMARKSTATUS_END);
  2567. return hrFetch;
  2568. }
  2569. //=--------------------------------------------------------------------------=
  2570. // ICursorMove methods implemented
  2571. //=--------------------------------------------------------------------------=
  2572. //=--------------------------------------------------------------------------=
  2573. // ICursorMove Move
  2574. //=--------------------------------------------------------------------------=
  2575. // Moves the current row to a new row within the cursor and optionally fetches
  2576. // rows from that new position
  2577. //
  2578. // Parameters:
  2579. // cbBookmark - [in] length in bytes of the bookmark
  2580. // pBookmark - [in] a pointer to a bookmark which serves as the
  2581. // origin for the calculation that determines the
  2582. // target row
  2583. // dlOffset - [in] a signed count of the rows from the origin
  2584. // bookmark to the target row
  2585. // pFetchParams - [in, out] a pointer to fetch rows structure
  2586. //
  2587. // Output:
  2588. // HRESULT - S_OK if successful
  2589. // E_INVALIDARG bad parameter
  2590. //
  2591. // Notes:
  2592. //
  2593. HRESULT CVDCursor::Move(ULONG cbBookmark, void *pBookmark, LARGE_INTEGER dlOffset, CURSOR_DBFETCHROWS *pFetchParams)
  2594. {
  2595. ASSERT_POINTER(pBookmark, BYTE)
  2596. ASSERT_NULL_OR_POINTER(pFetchParams, CURSOR_DBFETCHROWS)
  2597. if (!IsRowsetValid())
  2598. {
  2599. VDSetErrorInfo(IDS_ERR_ROWSETRELEASED, IID_ICursorMove, m_pResourceDLL);
  2600. return E_FAIL;
  2601. }
  2602. if (!cbBookmark || !pBookmark)
  2603. {
  2604. VDSetErrorInfo(IDS_ERR_INVALIDARG, IID_ICursorMove, m_pResourceDLL);
  2605. return E_INVALIDARG;
  2606. }
  2607. HRESULT hr = S_OK;
  2608. BOOL fNotifyOthers = TRUE;
  2609. // get current bookmark
  2610. ULONG cbCurrent = m_pCursorPosition->m_bmCurrent.GetBookmarkLen();
  2611. BYTE * pCurrent = m_pCursorPosition->m_bmCurrent.GetBookmark();
  2612. // check to see if caller is moving to the current row using the standard bookmark
  2613. if (CURSOR_DB_BMK_SIZE == cbBookmark && memcmp(&CURSOR_DBBMK_CURRENT, pBookmark, CURSOR_DB_BMK_SIZE) == 0 &&
  2614. dlOffset.HighPart == 0 && dlOffset.LowPart == 0)
  2615. {
  2616. // if caller is not fetching any rows, then get out
  2617. if (!pFetchParams || pFetchParams->cRowsRequested == 0)
  2618. return S_OK;
  2619. // if caller is only fetching one row, then don't generate notifications
  2620. if (pFetchParams && pFetchParams->cRowsRequested == 1)
  2621. fNotifyOthers = FALSE;
  2622. }
  2623. CURSOR_DBNOTIFYREASON rgReasons[1];
  2624. rgReasons[0].dwReason = CURSOR_DBREASON_MOVE;
  2625. rgReasons[0].arg1 = m_pCursorPosition->m_bmCurrent.GetBookmarkVariant();
  2626. VariantInit((VARIANT*)&rgReasons[0].arg2);
  2627. // notify other interested parties
  2628. DWORD dwEventWhat = CURSOR_DBEVENT_CURRENT_ROW_CHANGED;
  2629. if (fNotifyOthers)
  2630. hr = m_pCursorPosition->NotifyBefore(dwEventWhat, 1, rgReasons);
  2631. // make sure action was not cancelled
  2632. if (hr != S_OK)
  2633. {
  2634. VDSetErrorInfo(IDS_ERR_ACTIONCANCELLED, IID_ICursorMove, m_pResourceDLL);
  2635. return E_FAIL;
  2636. }
  2637. hr = FetchAtBookmark(cbBookmark, pBookmark, dlOffset, pFetchParams);
  2638. if (SUCCEEDED(hr))
  2639. {
  2640. rgReasons[0].arg1 = m_pCursorPosition->m_bmCurrent.GetBookmarkVariant();
  2641. if (fNotifyOthers)
  2642. m_pCursorPosition->NotifyAfter(dwEventWhat, 1, rgReasons);
  2643. }
  2644. else
  2645. {
  2646. if (fNotifyOthers)
  2647. m_pCursorPosition->NotifyFail(dwEventWhat, 1, rgReasons);
  2648. }
  2649. return hr;
  2650. }
  2651. //=--------------------------------------------------------------------------=
  2652. // ICursorMove GetBookmark
  2653. //=--------------------------------------------------------------------------=
  2654. // Returns the bookmark of the current row
  2655. //
  2656. // Parameters:
  2657. // pBookmarkType - [in] a pointer to the type of bookmark desired
  2658. // cbMaxSize - [in] length in bytes of the client buffer to put the
  2659. // returned bookmark into
  2660. // pcbBookmark - [out] a pointer to memory in which to return the actual
  2661. // length of the returned bookmark
  2662. // pBookmark - [out] a pointer to client buffer to put the returned
  2663. // bookmark into
  2664. //
  2665. // Output:
  2666. // HRESULT - S_OK if successful
  2667. // E_INVALIDARG bad parameter
  2668. //
  2669. // Notes:
  2670. //
  2671. HRESULT CVDCursor::GetBookmark(CURSOR_DBCOLUMNID *pBookmarkType,
  2672. ULONG cbMaxSize,
  2673. ULONG *pcbBookmark,
  2674. void *pBookmark)
  2675. {
  2676. ASSERT_POINTER(pBookmarkType, CURSOR_DBCOLUMNID);
  2677. ASSERT_POINTER(pcbBookmark, ULONG);
  2678. ASSERT_POINTER(pBookmark, BYTE);
  2679. ASSERT_(cbMaxSize > 0)
  2680. if (!IsRowsetValid())
  2681. {
  2682. VDSetErrorInfo(IDS_ERR_ROWSETRELEASED, IID_ICursorMove, m_pResourceDLL);
  2683. return E_FAIL;
  2684. }
  2685. if (!pcbBookmark || !pBookmark)
  2686. {
  2687. VDSetErrorInfo(IDS_ERR_INVALIDARG, IID_ICursorMove, m_pResourceDLL);
  2688. return E_INVALIDARG;
  2689. }
  2690. // verify bookmark type
  2691. if (memcmp(&CURSOR_COLUMN_BMKTEMPORARY, pBookmarkType, sizeof(CURSOR_DBCOLUMNID)) != 0 &&
  2692. memcmp(&CURSOR_COLUMN_BMKTEMPORARYREL, pBookmarkType, sizeof(CURSOR_DBCOLUMNID)) != 0)
  2693. {
  2694. VDSetErrorInfo(IDS_ERR_BADCOLUMNID, IID_ICursorMove, m_pResourceDLL);
  2695. return DB_E_BADCOLUMNID;
  2696. }
  2697. HRESULT hr = S_OK;
  2698. if (0 == cbMaxSize)
  2699. {
  2700. VDSetErrorInfo(IDS_ERR_BUFFERTOOSMALL, IID_ICursorMove, m_pResourceDLL);
  2701. hr = CURSOR_DB_E_BUFFERTOOSMALL;
  2702. }
  2703. else
  2704. {
  2705. switch (m_pCursorPosition->m_bmCurrent.GetStatus())
  2706. {
  2707. case VDBOOKMARKSTATUS_BEGINNING:
  2708. case VDBOOKMARKSTATUS_END:
  2709. case VDBOOKMARKSTATUS_CURRENT:
  2710. if (m_pCursorPosition->m_bmCurrent.GetBookmarkLen() > cbMaxSize)
  2711. {
  2712. VDSetErrorInfo(IDS_ERR_BUFFERTOOSMALL, IID_ICursorMove, m_pResourceDLL);
  2713. hr = CURSOR_DB_E_BUFFERTOOSMALL;
  2714. break;
  2715. }
  2716. *pcbBookmark = m_pCursorPosition->m_bmCurrent.GetBookmarkLen();
  2717. memcpy(pBookmark, m_pCursorPosition->m_bmCurrent.GetBookmark(), *pcbBookmark);
  2718. break;
  2719. case VDBOOKMARKSTATUS_INVALID:
  2720. *pcbBookmark = CURSOR_DB_BMK_SIZE;
  2721. *(BYTE*)pBookmark = CURSOR_DBBMK_INVALID;
  2722. break;
  2723. default:
  2724. ASSERT_(FALSE);
  2725. VDSetErrorInfo(IDS_ERR_INVALIDBMSTATUS, IID_ICursorMove, m_pResourceDLL);
  2726. hr = E_FAIL;
  2727. break;
  2728. }
  2729. }
  2730. return hr;
  2731. }
  2732. //=--------------------------------------------------------------------------=
  2733. // ICursorMove Clone
  2734. //=--------------------------------------------------------------------------=
  2735. // Returns a clone of the cursor
  2736. //
  2737. // Parameters:
  2738. // dwFlags - [in] a flag that specifies the clone options
  2739. // riid - [in] the interface desired for the returned clone
  2740. // ppvClonedCursor - [out] a pointer to memory in which to return newly
  2741. // created clone pointer
  2742. //
  2743. // Output:
  2744. // HRESULT - S_OK if successful
  2745. //
  2746. // Notes:
  2747. //
  2748. HRESULT CVDCursor::Clone(DWORD dwFlags, REFIID riid, IUnknown **ppvClonedCursor)
  2749. {
  2750. if (!IsRowsetValid())
  2751. {
  2752. VDSetErrorInfo(IDS_ERR_ROWSETRELEASED, IID_ICursorMove, m_pResourceDLL);
  2753. return E_FAIL;
  2754. }
  2755. CVDCursorPosition * pCursorPosition;
  2756. HRESULT hr;
  2757. if (CURSOR_DBCLONEOPTS_SAMEROW == dwFlags)
  2758. {
  2759. pCursorPosition = m_pCursorPosition;
  2760. }
  2761. else
  2762. {
  2763. // create new cursor position object
  2764. hr = CVDCursorPosition::Create(NULL,
  2765. m_pCursorPosition->GetCursorMain(),
  2766. &pCursorPosition,
  2767. m_pResourceDLL);
  2768. if (FAILED(hr))
  2769. return hr;
  2770. }
  2771. CVDCursor * pCursor = 0;
  2772. hr = CVDCursor::Create(pCursorPosition, &pCursor, m_pResourceDLL);
  2773. if (CURSOR_DBCLONEOPTS_SAMEROW != dwFlags)
  2774. {
  2775. // release our reference
  2776. pCursorPosition->Release();
  2777. }
  2778. *ppvClonedCursor = (ICursorScroll*)pCursor;
  2779. return hr;
  2780. }
  2781. //=--------------------------------------------------------------------------=
  2782. // ICursorScroll methods implemented
  2783. //=--------------------------------------------------------------------------=
  2784. //=--------------------------------------------------------------------------=
  2785. // ICursorScroll Scroll
  2786. //=--------------------------------------------------------------------------=
  2787. // Moves the current row to a new row within the cursor, specified as a
  2788. // fraction, and optionally fetches rows from that new position
  2789. //
  2790. // Parameters:
  2791. // ulNumerator - [in] the numerator of the fraction that states the
  2792. // position to scroll to in the cursor
  2793. // ulDenominator - [in] the denominator of that same fraction
  2794. // pFetchParams - [in, out] a pointer to fetch rows structure
  2795. //
  2796. // Output:
  2797. // HRESULT - S_OK if successful
  2798. // CURSOR_DB_E_BADFRACTION - bad fraction
  2799. //
  2800. // Notes:
  2801. //
  2802. HRESULT CVDCursor::Scroll(ULONG ulNumerator, ULONG ulDenominator, CURSOR_DBFETCHROWS *pFetchParams)
  2803. {
  2804. if (!IsRowsetValid())
  2805. {
  2806. VDSetErrorInfo(IDS_ERR_ROWSETRELEASED, IID_ICursorScroll, m_pResourceDLL);
  2807. return E_FAIL;
  2808. }
  2809. IRowsetScroll * pRowsetScroll = GetRowsetScroll();
  2810. if (!pRowsetScroll)
  2811. return E_NOTIMPL;
  2812. CURSOR_DBNOTIFYREASON rgReasons[1];
  2813. rgReasons[0].dwReason = CURSOR_DBREASON_MOVEPERCENT;
  2814. VariantInit((VARIANT*)&rgReasons[0].arg1);
  2815. rgReasons[0].arg1.vt = VT_UI4;
  2816. rgReasons[0].arg1.lVal = ulNumerator;
  2817. VariantInit((VARIANT*)&rgReasons[0].arg2);
  2818. rgReasons[0].arg2.vt = VT_UI4;
  2819. rgReasons[0].arg2.lVal = ulDenominator;
  2820. // notify other interested parties
  2821. DWORD dwEventWhat = CURSOR_DBEVENT_CURRENT_ROW_CHANGED;
  2822. HRESULT hr = m_pCursorPosition->NotifyBefore(dwEventWhat, 1, rgReasons);
  2823. // make sure action was not cancelled
  2824. if (hr != S_OK)
  2825. {
  2826. VDSetErrorInfo(IDS_ERR_ACTIONCANCELLED, IID_ICursorScroll, m_pResourceDLL);
  2827. return E_FAIL;
  2828. }
  2829. if (0 == ulNumerator) // go to first row
  2830. {
  2831. LARGE_INTEGER dlOffset;
  2832. dlOffset.HighPart = 0;
  2833. dlOffset.LowPart = 1;
  2834. hr = FetchAtBookmark(CURSOR_DB_BMK_SIZE, (void*)&CURSOR_DBBMK_BEGINNING, dlOffset, pFetchParams);
  2835. }
  2836. else
  2837. if (ulDenominator == ulNumerator) // go to last row
  2838. {
  2839. LARGE_INTEGER dlOffset;
  2840. dlOffset.HighPart = -1;
  2841. dlOffset.LowPart = 0xFFFFFFFF;
  2842. hr = FetchAtBookmark(CURSOR_DB_BMK_SIZE, (void*)&CURSOR_DBBMK_END, dlOffset, pFetchParams);
  2843. }
  2844. else
  2845. {
  2846. HROW * pRow = NULL;
  2847. ULONG cRowsObtained = 0;
  2848. hr = pRowsetScroll->GetRowsAtRatio(0, 0,
  2849. ulNumerator,
  2850. ulDenominator,
  2851. 1,
  2852. &cRowsObtained,
  2853. &pRow);
  2854. if FAILED(hr)
  2855. hr = VDMapRowsetHRtoCursorHR(hr, IDS_ERR_SCROLLFAILED, IID_ICursorScroll, pRowsetScroll, IID_IRowsetScroll, m_pResourceDLL);
  2856. if (SUCCEEDED(hr) && cRowsObtained)
  2857. {
  2858. // allocate buffer for bookmark plus length indicator
  2859. BYTE * pBuff = new BYTE[GetCursorMain()->GetMaxBookmarkLen() + sizeof(ULONG)];
  2860. if (!pBuff)
  2861. hr = E_OUTOFMEMORY;
  2862. else
  2863. {
  2864. // get the bookmark data
  2865. hr = GetRowset()->GetData(*pRow, GetCursorMain()->GetBookmarkAccessor(), pBuff);
  2866. if SUCCEEDED(hr)
  2867. {
  2868. ULONG * pulLen = (ULONG*)pBuff;
  2869. BYTE * pbmdata = pBuff + sizeof(ULONG);
  2870. LARGE_INTEGER dlOffset;
  2871. dlOffset.HighPart = 0;
  2872. dlOffset.LowPart = 0;
  2873. hr = FetchAtBookmark(*pulLen, pbmdata, dlOffset, pFetchParams);
  2874. }
  2875. else
  2876. {
  2877. hr = VDMapRowsetHRtoCursorHR(hr, IDS_ERR_GETDATAFAILED, IID_ICursorScroll, pRowsetScroll, IID_IRowset, m_pResourceDLL);
  2878. }
  2879. delete [] pBuff;
  2880. }
  2881. }
  2882. if (pRow)
  2883. {
  2884. if (cRowsObtained)
  2885. GetRowset()->ReleaseRows(1, pRow, NULL, NULL, NULL);
  2886. g_pMalloc->Free(pRow);
  2887. }
  2888. }
  2889. if SUCCEEDED(hr)
  2890. {
  2891. rgReasons[0].arg1 = m_pCursorPosition->m_bmCurrent.GetBookmarkVariant();
  2892. VariantClear((VARIANT*)&rgReasons[0].arg2);
  2893. m_pCursorPosition->NotifyAfter(dwEventWhat, 1, rgReasons);
  2894. }
  2895. else
  2896. m_pCursorPosition->NotifyFail(dwEventWhat, 1, rgReasons);
  2897. return hr;
  2898. }
  2899. //=--------------------------------------------------------------------------=
  2900. // ICursorScroll GetApproximatePosition
  2901. //=--------------------------------------------------------------------------=
  2902. // Returns the approximate location of a bookmark within the cursor, specified
  2903. // as a fraction
  2904. //
  2905. // Parameters:
  2906. // cbBookmark - [in] length in bytes of the bookmark
  2907. // pBookmark - [in] a pointer to the bookmark
  2908. // pulNumerator - [out] a pointer to memory in which to return the
  2909. // numerator of the faction that defines the
  2910. // approximate position of the bookmark
  2911. // pulDenominator - [out] a pointer to memory in which to return the
  2912. // denominator of that same faction
  2913. //
  2914. // Output:
  2915. // HRESULT - S_OK if successful
  2916. // E_INVALIDARG bad parameter
  2917. //
  2918. // Notes:
  2919. //
  2920. HRESULT CVDCursor::GetApproximatePosition(ULONG cbBookmark, void *pBookmark, ULONG *pulNumerator, ULONG *pulDenominator)
  2921. {
  2922. if (!IsRowsetValid())
  2923. {
  2924. VDSetErrorInfo(IDS_ERR_ROWSETRELEASED, IID_ICursorScroll, m_pResourceDLL);
  2925. return E_FAIL;
  2926. }
  2927. ASSERT_(cbBookmark);
  2928. ASSERT_POINTER(pBookmark, BYTE);
  2929. ASSERT_POINTER(pulNumerator, ULONG);
  2930. ASSERT_POINTER(pulDenominator, ULONG);
  2931. if (!cbBookmark || !pBookmark || !pulNumerator || !pulDenominator)
  2932. {
  2933. VDSetErrorInfo(IDS_ERR_INVALIDARG, IID_ICursorScroll, m_pResourceDLL);
  2934. return E_INVALIDARG;
  2935. }
  2936. if (CURSOR_DB_BMK_SIZE == cbBookmark)
  2937. {
  2938. if (memcmp(&CURSOR_DBBMK_BEGINNING, pBookmark, CURSOR_DB_BMK_SIZE) == 0)
  2939. {
  2940. *pulNumerator = 0;
  2941. *pulDenominator = 1;
  2942. return S_OK;
  2943. }
  2944. if (memcmp(&CURSOR_DBBMK_END, pBookmark, CURSOR_DB_BMK_SIZE) == 0)
  2945. {
  2946. *pulNumerator = 1;
  2947. *pulDenominator = 1;
  2948. return S_OK;
  2949. }
  2950. if (memcmp(&CURSOR_DBBMK_CURRENT, pBookmark, CURSOR_DB_BMK_SIZE) == 0)
  2951. {
  2952. cbBookmark = m_pCursorPosition->m_bmCurrent.GetBookmarkLen();
  2953. pBookmark = m_pCursorPosition->m_bmCurrent.GetBookmark();
  2954. }
  2955. }
  2956. IRowsetScroll * pRowsetScroll = GetRowsetScroll();
  2957. if (!pRowsetScroll)
  2958. return E_NOTIMPL;
  2959. HRESULT hr = pRowsetScroll->GetApproximatePosition(0,
  2960. cbBookmark,
  2961. (const BYTE *)pBookmark,
  2962. pulNumerator,
  2963. pulDenominator);
  2964. if SUCCEEDED(hr)
  2965. {
  2966. // since ICursor returns a zero based approximate position and IRowset is 1 based
  2967. // we need to adjust the return value
  2968. if (0 < *pulNumerator)
  2969. (*pulNumerator)--;
  2970. }
  2971. else
  2972. hr = VDMapRowsetHRtoCursorHR(hr, IDS_ERR_GETAPPROXPOSFAILED, IID_ICursorScroll, pRowsetScroll, IID_IRowsetScroll, m_pResourceDLL);
  2973. return hr;
  2974. }
  2975. //=--------------------------------------------------------------------------=
  2976. // ICursorScroll GetApproximateCount
  2977. //=--------------------------------------------------------------------------=
  2978. // Returns the approximate number of rows in the cursor
  2979. //
  2980. // Parameters:
  2981. // pudlApproxCount - [out] a pointer to a buffer containing the
  2982. // returned approximate count of the rows
  2983. // in the cursor
  2984. // pdwFullyPopuldated - [out] a pointer to a buffer containing returned
  2985. // flags indicating whether the cursor is fully
  2986. // populated
  2987. //
  2988. // Output:
  2989. // HRESULT - S_OK if successful
  2990. // E_INVALIDARG bad parameter
  2991. //
  2992. // Notes:
  2993. //
  2994. HRESULT CVDCursor::GetApproximateCount(LARGE_INTEGER *pudlApproxCount, DWORD *pdwFullyPopulated)
  2995. {
  2996. if (!IsRowsetValid())
  2997. {
  2998. VDSetErrorInfo(IDS_ERR_ROWSETRELEASED, IID_ICursorScroll, m_pResourceDLL);
  2999. return E_FAIL;
  3000. }
  3001. ASSERT_POINTER(pudlApproxCount, LARGE_INTEGER);
  3002. ASSERT_NULL_OR_POINTER(pdwFullyPopulated, DWORD);
  3003. if (!pudlApproxCount)
  3004. {
  3005. VDSetErrorInfo(IDS_ERR_INVALIDARG, IID_ICursorScroll, m_pResourceDLL);
  3006. return E_INVALIDARG;
  3007. }
  3008. IRowsetScroll * pRowsetScroll = GetRowsetScroll();
  3009. if (!pRowsetScroll)
  3010. return E_NOTIMPL;
  3011. HRESULT hr;
  3012. if (pdwFullyPopulated)
  3013. {
  3014. *pdwFullyPopulated = CURSOR_DBCURSORPOPULATED_FULLY;
  3015. IDBAsynchStatus * pDBAsynchStatus = NULL;
  3016. hr = pRowsetScroll->QueryInterface(IID_IDBAsynchStatus, (void**)&pDBAsynchStatus);
  3017. if (SUCCEEDED(hr) && pDBAsynchStatus)
  3018. {
  3019. ULONG ulProgress;
  3020. ULONG ulProgressMax;
  3021. ULONG ulStatusCode;
  3022. hr = pDBAsynchStatus->GetStatus(DB_NULL_HCHAPTER, DBASYNCHOP_OPEN, &ulProgress, &ulProgressMax, &ulStatusCode, NULL);
  3023. if (SUCCEEDED(hr))
  3024. {
  3025. if (ulProgress < ulProgressMax)
  3026. *pdwFullyPopulated = CURSOR_DBCURSORPOPULATED_PARTIALLY;
  3027. }
  3028. pDBAsynchStatus->Release();
  3029. }
  3030. }
  3031. pudlApproxCount->HighPart = 0;
  3032. hr = pRowsetScroll->GetApproximatePosition(0, 0, NULL, NULL, &pudlApproxCount->LowPart);
  3033. if FAILED(hr)
  3034. hr = VDMapRowsetHRtoCursorHR(hr, IDS_ERR_GETAPPROXPOSFAILED, IID_ICursorScroll, pRowsetScroll, IID_IRowsetScroll, m_pResourceDLL);
  3035. else
  3036. pudlApproxCount->LowPart -= m_pCursorPosition->GetCursorMain()->AddedRows();
  3037. return hr;
  3038. }
  3039. //=--------------------------------------------------------------------------=
  3040. // ICursorUpdateARow methods
  3041. //=--------------------------------------------------------------------------=
  3042. // ICursorUpdateARow BeginUpdate
  3043. //=--------------------------------------------------------------------------=
  3044. // Begins an operation that updates the current or adds a new row
  3045. //
  3046. // Parameters:
  3047. // dwFlags - [in] specifies the operation to begin
  3048. //
  3049. //
  3050. // Output:
  3051. // HRESULT - S_OK if successful
  3052. // E_FAIL a provider-specific error occured
  3053. // E_INVALIDARG bad parameter
  3054. // E_OUTOFMEMORY not enough memory
  3055. // CURSOR_DB_E_UPDATEINPROGRESS an update is already in progress
  3056. //
  3057. // Notes:
  3058. //
  3059. HRESULT CVDCursor::BeginUpdate(DWORD dwFlags)
  3060. {
  3061. IRowset * pRowset = GetRowset();
  3062. IAccessor * pAccessor = GetAccessor();
  3063. IRowsetChange * pRowsetChange = GetRowsetChange();
  3064. // make sure we have valid rowset, accessor and change pointers
  3065. if (!pRowset || !pAccessor || !pRowsetChange || !IsRowsetValid())
  3066. {
  3067. VDSetErrorInfo(IDS_ERR_ROWSETRELEASED, IID_ICursorUpdateARow, m_pResourceDLL);
  3068. return E_FAIL;
  3069. }
  3070. // check dwFlags for acceptable values
  3071. if (dwFlags != CURSOR_DBROWACTION_UPDATE && dwFlags != CURSOR_DBROWACTION_ADD)
  3072. {
  3073. VDSetErrorInfo(IDS_ERR_INVALIDARG, IID_ICursorUpdateARow, m_pResourceDLL);
  3074. return E_INVALIDARG;
  3075. }
  3076. // make sure that an update is not already in progress
  3077. if (m_pCursorPosition->GetEditMode() != CURSOR_DBEDITMODE_NONE)
  3078. {
  3079. VDSetErrorInfo(IDS_ERR_UPDATEINPROGRESS, IID_ICursorUpdateARow, m_pResourceDLL);
  3080. return CURSOR_DB_E_UPDATEINPROGRESS;
  3081. }
  3082. // setup notification structures
  3083. DWORD dwEventWhat = CURSOR_DBEVENT_CURRENT_ROW_DATA_CHANGED |
  3084. CURSOR_DBEVENT_SET_OF_ROWS_CHANGED;
  3085. CURSOR_DBNOTIFYREASON rgReasons[1];
  3086. VariantInit((VARIANT*)&rgReasons[0].arg1);
  3087. VariantInit((VARIANT*)&rgReasons[0].arg2);
  3088. switch (dwFlags)
  3089. {
  3090. case CURSOR_DBROWACTION_UPDATE:
  3091. rgReasons[0].dwReason = CURSOR_DBREASON_EDIT;
  3092. break;
  3093. case CURSOR_DBROWACTION_ADD:
  3094. rgReasons[0].dwReason = CURSOR_DBREASON_ADDNEW;
  3095. break;
  3096. }
  3097. // notify other interested parties of action
  3098. HRESULT hr = m_pCursorPosition->NotifyBefore(dwEventWhat, 1, rgReasons);
  3099. // make sure action was not cancelled
  3100. if (hr != S_OK)
  3101. {
  3102. VDSetErrorInfo(IDS_ERR_ACTIONCANCELLED, IID_ICursorUpdateARow, m_pResourceDLL);
  3103. return E_FAIL;
  3104. }
  3105. // insert new hRow if we're going into add mode
  3106. if (dwFlags == CURSOR_DBROWACTION_ADD)
  3107. {
  3108. hr = InsertNewRow();
  3109. if (FAILED(hr))
  3110. {
  3111. // notify other interested parties of failure
  3112. m_pCursorPosition->NotifyFail(dwEventWhat, 1, rgReasons);
  3113. return hr;
  3114. }
  3115. }
  3116. // reset column updates
  3117. hr = m_pCursorPosition->ResetColumnUpdates();
  3118. if (FAILED(hr))
  3119. {
  3120. // notify other interested parties of failure
  3121. m_pCursorPosition->NotifyFail(dwEventWhat, 1, rgReasons);
  3122. return hr;
  3123. }
  3124. // place cursor in correct mode
  3125. switch (dwFlags)
  3126. {
  3127. case CURSOR_DBROWACTION_UPDATE:
  3128. m_pCursorPosition->SetEditMode(CURSOR_DBEDITMODE_UPDATE);
  3129. break;
  3130. case CURSOR_DBROWACTION_ADD:
  3131. m_pCursorPosition->SetEditMode(CURSOR_DBEDITMODE_ADD);
  3132. break;
  3133. }
  3134. // notify other interested parties of success
  3135. m_pCursorPosition->NotifyAfter(dwEventWhat, 1, rgReasons);
  3136. return S_OK;
  3137. }
  3138. //=--------------------------------------------------------------------------=
  3139. // ICursorUpdateARow SetColumn
  3140. //=--------------------------------------------------------------------------=
  3141. // Sets the current value of the specified column
  3142. //
  3143. // Parameters:
  3144. // pcid - [in] a pointer to the columnID for which data is
  3145. // to be set
  3146. // pBindParams - [in] a pointer to a column binding structure containing
  3147. // information about the data and a pointer to the data
  3148. //
  3149. // Output:
  3150. // HRESULT - S_OK if successful
  3151. // E_INVALIDARG bad parameter
  3152. // E_OUTOFMEMORY not enough memory
  3153. // E_FAIL a provider-specific error occured
  3154. // CURSOR_DB_E_STATEERROR not in update or add mode
  3155. // CURSOR_DB_E_BADCOLUMNID pcid was not a valid column identifier
  3156. // CURSOR_DB_E_BADBINDINFO bad binding information
  3157. //
  3158. // Notes:
  3159. //
  3160. HRESULT CVDCursor::SetColumn(CURSOR_DBCOLUMNID *pcid, CURSOR_DBBINDPARAMS *pBindParams)
  3161. {
  3162. ASSERT_POINTER(pcid, CURSOR_DBCOLUMNID)
  3163. ASSERT_POINTER(pBindParams, CURSOR_DBBINDPARAMS)
  3164. // make sure we have valid rowset
  3165. if (!IsRowsetValid())
  3166. {
  3167. VDSetErrorInfo(IDS_ERR_ROWSETRELEASED, IID_ICursorUpdateARow, m_pResourceDLL);
  3168. return E_FAIL;
  3169. }
  3170. // make sure we have all necessary pointers
  3171. if (!pcid || !pBindParams || !pBindParams->pData)
  3172. {
  3173. VDSetErrorInfo(IDS_ERR_INVALIDARG, IID_ICursorUpdateARow, m_pResourceDLL);
  3174. return E_INVALIDARG;
  3175. }
  3176. // make sure we are in update or add mode
  3177. if (m_pCursorPosition->GetEditMode() == CURSOR_DBEDITMODE_NONE)
  3178. {
  3179. VDSetErrorInfo(IDS_ERR_STATEERROR, IID_ICursorUpdateARow, m_pResourceDLL);
  3180. return CURSOR_DB_E_STATEERROR;
  3181. }
  3182. CVDRowsetColumn * pColumn;
  3183. // validate cursor binding parameters and get rowset column
  3184. HRESULT hr = ValidateCursorBindParams(pcid, pBindParams, &pColumn);
  3185. if (FAILED(hr))
  3186. return hr;
  3187. CVDColumnUpdate * pColumnUpdate;
  3188. // create new column update object
  3189. hr = CVDColumnUpdate::Create(pColumn, pBindParams, &pColumnUpdate, m_pResourceDLL);
  3190. if (FAILED(hr))
  3191. return hr;
  3192. // setup notification structures
  3193. DWORD dwEventWhat = CURSOR_DBEVENT_CURRENT_ROW_DATA_CHANGED;
  3194. CURSOR_DBNOTIFYREASON rgReasons[1];
  3195. VariantInit((VARIANT*)&rgReasons[0].arg1);
  3196. VariantInit((VARIANT*)&rgReasons[0].arg2);
  3197. rgReasons[0].dwReason = CURSOR_DBREASON_SETCOLUMN;
  3198. rgReasons[0].arg1.vt = VT_I4;
  3199. rgReasons[0].arg1.lVal = pColumn->GetNumber();
  3200. rgReasons[0].arg2 = pColumnUpdate->GetVariant();
  3201. // notify other interested parties of action
  3202. hr = m_pCursorPosition->NotifyBefore(dwEventWhat, 1, rgReasons);
  3203. // make sure action was not cancelled
  3204. if (hr != S_OK)
  3205. {
  3206. // release column update object
  3207. pColumnUpdate->Release();
  3208. VDSetErrorInfo(IDS_ERR_ACTIONCANCELLED, IID_ICursorUpdateARow, m_pResourceDLL);
  3209. return E_FAIL;
  3210. }
  3211. // update column in cursor position
  3212. m_pCursorPosition->SetColumnUpdate(pColumn->GetNumber(), pColumnUpdate);
  3213. // notify other interested parties of success
  3214. m_pCursorPosition->NotifyAfter(dwEventWhat, 1, rgReasons);
  3215. return S_OK;
  3216. }
  3217. //=--------------------------------------------------------------------------=
  3218. // ICursorUpdateARow GetColumn
  3219. //=--------------------------------------------------------------------------=
  3220. // Gets the current value of the specified column
  3221. //
  3222. // Parameters:
  3223. // pcid - [in] a pointer to the columnID for which data is
  3224. // to be returned
  3225. // pBindParams - [out] a pointer to a column binding structure in which
  3226. // to return data
  3227. // pdwFlags - [out] a pointer to memory in which to return the
  3228. // changed state of the returned data
  3229. //
  3230. // Output:
  3231. // HRESULT - S_OK if successful
  3232. // E_INVALIDARG bad parameter
  3233. // E_OUTOFMEMORY not enough memory
  3234. // E_FAIL a provider-specific error occured
  3235. // CURSOR_DB_E_STATEERROR not in update or add mode
  3236. // CURSOR_DB_E_BADCOLUMNID pcid was not a valid column identifier
  3237. // CURSOR_DB_E_BADBINDINFO bad binding information
  3238. //
  3239. // Notes:
  3240. //
  3241. HRESULT CVDCursor::GetColumn(CURSOR_DBCOLUMNID *pcid, CURSOR_DBBINDPARAMS *pBindParams, DWORD *pdwFlags)
  3242. {
  3243. ASSERT_POINTER(pcid, CURSOR_DBCOLUMNID)
  3244. ASSERT_POINTER(pBindParams, CURSOR_DBBINDPARAMS)
  3245. ASSERT_NULL_OR_POINTER(pdwFlags, DWORD)
  3246. // make sure rowset is valid
  3247. if (!IsRowsetValid())
  3248. {
  3249. VDSetErrorInfo(IDS_ERR_ROWSETRELEASED, IID_ICursorUpdateARow, m_pResourceDLL);
  3250. return E_FAIL;
  3251. }
  3252. // make sure we have all necessary pointers
  3253. if (!pcid || !pBindParams || !pBindParams->pData)
  3254. {
  3255. VDSetErrorInfo(IDS_ERR_INVALIDARG, IID_ICursorUpdateARow, m_pResourceDLL);
  3256. return E_INVALIDARG;
  3257. }
  3258. // make sure we are in update or add mode
  3259. if (m_pCursorPosition->GetEditMode() == CURSOR_DBEDITMODE_NONE)
  3260. {
  3261. VDSetErrorInfo(IDS_ERR_STATEERROR, IID_ICursorUpdateARow, m_pResourceDLL);
  3262. return CURSOR_DB_E_STATEERROR;
  3263. }
  3264. CVDRowsetColumn * pColumn;
  3265. // validate cursor binding parameters and get rowset column
  3266. HRESULT hr = ValidateCursorBindParams(pcid, pBindParams, &pColumn);
  3267. if (FAILED(hr))
  3268. return hr;
  3269. // get column update pointer for this column
  3270. CVDColumnUpdate * pColumnUpdate = m_pCursorPosition->GetColumnUpdate(pColumn->GetNumber());
  3271. // if not changed, get original value
  3272. if (!pColumnUpdate)
  3273. {
  3274. hr = GetOriginalColumn(pColumn, pBindParams);
  3275. if (pdwFlags)
  3276. *pdwFlags = CURSOR_DBCOLUMNDATA_UNCHANGED;
  3277. }
  3278. else // otherwise, get modified value
  3279. {
  3280. hr = GetModifiedColumn(pColumnUpdate, pBindParams);
  3281. if (pdwFlags)
  3282. *pdwFlags = CURSOR_DBCOLUMNDATA_CHANGED;
  3283. }
  3284. return hr;
  3285. }
  3286. //=--------------------------------------------------------------------------=
  3287. // ICursorUpdateARow GetEditMode
  3288. //=--------------------------------------------------------------------------=
  3289. // Gets the current edit mode: add, update or none
  3290. //
  3291. // Parameters:
  3292. // pdwState - [out] a pointer to memory in which to return the
  3293. // current edit mode
  3294. //
  3295. // Output:
  3296. // HRESULT - S_OK if successful
  3297. // E_FAIL a provider-specific error occured
  3298. // E_INVALIDARG bad parameter
  3299. //
  3300. // Notes:
  3301. //
  3302. HRESULT CVDCursor::GetEditMode(DWORD *pdwState)
  3303. {
  3304. ASSERT_POINTER(pdwState, DWORD)
  3305. // make sure we have a valid rowset
  3306. if (!IsRowsetValid())
  3307. {
  3308. VDSetErrorInfo(IDS_ERR_ROWSETRELEASED, IID_ICursorUpdateARow, m_pResourceDLL);
  3309. return E_FAIL;
  3310. }
  3311. // make sure we have a pointer
  3312. if (!pdwState)
  3313. {
  3314. VDSetErrorInfo(IDS_ERR_INVALIDARG, IID_ICursorUpdateARow, m_pResourceDLL);
  3315. return E_INVALIDARG;
  3316. }
  3317. // return edit mode
  3318. *pdwState = m_pCursorPosition->GetEditMode();
  3319. return S_OK;
  3320. }
  3321. //=--------------------------------------------------------------------------=
  3322. // ICursorUpdateARow Update
  3323. //=--------------------------------------------------------------------------=
  3324. // Sends the contents of the edit buffer to the database and optionally
  3325. // returns the bookmark for the updated or added row
  3326. //
  3327. // Parameters:
  3328. // pBookmarkType - [in] a pointer to a columnID that specifies the type
  3329. // of bookmark desired
  3330. // pcbBookmark - [out] a pointer to memory in which to return the actual
  3331. // length of the returned bookmark
  3332. // ppBookmark - [out] a pointer to memory in which to return a pointer
  3333. // to a bookmark
  3334. //
  3335. // Output:
  3336. // HRESULT - S_OK if successful
  3337. // E_FAIL a provider-specific error occured
  3338. // E_OUTOFMEMORY not enough memory
  3339. // CURSOR_DB_E_STATEERROR not in update or add mode
  3340. //
  3341. // Notes:
  3342. // Kagera does not allow variant bindings on dbtimestamp fields, so this code
  3343. // updates dbtimestamp fields using string pointers if possible.
  3344. //
  3345. HRESULT CVDCursor::Update(CURSOR_DBCOLUMNID *pBookmarkType, ULONG *pcbBookmark, void **ppBookmark)
  3346. {
  3347. ASSERT_NULL_OR_POINTER(pBookmarkType, CURSOR_DBCOLUMNID)
  3348. ASSERT_NULL_OR_POINTER(pcbBookmark, ULONG)
  3349. ASSERT_NULL_OR_POINTER(ppBookmark, void*)
  3350. IAccessor * pAccessor = GetAccessor();
  3351. IRowsetChange * pRowsetChange = GetRowsetChange();
  3352. IRowsetUpdate * pRowsetUpdate = GetRowsetUpdate();
  3353. BOOL fUndo = FALSE;
  3354. BOOL fInsert = FALSE;
  3355. // make sure we have valid accessor and change pointers
  3356. if (!pAccessor || !pRowsetChange || !IsRowsetValid())
  3357. {
  3358. VDSetErrorInfo(IDS_ERR_ROWSETRELEASED, IID_ICursorUpdateARow, m_pResourceDLL);
  3359. return E_FAIL;
  3360. }
  3361. // get current edit mode
  3362. const DWORD dwEditMode = m_pCursorPosition->GetEditMode();
  3363. // make sure we are in update or add mode
  3364. if (dwEditMode == CURSOR_DBEDITMODE_NONE)
  3365. {
  3366. VDSetErrorInfo(IDS_ERR_STATEERROR, IID_ICursorUpdateARow, m_pResourceDLL);
  3367. return CURSOR_DB_E_STATEERROR;
  3368. }
  3369. // get hRow of the row currently being edited
  3370. HROW hRow = m_pCursorPosition->GetEditRow();
  3371. // get column count
  3372. const ULONG ulColumns = GetCursorMain()->GetColumnsCount();
  3373. // create update buffer accessor bindings
  3374. DBBINDING * pBindings = new DBBINDING[ulColumns];
  3375. if (!pBindings)
  3376. {
  3377. VDSetErrorInfo(IDS_ERR_OUTOFMEMORY, IID_ICursorUpdateARow, m_pResourceDLL);
  3378. return E_OUTOFMEMORY;
  3379. }
  3380. // clear out bindings
  3381. memset(pBindings, 0, ulColumns * sizeof(DBBINDING));
  3382. // setup notification structures
  3383. DWORD dwEventWhat = CURSOR_DBEVENT_CURRENT_ROW_DATA_CHANGED |
  3384. CURSOR_DBEVENT_NONCURRENT_ROW_DATA_CHANGED |
  3385. CURSOR_DBEVENT_SET_OF_ROWS_CHANGED;
  3386. CURSOR_DBNOTIFYREASON rgReasons[1];
  3387. VariantInit((VARIANT*)&rgReasons[0].arg1);
  3388. VariantInit((VARIANT*)&rgReasons[0].arg2);
  3389. switch (dwEditMode)
  3390. {
  3391. case CURSOR_DBEDITMODE_UPDATE:
  3392. rgReasons[0].dwReason = CURSOR_DBREASON_MODIFIED;
  3393. rgReasons[0].arg1 = m_pCursorPosition->m_bmCurrent.GetBookmarkVariant();
  3394. break;
  3395. case CURSOR_DBEDITMODE_ADD:
  3396. rgReasons[0].dwReason = CURSOR_DBREASON_INSERTED;
  3397. rgReasons[0].arg1 = m_pCursorPosition->m_bmAddRow.GetBookmarkVariant();
  3398. break;
  3399. }
  3400. // notify other interested parties of action
  3401. HRESULT hr = m_pCursorPosition->NotifyBefore(dwEventWhat, 1, rgReasons);
  3402. // make sure action was not cancelled
  3403. if (hr != S_OK)
  3404. {
  3405. // destroy bindings
  3406. delete [] pBindings;
  3407. VDSetErrorInfo(IDS_ERR_ACTIONCANCELLED, IID_ICursorUpdateARow, m_pResourceDLL);
  3408. return E_FAIL;
  3409. }
  3410. // variables
  3411. ULONG cBindings = 0;
  3412. DBBINDING * pBinding = pBindings;
  3413. CVDColumnUpdate * pColumnUpdate;
  3414. ULONG obUpdate = 0;
  3415. // iterate through columns and setup binding structures
  3416. for (ULONG ulCol = 0; ulCol < ulColumns; ulCol++)
  3417. {
  3418. // get column update pointer
  3419. pColumnUpdate = m_pCursorPosition->GetColumnUpdate(ulCol);
  3420. if (pColumnUpdate)
  3421. {
  3422. // create column update buffer binding
  3423. pBinding->iOrdinal = pColumnUpdate->GetColumn()->GetOrdinal();
  3424. pBinding->obValue = obUpdate + sizeof(DBSTATUS) + sizeof(ULONG);
  3425. pBinding->obLength = obUpdate + sizeof(DBSTATUS);
  3426. pBinding->obStatus = obUpdate;
  3427. pBinding->dwPart = DBPART_VALUE;
  3428. pBinding->dwMemOwner = DBMEMOWNER_CLIENTOWNED;
  3429. pBinding->wType = DBTYPE_VARIANT;
  3430. // determine if length part is included
  3431. if (pColumnUpdate->GetVarDataLen() != CURSOR_DB_NOVALUE)
  3432. pBinding->dwPart |= DBPART_LENGTH;
  3433. pBinding->dwPart |= DBPART_STATUS;
  3434. // check for variant binding on dbtimestamp field, and supplied variant is a bstr
  3435. if (pColumnUpdate->GetColumn()->GetType() == DBTYPE_DBTIMESTAMP && pColumnUpdate->GetVariantType() == VT_BSTR)
  3436. {
  3437. pBinding->dwPart &= ~DBPART_LENGTH;
  3438. pBinding->wType = DBTYPE_BYREF | DBTYPE_WSTR;
  3439. }
  3440. // increment update offset
  3441. obUpdate += sizeof(DBSTATUS) + sizeof(ULONG) + sizeof(VARIANT);
  3442. // increment binding
  3443. cBindings++;
  3444. pBinding++;
  3445. }
  3446. }
  3447. // if we have any bindings, then update
  3448. if (cBindings)
  3449. {
  3450. HACCESSOR hAccessor;
  3451. // create update accessor
  3452. hr = pAccessor->CreateAccessor(DBACCESSOR_ROWDATA, cBindings, pBindings, 0, &hAccessor, NULL);
  3453. hr = VDMapRowsetHRtoCursorHR(hr, IDS_ERR_CREATEACCESSORFAILED, IID_ICursorUpdateARow, pAccessor, IID_IAccessor,
  3454. m_pResourceDLL);
  3455. if (FAILED(hr))
  3456. {
  3457. // destroy bindings
  3458. delete [] pBindings;
  3459. // notify other interested parties of failure
  3460. m_pCursorPosition->NotifyFail(dwEventWhat, 1, rgReasons);
  3461. return hr;
  3462. }
  3463. // create update buffer
  3464. BYTE * pBuffer = new BYTE[cBindings * (sizeof(DBSTATUS) + sizeof(ULONG) + sizeof(VARIANT))];
  3465. BYTE * pBufferOld = new BYTE[cBindings * (sizeof(DBSTATUS) + sizeof(ULONG) + sizeof(VARIANT))];
  3466. if (!pBuffer || !pBufferOld)
  3467. {
  3468. // destroy bindings
  3469. delete [] pBindings;
  3470. // destroy buffers
  3471. delete [] pBuffer;
  3472. delete [] pBufferOld;
  3473. // release update accessor
  3474. pAccessor->ReleaseAccessor(hAccessor, NULL);
  3475. // notify other interested parties of failure
  3476. m_pCursorPosition->NotifyFail(dwEventWhat, 1, rgReasons);
  3477. return E_OUTOFMEMORY;
  3478. }
  3479. // variables
  3480. obUpdate = 0;
  3481. pBinding = pBindings;
  3482. CURSOR_DBVARIANT variant;
  3483. // iterate through columns and setup buffer
  3484. for (ULONG ulCol = 0; ulCol < ulColumns; ulCol++)
  3485. {
  3486. // get column update pointer
  3487. pColumnUpdate = m_pCursorPosition->GetColumnUpdate(ulCol);
  3488. if (pColumnUpdate)
  3489. {
  3490. // obtain current status
  3491. DBSTATUS status = CursorInfoToStatus(pColumnUpdate->GetInfo());
  3492. // get value
  3493. variant = pColumnUpdate->GetVariant();
  3494. // check for empty value since some controls treat this as NULL and make sure that we
  3495. // treat the empty value as null
  3496. if (status == DBSTATUS_S_OK &&
  3497. variant.vt == VT_BSTR &&
  3498. wcslen(variant.bstrVal) == 0)
  3499. {
  3500. *(DBSTATUS*)(pBuffer + obUpdate) = DBSTATUS_S_ISNULL;
  3501. }
  3502. else
  3503. {
  3504. *(DBSTATUS*)(pBuffer + obUpdate) = status;
  3505. }
  3506. *(DBSTATUS*)(pBufferOld + obUpdate) = DBSTATUS_S_ISNULL;
  3507. // if necessary, set length part in buffer
  3508. if (pBinding->dwPart & DBPART_LENGTH)
  3509. {
  3510. *(ULONG*)(pBuffer + obUpdate + sizeof(DBSTATUS)) = pColumnUpdate->GetVarDataLen();
  3511. *(ULONG*)(pBufferOld + obUpdate + sizeof(DBSTATUS)) = 0;
  3512. }
  3513. // always set value part in buffer
  3514. if (pBinding->wType == (DBTYPE_BYREF | DBTYPE_WSTR))
  3515. {
  3516. *(BSTR*)(pBuffer + obUpdate + sizeof(DBSTATUS) + sizeof(ULONG)) = variant.bstrVal;
  3517. *(BSTR*)(pBufferOld + obUpdate + sizeof(DBSTATUS) + sizeof(ULONG)) = NULL;
  3518. }
  3519. else
  3520. {
  3521. memcpy(pBuffer + obUpdate + sizeof(DBSTATUS) + sizeof(ULONG), &variant, sizeof(VARIANT));
  3522. VariantInit((VARIANT *) (pBufferOld + obUpdate + sizeof(DBSTATUS) + sizeof(ULONG)));
  3523. }
  3524. // increment update offset
  3525. obUpdate += sizeof(DBSTATUS) + sizeof(ULONG) + sizeof(VARIANT);
  3526. // increment binding
  3527. pBinding++;
  3528. }
  3529. }
  3530. DBPENDINGSTATUS status;
  3531. if (dwEditMode == CURSOR_DBEDITMODE_ADD)
  3532. fInsert = TRUE;
  3533. else if (pRowsetUpdate)
  3534. {
  3535. pRowsetUpdate->GetRowStatus(NULL, 1, &hRow, &status);
  3536. if (status == DBPENDINGSTATUS_UNCHANGED)
  3537. fUndo = TRUE;
  3538. }
  3539. if (!fUndo && !fInsert)
  3540. {
  3541. hr = GetRowset()->GetData(hRow, hAccessor, pBufferOld);
  3542. if (status != DBPENDINGSTATUS_NEW)
  3543. fUndo = TRUE;
  3544. }
  3545. // modify columns (set/clear internal set data flag)
  3546. GetCursorMain()->SetInternalSetData(TRUE);
  3547. hr = pRowsetChange->SetData(hRow, hAccessor, pBuffer);
  3548. if (hr == DB_S_ERRORSOCCURRED)
  3549. {
  3550. // since partial changes occurred, restore data back
  3551. // to original values.
  3552. if (fUndo)
  3553. pRowsetUpdate->Undo(NULL, 1, &hRow, NULL, NULL, NULL);
  3554. else if (status != DBPENDINGSTATUS_NEW)
  3555. pRowsetChange->SetData(hRow, hAccessor, pBufferOld);
  3556. hr = DB_E_ERRORSOCCURRED;
  3557. }
  3558. GetCursorMain()->SetInternalSetData(FALSE);
  3559. hr = VDMapRowsetHRtoCursorHR(hr, IDS_ERR_SETDATAFAILED, IID_ICursorUpdateARow, pRowsetChange, IID_IRowsetChange,
  3560. m_pResourceDLL);
  3561. // release update accessor
  3562. pAccessor->ReleaseAccessor(hAccessor, NULL);
  3563. obUpdate = 0;
  3564. pBinding = pBindings;
  3565. // iterate through columns and reset buffer
  3566. for (ulCol = 0; ulCol < ulColumns; ulCol++)
  3567. {
  3568. if (m_pCursorPosition->GetColumnUpdate(ulCol))
  3569. {
  3570. VARIANT var;
  3571. if (pBinding->wType == (DBTYPE_BYREF | DBTYPE_WSTR))
  3572. {
  3573. var.vt = VT_BSTR;
  3574. var.bstrVal = *(BSTR*)(pBufferOld + obUpdate + sizeof(DBSTATUS) + sizeof(ULONG));
  3575. }
  3576. else
  3577. {
  3578. memcpy(&var, pBufferOld + obUpdate + sizeof(DBSTATUS) + sizeof(ULONG), sizeof(VARIANT));
  3579. }
  3580. VariantClear(&var);
  3581. // increment update offset
  3582. obUpdate += sizeof(DBSTATUS) + sizeof(ULONG) + sizeof(VARIANT);
  3583. // increment binding
  3584. pBinding++;
  3585. }
  3586. }
  3587. // destroy update buffer
  3588. delete [] pBuffer;
  3589. delete [] pBufferOld;
  3590. }
  3591. // destroy bindings
  3592. delete [] pBindings;
  3593. if (FAILED(hr))
  3594. {
  3595. // notify other interested parties of failure
  3596. m_pCursorPosition->NotifyFail(dwEventWhat, 1, rgReasons);
  3597. }
  3598. else
  3599. {
  3600. // return bookmark if requested to do so
  3601. if (pBookmarkType && pcbBookmark && ppBookmark)
  3602. {
  3603. switch (dwEditMode)
  3604. {
  3605. case CURSOR_DBEDITMODE_UPDATE:
  3606. *pcbBookmark = m_pCursorPosition->m_bmCurrent.GetBookmarkLen();
  3607. memcpy(*ppBookmark, m_pCursorPosition->m_bmCurrent.GetBookmark(), *pcbBookmark);
  3608. break;
  3609. case CURSOR_DBEDITMODE_ADD:
  3610. *pcbBookmark = m_pCursorPosition->m_bmAddRow.GetBookmarkLen();
  3611. memcpy(*ppBookmark, m_pCursorPosition->m_bmAddRow.GetBookmark(), *pcbBookmark);
  3612. break;
  3613. }
  3614. }
  3615. // if acquired, release same-row clone
  3616. if (m_pCursorPosition->GetSameRowClone())
  3617. m_pCursorPosition->ReleaseSameRowClone();
  3618. // also, release add row if we have one
  3619. if (m_pCursorPosition->m_bmAddRow.GetHRow())
  3620. m_pCursorPosition->ReleaseAddRow();
  3621. // reset edit mode
  3622. m_pCursorPosition->SetEditMode(CURSOR_DBEDITMODE_NONE);
  3623. // reset column updates
  3624. m_pCursorPosition->ResetColumnUpdates();
  3625. // notify other interested parties of success
  3626. m_pCursorPosition->NotifyAfter(dwEventWhat, 1, rgReasons);
  3627. }
  3628. return hr;
  3629. }
  3630. //=--------------------------------------------------------------------------=
  3631. // ICursorUpdateARow Cancel
  3632. //=--------------------------------------------------------------------------=
  3633. // Cancels the update or add operation
  3634. //
  3635. // Parameters:
  3636. // none
  3637. //
  3638. // Output:
  3639. // HRESULT - S_OK if successful
  3640. // E_FAIL a provider-specific error occured
  3641. // CURSOR_DB_E_STATEERROR not in update or add mode
  3642. //
  3643. // Notes:
  3644. //
  3645. HRESULT CVDCursor::Cancel(void)
  3646. {
  3647. // make sure we have a valid rowset
  3648. if (!IsRowsetValid())
  3649. {
  3650. VDSetErrorInfo(IDS_ERR_ROWSETRELEASED, IID_ICursorUpdateARow, m_pResourceDLL);
  3651. return E_FAIL;
  3652. }
  3653. // get current edit mode
  3654. const DWORD dwEditMode = m_pCursorPosition->GetEditMode();
  3655. // make sure we are in update or add mode
  3656. if (dwEditMode == CURSOR_DBEDITMODE_NONE)
  3657. {
  3658. VDSetErrorInfo(IDS_ERR_STATEERROR, IID_ICursorUpdateARow, m_pResourceDLL);
  3659. return CURSOR_DB_E_STATEERROR;
  3660. }
  3661. // try to get update pointer
  3662. IRowsetUpdate * pRowsetUpdate = GetRowsetUpdate();
  3663. // get hRow of the row currently being edited
  3664. HROW hRow = m_pCursorPosition->GetEditRow();
  3665. // setup notification structures
  3666. DWORD dwEventWhat = CURSOR_DBEVENT_CURRENT_ROW_DATA_CHANGED;
  3667. CURSOR_DBNOTIFYREASON rgReasons[1];
  3668. VariantInit((VARIANT*)&rgReasons[0].arg1);
  3669. VariantInit((VARIANT*)&rgReasons[0].arg2);
  3670. rgReasons[0].dwReason = CURSOR_DBREASON_CANCELUPDATE;
  3671. // notify other interested parties of action
  3672. HRESULT hr = m_pCursorPosition->NotifyBefore(dwEventWhat, 1, rgReasons);
  3673. // make sure action was not cancelled
  3674. if (hr != S_OK)
  3675. {
  3676. VDSetErrorInfo(IDS_ERR_ACTIONCANCELLED, IID_ICursorUpdateARow, m_pResourceDLL);
  3677. return E_FAIL;
  3678. }
  3679. // if we are comming out of add mode, undo inserted row
  3680. if (pRowsetUpdate && dwEditMode == CURSOR_DBEDITMODE_ADD)
  3681. {
  3682. hr = pRowsetUpdate->Undo(0, 1, &hRow, NULL, NULL, NULL);
  3683. hr = VDMapRowsetHRtoCursorHR(hr, IDS_ERR_UNDOFAILED, IID_ICursorUpdateARow, pRowsetUpdate, IID_IRowsetUpdate,
  3684. m_pResourceDLL);
  3685. if (FAILED(hr))
  3686. {
  3687. // notify other interested parties of failure
  3688. m_pCursorPosition->NotifyFail(dwEventWhat, 1, rgReasons);
  3689. return hr;
  3690. }
  3691. }
  3692. // if acquired, release same-row clone
  3693. if (m_pCursorPosition->GetSameRowClone())
  3694. m_pCursorPosition->ReleaseSameRowClone();
  3695. // also, release add row if we have one
  3696. if (m_pCursorPosition->m_bmAddRow.GetHRow())
  3697. m_pCursorPosition->ReleaseAddRow();
  3698. // reset edit mode
  3699. m_pCursorPosition->SetEditMode(CURSOR_DBEDITMODE_NONE);
  3700. // reset column updates
  3701. m_pCursorPosition->ResetColumnUpdates();
  3702. // notify other interested parties of success
  3703. m_pCursorPosition->NotifyAfter(dwEventWhat, 1, rgReasons);
  3704. return S_OK;
  3705. }
  3706. //=--------------------------------------------------------------------------=
  3707. // ICursorUpdateARow Delete
  3708. //=--------------------------------------------------------------------------=
  3709. // Deletes the current row
  3710. //
  3711. // Parameters:
  3712. // none
  3713. //
  3714. // Output:
  3715. // HRESULT - S_OK if successful
  3716. // E_FAIL a provider-specific error occured
  3717. // CURSOR_DB_E_UPDATEINPROGRESS an update is already in progress
  3718. //
  3719. // Notes:
  3720. //
  3721. HRESULT CVDCursor::Delete(void)
  3722. {
  3723. IRowsetChange * pRowsetChange = GetRowsetChange();
  3724. // make sure we have a valid change pointer
  3725. if (!pRowsetChange || !IsRowsetValid())
  3726. {
  3727. VDSetErrorInfo(IDS_ERR_ROWSETRELEASED, IID_ICursorUpdateARow, m_pResourceDLL);
  3728. return E_FAIL;
  3729. }
  3730. // make sure that an update is not already in progress
  3731. if (m_pCursorPosition->GetEditMode() != CURSOR_DBEDITMODE_NONE)
  3732. {
  3733. VDSetErrorInfo(IDS_ERR_UPDATEINPROGRESS, IID_ICursorUpdateARow, m_pResourceDLL);
  3734. return CURSOR_DB_E_UPDATEINPROGRESS;
  3735. }
  3736. // get current hRow
  3737. HROW hRow = m_pCursorPosition->m_bmCurrent.GetHRow();
  3738. // setup notification structures
  3739. DWORD dwEventWhat = CURSOR_DBEVENT_CURRENT_ROW_DATA_CHANGED |
  3740. CURSOR_DBEVENT_SET_OF_ROWS_CHANGED;
  3741. CURSOR_DBNOTIFYREASON rgReasons[1];
  3742. VariantInit((VARIANT*)&rgReasons[0].arg1);
  3743. VariantInit((VARIANT*)&rgReasons[0].arg2);
  3744. rgReasons[0].dwReason = CURSOR_DBREASON_DELETED;
  3745. rgReasons[0].arg1 = m_pCursorPosition->m_bmCurrent.GetBookmarkVariant();
  3746. // notify other interested parties of action
  3747. HRESULT hr = m_pCursorPosition->NotifyBefore(dwEventWhat, 1, rgReasons);
  3748. // make sure action was not cancelled
  3749. if (hr != S_OK)
  3750. {
  3751. VDSetErrorInfo(IDS_ERR_ACTIONCANCELLED, IID_ICursorUpdateARow, m_pResourceDLL);
  3752. return E_FAIL;
  3753. }
  3754. // try to delete current row (set/clear internal delete rows flag)
  3755. GetCursorMain()->SetInternalDeleteRows(TRUE);
  3756. hr = pRowsetChange->DeleteRows(0, 1, &hRow, NULL);
  3757. GetCursorMain()->SetInternalDeleteRows(FALSE);
  3758. hr = VDMapRowsetHRtoCursorHR(hr, IDS_ERR_DELETEROWSFAILED, IID_ICursorUpdateARow, pRowsetChange, IID_IRowsetChange,
  3759. m_pResourceDLL);
  3760. if (FAILED(hr))
  3761. {
  3762. // notify other interested parties of failure
  3763. m_pCursorPosition->NotifyFail(dwEventWhat, 1, rgReasons);
  3764. }
  3765. else
  3766. {
  3767. // notify other interested parties of success
  3768. m_pCursorPosition->NotifyAfter(dwEventWhat, 1, rgReasons);
  3769. }
  3770. return hr;
  3771. }
  3772. //=--------------------------------------------------------------------------=
  3773. // ICursorFind methods
  3774. //=--------------------------------------------------------------------------=
  3775. // ICursorFind FindByValues
  3776. //
  3777. HRESULT CVDCursor::FindByValues(ULONG cbBookmark,
  3778. LPVOID pBookmark,
  3779. DWORD dwFindFlags,
  3780. ULONG cValues,
  3781. CURSOR_DBCOLUMNID rgColumns[],
  3782. CURSOR_DBVARIANT rgValues[],
  3783. DWORD rgdwSeekFlags[],
  3784. CURSOR_DBFETCHROWS FAR *pFetchParams)
  3785. {
  3786. //////////////////////////////////////////////////////////////////////////
  3787. // this implementation limits the number of columns that can be searched
  3788. // to one, since current OLEDB spec only allows a single column accessor
  3789. // to be passed to IRowsetFind::FindNextRow (06/11/97)
  3790. //
  3791. if (cValues > 1)
  3792. return E_FAIL;
  3793. //
  3794. //////////////////////////////////////////////////////////////////////////
  3795. IAccessor * pAccessor = GetAccessor();
  3796. IRowsetFind * pRowsetFind = GetRowsetFind();
  3797. // make sure we have valid accessor and find pointers
  3798. if (!pAccessor || !pRowsetFind || !IsRowsetValid())
  3799. {
  3800. VDSetErrorInfo(IDS_ERR_ROWSETRELEASED, IID_IEntryID, m_pResourceDLL);
  3801. return E_FAIL;
  3802. }
  3803. // check for values
  3804. if (!cValues)
  3805. return S_OK;
  3806. DWORD dwEventWhat = CURSOR_DBEVENT_CURRENT_ROW_CHANGED;
  3807. CURSOR_DBNOTIFYREASON rgReasons[1];
  3808. rgReasons[0].dwReason = CURSOR_DBREASON_FIND;
  3809. VariantInit((VARIANT*)&rgReasons[0].arg1);
  3810. rgReasons[0].arg1.vt = VT_UI4;
  3811. rgReasons[0].arg1.lVal = dwFindFlags;
  3812. VariantInit((VARIANT*)&rgReasons[0].arg2);
  3813. // notify other interested parties
  3814. HRESULT hr = m_pCursorPosition->NotifyBefore(dwEventWhat, 1, rgReasons);
  3815. // make sure action was not cancelled
  3816. if (hr != S_OK)
  3817. {
  3818. VDSetErrorInfo(IDS_ERR_ACTIONCANCELLED, IID_ICursorFind, m_pResourceDLL);
  3819. return E_FAIL;
  3820. }
  3821. ULONG ul;
  3822. HROW * pRow = NULL;
  3823. ULONG cRowsObtained = 0;
  3824. HACCESSOR hAccessor = NULL;
  3825. // allocate necessary memory
  3826. ULONG * pColumns = new ULONG[cValues];
  3827. DBTYPE * pDBTypes = new DBTYPE[cValues];
  3828. DBCOMPAREOP * pDBCompareOp = new DBCOMPAREOP[cValues];
  3829. BYTE ** ppValues = new BYTE*[cValues];
  3830. BOOL * fMemAllocated = new BOOL[cValues];
  3831. if (fMemAllocated)
  3832. {
  3833. // always init fMemAllocated flags to false
  3834. memset(fMemAllocated, 0, sizeof(BOOL) * cValues);
  3835. }
  3836. // make sure we received all requested memory
  3837. if (!pColumns || !pDBTypes || !ppValues || !pDBCompareOp || !fMemAllocated)
  3838. {
  3839. VDSetErrorInfo(IDS_ERR_OUTOFMEMORY, IID_IRowsetFind, m_pResourceDLL);
  3840. hr = E_OUTOFMEMORY;
  3841. goto cleanup;
  3842. }
  3843. // iterate through columns
  3844. for (ul = 0; ul < cValues; ul++)
  3845. {
  3846. // get column ordinal position
  3847. hr = GetOrdinal(rgColumns[ul], &pColumns[ul]);
  3848. if (FAILED(hr))
  3849. {
  3850. VDSetErrorInfo(IDS_ERR_INVALIDARG, IID_IRowsetFind, m_pResourceDLL);
  3851. hr = E_INVALIDARG;
  3852. goto cleanup;
  3853. }
  3854. // get find values from CURSOR_DBVARIANT
  3855. hr = GetDataFromDBVariant(&rgValues[ul],
  3856. &pDBTypes[ul],
  3857. &(ppValues[ul]),
  3858. &fMemAllocated[ul]);
  3859. if (FAILED(hr))
  3860. {
  3861. VDSetErrorInfo(IDS_ERR_CANTCOERCE, IID_IRowsetFind, m_pResourceDLL);
  3862. goto cleanup;
  3863. }
  3864. // setup seek flags
  3865. switch (rgdwSeekFlags[ul])
  3866. {
  3867. case CURSOR_DBSEEK_LT:
  3868. pDBCompareOp[ul] = DBCOMPAREOPS_LT;
  3869. break;
  3870. case CURSOR_DBSEEK_LE:
  3871. pDBCompareOp[ul] = DBCOMPAREOPS_LE;
  3872. break;
  3873. case CURSOR_DBSEEK_EQ:
  3874. pDBCompareOp[ul] = DBCOMPAREOPS_EQ;
  3875. break;
  3876. case CURSOR_DBSEEK_GE:
  3877. pDBCompareOp[ul] = DBCOMPAREOPS_GE;
  3878. break;
  3879. case CURSOR_DBSEEK_GT:
  3880. pDBCompareOp[ul] = DBCOMPAREOPS_GT;
  3881. break;
  3882. case CURSOR_DBSEEK_PARTIALEQ:
  3883. pDBCompareOp[ul] = DBCOMPAREOPS_BEGINSWITH;
  3884. break;
  3885. default:
  3886. VDSetErrorInfo(IDS_ERR_INVALIDSEEKFLAGS, IID_IRowsetFind, m_pResourceDLL);
  3887. hr = E_FAIL;
  3888. goto cleanup;
  3889. }
  3890. }
  3891. LONG cRows;
  3892. BOOL fSkipCurrent;
  3893. // determine direction of seek
  3894. if (CURSOR_DBFINDFLAGS_FINDPRIOR == dwFindFlags)
  3895. {
  3896. cRows = -1;
  3897. fSkipCurrent = TRUE;
  3898. }
  3899. else
  3900. {
  3901. cRows = 1;
  3902. fSkipCurrent = TRUE;
  3903. }
  3904. BYTE bSpecialBM;
  3905. // check for standard bookmarks
  3906. if (CURSOR_DB_BMK_SIZE == cbBookmark)
  3907. {
  3908. if (memcmp(&CURSOR_DBBMK_BEGINNING, pBookmark, CURSOR_DB_BMK_SIZE) == 0)
  3909. {
  3910. cbBookmark = sizeof(BYTE);
  3911. bSpecialBM = DBBMK_FIRST;
  3912. pBookmark = &bSpecialBM;
  3913. fSkipCurrent = FALSE;
  3914. }
  3915. else
  3916. if (memcmp(&CURSOR_DBBMK_END, pBookmark, CURSOR_DB_BMK_SIZE) == 0)
  3917. {
  3918. cbBookmark = sizeof(BYTE);
  3919. bSpecialBM = DBBMK_LAST;
  3920. pBookmark = &bSpecialBM;
  3921. fSkipCurrent = FALSE;
  3922. }
  3923. else
  3924. if (memcmp(&CURSOR_DBBMK_CURRENT, pBookmark, CURSOR_DB_BMK_SIZE) == 0)
  3925. {
  3926. cbBookmark = m_pCursorPosition->m_bmCurrent.GetBookmarkLen();
  3927. pBookmark = m_pCursorPosition->m_bmCurrent.GetBookmark();
  3928. }
  3929. }
  3930. DBBINDING binding;
  3931. // clear out binding
  3932. memset(&binding, 0, sizeof(DBBINDING));
  3933. // create value binding
  3934. binding.iOrdinal = pColumns[0];
  3935. binding.obValue = 0;
  3936. binding.dwPart = DBPART_VALUE;
  3937. binding.dwMemOwner = DBMEMOWNER_CLIENTOWNED;
  3938. binding.cbMaxLen = 0x7FFFFFFF;
  3939. binding.wType = pDBTypes[0];
  3940. // create accessor describing the value to be matched
  3941. hr = pAccessor->CreateAccessor(DBACCESSOR_ROWDATA, 1, &binding, 0, &hAccessor, NULL);
  3942. if (FAILED(hr))
  3943. goto cleanup;
  3944. // try to find hRow satisfying our condition
  3945. hr = pRowsetFind->FindNextRow(DB_NULL_HCHAPTER,
  3946. hAccessor,
  3947. ppValues[0],
  3948. pDBCompareOp[0],
  3949. cbBookmark,
  3950. (BYTE*)pBookmark,
  3951. fSkipCurrent,
  3952. cRows,
  3953. &cRowsObtained,
  3954. &pRow);
  3955. // check to see if we rached end of rowset
  3956. if (hr == DB_S_ENDOFROWSET && !cRowsObtained)
  3957. hr = E_FAIL;
  3958. if (FAILED(hr))
  3959. hr = VDMapRowsetHRtoCursorHR(hr, IDS_ERR_FINDFAILED, IID_ICursorFind, pRowsetFind, IID_IRowsetFind, m_pResourceDLL);
  3960. // check to see if we got the hRow
  3961. if (SUCCEEDED(hr) && cRowsObtained)
  3962. {
  3963. // allocate buffer for bookmark plus length indicator
  3964. BYTE * pBuff = new BYTE[GetCursorMain()->GetMaxBookmarkLen() + sizeof(ULONG)];
  3965. if (!pBuff)
  3966. hr = E_OUTOFMEMORY;
  3967. else
  3968. {
  3969. // get the bookmark data
  3970. hr = GetRowset()->GetData(*pRow, GetCursorMain()->GetBookmarkAccessor(), pBuff);
  3971. if (SUCCEEDED(hr))
  3972. {
  3973. ULONG * pulLen = (ULONG*)pBuff;
  3974. BYTE * pbmdata = pBuff + sizeof(ULONG);
  3975. LARGE_INTEGER dlOffset;
  3976. dlOffset.HighPart = 0;
  3977. dlOffset.LowPart = 0;
  3978. hr = FetchAtBookmark(*pulLen, pbmdata, dlOffset, pFetchParams);
  3979. }
  3980. else
  3981. hr = VDMapRowsetHRtoCursorHR(hr, IDS_ERR_GETDATAFAILED, IID_ICursorFind, pRowsetFind, IID_IRowset, m_pResourceDLL);
  3982. delete [] pBuff;
  3983. }
  3984. }
  3985. if (pRow)
  3986. {
  3987. // release hRow
  3988. if (cRowsObtained)
  3989. GetRowset()->ReleaseRows(1, pRow, NULL, NULL, NULL);
  3990. g_pMalloc->Free(pRow);
  3991. }
  3992. cleanup:
  3993. rgReasons[0].arg2.vt = VT_BOOL;
  3994. V_BOOL(&rgReasons[0].arg2) = SUCCEEDED(hr) ? TRUE : FALSE;
  3995. if (SUCCEEDED(hr))
  3996. {
  3997. // notify other interested parties of success
  3998. m_pCursorPosition->NotifyAfter(dwEventWhat, 1, rgReasons);
  3999. }
  4000. else
  4001. {
  4002. // notify other interested parties of failure
  4003. m_pCursorPosition->NotifyFail(dwEventWhat, 1, rgReasons);
  4004. }
  4005. // free values
  4006. if (ppValues && fMemAllocated)
  4007. {
  4008. for (ul = 0; ul < cValues; ul++)
  4009. {
  4010. if (fMemAllocated[ul] && ppValues[ul])
  4011. g_pMalloc->Free(ppValues[ul]);
  4012. }
  4013. }
  4014. // free memory
  4015. delete [] pColumns;
  4016. delete [] pDBTypes;
  4017. delete [] ppValues;
  4018. delete [] pDBCompareOp;
  4019. delete [] fMemAllocated;
  4020. // release accessor
  4021. if (hAccessor)
  4022. pAccessor->ReleaseAccessor(hAccessor, NULL);
  4023. return hr;
  4024. }
  4025. //=--------------------------------------------------------------------------=
  4026. // IEnrtyID methods
  4027. //=--------------------------------------------------------------------------=
  4028. // IEntryID GetInterface
  4029. //=--------------------------------------------------------------------------=
  4030. // Gets the requested interface pointer to the given entryID
  4031. //
  4032. // Parameters:
  4033. // cbEntryID - [in] the size of the entryID
  4034. // pEntryID - [in] a pointer to the entryID
  4035. // dwFlags - [in] interface specific flags
  4036. // riid - [in] the interface id for the interface desired
  4037. // ppvObj - [out] a pointer to memory in which to return interface pointer
  4038. //
  4039. // Output:
  4040. // HRESULT - S_OK if successful
  4041. // E_INVALIDARG bad parameter
  4042. // E_OUTOFMEMORY not enough memory
  4043. // E_FAIL a provider-specific error occured
  4044. // E_NOINTERFACE no such interface supported
  4045. // CURSOR_DB_E_BADENTRYID bad entry identifier
  4046. //
  4047. // Notes:
  4048. //
  4049. HRESULT CVDCursor::GetInterface(ULONG cbEntryID, void *pEntryID, DWORD dwFlags, REFIID riid, IUnknown **ppvObj)
  4050. {
  4051. ASSERT_POINTER(pEntryID, BYTE)
  4052. ASSERT_POINTER(ppvObj, IUnknown*)
  4053. IRowset * pRowset = GetRowset();
  4054. // make sure we have a valid rowset pointer
  4055. if (!pRowset || !IsRowsetValid())
  4056. {
  4057. VDSetErrorInfo(IDS_ERR_ROWSETRELEASED, IID_IEntryID, m_pResourceDLL);
  4058. return E_FAIL;
  4059. }
  4060. // make sure we have all necessary pointers
  4061. if (!pEntryID || !ppvObj)
  4062. {
  4063. VDSetErrorInfo(IDS_ERR_INVALIDARG, IID_IEntryID, m_pResourceDLL);
  4064. return E_INVALIDARG;
  4065. }
  4066. // init out parameter
  4067. *ppvObj = NULL;
  4068. HROW hRow;
  4069. CVDRowsetColumn * pColumn;
  4070. // validate supplied entryID, and get rowset column and hRow
  4071. HRESULT hr = ValidateEntryID(cbEntryID, (BYTE*)pEntryID, &pColumn, &hRow);
  4072. if (FAILED(hr))
  4073. return hr;
  4074. IUnknown * pUnknown = NULL;
  4075. // first, try to get requested interface from entry identifier
  4076. hr = QueryEntryIDInterface(pColumn, hRow, dwFlags, riid, &pUnknown);
  4077. // if we succeeded or caller is not asking for IStream then leave
  4078. if (SUCCEEDED(hr) || riid != IID_IStream)
  4079. {
  4080. // release reference on hRow
  4081. pRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
  4082. *ppvObj = pUnknown;
  4083. return hr;
  4084. }
  4085. #ifndef VD_DONT_IMPLEMENT_ISTREAM
  4086. IStream * pStream;
  4087. // create stream from entry identifier
  4088. hr = CreateEntryIDStream(pColumn, hRow, &pStream);
  4089. if (FAILED(hr))
  4090. {
  4091. // release reference on hRow
  4092. pRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
  4093. return hr;
  4094. }
  4095. CVDEntryIDData * pEntryIDData;
  4096. // create entryID data object
  4097. hr = CVDEntryIDData::Create(m_pCursorPosition, pColumn, hRow, pStream, &pEntryIDData, m_pResourceDLL);
  4098. // release reference on hRow
  4099. pRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
  4100. // release reference on stream
  4101. pStream->Release();
  4102. if (FAILED(hr))
  4103. return hr;
  4104. CVDStream * pVDStream;
  4105. // create viaduct stream object
  4106. hr = CVDStream::Create(pEntryIDData, pStream, &pVDStream, m_pResourceDLL);
  4107. // release reference on entryID data object
  4108. pEntryIDData->Release();
  4109. if (FAILED(hr))
  4110. return hr;
  4111. // return stream
  4112. *ppvObj = pVDStream;
  4113. return S_OK;
  4114. #else //VD_DONT_IMPLEMENT_ISTREAM
  4115. // release reference on hRow
  4116. pRowset->ReleaseRows(1, &hRow, NULL, NULL, NULL);
  4117. VDSetErrorInfo(IDS_ERR_NOINTERFACE, IID_IEntryID, m_pResourceDLL);
  4118. return E_NOINTERFACE;
  4119. #endif //VD_DONT_IMPLEMENT_ISTREAM
  4120. }
  4121. /////////////////////////////////////////////////////////////////////////
  4122. // CVDNotifier functions
  4123. /////////////////////////////////////////////////////////////////////////
  4124. //+-------------------------------------------------------------------------
  4125. // Member: Notify Fail (public)
  4126. //
  4127. // Synopsis: send NotifyFail notification
  4128. //
  4129. // Arguments: dwEventWhat [in] what event is causing the notification
  4130. // cReasons [in] how many reasons
  4131. // rgReasons [in] list of reasons for the event
  4132. //
  4133. // Returns: S_OK it worked
  4134. HRESULT
  4135. CVDCursor::NotifyFail(DWORD dwEventWhat, ULONG cReasons,
  4136. CURSOR_DBNOTIFYREASON rgReasons[])
  4137. {
  4138. CVDNotifyDBEventsConnPt * pNotifyDBEventsConnPt = m_pConnPtContainer->GetNotifyDBEventsConnPt();
  4139. UINT uiConnectionsActive = pNotifyDBEventsConnPt->GetConnectionsActive();
  4140. INotifyDBEvents ** ppNotifyDBEvents = pNotifyDBEventsConnPt->GetNotifyDBEventsTable();
  4141. for (UINT uiConn = 0; uiConn < uiConnectionsActive; uiConn++)
  4142. ppNotifyDBEvents[uiConnectionsActive - uiConn - 1]->FailedToDo(dwEventWhat, cReasons, rgReasons);
  4143. return S_OK;
  4144. }
  4145. /////////////////////////////////////////////////////////////////////////
  4146. // CCursorNotifier helper functions
  4147. /////////////////////////////////////////////////////////////////////////
  4148. //+-------------------------------------------------------------------------
  4149. // Member: Notify OK To Do (public)
  4150. //
  4151. // Synopsis: Send OKToDo notification. If a client objects (by
  4152. // returning a non-zero HR, send FailedToDo to notified
  4153. // clients to cancel the event.
  4154. //
  4155. // Arguments: dwEventWhat [in] what event is causing the notification
  4156. // cReasons [in] how many reasons
  4157. // rgReasons [in] list of reasons for the event
  4158. //
  4159. // Returns: S_OK all clients agree it's OK to do the event
  4160. // other some client disagrees
  4161. HRESULT
  4162. CVDCursor::NotifyOKToDo(DWORD dwEventWhat, ULONG cReasons,
  4163. CURSOR_DBNOTIFYREASON rgReasons[])
  4164. {
  4165. HRESULT hr = S_OK;
  4166. CVDNotifyDBEventsConnPt * pNotifyDBEventsConnPt = m_pConnPtContainer->GetNotifyDBEventsConnPt();
  4167. UINT uiConnectionsActive = pNotifyDBEventsConnPt->GetConnectionsActive();
  4168. INotifyDBEvents ** ppNotifyDBEvents = pNotifyDBEventsConnPt->GetNotifyDBEventsTable();
  4169. for (UINT uiConn = 0; uiConn < uiConnectionsActive; uiConn++)
  4170. {
  4171. hr = ppNotifyDBEvents[uiConnectionsActive - uiConn - 1]->OKToDo(dwEventWhat, cReasons, rgReasons);
  4172. if (S_OK != hr)
  4173. {
  4174. for (UINT ui = 0; ui <= uiConn; ui++)
  4175. ppNotifyDBEvents[uiConnectionsActive - ui - 1]->Cancelled(dwEventWhat, cReasons, rgReasons);
  4176. break;
  4177. }
  4178. }
  4179. return hr;
  4180. }
  4181. //+-------------------------------------------------------------------------
  4182. // Member: Notify Sync Before (public)
  4183. //
  4184. // Synopsis: Send SyncBefore notification
  4185. //
  4186. // Arguments: dwEventWhat [in] what event is causing the notification
  4187. // cReasons [in] how many reasons
  4188. // rgReasons [in] list of reasons for the event
  4189. //
  4190. // Returns: S_OK all clients received notification
  4191. // other some client returned an error
  4192. HRESULT
  4193. CVDCursor::NotifySyncBefore(DWORD dwEventWhat, ULONG cReasons,
  4194. CURSOR_DBNOTIFYREASON rgReasons[])
  4195. {
  4196. HRESULT hr = S_OK;
  4197. CVDNotifyDBEventsConnPt * pNotifyDBEventsConnPt = m_pConnPtContainer->GetNotifyDBEventsConnPt();
  4198. UINT uiConnectionsActive = pNotifyDBEventsConnPt->GetConnectionsActive();
  4199. INotifyDBEvents ** ppNotifyDBEvents = pNotifyDBEventsConnPt->GetNotifyDBEventsTable();
  4200. for (UINT uiConn = 0; uiConn < uiConnectionsActive; uiConn++)
  4201. {
  4202. hr = ppNotifyDBEvents[uiConnectionsActive - uiConn - 1]->SyncBefore(dwEventWhat, cReasons, rgReasons);
  4203. if (S_OK != hr)
  4204. break;
  4205. }
  4206. return hr;
  4207. }
  4208. //+-------------------------------------------------------------------------
  4209. // Member: Notify About To Do (public)
  4210. //
  4211. // Synopsis: Send AboutToDo notification
  4212. //
  4213. // Arguments: dwEventWhat [in] what event is causing the notification
  4214. // cReasons [in] how many reasons
  4215. // rgReasons [in] list of reasons for the event
  4216. //
  4217. // Returns: S_OK all clients notified
  4218. // other some client returned an error
  4219. HRESULT
  4220. CVDCursor::NotifyAboutToDo(DWORD dwEventWhat, ULONG cReasons,
  4221. CURSOR_DBNOTIFYREASON rgReasons[])
  4222. {
  4223. HRESULT hr = S_OK;
  4224. CVDNotifyDBEventsConnPt * pNotifyDBEventsConnPt = m_pConnPtContainer->GetNotifyDBEventsConnPt();
  4225. UINT uiConnectionsActive = pNotifyDBEventsConnPt->GetConnectionsActive();
  4226. INotifyDBEvents ** ppNotifyDBEvents = pNotifyDBEventsConnPt->GetNotifyDBEventsTable();
  4227. for (UINT uiConn = 0; uiConn < uiConnectionsActive; uiConn++)
  4228. {
  4229. hr = ppNotifyDBEvents[uiConnectionsActive - uiConn - 1]->AboutToDo(dwEventWhat, cReasons, rgReasons);
  4230. if (S_OK != hr)
  4231. break;
  4232. }
  4233. return hr;
  4234. }
  4235. //+-------------------------------------------------------------------------
  4236. // Member: Notify Sync After (public)
  4237. //
  4238. // Synopsis: Send SyncAfter notification.
  4239. //
  4240. // Arguments: dwEventWhat [in] what event is causing the notification
  4241. // cReasons [in] how many reasons
  4242. // rgReasons [in] list of reasons for the event
  4243. //
  4244. // Returns: S_OK all clients notified
  4245. HRESULT
  4246. CVDCursor::NotifySyncAfter(DWORD dwEventWhat, ULONG cReasons,
  4247. CURSOR_DBNOTIFYREASON rgReasons[])
  4248. {
  4249. CVDNotifyDBEventsConnPt * pNotifyDBEventsConnPt = m_pConnPtContainer->GetNotifyDBEventsConnPt();
  4250. UINT uiConnectionsActive = pNotifyDBEventsConnPt->GetConnectionsActive();
  4251. INotifyDBEvents ** ppNotifyDBEvents = pNotifyDBEventsConnPt->GetNotifyDBEventsTable();
  4252. for (UINT uiConn = 0; uiConn < uiConnectionsActive; uiConn++)
  4253. ppNotifyDBEvents[uiConnectionsActive - uiConn - 1]->SyncAfter(dwEventWhat, cReasons, rgReasons);
  4254. return S_OK;
  4255. }
  4256. //+-------------------------------------------------------------------------
  4257. // Member: Notify Did Event (public)
  4258. //
  4259. // Synopsis: Send DidEvent notification
  4260. //
  4261. // Arguments: dwEventWhat [in] what event is causing the notification
  4262. // cReasons [in] how many reasons
  4263. // rgReasons [in] list of reasons for the event
  4264. //
  4265. // Returns: S_OK all clients notified
  4266. HRESULT
  4267. CVDCursor::NotifyDidEvent(DWORD dwEventWhat, ULONG cReasons,
  4268. CURSOR_DBNOTIFYREASON rgReasons[])
  4269. {
  4270. CVDNotifyDBEventsConnPt * pNotifyDBEventsConnPt = m_pConnPtContainer->GetNotifyDBEventsConnPt();
  4271. UINT uiConnectionsActive = pNotifyDBEventsConnPt->GetConnectionsActive();
  4272. INotifyDBEvents ** ppNotifyDBEvents = pNotifyDBEventsConnPt->GetNotifyDBEventsTable();
  4273. for (UINT uiConn = 0; uiConn < uiConnectionsActive; uiConn++)
  4274. ppNotifyDBEvents[uiConnectionsActive - uiConn - 1]->DidEvent(dwEventWhat, cReasons, rgReasons);
  4275. return S_OK;
  4276. }
  4277. //+-------------------------------------------------------------------------
  4278. // Member: Notify Cancel (public)
  4279. //
  4280. // Synopsis: Send Cancelled notification
  4281. //
  4282. // Arguments: dwEventWhat [in] what event is causing the notification
  4283. // cReasons [in] how many reasons
  4284. // rgReasons [in] list of reasons for the event
  4285. //
  4286. // Returns: S_OK all clients notified
  4287. HRESULT
  4288. CVDCursor::NotifyCancel(DWORD dwEventWhat, ULONG cReasons,
  4289. CURSOR_DBNOTIFYREASON rgReasons[])
  4290. {
  4291. CVDNotifyDBEventsConnPt * pNotifyDBEventsConnPt = m_pConnPtContainer->GetNotifyDBEventsConnPt();
  4292. UINT uiConnectionsActive = pNotifyDBEventsConnPt->GetConnectionsActive();
  4293. INotifyDBEvents ** ppNotifyDBEvents = pNotifyDBEventsConnPt->GetNotifyDBEventsTable();
  4294. for (UINT uiConn = 0; uiConn < uiConnectionsActive; uiConn++)
  4295. ppNotifyDBEvents[uiConnectionsActive - uiConn - 1]->Cancelled(dwEventWhat, cReasons, rgReasons);
  4296. return S_OK;
  4297. }