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.

682 lines
22 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 2000.
  5. //
  6. // File: FATQuery.cxx
  7. //
  8. // Contents: IInternalQuery interface
  9. //
  10. // History: 18-Jun-93 KyleP Created
  11. //
  12. //--------------------------------------------------------------------------
  13. #include <pch.cxx>
  14. #pragma hdrstop
  15. #include <fatquery.hxx>
  16. #include <pidmap.hxx>
  17. #include <coldesc.hxx>
  18. #include <lang.hxx>
  19. #include <qparse.hxx>
  20. #include <cci.hxx>
  21. #include <rowset.hxx>
  22. #include <query.hxx>
  23. #include <seqquery.hxx>
  24. #include <qoptimiz.hxx>
  25. #include <cifailte.hxx>
  26. #include <dbprputl.hxx>
  27. #include <dbprpini.hxx>
  28. #include <ciframe.hxx>
  29. #include <pidcvt.hxx>
  30. #include <proprst.hxx>
  31. static const GUID guidQuery = PSGUID_QUERY;
  32. extern CLocateDocStore g_DocStoreLocator;
  33. //+-------------------------------------------------------------------------
  34. //
  35. // Member: CGenericQuery::QueryInterface, public
  36. //
  37. // Arguments: [ifid] -- Interface id
  38. // [ppiuk] -- Interface return pointer
  39. //
  40. // Returns: Error. No rebind from this class is supported.
  41. //
  42. // History: 01-Oct-92 KyleP Created
  43. //
  44. //--------------------------------------------------------------------------
  45. STDMETHODIMP CGenericQuery::QueryInterface( REFIID ifid, void ** ppiuk )
  46. {
  47. if ( IID_IUnknown == ifid )
  48. {
  49. *ppiuk = (void *)((IUnknown *)this);
  50. AddRef();
  51. return S_OK;
  52. }
  53. else
  54. {
  55. *ppiuk = 0;
  56. return E_NOINTERFACE;
  57. }
  58. }
  59. //+-------------------------------------------------------------------------
  60. //
  61. // Member: CGenericQuery::AddRef, public
  62. //
  63. // Synopsis: Reference the virtual table.
  64. //
  65. // History: 01-Oct-92 KyleP Created
  66. //
  67. //--------------------------------------------------------------------------
  68. STDMETHODIMP_(ULONG) CGenericQuery::AddRef(void)
  69. {
  70. return InterlockedIncrement( (long *)&_ref );
  71. }
  72. //+-------------------------------------------------------------------------
  73. //
  74. // Member: CGenericQuery::Release, public
  75. //
  76. // Synopsis: De-Reference the virtual table.
  77. //
  78. // Effects: If the ref count goes to 0 then the table is deleted.
  79. //
  80. // History: 01-Oct-92 KyleP Created
  81. //
  82. //--------------------------------------------------------------------------
  83. STDMETHODIMP_(ULONG) CGenericQuery::Release(void)
  84. {
  85. long l = InterlockedDecrement( (long *)&_ref );
  86. if ( l <= 0 )
  87. {
  88. // delete self
  89. vqDebugOut(( DEB_ITRACE,
  90. "FAT IInternalQuery unreferenced. Deleting.\n" ));
  91. delete this;
  92. return 0;
  93. }
  94. return l;
  95. }
  96. //+-------------------------------------------------------------------------
  97. //
  98. // Member: CGenericQuery::Execute, public
  99. //
  100. // Synopsis: Executes a query. Helper for ICommand::Execute.
  101. //
  102. // Arguments: [pUnkOuter] -- Outer unknown
  103. // [pRestriction] -- Query restriction
  104. // [pidmap] -- pid mapper for output, sort, category columns
  105. // [rColumns] -- Output columns in IRowset
  106. // [rSort] -- Initial sort
  107. // [xProps] -- Rowset properties (query flags)
  108. // [rCateg] -- Categorization specification
  109. // [cRowsets] -- # of rowsets
  110. // [ppUnknowns] -- IUnknown pointers returned here
  111. // [aAccessors] -- Bag of accessors which rowsets need to inherit
  112. //
  113. // Returns: Throws on error
  114. //
  115. // History: 26 Nov 1995 AlanW Created
  116. //
  117. //--------------------------------------------------------------------------
  118. void CGenericQuery::Execute( IUnknown * pUnkOuter,
  119. RESTRICTION * pRestriction,
  120. CPidMapperWithNames & pidmap,
  121. CColumnSet & rColumns,
  122. CSortSet & rSort,
  123. XPtr<CMRowsetProps> & xProps,
  124. CCategorizationSet & rCateg,
  125. ULONG cRowsets,
  126. IUnknown ** ppUnknowns,
  127. CAccessorBag & aAccessors,
  128. IUnknown * pUnkCreator )
  129. {
  130. #if 1
  131. Win4Assert( FALSE );
  132. #else
  133. SCODE sc = S_OK;
  134. TRY
  135. {
  136. if (0 == ppUnknowns)
  137. THROW( CException( E_INVALIDARG ));
  138. if ( cRowsets != 1 + (rCateg.Count() ? rCateg.Count() : 0) )
  139. THROW( CException( E_INVALIDARG ));
  140. if (_QueryUnknown.IsQueryActive())
  141. {
  142. vqDebugOut(( DEB_ERROR,
  143. "CGenericQuery: Query already active.\n" ));
  144. // pec variance: only if query changed
  145. THROW( CException( DB_E_OBJECTOPEN ));
  146. }
  147. //
  148. // Parameter checking.
  149. //
  150. *ppUnknowns = 0; // in case of error or exception
  151. //
  152. // Convert parsed query into low-level query understood by
  153. // the Query/CI engine. This process expands the query tree and
  154. // also maps GUID\DISPID and GUID\NAME style property names to
  155. // a ULONG pid.
  156. //
  157. //
  158. // Duplicate the output column set.
  159. //
  160. XColumnSet ColDup( new CColumnSet ( rColumns.Count() ) );
  161. for ( unsigned i = 0; i < rColumns.Count(); i++ )
  162. {
  163. ColDup->Add( rColumns.Get(i), i );
  164. }
  165. //
  166. // get a pointer to CLangList
  167. //
  168. CLangList * pLangList = 0;
  169. ICiManager * pICiManager = 0;
  170. ICiFrameworkQuery * pICiFrameworkQuery = 0;
  171. XInterface<ICiManager> xICiManager;
  172. XInterface<ICiFrameworkQuery> xICiFrameworkQuery;
  173. SCODE sc = _xDocStore->GetContentIndex(&pICiManager);
  174. if ( FAILED(sc) )
  175. {
  176. THROW( CException(sc) );
  177. }
  178. else
  179. {
  180. xICiManager.Set(pICiManager);
  181. }
  182. sc = xICiManager->QueryInterface(IID_ICiFrameworkQuery,(void **)&pICiFrameworkQuery);
  183. if ( FAILED(sc) )
  184. {
  185. THROW( CException(sc) );
  186. }
  187. else
  188. {
  189. xICiFrameworkQuery.Set(pICiFrameworkQuery);
  190. }
  191. sc = xICiFrameworkQuery->GetLangList( (void **) &pLangList);
  192. if ( FAILED(sc) )
  193. {
  194. THROW( CException(sc) );
  195. }
  196. //
  197. // end of getting a pointer to the langlist
  198. //
  199. //
  200. // Set up a property mapper. Used for restriction parsing and sort/output
  201. // column translation.
  202. //
  203. XInterface<IPropertyMapper> xPropMapper;
  204. sc = _xDocStore->GetPropertyMapper( xPropMapper.GetPPointer() );
  205. if ( FAILED( sc ) )
  206. {
  207. vqDebugOut(( DEB_ERROR, "CGenericQuery::Execute, GetPropertyMapper error 0x%x\n", sc ));
  208. THROW( CException( sc ) );
  209. }
  210. //
  211. // Adjust pidmap to translate properties. NOTE: Undone in CATCH for failure case.
  212. //
  213. CPidConverter PidConverter( xPropMapper.GetPointer() );
  214. pidmap.SetPidConverter( &PidConverter );
  215. XRestriction rstParsed;
  216. DWORD dwQueryStatus = 0;
  217. if ( pRestriction )
  218. {
  219. CQParse qparse( pidmap, *pLangList ); // Maps name to pid
  220. rstParsed.Set( qparse.Parse( (CRestriction *)pRestriction ) );
  221. DWORD dwParseStatus = qparse.GetStatus();
  222. if ( ( 0 != ( dwParseStatus & CI_NOISE_PHRASE ) ) &&
  223. ( ((CRestriction *)pRestriction)->Type() != RTVector ) )
  224. {
  225. vqDebugOut(( DEB_WARN, "Query contains phrase composed "
  226. "entirely of noise words.\n" ));
  227. THROW( CException( QUERY_E_ALLNOISE ) );
  228. }
  229. const DWORD dwCiNoise = CI_NOISE_IN_PHRASE | CI_NOISE_PHRASE;
  230. if ( 0 != ( dwCiNoise & dwParseStatus ) )
  231. dwQueryStatus |= STAT_NOISE_WORDS;
  232. }
  233. //
  234. // Duplicate the sort definition.
  235. //
  236. XSortSet SortDup;
  237. // Only create a sort duplicate if we have a sort spec AND it
  238. // actually contains anything.
  239. if ( 0 != rSort.Count() )
  240. {
  241. SortDup.Set( new CSortSet ( rSort.Count() ) );
  242. for ( unsigned i = 0; i < rSort.Count(); i++ )
  243. {
  244. SortDup->Add( rSort.Get(i), i );
  245. }
  246. }
  247. //
  248. // Duplicate the categorization specification
  249. //
  250. XCategorizationSet CategDup;
  251. if (cRowsets > 1)
  252. CategDup.Set( new CCategorizationSet ( rCateg ) );
  253. //
  254. // Re-map property ids.
  255. //
  256. //
  257. // TODO: Get rid of this whole pid remap thing. We should
  258. // really be able to do it earlier now that the pidmap
  259. // can be set up to convert fake to real pids.
  260. //
  261. XInterface<CPidRemapper> pidremap( new CPidRemapper( pidmap,
  262. xPropMapper,
  263. 0, // rstParsed.GetPointer(),
  264. ColDup.GetPointer(),
  265. SortDup.GetPointer() ) );
  266. //
  267. // WorkID may be added to the columns requested in SetBindings.
  268. // Be sure it's in the pidremap from the beginning.
  269. //
  270. CFullPropSpec psWorkId(guidQuery, DISPID_QUERY_WORKID);
  271. pidremap->NameToReal( &psWorkId );
  272. XInterface<PQuery> xQuery;
  273. XArray<ULONG> aCursors(cRowsets);
  274. ICiQueryPropertyMapper *pQueryPropMapper;
  275. sc = pidremap->QueryInterface( IID_ICiQueryPropertyMapper,
  276. (void **) &pQueryPropMapper );
  277. if ( FAILED(sc) )
  278. {
  279. vqDebugOut(( DEB_ERROR, "DoCreateQuery - QI for property mapper failed 0x%x\n", sc ));
  280. THROW ( CException( sc ) ) ;
  281. }
  282. XInterface<ICiQueryPropertyMapper> xQueryPropMapper( pQueryPropMapper );
  283. ICiCQuerySession *pQuerySession;
  284. SCODE scode = _xDocStore->GetQuerySession( &pQuerySession );
  285. if ( FAILED(scode) )
  286. {
  287. vqDebugOut(( DEB_ERROR, "CGenericQuery::Execute - QI failed 0x%x\n", scode ));
  288. THROW ( CException( scode ) ) ;
  289. }
  290. XInterface<ICiCQuerySession> xQuerySession( pQuerySession );
  291. //
  292. // Initialize the query session
  293. //
  294. xQuerySession->Init( pidmap.Count(),
  295. (FULLPROPSPEC const * const *)pidmap.GetPointer(),
  296. _xDbProperties.GetPointer(),
  297. xQueryPropMapper.GetPointer() );
  298. //
  299. // Optimize query.
  300. //
  301. CRowsetProperties Props;
  302. Props.SetDefaults( xProps->GetPropertyFlags(),
  303. xProps->GetMaxOpenRows(),
  304. xProps->GetMemoryUsage(),
  305. xProps->GetMaxResults(),
  306. xProps->GetCommandTimeout() );
  307. XQueryOptimizer xqopt( new CQueryOptimizer( xQuerySession,
  308. _xDocStore.GetPointer(),
  309. rstParsed,
  310. ColDup.GetReference(),
  311. SortDup.GetPointer(),
  312. pidremap.GetReference(),
  313. Props,
  314. dwQueryStatus ) );
  315. vqDebugOut(( DEB_ITRACE, "Query has %s1 component%s\n",
  316. xqopt->IsMultiCursor() ? "> " : "",
  317. xqopt->IsMultiCursor() ? "(s)" : "" ));
  318. vqDebugOut(( DEB_ITRACE, "Current component of query %s fully sorted\n",
  319. xqopt->IsFullySorted() ? "is" : "is not" ));
  320. vqDebugOut(( DEB_ITRACE, "Current component of query %s positionable\n",
  321. xqopt->IsPositionable() ? "is" : "is not" ));
  322. if ( (xProps->GetPropertyFlags() & eLocatable) == 0 )
  323. {
  324. //
  325. // If all components are fully sorted, then
  326. // it doesn't matter how many there are. A
  327. // merge could be done. But be careful, you
  328. // need an ordering even with a null sort.
  329. //
  330. // Categorized queries must go through bigtable for now
  331. // If someday we support categorizations that don't require
  332. // sorting then change this check.
  333. //
  334. if ( ( !xqopt->IsMultiCursor() ) &&
  335. ( xqopt->IsFullySorted() ) &&
  336. ( 1 == cRowsets ) )
  337. {
  338. xQuery.Set( new CSeqQuery( xqopt,
  339. ColDup,
  340. aCursors.GetPointer(),
  341. pidremap,
  342. _xDocStore.GetPointer() ) );
  343. }
  344. else
  345. {
  346. xQuery.Set( new CAsyncQuery( xqopt,
  347. ColDup,
  348. SortDup,
  349. CategDup,
  350. cRowsets,
  351. aCursors.GetPointer(),
  352. pidremap,
  353. FALSE,
  354. _xDocStore.GetPointer(),
  355. 0 ) );
  356. }
  357. }
  358. else
  359. {
  360. xQuery.Set( new CAsyncQuery( xqopt,
  361. ColDup,
  362. SortDup,
  363. CategDup,
  364. cRowsets,
  365. aCursors.GetPointer(),
  366. pidremap,
  367. (xProps->GetPropertyFlags() & eWatchable) != 0,
  368. _xDocStore.GetPointer(),
  369. 0 ) );
  370. }
  371. //
  372. // If we've been instructed to create a non-asynchronous cursor,
  373. // then we don't return to the caller until we have the first
  374. // row. In the case of a sorted sequential cursor (which is
  375. // implemented with a table), we wait until the query is
  376. // complete.
  377. //
  378. if ( (xProps->GetPropertyFlags() & eAsynchronous) == 0 )
  379. {
  380. //
  381. // An event would be better than these Sleeps...
  382. //
  383. ULONG sleepTime = 500;
  384. while ( TRUE )
  385. {
  386. DBCOUNTITEM ulDenominator;
  387. DBCOUNTITEM ulNumerator;
  388. DBCOUNTITEM cRows;
  389. BOOL fNewRows;
  390. xQuery->RatioFinished( 0,
  391. ulDenominator,
  392. ulNumerator,
  393. cRows,
  394. fNewRows );
  395. if ( ulNumerator == ulDenominator )
  396. break;
  397. Sleep( sleepTime );
  398. sleepTime *= 2;
  399. sleepTime = min( sleepTime, 4000 );
  400. }
  401. }
  402. // Make rowsets for each level in the hierarchy (usually 1).
  403. // Rowset 0 is the top of the hierarchy.
  404. _QueryUnknown.ReInit();
  405. CRowsetArray apRowsets( cRowsets );
  406. XArray<IUnknown *> xapUnknowns( cRowsets );
  407. CMRowsetProps & OrigProps = xProps.GetReference();
  408. #ifdef CI_FAILTEST
  409. NTSTATUS failStatus = CI_CORRUPT_CATALOG;
  410. ciFAILTEST( failStatus );
  411. #endif // CI_FAILTEST
  412. for (unsigned r = 0; r < cRowsets; r++)
  413. {
  414. XPtr<CMRowsetProps> xTmp;
  415. if ( 0 != r )
  416. {
  417. xTmp.Set( new CMRowsetProps( OrigProps ) );
  418. xTmp->SetChaptered( TRUE );
  419. }
  420. if ( 1 != cRowsets && 0 == r )
  421. xProps->SetChaptered( FALSE );
  422. apRowsets[r] = new CRowset( pUnkOuter,
  423. &xapUnknowns[r],
  424. (r == (cRowsets - 1)) ?
  425. rColumns :
  426. rCateg.Get(r)->GetColumnSet(),
  427. pidmap,
  428. xQuery.GetReference(),
  429. (IUnknown &) _QueryUnknown,
  430. 0 != r,
  431. ( 0 == r ) ? xProps : xTmp,
  432. aCursors[r],
  433. aAccessors,
  434. pUnkCreator );
  435. }
  436. for (r = 0; r < cRowsets; r++)
  437. {
  438. if (r < cRowsets-1)
  439. apRowsets[r]->SetRelatedRowset( apRowsets[r+1] );
  440. ppUnknowns[r] = (IRowset *) xapUnknowns[r];
  441. }
  442. // xQuery goes out of scope, doing a Release() on it.
  443. // Each rowset above has done an AddRef() on it and they own it.
  444. _QueryUnknown.ReInit( cRowsets, apRowsets.Acquire() );
  445. }
  446. CATCH( CException,e )
  447. {
  448. ciDebugOut(( DEB_ERROR,
  449. "Error 0x%X while executing query\n",
  450. e.GetErrorCode() ));
  451. pidmap.SetPidConverter( 0 );
  452. ICiManager *pCiManager = 0;
  453. sc = _xDocStore->GetContentIndex( &pCiManager );
  454. if ( SUCCEEDED( sc ) )
  455. {
  456. //
  457. // GetContentIndex may fail during shutdown
  458. //
  459. ICiFrameworkQuery * pIFwQuery = 0;
  460. sc = pCiManager->QueryInterface( IID_ICiFrameworkQuery,
  461. (void **) &pIFwQuery );
  462. pCiManager->Release();
  463. if ( pIFwQuery )
  464. {
  465. pIFwQuery->ProcessError( e.GetErrorCode() );
  466. pIFwQuery->Release();
  467. }
  468. }
  469. RETHROW();
  470. }
  471. END_CATCH
  472. pidmap.SetPidConverter( 0 );
  473. #endif
  474. } //Execute
  475. //+-------------------------------------------------------------------------
  476. //
  477. // Member: CGenericQuery::CGenericQuery, public
  478. //
  479. // Synopsis: Opens file system directory for query
  480. //
  481. // Arguments: [pDbProperties] -- Properties to be used for this query
  482. //
  483. // History: 18-Jun-93 KyleP Created
  484. // 22-Apr-97 KrishnaN Changed header block
  485. //
  486. //--------------------------------------------------------------------------
  487. CGenericQuery::CGenericQuery( IDBProperties * pDbProperties )
  488. : PIInternalQuery( 0 ),
  489. #pragma warning(disable : 4355) // 'this' in a constructor
  490. _QueryUnknown( * ((IUnknown *) this) )
  491. #pragma warning(default : 4355) // 'this' in a constructor
  492. {
  493. pDbProperties->AddRef();
  494. _xDbProperties.Set( pDbProperties );
  495. //
  496. // Locate the DocStore for the given set of properties.
  497. //
  498. ICiCDocStoreLocator * pLocator = g_DocStoreLocator.Get();
  499. if ( 0 == pLocator )
  500. {
  501. //
  502. // Determine the GUID of the docstore locator from the query and
  503. // use it.
  504. //
  505. CGetDbProps dbProps;
  506. dbProps.GetProperties( pDbProperties,
  507. CGetDbProps::eClientGuid );
  508. GUID const * pGuidClient = dbProps.GetClientGuid();
  509. if ( 0 == pGuidClient )
  510. {
  511. ciDebugOut(( DEB_ERROR, "The DocStoreLocator Guid is invalid\n" ));
  512. THROW( CException( E_INVALIDARG ) );
  513. }
  514. pLocator = g_DocStoreLocator.Get( *pGuidClient );
  515. }
  516. Win4Assert( pLocator != 0 );
  517. XInterface<ICiCDocStoreLocator> xLocator( pLocator );
  518. ICiCDocStore *pDocStore;
  519. SCODE sc = xLocator->LookUpDocStore( pDbProperties, &pDocStore, TRUE );
  520. if ( FAILED(sc) )
  521. {
  522. ciDebugOut(( DEB_ITRACE, "Failed to locate doc store. Error (0x%X)\n",
  523. sc ));
  524. THROW( CException(sc) );
  525. }
  526. Win4Assert( pDocStore != 0 );
  527. _xDocStore.Set( pDocStore );
  528. AddRef();
  529. } //CGenericQuery
  530. //+-------------------------------------------------------------------------
  531. //
  532. // Member: CGenericQuery::CGenericQuery, public
  533. //
  534. // Synopsis: Opens file system directory for query
  535. //
  536. // Arguments: [pDbProperties] -- Properties to be used for this query
  537. // [pDocStore] -- Docstore to query against
  538. //
  539. // History: 22-Apr-97 KrishnaN Created
  540. //
  541. //--------------------------------------------------------------------------
  542. CGenericQuery::CGenericQuery( IDBProperties * pDbProperties,
  543. ICiCDocStore * pDocStore )
  544. : PIInternalQuery( 0 ),
  545. #pragma warning(disable : 4355) // 'this' in a constructor
  546. _QueryUnknown( * ((IUnknown *) this) )
  547. #pragma warning(default : 4355) // 'this' in a constructor
  548. {
  549. pDbProperties->AddRef();
  550. _xDbProperties.Set( pDbProperties );
  551. Win4Assert( pDocStore != 0 );
  552. pDocStore->AddRef();
  553. _xDocStore.Set( pDocStore );
  554. AddRef();
  555. } //CGenericQuery
  556. //+-------------------------------------------------------------------------
  557. //
  558. // Member: CGenericQuery::~CGenericQuery, public
  559. //
  560. // Synopsis: Required virtual destructor
  561. //
  562. // History: 17-Jul-93 KyleP Created
  563. //
  564. //--------------------------------------------------------------------------
  565. CGenericQuery::~CGenericQuery()
  566. {
  567. }