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.

1765 lines
57 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. if (DBOP_or == $1->GetCommandType())
  800. {
  801. // add right term & release its smart pointer
  802. ((CDbBooleanNodeRestriction *)($1))->AppendChild( prstTerm.GetPointer() );
  803. prstTerm.Acquire();
  804. $$ = prstQuery.Acquire();
  805. }
  806. else
  807. {
  808. // create smart Or node
  809. XDbBooleanNodeRestriction prstNew( new CDbBooleanNodeRestriction( DBOP_or ) );
  810. if( 0 == prstNew.GetPointer() )
  811. THROW( CException( E_OUTOFMEMORY ) );
  812. prstNew->SetWeight(MAX_QUERY_RANK);
  813. // add left term & release its smart pointer
  814. prstNew->AppendChild( prstQuery.GetPointer() );
  815. prstQuery.Acquire();
  816. // add right term & release its smart pointer
  817. prstNew->AppendChild( prstTerm.GetPointer() );
  818. prstTerm.Acquire();
  819. $$ = prstNew.Acquire();
  820. }
  821. _setRst.Add( $$ );
  822. }
  823. | _NOT query
  824. {
  825. AssertReq($2);
  826. XDbRestriction prstQuery($2);
  827. _setRst.Remove( $2 );
  828. // Create not node
  829. XDbBooleanNodeRestriction prstNew( new CDbBooleanNodeRestriction( DBOP_not ) );
  830. if( 0 == prstNew.GetPointer() )
  831. THROW( CException( E_OUTOFMEMORY ) );
  832. prstNew->SetWeight(MAX_QUERY_RANK);
  833. // add right term and release its smart pointer
  834. prstNew->AppendChild( prstQuery.GetPointer() );
  835. prstQuery.Acquire();
  836. $$ = prstNew.Acquire();
  837. _setRst.Add( $$ );
  838. }
  839. ;
  840. AndTerm: NearTerm
  841. { $$ = $1;}
  842. | _NOT PropTerm
  843. {
  844. AssertReq($2);
  845. XDbRestriction prstTerm($2);
  846. _setRst.Remove( $2 );
  847. // Create not node
  848. XDbBooleanNodeRestriction prstNew( new CDbBooleanNodeRestriction( DBOP_not ) );
  849. if( 0 == prstNew.GetPointer() )
  850. THROW( CException( E_OUTOFMEMORY ) );
  851. prstNew->SetWeight(MAX_QUERY_RANK);
  852. // add right term and release its smart pointer
  853. prstNew->AppendChild( prstTerm.GetPointer() );
  854. prstTerm.Acquire();
  855. $$ = prstNew.Acquire();
  856. _setRst.Add( $$ );
  857. }
  858. | AndTerm _AND NearTerm
  859. {
  860. AssertReq($1);
  861. AssertReq($3);
  862. XDbRestriction prstQuery($1);
  863. XDbRestriction prstTerm($3);
  864. _setRst.Remove( $1 );
  865. _setRst.Remove( $3 );
  866. if (DBOP_and == $1->GetCommandType())
  867. {
  868. // add right term & release its smart pointer
  869. ((CDbBooleanNodeRestriction *)($1))->AppendChild( prstTerm.GetPointer() );
  870. prstTerm.Acquire();
  871. $$ = prstQuery.Acquire();
  872. }
  873. else
  874. {
  875. // create smart And node
  876. XDbBooleanNodeRestriction prstNew( new CDbBooleanNodeRestriction( DBOP_and ) );
  877. if( prstNew.GetPointer() == 0 )
  878. THROW( CException( E_OUTOFMEMORY ) );
  879. prstNew->SetWeight(MAX_QUERY_RANK);
  880. // add left term & release its smart pointer
  881. prstNew->AppendChild( prstQuery.GetPointer() );
  882. prstQuery.Acquire();
  883. // add right term & release its smart pointer
  884. prstNew->AppendChild( prstTerm.GetPointer() );
  885. prstTerm.Acquire();
  886. $$ = prstNew.Acquire();
  887. }
  888. _setRst.Add( $$ );
  889. }
  890. | AndTerm _AND _NOT NearTerm
  891. {
  892. AssertReq($1);
  893. AssertReq($4);
  894. XDbRestriction prstQuery($1);
  895. XDbRestriction prstTerm($4);
  896. _setRst.Remove( $1 );
  897. _setRst.Remove( $4 );
  898. // create smart Not node
  899. XDbNotRestriction prstNot( new CDbNotRestriction );
  900. if( prstNot.GetPointer() == 0 )
  901. THROW( CException( E_OUTOFMEMORY ) );
  902. prstNot->SetWeight(MAX_QUERY_RANK);
  903. // set child of Not node & release smart factor pointer
  904. prstNot->SetChild( prstTerm.GetPointer() );
  905. prstTerm.Acquire();
  906. if (DBOP_and == $1->GetCommandType())
  907. {
  908. // add right term & release its smart pointer
  909. ((CDbBooleanNodeRestriction *)($1))->AppendChild( prstNot.GetPointer() );
  910. prstNot.Acquire();
  911. $$ = prstQuery.Acquire();
  912. }
  913. else
  914. {
  915. // create smart And node
  916. XDbBooleanNodeRestriction prstNew( new CDbBooleanNodeRestriction( DBOP_and ) );
  917. if( prstNew.GetPointer() == 0 )
  918. THROW( CException( E_OUTOFMEMORY ) );
  919. prstNew->SetWeight(MAX_QUERY_RANK);
  920. // add left term & release its smart pointer
  921. prstNew->AppendChild( prstQuery.GetPointer() );
  922. prstQuery.Acquire();
  923. // add right term & release its smart pointer
  924. prstNew->AppendChild( prstNot.GetPointer() );
  925. prstNot.Acquire();
  926. $$ = prstNew.Acquire();
  927. }
  928. _setRst.Add( $$ );
  929. }
  930. ;
  931. NearTerm: CoerceTerm
  932. { $$ = $1; }
  933. | NearTerm _NEAR CoerceTerm
  934. {
  935. // uses defaults
  936. AssertReq($1);
  937. AssertReq($3);
  938. XDbRestriction prstLeft($1);
  939. XDbRestriction prstRight($3);
  940. _setRst.Remove( $1 );
  941. _setRst.Remove( $3 );
  942. if (DBOP_content_proximity == $1->GetCommandType() &&
  943. 50 == ((CDbProximityNodeRestriction *)$1)->GetProximityDistance() &&
  944. PROXIMITY_UNIT_WORD == ((CDbProximityNodeRestriction *)$1)->GetProximityUnit())
  945. {
  946. // add right term & release its smart pointer
  947. ((CDbProximityNodeRestriction *)$1)->AppendChild( prstRight.GetPointer() );
  948. prstRight.Acquire();
  949. $$ = prstLeft.Acquire();
  950. }
  951. else
  952. {
  953. // create smart Prox node
  954. XDbProximityNodeRestriction prstNew(new CDbProximityNodeRestriction()); // uses defaults
  955. if ( prstNew.IsNull() || !prstNew->IsValid() )
  956. THROW( CException( E_OUTOFMEMORY ) );
  957. // add left phrase & release its smart pointer
  958. prstNew->AppendChild( prstLeft.GetPointer() );
  959. prstLeft.Acquire();
  960. // add right term & release its smart pointer
  961. prstNew->AppendChild( prstRight.GetPointer() );
  962. prstRight.Acquire();
  963. $$ = prstNew.Acquire();
  964. }
  965. _setRst.Add( $$ );
  966. }
  967. | NearTerm _NEARDIST _NEARUNIT _NEAR_END CoerceTerm
  968. {
  969. AssertReq($1);
  970. AssertReq($2);
  971. AssertReq($3);
  972. AssertReq($5);
  973. XDbRestriction prstLeft($1);
  974. XDbRestriction prstRight($5);
  975. _setRst.Remove( $1 );
  976. _setRst.Remove( $5 );
  977. WCHAR * pwcEnd;
  978. ULONG ulValue = wcstol( $2, &pwcEnd, 10 );
  979. ULONG ulUnit;
  980. if (L'w' == *$3)
  981. ulUnit = PROXIMITY_UNIT_WORD;
  982. else if (L's' == *$3)
  983. ulUnit = PROXIMITY_UNIT_SENTENCE;
  984. else if (L'p' == *$3)
  985. ulUnit = PROXIMITY_UNIT_PARAGRAPH;
  986. else if (L'c' == *$3)
  987. ulUnit = PROXIMITY_UNIT_CHAPTER;
  988. if (DBOP_content_proximity == $1->GetCommandType() &&
  989. ulValue == ((CDbProximityNodeRestriction *)$1)->GetProximityDistance() &&
  990. ulUnit == ((CDbProximityNodeRestriction *)$1)->GetProximityUnit())
  991. {
  992. // add right term & release its smart pointer
  993. ((CDbProximityNodeRestriction *)$1)->AppendChild( prstRight.GetPointer() );
  994. prstRight.Acquire();
  995. $$ = prstLeft.Acquire();
  996. }
  997. else
  998. {
  999. // create smart Prox node
  1000. XDbProximityNodeRestriction prstNew(new CDbProximityNodeRestriction(ulUnit, ulValue));
  1001. if( prstNew.IsNull() || !prstNew->IsValid() )
  1002. THROW( CException( E_OUTOFMEMORY ) );
  1003. // add left phrase & release its smart pointer
  1004. prstNew->AppendChild( prstLeft.GetPointer() );
  1005. prstLeft.Acquire();
  1006. // add right term & release its smart pointer
  1007. prstNew->AppendChild( prstRight.GetPointer() );
  1008. prstRight.Acquire();
  1009. $$ = prstNew.Acquire();
  1010. }
  1011. _setRst.Add( $$ );
  1012. }
  1013. ;
  1014. CoerceTerm:
  1015. Gen NestTerm GenEnd
  1016. {
  1017. $$ = $2;
  1018. }
  1019. | Gen _COERCE Gen NestTerm GenEnd
  1020. {
  1021. AssertReq($4);
  1022. XDbRestriction prstQuery($4);
  1023. $4->SetWeight(MAX_QUERY_RANK);
  1024. $$ = prstQuery.Acquire();
  1025. }
  1026. | Gen _WEIGHT Gen NestTerm GenEnd
  1027. {
  1028. AssertReq($2);
  1029. AssertReq($4);
  1030. XDbRestriction prstQuery($4);
  1031. WCHAR * pwcEnd;
  1032. double dWeight = wcstod( $2, &pwcEnd );
  1033. if ( dWeight > 1.0 )
  1034. THROW( CParserException( QPARSE_E_WEIGHT_OUT_OF_RANGE ) );
  1035. LONG lWeight = (LONG)(dWeight * MAX_QUERY_RANK);
  1036. $4->SetWeight(lWeight);
  1037. $$ = prstQuery.Acquire();
  1038. }
  1039. ;
  1040. Gen: /* empty */
  1041. {
  1042. $$ = 0;
  1043. }
  1044. | _GENPREFIX
  1045. {
  1046. SetCurrentGenerate(GENERATE_METHOD_PREFIX);
  1047. $$ = GENERATE_METHOD_PREFIX;
  1048. }
  1049. | _GENINFLECT
  1050. {
  1051. SetCurrentGenerate(GENERATE_METHOD_INFLECT);
  1052. $$ = GENERATE_METHOD_INFLECT;
  1053. }
  1054. ;
  1055. GenEnd: /* empty */
  1056. {
  1057. $$ = GENERATE_METHOD_EXACT;
  1058. }
  1059. | _GENNORMAL
  1060. {
  1061. // don't set the generate method to 0 here. Doing so will
  1062. // reset the method before it gets used.
  1063. $$ = GENERATE_METHOD_EXACT;
  1064. }
  1065. NestTerm: VectorTerm
  1066. {
  1067. $$ = $1;
  1068. }
  1069. | Term
  1070. {
  1071. $$ = $1;
  1072. }
  1073. | Open query Close
  1074. {
  1075. $$ = $2;
  1076. }
  1077. ;
  1078. VectorTerm: VectorSpec _VECTOR_END
  1079. {
  1080. $$ = $1;
  1081. }
  1082. VectorSpec: _VEMETHOD _VE query
  1083. {
  1084. AssertReq($1);
  1085. AssertReq($3);
  1086. XDbRestriction prstQuery($3);
  1087. _setRst.Remove( $3 );
  1088. ULONG rankMethod = VECTOR_RANK_JACCARD; // default if nothing else matches
  1089. if ( 0 == _wcsicmp( L"jaccard", $1) )
  1090. {
  1091. rankMethod = VECTOR_RANK_JACCARD;
  1092. }
  1093. else if ( 0 == _wcsicmp( L"dice", $1) )
  1094. {
  1095. rankMethod = VECTOR_RANK_DICE;
  1096. }
  1097. else if ( 0 == _wcsicmp( L"inner", $1) )
  1098. {
  1099. rankMethod = VECTOR_RANK_INNER;
  1100. }
  1101. else if ( 0 == _wcsicmp( L"max", $1) )
  1102. {
  1103. rankMethod = VECTOR_RANK_MAX;
  1104. }
  1105. else if ( 0 == _wcsicmp( L"min", $1) )
  1106. {
  1107. rankMethod = VECTOR_RANK_MIN;
  1108. }
  1109. else
  1110. {
  1111. THROW( CException( QPARSE_E_INVALID_RANKMETHOD ) );
  1112. }
  1113. // create smart Vector node
  1114. XDbVectorRestriction prstNew( new CDbVectorRestriction( rankMethod ) );
  1115. if ( prstNew.IsNull() || !prstNew->IsValid() )
  1116. {
  1117. THROW( CException( E_OUTOFMEMORY ) );
  1118. }
  1119. // add expression & release its smart pointer
  1120. prstNew->AppendChild( prstQuery.GetPointer() );
  1121. prstQuery.Acquire();
  1122. // Let the next vector element start off with a clean slate...
  1123. // We don't want the current element's property and genmethod
  1124. // to rub off on it.
  1125. InitState();
  1126. $$ = prstNew.Acquire();
  1127. _setRst.Add( $$ );
  1128. }
  1129. | VectorSpec _VE query
  1130. {
  1131. AssertReq($1);
  1132. AssertReq($3);
  1133. XDbRestriction prstLeft($1);
  1134. XDbRestriction prstRight($3);
  1135. _setRst.Remove( $1 );
  1136. _setRst.Remove( $3 );
  1137. // add right term & release its smart pointer
  1138. ((CDbVectorRestriction *)($1))->AppendChild( prstRight.GetPointer() );
  1139. prstRight.Acquire();
  1140. // Let the next vector element start off with a clean slate...
  1141. // We don't want the current element's property and genmethod
  1142. // to rub off on it.
  1143. InitState();
  1144. $$ = prstLeft.Acquire();
  1145. _setRst.Add( $$ );
  1146. }
  1147. ;
  1148. Open: _OPEN
  1149. {
  1150. SaveState();
  1151. $$ = 0;
  1152. }
  1153. Close: _CLOSE
  1154. {
  1155. RestoreState();
  1156. $$ = 0;
  1157. }
  1158. Term: PropTerm
  1159. {
  1160. $$ = $1;
  1161. }
  1162. | Property Contains _PHRASE ShortGen PropEnd
  1163. {
  1164. $$ = BuildPhrase($3, $4);
  1165. _setRst.Add( $$ );
  1166. }
  1167. | Property Contains _PHRASE PropEnd
  1168. {
  1169. $$ = BuildPhrase($3, 0);
  1170. _setRst.Add( $$ );
  1171. }
  1172. | Property Contains Gen _PHRASE GenEnd PropEnd
  1173. {
  1174. $$ = BuildPhrase($4, $3);
  1175. _setRst.Add( $$ );
  1176. }
  1177. | Property Contains query
  1178. {
  1179. $$ = $3;
  1180. }
  1181. | Property Contains _FREETEXT ShortGen PropEnd
  1182. {
  1183. AssertReq($3);
  1184. CDbColId *pps;
  1185. DBTYPE dbType;
  1186. GetCurrentProperty(&pps, &dbType);
  1187. // We used the property. Now pop it off if need be
  1188. if (fDeferredPop)
  1189. PopProperty();
  1190. // Clear generation method so it won't rub off on the following phrase
  1191. SetCurrentGenerate(GENERATE_METHOD_EXACT);
  1192. // generation method not used - if it's there, ignore it
  1193. // (already stripped from longhand version, but not from
  1194. // shorthand version
  1195. LPWSTR pLast = $3 + wcslen($3) -1;
  1196. if ( L'*' == *pLast) // prefix
  1197. *pLast-- = L'\0';
  1198. if ( L'*' == *pLast) // inflect
  1199. *pLast-- = L'\0';
  1200. XDbNatLangRestriction pRest ( new CDbNatLangRestriction ($3, *pps, _lcid));
  1201. if ( pRest.IsNull() || !pRest->IsValid() )
  1202. THROW( CException( E_OUTOFMEMORY ) );
  1203. $$ = pRest.Acquire();
  1204. _setRst.Add( $$ );
  1205. }
  1206. ;
  1207. PropTerm: Property Matches _REGEX PropEnd
  1208. {
  1209. AssertReq($3);
  1210. CDbColId *pps;
  1211. DBTYPE dbType;
  1212. GetCurrentProperty(&pps, &dbType);
  1213. // We used the property. Now pop it off if need be
  1214. if (fDeferredPop)
  1215. PopProperty();
  1216. if ( ( ( DBTYPE_WSTR|DBTYPE_BYREF ) != dbType ) &&
  1217. ( ( DBTYPE_STR|DBTYPE_BYREF ) != dbType ) &&
  1218. ( VT_BSTR != dbType ) &&
  1219. ( VT_LPWSTR != dbType ) &&
  1220. ( VT_LPSTR != dbType ) )
  1221. THROW( CParserException( QPARSE_E_EXPECTING_REGEX_PROPERTY ) );
  1222. if( $3 == 0 )
  1223. THROW( CParserException( QPARSE_E_EXPECTING_REGEX ) );
  1224. // create smart Property node
  1225. XDbPropertyRestriction prstProp( new CDbPropertyRestriction );
  1226. if( prstProp.GetPointer() == 0 )
  1227. THROW( CException( E_OUTOFMEMORY ) );
  1228. prstProp->SetRelation(DBOP_like); // LIKE relation
  1229. if ( ( ! prstProp->SetProperty( *pps ) ) ||
  1230. ( ! prstProp->SetValue( $3 ) ) ||
  1231. ( ! prstProp->IsValid() ) )
  1232. THROW( CException( E_OUTOFMEMORY ) );
  1233. // release & return smart Property node
  1234. $$ = prstProp.Acquire();
  1235. _setRst.Add( $$ );
  1236. }
  1237. | Property Op Value PropEnd
  1238. {
  1239. AssertReq($2);
  1240. AssertReq($3);
  1241. XPtr<CStorageVariant> pStorageVar( $3 );
  1242. _setStgVar.Remove( $3 );
  1243. CDbColId *pps;
  1244. DBTYPE dbType;
  1245. GetCurrentProperty(&pps, &dbType);
  1246. // We used the property. Now pop it off if need be
  1247. if (fDeferredPop)
  1248. PopProperty();
  1249. // create smart Property node
  1250. XDbPropertyRestriction prstProp( new CDbPropertyRestriction );
  1251. if( prstProp.GetPointer() == 0 )
  1252. THROW( CException( E_OUTOFMEMORY ) );
  1253. if (! prstProp->SetProperty( *pps ) )
  1254. THROW( CException( E_OUTOFMEMORY ) );
  1255. // don't allow @contents <relop> X -- it's too expensive and we'll
  1256. // never find any hits anyway (until we implement this feature)
  1257. if ( *pps == psContents )
  1258. THROW( CParserException( QPARSE_E_EXPECTING_PHRASE ) );
  1259. prstProp->SetRelation( $2 );
  1260. if ( 0 != pStorageVar.GetPointer() )
  1261. {
  1262. // This should always be the case - else PropValueParser would have thrown
  1263. if ( ! ( ( prstProp->SetValue( pStorageVar.GetReference() ) ) &&
  1264. ( prstProp->IsValid() ) ) )
  1265. THROW( CException( E_OUTOFMEMORY ) );
  1266. }
  1267. $$ = prstProp.Acquire();
  1268. _setRst.Add( $$ );
  1269. }
  1270. ;
  1271. Property: /* empty */
  1272. {
  1273. $$ = 0;
  1274. }
  1275. | _PROPNAME
  1276. {
  1277. PushProperty($1);
  1278. $$ = 0;
  1279. }
  1280. ;
  1281. PropEnd: /* empty */
  1282. {
  1283. fDeferredPop = FALSE;
  1284. $$ = 0;
  1285. }
  1286. | _PROPEND
  1287. {
  1288. // When PropEnd is matched, the action of using the property
  1289. // hasn't yet taken place. So popping the property right now
  1290. // will cause the property to be unavailable when the action
  1291. // is performed. Instead, pop it off after it has been used.
  1292. fDeferredPop = TRUE;
  1293. $$ = 0;
  1294. }
  1295. ;
  1296. Op: _EQ
  1297. { $$ = DBOP_equal;}
  1298. | _NE
  1299. { $$ = DBOP_not_equal;}
  1300. | _GT
  1301. { $$ = DBOP_greater;}
  1302. | _GTE
  1303. { $$ = DBOP_greater_equal;}
  1304. | _LT
  1305. { $$ = DBOP_less;}
  1306. | _LTE
  1307. { $$ = DBOP_less_equal;}
  1308. | _ALLOF
  1309. { $$ = DBOP_allbits;}
  1310. | _SOMEOF
  1311. { $$ = DBOP_anybits;}
  1312. | _EQSOME
  1313. { $$ = DBOP_equal_any;}
  1314. | _NESOME
  1315. { $$ = DBOP_not_equal_any;}
  1316. | _GTSOME
  1317. { $$ = DBOP_greater_any;}
  1318. | _GTESOME
  1319. { $$ = DBOP_greater_equal_any;}
  1320. | _LTSOME
  1321. { $$ = DBOP_less_any;}
  1322. | _LTESOME
  1323. { $$ = DBOP_less_equal_any;}
  1324. | _ALLOFSOME
  1325. { $$ = DBOP_allbits_any;}
  1326. | _SOMEOFSOME
  1327. { $$ = DBOP_anybits_any;}
  1328. | _EQALL
  1329. { $$ = DBOP_equal_all;}
  1330. | _NEALL
  1331. { $$ = DBOP_not_equal_all;}
  1332. | _GTALL
  1333. { $$ = DBOP_greater_all;}
  1334. | _GTEALL
  1335. { $$ = DBOP_greater_equal_all;}
  1336. | _LTALL
  1337. { $$ = DBOP_less_all;}
  1338. | _LTEALL
  1339. { $$ = DBOP_less_equal_all;}
  1340. | _ALLOFALL
  1341. { $$ = DBOP_allbits_all;}
  1342. | _SOMEOFALL
  1343. { $$ = DBOP_anybits_all;}
  1344. ;
  1345. Matches: /* empty */
  1346. { $$ = 0; }
  1347. | _EQ
  1348. { $$ = DBOP_equal; }
  1349. Value: _PHRASE
  1350. {
  1351. CDbColId *pps;
  1352. DBTYPE dbType;
  1353. GetCurrentProperty(&pps, &dbType);
  1354. CValueParser PropValueParser( FALSE, dbType, _lcid );
  1355. StripQuotes($1);
  1356. PropValueParser.AddValue( $1 );
  1357. $$ = PropValueParser.AcquireStgVariant();
  1358. _setStgVar.Add( $$ );
  1359. }
  1360. | _FREETEXT
  1361. {
  1362. CDbColId *pps;
  1363. DBTYPE dbType;
  1364. GetCurrentProperty(&pps, &dbType);
  1365. CValueParser PropValueParser( FALSE, dbType, _lcid );
  1366. PropValueParser.AddValue( $1 );
  1367. $$ = PropValueParser.AcquireStgVariant();
  1368. _setStgVar.Add( $$ );
  1369. }
  1370. | VectorValue
  1371. {
  1372. $$ = $1;
  1373. }
  1374. ;
  1375. VectorValue: EmptyVector
  1376. {
  1377. XPtr <CValueParser> pPropValueParser ( $1 );
  1378. _setValueParser.Remove( $1 );
  1379. $$ = $1->AcquireStgVariant();
  1380. _setStgVar.Add( $$ );
  1381. }
  1382. | SingletVector
  1383. {
  1384. XPtr <CValueParser> pPropValueParser ( $1 );
  1385. _setValueParser.Remove( $1 );
  1386. $$ = $1->AcquireStgVariant();
  1387. _setStgVar.Add( $$ );
  1388. }
  1389. | MultiVector _VE_END
  1390. {
  1391. XPtr <CValueParser> pPropValueParser ( $1 );
  1392. _setValueParser.Remove( $1 );
  1393. $$ = $1->AcquireStgVariant();
  1394. _setStgVar.Add( $$ );
  1395. }
  1396. EmptyVector: _OPEN _CLOSE
  1397. {
  1398. CDbColId *pps;
  1399. DBTYPE dbType;
  1400. GetCurrentProperty(&pps, &dbType);
  1401. XPtr <CValueParser> pPropValueParser ( new CValueParser( TRUE, dbType, _lcid ) );
  1402. if( pPropValueParser.GetPointer() == 0 )
  1403. THROW( CException( E_OUTOFMEMORY ) );
  1404. $$ = pPropValueParser.Acquire();
  1405. _setValueParser.Add( $$ );
  1406. }
  1407. SingletVector: _OPEN _PHRASE _CLOSE
  1408. {
  1409. AssertReq($2);
  1410. CDbColId *pps;
  1411. DBTYPE dbType;
  1412. GetCurrentProperty(&pps, &dbType);
  1413. XPtr <CValueParser> pPropValueParser ( new CValueParser( TRUE, dbType, _lcid ) );
  1414. if( pPropValueParser.GetPointer() == 0 )
  1415. THROW( CException( E_OUTOFMEMORY ) );
  1416. StripQuotes($2);
  1417. pPropValueParser->AddValue( $2 );
  1418. $$ = pPropValueParser.Acquire();
  1419. _setValueParser.Add( $$ );
  1420. }
  1421. | _OPEN _FREETEXT _CLOSE
  1422. {
  1423. AssertReq($2);
  1424. CDbColId *pps;
  1425. DBTYPE dbType;
  1426. GetCurrentProperty(&pps, &dbType);
  1427. XPtr <CValueParser> pPropValueParser ( new CValueParser( TRUE, dbType, _lcid ) );
  1428. if( pPropValueParser.GetPointer() == 0 )
  1429. THROW( CException( E_OUTOFMEMORY ) );
  1430. pPropValueParser->AddValue( $2 );
  1431. $$ = pPropValueParser.Acquire();
  1432. _setValueParser.Add( $$ );
  1433. }
  1434. MultiVector: _VECTORELEMENT _VECTORELEMENT
  1435. {
  1436. AssertReq($1);
  1437. AssertReq($2);
  1438. CDbColId *pps;
  1439. DBTYPE dbType;
  1440. GetCurrentProperty(&pps, &dbType);
  1441. XPtr <CValueParser> pPropValueParser ( new CValueParser( TRUE, dbType, _lcid ) );
  1442. if( pPropValueParser.GetPointer() == 0 )
  1443. THROW( CException( E_OUTOFMEMORY ) );
  1444. pPropValueParser->AddValue( $1 );
  1445. pPropValueParser->AddValue( $2 );
  1446. $$ = pPropValueParser.Acquire();
  1447. _setValueParser.Add( $$ );
  1448. }
  1449. | MultiVector _VECTORELEMENT
  1450. {
  1451. AssertReq($1);
  1452. AssertReq($2);
  1453. $1->AddValue($2);
  1454. $$ = $1;
  1455. }
  1456. ;
  1457. Contains: /* empty */
  1458. {
  1459. $$ = 0;
  1460. }
  1461. | _CONTAINS
  1462. {
  1463. $$ = 0;
  1464. }
  1465. ;
  1466. ShortGen: /* empty */
  1467. {
  1468. $$ = 0;
  1469. }
  1470. | _SHGENPREFIX
  1471. {
  1472. $$ = 1;
  1473. }
  1474. | _SHGENINFLECT
  1475. {
  1476. $$ = 2;
  1477. }
  1478. ;