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.

1832 lines
61 KiB

  1. %{
  2. class CValueParser;
  3. #if 0
  4. %}
  5. %union
  6. {
  7. WCHAR * pwszChar;
  8. DBCOMMANDOP dbop;
  9. CDbRestriction * pRest;
  10. CStorageVariant * pStorageVar;
  11. CValueParser *pPropValueParser;
  12. int iInt;
  13. int iEmpty;
  14. }
  15. %left _OR
  16. %left _AND _NEAR _NEARDIST
  17. %left _NOT
  18. %left '(' ')'
  19. /***
  20. *** Tokens (used also by flex via parser.h)
  21. ***/
  22. /***
  23. *** reserved_words
  24. ***/
  25. %token _CONTAINS
  26. %token _AND
  27. %token _OR
  28. %token _NOT
  29. %token _NEAR
  30. %token _LT
  31. %token _GT
  32. %token _LTE
  33. %token _GTE
  34. %token _EQ
  35. %token _NE
  36. %token _ALLOF
  37. %token _SOMEOF
  38. %token _OPEN
  39. %token _CLOSE
  40. %token _VECTOR_END
  41. %token _VE
  42. %token _VE_END
  43. %token _PROPEND
  44. %token _NEAR_END
  45. %token _LTSOME
  46. %token _GTSOME
  47. %token _LTESOME
  48. %token _GTESOME
  49. %token _EQSOME
  50. %token _NESOME
  51. %token _ALLOFSOME
  52. %token _SOMEOFSOME
  53. %token _LTALL
  54. %token _GTALL
  55. %token _LTEALL
  56. %token _GTEALL
  57. %token _EQALL
  58. %token _NEALL
  59. %token _ALLOFALL
  60. %token _SOMEOFALL
  61. %token _COERCE
  62. %token _SHGENPREFIX
  63. %token _SHGENINFLECT
  64. %token _GENPREFIX
  65. %token _GENINFLECT
  66. %token _GENNORMAL
  67. /***
  68. *** Terminal tokens
  69. ***/
  70. %token <pwszChar> _PHRASE
  71. %token <pwszChar> _PROPNAME
  72. %token <pwszChar> _NEARDIST
  73. %token <pwszChar> _NEARUNIT
  74. %token <pwszChar> _WEIGHT
  75. %token <pwszChar> _REGEX
  76. %token <pwszChar> _FREETEXT
  77. %token <pwszChar> _VECTORELEMENT
  78. %token <pwszChar> _VEMETHOD
  79. %token <pwszChar> _PHRASEORREGEX
  80. /***
  81. *** Nonterminal tokens
  82. ***/
  83. %type <pStorageVar> Value
  84. %type <pStorageVar> VectorValue
  85. %type <pPropValueParser> SingletVector
  86. %type <pPropValueParser> EmptyVector
  87. %type <pPropValueParser> MultiVector
  88. %type <dbop> Op
  89. %type <dbop> Matches
  90. %type <iEmpty> Property // placeholder. value is empty (info saved to state)
  91. %type <iEmpty> Contains // placeholder. value is empty
  92. %type <iEmpty> Open // placeholder. value is empty
  93. %type <iEmpty> Close // placeholder. value is empty
  94. %type <iInt> Gen
  95. %type <iEmpty> GenEnd // placeholder. value is empty (info saved to state)
  96. %type <iEmpty> PropEnd // placeholder. value is empty (info saved to state)
  97. %type <iInt> ShortGen
  98. %type <pRest> Term
  99. %type <pRest> PropTerm
  100. %type <pRest> NestTerm
  101. %type <pRest> CoerceTerm
  102. %type <pRest> NearTerm
  103. %type <pRest> AndTerm
  104. %type <pRest> VectorTerm
  105. %type <pRest> VectorSpec
  106. %type <pRest> query
  107. %{
  108. #endif
  109. #define YYDEBUG CIDBG
  110. #include <malloc.h>
  111. #include "yybase.hxx"
  112. #include "parser.h" // defines yystype
  113. #include "parsepl.h"
  114. #include "flexcpp.h"
  115. #if CIDBG == 1
  116. #define AssertReq(x) Assert(x != NULL)
  117. #else
  118. #define AssertReq(x)
  119. #endif
  120. const GUID guidSystem = PSGUID_STORAGE;
  121. static CDbColId psContents( guidSystem, PID_STG_CONTENTS );
  122. //+---------------------------------------------------------------------------
  123. //
  124. // Function: TreeFromText, public
  125. //
  126. // Synopsis: Create a CDbRestriction from a restriction string
  127. //
  128. // Arguments: [wcsRestriction] -- restriction
  129. // [ColumnMapper] -- property list
  130. // [lcid] -- locale id of the query
  131. //
  132. // History: 01-Oct-97 emilyb created
  133. // 26-Aug-98 KLam No longer need to lower case
  134. //
  135. //----------------------------------------------------------------------------
  136. CDbContentRestriction * TreeFromText(
  137. WCHAR const * wcsRestriction,
  138. IColumnMapper & ColumnMapper,
  139. LCID lcid )
  140. {
  141. unsigned cwc = 1 + wcslen( wcsRestriction );
  142. XGrowable<WCHAR> xRestriction( cwc );
  143. WCHAR * pwc = xRestriction.Get();
  144. RtlCopyMemory( pwc, wcsRestriction, cwc * sizeof WCHAR );
  145. cwc--;
  146. // The parser can't deal with trailing space so strip it off
  147. while ( cwc > 0 && L' ' == pwc[cwc-1] )
  148. cwc--;
  149. pwc[cwc] = 0;
  150. TripLexer Lexer;
  151. XPtr<YYPARSER> xParser( new TripParser( ColumnMapper, lcid, Lexer ) );
  152. xParser->yyprimebuffer( pwc );
  153. #if 0 // YYDEBUG == 1
  154. // Set this to 1 if you want command line output. to 0 otherwise.
  155. xParser->SetDebug();
  156. #endif
  157. // Actually parse the text producing a tree
  158. SCODE hr = xParser->Parse();
  159. if (FAILED(hr))
  160. THROW( CException( hr ) );
  161. // return the DBCOMMANDTREE
  162. return (CDbContentRestriction *)( xParser->GetParseTree() );
  163. } //TextFromTree
  164. void StripQuotes(WCHAR *wcsPhrase)
  165. {
  166. ULONG cChars = wcslen(wcsPhrase);
  167. LPWSTR pLast = wcsPhrase + cChars - 1;
  168. if (L'"' == *wcsPhrase && L'"' == *pLast)
  169. {
  170. *pLast = L'\0';
  171. MoveMemory(wcsPhrase, wcsPhrase+1, sizeof(WCHAR) * (cChars-1) );
  172. }
  173. }
  174. //+---------------------------------------------------------------------------
  175. //
  176. // Member: CValueParser::CValueParser, public
  177. //
  178. // Synopsis: Allocs CStorageVariant of correct type
  179. //
  180. // History: 01-Oct-97 emilyb created
  181. // 02-Sep-98 KLam Added locale
  182. //
  183. //----------------------------------------------------------------------------
  184. CValueParser::CValueParser(
  185. BOOL fVectorElement,
  186. DBTYPE PropType,
  187. LCID locale ) :
  188. _pStgVariant( 0 ),
  189. _fVector(fVectorElement),
  190. _PropType (PropType),
  191. _cElements ( 0 ),
  192. _locale ( locale )
  193. {
  194. if ( _fVector )
  195. {
  196. // this is a vector
  197. if ( DBTYPE_VECTOR != ( _PropType & DBTYPE_VECTOR ) )
  198. THROW( CParserException( QPARSE_E_EXPECTING_PHRASE ) );
  199. VARENUM ve = (VARENUM ) _PropType;
  200. if ( _PropType == ( DBTYPE_VECTOR | DBTYPE_WSTR ) )
  201. ve = (VARENUM) (VT_VECTOR | VT_LPWSTR);
  202. else if ( _PropType == ( DBTYPE_VECTOR | DBTYPE_STR ) )
  203. ve = (VARENUM) (VT_VECTOR | VT_LPSTR);
  204. _pStgVariant.Set( new CStorageVariant( ve, _cElements ) );
  205. }
  206. else
  207. {
  208. _pStgVariant.Set( new CStorageVariant() );
  209. }
  210. if ( _pStgVariant.IsNull() )
  211. THROW( CException( E_OUTOFMEMORY ) );
  212. }
  213. //+---------------------------------------------------------------------------
  214. //
  215. // Member: CValueParser::AddValue, public
  216. //
  217. // Synopsis: Adds value to CStorageVariant
  218. //
  219. // Arguments: [pwszValue] -- value
  220. //
  221. // History: 01-Oct-97 emilyb code moved here from CPropertyValueParser
  222. //
  223. //----------------------------------------------------------------------------
  224. void CValueParser::AddValue(WCHAR const * pwszValue)
  225. {
  226. if ( _pStgVariant.IsNull() )
  227. THROW( CException( E_OUTOFMEMORY ) );
  228. switch ( _PropType & ~DBTYPE_VECTOR )
  229. {
  230. case DBTYPE_WSTR :
  231. case DBTYPE_WSTR | DBTYPE_BYREF :
  232. {
  233. if ( _PropType & DBTYPE_VECTOR )
  234. _pStgVariant->SetLPWSTR( pwszValue, _cElements );
  235. else
  236. _pStgVariant->SetLPWSTR( pwszValue );
  237. break;
  238. }
  239. case DBTYPE_BSTR :
  240. {
  241. BSTR bstr = SysAllocString( pwszValue );
  242. if ( 0 == bstr )
  243. THROW( CException( E_OUTOFMEMORY ) );
  244. if ( _PropType & DBTYPE_VECTOR )
  245. _pStgVariant->SetBSTR( bstr, _cElements );
  246. else
  247. _pStgVariant->SetBSTR( bstr );
  248. SysFreeString( bstr );
  249. break;
  250. }
  251. case DBTYPE_STR :
  252. case DBTYPE_STR | DBTYPE_BYREF :
  253. {
  254. // make sure there's enough room to translate
  255. unsigned cbBuffer = 1 + 3 * wcslen( pwszValue );
  256. XArray<char> xBuf( cbBuffer );
  257. int cc = WideCharToMultiByte( CP_ACP,
  258. 0,
  259. pwszValue,
  260. -1,
  261. xBuf.Get(),
  262. cbBuffer,
  263. NULL,
  264. NULL );
  265. if ( 0 == cc )
  266. {
  267. #if CIDBG
  268. ULONG ul = GetLastError();
  269. #endif
  270. THROW( CParserException( QPARSE_E_EXPECTING_PHRASE ) );
  271. }
  272. if ( _PropType & DBTYPE_VECTOR )
  273. _pStgVariant->SetLPSTR( xBuf.Get(), _cElements );
  274. else
  275. _pStgVariant->SetLPSTR( xBuf.Get() );
  276. break;
  277. }
  278. case DBTYPE_I1 :
  279. {
  280. CQueryScanner scan( pwszValue, FALSE, _locale );
  281. LONG l = 0;
  282. BOOL fAtEndOfString;
  283. if ( ! ( scan.GetNumber( l, fAtEndOfString ) &&
  284. fAtEndOfString ) )
  285. THROW( CParserException( QPARSE_E_EXPECTING_INTEGER ) );
  286. if ( ( l > SCHAR_MAX ) ||
  287. ( l < SCHAR_MIN ) )
  288. THROW( CParserException( QPARSE_E_EXPECTING_INTEGER ) );
  289. if ( _PropType & DBTYPE_VECTOR )
  290. _pStgVariant->SetI1( (CHAR) l, _cElements );
  291. else
  292. _pStgVariant->SetI1( (CHAR) l );
  293. break;
  294. }
  295. case DBTYPE_UI1 :
  296. {
  297. CQueryScanner scan( pwszValue, FALSE, _locale );
  298. ULONG ul = 0;
  299. BOOL fAtEndOfString;
  300. if ( ! ( scan.GetNumber( ul, fAtEndOfString ) &&
  301. fAtEndOfString ) )
  302. THROW( CParserException( QPARSE_E_EXPECTING_INTEGER ) );
  303. if ( ul > UCHAR_MAX )
  304. THROW( CParserException( QPARSE_E_EXPECTING_INTEGER ) );
  305. if ( _PropType & DBTYPE_VECTOR )
  306. _pStgVariant->SetUI1( (BYTE) ul, _cElements );
  307. else
  308. _pStgVariant->SetUI1( (BYTE) ul );
  309. break;
  310. }
  311. case DBTYPE_I2 :
  312. {
  313. CQueryScanner scan( pwszValue, FALSE, _locale );
  314. LONG l = 0;
  315. BOOL fAtEndOfString;
  316. if ( ! ( scan.GetNumber( l, fAtEndOfString ) &&
  317. fAtEndOfString ) )
  318. THROW( CParserException( QPARSE_E_EXPECTING_INTEGER ) );
  319. if ( ( l > SHRT_MAX ) ||
  320. ( l < SHRT_MIN ) )
  321. THROW( CParserException( QPARSE_E_EXPECTING_INTEGER ) );
  322. if ( _PropType & DBTYPE_VECTOR )
  323. _pStgVariant->SetI2( (short) l, _cElements );
  324. else
  325. _pStgVariant->SetI2( (short) l );
  326. break;
  327. }
  328. case DBTYPE_UI2 :
  329. {
  330. CQueryScanner scan( pwszValue, FALSE, _locale );
  331. ULONG ul = 0;
  332. BOOL fAtEndOfString;
  333. if ( ! ( scan.GetNumber( ul, fAtEndOfString ) &&
  334. fAtEndOfString ) )
  335. THROW( CParserException( QPARSE_E_EXPECTING_INTEGER ) );
  336. if ( ul > USHRT_MAX )
  337. THROW( CParserException( QPARSE_E_EXPECTING_INTEGER ) );
  338. if ( _PropType & DBTYPE_VECTOR )
  339. _pStgVariant->SetUI2( (USHORT) ul, _cElements );
  340. else
  341. _pStgVariant->SetUI2( (USHORT) ul );
  342. break;
  343. }
  344. case DBTYPE_I4 :
  345. {
  346. CQueryScanner scan( pwszValue, FALSE, _locale );
  347. LONG l = 0;
  348. BOOL fAtEndOfString;
  349. if ( ! ( scan.GetNumber( l, fAtEndOfString ) &&
  350. fAtEndOfString ) )
  351. THROW( CParserException( QPARSE_E_EXPECTING_INTEGER ) );
  352. if ( _PropType & DBTYPE_VECTOR )
  353. _pStgVariant->SetI4( l, _cElements );
  354. else
  355. _pStgVariant->SetI4( l );
  356. break;
  357. }
  358. case DBTYPE_UI4 :
  359. {
  360. CQueryScanner scan( pwszValue, FALSE, _locale );
  361. ULONG ul = 0;
  362. BOOL fAtEndOfString;
  363. if ( ! ( scan.GetNumber( ul, fAtEndOfString ) &&
  364. fAtEndOfString ) )
  365. THROW( CParserException( QPARSE_E_EXPECTING_INTEGER ) );
  366. if ( _PropType & DBTYPE_VECTOR )
  367. _pStgVariant->SetUI4( ul, _cElements );
  368. else
  369. _pStgVariant->SetUI4( ul );
  370. break;
  371. }
  372. case DBTYPE_ERROR :
  373. {
  374. // SCODE/HRESULT are typedefed as long (signed)
  375. CQueryScanner scan( pwszValue, FALSE, _locale );
  376. SCODE sc = 0;
  377. BOOL fAtEndOfString;
  378. if ( ! ( scan.GetNumber( sc, fAtEndOfString ) &&
  379. fAtEndOfString ) )
  380. THROW( CParserException( QPARSE_E_EXPECTING_INTEGER ) );
  381. if ( _PropType & DBTYPE_VECTOR )
  382. _pStgVariant->SetERROR( sc, _cElements );
  383. else
  384. _pStgVariant->SetERROR( sc );
  385. break;
  386. }
  387. case DBTYPE_I8 :
  388. {
  389. CQueryScanner scan( pwszValue, FALSE, _locale );
  390. _int64 ll = 0;
  391. BOOL fAtEndOfString;
  392. if ( ! ( scan.GetNumber( ll, fAtEndOfString ) &&
  393. fAtEndOfString ) )
  394. THROW( CParserException( QPARSE_E_EXPECTING_INTEGER ) );
  395. LARGE_INTEGER LargeInt;
  396. LargeInt.QuadPart = ll;
  397. if ( _PropType & DBTYPE_VECTOR )
  398. _pStgVariant->SetI8( LargeInt , _cElements );
  399. else
  400. _pStgVariant->SetI8( LargeInt );
  401. break;
  402. }
  403. case DBTYPE_UI8 :
  404. {
  405. CQueryScanner scan( pwszValue, FALSE, _locale );
  406. unsigned _int64 ull = 0;
  407. BOOL fAtEndOfString;
  408. if ( ! ( scan.GetNumber( ull, fAtEndOfString ) &&
  409. fAtEndOfString ) )
  410. THROW( CParserException( QPARSE_E_EXPECTING_INTEGER ) );
  411. ULARGE_INTEGER LargeInt;
  412. LargeInt.QuadPart = ull;
  413. if ( _PropType & DBTYPE_VECTOR )
  414. _pStgVariant->SetUI8( LargeInt , _cElements );
  415. else
  416. _pStgVariant->SetUI8( LargeInt );
  417. break;
  418. }
  419. case DBTYPE_BOOL :
  420. {
  421. if ( pwszValue[0] == 'T' ||
  422. pwszValue[0] == 't' )
  423. if ( _PropType & DBTYPE_VECTOR )
  424. _pStgVariant->SetBOOL( VARIANT_TRUE, _cElements );
  425. else
  426. _pStgVariant->SetBOOL( VARIANT_TRUE );
  427. else
  428. if ( _PropType & DBTYPE_VECTOR )
  429. _pStgVariant->SetBOOL( VARIANT_FALSE, _cElements );
  430. else
  431. _pStgVariant->SetBOOL( VARIANT_FALSE );
  432. break;
  433. }
  434. case DBTYPE_R4 :
  435. {
  436. WCHAR *pwcEnd = 0;
  437. float Float = (float)( wcstod( pwszValue, &pwcEnd ) );
  438. if ( *pwcEnd != 0 && !iswspace( *pwcEnd ) )
  439. THROW( CParserException( QPARSE_E_EXPECTING_REAL ) );
  440. if ( _PropType & DBTYPE_VECTOR )
  441. _pStgVariant->SetR4( Float, _cElements );
  442. else
  443. _pStgVariant->SetR4( Float );
  444. break;
  445. }
  446. case DBTYPE_R8 :
  447. {
  448. WCHAR *pwcEnd = 0;
  449. double Double = ( double )( wcstod( pwszValue, &pwcEnd ) );
  450. if ( *pwcEnd != 0 && !iswspace( *pwcEnd ) )
  451. THROW( CParserException( QPARSE_E_EXPECTING_REAL ) );
  452. if ( _PropType & DBTYPE_VECTOR )
  453. _pStgVariant->SetR8( Double, _cElements );
  454. else
  455. _pStgVariant->SetR8( Double );
  456. break;
  457. }
  458. case DBTYPE_DECIMAL :
  459. {
  460. WCHAR *pwcEnd = 0;
  461. double Double = ( double )( wcstod( pwszValue, &pwcEnd ) );
  462. if( *pwcEnd != 0 && !iswspace( *pwcEnd ) )
  463. THROW( CParserException( QPARSE_E_EXPECTING_REAL ) );
  464. // Vectors are not supported by OLE for VT_DECIMAL (yet)
  465. Win4Assert( 0 == ( _PropType & DBTYPE_VECTOR ) );
  466. PROPVARIANT * pPropVar = (PROPVARIANT *) _pStgVariant.GetPointer();
  467. VarDecFromR8( Double, &(pPropVar->decVal) );
  468. pPropVar->vt = VT_DECIMAL;
  469. break;
  470. }
  471. case DBTYPE_DATE :
  472. {
  473. FILETIME ftValue;
  474. ParseDateTime( pwszValue, ftValue );
  475. SYSTEMTIME stValue;
  476. BOOL fOK = FileTimeToSystemTime( &ftValue, &stValue );
  477. if ( !fOK )
  478. THROW( CParserException( QPARSE_E_EXPECTING_DATE ) );
  479. DATE dosDate;
  480. fOK = SystemTimeToVariantTime( &stValue, &dosDate );
  481. if ( !fOK )
  482. THROW( CParserException( QPARSE_E_EXPECTING_DATE ) );
  483. if ( _PropType & DBTYPE_VECTOR )
  484. _pStgVariant->SetDATE( dosDate, _cElements );
  485. else
  486. _pStgVariant->SetDATE( dosDate );
  487. break;
  488. }
  489. case VT_FILETIME :
  490. {
  491. FILETIME ftValue;
  492. ParseDateTime( pwszValue, ftValue );
  493. if ( _PropType & DBTYPE_VECTOR )
  494. _pStgVariant->SetFILETIME( ftValue, _cElements );
  495. else
  496. _pStgVariant->SetFILETIME( ftValue );
  497. break;
  498. }
  499. case DBTYPE_CY :
  500. {
  501. double dbl;
  502. if ( swscanf( pwszValue,
  503. L"%lf",
  504. &dbl ) < 1 )
  505. THROW( CParserException( QPARSE_E_EXPECTING_CURRENCY ) );
  506. CY cyCurrency;
  507. VarCyFromR8( dbl, &cyCurrency );
  508. if ( _PropType & DBTYPE_VECTOR )
  509. _pStgVariant->SetCY( cyCurrency, _cElements );
  510. else
  511. _pStgVariant->SetCY( cyCurrency );
  512. break;
  513. }
  514. case DBTYPE_GUID :
  515. case DBTYPE_GUID | DBTYPE_BYREF:
  516. {
  517. CLSID clsid;
  518. if ( swscanf( pwszValue,
  519. L"%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
  520. &clsid.Data1,
  521. &clsid.Data2,
  522. &clsid.Data3,
  523. &clsid.Data4[0], &clsid.Data4[1],
  524. &clsid.Data4[2], &clsid.Data4[3],
  525. &clsid.Data4[4], &clsid.Data4[5],
  526. &clsid.Data4[6], &clsid.Data4[7] ) < 11 )
  527. THROW( CParserException( QPARSE_E_EXPECTING_GUID ) );
  528. if ( _PropType & DBTYPE_VECTOR )
  529. _pStgVariant->SetCLSID( clsid, _cElements );
  530. else
  531. _pStgVariant->SetCLSID( &clsid );
  532. break;
  533. }
  534. default:
  535. {
  536. THROW( CParserException( QPARSE_E_UNSUPPORTED_PROPERTY_TYPE ) );
  537. }
  538. } // switch
  539. // make sure memory allocations succeeded
  540. if ( !_pStgVariant->IsValid() )
  541. THROW( CException( E_OUTOFMEMORY ) );
  542. if ( _fVector )
  543. {
  544. _cElements++;
  545. }
  546. }
  547. //+---------------------------------------------------------------------------
  548. //
  549. // Member: CValueParser::ParseDateTime, private
  550. //
  551. // Synopsis: Attempts to parse a date expression.
  552. //
  553. // Arguments: phrase -- pointer to the phrase to parse
  554. // ft -- reference to the FILETIME structure to fill in
  555. // with the result
  556. //
  557. // History: 31-May-96 dlee Created
  558. // 23-Jan-97 KyleP Better Year 2000 support
  559. // 02-Sep-98 KLam Use user settings for Y2K support
  560. //
  561. //----------------------------------------------------------------------------
  562. void CValueParser::ParseDateTime(
  563. WCHAR const * phrase,
  564. FILETIME & ft )
  565. {
  566. if( !CheckForRelativeDate( phrase, ft ) )
  567. {
  568. SYSTEMTIME stValue = { 0, 0, 0, 0, 0, 0, 0, 0 };
  569. int cItems = swscanf( phrase,
  570. L"%4hd/%2hd/%2hd %2hd:%2hd:%2hd:%3hd",
  571. &stValue.wYear,
  572. &stValue.wMonth,
  573. &stValue.wDay,
  574. &stValue.wHour,
  575. &stValue.wMinute,
  576. &stValue.wSecond,
  577. &stValue.wMilliseconds );
  578. if ( 1 == cItems )
  579. cItems = swscanf( phrase,
  580. L"%4hd-%2hd-%2hd %2hd:%2hd:%2hd:%3hd",
  581. &stValue.wYear,
  582. &stValue.wMonth,
  583. &stValue.wDay,
  584. &stValue.wHour,
  585. &stValue.wMinute,
  586. &stValue.wSecond,
  587. &stValue.wMilliseconds );
  588. if( cItems != 3 && cItems != 6 && cItems != 7)
  589. THROW( CParserException( QPARSE_E_EXPECTING_DATE ) );
  590. //
  591. // Make a sensible split for Year 2000 using the user's system settings
  592. //
  593. if ( stValue.wYear < 100 )
  594. {
  595. DWORD dwYearHigh = 0;
  596. if ( 0 == GetCalendarInfo ( _locale,
  597. CAL_GREGORIAN,
  598. CAL_ITWODIGITYEARMAX | CAL_RETURN_NUMBER,
  599. 0,
  600. 0,
  601. &dwYearHigh ) )
  602. {
  603. THROW ( CException () );
  604. }
  605. if ( ( dwYearHigh < 99 ) || ( dwYearHigh > 9999 ) )
  606. dwYearHigh = 2029;
  607. WORD wMaxDecade = (WORD) dwYearHigh % 100;
  608. WORD wMaxCentury = (WORD) dwYearHigh - wMaxDecade;
  609. if ( stValue.wYear <= wMaxDecade )
  610. stValue.wYear += wMaxCentury;
  611. else
  612. stValue.wYear += ( wMaxCentury - 100 );
  613. }
  614. if( !SystemTimeToFileTime( &stValue, &ft ) )
  615. THROW( CParserException( QPARSE_E_EXPECTING_DATE ) );
  616. }
  617. } //ParseDateTime
  618. //+---------------------------------------------------------------------------
  619. //
  620. // Member: CValueParser::CheckForRelativeDate, private
  621. //
  622. // Synopsis: Attempts to parse a relative date expression. If successful,
  623. // it fills in the FILETIME structure with the calculated
  624. // absolute date.
  625. //
  626. // Notes: Returns TRUE if the phrase is recognized as a relative
  627. // date (i.e., it begins with a '-'). Otherwise, returns FALSE.
  628. // The format of a relative date is
  629. // "-"{INTEGER("h"|"n"|"s"|"y"|"q"|"m"|"d"|"w")}*
  630. // Case is not significant.
  631. //
  632. // Arguments: phrase -- pointer to the phrase to parse
  633. // ft -- reference to the FILETIME structure to fill in
  634. // with the result
  635. //
  636. // History: 26-May-94 t-jeffc Created
  637. // 02-Mar-95 t-colinb Moved from CQueryParser to
  638. // be more accessible
  639. // 22-Jan-97 KyleP Fix local/UTC discrepancy
  640. //
  641. //----------------------------------------------------------------------------
  642. BOOL CValueParser::CheckForRelativeDate(
  643. WCHAR const * phrase,
  644. FILETIME & ft )
  645. {
  646. if( *phrase++ == L'-' )
  647. {
  648. SYSTEMTIME st;
  649. LARGE_INTEGER liLocal;
  650. LONGLONG llTicksInADay = ((LONGLONG)10000000) * ((LONGLONG)3600)
  651. * ((LONGLONG) 24);
  652. LONGLONG llTicksInAHour = ((LONGLONG) 10000000) * ((LONGLONG)3600);
  653. int iMonthDays[12] = {1,-1,1,0,1,0,1,1,0,1,0,1};
  654. int iLoopValue, iPrevMonth, iPrevQuarter, iQuarterOffset;
  655. WORD wYear, wDayOfMonth, wStartDate;
  656. //
  657. //Obtain local time and convert it to file time
  658. //Copy the filetime to largeint data struct
  659. //
  660. GetSystemTime(&st);
  661. if(!SystemTimeToFileTime(&st, &ft))
  662. THROW( CParserException( QPARSE_E_INVALID_LITERAL ));
  663. liLocal.LowPart = ft.dwLowDateTime;
  664. liLocal.HighPart = ft.dwHighDateTime;
  665. LONGLONG llRelDate = (LONGLONG)0;
  666. for( ;; )
  667. {
  668. // eat white space
  669. while( iswspace( *phrase ) )
  670. phrase++;
  671. if( *phrase == 0 ) break;
  672. // parse the number
  673. WCHAR * pwcEnd;
  674. LONG lValue = wcstol( phrase, &pwcEnd, 10 );
  675. if( lValue < 0 )
  676. THROW( CParserException( QPARSE_E_EXPECTING_DATE ) );
  677. // eat white space
  678. phrase = pwcEnd;
  679. while( iswspace( *phrase ) )
  680. phrase++;
  681. // grab the unit char & subtract the appropriate amount
  682. WCHAR wcUnit = *phrase++;
  683. switch( wcUnit )
  684. {
  685. case L'y':
  686. case L'Y':
  687. lValue *= 4;
  688. // Fall through and handle year like 4 quarters
  689. case L'q':
  690. case L'Q':
  691. lValue *= 3;
  692. // Fall through and handle quarters like 3 months
  693. case L'm':
  694. case L'M':
  695. // Getting the System time to determine the day and month.
  696. if(!FileTimeToSystemTime(&ft, &st))
  697. {
  698. THROW(CParserException(QPARSE_E_INVALID_LITERAL));
  699. }
  700. wStartDate = st.wDay;
  701. wDayOfMonth = st.wDay;
  702. iLoopValue = lValue;
  703. while(iLoopValue)
  704. {
  705. // Subtracting to the end of previous month
  706. llRelDate = llTicksInADay * ((LONGLONG)(wDayOfMonth));
  707. liLocal.QuadPart -= llRelDate;
  708. ft.dwLowDateTime = liLocal.LowPart;
  709. ft.dwHighDateTime = liLocal.HighPart;
  710. SYSTEMTIME stTemp;
  711. if(!FileTimeToSystemTime(&ft, &stTemp))
  712. {
  713. THROW(CParserException(QPARSE_E_INVALID_LITERAL));
  714. }
  715. //
  716. // if the end of previous month is greated then start date then we subtract to back up to the
  717. // start date. This will take care of 28/29 Feb(backing from 30/31 by 1 month).
  718. //
  719. if(stTemp.wDay > wStartDate)
  720. {
  721. llRelDate = llTicksInADay * ((LONGLONG)(stTemp.wDay - wStartDate));
  722. liLocal.QuadPart -= llRelDate;
  723. ft.dwLowDateTime = liLocal.LowPart;
  724. ft.dwHighDateTime = liLocal.HighPart;
  725. // Getting the date into stTemp for further iteration
  726. if(!FileTimeToSystemTime(&ft, &stTemp))
  727. {
  728. THROW( CParserException( QPARSE_E_INVALID_LITERAL ));
  729. }
  730. }
  731. wDayOfMonth = stTemp.wDay;
  732. iLoopValue--;
  733. } //End While
  734. break;
  735. case L'w':
  736. case L'W':
  737. lValue *= 7;
  738. case L'd':
  739. case L'D':
  740. llRelDate = llTicksInADay * ((LONGLONG)lValue);
  741. liLocal.QuadPart -= llRelDate;
  742. ft.dwLowDateTime = liLocal.LowPart;
  743. ft.dwHighDateTime = liLocal.HighPart;
  744. break;
  745. case L'h':
  746. case L'H':
  747. llRelDate = llTicksInAHour * ((LONGLONG)lValue);
  748. liLocal.QuadPart -= llRelDate;
  749. ft.dwLowDateTime = liLocal.LowPart;
  750. ft.dwHighDateTime = liLocal.HighPart;
  751. break;
  752. case L'n':
  753. case L'N':
  754. llRelDate = ((LONGLONG)10000000) * ((LONGLONG)60) * ((LONGLONG)lValue) ;
  755. liLocal.QuadPart -= llRelDate;
  756. ft.dwLowDateTime = liLocal.LowPart;
  757. ft.dwHighDateTime = liLocal.HighPart;
  758. break;
  759. case L's':
  760. case L'S':
  761. llRelDate = ((LONGLONG)10000000) * ((LONGLONG)lValue);
  762. liLocal.QuadPart -= llRelDate;
  763. ft.dwLowDateTime = liLocal.LowPart;
  764. ft.dwHighDateTime = liLocal.HighPart;
  765. break;
  766. default:
  767. THROW( CParserException( QPARSE_E_EXPECTING_DATE ) );
  768. }
  769. } // for( ;; )
  770. return TRUE;
  771. }
  772. else
  773. {
  774. return FALSE;
  775. }
  776. }
  777. %}
  778. %start query
  779. %%
  780. /***
  781. *** Tripolish YACC grammar
  782. ***
  783. *** Note - left recursion (i.e. A: A,B) used throughout because yacc
  784. *** handles it more efficiently.
  785. ***
  786. ***/
  787. query: AndTerm
  788. {
  789. $$ = $1;
  790. }
  791. | query _OR AndTerm
  792. {
  793. AssertReq($1);
  794. AssertReq($3);
  795. XDbRestriction prstQuery($1);
  796. XDbRestriction prstTerm($3);
  797. _setRst.Remove( $1 );
  798. _setRst.Remove( $3 );
  799. BOOL fAcquireQuery = FALSE;
  800. XDbBooleanNodeRestriction prstNew;
  801. if (DBOP_or == $1->GetCommandType())
  802. {
  803. // add right term & release its smart pointer
  804. ((CDbBooleanNodeRestriction *)($1))->AppendChild( prstTerm.GetPointer() );
  805. prstTerm.Acquire();
  806. fAcquireQuery = TRUE;
  807. $$ = prstQuery.GetPointer();
  808. }
  809. else
  810. {
  811. // create smart Or node
  812. prstNew.Set( new CDbBooleanNodeRestriction( DBOP_or ) );
  813. if( 0 == prstNew.GetPointer() )
  814. THROW( CException( E_OUTOFMEMORY ) );
  815. prstNew->SetWeight(MAX_QUERY_RANK);
  816. // add left term & release its smart pointer
  817. prstNew->AppendChild( prstQuery.GetPointer() );
  818. prstQuery.Acquire();
  819. // add right term & release its smart pointer
  820. prstNew->AppendChild( prstTerm.GetPointer() );
  821. prstTerm.Acquire();
  822. $$ = prstNew.GetPointer();
  823. }
  824. _setRst.Add( $$ );
  825. if ( fAcquireQuery )
  826. prstQuery.Acquire();
  827. else
  828. prstNew.Acquire();
  829. }
  830. | _NOT query
  831. {
  832. AssertReq($2);
  833. XDbRestriction prstQuery($2);
  834. _setRst.Remove( $2 );
  835. // Create not node
  836. XDbBooleanNodeRestriction prstNew( new CDbBooleanNodeRestriction( DBOP_not ) );
  837. if( 0 == prstNew.GetPointer() )
  838. THROW( CException( E_OUTOFMEMORY ) );
  839. prstNew->SetWeight(MAX_QUERY_RANK);
  840. // add right term and release its smart pointer
  841. prstNew->AppendChild( prstQuery.GetPointer() );
  842. prstQuery.Acquire();
  843. $$ = prstNew.GetPointer();
  844. _setRst.Add( $$ );
  845. prstNew.Acquire();
  846. }
  847. ;
  848. AndTerm: NearTerm
  849. { $$ = $1;}
  850. | _NOT PropTerm
  851. {
  852. AssertReq($2);
  853. XDbRestriction prstTerm($2);
  854. _setRst.Remove( $2 );
  855. // Create not node
  856. XDbBooleanNodeRestriction prstNew( new CDbBooleanNodeRestriction( DBOP_not ) );
  857. if( 0 == prstNew.GetPointer() )
  858. THROW( CException( E_OUTOFMEMORY ) );
  859. prstNew->SetWeight(MAX_QUERY_RANK);
  860. // add right term and release its smart pointer
  861. prstNew->AppendChild( prstTerm.GetPointer() );
  862. prstTerm.Acquire();
  863. $$ = prstNew.GetPointer();
  864. _setRst.Add( $$ );
  865. prstNew.Acquire();
  866. }
  867. | AndTerm _AND NearTerm
  868. {
  869. AssertReq($1);
  870. AssertReq($3);
  871. XDbRestriction prstQuery($1);
  872. XDbRestriction prstTerm($3);
  873. _setRst.Remove( $1 );
  874. _setRst.Remove( $3 );
  875. BOOL fAcquireQuery = FALSE;
  876. XDbBooleanNodeRestriction prstNew;
  877. if (DBOP_and == $1->GetCommandType())
  878. {
  879. // add right term & release its smart pointer
  880. ((CDbBooleanNodeRestriction *)($1))->AppendChild( prstTerm.GetPointer() );
  881. prstTerm.Acquire();
  882. fAcquireQuery = TRUE;
  883. $$ = prstQuery.GetPointer();
  884. }
  885. else
  886. {
  887. // create smart And node
  888. prstNew.Set( new CDbBooleanNodeRestriction( DBOP_and ) );
  889. if( prstNew.GetPointer() == 0 )
  890. THROW( CException( E_OUTOFMEMORY ) );
  891. prstNew->SetWeight(MAX_QUERY_RANK);
  892. // add left term & release its smart pointer
  893. prstNew->AppendChild( prstQuery.GetPointer() );
  894. prstQuery.Acquire();
  895. // add right term & release its smart pointer
  896. prstNew->AppendChild( prstTerm.GetPointer() );
  897. prstTerm.Acquire();
  898. $$ = prstNew.GetPointer();
  899. }
  900. _setRst.Add( $$ );
  901. if ( fAcquireQuery )
  902. prstQuery.Acquire();
  903. else
  904. prstNew.Acquire();
  905. }
  906. | AndTerm _AND _NOT NearTerm
  907. {
  908. AssertReq($1);
  909. AssertReq($4);
  910. XDbRestriction prstQuery($1);
  911. XDbRestriction prstTerm($4);
  912. _setRst.Remove( $1 );
  913. _setRst.Remove( $4 );
  914. // create smart Not node
  915. XDbNotRestriction prstNot( new CDbNotRestriction );
  916. if( prstNot.GetPointer() == 0 )
  917. THROW( CException( E_OUTOFMEMORY ) );
  918. prstNot->SetWeight(MAX_QUERY_RANK);
  919. // set child of Not node & release smart factor pointer
  920. prstNot->SetChild( prstTerm.GetPointer() );
  921. prstTerm.Acquire();
  922. BOOL fAcquireQuery = FALSE;
  923. XDbBooleanNodeRestriction prstNew;
  924. if (DBOP_and == $1->GetCommandType())
  925. {
  926. // add right term & release its smart pointer
  927. ((CDbBooleanNodeRestriction *)($1))->AppendChild( prstNot.GetPointer() );
  928. prstNot.Acquire();
  929. $$ = prstQuery.GetPointer();
  930. fAcquireQuery = TRUE;
  931. }
  932. else
  933. {
  934. // create smart And node
  935. prstNew.Set( new CDbBooleanNodeRestriction( DBOP_and ) );
  936. if( prstNew.GetPointer() == 0 )
  937. THROW( CException( E_OUTOFMEMORY ) );
  938. prstNew->SetWeight(MAX_QUERY_RANK);
  939. // add left term & release its smart pointer
  940. prstNew->AppendChild( prstQuery.GetPointer() );
  941. prstQuery.Acquire();
  942. // add right term & release its smart pointer
  943. prstNew->AppendChild( prstNot.GetPointer() );
  944. prstNot.Acquire();
  945. $$ = prstNew.GetPointer();
  946. }
  947. _setRst.Add( $$ );
  948. if ( fAcquireQuery )
  949. prstQuery.Acquire();
  950. else
  951. prstNew.Acquire();
  952. }
  953. ;
  954. NearTerm: CoerceTerm
  955. { $$ = $1; }
  956. | NearTerm _NEAR CoerceTerm
  957. {
  958. // uses defaults
  959. AssertReq($1);
  960. AssertReq($3);
  961. XDbRestriction prstLeft($1);
  962. XDbRestriction prstRight($3);
  963. _setRst.Remove( $1 );
  964. _setRst.Remove( $3 );
  965. BOOL fAcquireLeft = FALSE;
  966. XDbProximityNodeRestriction prstNew;
  967. if (DBOP_content_proximity == $1->GetCommandType() &&
  968. 50 == ((CDbProximityNodeRestriction *)$1)->GetProximityDistance() &&
  969. PROXIMITY_UNIT_WORD == ((CDbProximityNodeRestriction *)$1)->GetProximityUnit())
  970. {
  971. // add right term & release its smart pointer
  972. ((CDbProximityNodeRestriction *)$1)->AppendChild( prstRight.GetPointer() );
  973. prstRight.Acquire();
  974. $$ = prstLeft.GetPointer();
  975. fAcquireLeft = TRUE;
  976. }
  977. else
  978. {
  979. // create smart Prox node
  980. prstNew.Set(new CDbProximityNodeRestriction()); // uses defaults
  981. if ( prstNew.IsNull() || !prstNew->IsValid() )
  982. THROW( CException( E_OUTOFMEMORY ) );
  983. // add left phrase & release its smart pointer
  984. prstNew->AppendChild( prstLeft.GetPointer() );
  985. prstLeft.Acquire();
  986. // add right term & release its smart pointer
  987. prstNew->AppendChild( prstRight.GetPointer() );
  988. prstRight.Acquire();
  989. $$ = prstNew.GetPointer();
  990. }
  991. _setRst.Add( $$ );
  992. if ( fAcquireLeft )
  993. prstLeft.Acquire();
  994. else
  995. prstNew.Acquire();
  996. }
  997. | NearTerm _NEARDIST _NEARUNIT _NEAR_END CoerceTerm
  998. {
  999. AssertReq($1);
  1000. AssertReq($2);
  1001. AssertReq($3);
  1002. AssertReq($5);
  1003. XDbRestriction prstLeft($1);
  1004. XDbRestriction prstRight($5);
  1005. _setRst.Remove( $1 );
  1006. _setRst.Remove( $5 );
  1007. WCHAR * pwcEnd;
  1008. ULONG ulValue = wcstol( $2, &pwcEnd, 10 );
  1009. ULONG ulUnit;
  1010. if (L'w' == *$3)
  1011. ulUnit = PROXIMITY_UNIT_WORD;
  1012. else if (L's' == *$3)
  1013. ulUnit = PROXIMITY_UNIT_SENTENCE;
  1014. else if (L'p' == *$3)
  1015. ulUnit = PROXIMITY_UNIT_PARAGRAPH;
  1016. else if (L'c' == *$3)
  1017. ulUnit = PROXIMITY_UNIT_CHAPTER;
  1018. BOOL fAcquireLeft = FALSE;
  1019. XDbProximityNodeRestriction prstNew;
  1020. if (DBOP_content_proximity == $1->GetCommandType() &&
  1021. ulValue == ((CDbProximityNodeRestriction *)$1)->GetProximityDistance() &&
  1022. ulUnit == ((CDbProximityNodeRestriction *)$1)->GetProximityUnit())
  1023. {
  1024. // add right term & release its smart pointer
  1025. ((CDbProximityNodeRestriction *)$1)->AppendChild( prstRight.GetPointer() );
  1026. prstRight.Acquire();
  1027. $$ = prstLeft.GetPointer();
  1028. fAcquireLeft = TRUE;
  1029. }
  1030. else
  1031. {
  1032. // create smart Prox node
  1033. prstNew.Set(new CDbProximityNodeRestriction(ulUnit, ulValue));
  1034. if( prstNew.IsNull() || !prstNew->IsValid() )
  1035. THROW( CException( E_OUTOFMEMORY ) );
  1036. // add left phrase & release its smart pointer
  1037. prstNew->AppendChild( prstLeft.GetPointer() );
  1038. prstLeft.Acquire();
  1039. // add right term & release its smart pointer
  1040. prstNew->AppendChild( prstRight.GetPointer() );
  1041. prstRight.Acquire();
  1042. $$ = prstNew.GetPointer();
  1043. }
  1044. _setRst.Add( $$ );
  1045. if ( fAcquireLeft )
  1046. prstLeft.Acquire();
  1047. else
  1048. prstNew.Acquire();
  1049. }
  1050. ;
  1051. CoerceTerm:
  1052. Gen NestTerm GenEnd
  1053. {
  1054. $$ = $2;
  1055. }
  1056. | Gen _COERCE Gen NestTerm GenEnd
  1057. {
  1058. AssertReq($4);
  1059. XDbRestriction prstQuery($4);
  1060. $4->SetWeight(MAX_QUERY_RANK);
  1061. $$ = prstQuery.Acquire();
  1062. }
  1063. | Gen _WEIGHT Gen NestTerm GenEnd
  1064. {
  1065. AssertReq($2);
  1066. AssertReq($4);
  1067. XDbRestriction prstQuery($4);
  1068. WCHAR * pwcEnd;
  1069. double dWeight = wcstod( $2, &pwcEnd );
  1070. if ( dWeight > 1.0 )
  1071. THROW( CParserException( QPARSE_E_WEIGHT_OUT_OF_RANGE ) );
  1072. LONG lWeight = (LONG)(dWeight * MAX_QUERY_RANK);
  1073. $4->SetWeight(lWeight);
  1074. $$ = prstQuery.Acquire();
  1075. }
  1076. ;
  1077. Gen: /* empty */
  1078. {
  1079. $$ = 0;
  1080. }
  1081. | _GENPREFIX
  1082. {
  1083. SetCurrentGenerate(GENERATE_METHOD_PREFIX);
  1084. $$ = GENERATE_METHOD_PREFIX;
  1085. }
  1086. | _GENINFLECT
  1087. {
  1088. SetCurrentGenerate(GENERATE_METHOD_INFLECT);
  1089. $$ = GENERATE_METHOD_INFLECT;
  1090. }
  1091. ;
  1092. GenEnd: /* empty */
  1093. {
  1094. $$ = GENERATE_METHOD_EXACT;
  1095. }
  1096. | _GENNORMAL
  1097. {
  1098. // don't set the generate method to 0 here. Doing so will
  1099. // reset the method before it gets used.
  1100. $$ = GENERATE_METHOD_EXACT;
  1101. }
  1102. NestTerm: VectorTerm
  1103. {
  1104. $$ = $1;
  1105. }
  1106. | Term
  1107. {
  1108. $$ = $1;
  1109. }
  1110. | Open query Close
  1111. {
  1112. $$ = $2;
  1113. }
  1114. ;
  1115. VectorTerm: VectorSpec _VECTOR_END
  1116. {
  1117. $$ = $1;
  1118. }
  1119. VectorSpec: _VEMETHOD _VE query
  1120. {
  1121. AssertReq($1);
  1122. AssertReq($3);
  1123. XDbRestriction prstQuery($3);
  1124. _setRst.Remove( $3 );
  1125. ULONG rankMethod = VECTOR_RANK_JACCARD; // default if nothing else matches
  1126. if ( 0 == _wcsicmp( L"jaccard", $1) )
  1127. {
  1128. rankMethod = VECTOR_RANK_JACCARD;
  1129. }
  1130. else if ( 0 == _wcsicmp( L"dice", $1) )
  1131. {
  1132. rankMethod = VECTOR_RANK_DICE;
  1133. }
  1134. else if ( 0 == _wcsicmp( L"inner", $1) )
  1135. {
  1136. rankMethod = VECTOR_RANK_INNER;
  1137. }
  1138. else if ( 0 == _wcsicmp( L"max", $1) )
  1139. {
  1140. rankMethod = VECTOR_RANK_MAX;
  1141. }
  1142. else if ( 0 == _wcsicmp( L"min", $1) )
  1143. {
  1144. rankMethod = VECTOR_RANK_MIN;
  1145. }
  1146. else
  1147. {
  1148. THROW( CException( QPARSE_E_INVALID_RANKMETHOD ) );
  1149. }
  1150. // create smart Vector node
  1151. XDbVectorRestriction prstNew( new CDbVectorRestriction( rankMethod ) );
  1152. if ( prstNew.IsNull() || !prstNew->IsValid() )
  1153. {
  1154. THROW( CException( E_OUTOFMEMORY ) );
  1155. }
  1156. // add expression & release its smart pointer
  1157. prstNew->AppendChild( prstQuery.GetPointer() );
  1158. prstQuery.Acquire();
  1159. // Let the next vector element start off with a clean slate...
  1160. // We don't want the current element's property and genmethod
  1161. // to rub off on it.
  1162. InitState();
  1163. $$ = prstNew.GetPointer();
  1164. _setRst.Add( $$ );
  1165. prstNew.Acquire();
  1166. }
  1167. | VectorSpec _VE query
  1168. {
  1169. AssertReq($1);
  1170. AssertReq($3);
  1171. XDbRestriction prstLeft($1);
  1172. XDbRestriction prstRight($3);
  1173. _setRst.Remove( $1 );
  1174. _setRst.Remove( $3 );
  1175. // add right term & release its smart pointer
  1176. ((CDbVectorRestriction *)($1))->AppendChild( prstRight.GetPointer() );
  1177. prstRight.Acquire();
  1178. // Let the next vector element start off with a clean slate...
  1179. // We don't want the current element's property and genmethod
  1180. // to rub off on it.
  1181. InitState();
  1182. $$ = prstLeft.GetPointer();
  1183. _setRst.Add( $$ );
  1184. prstLeft.Acquire();
  1185. }
  1186. ;
  1187. Open: _OPEN
  1188. {
  1189. SaveState();
  1190. $$ = 0;
  1191. }
  1192. Close: _CLOSE
  1193. {
  1194. RestoreState();
  1195. $$ = 0;
  1196. }
  1197. Term: PropTerm
  1198. {
  1199. $$ = $1;
  1200. }
  1201. | Property Contains _PHRASE ShortGen PropEnd
  1202. {
  1203. $$ = BuildPhrase($3, $4);
  1204. _setRst.Add( $$ );
  1205. }
  1206. | Property Contains _PHRASE PropEnd
  1207. {
  1208. $$ = BuildPhrase($3, 0);
  1209. _setRst.Add( $$ );
  1210. }
  1211. | Property Contains Gen _PHRASE GenEnd PropEnd
  1212. {
  1213. $$ = BuildPhrase($4, $3);
  1214. _setRst.Add( $$ );
  1215. }
  1216. | Property Contains query
  1217. {
  1218. $$ = $3;
  1219. }
  1220. | Property Contains _FREETEXT ShortGen PropEnd
  1221. {
  1222. AssertReq($3);
  1223. CDbColId *pps;
  1224. DBTYPE dbType;
  1225. GetCurrentProperty(&pps, &dbType);
  1226. // We used the property. Now pop it off if need be
  1227. if (fDeferredPop)
  1228. PopProperty();
  1229. // Clear generation method so it won't rub off on the following phrase
  1230. SetCurrentGenerate(GENERATE_METHOD_EXACT);
  1231. // generation method not used - if it's there, ignore it
  1232. // (already stripped from longhand version, but not from
  1233. // shorthand version
  1234. LPWSTR pLast = $3 + wcslen($3) -1;
  1235. if ( L'*' == *pLast) // prefix
  1236. *pLast-- = L'\0';
  1237. if ( L'*' == *pLast) // inflect
  1238. *pLast-- = L'\0';
  1239. XDbNatLangRestriction pRest ( new CDbNatLangRestriction ($3, *pps, _lcid));
  1240. if ( pRest.IsNull() || !pRest->IsValid() )
  1241. THROW( CException( E_OUTOFMEMORY ) );
  1242. $$ = pRest.GetPointer();
  1243. _setRst.Add( $$ );
  1244. pRest.Acquire();
  1245. }
  1246. ;
  1247. PropTerm: Property Matches _REGEX PropEnd
  1248. {
  1249. AssertReq($3);
  1250. CDbColId *pps;
  1251. DBTYPE dbType;
  1252. GetCurrentProperty(&pps, &dbType);
  1253. // We used the property. Now pop it off if need be
  1254. if (fDeferredPop)
  1255. PopProperty();
  1256. if ( ( ( DBTYPE_WSTR|DBTYPE_BYREF ) != dbType ) &&
  1257. ( ( DBTYPE_STR|DBTYPE_BYREF ) != dbType ) &&
  1258. ( VT_BSTR != dbType ) &&
  1259. ( VT_LPWSTR != dbType ) &&
  1260. ( VT_LPSTR != dbType ) )
  1261. THROW( CParserException( QPARSE_E_EXPECTING_REGEX_PROPERTY ) );
  1262. if( $3 == 0 )
  1263. THROW( CParserException( QPARSE_E_EXPECTING_REGEX ) );
  1264. // create smart Property node
  1265. XDbPropertyRestriction prstProp( new CDbPropertyRestriction );
  1266. if( prstProp.GetPointer() == 0 )
  1267. THROW( CException( E_OUTOFMEMORY ) );
  1268. prstProp->SetRelation(DBOP_like); // LIKE relation
  1269. if ( ( ! prstProp->SetProperty( *pps ) ) ||
  1270. ( ! prstProp->SetValue( $3 ) ) ||
  1271. ( ! prstProp->IsValid() ) )
  1272. THROW( CException( E_OUTOFMEMORY ) );
  1273. // release & return smart Property node
  1274. $$ = prstProp.GetPointer();
  1275. _setRst.Add( $$ );
  1276. prstProp.Acquire();
  1277. }
  1278. | Property Op Value PropEnd
  1279. {
  1280. AssertReq($2);
  1281. AssertReq($3);
  1282. XPtr<CStorageVariant> pStorageVar( $3 );
  1283. _setStgVar.Remove( $3 );
  1284. CDbColId *pps;
  1285. DBTYPE dbType;
  1286. GetCurrentProperty(&pps, &dbType);
  1287. // We used the property. Now pop it off if need be
  1288. if (fDeferredPop)
  1289. PopProperty();
  1290. // create smart Property node
  1291. XDbPropertyRestriction prstProp( new CDbPropertyRestriction );
  1292. if( prstProp.GetPointer() == 0 )
  1293. THROW( CException( E_OUTOFMEMORY ) );
  1294. if (! prstProp->SetProperty( *pps ) )
  1295. THROW( CException( E_OUTOFMEMORY ) );
  1296. // don't allow @contents <relop> X -- it's too expensive and we'll
  1297. // never find any hits anyway (until we implement this feature)
  1298. if ( *pps == psContents )
  1299. THROW( CParserException( QPARSE_E_EXPECTING_PHRASE ) );
  1300. prstProp->SetRelation( $2 );
  1301. if ( 0 != pStorageVar.GetPointer() )
  1302. {
  1303. // This should always be the case - else PropValueParser would have thrown
  1304. if ( ! ( ( prstProp->SetValue( pStorageVar.GetReference() ) ) &&
  1305. ( prstProp->IsValid() ) ) )
  1306. THROW( CException( E_OUTOFMEMORY ) );
  1307. }
  1308. $$ = prstProp.GetPointer();
  1309. _setRst.Add( $$ );
  1310. prstProp.Acquire();
  1311. }
  1312. ;
  1313. Property: /* empty */
  1314. {
  1315. $$ = 0;
  1316. }
  1317. | _PROPNAME
  1318. {
  1319. PushProperty($1);
  1320. $$ = 0;
  1321. }
  1322. ;
  1323. PropEnd: /* empty */
  1324. {
  1325. fDeferredPop = FALSE;
  1326. $$ = 0;
  1327. }
  1328. | _PROPEND
  1329. {
  1330. // When PropEnd is matched, the action of using the property
  1331. // hasn't yet taken place. So popping the property right now
  1332. // will cause the property to be unavailable when the action
  1333. // is performed. Instead, pop it off after it has been used.
  1334. fDeferredPop = TRUE;
  1335. $$ = 0;
  1336. }
  1337. ;
  1338. Op: _EQ
  1339. { $$ = DBOP_equal;}
  1340. | _NE
  1341. { $$ = DBOP_not_equal;}
  1342. | _GT
  1343. { $$ = DBOP_greater;}
  1344. | _GTE
  1345. { $$ = DBOP_greater_equal;}
  1346. | _LT
  1347. { $$ = DBOP_less;}
  1348. | _LTE
  1349. { $$ = DBOP_less_equal;}
  1350. | _ALLOF
  1351. { $$ = DBOP_allbits;}
  1352. | _SOMEOF
  1353. { $$ = DBOP_anybits;}
  1354. | _EQSOME
  1355. { $$ = DBOP_equal_any;}
  1356. | _NESOME
  1357. { $$ = DBOP_not_equal_any;}
  1358. | _GTSOME
  1359. { $$ = DBOP_greater_any;}
  1360. | _GTESOME
  1361. { $$ = DBOP_greater_equal_any;}
  1362. | _LTSOME
  1363. { $$ = DBOP_less_any;}
  1364. | _LTESOME
  1365. { $$ = DBOP_less_equal_any;}
  1366. | _ALLOFSOME
  1367. { $$ = DBOP_allbits_any;}
  1368. | _SOMEOFSOME
  1369. { $$ = DBOP_anybits_any;}
  1370. | _EQALL
  1371. { $$ = DBOP_equal_all;}
  1372. | _NEALL
  1373. { $$ = DBOP_not_equal_all;}
  1374. | _GTALL
  1375. { $$ = DBOP_greater_all;}
  1376. | _GTEALL
  1377. { $$ = DBOP_greater_equal_all;}
  1378. | _LTALL
  1379. { $$ = DBOP_less_all;}
  1380. | _LTEALL
  1381. { $$ = DBOP_less_equal_all;}
  1382. | _ALLOFALL
  1383. { $$ = DBOP_allbits_all;}
  1384. | _SOMEOFALL
  1385. { $$ = DBOP_anybits_all;}
  1386. ;
  1387. Matches: /* empty */
  1388. { $$ = 0; }
  1389. | _EQ
  1390. { $$ = DBOP_equal; }
  1391. Value: _PHRASE
  1392. {
  1393. CDbColId *pps;
  1394. DBTYPE dbType;
  1395. GetCurrentProperty(&pps, &dbType);
  1396. CValueParser PropValueParser( FALSE, dbType, _lcid );
  1397. StripQuotes($1);
  1398. PropValueParser.AddValue( $1 );
  1399. $$ = PropValueParser.GetStgVariant();
  1400. _setStgVar.Add( $$ );
  1401. PropValueParser.AcquireStgVariant();
  1402. }
  1403. | _FREETEXT
  1404. {
  1405. CDbColId *pps;
  1406. DBTYPE dbType;
  1407. GetCurrentProperty(&pps, &dbType);
  1408. CValueParser PropValueParser( FALSE, dbType, _lcid );
  1409. PropValueParser.AddValue( $1 );
  1410. $$ = PropValueParser.GetStgVariant();
  1411. _setStgVar.Add( $$ );
  1412. PropValueParser.AcquireStgVariant();
  1413. }
  1414. | VectorValue
  1415. {
  1416. $$ = $1;
  1417. }
  1418. ;
  1419. VectorValue: EmptyVector
  1420. {
  1421. XPtr <CValueParser> pPropValueParser ( $1 );
  1422. _setValueParser.Remove( $1 );
  1423. $$ = $1->GetStgVariant();
  1424. _setStgVar.Add( $$ );
  1425. $1->AcquireStgVariant();
  1426. }
  1427. | SingletVector
  1428. {
  1429. XPtr <CValueParser> pPropValueParser ( $1 );
  1430. _setValueParser.Remove( $1 );
  1431. $$ = $1->GetStgVariant();
  1432. _setStgVar.Add( $$ );
  1433. $1->AcquireStgVariant();
  1434. }
  1435. | MultiVector _VE_END
  1436. {
  1437. XPtr <CValueParser> pPropValueParser ( $1 );
  1438. _setValueParser.Remove( $1 );
  1439. $$ = $1->GetStgVariant();
  1440. _setStgVar.Add( $$ );
  1441. $1->AcquireStgVariant();
  1442. }
  1443. EmptyVector: _OPEN _CLOSE
  1444. {
  1445. CDbColId *pps;
  1446. DBTYPE dbType;
  1447. GetCurrentProperty(&pps, &dbType);
  1448. XPtr <CValueParser> pPropValueParser ( new CValueParser( TRUE, dbType, _lcid ) );
  1449. if( pPropValueParser.GetPointer() == 0 )
  1450. THROW( CException( E_OUTOFMEMORY ) );
  1451. $$ = pPropValueParser.GetPointer();
  1452. _setValueParser.Add( $$ );
  1453. pPropValueParser.Acquire();
  1454. }
  1455. SingletVector: _OPEN _PHRASE _CLOSE
  1456. {
  1457. AssertReq($2);
  1458. CDbColId *pps;
  1459. DBTYPE dbType;
  1460. GetCurrentProperty(&pps, &dbType);
  1461. XPtr <CValueParser> pPropValueParser ( new CValueParser( TRUE, dbType, _lcid ) );
  1462. if( pPropValueParser.GetPointer() == 0 )
  1463. THROW( CException( E_OUTOFMEMORY ) );
  1464. StripQuotes($2);
  1465. pPropValueParser->AddValue( $2 );
  1466. $$ = pPropValueParser.GetPointer();
  1467. _setValueParser.Add( $$ );
  1468. pPropValueParser.Acquire();
  1469. }
  1470. | _OPEN _FREETEXT _CLOSE
  1471. {
  1472. AssertReq($2);
  1473. CDbColId *pps;
  1474. DBTYPE dbType;
  1475. GetCurrentProperty(&pps, &dbType);
  1476. XPtr <CValueParser> pPropValueParser ( new CValueParser( TRUE, dbType, _lcid ) );
  1477. if( pPropValueParser.GetPointer() == 0 )
  1478. THROW( CException( E_OUTOFMEMORY ) );
  1479. pPropValueParser->AddValue( $2 );
  1480. $$ = pPropValueParser.GetPointer();
  1481. _setValueParser.Add( $$ );
  1482. pPropValueParser.Acquire();
  1483. }
  1484. MultiVector: _VECTORELEMENT _VECTORELEMENT
  1485. {
  1486. AssertReq($1);
  1487. AssertReq($2);
  1488. CDbColId *pps;
  1489. DBTYPE dbType;
  1490. GetCurrentProperty(&pps, &dbType);
  1491. XPtr <CValueParser> pPropValueParser ( new CValueParser( TRUE, dbType, _lcid ) );
  1492. if( pPropValueParser.GetPointer() == 0 )
  1493. THROW( CException( E_OUTOFMEMORY ) );
  1494. pPropValueParser->AddValue( $1 );
  1495. pPropValueParser->AddValue( $2 );
  1496. $$ = pPropValueParser.GetPointer();
  1497. _setValueParser.Add( $$ );
  1498. pPropValueParser.Acquire();
  1499. }
  1500. | MultiVector _VECTORELEMENT
  1501. {
  1502. AssertReq($1);
  1503. AssertReq($2);
  1504. $1->AddValue($2);
  1505. $$ = $1;
  1506. }
  1507. ;
  1508. Contains: /* empty */
  1509. {
  1510. $$ = 0;
  1511. }
  1512. | _CONTAINS
  1513. {
  1514. $$ = 0;
  1515. }
  1516. ;
  1517. ShortGen: /* empty */
  1518. {
  1519. $$ = 0;
  1520. }
  1521. | _SHGENPREFIX
  1522. {
  1523. $$ = 1;
  1524. }
  1525. | _SHGENINFLECT
  1526. {
  1527. $$ = 2;
  1528. }
  1529. ;