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.

627 lines
16 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) Microsoft Corp. All rights reserved.
  4. //
  5. // FILE
  6. //
  7. // SimTable.cpp
  8. //
  9. // SYNOPSIS
  10. //
  11. // This file implements the class CSimpleTable
  12. //
  13. // MODIFICATION HISTORY
  14. //
  15. // 10/31/1997 Original version.
  16. // 02/09/1998 Reorganized some things to make is easier to extend.
  17. // 02/27/1998 Changes to support moving it into the iasutil.lib
  18. // 10/16/1998 Support DBTYPE_WSTR.
  19. //
  20. ///////////////////////////////////////////////////////////////////////////////
  21. #include <windows.h>
  22. #include <comdef.h>
  23. #include <iasdefs.h>
  24. #include <iasutil.h>
  25. #include <oledberr.h>
  26. #include <SimTable.h>
  27. //////////
  28. // Stack version of the new operator.
  29. //////////
  30. #define stack_new(obj, num) new (_alloca(sizeof(obj)*num)) obj[num]
  31. ///////////////////////////////////////////////////////////////////////////////
  32. //
  33. // STRUCT
  34. //
  35. // DBBinding
  36. //
  37. // DESCRIPTION
  38. //
  39. // This struct extends the DBBINDING struct to provide functionality
  40. // to initialize the struct from a DBCOLUMNINFO struct.
  41. //
  42. ///////////////////////////////////////////////////////////////////////////////
  43. struct DBBinding : DBBINDING
  44. {
  45. //////////
  46. // 'offset' is the offset in bytes of this column's data within the
  47. // row buffer.
  48. //////////
  49. void Initialize(DBCOLUMNINFO& columnInfo, DBBYTEOFFSET& offset)
  50. {
  51. iOrdinal = columnInfo.iOrdinal;
  52. obValue = offset;
  53. obLength = offset + columnInfo.ulColumnSize;
  54. obStatus = obLength + sizeof(DBLENGTH);
  55. pTypeInfo = NULL;
  56. pObject = NULL;
  57. pBindExt = NULL;
  58. dwPart = DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS;
  59. eParamIO = DBPARAMIO_NOTPARAM;
  60. dwMemOwner = (columnInfo.wType & DBTYPE_BYREF) ? DBMEMOWNER_PROVIDEROWNED
  61. : DBMEMOWNER_CLIENTOWNED;
  62. cbMaxLen = columnInfo.ulColumnSize;
  63. dwFlags = 0;
  64. wType = columnInfo.wType;
  65. bPrecision = columnInfo.bPrecision;
  66. bScale = columnInfo.bScale;
  67. offset = obStatus + sizeof(DBSTATUS);
  68. }
  69. };
  70. ///////////////////////////////////////////////////////////////////////////////
  71. //
  72. // METHOD
  73. //
  74. // CSimpleTable::CSimpleTable
  75. //
  76. // DESCRIPTION
  77. //
  78. // Constructor.
  79. //
  80. ///////////////////////////////////////////////////////////////////////////////
  81. CSimpleTable::CSimpleTable()
  82. : numColumns(0),
  83. columnInfo(NULL),
  84. stringsBuffer(NULL),
  85. columnBinding(NULL),
  86. readAccess(NULL),
  87. buffer(NULL),
  88. numRows(0),
  89. currentRow(0),
  90. endOfRowset(false)
  91. {
  92. }
  93. ///////////////////////////////////////////////////////////////////////////////
  94. //
  95. // METHOD
  96. //
  97. // CSimpleTable::~CSimpleTable
  98. //
  99. // DESCRIPTION
  100. //
  101. // Destructor.
  102. //
  103. ///////////////////////////////////////////////////////////////////////////////
  104. CSimpleTable::~CSimpleTable()
  105. {
  106. Detach();
  107. }
  108. ///////////////////////////////////////////////////////////////////////////////
  109. //
  110. // METHOD
  111. //
  112. // CSimpleTable::Attach
  113. //
  114. // DESCRIPTION
  115. //
  116. // This method binds the table object to a new rowset. The previous rowset
  117. // (if any) will be detached.
  118. //
  119. ///////////////////////////////////////////////////////////////////////////////
  120. HRESULT CSimpleTable::Attach(IRowset* pRowset)
  121. {
  122. // Make sure we didn't get a null pointer.
  123. if (!pRowset) { return E_POINTER; }
  124. // Detach the current rowset.
  125. Detach();
  126. // We don't care if this returns an error. It will just prevent
  127. // the user from updating.
  128. pRowset->QueryInterface(IID_IRowsetChange, (void**)&rowsetChange);
  129. //////////
  130. // Get the column information for the table.
  131. //////////
  132. CComPtr<IColumnsInfo> ColumnsInfo;
  133. RETURN_ERROR(pRowset->QueryInterface(IID_IColumnsInfo,
  134. (void**)&ColumnsInfo));
  135. RETURN_ERROR(ColumnsInfo->GetColumnInfo(&numColumns,
  136. &columnInfo,
  137. &stringsBuffer));
  138. //////////
  139. // Allocate the per-column data.
  140. //////////
  141. try
  142. {
  143. columnBinding = new DBBinding[numColumns];
  144. dirty.resize(numColumns);
  145. }
  146. catch (std::bad_alloc)
  147. {
  148. return E_OUTOFMEMORY;
  149. }
  150. //////////
  151. // Create a binding for each column.
  152. //////////
  153. bufferLength = 0;
  154. for (DBORDINAL i = 0; i < numColumns; ++i)
  155. {
  156. // Compute the width of the column.
  157. DBLENGTH width = columnInfo[i].ulColumnSize;
  158. // Add room for the null terminator.
  159. if (columnInfo[i].wType == DBTYPE_STR)
  160. {
  161. width += 1;
  162. }
  163. else if (columnInfo[i].wType == DBTYPE_WSTR)
  164. {
  165. width = (width + 1) * sizeof(WCHAR);
  166. }
  167. // ulColumnSize is 1 giga byte for columns of type "Memo"
  168. // such as ias.mdb -> Properties.StrVal
  169. // Set the buffer to the maximum size the datastore allows
  170. if (width > PROPERTY_VALUE_LENGTH)
  171. {
  172. width = PROPERTY_VALUE_LENGTH;
  173. }
  174. // Round to an 8-byte boundary (could peek ahead and be more efficient).
  175. width = (width + 7) >> 3 << 3;
  176. columnInfo[i].ulColumnSize = width;
  177. // We're using the pTypeInfo element to store the offset to our data.
  178. // We have to store the offset now, since it will be overwritten by
  179. // DBBinding::Initialize.
  180. columnInfo[i].pTypeInfo = (ITypeInfo*)bufferLength;
  181. columnBinding[i].Initialize(columnInfo[i], bufferLength);
  182. }
  183. //////////
  184. // Allocate a buffer for the row data.
  185. //////////
  186. buffer = new (std::nothrow) BYTE[bufferLength];
  187. if (!buffer) { return E_OUTOFMEMORY; }
  188. //////////
  189. // Create an accessor.
  190. //////////
  191. RETURN_ERROR(pRowset->QueryInterface(IID_IAccessor,
  192. (void**)&accessor));
  193. RETURN_ERROR(accessor->CreateAccessor(DBACCESSOR_ROWDATA,
  194. numColumns,
  195. columnBinding,
  196. bufferLength,
  197. &readAccess,
  198. NULL));
  199. // I used this hokey method of assigning the pointer to avoid a
  200. // dependency on atlimpl.cpp
  201. //
  202. // We do this assignment last, so that the presence of a rowset means the
  203. // entire initialization succeeded.
  204. (rowset.p = pRowset)->AddRef();
  205. endOfRowset = false;
  206. return S_OK;
  207. }
  208. ///////////////////////////////////////////////////////////////////////////////
  209. //
  210. // METHOD
  211. //
  212. // CSimpleTable::Detach
  213. //
  214. // DESCRIPTION
  215. //
  216. // Frees all the resources associated with the current rowset.
  217. //
  218. ///////////////////////////////////////////////////////////////////////////////
  219. IRowset* CSimpleTable::Detach()
  220. {
  221. ReleaseRows();
  222. delete[] buffer;
  223. buffer = NULL;
  224. delete[] columnBinding;
  225. columnBinding = NULL;
  226. CoTaskMemFree(columnInfo);
  227. columnInfo = NULL;
  228. CoTaskMemFree(stringsBuffer);
  229. stringsBuffer = NULL;
  230. accessor.Release();
  231. rowsetChange.Release();
  232. IRowset* temp = rowset;
  233. rowset.Release();
  234. return temp;
  235. }
  236. ///////////////////////////////////////////////////////////////////////////////
  237. //
  238. // METHOD
  239. //
  240. // CSimpleTable::MoveFirst
  241. //
  242. // DESCRIPTION
  243. //
  244. // Positions the cursor over the first row in the rowset.
  245. //
  246. ///////////////////////////////////////////////////////////////////////////////
  247. HRESULT CSimpleTable::MoveFirst()
  248. {
  249. if (rowset == NULL) return E_FAIL;
  250. ReleaseRows();
  251. RETURN_ERROR(rowset->RestartPosition(NULL));
  252. endOfRowset = false;
  253. return MoveNext();
  254. }
  255. ///////////////////////////////////////////////////////////////////////////////
  256. //
  257. // METHOD
  258. //
  259. // CSimpleTable::MoveNext
  260. //
  261. // DESCRIPTION
  262. //
  263. // Positions the cursor over the next row in the rowset.
  264. //
  265. ///////////////////////////////////////////////////////////////////////////////
  266. HRESULT CSimpleTable::MoveNext()
  267. {
  268. // If the data wasn't opened successfully then fail
  269. if (rowset == NULL) return E_FAIL;
  270. // Too late to save any changes.
  271. DiscardChanges();
  272. // If we've used all the rows from the last fetch, then get some more.
  273. if (++currentRow >= numRows)
  274. {
  275. ReleaseRows();
  276. // We have to do this check here, since some providers automatically
  277. // reset to the beginning of the rowset.
  278. if (endOfRowset) { return DB_S_ENDOFROWSET; }
  279. HROW* pRow = row;
  280. HRESULT hr = rowset->GetNextRows(NULL,
  281. 0,
  282. FETCH_QUANTUM,
  283. &numRows,
  284. &pRow);
  285. if (hr == DB_S_ENDOFROWSET)
  286. {
  287. // Mark that we've reached the end of the rowset.
  288. endOfRowset = true;
  289. // If we didn't get any rows, then we're really at the end.
  290. if (numRows == 0) { return DB_S_ENDOFROWSET; }
  291. }
  292. else if (FAILED(hr))
  293. {
  294. return hr;
  295. }
  296. }
  297. // Load the data into the buffer.
  298. RETURN_ERROR(rowset->GetData(row[currentRow], readAccess, buffer));
  299. return S_OK;
  300. }
  301. ///////////////////////////////////////////////////////////////////////////////
  302. //
  303. // METHOD
  304. //
  305. // CSimpleTable::Insert
  306. //
  307. // DESCRIPTION
  308. //
  309. // Inserts the contents of the accessor buffer into the rowset.
  310. //
  311. ///////////////////////////////////////////////////////////////////////////////
  312. HRESULT CSimpleTable::Insert()
  313. {
  314. // Is a rowset attached?
  315. if (!rowset) { return E_FAIL; }
  316. // Does this rowset support changes?
  317. if (!rowsetChange) { return E_NOINTERFACE; }
  318. // Get an accessor for the dirty columns.
  319. HACCESSOR writeAccess;
  320. RETURN_ERROR(CreateAccessorForWrite(&writeAccess));
  321. // Release the existing rows to make room for the new one.
  322. ReleaseRows();
  323. HRESULT hr = rowsetChange->InsertRow(NULL, writeAccess, buffer, row);
  324. if (SUCCEEDED(hr))
  325. {
  326. // The changes were save successfully, so reset the dirty vector.
  327. DiscardChanges();
  328. // We now have exactly one row in our buffer.
  329. numRows = 1;
  330. }
  331. // Release the accessor.
  332. accessor->ReleaseAccessor(writeAccess, NULL);
  333. return hr;
  334. }
  335. ///////////////////////////////////////////////////////////////////////////////
  336. //
  337. // METHOD
  338. //
  339. // CSimpleTable::Delete
  340. //
  341. // DESCRIPTION
  342. //
  343. // Deletes the current row from the rowset.
  344. //
  345. ///////////////////////////////////////////////////////////////////////////////
  346. HRESULT CSimpleTable::Delete()
  347. {
  348. // Are we positioned over a valid row?
  349. if (!rowset || currentRow >= numRows) { return E_FAIL; }
  350. // Does this rowset support changes?
  351. if (!rowsetChange) { return E_NOINTERFACE; }
  352. DBROWSTATUS rowStatus[1];
  353. return rowsetChange->DeleteRows(NULL, 1, row + currentRow, rowStatus);
  354. }
  355. ///////////////////////////////////////////////////////////////////////////////
  356. //
  357. // METHOD
  358. //
  359. // CSimpleTable::SetData
  360. //
  361. // DESCRIPTION
  362. //
  363. // Updates the current row with the data in the accessor buffer.
  364. //
  365. ///////////////////////////////////////////////////////////////////////////////
  366. HRESULT CSimpleTable::SetData()
  367. {
  368. // Are we positioned over a valid row?
  369. if (!rowset || currentRow >= numRows) { return E_FAIL; }
  370. // Does this rowset support changes?
  371. if (!rowsetChange) { return E_NOINTERFACE; }
  372. // Get an accessor for the dirty columns.
  373. HACCESSOR writeAccess;
  374. RETURN_ERROR(CreateAccessorForWrite(&writeAccess));
  375. HRESULT hr = rowsetChange->SetData(row[currentRow], writeAccess, buffer);
  376. if (SUCCEEDED(hr))
  377. {
  378. // The changes were save successfully, so reset the dirty vector.
  379. DiscardChanges();
  380. }
  381. // Release the accessor.
  382. accessor->ReleaseAccessor(writeAccess, NULL);
  383. return hr;
  384. }
  385. ///////////////////////////////////////////////////////////////////////////////
  386. //
  387. // METHOD
  388. //
  389. // CSimpleTable::GetLength
  390. //
  391. // DESCRIPTION
  392. //
  393. // Returns the length of the current value for a given column.
  394. //
  395. ///////////////////////////////////////////////////////////////////////////////
  396. DBLENGTH CSimpleTable::GetLength(DBORDINAL nOrdinal) const
  397. {
  398. return *(DBLENGTH*)((BYTE*)_GetDataPtr(nOrdinal) +
  399. columnInfo[OrdinalToColumn(nOrdinal)].ulColumnSize);
  400. }
  401. ///////////////////////////////////////////////////////////////////////////////
  402. //
  403. // METHOD
  404. //
  405. // CSimpleTable::GetOrdinal
  406. //
  407. // DESCRIPTION
  408. //
  409. // Returns the ordinal for a given column name.
  410. //
  411. ///////////////////////////////////////////////////////////////////////////////
  412. bool CSimpleTable::GetOrdinal(LPCWSTR szColumnName, DBORDINAL* pOrdinal) const
  413. {
  414. for (DBORDINAL i = 0; i < numColumns; ++i)
  415. {
  416. if (lstrcmpW(columnInfo[i].pwszName, szColumnName) == 0)
  417. {
  418. *pOrdinal = columnInfo[i].iOrdinal;
  419. return true;
  420. }
  421. }
  422. return false;
  423. }
  424. ///////////////////////////////////////////////////////////////////////////////
  425. //
  426. // METHOD
  427. //
  428. // CSimpleTable::GetStatus
  429. //
  430. // DESCRIPTION
  431. //
  432. // Returns the status code associated with the current value of a column.
  433. //
  434. ///////////////////////////////////////////////////////////////////////////////
  435. DBSTATUS CSimpleTable::GetStatus(DBORDINAL nOrdinal) const
  436. {
  437. return *(DBSTATUS*)((BYTE*)_GetDataPtr(nOrdinal) +
  438. columnInfo[OrdinalToColumn(nOrdinal)].ulColumnSize +
  439. sizeof(DBLENGTH));
  440. }
  441. ///////////////////////////////////////////////////////////////////////////////
  442. //
  443. // METHOD
  444. //
  445. // CSimpleTable::CreateAccessorForWrite
  446. //
  447. // DESCRIPTION
  448. //
  449. // Creates an accessor that is only to bound to columns that have been
  450. // modified.
  451. //
  452. ///////////////////////////////////////////////////////////////////////////////
  453. HRESULT CSimpleTable::CreateAccessorForWrite(HACCESSOR* phAccessor)
  454. {
  455. //////////
  456. // Allocate temporary space for the bindings.
  457. //////////
  458. DBBINDING* writeBind = stack_new(DBBINDING, dirty.count());
  459. //////////
  460. // Load in all the dirty columns.
  461. //////////
  462. size_t total = 0;
  463. for (size_t i = 0; total < dirty.count(); ++i)
  464. {
  465. if (dirty.test(i))
  466. {
  467. // We only want to bind the value.
  468. (writeBind[total++] = columnBinding[i]).dwPart = DBPART_VALUE;
  469. }
  470. }
  471. //////////
  472. // Create the accessor.
  473. //////////
  474. return accessor->CreateAccessor(DBACCESSOR_ROWDATA,
  475. dirty.count(),
  476. writeBind,
  477. bufferLength,
  478. phAccessor,
  479. NULL);
  480. }
  481. ///////////////////////////////////////////////////////////////////////////////
  482. //
  483. // METHOD
  484. //
  485. // CSimpleTable::_GetDataPtr
  486. //
  487. // DESCRIPTION
  488. //
  489. // Non-const version of _GetDataPtr. Marks the target column as dirty.
  490. //
  491. ///////////////////////////////////////////////////////////////////////////////
  492. void* CSimpleTable::_GetDataPtr(DBORDINAL nOrdinal)
  493. {
  494. DBORDINAL nColumn = OrdinalToColumn(nOrdinal);
  495. dirty.set(nColumn);
  496. return buffer + (ULONG_PTR)columnInfo[nColumn].pTypeInfo;
  497. }
  498. ///////////////////////////////////////////////////////////////////////////////
  499. //
  500. // METHOD
  501. //
  502. // CSimpleTable::ReleaseRows
  503. //
  504. // DESCRIPTION
  505. //
  506. // Releases all the rows returned by the last fetch.
  507. //
  508. ///////////////////////////////////////////////////////////////////////////////
  509. HRESULT CSimpleTable::ReleaseRows()
  510. {
  511. if (rowset != NULL)
  512. {
  513. HRESULT hr = rowset->ReleaseRows(numRows, row, NULL, NULL, NULL);
  514. currentRow = numRows = 0;
  515. return hr;
  516. }
  517. return S_OK;
  518. }