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.

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