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.

1980 lines
59 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 2000.
  5. //
  6. // File: srchq.cxx
  7. //
  8. // Contents:
  9. //
  10. // History: 15 Aug 1996 DLee Created
  11. //
  12. //--------------------------------------------------------------------------
  13. #include "pch.cxx"
  14. #pragma hdrstop
  15. #define guidCPP { 0x8DEE0300, 0x16C2, 0x101B, { 0xB1, 0x21, 0x08, 0x00, 0x2B, 0x2E, 0xCD, 0xA9 } }
  16. static GUID guidCPlusPlus = guidCPP;
  17. static GUID guidBmk = DBBMKGUID;
  18. static const GUID guidQueryExt = DBPROPSET_QUERYEXT;
  19. static const GUID guidRowsetProps = DBPROPSET_ROWSET;
  20. static const DBID dbcolNull = { {0,0,0,{0,0,0,0,0,0,0,0}},DBKIND_GUID_PROPID,0};
  21. #define guidZero { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
  22. const DBID dbcolCPlusPlusClass = { guidCPP, DBKIND_GUID_NAME, L"class" };
  23. const DBID dbcolCPlusPlusFunc = { guidCPP, DBKIND_GUID_NAME, L"func" };
  24. const DBID dbcolBookMark = { DBBMKGUID, DBKIND_GUID_PROPID, (LPWSTR) (ULONG_PTR) PROPID_DBBMK_BOOKMARK };
  25. const DBID dbcolPath = { PSGUID_STORAGE, DBKIND_GUID_PROPID,
  26. (LPWSTR) ULongToPtr( PID_STG_PATH ) };
  27. const DBBINDING dbbindingPath = { 0,
  28. 0,
  29. 0,
  30. 0,
  31. 0,
  32. 0,
  33. 0,
  34. DBPART_VALUE,
  35. DBMEMOWNER_PROVIDEROWNED,
  36. DBPARAMIO_NOTPARAM,
  37. sizeof (WCHAR *),
  38. 0,
  39. DBTYPE_WSTR|DBTYPE_BYREF,
  40. 0,
  41. 0,
  42. };
  43. DBBINDING aBmkColumn[] = { 0,
  44. sizeof DBLENGTH,
  45. 0,
  46. 0,
  47. 0,
  48. 0,
  49. 0,
  50. DBPART_VALUE | DBPART_LENGTH,
  51. DBMEMOWNER_CLIENTOWNED,
  52. DBPARAMIO_NOTPARAM,
  53. MAX_BOOKMARK_LENGTH,
  54. 0,
  55. DBTYPE_BYTES,
  56. 0,
  57. 0,
  58. };
  59. CIPROPERTYDEF aCPPProperties[] =
  60. {
  61. {
  62. L"FUNC",
  63. DBTYPE_WSTR | DBTYPE_BYREF,
  64. {
  65. { 0x8dee0300, 0x16c2, 0x101b, 0xb1, 0x21, 0x08, 0x00, 0x2b, 0x2e, 0xcd, 0xa9 },
  66. DBKIND_GUID_NAME,
  67. L"func"
  68. }
  69. },
  70. {
  71. L"CLASS",
  72. DBTYPE_WSTR | DBTYPE_BYREF,
  73. {
  74. { 0x8dee0300, 0x16c2, 0x101b, 0xb1, 0x21, 0x08, 0x00, 0x2b, 0x2e, 0xcd, 0xa9 },
  75. DBKIND_GUID_NAME,
  76. L"class"
  77. }
  78. }
  79. };
  80. unsigned cCPPProperties = sizeof aCPPProperties /
  81. sizeof aCPPProperties[0];
  82. SCODE ParseQuery(
  83. WCHAR * pwcQuery,
  84. ULONG ulDialect,
  85. LCID lcid,
  86. DBCOMMANDTREE ** ppQuery )
  87. {
  88. *ppQuery = 0;
  89. return CITextToSelectTreeEx( pwcQuery,
  90. ulDialect,
  91. ppQuery,
  92. cCPPProperties,
  93. aCPPProperties,
  94. lcid );
  95. } //ParseQuery
  96. //-----------------------------------------------------------------------------
  97. //
  98. // Function: GetOleDBErrorInfo
  99. //
  100. // Synopsis: Retrieves the secondary error from the OLE DB error object.
  101. //
  102. // Arguments: [pErrSrc] - Pointer to object that posted the error.
  103. // [riid] - Interface that posted the error.
  104. // [lcid] - Locale in which the text is desired.
  105. // [pErrorInfo] - Pointer to memory where ERRORINFO should be.
  106. // [ppIErrorInfo] - Holds the returning IErrorInfo. Caller
  107. // should release this.
  108. //
  109. // Returns: HRESULT for whether the error info was retrieved
  110. //
  111. //-----------------------------------------------------------------------------
  112. HRESULT GetOleDBErrorInfo(
  113. IUnknown * pErrSrc,
  114. REFIID riid,
  115. LCID lcid,
  116. ERRORINFO * pErrorInfo,
  117. IErrorInfo ** ppIErrorInfo )
  118. {
  119. *ppIErrorInfo = 0;
  120. // See if an error is available that is of interest to us.
  121. XInterface<ISupportErrorInfo> xSupportErrorInfo;
  122. HRESULT hr = pErrSrc->QueryInterface( IID_ISupportErrorInfo,
  123. xSupportErrorInfo.GetQIPointer() );
  124. if ( FAILED( hr ) )
  125. return hr;
  126. hr = xSupportErrorInfo->InterfaceSupportsErrorInfo( riid );
  127. if ( FAILED( hr ) )
  128. return hr;
  129. // Get the current error object. Return if none exists.
  130. XInterface<IErrorInfo> xErrorInfo;
  131. hr = GetErrorInfo( 0, xErrorInfo.GetPPointer() );
  132. if ( xErrorInfo.IsNull() )
  133. return hr;
  134. // Get the IErrorRecord interface and get the count of errors.
  135. XInterface<IErrorRecords> xErrorRecords;
  136. hr = xErrorInfo->QueryInterface( IID_IErrorRecords,
  137. xErrorRecords.GetQIPointer() );
  138. if ( FAILED( hr ) )
  139. return hr;
  140. ULONG cErrRecords;
  141. hr = xErrorRecords->GetRecordCount( &cErrRecords );
  142. if ( 0 == cErrRecords )
  143. return hr;
  144. #if 0 // A good way to get the complete error message...
  145. XInterface<IErrorInfo> xErrorInfoRec;
  146. ERRORINFO ErrorInfo;
  147. for ( unsigned i=0; i<cErrRecords; i++ )
  148. {
  149. // Get basic error information.
  150. xErrorRecords->GetBasicErrorInfo( i, &ErrorInfo );
  151. // Get error description and source through the IErrorInfo interface
  152. // pointer on a particular record.
  153. xErrorRecords->GetErrorInfo( i, lcid, xErrorInfoRec.GetPPointer() );
  154. XBStr bstrDescriptionOfError;
  155. XBStr bstrSourceOfError;
  156. BSTR bstrDesc = bstrDescriptionOfError.GetPointer();
  157. BSTR bstrSrc = bstrSourceOfError.GetPointer();
  158. xErrorInfoRec->GetDescription( &bstrDesc );
  159. xErrorInfoRec->GetSource( &bstrSrc );
  160. // At this point, you could call GetCustomErrorObject and query for
  161. // additional interfaces to determine what else happened.
  162. wprintf( L"%s (%#x)\n%s\n", bstrDesc, ErrorInfo.hrError, bstrSrc );
  163. }
  164. #endif
  165. // Get basic error information for the most recent error
  166. ULONG iRecord = cErrRecords - 1;
  167. hr = xErrorRecords->GetBasicErrorInfo( iRecord, pErrorInfo );
  168. if ( FAILED( hr ) )
  169. return hr;
  170. return xErrorRecords->GetErrorInfo( iRecord, lcid, ppIErrorInfo );
  171. } //GetOleDBErrorInfo
  172. //
  173. // CSearchQuery
  174. //
  175. CSearchQuery::CSearchQuery(
  176. const XGrowable<WCHAR> & xCatList,
  177. WCHAR *pwcQuery,
  178. HWND hNotify,
  179. int cRowsDisp,
  180. LCID lcid,
  181. ESearchType srchType,
  182. IColumnMapper & columnMapper,
  183. CColumnList &columns,
  184. CSortList &sort,
  185. ULONG ulDialect,
  186. ULONG ulLimit,
  187. ULONG ulFirstRows )
  188. : _hwndNotify(hNotify),
  189. _hwndList (0),
  190. _cRowsTotal(0),
  191. _cHRows(0),
  192. _cRowsDisp(cRowsDisp),
  193. _lcid(lcid),
  194. _fDone(FALSE),
  195. _srchType(srchType),
  196. _columns(columns),
  197. _columnMapper(columnMapper),
  198. _hAccessor(0),
  199. _hBmkAccessor(0),
  200. _hBrowseAccessor(0),
  201. _iRowCurrent(0),
  202. _hRegion(0),
  203. _pctDone(0),
  204. _dwQueryStatus(0),
  205. _scLastError(0),
  206. _dwStartTime(0),
  207. _dwEndTime(0),
  208. _prstQuery(0),
  209. _xCatList( xCatList )
  210. {
  211. srchDebugOut((DEB_TRACE,"top of CSearchQuery()\n"));
  212. _dwStartTime = GetTickCount();
  213. _bmkTop.MakeFirst();
  214. for (int i = 0; i < cMaxRowCache; i++)
  215. _aHRows [i] = 0;
  216. ICommand *pICommand = 0;
  217. SCODE sc = InstantiateICommand( &pICommand );
  218. if ( FAILED( sc ) )
  219. THROW( CException( sc ) );
  220. XInterface< ICommand> xCommand( pICommand );
  221. _xwcQuery.SetSize(wcslen(pwcQuery) + 1);
  222. wcscpy(_xwcQuery.Get(),pwcQuery);
  223. switch ( ulDialect )
  224. {
  225. case ISQLANG_V1:
  226. case ISQLANG_V2:
  227. {
  228. if (srchNormal == _srchType)
  229. {
  230. sc = ParseQuery( _xwcQuery.Get(), ulDialect, lcid, &_prstQuery );
  231. if ( FAILED(sc) )
  232. THROW( CException(sc) );
  233. }
  234. else
  235. {
  236. XArray<WCHAR> xQuery( wcslen( _xwcQuery.Get() ) + 50 );
  237. wcscpy( xQuery.Get(), ( _srchType == srchClass ) ? L"@class " : L"@func " );
  238. wcscat( xQuery.Get(), _xwcQuery.Get() );
  239. sc = ParseQuery( xQuery.Get(), ulDialect, lcid, &_prstQuery );
  240. if ( FAILED(sc) )
  241. THROW( CException(sc) );
  242. }
  243. XArray<WCHAR> xColumns;
  244. columns.MakeList( xColumns );
  245. XArray<WCHAR> xSort;
  246. sort.MakeList( xSort );
  247. DBCOMMANDTREE *pTree;
  248. sc = CIRestrictionToFullTree( _prstQuery,
  249. xColumns.Get(),
  250. xSort.Get(),
  251. 0,
  252. &pTree,
  253. 0,
  254. 0,
  255. lcid );
  256. if ( FAILED( sc ) )
  257. THROW( CException(sc) );
  258. XInterface<ICommandTree> xCommandTree;
  259. sc = pICommand->QueryInterface( IID_ICommandTree, xCommandTree.GetQIPointer() );
  260. if ( FAILED( sc ) )
  261. THROW( CException(sc) );
  262. sc = xCommandTree->SetCommandTree( &pTree, DBCOMMANDREUSE_NONE, FALSE);
  263. if (FAILED (sc) )
  264. THROW( CException( sc ) );
  265. break;
  266. }
  267. case SQLTEXT:
  268. {
  269. WCHAR awcCommand[cwcMaxQuery];
  270. WCHAR awcPropList[cwcMaxQuery] = L"Path";
  271. CResString wstrQueryFormat(IDS_SQLQUERY_FORMAT);
  272. XInterface<ICommandText> xCommandText;
  273. sc = pICommand->QueryInterface( IID_ICommandText, xCommandText.GetQIPointer() );
  274. if ( FAILED( sc ) )
  275. THROW( CException( sc ) );
  276. // set the list of columns
  277. // !! Allways select the PATH column !!
  278. for ( ULONG iCol = 0; iCol < _columns.NumberOfColumns(); iCol++ )
  279. {
  280. if ( _wcsicmp ( _columns.GetColumn(iCol), L"Path" ) )
  281. {
  282. wcscat( awcPropList, L", " );
  283. wcscat( awcPropList, _columns.GetColumn( iCol ) );
  284. }
  285. }
  286. WCHAR awcMachine[MAX_PATH];
  287. WCHAR awcCatalog[MAX_PATH];
  288. WCHAR awcPath[MAX_PATH];
  289. BOOL fDeep;
  290. // What about ditributed queries? Not supported, but that's OK
  291. // since this is a test tool.
  292. GetCatListItem( _xCatList, 0, awcMachine, awcCatalog, awcPath, fDeep );
  293. swprintf( awcCommand, wstrQueryFormat.Get(), awcPropList, awcCatalog, awcPath, pwcQuery );
  294. srchDebugOut((DEB_TRACE, "SQL query: %ws\n", awcCommand));
  295. sc = xCommandText->SetCommandText( DBGUID_SQL, awcCommand);
  296. if ( FAILED (sc) )
  297. THROW( CException( sc ) );
  298. XInterface<ICommandPrepare> xCommandPrepare;
  299. sc = pICommand->QueryInterface( IID_ICommandPrepare, xCommandPrepare.GetQIPointer() );
  300. if ( FAILED (sc) )
  301. THROW( CException( sc ) );
  302. sc = xCommandPrepare->Prepare( 1 );
  303. if ( FAILED (sc) )
  304. THROW( CException( sc ) );
  305. XInterface<ICommandProperties> xCommandProperties;
  306. sc = pICommand->QueryInterface( IID_ICommandProperties, xCommandProperties.GetQIPointer() );
  307. if ( FAILED (sc) )
  308. THROW( CException( sc ) );
  309. // set the machine name
  310. DBPROPSET PropSet;
  311. DBPROP Prop;
  312. const GUID guidQueryCorePropset = DBPROPSET_CIFRMWRKCORE_EXT;
  313. PropSet.rgProperties = &Prop;
  314. PropSet.cProperties = 1;
  315. PropSet.guidPropertySet = guidQueryCorePropset;
  316. Prop.dwPropertyID = DBPROP_MACHINE;
  317. Prop.colid = DB_NULLID;
  318. Prop.vValue.vt = VT_BSTR;
  319. Prop.vValue.bstrVal = SysAllocString( awcMachine );
  320. if ( NULL == Prop.vValue.bstrVal )
  321. THROW( CException( E_OUTOFMEMORY ) );
  322. sc = xCommandProperties->SetProperties ( 1, &PropSet );
  323. VariantClear( &Prop.vValue );
  324. if ( FAILED (sc) )
  325. THROW( CException( sc ) );
  326. // try to get the restriction
  327. DBPROPIDSET PropIDSet;
  328. DBPROPID PropID = MSIDXSPROP_QUERY_RESTRICTION;
  329. PropIDSet.rgPropertyIDs = &PropID;
  330. PropIDSet.cPropertyIDs = 1;
  331. const GUID guidMSIDXS_ROWSETEXT = DBPROPSET_MSIDXS_ROWSETEXT;
  332. PropIDSet.guidPropertySet = guidMSIDXS_ROWSETEXT;
  333. ULONG cPropSets;
  334. DBPROPSET *pPropSet;
  335. sc = xCommandProperties->GetProperties ( 1, &PropIDSet, &cPropSets, &pPropSet );
  336. if ( FAILED (sc) )
  337. THROW( CException( sc ) );
  338. Win4Assert( 1 == cPropSets );
  339. XCoMem<DBPROPSET> xPropSet( pPropSet );
  340. XCoMem<DBPROP> xProp( pPropSet->rgProperties );
  341. srchDebugOut((DEB_TRACE, "SQL query as tripolish: %ws\n",
  342. pPropSet->rgProperties->vValue.bstrVal ));
  343. // MSIDXSPROP_QUERY_RESTRICTION returns the restriction in in Triplish1 syntax.
  344. // It is sometimes bogus. Just set a zero and ignore the error for now.
  345. DBCOMMANDTREE *pQuery = 0;
  346. ParseQuery( pPropSet->rgProperties->vValue.bstrVal,
  347. ISQLANG_V1,
  348. lcid,
  349. &pQuery );
  350. _prstQuery = pQuery;
  351. sc = VariantClear( &pPropSet->rgProperties->vValue );
  352. if ( FAILED (sc) )
  353. THROW( CException( sc ) );
  354. break;
  355. }
  356. }
  357. // Set the property that says we want to use asynch. queries
  358. {
  359. ICommandProperties * pCmdProp = 0;
  360. sc = pICommand->QueryInterface( IID_ICommandProperties,
  361. (void **)&pCmdProp );
  362. if (FAILED (sc) )
  363. THROW( CException( sc ) );
  364. XInterface< ICommandProperties > xComdProp( pCmdProp );
  365. const unsigned MAX_PROPS = 8;
  366. DBPROPSET aPropSet[MAX_PROPS];
  367. DBPROP aProp[MAX_PROPS];
  368. ULONG cProps = 0;
  369. // asynchronous, watchable query
  370. aProp[cProps].dwPropertyID = DBPROP_IDBAsynchStatus;
  371. aProp[cProps].dwOptions = DBPROPOPTIONS_REQUIRED;
  372. aProp[cProps].dwStatus = 0;
  373. aProp[cProps].colid = dbcolNull;
  374. aProp[cProps].vValue.vt = VT_BOOL;
  375. aProp[cProps].vValue.boolVal = VARIANT_TRUE;
  376. aPropSet[cProps].rgProperties = &aProp[cProps];
  377. aPropSet[cProps].cProperties = 1;
  378. aPropSet[cProps].guidPropertySet = guidRowsetProps;
  379. cProps++;
  380. aProp[cProps].dwPropertyID = DBPROP_IRowsetWatchRegion;
  381. aProp[cProps].dwOptions = DBPROPOPTIONS_REQUIRED;
  382. aProp[cProps].dwStatus = 0;
  383. aProp[cProps].colid = dbcolNull;
  384. aProp[cProps].vValue.vt = VT_BOOL;
  385. aProp[cProps].vValue.boolVal = VARIANT_TRUE;
  386. aPropSet[cProps].rgProperties = &aProp[cProps];
  387. aPropSet[cProps].cProperties = 1;
  388. aPropSet[cProps].guidPropertySet = guidRowsetProps;
  389. cProps++;
  390. // don't timeout queries
  391. aProp[cProps].dwPropertyID = DBPROP_COMMANDTIMEOUT;
  392. aProp[cProps].dwOptions = DBPROPOPTIONS_OPTIONAL;
  393. aProp[cProps].dwStatus = 0;
  394. aProp[cProps].colid = dbcolNull;
  395. aProp[cProps].vValue.vt = VT_I4;
  396. aProp[cProps].vValue.lVal = 0;
  397. aPropSet[cProps].rgProperties = &aProp[cProps];
  398. aPropSet[cProps].cProperties = 1;
  399. aPropSet[cProps].guidPropertySet = guidRowsetProps;
  400. cProps++;
  401. // We can handle PROPVARIANTs
  402. aProp[cProps].dwPropertyID = DBPROP_USEEXTENDEDDBTYPES;
  403. aProp[cProps].dwOptions = DBPROPOPTIONS_OPTIONAL;
  404. aProp[cProps].dwStatus = 0;
  405. aProp[cProps].colid = dbcolNull;
  406. aProp[cProps].vValue.vt = VT_BOOL;
  407. aProp[cProps].vValue.boolVal = VARIANT_TRUE;
  408. aPropSet[cProps].rgProperties = &aProp[cProps];
  409. aPropSet[cProps].cProperties = 1;
  410. aPropSet[cProps].guidPropertySet = guidQueryExt;
  411. cProps++;
  412. if ( App.ForceUseCI() )
  413. {
  414. // Set the property that says we don't want to enumerate
  415. aProp[cProps].dwPropertyID = DBPROP_USECONTENTINDEX;
  416. aProp[cProps].dwOptions = DBPROPOPTIONS_OPTIONAL;
  417. aProp[cProps].dwStatus = 0;
  418. aProp[cProps].colid = dbcolNull;
  419. aProp[cProps].vValue.vt = VT_BOOL;
  420. aProp[cProps].vValue.boolVal = VARIANT_TRUE;
  421. aPropSet[cProps].rgProperties = &aProp[cProps];
  422. aPropSet[cProps].cProperties = 1;
  423. aPropSet[cProps].guidPropertySet = guidQueryExt;
  424. cProps++;
  425. }
  426. Win4Assert( MAX_PROPS >= cProps );
  427. sc = pCmdProp->SetProperties( cProps, aPropSet );
  428. if (FAILED (sc) || DB_S_ERRORSOCCURRED == sc )
  429. THROW( CException( sc ) );
  430. }
  431. if ( 0 != ulLimit || 0 != ulFirstRows )
  432. {
  433. static const DBID dbcolNull = { { 0,0,0, { 0,0,0,0,0,0,0,0 } },
  434. DBKIND_GUID_PROPID, 0 };
  435. DBPROP aRowsetProp[1];
  436. aRowsetProp[0].dwOptions = DBPROPOPTIONS_OPTIONAL;
  437. aRowsetProp[0].dwStatus = 0;
  438. aRowsetProp[0].colid = dbcolNull;
  439. aRowsetProp[0].dwPropertyID = (0 != ulLimit) ? DBPROP_MAXROWS : DBPROP_FIRSTROWS;
  440. aRowsetProp[0].vValue.vt = VT_I4;
  441. aRowsetProp[0].vValue.lVal = (LONG) (0 != ulLimit) ? ulLimit : ulFirstRows;
  442. DBPROPSET aPropSet[1];
  443. aPropSet[0].rgProperties = &aRowsetProp[0];
  444. aPropSet[0].cProperties = 1;
  445. aPropSet[0].guidPropertySet = DBPROPSET_ROWSET;
  446. XInterface<ICommandProperties> xICommandProperties;
  447. sc = pICommand->QueryInterface( IID_ICommandProperties,
  448. xICommandProperties.GetQIPointer() );
  449. if ( FAILED( sc ) )
  450. THROW( CException( sc ) );
  451. sc = xICommandProperties->SetProperties( 1,
  452. aPropSet ); // the properties
  453. if (FAILED (sc) || DB_S_ERRORSOCCURRED == sc )
  454. THROW( CException( sc ) );
  455. }
  456. IRowsetScroll * pRowset;
  457. sc = pICommand->Execute( 0, // no aggr. IUnknown
  458. IID_IRowsetScroll, // IID for i/f to return
  459. 0, // dbparams
  460. 0, // chapter
  461. (IUnknown **) & pRowset ); // Returned interface
  462. if ( FAILED(sc) )
  463. {
  464. // get the real error here
  465. ERRORINFO ErrorInfo;
  466. XInterface<IErrorInfo> xErrorInfo;
  467. SCODE sc2 = GetOleDBErrorInfo( pICommand,
  468. IID_ICommand,
  469. lcid,
  470. &ErrorInfo,
  471. xErrorInfo.GetPPointer() );
  472. // Post IErrorInfo only if we have a valid ptr to it.
  473. if (SUCCEEDED(sc2) && 0 != xErrorInfo.GetPointer())
  474. sc = ErrorInfo.hrError;
  475. THROW( CException(sc) );
  476. }
  477. _xRowset.Set( pRowset );
  478. IRowsetQueryStatus *pRowsetStatus;
  479. sc = _xRowset->QueryInterface( IID_IRowsetQueryStatus,
  480. (void**) &pRowsetStatus );
  481. if (SUCCEEDED( sc ) )
  482. _xRowsetStatus.Set( pRowsetStatus );
  483. IColumnsInfo *pColInfo = 0;
  484. sc = _xRowset->QueryInterface( IID_IColumnsInfo, (void **)&pColInfo );
  485. if (FAILED(sc))
  486. THROW( CException( sc ) );
  487. XInterface< IColumnsInfo > xColInfo( pColInfo );
  488. IAccessor *pIAccessor;
  489. sc = _xRowset->QueryInterface( IID_IAccessor, (void **)&pIAccessor );
  490. if (FAILED(sc))
  491. THROW (CException (sc));
  492. _xIAccessor.Set( pIAccessor );
  493. //
  494. // set up an accessor for bookmarks.
  495. //
  496. DBID acols[1];
  497. acols[0] = dbcolBookMark;
  498. DBORDINAL lcol;
  499. sc = pColInfo->MapColumnIDs(1, acols, &lcol);
  500. if (FAILED(sc))
  501. THROW (CException (sc));
  502. Win4Assert( 0 == lcol );
  503. aBmkColumn[0].iOrdinal = lcol;
  504. sc = _xIAccessor->CreateAccessor( DBACCESSOR_ROWDATA,
  505. 1,
  506. aBmkColumn,
  507. 0,
  508. &_hBmkAccessor,
  509. 0 );
  510. if ( FAILED(sc) )
  511. THROW (CException (sc));
  512. SetupColumnMappingsAndAccessors();
  513. // Get a pointer to the IDBAsynchStatus for checking completion state
  514. IDBAsynchStatus *pDBAsynchStatus;
  515. sc = _xRowset->QueryInterface( IID_IDBAsynchStatus,
  516. (void**) &pDBAsynchStatus );
  517. if ( FAILED(sc) )
  518. THROW (CException (sc));
  519. _xDBAsynchStatus.Set( pDBAsynchStatus );
  520. } //CSearchQuery
  521. void CSearchQuery::InitNotifications(
  522. HWND hwndList)
  523. {
  524. _hwndList = hwndList;
  525. _xWatch.Set( new CWatchQuery( this, _xRowset.GetPointer() ) );
  526. if (!_xWatch->Ok())
  527. _xWatch.Free();
  528. else
  529. _hRegion = _xWatch->Handle();
  530. } //InitNotifications
  531. CSearchQuery::~CSearchQuery()
  532. {
  533. srchDebugOut((DEB_TRACE,"top of ~CSearchQuery()\n"));
  534. _xRowsetStatus.Free();
  535. //
  536. // make sure notification thread isn't stuck sleeping in our code
  537. // when we shut down notifications. this is ok, but will cause
  538. // an unnecessary delay in shutting down the query.
  539. //
  540. if ( !_xWatch.IsNull() )
  541. _xWatch->IgnoreNotifications( TRUE );
  542. _xDBAsynchStatus.Free();
  543. _xWatch.Free();
  544. if ( !_xIAccessor.IsNull() )
  545. {
  546. if (_hAccessor)
  547. _xIAccessor->ReleaseAccessor( _hAccessor, 0 );
  548. if ( _hBmkAccessor )
  549. _xIAccessor->ReleaseAccessor( _hBmkAccessor, 0 );
  550. if ( _hBrowseAccessor )
  551. _xIAccessor->ReleaseAccessor( _hBrowseAccessor, 0 );
  552. _xIAccessor.Free();
  553. }
  554. if ( !_xRowset.IsNull() )
  555. {
  556. srchDebugOut((DEB_TRACE,"~ Releasing %d rows, first %d\n",_cHRows,_aHRows[0]));
  557. _xRowset->ReleaseRows(_cHRows, _aHRows, 0, 0, 0);
  558. _xRowset.Free();
  559. }
  560. srchDebugOut(( DEB_TRACE, "bottom of ~CSearchQuery()\n" ));
  561. } //~CSearchQuery
  562. BOOL CSearchQuery::ListNotify(
  563. HWND hwnd,
  564. WPARAM action,
  565. long * pDist)
  566. {
  567. BOOL fRet = TRUE;
  568. CWaitCursor wait;
  569. switch (action)
  570. {
  571. case listScrollLineUp:
  572. ScrollLineUp (pDist);
  573. break;
  574. case listScrollLineDn:
  575. ScrollLineDn (pDist);
  576. break;
  577. case listScrollPageUp:
  578. ScrollPageUp (pDist);
  579. break;
  580. case listScrollPageDn:
  581. ScrollPageDn (pDist);
  582. break;
  583. case listScrollTop:
  584. ScrollTop (pDist);
  585. break;
  586. case listScrollBottom:
  587. ScrollBottom (pDist);
  588. break;
  589. case listScrollPos:
  590. ScrollPos (pDist);
  591. break;
  592. case listSize:
  593. fRet = WindowResized (*(ULONG*)pDist);
  594. break;
  595. case listSelect:
  596. return Select (pDist);
  597. break;
  598. case listSelectUp:
  599. fRet = SelectUp( pDist );
  600. break;
  601. case listSelectDown:
  602. fRet = SelectDown( pDist );
  603. break;
  604. default:
  605. Win4Assert (!"Unknown action in CSearchQuery::Scroll");
  606. }
  607. return fRet;
  608. } //ListNotify
  609. long CSearchQuery::FindSelection()
  610. {
  611. long iSel;
  612. if (IsSelected())
  613. {
  614. // Find out what is selected
  615. for (ULONG i = 0; i < _cHRows; i++)
  616. if (IsSelected(i))
  617. break;
  618. if (i == _cHRows)
  619. iSel = -1;
  620. else
  621. iSel = i;
  622. }
  623. else
  624. {
  625. iSel = -1;
  626. }
  627. return iSel;
  628. } //FindSelection
  629. BOOL CSearchQuery::SelectUp(
  630. long * piNew )
  631. {
  632. *piNew = FindSelection();
  633. if ( -1 == *piNew || 0 == *piNew )
  634. return FALSE;
  635. (*piNew)--;
  636. GetBookMark( _aHRows[ *piNew ], _bmkSelect );
  637. return TRUE;
  638. } //SelectUp
  639. BOOL CSearchQuery::SelectDown(
  640. long * piNew )
  641. {
  642. *piNew = FindSelection();
  643. if ( ( -1 == *piNew ) || ( *piNew == (long) ( _cHRows - 1) ) )
  644. return FALSE;
  645. (*piNew)++;
  646. GetBookMark( _aHRows[ *piNew ], _bmkSelect );
  647. return TRUE;
  648. } //SelectDown
  649. BOOL CSearchQuery::Select(
  650. long* piRow )
  651. {
  652. ULONG newRow = *piRow;
  653. if (newRow >= _cHRows)
  654. {
  655. return FALSE;
  656. }
  657. *piRow = FindSelection();
  658. if (*piRow != (long)newRow)
  659. GetBookMark (_aHRows[newRow], _bmkSelect);
  660. #if 0
  661. else
  662. _bmkSelect.Invalidate();
  663. #endif
  664. return TRUE;
  665. } //Select
  666. BOOL CSearchQuery::IsSelected(
  667. UINT iRow )
  668. {
  669. if (iRow >= _cHRows)
  670. return FALSE;
  671. CBookMark bmk;
  672. GetBookMark (_aHRows[iRow], bmk);
  673. return bmk.IsEqual (_bmkSelect);
  674. } //IsSelected
  675. BOOL CSearchQuery::WindowResized(
  676. ULONG & cRows)
  677. {
  678. BOOL fInvalidate = FALSE;
  679. if (cRows < _cHRows)
  680. {
  681. if ( !_xWatch.IsNull() )
  682. _xWatch->Shrink (_hRegion, _bmkTop, cRows);
  683. _xRowset->ReleaseRows(_cHRows - cRows, _aHRows + cRows, 0, 0, 0);
  684. for (ULONG i = cRows; i < _cHRows; i++)
  685. _aHRows[i] = 0;
  686. _cHRows = cRows;
  687. }
  688. else if (cRows > _cHRows)
  689. {
  690. if (cRows > cMaxRowCache)
  691. cRows = cMaxRowCache;
  692. CBookMark bmk;
  693. long cSkip;
  694. if (_cHRows == 0)
  695. {
  696. cSkip = 0;
  697. bmk.MakeFirst();
  698. }
  699. else
  700. {
  701. cSkip = 1;
  702. GetBookMark (_aHRows[_cHRows-1], bmk);
  703. }
  704. DBCOUNTITEM cRowsFetched = 0;
  705. if ( !_xWatch.IsNull() )
  706. _xWatch->Extend (_hRegion);
  707. ULONG cRowsNeeded = cRows - _cHRows;
  708. FetchResult res = Fetch ( bmk, cSkip, cRowsNeeded, cRowsFetched, _aHRows + _cHRows, _hRegion);
  709. if ( cRowsFetched )
  710. {
  711. _cHRows += (ULONG) cRowsFetched;
  712. cRowsNeeded -= (ULONG) cRowsFetched;
  713. }
  714. if ( cRowsNeeded && _cHRows < _cRowsTotal )
  715. {
  716. // looks like we are at the ned
  717. // try to get rows from the top to fill up new space
  718. fInvalidate = TRUE;
  719. Win4Assert( fetchBoundary == res );
  720. if ( cRowsNeeded > _cRowsTotal - _cHRows )
  721. {
  722. cRowsNeeded = (ULONG) ( _cRowsTotal - _cHRows );
  723. }
  724. _cRowsDisp = cRows; // need to set this here before PageUp
  725. ScrollPageUp( (long*) &cRowsNeeded );
  726. }
  727. }
  728. _cRowsDisp = cRows;
  729. cRows = _cHRows;
  730. // return TRUE if an invalidate is needed or FALSE if just updating
  731. // the scroll bars is sufficient.
  732. return fInvalidate;
  733. } //WindowResized
  734. void CSearchQuery::ScrollLineUp(
  735. long * pDist)
  736. {
  737. if (_cHRows == 0)
  738. {
  739. *pDist = 0;
  740. return;
  741. }
  742. // Try to fetch new first row
  743. HROW hrow;
  744. CBookMark bmk;
  745. GetBookMark (_aHRows[0], bmk);
  746. DBCOUNTITEM cRowsFetched = 0;
  747. if ( !_xWatch.IsNull() )
  748. _xWatch->Move (_hRegion);
  749. FetchResult res = Fetch ( bmk, -1, 1, cRowsFetched, &hrow, _hRegion);
  750. if ( isFetchOK( res ) && cRowsFetched == 1)
  751. {
  752. if (_cHRows == _cRowsDisp)
  753. {
  754. // Release last row
  755. _xRowset->ReleaseRows (1, _aHRows + _cHRows - 1, 0, 0, 0);
  756. }
  757. else
  758. {
  759. _cHRows++;
  760. }
  761. // shift all rows down
  762. for (ULONG i = _cHRows - 1; i > 0; i--)
  763. _aHRows [i] = _aHRows [i-1];
  764. _aHRows [0] = hrow;
  765. GetBookMark (hrow, _bmkTop);
  766. }
  767. else
  768. {
  769. *pDist = 0;
  770. _bmkTop.MakeFirst();
  771. }
  772. } //ScrollLineUp
  773. void CSearchQuery::ScrollLineDn(
  774. long* pDist)
  775. {
  776. if (_cHRows < _cRowsDisp || _cHRows == 0)
  777. {
  778. // can't scroll
  779. *pDist = 0;
  780. }
  781. else
  782. {
  783. // Try to fetch new last row
  784. HROW hrow;
  785. CBookMark bmk;
  786. GetBookMark (_aHRows[_cHRows-1], bmk);
  787. DBCOUNTITEM cRowsFetched = 0;
  788. if ( !_xWatch.IsNull() )
  789. _xWatch->Move( _hRegion );
  790. FetchResult res = Fetch ( bmk, 1, 1, cRowsFetched, &hrow, _hRegion);
  791. if ( ( isFetchOK( res ) ) && ( 1 == cRowsFetched ) )
  792. {
  793. // release zeroth row
  794. _xRowset->ReleaseRows (1, _aHRows, 0, 0, 0);
  795. // shift all rows up
  796. for (ULONG i = 0; i < _cHRows - 1; i++)
  797. _aHRows [i] = _aHRows [i+1];
  798. // if we fetched the row
  799. if (cRowsFetched == 1)
  800. _aHRows [_cHRows - 1] = hrow;
  801. GetBookMark (_aHRows[0], _bmkTop);
  802. }
  803. else *pDist = 0;
  804. }
  805. } //ScrollLineDn
  806. void CSearchQuery::ScrollPageUp(
  807. long* pDist)
  808. {
  809. if (_cHRows == 0)
  810. {
  811. *pDist = 0;
  812. return;
  813. }
  814. // Try to fetch new first rows
  815. CBookMark bmk;
  816. GetBookMark (_aHRows[0], bmk);
  817. DBCOUNTITEM cRowsFetched = 0;
  818. long count = *pDist;
  819. FetchResult res;
  820. if ( !_xWatch.IsNull() )
  821. _xWatch->Move( _hRegion );
  822. res = Fetch ( bmk, -count, count, cRowsFetched, _aHRowsTmp, _hRegion);
  823. *pDist = (long) cRowsFetched;
  824. if ( isFetchOK( res ) && cRowsFetched != 0)
  825. {
  826. // release rows at the end
  827. int cRowsToRelease = (int) ( _cHRows + cRowsFetched - _cRowsDisp );
  828. int cRowsToShift = (int) ( _cRowsDisp - cRowsFetched );
  829. _cHRows += (ULONG) cRowsFetched;
  830. if (cRowsToRelease > 0)
  831. {
  832. Win4Assert ( cRowsToShift >= 0);
  833. _xRowset->ReleaseRows (cRowsToRelease,
  834. _aHRows + cRowsToShift, 0, 0, 0);
  835. _cHRows -= cRowsToRelease;
  836. }
  837. if (cRowsToShift > 0)
  838. {
  839. for (int i = 0; i < cRowsToShift; i++)
  840. _aHRowsTmp[cRowsFetched + i] = _aHRows[i];
  841. }
  842. for (ULONG i = 0; i < _cRowsDisp; i++)
  843. _aHRows[i] = _aHRowsTmp[i];
  844. if (res == fetchBoundary)
  845. _bmkTop.MakeFirst();
  846. else
  847. GetBookMark (_aHRows[0], _bmkTop);
  848. }
  849. } //ScrollPageUp
  850. void CSearchQuery::ScrollPageDn(
  851. long* pDist)
  852. {
  853. if (_cHRows < _cRowsDisp || _cHRows == 0)
  854. {
  855. // can't scroll
  856. *pDist = 0;
  857. }
  858. else
  859. {
  860. // Try to fetch new bottom rows
  861. CBookMark bmk;
  862. GetBookMark (_aHRows[_cHRows-1], bmk);
  863. DBCOUNTITEM cRowsFetched = 0;
  864. if ( !_xWatch.IsNull() )
  865. _xWatch->Move( _hRegion );
  866. FetchResult res = Fetch ( bmk, 1, *pDist, cRowsFetched, _aHRowsTmp, _hRegion);
  867. *pDist = (long) cRowsFetched;
  868. if ( isFetchOK( res ) && ( cRowsFetched > 0 ) )
  869. {
  870. int cRowsToRelease = (int) ( cRowsFetched + _cHRows - _cRowsDisp );
  871. int cRowsToShift = (int) ( _cRowsDisp - cRowsFetched );
  872. // release top rows
  873. _xRowset->ReleaseRows (cRowsToRelease, _aHRows, 0, 0, 0);
  874. // shift all rows up
  875. for (int i = 0; i < cRowsToShift; i++)
  876. _aHRows [i] = _aHRows [i+cRowsToRelease];
  877. for (ULONG j = 0; j < cRowsFetched; j++)
  878. _aHRows [cRowsToShift + j] = _aHRowsTmp[j];
  879. _cHRows = (ULONG) ( cRowsToShift + cRowsFetched );
  880. GetBookMark (_aHRows[0], _bmkTop);
  881. }
  882. }
  883. } //ScrollPageDn
  884. void CSearchQuery::ScrollBottom(
  885. long* pDist)
  886. {
  887. CBookMark bmk(DBBMK_LAST);
  888. DBCOUNTITEM cRowsFetched = 0;
  889. if ( !_xWatch.IsNull() )
  890. _xWatch->Move (_hRegion);
  891. FetchResult res = Fetch ( bmk, 1 - *pDist, *pDist, cRowsFetched, _aHRowsTmp, _hRegion);
  892. if ( isFetchOK( res ) )
  893. {
  894. _xRowset->ReleaseRows(_cHRows, _aHRows, 0, 0, 0);
  895. for (ULONG i = 0; i < cRowsFetched; i++)
  896. _aHRows[i] = _aHRowsTmp[i];
  897. for (; i < _cHRows; i++)
  898. _aHRows[i] = 0;
  899. _cHRows = (ULONG) cRowsFetched;
  900. *pDist = (long) cRowsFetched;
  901. GetBookMark (_aHRows[0], _bmkTop);
  902. }
  903. } //ScrollBottom
  904. void CSearchQuery::ScrollTop(
  905. long* pDist)
  906. {
  907. CBookMark bmk(DBBMK_FIRST);
  908. DBCOUNTITEM cRowsFetched = 0;
  909. if ( !_xWatch.IsNull() )
  910. _xWatch->Move (_hRegion);
  911. FetchResult res = Fetch ( bmk, 0, *pDist, cRowsFetched, _aHRowsTmp, _hRegion);
  912. if ( isFetchOK( res ) )
  913. {
  914. _xRowset->ReleaseRows(_cHRows, _aHRows, 0, 0, 0);
  915. for (ULONG i = 0; i < cRowsFetched; i++)
  916. _aHRows[i] = _aHRowsTmp[i];
  917. for (; i < _cHRows; i++)
  918. _aHRows[i] = 0;
  919. _cHRows = (ULONG) cRowsFetched;
  920. *pDist = (long) cRowsFetched;
  921. }
  922. _bmkTop.MakeFirst();
  923. } //ScrollTop
  924. void CSearchQuery::ScrollPos(
  925. long* pDist)
  926. {
  927. DBCOUNTITEM cRowsFetched = 0;
  928. if ( !_xWatch.IsNull() )
  929. _xWatch->Move (_hRegion);
  930. if (FetchApprox (*pDist, _cRowsDisp, cRowsFetched, _aHRowsTmp, _hRegion))
  931. {
  932. _xRowset->ReleaseRows(_cHRows, _aHRows, 0, 0, 0);
  933. for (ULONG i = (ULONG) cRowsFetched; i < _cHRows; i++)
  934. _aHRows[i] = 0;
  935. for (i = 0; i < cRowsFetched; i++)
  936. _aHRows [i] = _aHRowsTmp [i];
  937. _cHRows = (ULONG) cRowsFetched;
  938. CBookMark bmk;
  939. GetBookMark (_aHRowsTmp[0], bmk);
  940. _xRowset->GetApproximatePosition(0, bmk.cbBmk, bmk.abBmk, &_iRowCurrent, &_cRowsTotal);
  941. if (_iRowCurrent > 0)
  942. _iRowCurrent--;
  943. *pDist = (long) _iRowCurrent;
  944. GetBookMark (_aHRows[0], _bmkTop);
  945. }
  946. else
  947. *pDist = -1;
  948. } //ScrollPos
  949. void CSearchQuery::InvalidateCache()
  950. {
  951. ULONG cRows = _cRowsDisp;
  952. ULONG zero = 0;
  953. WindowResized (zero);
  954. WindowResized (cRows);
  955. } //InvalidateCache
  956. void CSearchQuery::UpdateProgress(
  957. BOOL& fMore)
  958. {
  959. if ( _xRowset.IsNull() )
  960. {
  961. _pctDone = 0;
  962. return;
  963. }
  964. #if 0
  965. if ( !_xRowsetStatus.IsNull() )
  966. {
  967. ULONG ulNumerator,ulDenominator;
  968. DWORD cFilteredDocs,cDocsToFilter;
  969. SCODE sc;
  970. if ( 0 != _cHRows )
  971. {
  972. sc = _xRowsetStatus->GetStatusEx( &_dwQueryStatus,
  973. &cFilteredDocs,
  974. &cDocsToFilter,
  975. &ulDenominator,
  976. &ulNumerator,
  977. _bmkTop.cbBmk,
  978. _bmkTop.abBmk,
  979. &_iRowCurrent,
  980. &_cRowsTotal );
  981. _iRowCurrent--; // zero base
  982. }
  983. else
  984. {
  985. DWORD current;
  986. sc = _xRowsetStatus->GetStatusEx( &_dwQueryStatus,
  987. &cFilteredDocs,
  988. &cDocsToFilter,
  989. &ulDenominator,
  990. &ulNumerator,
  991. 0,
  992. 0,
  993. &current,
  994. &_cRowsTotal );
  995. }
  996. if ( FAILED( sc ) )
  997. {
  998. // query failed when we weren't looking
  999. _pctDone = 100;
  1000. _iRowCurrent = 0;
  1001. _cRowsTotal = 0;
  1002. _fDone = TRUE;
  1003. _dwQueryStatus = STAT_ERROR;
  1004. _scLastError = sc;
  1005. }
  1006. else
  1007. {
  1008. Win4Assert( ulNumerator <= ulDenominator );
  1009. _pctDone = 100 * ulNumerator;
  1010. if ( 0 == ulDenominator ) // Prevent division by 0
  1011. ulDenominator = 1;
  1012. _pctDone /= ulDenominator;
  1013. }
  1014. }
  1015. else
  1016. #endif // 0
  1017. {
  1018. DBCOUNTITEM ulNumerator, ulDenominator;
  1019. DBASYNCHPHASE ulAsynchPhase;
  1020. SCODE sc = _xDBAsynchStatus->GetStatus( DB_NULL_HCHAPTER,
  1021. DBASYNCHOP_OPEN,
  1022. &ulNumerator,
  1023. &ulDenominator,
  1024. &ulAsynchPhase,
  1025. 0 );
  1026. if ( FAILED( sc ) )
  1027. {
  1028. // query failed when we weren't looking
  1029. _pctDone = 100;
  1030. _iRowCurrent = 0;
  1031. _cRowsTotal = 0;
  1032. _fDone = TRUE;
  1033. }
  1034. else
  1035. {
  1036. if ( !_xRowsetStatus.IsNull() )
  1037. _xRowsetStatus->GetStatus( &_dwQueryStatus );
  1038. Win4Assert( (ulAsynchPhase == DBASYNCHPHASE_COMPLETE) ?
  1039. (ulNumerator == ulDenominator) :
  1040. (ulNumerator < ulDenominator) );
  1041. _pctDone = 100 * (ULONG) ulNumerator;
  1042. if ( 0 == ulDenominator ) // Prevent division by 0
  1043. ulDenominator = 1;
  1044. _pctDone /= (ULONG) ulDenominator;
  1045. if (_cHRows != 0)
  1046. {
  1047. _xRowset->GetApproximatePosition( 0,
  1048. _bmkTop.cbBmk,
  1049. _bmkTop.abBmk,
  1050. &_iRowCurrent,
  1051. &_cRowsTotal );
  1052. _iRowCurrent--; // zero base
  1053. }
  1054. else
  1055. {
  1056. _xRowset->GetApproximatePosition(0, 0, 0, 0, &_cRowsTotal);
  1057. }
  1058. }
  1059. }
  1060. } //UpdateProgress
  1061. void CSearchQuery::ProcessNotification(
  1062. HWND hwndList,
  1063. DBWATCHNOTIFY changeType,
  1064. IRowset * pRowset)
  1065. {
  1066. if ( _xRowset.GetPointer() == pRowset && !_xWatch.IsNull() )
  1067. _xWatch->Notify( hwndList, changeType );
  1068. _dwEndTime = GetTickCount();
  1069. } //ProcessNotification
  1070. void CSearchQuery::ProcessNotificationComplete()
  1071. {
  1072. if ( !_xWatch.IsNull() )
  1073. _xWatch->NotifyComplete();
  1074. } //ProcessNotificationComplete
  1075. void CSearchQuery::CreateScript(
  1076. DBCOUNTITEM * pcChanges,
  1077. DBROWWATCHCHANGE ** paScript)
  1078. {
  1079. if (_cRowsDisp == 0)
  1080. {
  1081. *pcChanges = 0;
  1082. return;
  1083. }
  1084. Win4Assert (_cHRows == 0 || _aHRows[_cHRows-1] != 0);
  1085. *paScript = (DBROWWATCHCHANGE*) CoTaskMemAlloc (2 * _cRowsDisp * sizeof DBROWWATCHCHANGE);
  1086. DBCOUNTITEM cRowsFetched = 0;
  1087. if ( !_xWatch.IsNull() )
  1088. _xWatch->Move (_hRegion);
  1089. //srchDebugOut((DEB_TRACE,"CreateScript fetch\n"));
  1090. Fetch ( _bmkTop, 0, _cRowsDisp, cRowsFetched, _aHRowsTmp, _hRegion);
  1091. if (cRowsFetched > 0)
  1092. {
  1093. //srchDebugOut((DEB_TRACE," CreateScript fetched %d rows\n",cRowsFetched));
  1094. ULONG iSrc = 0;
  1095. ULONG iDst = 0;
  1096. do
  1097. {
  1098. if ( iDst == _cHRows || _aHRows[iDst] != _aHRowsTmp [iSrc])
  1099. {
  1100. // maybe the current iDst row was deleted?
  1101. // Find out it the iSrc row appears
  1102. // somewhere after the current row
  1103. for (ULONG i = iDst + 1; i < _cHRows; i++)
  1104. {
  1105. if (_aHRows[i] == _aHRowsTmp[iSrc])
  1106. break;
  1107. }
  1108. if (i < _cHRows && iSrc < _cRowsDisp )
  1109. {
  1110. // everything from iDst up to i - 1
  1111. // has been deleted
  1112. while ( iDst < i )
  1113. {
  1114. DBROWWATCHCHANGE& change = (*paScript)[*pcChanges];
  1115. change.hRegion = _hRegion;
  1116. change.eChangeKind = DBROWCHANGEKIND_DELETE;
  1117. change.iRow = iSrc;
  1118. change.hRow = 0;
  1119. (*pcChanges)++;
  1120. iDst++;
  1121. }
  1122. }
  1123. else
  1124. {
  1125. // insertion
  1126. DBROWWATCHCHANGE& change = (*paScript)[*pcChanges];
  1127. change.hRegion = _hRegion;
  1128. change.eChangeKind = DBROWCHANGEKIND_INSERT;
  1129. change.iRow = iSrc - 1;
  1130. change.hRow = _aHRowsTmp[iSrc];
  1131. (*pcChanges)++;
  1132. iSrc++;
  1133. }
  1134. }
  1135. else
  1136. {
  1137. //srchDebugOut((DEB_TRACE," CreateScript ignoring row %d\n",_aHRowsTmp[iSrc]));
  1138. _xRowset->ReleaseRows ( 1, _aHRowsTmp + iSrc, 0, 0, 0);
  1139. iDst++;
  1140. iSrc++;
  1141. }
  1142. } while (iDst < _cRowsDisp && iSrc < cRowsFetched);
  1143. if ( iSrc < cRowsFetched )
  1144. {
  1145. //srchDebugOut((DEB_TRACE," CreateScript freeing rows left behind\n"));
  1146. _xRowset->ReleaseRows ( cRowsFetched - iSrc,
  1147. _aHRowsTmp + iSrc,
  1148. 0, 0, 0);
  1149. }
  1150. else if (iSrc == cRowsFetched && iSrc < _cRowsDisp)
  1151. {
  1152. // the rest of the rows were deleted
  1153. while (iDst < _cHRows)
  1154. {
  1155. DBROWWATCHCHANGE& change = (*paScript)[*pcChanges];
  1156. change.hRegion = _hRegion;
  1157. change.eChangeKind = DBROWCHANGEKIND_DELETE;
  1158. change.iRow = iSrc;
  1159. change.hRow = 0;
  1160. (*pcChanges)++;
  1161. iDst++;
  1162. }
  1163. }
  1164. }
  1165. if (*pcChanges == 0)
  1166. {
  1167. CoTaskMemFree (*paScript);
  1168. *paScript = 0;
  1169. }
  1170. } //CreateScript
  1171. void CSearchQuery::InsertRowAfter(
  1172. int iRow,
  1173. HROW hrow)
  1174. {
  1175. Win4Assert (iRow >= -1 && iRow < (int) _cHRows && iRow < (int)_cRowsDisp - 1);
  1176. int iLastRow = _cHRows - 1;
  1177. // release last row
  1178. if (_cHRows == _cRowsDisp)
  1179. {
  1180. //srchDebugOut((DEB_TRACE,"InsertRowAfter releasing 1 row %d\n",_aHRows[iLastRow]));
  1181. _xRowset->ReleaseRows(1, _aHRows + iLastRow, 0, 0, 0);
  1182. // shift rows down
  1183. for (int i = iLastRow; i > iRow + 1; i--)
  1184. {
  1185. _aHRows [i] = _aHRows [i-1];
  1186. }
  1187. }
  1188. else
  1189. {
  1190. // shift rows down
  1191. for (int i = iLastRow + 1; i > iRow + 1; i--)
  1192. {
  1193. _aHRows [i] = _aHRows [i-1];
  1194. }
  1195. _cHRows++;
  1196. }
  1197. _aHRows [iRow + 1] = hrow;
  1198. if (iRow == -1 && !_bmkTop.IsFirst())
  1199. {
  1200. GetBookMark (_aHRows[0], _bmkTop);
  1201. }
  1202. } //InsertRowAfter
  1203. void CSearchQuery::DeleteRow(
  1204. int iRow)
  1205. {
  1206. // with limited rows, rows to be deleted may exceed the number of
  1207. // rows in the result
  1208. //Win4Assert (iRow >= 0 && iRow < (int)_cHRows);
  1209. if ( _aHRows[iRow] > 0 )
  1210. {
  1211. _xRowset->ReleaseRows (1, _aHRows + iRow, 0, 0, 0);
  1212. _aHRows[iRow] = 0;
  1213. }
  1214. // shift rows up
  1215. for (ULONG i = iRow; i < _cHRows - 1; i++)
  1216. _aHRows [i] = _aHRows [i+1];
  1217. #if 0
  1218. if (_cHRows < _cRowsDisp)
  1219. {
  1220. _aHRows[_cHRows-1] = 0;
  1221. _cHRows--;
  1222. }
  1223. else
  1224. {
  1225. // Try to fetch new last row
  1226. HROW hrow;
  1227. CBookMark bmk;
  1228. GetBookMark (_aHRows[_cHRows-1], bmk);
  1229. DBCOUNTITEM cRowsFetched = 0;
  1230. // no need when running script
  1231. if ( !_xWatch.IsNull() )
  1232. _xWatch->Move (_hRegion);
  1233. FetchResult res = Fetch ( bmk, 1, 1, cRowsFetched, &hrow, _hRegion);
  1234. if ( isFetchOK( res ) && ( cRowsFetched > 0 ) )
  1235. _xRowset->ReleaseRows(1, &hrow, 0, 0, 0);
  1236. }
  1237. #else
  1238. if ( (ULONG)iRow < _cHRows )
  1239. {
  1240. _aHRows[_cHRows-1] = 0;
  1241. _cHRows--;
  1242. }
  1243. #endif
  1244. if (iRow == 0 && !_bmkTop.IsFirst() && _aHRows[0] != 0)
  1245. GetBookMark (_aHRows[0], _bmkTop);
  1246. } //DeleteRow
  1247. void CSearchQuery::UpdateRow(
  1248. int iRow,
  1249. HROW hrow)
  1250. {
  1251. Win4Assert (iRow >= 0 && iRow < (int)_cHRows);
  1252. //srchDebugOut((DEB_TRACE,"UpdateRowAfter releasing 1 row %d\n",_aHRows[iRow]));
  1253. _xRowset->ReleaseRows (1, _aHRows + iRow, 0, 0, 0);
  1254. _aHRows[iRow] = hrow;
  1255. } //UpdateRow
  1256. BOOL CSearchQuery::GetSelectedRowData(
  1257. WCHAR *&rpPath,
  1258. HROW &hrow )
  1259. {
  1260. if (!_bmkSelect.IsValid())
  1261. return FALSE;
  1262. DBCOUNTITEM cRowsFetched = 0;
  1263. FetchResult res = Fetch ( _bmkSelect, 0, 1, cRowsFetched, &hrow, 0);
  1264. if ( ( !isFetchOK( res ) ) || ( cRowsFetched != 1 ) )
  1265. return FALSE;
  1266. return SUCCEEDED( _xRowset->GetData( hrow, _hBrowseAccessor, &rpPath ) );
  1267. } //GetSelectedRowData
  1268. void CSearchQuery::FreeSelectedRowData(
  1269. HROW hrow )
  1270. {
  1271. _xRowset->ReleaseRows( 1, &hrow, 0, 0, 0 );
  1272. } //FreeSelectedRowData
  1273. BOOL CSearchQuery::Browse( enumViewFile eViewType )
  1274. {
  1275. BOOL fOK = TRUE;
  1276. if (!_bmkSelect.IsValid())
  1277. return TRUE;
  1278. HROW hrow;
  1279. DBCOUNTITEM cRowsFetched = 0;
  1280. FetchResult res = Fetch( _bmkSelect, 0, 1, cRowsFetched, &hrow, 0 );
  1281. if ( ( !isFetchOK( res ) ) || ( cRowsFetched != 1 ) )
  1282. return fOK;
  1283. WCHAR *pwcPathFound;
  1284. SCODE sc = _xRowset->GetData( hrow, _hBrowseAccessor, &pwcPathFound );
  1285. if (SUCCEEDED(sc) && ( 0 != _prstQuery ) )
  1286. {
  1287. fOK = ViewFile( pwcPathFound, eViewType, 1, _prstQuery );
  1288. _xRowset->ReleaseRows(1, &hrow, 0, 0, 0);
  1289. }
  1290. else
  1291. fOK = FALSE;
  1292. return fOK;
  1293. } //Browse
  1294. //
  1295. // Helper method(s)
  1296. //
  1297. void CSearchQuery::ParseCatList( WCHAR * * aScopes, WCHAR * * aCatalogs,
  1298. WCHAR * * aMachines, DWORD * aDepths,
  1299. ULONG & cScopes )
  1300. {
  1301. BOOL fDeep;
  1302. WCHAR aScope[MAX_PATH];
  1303. WCHAR aCatalog[MAX_PATH];
  1304. WCHAR aMachine[MAX_PATH];
  1305. for(cScopes = 0; ; cScopes++)
  1306. {
  1307. if ( !GetCatListItem( _xCatList,
  1308. cScopes,
  1309. aMachine,
  1310. aCatalog,
  1311. aScope,
  1312. fDeep ) )
  1313. {
  1314. break;
  1315. }
  1316. aMachines[cScopes] = new WCHAR[ wcslen( aMachine ) + 1 ];
  1317. aCatalogs[cScopes] = new WCHAR[ wcslen( aCatalog ) + 1 ];
  1318. aScopes[cScopes] = new WCHAR[ wcslen( aScope ) + 1 ];
  1319. wcscpy( aMachines[cScopes], aMachine );
  1320. wcscpy( aCatalogs[cScopes], aCatalog );
  1321. wcscpy( aScopes[cScopes], aScope );
  1322. aDepths[cScopes] = ( fDeep ? QUERY_DEEP : QUERY_SHALLOW );
  1323. // If the scope is virtual, set the flag and flip the slashes
  1324. if ( L'/' == aScope[0] )
  1325. {
  1326. aDepths[ cScopes ] |= QUERY_VIRTUAL_PATH;
  1327. for ( WCHAR *p = aScopes[cScopes]; *p; p++ )
  1328. if ( L'/' == *p )
  1329. *p = L'\\';
  1330. }
  1331. }
  1332. }
  1333. SCODE CSearchQuery::InstantiateICommand(
  1334. ICommand ** ppICommand )
  1335. {
  1336. DWORD aDepths[ 20 ]; // hope 20 is big enough
  1337. WCHAR * aScopes[ 20 ];
  1338. WCHAR * aCatalogs[ 20 ];
  1339. WCHAR * aMachines[ 20 ];
  1340. ULONG cScopes = 0;
  1341. SCODE sc = S_FALSE;
  1342. ParseCatList( aScopes, aCatalogs, aMachines, aDepths, cScopes );
  1343. *ppICommand = 0;
  1344. sc = CIMakeICommand( ppICommand,
  1345. cScopes,
  1346. aDepths,
  1347. (WCHAR const * const *)aScopes,
  1348. (WCHAR const * const *)aCatalogs,
  1349. (WCHAR const * const *)aMachines );
  1350. unsigned ii;
  1351. for( ii = 0; ii < cScopes; ii ++)
  1352. {
  1353. delete [] aMachines[ii]; // This mem may not get deleted if we throw
  1354. delete [] aCatalogs[ii]; // in this func ?
  1355. delete [] aScopes[ii];
  1356. }
  1357. return sc;
  1358. } //InstantiateICommand
  1359. BOOL CSearchQuery::FetchApprox(
  1360. LONG iFirstRow,
  1361. LONG cToFetch,
  1362. DBCOUNTITEM &rcFetched,
  1363. HROW *pHRows,
  1364. HWATCHREGION hRegion)
  1365. {
  1366. SCODE sc;
  1367. if ( 0 != _cRowsTotal )
  1368. {
  1369. sc = _xRowset->GetRowsAtRatio( hRegion,
  1370. 0, // no chapters
  1371. iFirstRow,
  1372. _cRowsTotal,
  1373. cToFetch,
  1374. &rcFetched,
  1375. &pHRows );
  1376. if ( FAILED( sc ) )
  1377. _scLastError = sc;
  1378. }
  1379. else
  1380. {
  1381. rcFetched = 0;
  1382. sc = S_OK;
  1383. }
  1384. return (SUCCEEDED(sc) && rcFetched);
  1385. } //FetchApprox
  1386. FetchResult CSearchQuery::Fetch(
  1387. CBookMark & bmkStart,
  1388. LONG iFirstRow,
  1389. LONG cToFetch,
  1390. DBCOUNTITEM & rcFetched,
  1391. HROW * pHRows,
  1392. HWATCHREGION hRegion)
  1393. {
  1394. //srchDebugOut((DEB_TRACE," Fetch fetch\n"));
  1395. Win4Assert (bmkStart.IsValid());
  1396. SCODE scTmp;
  1397. SCODE sc = _xRowset->GetRowsAt( hRegion,
  1398. 0, // no chapters
  1399. bmkStart.cbBmk,
  1400. bmkStart.abBmk,
  1401. iFirstRow,
  1402. cToFetch,
  1403. &rcFetched,
  1404. &pHRows );
  1405. WCHAR* szError = 0;
  1406. WCHAR buf[100];
  1407. if ( FAILED( sc ) )
  1408. _scLastError = sc;
  1409. switch (sc)
  1410. {
  1411. case S_OK:
  1412. //srchDebugOut((DEB_TRACE," ::fetch ok got %d rows, first: %d\n",rcFetched,pHRows[0]));
  1413. if (cToFetch == (long)rcFetched)
  1414. return fetchOk;
  1415. else
  1416. szError = L"Incomplete Fetch returned S_OK";
  1417. break;
  1418. case DB_S_ENDOFROWSET:
  1419. //srchDebugOut((DEB_TRACE," ::fetch EOR got %d rows, first: %d\n",rcFetched,pHRows[0]));
  1420. // Debugging
  1421. // Turn it back on when we have frozen state!
  1422. //
  1423. if ( FALSE && rcFetched != 0)
  1424. {
  1425. HROW* pHRowsTmp = new HROW [cToFetch];
  1426. DBCOUNTITEM cFetchedTmp = 0;
  1427. CBookMark bmk;
  1428. GetBookMark (pHRows[0], bmk);
  1429. scTmp = _xRowset->GetRowsAt( hRegion,
  1430. 0, // no chapters
  1431. bmk.cbBmk,
  1432. bmk.abBmk,
  1433. 0,
  1434. cToFetch,
  1435. &cFetchedTmp,
  1436. &pHRowsTmp );
  1437. if (FAILED(scTmp))
  1438. {
  1439. szError = buf;
  1440. swprintf (buf, L"Repeated call returned error 0x%04x", scTmp);
  1441. }
  1442. else if (cFetchedTmp < rcFetched)
  1443. {
  1444. szError = L"Repeated call returned fewer rows";
  1445. }
  1446. else
  1447. {
  1448. for (ULONG i = 0; i < rcFetched; i++)
  1449. {
  1450. if (pHRows[i] != pHRowsTmp[i])
  1451. {
  1452. szError = L"Repeated call returned different HROWs";
  1453. break;
  1454. }
  1455. }
  1456. }
  1457. _xRowset->ReleaseRows(cFetchedTmp, pHRowsTmp, 0, 0, 0);
  1458. delete pHRowsTmp;
  1459. if (szError != 0)
  1460. break;
  1461. }
  1462. return fetchBoundary;
  1463. case DB_E_BADSTARTPOSITION:
  1464. //srchDebugOut((DEB_TRACE," ::fetch %d returned DB_E_BADSTARTPOSITION \n",cToFetch));
  1465. //Win4Assert(sc != DB_E_BADSTARTPOSITION);
  1466. szError = L"DB_E_BADSTARTPOSITION";
  1467. break;
  1468. case DB_S_BOOKMARKSKIPPED:
  1469. szError = L"DB_S_BOOKMARKSKIPPED";
  1470. break;
  1471. case DB_S_ROWLIMITEXCEEDED:
  1472. szError = L"DB_S_ROWLIMITEXCEEDED";
  1473. break;
  1474. case DB_E_BADBOOKMARK:
  1475. szError = L"DB_E_BADBOOKMARK";
  1476. break;
  1477. case DB_E_BADCHAPTER:
  1478. szError = L"DB_E_BADCHAPTER";
  1479. break;
  1480. case DB_E_NOTREENTRANT:
  1481. szError = L"DB_E_NOTREENTRANT";
  1482. break;
  1483. case E_FAIL:
  1484. szError = L"E_FAIL";
  1485. break;
  1486. case E_INVALIDARG:
  1487. szError = L"E_INVALIDARG";
  1488. break;
  1489. case E_OUTOFMEMORY:
  1490. szError = L"E_OUTOFMEMORY";
  1491. break;
  1492. case E_UNEXPECTED:
  1493. szError = L"E_UNEXPECTED";
  1494. break;
  1495. default:
  1496. szError = buf;
  1497. swprintf (buf, L"Unexpected error 0x%04x", sc);
  1498. }
  1499. //MessageBox ( 0, szError, L"GetRowsAt", MB_OK );
  1500. return fetchError;
  1501. } //Fetch
  1502. const unsigned cAtATime = 20;
  1503. void CSearchQuery::WriteResults()
  1504. {
  1505. CBookMark bmk(DBBMK_FIRST);
  1506. XArray<HROW> xRows( cAtATime );
  1507. ULONG cRowsToGo = (ULONG) _cRowsTotal;
  1508. CDynArrayInPlace<WCHAR> awcBuf( 4096 );
  1509. int cwc = 0;
  1510. while ( 0 != cRowsToGo )
  1511. {
  1512. DBCOUNTITEM cFetched = 0;
  1513. FetchResult res = Fetch( bmk,
  1514. (LONG) ( _cRowsTotal - cRowsToGo ),
  1515. __min( cAtATime, cRowsToGo ),
  1516. cFetched,
  1517. xRows.GetPointer(),
  1518. 0 );
  1519. if ( ( fetchError == res ) ||
  1520. ( 0 == cFetched ) )
  1521. return;
  1522. cRowsToGo -= (ULONG) cFetched;
  1523. for ( ULONG row = 0; row < cFetched; row++ )
  1524. {
  1525. WCHAR *pwcPath;
  1526. _xRowset->GetData( xRows[ row ], _hBrowseAccessor, &pwcPath );
  1527. while ( *pwcPath )
  1528. awcBuf[ cwc++ ] = *pwcPath++;
  1529. awcBuf[ cwc++ ] = L'\r';
  1530. awcBuf[ cwc++ ] = L'\n';
  1531. }
  1532. _xRowset->ReleaseRows( cFetched, xRows.GetPointer(), 0, 0, 0 );
  1533. }
  1534. awcBuf[ cwc++ ] = 0;
  1535. PutInClipboard( awcBuf.Get() );
  1536. } //WriteResults
  1537. const unsigned COUNT_HIDDEN_COLUMNS = 1;
  1538. void CSearchQuery::SetupColumnMappingsAndAccessors()
  1539. {
  1540. // allocate the necessary resources
  1541. unsigned cColumns = _columns.NumberOfColumns();
  1542. DBID aDbCols[maxBoundCols];
  1543. for ( unsigned iCol = 0; iCol < cColumns; iCol++ )
  1544. {
  1545. // Get the next desired property
  1546. DBTYPE propType;
  1547. unsigned int uiWidth;
  1548. DBID *pdbid;
  1549. SCODE sc = _columnMapper.GetPropInfoFromName( _columns.GetColumn( iCol ),
  1550. &pdbid,
  1551. &propType,
  1552. &uiWidth );
  1553. memcpy( &aDbCols[ iCol ], pdbid, sizeof DBID );
  1554. if (FAILED(sc))
  1555. THROW( CException( sc ) );
  1556. }
  1557. IColumnsInfo *pColInfo = 0;
  1558. SCODE sc = _xRowset->QueryInterface ( IID_IColumnsInfo,
  1559. ( void ** )&pColInfo );
  1560. if (FAILED(sc))
  1561. THROW( CException( sc ) );
  1562. XInterface< IColumnsInfo > xColInfo( pColInfo );
  1563. DBORDINAL aColumnIds[ maxBoundCols ];
  1564. // Map the columns
  1565. sc = pColInfo->MapColumnIDs( cColumns, aDbCols, aColumnIds );
  1566. if (FAILED(sc))
  1567. THROW (CException (sc));
  1568. // Map hidden columns
  1569. DBID apsHidden[COUNT_HIDDEN_COLUMNS];
  1570. apsHidden[0] = dbcolPath;
  1571. DBORDINAL aColumnIdHidden[COUNT_HIDDEN_COLUMNS];
  1572. sc = pColInfo->MapColumnIDs( 1,
  1573. apsHidden,
  1574. aColumnIdHidden );
  1575. if (FAILED(sc))
  1576. THROW (CException (sc));
  1577. // allocate the necessary resources and cache in the
  1578. // object
  1579. DBBINDING aGenBindings[maxBoundCols];
  1580. ULONG oCurrentOffset = 0;
  1581. // Add each requested property to the binding
  1582. for ( unsigned iBind = 0; iBind < cColumns; iBind++ )
  1583. {
  1584. // Set up the binding array
  1585. aGenBindings[ iBind ].iOrdinal = aColumnIds[ iBind ]; // Ordinal of column
  1586. aGenBindings[ iBind ].obValue = oCurrentOffset; // Offset of data
  1587. aGenBindings[ iBind ].obLength = 0, // Offset where length data is stored
  1588. aGenBindings[ iBind ].obStatus = 0, // Status info for column written
  1589. aGenBindings[ iBind ].pTypeInfo = 0, // Reserved
  1590. aGenBindings[ iBind ].pObject = 0, // DBOBJECT structure
  1591. aGenBindings[ iBind ].pBindExt = 0, // Ignored
  1592. aGenBindings[ iBind ].dwPart = DBPART_VALUE; // Return data
  1593. aGenBindings[ iBind ].dwMemOwner = DBMEMOWNER_PROVIDEROWNED; // Memory owne
  1594. aGenBindings[ iBind ].eParamIO = 0; // eParamIo
  1595. aGenBindings[ iBind ].cbMaxLen = sizeof(PROPVARIANT *); // Size of data to return
  1596. aGenBindings[ iBind ].dwFlags = 0; // Reserved
  1597. aGenBindings[ iBind ].wType = DBTYPE_VARIANT | DBTYPE_BYREF; // Type of return data
  1598. aGenBindings[ iBind ].bPrecision = 0; // Precision to use
  1599. aGenBindings[ iBind ].bScale = 0; // Scale to us
  1600. oCurrentOffset += sizeof( PROPVARIANT *);
  1601. }
  1602. sc = _xIAccessor->CreateAccessor( DBACCESSOR_ROWDATA,
  1603. cColumns,
  1604. aGenBindings,
  1605. 0, // cbRowSize
  1606. &_hAccessor,
  1607. 0 );
  1608. if (FAILED(sc))
  1609. THROW ( CException( sc ) );
  1610. DBBINDING aBrowBindings[1];
  1611. aBrowBindings[0] = dbbindingPath;
  1612. aBrowBindings[0].iOrdinal = aColumnIdHidden[0];
  1613. sc = _xIAccessor->CreateAccessor( DBACCESSOR_ROWDATA,
  1614. 1,
  1615. aBrowBindings,
  1616. 0, // cbRowSize
  1617. &_hBrowseAccessor,
  1618. 0 );
  1619. if (FAILED(sc))
  1620. THROW ( CException( sc ) );
  1621. } //SetupColumnMappingsAndAccessors