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.

2047 lines
48 KiB

  1. //
  2. // Microsoft Windows
  3. // Copyright (C) Microsoft Corporation, 1992 - 1995
  4. //
  5. // File: ccommand.cxx
  6. //
  7. // Contents: Microsoft OleDB/OleDS Data Source Object for ADSI
  8. //
  9. //
  10. // History: 08-01-96 shanksh Created.
  11. //
  12. //----------------------------------------------------------------------------
  13. #include "oleds.hxx"
  14. #pragma hdrstop
  15. static WCHAR gpszADsPathAttr[] = L"ADsPath";
  16. static BOOL
  17. IsAutomatable(
  18. DBTYPE dbType
  19. );
  20. //+---------------------------------------------------------------------------
  21. //
  22. // Function: CCommandObject::AddRefAccessor
  23. //
  24. // Synopsis:
  25. //
  26. // Arguments:
  27. //
  28. //
  29. // Returns:
  30. //
  31. //
  32. // Modifies:
  33. //
  34. // History: 08-28-96 ShankSh Created.
  35. //
  36. //----------------------------------------------------------------------------
  37. STDMETHODIMP
  38. CCommandObject::AddRefAccessor(
  39. HACCESSOR hAccessor,
  40. DBREFCOUNT * pcRefCount
  41. )
  42. {
  43. //
  44. // Asserts
  45. //
  46. ADsAssert(_pAccessor);
  47. RRETURN( _pAccessor->AddRefAccessor(
  48. hAccessor,
  49. pcRefCount) );
  50. }
  51. //+---------------------------------------------------------------------------
  52. //
  53. // Function: CCommandObject::CreateAccessor
  54. //
  55. // Synopsis:
  56. //
  57. // Arguments:
  58. //
  59. //
  60. // Returns:
  61. //
  62. //
  63. // Modifies:
  64. //
  65. // History: 08-28-96 ShankSh Created.
  66. //
  67. //----------------------------------------------------------------------------
  68. STDMETHODIMP
  69. CCommandObject::CreateAccessor(
  70. DBACCESSORFLAGS dwAccessorFlags,
  71. DBCOUNTITEM cBindings,
  72. const DBBINDING rgBindings[],
  73. DBLENGTH cbRowSize,
  74. HACCESSOR * phAccessor,
  75. DBBINDSTATUS rgStatus[]
  76. )
  77. {
  78. //
  79. // Asserts
  80. //
  81. ADsAssert(_pAccessor);
  82. RRETURN( _pAccessor->CreateAccessor(
  83. dwAccessorFlags,
  84. cBindings,
  85. rgBindings,
  86. cbRowSize,
  87. phAccessor,
  88. rgStatus) );
  89. }
  90. //+---------------------------------------------------------------------------
  91. //
  92. // Function: CCommandObject::ReleaseAccessor
  93. //
  94. // Synopsis:
  95. //
  96. // Arguments:
  97. //
  98. // Returns:
  99. //
  100. // Modifies:
  101. //
  102. // History: 08-28-96 ShankSh Created.
  103. //
  104. //----------------------------------------------------------------------------
  105. STDMETHODIMP
  106. CCommandObject::ReleaseAccessor(
  107. HACCESSOR hAccessor,
  108. DBREFCOUNT * pcRefCount
  109. )
  110. {
  111. //
  112. // Asserts
  113. //
  114. ADsAssert(_pAccessor);
  115. RRETURN( _pAccessor->ReleaseAccessor(
  116. hAccessor,
  117. pcRefCount) );
  118. }
  119. //+---------------------------------------------------------------------------
  120. //
  121. // Function: CCommandObject::GetBindings
  122. //
  123. // Synopsis:
  124. //
  125. //
  126. // Arguments:
  127. //
  128. // Returns:
  129. //
  130. // Modifies:
  131. //
  132. // History: 08-28-96 ShankSh Created.
  133. //
  134. //----------------------------------------------------------------------------
  135. STDMETHODIMP
  136. CCommandObject::GetBindings(
  137. HACCESSOR hAccessor,
  138. DBACCESSORFLAGS * pdwAccessorFlags,
  139. DBCOUNTITEM * pcBindings,
  140. DBBINDING ** prgBindings
  141. )
  142. {
  143. //
  144. // Asserts
  145. //
  146. ADsAssert(_pAccessor);
  147. RRETURN( _pAccessor->GetBindings(
  148. hAccessor,
  149. pdwAccessorFlags,
  150. pcBindings, prgBindings) );
  151. }
  152. STDMETHODIMP
  153. CCommandObject::GetColumnInfo2(
  154. DBORDINAL * pcColumns,
  155. DBCOLUMNINFO ** prgInfo,
  156. OLECHAR ** ppStringBuffer,
  157. BOOL ** ppfMultiValued
  158. )
  159. {
  160. HRESULT hr;
  161. ULONG pos, nStringBufLen;
  162. DBCOLUMNINFO *pInfo=NULL;
  163. OLECHAR* pStringBuffer=NULL ;
  164. DWORD i;
  165. DBTYPE wType;
  166. DWORD cAttrsReturned;
  167. LPWSTR *ppszTmpAttrs = NULL;
  168. DWORD cTmpAttrs;
  169. IDirectorySchemaMgmt *pDSAttrMgmt = NULL;
  170. PADS_ATTR_DEF pAttrDefinition = NULL;
  171. ADsAssert(_pIMalloc != NULL);
  172. //
  173. // IMalloc->Alloc is the way we have to allocate memory for out parameters
  174. //
  175. nStringBufLen = 0;
  176. for (i=0; i < _cAttrs; i++) {
  177. nStringBufLen += (wcslen(_ppszAttrs[i]) + 1) * sizeof (WCHAR);
  178. }
  179. nStringBufLen+= sizeof(WCHAR); // For the bookmark column which is a null string
  180. //
  181. // No. of DBCOLUMN structures to be allocated
  182. //
  183. pInfo = (DBCOLUMNINFO *)_pIMalloc->Alloc((_cAttrs+1)*sizeof(DBCOLUMNINFO));
  184. if( !pInfo ) {
  185. hr = E_OUTOFMEMORY;
  186. goto error;
  187. }
  188. memset(pInfo, 0, (_cAttrs*sizeof(DBCOLUMNINFO)));
  189. pStringBuffer = (WCHAR *)_pIMalloc->Alloc(nStringBufLen);
  190. if( !pStringBuffer ) {
  191. hr = E_OUTOFMEMORY;
  192. goto error;
  193. };
  194. memset(pStringBuffer, 0, nStringBufLen);
  195. //
  196. // Get the attribute types by enquiring the DS schema
  197. //
  198. hr = _pDSSearch->QueryInterface(
  199. IID_IDirectorySchemaMgmt,
  200. (void**)&pDSAttrMgmt
  201. );
  202. BAIL_ON_FAILURE( hr );
  203. // Fix for #285757. We should not send the ADsPath attribute to the
  204. // server. So, search for occurences of this attribute and remove them.
  205. ppszTmpAttrs = (LPWSTR *) AllocADsMem(sizeof(LPWSTR) * _cAttrs);
  206. if(NULL == ppszTmpAttrs)
  207. {
  208. hr = E_OUTOFMEMORY;
  209. BAIL_ON_FAILURE(hr);
  210. }
  211. cTmpAttrs = 0;
  212. for(i = 0; i < _cAttrs; i++)
  213. {
  214. if( _wcsicmp(L"ADsPath", _ppszAttrs[i]) )
  215. {
  216. ppszTmpAttrs[cTmpAttrs] = _ppszAttrs[i];
  217. cTmpAttrs++;
  218. }
  219. }
  220. // Request attributes only if there is some attribute other than ADsPath
  221. if(cTmpAttrs)
  222. hr = pDSAttrMgmt->EnumAttributes(
  223. ppszTmpAttrs,
  224. cTmpAttrs,
  225. &pAttrDefinition,
  226. &cAttrsReturned
  227. );
  228. else
  229. {
  230. cAttrsReturned = 0;
  231. pAttrDefinition = NULL;
  232. }
  233. if(ppszTmpAttrs != NULL)
  234. FreeADsMem(ppszTmpAttrs);
  235. pDSAttrMgmt->Release();
  236. BAIL_ON_FAILURE( hr );
  237. //fill up the Bookmark column
  238. // bookmark name is empty string
  239. pInfo[0].pwszName = NULL;
  240. pInfo[0].columnid.eKind = DBKIND_GUID_PROPID;
  241. pInfo[0].columnid.uGuid.guid = DBCOL_SPECIALCOL;
  242. pInfo[0].columnid.uName.ulPropid = 2; // Value from note about
  243. // bookmarks in spec.
  244. pInfo[0].pTypeInfo = NULL;
  245. pInfo[0].iOrdinal = 0;
  246. pInfo[0].ulColumnSize = sizeof(ULONG);
  247. pInfo[0].wType = DBTYPE_UI4;
  248. pInfo[0].bPrecision = 10; // Precision for I4.
  249. pInfo[0].bScale = (BYTE) ~ 0;
  250. pInfo[0].dwFlags = DBCOLUMNFLAGS_ISBOOKMARK
  251. | DBCOLUMNFLAGS_ISFIXEDLENGTH;
  252. //
  253. // Fill up the columnsinfo by getting the attribute types
  254. //
  255. pos = 0;
  256. for(i=0; i < _cAttrs; i++) {
  257. wcscpy(&pStringBuffer[pos], _ppszAttrs[i]);
  258. pInfo[i+1].pwszName= &pStringBuffer[pos];
  259. //
  260. // Get the type and size of the attribute
  261. //
  262. // Because of a Temporary bug in TmpTable, ~0 (specifying variable
  263. // size) is replaced by 256. This does not actually put a memory
  264. // restriction on the column size, but done merely to avoid the bug.
  265. //
  266. if( _wcsicmp(_ppszAttrs[i], L"ADsPath") == 0) {
  267. pInfo[i+1].wType = DBTYPE_WSTR|DBTYPE_BYREF;
  268. // pInfo[i+1].ulColumnSize = (ULONG) ~0;
  269. pInfo[i+1].ulColumnSize = (ULONG)256;
  270. }
  271. else {
  272. hr = GetDBType(
  273. pAttrDefinition,
  274. cAttrsReturned,
  275. _ppszAttrs[i],
  276. &pInfo[i+1].wType,
  277. &pInfo[i+1].ulColumnSize
  278. );
  279. if( FAILED(hr) )
  280. BAIL_ON_FAILURE( hr=E_FAIL );
  281. }
  282. wType = pInfo[i+1].wType & ~DBTYPE_BYREF;
  283. // any change made to setting dwFlags below should also be made in
  284. // GetRestrictedColumnInfo in row.cxx, for consistency
  285. if( (wType == DBTYPE_STR) ||
  286. (wType == DBTYPE_WSTR) ||
  287. (wType == DBTYPE_BYTES) )
  288. pInfo[i+1].dwFlags = DBCOLUMNFLAGS_ISNULLABLE;
  289. else {
  290. // Temporary check
  291. // pInfo[i+1].dwFlags = (0);
  292. pInfo[i+1].dwFlags = DBCOLUMNFLAGS_ISNULLABLE |
  293. DBCOLUMNFLAGS_ISFIXEDLENGTH;
  294. }
  295. pInfo[i+1].pTypeInfo = NULL;
  296. pInfo[i+1].iOrdinal = i+1;
  297. pInfo[i+1].bPrecision = SetPrecision(wType);
  298. pInfo[i+1].bScale = (UCHAR) ~0;
  299. pInfo[i+1].columnid.eKind=DBKIND_NAME;
  300. pInfo[i+1].columnid.uGuid.guid=GUID_NULL;
  301. pInfo[i+1].columnid.uName.pwszName=pInfo[i+1].pwszName;
  302. pos += (wcslen(_ppszAttrs[i]) + 1);
  303. }
  304. if( ppfMultiValued ) {
  305. //
  306. // Filling in MultiValue array
  307. //
  308. BOOL * pfMultiValuedTemp;
  309. pfMultiValuedTemp= (BOOL *) AllocADsMem(sizeof(BOOL) * (_cAttrs+1));
  310. if( !(pfMultiValuedTemp) ) {
  311. hr=E_OUTOFMEMORY;
  312. BAIL_ON_FAILURE(hr);
  313. }
  314. pfMultiValuedTemp[0] = FALSE; // First one is bookmark which is always FALSE
  315. for(ULONG j=0; j < _cAttrs; j++) {
  316. for(ULONG k=0; k < cAttrsReturned; k++) {
  317. if( !_wcsicmp(_ppszAttrs[j], pAttrDefinition[k].pszAttrName) )
  318. break;
  319. }
  320. if( (k != cAttrsReturned) &&
  321. (pAttrDefinition[k].fMultiValued &&
  322. IsAutomatable(g_MapADsTypeToVarType[pAttrDefinition[k].dwADsType]))) {
  323. pfMultiValuedTemp[j+1] = TRUE;
  324. }
  325. else {
  326. pfMultiValuedTemp[j+1] = FALSE;
  327. }
  328. }
  329. *ppfMultiValued = pfMultiValuedTemp;
  330. }
  331. if( pAttrDefinition ) {
  332. FreeADsMem(pAttrDefinition);
  333. }
  334. *pcColumns = _cAttrs + 1;
  335. *prgInfo = pInfo;
  336. *ppStringBuffer = pStringBuffer;
  337. RRETURN( S_OK );
  338. error:
  339. if( pInfo != NULL )
  340. _pIMalloc->Free(pInfo);
  341. if( pStringBuffer != NULL )
  342. _pIMalloc->Free(pStringBuffer);
  343. if( pAttrDefinition ) {
  344. FreeADsMem(pAttrDefinition);
  345. }
  346. RRETURN( hr );
  347. }
  348. //+---------------------------------------------------------------------------
  349. //
  350. // Function: CCommandObject::GetColumnInfo
  351. //
  352. // Synopsis:
  353. //
  354. // Arguments:
  355. //
  356. // Returns:
  357. //
  358. //
  359. // Modifies:
  360. //
  361. // History: 10-10-96 ShankSh Created.
  362. //
  363. //----------------------------------------------------------------------------
  364. STDMETHODIMP
  365. CCommandObject::GetColumnInfo(
  366. DBORDINAL * pcColumns,
  367. DBCOLUMNINFO ** prgInfo,
  368. OLECHAR ** ppStringBuffer
  369. )
  370. {
  371. if( pcColumns )
  372. *pcColumns = 0;
  373. if( prgInfo )
  374. *prgInfo = NULL;
  375. if( ppStringBuffer )
  376. *ppStringBuffer = NULL;
  377. if( !pcColumns || !prgInfo || !ppStringBuffer )
  378. RRETURN( E_INVALIDARG );
  379. if( !IsCommandSet() )
  380. RRETURN( DB_E_NOCOMMAND );
  381. if( !IsCommandPrepared() )
  382. RRETURN( DB_E_NOTPREPARED );
  383. RRETURN( GetColumnInfo2(
  384. pcColumns,
  385. prgInfo,
  386. ppStringBuffer,
  387. NULL
  388. ) );
  389. }
  390. //+---------------------------------------------------------------------------
  391. //
  392. // Function: CCommandObject::MapColumnIDs
  393. //
  394. // Synopsis:
  395. //
  396. // Arguments:
  397. //
  398. // Returns:
  399. //
  400. //
  401. // Modifies:
  402. //
  403. // History: 08-28-96 ShankSh Created.
  404. //
  405. //----------------------------------------------------------------------------
  406. STDMETHODIMP
  407. CCommandObject::MapColumnIDs(
  408. DBORDINAL cColumnIDs,
  409. const DBID rgColumnIDs[],
  410. DBORDINAL rgColumns[]
  411. )
  412. {
  413. DBORDINAL cValidCols = 0;
  414. //
  415. // No Column IDs are set when GetColumnInfo returns ColumnsInfo structure.
  416. // Hence, any value of ID will not match with any column
  417. //
  418. DBORDINAL iCol;
  419. if( cColumnIDs == 0 )
  420. RRETURN( S_OK );
  421. // Spec-defined checks.
  422. // Note that this guarantees we can access rgColumnIDs[] in loop below.
  423. // (Because we'll just fall through.)
  424. if ( cColumnIDs && (!rgColumnIDs || !rgColumns) )
  425. RRETURN( E_INVALIDARG );
  426. if( !IsCommandSet() )
  427. RRETURN( DB_E_NOCOMMAND );
  428. if( !IsCommandPrepared() )
  429. RRETURN( DB_E_NOTPREPARED );
  430. //
  431. // Set the columns ordinals to invalid values
  432. //
  433. for(iCol=0; iCol < cColumnIDs; iCol++) {
  434. // Initialize
  435. rgColumns[iCol] = DB_INVALIDCOLUMN;
  436. //
  437. // The columnid with the Bookmark ID
  438. //
  439. if( rgColumnIDs[iCol].eKind == DBKIND_GUID_PROPID &&
  440. rgColumnIDs[iCol].uGuid.guid == DBCOL_SPECIALCOL &&
  441. rgColumnIDs[iCol].uName.ulPropid == 2 ) {
  442. rgColumns[iCol] = 0;
  443. cValidCols++;
  444. continue;
  445. }
  446. //
  447. // The columnid with the Column Name
  448. //
  449. if( rgColumnIDs[iCol].eKind == DBKIND_NAME &&
  450. rgColumnIDs[iCol].uName.pwszName ) {
  451. //
  452. // Find the name in the list of Attributes
  453. //
  454. for (ULONG iOrdinal=0; iOrdinal < _cAttrs; iOrdinal++) {
  455. if( !_wcsicmp(_ppszAttrs[iOrdinal],
  456. rgColumnIDs[iCol].uName.pwszName) ) {
  457. rgColumns[iCol] = iOrdinal+1;
  458. cValidCols++;
  459. break;
  460. }
  461. }
  462. }
  463. }
  464. if( cValidCols == 0 )
  465. RRETURN( DB_E_ERRORSOCCURRED );
  466. else if( cValidCols < cColumnIDs )
  467. RRETURN( DB_S_ERRORSOCCURRED );
  468. else
  469. RRETURN( S_OK );
  470. }
  471. //+---------------------------------------------------------------------------
  472. //
  473. // Function: CCommandObject::Cancel
  474. //
  475. // Synopsis:
  476. //
  477. // Arguments:
  478. //
  479. // Returns:
  480. //
  481. // Modifies:
  482. //
  483. // History: 08-28-96 ShankSh Created.
  484. //
  485. //----------------------------------------------------------------------------
  486. STDMETHODIMP
  487. CCommandObject::Cancel(
  488. void
  489. )
  490. {
  491. //
  492. // Need to protect _dwStatus for mutual exclusion when we support
  493. // multiple threads acting on the same Command object
  494. //
  495. _dwStatus |= CMD_EXEC_CANCELLED;
  496. return S_OK;
  497. }
  498. //+---------------------------------------------------------------------------
  499. //
  500. // Function: CCommandObject::Execute
  501. //
  502. // Synopsis:
  503. //
  504. //
  505. // Arguments:
  506. //
  507. // Returns:
  508. //
  509. // Modifies:
  510. //
  511. // History: 08-28-96 ShankSh Created.
  512. //
  513. //----------------------------------------------------------------------------
  514. STDMETHODIMP
  515. CCommandObject::Execute(
  516. IUnknown * pUnkOuter,
  517. REFIID riid,
  518. DBPARAMS * pParams,
  519. DBROWCOUNT *pcRowsAffected,
  520. IUnknown ** ppRowset
  521. )
  522. {
  523. HRESULT hr;
  524. DWORD dwFlags = 0;
  525. ULONG cAccessors = 0;
  526. HACCESSOR *prgAccessors = NULL;
  527. BOOL *pbMultiValued = NULL;
  528. CRowProvider *pRowProvider = NULL;
  529. DBORDINAL cColumns = 0;
  530. DBCOLUMNINFO *prgInfo = NULL;
  531. WCHAR *pStringBuffer = NULL;
  532. ULONG cPropertySets = 0;
  533. DBPROPSET *prgPropertySets = NULL;
  534. ULONG i, j;
  535. ADsAssert(_pIMalloc != NULL);
  536. ADsAssert(_pAccessor != NULL);
  537. ADsAssert(_pCSession != NULL);
  538. if( ppRowset )
  539. *ppRowset = NULL;
  540. if( pcRowsAffected )
  541. *pcRowsAffected= -1;
  542. //
  543. // If the IID asked for is IID_NULL, then we can expect
  544. // that this is a non-row returning statement
  545. //
  546. if( riid == IID_NULL )
  547. dwFlags |= EXECUTE_NOROWSET;
  548. //
  549. // Check Arguments - Only check on row returning statements
  550. //
  551. if( !(dwFlags & EXECUTE_NOROWSET) &&
  552. (ppRowset == NULL) )
  553. RRETURN( E_INVALIDARG );
  554. //
  555. // Only 1 ParamSet if ppRowset is non-null
  556. //
  557. if( pParams &&
  558. (pParams->cParamSets > 1) &&
  559. ppRowset )
  560. RRETURN( E_INVALIDARG );
  561. //
  562. // Check that a command has been set
  563. //
  564. if( !IsCommandSet() )
  565. RRETURN( DB_E_NOCOMMAND );
  566. if( pUnkOuter )
  567. RRETURN( DB_E_NOAGGREGATION );
  568. //
  569. // Prepare the Command if not already done
  570. //
  571. if( !IsCommandPrepared() ) {
  572. hr = PrepareHelper();
  573. BAIL_ON_FAILURE( hr );
  574. }
  575. //
  576. // Check for a non row returning statement
  577. //
  578. if( dwFlags & EXECUTE_NOROWSET )
  579. RRETURN( S_OK );
  580. //
  581. // Get ColumnsInfo based on the list of attributes that we want to be
  582. // returned
  583. //
  584. hr = GetColumnInfo2(
  585. &cColumns,
  586. &prgInfo,
  587. &pStringBuffer,
  588. &pbMultiValued
  589. );
  590. BAIL_ON_FAILURE( hr );
  591. //
  592. // Commit the properties in the Command Object as the preferences to the
  593. // search
  594. //
  595. hr = SetSearchPrefs();
  596. BAIL_ON_FAILURE( hr );
  597. //
  598. // Create RowProvider object to pass to rowset code
  599. //
  600. _pDSSearch->AddRef();
  601. hr= CRowProvider::CreateRowProvider(
  602. _pDSSearch,
  603. _pszSearchFilter,
  604. _ppszAttrs,
  605. _cAttrs,
  606. cColumns,
  607. prgInfo,
  608. pStringBuffer,
  609. IID_IRowProvider,
  610. pbMultiValued,
  611. _fADSPathPresent,
  612. NULL,
  613. (void **) &pRowProvider);
  614. BAIL_ON_FAILURE( hr );
  615. pbMultiValued = NULL; // RowProvider responsible for deallocation
  616. //
  617. // We no longer need the ColumnsInfo; Release it
  618. //
  619. if (prgInfo)
  620. {
  621. _pIMalloc->Free(prgInfo);
  622. prgInfo = NULL;
  623. }
  624. if (pStringBuffer)
  625. {
  626. _pIMalloc->Free(pStringBuffer);
  627. pStringBuffer = NULL;
  628. }
  629. if( _pAccessor &&
  630. _pAccessor->_pextbuffer ) {
  631. cAccessors = _pAccessor->_pextbuffer->GetLastHandleCount();
  632. if( cAccessors > 0 ) {
  633. prgAccessors = (HACCESSOR *) AllocADsMem(
  634. sizeof(HACCESSOR) * cAccessors
  635. );
  636. if( !prgAccessors )
  637. cAccessors = 0;
  638. else
  639. for(ULONG i=0; i<cAccessors; i++)
  640. prgAccessors[i] = i+1;
  641. }
  642. }
  643. hr = GetProperties(0, NULL, &cPropertySets, &prgPropertySets);
  644. BAIL_ON_FAILURE( hr );
  645. hr= CRowset::CreateRowset(
  646. pRowProvider,
  647. (LPUNKNOWN)(IAccessor FAR *)this ,
  648. NULL,
  649. this,
  650. cPropertySets,
  651. prgPropertySets,
  652. cAccessors,
  653. prgAccessors,
  654. _fADSPathPresent,
  655. _fAllAttrs,
  656. riid,
  657. ppRowset
  658. );
  659. if (prgAccessors)
  660. {
  661. FreeADsMem(prgAccessors);
  662. prgAccessors = NULL;
  663. }
  664. BAIL_ON_FAILURE( hr );
  665. error:
  666. if (FAILED(hr))
  667. {
  668. //
  669. // Remove the Prepare flag,
  670. //
  671. _dwStatus &= ~(CMD_PREPARED);
  672. }
  673. //
  674. // Free the memory
  675. //
  676. if( pRowProvider )
  677. pRowProvider->Release();
  678. if( prgInfo )
  679. _pIMalloc->Free(prgInfo);
  680. if( pStringBuffer )
  681. _pIMalloc->Free(pStringBuffer);
  682. if( prgAccessors )
  683. FreeADsMem(prgAccessors);
  684. if( pbMultiValued ) {
  685. FreeADsMem(pbMultiValued);
  686. }
  687. // Free memory allocated by GetProperties
  688. for (i = 0; i < cPropertySets; i++)
  689. {
  690. for (j = 0; j < prgPropertySets[i].cProperties; j++)
  691. {
  692. DBPROP *pProp = &(prgPropertySets[i].rgProperties[j]);
  693. ADsAssert(pProp);
  694. // We should free the DBID in pProp, but we know that
  695. // GetProperties always returns DB_NULLID and FreeDBID doesn't
  696. // handle DB_NULLID. So, DBID is not freed here.
  697. VariantClear(&pProp->vValue);
  698. }
  699. _pIMalloc->Free(prgPropertySets[i].rgProperties);
  700. }
  701. _pIMalloc->Free(prgPropertySets);
  702. RRETURN( hr );
  703. }
  704. //+---------------------------------------------------------------------------
  705. //
  706. // Function: CCommandObject::GetDBSession
  707. //
  708. // Synopsis:
  709. //
  710. //
  711. // Arguments:
  712. //
  713. // Returns:
  714. //
  715. // Modifies:
  716. //
  717. // History: 08-28-96 ShankSh Created.
  718. //
  719. //----------------------------------------------------------------------------
  720. STDMETHODIMP
  721. CCommandObject::GetDBSession(
  722. REFIID riid,
  723. IUnknown ** ppSession
  724. )
  725. {
  726. HRESULT hr;
  727. //
  728. // Asserts
  729. //
  730. ADsAssert(_pCSession);
  731. //
  732. // Check Arguments
  733. //
  734. if( ppSession == NULL )
  735. RRETURN( E_INVALIDARG );
  736. //
  737. // Query for the interface on the session object. If failure,
  738. // return the error from QueryInterface.
  739. //
  740. RRETURN( (_pCSession)->QueryInterface(riid, (VOID**)ppSession) );
  741. }
  742. //+---------------------------------------------------------------------------
  743. //
  744. // Function: CCommandObject::GetProperties
  745. //
  746. // Synopsis:
  747. //
  748. //
  749. // Arguments:
  750. //
  751. // Returns:
  752. //
  753. // Modifies:
  754. //
  755. // History: 08-28-96 ShankSh Created.
  756. //
  757. //----------------------------------------------------------------------------
  758. STDMETHODIMP
  759. CCommandObject::GetProperties(
  760. const ULONG cPropIDSets,
  761. const DBPROPIDSET rgPropIDSets[],
  762. ULONG * pcPropSets,
  763. DBPROPSET ** pprgPropSets
  764. )
  765. {
  766. //
  767. // Asserts
  768. //
  769. ADsAssert(_pUtilProp);
  770. //
  771. // Check in-params and NULL out-params in case of error
  772. //
  773. HRESULT hr = _pUtilProp->GetPropertiesArgChk(
  774. cPropIDSets,
  775. rgPropIDSets,
  776. pcPropSets,
  777. pprgPropSets,
  778. PROPSET_COMMAND);
  779. if( FAILED(hr) )
  780. RRETURN( hr );
  781. //
  782. // Just pass this call on to the utility object that manages our properties
  783. //
  784. RRETURN( _pUtilProp->GetProperties(
  785. cPropIDSets,
  786. rgPropIDSets,
  787. pcPropSets,
  788. pprgPropSets,
  789. PROPSET_COMMAND) );
  790. }
  791. //+---------------------------------------------------------------------------
  792. //
  793. // Function: CCommandObject::SetProperties
  794. //
  795. // Synopsis:
  796. //
  797. //
  798. // Arguments:
  799. //
  800. // Returns:
  801. //
  802. // Modifies:
  803. //
  804. // History: 08-28-96 ShankSh Created.
  805. //
  806. //----------------------------------------------------------------------------
  807. STDMETHODIMP
  808. CCommandObject::SetProperties(
  809. ULONG cPropertySets,
  810. DBPROPSET rgPropertySets[]
  811. )
  812. {
  813. //
  814. // Asserts
  815. //
  816. ADsAssert(_pUtilProp);
  817. // Don't allow properties to be set if we've got a rowset open
  818. if( IsRowsetOpen() )
  819. RRETURN( DB_E_OBJECTOPEN );
  820. //
  821. // Just pass this call on to the utility object that manages our properties
  822. //
  823. RRETURN( _pUtilProp->SetProperties(
  824. cPropertySets,
  825. rgPropertySets,
  826. PROPSET_COMMAND) );
  827. }
  828. //+---------------------------------------------------------------------------
  829. //
  830. // Function: CCommandObject::GetCommandText
  831. //
  832. // Synopsis:
  833. //
  834. //
  835. // Arguments:
  836. //
  837. // Returns:
  838. //
  839. // Modifies:
  840. //
  841. // History: 08-28-96 ShankSh Created.
  842. //
  843. //----------------------------------------------------------------------------
  844. STDMETHODIMP
  845. CCommandObject::GetCommandText(
  846. GUID * pguidDialect,
  847. LPOLESTR * ppwszCommand
  848. )
  849. {
  850. HRESULT hr = S_OK;
  851. ADsAssert(_pIMalloc!= NULL);
  852. //
  853. // Check Function Arguments
  854. //
  855. if( ppwszCommand == NULL ) {
  856. hr = E_INVALIDARG;
  857. goto error;
  858. }
  859. *ppwszCommand = NULL;
  860. //
  861. // If the command has not been set, make sure the buffer
  862. // contains an empty stringt to return to the consumer
  863. //
  864. if( !IsCommandSet() ) {
  865. hr = DB_E_NOCOMMAND;
  866. goto error;
  867. }
  868. //
  869. // Allocate memory for the string we're going to return to the caller
  870. //
  871. *ppwszCommand = (LPWSTR)_pIMalloc->Alloc((wcslen(_pszCommandText)+1) * sizeof(WCHAR));
  872. if( !*ppwszCommand ) {
  873. hr = E_OUTOFMEMORY;
  874. goto error;
  875. }
  876. //
  877. // Copy our saved text into the newly allocated string
  878. //
  879. wcscpy(*ppwszCommand, _pszCommandText);
  880. //
  881. // If the text we're giving back is a different dialect than was
  882. // requested, let the caller know what dialect the text is in
  883. //
  884. if( pguidDialect != NULL && *pguidDialect != _guidCmdDialect)
  885. {
  886. hr = DB_S_DIALECTIGNORED;
  887. *pguidDialect = _guidCmdDialect;
  888. }
  889. error:
  890. if( FAILED(hr) ) {
  891. if( pguidDialect )
  892. memset(pguidDialect, 0, sizeof(GUID));
  893. }
  894. return hr;
  895. }
  896. //+---------------------------------------------------------------------------
  897. //
  898. // Function: CCommandObject::SetCommandText
  899. //
  900. // Synopsis:
  901. //
  902. //
  903. // Arguments:
  904. //
  905. // Returns:
  906. //
  907. // Modifies:
  908. //
  909. // History: 08-28-96 ShankSh Created.
  910. //
  911. //----------------------------------------------------------------------------
  912. STDMETHODIMP
  913. CCommandObject::SetCommandText(
  914. REFGUID rguidDialect,
  915. LPCOLESTR pszCommand
  916. )
  917. {
  918. // Don't allow text to be set if we've got a rowset open
  919. if( IsRowsetOpen() )
  920. RRETURN( DB_E_OBJECTOPEN );
  921. // Check Dialect
  922. if( rguidDialect != DBGUID_LDAPDialect &&
  923. rguidDialect != DBGUID_DBSQL &&
  924. rguidDialect != DBGUID_SQL &&
  925. rguidDialect != DBGUID_DEFAULT )
  926. RRETURN( DB_E_DIALECTNOTSUPPORTED );
  927. //
  928. // If a CommandText is set with a Null or an empty string, it effectively
  929. // unsets the CommandText to a null string
  930. //
  931. if( (pszCommand == NULL) ||
  932. (*pszCommand == L'\0') ) {
  933. if( _dwStatus & CMD_TEXT_SET )
  934. FreeADsStr(_pszCommandText);
  935. _pszCommandText = NULL;
  936. _dwStatus &= ~(CMD_TEXT_SET | CMD_PREPARED);
  937. RRETURN( S_OK );
  938. }
  939. //
  940. // Set the CommandText
  941. //
  942. LPWSTR pszSQLCmd = (LPWSTR)AllocADsMem((wcslen(pszCommand)+1) * sizeof(WCHAR));
  943. if( !pszSQLCmd )
  944. RRETURN( E_OUTOFMEMORY );
  945. //
  946. // Free the old memory, and set new text
  947. //
  948. if( _dwStatus & CMD_TEXT_SET )
  949. FreeADsMem(_pszCommandText);
  950. _pszCommandText = pszSQLCmd;
  951. wcscpy(_pszCommandText, pszCommand);
  952. //
  953. // Reset adspath present flag.
  954. //
  955. _fADSPathPresent = FALSE;
  956. //
  957. // Set status flag that we have set text
  958. //
  959. _dwStatus |= CMD_TEXT_SET;
  960. _dwStatus &= ~CMD_PREPARED;
  961. //
  962. // Remember the dialect that was passed in
  963. //
  964. _guidCmdDialect = rguidDialect;
  965. RRETURN( S_OK );
  966. }
  967. //+---------------------------------------------------------------------------
  968. //
  969. // Function: CCommandObject::CanConvert
  970. //
  971. // Synopsis:
  972. //
  973. //
  974. // Arguments:
  975. //
  976. // Returns:
  977. //
  978. // Modifies:
  979. //
  980. // History: 08-28-96 ShankSh Created.
  981. //
  982. //----------------------------------------------------------------------------
  983. STDMETHODIMP
  984. CCommandObject::CanConvert(
  985. DBTYPE wFromType,
  986. DBTYPE wToType,
  987. DBCONVERTFLAGS dwConvertFlags
  988. )
  989. {
  990. RRETURN( CanConvertHelper(
  991. wFromType,
  992. wToType,
  993. dwConvertFlags) );
  994. }
  995. //+---------------------------------------------------------------------------
  996. //
  997. // Function: SplitCommandText
  998. //
  999. // Synopsis:
  1000. //
  1001. //
  1002. // Arguments:
  1003. //
  1004. //
  1005. //
  1006. //
  1007. //
  1008. //
  1009. // Returns: HRESULT
  1010. // S_OK NO ERROR
  1011. // E_ADS_BAD_PARAMETER bad parameter
  1012. //
  1013. // Modifies:
  1014. //
  1015. // History: 08-15-96 ShankSh Created.
  1016. // 11-21-96 Felix Wong modified to get only bind and attr
  1017. //----------------------------------------------------------------------------
  1018. HRESULT
  1019. CCommandObject::SplitCommandText(
  1020. LPWSTR pszParsedCmd
  1021. )
  1022. {
  1023. LPWSTR pszAttrs = NULL;
  1024. LPWSTR pszFirstAttr = NULL;
  1025. LPWSTR pszCurrentAttr = NULL;
  1026. LPWSTR pszSearchScope = NULL;
  1027. LPWSTR pszTemp = NULL;
  1028. HRESULT hr;
  1029. LPWSTR ptr;
  1030. // Command Text is the concatenation of three components separated by
  1031. // semicolons
  1032. //
  1033. // 1. ADsPathName of the object of the root of the search which contains
  1034. // the host name and the context enclosed by '<' and '>'
  1035. // 2. The LDAP search string
  1036. // 3. The list of names of the attributes to be returned separated by
  1037. // commas
  1038. //
  1039. // If the attributes have any specifiers like Range (for eg.,
  1040. // objectclass;Range=0-1, we need to do some special processing to include
  1041. // it in the list of attributes
  1042. //
  1043. // The fourth component is optional
  1044. //
  1045. // 4. The scope of the search: Either "Base", "Onelevel", "SubTree"
  1046. // (case insensitve)
  1047. //
  1048. // Search defaults to Subtree
  1049. //
  1050. // White spaces are insignificant
  1051. _searchScope = ADS_SCOPE_SUBTREE;
  1052. _pszADsContext = NULL;
  1053. _pszSearchFilter = NULL;
  1054. if( _ppszAttrs ) {
  1055. FreeADsMem(_ppszAttrs);
  1056. _ppszAttrs = NULL;
  1057. }
  1058. if( _pszCommandTextCp ) {
  1059. FreeADsStr(_pszCommandTextCp);
  1060. _pszCommandTextCp = NULL;
  1061. }
  1062. _pszCommandTextCp = AllocADsStr(pszParsedCmd);
  1063. if( !_pszCommandTextCp)
  1064. BAIL_ON_FAILURE( hr=E_OUTOFMEMORY );
  1065. _pszADsContext = RemoveWhiteSpaces(_pszCommandTextCp);
  1066. if( _pszADsContext[0] != L'<' ) {
  1067. BAIL_ON_FAILURE( hr=DB_E_ERRORSINCOMMAND);
  1068. }
  1069. _pszADsContext++;
  1070. ptr = _pszADsContext;
  1071. hr = SeekPastADsPath(ptr, &ptr);
  1072. BAIL_ON_FAILURE( hr );
  1073. if( *ptr != L'>' || *(ptr+1) != L';') {
  1074. BAIL_ON_FAILURE( hr=DB_E_ERRORSINCOMMAND);
  1075. }
  1076. *ptr = L'\0';
  1077. //
  1078. // If the command text does not contain a filter, set it to NULL
  1079. //
  1080. if (*(ptr + 2) == L';') {
  1081. _pszSearchFilter = NULL;
  1082. ptr+=2;
  1083. }
  1084. else {
  1085. _pszSearchFilter = ptr + 2;
  1086. _pszSearchFilter = RemoveWhiteSpaces(_pszSearchFilter);
  1087. hr = SeekPastSearchFilter(_pszSearchFilter, &ptr);
  1088. BAIL_ON_FAILURE( hr );
  1089. }
  1090. if (*ptr != L';') {
  1091. BAIL_ON_FAILURE( hr=DB_E_ERRORSINCOMMAND);
  1092. }
  1093. *ptr = L'\0';
  1094. ptr++;
  1095. //
  1096. // The next component is the list of attributes followed by (optionally)
  1097. // the scope of the search
  1098. //
  1099. // Since the attributes themselves can contain a ';' because of some
  1100. // attribute specifiers, we need to make sure which ';' we are looking at.
  1101. pszAttrs = ptr;
  1102. while ((pszTemp = wcschr(ptr, ';')) != NULL)
  1103. if ( !_wcsicmp(pszTemp+1, L"Base") ||
  1104. !_wcsicmp(pszTemp+1, L"Onelevel") ||
  1105. !_wcsicmp(pszTemp+1, L"Subtree") ) {
  1106. //
  1107. // we have hit the end of the attribute list
  1108. //
  1109. *pszTemp = L'\0';
  1110. pszSearchScope = pszTemp+1;
  1111. break;
  1112. }
  1113. else {
  1114. ptr = pszTemp + 1;
  1115. }
  1116. if( pszSearchScope ) {
  1117. if(!_wcsicmp(pszSearchScope, L"Base"))
  1118. _searchScope = ADS_SCOPE_BASE;
  1119. else if(!_wcsicmp(pszSearchScope, L"Onelevel"))
  1120. _searchScope = ADS_SCOPE_ONELEVEL;
  1121. else if(!_wcsicmp(pszSearchScope, L"SubTree"))
  1122. _searchScope = ADS_SCOPE_SUBTREE;
  1123. else
  1124. BAIL_ON_FAILURE( hr=DB_E_ERRORSINCOMMAND);
  1125. //
  1126. // set the search preference property
  1127. //
  1128. DBPROPSET rgCmdPropSet[1];
  1129. DBPROP rgCmdProp[1];
  1130. rgCmdPropSet[0].rgProperties = rgCmdProp;
  1131. rgCmdPropSet[0].cProperties = 1;
  1132. rgCmdPropSet[0].guidPropertySet = DBPROPSET_ADSISEARCH;
  1133. rgCmdProp[0].dwPropertyID = ADS_SEARCHPREF_SEARCH_SCOPE;
  1134. rgCmdProp[0].dwOptions = DBPROPOPTIONS_REQUIRED;
  1135. rgCmdProp[0].vValue.vt = VT_I4;
  1136. V_I4(&rgCmdProp[0].vValue) = _searchScope;
  1137. hr = SetProperties(
  1138. 1,
  1139. rgCmdPropSet);
  1140. BAIL_ON_FAILURE( hr );
  1141. }
  1142. pszCurrentAttr = pszFirstAttr = wcstok(pszAttrs, L",");
  1143. for (_cAttrs=0; pszCurrentAttr != NULL; _cAttrs++ ) {
  1144. pszCurrentAttr = wcstok(NULL, L",");
  1145. }
  1146. if( _cAttrs == 0 ) {
  1147. hr=DB_E_ERRORSINCOMMAND;
  1148. goto error;
  1149. }
  1150. pszFirstAttr = RemoveWhiteSpaces(pszFirstAttr);
  1151. if( _cAttrs == 1 && !wcscmp( pszFirstAttr, L"*")) {
  1152. // _cAttrs=1; Just ADsPath and Class attribute is sent
  1153. _ppszAttrs = (LPWSTR *) AllocADsMem(sizeof(LPWSTR) * _cAttrs);
  1154. if( !_ppszAttrs )
  1155. BAIL_ON_FAILURE( hr=E_OUTOFMEMORY );
  1156. _ppszAttrs[0] = gpszADsPathAttr;
  1157. _fADSPathPresent = TRUE;
  1158. _fAllAttrs = TRUE;
  1159. }
  1160. else {
  1161. // Allocate memory for all the string pointers
  1162. _ppszAttrs = (LPWSTR *) AllocADsMem(sizeof(LPWSTR) * (_cAttrs+1));
  1163. if( !_ppszAttrs ) {
  1164. BAIL_ON_FAILURE( hr=E_OUTOFMEMORY );
  1165. }
  1166. pszCurrentAttr = pszFirstAttr;
  1167. // Remember if adspath and rdn are avaialble or not.
  1168. for (ULONG i=0 ; i < _cAttrs; i++) {
  1169. if( !_wcsicmp(L"ADsPath", pszCurrentAttr) )
  1170. _fADSPathPresent = TRUE;
  1171. _ppszAttrs[i] = pszCurrentAttr;
  1172. pszCurrentAttr += wcslen(pszCurrentAttr) + 1;
  1173. _ppszAttrs[i] = RemoveWhiteSpaces(_ppszAttrs[i]);
  1174. }
  1175. //
  1176. // If adspath is not in the list add it
  1177. //
  1178. if( _fADSPathPresent == FALSE )
  1179. _ppszAttrs[i] = L"ADsPath";
  1180. _fAllAttrs = FALSE; // not a SELECT * query
  1181. }
  1182. RRETURN( S_OK );
  1183. error:
  1184. _pszADsContext = NULL;
  1185. if( _ppszAttrs ) {
  1186. FreeADsMem(_ppszAttrs);
  1187. _ppszAttrs = NULL;
  1188. }
  1189. if( _pszCommandTextCp ) {
  1190. FreeADsStr(_pszCommandTextCp);
  1191. _pszCommandTextCp = NULL;
  1192. }
  1193. RRETURN( hr );
  1194. }
  1195. //
  1196. // Look up for the given attribute name in the list of ADS_ATTR_DEF structures.
  1197. // Convert the ADSTYPE to the appropriate OLE DB type.
  1198. //
  1199. STDMETHODIMP
  1200. CCommandObject::GetDBType(
  1201. PADS_ATTR_DEF pAttrDefinition,
  1202. DWORD dwNumAttrs,
  1203. LPWSTR pszAttrName,
  1204. WORD * pwType,
  1205. DBLENGTH * pulSize
  1206. )
  1207. {
  1208. HRESULT hr = S_OK;
  1209. ADsAssert(pwType && pulSize);
  1210. for (ULONG i=0; i < dwNumAttrs; i++) {
  1211. if( !_wcsicmp(pszAttrName, pAttrDefinition[i].pszAttrName) )
  1212. break;
  1213. }
  1214. if( i == dwNumAttrs )
  1215. BAIL_ON_FAILURE( hr=E_ADS_PROPERTY_NOT_FOUND );
  1216. if( pAttrDefinition[i].fMultiValued &&
  1217. IsAutomatable(g_MapADsTypeToVarType[pAttrDefinition[i].dwADsType])) {
  1218. //
  1219. // Can be represented it as a variant
  1220. //
  1221. *pwType = DBTYPE_VARIANT | DBTYPE_BYREF;
  1222. *pulSize = sizeof(VARIANT);
  1223. }
  1224. else if( (ULONG)pAttrDefinition[i].dwADsType >= g_cMapADsTypeToDBType ||
  1225. pAttrDefinition[i].dwADsType == ADSTYPE_INVALID ||
  1226. pAttrDefinition[i].dwADsType == ADSTYPE_PROV_SPECIFIC) {
  1227. BAIL_ON_FAILURE( hr=E_ADS_CANT_CONVERT_DATATYPE );
  1228. }
  1229. else {
  1230. *pwType = g_MapADsTypeToDBType[pAttrDefinition[i].dwADsType].wType;
  1231. *pulSize = g_MapADsTypeToDBType[pAttrDefinition[i].dwADsType].ulSize;
  1232. }
  1233. error:
  1234. RRETURN (hr);
  1235. }
  1236. STDMETHODIMP
  1237. CCommandObject::SetSearchPrefs(
  1238. void
  1239. )
  1240. {
  1241. PROPSET *pPropSet;
  1242. PADS_SEARCHPREF_INFO pSearchPref = NULL;
  1243. HRESULT hr = S_OK;
  1244. ULONG i;
  1245. //
  1246. // Asserts
  1247. //
  1248. ADsAssert(_pUtilProp);
  1249. ADsAssert(_pDSSearch);
  1250. pPropSet = _pUtilProp->GetPropSetFromGuid(DBPROPSET_ADSISEARCH);
  1251. if( !pPropSet || !pPropSet->cProperties )
  1252. RRETURN( S_OK );
  1253. pSearchPref = (PADS_SEARCHPREF_INFO) AllocADsMem(
  1254. pPropSet->cProperties *
  1255. sizeof(ADS_SEARCHPREF_INFO)
  1256. );
  1257. if( !pSearchPref )
  1258. BAIL_ON_FAILURE( hr=E_OUTOFMEMORY );
  1259. for (i=0; i<pPropSet->cProperties; i++) {
  1260. hr = _pUtilProp->GetSearchPrefInfo(
  1261. pPropSet->pUPropInfo[i].dwPropertyID,
  1262. &pSearchPref[i]
  1263. );
  1264. BAIL_ON_FAILURE( hr );
  1265. }
  1266. hr = _pDSSearch->SetSearchPreference(
  1267. pSearchPref,
  1268. pPropSet->cProperties
  1269. );
  1270. _pUtilProp->FreeSearchPrefInfo(pSearchPref, pPropSet->cProperties);
  1271. BAIL_ON_FAILURE( hr );
  1272. error:
  1273. if( pSearchPref )
  1274. FreeADsMem(pSearchPref);
  1275. RRETURN( hr );
  1276. }
  1277. //+---------------------------------------------------------------------------
  1278. //
  1279. // Function: CCommandObject::CCommandObject
  1280. //
  1281. // Synopsis: Constructor
  1282. //
  1283. // Arguments:
  1284. // pUnkOuter Outer Unkown Pointer
  1285. //
  1286. // Returns:
  1287. //
  1288. // Modifies:
  1289. //
  1290. // History: 08-28-96 ShankSh Created.
  1291. //
  1292. //----------------------------------------------------------------------------
  1293. CCommandObject::CCommandObject(
  1294. LPUNKNOWN pUnkOuter // Outer Unkown Pointer
  1295. )
  1296. {
  1297. // Initialize simple member vars
  1298. _pUnkOuter = pUnkOuter ? pUnkOuter : (IAccessor FAR *) this;
  1299. _dwStatus = 0L;
  1300. _cRowsetsOpen = 0;
  1301. _pAccessor = NULL;
  1302. _pUtilProp = NULL;
  1303. _pDSSearch = NULL;
  1304. _fADSPathPresent = FALSE;
  1305. _fAllAttrs = FALSE;
  1306. ENLIST_TRACKING(CCommandObject);
  1307. return;
  1308. }
  1309. //+---------------------------------------------------------------------------
  1310. //
  1311. // Function: CCommandObject::~CCommandObject
  1312. //
  1313. // Synopsis: Destructor
  1314. //
  1315. // Arguments:
  1316. //
  1317. // Returns:
  1318. //
  1319. // Modifies:
  1320. //
  1321. // History: 08-28-96 ShankSh Created.
  1322. //
  1323. //----------------------------------------------------------------------------
  1324. CCommandObject::~CCommandObject( )
  1325. {
  1326. if( _pCSession ) {
  1327. _pCSession->DecrementOpenCommands();
  1328. _pCSession->Release();
  1329. }
  1330. delete _pUtilProp;
  1331. if( _pszCommandText ) {
  1332. FreeADsMem(_pszCommandText);
  1333. }
  1334. if( _ppszAttrs ) {
  1335. FreeADsMem(_ppszAttrs);
  1336. }
  1337. if( _pszCommandTextCp ) {
  1338. FreeADsStr(_pszCommandTextCp);
  1339. }
  1340. if( _pAccessor )
  1341. delete _pAccessor;
  1342. if( _pIMalloc )
  1343. _pIMalloc->Release();
  1344. if( _pDSSearch ) {
  1345. _pDSSearch->Release();
  1346. }
  1347. }
  1348. //+---------------------------------------------------------------------------
  1349. //
  1350. // Function: CCommandObject::FInit
  1351. //
  1352. // Synopsis: Initialize the data source Object
  1353. //
  1354. // Arguments:
  1355. //
  1356. // Returns:
  1357. // Did the Initialization Succeed
  1358. // TRUE Initialization succeeded
  1359. // FALSE Initialization failed
  1360. //
  1361. // Modifies:
  1362. //
  1363. // History: 08-28-96 ShankSh Created.
  1364. //
  1365. //----------------------------------------------------------------------------
  1366. BOOL
  1367. CCommandObject::FInit(
  1368. CSessionObject * pSession,
  1369. CCredentials& Credentials
  1370. )
  1371. {
  1372. HRESULT hr;
  1373. //
  1374. // Asserts
  1375. //
  1376. ADsAssert(pSession);
  1377. ADsAssert(&Credentials);
  1378. _pCSession = pSession;
  1379. _pCSession->AddRef();
  1380. _pCSession->IncrementOpenCommands();
  1381. //
  1382. // Allocate properties management object
  1383. //
  1384. _pUtilProp = new CUtilProp();
  1385. if( !_pUtilProp )
  1386. return FALSE;
  1387. hr = _pUtilProp->FInit(&Credentials);
  1388. BAIL_ON_FAILURE(hr);
  1389. // IAccessor is always instantiated.
  1390. _pAccessor = new CImpIAccessor(this, _pUnkOuter);
  1391. if( _pAccessor == NULL || FAILED(_pAccessor->FInit()) )
  1392. return FALSE;
  1393. hr = CoGetMalloc(MEMCTX_TASK, &_pIMalloc);
  1394. if( FAILED(hr) )
  1395. return FALSE;
  1396. _Credentials = Credentials;
  1397. return TRUE;
  1398. error:
  1399. return FALSE;
  1400. }
  1401. //+---------------------------------------------------------------------------
  1402. //
  1403. // Function: CCommandObject::QueryInterface
  1404. //
  1405. // Synopsis: Returns a pointer to a specified interface. Callers use
  1406. // QueryInterface to determine which interfaces the called object
  1407. // supports.
  1408. //
  1409. // Arguments:
  1410. // riid Interface ID of the interface being queried for
  1411. // ppv Pointer to interface that was instantiated
  1412. //
  1413. // Returns:
  1414. // S_OK Interface is supported and ppvObject is set.
  1415. // E_NOINTERFACE Interface is not supported by the object
  1416. // E_INVALIDARG One or more arguments are invalid.
  1417. //
  1418. // Modifies:
  1419. //
  1420. // History: 08-28-96 ShankSh Created.
  1421. //
  1422. //----------------------------------------------------------------------------
  1423. STDMETHODIMP
  1424. CCommandObject::QueryInterface(REFIID iid, LPVOID FAR* ppv)
  1425. {
  1426. // Is the pointer bad?
  1427. if( ppv == NULL )
  1428. RRETURN( E_INVALIDARG );
  1429. if( IsEqualIID(iid, IID_IUnknown) ) {
  1430. *ppv = (IAccessor FAR *) this;
  1431. }
  1432. else if( IsEqualIID(iid, IID_IAccessor) ) {
  1433. *ppv = (IAccessor FAR *) this;
  1434. }
  1435. else if( IsEqualIID(iid, IID_IColumnsInfo) ) {
  1436. *ppv = (IColumnsInfo FAR *) this;
  1437. }
  1438. else if( IsEqualIID(iid, IID_ICommand) ) {
  1439. *ppv = (ICommand FAR *) this;
  1440. }
  1441. else if( IsEqualIID(iid, IID_ICommandProperties) ) {
  1442. *ppv = (ICommandProperties FAR *) this;
  1443. }
  1444. else if( IsEqualIID(iid, IID_ICommandText) ) {
  1445. *ppv = (ICommandText FAR *) this;
  1446. }
  1447. else if( IsEqualIID(iid, IID_IConvertType) ) {
  1448. *ppv = (IConvertType FAR *) this;
  1449. }
  1450. else if( IsEqualIID(iid, IID_ICommandPrepare) ) {
  1451. *ppv = (ICommandPrepare FAR *) this;
  1452. }
  1453. else {
  1454. *ppv = NULL;
  1455. return E_NOINTERFACE;
  1456. }
  1457. AddRef();
  1458. return S_OK;
  1459. }
  1460. BOOL
  1461. IsAutomatable(
  1462. DBTYPE dbType
  1463. )
  1464. {
  1465. if (dbType != DBTYPE_NULL) {
  1466. return TRUE;
  1467. }
  1468. else {
  1469. return FALSE;
  1470. }
  1471. }
  1472. HRESULT
  1473. CCommandObject::SeekPastADsPath(
  1474. IN LPWSTR pszIn,
  1475. OUT LPWSTR * ppszOut
  1476. )
  1477. {
  1478. BOOL fEscapeOn = FALSE, fQuotingOn = FALSE;
  1479. WCHAR ch = 0;
  1480. // No. of LParans '<' over RParans '>'
  1481. DWORD dwParanOffset = 1;
  1482. ADsAssert(pszIn);
  1483. ADsAssert(ppszOut);
  1484. while (1) {
  1485. ch = *pszIn;
  1486. if( ch == TEXT('\0') ) {
  1487. break;
  1488. }
  1489. if( fEscapeOn ) {
  1490. fEscapeOn = FALSE;
  1491. }
  1492. else if( fQuotingOn ) {
  1493. if( ch == TEXT('"') ) {
  1494. fQuotingOn = FALSE;
  1495. }
  1496. }
  1497. else if( ch == TEXT('\\') ) {
  1498. fEscapeOn = TRUE;
  1499. }
  1500. else if( ch == TEXT('"') ) {
  1501. fQuotingOn = TRUE;
  1502. }
  1503. else if( ch == L'<' ) {
  1504. dwParanOffset++;
  1505. }
  1506. else if( ch == L'>' ) {
  1507. if( --dwParanOffset == 0)
  1508. break;
  1509. }
  1510. pszIn++;
  1511. }
  1512. if( fEscapeOn || fQuotingOn || dwParanOffset != 0 ) {
  1513. RRETURN( DB_E_ERRORSINCOMMAND );
  1514. }
  1515. *ppszOut = pszIn;
  1516. RRETURN( S_OK );
  1517. }
  1518. HRESULT
  1519. CCommandObject::SeekPastSearchFilter(
  1520. IN LPWSTR pszIn,
  1521. OUT LPWSTR * ppszOut
  1522. )
  1523. {
  1524. BOOL fEscapeOn = FALSE, fQuotingOn = FALSE;
  1525. DWORD dwParanOffset = 0;
  1526. ADsAssert(pszIn);
  1527. if( *pszIn != L'(' ) {
  1528. RRETURN( DB_E_ERRORSINCOMMAND );
  1529. }
  1530. //
  1531. // No. of LParans over RParans
  1532. //
  1533. dwParanOffset = 1;
  1534. pszIn++;
  1535. while (*pszIn && (*pszIn != L')' || dwParanOffset != 1)) {
  1536. if( *pszIn == L'(' ) {
  1537. dwParanOffset++;
  1538. }
  1539. if( *pszIn == L')' ) {
  1540. dwParanOffset--;
  1541. }
  1542. pszIn++;
  1543. }
  1544. if( *pszIn != L')' ) {
  1545. RRETURN( DB_E_ERRORSINCOMMAND );
  1546. }
  1547. *ppszOut = pszIn + 1;
  1548. RRETURN( S_OK );
  1549. }
  1550. HRESULT
  1551. CCommandObject::Prepare(
  1552. ULONG cExpectedRuns
  1553. )
  1554. {
  1555. //
  1556. // If the command has not been set, make sure the buffer
  1557. // contains an empty stringt to return to the consumer
  1558. //
  1559. if( !IsCommandSet() )
  1560. RRETURN( DB_E_NOCOMMAND );
  1561. //
  1562. // Don't allow prepare if we've got a rowset open
  1563. //
  1564. if( IsRowsetOpen() )
  1565. RRETURN( DB_E_OBJECTOPEN );
  1566. //
  1567. // SQL dialect: Convert to LDAP and save
  1568. //
  1569. HRESULT hr = PrepareHelper();
  1570. //
  1571. // Fixup the HRESULT
  1572. //
  1573. if( hr == DB_E_NOTABLE )
  1574. hr = DB_E_ERRORSINCOMMAND;
  1575. BAIL_ON_FAILURE( hr );
  1576. //
  1577. // Set the Prepare state
  1578. //
  1579. _dwStatus |= CMD_PREPARED;
  1580. error:
  1581. RRETURN( hr );
  1582. }
  1583. HRESULT
  1584. CCommandObject::Unprepare()
  1585. {
  1586. //
  1587. // Don't allow unprepare if we've got a rowset open
  1588. //
  1589. if( IsRowsetOpen() )
  1590. RRETURN( DB_E_OBJECTOPEN );
  1591. //
  1592. // Reset the Prepare state
  1593. //
  1594. _dwStatus &= ~(CMD_PREPARED);
  1595. RRETURN( S_OK );
  1596. }
  1597. //+---------------------------------------------------------------------------
  1598. //
  1599. // Function: CCommandObject::PrepareHelper
  1600. //
  1601. // Synopsis:
  1602. //
  1603. //
  1604. // Arguments:
  1605. //
  1606. // Returns:
  1607. //
  1608. // Modifies:
  1609. //
  1610. // History: 08-28-96 ShankSh Created.
  1611. //
  1612. //----------------------------------------------------------------------------
  1613. STDMETHODIMP
  1614. CCommandObject::PrepareHelper(void)
  1615. {
  1616. LPWSTR pszOrderList = NULL;
  1617. LPWSTR pszSelect = NULL;
  1618. LPWSTR pszLocation = NULL;
  1619. LPWSTR pszLdapQuery = NULL;
  1620. LPWSTR pszParsedCmd = NULL;
  1621. //
  1622. // SQL dialect: Convert to LDAP and save
  1623. // If SQLParse Fails the function cleans up memory
  1624. //
  1625. HRESULT hr = SQLParse(
  1626. (const LPWSTR) _pszCommandText,
  1627. &pszLocation,
  1628. &pszLdapQuery,
  1629. &pszSelect,
  1630. &pszOrderList
  1631. );
  1632. if( FAILED(hr) && hr != E_ADS_INVALID_FILTER)
  1633. RRETURN( hr=DB_E_ERRORSINCOMMAND );
  1634. if (SUCCEEDED(hr))
  1635. {
  1636. //
  1637. // the ldap query is optional, it can be NULL. When it is NULL, it
  1638. // implies a * search.
  1639. //
  1640. DWORD dwLdapQuery = 0;
  1641. if (pszLdapQuery) {
  1642. dwLdapQuery = wcslen(pszLdapQuery);
  1643. }
  1644. pszParsedCmd =(LPWSTR) AllocADsMem((wcslen(pszLocation) +
  1645. dwLdapQuery+
  1646. wcslen(pszSelect) +
  1647. 5 + // 2 semicolons and 2 <
  1648. 1) * sizeof(WCHAR));
  1649. if( !pszParsedCmd ) {
  1650. _dwStatus &= ~CMD_TEXT_SET;
  1651. BAIL_ON_FAILURE( hr=E_OUTOFMEMORY );
  1652. }
  1653. //
  1654. // Put the statement together.
  1655. //
  1656. wcscpy(pszParsedCmd, L"<");
  1657. wcscat(pszParsedCmd, pszLocation);
  1658. wcscat(pszParsedCmd, L">;");
  1659. if (pszLdapQuery)
  1660. wcscat(pszParsedCmd, pszLdapQuery);
  1661. wcscat(pszParsedCmd, L";");
  1662. wcscat(pszParsedCmd, pszSelect);
  1663. hr = SplitCommandText(pszParsedCmd);
  1664. }
  1665. else
  1666. {
  1667. //
  1668. // Assume valid LDAP filter
  1669. //
  1670. hr = SplitCommandText(_pszCommandText);
  1671. }
  1672. BAIL_ON_FAILURE( hr )
  1673. //
  1674. // Set the sort preference property if necessary
  1675. //
  1676. if( pszOrderList ) {
  1677. DBPROPSET rgCmdPropSet[1];
  1678. DBPROP rgCmdProp[1];
  1679. rgCmdPropSet[0].rgProperties = rgCmdProp;
  1680. rgCmdPropSet[0].cProperties = 1;
  1681. rgCmdPropSet[0].guidPropertySet = DBPROPSET_ADSISEARCH;
  1682. rgCmdProp[0].dwPropertyID = ADSIPROP_SORT_ON;
  1683. rgCmdProp[0].dwOptions = DBPROPOPTIONS_REQUIRED;
  1684. rgCmdProp[0].vValue.vt = VT_BSTR;
  1685. V_BSTR (&rgCmdProp[0].vValue) = pszOrderList;
  1686. hr = SetProperties(1, rgCmdPropSet);
  1687. BAIL_ON_FAILURE( hr );
  1688. }
  1689. if( _pDSSearch ) {
  1690. _pDSSearch->Release();
  1691. _pDSSearch = NULL;
  1692. }
  1693. //
  1694. // If integrated security is being used, impersonate the caller
  1695. //
  1696. BOOL fImpersonating;
  1697. fImpersonating = FALSE;
  1698. if(_pCSession->IsIntegratedSecurity())
  1699. {
  1700. HANDLE ThreadToken = _pCSession->GetThreadToken();
  1701. ASSERT(ThreadToken != NULL);
  1702. if (ThreadToken)
  1703. {
  1704. if (!ImpersonateLoggedOnUser(ThreadToken))
  1705. RRETURN(E_FAIL);
  1706. fImpersonating = TRUE;
  1707. }
  1708. else
  1709. RRETURN(E_FAIL);
  1710. }
  1711. hr = GetDSInterface(_pszADsContext,
  1712. _Credentials,
  1713. IID_IDirectorySearch,
  1714. (void **)&_pDSSearch);
  1715. if (fImpersonating)
  1716. {
  1717. RevertToSelf();
  1718. fImpersonating = FALSE;
  1719. }
  1720. BAIL_ON_FAILURE( hr );
  1721. error:
  1722. if( pszLocation )
  1723. FreeADsMem(pszLocation);
  1724. if( pszLdapQuery )
  1725. FreeADsMem(pszLdapQuery);
  1726. if( pszSelect )
  1727. FreeADsMem(pszSelect);
  1728. if( pszOrderList )
  1729. FreeADsStr(pszOrderList);
  1730. if( pszParsedCmd )
  1731. FreeADsStr(pszParsedCmd);
  1732. RRETURN( hr );
  1733. }