cubicweb/server/test/unittest_rql2sql.py
changeset 11077 09be48c01fa4
parent 11057 0b59724cb3f2
child 11237 f32134dd0067
equal deleted inserted replaced
11076:403a901b6b1e 11077:09be48c01fa4
  1254                 print('!=')
  1254                 print('!=')
  1255                 print(sql.strip())
  1255                 print(sql.strip())
  1256             print('RQL:', rql)
  1256             print('RQL:', rql)
  1257             raise
  1257             raise
  1258 
  1258 
  1259     def _parse(self, rqls):
       
  1260         for rql, sql in rqls:
       
  1261             yield self._check, rql, sql
       
  1262 
       
  1263     def _checkall(self, rql, sql):
  1259     def _checkall(self, rql, sql):
  1264         if isinstance(rql, tuple):
  1260         if isinstance(rql, tuple):
  1265             rql, args = rql
  1261             rql, args = rql
  1266         else:
  1262         else:
  1267             args = None
  1263             args = None
  1334                                '''SELECT _X.cw_eid
  1330                                '''SELECT _X.cw_eid
  1335 FROM cw_CWUser AS _X
  1331 FROM cw_CWUser AS _X
  1336 WHERE _X.cw_login IS NULL''')
  1332 WHERE _X.cw_login IS NULL''')
  1337 
  1333 
  1338     def test_today(self):
  1334     def test_today(self):
  1339         for t in self._parse([("Any X WHERE X creation_date TODAY, X is Affaire",
  1335         for rql, sql in [
  1340                               '''SELECT _X.cw_eid
  1336             ("Any X WHERE X creation_date TODAY, X is Affaire",
       
  1337              '''SELECT _X.cw_eid
  1341 FROM cw_Affaire AS _X
  1338 FROM cw_Affaire AS _X
  1342 WHERE DATE(_X.cw_creation_date)=CAST(clock_timestamp() AS DATE)'''),
  1339 WHERE DATE(_X.cw_creation_date)=CAST(clock_timestamp() AS DATE)'''),
  1343                              ("Personne P where not P datenaiss TODAY",
  1340             ("Personne P where not P datenaiss TODAY",
  1344                               '''SELECT _P.cw_eid
  1341              '''SELECT _P.cw_eid
  1345 FROM cw_Personne AS _P
  1342 FROM cw_Personne AS _P
  1346 WHERE NOT (DATE(_P.cw_datenaiss)=CAST(clock_timestamp() AS DATE))'''),
  1343 WHERE NOT (DATE(_P.cw_datenaiss)=CAST(clock_timestamp() AS DATE))'''),
  1347                              ]):
  1344             ]:
  1348             yield t
  1345             with self.subTest(rql=rql):
       
  1346                 self._check(rql, sql)
  1349 
  1347 
  1350     def test_date_extraction(self):
  1348     def test_date_extraction(self):
  1351         self._check("Any MONTH(D) WHERE P is Personne, P creation_date D",
  1349         self._check("Any MONTH(D) WHERE P is Personne, P creation_date D",
  1352                     '''SELECT CAST(EXTRACT(MONTH from _P.cw_creation_date) AS INTEGER)
  1350                     '''SELECT CAST(EXTRACT(MONTH from _P.cw_creation_date) AS INTEGER)
  1353 FROM cw_Personne AS _P''')
  1351 FROM cw_Personne AS _P''')
  1373 FROM cw_CWUser AS _X
  1371 FROM cw_CWUser AS _X
  1374 WHERE _X.cw_login ~ [0-9].*
  1372 WHERE _X.cw_login ~ [0-9].*
  1375 ''')
  1373 ''')
  1376 
  1374 
  1377     def test_parser_parse(self):
  1375     def test_parser_parse(self):
  1378         for t in self._parse(PARSER):
  1376         for rql, sql in PARSER:
  1379             yield t
  1377             with self.subTest(rql=rql):
       
  1378                 self._check(rql, sql)
  1380 
  1379 
  1381     def test_basic_parse(self):
  1380     def test_basic_parse(self):
  1382         for t in self._parse(BASIC + BASIC_WITH_LIMIT):
  1381         for rql, sql in (BASIC + BASIC_WITH_LIMIT):
  1383             yield t
  1382             with self.subTest(rql=rql):
       
  1383                 self._check(rql, sql)
  1384 
  1384 
  1385     def test_advanced_parse(self):
  1385     def test_advanced_parse(self):
  1386         for t in self._parse(ADVANCED + ADVANCED_WITH_LIMIT_OR_ORDERBY + ADVANCED_WITH_GROUP_CONCAT):
  1386         for rql, sql in (ADVANCED + ADVANCED_WITH_LIMIT_OR_ORDERBY + ADVANCED_WITH_GROUP_CONCAT):
  1387             yield t
  1387             with self.subTest(rql=rql):
       
  1388                 self._check(rql, sql)
  1388 
  1389 
  1389     def test_outer_join_parse(self):
  1390     def test_outer_join_parse(self):
  1390         for t in self._parse(OUTER_JOIN):
  1391         for rql, sql in OUTER_JOIN:
  1391             yield t
  1392             with self.subTest(rql=rql):
       
  1393                 self._check(rql, sql)
  1392 
  1394 
  1393     def test_virtual_vars_parse(self):
  1395     def test_virtual_vars_parse(self):
  1394         for t in self._parse(VIRTUAL_VARS):
  1396         for rql, sql in VIRTUAL_VARS:
  1395             yield t
  1397             with self.subTest(rql=rql):
       
  1398                 self._check(rql, sql)
  1396 
  1399 
  1397     def test_multiple_sel_parse(self):
  1400     def test_multiple_sel_parse(self):
  1398         for t in self._parse(MULTIPLE_SEL):
  1401         for rql, sql in MULTIPLE_SEL:
  1399             yield t
  1402             with self.subTest(rql=rql):
       
  1403                 self._check(rql, sql)
  1400 
  1404 
  1401     def test_functions(self):
  1405     def test_functions(self):
  1402         for t in self._parse(FUNCS):
  1406         for rql, sql in FUNCS:
  1403             yield t
  1407             with self.subTest(rql=rql):
       
  1408                 self._check(rql, sql)
  1404 
  1409 
  1405     def test_negation(self):
  1410     def test_negation(self):
  1406         for t in self._parse(NEGATIONS):
  1411         for rql, sql in NEGATIONS:
  1407             yield t
  1412             with self.subTest(rql=rql):
       
  1413                 self._check(rql, sql)
  1408 
  1414 
  1409     def test_intersection(self):
  1415     def test_intersection(self):
  1410         for t in self._parse(INTERSECT):
  1416         for rql, sql in INTERSECT:
  1411             yield t
  1417             with self.subTest(rql=rql):
       
  1418                 self._check(rql, sql)
  1412 
  1419 
  1413     def test_union(self):
  1420     def test_union(self):
  1414         for t in self._parse((
  1421         for rql, sql in [
  1415             ('(Any N ORDERBY 1 WHERE X name N, X is State)'
  1422             ('(Any N ORDERBY 1 WHERE X name N, X is State)'
  1416              ' UNION '
  1423              ' UNION '
  1417              '(Any NN ORDERBY 1 WHERE XX name NN, XX is Transition)',
  1424              '(Any NN ORDERBY 1 WHERE XX name NN, XX is Transition)',
  1418              '''(SELECT _X.cw_name
  1425              '''(SELECT _X.cw_name
  1419 FROM cw_State AS _X
  1426 FROM cw_State AS _X
  1420 ORDER BY 1)
  1427 ORDER BY 1)
  1421 UNION ALL
  1428 UNION ALL
  1422 (SELECT _XX.cw_name
  1429 (SELECT _XX.cw_name
  1423 FROM cw_Transition AS _XX
  1430 FROM cw_Transition AS _XX
  1424 ORDER BY 1)'''),
  1431 ORDER BY 1)'''),
  1425             )):
  1432         ]:
  1426             yield t
  1433             with self.subTest(rql=rql):
       
  1434                 self._check(rql, sql)
  1427 
  1435 
  1428     def test_subquery(self):
  1436     def test_subquery(self):
  1429         for t in self._parse((
  1437         for rql, sql in [
  1430 
       
  1431             ('Any X,N '
  1438             ('Any X,N '
  1432              'WHERE NOT EXISTS(X owned_by U) '
  1439              'WHERE NOT EXISTS(X owned_by U) '
  1433              'WITH X,N BEING '
  1440              'WITH X,N BEING '
  1434              '((Any X,N WHERE X name N, X is State)'
  1441              '((Any X,N WHERE X name N, X is State)'
  1435              ' UNION '
  1442              ' UNION '
  1514 FROM cw_Affaire AS _T
  1521 FROM cw_Affaire AS _T
  1515 GROUP BY _T.cw_eid) AS _T1 LEFT OUTER JOIN (SELECT _T.cw_eid AS C0, SUM(_T.cw_duration) AS C1
  1522 GROUP BY _T.cw_eid) AS _T1 LEFT OUTER JOIN (SELECT _T.cw_eid AS C0, SUM(_T.cw_duration) AS C1
  1516 FROM cw_Affaire AS _T LEFT OUTER JOIN tags_relation AS rel_tags0 ON (rel_tags0.eid_to=_T.cw_eid) LEFT OUTER JOIN cw_Tag AS _TAG ON (rel_tags0.eid_from=_TAG.cw_eid AND _TAG.cw_name=t)
  1523 FROM cw_Affaire AS _T LEFT OUTER JOIN tags_relation AS rel_tags0 ON (rel_tags0.eid_to=_T.cw_eid) LEFT OUTER JOIN cw_Tag AS _TAG ON (rel_tags0.eid_from=_TAG.cw_eid AND _TAG.cw_name=t)
  1517 GROUP BY _T.cw_eid) AS _T0 ON (_T1.C0=_T0.C0)'''),
  1524 GROUP BY _T.cw_eid) AS _T0 ON (_T1.C0=_T0.C0)'''),
  1518 
  1525 
  1519                              )):
  1526         ]:
  1520             yield t
  1527             with self.subTest(rql=rql):
  1521 
  1528                 self._check(rql, sql)
  1522 
  1529 
  1523     def test_subquery_error(self):
  1530     def test_subquery_error(self):
  1524         rql = ('Any N WHERE X name N WITH X BEING '
  1531         rql = ('Any N WHERE X name N WITH X BEING '
  1525                '((Any X WHERE X is State)'
  1532                '((Any X WHERE X is State)'
  1526                ' UNION '
  1533                ' UNION '
  1527                ' (Any X WHERE X is Transition))')
  1534                ' (Any X WHERE X is Transition))')
  1528         rqlst = self._prepare(rql)
  1535         rqlst = self._prepare(rql)
  1529         self.assertRaises(BadRQLQuery, self.o.generate, rqlst)
  1536         self.assertRaises(BadRQLQuery, self.o.generate, rqlst)
  1530 
  1537 
  1531     def test_inline(self):
  1538     def test_inline(self):
  1532         for t in self._parse(INLINE):
  1539         for rql, sql in INLINE:
  1533             yield t
  1540             with self.subTest(rql=rql):
       
  1541                 self._check(rql, sql)
  1534 
  1542 
  1535     def test_has_text(self):
  1543     def test_has_text(self):
  1536         for t in self._parse((
  1544         for rql, sql in [
  1537             ('Any X WHERE X has_text "toto tata"',
  1545             ('Any X WHERE X has_text "toto tata"',
  1538              """SELECT appears0.uid
  1546              """SELECT appears0.uid
  1539 FROM appears AS appears0
  1547 FROM appears AS appears0
  1540 WHERE appears0.words @@ to_tsquery('default', 'toto&tata')"""),
  1548 WHERE appears0.words @@ to_tsquery('default', 'toto&tata')"""),
  1541 
  1549 
  1608              '''SELECT appears1.uid
  1616              '''SELECT appears1.uid
  1609 FROM appears AS appears1
  1617 FROM appears AS appears1
  1610 WHERE NOT (EXISTS(SELECT 1 FROM tags_relation AS rel_tags0 WHERE appears1.uid=rel_tags0.eid_to)) AND appears1.words @@ to_tsquery('default', 'pouet')
  1618 WHERE NOT (EXISTS(SELECT 1 FROM tags_relation AS rel_tags0 WHERE appears1.uid=rel_tags0.eid_to)) AND appears1.words @@ to_tsquery('default', 'pouet')
  1611 '''),
  1619 '''),
  1612 
  1620 
  1613             )):
  1621         ]:
  1614             yield t
  1622             with self.subTest(rql=rql):
  1615 
  1623                 self._check(rql, sql)
  1616 
  1624 
  1617     def test_from_clause_needed(self):
  1625     def test_from_clause_needed(self):
  1618         queries = [("Any 1 WHERE EXISTS(T is CWGroup, T name 'managers')",
  1626         queries = [("Any 1 WHERE EXISTS(T is CWGroup, T name 'managers')",
  1619                     '''SELECT 1
  1627                     '''SELECT 1
  1620 WHERE EXISTS(SELECT 1 FROM cw_CWGroup AS _T WHERE _T.cw_name=managers)'''),
  1628 WHERE EXISTS(SELECT 1 FROM cw_CWGroup AS _T WHERE _T.cw_name=managers)'''),
  1621                    ('Any X,Y WHERE NOT X created_by Y, X eid 5, Y eid 6',
  1629                    ('Any X,Y WHERE NOT X created_by Y, X eid 5, Y eid 6',
  1622                     '''SELECT 5, 6
  1630                     '''SELECT 5, 6
  1623 WHERE NOT (EXISTS(SELECT 1 FROM created_by_relation AS rel_created_by0 WHERE rel_created_by0.eid_from=5 AND rel_created_by0.eid_to=6))'''),
  1631 WHERE NOT (EXISTS(SELECT 1 FROM created_by_relation AS rel_created_by0 WHERE rel_created_by0.eid_from=5 AND rel_created_by0.eid_to=6))'''),
  1624                    ]
  1632                    ]
  1625         for t in self._parse(queries):
  1633         for rql, sql in queries:
  1626             yield t
  1634             with self.subTest(rql=rql):
       
  1635                 self._check(rql, sql)
  1627 
  1636 
  1628     def test_ambigous_exists_no_from_clause(self):
  1637     def test_ambigous_exists_no_from_clause(self):
  1629         self._check('Any COUNT(U) WHERE U eid 1, EXISTS (P owned_by U, P is IN (Note, Affaire))',
  1638         self._check('Any COUNT(U) WHERE U eid 1, EXISTS (P owned_by U, P is IN (Note, Affaire))',
  1630                     '''SELECT COUNT(1)
  1639                     '''SELECT COUNT(1)
  1631 WHERE EXISTS(SELECT 1 FROM cw_Affaire AS _P, owned_by_relation AS rel_owned_by0 WHERE rel_owned_by0.eid_from=_P.cw_eid AND rel_owned_by0.eid_to=1 UNION SELECT 1 FROM cw_Note AS _P, owned_by_relation AS rel_owned_by1 WHERE rel_owned_by1.eid_from=_P.cw_eid AND rel_owned_by1.eid_to=1)''')
  1640 WHERE EXISTS(SELECT 1 FROM cw_Affaire AS _P, owned_by_relation AS rel_owned_by0 WHERE rel_owned_by0.eid_from=_P.cw_eid AND rel_owned_by0.eid_to=1 UNION SELECT 1 FROM cw_Note AS _P, owned_by_relation AS rel_owned_by1 WHERE rel_owned_by1.eid_from=_P.cw_eid AND rel_owned_by1.eid_to=1)''')
  1728     backend = 'sqlserver2005'
  1737     backend = 'sqlserver2005'
  1729     def _norm_sql(self, sql):
  1738     def _norm_sql(self, sql):
  1730         return sql.strip().replace(' SUBSTR', ' SUBSTRING').replace(' || ', ' + ').replace(' ILIKE ', ' LIKE ')
  1739         return sql.strip().replace(' SUBSTR', ' SUBSTRING').replace(' || ', ' + ').replace(' ILIKE ', ' LIKE ')
  1731 
  1740 
  1732     def test_has_text(self):
  1741     def test_has_text(self):
  1733         for t in self._parse(HAS_TEXT_LG_INDEXER):
  1742         for rql, sql in HAS_TEXT_LG_INDEXER:
  1734             yield t
  1743             with self.subTest(rql=rql):
       
  1744                 self._check(rql, sql)
  1735 
  1745 
  1736     def test_regexp(self):
  1746     def test_regexp(self):
  1737         self.skipTest('regexp-based pattern matching not implemented in sqlserver')
  1747         self.skipTest('regexp-based pattern matching not implemented in sqlserver')
  1738 
  1748 
  1739     def test_or_having_fake_terms_base(self):
  1749     def test_or_having_fake_terms_base(self):
  1751         self._check("Any WEEKDAY(D) WHERE P is Personne, P creation_date D",
  1761         self._check("Any WEEKDAY(D) WHERE P is Personne, P creation_date D",
  1752                     '''SELECT DATEPART(WEEKDAY, _P.cw_creation_date)
  1762                     '''SELECT DATEPART(WEEKDAY, _P.cw_creation_date)
  1753 FROM cw_Personne AS _P''')
  1763 FROM cw_Personne AS _P''')
  1754 
  1764 
  1755     def test_basic_parse(self):
  1765     def test_basic_parse(self):
  1756         for t in self._parse(BASIC):# + BASIC_WITH_LIMIT):
  1766         for rql, sql in BASIC:# + BASIC_WITH_LIMIT):
  1757             yield t
  1767             with self.subTest(rql=rql):
       
  1768                 self._check(rql, sql)
  1758 
  1769 
  1759     def test_advanced_parse(self):
  1770     def test_advanced_parse(self):
  1760         for t in self._parse(ADVANCED):# + ADVANCED_WITH_LIMIT_OR_ORDERBY):
  1771         for rql, sql in ADVANCED:# + ADVANCED_WITH_LIMIT_OR_ORDERBY):
  1761             yield t
  1772             with self.subTest(rql=rql):
       
  1773                 self._check(rql, sql)
  1762 
  1774 
  1763     def test_limit_offset(self):
  1775     def test_limit_offset(self):
  1764         WITH_LIMIT = [
  1776         WITH_LIMIT = [
  1765     ("Personne P LIMIT 20 OFFSET 10",
  1777     ("Personne P LIMIT 20 OFFSET 10",
  1766              '''WITH orderedrows AS (
  1778              '''WITH orderedrows AS (
  1870 _L01, _L02, _L03
  1882 _L01, _L02, _L03
  1871 FROM orderedrows WHERE
  1883 FROM orderedrows WHERE
  1872 __RowNumber <= 1
  1884 __RowNumber <= 1
  1873 '''),
  1885 '''),
  1874             ]
  1886             ]
  1875         for t in self._parse(WITH_LIMIT):# + ADVANCED_WITH_LIMIT_OR_ORDERBY):
  1887         for rql, sql in WITH_LIMIT:# + ADVANCED_WITH_LIMIT_OR_ORDERBY):
  1876             yield t
  1888             with self.subTest(rql=rql):
       
  1889                 self._check(rql, sql)
  1877 
  1890 
  1878     def test_cast(self):
  1891     def test_cast(self):
  1879         self._check("Any CAST(String, P) WHERE P is Personne",
  1892         self._check("Any CAST(String, P) WHERE P is Personne",
  1880                     '''SELECT CAST(_P.cw_eid AS nvarchar(max))
  1893                     '''SELECT CAST(_P.cw_eid AS nvarchar(max))
  1881 FROM cw_Personne AS _P''')
  1894 FROM cw_Personne AS _P''')
  1889 FROM cw_CWAttribute AS _X
  1902 FROM cw_CWAttribute AS _X
  1890 GROUP BY DATEPART(YEAR, _X.cw_modification_date),DATEPART(MONTH, _X.cw_modification_date)
  1903 GROUP BY DATEPART(YEAR, _X.cw_modification_date),DATEPART(MONTH, _X.cw_modification_date)
  1891 ORDER BY 1''')
  1904 ORDER BY 1''')
  1892 
  1905 
  1893     def test_today(self):
  1906     def test_today(self):
  1894         for t in self._parse([("Any X WHERE X creation_date TODAY, X is Affaire",
  1907         for rql, sql in [
  1895                         '''SELECT _X.cw_eid
  1908             ("Any X WHERE X creation_date TODAY, X is Affaire",
       
  1909              '''SELECT _X.cw_eid
  1896 FROM cw_Affaire AS _X
  1910 FROM cw_Affaire AS _X
  1897 WHERE DATE(_X.cw_creation_date)=%s''' % self.dbhelper.sql_current_date()),
  1911 WHERE DATE(_X.cw_creation_date)=%s''' % self.dbhelper.sql_current_date()),
  1898 
  1912 
  1899                        ("Personne P where not P datenaiss TODAY",
  1913              ("Personne P where not P datenaiss TODAY",
  1900                         '''SELECT _P.cw_eid
  1914               '''SELECT _P.cw_eid
  1901 FROM cw_Personne AS _P
  1915 FROM cw_Personne AS _P
  1902 WHERE NOT (DATE(_P.cw_datenaiss)=%s)''' % self.dbhelper.sql_current_date()),
  1916 WHERE NOT (DATE(_P.cw_datenaiss)=%s)''' % self.dbhelper.sql_current_date()),
  1903                        ]):
  1917         ]:
  1904             yield t
  1918             with self.subTest(rql=rql):
       
  1919                 self._check(rql, sql)
  1905 
  1920 
  1906 
  1921 
  1907 class SqliteSQLGeneratorTC(PostgresSQLGeneratorTC):
  1922 class SqliteSQLGeneratorTC(PostgresSQLGeneratorTC):
  1908     backend = 'sqlite'
  1923     backend = 'sqlite'
  1909 
  1924 
  1926                     '''SELECT _X.cw_eid
  1941                     '''SELECT _X.cw_eid
  1927 FROM cw_CWUser AS _X
  1942 FROM cw_CWUser AS _X
  1928 WHERE _X.cw_login REGEXP [0-9].*
  1943 WHERE _X.cw_login REGEXP [0-9].*
  1929 ''')
  1944 ''')
  1930 
  1945 
  1931 
       
  1932     def test_union(self):
  1946     def test_union(self):
  1933         for t in self._parse((
  1947         for rql, sql in [
  1934             ('(Any N ORDERBY 1 WHERE X name N, X is State)'
  1948             ('(Any N ORDERBY 1 WHERE X name N, X is State)'
  1935              ' UNION '
  1949              ' UNION '
  1936              '(Any NN ORDERBY 1 WHERE XX name NN, XX is Transition)',
  1950              '(Any NN ORDERBY 1 WHERE XX name NN, XX is Transition)',
  1937              '''SELECT _X.cw_name
  1951              '''SELECT _X.cw_name
  1938 FROM cw_State AS _X
  1952 FROM cw_State AS _X
  1939 ORDER BY 1
  1953 ORDER BY 1
  1940 UNION ALL
  1954 UNION ALL
  1941 SELECT _XX.cw_name
  1955 SELECT _XX.cw_name
  1942 FROM cw_Transition AS _XX
  1956 FROM cw_Transition AS _XX
  1943 ORDER BY 1'''),
  1957 ORDER BY 1'''),
  1944             )):
  1958         ]:
  1945             yield t
  1959             with self.subTest(rql=rql):
  1946 
  1960                 self._check(rql, sql)
  1947 
  1961 
  1948     def test_subquery(self):
  1962     def test_subquery(self):
  1949         # NOTE: no paren around UNION with sqlitebackend
  1963         # NOTE: no paren around UNION with sqlitebackend
  1950         for t in self._parse((
  1964         for rql, sql in [
  1951 
       
  1952             ('Any N ORDERBY 1 WITH N BEING '
  1965             ('Any N ORDERBY 1 WITH N BEING '
  1953              '((Any N WHERE X name N, X is State)'
  1966              '((Any N WHERE X name N, X is State)'
  1954              ' UNION '
  1967              ' UNION '
  1955              '(Any NN WHERE XX name NN, XX is Transition))',
  1968              '(Any NN WHERE XX name NN, XX is Transition))',
  1956              '''SELECT _T0.C0
  1969              '''SELECT _T0.C0
  1986 UNION ALL
  1999 UNION ALL
  1987 SELECT _X.cw_eid AS C0, _X.cw_name AS C1
  2000 SELECT _X.cw_eid AS C0, _X.cw_name AS C1
  1988 FROM cw_Transition AS _X) AS _T0
  2001 FROM cw_Transition AS _X) AS _T0
  1989 GROUP BY _T0.C1
  2002 GROUP BY _T0.C1
  1990 HAVING COUNT(_T0.C0)>1'''),
  2003 HAVING COUNT(_T0.C0)>1'''),
  1991             )):
  2004         ]:
  1992             yield t
  2005             with self.subTest(rql=rql):
       
  2006                 self._check(rql, sql)
  1993 
  2007 
  1994     def test_has_text(self):
  2008     def test_has_text(self):
  1995         for t in self._parse((
  2009         for rql, sql in [
  1996             ('Any X WHERE X has_text "toto tata"',
  2010             ('Any X WHERE X has_text "toto tata"',
  1997              """SELECT DISTINCT appears0.uid
  2011              """SELECT DISTINCT appears0.uid
  1998 FROM appears AS appears0
  2012 FROM appears AS appears0
  1999 WHERE appears0.word_id IN (SELECT word_id FROM word WHERE word in ('toto', 'tata'))"""),
  2013 WHERE appears0.word_id IN (SELECT word_id FROM word WHERE word in ('toto', 'tata'))"""),
  2000 
  2014 
  2035 
  2049 
  2036             ('Any X, FTIRANK(X) WHERE X has_text "toto tata"',
  2050             ('Any X, FTIRANK(X) WHERE X has_text "toto tata"',
  2037              """SELECT DISTINCT appears0.uid, 1.0
  2051              """SELECT DISTINCT appears0.uid, 1.0
  2038 FROM appears AS appears0
  2052 FROM appears AS appears0
  2039 WHERE appears0.word_id IN (SELECT word_id FROM word WHERE word in ('toto', 'tata'))"""),
  2053 WHERE appears0.word_id IN (SELECT word_id FROM word WHERE word in ('toto', 'tata'))"""),
  2040             )):
  2054         ]:
  2041             yield t
  2055             with self.subTest(rql=rql):
       
  2056                 self._check(rql, sql)
  2042 
  2057 
  2043 
  2058 
  2044     def test_or_having_fake_terms_base(self):
  2059     def test_or_having_fake_terms_base(self):
  2045         self._check('Any X WHERE X is CWUser, X creation_date D HAVING YEAR(D) = "2010" OR D = NULL',
  2060         self._check('Any X WHERE X is CWUser, X creation_date D HAVING YEAR(D) = "2010" OR D = NULL',
  2046                     '''SELECT _X.cw_eid
  2061                     '''SELECT _X.cw_eid
  2056 FROM cw_CWAttribute AS _X
  2071 FROM cw_CWAttribute AS _X
  2057 GROUP BY YEAR(_X.cw_modification_date),MONTH(_X.cw_modification_date)
  2072 GROUP BY YEAR(_X.cw_modification_date),MONTH(_X.cw_modification_date)
  2058 ORDER BY 1'''),
  2073 ORDER BY 1'''),
  2059 
  2074 
  2060     def test_today(self):
  2075     def test_today(self):
  2061         for t in self._parse([("Any X WHERE X creation_date TODAY, X is Affaire",
  2076         for rql, sql in [
  2062                         '''SELECT _X.cw_eid
  2077             ("Any X WHERE X creation_date TODAY, X is Affaire",
       
  2078              '''SELECT _X.cw_eid
  2063 FROM cw_Affaire AS _X
  2079 FROM cw_Affaire AS _X
  2064 WHERE DATE(_X.cw_creation_date)=CURRENT_DATE'''),
  2080 WHERE DATE(_X.cw_creation_date)=CURRENT_DATE'''),
  2065 
  2081 
  2066                        ("Personne P where not P datenaiss TODAY",
  2082             ("Personne P where not P datenaiss TODAY",
  2067                         '''SELECT _P.cw_eid
  2083              '''SELECT _P.cw_eid
  2068 FROM cw_Personne AS _P
  2084 FROM cw_Personne AS _P
  2069 WHERE NOT (DATE(_P.cw_datenaiss)=CURRENT_DATE)'''),
  2085 WHERE NOT (DATE(_P.cw_datenaiss)=CURRENT_DATE)'''),
  2070                        ]):
  2086         ]:
  2071             yield t
  2087             with self.subTest(rql=rql):
       
  2088                 self._check(rql, sql)
  2072 
  2089 
  2073 
  2090 
  2074 class MySQLGenerator(PostgresSQLGeneratorTC):
  2091 class MySQLGenerator(PostgresSQLGeneratorTC):
  2075     backend = 'mysql'
  2092     backend = 'mysql'
  2076 
  2093 
  2116                    ('Any X,Y WHERE NOT X created_by Y, X eid 5, Y eid 6',
  2133                    ('Any X,Y WHERE NOT X created_by Y, X eid 5, Y eid 6',
  2117                     '''SELECT 5, 6
  2134                     '''SELECT 5, 6
  2118 FROM (SELECT 1) AS _T
  2135 FROM (SELECT 1) AS _T
  2119 WHERE NOT (EXISTS(SELECT 1 FROM created_by_relation AS rel_created_by0 WHERE rel_created_by0.eid_from=5 AND rel_created_by0.eid_to=6))'''),
  2136 WHERE NOT (EXISTS(SELECT 1 FROM created_by_relation AS rel_created_by0 WHERE rel_created_by0.eid_from=5 AND rel_created_by0.eid_to=6))'''),
  2120                    ]
  2137                    ]
  2121         for t in self._parse(queries):
  2138         for rql, sql in queries:
  2122             yield t
  2139             with self.subTest(rql=rql):
       
  2140                 self._check(rql, sql)
  2123 
  2141 
  2124 
  2142 
  2125     def test_has_text(self):
  2143     def test_has_text(self):
  2126         queries = [
  2144         queries = [
  2127             ('Any X WHERE X has_text "toto tata"',
  2145             ('Any X WHERE X has_text "toto tata"',
  2144 SELECT _X.cw_eid
  2162 SELECT _X.cw_eid
  2145 FROM appears AS appears0, cw_Folder AS _X
  2163 FROM appears AS appears0, cw_Folder AS _X
  2146 WHERE MATCH (appears0.words) AGAINST ('toto tata' IN BOOLEAN MODE) AND appears0.uid=_X.cw_eid AND _X.cw_name=tutu
  2164 WHERE MATCH (appears0.words) AGAINST ('toto tata' IN BOOLEAN MODE) AND appears0.uid=_X.cw_eid AND _X.cw_name=tutu
  2147 """)
  2165 """)
  2148             ]
  2166             ]
  2149         for t in self._parse(queries):
  2167         for rql, sql in queries:
  2150             yield t
  2168             with self.subTest(rql=rql):
       
  2169                 self._check(rql, sql)
  2151 
  2170 
  2152 
  2171 
  2153     def test_ambigous_exists_no_from_clause(self):
  2172     def test_ambigous_exists_no_from_clause(self):
  2154         self._check('Any COUNT(U) WHERE U eid 1, EXISTS (P owned_by U, P is IN (Note, Affaire))',
  2173         self._check('Any COUNT(U) WHERE U eid 1, EXISTS (P owned_by U, P is IN (Note, Affaire))',
  2155                     '''SELECT COUNT(1)
  2174                     '''SELECT COUNT(1)
  2191 FROM cw_CWAttribute AS _X
  2210 FROM cw_CWAttribute AS _X
  2192 GROUP BY EXTRACT(YEAR from _X.cw_modification_date),EXTRACT(MONTH from _X.cw_modification_date)
  2211 GROUP BY EXTRACT(YEAR from _X.cw_modification_date),EXTRACT(MONTH from _X.cw_modification_date)
  2193 ORDER BY 1'''),
  2212 ORDER BY 1'''),
  2194 
  2213 
  2195     def test_today(self):
  2214     def test_today(self):
  2196         for t in self._parse([("Any X WHERE X creation_date TODAY, X is Affaire",
  2215         for rql, sql in [
  2197                         '''SELECT _X.cw_eid
  2216             ("Any X WHERE X creation_date TODAY, X is Affaire",
       
  2217              '''SELECT _X.cw_eid
  2198 FROM cw_Affaire AS _X
  2218 FROM cw_Affaire AS _X
  2199 WHERE DATE(_X.cw_creation_date)=CURRENT_DATE'''),
  2219 WHERE DATE(_X.cw_creation_date)=CURRENT_DATE'''),
  2200 
  2220             ("Personne P where not P datenaiss TODAY",
  2201                        ("Personne P where not P datenaiss TODAY",
  2221              '''SELECT _P.cw_eid
  2202                         '''SELECT _P.cw_eid
       
  2203 FROM cw_Personne AS _P
  2222 FROM cw_Personne AS _P
  2204 WHERE NOT (DATE(_P.cw_datenaiss)=CURRENT_DATE)'''),
  2223 WHERE NOT (DATE(_P.cw_datenaiss)=CURRENT_DATE)'''),
  2205                        ]):
  2224             ]:
  2206             yield t
  2225             with self.subTest(rql=rql):
       
  2226                 self._check(rql, sql)
  2207 
  2227 
  2208 class removeUnsusedSolutionsTC(TestCase):
  2228 class removeUnsusedSolutionsTC(TestCase):
  2209     def test_invariant_not_varying(self):
  2229     def test_invariant_not_varying(self):
  2210         rqlst = mock_object(defined_vars={})
  2230         rqlst = mock_object(defined_vars={})
  2211         rqlst.defined_vars['A'] = mock_object(scope=rqlst, stinfo={}, _q_invariant=True)
  2231         rqlst.defined_vars['A'] = mock_object(scope=rqlst, stinfo={}, _q_invariant=True)