Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2442 lines
74 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1995 - 2000.
  5. //
  6. // File: qryspec.cxx
  7. //
  8. // Contents: ICommandTree implementation for OFS file stores
  9. //
  10. // Classes: CRootQuerySpec
  11. //
  12. // Functions: CheckForErrors
  13. // CheckForPriorTree
  14. //
  15. // History: 30 Jun 1995 AlanW Created
  16. // 10-31-97 danleg Added ICommandText & ICommandPrepare
  17. //
  18. //----------------------------------------------------------------------------
  19. #include "pch.cxx"
  20. #pragma hdrstop
  21. #include <colinfo.hxx>
  22. #include <parstree.hxx>
  23. #include <hraccess.hxx>
  24. #include <mparser.h>
  25. #include <propglob.hxx>
  26. #include <doquery.hxx>
  27. #include "qryspec.hxx"
  28. // Command object Interfaces that support Ole DB error objects
  29. static const IID * apCommandErrorIFs[] =
  30. {
  31. &IID_IAccessor,
  32. &IID_IColumnsInfo,
  33. &IID_ICommand,
  34. &IID_ICommandProperties,
  35. &IID_ICommandText,
  36. &IID_IConvertType,
  37. //&IID_IColumnsRowset,
  38. &IID_ICommandPrepare,
  39. &IID_ICommandTree,
  40. //&IID_ICommandWithParameters,
  41. &IID_IQuery,
  42. //&IID_ISupportErrorInfo,
  43. &IID_IServiceProperties
  44. };
  45. static const ULONG cCommandErrorIFs = sizeof(apCommandErrorIFs)/sizeof(apCommandErrorIFs[0]);
  46. // SQL defining global views. These views are defined at the datasrc level, if one is present,
  47. // or at the command level otherwise.
  48. extern const LPWSTR s_pwszPredefinedViews =
  49. L"SET GLOBAL ON; "
  50. L"CREATE VIEW FILEINFO "
  51. L" AS SELECT PATH, FILENAME, SIZE, WRITE, ATTRIB FROM SCOPE(); "
  52. L"CREATE VIEW FILEINFO_ABSTRACT "
  53. L" AS SELECT PATH, FILENAME, SIZE, WRITE, ATTRIB, CHARACTERIZATION FROM SCOPE(); "
  54. L"CREATE VIEW EXTENDED_FILEINFO "
  55. L" AS SELECT PATH, FILENAME, SIZE, WRITE, ATTRIB, DOCTITLE, DOCAUTHOR, DOCSUBJECT, DOCKEYWORDS, CHARACTERIZATION FROM SCOPE(); "
  56. L"CREATE VIEW WEBINFO "
  57. L" AS SELECT VPATH, PATH, FILENAME, SIZE, WRITE, ATTRIB, CHARACTERIZATION, DOCTITLE FROM SCOPE(); "
  58. L"CREATE VIEW EXTENDED_WEBINFO "
  59. L" AS SELECT VPATH, PATH, FILENAME, SIZE, CHARACTERIZATION, WRITE, DOCAUTHOR, DOCSUBJECT, DOCKEYWORDS, DOCTITLE FROM SCOPE(); "
  60. L"CREATE VIEW SSWebInfo "
  61. L" AS SELECT URL, DOCTITLE, RANK, SIZE, WRITE FROM SCOPE(); "
  62. L"CREATE VIEW SSExtended_WebInfo "
  63. L" AS SELECT URL, DOCTITLE, RANK, HITCOUNT, DOCAUTHOR, CHARACTERIZATION, SIZE, WRITE FROM SCOPE()";
  64. //+-------------------------------------------------------------------------
  65. //
  66. // Member: CRootQuerySpec::CRootQuerySpec, public
  67. //
  68. // Synopsis: Constructor of a CRootQuerySpec
  69. //
  70. // Arguments: [pOuterUnk] - Outer unknown
  71. // [ppMyUnk] - OUT: filled in with pointer to non-delegated
  72. // IUnknown on return
  73. //
  74. // History: 08-Feb-96 KyleP Added support for virtual paths
  75. //
  76. //--------------------------------------------------------------------------
  77. CRootQuerySpec::CRootQuerySpec (IUnknown * pOuterUnk,
  78. IUnknown ** ppMyUnk,
  79. CDBSession * pSession)
  80. : _dwDepth(QUERY_SHALLOW),
  81. _pInternalQuery(0),
  82. _pQueryTree(0),
  83. _pColumnsInfo(0),
  84. #pragma warning(disable : 4355) // 'this' in a constructor
  85. _impIUnknown(this),
  86. _aAccessors( (IUnknown *) (ICommand *)this ),
  87. _DBErrorObj( * ((IUnknown *) (ICommand *) this), _mtxCmd ),
  88. #pragma warning(default : 4355) // 'this' in a constructor
  89. _dwStatus(0),
  90. _guidCmdDialect(DBGUID_SQL),
  91. _fGenByOpenRowset(FALSE),
  92. _pwszSQLText(0),
  93. _RowsetProps( pSession ?
  94. pSession->GetDataSrcPtr()->GetDSPropsPtr()->
  95. GetValLong( CMDSProps::eid_DBPROPSET_DBINIT,
  96. CMDSProps::eid_DBPROPVAL_INIT_LCID ) :
  97. 0 ),
  98. _PropInfo()
  99. {
  100. if (pOuterUnk)
  101. _pControllingUnknown = pOuterUnk;
  102. else
  103. _pControllingUnknown = (IUnknown * )&_impIUnknown;
  104. _DBErrorObj.SetInterfaceArray(cCommandErrorIFs, apCommandErrorIFs);
  105. if ( pSession )
  106. {
  107. _xSession.Set( pSession );
  108. _xSession->AddRef();
  109. _xpIPSession.Set( pSession->GetParserSession() );
  110. //
  111. // The above Set() doesn't AddRef. This will balance the XInterface<>
  112. // dtor Release
  113. //
  114. _xpIPSession->AddRef();
  115. }
  116. *ppMyUnk = ((IUnknown *)&_impIUnknown);
  117. (*ppMyUnk)->AddRef();
  118. }
  119. //+---------------------------------------------------------------------------
  120. //
  121. // Method: CRootQuerySpec::CRootQuerySpec, public
  122. //
  123. // Synopsis: Copy constructor
  124. //
  125. // Arguments: [src] -- Source query spec
  126. //
  127. // History: 27 Jun 95 AlanW Created
  128. // 10 Jan 98 danleg Replaced body with Assert
  129. //
  130. //----------------------------------------------------------------------------
  131. CRootQuerySpec::CRootQuerySpec( CRootQuerySpec & src )
  132. : _dwDepth( src._dwDepth ),
  133. _pInternalQuery(0),
  134. _pQueryTree(0),
  135. _pColumnsInfo(0),
  136. #pragma warning(disable : 4355) // 'this' in a constructor
  137. _impIUnknown(this),
  138. _aAccessors( (IUnknown *) (ICommand *)this ),
  139. _DBErrorObj( * ((IUnknown *) (ICommand *) this), _mtxCmd ),
  140. #pragma warning(default : 4355) // 'this' in a constructor
  141. _dwStatus(src._dwStatus),
  142. _guidCmdDialect(src._guidCmdDialect),
  143. _fGenByOpenRowset(src._fGenByOpenRowset),
  144. _pwszSQLText(0),
  145. _RowsetProps( src._RowsetProps ),
  146. _PropInfo()
  147. {
  148. Win4Assert( !"CRootQuerySpec copy constructor not implemented.");
  149. }
  150. //+-------------------------------------------------------------------------
  151. //
  152. // Member: CRootQuerySpec::~CRootQuerySpec, private
  153. //
  154. // Synopsis: Destructor of a CRootQuerySpec
  155. //
  156. //--------------------------------------------------------------------------
  157. CRootQuerySpec::~CRootQuerySpec()
  158. {
  159. ReleaseInternalQuery();
  160. delete _pColumnsInfo;
  161. delete _pQueryTree;
  162. delete [] _pwszSQLText;
  163. }
  164. //+-------------------------------------------------------------------------
  165. //
  166. // Member: CRootQuerySpec::RealQueryInterface, public
  167. //
  168. // Synopsis: Get a reference to another interface on the cursor. AddRef
  169. // is done in CImpIUnknown::QueryInterface
  170. //
  171. // History: 10-31-97 danleg Added ICommandText& ICommandPrepare
  172. //
  173. //--------------------------------------------------------------------------
  174. //
  175. // Hack #214: IID_ICommandProperties is intercepted by service layers, which
  176. // don't like us passing in the magic code to fetch hidden scope
  177. // properties. But the controlling unknown doesn't recognize
  178. // IID_IKyleProp and sends it right to us. Implementation is
  179. // identical to ICommandProperties.
  180. //
  181. extern GUID IID_IKyleProp;
  182. SCODE CRootQuerySpec::RealQueryInterface(
  183. REFIID ifid,
  184. void * *ppiuk )
  185. {
  186. SCODE sc = S_OK;
  187. TRY
  188. {
  189. // validate the param before any addrefs
  190. *ppiuk = 0;
  191. // note -- IID_IUnknown covered in QueryInterface
  192. if ( IID_ICommand == ifid )
  193. {
  194. *ppiuk = (void *) ((ICommand *) this);
  195. }
  196. else if (IID_ISupportErrorInfo == ifid)
  197. {
  198. *ppiuk = (void *) ((IUnknown *) (ISupportErrorInfo *) &_DBErrorObj);
  199. }
  200. else if ( IID_IAccessor == ifid )
  201. {
  202. *ppiuk = (void *) (IAccessor *) this;
  203. }
  204. else if ( IID_IColumnsInfo == ifid )
  205. {
  206. *ppiuk = (void *) (IColumnsInfo *) GetColumnsInfo();
  207. }
  208. // NTRAID#DB-NTBUG9-84306-2000/07/31-dlee OLE-DB spec variance in Indexing Service, some interfaces not implemented
  209. #if 0
  210. else if ( IID_IRowsetInfo == ifid )
  211. {
  212. *ppiuk = (void *) (IRowsetInfo *) this;
  213. }
  214. #endif // 0
  215. else if ( IID_ICommandTree == ifid )
  216. {
  217. *ppiuk = (void *) (ICommandTree *) this;
  218. }
  219. // NTRAID#DB-NTBUG9-84306-2000/07/31-dlee OLE-DB spec variance in Indexing Service, some interfaces not implemented
  220. #if 0
  221. else if ( IID_ICommandValidate == ifid )
  222. {
  223. *ppiuk = (void *) (ICommandValidate *) this;
  224. }
  225. #endif // 0
  226. else if ( IID_IQuery == ifid )
  227. {
  228. *ppiuk = (void *) (IQuery *) this;
  229. }
  230. else if ( IID_ICommandProperties == ifid || IID_IKyleProp == ifid )
  231. {
  232. *ppiuk = (void *) (ICommandProperties *) this;
  233. }
  234. else if ( IID_IServiceProperties == ifid )
  235. {
  236. *ppiuk = (void *) (IServiceProperties *) this;
  237. }
  238. else if ( IID_IConvertType == ifid )
  239. {
  240. *ppiuk = (void *) (IConvertType *) this;
  241. }
  242. else if ( IID_ICommandText == ifid )
  243. {
  244. // Create parser sesson object if deferred during construction
  245. if ( _xpIPSession.IsNull() )
  246. CreateParser();
  247. *ppiuk = (void *) (ICommandText *) this;
  248. }
  249. else if ( IID_ICommandPrepare == ifid )
  250. {
  251. *ppiuk = (void *) (ICommandPrepare *) this;
  252. }
  253. else
  254. {
  255. *ppiuk = 0;
  256. sc = E_NOINTERFACE;
  257. }
  258. }
  259. CATCH( CException, e )
  260. {
  261. vqDebugOut(( DEB_ERROR, "Exception %08x while doing QueryInterface \n",
  262. e.GetErrorCode() ));
  263. sc = GetOleError(e);
  264. }
  265. END_CATCH
  266. return sc;
  267. }
  268. //+---------------------------------------------------------------------------
  269. //
  270. // Method: CRootQuerySpec::FindErrorNodes, public
  271. //
  272. // Synopsis: Find error nodes in a command tree
  273. //
  274. // Arguments: [pRoot] -- DBCOMMANDTREE node at root of tree
  275. // [pcErrorNodes] -- pointer where count of error nodes is ret'd
  276. //
  277. // History: 27 Jun 95 AlanW Created
  278. //
  279. //----------------------------------------------------------------------------
  280. BOOL CheckForErrors( const CDbCmdTreeNode *pNode )
  281. {
  282. if (pNode->GetError() != S_OK)
  283. return TRUE;
  284. else
  285. return FALSE;
  286. }
  287. SCODE CRootQuerySpec::FindErrorNodes(
  288. const DBCOMMANDTREE * pRoot,
  289. ULONG * pcErrorNodes,
  290. DBCOMMANDTREE *** prgErrorNodes)
  291. {
  292. SCODE sc = S_OK;
  293. ULONG cErrors = 0;
  294. XArrayOLE<DBCOMMANDTREE *> pErrorNodes;
  295. TRANSLATE_EXCEPTIONS;
  296. TRY
  297. {
  298. _FindTreeNodes( CDbCmdTreeNode::CastFromStruct(pRoot),
  299. cErrors,
  300. pErrorNodes,
  301. CheckForErrors );
  302. *pcErrorNodes = cErrors;
  303. *prgErrorNodes = pErrorNodes.GetPointer();
  304. pErrorNodes.Acquire();
  305. }
  306. CATCH( CException, e )
  307. {
  308. sc = _DBErrorObj.PostHResult( e, IID_ICommandTree );
  309. }
  310. END_CATCH;
  311. UNTRANSLATE_EXCEPTIONS;
  312. return sc;
  313. }
  314. //+---------------------------------------------------------------------------
  315. //
  316. // Method: CRootQuerySpec::_FindTreeNodes, private
  317. //
  318. // Synopsis: Find nodes in a command tree meeting some condition
  319. //
  320. // Arguments: [pRoot] -- DBCOMMANDTREE node at root of tree
  321. // [rcMatchingNodes] -- count of matching nodes returned
  322. // [prgMatchingNodes] -- pointer to array of nodes returned
  323. // [pfnCheckNode] -- function which returns true if a tree
  324. // node matches desired condition.
  325. // [iDepth] -- depth of tree; for detecting cycles
  326. //
  327. // Notes: In order to avoid looping endlessly over a tree with cycles,
  328. // this routine will bail out if the tree depth is greater
  329. // than 1000 or if the tree width is greater than 100,000.
  330. //
  331. // We don't expect this routine to be called in situations
  332. // where it will return very large numbers of tree nodes,
  333. // so we grow the returned array only one element at a time.
  334. //
  335. // History: 27 Jun 95 AlanW Created
  336. //
  337. //----------------------------------------------------------------------------
  338. const unsigned MAX_TREE_DEPTH = 1000; // max tree depth
  339. const unsigned MAX_TREE_WIDTH = 100000; // max tree width
  340. void CRootQuerySpec::_FindTreeNodes(
  341. const CDbCmdTreeNode * pRoot,
  342. ULONG & rcMatchingNodes,
  343. XArrayOLE<DBCOMMANDTREE *> & rpMatchingNodes,
  344. PFNCHECKTREENODE pfnCheckNode,
  345. unsigned iDepth)
  346. {
  347. if (iDepth > MAX_TREE_DEPTH)
  348. THROW(CException(E_FAIL));
  349. unsigned iWidth = 0;
  350. while (pRoot)
  351. {
  352. if (pRoot->GetFirstChild())
  353. _FindTreeNodes( pRoot->GetFirstChild(),
  354. rcMatchingNodes,
  355. rpMatchingNodes,
  356. pfnCheckNode,
  357. iDepth+1);
  358. if (iWidth > MAX_TREE_WIDTH)
  359. THROW(CException(E_FAIL));
  360. if ((pfnCheckNode)(pRoot))
  361. {
  362. XArrayOLE<DBCOMMANDTREE *> pMatchTemp( rcMatchingNodes+1 );
  363. if (0 == pMatchTemp.GetPointer())
  364. THROW(CException(E_OUTOFMEMORY));
  365. if (rcMatchingNodes > 0)
  366. {
  367. Win4Assert(rpMatchingNodes.GetPointer() != 0);
  368. RtlCopyMemory(pMatchTemp.GetPointer(),
  369. rpMatchingNodes.GetPointer(),
  370. sizeof (DBCOMMANDTREE*) * rcMatchingNodes);
  371. CoTaskMemFree(rpMatchingNodes.Acquire());
  372. }
  373. (pMatchTemp.GetPointer())[rcMatchingNodes] = pRoot->CastToStruct();
  374. rcMatchingNodes++;
  375. rpMatchingNodes.Set( rcMatchingNodes, pMatchTemp.Acquire() );
  376. }
  377. pRoot = pRoot->GetNextSibling();
  378. iWidth++;
  379. }
  380. return;
  381. }
  382. //+---------------------------------------------------------------------------
  383. //
  384. // Method: CRootQuerySpec::FreeCommandTree, public
  385. //
  386. // Synopsis: Free a command tree
  387. //
  388. // Arguments: [ppRoot] -- DBCOMMANDTREE node at root of tree to be freed
  389. //
  390. // History: 27 Jun 95 AlanW Created
  391. //
  392. //----------------------------------------------------------------------------
  393. SCODE CRootQuerySpec::FreeCommandTree(
  394. DBCOMMANDTREE * * ppRoot)
  395. {
  396. SCODE sc = S_OK;
  397. if ( 0 == ppRoot )
  398. return E_INVALIDARG;
  399. TRANSLATE_EXCEPTIONS;
  400. TRY
  401. {
  402. CDbCmdTreeNode * pCmdTree = (CDbCmdTreeNode *)
  403. CDbCmdTreeNode::CastFromStruct(*ppRoot);
  404. //
  405. // If the user tries to delete our query tree, zero our pointer to it.
  406. //
  407. // NOTE: Nothing prevents the user from freeing a subtree of
  408. // our tree if they called SetCommandTree with fCopy FALSE.
  409. //
  410. // There is a proposed spec change on this. According to the current spec,
  411. // if fCopy was FALSE we need to return DB_E_CANNOTFREE here. (MDAC BUGG# 6386)
  412. if ( _dwStatus & CMD_OWNS_TREE )
  413. {
  414. THROW( CException(DB_E_CANNOTFREE) );
  415. }
  416. else
  417. {
  418. if ( pCmdTree == _pQueryTree )
  419. _pQueryTree = 0;
  420. delete pCmdTree;
  421. *ppRoot = 0;
  422. }
  423. }
  424. CATCH( CException, e )
  425. {
  426. sc = _DBErrorObj.PostHResult( e, IID_ICommandTree );
  427. }
  428. END_CATCH;
  429. UNTRANSLATE_EXCEPTIONS;
  430. return sc;
  431. }
  432. //+---------------------------------------------------------------------------
  433. //
  434. // Method: CRootQuerySpec::GetCommandTree, public
  435. //
  436. // Synopsis: Get a copy of the command tree.
  437. //
  438. // Arguments: [ppRoot] -- pointer to where DBCOMMANDTREE is returned
  439. //
  440. // History: 27 Jun 95 AlanW Created
  441. //
  442. //----------------------------------------------------------------------------
  443. SCODE CRootQuerySpec::GetCommandTree(
  444. DBCOMMANDTREE * * ppRoot)
  445. {
  446. if ( 0 == ppRoot )
  447. return _DBErrorObj.PostHResult( E_INVALIDARG, IID_ICommandTree );
  448. SCODE sc = S_OK;
  449. TRANSLATE_EXCEPTIONS;
  450. TRY
  451. {
  452. //
  453. // Initialize return parameter
  454. //
  455. *ppRoot = 0;
  456. if ( 0 == _pQueryTree )
  457. {
  458. //
  459. // Build it if we have a command text
  460. //
  461. if ( IsCommandSet() )
  462. {
  463. sc = BuildTree( );
  464. // SET PROPERTYNAME ... query
  465. if ( DB_S_NORESULT == sc )
  466. return S_OK;
  467. _dwStatus |= CMD_TREE_BUILT;
  468. }
  469. //
  470. // The command text didn't generate a tree (i.e. it was
  471. // either a CREATE VIEW or SET PROPERTYNAME ) or a
  472. // command text wasn't set
  473. //
  474. if ( 0 == _pQueryTree )
  475. {
  476. return S_OK;
  477. }
  478. }
  479. XPtr<CDbCmdTreeNode> TreeCopy( _pQueryTree->Clone(TRUE) );
  480. if (0 == TreeCopy.GetPointer())
  481. THROW(CException(E_OUTOFMEMORY));
  482. *ppRoot = TreeCopy.GetPointer()->CastToStruct();
  483. TreeCopy.Acquire();
  484. }
  485. CATCH( CException, e )
  486. {
  487. sc = _DBErrorObj.PostHResult( e, IID_ICommandTree );
  488. }
  489. END_CATCH;
  490. UNTRANSLATE_EXCEPTIONS;
  491. return sc;
  492. }
  493. //+---------------------------------------------------------------------------
  494. //
  495. // Method: CRootQuerySpec::SetCommandTree, public
  496. //
  497. // Synopsis: Set the command tree.
  498. //
  499. // Arguments: [ppRoot] -- pointer to DBCOMMANDTREE to be set in command obj
  500. // [dwCommandReuse] -- indicates whether state is retained.
  501. // [fCopy] -- if TRUE, a copy of ppRoot is made. Otherwise,
  502. // ownership of the command tree passes to the
  503. // command object.
  504. //
  505. // History: 27 Jun 95 AlanW Created
  506. //
  507. //----------------------------------------------------------------------------
  508. SCODE CRootQuerySpec::SetCommandTree(
  509. DBCOMMANDTREE * * ppRoot,
  510. DBCOMMANDREUSE dwCommandReuse,
  511. BOOL fCopy)
  512. {
  513. if ( HaveQuery() && _pInternalQuery->IsQueryActive() )
  514. return DB_E_OBJECTOPEN;
  515. if ( 0 == ppRoot )
  516. return E_INVALIDARG;
  517. SCODE sc = S_OK;
  518. TRANSLATE_EXCEPTIONS;
  519. TRY
  520. {
  521. _CheckRootNode( *ppRoot );
  522. if ( 0 != _pQueryTree )
  523. {
  524. delete _pQueryTree;
  525. _pQueryTree = 0;
  526. }
  527. CDbCmdTreeNode const * pCmdTree = CDbCmdTreeNode::CastFromStruct(*ppRoot);
  528. if ( FALSE == fCopy )
  529. {
  530. _dwStatus |= CMD_OWNS_TREE;
  531. _pQueryTree = (CDbCmdTreeNode *)pCmdTree;
  532. *ppRoot = 0;
  533. }
  534. else
  535. {
  536. _pQueryTree = pCmdTree->Clone();
  537. //
  538. // If Clone() fails it cleans up after itself and returns 0
  539. //
  540. if ( 0 == _pQueryTree )
  541. THROW( CException( E_OUTOFMEMORY ) );
  542. }
  543. _dwStatus &= ~CMD_COLINFO_NOTPREPARED;
  544. if ( _pColumnsInfo )
  545. InitColumns();
  546. //
  547. // If this is not being called internally (from BuildTree) remove the
  548. // the command text
  549. //
  550. if ( _dwStatus & CMD_TEXT_TOTREE )
  551. {
  552. _dwStatus &= ~CMD_TEXT_TOTREE;
  553. }
  554. else
  555. {
  556. delete [] _pwszSQLText;
  557. _pwszSQLText = 0;
  558. _guidCmdDialect = DBGUID_SQL;
  559. _dwStatus &= ~CMD_TEXT_SET;
  560. }
  561. }
  562. CATCH( CException, e )
  563. {
  564. sc = _DBErrorObj.PostHResult( e, IID_ICommandTree );
  565. }
  566. END_CATCH;
  567. UNTRANSLATE_EXCEPTIONS;
  568. return sc;
  569. }
  570. //+---------------------------------------------------------------------------
  571. //
  572. // Method: CRootQuerySpec::Execute, public
  573. //
  574. // Synopsis: Execute the command; create rowsets for the query resu.
  575. //
  576. // Arguments: [pOuterUnk] -- controlling IUnknown for the rowset
  577. // [riid] -- interface IID requested for the rowset
  578. // [pParams] -- parameters for the query
  579. // [pcRowsAffected] -- returned count of affected rows
  580. // [ppRowset] -- returned rowset
  581. //
  582. // History: 27 Jun 95 AlanW Created
  583. // 11-20-97 danleg Added ICommandText & ICommandPrepare
  584. //
  585. //----------------------------------------------------------------------------
  586. SCODE CRootQuerySpec::Execute(
  587. IUnknown * pOuterUnk,
  588. REFIID riid,
  589. DBPARAMS * pParams,
  590. DBROWCOUNT * pcRowsAffected,
  591. IUnknown * * ppRowset)
  592. {
  593. _DBErrorObj.ClearErrorInfo();
  594. //
  595. // Called from OpenRowset?
  596. //
  597. GUID guidPost = (_fGenByOpenRowset) ? IID_IOpenRowset : IID_ICommand;
  598. if (0 == ppRowset && IID_NULL != riid )
  599. return _DBErrorObj.PostHResult( E_INVALIDARG, guidPost );
  600. if (0 != pOuterUnk && riid != IID_IUnknown)
  601. return _DBErrorObj.PostHResult( DB_E_NOAGGREGATION, guidPost );
  602. CLock lck( _mtxCmd );
  603. SCODE scResult = S_OK;
  604. IRowset * pIRowset = 0;
  605. _dwStatus &= ~(CMD_EXEC_RUNNING);
  606. TRANSLATE_EXCEPTIONS;
  607. TRY
  608. {
  609. if ( ppRowset )
  610. *ppRowset = 0;
  611. // Impersonate the session logon user
  612. HANDLE hToken = INVALID_HANDLE_VALUE;
  613. if ( !_xSession.IsNull() )
  614. hToken = _xSession->GetLogonToken();
  615. CImpersonateSessionUser imp( hToken );
  616. // Either SetCommandTree or SetCommandText should have already been called
  617. if ( 0 == _pQueryTree )
  618. {
  619. if ( IsCommandSet() )
  620. {
  621. //
  622. // No query tree. Build one from the command text if one has been set.
  623. //
  624. scResult = BuildTree( );
  625. if ( DB_S_NORESULT == scResult )
  626. return scResult;
  627. _dwStatus |= CMD_TREE_BUILT;
  628. }
  629. else
  630. THROW( CException(DB_E_NOCOMMAND) );
  631. }
  632. _dwStatus |= CMD_EXEC_RUNNING;
  633. //
  634. // Convert the tree into restriction, etc.
  635. // The pParams should probably be passed to the ctor of
  636. // the parser (when we do parameterized queries).
  637. //
  638. CParseCommandTree Parse;
  639. Parse.ParseTree( _pQueryTree );
  640. XGrowable<const WCHAR *,SCOPE_COUNT_GROWSIZE> xaScopes( SCOPE_COUNT_GROWSIZE );
  641. XGrowable<ULONG,SCOPE_COUNT_GROWSIZE> xaFlags( SCOPE_COUNT_GROWSIZE );
  642. XGrowable<const WCHAR *,SCOPE_COUNT_GROWSIZE> xaCatalogs( SCOPE_COUNT_GROWSIZE );
  643. XGrowable<const WCHAR *,SCOPE_COUNT_GROWSIZE> xaMachines( SCOPE_COUNT_GROWSIZE );
  644. unsigned cScopes = 0;
  645. Parse.GetScopes( cScopes, xaScopes, xaFlags, xaCatalogs, xaMachines );
  646. // If the tree had a DBOP_tree node instead of a DBOP_content_table, we can't
  647. // parse scope information from the tree. The client is responsible for
  648. // setting scope properties. Currently, this means the Tripolish parser
  649. if ( 0 < cScopes )
  650. {
  651. SetScopeProperties( this,
  652. cScopes,
  653. xaScopes.Get(),
  654. xaFlags.Get(),
  655. xaCatalogs.Get(),
  656. xaMachines.Get() );
  657. }
  658. CRestriction * pCrst = Parse.GetRestriction();
  659. CCategorizationSet & categ = Parse.GetCategorization();
  660. unsigned cRowsets = 1;
  661. if ( 0 != categ.Count() )
  662. cRowsets += categ.Count();
  663. if (Parse.GetOutputColumns().Count() == 0)
  664. THROW( CException(DB_E_ERRORSINCOMMAND) );
  665. XArray<IUnknown *> Unknowns( cRowsets );
  666. //
  667. // If it appears the server went down between the time we made
  668. // the connection and did the execute, attempt once to
  669. // re-establish the connection.
  670. //
  671. int cTries = 1;
  672. XPtr<CMRowsetProps> xProps;
  673. do
  674. {
  675. //
  676. // Use a copy of the properties so the command object isn't
  677. // affected by the implied properties. xProps may be acquired
  678. // in a failed loop if the server disconnects just before the
  679. // setbindings call.
  680. //
  681. if ( xProps.IsNull() )
  682. {
  683. xProps.Set( new CMRowsetProps( _RowsetProps ) );
  684. xProps->SetImpliedProperties( riid, cRowsets );
  685. //
  686. // Check if there are any properties in error. If properties are found
  687. // to be in error, indicate this on _RowsetProps.
  688. //
  689. scResult = xProps->ArePropsInError( _RowsetProps );
  690. if ( S_OK != scResult )
  691. return scResult;
  692. if ( Parse.GetMaxResults() > 0 )
  693. xProps->SetValLong( CMRowsetProps::eid_DBPROPSET_ROWSET,
  694. CMRowsetProps::eid_PROPVAL_MAXROWS,
  695. Parse.GetMaxResults() );
  696. if ( Parse.GetFirstRows() > 0 )
  697. xProps->SetFirstRows( Parse.GetFirstRows() );
  698. }
  699. if ( !HaveQuery() )
  700. _pInternalQuery = QueryInternalQuery();
  701. SCODE scEx = S_OK;
  702. TRY
  703. {
  704. //
  705. // Used for GetSpecification on the rowset
  706. //
  707. IUnknown * pCreatorUnk = 0;
  708. if ( IsGenByOpenRowset() )
  709. {
  710. Win4Assert( !_xSession.IsNull() );
  711. pCreatorUnk = _xSession->GetOuterUnk();
  712. }
  713. else
  714. {
  715. pCreatorUnk = (IUnknown *) _pControllingUnknown;
  716. }
  717. Win4Assert( 0 != xProps.GetPointer() );
  718. _pInternalQuery->Execute( pOuterUnk,
  719. pCrst ? pCrst->CastToStruct() : 0, // Restrictions
  720. Parse.GetPidmap(),
  721. Parse.GetOutputColumns(), // Output columns
  722. Parse.GetSortColumns(), // Sort Order
  723. xProps,
  724. categ, // Categorization
  725. cRowsets,
  726. Unknowns.GetPointer(), // Return interfaces
  727. _aAccessors,
  728. pCreatorUnk);
  729. }
  730. CATCH( CException, e )
  731. {
  732. scEx = e.GetErrorCode();
  733. if ( ( STATUS_CONNECTION_DISCONNECTED != scEx ) ||
  734. ( cTries > 1 ) )
  735. RETHROW();
  736. }
  737. END_CATCH;
  738. if ( STATUS_CONNECTION_DISCONNECTED == scEx )
  739. {
  740. Win4Assert( 1 == cTries );
  741. cTries++;
  742. ReleaseInternalQuery();
  743. continue;
  744. }
  745. else
  746. {
  747. Win4Assert( S_OK == scEx );
  748. break;
  749. }
  750. }
  751. while ( TRUE );
  752. // release these categorized rowsets -- they are addref'ed when the
  753. // client does a getreferencedrowset
  754. for ( unsigned x = 1; x < cRowsets; x++ )
  755. Unknowns[ x ]->Release();
  756. XInterface<IUnknown> xUnknown( Unknowns[0] );
  757. if (IID_IUnknown == riid)
  758. {
  759. *ppRowset = xUnknown.GetPointer();
  760. xUnknown.Acquire();
  761. }
  762. else
  763. {
  764. if (IID_NULL != riid)
  765. scResult = xUnknown->QueryInterface( riid, (void **)ppRowset );
  766. Win4Assert( S_OK == scResult ); // should have failed earlier
  767. if (FAILED(scResult))
  768. THROW( CException(scResult) );
  769. }
  770. _dwStatus &= ~(CMD_EXEC_RUNNING);
  771. imp.Revert();
  772. }
  773. CATCH( CException, e )
  774. {
  775. //
  776. // Can't use PostHResult( e...) here because the final SCODE may get translated
  777. //
  778. scResult = e.GetErrorCode();
  779. vqDebugOut(( DEB_ERROR, "Exception %08x while creating query\n", scResult ));
  780. if ( QUERY_E_INVALIDRESTRICTION == scResult )
  781. scResult = DB_E_ERRORSINCOMMAND;
  782. //
  783. // In the case of OpenRowset, don't want to Post DB_E_ERRORSINCOMMAND
  784. //
  785. if ( _fGenByOpenRowset )
  786. {
  787. if( scResult == DB_E_ERRORSINCOMMAND )
  788. scResult = DB_E_NOTABLE;
  789. }
  790. _DBErrorObj.PostHResult( scResult, guidPost );
  791. }
  792. END_CATCH;
  793. UNTRANSLATE_EXCEPTIONS;
  794. #if CIDBG == 1
  795. if ( ( S_OK == scResult ) && ( IID_NULL != riid ) )
  796. Win4Assert( 0 != *ppRowset );
  797. #endif
  798. return scResult;
  799. }
  800. //+---------------------------------------------------------------------------
  801. //
  802. // Method: CRootQuerySpec::Cancel, public
  803. //
  804. // Synopsis: The consumer can allocate a secondary thread in which to cancel
  805. // the currently executing thread. This cancel will only succeed
  806. // if the result set is still being generated. If the rowset
  807. // object is being created, then it will be to late to cancel.
  808. //
  809. // History: 11-20-97 danleg Created
  810. //----------------------------------------------------------------------------
  811. SCODE CRootQuerySpec::Cancel( void )
  812. {
  813. _DBErrorObj.ClearErrorInfo();
  814. if( 0 == (_dwStatus & CMD_EXEC_RUNNING) )
  815. return S_OK;
  816. return _DBErrorObj.PostHResult(DB_E_CANTCANCEL, IID_ICommand);
  817. }
  818. #if 0 // ICommandValidate not yet implemented
  819. //
  820. // ICommandValidate methods
  821. //
  822. SCODE CRootQuerySpec::ValidateCompletely( void )
  823. {
  824. _DBErrorObj.ClearErrorInfo();
  825. vqDebugOut(( DEB_WARN, "CRootQuerySpec::ValidateCompletely not implemented\n" ));
  826. return PostHResult(E_NOTIMPL, IID_ICommandValidate);
  827. }
  828. SCODE CRootQuerySpec::ValidateSyntax( void )
  829. {
  830. _DBErrorObj.ClearErrorInfo();
  831. vqDebugOut(( DEB_WARN, "CRootQuerySpec::ValidateSyntax not implemented\n" ));
  832. return PostHResult(E_NOTIMPL, IID_ICommandValidate);
  833. }
  834. #endif // 0
  835. //+---------------------------------------------------------------------------
  836. //
  837. // Method: CRootQuerySpec::GetDBSession, public
  838. //
  839. // Synopsis: Return the session object associated with this command
  840. //
  841. // Arguments: [riid] -- IID of the desired interface
  842. // [ppSession] -- pointer to where to return interface pointer
  843. //
  844. // History: 11-20-97 danleg Created
  845. //----------------------------------------------------------------------------
  846. SCODE CRootQuerySpec::GetDBSession(
  847. REFIID riid,
  848. IUnknown ** ppSession )
  849. {
  850. _DBErrorObj.ClearErrorInfo();
  851. if (0 == ppSession)
  852. return _DBErrorObj.PostHResult(E_INVALIDARG, IID_ICommand);
  853. SCODE sc = S_OK;
  854. if ( !_xSession.IsNull() )
  855. {
  856. sc = (_xSession->GetOuterUnk())->QueryInterface( riid, (void **) ppSession );
  857. }
  858. else // there was no session object
  859. {
  860. *ppSession = 0;
  861. sc = S_FALSE;
  862. }
  863. return sc;
  864. }
  865. //
  866. // ICommandText methods
  867. //
  868. //+---------------------------------------------------------------------------
  869. //
  870. // Method: CRootQuerySpec::GetCommandText, public
  871. //
  872. // Synopsis: Echos the current command as text, including all
  873. // post-processing operations added.
  874. //
  875. // Arguments: [pguidDialect] -- Guid denoting the dialect of SQL
  876. // [ppwszCommand] -- Pointer to mem where to return command text
  877. //
  878. // History: 10-01-97 danleg Created from Monarch
  879. //
  880. //----------------------------------------------------------------------------
  881. STDMETHODIMP CRootQuerySpec::GetCommandText
  882. (
  883. GUID * pguidDialect, //@parm INOUT | Guid denoting the dialect of sql
  884. LPOLESTR * ppwszCommand //@parm OUT | Pointer for the command text
  885. )
  886. {
  887. SCODE sc = S_OK;
  888. BOOL fpguidNULL = FALSE;
  889. GUID guidDialect;
  890. _DBErrorObj.ClearErrorInfo();
  891. CLock lck( _mtxCmd );
  892. TRANSLATE_EXCEPTIONS;
  893. TRY
  894. {
  895. if( 0 == ppwszCommand )
  896. {
  897. THROW( CException(E_INVALIDARG) );
  898. }
  899. else
  900. {
  901. *ppwszCommand = 0;
  902. // Substitute a correct GUID for a NULL pguidDialect
  903. if( !pguidDialect )
  904. {
  905. guidDialect = DBGUID_SQL;
  906. pguidDialect = &guidDialect;
  907. // Don't return DB_S_DIALECTIGNORED in this case...
  908. fpguidNULL = TRUE;
  909. }
  910. // If the command has not been set, make sure the buffer
  911. // contains an empty string to return to the consumer
  912. if( !IsCommandSet() )
  913. {
  914. THROW( CException(DB_E_NOCOMMAND) );
  915. }
  916. else
  917. {
  918. // Allocate memory for the string we're going to return to the caller
  919. XArrayOLE<WCHAR> xwszCommand( wcslen(_pwszSQLText) + 1 ) ;
  920. // Copy our saved text into the newly allocated string
  921. wcscpy(xwszCommand.GetPointer(), _pwszSQLText);
  922. // If the text we're giving back is a different dialect than was
  923. // requested, let the caller know what dialect the text is in
  924. if( !fpguidNULL && _guidCmdDialect != *pguidDialect )
  925. {
  926. *pguidDialect = _guidCmdDialect;
  927. sc = DB_S_DIALECTIGNORED;
  928. }
  929. *ppwszCommand = xwszCommand.Acquire();
  930. }
  931. }
  932. }
  933. CATCH( CException, e )
  934. {
  935. sc = _DBErrorObj.PostHResult( e, IID_ICommandText );
  936. if( pguidDialect )
  937. RtlZeroMemory( pguidDialect, sizeof(GUID) );
  938. }
  939. END_CATCH;
  940. UNTRANSLATE_EXCEPTIONS;
  941. return sc;
  942. }
  943. //+---------------------------------------------------------------------------
  944. //
  945. // Method: CRootQuerySpec::SetCommandText, public
  946. //
  947. // Synopsis: Sets the current command text..
  948. //
  949. // Arguments: [rguidDialect] -- Guid denoting the dialect of SQL
  950. // [pwszCommand] -- Command Text
  951. //
  952. // History: 10-01-97 danleg Created from Monarch
  953. //
  954. //----------------------------------------------------------------------------
  955. STDMETHODIMP CRootQuerySpec::SetCommandText
  956. (
  957. REFGUID rguidDialect,
  958. LPCOLESTR pwszCommand
  959. )
  960. {
  961. SCODE sc = S_OK;
  962. // Clear previous Error Object for this thread
  963. _DBErrorObj.ClearErrorInfo();
  964. CLock lck( _mtxCmd );
  965. TRANSLATE_EXCEPTIONS;
  966. TRY
  967. {
  968. // Don't allow text to be set if we've got a rowset open
  969. if( !IsRowsetOpen() )
  970. {
  971. // Check Dialect
  972. if( rguidDialect == DBGUID_SQL || rguidDialect == DBGUID_DEFAULT )
  973. {
  974. //
  975. // Delete existing SQL text
  976. //
  977. delete [] _pwszSQLText;
  978. _pwszSQLText = 0;
  979. //
  980. // Delete Command Tree
  981. //
  982. delete _pQueryTree;
  983. _pQueryTree = 0;
  984. if( (0 == pwszCommand) || (L'\0' == *pwszCommand) )
  985. {
  986. _guidCmdDialect = DBGUID_SQL;
  987. _dwStatus &= ~CMD_TEXT_SET;
  988. _dwStatus &= ~CMD_COLINFO_NOTPREPARED;
  989. }
  990. else
  991. {
  992. //
  993. // Save the text and dialect
  994. //
  995. XArray<WCHAR> xwszSQLText( wcslen(pwszCommand) + 1 );
  996. wcscpy(xwszSQLText.GetPointer(), pwszCommand);
  997. _pwszSQLText = xwszSQLText.Acquire();
  998. _guidCmdDialect = rguidDialect;
  999. // Set status flag that we have set text
  1000. _dwStatus |= CMD_TEXT_SET;
  1001. _dwStatus |= CMD_COLINFO_NOTPREPARED;
  1002. }
  1003. if ( _pColumnsInfo )
  1004. InitColumns( );
  1005. _dwStatus &= ~CMD_TEXT_PREPARED;
  1006. _dwStatus &= ~CMD_TREE_BUILT;
  1007. // Whenever new text is set on the Command Object,
  1008. // the value for QUERY_RESTRICTION should be set to
  1009. // an empty string
  1010. _RowsetProps.SetValString(
  1011. CMRowsetProps::eid_DBPROPSET_MSIDXS_ROWSET_EXT,
  1012. CMRowsetProps::eid_MSIDXSPROPVAL_QUERY_RESTRICTION,
  1013. L"");
  1014. }
  1015. else
  1016. {
  1017. THROW( CException(DB_E_DIALECTNOTSUPPORTED) );
  1018. }
  1019. }
  1020. else
  1021. {
  1022. THROW( CException(DB_E_OBJECTOPEN) );
  1023. }
  1024. }
  1025. CATCH( CException, e )
  1026. {
  1027. sc = _DBErrorObj.PostHResult( e, IID_ICommandText );
  1028. }
  1029. END_CATCH;
  1030. UNTRANSLATE_EXCEPTIONS;
  1031. return sc;
  1032. }
  1033. //
  1034. // ICommandPrepare methods
  1035. //
  1036. //+---------------------------------------------------------------------------
  1037. //
  1038. // Method: CRootQuerySpec::Prepare, public
  1039. //
  1040. // Synopsis: Given that a SQL text has been set, prepare the statement
  1041. //
  1042. // History: 10-31-97 danleg Created from Monarch
  1043. //
  1044. //----------------------------------------------------------------------------
  1045. STDMETHODIMP CRootQuerySpec::Prepare
  1046. (
  1047. ULONG cExpectedRuns
  1048. )
  1049. {
  1050. SCODE sc = S_OK;
  1051. // Clear previous Error Object for this thread
  1052. _DBErrorObj.ClearErrorInfo();
  1053. CLock lck( _mtxCmd );
  1054. TRANSLATE_EXCEPTIONS;
  1055. TRY
  1056. {
  1057. // Don't allow a new prepare with an open rowset
  1058. if( !IsRowsetOpen() )
  1059. {
  1060. if( IsCommandSet() )
  1061. {
  1062. //
  1063. // Don't build the tree again if it was built as a result of
  1064. // GetCommandTree or Execute, and we haven't done a SetCommandText
  1065. // since.
  1066. //
  1067. if ( !(_dwStatus & CMD_TREE_BUILT) )
  1068. {
  1069. // Impersonate the session logon user
  1070. HANDLE hToken = INVALID_HANDLE_VALUE;
  1071. if ( !_xSession.IsNull() )
  1072. hToken = _xSession->GetLogonToken();
  1073. CImpersonateSessionUser imp( hToken );
  1074. sc = BuildTree( );
  1075. if ( DB_S_NORESULT == sc )
  1076. return sc;
  1077. _dwStatus |= CMD_TEXT_PREPARED;
  1078. if ( _pColumnsInfo )
  1079. InitColumns();
  1080. imp.Revert();
  1081. }
  1082. }
  1083. else
  1084. sc = DB_E_NOCOMMAND;
  1085. }
  1086. else
  1087. {
  1088. sc = DB_E_OBJECTOPEN;
  1089. }
  1090. }
  1091. CATCH( CException, e )
  1092. {
  1093. sc = _DBErrorObj.PostHResult( e, IID_ICommandText );
  1094. }
  1095. END_CATCH;
  1096. UNTRANSLATE_EXCEPTIONS;
  1097. return sc;
  1098. }
  1099. //+---------------------------------------------------------------------------
  1100. //
  1101. // Method: CRootQuerySpec::Unprepare, public
  1102. //
  1103. // Synopsis: Unprepare the current prepared command plan, if there is one.
  1104. //
  1105. // History: 10-31-97 danleg Created from Monarch
  1106. //
  1107. //----------------------------------------------------------------------------
  1108. STDMETHODIMP CRootQuerySpec::Unprepare
  1109. (
  1110. )
  1111. {
  1112. SCODE sc = S_OK;
  1113. // Clear previous Error Object for this thread
  1114. _DBErrorObj.ClearErrorInfo();
  1115. CLock lck( _mtxCmd );
  1116. TRANSLATE_EXCEPTIONS;
  1117. TRY
  1118. {
  1119. if( !IsRowsetOpen() )
  1120. {
  1121. _dwStatus &= ~CMD_TEXT_PREPARED;
  1122. _dwStatus |= CMD_COLINFO_NOTPREPARED;
  1123. if ( _pColumnsInfo )
  1124. InitColumns( );
  1125. }
  1126. else
  1127. THROW( CException(DB_E_OBJECTOPEN) );
  1128. }
  1129. CATCH( CException, e )
  1130. {
  1131. sc = _DBErrorObj.PostHResult( e, IID_ICommandPrepare );
  1132. }
  1133. END_CATCH;
  1134. UNTRANSLATE_EXCEPTIONS;
  1135. return sc;
  1136. }
  1137. //
  1138. // IQuery methods
  1139. //
  1140. //+---------------------------------------------------------------------------
  1141. //
  1142. // Method: CRootQuerySpec::AddPostProcessing, public
  1143. //
  1144. // Synopsis: Add to the top of a command tree
  1145. //
  1146. // Arguments: [ppRoot] -- DBCOMMANDTREE node at root of tree
  1147. // [fCopy] - TRUE if command tree should be copied
  1148. //
  1149. // History: 29 Jun 95 AlanW Created
  1150. //
  1151. //----------------------------------------------------------------------------
  1152. BOOL CheckForPriorTree( const CDbCmdTreeNode *pNode )
  1153. {
  1154. return pNode->GetCommandType() == DBOP_prior_command_tree;
  1155. }
  1156. SCODE CRootQuerySpec::AddPostProcessing(
  1157. DBCOMMANDTREE * * ppRoot,
  1158. BOOL fCopy)
  1159. {
  1160. _DBErrorObj.ClearErrorInfo();
  1161. // OLEDB spec. bug #????; fCopy is non-sensical
  1162. if (0 == ppRoot || FALSE == fCopy)
  1163. return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IQuery);
  1164. SCODE sc = S_OK;
  1165. TRANSLATE_EXCEPTIONS;
  1166. TRY
  1167. {
  1168. _CheckRootNode( *ppRoot );
  1169. XPtr<CDbCmdTreeNode> TreeCopy( CDbCmdTreeNode::CastFromStruct(*ppRoot)->Clone() );
  1170. if (0 == TreeCopy.GetPointer())
  1171. THROW(CException(E_OUTOFMEMORY));
  1172. ULONG cNodes = 0;
  1173. XArrayOLE<DBCOMMANDTREE *> pNodes;
  1174. _FindTreeNodes( TreeCopy.GetPointer(),
  1175. cNodes,
  1176. pNodes,
  1177. CheckForPriorTree );
  1178. if (cNodes != 1)
  1179. {
  1180. vqDebugOut((DEB_WARN, "CRootQuerySpec::AddPostProcessing - "
  1181. "%d references to prior tree found\n",
  1182. cNodes));
  1183. THROW(CException(E_INVALIDARG)); // DB_E_BADCOMMANDTREE???
  1184. }
  1185. //
  1186. // The command tree node with DBOP_prior_command_tree can have
  1187. // siblings, but it must not have any children.
  1188. // Likewise, the original command tree can have children, but it
  1189. // must not have any siblings.
  1190. // Splice the trees together by copying the root node of the
  1191. // original tree onto the DBOP_prior_command_tree node, then
  1192. // freeing the orginal root node.
  1193. //
  1194. if (pNodes[0]->pctFirstChild != 0 ||
  1195. pNodes[0]->wKind != DBVALUEKIND_EMPTY)
  1196. THROW(CException(E_INVALIDARG)); // DB_E_BADCOMMANDTREE???
  1197. // Perhaps we should just substitute a DBOP_table_identifier
  1198. // node with default table in this case.
  1199. if (0 == _pQueryTree)
  1200. THROW(CException(E_INVALIDARG)); // DB_E_NOCOMMANDTREE???
  1201. //
  1202. // Transfer the pointers and values from the root node
  1203. // to the prior_command_tree node.
  1204. //
  1205. _pQueryTree->TransferNode( CDbCmdTreeNode::CastFromStruct(pNodes[0]) );
  1206. Win4Assert(0 == _pQueryTree->GetFirstChild() &&
  1207. 0 == _pQueryTree->GetNextSibling() &&
  1208. DBVALUEKIND_EMPTY == _pQueryTree->GetValueType());
  1209. delete _pQueryTree;
  1210. _pQueryTree = TreeCopy.Acquire();
  1211. }
  1212. CATCH( CException, e )
  1213. {
  1214. sc = _DBErrorObj.PostHResult( e, IID_IQuery );
  1215. }
  1216. END_CATCH;
  1217. UNTRANSLATE_EXCEPTIONS;
  1218. return sc;
  1219. }
  1220. //+---------------------------------------------------------------------------
  1221. //
  1222. // Method: CRootQuerySpec::GetCardinalityEstimate, public
  1223. //
  1224. // Synopsis: Get estimated cardinality of the query tree
  1225. //
  1226. // Arguments: [pulCardinality] -- Pointer to memory to hold cardinality
  1227. //
  1228. // History: 29 Jun 95 AlanW Created
  1229. // 2 May 97 KrishnaN Added this header block
  1230. //
  1231. //----------------------------------------------------------------------------
  1232. SCODE CRootQuerySpec::GetCardinalityEstimate(
  1233. DBORDINAL * pulCardinality)
  1234. {
  1235. _DBErrorObj.ClearErrorInfo();
  1236. vqDebugOut(( DEB_WARN, "CRootQuerySpec::GetCardinalityEstimate not implemented\n" ));
  1237. return _DBErrorObj.PostHResult(S_FALSE, IID_IQuery);
  1238. }
  1239. //
  1240. // ICommandProperties methods
  1241. //
  1242. //+---------------------------------------------------------------------------
  1243. //
  1244. // Method: DetermineScodeIndex
  1245. //
  1246. // Synopsis: Returns an index into a static array of SCODEs
  1247. //
  1248. // NOTE: This function will go away once CRowsetProperties and
  1249. // CMRowsetProps are merged completely.
  1250. //
  1251. // Arguments: [sc] - SCODE for which an index is returned
  1252. //
  1253. // History: 01-05-98 danleg Created
  1254. //
  1255. //----------------------------------------------------------------------------
  1256. inline ULONG DetermineScodeIndex
  1257. (
  1258. SCODE sc
  1259. )
  1260. {
  1261. switch( sc )
  1262. {
  1263. case S_OK: return 0;
  1264. case DB_S_ERRORSOCCURRED: return 1;
  1265. case E_FAIL:
  1266. default: return 2;
  1267. case E_INVALIDARG: return 3;
  1268. case E_OUTOFMEMORY: return 4;
  1269. case DB_E_ERRORSOCCURRED: return 5;
  1270. }
  1271. }
  1272. //+---------------------------------------------------------------------------
  1273. //
  1274. // Method: DetermineNewSCODE
  1275. //
  1276. // Synopsis: Given two SCODEs returned by the two property handling
  1277. // mechanisms used, returned a resultant SCODE to return from
  1278. // Get/SetProperties.
  1279. //
  1280. // NOTE: This function will go away once CRowsetProperties and
  1281. // CMRowsetProps are merged completely.
  1282. //
  1283. // Arguments:
  1284. //
  1285. // History: 01-05-98 danleg Created
  1286. //
  1287. //----------------------------------------------------------------------------
  1288. SCODE DetermineNewSCODE
  1289. (
  1290. SCODE sc1,
  1291. SCODE sc2
  1292. )
  1293. {
  1294. ULONG isc1 = DetermineScodeIndex(sc1),
  1295. isc2 = DetermineScodeIndex(sc2);
  1296. static const SCODE s_rgPropHresultMap[6][6] =
  1297. {
  1298. {S_OK, DB_S_ERRORSOCCURRED, E_FAIL, E_INVALIDARG, E_OUTOFMEMORY, DB_S_ERRORSOCCURRED},
  1299. {DB_S_ERRORSOCCURRED, DB_S_ERRORSOCCURRED, E_FAIL, E_INVALIDARG, E_OUTOFMEMORY, DB_S_ERRORSOCCURRED},
  1300. {E_FAIL, E_FAIL, E_FAIL, E_FAIL, E_FAIL, E_FAIL},
  1301. {E_INVALIDARG, E_INVALIDARG, E_FAIL, E_INVALIDARG, E_INVALIDARG, E_INVALIDARG},
  1302. {E_OUTOFMEMORY, E_OUTOFMEMORY, E_FAIL, E_OUTOFMEMORY, E_OUTOFMEMORY, E_OUTOFMEMORY},
  1303. {DB_S_ERRORSOCCURRED, DB_S_ERRORSOCCURRED, E_FAIL, E_INVALIDARG, E_OUTOFMEMORY, DB_E_ERRORSOCCURRED},
  1304. };
  1305. return s_rgPropHresultMap[isc1][isc2];
  1306. }
  1307. //+---------------------------------------------------------------------------
  1308. //
  1309. // Method: CRootQuerySpec::GetProperties, public
  1310. //
  1311. // Synopsis: Get rowset properties
  1312. //
  1313. // Arguments: [cPropertySetIDs] - number of desired properties or 0
  1314. // [rgPropertySetIDs] - array of desired properties or NULL
  1315. // [pcPropertySets] - number of property sets returned
  1316. // [prgPropertySets] - array of returned property sets
  1317. //
  1318. // History: 16 Nov 95 AlanW Created
  1319. // 02-22-98 danleg Changed to use CMRowsetProps
  1320. //
  1321. //----------------------------------------------------------------------------
  1322. SCODE CRootQuerySpec::GetProperties(
  1323. const ULONG cPropertySetIDs,
  1324. const DBPROPIDSET rgPropertySetIDs[],
  1325. ULONG * pcPropertySets,
  1326. DBPROPSET ** prgPropertySets)
  1327. {
  1328. _DBErrorObj.ClearErrorInfo();
  1329. SCODE sc = S_OK;
  1330. TRANSLATE_EXCEPTIONS;
  1331. TRY
  1332. {
  1333. _RowsetProps.GetPropertiesArgChk( cPropertySetIDs,
  1334. rgPropertySetIDs,
  1335. pcPropertySets,
  1336. prgPropertySets );
  1337. sc = _RowsetProps.GetProperties( cPropertySetIDs,
  1338. rgPropertySetIDs,
  1339. pcPropertySets,
  1340. prgPropertySets );
  1341. }
  1342. CATCH( CException, e )
  1343. {
  1344. //
  1345. // Don't PostHResult here. Let the caller do the posting.
  1346. //
  1347. sc = _DBErrorObj.PostHResult( e, IID_ICommandProperties );
  1348. }
  1349. END_CATCH;
  1350. UNTRANSLATE_EXCEPTIONS;
  1351. return sc;
  1352. } //GetProperties
  1353. //+---------------------------------------------------------------------------
  1354. //
  1355. // Method: CRootQuerySpec::SetProperties, public
  1356. //
  1357. // Synopsis: Set rowset properties
  1358. //
  1359. // Arguments: [cPropertySets] - number of property sets
  1360. // [rgProperties] - array of property sets to be set
  1361. //
  1362. // History: 16 Nov 95 AlanW Created
  1363. //
  1364. //----------------------------------------------------------------------------
  1365. SCODE CRootQuerySpec::SetProperties(
  1366. ULONG cPropertySets,
  1367. DBPROPSET rgPropertySets[])
  1368. {
  1369. _DBErrorObj.ClearErrorInfo();
  1370. if ( HaveQuery() && _pInternalQuery->IsQueryActive() )
  1371. return _DBErrorObj.PostHResult(DB_E_OBJECTOPEN, IID_ICommandProperties);
  1372. //
  1373. // Quick return
  1374. //
  1375. if( cPropertySets == 0 )
  1376. return S_OK;
  1377. SCODE sc = S_OK;
  1378. TRANSLATE_EXCEPTIONS;
  1379. TRY
  1380. {
  1381. CUtlProps::SetPropertiesArgChk( cPropertySets, rgPropertySets );
  1382. if ( IsRowsetOpen() )
  1383. THROW( CException(DB_E_OBJECTOPEN) );
  1384. DWORD dwPropFlags = _RowsetProps.GetPropertyFlags();
  1385. sc = _RowsetProps.SetProperties( cPropertySets, rgPropertySets );
  1386. if ( SUCCEEDED( sc ) )
  1387. {
  1388. if ( _pColumnsInfo &&
  1389. _RowsetProps.GetPropertyFlags() != dwPropFlags )
  1390. InitColumns();
  1391. }
  1392. }
  1393. CATCH( CException, e )
  1394. {
  1395. //
  1396. // Don't PostHResult here. Let the caller do the posting.
  1397. //
  1398. sc = e.GetErrorCode();
  1399. }
  1400. END_CATCH;
  1401. UNTRANSLATE_EXCEPTIONS;
  1402. return sc;
  1403. }
  1404. //
  1405. // IServiceProperties methods
  1406. //
  1407. //+---------------------------------------------------------------------------
  1408. //
  1409. // Method: CRootQuerySpec::GetPropertyInfo, public
  1410. //
  1411. // Synopsis: Get rowset properties
  1412. //
  1413. // Arguments: [cPropertySetIDs] - number of desired properties or 0
  1414. // [rgPropertySetIDs] - array of desired properties or NULL
  1415. // [pcPropertySets] - number of property sets returned
  1416. // [prgPropertySets] - array of returned property sets
  1417. // [ppwszDesc] - if non-zero, property descriptions are
  1418. // returneed
  1419. //
  1420. // History: 16 Nov 95 AlanW Created
  1421. //
  1422. //----------------------------------------------------------------------------
  1423. SCODE CRootQuerySpec::GetPropertyInfo(
  1424. const ULONG cPropertySetIDs,
  1425. const DBPROPIDSET rgPropertySetIDs[],
  1426. ULONG * pcPropertySets,
  1427. DBPROPINFOSET ** prgPropertySets,
  1428. WCHAR ** ppwszDesc)
  1429. {
  1430. if ( (0 != cPropertySetIDs && 0 == rgPropertySetIDs) ||
  1431. 0 == pcPropertySets ||
  1432. 0 == prgPropertySets )
  1433. {
  1434. if (pcPropertySets)
  1435. *pcPropertySets = 0;
  1436. if (prgPropertySets)
  1437. *prgPropertySets = 0;
  1438. return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IServiceProperties);
  1439. }
  1440. SCODE sc = S_OK;
  1441. *pcPropertySets = 0;
  1442. *prgPropertySets = 0;
  1443. if (ppwszDesc)
  1444. *ppwszDesc = 0;
  1445. TRANSLATE_EXCEPTIONS;
  1446. TRY
  1447. {
  1448. sc = _PropInfo.GetPropertyInfo( cPropertySetIDs,
  1449. rgPropertySetIDs,
  1450. pcPropertySets,
  1451. prgPropertySets,
  1452. ppwszDesc );
  1453. // Don't PostHResult here -- it's a good chance it's a scope
  1454. // property that we're expecting to fail. Spare the expense.
  1455. // The child object will post the error for us.
  1456. }
  1457. CATCH( CException, e )
  1458. {
  1459. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IServiceProperties);
  1460. sc = GetOleError(e);
  1461. }
  1462. END_CATCH;
  1463. UNTRANSLATE_EXCEPTIONS;
  1464. return sc;
  1465. }
  1466. //+---------------------------------------------------------------------------
  1467. //
  1468. // Method: CRootQuerySpec::SetRequestedProperties, public
  1469. //
  1470. // Synopsis: Set rowset properties
  1471. //
  1472. // Arguments: [cPropertySets] - number of property sets
  1473. // [rgProperties] - array of property sets to be set
  1474. //
  1475. // History: 16 Nov 95 AlanW Created
  1476. //
  1477. //----------------------------------------------------------------------------
  1478. SCODE CRootQuerySpec::SetRequestedProperties(
  1479. ULONG cPropertySets,
  1480. DBPROPSET rgPropertySets[])
  1481. {
  1482. if ( HaveQuery() && _pInternalQuery->IsQueryActive() )
  1483. return _DBErrorObj.PostHResult(DB_E_OBJECTOPEN, IID_IServiceProperties);
  1484. if ( 0 != cPropertySets && 0 == rgPropertySets)
  1485. return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IServiceProperties);
  1486. SCODE sc = S_OK;
  1487. TRANSLATE_EXCEPTIONS;
  1488. TRY
  1489. {
  1490. sc = _RowsetProps.SetProperties( cPropertySets,
  1491. rgPropertySets );
  1492. // Don't PostHResult here -- it's a good chance it's a scope
  1493. // property that we're expecting to fail. Spare the expense.
  1494. // The child object will post the error for us.
  1495. }
  1496. CATCH( CException, e )
  1497. {
  1498. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IServiceProperties);
  1499. sc = GetOleError(e);
  1500. }
  1501. END_CATCH;
  1502. UNTRANSLATE_EXCEPTIONS;
  1503. return sc;
  1504. }
  1505. //+---------------------------------------------------------------------------
  1506. //
  1507. // Method: CRootQuerySpec::SetSuppliedProperties, public
  1508. //
  1509. // Synopsis: Set rowset properties
  1510. //
  1511. // Arguments: [cPropertySets] - number of property sets
  1512. // [rgProperties] - array of property sets to be set
  1513. //
  1514. // History: 16 Nov 95 AlanW Created
  1515. //
  1516. //----------------------------------------------------------------------------
  1517. SCODE CRootQuerySpec::SetSuppliedProperties(
  1518. ULONG cPropertySets,
  1519. DBPROPSET rgPropertySets[])
  1520. {
  1521. if ( HaveQuery() && _pInternalQuery->IsQueryActive() )
  1522. return _DBErrorObj.PostHResult(DB_E_OBJECTOPEN, IID_IServiceProperties);
  1523. if ( 0 != cPropertySets && 0 == rgPropertySets)
  1524. return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IServiceProperties);
  1525. SCODE sc = S_OK;
  1526. TRANSLATE_EXCEPTIONS;
  1527. TRY
  1528. {
  1529. sc = _RowsetProps.SetProperties( cPropertySets,
  1530. rgPropertySets );
  1531. // Don't PostHResult here -- it's a good chance it's a scope
  1532. // property that we're expecting to fail. Spare the expense.
  1533. // The child object will post the error for us.
  1534. }
  1535. CATCH( CException, e )
  1536. {
  1537. _DBErrorObj.PostHResult(e.GetErrorCode(), IID_IServiceProperties);
  1538. sc = GetOleError(e);
  1539. }
  1540. END_CATCH;
  1541. UNTRANSLATE_EXCEPTIONS;
  1542. return sc;
  1543. }
  1544. //+---------------------------------------------------------------------------
  1545. //
  1546. // Method: CRootQuerySpec::_CheckRootNode, private
  1547. //
  1548. // Synopsis: Check a client's root node for validity
  1549. //
  1550. // Arguments: [pRoot] -- DBCOMMANDTREE node at root of tree
  1551. //
  1552. // Notes: A command tree root node may have children, but it
  1553. // may not have siblings.
  1554. //
  1555. // History: 29 Jun 95 AlanW Created
  1556. //
  1557. //----------------------------------------------------------------------------
  1558. void CRootQuerySpec::_CheckRootNode(
  1559. const DBCOMMANDTREE * pRoot)
  1560. {
  1561. if (pRoot->pctNextSibling)
  1562. THROW(CException(E_INVALIDARG));
  1563. }
  1564. //+---------------------------------------------------------------------------
  1565. //
  1566. // Method: CRootQuerySpec::GetColumnsInfo, private
  1567. //
  1568. // Synopsis: Create an IColumnsInfo* for the columns in the query tree
  1569. //
  1570. // Arguments: -none-
  1571. //
  1572. // Returns: CColumnsInfo* - a pointer to a CColumnsInfo that implements
  1573. // IColumnsInfo.
  1574. //
  1575. //----------------------------------------------------------------------------
  1576. static GUID guidBmk = DBBMKGUID;
  1577. CColumnsInfo * CRootQuerySpec::GetColumnsInfo()
  1578. {
  1579. if ( 0 == _pColumnsInfo )
  1580. {
  1581. _pColumnsInfo = new CColumnsInfo( *((IUnknown *) (ICommand *) this),
  1582. _DBErrorObj, FALSE );
  1583. InitColumns( );
  1584. }
  1585. return _pColumnsInfo;
  1586. }
  1587. //+---------------------------------------------------------------------------
  1588. //
  1589. // Method: CRootQuerySpec::InitColumns, private
  1590. //
  1591. // Synopsis: Reinitialize the columns associated with the CColumnsInfo
  1592. //
  1593. // Arguments: -none-
  1594. //
  1595. //----------------------------------------------------------------------------
  1596. void CRootQuerySpec::InitColumns( )
  1597. {
  1598. if ( _pQueryTree && !(_dwStatus & CMD_COLINFO_NOTPREPARED) )
  1599. {
  1600. BOOL fSequential = TRUE; // need to know for CColumnsInfo ctor
  1601. //
  1602. // Fault-in columnsinfo.
  1603. //
  1604. CParseCommandTree Parse;
  1605. Parse.ParseTree( _pQueryTree );
  1606. CCategorizationSet & rCateg = Parse.GetCategorization();
  1607. CPidMapperWithNames & pidmap = Parse.GetPidmap();
  1608. CColumnSet const * pColSet = &Parse.GetOutputColumns();
  1609. if ( 0 != rCateg.Count() )
  1610. {
  1611. //
  1612. // Ole-db spec says that for categorization, we must use the
  1613. // top-level columns only.
  1614. //
  1615. pColSet = &(rCateg.Get(0)->GetColumnSet());
  1616. }
  1617. for ( unsigned i = 0; i < pColSet->Count(); i++ )
  1618. {
  1619. CFullPropSpec const * pPropSpec = pidmap.PidToName( pColSet->Get(i));
  1620. if (pPropSpec->IsPropertyPropid() &&
  1621. pPropSpec->GetPropertyPropid() == PROPID_DBBMK_BOOKMARK &&
  1622. pPropSpec->GetPropSet() == guidBmk)
  1623. fSequential = FALSE;
  1624. }
  1625. if ( _RowsetProps.GetPropertyFlags() &
  1626. ( eLocatable | eScrollable ) )
  1627. fSequential = FALSE;
  1628. _pColumnsInfo->InitColumns( *pColSet,
  1629. pidmap,
  1630. fSequential );
  1631. }
  1632. else
  1633. {
  1634. _pColumnsInfo->InitColumns( (_dwStatus & CMD_COLINFO_NOTPREPARED) );
  1635. }
  1636. }
  1637. //+---------------------------------------------------------------------------
  1638. //
  1639. // Member: CRootQuerySpec::CreateAccessor
  1640. //
  1641. // Synopsis: Makes an accessor that a client can use to get data.
  1642. //
  1643. // Arguments: [dwAccessorFlags] -- read/write access requested
  1644. // [cBindings] -- # of bindings in rgBindings
  1645. // [rgBindings] -- array of bindings for the accessor to support
  1646. // [cbRowSize] -- ignored for IRowset
  1647. // [phAccessor] -- returns created accessor if all is ok
  1648. // [rgBindStatus] -- array of binding statuses
  1649. //
  1650. // Returns: SCODE error code
  1651. //
  1652. // History: 11-07-95 srikants Created
  1653. //
  1654. // Notes:
  1655. //
  1656. //----------------------------------------------------------------------------
  1657. STDMETHODIMP CRootQuerySpec::CreateAccessor(
  1658. DBACCESSORFLAGS dwAccessorFlags,
  1659. DBCOUNTITEM cBindings,
  1660. const DBBINDING rgBindings[],
  1661. DBLENGTH cbRowSize,
  1662. HACCESSOR * phAccessor,
  1663. DBBINDSTATUS rgBindStatus[])
  1664. {
  1665. _DBErrorObj.ClearErrorInfo();
  1666. SCODE sc = S_OK;
  1667. if (0 == phAccessor || (0 != cBindings && 0 == rgBindings))
  1668. return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IAccessor);
  1669. // Make sure pointer is good while zeroing in case of a later error
  1670. *phAccessor = 0;
  1671. TRANSLATE_EXCEPTIONS;
  1672. TRY
  1673. {
  1674. CColumnsInfo * pColumnsInfo = 0;
  1675. XPtr<CRowDataAccessor> Accessor(new CRowDataAccessor(dwAccessorFlags,
  1676. cBindings,
  1677. rgBindings,
  1678. rgBindStatus,
  1679. (_RowsetProps.GetPropertyFlags() & eExtendedTypes) != 0,
  1680. (IUnknown *) (ICommand *) this,
  1681. pColumnsInfo
  1682. ));
  1683. CLock lck( _mtxCmd );
  1684. _aAccessors.Add( Accessor.GetPointer() );
  1685. *phAccessor = (Accessor.Acquire())->Cast();
  1686. }
  1687. CATCH(CException, e)
  1688. {
  1689. sc = _DBErrorObj.PostHResult( e, IID_IAccessor );
  1690. _DBErrorObj.PostHResult( sc, IID_IAccessor );
  1691. }
  1692. END_CATCH;
  1693. UNTRANSLATE_EXCEPTIONS;
  1694. return sc;
  1695. }
  1696. //+---------------------------------------------------------------------------
  1697. //
  1698. // Member: CRootQuerySpec::GetBindings, private
  1699. //
  1700. // Synopsis: Returns an accessor's bindings
  1701. //
  1702. // Arguments: [hAccessor] -- accessor being queried
  1703. // [dwAccessorFlags] -- returns read/write access of accessor
  1704. // [pcBindings] -- returns # of bindings in rgBindings
  1705. // [prgBindings] -- returns array of bindings
  1706. //
  1707. // Returns: SCODE error code
  1708. //
  1709. // History: 14 Dec 94 dlee Created
  1710. //
  1711. //----------------------------------------------------------------------------
  1712. STDMETHODIMP CRootQuerySpec::GetBindings(
  1713. HACCESSOR hAccessor,
  1714. DBACCESSORFLAGS * pdwAccessorFlags,
  1715. DBCOUNTITEM * pcBindings,
  1716. DBBINDING * * prgBindings) /*const*/
  1717. {
  1718. _DBErrorObj.ClearErrorInfo();
  1719. SCODE sc = S_OK;
  1720. if (0 == pdwAccessorFlags ||
  1721. 0 == pcBindings ||
  1722. 0 == prgBindings)
  1723. {
  1724. // fill in error values where possible
  1725. if (pdwAccessorFlags)
  1726. *pdwAccessorFlags = DBACCESSOR_INVALID;
  1727. if (pcBindings)
  1728. *pcBindings = 0;
  1729. if (prgBindings)
  1730. *prgBindings = 0;
  1731. return _DBErrorObj.PostHResult(E_INVALIDARG, IID_IAccessor);
  1732. }
  1733. *pdwAccessorFlags = DBACCESSOR_INVALID;
  1734. *pcBindings = 0;
  1735. *prgBindings = 0;
  1736. TRANSLATE_EXCEPTIONS;
  1737. TRY
  1738. {
  1739. CLock lck( _mtxCmd );
  1740. CAccessor * pAccessor = (CAccessor *)_aAccessors.Convert( hAccessor );
  1741. pAccessor->GetBindings(pdwAccessorFlags, pcBindings, prgBindings);
  1742. }
  1743. CATCH(CException, e)
  1744. {
  1745. sc = _DBErrorObj.PostHResult( e, IID_IAccessor );
  1746. _DBErrorObj.PostHResult( sc, IID_IAccessor );
  1747. }
  1748. END_CATCH;
  1749. UNTRANSLATE_EXCEPTIONS;
  1750. return sc;
  1751. }
  1752. //+---------------------------------------------------------------------------
  1753. //
  1754. // Member: CRootQuerySpec::AddRefAccessor, private
  1755. //
  1756. // Synopsis: Frees an accessor
  1757. //
  1758. // Arguments: [hAccessor] -- accessor being freed
  1759. // [pcRefCount] -- pointer to residual refcount (optional)
  1760. //
  1761. // Returns: SCODE error code
  1762. //
  1763. // History: 14 Dec 94 dlee Created
  1764. //
  1765. //----------------------------------------------------------------------------
  1766. STDMETHODIMP CRootQuerySpec::AddRefAccessor(
  1767. HACCESSOR hAccessor,
  1768. ULONG * pcRefCount )
  1769. {
  1770. _DBErrorObj.ClearErrorInfo();
  1771. SCODE sc = S_OK;
  1772. TRANSLATE_EXCEPTIONS;
  1773. TRY
  1774. {
  1775. CLock lck( _mtxCmd );
  1776. _aAccessors.AddRef( hAccessor, pcRefCount );
  1777. }
  1778. CATCH(CException, e)
  1779. {
  1780. sc = _DBErrorObj.PostHResult( e, IID_IAccessor );
  1781. _DBErrorObj.PostHResult(sc, IID_IAccessor);
  1782. }
  1783. END_CATCH;
  1784. UNTRANSLATE_EXCEPTIONS;
  1785. return sc;
  1786. }
  1787. //+---------------------------------------------------------------------------
  1788. //
  1789. // Member: CRootQuerySpec::ReleaseAccessor, private
  1790. //
  1791. // Synopsis: Frees an accessor
  1792. //
  1793. // Arguments: [hAccessor] -- accessor being freed
  1794. // [pcRefCount] -- pointer to residual refcount (optional)
  1795. //
  1796. // Returns: SCODE error code
  1797. //
  1798. // History: 14 Dec 94 dlee Created
  1799. //
  1800. //----------------------------------------------------------------------------
  1801. STDMETHODIMP CRootQuerySpec::ReleaseAccessor(
  1802. HACCESSOR hAccessor,
  1803. ULONG * pcRefCount )
  1804. {
  1805. _DBErrorObj.ClearErrorInfo();
  1806. SCODE sc = S_OK;
  1807. TRANSLATE_EXCEPTIONS;
  1808. TRY
  1809. {
  1810. CLock lck( _mtxCmd );
  1811. _aAccessors.Release( hAccessor, pcRefCount );
  1812. }
  1813. CATCH(CException, e)
  1814. {
  1815. sc = _DBErrorObj.PostHResult( e, IID_IAccessor );
  1816. _DBErrorObj.PostHResult(sc, IID_IAccessor);
  1817. }
  1818. END_CATCH;
  1819. UNTRANSLATE_EXCEPTIONS;
  1820. return sc;
  1821. }
  1822. //+---------------------------------------------------------------------------
  1823. //
  1824. // Member: CRootQuerySpec::CanConvert, public
  1825. //
  1826. // Synopsis: Indicate whether a type conversion is valid.
  1827. //
  1828. // Arguments: [wFromType] -- source type
  1829. // [wToType] -- destination type
  1830. // [dwConvertFlags] -- read/write access requested
  1831. //
  1832. // Returns: S_OK if the conversion is available, S_FALSE otherwise.
  1833. // E_FAIL, E_INVALIDARG or DB_E_BADCONVERTFLAG on errors.
  1834. //
  1835. // History: 20 Nov 96 AlanW Created
  1836. // 14 Jan 98 VikasMan Passed IDataConvert(OLE-DB data conv.
  1837. // interface) to CanConvertType
  1838. //
  1839. //----------------------------------------------------------------------------
  1840. STDMETHODIMP CRootQuerySpec::CanConvert( DBTYPE wFromType, DBTYPE wToType, DBCONVERTFLAGS dwConvertFlags )
  1841. {
  1842. _DBErrorObj.ClearErrorInfo();
  1843. SCODE sc = S_OK;
  1844. TRANSLATE_EXCEPTIONS;
  1845. TRY
  1846. {
  1847. if (((dwConvertFlags & DBCONVERTFLAGS_COLUMN) &&
  1848. (dwConvertFlags & DBCONVERTFLAGS_PARAMETER)) ||
  1849. (dwConvertFlags & ~(DBCONVERTFLAGS_COLUMN |
  1850. DBCONVERTFLAGS_PARAMETER |
  1851. DBCONVERTFLAGS_ISFIXEDLENGTH |
  1852. DBCONVERTFLAGS_ISLONG |
  1853. DBCONVERTFLAGS_FROMVARIANT)))
  1854. {
  1855. sc = DB_E_BADCONVERTFLAG;
  1856. }
  1857. else if ( ( dwConvertFlags & DBCONVERTFLAGS_FROMVARIANT ) &&
  1858. !IsValidFromVariantType(wFromType) )
  1859. {
  1860. sc = DB_E_BADTYPE;
  1861. }
  1862. else
  1863. {
  1864. // Allocate this on the stack
  1865. XInterface<IDataConvert> xDataConvert;
  1866. BOOL fOk = CAccessor::CanConvertType( wFromType,
  1867. wToType,
  1868. (_RowsetProps.GetPropertyFlags() & eExtendedTypes) != 0,
  1869. xDataConvert );
  1870. sc = fOk ? S_OK : S_FALSE;
  1871. }
  1872. if (FAILED(sc))
  1873. _DBErrorObj.PostHResult(sc, IID_IConvertType);
  1874. }
  1875. CATCH(CException, e)
  1876. {
  1877. sc = _DBErrorObj.PostHResult( e, IID_IConvertType );
  1878. _DBErrorObj.PostHResult( sc, IID_IConvertType );
  1879. }
  1880. END_CATCH;
  1881. UNTRANSLATE_EXCEPTIONS;
  1882. return sc;
  1883. }
  1884. //+---------------------------------------------------------------------------
  1885. //
  1886. // Member: CRootQuerySpec::BuildTree, public
  1887. //
  1888. // Synopsis: Takes a cached SQL Text and translates it into a Query Tree
  1889. // Called from Execute(), Prepare() and GetCommandTree().
  1890. //
  1891. // Arguments: [pIID] - IID of interface calling this function
  1892. //
  1893. //
  1894. // Returns: [S_OK] - a command tree was built successfully
  1895. // [DB_S_NORESULT] - the command didn't generate a tree
  1896. // (e.g SET PROPERTYNAME...)
  1897. // All error codes are thrown.
  1898. //
  1899. //
  1900. // History: 10-31-97 danleg Created
  1901. // 01-01-98 danleg Moved global views to CreateParser
  1902. //
  1903. //----------------------------------------------------------------------------
  1904. SCODE CRootQuerySpec::BuildTree( )
  1905. {
  1906. SCODE sc = S_OK;
  1907. DBCOMMANDTREE * pDBCOMMANDTREE = 0;
  1908. XInterface<IParserTreeProperties> xIPTProperties;
  1909. LCID lcidContent = GetLCIDFromString((LPWSTR)_RowsetProps.GetValString(
  1910. CMRowsetProps::eid_DBPROPSET_MSIDXS_ROWSET_EXT,
  1911. CMRowsetProps::eid_MSIDXSPROPVAL_COMMAND_LOCALE_STRING));
  1912. //
  1913. // Synch IParserSession's catalog cache with DBPROP_CURRENTCATALOG. If no session,
  1914. // catalogs are specified using the catalog..scope() syntax anyway.
  1915. //
  1916. if ( !_xSession.IsNull() )
  1917. {
  1918. LPCWSTR pwszCatalog = ((_xSession->GetDataSrcPtr())->GetDSPropsPtr())->GetValString(
  1919. CMDSProps::eid_DBPROPSET_DATASOURCE,
  1920. CMDSProps::eid_DBPROPVAL_CURRENTCATALOG );
  1921. _xpIPSession->SetCatalog( pwszCatalog );
  1922. }
  1923. // NOTE: For CREATE VIEW and SET PROPERTYNAME calls, ToTree will return DB_S_NORESULT
  1924. sc = _xpIPSession->ToTree( lcidContent,
  1925. _pwszSQLText,
  1926. &pDBCOMMANDTREE,
  1927. xIPTProperties.GetPPointer() );
  1928. if( S_OK == sc )
  1929. {
  1930. //
  1931. // Set flag to indicate that BuildTree is calling SetCommandTree
  1932. //
  1933. _dwStatus |= CMD_TEXT_TOTREE;
  1934. // Set the command tree
  1935. sc = SetCommandTree( &pDBCOMMANDTREE, DBCOMMANDREUSE_NONE, FALSE );
  1936. if ( SUCCEEDED(sc) )
  1937. {
  1938. VARIANT vVal;
  1939. VariantInit( &vVal );
  1940. // We need to set the QUERY_RESTRICTION so it can be cloned into
  1941. // the rowset properties object
  1942. if( SUCCEEDED( xIPTProperties->GetProperties(PTPROPS_CIRESTRICTION,
  1943. &vVal)) )
  1944. {
  1945. _RowsetProps.SetValString(
  1946. CMRowsetProps::eid_DBPROPSET_MSIDXS_ROWSET_EXT,
  1947. CMRowsetProps::eid_MSIDXSPROPVAL_QUERY_RESTRICTION,
  1948. (LPCWSTR)V_BSTR(&vVal) );
  1949. }
  1950. VariantClear( &vVal );
  1951. }
  1952. }
  1953. else if( FAILED(sc) && !xIPTProperties.IsNull() )
  1954. {
  1955. // Retrieve Error Information
  1956. SCODE sc2 = S_OK;
  1957. DISPPARAMS * pDispParams = NULL;
  1958. VARIANT vVal[3];
  1959. ULONG ul;
  1960. for(ul=0; ul<NUMELEM(vVal); ul++)
  1961. VariantInit(&vVal[ul]);
  1962. if( SUCCEEDED(sc2 = xIPTProperties->GetProperties(
  1963. PTPROPS_ERR_IDS, &vVal[0])) )
  1964. {
  1965. if( (V_I4(&vVal[0]) > 0) && SUCCEEDED(sc2 = xIPTProperties->GetProperties(
  1966. PTPROPS_ERR_HR, &vVal[1])) )
  1967. {
  1968. if( SUCCEEDED(sc2 = xIPTProperties->GetProperties(
  1969. PTPROPS_ERR_DISPPARAM, &vVal[2])) )
  1970. {
  1971. // Change safearray into DISPPARMS
  1972. SAFEARRAY* psa = V_ARRAY(&vVal[2]);
  1973. if( psa && psa->rgsabound[0].cElements)
  1974. {
  1975. pDispParams = (DISPPARAMS*)CoTaskMemAlloc(sizeof(DISPPARAMS));
  1976. if( pDispParams )
  1977. {
  1978. pDispParams->cNamedArgs = 0;
  1979. pDispParams->rgdispidNamedArgs = NULL;
  1980. pDispParams->cArgs = psa->rgsabound[0].cElements;
  1981. pDispParams->rgvarg =
  1982. (VARIANT*)CoTaskMemAlloc(sizeof(VARIANTARG) * psa->rgsabound[0].cElements);
  1983. if( pDispParams->rgvarg )
  1984. {
  1985. for (ULONG i=0; i<psa->rgsabound[0].cElements; i++)
  1986. {
  1987. VariantInit(&(pDispParams->rgvarg[i]));
  1988. V_VT(&(pDispParams->rgvarg[i])) = VT_BSTR;
  1989. V_BSTR(&(pDispParams->rgvarg[i])) = ((BSTR*)psa->pvData)[i];
  1990. ((BSTR*)psa->pvData)[i] = NULL;
  1991. }
  1992. }
  1993. }
  1994. }
  1995. // Post a parser error
  1996. _DBErrorObj.PostParserError( V_I4(&vVal[1]),
  1997. V_I4(&vVal[0]),
  1998. &pDispParams );
  1999. // This is the SCODE of the error just posted.
  2000. sc2 = V_I4(&vVal[1]);
  2001. if ( FAILED(sc2) )
  2002. sc = sc2;
  2003. Win4Assert( pDispParams == NULL ); // Should be null after post
  2004. }
  2005. }
  2006. }
  2007. for ( ul=0; ul<NUMELEM(vVal); ul++ )
  2008. VariantClear( &vVal[ul] );
  2009. }
  2010. if( pDBCOMMANDTREE )
  2011. FreeCommandTree( &pDBCOMMANDTREE );
  2012. if ( FAILED(sc) )
  2013. THROW( CException(sc) );
  2014. return sc;
  2015. }
  2016. //+---------------------------------------------------------------------------
  2017. //
  2018. // Member: CRootQuerySpec::CreateParser, private
  2019. //
  2020. // Synopsis: Creates a parser object if one was not passed through a session
  2021. //
  2022. // History: 11-25-97 danleg Created
  2023. //
  2024. //----------------------------------------------------------------------------
  2025. void CRootQuerySpec::CreateParser()
  2026. {
  2027. SCODE sc = S_OK;
  2028. CLock lck( _mtxCmd );
  2029. sc = MakeIParser( _xIParser.GetPPointer() );
  2030. if ( FAILED(sc) )
  2031. {
  2032. Win4Assert( sc != E_INVALIDARG );
  2033. THROW( CException(sc) );
  2034. }
  2035. XInterface<IColumnMapperCreator> xColMapCreator;
  2036. XInterface<CImpIParserVerify> xIPVerify(new CImpIParserVerify());
  2037. //
  2038. // Create an IParserSession object
  2039. //
  2040. xIPVerify->GetColMapCreator( ((IColumnMapperCreator**)xColMapCreator.GetQIPointer()) );
  2041. sc = _xIParser->CreateSession( &DBGUID_MSSQLTEXT,
  2042. DEFAULT_MACHINE,
  2043. xIPVerify.GetPointer(),
  2044. xColMapCreator.GetPointer(),
  2045. (IParserSession**)_xpIPSession.GetQIPointer() );
  2046. if ( FAILED(sc) )
  2047. THROW( CException(sc) );
  2048. //
  2049. // Set default catalog in the parser session object
  2050. //
  2051. _xpwszCatalog.Init( MAX_PATH );
  2052. ULONG cOut;
  2053. sc = xIPVerify->GetDefaultCatalog( _xpwszCatalog.GetPointer(),
  2054. _xpwszCatalog.Count(),
  2055. &cOut);
  2056. //
  2057. // _xpwszCatalog isn't long enough
  2058. //
  2059. Win4Assert( E_INVALIDARG != sc );
  2060. if ( FAILED(sc) )
  2061. THROW( CException(sc) );
  2062. sc = _xpIPSession->SetCatalog( _xpwszCatalog.GetPointer() );
  2063. if( FAILED(sc) )
  2064. THROW( CException(sc) );
  2065. DBCOMMANDTREE * pDBCOMMANDTREE = 0;
  2066. XInterface<IParserTreeProperties> xIPTProperties;
  2067. LCID lcidContent = GetLCIDFromString((LPWSTR)_RowsetProps.GetValString(
  2068. CMRowsetProps::eid_DBPROPSET_MSIDXS_ROWSET_EXT,
  2069. CMRowsetProps::eid_MSIDXSPROPVAL_COMMAND_LOCALE_STRING));
  2070. //
  2071. // Predefined views
  2072. //
  2073. sc = _xpIPSession->ToTree( lcidContent,
  2074. s_pwszPredefinedViews,
  2075. &pDBCOMMANDTREE,
  2076. xIPTProperties.GetPPointer() );
  2077. if ( FAILED(sc) )
  2078. THROW( CException(sc) );
  2079. } //CreateParser