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.

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