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.

620 lines
16 KiB

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