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

2332 lines
81 KiB

  1. // Row.cxx : Implementation of CRow
  2. #include "oleds.hxx"
  3. #if (!defined(BUILD_FOR_NT40))
  4. #include "atl.h"
  5. #include "row.hxx"
  6. #include "cstream.h"
  7. HRESULT PackLargeInteger(LARGE_INTEGER *plargeint, PVARIANT pVarDestObject);
  8. #define ARRAYSIZE(x) sizeof((x))/sizeof((x)[0])
  9. extern const WCHAR g_cwszSpecialColumnURL[] = L"RESOURCE_ABSOLUTE_PARSENAME";
  10. extern const WCHAR g_cwszAdsPath[] = L"ADsPath";
  11. //----------------------------------------------------------------------------
  12. // Note on m_fIsTearOff and m_fGetColInfoFromRowset
  13. //
  14. // m_fIsTearOff is set to TRUE when the row is a tear-off from a rowset from
  15. // the client's point of view i.e, the client created a rowset and got a row
  16. // off the rowset. Thus, a call to GetSourceRowset returns a rowset interface
  17. // pointer only if m_fIsTearOff is TRUE.
  18. // m_fGetColInfoFromRowset is set to TRUE if the row should get the column
  19. // info and the column values from the rowset. If FALSE, this information is
  20. // obtained through ADSI calls.
  21. //
  22. // There are 4 cases of interest.
  23. //
  24. // 1) The row is obtained directly from a command object using a query which
  25. // doesn't specify "SELECT *" i.e, not all attributes are requested OR the row
  26. // is obtained directly from a session object (defaults to no "SELECT *"). This
  27. // is implemented by actually creating a rowset and getting its first row.
  28. // In this case m_fIsTearOff is FALSE, m_fGetColInfoFromRowset is
  29. // TRUE and m_pSourceRowset is non-NULL. Thus, if the client called
  30. // GetSourceRowset on the row, no interface pointer is returned. However, there
  31. // is a rowset backing up this row and this is used for getting column info and
  32. // column values.
  33. //
  34. // 2) The row is obtained directly from a command object using SELECT *
  35. // as the query. In this case, m_fIsTearOff is FALSE, m_fGetColInfoFromRowset
  36. // is FALSE and m_pSourceRowset is non-NULL. Though m_pSourceRowset is
  37. // non-NULL, it is not used.
  38. //
  39. // An alternative scheme would be to to call CSession::Bind directly in this
  40. // case which would obviate the need for keeping a rowset around.
  41. //
  42. // 3) The row is obtained from a rowset using GetRowFromHROW. In this case,
  43. // m_fIsTearOff is TRUE. However, if the rowset was created from a command
  44. // object using a SELECT * query, then m_fGetColInfoFromRowset is FALSE.
  45. // Otherwise, fGetColInfoFromRowset is TRUE. m_pSourceRowset is non-NULL.
  46. //
  47. // 4) The row is created using IBindResource::Bind. In this case, m_fIsTearOff
  48. // is FALSE, m_fGetColInfoFromRowset is FALSE and m_pSourceRowset is NULL.
  49. //
  50. // The following table summarizes the above 4 cases.
  51. //
  52. // m_fIsTearOff m_fGetColInfoFromRowset Description
  53. // ------------ ----------------------- ------------
  54. // T T GetRowFromHROW, not SELECT *
  55. // F F Row obtained from command object
  56. // using SELECT * OR
  57. // Row got using IBindResource::Bind
  58. // T F GetRowFromHROW, SELECT *
  59. // F T Row obtained from command object
  60. // without a SELECT * query OR
  61. // Row obtained from session object
  62. //
  63. // Every row object has a special URL column. The URL column (and any row
  64. // columns that are not in the source rowset) should appear after all the
  65. // source rowset columns.
  66. //
  67. // ADsPath needs to be treated as a special case. If m_fGetColInfoFromRowset
  68. // is TRUE, then we will get the ADsPath just by using the rowset's copy
  69. // of the column. However, if m_fGetColInfoFromRowset is FALSE, then
  70. // the row should return ADsPath if it is a tear-off AND ADsPath is one of the
  71. // columns of the source rowset. This is required by the OLEDB spec
  72. // since the row's columns should be a superset of the rowset's columns.
  73. // Currently, the only case where this would happen is a SELECT * query that
  74. // requests a rowset and then a row is obtained from that rowset. In this case,
  75. // the row adds ADsPath to the columns it returns. To be consistent, if a row
  76. // is obtained from a command object using a SELECT * query OR the row is
  77. // obtained using IBindResource::Bind(), then ADsPath is added to the columns
  78. // returned by the row.
  79. //
  80. //----------------------------------------------------------------------------
  81. //
  82. //////////////////////////////////////////////////////////////////////////////
  83. //helper functions
  84. //
  85. //+---------------------------------------------------------------------------
  86. //
  87. // Function: GetIDataConvert
  88. //
  89. // Synopsis: Create OLE DB conversion library and store it in static.
  90. //
  91. // Arguments:
  92. // [out] pointer to pointer to IDataConvert
  93. //
  94. // Returns: HRESULT
  95. //----------------------------------------------------------------------------
  96. HRESULT GetIDataConvert(IDataConvert** ppDataConvert)
  97. {
  98. HRESULT hr = S_OK;
  99. auto_rel<IDataConvert> pIDataConvert;
  100. auto_rel<IDCInfo> pIDCInfo;
  101. DCINFO rgInfo[] = {{DCINFOTYPE_VERSION, {VT_UI4, 0, 0, 0, 0x0200}}};
  102. ADsAssert(ppDataConvert);
  103. hr = CoCreateInstance(CLSID_OLEDB_CONVERSIONLIBRARY,
  104. NULL,
  105. CLSCTX_INPROC_SERVER,
  106. IID_IDataConvert,
  107. (void **) &pIDataConvert);
  108. if (FAILED(hr))
  109. goto exit;
  110. // Tell data convert our OLE DB version
  111. hr = pIDataConvert->QueryInterface(IID_IDCInfo,
  112. (void **)&pIDCInfo);
  113. if( SUCCEEDED(hr) )
  114. hr = pIDCInfo->SetInfo(ARRAYSIZE(rgInfo), rgInfo);
  115. // auto_rel operator = does the release
  116. if( FAILED(hr) )
  117. pIDataConvert = NULL;
  118. if (pIDataConvert)
  119. pIDataConvert->AddRef();
  120. *ppDataConvert = pIDataConvert;
  121. exit:
  122. RRETURN(hr);
  123. }
  124. /////////////////////////////////////////////////////////////////////////////
  125. //Internal methods
  126. //
  127. //+---------------------------------------------------------------------------
  128. //
  129. // Function: CRow::Initialize
  130. //
  131. // Synopsis: Initializes a directly bound CRow object as opposed to a row
  132. // created from a rowset. See the other overloaded Initialize below.
  133. //
  134. // Returns: HRESULT
  135. //----------------------------------------------------------------------------
  136. STDMETHODIMP CRow::Initialize(PWSTR pwszURL,
  137. IUnknown *pSession,
  138. IAuthenticate *pAuthenticate,
  139. DWORD dwBindFlags,
  140. BOOL fIsTearOff,
  141. BOOL fGetColInfoFromRowset,
  142. CCredentials *pSessCreds,
  143. bool fBind)
  144. {
  145. HRESULT hr = S_OK;
  146. auto_leave cs_auto_leave(m_autocs);
  147. DWORD fAuthFlags;
  148. //Make sure we have a valid session.
  149. ADsAssert(pSession);
  150. TRYBLOCK
  151. cs_auto_leave.EnterCriticalSection();
  152. m_dwBindFlags = dwBindFlags;
  153. m_objURL = pwszURL;
  154. m_pSession = pSession;
  155. m_pSession->AddRef();
  156. if (!fBind) //no need to bind. Just return.
  157. RRETURN(S_OK);
  158. m_fIsTearOff = fIsTearOff;
  159. m_fGetColInfoFromRowset = fGetColInfoFromRowset;
  160. // Any changes made below should also be made in the overloaded
  161. // Initialize() below for consistency.
  162. // Fix for 351040. Use explicit credentials first, then credentials in
  163. // session object, then default credentials. Credential in session
  164. // object will be the default credentials if we come in through the
  165. // binder. But, if IBindResource is obtained from the session object,
  166. // then the credentials may not be the default credentials. From ADO,
  167. // using Open without specifying an active connection causes the
  168. // binder to be invoked. If an active connection is specified, then
  169. // IBindResource is obtained from the session object.
  170. if(pAuthenticate)
  171. {
  172. hr = GetCredentialsFromIAuthenticate(pAuthenticate,
  173. m_objCredentials);
  174. if(FAILED(hr))
  175. BAIL_ON_FAILURE(E_INVALIDARG);
  176. fAuthFlags = m_objCredentials.GetAuthFlags();
  177. m_objCredentials.SetAuthFlags(fAuthFlags |
  178. ADS_SECURE_AUTHENTICATION);
  179. hr = GetDSInterface(
  180. pwszURL,
  181. m_objCredentials,
  182. IID_IADs,
  183. (void **)&m_pADsObj
  184. );
  185. }
  186. if( (!pAuthenticate) || (INVALID_CREDENTIALS_ERROR(hr)) )
  187. // try credentials in session object
  188. {
  189. m_objCredentials = *pSessCreds;
  190. hr = GetDSInterface(
  191. pwszURL,
  192. m_objCredentials,
  193. IID_IADs,
  194. (void **)&m_pADsObj
  195. );
  196. }
  197. if(INVALID_CREDENTIALS_ERROR(hr))
  198. // try default credentials
  199. {
  200. CCredentials TmpCreds; // default credentials
  201. m_objCredentials = TmpCreds;
  202. fAuthFlags = m_objCredentials.GetAuthFlags();
  203. m_objCredentials.SetAuthFlags(fAuthFlags |
  204. ADS_SECURE_AUTHENTICATION);
  205. hr = GetDSInterface(
  206. pwszURL,
  207. m_objCredentials,
  208. IID_IADs,
  209. (void **)&m_pADsObj
  210. );
  211. }
  212. BAIL_ON_FAILURE(hr);
  213. //Get the Schema Root and store it in m_bstrSchemaRoot
  214. hr = GetSchemaRoot();
  215. BAIL_ON_FAILURE(hr);
  216. // Get the data. without the GetRestrictedColunInfo will no return column information.
  217. hr = m_pADsObj->GetInfo();
  218. BAIL_ON_FAILURE(hr);
  219. CATCHBLOCKBAIL(hr)
  220. error:
  221. RRETURN(hr);
  222. }
  223. //+---------------------------------------------------------------------------
  224. //
  225. // Function: CRow::Initialize
  226. //
  227. // Synopsis: Initializes a row object that represents a row in a rowset as
  228. // as opposed to a directly bound row object.
  229. // See the other overloaded Initialize above.
  230. //
  231. // Returns: HRESULT
  232. //----------------------------------------------------------------------------
  233. STDMETHODIMP CRow::Initialize(
  234. PWSTR pwszURL,
  235. IUnknown *pSession,
  236. IUnknown *pSourceRowset,
  237. HROW hRow,
  238. PWSTR pwszUser,
  239. PWSTR pwszPassword,
  240. DWORD dwBindFlags,
  241. BOOL fIsTearOff,
  242. BOOL fGetColInfoFromRowset,
  243. CRowProvider *pRowProvider
  244. )
  245. {
  246. HRESULT hr = S_OK;
  247. auto_leave cs_auto_leave(m_autocs);
  248. DWORD fAuthFlags;
  249. auto_rel<IRowset> pRowset;
  250. auto_rel<IColumnsInfo> pRowsetColumnsInfo;
  251. //Make sure we have valid arguments
  252. ADsAssert(pSession);
  253. ADsAssert(pSourceRowset);
  254. ADsAssert(hRow != DB_NULL_HROW);
  255. TRYBLOCK
  256. cs_auto_leave.EnterCriticalSection();
  257. if (pRowProvider == NULL)
  258. BAIL_ON_FAILURE(hr = E_INVALIDARG);
  259. m_pRowProvider = pRowProvider;
  260. m_dwBindFlags = dwBindFlags;
  261. m_pSession = pSession;
  262. m_pSession->AddRef();
  263. m_pSourceRowset = pSourceRowset;
  264. m_hRow = hRow;
  265. m_fIsTearOff = fIsTearOff;
  266. m_fGetColInfoFromRowset = fGetColInfoFromRowset;
  267. pSourceRowset->AddRef();
  268. //Get IRowset pointer
  269. hr = pSourceRowset->QueryInterface(__uuidof(IRowset),
  270. (void **)&pRowset);
  271. BAIL_ON_FAILURE(hr);
  272. //Get Rowset columns info and store it. Spec says a row's columns
  273. //are always a superset of those of the source rowset. To make
  274. //sure we return proper columns info from row object,
  275. //we need the rowset's column info.
  276. hr = pSourceRowset->QueryInterface(
  277. __uuidof(IColumnsInfo),
  278. (void **)&pRowsetColumnsInfo);
  279. BAIL_ON_FAILURE(hr);
  280. hr = pRowsetColumnsInfo->GetColumnInfo(
  281. &m_cSourceRowsetColumns,
  282. &m_pSourceRowsetColumnInfo,
  283. &m_pSourceRowsetStringsBuffer);
  284. BAIL_ON_FAILURE(hr);
  285. //Get username, password and authFlags from Credentials.
  286. hr = m_objCredentials.SetUserName(pwszUser);
  287. BAIL_ON_FAILURE(hr);
  288. hr = m_objCredentials.SetPassword(pwszPassword);
  289. BAIL_ON_FAILURE(hr);
  290. //Store the URL and AddRef row handle.
  291. m_objURL = pwszURL;
  292. hr = pRowset->AddRefRows(1, &m_hRow, NULL, NULL);
  293. BAIL_ON_FAILURE(hr);
  294. //check if the column info is to be obtained thruogh ADSI
  295. if( !fGetColInfoFromRowset )
  296. {
  297. // code below should be consistent with the Initialize() call
  298. // (overloaded function above) used for direct binding
  299. DWORD fAuthFlags = m_objCredentials.GetAuthFlags();
  300. m_objCredentials.SetAuthFlags(fAuthFlags |
  301. ADS_SECURE_AUTHENTICATION);
  302. hr = GetDSInterface(
  303. pwszURL,
  304. m_objCredentials,
  305. IID_IADs,
  306. (void **)&m_pADsObj
  307. );
  308. BAIL_ON_FAILURE(hr);
  309. //Get the Schema Root and store it in m_bstrSchemaRoot
  310. hr = GetSchemaRoot();
  311. BAIL_ON_FAILURE(hr);
  312. // Get the data. without it GetRestrictedColunInfo will not return
  313. // column info.
  314. hr = m_pADsObj->GetInfo();
  315. BAIL_ON_FAILURE(hr);
  316. }
  317. CATCHBLOCKBAIL(hr)
  318. error:
  319. RRETURN(hr);
  320. }
  321. //+---------------------------------------------------------------------------
  322. //
  323. // Function: CRow::fMatchesMaskCriteria
  324. //
  325. // Synopsis: Tells if the given column name matches any mask criteria
  326. // for column ids.
  327. //
  328. // Returns: true if matches, false otherwise
  329. //----------------------------------------------------------------------------
  330. bool CRow::fMatchesMaskCriteria(PWCHAR pwszColumnName,
  331. ULONG cColumnIDMasks,
  332. const DBID rgColumnIDMasks[ ])
  333. {
  334. //if there are no masks, the name is a match.
  335. if (cColumnIDMasks == 0)
  336. return true;
  337. ULONG ulStrLen = 0;
  338. for (int j = 0; j < cColumnIDMasks; j++)
  339. {
  340. if( (rgColumnIDMasks[j].eKind != DBKIND_NAME) ||
  341. (NULL == rgColumnIDMasks[j].uName.pwszName) )
  342. continue;
  343. ulStrLen = wcslen(rgColumnIDMasks[j].uName.pwszName);
  344. if (_wcsnicmp( rgColumnIDMasks[j].uName.pwszName,
  345. pwszColumnName,
  346. ulStrLen ) == 0)
  347. {
  348. // Matches criterion
  349. return true;
  350. }
  351. }
  352. //doesn't match.
  353. return false;
  354. }
  355. //+---------------------------------------------------------------------------
  356. //
  357. // Function: CRow::fMatchesMaskCriteria (OVERLOADED)
  358. //
  359. // Synopsis: Tells if the given column id matches any mask criteria
  360. // for column ids.
  361. //
  362. // Returns: true if matches, false otherwise
  363. //----------------------------------------------------------------------------
  364. bool CRow::fMatchesMaskCriteria(DBID columnid,
  365. ULONG cColumnIDMasks,
  366. const DBID rgColumnIDMasks[ ])
  367. {
  368. //if there are no masks, the name is a match.
  369. if (cColumnIDMasks == 0)
  370. return true;
  371. ULONG ulStrLen = 0;
  372. for (int j = 0; j < cColumnIDMasks; j++)
  373. {
  374. if (TRUE == CompareDBIDs(&columnid, &rgColumnIDMasks[j]))
  375. {
  376. // Matches criterion
  377. return true;
  378. }
  379. }
  380. //doesn't match.
  381. return false;
  382. }
  383. //+---------------------------------------------------------------------------
  384. //
  385. // Function: CRow::GetSchemaAttributes
  386. //
  387. // Synopsis: Gets MultiValued and MaxRange Attributes of an ADS Property.
  388. // Any of these can be NULL indicating the caller is not interested
  389. // in getting the attribute.
  390. //
  391. // Returns: HRESULT
  392. //----------------------------------------------------------------------------
  393. HRESULT CRow::GetSchemaAttributes(
  394. PWCHAR pwszColumnName,
  395. VARIANT_BOOL *pfMultiValued,
  396. long *plMaxRange
  397. )
  398. {
  399. HRESULT hr = S_OK;
  400. auto_rel<IADsProperty> pProperty;
  401. CComBSTR bstrSchemaName;
  402. ADsAssert(m_bstrSchemaRoot.Length());
  403. ADsAssert(pwszColumnName != NULL);
  404. //Does the caller want at least one attribute?
  405. if (!pfMultiValued && !plMaxRange)
  406. return S_OK;
  407. //Append a '/' and property name to root schema name
  408. //to make the Schema ADsPath for this property.
  409. bstrSchemaName = m_bstrSchemaRoot;
  410. bstrSchemaName.Append(L"/");
  411. bstrSchemaName.Append(pwszColumnName);
  412. //Bind to the schema entry and get IADsProperty interface.
  413. hr = GetDSInterface(
  414. bstrSchemaName,
  415. m_objCredentials,
  416. __uuidof(IADsProperty),
  417. (void **)&pProperty
  418. );
  419. BAIL_ON_FAILURE(hr);
  420. if (pfMultiValued != NULL)
  421. {
  422. //Get multivalued attribute.
  423. hr = pProperty->get_MultiValued(pfMultiValued);
  424. BAIL_ON_FAILURE(hr);
  425. }
  426. // The following call get_MaxRange seems to create perf problems
  427. // because it apparently requires a round-trip to the server.
  428. // This is not critical and we cn live without asking
  429. // for max range here.
  430. //if (plMaxRange != NULL)
  431. //{
  432. // //Get MaxSize attribute. Ignore error
  433. // //since some properties may not have
  434. // //this attribute set.
  435. // pProperty->get_MaxRange(plMaxRange);
  436. //}
  437. error:
  438. RRETURN(hr);
  439. }
  440. //+---------------------------------------------------------------------------
  441. //
  442. // Function: CRow::GetTypeAndSize
  443. //
  444. // Synopsis: Gets the type and size of a property
  445. //
  446. // Returns: HRESULT
  447. //----------------------------------------------------------------------------
  448. HRESULT CRow::GetTypeAndSize(
  449. ADSTYPE dwADsType,
  450. CComBSTR& bstrPropName,
  451. DBTYPE *pdbType,
  452. ULONG *pulSize
  453. )
  454. {
  455. ADsAssert(pdbType != NULL);
  456. ADsAssert(pulSize != NULL);
  457. long lAdsType = dwADsType;
  458. VARIANT_BOOL fMultiValued = VARIANT_FALSE;
  459. HRESULT hr = S_OK;
  460. //Initialize out params
  461. *pdbType = DBTYPE_ERROR;
  462. *pulSize = ~0;
  463. hr = GetSchemaAttributes(bstrPropName, &fMultiValued, (long *)pulSize);
  464. BAIL_ON_FAILURE(hr);
  465. //Give our best shot at determining type and size.
  466. if (fMultiValued == VARIANT_TRUE)
  467. *pdbType = DBTYPE_BYREF | DBTYPE_VARIANT;
  468. else if (lAdsType < g_cMapADsTypeToDBType2)
  469. *pdbType = g_MapADsTypeToDBType2[lAdsType].wType;
  470. else
  471. *pdbType = DBTYPE_ERROR;
  472. // If we could not determine the size from schema information,
  473. // set the size from the mapping table.
  474. if (*pulSize == ~0)
  475. *pulSize = g_MapADsTypeToDBType2[lAdsType].ulSize;
  476. error:
  477. RRETURN (hr);
  478. }
  479. //+---------------------------------------------------------------------------
  480. //
  481. // Function: CRow::GetSchemaRoot
  482. //
  483. // Synopsis: Gets the root schema path and stores it in m_bstrSchemaRoot
  484. //
  485. // Returns: HRESULT
  486. //----------------------------------------------------------------------------
  487. HRESULT CRow::GetSchemaRoot()
  488. {
  489. HRESULT hr = S_OK;
  490. CComBSTR bstrSchema;
  491. auto_rel<IADs> pADsSchema;
  492. Assert(m_pADsObj.get());
  493. hr = m_pADsObj->get_Schema(&bstrSchema);
  494. BAIL_ON_FAILURE(hr);
  495. hr = GetDSInterface(
  496. bstrSchema,
  497. m_objCredentials,
  498. __uuidof(IADs),
  499. (void **)&pADsSchema
  500. );
  501. BAIL_ON_FAILURE(hr);
  502. hr = pADsSchema->get_Parent(&m_bstrSchemaRoot);
  503. BAIL_ON_FAILURE(hr);
  504. error:
  505. RRETURN(hr);
  506. }
  507. //+---------------------------------------------------------------------------
  508. //
  509. // Function: CRow::GetSourceRowsetColumns
  510. //
  511. // Synopsis: Gets the requested column data from the source rowset.
  512. //
  513. // Returns: HRESULT
  514. //----------------------------------------------------------------------------
  515. HRESULT CRow::GetSourceRowsetColumns(
  516. ULONG cColumns,
  517. DBCOLUMNACCESS rgColumns[],
  518. ULONG *pcErrors )
  519. {
  520. // Make sure there is a rowset backing this row (this doesn't imply that
  521. // the row is a tear-off (see comment at the beginning).
  522. ADsAssert(m_pSourceRowset.get() != NULL);
  523. ADsAssert(m_pRowProvider != NULL);
  524. ADsAssert(m_fGetColInfoFromRowset == TRUE);
  525. HRESULT hr = S_OK;
  526. auto_rel<IAccessor> pAccessor;
  527. auto_rel<IRowset> pRowset;
  528. auto_rel<IColumnsInfo> pColumnsInfo;
  529. HACCESSOR hAccessor;
  530. ULONG iCol;
  531. ULONG ulRefCount = 0;
  532. DBBINDING binding = {0};
  533. DBBINDSTATUS bindStatus = {0};
  534. int iRowsetIndex;
  535. DBID dbidRowUrl = DBROWCOL_ROWURL;
  536. ADsAssert(pcErrors != NULL);
  537. *pcErrors = 0;
  538. hr = m_pSourceRowset->QueryInterface(&pRowset);
  539. BAIL_ON_FAILURE(hr);
  540. hr = m_pSourceRowset->QueryInterface(&pAccessor);
  541. BAIL_ON_FAILURE(hr);
  542. hr = m_pSourceRowset->QueryInterface(&pColumnsInfo);
  543. BAIL_ON_FAILURE(hr);
  544. for (iCol = 0; iCol < cColumns; iCol++)
  545. {
  546. rgColumns[iCol].dwStatus = DBSTATUS_S_OK;
  547. if( (rgColumns[iCol].pData != NULL) &&
  548. (!IgnorecbMaxLen(rgColumns[iCol].wType)) )
  549. ZeroMemory(rgColumns[iCol].pData, rgColumns[iCol].cbMaxLen);
  550. //Is this the special URL column.
  551. if(TRUE == CompareDBIDs(&dbidRowUrl, &rgColumns[iCol].columnid))
  552. {
  553. CComVariant varTemp;
  554. varTemp.Clear();
  555. varTemp = m_objURL;
  556. //Set max length of column. 256 is consistent with 2.0 code.
  557. rgColumns[iCol].cbDataLen = 256;
  558. rgColumns[iCol].dwStatus = DBSTATUS_S_OK;
  559. //Does the caller want pData?
  560. if (rgColumns[iCol].pData != NULL)
  561. {
  562. //Get IDataConvert interface pointer.
  563. auto_rel<IDataConvert> pDataConvert;
  564. hr = GetIDataConvert(&pDataConvert);
  565. if(SUCCEEDED(hr))
  566. hr = pDataConvert->DataConvert(
  567. DBTYPE_VARIANT,
  568. rgColumns[iCol].wType,
  569. sizeof(VARIANT),
  570. &rgColumns[iCol].cbDataLen,
  571. &varTemp,
  572. rgColumns[iCol].pData,
  573. rgColumns[iCol].cbMaxLen,
  574. DBSTATUS_S_OK,
  575. &rgColumns[iCol].dwStatus,
  576. rgColumns[iCol].bPrecision,
  577. rgColumns[iCol].bScale,
  578. DBDATACONVERT_DEFAULT
  579. );
  580. if(FAILED(hr))
  581. {
  582. hr = S_OK;
  583. // rgColumns[iCol].dwStatus already set above by
  584. // DataConvert().
  585. (*pcErrors)++;
  586. continue;
  587. }
  588. }
  589. continue; // on to next column
  590. }
  591. //Is this the bookmark column?
  592. if (rgColumns[iCol].columnid.eKind == DBKIND_GUID_PROPID &&
  593. rgColumns[iCol].columnid.uGuid.guid == DBCOL_SPECIALCOL &&
  594. rgColumns[iCol].columnid.uName.ulPropid == 2 )
  595. {
  596. iRowsetIndex = 0; // bookmark is first column
  597. }
  598. else
  599. {
  600. // Is column id of DBKIND_NAME?
  601. if (rgColumns[iCol].columnid.eKind != DBKIND_NAME)
  602. {
  603. rgColumns[iCol].dwStatus = DBSTATUS_E_DOESNOTEXIST;
  604. (*pcErrors)++;
  605. continue;
  606. }
  607. iRowsetIndex = 0;
  608. hr = m_pRowProvider->GetIndex(
  609. pColumnsInfo,
  610. rgColumns[iCol].columnid.uName.pwszName,
  611. iRowsetIndex
  612. );
  613. if (FAILED(hr) || 0 == iRowsetIndex) // failure or name not found
  614. {
  615. hr = S_OK;
  616. if(FAILED(hr))
  617. rgColumns[iCol].dwStatus = DBSTATUS_E_UNAVAILABLE;
  618. else
  619. rgColumns[iCol].dwStatus = DBSTATUS_E_DOESNOTEXIST;
  620. (*pcErrors)++;
  621. continue;
  622. }
  623. } // else
  624. binding.dwPart = DBPART_VALUE;
  625. binding.obLength = 0;
  626. binding.bPrecision = rgColumns[iCol].bPrecision;
  627. binding.bScale = rgColumns[iCol].bScale;
  628. binding.pTypeInfo = 0;
  629. binding.pObject = NULL;
  630. binding.iOrdinal = iRowsetIndex;
  631. binding.cbMaxLen = rgColumns[iCol].cbMaxLen;
  632. binding.dwMemOwner = DBMEMOWNER_CLIENTOWNED;
  633. binding.wType = rgColumns[iCol].wType;
  634. hr = pAccessor->CreateAccessor(
  635. DBACCESSOR_ROWDATA,
  636. 1,
  637. &binding,
  638. 0,
  639. &hAccessor,
  640. &bindStatus
  641. );
  642. if (FAILED(hr))
  643. {
  644. rgColumns[iCol].dwStatus = DBSTATUS_E_CANTCONVERTVALUE;
  645. (*pcErrors)++;
  646. hr = S_OK;
  647. continue;
  648. }
  649. if(rgColumns[iCol].pData != NULL)
  650. {
  651. hr = pRowset->GetData(m_hRow, hAccessor, rgColumns[iCol].pData);
  652. if (FAILED(hr))
  653. {
  654. rgColumns[iCol].dwStatus = StatusFromHRESULT(hr);
  655. (*pcErrors)++;
  656. hr = S_OK;
  657. pAccessor->ReleaseAccessor(hAccessor, &ulRefCount);
  658. continue;
  659. }
  660. }
  661. hr = pAccessor->ReleaseAccessor(hAccessor, &ulRefCount);
  662. // now get the status and length
  663. binding.dwPart = DBPART_LENGTH | DBPART_STATUS;
  664. binding.obStatus = FIELD_OFFSET(DBCOLUMNACCESS, dwStatus);
  665. binding.obLength = FIELD_OFFSET(DBCOLUMNACCESS, cbDataLen);
  666. hr = pAccessor->CreateAccessor(
  667. DBACCESSOR_ROWDATA,
  668. 1,
  669. &binding,
  670. 0,
  671. &hAccessor,
  672. &bindStatus
  673. );
  674. if (FAILED(hr))
  675. {
  676. rgColumns[iCol].dwStatus = DBSTATUS_E_CANTCONVERTVALUE;
  677. (*pcErrors)++;
  678. hr = S_OK;
  679. continue;
  680. }
  681. hr = pRowset->GetData(m_hRow, hAccessor, &(rgColumns[iCol]));
  682. if (FAILED(hr))
  683. {
  684. rgColumns[iCol].dwStatus = StatusFromHRESULT(hr);
  685. (*pcErrors)++;
  686. }
  687. hr = pAccessor->ReleaseAccessor(hAccessor, &ulRefCount);
  688. // We have set the dwStatus to reflect any problems, so clear error.
  689. hr = S_OK;
  690. }
  691. error:
  692. if (FAILED(hr))
  693. {
  694. for (iCol = 0; iCol < cColumns; iCol++)
  695. rgColumns[iCol].dwStatus = DBSTATUS_E_UNAVAILABLE;
  696. *pcErrors = cColumns;
  697. }
  698. RRETURN (hr);
  699. }
  700. //+---------------------------------------------------------------------------
  701. //
  702. // Function: CRow::StatusFromHRESULT
  703. //
  704. // Synopsis: Gets DBSTATUS from a given HRESULT.
  705. //
  706. // Returns: DBSTATUS
  707. //----------------------------------------------------------------------------
  708. DBSTATUS CRow::StatusFromHRESULT(HRESULT hr)
  709. {
  710. if (SUCCEEDED(hr))
  711. RRETURN(DBSTATUS_S_OK);
  712. switch(hr)
  713. {
  714. case (E_INVALIDARG):
  715. RRETURN(DBSTATUS_E_CANTCREATE);
  716. case (DB_E_BADACCESSORHANDLE):
  717. case (DB_E_BADACCESSORTYPE):
  718. case (DB_E_BADBINDINFO):
  719. case (DB_E_BADORDINAL):
  720. case (DB_E_BADSTORAGEFLAGS):
  721. RRETURN(DBSTATUS_E_CANTCONVERTVALUE);
  722. case (DB_E_UNSUPPORTEDCONVERSION):
  723. RRETURN(DBSTATUS_E_CANTCONVERTVALUE);
  724. case (DB_E_BADROWHANDLE):
  725. case (DB_E_DELETEDROW):
  726. RRETURN(DBSTATUS_E_UNAVAILABLE);
  727. default:
  728. RRETURN(DBSTATUS_E_BADSTATUS);
  729. }
  730. }
  731. //////////////////////////////////////////////////////////////////////////////
  732. //ISupportErrorInfo
  733. //
  734. //+---------------------------------------------------------------------------
  735. //
  736. // Function: CRow::InterfaceSupportsErrorInfo
  737. //
  738. // Synopsis: Given an interface ID, tells if that interface supports
  739. // the interface ISupportErrorInfo
  740. //
  741. // Arguments:
  742. // REFIID riid
  743. //
  744. // Returns: HRESULT
  745. // S_OK yes, the interface supports ISupportErrorInfo
  746. // S_FALSE no, the interface doesn't support it.
  747. //----------------------------------------------------------------------------
  748. STDMETHODIMP CRow::InterfaceSupportsErrorInfo(REFIID riid)
  749. {
  750. static const IID* arr[] =
  751. {
  752. &IID_IRow,
  753. &IID_IColumnsInfo,
  754. &IID_IColumnsInfo2,
  755. &IID_IConvertType,
  756. &IID_IGetSession
  757. };
  758. for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++)
  759. {
  760. if (InlineIsEqualGUID(*arr[i],riid))
  761. RRETURN(S_OK);
  762. }
  763. RRETURN(S_FALSE);
  764. }
  765. //////////////////////////////////////////////////////////////////////////////
  766. //IRow methods
  767. //
  768. //+---------------------------------------------------------------------------
  769. //
  770. // Function: CRow::GetColumns
  771. //
  772. // Synopsis: Gets Columns from a Row.
  773. //
  774. // Returns: HRESULT
  775. //
  776. // For more info see OLE DB 2.5 spec.
  777. //----------------------------------------------------------------------------
  778. STDMETHODIMP CRow::GetColumns(
  779. /* [in] */ DBORDINAL cColumns,
  780. /* [size_is][out][in] */ DBCOLUMNACCESS rgColumns[ ])
  781. {
  782. HRESULT hr;
  783. DWORD cErrors = 0;
  784. auto_leave cs_auto_leave(m_autocs);
  785. int i;
  786. DBID dbidRowUrl = DBROWCOL_ROWURL;
  787. if ( cColumns == 0 )
  788. {
  789. // Nothing to do:
  790. RRETURN(S_OK);
  791. }
  792. if (!rgColumns)
  793. RRETURN(E_INVALIDARG);
  794. TRYBLOCK
  795. cs_auto_leave.EnterCriticalSection();
  796. // We must have a valid ADs object or a valid Source Rowset
  797. ADsAssert(m_pADsObj.get() || m_pSourceRowset.get());
  798. if( m_fGetColInfoFromRowset )
  799. {
  800. ADsAssert(m_pSourceRowset.get() != NULL);
  801. hr = GetSourceRowsetColumns(cColumns, rgColumns, &cErrors);
  802. }
  803. else
  804. {
  805. //Get IDataConvert interface pointer.
  806. auto_rel<IDataConvert> pDataConvert;
  807. hr = GetIDataConvert(&pDataConvert);
  808. if (FAILED(hr))
  809. BAIL_ON_FAILURE(hr = DB_E_ERRORSOCCURRED);
  810. for (i = 0; i < cColumns; i++)
  811. {
  812. // DBKIND is DBKIND_NAME and null or zero length column name
  813. if ( rgColumns[i].columnid.eKind == DBKIND_NAME &&
  814. (rgColumns[i].columnid.uName.pwszName == NULL ||
  815. wcslen(rgColumns[i].columnid.uName.pwszName) == 0))
  816. {
  817. rgColumns[i].dwStatus = DBSTATUS_E_DOESNOTEXIST;
  818. cErrors++;
  819. continue;
  820. }
  821. CComVariant varTemp;
  822. DBTYPE propType = DBTYPE_VARIANT;
  823. varTemp.Clear();
  824. hr = S_OK;
  825. //Check if this is the special URL column or the ADsPath
  826. //column. If so, assign the URL to varTemp and proceed to data
  827. //conversion.
  828. if ( (rgColumns[i].columnid.eKind == DBKIND_NAME &&
  829. _wcsicmp(rgColumns[i].columnid.uName.pwszName, g_cwszAdsPath) == 0) ||
  830. (TRUE == CompareDBIDs(&dbidRowUrl, &rgColumns[i].columnid))
  831. )
  832. {
  833. varTemp = m_objURL;
  834. //Set max length of column.
  835. //MaxLen=256 is consistent with 2.0 provider code.
  836. rgColumns[i].cbDataLen = 256;
  837. }
  838. // check if this is the bookmark column
  839. else if (rgColumns[i].columnid.eKind == DBKIND_GUID_PROPID &&
  840. rgColumns[i].columnid.uGuid.guid == DBCOL_SPECIALCOL &&
  841. rgColumns[i].columnid.uName.ulPropid == 2 )
  842. {
  843. UINT uBmk;
  844. if( m_hRow != DB_NULL_HROW )
  845. // get the bookmark associated with this row handle
  846. {
  847. auto_rel<IRowset> pRowset;
  848. CRowset *pCRowset;
  849. LONG lRow;
  850. RBOOKMARK bmk;
  851. hr = m_pSourceRowset->QueryInterface(__uuidof(IRowset),
  852. (void **)&pRowset);
  853. if( SUCCEEDED(hr) )
  854. {
  855. pCRowset = (CRowset *) ((IRowset *) pRowset);
  856. lRow = pCRowset->HROWToRow(m_hRow);
  857. bmk = pCRowset->RowToBmk(lRow);
  858. uBmk = (UINT) bmk;
  859. }
  860. }
  861. else // use any value for bookmark
  862. uBmk = 0;
  863. if( SUCCEEDED(hr) )
  864. {
  865. VARIANT vTmpVariant;
  866. V_VT(&vTmpVariant) = VT_UI4;
  867. V_UI4(&vTmpVariant) = uBmk;
  868. varTemp = vTmpVariant;
  869. }
  870. // else we will fail below and continue to next iteration
  871. }
  872. else if (rgColumns[i].columnid.eKind == DBKIND_NAME)
  873. {
  874. //Find out if property is multivalued and its size.
  875. VARIANT_BOOL fMultiValued;
  876. long lSize = ~0;
  877. hr = GetSchemaAttributes(
  878. rgColumns[i].columnid.uName.pwszName,
  879. &fMultiValued,
  880. &lSize
  881. );
  882. if (SUCCEEDED(hr))
  883. {
  884. // if security descriptor is requested as a variant,
  885. // then we return a variant with an octet string
  886. // inside. This would always be the case with ADO as
  887. // it requests all columns as variants. If it is
  888. // requested as an octet string, we return an octet
  889. // string. If it is requested as some other
  890. // type from C++ (say DBTYPE_IDISPATCH), then we will
  891. // call Get/GetEx and try to convert the resulting
  892. // variant to the appropriate type. Returning security
  893. // descriptor as an octet string is much cheaper as
  894. // there is no network traffic for ACE conversion.
  895. if( (!_wcsicmp(rgColumns[i].columnid.uName.pwszName,
  896. NT_SEC_DESC_ATTR)) &&
  897. ((rgColumns[i].wType & DBTYPE_VARIANT) ||
  898. (rgColumns[i].wType & DBTYPE_BYTES)) )
  899. {
  900. hr = GetSecurityDescriptor(&rgColumns[i],
  901. fMultiValued);
  902. if(FAILED(hr))
  903. {
  904. // Clear error. Status has already been set
  905. // in rgColumns[i]
  906. hr = S_OK;
  907. cErrors++;
  908. }
  909. //Nothing more to do, continue with next column.
  910. continue;
  911. }
  912. if (fMultiValued)
  913. {
  914. //multi-valued column. Use GetEx.
  915. hr = m_pADsObj->GetEx(
  916. rgColumns[i].columnid.uName.pwszName,
  917. &varTemp
  918. );
  919. propType = DBTYPE_BYREF | DBTYPE_VARIANT;
  920. }
  921. else
  922. {
  923. //single-valued. Use Get.
  924. hr = m_pADsObj->Get(
  925. rgColumns[i].columnid.uName.pwszName,
  926. &varTemp
  927. );
  928. }
  929. }
  930. rgColumns[i].cbDataLen = lSize;
  931. }
  932. else
  933. {
  934. rgColumns[i].dwStatus = DBSTATUS_E_UNAVAILABLE;
  935. cErrors++;
  936. continue;
  937. }
  938. if (FAILED(hr))
  939. {
  940. //Clear error. dwStatus below will reflect
  941. //the error for this column.
  942. hr = S_OK;
  943. rgColumns[i].dwStatus = DBSTATUS_E_UNAVAILABLE;
  944. cErrors++; //Increment error count.
  945. //Nothing more to do, continue with next column.
  946. continue;
  947. }
  948. //Does the caller want pData?
  949. if (rgColumns[i].pData != NULL)
  950. {
  951. rgColumns[i].dwStatus = DBSTATUS_S_OK;
  952. //Convert data into requested type
  953. if (propType == (DBTYPE_VARIANT | DBTYPE_BYREF)) //multi-valued
  954. {
  955. if( !(rgColumns[i].wType & DBTYPE_VARIANT) )
  956. // can't convert a multi-valued attr. to anything else
  957. {
  958. rgColumns[i].dwStatus = DBSTATUS_E_CANTCONVERTVALUE;
  959. cErrors++;
  960. continue;
  961. }
  962. else
  963. {
  964. DWORD dwRequiredLen;
  965. PVARIANT pVar;
  966. if((rgColumns[i].wType & (~DBTYPE_BYREF)) !=
  967. DBTYPE_VARIANT)
  968. {
  969. // bad type
  970. rgColumns[i].dwStatus =
  971. DBSTATUS_E_CANTCONVERTVALUE;
  972. cErrors++;
  973. continue;
  974. }
  975. if(rgColumns[i].wType & DBTYPE_BYREF)
  976. dwRequiredLen = sizeof(VARIANT *);
  977. else
  978. dwRequiredLen = sizeof(VARIANT);
  979. if(rgColumns[i].cbMaxLen < dwRequiredLen)
  980. {
  981. rgColumns[i].dwStatus =
  982. DBSTATUS_E_CANTCONVERTVALUE;
  983. cErrors++;
  984. continue;
  985. }
  986. if(rgColumns[i].wType & DBTYPE_BYREF)
  987. {
  988. pVar = (PVARIANT)
  989. CoTaskMemAlloc(sizeof(VARIANT));
  990. if (pVar == NULL)
  991. {
  992. rgColumns[i].dwStatus =
  993. DBSTATUS_E_CANTCREATE;
  994. cErrors++;
  995. continue;
  996. }
  997. }
  998. else
  999. pVar = (PVARIANT) rgColumns[i].pData;
  1000. VariantInit(pVar);
  1001. hr = VariantCopy(pVar, &varTemp);
  1002. if(FAILED(hr))
  1003. {
  1004. hr = S_OK;
  1005. rgColumns[i].dwStatus = DBSTATUS_E_CANTCREATE;
  1006. cErrors++;
  1007. if(rgColumns[i].wType & DBTYPE_BYREF)
  1008. CoTaskMemFree(pVar);
  1009. continue;
  1010. }
  1011. if(rgColumns[i].wType & DBTYPE_BYREF)
  1012. {
  1013. *(PVARIANT *)rgColumns[i].pData = pVar;
  1014. rgColumns[i].cbDataLen = sizeof(PVARIANT);
  1015. }
  1016. else
  1017. rgColumns[i].cbDataLen = sizeof(VARIANT);
  1018. }
  1019. }
  1020. else //single valued
  1021. {
  1022. hr = pDataConvert->DataConvert(
  1023. propType,
  1024. rgColumns[i].wType,
  1025. sizeof(VARIANT),
  1026. &rgColumns[i].cbDataLen,
  1027. &varTemp,
  1028. rgColumns[i].pData,
  1029. rgColumns[i].cbMaxLen,
  1030. DBSTATUS_S_OK,
  1031. &rgColumns[i].dwStatus,
  1032. rgColumns[i].bPrecision,
  1033. rgColumns[i].bScale,
  1034. DBDATACONVERT_DEFAULT
  1035. );
  1036. }
  1037. if (FAILED(hr))
  1038. {
  1039. hr = S_OK;
  1040. rgColumns[i].dwStatus = DBSTATUS_E_CANTCONVERTVALUE;
  1041. cErrors++;
  1042. }
  1043. }
  1044. }
  1045. }
  1046. CATCHBLOCKBAIL(hr)
  1047. if (cErrors == 0)
  1048. RRETURN(S_OK);
  1049. else if (cErrors < cColumns)
  1050. RRETURN(DB_S_ERRORSOCCURRED);
  1051. else
  1052. RRETURN(DB_E_ERRORSOCCURRED);
  1053. error:
  1054. RRETURN(hr);
  1055. }
  1056. //+---------------------------------------------------------------------------
  1057. //
  1058. // Function: CRow::GetSourceRowset
  1059. //
  1060. // Synopsis: Returns interface pointer on the Source Rowset from which this
  1061. // Row was created.
  1062. //
  1063. // Returns: HRESULT
  1064. //
  1065. // For more info see OLE DB 2.5 spec.
  1066. //----------------------------------------------------------------------------
  1067. STDMETHODIMP CRow::GetSourceRowset(
  1068. /* [in] */ REFIID riid,
  1069. /* [iid_is][out] */ IUnknown **ppRowset,
  1070. /* [out] */ HROW *phRow)
  1071. {
  1072. if (ppRowset == NULL && phRow == NULL)
  1073. RRETURN(E_INVALIDARG);
  1074. HRESULT hr;
  1075. auto_leave cs_auto_leave(m_autocs);
  1076. if (ppRowset)
  1077. *ppRowset = NULL;
  1078. if (phRow)
  1079. *phRow = DB_NULL_HROW;
  1080. TRYBLOCK
  1081. cs_auto_leave.EnterCriticalSection();
  1082. if( m_fIsTearOff )
  1083. {
  1084. ADsAssert(m_pSourceRowset.get());
  1085. if (ppRowset)
  1086. {
  1087. hr = m_pSourceRowset->QueryInterface(riid, (void**)ppRowset);
  1088. if (FAILED(hr))
  1089. BAIL_ON_FAILURE(hr = E_NOINTERFACE);
  1090. }
  1091. if (phRow)
  1092. {
  1093. // increment reference count of row handle
  1094. auto_rel<IRowset> pRowset;
  1095. hr = m_pSourceRowset->QueryInterface(__uuidof(IRowset),
  1096. (void **)&pRowset);
  1097. BAIL_ON_FAILURE(hr);
  1098. hr = pRowset->AddRefRows(1, &m_hRow, NULL, NULL);
  1099. BAIL_ON_FAILURE(hr);
  1100. *phRow = m_hRow;
  1101. }
  1102. }
  1103. else
  1104. {
  1105. BAIL_ON_FAILURE(hr = DB_E_NOSOURCEOBJECT);
  1106. }
  1107. CATCHBLOCKBAIL(hr)
  1108. RRETURN(S_OK);
  1109. error:
  1110. if(ppRowset && (*ppRowset != NULL))
  1111. {
  1112. (*ppRowset)->Release();
  1113. *ppRowset = NULL;
  1114. }
  1115. RRETURN(hr);
  1116. }
  1117. //+---------------------------------------------------------------------------
  1118. //
  1119. // Function: CRow::Open
  1120. //
  1121. // Synopsis: Opens a column of a row and returns the requested
  1122. // interface on it.
  1123. //
  1124. // Returns: HRESULT
  1125. //
  1126. // For more info see OLE DB 2.5 spec.
  1127. //----------------------------------------------------------------------------
  1128. STDMETHODIMP CRow::Open(
  1129. /* [unique][in] */ IUnknown *pUnkOuter,
  1130. /* [in] */ DBID *pColumnID,
  1131. /* [in] */ REFGUID rguidColumnType,
  1132. /* [in] */ DWORD dwBindFlags,
  1133. /* [in] */ REFIID riid,
  1134. /* [iid_is][out] */ IUnknown **ppUnk)
  1135. {
  1136. HRESULT hr = S_OK;
  1137. CComVariant varData;
  1138. CComObject<CStreamMem>* pMemoryStream = NULL;
  1139. auto_rel<IStream> pStreamDelete;
  1140. DBCOLUMNACCESS rgColumns[1];
  1141. DBID dbidRowUrl = DBROWCOL_ROWURL;
  1142. TRYBLOCK
  1143. //General validation checks. dwBindFlags is reserved and must be 0.
  1144. if (ppUnk == NULL || pColumnID == NULL || dwBindFlags != 0)
  1145. RRETURN(E_INVALIDARG);
  1146. *ppUnk = NULL;
  1147. // columnID has to be URL, bookmark or DBKIND_NAME
  1148. if ((pColumnID->eKind != DBKIND_NAME) &&
  1149. (FALSE == CompareDBIDs(&dbidRowUrl, pColumnID)) &&
  1150. (!((pColumnID->eKind == DBKIND_GUID_PROPID) &&
  1151. (pColumnID->uGuid.guid == DBCOL_SPECIALCOL) &&
  1152. (pColumnID->uName.ulPropid == 2))
  1153. )
  1154. )
  1155. RRETURN(DB_E_BADCOLUMNID);
  1156. if ((pColumnID->eKind == DBKIND_NAME) &&
  1157. (pColumnID->uName.pwszName == NULL))
  1158. RRETURN(DB_E_BADCOLUMNID);
  1159. if (pUnkOuter != NULL && !InlineIsEqualGUID(riid, IID_IUnknown))
  1160. RRETURN(DB_E_NOAGGREGATION);
  1161. //we don't support aggregation
  1162. if (pUnkOuter != NULL)
  1163. RRETURN(DB_E_NOAGGREGATION);
  1164. // riid has to be one of the interfaces that can be QIed from
  1165. // IStream, need not necessarily be IID_IStream
  1166. hr = CopyDBIDs(&rgColumns[0].columnid, pColumnID);
  1167. if (FAILED(hr))
  1168. BAIL_ON_FAILURE(hr = DB_E_BADCOLUMNID);
  1169. //fill relevant fields of rgColumns[0]
  1170. rgColumns[0].wType = DBTYPE_VARIANT;
  1171. rgColumns[0].pData = (VARIANT *)&varData;
  1172. rgColumns[0].cbMaxLen = sizeof(VARIANT);
  1173. //get column data
  1174. hr = GetColumns(1, rgColumns);
  1175. if (FAILED(hr))
  1176. BAIL_ON_FAILURE(hr = DB_E_BADCOLUMNID);
  1177. if (rguidColumnType != DBGUID_STREAM)
  1178. //we currently support only streams
  1179. RRETURN(DB_E_OBJECTMISMATCH);
  1180. //Check if the returned data is of type binary -
  1181. //Note: ADSI returns binary data as type VT_ARRAY | VT_UI1.
  1182. if (V_VT(&varData) != (VT_ARRAY | VT_UI1))
  1183. BAIL_ON_FAILURE(hr = DB_E_OBJECTMISMATCH);
  1184. hr = CComObject<CStreamMem>::CreateInstance(&pMemoryStream);
  1185. if (FAILED(hr))
  1186. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1187. //To make sure we delete the CStreamMem object in case we ecounter
  1188. //errors after this point.
  1189. pMemoryStream->AddRef();
  1190. pStreamDelete = pMemoryStream;
  1191. hr = pMemoryStream->Initialize(&varData, (IRow *)this, m_hRow);
  1192. if (FAILED(hr))
  1193. BAIL_ON_FAILURE(hr = DB_E_OBJECTMISMATCH);
  1194. hr = pMemoryStream->QueryInterface(riid, (void **)ppUnk);
  1195. if (FAILED(hr))
  1196. BAIL_ON_FAILURE(hr = E_NOINTERFACE);
  1197. CATCHBLOCKBAIL(hr);
  1198. error:
  1199. FreeDBID(&rgColumns[0].columnid);
  1200. RRETURN(hr);
  1201. }
  1202. ///////////////////////////////////////////////////////////////////////////////
  1203. //IColumnsInfo2 : IColumnsInfo
  1204. //
  1205. //+---------------------------------------------------------------------------
  1206. //
  1207. // Function: CRow::GetColumnInfo
  1208. //
  1209. // Synopsis: returns column information on a row. Column 0 is the URL column.
  1210. //
  1211. // Returns: HRESULT
  1212. //
  1213. // For more info see OLE DB 2.5 spec.
  1214. //----------------------------------------------------------------------------
  1215. STDMETHODIMP CRow::GetColumnInfo(
  1216. /* [out][in] */ DBORDINAL *pcColumns,
  1217. /* [size_is][size_is][out] */ DBCOLUMNINFO **prgInfo,
  1218. /* [out] */ OLECHAR **ppStringsBuffer)
  1219. {
  1220. if( pcColumns )
  1221. *pcColumns = 0;
  1222. if( prgInfo )
  1223. *prgInfo = NULL;
  1224. if( ppStringsBuffer )
  1225. *ppStringsBuffer = NULL;
  1226. if( !pcColumns || !prgInfo || !ppStringsBuffer )
  1227. RRETURN( E_INVALIDARG );
  1228. RRETURN(GetRestrictedColumnInfo (
  1229. 0,
  1230. NULL,
  1231. 0,
  1232. pcColumns,
  1233. NULL,
  1234. prgInfo,
  1235. ppStringsBuffer
  1236. ));
  1237. }
  1238. //+---------------------------------------------------------------------------
  1239. //
  1240. // Function: CRow::MapColumnIDs
  1241. //
  1242. // Synopsis: Maps column IDs
  1243. //
  1244. // Returns: HRESULT
  1245. //
  1246. // For more info see OLE DB 2.5 spec.
  1247. //----------------------------------------------------------------------------
  1248. STDMETHODIMP CRow::MapColumnIDs(
  1249. /* [in] */ DBORDINAL cColumnIDs,
  1250. /* [size_is][in] */ const DBID rgColumnIDs[ ],
  1251. /* [size_is][out] */ DBORDINAL rgColumns[ ])
  1252. {
  1253. HRESULT hr;
  1254. ULONG cValidCols = 0;
  1255. //
  1256. // check in-params and NULL out-params in case of error
  1257. //
  1258. if( cColumnIDs == 0 )
  1259. RRETURN( S_OK );
  1260. if( !rgColumnIDs || !rgColumns )
  1261. RRETURN( E_INVALIDARG );
  1262. //
  1263. // Get the ColumnsInfo
  1264. //
  1265. DBORDINAL ulColumns;
  1266. DBCOLUMNINFO * rgColumnInfo = NULL;
  1267. OLECHAR * pStringBuffer = NULL;
  1268. hr=GetColumnInfo((DBORDINAL *)&ulColumns, &rgColumnInfo, &pStringBuffer);
  1269. if( FAILED(hr) )
  1270. RRETURN( hr );
  1271. for(ULONG iCol=0; iCol < cColumnIDs; iCol++)
  1272. {
  1273. // Initialize the column ordinal to invalid column
  1274. rgColumns[iCol] = DB_INVALIDCOLUMN;
  1275. for (ULONG iOrdinal = 0; iOrdinal < ulColumns; iOrdinal++)
  1276. {
  1277. if (TRUE == CompareDBIDs(
  1278. &rgColumnIDs[iCol],
  1279. &rgColumnInfo[iOrdinal].columnid))
  1280. {
  1281. rgColumns[iCol] = rgColumnInfo[iOrdinal].iOrdinal;
  1282. cValidCols++;
  1283. break;
  1284. }
  1285. }
  1286. }
  1287. //
  1288. // Free the ColumnsInfo
  1289. //
  1290. if( rgColumnInfo )
  1291. CoTaskMemFree(rgColumnInfo);
  1292. if( pStringBuffer )
  1293. CoTaskMemFree(pStringBuffer);
  1294. //
  1295. // Return the HRESULT
  1296. //
  1297. if( cValidCols == 0 )
  1298. RRETURN( DB_E_ERRORSOCCURRED );
  1299. else if( cValidCols < cColumnIDs )
  1300. RRETURN( DB_S_ERRORSOCCURRED );
  1301. else
  1302. RRETURN( S_OK );
  1303. }
  1304. //+---------------------------------------------------------------------------
  1305. //
  1306. // Function: CRow::GetRestrictedColumnInfo
  1307. //
  1308. // Synopsis: returns column information for those columns which match given
  1309. // mask criteria.
  1310. //
  1311. // Returns: HRESULT
  1312. //
  1313. // For more info see OLE DB 2.5 spec.
  1314. //----------------------------------------------------------------------------
  1315. STDMETHODIMP CRow::GetRestrictedColumnInfo(
  1316. /* [in] */ DBORDINAL cColumnIDMasks,
  1317. /* [in] */ const DBID rgColumnIDMasks[ ],
  1318. /* [in] */ DWORD dwFlags,
  1319. /* [out][in] */ DBORDINAL *pcColumns,
  1320. /* [size_is][size_is][out] */ DBID **prgColumnIDs,
  1321. /* [size_is][size_is][out] */ DBCOLUMNINFO **prgColumnInfo,
  1322. /* [out] */ OLECHAR **ppStringsBuffer)
  1323. {
  1324. HRESULT hr = S_OK;
  1325. ULONG ulNumColumns = 0, ulStartColumn;
  1326. int iColumn = 0;
  1327. int i = 0, j=0, iMask = 0;
  1328. auto_leave cs_auto_leave(m_autocs);
  1329. DWORD cMaxColumns ;
  1330. auto_rel<IDirectoryObject> pIDirObj;
  1331. DBID bookMarkColid;
  1332. bool bAddBookMark = false;
  1333. //
  1334. // Zero the out params:
  1335. //
  1336. if (pcColumns)
  1337. *pcColumns = 0;
  1338. if (prgColumnIDs)
  1339. *prgColumnIDs = NULL;
  1340. if (prgColumnInfo)
  1341. *prgColumnInfo = NULL;
  1342. if (ppStringsBuffer)
  1343. *ppStringsBuffer = NULL;
  1344. // Validate arguments.
  1345. if ((dwFlags) || (pcColumns == NULL) || (ppStringsBuffer == NULL) )
  1346. RRETURN( E_INVALIDARG);
  1347. // Either column info or column ids should be available.
  1348. if ((NULL == prgColumnIDs) && (NULL == prgColumnInfo))
  1349. RRETURN( E_INVALIDARG);
  1350. //Validate the mask
  1351. if (cColumnIDMasks && !rgColumnIDMasks)
  1352. RRETURN( E_INVALIDARG);
  1353. for (iMask = 0; iMask < cColumnIDMasks; iMask++)
  1354. if (S_FALSE == IsValidDBID(&rgColumnIDMasks[iMask]))
  1355. RRETURN( DB_E_BADCOLUMNID );
  1356. TRYBLOCK
  1357. {
  1358. cs_auto_leave.EnterCriticalSection();
  1359. // We must have a valid ADs object or a valid Source Rowset
  1360. ADsAssert(m_pADsObj.get() || m_pSourceRowset.get());
  1361. // Calculate maximum number of columns that we will return,
  1362. // excluding the bookmark column. We will add bookmark later.
  1363. if (m_fGetColInfoFromRowset)
  1364. {
  1365. ADsAssert(m_pSourceRowset.get() != NULL);
  1366. // m_cSourceRowsetColumns includes the bookmark column.
  1367. cMaxColumns = m_cSourceRowsetColumns - 1;
  1368. }
  1369. else
  1370. {
  1371. if(m_cMaxColumns != -1)
  1372. cMaxColumns = m_cMaxColumns;
  1373. else
  1374. {
  1375. hr = m_pADsObj->QueryInterface(__uuidof(IDirectoryObject),
  1376. (void**)&pIDirObj);
  1377. BAIL_ON_FAILURE(hr);
  1378. hr = pIDirObj->GetObjectAttributes(NULL, -1, &m_pAttrInfo,
  1379. &cMaxColumns);
  1380. BAIL_ON_FAILURE(hr);
  1381. // Add one for ADsPath. ADsPath is returned if the query was a
  1382. // SELECT * query (irrespective of whether the row was obtained
  1383. // from a rowset or directly from a command object) OR if
  1384. // IBindResource::Bind was used to get the row.
  1385. cMaxColumns += 1;
  1386. m_cMaxColumns = cMaxColumns;
  1387. }
  1388. }
  1389. // Add one for URL (for all rows)
  1390. cMaxColumns++;
  1391. BSTR bstrName;
  1392. auto_prg<CComBSTR> propStrings;
  1393. auto_prg<DBTYPE> propTypes;
  1394. auto_prg<ULONG> propSizes;
  1395. propStrings = new CComBSTR[cMaxColumns];
  1396. if (!propStrings)
  1397. {
  1398. hr = E_OUTOFMEMORY;
  1399. BAIL_ON_FAILURE(hr);
  1400. }
  1401. // If client asked for columns info. allocate DBTYPE array
  1402. if (prgColumnInfo)
  1403. {
  1404. propTypes = new DBTYPE[cMaxColumns];
  1405. propSizes = new ULONG[cMaxColumns];
  1406. if (!propTypes || !propSizes)
  1407. BAIL_ON_FAILURE(E_OUTOFMEMORY);
  1408. }
  1409. int totalLen = 0;
  1410. ulNumColumns = 0;
  1411. BOOL fURLMatchesMask = FALSE;
  1412. if (m_fGetColInfoFromRowset)
  1413. {
  1414. ADsAssert(m_pSourceRowset.get() != NULL);
  1415. // start with 1 because column # 0 in source rowset
  1416. // is always a bookmark column.
  1417. for (i = 1; i < m_cSourceRowsetColumns; i++)
  1418. {
  1419. //We need to check if this column matches mask criteria. Use
  1420. // the column name for comparison since we should have a match
  1421. // even if a substring of the column name is specified by the
  1422. // client. Comparing column ID won't work in this case.
  1423. // We know that all columns other than the bookmark (column 0)
  1424. // are of type DBKIND_NAME. So we can access pwszName safely.
  1425. if (fMatchesMaskCriteria(
  1426. m_pSourceRowsetColumnInfo[i].columnid.uName.pwszName,
  1427. cColumnIDMasks,
  1428. rgColumnIDMasks) == false)
  1429. continue;
  1430. //matches the criteria, add to list and
  1431. //update totalLen for strings buffer.
  1432. propStrings[(int)ulNumColumns] =
  1433. m_pSourceRowsetColumnInfo[i].pwszName;
  1434. totalLen += SysStringLen(propStrings[(int)ulNumColumns]) + 1;
  1435. //add type and size to list if columninfo is requested.
  1436. if (prgColumnInfo)
  1437. {
  1438. propTypes[(int)ulNumColumns] =
  1439. m_pSourceRowsetColumnInfo[i].wType;
  1440. propSizes[(int)ulNumColumns] =
  1441. m_pSourceRowsetColumnInfo[i].ulColumnSize;
  1442. }
  1443. ulNumColumns++;
  1444. }
  1445. // Finally, check if URL column is requested
  1446. if (fMatchesMaskCriteria(DBROWCOL_ROWURL, cColumnIDMasks,
  1447. rgColumnIDMasks) == true)
  1448. {
  1449. //matches the criteria, add to list and
  1450. //update totalLen for strings buffer.
  1451. bstrName = SysAllocString(g_cwszAdsPath);
  1452. propStrings[(int)ulNumColumns].Attach(bstrName);
  1453. bstrName = NULL;
  1454. totalLen += SysStringLen(propStrings[(int)ulNumColumns]) + 1;
  1455. // we know the type and size of the URL column
  1456. ulNumColumns++;
  1457. fURLMatchesMask = TRUE;
  1458. }
  1459. }
  1460. else
  1461. {
  1462. for (i = 0; i < cMaxColumns; i++)
  1463. {
  1464. if ((cMaxColumns-1) == i) // special URL column
  1465. {
  1466. if (fMatchesMaskCriteria(DBROWCOL_ROWURL, cColumnIDMasks,
  1467. rgColumnIDMasks) == true)
  1468. {
  1469. bstrName = SysAllocString(g_cwszAdsPath);
  1470. fURLMatchesMask = TRUE;
  1471. }
  1472. else
  1473. continue;
  1474. }
  1475. else
  1476. {
  1477. if (0 == i) //ADsPath
  1478. bstrName = SysAllocString(g_cwszAdsPath);
  1479. else
  1480. {
  1481. bstrName =SysAllocString(m_pAttrInfo[i-1].pszAttrName);
  1482. }
  1483. // If property doesn't match
  1484. // mask criteria, continue with next property.
  1485. if (
  1486. (fMatchesMaskCriteria(bstrName,
  1487. cColumnIDMasks,
  1488. rgColumnIDMasks) == false)
  1489. )
  1490. {
  1491. SysFreeString(bstrName);
  1492. bstrName = NULL;
  1493. continue;
  1494. }
  1495. } // else
  1496. // OK Matches the criterion add to the list and
  1497. // update toalLen for strings buffer.
  1498. propStrings[(int)ulNumColumns].Attach(bstrName);
  1499. bstrName = NULL;
  1500. totalLen += SysStringLen(propStrings[(int)ulNumColumns]) + 1;
  1501. //Get Type and size of column if ColumnInfo is requested.
  1502. //For the special URL column and the ADsPath column, we already
  1503. //know the type.
  1504. if ((i > 0) && (i < (cMaxColumns-1)) && (prgColumnInfo != NULL))
  1505. {
  1506. hr = GetTypeAndSize(
  1507. m_pAttrInfo[i-1].dwADsType,
  1508. propStrings[(int)ulNumColumns],
  1509. &propTypes[(int)ulNumColumns],
  1510. &propSizes[(int)ulNumColumns]
  1511. );
  1512. BAIL_ON_FAILURE(hr);
  1513. }
  1514. // Increment number of columns count
  1515. ulNumColumns++;
  1516. }
  1517. }
  1518. if (ulNumColumns == 0)
  1519. BAIL_ON_FAILURE(hr = DB_E_NOCOLUMN);
  1520. //We will add a bookmark column to the list that we are going to return.
  1521. bookMarkColid.eKind = DBKIND_GUID_PROPID;
  1522. bookMarkColid.uGuid.guid = DBCOL_SPECIALCOL;
  1523. bookMarkColid.uName.ulPropid = 2;
  1524. if (fMatchesMaskCriteria(bookMarkColid, cColumnIDMasks, rgColumnIDMasks))
  1525. {
  1526. bAddBookMark = true;
  1527. ulNumColumns += 1;
  1528. }
  1529. *pcColumns = ulNumColumns;
  1530. // Does the caller want column IDS?
  1531. if ( prgColumnIDs )
  1532. {
  1533. *prgColumnIDs =
  1534. (DBID *) CoTaskMemAlloc( (ulNumColumns) * sizeof (DBID) );
  1535. if (NULL == *prgColumnIDs)
  1536. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1537. ZeroMemory ( *prgColumnIDs, (ulNumColumns) * sizeof (DBID));
  1538. }
  1539. // Does the caller want COLUMNINFO?
  1540. if ( prgColumnInfo )
  1541. {
  1542. *prgColumnInfo = (DBCOLUMNINFO *)
  1543. CoTaskMemAlloc( (ulNumColumns) * sizeof (DBCOLUMNINFO) );
  1544. if (NULL == *prgColumnInfo)
  1545. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1546. ZeroMemory ( *prgColumnInfo,
  1547. (ulNumColumns) * sizeof (DBCOLUMNINFO) );
  1548. }
  1549. // get the string buffer allocated.
  1550. *ppStringsBuffer = (OLECHAR *)CoTaskMemAlloc(sizeof(OLECHAR)*totalLen);
  1551. if (NULL ==*ppStringsBuffer)
  1552. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1553. OLECHAR *pwChar = *ppStringsBuffer;
  1554. //First fill bookmark column information.
  1555. if (prgColumnIDs && bAddBookMark)
  1556. {
  1557. (*prgColumnIDs)[0] = bookMarkColid;
  1558. }
  1559. if (prgColumnInfo && bAddBookMark)
  1560. {
  1561. (*prgColumnInfo)[0].pwszName = NULL;
  1562. (*prgColumnInfo)[0].pTypeInfo = NULL;
  1563. (*prgColumnInfo)[0].iOrdinal = 0;
  1564. (*prgColumnInfo)[0].ulColumnSize = sizeof(ULONG);
  1565. (*prgColumnInfo)[0].wType = DBTYPE_UI4;
  1566. (*prgColumnInfo)[0].bPrecision = 10;
  1567. (*prgColumnInfo)[0].bScale = (BYTE) ~ 0;
  1568. (*prgColumnInfo)[0].columnid.eKind = DBKIND_GUID_PROPID;
  1569. (*prgColumnInfo)[0].columnid.uGuid.guid = DBCOL_SPECIALCOL;
  1570. (*prgColumnInfo)[0].columnid.uName.ulPropid = 2;
  1571. (*prgColumnInfo)[0].dwFlags = DBCOLUMNFLAGS_ISBOOKMARK |
  1572. DBCOLUMNFLAGS_ISFIXEDLENGTH;
  1573. }
  1574. // Fill the rest of the columns.
  1575. if (bAddBookMark)
  1576. ulStartColumn = 1;
  1577. else
  1578. ulStartColumn = 0;
  1579. for (iColumn= ulStartColumn, i = 0; iColumn < ulNumColumns; iColumn++, i++)
  1580. {
  1581. wcscpy(pwChar, propStrings[i]);
  1582. //Is this the special URL column (has to be last column)
  1583. if( fURLMatchesMask && (iColumn == (ulNumColumns -1)) &&
  1584. (_wcsicmp(pwChar, g_cwszAdsPath)) == 0 )
  1585. {
  1586. if ( prgColumnIDs )
  1587. {
  1588. // Add a new DBID for this column:
  1589. //
  1590. (*prgColumnIDs)[iColumn] = DBROWCOL_ROWURL;
  1591. }
  1592. if ( prgColumnInfo )
  1593. {
  1594. (*prgColumnInfo)[iColumn].pwszName = pwChar;
  1595. (*prgColumnInfo)[iColumn].pTypeInfo = NULL;
  1596. (*prgColumnInfo)[iColumn].iOrdinal = iColumn;
  1597. (*prgColumnInfo)[iColumn].dwFlags = DBCOLUMNFLAGS_ISROWURL;
  1598. //Rowset code sets ulColumnSize for Adspath to 256.
  1599. //We do the same thing for consistency.
  1600. (*prgColumnInfo)[iColumn].ulColumnSize = 256;
  1601. (*prgColumnInfo)[iColumn].wType = DBTYPE_WSTR;
  1602. (*prgColumnInfo)[iColumn].bPrecision = ~0;
  1603. (*prgColumnInfo)[iColumn].bScale = ~0;
  1604. (*prgColumnInfo)[iColumn].columnid = DBROWCOL_ROWURL;
  1605. }
  1606. }
  1607. // Is this the ADsPath column (if it has the name ADsPath and it
  1608. // is not URL, it has to be the ADsPath column)
  1609. else if(_wcsicmp(pwChar, g_cwszAdsPath) == 0)
  1610. {
  1611. if ( prgColumnIDs )
  1612. {
  1613. // Add DBID for ADsPath
  1614. (*prgColumnIDs)[iColumn].eKind = DBKIND_NAME;
  1615. (*prgColumnIDs)[iColumn].uGuid.guid = GUID_NULL;
  1616. (*prgColumnIDs)[iColumn].uName.pwszName = pwChar;
  1617. }
  1618. if ( prgColumnInfo )
  1619. {
  1620. // Add a DBCOLUMNINFO for ADsPath
  1621. DBTYPE wType = DBTYPE_WSTR | DBTYPE_BYREF;
  1622. (*prgColumnInfo)[iColumn].pwszName = pwChar;
  1623. (*prgColumnInfo)[iColumn].pTypeInfo = NULL;
  1624. (*prgColumnInfo)[iColumn].iOrdinal = iColumn;
  1625. // OLEDB 2.0 code sets ulColumnsSize to 256 for ADsPath
  1626. (*prgColumnInfo)[iColumn].ulColumnSize = 256;
  1627. (*prgColumnInfo)[iColumn].wType = wType;
  1628. // the code below has to be identical to the code in
  1629. // GetColumnsInfo2 in ccommand.cxx
  1630. wType = wType & (~DBTYPE_BYREF);
  1631. if( (wType == DBTYPE_STR) ||
  1632. (wType == DBTYPE_WSTR) ||
  1633. (wType == DBTYPE_BYTES) )
  1634. (*prgColumnInfo)[iColumn].dwFlags =
  1635. DBCOLUMNFLAGS_ISNULLABLE;
  1636. else
  1637. (*prgColumnInfo)[iColumn].dwFlags =
  1638. DBCOLUMNFLAGS_ISNULLABLE | DBCOLUMNFLAGS_ISFIXEDLENGTH;
  1639. (*prgColumnInfo)[iColumn].bPrecision = SetPrecision(wType);
  1640. (*prgColumnInfo)[iColumn].bScale = ~0;
  1641. (*prgColumnInfo)[iColumn].columnid.eKind = DBKIND_NAME;
  1642. (*prgColumnInfo)[iColumn].columnid.uGuid.guid = GUID_NULL;
  1643. (*prgColumnInfo)[iColumn].columnid.uName.pwszName= pwChar;
  1644. }
  1645. }
  1646. else
  1647. {
  1648. if ( prgColumnIDs )
  1649. {
  1650. // Add a new DBID for this column:
  1651. //
  1652. (*prgColumnIDs)[iColumn].eKind = DBKIND_NAME;
  1653. (*prgColumnIDs)[iColumn].uGuid.guid = GUID_NULL;
  1654. (*prgColumnIDs)[iColumn].uName.pwszName = pwChar;
  1655. }
  1656. if ( prgColumnInfo )
  1657. {
  1658. // Add a new DBCOLUMNINFO for this column:
  1659. //
  1660. DBTYPE wType = propTypes[i];
  1661. (*prgColumnInfo)[iColumn].pwszName = pwChar;
  1662. (*prgColumnInfo)[iColumn].pTypeInfo = NULL;
  1663. (*prgColumnInfo)[iColumn].iOrdinal = iColumn;
  1664. (*prgColumnInfo)[iColumn].ulColumnSize = propSizes[i]; ;
  1665. (*prgColumnInfo)[iColumn].wType = wType;
  1666. // the code below has to be identical to the code in
  1667. // GetColumnsInfo2 in ccommand.cxx
  1668. wType = wType & (~DBTYPE_BYREF);
  1669. if( (wType == DBTYPE_STR) ||
  1670. (wType == DBTYPE_WSTR) ||
  1671. (wType == DBTYPE_BYTES) )
  1672. (*prgColumnInfo)[iColumn].dwFlags =
  1673. DBCOLUMNFLAGS_ISNULLABLE;
  1674. else
  1675. (*prgColumnInfo)[iColumn].dwFlags =
  1676. DBCOLUMNFLAGS_ISNULLABLE | DBCOLUMNFLAGS_ISFIXEDLENGTH;
  1677. (*prgColumnInfo)[iColumn].bPrecision = SetPrecision(wType);
  1678. (*prgColumnInfo)[iColumn].bScale = ~0;
  1679. (*prgColumnInfo)[iColumn].columnid.eKind = DBKIND_NAME;
  1680. (*prgColumnInfo)[iColumn].columnid.uGuid.guid = GUID_NULL;
  1681. (*prgColumnInfo)[iColumn].columnid.uName.pwszName= pwChar;
  1682. }
  1683. }
  1684. //Position the pointer in strings buffer
  1685. //for writing next column name.
  1686. pwChar += SysStringLen(propStrings[i]) + 1;
  1687. }
  1688. }
  1689. CATCHBLOCKBAIL(hr)
  1690. RRETURN(S_OK);
  1691. error:
  1692. if ((prgColumnIDs) && (*prgColumnIDs))
  1693. {
  1694. CoTaskMemFree(*prgColumnIDs);
  1695. *prgColumnIDs = NULL;
  1696. }
  1697. if ((prgColumnInfo) && (*prgColumnInfo))
  1698. {
  1699. CoTaskMemFree(*prgColumnInfo);
  1700. *prgColumnInfo = NULL;
  1701. }
  1702. if ((ppStringsBuffer) && (*ppStringsBuffer))
  1703. {
  1704. CoTaskMemFree(*ppStringsBuffer);
  1705. *ppStringsBuffer = NULL;
  1706. }
  1707. if (pcColumns)
  1708. *pcColumns = 0;
  1709. RRETURN(hr);
  1710. }
  1711. /////////////////////////////////////////////////////////////////////////////
  1712. //IConvertType
  1713. //
  1714. //+---------------------------------------------------------------------------
  1715. //
  1716. // Function: CRow::ConvertType
  1717. //
  1718. // Synopsis: Converts one DBTYPE to another using data conversion library.
  1719. //
  1720. // Returns: HRESULT
  1721. //
  1722. // For more info see OLE DB 2.0 spec.
  1723. //----------------------------------------------------------------------------
  1724. STDMETHODIMP CRow::CanConvert(
  1725. /* [in] */ DBTYPE wFromType,
  1726. /* [in] */ DBTYPE wToType,
  1727. /* [in] */ DBCONVERTFLAGS dwConvertFlags)
  1728. {
  1729. auto_rel<IDataConvert> pDataConvert;
  1730. HRESULT hr = GetIDataConvert(&pDataConvert);
  1731. BAIL_ON_FAILURE(hr);
  1732. ADsAssert(pDataConvert.get());
  1733. if( dwConvertFlags & DBCONVERTFLAGS_PARAMETER ) // not allowed on row
  1734. RRETURN( DB_E_BADCONVERTFLAG );
  1735. if( (dwConvertFlags & (~(DBCONVERTFLAGS_ISLONG |
  1736. DBCONVERTFLAGS_ISFIXEDLENGTH |
  1737. DBCONVERTFLAGS_FROMVARIANT))) !=
  1738. DBCONVERTFLAGS_COLUMN )
  1739. RRETURN( DB_E_BADCONVERTFLAG );
  1740. if( dwConvertFlags & DBCONVERTFLAGS_ISLONG )
  1741. {
  1742. DBTYPE wType;
  1743. wType = wFromType & (~(DBTYPE_BYREF | DBTYPE_ARRAY | DBTYPE_VECTOR));
  1744. // wType has to be variable-length DBTYPE
  1745. if( (wType != DBTYPE_STR) && (wType != DBTYPE_WSTR) &&
  1746. (wType != DBTYPE_BYTES) && (wType != DBTYPE_VARNUMERIC) )
  1747. RRETURN( DB_E_BADCONVERTFLAG );
  1748. }
  1749. if( dwConvertFlags & DBCONVERTFLAGS_FROMVARIANT )
  1750. {
  1751. DBTYPE dbTmpType, wVtType;
  1752. wVtType = wFromType & VT_TYPEMASK;
  1753. // Take out all of the Valid VT_TYPES (36 is VT_RECORD in VC 6)
  1754. if( (wVtType > VT_DECIMAL && wVtType < VT_I1) ||
  1755. ((wVtType > VT_LPWSTR && wVtType < VT_FILETIME) && wVtType !=36) ||
  1756. (wVtType > VT_CLSID) )
  1757. RRETURN( DB_E_BADTYPE );
  1758. }
  1759. RRETURN(pDataConvert->CanConvert(wFromType, wToType));
  1760. error:
  1761. RRETURN(hr);
  1762. }
  1763. ///////////////////////////////////////////////////////////////////////////////
  1764. //IGetSession
  1765. //
  1766. //+---------------------------------------------------------------------------
  1767. //
  1768. // Function: CRow::GetSession
  1769. //
  1770. // Synopsis: Gets the Session interface through which this row has been
  1771. // created.
  1772. //
  1773. // Returns: HRESULT
  1774. //
  1775. // For more info see OLE DB 2.5 spec.
  1776. //----------------------------------------------------------------------------
  1777. STDMETHODIMP CRow::GetSession(
  1778. REFIID riid,
  1779. IUnknown **ppunkSession)
  1780. {
  1781. if (ppunkSession == NULL)
  1782. RRETURN(E_INVALIDARG);
  1783. *ppunkSession = NULL;
  1784. if (!m_pSession.get())
  1785. RRETURN(DB_E_NOSOURCEOBJECT);
  1786. HRESULT hr = m_pSession->QueryInterface(riid, (void**)ppunkSession);
  1787. if (FAILED(hr))
  1788. RRETURN(E_NOINTERFACE);
  1789. RRETURN(S_OK);
  1790. }
  1791. //----------------------------------------------------------------------------
  1792. // GetSecurityDescriptor
  1793. //
  1794. // Returns the security descriptor as an octet string.
  1795. //
  1796. //----------------------------------------------------------------------------
  1797. HRESULT CRow::GetSecurityDescriptor(
  1798. DBCOLUMNACCESS *pColumn,
  1799. BOOL fMultiValued
  1800. )
  1801. {
  1802. HRESULT hr;
  1803. auto_rel<IDirectoryObject> pIDirObj;
  1804. PVARIANT pVariant = NULL, pVarArray = NULL;
  1805. SAFEARRAY *aList = NULL;
  1806. SAFEARRAYBOUND aBound;
  1807. VARTYPE vType;
  1808. DWORD dwRequiredLen;
  1809. int iAttr, j;
  1810. // multivalued attributes are always returned as variants. Single-valued
  1811. // security descriptor has to be returned as either variant or octet
  1812. // string.
  1813. if( ((pColumn->wType != (DBTYPE_VARIANT | DBTYPE_BYREF)) &&
  1814. (pColumn->wType != DBTYPE_VARIANT)) &&
  1815. (fMultiValued || ((fMultiValued == FALSE) &&
  1816. (pColumn->wType != DBTYPE_BYTES) &&
  1817. (pColumn->wType != (DBTYPE_BYTES | DBTYPE_BYREF)))) )
  1818. {
  1819. pColumn->dwStatus = DBSTATUS_E_CANTCONVERTVALUE;
  1820. BAIL_ON_FAILURE(hr = DB_E_CANTCONVERTVALUE);
  1821. }
  1822. pColumn->dwStatus = DBSTATUS_S_OK;
  1823. pColumn->cbDataLen = 0;
  1824. if(pColumn->pData == NULL) // client doesn't want any data returned
  1825. RRETURN(S_OK);
  1826. if(m_cMaxColumns == -1) // GetObjectAttributes has not been called
  1827. {
  1828. hr = m_pADsObj->QueryInterface(__uuidof(IDirectoryObject),
  1829. (void**)&pIDirObj);
  1830. BAIL_ON_FAILURE(hr);
  1831. hr = pIDirObj->GetObjectAttributes(NULL, -1, &m_pAttrInfo,
  1832. (DWORD *) &m_cMaxColumns);
  1833. BAIL_ON_FAILURE(hr);
  1834. m_cMaxColumns++; // include ADsPath
  1835. }
  1836. // get the index of security descriptor in the attribute array
  1837. for(iAttr = 0; iAttr < (m_cMaxColumns-1); iAttr++)
  1838. if(!_wcsicmp(m_pAttrInfo[iAttr].pszAttrName, NT_SEC_DESC_ATTR))
  1839. break;
  1840. if(iAttr == (m_cMaxColumns-1))
  1841. {
  1842. pColumn->dwStatus = DBSTATUS_E_UNAVAILABLE;
  1843. BAIL_ON_FAILURE(hr = DB_E_NOTFOUND);
  1844. }
  1845. ADsAssert(m_pAttrInfo[iAttr].dwADsType == ADSTYPE_NT_SECURITY_DESCRIPTOR);
  1846. if(fMultiValued)
  1847. {
  1848. // check if the client has enough space to copy over the variant
  1849. if(pColumn->wType & DBTYPE_BYREF)
  1850. dwRequiredLen = sizeof(VARIANT *);
  1851. else
  1852. dwRequiredLen = sizeof(VARIANT);
  1853. if(pColumn->cbMaxLen < dwRequiredLen)
  1854. {
  1855. pColumn->dwStatus = DBSTATUS_E_CANTCONVERTVALUE;
  1856. BAIL_ON_FAILURE(hr = DB_E_CANTCONVERTVALUE);
  1857. }
  1858. aBound.lLbound = 0;
  1859. aBound.cElements = m_pAttrInfo[iAttr].dwNumValues;
  1860. if(pColumn->wType & DBTYPE_BYREF)
  1861. {
  1862. pVariant = (PVARIANT) AllocADsMem(sizeof(VARIANT));
  1863. if(NULL == pVariant)
  1864. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1865. }
  1866. else
  1867. pVariant = (PVARIANT) pColumn->pData;
  1868. VariantInit(pVariant);
  1869. aList = SafeArrayCreate( VT_VARIANT, 1, &aBound );
  1870. if (aList == NULL)
  1871. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1872. hr = SafeArrayAccessData( aList, (void **) &pVarArray );
  1873. BAIL_ON_FAILURE(hr);
  1874. vType = g_MapADsTypeToVarType[m_pAttrInfo[iAttr].dwADsType];
  1875. for (j=0; j<aBound.cElements; j++)
  1876. {
  1877. VariantInit(pVarArray+j);
  1878. V_VT(pVarArray+j) = vType;
  1879. hr = BinaryToVariant(
  1880. m_pAttrInfo[iAttr].pADsValues[j].SecurityDescriptor.dwLength,
  1881. m_pAttrInfo[iAttr].pADsValues[j].SecurityDescriptor.lpValue,
  1882. pVarArray+j);
  1883. if(FAILED(hr))
  1884. {
  1885. int k;
  1886. for(k = 0; k < j; k++)
  1887. VariantClear(pVarArray+k);
  1888. }
  1889. BAIL_ON_FAILURE(hr);
  1890. }
  1891. SafeArrayUnaccessData( aList );
  1892. V_VT((PVARIANT)pVariant) = VT_ARRAY | VT_VARIANT;
  1893. V_ARRAY((PVARIANT)pVariant) = aList;
  1894. if(pColumn->wType & DBTYPE_BYREF)
  1895. *(PVARIANT *)pColumn->pData = pVariant;
  1896. pColumn->cbDataLen = sizeof(VARIANT);
  1897. }
  1898. else // single valued
  1899. {
  1900. // check if the client has enough space to copy over the octet string
  1901. if(pColumn->wType & DBTYPE_VARIANT)
  1902. {
  1903. if(pColumn->wType & DBTYPE_BYREF)
  1904. dwRequiredLen = sizeof(VARIANT *);
  1905. else
  1906. dwRequiredLen = sizeof(VARIANT);
  1907. }
  1908. else if(pColumn->wType & DBTYPE_BYTES)
  1909. {
  1910. if(pColumn->wType & DBTYPE_BYREF)
  1911. dwRequiredLen = sizeof(BYTE *);
  1912. else
  1913. dwRequiredLen =
  1914. m_pAttrInfo[iAttr].pADsValues[0].SecurityDescriptor.dwLength;
  1915. }
  1916. if(pColumn->cbMaxLen < dwRequiredLen)
  1917. {
  1918. pColumn->dwStatus = DBSTATUS_E_CANTCONVERTVALUE;
  1919. BAIL_ON_FAILURE(hr = DB_E_CANTCONVERTVALUE);
  1920. }
  1921. if(pColumn->wType & DBTYPE_VARIANT)
  1922. {
  1923. if(pColumn->wType & DBTYPE_BYREF)
  1924. {
  1925. pVariant = (PVARIANT) AllocADsMem(sizeof(VARIANT));
  1926. if(NULL == pVariant)
  1927. BAIL_ON_FAILURE(hr = E_OUTOFMEMORY);
  1928. }
  1929. else
  1930. pVariant = (PVARIANT) pColumn->pData;
  1931. VariantInit(pVariant);
  1932. vType = g_MapADsTypeToVarType[m_pAttrInfo[iAttr].dwADsType];
  1933. V_VT(pVariant) = vType;
  1934. hr = BinaryToVariant(
  1935. m_pAttrInfo[iAttr].pADsValues[0].SecurityDescriptor.dwLength,
  1936. m_pAttrInfo[iAttr].pADsValues[0].SecurityDescriptor.lpValue,
  1937. pVariant);
  1938. BAIL_ON_FAILURE(hr);
  1939. if(pColumn->wType & DBTYPE_BYREF)
  1940. *(PVARIANT *)pColumn->pData = pVariant;
  1941. pColumn->cbDataLen = sizeof(VARIANT);
  1942. }
  1943. else if(pColumn->wType & DBTYPE_BYTES)
  1944. {
  1945. if(pColumn->wType & DBTYPE_BYREF)
  1946. *(BYTE **)pColumn->pData =
  1947. m_pAttrInfo[iAttr].pADsValues[0].SecurityDescriptor.lpValue;
  1948. else
  1949. memcpy(pColumn->pData,
  1950. m_pAttrInfo[iAttr].pADsValues[0].SecurityDescriptor.lpValue,
  1951. m_pAttrInfo[iAttr].pADsValues[0].SecurityDescriptor.dwLength);
  1952. pColumn->cbDataLen =
  1953. m_pAttrInfo[iAttr].pADsValues[0].SecurityDescriptor.dwLength;
  1954. }
  1955. }
  1956. RRETURN(S_OK);
  1957. error:
  1958. if(aList)
  1959. SafeArrayDestroy(aList);
  1960. if((pVariant) && (pColumn->wType & DBTYPE_BYREF))
  1961. FreeADsMem(pVariant);
  1962. RRETURN(hr);
  1963. }
  1964. //---------------------------------------------------------------------------
  1965. // IgnorecbMaxLen
  1966. //
  1967. // This function returns 1 if the cbMaxLen field of DBCOLUMNACCESS structure
  1968. // should be ignored and 0 otherwise. cbMaxLen should be ignored for fixed
  1969. // length data types and data types combined with DBTYPE_BYREF, DBTYPE_VECTOR
  1970. // and DBTYPE_ARRAY (page 107, OLEDB 2.0 spec)
  1971. //
  1972. //---------------------------------------------------------------------------
  1973. int CRow::IgnorecbMaxLen(DBTYPE wType)
  1974. {
  1975. if( (wType & DBTYPE_BYREF) ||
  1976. (wType & DBTYPE_VECTOR) ||
  1977. (wType & DBTYPE_ARRAY) )
  1978. return 1;
  1979. wType &= ( (~DBTYPE_BYREF) & (~DBTYPE_VECTOR) & (~DBTYPE_ARRAY) );
  1980. // check if it is a variable length data type
  1981. if( (DBTYPE_STR == wType) ||
  1982. (DBTYPE_BYTES == wType) ||
  1983. (DBTYPE_WSTR == wType) ||
  1984. (DBTYPE_VARNUMERIC == wType) )
  1985. return 0;
  1986. // must be fixed length data type
  1987. return 1;
  1988. }
  1989. //-----------------------------------------------------------------------------
  1990. #endif