switch from literate to regular haskell source
This commit is contained in:
parent
f51600e0b1
commit
ec8ce0243e
74 changed files with 11498 additions and 10996 deletions
tools/Language/SQL/SimpleSQL
CreateIndex.hsCreateIndex.lhsCustomDialect.hsCustomDialect.lhsEmptyStatement.hsEmptyStatement.lhsErrorMessages.hsFullQueries.hsFullQueries.lhsGroupBy.hsGroupBy.lhsLexerTests.hsLexerTests.lhsMySQL.hsMySQL.lhsOdbc.hsOdbc.lhsOracle.hsOracle.lhsPostgres.hsPostgres.lhsQueryExprComponents.hsQueryExprComponents.lhsQueryExprs.hsQueryExprs.lhsSQL2011AccessControl.hsSQL2011AccessControl.lhsSQL2011Bits.hsSQL2011DataManipulation.hsSQL2011Queries.hsSQL2011Schema.hsScalarExprs.hsScalarExprs.lhsTableRefs.hsTableRefs.lhsTestTypes.hsTestTypes.lhsTests.hsTests.lhsTpch.hsTpch.lhs
17
tools/Language/SQL/SimpleSQL/CreateIndex.hs
Normal file
17
tools/Language/SQL/SimpleSQL/CreateIndex.hs
Normal file
|
@ -0,0 +1,17 @@
|
|||
|
||||
module Language.SQL.SimpleSQL.CreateIndex where
|
||||
|
||||
import Language.SQL.SimpleSQL.Syntax
|
||||
import Language.SQL.SimpleSQL.TestTypes
|
||||
|
||||
createIndexTests :: TestItem
|
||||
createIndexTests = Group "create index tests"
|
||||
[TestStatement ansi2011 "create index a on tbl(c1)"
|
||||
$ CreateIndex False [nm "a"] [nm "tbl"] [nm "c1"]
|
||||
,TestStatement ansi2011 "create index a.b on sc.tbl (c1, c2)"
|
||||
$ CreateIndex False [nm "a", nm "b"] [nm "sc", nm "tbl"] [nm "c1", nm "c2"]
|
||||
,TestStatement ansi2011 "create unique index a on tbl(c1)"
|
||||
$ CreateIndex True [nm "a"] [nm "tbl"] [nm "c1"]
|
||||
]
|
||||
where
|
||||
nm = Name Nothing
|
|
@ -1,17 +0,0 @@
|
|||
|
||||
> module Language.SQL.SimpleSQL.CreateIndex where
|
||||
>
|
||||
> import Language.SQL.SimpleSQL.Syntax
|
||||
> import Language.SQL.SimpleSQL.TestTypes
|
||||
>
|
||||
> createIndexTests :: TestItem
|
||||
> createIndexTests = Group "create index tests"
|
||||
> [TestStatement ansi2011 "create index a on tbl(c1)"
|
||||
> $ CreateIndex False [nm "a"] [nm "tbl"] [nm "c1"]
|
||||
> ,TestStatement ansi2011 "create index a.b on sc.tbl (c1, c2)"
|
||||
> $ CreateIndex False [nm "a", nm "b"] [nm "sc", nm "tbl"] [nm "c1", nm "c2"]
|
||||
> ,TestStatement ansi2011 "create unique index a on tbl(c1)"
|
||||
> $ CreateIndex True [nm "a"] [nm "tbl"] [nm "c1"]
|
||||
> ]
|
||||
> where
|
||||
> nm = Name Nothing
|
27
tools/Language/SQL/SimpleSQL/CustomDialect.hs
Normal file
27
tools/Language/SQL/SimpleSQL/CustomDialect.hs
Normal file
|
@ -0,0 +1,27 @@
|
|||
|
||||
module Language.SQL.SimpleSQL.CustomDialect (customDialectTests) where
|
||||
|
||||
import Language.SQL.SimpleSQL.TestTypes
|
||||
|
||||
customDialectTests :: TestItem
|
||||
customDialectTests = Group "custom dialect tests" (map (uncurry ParseQueryExpr) passTests
|
||||
++ map (uncurry ParseScalarExprFails) failTests )
|
||||
where
|
||||
failTests = [(ansi2011,"SELECT DATE('2000-01-01')")
|
||||
,(ansi2011,"SELECT DATE")
|
||||
,(dateApp,"SELECT DATE")
|
||||
,(dateIden,"SELECT DATE('2000-01-01')")
|
||||
-- show this never being allowed as an alias
|
||||
,(ansi2011,"SELECT a date")
|
||||
,(dateApp,"SELECT a date")
|
||||
,(dateIden,"SELECT a date")
|
||||
]
|
||||
passTests = [(ansi2011,"SELECT a b")
|
||||
,(noDateKeyword,"SELECT DATE('2000-01-01')")
|
||||
,(noDateKeyword,"SELECT DATE")
|
||||
,(dateApp,"SELECT DATE('2000-01-01')")
|
||||
,(dateIden,"SELECT DATE")
|
||||
]
|
||||
noDateKeyword = ansi2011 {diKeywords = filter (/="date") (diKeywords ansi2011)}
|
||||
dateIden = ansi2011 {diIdentifierKeywords = "date" : diIdentifierKeywords ansi2011}
|
||||
dateApp = ansi2011 {diAppKeywords = "date" : diAppKeywords ansi2011}
|
|
@ -1,27 +0,0 @@
|
|||
|
||||
> module Language.SQL.SimpleSQL.CustomDialect (customDialectTests) where
|
||||
|
||||
> import Language.SQL.SimpleSQL.TestTypes
|
||||
|
||||
> customDialectTests :: TestItem
|
||||
> customDialectTests = Group "custom dialect tests" (map (uncurry ParseQueryExpr) passTests
|
||||
> ++ map (uncurry ParseScalarExprFails) failTests )
|
||||
> where
|
||||
> failTests = [(ansi2011,"SELECT DATE('2000-01-01')")
|
||||
> ,(ansi2011,"SELECT DATE")
|
||||
> ,(dateApp,"SELECT DATE")
|
||||
> ,(dateIden,"SELECT DATE('2000-01-01')")
|
||||
> -- show this never being allowed as an alias
|
||||
> ,(ansi2011,"SELECT a date")
|
||||
> ,(dateApp,"SELECT a date")
|
||||
> ,(dateIden,"SELECT a date")
|
||||
> ]
|
||||
> passTests = [(ansi2011,"SELECT a b")
|
||||
> ,(noDateKeyword,"SELECT DATE('2000-01-01')")
|
||||
> ,(noDateKeyword,"SELECT DATE")
|
||||
> ,(dateApp,"SELECT DATE('2000-01-01')")
|
||||
> ,(dateIden,"SELECT DATE")
|
||||
> ]
|
||||
> noDateKeyword = ansi2011 {diKeywords = filter (/="date") (diKeywords ansi2011)}
|
||||
> dateIden = ansi2011 {diIdentifierKeywords = "date" : diIdentifierKeywords ansi2011}
|
||||
> dateApp = ansi2011 {diAppKeywords = "date" : diAppKeywords ansi2011}
|
20
tools/Language/SQL/SimpleSQL/EmptyStatement.hs
Normal file
20
tools/Language/SQL/SimpleSQL/EmptyStatement.hs
Normal file
|
@ -0,0 +1,20 @@
|
|||
module Language.SQL.SimpleSQL.EmptyStatement where
|
||||
|
||||
import Language.SQL.SimpleSQL.Syntax
|
||||
import Language.SQL.SimpleSQL.TestTypes
|
||||
|
||||
emptyStatementTests :: TestItem
|
||||
emptyStatementTests = Group "empty statement"
|
||||
[ TestStatement ansi2011 ";" EmptyStatement
|
||||
, TestStatements ansi2011 ";" [EmptyStatement]
|
||||
, TestStatements ansi2011 ";;" [EmptyStatement, EmptyStatement]
|
||||
, TestStatements ansi2011 ";;;" [EmptyStatement, EmptyStatement, EmptyStatement]
|
||||
, TestStatement ansi2011 "/* comment */ ;" EmptyStatement
|
||||
, TestStatements ansi2011 "" []
|
||||
, TestStatements ansi2011 "/* comment */" []
|
||||
, TestStatements ansi2011 "/* comment */ ;" [EmptyStatement]
|
||||
, TestStatements ansi2011 "/* comment */ ; /* comment */ ;"
|
||||
[EmptyStatement, EmptyStatement]
|
||||
, TestStatements ansi2011 "/* comment */ ; /* comment */ ; /* comment */ ;"
|
||||
[EmptyStatement, EmptyStatement, EmptyStatement]
|
||||
]
|
|
@ -1,20 +0,0 @@
|
|||
> module Language.SQL.SimpleSQL.EmptyStatement where
|
||||
>
|
||||
> import Language.SQL.SimpleSQL.Syntax
|
||||
> import Language.SQL.SimpleSQL.TestTypes
|
||||
>
|
||||
> emptyStatementTests :: TestItem
|
||||
> emptyStatementTests = Group "empty statement"
|
||||
> [ TestStatement ansi2011 ";" EmptyStatement
|
||||
> , TestStatements ansi2011 ";" [EmptyStatement]
|
||||
> , TestStatements ansi2011 ";;" [EmptyStatement, EmptyStatement]
|
||||
> , TestStatements ansi2011 ";;;" [EmptyStatement, EmptyStatement, EmptyStatement]
|
||||
> , TestStatement ansi2011 "/* comment */ ;" EmptyStatement
|
||||
> , TestStatements ansi2011 "" []
|
||||
> , TestStatements ansi2011 "/* comment */" []
|
||||
> , TestStatements ansi2011 "/* comment */ ;" [EmptyStatement]
|
||||
> , TestStatements ansi2011 "/* comment */ ; /* comment */ ;"
|
||||
> [EmptyStatement, EmptyStatement]
|
||||
> , TestStatements ansi2011 "/* comment */ ; /* comment */ ; /* comment */ ;"
|
||||
> [EmptyStatement, EmptyStatement, EmptyStatement]
|
||||
> ]
|
|
@ -1,4 +1,5 @@
|
|||
|
||||
{-
|
||||
Want to work on the error messages. Ultimately, parsec won't give the
|
||||
best error message for a parser combinator library in haskell. Should
|
||||
check out the alternatives such as polyparse and uu-parsing.
|
||||
|
@ -51,100 +52,105 @@ review the error messages.
|
|||
|
||||
Then, create some query expressions to focus on the non value
|
||||
expression parts.
|
||||
-}
|
||||
|
||||
|
||||
> module Language.SQL.SimpleSQL.ErrorMessages where
|
||||
module Language.SQL.SimpleSQL.ErrorMessages where
|
||||
|
||||
> {-import Language.SQL.SimpleSQL.Parser
|
||||
> import Data.List
|
||||
> import Text.Groom
|
||||
{-import Language.SQL.SimpleSQL.Parser
|
||||
import Data.List
|
||||
import Text.Groom
|
||||
|
||||
> valueExpressions :: [String]
|
||||
> valueExpressions =
|
||||
> ["10.."
|
||||
> ,"..10"
|
||||
> ,"10e1e2"
|
||||
> ,"10e--3"
|
||||
> ,"1a"
|
||||
> ,"1%"
|
||||
valueExpressions :: [String]
|
||||
valueExpressions =
|
||||
["10.."
|
||||
,"..10"
|
||||
,"10e1e2"
|
||||
,"10e--3"
|
||||
,"1a"
|
||||
,"1%"
|
||||
|
||||
> ,"'b'ad'"
|
||||
> ,"'bad"
|
||||
> ,"bad'"
|
||||
,"'b'ad'"
|
||||
,"'bad"
|
||||
,"bad'"
|
||||
|
||||
> ,"interval '5' ay"
|
||||
> ,"interval '5' day (4.4)"
|
||||
> ,"interval '5' day (a)"
|
||||
> ,"intervala '5' day"
|
||||
> ,"interval 'x' day (3"
|
||||
> ,"interval 'x' day 3)"
|
||||
,"interval '5' ay"
|
||||
,"interval '5' day (4.4)"
|
||||
,"interval '5' day (a)"
|
||||
,"intervala '5' day"
|
||||
,"interval 'x' day (3"
|
||||
,"interval 'x' day 3)"
|
||||
|
||||
> ,"1badiden"
|
||||
> ,"$"
|
||||
> ,"!"
|
||||
> ,"*.a"
|
||||
,"1badiden"
|
||||
,"$"
|
||||
,"!"
|
||||
,"*.a"
|
||||
|
||||
> ,"??"
|
||||
> ,"3?"
|
||||
> ,"?a"
|
||||
,"??"
|
||||
,"3?"
|
||||
,"?a"
|
||||
|
||||
> ,"row"
|
||||
> ,"row 1,2"
|
||||
> ,"row(1,2"
|
||||
> ,"row 1,2)"
|
||||
> ,"row(1 2)"
|
||||
,"row"
|
||||
,"row 1,2"
|
||||
,"row(1,2"
|
||||
,"row 1,2)"
|
||||
,"row(1 2)"
|
||||
|
||||
> ,"f("
|
||||
> ,"f)"
|
||||
,"f("
|
||||
,"f)"
|
||||
|
||||
> ,"f(a"
|
||||
> ,"f a)"
|
||||
> ,"f(a b)"
|
||||
,"f(a"
|
||||
,"f a)"
|
||||
,"f(a b)"
|
||||
|
||||
{-
|
||||
TODO:
|
||||
case
|
||||
operators
|
||||
-}
|
||||
|
||||
> ,"a + (b + c"
|
||||
,"a + (b + c"
|
||||
|
||||
{-
|
||||
casts
|
||||
subqueries: + whole set of parentheses use
|
||||
in list
|
||||
'keyword' functions
|
||||
aggregates
|
||||
window functions
|
||||
-}
|
||||
|
||||
|
||||
> ]
|
||||
]
|
||||
|
||||
> queryExpressions :: [String]
|
||||
> queryExpressions =
|
||||
> map sl1 valueExpressions
|
||||
> ++ map sl2 valueExpressions
|
||||
> ++ map sl3 valueExpressions
|
||||
> ++
|
||||
> ["select a from t inner jin u"]
|
||||
> where
|
||||
> sl1 x = "select " ++ x ++ " from t"
|
||||
> sl2 x = "select " ++ x ++ ", y from t"
|
||||
> sl3 x = "select " ++ x ++ " fom t"
|
||||
queryExpressions :: [String]
|
||||
queryExpressions =
|
||||
map sl1 valueExpressions
|
||||
++ map sl2 valueExpressions
|
||||
++ map sl3 valueExpressions
|
||||
++
|
||||
["select a from t inner jin u"]
|
||||
where
|
||||
sl1 x = "select " ++ x ++ " from t"
|
||||
sl2 x = "select " ++ x ++ ", y from t"
|
||||
sl3 x = "select " ++ x ++ " fom t"
|
||||
|
||||
> valExprs :: [String] -> [(String,String)]
|
||||
> valExprs = map parseOne
|
||||
> where
|
||||
> parseOne x = let p = parseValueExpr "" Nothing x
|
||||
> in (x,either peFormattedError (\x -> "ERROR: parsed ok " ++ groom x) p)
|
||||
valExprs :: [String] -> [(String,String)]
|
||||
valExprs = map parseOne
|
||||
where
|
||||
parseOne x = let p = parseValueExpr "" Nothing x
|
||||
in (x,either peFormattedError (\x -> "ERROR: parsed ok " ++ groom x) p)
|
||||
|
||||
|
||||
> queryExprs :: [String] -> [(String,String)]
|
||||
> queryExprs = map parseOne
|
||||
> where
|
||||
> parseOne x = let p = parseQueryExpr "" Nothing x
|
||||
> in (x,either peFormattedError (\x -> "ERROR: parsed ok " ++ groom x) p)
|
||||
queryExprs :: [String] -> [(String,String)]
|
||||
queryExprs = map parseOne
|
||||
where
|
||||
parseOne x = let p = parseQueryExpr "" Nothing x
|
||||
in (x,either peFormattedError (\x -> "ERROR: parsed ok " ++ groom x) p)
|
||||
|
||||
|
||||
> pExprs :: [String] -> [String] -> String
|
||||
> pExprs x y =
|
||||
> let l = valExprs x ++ queryExprs y
|
||||
> in intercalate "\n\n\n\n" $ map (\(a,b) -> a ++ "\n" ++ b) l
|
||||
> -}
|
||||
pExprs :: [String] -> [String] -> String
|
||||
pExprs x y =
|
||||
let l = valExprs x ++ queryExprs y
|
||||
in intercalate "\n\n\n\n" $ map (\(a,b) -> a ++ "\n" ++ b) l
|
||||
-}
|
39
tools/Language/SQL/SimpleSQL/FullQueries.hs
Normal file
39
tools/Language/SQL/SimpleSQL/FullQueries.hs
Normal file
|
@ -0,0 +1,39 @@
|
|||
|
||||
-- Some tests for parsing full queries.
|
||||
|
||||
module Language.SQL.SimpleSQL.FullQueries (fullQueriesTests) where
|
||||
|
||||
import Language.SQL.SimpleSQL.TestTypes
|
||||
import Language.SQL.SimpleSQL.Syntax
|
||||
|
||||
|
||||
fullQueriesTests :: TestItem
|
||||
fullQueriesTests = Group "queries" $ map (uncurry (TestQueryExpr ansi2011))
|
||||
[("select count(*) from t"
|
||||
,makeSelect
|
||||
{qeSelectList = [(App [Name Nothing "count"] [Star], Nothing)]
|
||||
,qeFrom = [TRSimple [Name Nothing "t"]]
|
||||
}
|
||||
)
|
||||
|
||||
,("select a, sum(c+d) as s\n\
|
||||
\ from t,u\n\
|
||||
\ where a > 5\n\
|
||||
\ group by a\n\
|
||||
\ having count(1) > 5\n\
|
||||
\ order by s"
|
||||
,makeSelect
|
||||
{qeSelectList = [(Iden [Name Nothing "a"], Nothing)
|
||||
,(App [Name Nothing "sum"]
|
||||
[BinOp (Iden [Name Nothing "c"])
|
||||
[Name Nothing "+"] (Iden [Name Nothing "d"])]
|
||||
,Just $ Name Nothing "s")]
|
||||
,qeFrom = [TRSimple [Name Nothing "t"], TRSimple [Name Nothing "u"]]
|
||||
,qeWhere = Just $ BinOp (Iden [Name Nothing "a"]) [Name Nothing ">"] (NumLit "5")
|
||||
,qeGroupBy = [SimpleGroup $ Iden [Name Nothing "a"]]
|
||||
,qeHaving = Just $ BinOp (App [Name Nothing "count"] [NumLit "1"])
|
||||
[Name Nothing ">"] (NumLit "5")
|
||||
,qeOrderBy = [SortSpec (Iden [Name Nothing "s"]) DirDefault NullsOrderDefault]
|
||||
}
|
||||
)
|
||||
]
|
|
@ -1,39 +0,0 @@
|
|||
|
||||
Some tests for parsing full queries.
|
||||
|
||||
> module Language.SQL.SimpleSQL.FullQueries (fullQueriesTests) where
|
||||
|
||||
> import Language.SQL.SimpleSQL.TestTypes
|
||||
> import Language.SQL.SimpleSQL.Syntax
|
||||
|
||||
|
||||
> fullQueriesTests :: TestItem
|
||||
> fullQueriesTests = Group "queries" $ map (uncurry (TestQueryExpr ansi2011))
|
||||
> [("select count(*) from t"
|
||||
> ,makeSelect
|
||||
> {qeSelectList = [(App [Name Nothing "count"] [Star], Nothing)]
|
||||
> ,qeFrom = [TRSimple [Name Nothing "t"]]
|
||||
> }
|
||||
> )
|
||||
|
||||
> ,("select a, sum(c+d) as s\n\
|
||||
> \ from t,u\n\
|
||||
> \ where a > 5\n\
|
||||
> \ group by a\n\
|
||||
> \ having count(1) > 5\n\
|
||||
> \ order by s"
|
||||
> ,makeSelect
|
||||
> {qeSelectList = [(Iden [Name Nothing "a"], Nothing)
|
||||
> ,(App [Name Nothing "sum"]
|
||||
> [BinOp (Iden [Name Nothing "c"])
|
||||
> [Name Nothing "+"] (Iden [Name Nothing "d"])]
|
||||
> ,Just $ Name Nothing "s")]
|
||||
> ,qeFrom = [TRSimple [Name Nothing "t"], TRSimple [Name Nothing "u"]]
|
||||
> ,qeWhere = Just $ BinOp (Iden [Name Nothing "a"]) [Name Nothing ">"] (NumLit "5")
|
||||
> ,qeGroupBy = [SimpleGroup $ Iden [Name Nothing "a"]]
|
||||
> ,qeHaving = Just $ BinOp (App [Name Nothing "count"] [NumLit "1"])
|
||||
> [Name Nothing ">"] (NumLit "5")
|
||||
> ,qeOrderBy = [SortSpec (Iden [Name Nothing "s"]) DirDefault NullsOrderDefault]
|
||||
> }
|
||||
> )
|
||||
> ]
|
237
tools/Language/SQL/SimpleSQL/GroupBy.hs
Normal file
237
tools/Language/SQL/SimpleSQL/GroupBy.hs
Normal file
|
@ -0,0 +1,237 @@
|
|||
|
||||
-- Here are the tests for the group by component of query exprs
|
||||
|
||||
module Language.SQL.SimpleSQL.GroupBy (groupByTests) where
|
||||
|
||||
import Language.SQL.SimpleSQL.TestTypes
|
||||
import Language.SQL.SimpleSQL.Syntax
|
||||
|
||||
|
||||
groupByTests :: TestItem
|
||||
groupByTests = Group "groupByTests"
|
||||
[simpleGroupBy
|
||||
,newGroupBy
|
||||
,randomGroupBy
|
||||
]
|
||||
|
||||
simpleGroupBy :: TestItem
|
||||
simpleGroupBy = Group "simpleGroupBy" $ map (uncurry (TestQueryExpr ansi2011))
|
||||
[("select a,sum(b) from t group by a"
|
||||
,makeSelect {qeSelectList = [(Iden [Name Nothing "a"],Nothing)
|
||||
,(App [Name Nothing "sum"] [Iden [Name Nothing "b"]],Nothing)]
|
||||
,qeFrom = [TRSimple [Name Nothing "t"]]
|
||||
,qeGroupBy = [SimpleGroup $ Iden [Name Nothing "a"]]
|
||||
})
|
||||
|
||||
,("select a,b,sum(c) from t group by a,b"
|
||||
,makeSelect {qeSelectList = [(Iden [Name Nothing "a"],Nothing)
|
||||
,(Iden [Name Nothing "b"],Nothing)
|
||||
,(App [Name Nothing "sum"] [Iden [Name Nothing "c"]],Nothing)]
|
||||
,qeFrom = [TRSimple [Name Nothing "t"]]
|
||||
,qeGroupBy = [SimpleGroup $ Iden [Name Nothing "a"]
|
||||
,SimpleGroup $ Iden [Name Nothing "b"]]
|
||||
})
|
||||
]
|
||||
|
||||
{-
|
||||
test the new group by (), grouping sets, cube and rollup syntax (not
|
||||
sure which sql version they were introduced, 1999 or 2003 I think).
|
||||
-}
|
||||
|
||||
newGroupBy :: TestItem
|
||||
newGroupBy = Group "newGroupBy" $ map (uncurry (TestQueryExpr ansi2011))
|
||||
[("select * from t group by ()", ms [GroupingParens []])
|
||||
,("select * from t group by grouping sets ((), (a))"
|
||||
,ms [GroupingSets [GroupingParens []
|
||||
,GroupingParens [SimpleGroup $ Iden [Name Nothing "a"]]]])
|
||||
,("select * from t group by cube(a,b)"
|
||||
,ms [Cube [SimpleGroup $ Iden [Name Nothing "a"], SimpleGroup $ Iden [Name Nothing "b"]]])
|
||||
,("select * from t group by rollup(a,b)"
|
||||
,ms [Rollup [SimpleGroup $ Iden [Name Nothing "a"], SimpleGroup $ Iden [Name Nothing "b"]]])
|
||||
]
|
||||
where
|
||||
ms g = makeSelect {qeSelectList = [(Star,Nothing)]
|
||||
,qeFrom = [TRSimple [Name Nothing "t"]]
|
||||
,qeGroupBy = g}
|
||||
|
||||
randomGroupBy :: TestItem
|
||||
randomGroupBy = Group "randomGroupBy" $ map (ParseQueryExpr ansi2011)
|
||||
["select * from t GROUP BY a"
|
||||
,"select * from t GROUP BY GROUPING SETS((a))"
|
||||
,"select * from t GROUP BY a,b,c"
|
||||
,"select * from t GROUP BY GROUPING SETS((a,b,c))"
|
||||
,"select * from t GROUP BY ROLLUP(a,b)"
|
||||
,"select * from t GROUP BY GROUPING SETS((a,b),\n\
|
||||
\(a),\n\
|
||||
\() )"
|
||||
,"select * from t GROUP BY ROLLUP(b,a)"
|
||||
,"select * from t GROUP BY GROUPING SETS((b,a),\n\
|
||||
\(b),\n\
|
||||
\() )"
|
||||
,"select * from t GROUP BY CUBE(a,b,c)"
|
||||
,"select * from t GROUP BY GROUPING SETS((a,b,c),\n\
|
||||
\(a,b),\n\
|
||||
\(a,c),\n\
|
||||
\(b,c),\n\
|
||||
\(a),\n\
|
||||
\(b),\n\
|
||||
\(c),\n\
|
||||
\() )"
|
||||
,"select * from t GROUP BY ROLLUP(Province, County, City)"
|
||||
,"select * from t GROUP BY ROLLUP(Province, (County, City))"
|
||||
,"select * from t GROUP BY ROLLUP(Province, (County, City))"
|
||||
,"select * from t GROUP BY GROUPING SETS((Province, County, City),\n\
|
||||
\(Province),\n\
|
||||
\() )"
|
||||
,"select * from t GROUP BY GROUPING SETS((Province, County, City),\n\
|
||||
\(Province, County),\n\
|
||||
\(Province),\n\
|
||||
\() )"
|
||||
,"select * from t GROUP BY a, ROLLUP(b,c)"
|
||||
,"select * from t GROUP BY GROUPING SETS((a,b,c),\n\
|
||||
\(a,b),\n\
|
||||
\(a) )"
|
||||
,"select * from t GROUP BY a, b, ROLLUP(c,d)"
|
||||
,"select * from t GROUP BY GROUPING SETS((a,b,c,d),\n\
|
||||
\(a,b,c),\n\
|
||||
\(a,b) )"
|
||||
,"select * from t GROUP BY ROLLUP(a), ROLLUP(b,c)"
|
||||
,"select * from t GROUP BY GROUPING SETS((a,b,c),\n\
|
||||
\(a,b),\n\
|
||||
\(a),\n\
|
||||
\(b,c),\n\
|
||||
\(b),\n\
|
||||
\() )"
|
||||
,"select * from t GROUP BY ROLLUP(a), CUBE(b,c)"
|
||||
,"select * from t GROUP BY GROUPING SETS((a,b,c),\n\
|
||||
\(a,b),\n\
|
||||
\(a,c),\n\
|
||||
\(a),\n\
|
||||
\(b,c),\n\
|
||||
\(b),\n\
|
||||
\(c),\n\
|
||||
\() )"
|
||||
,"select * from t GROUP BY CUBE(a,b), ROLLUP(c,d)"
|
||||
,"select * from t GROUP BY GROUPING SETS((a,b,c,d),\n\
|
||||
\(a,b,c),\n\
|
||||
\(a,b),\n\
|
||||
\(a,c,d),\n\
|
||||
\(a,c),\n\
|
||||
\(a),\n\
|
||||
\(b,c,d),\n\
|
||||
\(b,c),\n\
|
||||
\(b),\n\
|
||||
\(c,d),\n\
|
||||
\(c),\n\
|
||||
\() )"
|
||||
,"select * from t GROUP BY a, ROLLUP(a,b)"
|
||||
,"select * from t GROUP BY GROUPING SETS((a,b),\n\
|
||||
\(a) )"
|
||||
,"select * from t GROUP BY Region,\n\
|
||||
\ROLLUP(Sales_Person, WEEK(Sales_Date)),\n\
|
||||
\CUBE(YEAR(Sales_Date), MONTH (Sales_Date))"
|
||||
,"select * from t GROUP BY ROLLUP (Region, Sales_Person, WEEK(Sales_Date),\n\
|
||||
\YEAR(Sales_Date), MONTH(Sales_Date) )"
|
||||
|
||||
,"SELECT WEEK(SALES_DATE) AS WEEK,\n\
|
||||
\DAYOFWEEK(SALES_DATE) AS DAY_WEEK,\n\
|
||||
\SALES_PERSON, SUM(SALES) AS UNITS_SOLD\n\
|
||||
\FROM SALES\n\
|
||||
\WHERE WEEK(SALES_DATE) = 13\n\
|
||||
\GROUP BY WEEK(SALES_DATE), DAYOFWEEK(SALES_DATE), SALES_PERSON\n\
|
||||
\ORDER BY WEEK, DAY_WEEK, SALES_PERSON"
|
||||
|
||||
,"SELECT WEEK(SALES_DATE) AS WEEK,\n\
|
||||
\DAYOFWEEK(SALES_DATE) AS DAY_WEEK,\n\
|
||||
\SALES_PERSON, SUM(SALES) AS UNITS_SOLD\n\
|
||||
\FROM SALES\n\
|
||||
\WHERE WEEK(SALES_DATE) = 13\n\
|
||||
\GROUP BY GROUPING SETS ( (WEEK(SALES_DATE), SALES_PERSON),\n\
|
||||
\(DAYOFWEEK(SALES_DATE), SALES_PERSON))\n\
|
||||
\ORDER BY WEEK, DAY_WEEK, SALES_PERSON"
|
||||
|
||||
,"SELECT WEEK(SALES_DATE) AS WEEK,\n\
|
||||
\DAYOFWEEK(SALES_DATE) AS DAY_WEEK,\n\
|
||||
\SALES_PERSON, SUM(SALES) AS UNITS_SOLD\n\
|
||||
\FROM SALES\n\
|
||||
\WHERE WEEK(SALES_DATE) = 13\n\
|
||||
\GROUP BY ROLLUP ( WEEK(SALES_DATE), DAYOFWEEK(SALES_DATE), SALES_PERSON )\n\
|
||||
\ORDER BY WEEK, DAY_WEEK, SALES_PERSON"
|
||||
|
||||
,"SELECT WEEK(SALES_DATE) AS WEEK,\n\
|
||||
\DAYOFWEEK(SALES_DATE) AS DAY_WEEK,\n\
|
||||
\SALES_PERSON, SUM(SALES) AS UNITS_SOLD\n\
|
||||
\FROM SALES\n\
|
||||
\WHERE WEEK(SALES_DATE) = 13\n\
|
||||
\GROUP BY CUBE ( WEEK(SALES_DATE), DAYOFWEEK(SALES_DATE), SALES_PERSON )\n\
|
||||
\ORDER BY WEEK, DAY_WEEK, SALES_PERSON"
|
||||
|
||||
,"SELECT SALES_PERSON,\n\
|
||||
\MONTH(SALES_DATE) AS MONTH,\n\
|
||||
\SUM(SALES) AS UNITS_SOLD\n\
|
||||
\FROM SALES\n\
|
||||
\GROUP BY GROUPING SETS ( (SALES_PERSON, MONTH(SALES_DATE)),\n\
|
||||
\()\n\
|
||||
\)\n\
|
||||
\ORDER BY SALES_PERSON, MONTH"
|
||||
|
||||
,"SELECT WEEK(SALES_DATE) AS WEEK,\n\
|
||||
\DAYOFWEEK(SALES_DATE) AS DAY_WEEK,\n\
|
||||
\SUM(SALES) AS UNITS_SOLD\n\
|
||||
\FROM SALES\n\
|
||||
\GROUP BY ROLLUP ( WEEK(SALES_DATE), DAYOFWEEK(SALES_DATE) )\n\
|
||||
\ORDER BY WEEK, DAY_WEEK"
|
||||
|
||||
,"SELECT MONTH(SALES_DATE) AS MONTH,\n\
|
||||
\REGION,\n\
|
||||
\SUM(SALES) AS UNITS_SOLD\n\
|
||||
\FROM SALES\n\
|
||||
\GROUP BY ROLLUP ( MONTH(SALES_DATE), REGION )\n\
|
||||
\ORDER BY MONTH, REGION"
|
||||
|
||||
,"SELECT WEEK(SALES_DATE) AS WEEK,\n\
|
||||
\DAYOFWEEK(SALES_DATE) AS DAY_WEEK,\n\
|
||||
\MONTH(SALES_DATE) AS MONTH,\n\
|
||||
\REGION,\n\
|
||||
\SUM(SALES) AS UNITS_SOLD\n\
|
||||
\FROM SALES\n\
|
||||
\GROUP BY GROUPING SETS ( ROLLUP( WEEK(SALES_DATE), DAYOFWEEK(SALES_DATE) ),\n\
|
||||
\ROLLUP( MONTH(SALES_DATE), REGION ) )\n\
|
||||
\ORDER BY WEEK, DAY_WEEK, MONTH, REGION"
|
||||
|
||||
,"SELECT R1, R2,\n\
|
||||
\WEEK(SALES_DATE) AS WEEK,\n\
|
||||
\DAYOFWEEK(SALES_DATE) AS DAY_WEEK,\n\
|
||||
\MONTH(SALES_DATE) AS MONTH,\n\
|
||||
\REGION, SUM(SALES) AS UNITS_SOLD\n\
|
||||
\FROM SALES,(VALUES('GROUP 1','GROUP 2')) AS X(R1,R2)\n\
|
||||
\GROUP BY GROUPING SETS ((R1, ROLLUP(WEEK(SALES_DATE),\n\
|
||||
\DAYOFWEEK(SALES_DATE))),\n\
|
||||
\(R2,ROLLUP( MONTH(SALES_DATE), REGION ) ))\n\
|
||||
\ORDER BY WEEK, DAY_WEEK, MONTH, REGION"
|
||||
|
||||
{-,"SELECT COALESCE(R1,R2) AS GROUP,\n\
|
||||
\WEEK(SALES_DATE) AS WEEK,\n\
|
||||
\DAYOFWEEK(SALES_DATE) AS DAY_WEEK,\n\
|
||||
\MONTH(SALES_DATE) AS MONTH,\n\
|
||||
\REGION, SUM(SALES) AS UNITS_SOLD\n\
|
||||
\FROM SALES,(VALUES('GROUP 1','GROUP 2')) AS X(R1,R2)\n\
|
||||
\GROUP BY GROUPING SETS ((R1, ROLLUP(WEEK(SALES_DATE),\n\
|
||||
\DAYOFWEEK(SALES_DATE))),\n\
|
||||
\(R2,ROLLUP( MONTH(SALES_DATE), REGION ) ))\n\
|
||||
\ORDER BY GROUP, WEEK, DAY_WEEK, MONTH, REGION"-}
|
||||
-- as group - needs more subtle keyword blacklisting
|
||||
|
||||
-- decimal as a function not allowed due to the reserved keyword
|
||||
-- handling: todo, review if this is ansi standard function or
|
||||
-- if there are places where reserved keywords can still be used
|
||||
,"SELECT MONTH(SALES_DATE) AS MONTH,\n\
|
||||
\REGION,\n\
|
||||
\SUM(SALES) AS UNITS_SOLD,\n\
|
||||
\MAX(SALES) AS BEST_SALE,\n\
|
||||
\CAST(ROUND(AVG(DECIMALx(SALES)),2) AS DECIMAL(5,2)) AS AVG_UNITS_SOLD\n\
|
||||
\FROM SALES\n\
|
||||
\GROUP BY CUBE(MONTH(SALES_DATE),REGION)\n\
|
||||
\ORDER BY MONTH, REGION"
|
||||
|
||||
]
|
|
@ -1,235 +0,0 @@
|
|||
|
||||
Here are the tests for the group by component of query exprs
|
||||
|
||||
> module Language.SQL.SimpleSQL.GroupBy (groupByTests) where
|
||||
|
||||
> import Language.SQL.SimpleSQL.TestTypes
|
||||
> import Language.SQL.SimpleSQL.Syntax
|
||||
|
||||
|
||||
> groupByTests :: TestItem
|
||||
> groupByTests = Group "groupByTests"
|
||||
> [simpleGroupBy
|
||||
> ,newGroupBy
|
||||
> ,randomGroupBy
|
||||
> ]
|
||||
|
||||
> simpleGroupBy :: TestItem
|
||||
> simpleGroupBy = Group "simpleGroupBy" $ map (uncurry (TestQueryExpr ansi2011))
|
||||
> [("select a,sum(b) from t group by a"
|
||||
> ,makeSelect {qeSelectList = [(Iden [Name Nothing "a"],Nothing)
|
||||
> ,(App [Name Nothing "sum"] [Iden [Name Nothing "b"]],Nothing)]
|
||||
> ,qeFrom = [TRSimple [Name Nothing "t"]]
|
||||
> ,qeGroupBy = [SimpleGroup $ Iden [Name Nothing "a"]]
|
||||
> })
|
||||
|
||||
> ,("select a,b,sum(c) from t group by a,b"
|
||||
> ,makeSelect {qeSelectList = [(Iden [Name Nothing "a"],Nothing)
|
||||
> ,(Iden [Name Nothing "b"],Nothing)
|
||||
> ,(App [Name Nothing "sum"] [Iden [Name Nothing "c"]],Nothing)]
|
||||
> ,qeFrom = [TRSimple [Name Nothing "t"]]
|
||||
> ,qeGroupBy = [SimpleGroup $ Iden [Name Nothing "a"]
|
||||
> ,SimpleGroup $ Iden [Name Nothing "b"]]
|
||||
> })
|
||||
> ]
|
||||
|
||||
test the new group by (), grouping sets, cube and rollup syntax (not
|
||||
sure which sql version they were introduced, 1999 or 2003 I think).
|
||||
|
||||
> newGroupBy :: TestItem
|
||||
> newGroupBy = Group "newGroupBy" $ map (uncurry (TestQueryExpr ansi2011))
|
||||
> [("select * from t group by ()", ms [GroupingParens []])
|
||||
> ,("select * from t group by grouping sets ((), (a))"
|
||||
> ,ms [GroupingSets [GroupingParens []
|
||||
> ,GroupingParens [SimpleGroup $ Iden [Name Nothing "a"]]]])
|
||||
> ,("select * from t group by cube(a,b)"
|
||||
> ,ms [Cube [SimpleGroup $ Iden [Name Nothing "a"], SimpleGroup $ Iden [Name Nothing "b"]]])
|
||||
> ,("select * from t group by rollup(a,b)"
|
||||
> ,ms [Rollup [SimpleGroup $ Iden [Name Nothing "a"], SimpleGroup $ Iden [Name Nothing "b"]]])
|
||||
> ]
|
||||
> where
|
||||
> ms g = makeSelect {qeSelectList = [(Star,Nothing)]
|
||||
> ,qeFrom = [TRSimple [Name Nothing "t"]]
|
||||
> ,qeGroupBy = g}
|
||||
|
||||
> randomGroupBy :: TestItem
|
||||
> randomGroupBy = Group "randomGroupBy" $ map (ParseQueryExpr ansi2011)
|
||||
> ["select * from t GROUP BY a"
|
||||
> ,"select * from t GROUP BY GROUPING SETS((a))"
|
||||
> ,"select * from t GROUP BY a,b,c"
|
||||
> ,"select * from t GROUP BY GROUPING SETS((a,b,c))"
|
||||
> ,"select * from t GROUP BY ROLLUP(a,b)"
|
||||
> ,"select * from t GROUP BY GROUPING SETS((a,b),\n\
|
||||
> \(a),\n\
|
||||
> \() )"
|
||||
> ,"select * from t GROUP BY ROLLUP(b,a)"
|
||||
> ,"select * from t GROUP BY GROUPING SETS((b,a),\n\
|
||||
> \(b),\n\
|
||||
> \() )"
|
||||
> ,"select * from t GROUP BY CUBE(a,b,c)"
|
||||
> ,"select * from t GROUP BY GROUPING SETS((a,b,c),\n\
|
||||
> \(a,b),\n\
|
||||
> \(a,c),\n\
|
||||
> \(b,c),\n\
|
||||
> \(a),\n\
|
||||
> \(b),\n\
|
||||
> \(c),\n\
|
||||
> \() )"
|
||||
> ,"select * from t GROUP BY ROLLUP(Province, County, City)"
|
||||
> ,"select * from t GROUP BY ROLLUP(Province, (County, City))"
|
||||
> ,"select * from t GROUP BY ROLLUP(Province, (County, City))"
|
||||
> ,"select * from t GROUP BY GROUPING SETS((Province, County, City),\n\
|
||||
> \(Province),\n\
|
||||
> \() )"
|
||||
> ,"select * from t GROUP BY GROUPING SETS((Province, County, City),\n\
|
||||
> \(Province, County),\n\
|
||||
> \(Province),\n\
|
||||
> \() )"
|
||||
> ,"select * from t GROUP BY a, ROLLUP(b,c)"
|
||||
> ,"select * from t GROUP BY GROUPING SETS((a,b,c),\n\
|
||||
> \(a,b),\n\
|
||||
> \(a) )"
|
||||
> ,"select * from t GROUP BY a, b, ROLLUP(c,d)"
|
||||
> ,"select * from t GROUP BY GROUPING SETS((a,b,c,d),\n\
|
||||
> \(a,b,c),\n\
|
||||
> \(a,b) )"
|
||||
> ,"select * from t GROUP BY ROLLUP(a), ROLLUP(b,c)"
|
||||
> ,"select * from t GROUP BY GROUPING SETS((a,b,c),\n\
|
||||
> \(a,b),\n\
|
||||
> \(a),\n\
|
||||
> \(b,c),\n\
|
||||
> \(b),\n\
|
||||
> \() )"
|
||||
> ,"select * from t GROUP BY ROLLUP(a), CUBE(b,c)"
|
||||
> ,"select * from t GROUP BY GROUPING SETS((a,b,c),\n\
|
||||
> \(a,b),\n\
|
||||
> \(a,c),\n\
|
||||
> \(a),\n\
|
||||
> \(b,c),\n\
|
||||
> \(b),\n\
|
||||
> \(c),\n\
|
||||
> \() )"
|
||||
> ,"select * from t GROUP BY CUBE(a,b), ROLLUP(c,d)"
|
||||
> ,"select * from t GROUP BY GROUPING SETS((a,b,c,d),\n\
|
||||
> \(a,b,c),\n\
|
||||
> \(a,b),\n\
|
||||
> \(a,c,d),\n\
|
||||
> \(a,c),\n\
|
||||
> \(a),\n\
|
||||
> \(b,c,d),\n\
|
||||
> \(b,c),\n\
|
||||
> \(b),\n\
|
||||
> \(c,d),\n\
|
||||
> \(c),\n\
|
||||
> \() )"
|
||||
> ,"select * from t GROUP BY a, ROLLUP(a,b)"
|
||||
> ,"select * from t GROUP BY GROUPING SETS((a,b),\n\
|
||||
> \(a) )"
|
||||
> ,"select * from t GROUP BY Region,\n\
|
||||
> \ROLLUP(Sales_Person, WEEK(Sales_Date)),\n\
|
||||
> \CUBE(YEAR(Sales_Date), MONTH (Sales_Date))"
|
||||
> ,"select * from t GROUP BY ROLLUP (Region, Sales_Person, WEEK(Sales_Date),\n\
|
||||
> \YEAR(Sales_Date), MONTH(Sales_Date) )"
|
||||
|
||||
> ,"SELECT WEEK(SALES_DATE) AS WEEK,\n\
|
||||
> \DAYOFWEEK(SALES_DATE) AS DAY_WEEK,\n\
|
||||
> \SALES_PERSON, SUM(SALES) AS UNITS_SOLD\n\
|
||||
> \FROM SALES\n\
|
||||
> \WHERE WEEK(SALES_DATE) = 13\n\
|
||||
> \GROUP BY WEEK(SALES_DATE), DAYOFWEEK(SALES_DATE), SALES_PERSON\n\
|
||||
> \ORDER BY WEEK, DAY_WEEK, SALES_PERSON"
|
||||
|
||||
> ,"SELECT WEEK(SALES_DATE) AS WEEK,\n\
|
||||
> \DAYOFWEEK(SALES_DATE) AS DAY_WEEK,\n\
|
||||
> \SALES_PERSON, SUM(SALES) AS UNITS_SOLD\n\
|
||||
> \FROM SALES\n\
|
||||
> \WHERE WEEK(SALES_DATE) = 13\n\
|
||||
> \GROUP BY GROUPING SETS ( (WEEK(SALES_DATE), SALES_PERSON),\n\
|
||||
> \(DAYOFWEEK(SALES_DATE), SALES_PERSON))\n\
|
||||
> \ORDER BY WEEK, DAY_WEEK, SALES_PERSON"
|
||||
|
||||
> ,"SELECT WEEK(SALES_DATE) AS WEEK,\n\
|
||||
> \DAYOFWEEK(SALES_DATE) AS DAY_WEEK,\n\
|
||||
> \SALES_PERSON, SUM(SALES) AS UNITS_SOLD\n\
|
||||
> \FROM SALES\n\
|
||||
> \WHERE WEEK(SALES_DATE) = 13\n\
|
||||
> \GROUP BY ROLLUP ( WEEK(SALES_DATE), DAYOFWEEK(SALES_DATE), SALES_PERSON )\n\
|
||||
> \ORDER BY WEEK, DAY_WEEK, SALES_PERSON"
|
||||
|
||||
> ,"SELECT WEEK(SALES_DATE) AS WEEK,\n\
|
||||
> \DAYOFWEEK(SALES_DATE) AS DAY_WEEK,\n\
|
||||
> \SALES_PERSON, SUM(SALES) AS UNITS_SOLD\n\
|
||||
> \FROM SALES\n\
|
||||
> \WHERE WEEK(SALES_DATE) = 13\n\
|
||||
> \GROUP BY CUBE ( WEEK(SALES_DATE), DAYOFWEEK(SALES_DATE), SALES_PERSON )\n\
|
||||
> \ORDER BY WEEK, DAY_WEEK, SALES_PERSON"
|
||||
|
||||
> ,"SELECT SALES_PERSON,\n\
|
||||
> \MONTH(SALES_DATE) AS MONTH,\n\
|
||||
> \SUM(SALES) AS UNITS_SOLD\n\
|
||||
> \FROM SALES\n\
|
||||
> \GROUP BY GROUPING SETS ( (SALES_PERSON, MONTH(SALES_DATE)),\n\
|
||||
> \()\n\
|
||||
> \)\n\
|
||||
> \ORDER BY SALES_PERSON, MONTH"
|
||||
|
||||
> ,"SELECT WEEK(SALES_DATE) AS WEEK,\n\
|
||||
> \DAYOFWEEK(SALES_DATE) AS DAY_WEEK,\n\
|
||||
> \SUM(SALES) AS UNITS_SOLD\n\
|
||||
> \FROM SALES\n\
|
||||
> \GROUP BY ROLLUP ( WEEK(SALES_DATE), DAYOFWEEK(SALES_DATE) )\n\
|
||||
> \ORDER BY WEEK, DAY_WEEK"
|
||||
|
||||
> ,"SELECT MONTH(SALES_DATE) AS MONTH,\n\
|
||||
> \REGION,\n\
|
||||
> \SUM(SALES) AS UNITS_SOLD\n\
|
||||
> \FROM SALES\n\
|
||||
> \GROUP BY ROLLUP ( MONTH(SALES_DATE), REGION )\n\
|
||||
> \ORDER BY MONTH, REGION"
|
||||
|
||||
> ,"SELECT WEEK(SALES_DATE) AS WEEK,\n\
|
||||
> \DAYOFWEEK(SALES_DATE) AS DAY_WEEK,\n\
|
||||
> \MONTH(SALES_DATE) AS MONTH,\n\
|
||||
> \REGION,\n\
|
||||
> \SUM(SALES) AS UNITS_SOLD\n\
|
||||
> \FROM SALES\n\
|
||||
> \GROUP BY GROUPING SETS ( ROLLUP( WEEK(SALES_DATE), DAYOFWEEK(SALES_DATE) ),\n\
|
||||
> \ROLLUP( MONTH(SALES_DATE), REGION ) )\n\
|
||||
> \ORDER BY WEEK, DAY_WEEK, MONTH, REGION"
|
||||
|
||||
> ,"SELECT R1, R2,\n\
|
||||
> \WEEK(SALES_DATE) AS WEEK,\n\
|
||||
> \DAYOFWEEK(SALES_DATE) AS DAY_WEEK,\n\
|
||||
> \MONTH(SALES_DATE) AS MONTH,\n\
|
||||
> \REGION, SUM(SALES) AS UNITS_SOLD\n\
|
||||
> \FROM SALES,(VALUES('GROUP 1','GROUP 2')) AS X(R1,R2)\n\
|
||||
> \GROUP BY GROUPING SETS ((R1, ROLLUP(WEEK(SALES_DATE),\n\
|
||||
> \DAYOFWEEK(SALES_DATE))),\n\
|
||||
> \(R2,ROLLUP( MONTH(SALES_DATE), REGION ) ))\n\
|
||||
> \ORDER BY WEEK, DAY_WEEK, MONTH, REGION"
|
||||
|
||||
> {-,"SELECT COALESCE(R1,R2) AS GROUP,\n\
|
||||
> \WEEK(SALES_DATE) AS WEEK,\n\
|
||||
> \DAYOFWEEK(SALES_DATE) AS DAY_WEEK,\n\
|
||||
> \MONTH(SALES_DATE) AS MONTH,\n\
|
||||
> \REGION, SUM(SALES) AS UNITS_SOLD\n\
|
||||
> \FROM SALES,(VALUES('GROUP 1','GROUP 2')) AS X(R1,R2)\n\
|
||||
> \GROUP BY GROUPING SETS ((R1, ROLLUP(WEEK(SALES_DATE),\n\
|
||||
> \DAYOFWEEK(SALES_DATE))),\n\
|
||||
> \(R2,ROLLUP( MONTH(SALES_DATE), REGION ) ))\n\
|
||||
> \ORDER BY GROUP, WEEK, DAY_WEEK, MONTH, REGION"-}
|
||||
> -- as group - needs more subtle keyword blacklisting
|
||||
|
||||
> -- decimal as a function not allowed due to the reserved keyword
|
||||
> -- handling: todo, review if this is ansi standard function or
|
||||
> -- if there are places where reserved keywords can still be used
|
||||
> ,"SELECT MONTH(SALES_DATE) AS MONTH,\n\
|
||||
> \REGION,\n\
|
||||
> \SUM(SALES) AS UNITS_SOLD,\n\
|
||||
> \MAX(SALES) AS BEST_SALE,\n\
|
||||
> \CAST(ROUND(AVG(DECIMALx(SALES)),2) AS DECIMAL(5,2)) AS AVG_UNITS_SOLD\n\
|
||||
> \FROM SALES\n\
|
||||
> \GROUP BY CUBE(MONTH(SALES_DATE),REGION)\n\
|
||||
> \ORDER BY MONTH, REGION"
|
||||
|
||||
> ]
|
343
tools/Language/SQL/SimpleSQL/LexerTests.hs
Normal file
343
tools/Language/SQL/SimpleSQL/LexerTests.hs
Normal file
|
@ -0,0 +1,343 @@
|
|||
|
||||
|
||||
-- Test for the lexer
|
||||
|
||||
module Language.SQL.SimpleSQL.LexerTests (lexerTests) where
|
||||
|
||||
import Language.SQL.SimpleSQL.TestTypes
|
||||
import Language.SQL.SimpleSQL.Lex (Token(..),tokenListWillPrintAndLex)
|
||||
--import Debug.Trace
|
||||
--import Data.Char (isAlpha)
|
||||
import Data.List
|
||||
|
||||
lexerTests :: TestItem
|
||||
lexerTests = Group "lexerTests" $
|
||||
[Group "lexer token tests" [ansiLexerTests
|
||||
,postgresLexerTests
|
||||
,sqlServerLexerTests
|
||||
,oracleLexerTests
|
||||
,mySqlLexerTests
|
||||
,odbcLexerTests]]
|
||||
|
||||
ansiLexerTable :: [(String,[Token])]
|
||||
ansiLexerTable =
|
||||
-- single char symbols
|
||||
map (\s -> ([s],[Symbol [s]])) "+-^*/%~&|?<>[]=,;()"
|
||||
-- multi char symbols
|
||||
++ map (\s -> (s,[Symbol s])) [">=","<=","!=","<>","||"]
|
||||
++ (let idens = ["a", "_a", "test", "table", "Stuff", "STUFF"]
|
||||
-- simple identifiers
|
||||
in map (\i -> (i, [Identifier Nothing i])) idens
|
||||
++ map (\i -> ("\"" ++ i ++ "\"", [Identifier (Just ("\"","\"")) i])) idens
|
||||
-- todo: in order to make lex . pretty id, need to
|
||||
-- preserve the case of the u
|
||||
++ map (\i -> ("u&\"" ++ i ++ "\"", [Identifier (Just ("u&\"","\"")) i])) idens
|
||||
-- host param
|
||||
++ map (\i -> (':':i, [PrefixedVariable ':' i])) idens
|
||||
)
|
||||
-- quoted identifiers with embedded double quotes
|
||||
-- the lexer doesn't unescape the quotes
|
||||
++ [("\"normal \"\" iden\"", [Identifier (Just ("\"","\"")) "normal \"\" iden"])]
|
||||
-- strings
|
||||
-- the lexer doesn't apply escapes at all
|
||||
++ [("'string'", [SqlString "'" "'" "string"])
|
||||
,("'normal '' quote'", [SqlString "'" "'" "normal '' quote"])
|
||||
,("'normalendquote '''", [SqlString "'" "'" "normalendquote ''"])
|
||||
,("'\n'", [SqlString "'" "'" "\n"])]
|
||||
-- csstrings
|
||||
++ map (\c -> (c ++ "'test'", [SqlString (c ++ "'") "'" "test"]))
|
||||
["n", "N","b", "B","x", "X", "u&"]
|
||||
-- numbers
|
||||
++ [("10", [SqlNumber "10"])
|
||||
,(".1", [SqlNumber ".1"])
|
||||
,("5e3", [SqlNumber "5e3"])
|
||||
,("5e+3", [SqlNumber "5e+3"])
|
||||
,("5e-3", [SqlNumber "5e-3"])
|
||||
,("10.2", [SqlNumber "10.2"])
|
||||
,("10.2e7", [SqlNumber "10.2e7"])]
|
||||
-- whitespace
|
||||
++ concat [[([a],[Whitespace [a]])
|
||||
,([a,b], [Whitespace [a,b]])]
|
||||
| a <- " \n\t", b <- " \n\t"]
|
||||
-- line comment
|
||||
++ map (\c -> (c, [LineComment c]))
|
||||
["--", "-- ", "-- this is a comment", "-- line com\n"]
|
||||
-- block comment
|
||||
++ map (\c -> (c, [BlockComment c]))
|
||||
["/**/", "/* */","/* this is a comment */"
|
||||
,"/* this *is/ a comment */"
|
||||
]
|
||||
|
||||
ansiLexerTests :: TestItem
|
||||
ansiLexerTests = Group "ansiLexerTests" $
|
||||
[Group "ansi lexer token tests" $ [LexTest ansi2011 s t | (s,t) <- ansiLexerTable]
|
||||
,Group "ansi generated combination lexer tests" $
|
||||
[ LexTest ansi2011 (s ++ s1) (t ++ t1)
|
||||
| (s,t) <- ansiLexerTable
|
||||
, (s1,t1) <- ansiLexerTable
|
||||
, tokenListWillPrintAndLex ansi2011 $ t ++ t1
|
||||
|
||||
]
|
||||
,Group "ansiadhoclexertests" $
|
||||
map (uncurry $ LexTest ansi2011)
|
||||
[("", [])
|
||||
,("-- line com\nstuff", [LineComment "-- line com\n",Identifier Nothing "stuff"])
|
||||
] ++
|
||||
[-- want to make sure this gives a parse error
|
||||
LexFails ansi2011 "*/"
|
||||
-- combinations of pipes: make sure they fail because they could be
|
||||
-- ambiguous and it is really unclear when they are or not, and
|
||||
-- what the result is even when they are not ambiguous
|
||||
,LexFails ansi2011 "|||"
|
||||
,LexFails ansi2011 "||||"
|
||||
,LexFails ansi2011 "|||||"
|
||||
-- another user experience thing: make sure extra trailing
|
||||
-- number chars are rejected rather than attempting to parse
|
||||
-- if the user means to write something that is rejected by this code,
|
||||
-- then they can use whitespace to make it clear and then it will parse
|
||||
,LexFails ansi2011 "12e3e4"
|
||||
,LexFails ansi2011 "12e3e4"
|
||||
,LexFails ansi2011 "12e3e4"
|
||||
,LexFails ansi2011 "12e3.4"
|
||||
,LexFails ansi2011 "12.4.5"
|
||||
,LexFails ansi2011 "12.4e5.6"
|
||||
,LexFails ansi2011 "12.4e5e7"]
|
||||
]
|
||||
|
||||
{-
|
||||
todo: lexing tests
|
||||
do quickcheck testing:
|
||||
can try to generate valid tokens then check they parse
|
||||
|
||||
same as above: can also try to pair tokens, create an accurate
|
||||
function to say which ones can appear adjacent, and test
|
||||
|
||||
I think this plus the explicit lists of tokens like above which do
|
||||
basic sanity + explicit edge casts will provide a high level of
|
||||
assurance.
|
||||
-}
|
||||
|
||||
|
||||
|
||||
postgresLexerTable :: [(String,[Token])]
|
||||
postgresLexerTable =
|
||||
-- single char symbols
|
||||
map (\s -> ([s],[Symbol [s]])) "+-^*/%~&|?<>[]=,;():"
|
||||
-- multi char symbols
|
||||
++ map (\s -> (s,[Symbol s])) [">=","<=","!=","<>","||", "::","..",":="]
|
||||
-- generic symbols
|
||||
|
||||
++ (let idens = ["a", "_a", "test", "table", "Stuff", "STUFF"]
|
||||
-- simple identifiers
|
||||
in map (\i -> (i, [Identifier Nothing i])) idens
|
||||
++ map (\i -> ("\"" ++ i ++ "\"", [Identifier (Just ("\"","\"")) i])) idens
|
||||
-- todo: in order to make lex . pretty id, need to
|
||||
-- preserve the case of the u
|
||||
++ map (\i -> ("u&\"" ++ i ++ "\"", [Identifier (Just ("u&\"","\"")) i])) idens
|
||||
-- host param
|
||||
++ map (\i -> (':':i, [PrefixedVariable ':' i])) idens
|
||||
)
|
||||
-- positional var
|
||||
++ [("$1", [PositionalArg 1])]
|
||||
-- quoted identifiers with embedded double quotes
|
||||
++ [("\"normal \"\" iden\"", [Identifier (Just ("\"","\"")) "normal \"\" iden"])]
|
||||
-- strings
|
||||
++ [("'string'", [SqlString "'" "'" "string"])
|
||||
,("'normal '' quote'", [SqlString "'" "'" "normal '' quote"])
|
||||
,("'normalendquote '''", [SqlString "'" "'" "normalendquote ''"])
|
||||
,("'\n'", [SqlString "'" "'" "\n"])
|
||||
,("E'\n'", [SqlString "E'" "'" "\n"])
|
||||
,("e'this '' quote'", [SqlString "e'" "'" "this '' quote"])
|
||||
,("e'this \\' quote'", [SqlString "e'" "'" "this \\' quote"])
|
||||
,("'not this \\' quote", [SqlString "'" "'" "not this \\"
|
||||
,Whitespace " "
|
||||
,Identifier Nothing "quote"])
|
||||
,("$$ string 1 $$", [SqlString "$$" "$$" " string 1 "])
|
||||
,("$$ string $ 2 $$", [SqlString "$$" "$$" " string $ 2 "])
|
||||
,("$a$ $$string 3$$ $a$", [SqlString "$a$" "$a$" " $$string 3$$ "])
|
||||
]
|
||||
-- csstrings
|
||||
++ map (\c -> (c ++ "'test'", [SqlString (c ++ "'") "'" "test"]))
|
||||
["n", "N","b", "B","x", "X", "u&", "e", "E"]
|
||||
-- numbers
|
||||
++ [("10", [SqlNumber "10"])
|
||||
,(".1", [SqlNumber ".1"])
|
||||
,("5e3", [SqlNumber "5e3"])
|
||||
,("5e+3", [SqlNumber "5e+3"])
|
||||
,("5e-3", [SqlNumber "5e-3"])
|
||||
,("10.2", [SqlNumber "10.2"])
|
||||
,("10.2e7", [SqlNumber "10.2e7"])]
|
||||
-- whitespace
|
||||
++ concat [[([a],[Whitespace [a]])
|
||||
,([a,b], [Whitespace [a,b]])]
|
||||
| a <- " \n\t", b <- " \n\t"]
|
||||
-- line comment
|
||||
++ map (\c -> (c, [LineComment c]))
|
||||
["--", "-- ", "-- this is a comment", "-- line com\n"]
|
||||
-- block comment
|
||||
++ map (\c -> (c, [BlockComment c]))
|
||||
["/**/", "/* */","/* this is a comment */"
|
||||
,"/* this *is/ a comment */"
|
||||
]
|
||||
|
||||
{-
|
||||
An operator name is a sequence of up to NAMEDATALEN-1 (63 by default) characters from the following list:
|
||||
|
||||
+ - * / < > = ~ ! @ # % ^ & | ` ?
|
||||
|
||||
There are a few restrictions on operator names, however:
|
||||
-- and /* cannot appear anywhere in an operator name, since they will be taken as the start of a comment.
|
||||
|
||||
A multiple-character operator name cannot end in + or -, unless the name also contains at least one of these characters:
|
||||
|
||||
~ ! @ # % ^ & | ` ?
|
||||
|
||||
todo: 'negative' tests
|
||||
symbol then --
|
||||
symbol then /*
|
||||
operators without one of the exception chars
|
||||
followed by + or - without whitespace
|
||||
|
||||
also: do the testing for the ansi compatibility special cases
|
||||
-}
|
||||
|
||||
postgresShortOperatorTable :: [(String,[Token])]
|
||||
postgresShortOperatorTable =
|
||||
[ (x, [Symbol x]) | x <- someValidPostgresOperators 2]
|
||||
|
||||
|
||||
postgresExtraOperatorTable :: [(String,[Token])]
|
||||
postgresExtraOperatorTable =
|
||||
[ (x, [Symbol x]) | x <- someValidPostgresOperators 4]
|
||||
|
||||
|
||||
someValidPostgresOperators :: Int -> [String]
|
||||
someValidPostgresOperators l =
|
||||
[ x
|
||||
| n <- [1..l]
|
||||
, x <- combos "+-*/<>=~!@#%^&|`?" n
|
||||
, not ("--" `isInfixOf` x || "/*" `isInfixOf` x || "*/" `isInfixOf` x)
|
||||
, not (last x `elem` "+-")
|
||||
|| or (map (`elem` x) "~!@#%^&|`?")
|
||||
]
|
||||
|
||||
{-
|
||||
These are postgres operators, which if followed immediately by a + or
|
||||
-, will lex as separate operators rather than one operator including
|
||||
the + or -.
|
||||
-}
|
||||
|
||||
somePostgresOpsWhichWontAddTrailingPlusMinus :: Int -> [String]
|
||||
somePostgresOpsWhichWontAddTrailingPlusMinus l =
|
||||
[ x
|
||||
| n <- [1..l]
|
||||
, x <- combos "+-*/<>=" n
|
||||
, not ("--" `isInfixOf` x || "/*" `isInfixOf` x || "*/" `isInfixOf` x)
|
||||
, not (last x `elem` "+-")
|
||||
]
|
||||
|
||||
|
||||
postgresLexerTests :: TestItem
|
||||
postgresLexerTests = Group "postgresLexerTests" $
|
||||
[Group "postgres lexer token tests" $
|
||||
[LexTest postgres s t | (s,t) <- postgresLexerTable]
|
||||
,Group "postgres generated lexer token tests" $
|
||||
[LexTest postgres s t | (s,t) <- postgresShortOperatorTable ++ postgresExtraOperatorTable]
|
||||
,Group "postgres generated combination lexer tests" $
|
||||
[ LexTest postgres (s ++ s1) (t ++ t1)
|
||||
| (s,t) <- postgresLexerTable ++ postgresShortOperatorTable
|
||||
, (s1,t1) <- postgresLexerTable ++ postgresShortOperatorTable
|
||||
, tokenListWillPrintAndLex postgres $ t ++ t1
|
||||
|
||||
]
|
||||
,Group "generated postgres edgecase lexertests" $
|
||||
[LexTest postgres s t
|
||||
| (s,t) <- edgeCaseCommentOps
|
||||
++ edgeCasePlusMinusOps
|
||||
++ edgeCasePlusMinusComments]
|
||||
|
||||
,Group "adhoc postgres lexertests" $
|
||||
-- need more tests for */ to make sure it is caught if it is in the middle of a
|
||||
-- sequence of symbol letters
|
||||
[LexFails postgres "*/"
|
||||
,LexFails postgres ":::"
|
||||
,LexFails postgres "::::"
|
||||
,LexFails postgres ":::::"
|
||||
,LexFails postgres "@*/"
|
||||
,LexFails postgres "-*/"
|
||||
,LexFails postgres "12e3e4"
|
||||
,LexFails postgres "12e3e4"
|
||||
,LexFails postgres "12e3e4"
|
||||
,LexFails postgres "12e3.4"
|
||||
,LexFails postgres "12.4.5"
|
||||
,LexFails postgres "12.4e5.6"
|
||||
,LexFails postgres "12.4e5e7"
|
||||
-- special case allow this to lex to 1 .. 2
|
||||
-- this is for 'for loops' in plpgsql
|
||||
,LexTest postgres "1..2" [SqlNumber "1", Symbol "..", SqlNumber "2"]]
|
||||
]
|
||||
where
|
||||
edgeCaseCommentOps =
|
||||
[ (x ++ "/*<test*/", [Symbol x, BlockComment "/*<test*/"])
|
||||
| x <- eccops
|
||||
, not (last x == '*')
|
||||
] ++
|
||||
[ (x ++ "--<test", [Symbol x, LineComment "--<test"])
|
||||
| x <- eccops
|
||||
, not (last x == '-')
|
||||
]
|
||||
eccops = someValidPostgresOperators 2
|
||||
edgeCasePlusMinusOps = concat
|
||||
[ [ (x ++ "+", [Symbol x, Symbol "+"])
|
||||
, (x ++ "-", [Symbol x, Symbol "-"]) ]
|
||||
| x <- somePostgresOpsWhichWontAddTrailingPlusMinus 2
|
||||
]
|
||||
edgeCasePlusMinusComments =
|
||||
[("---", [LineComment "---"])
|
||||
,("+--", [Symbol "+", LineComment "--"])
|
||||
,("-/**/", [Symbol "-", BlockComment "/**/"])
|
||||
,("+/**/", [Symbol "+", BlockComment "/**/"])
|
||||
]
|
||||
|
||||
|
||||
sqlServerLexerTests :: TestItem
|
||||
sqlServerLexerTests = Group "sqlServerLexTests" $
|
||||
[ LexTest sqlserver s t | (s,t) <-
|
||||
[("@variable", [(PrefixedVariable '@' "variable")])
|
||||
,("#variable", [(PrefixedVariable '#' "variable")])
|
||||
,("[quoted identifier]", [(Identifier (Just ("[", "]")) "quoted identifier")])
|
||||
]]
|
||||
|
||||
oracleLexerTests :: TestItem
|
||||
oracleLexerTests = Group "oracleLexTests" $
|
||||
[] -- nothing oracle specific atm
|
||||
|
||||
mySqlLexerTests :: TestItem
|
||||
mySqlLexerTests = Group "mySqlLexerTests" $
|
||||
[ LexTest mysql s t | (s,t) <-
|
||||
[("`quoted identifier`", [(Identifier (Just ("`", "`")) "quoted identifier")])
|
||||
]
|
||||
]
|
||||
|
||||
odbcLexerTests :: TestItem
|
||||
odbcLexerTests = Group "odbcLexTests" $
|
||||
[ LexTest sqlserver {diOdbc = True} s t | (s,t) <-
|
||||
[("{}", [Symbol "{", Symbol "}"])
|
||||
]]
|
||||
++ [LexFails sqlserver {diOdbc = False} "{"
|
||||
,LexFails sqlserver {diOdbc = False} "}"]
|
||||
|
||||
combos :: [a] -> Int -> [[a]]
|
||||
combos _ 0 = [[]]
|
||||
combos l n = [ x:tl | x <- l, tl <- combos l (n - 1) ]
|
||||
|
||||
{-
|
||||
figure out a way to do quickcheck testing:
|
||||
1. generate valid tokens and check they parse
|
||||
|
||||
2. combine two generated tokens together for the combo testing
|
||||
|
||||
this especially will work much better for the postgresql extensible
|
||||
operator tests which doing exhaustively takes ages and doesn't bring
|
||||
much benefit over testing a few using quickcheck.
|
||||
-}
|
|
@ -1,335 +0,0 @@
|
|||
|
||||
|
||||
Test for the lexer
|
||||
|
||||
> module Language.SQL.SimpleSQL.LexerTests (lexerTests) where
|
||||
|
||||
> import Language.SQL.SimpleSQL.TestTypes
|
||||
> import Language.SQL.SimpleSQL.Lex (Token(..),tokenListWillPrintAndLex)
|
||||
> --import Debug.Trace
|
||||
> --import Data.Char (isAlpha)
|
||||
> import Data.List
|
||||
|
||||
> lexerTests :: TestItem
|
||||
> lexerTests = Group "lexerTests" $
|
||||
> [Group "lexer token tests" [ansiLexerTests
|
||||
> ,postgresLexerTests
|
||||
> ,sqlServerLexerTests
|
||||
> ,oracleLexerTests
|
||||
> ,mySqlLexerTests
|
||||
> ,odbcLexerTests]]
|
||||
|
||||
> ansiLexerTable :: [(String,[Token])]
|
||||
> ansiLexerTable =
|
||||
> -- single char symbols
|
||||
> map (\s -> ([s],[Symbol [s]])) "+-^*/%~&|?<>[]=,;()"
|
||||
> -- multi char symbols
|
||||
> ++ map (\s -> (s,[Symbol s])) [">=","<=","!=","<>","||"]
|
||||
> ++ (let idens = ["a", "_a", "test", "table", "Stuff", "STUFF"]
|
||||
> -- simple identifiers
|
||||
> in map (\i -> (i, [Identifier Nothing i])) idens
|
||||
> ++ map (\i -> ("\"" ++ i ++ "\"", [Identifier (Just ("\"","\"")) i])) idens
|
||||
> -- todo: in order to make lex . pretty id, need to
|
||||
> -- preserve the case of the u
|
||||
> ++ map (\i -> ("u&\"" ++ i ++ "\"", [Identifier (Just ("u&\"","\"")) i])) idens
|
||||
> -- host param
|
||||
> ++ map (\i -> (':':i, [PrefixedVariable ':' i])) idens
|
||||
> )
|
||||
> -- quoted identifiers with embedded double quotes
|
||||
> -- the lexer doesn't unescape the quotes
|
||||
> ++ [("\"normal \"\" iden\"", [Identifier (Just ("\"","\"")) "normal \"\" iden"])]
|
||||
> -- strings
|
||||
> -- the lexer doesn't apply escapes at all
|
||||
> ++ [("'string'", [SqlString "'" "'" "string"])
|
||||
> ,("'normal '' quote'", [SqlString "'" "'" "normal '' quote"])
|
||||
> ,("'normalendquote '''", [SqlString "'" "'" "normalendquote ''"])
|
||||
> ,("'\n'", [SqlString "'" "'" "\n"])]
|
||||
> -- csstrings
|
||||
> ++ map (\c -> (c ++ "'test'", [SqlString (c ++ "'") "'" "test"]))
|
||||
> ["n", "N","b", "B","x", "X", "u&"]
|
||||
> -- numbers
|
||||
> ++ [("10", [SqlNumber "10"])
|
||||
> ,(".1", [SqlNumber ".1"])
|
||||
> ,("5e3", [SqlNumber "5e3"])
|
||||
> ,("5e+3", [SqlNumber "5e+3"])
|
||||
> ,("5e-3", [SqlNumber "5e-3"])
|
||||
> ,("10.2", [SqlNumber "10.2"])
|
||||
> ,("10.2e7", [SqlNumber "10.2e7"])]
|
||||
> -- whitespace
|
||||
> ++ concat [[([a],[Whitespace [a]])
|
||||
> ,([a,b], [Whitespace [a,b]])]
|
||||
> | a <- " \n\t", b <- " \n\t"]
|
||||
> -- line comment
|
||||
> ++ map (\c -> (c, [LineComment c]))
|
||||
> ["--", "-- ", "-- this is a comment", "-- line com\n"]
|
||||
> -- block comment
|
||||
> ++ map (\c -> (c, [BlockComment c]))
|
||||
> ["/**/", "/* */","/* this is a comment */"
|
||||
> ,"/* this *is/ a comment */"
|
||||
> ]
|
||||
|
||||
> ansiLexerTests :: TestItem
|
||||
> ansiLexerTests = Group "ansiLexerTests" $
|
||||
> [Group "ansi lexer token tests" $ [LexTest ansi2011 s t | (s,t) <- ansiLexerTable]
|
||||
> ,Group "ansi generated combination lexer tests" $
|
||||
> [ LexTest ansi2011 (s ++ s1) (t ++ t1)
|
||||
> | (s,t) <- ansiLexerTable
|
||||
> , (s1,t1) <- ansiLexerTable
|
||||
> , tokenListWillPrintAndLex ansi2011 $ t ++ t1
|
||||
|
||||
> ]
|
||||
> ,Group "ansiadhoclexertests" $
|
||||
> map (uncurry $ LexTest ansi2011)
|
||||
> [("", [])
|
||||
> ,("-- line com\nstuff", [LineComment "-- line com\n",Identifier Nothing "stuff"])
|
||||
> ] ++
|
||||
> [-- want to make sure this gives a parse error
|
||||
> LexFails ansi2011 "*/"
|
||||
> -- combinations of pipes: make sure they fail because they could be
|
||||
> -- ambiguous and it is really unclear when they are or not, and
|
||||
> -- what the result is even when they are not ambiguous
|
||||
> ,LexFails ansi2011 "|||"
|
||||
> ,LexFails ansi2011 "||||"
|
||||
> ,LexFails ansi2011 "|||||"
|
||||
> -- another user experience thing: make sure extra trailing
|
||||
> -- number chars are rejected rather than attempting to parse
|
||||
> -- if the user means to write something that is rejected by this code,
|
||||
> -- then they can use whitespace to make it clear and then it will parse
|
||||
> ,LexFails ansi2011 "12e3e4"
|
||||
> ,LexFails ansi2011 "12e3e4"
|
||||
> ,LexFails ansi2011 "12e3e4"
|
||||
> ,LexFails ansi2011 "12e3.4"
|
||||
> ,LexFails ansi2011 "12.4.5"
|
||||
> ,LexFails ansi2011 "12.4e5.6"
|
||||
> ,LexFails ansi2011 "12.4e5e7"]
|
||||
> ]
|
||||
|
||||
todo: lexing tests
|
||||
do quickcheck testing:
|
||||
can try to generate valid tokens then check they parse
|
||||
|
||||
same as above: can also try to pair tokens, create an accurate
|
||||
function to say which ones can appear adjacent, and test
|
||||
|
||||
I think this plus the explicit lists of tokens like above which do
|
||||
basic sanity + explicit edge casts will provide a high level of
|
||||
assurance.
|
||||
|
||||
|
||||
|
||||
> postgresLexerTable :: [(String,[Token])]
|
||||
> postgresLexerTable =
|
||||
> -- single char symbols
|
||||
> map (\s -> ([s],[Symbol [s]])) "+-^*/%~&|?<>[]=,;():"
|
||||
> -- multi char symbols
|
||||
> ++ map (\s -> (s,[Symbol s])) [">=","<=","!=","<>","||", "::","..",":="]
|
||||
> -- generic symbols
|
||||
|
||||
> ++ (let idens = ["a", "_a", "test", "table", "Stuff", "STUFF"]
|
||||
> -- simple identifiers
|
||||
> in map (\i -> (i, [Identifier Nothing i])) idens
|
||||
> ++ map (\i -> ("\"" ++ i ++ "\"", [Identifier (Just ("\"","\"")) i])) idens
|
||||
> -- todo: in order to make lex . pretty id, need to
|
||||
> -- preserve the case of the u
|
||||
> ++ map (\i -> ("u&\"" ++ i ++ "\"", [Identifier (Just ("u&\"","\"")) i])) idens
|
||||
> -- host param
|
||||
> ++ map (\i -> (':':i, [PrefixedVariable ':' i])) idens
|
||||
> )
|
||||
> -- positional var
|
||||
> ++ [("$1", [PositionalArg 1])]
|
||||
> -- quoted identifiers with embedded double quotes
|
||||
> ++ [("\"normal \"\" iden\"", [Identifier (Just ("\"","\"")) "normal \"\" iden"])]
|
||||
> -- strings
|
||||
> ++ [("'string'", [SqlString "'" "'" "string"])
|
||||
> ,("'normal '' quote'", [SqlString "'" "'" "normal '' quote"])
|
||||
> ,("'normalendquote '''", [SqlString "'" "'" "normalendquote ''"])
|
||||
> ,("'\n'", [SqlString "'" "'" "\n"])
|
||||
> ,("E'\n'", [SqlString "E'" "'" "\n"])
|
||||
> ,("e'this '' quote'", [SqlString "e'" "'" "this '' quote"])
|
||||
> ,("e'this \\' quote'", [SqlString "e'" "'" "this \\' quote"])
|
||||
> ,("'not this \\' quote", [SqlString "'" "'" "not this \\"
|
||||
> ,Whitespace " "
|
||||
> ,Identifier Nothing "quote"])
|
||||
> ,("$$ string 1 $$", [SqlString "$$" "$$" " string 1 "])
|
||||
> ,("$$ string $ 2 $$", [SqlString "$$" "$$" " string $ 2 "])
|
||||
> ,("$a$ $$string 3$$ $a$", [SqlString "$a$" "$a$" " $$string 3$$ "])
|
||||
> ]
|
||||
> -- csstrings
|
||||
> ++ map (\c -> (c ++ "'test'", [SqlString (c ++ "'") "'" "test"]))
|
||||
> ["n", "N","b", "B","x", "X", "u&", "e", "E"]
|
||||
> -- numbers
|
||||
> ++ [("10", [SqlNumber "10"])
|
||||
> ,(".1", [SqlNumber ".1"])
|
||||
> ,("5e3", [SqlNumber "5e3"])
|
||||
> ,("5e+3", [SqlNumber "5e+3"])
|
||||
> ,("5e-3", [SqlNumber "5e-3"])
|
||||
> ,("10.2", [SqlNumber "10.2"])
|
||||
> ,("10.2e7", [SqlNumber "10.2e7"])]
|
||||
> -- whitespace
|
||||
> ++ concat [[([a],[Whitespace [a]])
|
||||
> ,([a,b], [Whitespace [a,b]])]
|
||||
> | a <- " \n\t", b <- " \n\t"]
|
||||
> -- line comment
|
||||
> ++ map (\c -> (c, [LineComment c]))
|
||||
> ["--", "-- ", "-- this is a comment", "-- line com\n"]
|
||||
> -- block comment
|
||||
> ++ map (\c -> (c, [BlockComment c]))
|
||||
> ["/**/", "/* */","/* this is a comment */"
|
||||
> ,"/* this *is/ a comment */"
|
||||
> ]
|
||||
|
||||
An operator name is a sequence of up to NAMEDATALEN-1 (63 by default) characters from the following list:
|
||||
|
||||
+ - * / < > = ~ ! @ # % ^ & | ` ?
|
||||
|
||||
There are a few restrictions on operator names, however:
|
||||
-- and /* cannot appear anywhere in an operator name, since they will be taken as the start of a comment.
|
||||
|
||||
A multiple-character operator name cannot end in + or -, unless the name also contains at least one of these characters:
|
||||
|
||||
~ ! @ # % ^ & | ` ?
|
||||
|
||||
todo: 'negative' tests
|
||||
symbol then --
|
||||
symbol then /*
|
||||
operators without one of the exception chars
|
||||
followed by + or - without whitespace
|
||||
|
||||
also: do the testing for the ansi compatibility special cases
|
||||
|
||||
> postgresShortOperatorTable :: [(String,[Token])]
|
||||
> postgresShortOperatorTable =
|
||||
> [ (x, [Symbol x]) | x <- someValidPostgresOperators 2]
|
||||
|
||||
|
||||
> postgresExtraOperatorTable :: [(String,[Token])]
|
||||
> postgresExtraOperatorTable =
|
||||
> [ (x, [Symbol x]) | x <- someValidPostgresOperators 4]
|
||||
|
||||
|
||||
> someValidPostgresOperators :: Int -> [String]
|
||||
> someValidPostgresOperators l =
|
||||
> [ x
|
||||
> | n <- [1..l]
|
||||
> , x <- combos "+-*/<>=~!@#%^&|`?" n
|
||||
> , not ("--" `isInfixOf` x || "/*" `isInfixOf` x || "*/" `isInfixOf` x)
|
||||
> , not (last x `elem` "+-")
|
||||
> || or (map (`elem` x) "~!@#%^&|`?")
|
||||
> ]
|
||||
|
||||
These are postgres operators, which if followed immediately by a + or
|
||||
-, will lex as separate operators rather than one operator including
|
||||
the + or -.
|
||||
|
||||
> somePostgresOpsWhichWontAddTrailingPlusMinus :: Int -> [String]
|
||||
> somePostgresOpsWhichWontAddTrailingPlusMinus l =
|
||||
> [ x
|
||||
> | n <- [1..l]
|
||||
> , x <- combos "+-*/<>=" n
|
||||
> , not ("--" `isInfixOf` x || "/*" `isInfixOf` x || "*/" `isInfixOf` x)
|
||||
> , not (last x `elem` "+-")
|
||||
> ]
|
||||
|
||||
|
||||
> postgresLexerTests :: TestItem
|
||||
> postgresLexerTests = Group "postgresLexerTests" $
|
||||
> [Group "postgres lexer token tests" $
|
||||
> [LexTest postgres s t | (s,t) <- postgresLexerTable]
|
||||
> ,Group "postgres generated lexer token tests" $
|
||||
> [LexTest postgres s t | (s,t) <- postgresShortOperatorTable ++ postgresExtraOperatorTable]
|
||||
> ,Group "postgres generated combination lexer tests" $
|
||||
> [ LexTest postgres (s ++ s1) (t ++ t1)
|
||||
> | (s,t) <- postgresLexerTable ++ postgresShortOperatorTable
|
||||
> , (s1,t1) <- postgresLexerTable ++ postgresShortOperatorTable
|
||||
> , tokenListWillPrintAndLex postgres $ t ++ t1
|
||||
|
||||
> ]
|
||||
> ,Group "generated postgres edgecase lexertests" $
|
||||
> [LexTest postgres s t
|
||||
> | (s,t) <- edgeCaseCommentOps
|
||||
> ++ edgeCasePlusMinusOps
|
||||
> ++ edgeCasePlusMinusComments]
|
||||
|
||||
> ,Group "adhoc postgres lexertests" $
|
||||
> -- need more tests for */ to make sure it is caught if it is in the middle of a
|
||||
> -- sequence of symbol letters
|
||||
> [LexFails postgres "*/"
|
||||
> ,LexFails postgres ":::"
|
||||
> ,LexFails postgres "::::"
|
||||
> ,LexFails postgres ":::::"
|
||||
> ,LexFails postgres "@*/"
|
||||
> ,LexFails postgres "-*/"
|
||||
> ,LexFails postgres "12e3e4"
|
||||
> ,LexFails postgres "12e3e4"
|
||||
> ,LexFails postgres "12e3e4"
|
||||
> ,LexFails postgres "12e3.4"
|
||||
> ,LexFails postgres "12.4.5"
|
||||
> ,LexFails postgres "12.4e5.6"
|
||||
> ,LexFails postgres "12.4e5e7"
|
||||
> -- special case allow this to lex to 1 .. 2
|
||||
> -- this is for 'for loops' in plpgsql
|
||||
> ,LexTest postgres "1..2" [SqlNumber "1", Symbol "..", SqlNumber "2"]]
|
||||
> ]
|
||||
> where
|
||||
> edgeCaseCommentOps =
|
||||
> [ (x ++ "/*<test*/", [Symbol x, BlockComment "/*<test*/"])
|
||||
> | x <- eccops
|
||||
> , not (last x == '*')
|
||||
> ] ++
|
||||
> [ (x ++ "--<test", [Symbol x, LineComment "--<test"])
|
||||
> | x <- eccops
|
||||
> , not (last x == '-')
|
||||
> ]
|
||||
> eccops = someValidPostgresOperators 2
|
||||
> edgeCasePlusMinusOps = concat
|
||||
> [ [ (x ++ "+", [Symbol x, Symbol "+"])
|
||||
> , (x ++ "-", [Symbol x, Symbol "-"]) ]
|
||||
> | x <- somePostgresOpsWhichWontAddTrailingPlusMinus 2
|
||||
> ]
|
||||
> edgeCasePlusMinusComments =
|
||||
> [("---", [LineComment "---"])
|
||||
> ,("+--", [Symbol "+", LineComment "--"])
|
||||
> ,("-/**/", [Symbol "-", BlockComment "/**/"])
|
||||
> ,("+/**/", [Symbol "+", BlockComment "/**/"])
|
||||
> ]
|
||||
|
||||
|
||||
> sqlServerLexerTests :: TestItem
|
||||
> sqlServerLexerTests = Group "sqlServerLexTests" $
|
||||
> [ LexTest sqlserver s t | (s,t) <-
|
||||
> [("@variable", [(PrefixedVariable '@' "variable")])
|
||||
> ,("#variable", [(PrefixedVariable '#' "variable")])
|
||||
> ,("[quoted identifier]", [(Identifier (Just ("[", "]")) "quoted identifier")])
|
||||
> ]]
|
||||
|
||||
> oracleLexerTests :: TestItem
|
||||
> oracleLexerTests = Group "oracleLexTests" $
|
||||
> [] -- nothing oracle specific atm
|
||||
|
||||
> mySqlLexerTests :: TestItem
|
||||
> mySqlLexerTests = Group "mySqlLexerTests" $
|
||||
> [ LexTest mysql s t | (s,t) <-
|
||||
> [("`quoted identifier`", [(Identifier (Just ("`", "`")) "quoted identifier")])
|
||||
> ]
|
||||
> ]
|
||||
|
||||
> odbcLexerTests :: TestItem
|
||||
> odbcLexerTests = Group "odbcLexTests" $
|
||||
> [ LexTest sqlserver {diOdbc = True} s t | (s,t) <-
|
||||
> [("{}", [Symbol "{", Symbol "}"])
|
||||
> ]]
|
||||
> ++ [LexFails sqlserver {diOdbc = False} "{"
|
||||
> ,LexFails sqlserver {diOdbc = False} "}"]
|
||||
|
||||
> combos :: [a] -> Int -> [[a]]
|
||||
> combos _ 0 = [[]]
|
||||
> combos l n = [ x:tl | x <- l, tl <- combos l (n - 1) ]
|
||||
|
||||
figure out a way to do quickcheck testing:
|
||||
1. generate valid tokens and check they parse
|
||||
|
||||
2. combine two generated tokens together for the combo testing
|
||||
|
||||
this especially will work much better for the postgresql extensible
|
||||
operator tests which doing exhaustively takes ages and doesn't bring
|
||||
much benefit over testing a few using quickcheck.
|
42
tools/Language/SQL/SimpleSQL/MySQL.hs
Normal file
42
tools/Language/SQL/SimpleSQL/MySQL.hs
Normal file
|
@ -0,0 +1,42 @@
|
|||
|
||||
-- Tests for mysql dialect parsing
|
||||
|
||||
module Language.SQL.SimpleSQL.MySQL (mySQLTests) where
|
||||
|
||||
import Language.SQL.SimpleSQL.TestTypes
|
||||
import Language.SQL.SimpleSQL.Syntax
|
||||
|
||||
mySQLTests :: TestItem
|
||||
mySQLTests = Group "mysql dialect"
|
||||
[backtickQuotes
|
||||
,limit]
|
||||
|
||||
{-
|
||||
backtick quotes
|
||||
|
||||
limit syntax
|
||||
|
||||
[LIMIT {[offset,] row_count | row_count OFFSET offset}]
|
||||
-}
|
||||
|
||||
backtickQuotes :: TestItem
|
||||
backtickQuotes = Group "backtickQuotes" (map (uncurry (TestScalarExpr mysql))
|
||||
[("`test`", Iden [Name (Just ("`","`")) "test"])
|
||||
]
|
||||
++ [ParseScalarExprFails ansi2011 "`test`"]
|
||||
)
|
||||
|
||||
limit :: TestItem
|
||||
limit = Group "queries" ( map (uncurry (TestQueryExpr mysql))
|
||||
[("select * from t limit 5"
|
||||
,sel {qeFetchFirst = Just (NumLit "5")}
|
||||
)
|
||||
]
|
||||
++ [ParseQueryExprFails mysql "select a from t fetch next 10 rows only;"
|
||||
,ParseQueryExprFails ansi2011 "select * from t limit 5"]
|
||||
)
|
||||
where
|
||||
sel = makeSelect
|
||||
{qeSelectList = [(Star, Nothing)]
|
||||
,qeFrom = [TRSimple [Name Nothing "t"]]
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
|
||||
Tests for mysql dialect parsing
|
||||
|
||||
> module Language.SQL.SimpleSQL.MySQL (mySQLTests) where
|
||||
|
||||
> import Language.SQL.SimpleSQL.TestTypes
|
||||
> import Language.SQL.SimpleSQL.Syntax
|
||||
|
||||
> mySQLTests :: TestItem
|
||||
> mySQLTests = Group "mysql dialect"
|
||||
> [backtickQuotes
|
||||
> ,limit]
|
||||
|
||||
backtick quotes
|
||||
|
||||
limit syntax
|
||||
|
||||
[LIMIT {[offset,] row_count | row_count OFFSET offset}]
|
||||
|
||||
> backtickQuotes :: TestItem
|
||||
> backtickQuotes = Group "backtickQuotes" (map (uncurry (TestScalarExpr mysql))
|
||||
> [("`test`", Iden [Name (Just ("`","`")) "test"])
|
||||
> ]
|
||||
> ++ [ParseScalarExprFails ansi2011 "`test`"]
|
||||
> )
|
||||
|
||||
> limit :: TestItem
|
||||
> limit = Group "queries" ( map (uncurry (TestQueryExpr mysql))
|
||||
> [("select * from t limit 5"
|
||||
> ,sel {qeFetchFirst = Just (NumLit "5")}
|
||||
> )
|
||||
> ]
|
||||
> ++ [ParseQueryExprFails mysql "select a from t fetch next 10 rows only;"
|
||||
> ,ParseQueryExprFails ansi2011 "select * from t limit 5"]
|
||||
> )
|
||||
> where
|
||||
> sel = makeSelect
|
||||
> {qeSelectList = [(Star, Nothing)]
|
||||
> ,qeFrom = [TRSimple [Name Nothing "t"]]
|
||||
> }
|
52
tools/Language/SQL/SimpleSQL/Odbc.hs
Normal file
52
tools/Language/SQL/SimpleSQL/Odbc.hs
Normal file
|
@ -0,0 +1,52 @@
|
|||
|
||||
module Language.SQL.SimpleSQL.Odbc (odbcTests) where
|
||||
|
||||
import Language.SQL.SimpleSQL.TestTypes
|
||||
import Language.SQL.SimpleSQL.Syntax
|
||||
|
||||
odbcTests :: TestItem
|
||||
odbcTests = Group "odbc" [
|
||||
Group "datetime" [
|
||||
e "{d '2000-01-01'}" (OdbcLiteral OLDate "2000-01-01")
|
||||
,e "{t '12:00:01.1'}" (OdbcLiteral OLTime "12:00:01.1")
|
||||
,e "{ts '2000-01-01 12:00:01.1'}"
|
||||
(OdbcLiteral OLTimestamp "2000-01-01 12:00:01.1")
|
||||
]
|
||||
,Group "functions" [
|
||||
e "{fn CHARACTER_LENGTH(string_exp)}"
|
||||
$ OdbcFunc (ap "CHARACTER_LENGTH" [iden "string_exp"])
|
||||
,e "{fn EXTRACT(day from t)}"
|
||||
$ OdbcFunc (SpecialOpK [Name Nothing "extract"] (Just $ Iden [Name Nothing "day"]) [("from", Iden [Name Nothing "t"])])
|
||||
,e "{fn now()}"
|
||||
$ OdbcFunc (ap "now" [])
|
||||
,e "{fn CONVERT('2000-01-01', SQL_DATE)}"
|
||||
$ OdbcFunc (ap "CONVERT"
|
||||
[StringLit "'" "'" "2000-01-01"
|
||||
,iden "SQL_DATE"])
|
||||
,e "{fn CONVERT({fn CURDATE()}, SQL_DATE)}"
|
||||
$ OdbcFunc (ap "CONVERT"
|
||||
[OdbcFunc (ap "CURDATE" [])
|
||||
,iden "SQL_DATE"])
|
||||
]
|
||||
,Group "outer join" [
|
||||
TestQueryExpr ansi2011 {diOdbc=True}
|
||||
"select * from {oj t1 left outer join t2 on expr}"
|
||||
$ makeSelect
|
||||
{qeSelectList = [(Star,Nothing)]
|
||||
,qeFrom = [TROdbc $ TRJoin (TRSimple [Name Nothing "t1"]) False JLeft (TRSimple [Name Nothing "t2"])
|
||||
(Just $ JoinOn $ Iden [Name Nothing "expr"])]}]
|
||||
,Group "check parsing bugs" [
|
||||
TestQueryExpr ansi2011 {diOdbc=True}
|
||||
"select {fn CONVERT(cint,SQL_BIGINT)} from t;"
|
||||
$ makeSelect
|
||||
{qeSelectList = [(OdbcFunc (ap "CONVERT"
|
||||
[iden "cint"
|
||||
,iden "SQL_BIGINT"]), Nothing)]
|
||||
,qeFrom = [TRSimple [Name Nothing "t"]]}]
|
||||
]
|
||||
where
|
||||
e = TestScalarExpr ansi2011 {diOdbc = True}
|
||||
--tsql = ParseProcSql defaultParseFlags {pfDialect=sqlServerDialect}
|
||||
ap n = App [Name Nothing n]
|
||||
iden n = Iden [Name Nothing n]
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
|
||||
> module Language.SQL.SimpleSQL.Odbc (odbcTests) where
|
||||
|
||||
> import Language.SQL.SimpleSQL.TestTypes
|
||||
> import Language.SQL.SimpleSQL.Syntax
|
||||
|
||||
> odbcTests :: TestItem
|
||||
> odbcTests = Group "odbc" [
|
||||
> Group "datetime" [
|
||||
> e "{d '2000-01-01'}" (OdbcLiteral OLDate "2000-01-01")
|
||||
> ,e "{t '12:00:01.1'}" (OdbcLiteral OLTime "12:00:01.1")
|
||||
> ,e "{ts '2000-01-01 12:00:01.1'}"
|
||||
> (OdbcLiteral OLTimestamp "2000-01-01 12:00:01.1")
|
||||
> ]
|
||||
> ,Group "functions" [
|
||||
> e "{fn CHARACTER_LENGTH(string_exp)}"
|
||||
> $ OdbcFunc (ap "CHARACTER_LENGTH" [iden "string_exp"])
|
||||
> ,e "{fn EXTRACT(day from t)}"
|
||||
> $ OdbcFunc (SpecialOpK [Name Nothing "extract"] (Just $ Iden [Name Nothing "day"]) [("from", Iden [Name Nothing "t"])])
|
||||
> ,e "{fn now()}"
|
||||
> $ OdbcFunc (ap "now" [])
|
||||
> ,e "{fn CONVERT('2000-01-01', SQL_DATE)}"
|
||||
> $ OdbcFunc (ap "CONVERT"
|
||||
> [StringLit "'" "'" "2000-01-01"
|
||||
> ,iden "SQL_DATE"])
|
||||
> ,e "{fn CONVERT({fn CURDATE()}, SQL_DATE)}"
|
||||
> $ OdbcFunc (ap "CONVERT"
|
||||
> [OdbcFunc (ap "CURDATE" [])
|
||||
> ,iden "SQL_DATE"])
|
||||
> ]
|
||||
> ,Group "outer join" [
|
||||
> TestQueryExpr ansi2011 {diOdbc=True}
|
||||
> "select * from {oj t1 left outer join t2 on expr}"
|
||||
> $ makeSelect
|
||||
> {qeSelectList = [(Star,Nothing)]
|
||||
> ,qeFrom = [TROdbc $ TRJoin (TRSimple [Name Nothing "t1"]) False JLeft (TRSimple [Name Nothing "t2"])
|
||||
> (Just $ JoinOn $ Iden [Name Nothing "expr"])]}]
|
||||
> ,Group "check parsing bugs" [
|
||||
> TestQueryExpr ansi2011 {diOdbc=True}
|
||||
> "select {fn CONVERT(cint,SQL_BIGINT)} from t;"
|
||||
> $ makeSelect
|
||||
> {qeSelectList = [(OdbcFunc (ap "CONVERT"
|
||||
> [iden "cint"
|
||||
> ,iden "SQL_BIGINT"]), Nothing)]
|
||||
> ,qeFrom = [TRSimple [Name Nothing "t"]]}]
|
||||
> ]
|
||||
> where
|
||||
> e = TestScalarExpr ansi2011 {diOdbc = True}
|
||||
> --tsql = ParseProcSql defaultParseFlags {pfDialect=sqlServerDialect}
|
||||
> ap n = App [Name Nothing n]
|
||||
> iden n = Iden [Name Nothing n]
|
||||
|
29
tools/Language/SQL/SimpleSQL/Oracle.hs
Normal file
29
tools/Language/SQL/SimpleSQL/Oracle.hs
Normal file
|
@ -0,0 +1,29 @@
|
|||
|
||||
-- Tests for oracle dialect parsing
|
||||
|
||||
module Language.SQL.SimpleSQL.Oracle (oracleTests) where
|
||||
|
||||
import Language.SQL.SimpleSQL.TestTypes
|
||||
import Language.SQL.SimpleSQL.Syntax
|
||||
|
||||
oracleTests :: TestItem
|
||||
oracleTests = Group "oracle dialect"
|
||||
[oracleLobUnits]
|
||||
|
||||
|
||||
oracleLobUnits :: TestItem
|
||||
oracleLobUnits = Group "oracleLobUnits" (map (uncurry (TestScalarExpr oracle))
|
||||
[("cast (a as varchar2(3 char))"
|
||||
,Cast (Iden [Name Nothing "a"]) (
|
||||
PrecLengthTypeName [Name Nothing "varchar2"] 3 Nothing (Just PrecCharacters)))
|
||||
,("cast (a as varchar2(3 byte))"
|
||||
,Cast (Iden [Name Nothing "a"]) (
|
||||
PrecLengthTypeName [Name Nothing "varchar2"] 3 Nothing (Just PrecOctets)))
|
||||
]
|
||||
++ [TestStatement oracle
|
||||
"create table t (a varchar2(55 BYTE));"
|
||||
$ CreateTable [Name Nothing "t"]
|
||||
[TableColumnDef $ ColumnDef (Name Nothing "a")
|
||||
(PrecLengthTypeName [Name Nothing "varchar2"] 55 Nothing (Just PrecOctets))
|
||||
Nothing []]]
|
||||
)
|
|
@ -1,29 +0,0 @@
|
|||
|
||||
Tests for oracle dialect parsing
|
||||
|
||||
> module Language.SQL.SimpleSQL.Oracle (oracleTests) where
|
||||
|
||||
> import Language.SQL.SimpleSQL.TestTypes
|
||||
> import Language.SQL.SimpleSQL.Syntax
|
||||
|
||||
> oracleTests :: TestItem
|
||||
> oracleTests = Group "oracle dialect"
|
||||
> [oracleLobUnits]
|
||||
|
||||
|
||||
> oracleLobUnits :: TestItem
|
||||
> oracleLobUnits = Group "oracleLobUnits" (map (uncurry (TestScalarExpr oracle))
|
||||
> [("cast (a as varchar2(3 char))"
|
||||
> ,Cast (Iden [Name Nothing "a"]) (
|
||||
> PrecLengthTypeName [Name Nothing "varchar2"] 3 Nothing (Just PrecCharacters)))
|
||||
> ,("cast (a as varchar2(3 byte))"
|
||||
> ,Cast (Iden [Name Nothing "a"]) (
|
||||
> PrecLengthTypeName [Name Nothing "varchar2"] 3 Nothing (Just PrecOctets)))
|
||||
> ]
|
||||
> ++ [TestStatement oracle
|
||||
> "create table t (a varchar2(55 BYTE));"
|
||||
> $ CreateTable [Name Nothing "t"]
|
||||
> [TableColumnDef $ ColumnDef (Name Nothing "a")
|
||||
> (PrecLengthTypeName [Name Nothing "varchar2"] 55 Nothing (Just PrecOctets))
|
||||
> Nothing []]]
|
||||
> )
|
278
tools/Language/SQL/SimpleSQL/Postgres.hs
Normal file
278
tools/Language/SQL/SimpleSQL/Postgres.hs
Normal file
|
@ -0,0 +1,278 @@
|
|||
|
||||
{-
|
||||
Here are some tests taken from the SQL in the postgres manual. Almost
|
||||
all of the postgres specific syntax has been skipped, this can be
|
||||
revisited when the dialect support is added.
|
||||
-}
|
||||
|
||||
module Language.SQL.SimpleSQL.Postgres (postgresTests) where
|
||||
|
||||
import Language.SQL.SimpleSQL.TestTypes
|
||||
|
||||
postgresTests :: TestItem
|
||||
postgresTests = Group "postgresTests" $ map (ParseQueryExpr ansi2011)
|
||||
|
||||
{-
|
||||
lexical syntax section
|
||||
|
||||
TODO: get all the commented out tests working
|
||||
-}
|
||||
|
||||
[-- "SELECT 'foo'\n\
|
||||
-- \'bar';" -- this should parse as select 'foobar'
|
||||
-- ,
|
||||
"SELECT name, (SELECT max(pop) FROM cities\n\
|
||||
\ WHERE cities.state = states.name)\n\
|
||||
\ FROM states;"
|
||||
,"SELECT ROW(1,2.5,'this is a test');"
|
||||
|
||||
,"SELECT ROW(t.*, 42) FROM t;"
|
||||
,"SELECT ROW(t.f1, t.f2, 42) FROM t;"
|
||||
,"SELECT getf1(CAST(ROW(11,'this is a test',2.5) AS myrowtype));"
|
||||
|
||||
,"SELECT ROW(1,2.5,'this is a test') = ROW(1, 3, 'not the same');"
|
||||
|
||||
-- table is a reservered keyword?
|
||||
--,"SELECT ROW(table.*) IS NULL FROM table;"
|
||||
,"SELECT ROW(tablex.*) IS NULL FROM tablex;"
|
||||
|
||||
,"SELECT true OR somefunc();"
|
||||
|
||||
,"SELECT somefunc() OR true;"
|
||||
|
||||
-- queries section
|
||||
|
||||
,"SELECT * FROM t1 CROSS JOIN t2;"
|
||||
,"SELECT * FROM t1 INNER JOIN t2 ON t1.num = t2.num;"
|
||||
,"SELECT * FROM t1 INNER JOIN t2 USING (num);"
|
||||
,"SELECT * FROM t1 NATURAL INNER JOIN t2;"
|
||||
,"SELECT * FROM t1 LEFT JOIN t2 ON t1.num = t2.num;"
|
||||
,"SELECT * FROM t1 LEFT JOIN t2 USING (num);"
|
||||
,"SELECT * FROM t1 RIGHT JOIN t2 ON t1.num = t2.num;"
|
||||
,"SELECT * FROM t1 FULL JOIN t2 ON t1.num = t2.num;"
|
||||
,"SELECT * FROM t1 LEFT JOIN t2 ON t1.num = t2.num AND t2.value = 'xxx';"
|
||||
,"SELECT * FROM t1 LEFT JOIN t2 ON t1.num = t2.num WHERE t2.value = 'xxx';"
|
||||
|
||||
,"SELECT * FROM some_very_long_table_name s\n\
|
||||
\JOIN another_fairly_long_name a ON s.id = a.num;"
|
||||
,"SELECT * FROM people AS mother JOIN people AS child\n\
|
||||
\ ON mother.id = child.mother_id;"
|
||||
,"SELECT * FROM my_table AS a CROSS JOIN my_table AS b;"
|
||||
,"SELECT * FROM (my_table AS a CROSS JOIN my_table) AS b;"
|
||||
,"SELECT * FROM getfoo(1) AS t1;"
|
||||
,"SELECT * FROM foo\n\
|
||||
\ WHERE foosubid IN (\n\
|
||||
\ SELECT foosubid\n\
|
||||
\ FROM getfoo(foo.fooid) z\n\
|
||||
\ WHERE z.fooid = foo.fooid\n\
|
||||
\ );"
|
||||
{-,"SELECT *\n\
|
||||
\ FROM dblink('dbname=mydb', 'SELECT proname, prosrc FROM pg_proc')\n\
|
||||
\ AS t1(proname name, prosrc text)\n\
|
||||
\ WHERE proname LIKE 'bytea%';"-} -- types in the alias??
|
||||
|
||||
,"SELECT * FROM foo, LATERAL (SELECT * FROM bar WHERE bar.id = foo.bar_id) ss;"
|
||||
,"SELECT * FROM foo, bar WHERE bar.id = foo.bar_id;"
|
||||
|
||||
{-,"SELECT p1.id, p2.id, v1, v2\n\
|
||||
\FROM polygons p1, polygons p2,\n\
|
||||
\ LATERAL vertices(p1.poly) v1,\n\
|
||||
\ LATERAL vertices(p2.poly) v2\n\
|
||||
\WHERE (v1 <-> v2) < 10 AND p1.id != p2.id;"-} -- <-> operator?
|
||||
|
||||
{-,"SELECT p1.id, p2.id, v1, v2\n\
|
||||
\FROM polygons p1 CROSS JOIN LATERAL vertices(p1.poly) v1,\n\
|
||||
\ polygons p2 CROSS JOIN LATERAL vertices(p2.poly) v2\n\
|
||||
\WHERE (v1 <-> v2) < 10 AND p1.id != p2.id;"-}
|
||||
|
||||
,"SELECT m.name\n\
|
||||
\FROM manufacturers m LEFT JOIN LATERAL get_product_names(m.id) pname ON true\n\
|
||||
\WHERE pname IS NULL;"
|
||||
|
||||
|
||||
,"SELECT * FROM fdt WHERE c1 > 5"
|
||||
|
||||
,"SELECT * FROM fdt WHERE c1 IN (1, 2, 3)"
|
||||
|
||||
,"SELECT * FROM fdt WHERE c1 IN (SELECT c1 FROM t2)"
|
||||
|
||||
,"SELECT * FROM fdt WHERE c1 IN (SELECT c3 FROM t2 WHERE c2 = fdt.c1 + 10)"
|
||||
|
||||
,"SELECT * FROM fdt WHERE c1 BETWEEN \n\
|
||||
\ (SELECT c3 FROM t2 WHERE c2 = fdt.c1 + 10) AND 100"
|
||||
|
||||
,"SELECT * FROM fdt WHERE EXISTS (SELECT c1 FROM t2 WHERE c2 > fdt.c1)"
|
||||
|
||||
,"SELECT * FROM test1;"
|
||||
|
||||
,"SELECT x FROM test1 GROUP BY x;"
|
||||
,"SELECT x, sum(y) FROM test1 GROUP BY x;"
|
||||
-- s.date changed to s.datex because of reserved keyword
|
||||
-- handling, not sure if this is correct or not for ansi sql
|
||||
,"SELECT product_id, p.name, (sum(s.units) * p.price) AS sales\n\
|
||||
\ FROM products p LEFT JOIN sales s USING (product_id)\n\
|
||||
\ GROUP BY product_id, p.name, p.price;"
|
||||
|
||||
,"SELECT x, sum(y) FROM test1 GROUP BY x HAVING sum(y) > 3;"
|
||||
,"SELECT x, sum(y) FROM test1 GROUP BY x HAVING x < 'c';"
|
||||
,"SELECT product_id, p.name, (sum(s.units) * (p.price - p.cost)) AS profit\n\
|
||||
\ FROM products p LEFT JOIN sales s USING (product_id)\n\
|
||||
\ WHERE s.datex > CURRENT_DATE - INTERVAL '4 weeks'\n\
|
||||
\ GROUP BY product_id, p.name, p.price, p.cost\n\
|
||||
\ HAVING sum(p.price * s.units) > 5000;"
|
||||
|
||||
,"SELECT a, b, c FROM t"
|
||||
|
||||
,"SELECT tbl1.a, tbl2.a, tbl1.b FROM t"
|
||||
|
||||
,"SELECT tbl1.*, tbl2.a FROM t"
|
||||
|
||||
,"SELECT a AS value, b + c AS sum FROM t"
|
||||
|
||||
,"SELECT a \"value\", b + c AS sum FROM t"
|
||||
|
||||
,"SELECT DISTINCT select_list t"
|
||||
|
||||
,"VALUES (1, 'one'), (2, 'two'), (3, 'three');"
|
||||
|
||||
,"SELECT 1 AS column1, 'one' AS column2\n\
|
||||
\UNION ALL\n\
|
||||
\SELECT 2, 'two'\n\
|
||||
\UNION ALL\n\
|
||||
\SELECT 3, 'three';"
|
||||
|
||||
,"SELECT * FROM (VALUES (1, 'one'), (2, 'two'), (3, 'three')) AS t (num,letter);"
|
||||
|
||||
,"WITH regional_sales AS (\n\
|
||||
\ SELECT region, SUM(amount) AS total_sales\n\
|
||||
\ FROM orders\n\
|
||||
\ GROUP BY region\n\
|
||||
\ ), top_regions AS (\n\
|
||||
\ SELECT region\n\
|
||||
\ FROM regional_sales\n\
|
||||
\ WHERE total_sales > (SELECT SUM(total_sales)/10 FROM regional_sales)\n\
|
||||
\ )\n\
|
||||
\SELECT region,\n\
|
||||
\ product,\n\
|
||||
\ SUM(quantity) AS product_units,\n\
|
||||
\ SUM(amount) AS product_sales\n\
|
||||
\FROM orders\n\
|
||||
\WHERE region IN (SELECT region FROM top_regions)\n\
|
||||
\GROUP BY region, product;"
|
||||
|
||||
,"WITH RECURSIVE t(n) AS (\n\
|
||||
\ VALUES (1)\n\
|
||||
\ UNION ALL\n\
|
||||
\ SELECT n+1 FROM t WHERE n < 100\n\
|
||||
\)\n\
|
||||
\SELECT sum(n) FROM t"
|
||||
|
||||
,"WITH RECURSIVE included_parts(sub_part, part, quantity) AS (\n\
|
||||
\ SELECT sub_part, part, quantity FROM parts WHERE part = 'our_product'\n\
|
||||
\ UNION ALL\n\
|
||||
\ SELECT p.sub_part, p.part, p.quantity\n\
|
||||
\ FROM included_parts pr, parts p\n\
|
||||
\ WHERE p.part = pr.sub_part\n\
|
||||
\ )\n\
|
||||
\SELECT sub_part, SUM(quantity) as total_quantity\n\
|
||||
\FROM included_parts\n\
|
||||
\GROUP BY sub_part"
|
||||
|
||||
,"WITH RECURSIVE search_graph(id, link, data, depth) AS (\n\
|
||||
\ SELECT g.id, g.link, g.data, 1\n\
|
||||
\ FROM graph g\n\
|
||||
\ UNION ALL\n\
|
||||
\ SELECT g.id, g.link, g.data, sg.depth + 1\n\
|
||||
\ FROM graph g, search_graph sg\n\
|
||||
\ WHERE g.id = sg.link\n\
|
||||
\)\n\
|
||||
\SELECT * FROM search_graph;"
|
||||
|
||||
{-,"WITH RECURSIVE search_graph(id, link, data, depth, path, cycle) AS (\n\
|
||||
\ SELECT g.id, g.link, g.data, 1,\n\
|
||||
\ ARRAY[g.id],\n\
|
||||
\ false\n\
|
||||
\ FROM graph g\n\
|
||||
\ UNION ALL\n\
|
||||
\ SELECT g.id, g.link, g.data, sg.depth + 1,\n\
|
||||
\ path || g.id,\n\
|
||||
\ g.id = ANY(path)\n\
|
||||
\ FROM graph g, search_graph sg\n\
|
||||
\ WHERE g.id = sg.link AND NOT cycle\n\
|
||||
\)\n\
|
||||
\SELECT * FROM search_graph;"-} -- ARRAY
|
||||
|
||||
{-,"WITH RECURSIVE search_graph(id, link, data, depth, path, cycle) AS (\n\
|
||||
\ SELECT g.id, g.link, g.data, 1,\n\
|
||||
\ ARRAY[ROW(g.f1, g.f2)],\n\
|
||||
\ false\n\
|
||||
\ FROM graph g\n\
|
||||
\ UNION ALL\n\
|
||||
\ SELECT g.id, g.link, g.data, sg.depth + 1,\n\
|
||||
\ path || ROW(g.f1, g.f2),\n\
|
||||
\ ROW(g.f1, g.f2) = ANY(path)\n\
|
||||
\ FROM graph g, search_graph sg\n\
|
||||
\ WHERE g.id = sg.link AND NOT cycle\n\
|
||||
\)\n\
|
||||
\SELECT * FROM search_graph;"-} -- ARRAY
|
||||
|
||||
,"WITH RECURSIVE t(n) AS (\n\
|
||||
\ SELECT 1\n\
|
||||
\ UNION ALL\n\
|
||||
\ SELECT n+1 FROM t\n\
|
||||
\)\n\
|
||||
\SELECT n FROM t --LIMIT 100;" -- limit is not standard
|
||||
|
||||
-- select page reference
|
||||
|
||||
,"SELECT f.title, f.did, d.name, f.date_prod, f.kind\n\
|
||||
\ FROM distributors d, films f\n\
|
||||
\ WHERE f.did = d.did"
|
||||
|
||||
,"SELECT kind, sum(len) AS total\n\
|
||||
\ FROM films\n\
|
||||
\ GROUP BY kind\n\
|
||||
\ HAVING sum(len) < interval '5 hours';"
|
||||
|
||||
,"SELECT * FROM distributors ORDER BY name;"
|
||||
,"SELECT * FROM distributors ORDER BY 2;"
|
||||
|
||||
,"SELECT distributors.name\n\
|
||||
\ FROM distributors\n\
|
||||
\ WHERE distributors.name LIKE 'W%'\n\
|
||||
\UNION\n\
|
||||
\SELECT actors.name\n\
|
||||
\ FROM actors\n\
|
||||
\ WHERE actors.name LIKE 'W%';"
|
||||
|
||||
,"WITH t AS (\n\
|
||||
\ SELECT random() as x FROM generate_series(1, 3)\n\
|
||||
\ )\n\
|
||||
\SELECT * FROM t\n\
|
||||
\UNION ALL\n\
|
||||
\SELECT * FROM t"
|
||||
|
||||
,"WITH RECURSIVE employee_recursive(distance, employee_name, manager_name) AS (\n\
|
||||
\ SELECT 1, employee_name, manager_name\n\
|
||||
\ FROM employee\n\
|
||||
\ WHERE manager_name = 'Mary'\n\
|
||||
\ UNION ALL\n\
|
||||
\ SELECT er.distance + 1, e.employee_name, e.manager_name\n\
|
||||
\ FROM employee_recursive er, employee e\n\
|
||||
\ WHERE er.employee_name = e.manager_name\n\
|
||||
\ )\n\
|
||||
\SELECT distance, employee_name FROM employee_recursive;"
|
||||
|
||||
,"SELECT m.name AS mname, pname\n\
|
||||
\FROM manufacturers m, LATERAL get_product_names(m.id) pname;"
|
||||
|
||||
,"SELECT m.name AS mname, pname\n\
|
||||
\FROM manufacturers m LEFT JOIN LATERAL get_product_names(m.id) pname ON true;"
|
||||
|
||||
,"SELECT 2+2;"
|
||||
|
||||
-- simple-sql-parser doesn't support where without from
|
||||
-- this can be added for the postgres dialect when it is written
|
||||
--,"SELECT distributors.* WHERE distributors.name = 'Westward';"
|
||||
|
||||
]
|
|
@ -1,274 +0,0 @@
|
|||
|
||||
Here are some tests taken from the SQL in the postgres manual. Almost
|
||||
all of the postgres specific syntax has been skipped, this can be
|
||||
revisited when the dialect support is added.
|
||||
|
||||
> module Language.SQL.SimpleSQL.Postgres (postgresTests) where
|
||||
|
||||
> import Language.SQL.SimpleSQL.TestTypes
|
||||
|
||||
> postgresTests :: TestItem
|
||||
> postgresTests = Group "postgresTests" $ map (ParseQueryExpr ansi2011)
|
||||
|
||||
lexical syntax section
|
||||
|
||||
TODO: get all the commented out tests working
|
||||
|
||||
> [-- "SELECT 'foo'\n\
|
||||
> -- \'bar';" -- this should parse as select 'foobar'
|
||||
> -- ,
|
||||
> "SELECT name, (SELECT max(pop) FROM cities\n\
|
||||
> \ WHERE cities.state = states.name)\n\
|
||||
> \ FROM states;"
|
||||
> ,"SELECT ROW(1,2.5,'this is a test');"
|
||||
|
||||
> ,"SELECT ROW(t.*, 42) FROM t;"
|
||||
> ,"SELECT ROW(t.f1, t.f2, 42) FROM t;"
|
||||
> ,"SELECT getf1(CAST(ROW(11,'this is a test',2.5) AS myrowtype));"
|
||||
|
||||
> ,"SELECT ROW(1,2.5,'this is a test') = ROW(1, 3, 'not the same');"
|
||||
|
||||
> -- table is a reservered keyword?
|
||||
> --,"SELECT ROW(table.*) IS NULL FROM table;"
|
||||
> ,"SELECT ROW(tablex.*) IS NULL FROM tablex;"
|
||||
|
||||
> ,"SELECT true OR somefunc();"
|
||||
|
||||
> ,"SELECT somefunc() OR true;"
|
||||
|
||||
queries section
|
||||
|
||||
> ,"SELECT * FROM t1 CROSS JOIN t2;"
|
||||
> ,"SELECT * FROM t1 INNER JOIN t2 ON t1.num = t2.num;"
|
||||
> ,"SELECT * FROM t1 INNER JOIN t2 USING (num);"
|
||||
> ,"SELECT * FROM t1 NATURAL INNER JOIN t2;"
|
||||
> ,"SELECT * FROM t1 LEFT JOIN t2 ON t1.num = t2.num;"
|
||||
> ,"SELECT * FROM t1 LEFT JOIN t2 USING (num);"
|
||||
> ,"SELECT * FROM t1 RIGHT JOIN t2 ON t1.num = t2.num;"
|
||||
> ,"SELECT * FROM t1 FULL JOIN t2 ON t1.num = t2.num;"
|
||||
> ,"SELECT * FROM t1 LEFT JOIN t2 ON t1.num = t2.num AND t2.value = 'xxx';"
|
||||
> ,"SELECT * FROM t1 LEFT JOIN t2 ON t1.num = t2.num WHERE t2.value = 'xxx';"
|
||||
|
||||
> ,"SELECT * FROM some_very_long_table_name s\n\
|
||||
> \JOIN another_fairly_long_name a ON s.id = a.num;"
|
||||
> ,"SELECT * FROM people AS mother JOIN people AS child\n\
|
||||
> \ ON mother.id = child.mother_id;"
|
||||
> ,"SELECT * FROM my_table AS a CROSS JOIN my_table AS b;"
|
||||
> ,"SELECT * FROM (my_table AS a CROSS JOIN my_table) AS b;"
|
||||
> ,"SELECT * FROM getfoo(1) AS t1;"
|
||||
> ,"SELECT * FROM foo\n\
|
||||
> \ WHERE foosubid IN (\n\
|
||||
> \ SELECT foosubid\n\
|
||||
> \ FROM getfoo(foo.fooid) z\n\
|
||||
> \ WHERE z.fooid = foo.fooid\n\
|
||||
> \ );"
|
||||
> {-,"SELECT *\n\
|
||||
> \ FROM dblink('dbname=mydb', 'SELECT proname, prosrc FROM pg_proc')\n\
|
||||
> \ AS t1(proname name, prosrc text)\n\
|
||||
> \ WHERE proname LIKE 'bytea%';"-} -- types in the alias??
|
||||
|
||||
> ,"SELECT * FROM foo, LATERAL (SELECT * FROM bar WHERE bar.id = foo.bar_id) ss;"
|
||||
> ,"SELECT * FROM foo, bar WHERE bar.id = foo.bar_id;"
|
||||
|
||||
> {-,"SELECT p1.id, p2.id, v1, v2\n\
|
||||
> \FROM polygons p1, polygons p2,\n\
|
||||
> \ LATERAL vertices(p1.poly) v1,\n\
|
||||
> \ LATERAL vertices(p2.poly) v2\n\
|
||||
> \WHERE (v1 <-> v2) < 10 AND p1.id != p2.id;"-} -- <-> operator?
|
||||
|
||||
> {-,"SELECT p1.id, p2.id, v1, v2\n\
|
||||
> \FROM polygons p1 CROSS JOIN LATERAL vertices(p1.poly) v1,\n\
|
||||
> \ polygons p2 CROSS JOIN LATERAL vertices(p2.poly) v2\n\
|
||||
> \WHERE (v1 <-> v2) < 10 AND p1.id != p2.id;"-}
|
||||
|
||||
> ,"SELECT m.name\n\
|
||||
> \FROM manufacturers m LEFT JOIN LATERAL get_product_names(m.id) pname ON true\n\
|
||||
> \WHERE pname IS NULL;"
|
||||
|
||||
|
||||
> ,"SELECT * FROM fdt WHERE c1 > 5"
|
||||
|
||||
> ,"SELECT * FROM fdt WHERE c1 IN (1, 2, 3)"
|
||||
|
||||
> ,"SELECT * FROM fdt WHERE c1 IN (SELECT c1 FROM t2)"
|
||||
|
||||
> ,"SELECT * FROM fdt WHERE c1 IN (SELECT c3 FROM t2 WHERE c2 = fdt.c1 + 10)"
|
||||
|
||||
> ,"SELECT * FROM fdt WHERE c1 BETWEEN \n\
|
||||
> \ (SELECT c3 FROM t2 WHERE c2 = fdt.c1 + 10) AND 100"
|
||||
|
||||
> ,"SELECT * FROM fdt WHERE EXISTS (SELECT c1 FROM t2 WHERE c2 > fdt.c1)"
|
||||
|
||||
> ,"SELECT * FROM test1;"
|
||||
|
||||
> ,"SELECT x FROM test1 GROUP BY x;"
|
||||
> ,"SELECT x, sum(y) FROM test1 GROUP BY x;"
|
||||
> -- s.date changed to s.datex because of reserved keyword
|
||||
> -- handling, not sure if this is correct or not for ansi sql
|
||||
> ,"SELECT product_id, p.name, (sum(s.units) * p.price) AS sales\n\
|
||||
> \ FROM products p LEFT JOIN sales s USING (product_id)\n\
|
||||
> \ GROUP BY product_id, p.name, p.price;"
|
||||
|
||||
> ,"SELECT x, sum(y) FROM test1 GROUP BY x HAVING sum(y) > 3;"
|
||||
> ,"SELECT x, sum(y) FROM test1 GROUP BY x HAVING x < 'c';"
|
||||
> ,"SELECT product_id, p.name, (sum(s.units) * (p.price - p.cost)) AS profit\n\
|
||||
> \ FROM products p LEFT JOIN sales s USING (product_id)\n\
|
||||
> \ WHERE s.datex > CURRENT_DATE - INTERVAL '4 weeks'\n\
|
||||
> \ GROUP BY product_id, p.name, p.price, p.cost\n\
|
||||
> \ HAVING sum(p.price * s.units) > 5000;"
|
||||
|
||||
> ,"SELECT a, b, c FROM t"
|
||||
|
||||
> ,"SELECT tbl1.a, tbl2.a, tbl1.b FROM t"
|
||||
|
||||
> ,"SELECT tbl1.*, tbl2.a FROM t"
|
||||
|
||||
> ,"SELECT a AS value, b + c AS sum FROM t"
|
||||
|
||||
> ,"SELECT a \"value\", b + c AS sum FROM t"
|
||||
|
||||
> ,"SELECT DISTINCT select_list t"
|
||||
|
||||
> ,"VALUES (1, 'one'), (2, 'two'), (3, 'three');"
|
||||
|
||||
> ,"SELECT 1 AS column1, 'one' AS column2\n\
|
||||
> \UNION ALL\n\
|
||||
> \SELECT 2, 'two'\n\
|
||||
> \UNION ALL\n\
|
||||
> \SELECT 3, 'three';"
|
||||
|
||||
> ,"SELECT * FROM (VALUES (1, 'one'), (2, 'two'), (3, 'three')) AS t (num,letter);"
|
||||
|
||||
> ,"WITH regional_sales AS (\n\
|
||||
> \ SELECT region, SUM(amount) AS total_sales\n\
|
||||
> \ FROM orders\n\
|
||||
> \ GROUP BY region\n\
|
||||
> \ ), top_regions AS (\n\
|
||||
> \ SELECT region\n\
|
||||
> \ FROM regional_sales\n\
|
||||
> \ WHERE total_sales > (SELECT SUM(total_sales)/10 FROM regional_sales)\n\
|
||||
> \ )\n\
|
||||
> \SELECT region,\n\
|
||||
> \ product,\n\
|
||||
> \ SUM(quantity) AS product_units,\n\
|
||||
> \ SUM(amount) AS product_sales\n\
|
||||
> \FROM orders\n\
|
||||
> \WHERE region IN (SELECT region FROM top_regions)\n\
|
||||
> \GROUP BY region, product;"
|
||||
|
||||
> ,"WITH RECURSIVE t(n) AS (\n\
|
||||
> \ VALUES (1)\n\
|
||||
> \ UNION ALL\n\
|
||||
> \ SELECT n+1 FROM t WHERE n < 100\n\
|
||||
> \)\n\
|
||||
> \SELECT sum(n) FROM t"
|
||||
|
||||
> ,"WITH RECURSIVE included_parts(sub_part, part, quantity) AS (\n\
|
||||
> \ SELECT sub_part, part, quantity FROM parts WHERE part = 'our_product'\n\
|
||||
> \ UNION ALL\n\
|
||||
> \ SELECT p.sub_part, p.part, p.quantity\n\
|
||||
> \ FROM included_parts pr, parts p\n\
|
||||
> \ WHERE p.part = pr.sub_part\n\
|
||||
> \ )\n\
|
||||
> \SELECT sub_part, SUM(quantity) as total_quantity\n\
|
||||
> \FROM included_parts\n\
|
||||
> \GROUP BY sub_part"
|
||||
|
||||
> ,"WITH RECURSIVE search_graph(id, link, data, depth) AS (\n\
|
||||
> \ SELECT g.id, g.link, g.data, 1\n\
|
||||
> \ FROM graph g\n\
|
||||
> \ UNION ALL\n\
|
||||
> \ SELECT g.id, g.link, g.data, sg.depth + 1\n\
|
||||
> \ FROM graph g, search_graph sg\n\
|
||||
> \ WHERE g.id = sg.link\n\
|
||||
> \)\n\
|
||||
> \SELECT * FROM search_graph;"
|
||||
|
||||
> {-,"WITH RECURSIVE search_graph(id, link, data, depth, path, cycle) AS (\n\
|
||||
> \ SELECT g.id, g.link, g.data, 1,\n\
|
||||
> \ ARRAY[g.id],\n\
|
||||
> \ false\n\
|
||||
> \ FROM graph g\n\
|
||||
> \ UNION ALL\n\
|
||||
> \ SELECT g.id, g.link, g.data, sg.depth + 1,\n\
|
||||
> \ path || g.id,\n\
|
||||
> \ g.id = ANY(path)\n\
|
||||
> \ FROM graph g, search_graph sg\n\
|
||||
> \ WHERE g.id = sg.link AND NOT cycle\n\
|
||||
> \)\n\
|
||||
> \SELECT * FROM search_graph;"-} -- ARRAY
|
||||
|
||||
> {-,"WITH RECURSIVE search_graph(id, link, data, depth, path, cycle) AS (\n\
|
||||
> \ SELECT g.id, g.link, g.data, 1,\n\
|
||||
> \ ARRAY[ROW(g.f1, g.f2)],\n\
|
||||
> \ false\n\
|
||||
> \ FROM graph g\n\
|
||||
> \ UNION ALL\n\
|
||||
> \ SELECT g.id, g.link, g.data, sg.depth + 1,\n\
|
||||
> \ path || ROW(g.f1, g.f2),\n\
|
||||
> \ ROW(g.f1, g.f2) = ANY(path)\n\
|
||||
> \ FROM graph g, search_graph sg\n\
|
||||
> \ WHERE g.id = sg.link AND NOT cycle\n\
|
||||
> \)\n\
|
||||
> \SELECT * FROM search_graph;"-} -- ARRAY
|
||||
|
||||
> ,"WITH RECURSIVE t(n) AS (\n\
|
||||
> \ SELECT 1\n\
|
||||
> \ UNION ALL\n\
|
||||
> \ SELECT n+1 FROM t\n\
|
||||
> \)\n\
|
||||
> \SELECT n FROM t --LIMIT 100;" -- limit is not standard
|
||||
|
||||
select page reference
|
||||
|
||||
> ,"SELECT f.title, f.did, d.name, f.date_prod, f.kind\n\
|
||||
> \ FROM distributors d, films f\n\
|
||||
> \ WHERE f.did = d.did"
|
||||
|
||||
> ,"SELECT kind, sum(len) AS total\n\
|
||||
> \ FROM films\n\
|
||||
> \ GROUP BY kind\n\
|
||||
> \ HAVING sum(len) < interval '5 hours';"
|
||||
|
||||
> ,"SELECT * FROM distributors ORDER BY name;"
|
||||
> ,"SELECT * FROM distributors ORDER BY 2;"
|
||||
|
||||
> ,"SELECT distributors.name\n\
|
||||
> \ FROM distributors\n\
|
||||
> \ WHERE distributors.name LIKE 'W%'\n\
|
||||
> \UNION\n\
|
||||
> \SELECT actors.name\n\
|
||||
> \ FROM actors\n\
|
||||
> \ WHERE actors.name LIKE 'W%';"
|
||||
|
||||
> ,"WITH t AS (\n\
|
||||
> \ SELECT random() as x FROM generate_series(1, 3)\n\
|
||||
> \ )\n\
|
||||
> \SELECT * FROM t\n\
|
||||
> \UNION ALL\n\
|
||||
> \SELECT * FROM t"
|
||||
|
||||
> ,"WITH RECURSIVE employee_recursive(distance, employee_name, manager_name) AS (\n\
|
||||
> \ SELECT 1, employee_name, manager_name\n\
|
||||
> \ FROM employee\n\
|
||||
> \ WHERE manager_name = 'Mary'\n\
|
||||
> \ UNION ALL\n\
|
||||
> \ SELECT er.distance + 1, e.employee_name, e.manager_name\n\
|
||||
> \ FROM employee_recursive er, employee e\n\
|
||||
> \ WHERE er.employee_name = e.manager_name\n\
|
||||
> \ )\n\
|
||||
> \SELECT distance, employee_name FROM employee_recursive;"
|
||||
|
||||
> ,"SELECT m.name AS mname, pname\n\
|
||||
> \FROM manufacturers m, LATERAL get_product_names(m.id) pname;"
|
||||
|
||||
> ,"SELECT m.name AS mname, pname\n\
|
||||
> \FROM manufacturers m LEFT JOIN LATERAL get_product_names(m.id) pname ON true;"
|
||||
|
||||
> ,"SELECT 2+2;"
|
||||
|
||||
> -- simple-sql-parser doesn't support where without from
|
||||
> -- this can be added for the postgres dialect when it is written
|
||||
> --,"SELECT distributors.* WHERE distributors.name = 'Westward';"
|
||||
|
||||
> ]
|
211
tools/Language/SQL/SimpleSQL/QueryExprComponents.hs
Normal file
211
tools/Language/SQL/SimpleSQL/QueryExprComponents.hs
Normal file
|
@ -0,0 +1,211 @@
|
|||
|
||||
{-
|
||||
These are the tests for the query expression components apart from the
|
||||
table refs which are in a separate file.
|
||||
|
||||
|
||||
These are a few misc tests which don't fit anywhere else.
|
||||
-}
|
||||
|
||||
module Language.SQL.SimpleSQL.QueryExprComponents (queryExprComponentTests) where
|
||||
|
||||
import Language.SQL.SimpleSQL.TestTypes
|
||||
import Language.SQL.SimpleSQL.Syntax
|
||||
|
||||
|
||||
queryExprComponentTests :: TestItem
|
||||
queryExprComponentTests = Group "queryExprComponentTests"
|
||||
[duplicates
|
||||
,selectLists
|
||||
,whereClause
|
||||
,having
|
||||
,orderBy
|
||||
,offsetFetch
|
||||
,combos
|
||||
,withQueries
|
||||
,values
|
||||
,tables
|
||||
]
|
||||
|
||||
|
||||
|
||||
duplicates :: TestItem
|
||||
duplicates = Group "duplicates" $ map (uncurry (TestQueryExpr ansi2011))
|
||||
[("select a from t" ,ms SQDefault)
|
||||
,("select all a from t" ,ms All)
|
||||
,("select distinct a from t", ms Distinct)
|
||||
]
|
||||
where
|
||||
ms d = makeSelect
|
||||
{qeSetQuantifier = d
|
||||
,qeSelectList = [(Iden [Name Nothing "a"],Nothing)]
|
||||
,qeFrom = [TRSimple [Name Nothing "t"]]}
|
||||
|
||||
selectLists :: TestItem
|
||||
selectLists = Group "selectLists" $ map (uncurry (TestQueryExpr ansi2011))
|
||||
[("select 1",
|
||||
makeSelect {qeSelectList = [(NumLit "1",Nothing)]})
|
||||
|
||||
,("select a"
|
||||
,makeSelect {qeSelectList = [(Iden [Name Nothing "a"],Nothing)]})
|
||||
|
||||
,("select a,b"
|
||||
,makeSelect {qeSelectList = [(Iden [Name Nothing "a"],Nothing)
|
||||
,(Iden [Name Nothing "b"],Nothing)]})
|
||||
|
||||
,("select 1+2,3+4"
|
||||
,makeSelect {qeSelectList =
|
||||
[(BinOp (NumLit "1") [Name Nothing "+"] (NumLit "2"),Nothing)
|
||||
,(BinOp (NumLit "3") [Name Nothing "+"] (NumLit "4"),Nothing)]})
|
||||
|
||||
,("select a as a, /*comment*/ b as b"
|
||||
,makeSelect {qeSelectList = [(Iden [Name Nothing "a"], Just $ Name Nothing "a")
|
||||
,(Iden [Name Nothing "b"], Just $ Name Nothing "b")]})
|
||||
|
||||
,("select a a, b b"
|
||||
,makeSelect {qeSelectList = [(Iden [Name Nothing "a"], Just $ Name Nothing "a")
|
||||
,(Iden [Name Nothing "b"], Just $ Name Nothing "b")]})
|
||||
|
||||
,("select a + b * c"
|
||||
,makeSelect {qeSelectList =
|
||||
[(BinOp (Iden [Name Nothing "a"]) [Name Nothing "+"]
|
||||
(BinOp (Iden [Name Nothing "b"]) [Name Nothing "*"] (Iden [Name Nothing "c"]))
|
||||
,Nothing)]})
|
||||
|
||||
]
|
||||
|
||||
whereClause :: TestItem
|
||||
whereClause = Group "whereClause" $ map (uncurry (TestQueryExpr ansi2011))
|
||||
[("select a from t where a = 5"
|
||||
,makeSelect {qeSelectList = [(Iden [Name Nothing "a"],Nothing)]
|
||||
,qeFrom = [TRSimple [Name Nothing "t"]]
|
||||
,qeWhere = Just $ BinOp (Iden [Name Nothing "a"]) [Name Nothing "="] (NumLit "5")})
|
||||
]
|
||||
|
||||
having :: TestItem
|
||||
having = Group "having" $ map (uncurry (TestQueryExpr ansi2011))
|
||||
[("select a,sum(b) from t group by a having sum(b) > 5"
|
||||
,makeSelect {qeSelectList = [(Iden [Name Nothing "a"],Nothing)
|
||||
,(App [Name Nothing "sum"] [Iden [Name Nothing "b"]],Nothing)]
|
||||
,qeFrom = [TRSimple [Name Nothing "t"]]
|
||||
,qeGroupBy = [SimpleGroup $ Iden [Name Nothing "a"]]
|
||||
,qeHaving = Just $ BinOp (App [Name Nothing "sum"] [Iden [Name Nothing "b"]])
|
||||
[Name Nothing ">"] (NumLit "5")
|
||||
})
|
||||
]
|
||||
|
||||
orderBy :: TestItem
|
||||
orderBy = Group "orderBy" $ map (uncurry (TestQueryExpr ansi2011))
|
||||
[("select a from t order by a"
|
||||
,ms [SortSpec (Iden [Name Nothing "a"]) DirDefault NullsOrderDefault])
|
||||
|
||||
,("select a from t order by a, b"
|
||||
,ms [SortSpec (Iden [Name Nothing "a"]) DirDefault NullsOrderDefault
|
||||
,SortSpec (Iden [Name Nothing "b"]) DirDefault NullsOrderDefault])
|
||||
|
||||
,("select a from t order by a asc"
|
||||
,ms [SortSpec (Iden [Name Nothing "a"]) Asc NullsOrderDefault])
|
||||
|
||||
,("select a from t order by a desc, b desc"
|
||||
,ms [SortSpec (Iden [Name Nothing "a"]) Desc NullsOrderDefault
|
||||
,SortSpec (Iden [Name Nothing "b"]) Desc NullsOrderDefault])
|
||||
|
||||
,("select a from t order by a desc nulls first, b desc nulls last"
|
||||
,ms [SortSpec (Iden [Name Nothing "a"]) Desc NullsFirst
|
||||
,SortSpec (Iden [Name Nothing "b"]) Desc NullsLast])
|
||||
|
||||
]
|
||||
where
|
||||
ms o = makeSelect {qeSelectList = [(Iden [Name Nothing "a"],Nothing)]
|
||||
,qeFrom = [TRSimple [Name Nothing "t"]]
|
||||
,qeOrderBy = o}
|
||||
|
||||
offsetFetch :: TestItem
|
||||
offsetFetch = Group "offsetFetch" $ map (uncurry (TestQueryExpr ansi2011))
|
||||
[-- ansi standard
|
||||
("select a from t offset 5 rows fetch next 10 rows only"
|
||||
,ms (Just $ NumLit "5") (Just $ NumLit "10"))
|
||||
,("select a from t offset 5 rows;"
|
||||
,ms (Just $ NumLit "5") Nothing)
|
||||
,("select a from t fetch next 10 row only;"
|
||||
,ms Nothing (Just $ NumLit "10"))
|
||||
,("select a from t offset 5 row fetch first 10 row only"
|
||||
,ms (Just $ NumLit "5") (Just $ NumLit "10"))
|
||||
-- postgres: disabled, will add back when postgres
|
||||
-- dialect is added
|
||||
--,("select a from t limit 10 offset 5"
|
||||
-- ,ms (Just $ NumLit "5") (Just $ NumLit "10"))
|
||||
]
|
||||
where
|
||||
ms o l = makeSelect
|
||||
{qeSelectList = [(Iden [Name Nothing "a"],Nothing)]
|
||||
,qeFrom = [TRSimple [Name Nothing "t"]]
|
||||
,qeOffset = o
|
||||
,qeFetchFirst = l}
|
||||
|
||||
combos :: TestItem
|
||||
combos = Group "combos" $ map (uncurry (TestQueryExpr ansi2011))
|
||||
[("select a from t union select b from u"
|
||||
,QueryExprSetOp ms1 Union SQDefault Respectively ms2)
|
||||
|
||||
,("select a from t intersect select b from u"
|
||||
,QueryExprSetOp ms1 Intersect SQDefault Respectively ms2)
|
||||
|
||||
,("select a from t except all select b from u"
|
||||
,QueryExprSetOp ms1 Except All Respectively ms2)
|
||||
|
||||
,("select a from t union distinct corresponding \
|
||||
\select b from u"
|
||||
,QueryExprSetOp ms1 Union Distinct Corresponding ms2)
|
||||
|
||||
,("select a from t union select a from t union select a from t"
|
||||
-- TODO: union should be left associative. I think the others also
|
||||
-- so this needs to be fixed (new optionSuffix variation which
|
||||
-- handles this)
|
||||
,QueryExprSetOp ms1 Union SQDefault Respectively
|
||||
(QueryExprSetOp ms1 Union SQDefault Respectively ms1))
|
||||
]
|
||||
where
|
||||
ms1 = makeSelect
|
||||
{qeSelectList = [(Iden [Name Nothing "a"],Nothing)]
|
||||
,qeFrom = [TRSimple [Name Nothing "t"]]}
|
||||
ms2 = makeSelect
|
||||
{qeSelectList = [(Iden [Name Nothing "b"],Nothing)]
|
||||
,qeFrom = [TRSimple [Name Nothing "u"]]}
|
||||
|
||||
|
||||
withQueries :: TestItem
|
||||
withQueries = Group "with queries" $ map (uncurry (TestQueryExpr ansi2011))
|
||||
[("with u as (select a from t) select a from u"
|
||||
,With False [(Alias (Name Nothing "u") Nothing, ms1)] ms2)
|
||||
|
||||
,("with u(b) as (select a from t) select a from u"
|
||||
,With False [(Alias (Name Nothing "u") (Just [Name Nothing "b"]), ms1)] ms2)
|
||||
|
||||
,("with x as (select a from t),\n\
|
||||
\ u as (select a from x)\n\
|
||||
\select a from u"
|
||||
,With False [(Alias (Name Nothing "x") Nothing, ms1), (Alias (Name Nothing "u") Nothing,ms3)] ms2)
|
||||
|
||||
,("with recursive u as (select a from t) select a from u"
|
||||
,With True [(Alias (Name Nothing "u") Nothing, ms1)] ms2)
|
||||
]
|
||||
where
|
||||
ms c t = makeSelect
|
||||
{qeSelectList = [(Iden [Name Nothing c],Nothing)]
|
||||
,qeFrom = [TRSimple [Name Nothing t]]}
|
||||
ms1 = ms "a" "t"
|
||||
ms2 = ms "a" "u"
|
||||
ms3 = ms "a" "x"
|
||||
|
||||
values :: TestItem
|
||||
values = Group "values" $ map (uncurry (TestQueryExpr ansi2011))
|
||||
[("values (1,2),(3,4)"
|
||||
,Values [[NumLit "1", NumLit "2"]
|
||||
,[NumLit "3", NumLit "4"]])
|
||||
]
|
||||
|
||||
tables :: TestItem
|
||||
tables = Group "tables" $ map (uncurry (TestQueryExpr ansi2011))
|
||||
[("table tbl", Table [Name Nothing "tbl"])
|
||||
]
|
|
@ -1,209 +0,0 @@
|
|||
|
||||
These are the tests for the query expression components apart from the
|
||||
table refs which are in a separate file.
|
||||
|
||||
|
||||
These are a few misc tests which don't fit anywhere else.
|
||||
|
||||
> module Language.SQL.SimpleSQL.QueryExprComponents (queryExprComponentTests) where
|
||||
|
||||
> import Language.SQL.SimpleSQL.TestTypes
|
||||
> import Language.SQL.SimpleSQL.Syntax
|
||||
|
||||
|
||||
> queryExprComponentTests :: TestItem
|
||||
> queryExprComponentTests = Group "queryExprComponentTests"
|
||||
> [duplicates
|
||||
> ,selectLists
|
||||
> ,whereClause
|
||||
> ,having
|
||||
> ,orderBy
|
||||
> ,offsetFetch
|
||||
> ,combos
|
||||
> ,withQueries
|
||||
> ,values
|
||||
> ,tables
|
||||
> ]
|
||||
|
||||
|
||||
|
||||
> duplicates :: TestItem
|
||||
> duplicates = Group "duplicates" $ map (uncurry (TestQueryExpr ansi2011))
|
||||
> [("select a from t" ,ms SQDefault)
|
||||
> ,("select all a from t" ,ms All)
|
||||
> ,("select distinct a from t", ms Distinct)
|
||||
> ]
|
||||
> where
|
||||
> ms d = makeSelect
|
||||
> {qeSetQuantifier = d
|
||||
> ,qeSelectList = [(Iden [Name Nothing "a"],Nothing)]
|
||||
> ,qeFrom = [TRSimple [Name Nothing "t"]]}
|
||||
|
||||
> selectLists :: TestItem
|
||||
> selectLists = Group "selectLists" $ map (uncurry (TestQueryExpr ansi2011))
|
||||
> [("select 1",
|
||||
> makeSelect {qeSelectList = [(NumLit "1",Nothing)]})
|
||||
|
||||
> ,("select a"
|
||||
> ,makeSelect {qeSelectList = [(Iden [Name Nothing "a"],Nothing)]})
|
||||
|
||||
> ,("select a,b"
|
||||
> ,makeSelect {qeSelectList = [(Iden [Name Nothing "a"],Nothing)
|
||||
> ,(Iden [Name Nothing "b"],Nothing)]})
|
||||
|
||||
> ,("select 1+2,3+4"
|
||||
> ,makeSelect {qeSelectList =
|
||||
> [(BinOp (NumLit "1") [Name Nothing "+"] (NumLit "2"),Nothing)
|
||||
> ,(BinOp (NumLit "3") [Name Nothing "+"] (NumLit "4"),Nothing)]})
|
||||
|
||||
> ,("select a as a, /*comment*/ b as b"
|
||||
> ,makeSelect {qeSelectList = [(Iden [Name Nothing "a"], Just $ Name Nothing "a")
|
||||
> ,(Iden [Name Nothing "b"], Just $ Name Nothing "b")]})
|
||||
|
||||
> ,("select a a, b b"
|
||||
> ,makeSelect {qeSelectList = [(Iden [Name Nothing "a"], Just $ Name Nothing "a")
|
||||
> ,(Iden [Name Nothing "b"], Just $ Name Nothing "b")]})
|
||||
|
||||
> ,("select a + b * c"
|
||||
> ,makeSelect {qeSelectList =
|
||||
> [(BinOp (Iden [Name Nothing "a"]) [Name Nothing "+"]
|
||||
> (BinOp (Iden [Name Nothing "b"]) [Name Nothing "*"] (Iden [Name Nothing "c"]))
|
||||
> ,Nothing)]})
|
||||
|
||||
> ]
|
||||
|
||||
> whereClause :: TestItem
|
||||
> whereClause = Group "whereClause" $ map (uncurry (TestQueryExpr ansi2011))
|
||||
> [("select a from t where a = 5"
|
||||
> ,makeSelect {qeSelectList = [(Iden [Name Nothing "a"],Nothing)]
|
||||
> ,qeFrom = [TRSimple [Name Nothing "t"]]
|
||||
> ,qeWhere = Just $ BinOp (Iden [Name Nothing "a"]) [Name Nothing "="] (NumLit "5")})
|
||||
> ]
|
||||
|
||||
> having :: TestItem
|
||||
> having = Group "having" $ map (uncurry (TestQueryExpr ansi2011))
|
||||
> [("select a,sum(b) from t group by a having sum(b) > 5"
|
||||
> ,makeSelect {qeSelectList = [(Iden [Name Nothing "a"],Nothing)
|
||||
> ,(App [Name Nothing "sum"] [Iden [Name Nothing "b"]],Nothing)]
|
||||
> ,qeFrom = [TRSimple [Name Nothing "t"]]
|
||||
> ,qeGroupBy = [SimpleGroup $ Iden [Name Nothing "a"]]
|
||||
> ,qeHaving = Just $ BinOp (App [Name Nothing "sum"] [Iden [Name Nothing "b"]])
|
||||
> [Name Nothing ">"] (NumLit "5")
|
||||
> })
|
||||
> ]
|
||||
|
||||
> orderBy :: TestItem
|
||||
> orderBy = Group "orderBy" $ map (uncurry (TestQueryExpr ansi2011))
|
||||
> [("select a from t order by a"
|
||||
> ,ms [SortSpec (Iden [Name Nothing "a"]) DirDefault NullsOrderDefault])
|
||||
|
||||
> ,("select a from t order by a, b"
|
||||
> ,ms [SortSpec (Iden [Name Nothing "a"]) DirDefault NullsOrderDefault
|
||||
> ,SortSpec (Iden [Name Nothing "b"]) DirDefault NullsOrderDefault])
|
||||
|
||||
> ,("select a from t order by a asc"
|
||||
> ,ms [SortSpec (Iden [Name Nothing "a"]) Asc NullsOrderDefault])
|
||||
|
||||
> ,("select a from t order by a desc, b desc"
|
||||
> ,ms [SortSpec (Iden [Name Nothing "a"]) Desc NullsOrderDefault
|
||||
> ,SortSpec (Iden [Name Nothing "b"]) Desc NullsOrderDefault])
|
||||
|
||||
> ,("select a from t order by a desc nulls first, b desc nulls last"
|
||||
> ,ms [SortSpec (Iden [Name Nothing "a"]) Desc NullsFirst
|
||||
> ,SortSpec (Iden [Name Nothing "b"]) Desc NullsLast])
|
||||
|
||||
> ]
|
||||
> where
|
||||
> ms o = makeSelect {qeSelectList = [(Iden [Name Nothing "a"],Nothing)]
|
||||
> ,qeFrom = [TRSimple [Name Nothing "t"]]
|
||||
> ,qeOrderBy = o}
|
||||
|
||||
> offsetFetch :: TestItem
|
||||
> offsetFetch = Group "offsetFetch" $ map (uncurry (TestQueryExpr ansi2011))
|
||||
> [-- ansi standard
|
||||
> ("select a from t offset 5 rows fetch next 10 rows only"
|
||||
> ,ms (Just $ NumLit "5") (Just $ NumLit "10"))
|
||||
> ,("select a from t offset 5 rows;"
|
||||
> ,ms (Just $ NumLit "5") Nothing)
|
||||
> ,("select a from t fetch next 10 row only;"
|
||||
> ,ms Nothing (Just $ NumLit "10"))
|
||||
> ,("select a from t offset 5 row fetch first 10 row only"
|
||||
> ,ms (Just $ NumLit "5") (Just $ NumLit "10"))
|
||||
> -- postgres: disabled, will add back when postgres
|
||||
> -- dialect is added
|
||||
> --,("select a from t limit 10 offset 5"
|
||||
> -- ,ms (Just $ NumLit "5") (Just $ NumLit "10"))
|
||||
> ]
|
||||
> where
|
||||
> ms o l = makeSelect
|
||||
> {qeSelectList = [(Iden [Name Nothing "a"],Nothing)]
|
||||
> ,qeFrom = [TRSimple [Name Nothing "t"]]
|
||||
> ,qeOffset = o
|
||||
> ,qeFetchFirst = l}
|
||||
|
||||
> combos :: TestItem
|
||||
> combos = Group "combos" $ map (uncurry (TestQueryExpr ansi2011))
|
||||
> [("select a from t union select b from u"
|
||||
> ,QueryExprSetOp ms1 Union SQDefault Respectively ms2)
|
||||
|
||||
> ,("select a from t intersect select b from u"
|
||||
> ,QueryExprSetOp ms1 Intersect SQDefault Respectively ms2)
|
||||
|
||||
> ,("select a from t except all select b from u"
|
||||
> ,QueryExprSetOp ms1 Except All Respectively ms2)
|
||||
|
||||
> ,("select a from t union distinct corresponding \
|
||||
> \select b from u"
|
||||
> ,QueryExprSetOp ms1 Union Distinct Corresponding ms2)
|
||||
|
||||
> ,("select a from t union select a from t union select a from t"
|
||||
> -- TODO: union should be left associative. I think the others also
|
||||
> -- so this needs to be fixed (new optionSuffix variation which
|
||||
> -- handles this)
|
||||
> ,QueryExprSetOp ms1 Union SQDefault Respectively
|
||||
> (QueryExprSetOp ms1 Union SQDefault Respectively ms1))
|
||||
> ]
|
||||
> where
|
||||
> ms1 = makeSelect
|
||||
> {qeSelectList = [(Iden [Name Nothing "a"],Nothing)]
|
||||
> ,qeFrom = [TRSimple [Name Nothing "t"]]}
|
||||
> ms2 = makeSelect
|
||||
> {qeSelectList = [(Iden [Name Nothing "b"],Nothing)]
|
||||
> ,qeFrom = [TRSimple [Name Nothing "u"]]}
|
||||
|
||||
|
||||
> withQueries :: TestItem
|
||||
> withQueries = Group "with queries" $ map (uncurry (TestQueryExpr ansi2011))
|
||||
> [("with u as (select a from t) select a from u"
|
||||
> ,With False [(Alias (Name Nothing "u") Nothing, ms1)] ms2)
|
||||
|
||||
> ,("with u(b) as (select a from t) select a from u"
|
||||
> ,With False [(Alias (Name Nothing "u") (Just [Name Nothing "b"]), ms1)] ms2)
|
||||
|
||||
> ,("with x as (select a from t),\n\
|
||||
> \ u as (select a from x)\n\
|
||||
> \select a from u"
|
||||
> ,With False [(Alias (Name Nothing "x") Nothing, ms1), (Alias (Name Nothing "u") Nothing,ms3)] ms2)
|
||||
|
||||
> ,("with recursive u as (select a from t) select a from u"
|
||||
> ,With True [(Alias (Name Nothing "u") Nothing, ms1)] ms2)
|
||||
> ]
|
||||
> where
|
||||
> ms c t = makeSelect
|
||||
> {qeSelectList = [(Iden [Name Nothing c],Nothing)]
|
||||
> ,qeFrom = [TRSimple [Name Nothing t]]}
|
||||
> ms1 = ms "a" "t"
|
||||
> ms2 = ms "a" "u"
|
||||
> ms3 = ms "a" "x"
|
||||
|
||||
> values :: TestItem
|
||||
> values = Group "values" $ map (uncurry (TestQueryExpr ansi2011))
|
||||
> [("values (1,2),(3,4)"
|
||||
> ,Values [[NumLit "1", NumLit "2"]
|
||||
> ,[NumLit "3", NumLit "4"]])
|
||||
> ]
|
||||
|
||||
> tables :: TestItem
|
||||
> tables = Group "tables" $ map (uncurry (TestQueryExpr ansi2011))
|
||||
> [("table tbl", Table [Name Nothing "tbl"])
|
||||
> ]
|
26
tools/Language/SQL/SimpleSQL/QueryExprs.hs
Normal file
26
tools/Language/SQL/SimpleSQL/QueryExprs.hs
Normal file
|
@ -0,0 +1,26 @@
|
|||
|
||||
{-
|
||||
These are the tests for the queryExprs parsing which parses multiple
|
||||
query expressions from one string.
|
||||
-}
|
||||
|
||||
module Language.SQL.SimpleSQL.QueryExprs (queryExprsTests) where
|
||||
|
||||
import Language.SQL.SimpleSQL.TestTypes
|
||||
import Language.SQL.SimpleSQL.Syntax
|
||||
|
||||
queryExprsTests :: TestItem
|
||||
queryExprsTests = Group "query exprs" $ map (uncurry (TestStatements ansi2011))
|
||||
[("select 1",[ms])
|
||||
,("select 1;",[ms])
|
||||
,("select 1;select 1",[ms,ms])
|
||||
,(" select 1;select 1; ",[ms,ms])
|
||||
,("SELECT CURRENT_TIMESTAMP;"
|
||||
,[SelectStatement $ makeSelect
|
||||
{qeSelectList = [(Iden [Name Nothing "CURRENT_TIMESTAMP"],Nothing)]}])
|
||||
,("SELECT \"CURRENT_TIMESTAMP\";"
|
||||
,[SelectStatement $ makeSelect
|
||||
{qeSelectList = [(Iden [Name (Just ("\"","\"")) "CURRENT_TIMESTAMP"],Nothing)]}])
|
||||
]
|
||||
where
|
||||
ms = SelectStatement $ makeSelect {qeSelectList = [(NumLit "1",Nothing)]}
|
|
@ -1,24 +0,0 @@
|
|||
|
||||
These are the tests for the queryExprs parsing which parses multiple
|
||||
query expressions from one string.
|
||||
|
||||
> module Language.SQL.SimpleSQL.QueryExprs (queryExprsTests) where
|
||||
|
||||
> import Language.SQL.SimpleSQL.TestTypes
|
||||
> import Language.SQL.SimpleSQL.Syntax
|
||||
|
||||
> queryExprsTests :: TestItem
|
||||
> queryExprsTests = Group "query exprs" $ map (uncurry (TestStatements ansi2011))
|
||||
> [("select 1",[ms])
|
||||
> ,("select 1;",[ms])
|
||||
> ,("select 1;select 1",[ms,ms])
|
||||
> ,(" select 1;select 1; ",[ms,ms])
|
||||
> ,("SELECT CURRENT_TIMESTAMP;"
|
||||
> ,[SelectStatement $ makeSelect
|
||||
> {qeSelectList = [(Iden [Name Nothing "CURRENT_TIMESTAMP"],Nothing)]}])
|
||||
> ,("SELECT \"CURRENT_TIMESTAMP\";"
|
||||
> ,[SelectStatement $ makeSelect
|
||||
> {qeSelectList = [(Iden [Name (Just ("\"","\"")) "CURRENT_TIMESTAMP"],Nothing)]}])
|
||||
> ]
|
||||
> where
|
||||
> ms = SelectStatement $ makeSelect {qeSelectList = [(NumLit "1",Nothing)]}
|
329
tools/Language/SQL/SimpleSQL/SQL2011AccessControl.hs
Normal file
329
tools/Language/SQL/SimpleSQL/SQL2011AccessControl.hs
Normal file
|
@ -0,0 +1,329 @@
|
|||
|
||||
{-
|
||||
Section 12 in Foundation
|
||||
|
||||
grant, etc
|
||||
-}
|
||||
|
||||
|
||||
module Language.SQL.SimpleSQL.SQL2011AccessControl (sql2011AccessControlTests) where
|
||||
|
||||
import Language.SQL.SimpleSQL.TestTypes
|
||||
import Language.SQL.SimpleSQL.Syntax
|
||||
|
||||
sql2011AccessControlTests :: TestItem
|
||||
sql2011AccessControlTests = Group "sql 2011 access control tests" [
|
||||
|
||||
{-
|
||||
12 Access control
|
||||
|
||||
12.1 <grant statement>
|
||||
|
||||
<grant statement> ::=
|
||||
<grant privilege statement>
|
||||
| <grant role statement>
|
||||
|
||||
12.2 <grant privilege statement>
|
||||
|
||||
<grant privilege statement> ::=
|
||||
GRANT <privileges> TO <grantee> [ { <comma> <grantee> }... ]
|
||||
[ WITH HIERARCHY OPTION ]
|
||||
[ WITH GRANT OPTION ]
|
||||
[ GRANTED BY <grantor> ]
|
||||
|
||||
12.3 <privileges>
|
||||
<privileges> ::=
|
||||
<object privileges> ON <object name>
|
||||
|
||||
<object name> ::=
|
||||
[ TABLE ] <table name>
|
||||
| DOMAIN <domain name>
|
||||
| COLLATION <collation name>
|
||||
| CHARACTER SET <character set name>
|
||||
| TRANSLATION <transliteration name>
|
||||
| TYPE <schema-resolved user-defined type name>
|
||||
| SEQUENCE <sequence generator name>
|
||||
| <specific routine designator>
|
||||
|
||||
<object privileges> ::=
|
||||
ALL PRIVILEGES
|
||||
| <action> [ { <comma> <action> }... ]
|
||||
|
||||
<action> ::=
|
||||
SELECT
|
||||
| SELECT <left paren> <privilege column list> <right paren>
|
||||
| SELECT <left paren> <privilege method list> <right paren>
|
||||
| DELETE
|
||||
| INSERT [ <left paren> <privilege column list> <right paren> ]
|
||||
| UPDATE [ <left paren> <privilege column list> <right paren> ]
|
||||
| REFERENCES [ <left paren> <privilege column list> <right paren> ]
|
||||
| USAGE
|
||||
| TRIGGER
|
||||
| UNDER
|
||||
| EXECUTE
|
||||
|
||||
<privilege method list> ::=
|
||||
<specific routine designator> [ { <comma> <specific routine designator> }... ]
|
||||
|
||||
<privilege column list> ::=
|
||||
<column name list>
|
||||
|
||||
<grantee> ::=
|
||||
PUBLIC
|
||||
| <authorization identifier>
|
||||
|
||||
<grantor> ::=
|
||||
CURRENT_USER
|
||||
| CURRENT_ROLE
|
||||
-}
|
||||
|
||||
(TestStatement ansi2011
|
||||
"grant all privileges on tbl1 to role1"
|
||||
$ GrantPrivilege [PrivAll]
|
||||
(PrivTable [Name Nothing "tbl1"])
|
||||
[Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
|
||||
,(TestStatement ansi2011
|
||||
"grant all privileges on tbl1 to role1,role2"
|
||||
$ GrantPrivilege [PrivAll]
|
||||
(PrivTable [Name Nothing "tbl1"])
|
||||
[Name Nothing "role1",Name Nothing "role2"] WithoutGrantOption)
|
||||
|
||||
,(TestStatement ansi2011
|
||||
"grant all privileges on tbl1 to role1 with grant option"
|
||||
$ GrantPrivilege [PrivAll]
|
||||
(PrivTable [Name Nothing "tbl1"])
|
||||
[Name Nothing "role1"] WithGrantOption)
|
||||
|
||||
,(TestStatement ansi2011
|
||||
"grant all privileges on table tbl1 to role1"
|
||||
$ GrantPrivilege [PrivAll]
|
||||
(PrivTable [Name Nothing "tbl1"])
|
||||
[Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
,(TestStatement ansi2011
|
||||
"grant all privileges on domain mydom to role1"
|
||||
$ GrantPrivilege [PrivAll]
|
||||
(PrivDomain [Name Nothing "mydom"])
|
||||
[Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
,(TestStatement ansi2011
|
||||
"grant all privileges on type t1 to role1"
|
||||
$ GrantPrivilege [PrivAll]
|
||||
(PrivType [Name Nothing "t1"])
|
||||
[Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
,(TestStatement ansi2011
|
||||
"grant all privileges on sequence s1 to role1"
|
||||
$ GrantPrivilege [PrivAll]
|
||||
(PrivSequence [Name Nothing "s1"])
|
||||
[Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
|
||||
,(TestStatement ansi2011
|
||||
"grant select on table t1 to role1"
|
||||
$ GrantPrivilege [PrivSelect []]
|
||||
(PrivTable [Name Nothing "t1"])
|
||||
[Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
,(TestStatement ansi2011
|
||||
"grant select(a,b) on table t1 to role1"
|
||||
$ GrantPrivilege [PrivSelect [Name Nothing "a", Name Nothing "b"]]
|
||||
(PrivTable [Name Nothing "t1"])
|
||||
[Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
,(TestStatement ansi2011
|
||||
"grant delete on table t1 to role1"
|
||||
$ GrantPrivilege [PrivDelete]
|
||||
(PrivTable [Name Nothing "t1"])
|
||||
[Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
,(TestStatement ansi2011
|
||||
"grant insert on table t1 to role1"
|
||||
$ GrantPrivilege [PrivInsert []]
|
||||
(PrivTable [Name Nothing "t1"])
|
||||
[Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
,(TestStatement ansi2011
|
||||
"grant insert(a,b) on table t1 to role1"
|
||||
$ GrantPrivilege [PrivInsert [Name Nothing "a", Name Nothing "b"]]
|
||||
(PrivTable [Name Nothing "t1"])
|
||||
[Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
,(TestStatement ansi2011
|
||||
"grant update on table t1 to role1"
|
||||
$ GrantPrivilege [PrivUpdate []]
|
||||
(PrivTable [Name Nothing "t1"])
|
||||
[Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
,(TestStatement ansi2011
|
||||
"grant update(a,b) on table t1 to role1"
|
||||
$ GrantPrivilege [PrivUpdate [Name Nothing "a", Name Nothing "b"]]
|
||||
(PrivTable [Name Nothing "t1"])
|
||||
[Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
,(TestStatement ansi2011
|
||||
"grant references on table t1 to role1"
|
||||
$ GrantPrivilege [PrivReferences []]
|
||||
(PrivTable [Name Nothing "t1"])
|
||||
[Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
,(TestStatement ansi2011
|
||||
"grant references(a,b) on table t1 to role1"
|
||||
$ GrantPrivilege [PrivReferences [Name Nothing "a", Name Nothing "b"]]
|
||||
(PrivTable [Name Nothing "t1"])
|
||||
[Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
,(TestStatement ansi2011
|
||||
"grant usage on table t1 to role1"
|
||||
$ GrantPrivilege [PrivUsage]
|
||||
(PrivTable [Name Nothing "t1"])
|
||||
[Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
,(TestStatement ansi2011
|
||||
"grant trigger on table t1 to role1"
|
||||
$ GrantPrivilege [PrivTrigger]
|
||||
(PrivTable [Name Nothing "t1"])
|
||||
[Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
|
||||
,(TestStatement ansi2011
|
||||
"grant execute on specific function f to role1"
|
||||
$ GrantPrivilege [PrivExecute]
|
||||
(PrivFunction [Name Nothing "f"])
|
||||
[Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
,(TestStatement ansi2011
|
||||
"grant select,delete on table t1 to role1"
|
||||
$ GrantPrivilege [PrivSelect [], PrivDelete]
|
||||
(PrivTable [Name Nothing "t1"])
|
||||
[Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
{-
|
||||
skipping for now:
|
||||
|
||||
what is 'under' action?
|
||||
|
||||
collation, character set, translation, member thing, methods
|
||||
|
||||
for review
|
||||
|
||||
some pretty big things missing in the standard:
|
||||
|
||||
schema, database
|
||||
|
||||
functions, etc., by argument types since they can be overloaded
|
||||
|
||||
|
||||
|
||||
12.4 <role definition>
|
||||
|
||||
<role definition> ::=
|
||||
CREATE ROLE <role name> [ WITH ADMIN <grantor> ]
|
||||
-}
|
||||
|
||||
,(TestStatement ansi2011
|
||||
"create role rolee"
|
||||
$ CreateRole (Name Nothing "rolee"))
|
||||
|
||||
|
||||
{-
|
||||
12.5 <grant role statement>
|
||||
|
||||
<grant role statement> ::=
|
||||
GRANT <role granted> [ { <comma> <role granted> }... ]
|
||||
TO <grantee> [ { <comma> <grantee> }... ]
|
||||
[ WITH ADMIN OPTION ]
|
||||
[ GRANTED BY <grantor> ]
|
||||
|
||||
<role granted> ::=
|
||||
<role name>
|
||||
-}
|
||||
|
||||
,(TestStatement ansi2011
|
||||
"grant role1 to public"
|
||||
$ GrantRole [Name Nothing "role1"] [Name Nothing "public"] WithoutAdminOption)
|
||||
|
||||
,(TestStatement ansi2011
|
||||
"grant role1,role2 to role3,role4"
|
||||
$ GrantRole [Name Nothing "role1",Name Nothing "role2"]
|
||||
[Name Nothing "role3", Name Nothing "role4"] WithoutAdminOption)
|
||||
|
||||
,(TestStatement ansi2011
|
||||
"grant role1 to role3 with admin option"
|
||||
$ GrantRole [Name Nothing "role1"] [Name Nothing "role3"] WithAdminOption)
|
||||
|
||||
|
||||
{-
|
||||
12.6 <drop role statement>
|
||||
|
||||
<drop role statement> ::=
|
||||
DROP ROLE <role name>
|
||||
-}
|
||||
|
||||
,(TestStatement ansi2011
|
||||
"drop role rolee"
|
||||
$ DropRole (Name Nothing "rolee"))
|
||||
|
||||
|
||||
{-
|
||||
12.7 <revoke statement>
|
||||
|
||||
<revoke statement> ::=
|
||||
<revoke privilege statement>
|
||||
| <revoke role statement>
|
||||
|
||||
<revoke privilege statement> ::=
|
||||
REVOKE [ <revoke option extension> ] <privileges>
|
||||
FROM <grantee> [ { <comma> <grantee> }... ]
|
||||
[ GRANTED BY <grantor> ]
|
||||
<drop behavior>
|
||||
|
||||
<revoke option extension> ::=
|
||||
GRANT OPTION FOR
|
||||
| HIERARCHY OPTION FOR
|
||||
-}
|
||||
|
||||
|
||||
,(TestStatement ansi2011
|
||||
"revoke select on t1 from role1"
|
||||
$ RevokePrivilege NoGrantOptionFor [PrivSelect []]
|
||||
(PrivTable [Name Nothing "t1"])
|
||||
[Name Nothing "role1"] DefaultDropBehaviour)
|
||||
|
||||
,(TestStatement ansi2011
|
||||
"revoke grant option for select on t1 from role1,role2 cascade"
|
||||
$ RevokePrivilege GrantOptionFor [PrivSelect []]
|
||||
(PrivTable [Name Nothing "t1"])
|
||||
[Name Nothing "role1",Name Nothing "role2"] Cascade)
|
||||
|
||||
|
||||
{-
|
||||
<revoke role statement> ::=
|
||||
REVOKE [ ADMIN OPTION FOR ] <role revoked> [ { <comma> <role revoked> }... ]
|
||||
FROM <grantee> [ { <comma> <grantee> }... ]
|
||||
[ GRANTED BY <grantor> ]
|
||||
<drop behavior>
|
||||
|
||||
<role revoked> ::=
|
||||
<role name>
|
||||
-}
|
||||
|
||||
,(TestStatement ansi2011
|
||||
"revoke role1 from role2"
|
||||
$ RevokeRole NoAdminOptionFor [Name Nothing "role1"]
|
||||
[Name Nothing "role2"] DefaultDropBehaviour)
|
||||
|
||||
,(TestStatement ansi2011
|
||||
"revoke role1,role2 from role3,role4"
|
||||
$ RevokeRole NoAdminOptionFor [Name Nothing "role1",Name Nothing "role2"]
|
||||
[Name Nothing "role3",Name Nothing "role4"] DefaultDropBehaviour)
|
||||
|
||||
|
||||
,(TestStatement ansi2011
|
||||
"revoke admin option for role1 from role2 cascade"
|
||||
$ RevokeRole AdminOptionFor [Name Nothing "role1"] [Name Nothing "role2"] Cascade)
|
||||
|
||||
|
||||
]
|
|
@ -1,315 +0,0 @@
|
|||
|
||||
Section 12 in Foundation
|
||||
|
||||
grant, etc
|
||||
|
||||
|
||||
> module Language.SQL.SimpleSQL.SQL2011AccessControl (sql2011AccessControlTests) where
|
||||
|
||||
> import Language.SQL.SimpleSQL.TestTypes
|
||||
> import Language.SQL.SimpleSQL.Syntax
|
||||
|
||||
> sql2011AccessControlTests :: TestItem
|
||||
> sql2011AccessControlTests = Group "sql 2011 access control tests" [
|
||||
|
||||
12 Access control
|
||||
|
||||
12.1 <grant statement>
|
||||
|
||||
<grant statement> ::=
|
||||
<grant privilege statement>
|
||||
| <grant role statement>
|
||||
|
||||
12.2 <grant privilege statement>
|
||||
|
||||
<grant privilege statement> ::=
|
||||
GRANT <privileges> TO <grantee> [ { <comma> <grantee> }... ]
|
||||
[ WITH HIERARCHY OPTION ]
|
||||
[ WITH GRANT OPTION ]
|
||||
[ GRANTED BY <grantor> ]
|
||||
|
||||
12.3 <privileges>
|
||||
<privileges> ::=
|
||||
<object privileges> ON <object name>
|
||||
|
||||
<object name> ::=
|
||||
[ TABLE ] <table name>
|
||||
| DOMAIN <domain name>
|
||||
| COLLATION <collation name>
|
||||
| CHARACTER SET <character set name>
|
||||
| TRANSLATION <transliteration name>
|
||||
| TYPE <schema-resolved user-defined type name>
|
||||
| SEQUENCE <sequence generator name>
|
||||
| <specific routine designator>
|
||||
|
||||
<object privileges> ::=
|
||||
ALL PRIVILEGES
|
||||
| <action> [ { <comma> <action> }... ]
|
||||
|
||||
<action> ::=
|
||||
SELECT
|
||||
| SELECT <left paren> <privilege column list> <right paren>
|
||||
| SELECT <left paren> <privilege method list> <right paren>
|
||||
| DELETE
|
||||
| INSERT [ <left paren> <privilege column list> <right paren> ]
|
||||
| UPDATE [ <left paren> <privilege column list> <right paren> ]
|
||||
| REFERENCES [ <left paren> <privilege column list> <right paren> ]
|
||||
| USAGE
|
||||
| TRIGGER
|
||||
| UNDER
|
||||
| EXECUTE
|
||||
|
||||
<privilege method list> ::=
|
||||
<specific routine designator> [ { <comma> <specific routine designator> }... ]
|
||||
|
||||
<privilege column list> ::=
|
||||
<column name list>
|
||||
|
||||
<grantee> ::=
|
||||
PUBLIC
|
||||
| <authorization identifier>
|
||||
|
||||
<grantor> ::=
|
||||
CURRENT_USER
|
||||
| CURRENT_ROLE
|
||||
|
||||
> (TestStatement ansi2011
|
||||
> "grant all privileges on tbl1 to role1"
|
||||
> $ GrantPrivilege [PrivAll]
|
||||
> (PrivTable [Name Nothing "tbl1"])
|
||||
> [Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "grant all privileges on tbl1 to role1,role2"
|
||||
> $ GrantPrivilege [PrivAll]
|
||||
> (PrivTable [Name Nothing "tbl1"])
|
||||
> [Name Nothing "role1",Name Nothing "role2"] WithoutGrantOption)
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "grant all privileges on tbl1 to role1 with grant option"
|
||||
> $ GrantPrivilege [PrivAll]
|
||||
> (PrivTable [Name Nothing "tbl1"])
|
||||
> [Name Nothing "role1"] WithGrantOption)
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "grant all privileges on table tbl1 to role1"
|
||||
> $ GrantPrivilege [PrivAll]
|
||||
> (PrivTable [Name Nothing "tbl1"])
|
||||
> [Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "grant all privileges on domain mydom to role1"
|
||||
> $ GrantPrivilege [PrivAll]
|
||||
> (PrivDomain [Name Nothing "mydom"])
|
||||
> [Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "grant all privileges on type t1 to role1"
|
||||
> $ GrantPrivilege [PrivAll]
|
||||
> (PrivType [Name Nothing "t1"])
|
||||
> [Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "grant all privileges on sequence s1 to role1"
|
||||
> $ GrantPrivilege [PrivAll]
|
||||
> (PrivSequence [Name Nothing "s1"])
|
||||
> [Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "grant select on table t1 to role1"
|
||||
> $ GrantPrivilege [PrivSelect []]
|
||||
> (PrivTable [Name Nothing "t1"])
|
||||
> [Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "grant select(a,b) on table t1 to role1"
|
||||
> $ GrantPrivilege [PrivSelect [Name Nothing "a", Name Nothing "b"]]
|
||||
> (PrivTable [Name Nothing "t1"])
|
||||
> [Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "grant delete on table t1 to role1"
|
||||
> $ GrantPrivilege [PrivDelete]
|
||||
> (PrivTable [Name Nothing "t1"])
|
||||
> [Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "grant insert on table t1 to role1"
|
||||
> $ GrantPrivilege [PrivInsert []]
|
||||
> (PrivTable [Name Nothing "t1"])
|
||||
> [Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "grant insert(a,b) on table t1 to role1"
|
||||
> $ GrantPrivilege [PrivInsert [Name Nothing "a", Name Nothing "b"]]
|
||||
> (PrivTable [Name Nothing "t1"])
|
||||
> [Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "grant update on table t1 to role1"
|
||||
> $ GrantPrivilege [PrivUpdate []]
|
||||
> (PrivTable [Name Nothing "t1"])
|
||||
> [Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "grant update(a,b) on table t1 to role1"
|
||||
> $ GrantPrivilege [PrivUpdate [Name Nothing "a", Name Nothing "b"]]
|
||||
> (PrivTable [Name Nothing "t1"])
|
||||
> [Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "grant references on table t1 to role1"
|
||||
> $ GrantPrivilege [PrivReferences []]
|
||||
> (PrivTable [Name Nothing "t1"])
|
||||
> [Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "grant references(a,b) on table t1 to role1"
|
||||
> $ GrantPrivilege [PrivReferences [Name Nothing "a", Name Nothing "b"]]
|
||||
> (PrivTable [Name Nothing "t1"])
|
||||
> [Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "grant usage on table t1 to role1"
|
||||
> $ GrantPrivilege [PrivUsage]
|
||||
> (PrivTable [Name Nothing "t1"])
|
||||
> [Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "grant trigger on table t1 to role1"
|
||||
> $ GrantPrivilege [PrivTrigger]
|
||||
> (PrivTable [Name Nothing "t1"])
|
||||
> [Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "grant execute on specific function f to role1"
|
||||
> $ GrantPrivilege [PrivExecute]
|
||||
> (PrivFunction [Name Nothing "f"])
|
||||
> [Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "grant select,delete on table t1 to role1"
|
||||
> $ GrantPrivilege [PrivSelect [], PrivDelete]
|
||||
> (PrivTable [Name Nothing "t1"])
|
||||
> [Name Nothing "role1"] WithoutGrantOption)
|
||||
|
||||
skipping for now:
|
||||
|
||||
what is 'under' action?
|
||||
|
||||
collation, character set, translation, member thing, methods
|
||||
|
||||
for review
|
||||
|
||||
some pretty big things missing in the standard:
|
||||
|
||||
schema, database
|
||||
|
||||
functions, etc., by argument types since they can be overloaded
|
||||
|
||||
|
||||
|
||||
12.4 <role definition>
|
||||
|
||||
<role definition> ::=
|
||||
CREATE ROLE <role name> [ WITH ADMIN <grantor> ]
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "create role rolee"
|
||||
> $ CreateRole (Name Nothing "rolee"))
|
||||
|
||||
|
||||
12.5 <grant role statement>
|
||||
|
||||
<grant role statement> ::=
|
||||
GRANT <role granted> [ { <comma> <role granted> }... ]
|
||||
TO <grantee> [ { <comma> <grantee> }... ]
|
||||
[ WITH ADMIN OPTION ]
|
||||
[ GRANTED BY <grantor> ]
|
||||
|
||||
<role granted> ::=
|
||||
<role name>
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "grant role1 to public"
|
||||
> $ GrantRole [Name Nothing "role1"] [Name Nothing "public"] WithoutAdminOption)
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "grant role1,role2 to role3,role4"
|
||||
> $ GrantRole [Name Nothing "role1",Name Nothing "role2"]
|
||||
> [Name Nothing "role3", Name Nothing "role4"] WithoutAdminOption)
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "grant role1 to role3 with admin option"
|
||||
> $ GrantRole [Name Nothing "role1"] [Name Nothing "role3"] WithAdminOption)
|
||||
|
||||
|
||||
12.6 <drop role statement>
|
||||
|
||||
<drop role statement> ::=
|
||||
DROP ROLE <role name>
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "drop role rolee"
|
||||
> $ DropRole (Name Nothing "rolee"))
|
||||
|
||||
|
||||
12.7 <revoke statement>
|
||||
|
||||
<revoke statement> ::=
|
||||
<revoke privilege statement>
|
||||
| <revoke role statement>
|
||||
|
||||
<revoke privilege statement> ::=
|
||||
REVOKE [ <revoke option extension> ] <privileges>
|
||||
FROM <grantee> [ { <comma> <grantee> }... ]
|
||||
[ GRANTED BY <grantor> ]
|
||||
<drop behavior>
|
||||
|
||||
<revoke option extension> ::=
|
||||
GRANT OPTION FOR
|
||||
| HIERARCHY OPTION FOR
|
||||
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "revoke select on t1 from role1"
|
||||
> $ RevokePrivilege NoGrantOptionFor [PrivSelect []]
|
||||
> (PrivTable [Name Nothing "t1"])
|
||||
> [Name Nothing "role1"] DefaultDropBehaviour)
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "revoke grant option for select on t1 from role1,role2 cascade"
|
||||
> $ RevokePrivilege GrantOptionFor [PrivSelect []]
|
||||
> (PrivTable [Name Nothing "t1"])
|
||||
> [Name Nothing "role1",Name Nothing "role2"] Cascade)
|
||||
|
||||
|
||||
<revoke role statement> ::=
|
||||
REVOKE [ ADMIN OPTION FOR ] <role revoked> [ { <comma> <role revoked> }... ]
|
||||
FROM <grantee> [ { <comma> <grantee> }... ]
|
||||
[ GRANTED BY <grantor> ]
|
||||
<drop behavior>
|
||||
|
||||
<role revoked> ::=
|
||||
<role name>
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "revoke role1 from role2"
|
||||
> $ RevokeRole NoAdminOptionFor [Name Nothing "role1"]
|
||||
> [Name Nothing "role2"] DefaultDropBehaviour)
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "revoke role1,role2 from role3,role4"
|
||||
> $ RevokeRole NoAdminOptionFor [Name Nothing "role1",Name Nothing "role2"]
|
||||
> [Name Nothing "role3",Name Nothing "role4"] DefaultDropBehaviour)
|
||||
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "revoke admin option for role1 from role2 cascade"
|
||||
> $ RevokeRole AdminOptionFor [Name Nothing "role1"] [Name Nothing "role2"] Cascade)
|
||||
|
||||
|
||||
> ]
|
|
@ -1,18 +1,21 @@
|
|||
|
||||
{-
|
||||
Sections 17 and 19 in Foundation
|
||||
|
||||
This module covers the tests for transaction management (begin,
|
||||
commit, savepoint, etc.), and session management (set).
|
||||
-}
|
||||
|
||||
|
||||
> module Language.SQL.SimpleSQL.SQL2011Bits (sql2011BitsTests) where
|
||||
module Language.SQL.SimpleSQL.SQL2011Bits (sql2011BitsTests) where
|
||||
|
||||
> import Language.SQL.SimpleSQL.TestTypes
|
||||
> import Language.SQL.SimpleSQL.Syntax
|
||||
import Language.SQL.SimpleSQL.TestTypes
|
||||
import Language.SQL.SimpleSQL.Syntax
|
||||
|
||||
> sql2011BitsTests :: TestItem
|
||||
> sql2011BitsTests = Group "sql 2011 bits tests" [
|
||||
sql2011BitsTests :: TestItem
|
||||
sql2011BitsTests = Group "sql 2011 bits tests" [
|
||||
|
||||
{-
|
||||
17 Transaction management
|
||||
|
||||
17.1 <start transaction statement>
|
||||
|
@ -21,11 +24,13 @@ commit, savepoint, etc.), and session management (set).
|
|||
START TRANSACTION [ <transaction characteristics> ]
|
||||
|
||||
BEGIN is not in the standard!
|
||||
-}
|
||||
|
||||
> (TestStatement ansi2011
|
||||
> "start transaction"
|
||||
> $ StartTransaction)
|
||||
(TestStatement ansi2011
|
||||
"start transaction"
|
||||
$ StartTransaction)
|
||||
|
||||
{-
|
||||
17.2 <set transaction statement>
|
||||
|
||||
<set transaction statement> ::=
|
||||
|
@ -76,36 +81,42 @@ BEGIN is not in the standard!
|
|||
|
||||
<savepoint specifier> ::=
|
||||
<savepoint name>
|
||||
-}
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "savepoint difficult_bit"
|
||||
> $ Savepoint $ Name Nothing "difficult_bit")
|
||||
,(TestStatement ansi2011
|
||||
"savepoint difficult_bit"
|
||||
$ Savepoint $ Name Nothing "difficult_bit")
|
||||
|
||||
|
||||
{-
|
||||
17.6 <release savepoint statement>
|
||||
|
||||
<release savepoint statement> ::=
|
||||
RELEASE SAVEPOINT <savepoint specifier>
|
||||
-}
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "release savepoint difficult_bit"
|
||||
> $ ReleaseSavepoint $ Name Nothing "difficult_bit")
|
||||
,(TestStatement ansi2011
|
||||
"release savepoint difficult_bit"
|
||||
$ ReleaseSavepoint $ Name Nothing "difficult_bit")
|
||||
|
||||
|
||||
{-
|
||||
17.7 <commit statement>
|
||||
|
||||
<commit statement> ::=
|
||||
COMMIT [ WORK ] [ AND [ NO ] CHAIN ]
|
||||
-}
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "commit"
|
||||
> $ Commit)
|
||||
,(TestStatement ansi2011
|
||||
"commit"
|
||||
$ Commit)
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "commit work"
|
||||
> $ Commit)
|
||||
,(TestStatement ansi2011
|
||||
"commit work"
|
||||
$ Commit)
|
||||
|
||||
|
||||
{-
|
||||
17.8 <rollback statement>
|
||||
|
||||
<rollback statement> ::=
|
||||
|
@ -113,20 +124,22 @@ BEGIN is not in the standard!
|
|||
|
||||
<savepoint clause> ::=
|
||||
TO SAVEPOINT <savepoint specifier>
|
||||
-}
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "rollback"
|
||||
> $ Rollback Nothing)
|
||||
,(TestStatement ansi2011
|
||||
"rollback"
|
||||
$ Rollback Nothing)
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "rollback work"
|
||||
> $ Rollback Nothing)
|
||||
,(TestStatement ansi2011
|
||||
"rollback work"
|
||||
$ Rollback Nothing)
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "rollback to savepoint difficult_bit"
|
||||
> $ Rollback $ Just $ Name Nothing "difficult_bit")
|
||||
,(TestStatement ansi2011
|
||||
"rollback to savepoint difficult_bit"
|
||||
$ Rollback $ Just $ Name Nothing "difficult_bit")
|
||||
|
||||
|
||||
{-
|
||||
19 Session management
|
||||
|
||||
19.1 <set session characteristics statement>
|
||||
|
@ -215,5 +228,6 @@ BEGIN is not in the standard!
|
|||
|
||||
<collation specification> ::=
|
||||
<value specification>
|
||||
-}
|
||||
|
||||
> ]
|
||||
]
|
|
@ -1,17 +1,18 @@
|
|||
|
||||
Section 14 in Foundation
|
||||
-- Section 14 in Foundation
|
||||
|
||||
|
||||
> module Language.SQL.SimpleSQL.SQL2011DataManipulation (sql2011DataManipulationTests) where
|
||||
module Language.SQL.SimpleSQL.SQL2011DataManipulation (sql2011DataManipulationTests) where
|
||||
|
||||
> import Language.SQL.SimpleSQL.TestTypes
|
||||
> import Language.SQL.SimpleSQL.Syntax
|
||||
import Language.SQL.SimpleSQL.TestTypes
|
||||
import Language.SQL.SimpleSQL.Syntax
|
||||
|
||||
> sql2011DataManipulationTests :: TestItem
|
||||
> sql2011DataManipulationTests = Group "sql 2011 data manipulation tests"
|
||||
> [
|
||||
sql2011DataManipulationTests :: TestItem
|
||||
sql2011DataManipulationTests = Group "sql 2011 data manipulation tests"
|
||||
[
|
||||
|
||||
|
||||
{-
|
||||
14 Data manipulation
|
||||
|
||||
|
||||
|
@ -107,22 +108,24 @@ Section 14 in Foundation
|
|||
FROM <point in time 1> TO <point in time 2> ]
|
||||
[ [ AS ] <correlation name> ]
|
||||
[ WHERE <search condition> ]
|
||||
-}
|
||||
|
||||
> (TestStatement ansi2011 "delete from t"
|
||||
> $ Delete [Name Nothing "t"] Nothing Nothing)
|
||||
(TestStatement ansi2011 "delete from t"
|
||||
$ Delete [Name Nothing "t"] Nothing Nothing)
|
||||
|
||||
> ,(TestStatement ansi2011 "delete from t as u"
|
||||
> $ Delete [Name Nothing "t"] (Just (Name Nothing "u")) Nothing)
|
||||
,(TestStatement ansi2011 "delete from t as u"
|
||||
$ Delete [Name Nothing "t"] (Just (Name Nothing "u")) Nothing)
|
||||
|
||||
> ,(TestStatement ansi2011 "delete from t where x = 5"
|
||||
> $ Delete [Name Nothing "t"] Nothing
|
||||
> (Just $ BinOp (Iden [Name Nothing "x"]) [Name Nothing "="] (NumLit "5")))
|
||||
,(TestStatement ansi2011 "delete from t where x = 5"
|
||||
$ Delete [Name Nothing "t"] Nothing
|
||||
(Just $ BinOp (Iden [Name Nothing "x"]) [Name Nothing "="] (NumLit "5")))
|
||||
|
||||
|
||||
> ,(TestStatement ansi2011 "delete from t as u where u.x = 5"
|
||||
> $ Delete [Name Nothing "t"] (Just (Name Nothing "u"))
|
||||
> (Just $ BinOp (Iden [Name Nothing "u", Name Nothing "x"]) [Name Nothing "="] (NumLit "5")))
|
||||
,(TestStatement ansi2011 "delete from t as u where u.x = 5"
|
||||
$ Delete [Name Nothing "t"] (Just (Name Nothing "u"))
|
||||
(Just $ BinOp (Iden [Name Nothing "u", Name Nothing "x"]) [Name Nothing "="] (NumLit "5")))
|
||||
|
||||
{-
|
||||
14.10 <truncate table statement>
|
||||
|
||||
<truncate table statement> ::=
|
||||
|
@ -131,17 +134,19 @@ Section 14 in Foundation
|
|||
<identity column restart option> ::=
|
||||
CONTINUE IDENTITY
|
||||
| RESTART IDENTITY
|
||||
-}
|
||||
|
||||
> ,(TestStatement ansi2011 "truncate table t"
|
||||
> $ Truncate [Name Nothing "t"] DefaultIdentityRestart)
|
||||
,(TestStatement ansi2011 "truncate table t"
|
||||
$ Truncate [Name Nothing "t"] DefaultIdentityRestart)
|
||||
|
||||
> ,(TestStatement ansi2011 "truncate table t continue identity"
|
||||
> $ Truncate [Name Nothing "t"] ContinueIdentity)
|
||||
,(TestStatement ansi2011 "truncate table t continue identity"
|
||||
$ Truncate [Name Nothing "t"] ContinueIdentity)
|
||||
|
||||
> ,(TestStatement ansi2011 "truncate table t restart identity"
|
||||
> $ Truncate [Name Nothing "t"] RestartIdentity)
|
||||
,(TestStatement ansi2011 "truncate table t restart identity"
|
||||
$ Truncate [Name Nothing "t"] RestartIdentity)
|
||||
|
||||
|
||||
{-
|
||||
14.11 <insert statement>
|
||||
|
||||
<insert statement> ::=
|
||||
|
@ -174,40 +179,42 @@ Section 14 in Foundation
|
|||
|
||||
<insert column list> ::=
|
||||
<column name list>
|
||||
-}
|
||||
|
||||
> ,(TestStatement ansi2011 "insert into t select * from u"
|
||||
> $ Insert [Name Nothing "t"] Nothing
|
||||
> $ InsertQuery makeSelect
|
||||
> {qeSelectList = [(Star, Nothing)]
|
||||
> ,qeFrom = [TRSimple [Name Nothing "u"]]})
|
||||
,(TestStatement ansi2011 "insert into t select * from u"
|
||||
$ Insert [Name Nothing "t"] Nothing
|
||||
$ InsertQuery makeSelect
|
||||
{qeSelectList = [(Star, Nothing)]
|
||||
,qeFrom = [TRSimple [Name Nothing "u"]]})
|
||||
|
||||
> ,(TestStatement ansi2011 "insert into t(a,b,c) select * from u"
|
||||
> $ Insert [Name Nothing "t"] (Just [Name Nothing "a", Name Nothing "b", Name Nothing "c"])
|
||||
> $ InsertQuery makeSelect
|
||||
> {qeSelectList = [(Star, Nothing)]
|
||||
> ,qeFrom = [TRSimple [Name Nothing "u"]]})
|
||||
,(TestStatement ansi2011 "insert into t(a,b,c) select * from u"
|
||||
$ Insert [Name Nothing "t"] (Just [Name Nothing "a", Name Nothing "b", Name Nothing "c"])
|
||||
$ InsertQuery makeSelect
|
||||
{qeSelectList = [(Star, Nothing)]
|
||||
,qeFrom = [TRSimple [Name Nothing "u"]]})
|
||||
|
||||
> ,(TestStatement ansi2011 "insert into t default values"
|
||||
> $ Insert [Name Nothing "t"] Nothing DefaultInsertValues)
|
||||
,(TestStatement ansi2011 "insert into t default values"
|
||||
$ Insert [Name Nothing "t"] Nothing DefaultInsertValues)
|
||||
|
||||
> ,(TestStatement ansi2011 "insert into t values(1,2)"
|
||||
> $ Insert [Name Nothing "t"] Nothing
|
||||
> $ InsertQuery $ Values [[NumLit "1", NumLit "2"]])
|
||||
,(TestStatement ansi2011 "insert into t values(1,2)"
|
||||
$ Insert [Name Nothing "t"] Nothing
|
||||
$ InsertQuery $ Values [[NumLit "1", NumLit "2"]])
|
||||
|
||||
> ,(TestStatement ansi2011 "insert into t values (1,2),(3,4)"
|
||||
> $ Insert [Name Nothing "t"] Nothing
|
||||
> $ InsertQuery $ Values [[NumLit "1", NumLit "2"]
|
||||
> ,[NumLit "3", NumLit "4"]])
|
||||
,(TestStatement ansi2011 "insert into t values (1,2),(3,4)"
|
||||
$ Insert [Name Nothing "t"] Nothing
|
||||
$ InsertQuery $ Values [[NumLit "1", NumLit "2"]
|
||||
,[NumLit "3", NumLit "4"]])
|
||||
|
||||
> ,(TestStatement ansi2011
|
||||
> "insert into t values (default,null,array[],multiset[])"
|
||||
> $ Insert [Name Nothing "t"] Nothing
|
||||
> $ InsertQuery $ Values [[Iden [Name Nothing "default"]
|
||||
> ,Iden [Name Nothing "null"]
|
||||
> ,Array (Iden [Name Nothing "array"]) []
|
||||
> ,MultisetCtor []]])
|
||||
,(TestStatement ansi2011
|
||||
"insert into t values (default,null,array[],multiset[])"
|
||||
$ Insert [Name Nothing "t"] Nothing
|
||||
$ InsertQuery $ Values [[Iden [Name Nothing "default"]
|
||||
,Iden [Name Nothing "null"]
|
||||
,Array (Iden [Name Nothing "array"]) []
|
||||
,MultisetCtor []]])
|
||||
|
||||
|
||||
{-
|
||||
14.12 <merge statement>
|
||||
|
||||
<merge statement> ::=
|
||||
|
@ -445,37 +452,39 @@ FROM CentralOfficeAccounts;
|
|||
[ [ AS ] <correlation name> ]
|
||||
SET <set clause list>
|
||||
[ WHERE <search condition> ]
|
||||
-}
|
||||
|
||||
|
||||
> ,(TestStatement ansi2011 "update t set a=b"
|
||||
> $ Update [Name Nothing "t"] Nothing
|
||||
> [Set [Name Nothing "a"] (Iden [Name Nothing "b"])] Nothing)
|
||||
,(TestStatement ansi2011 "update t set a=b"
|
||||
$ Update [Name Nothing "t"] Nothing
|
||||
[Set [Name Nothing "a"] (Iden [Name Nothing "b"])] Nothing)
|
||||
|
||||
> ,(TestStatement ansi2011 "update t set a=b, c=5"
|
||||
> $ Update [Name Nothing "t"] Nothing
|
||||
> [Set [Name Nothing "a"] (Iden [Name Nothing "b"])
|
||||
> ,Set [Name Nothing "c"] (NumLit "5")] Nothing)
|
||||
,(TestStatement ansi2011 "update t set a=b, c=5"
|
||||
$ Update [Name Nothing "t"] Nothing
|
||||
[Set [Name Nothing "a"] (Iden [Name Nothing "b"])
|
||||
,Set [Name Nothing "c"] (NumLit "5")] Nothing)
|
||||
|
||||
|
||||
> ,(TestStatement ansi2011 "update t set a=b where a>5"
|
||||
> $ Update [Name Nothing "t"] Nothing
|
||||
> [Set [Name Nothing "a"] (Iden [Name Nothing "b"])]
|
||||
> $ Just $ BinOp (Iden [Name Nothing "a"]) [Name Nothing ">"] (NumLit "5"))
|
||||
,(TestStatement ansi2011 "update t set a=b where a>5"
|
||||
$ Update [Name Nothing "t"] Nothing
|
||||
[Set [Name Nothing "a"] (Iden [Name Nothing "b"])]
|
||||
$ Just $ BinOp (Iden [Name Nothing "a"]) [Name Nothing ">"] (NumLit "5"))
|
||||
|
||||
|
||||
> ,(TestStatement ansi2011 "update t as u set a=b where u.a>5"
|
||||
> $ Update [Name Nothing "t"] (Just $ Name Nothing "u")
|
||||
> [Set [Name Nothing "a"] (Iden [Name Nothing "b"])]
|
||||
> $ Just $ BinOp (Iden [Name Nothing "u",Name Nothing "a"])
|
||||
> [Name Nothing ">"] (NumLit "5"))
|
||||
,(TestStatement ansi2011 "update t as u set a=b where u.a>5"
|
||||
$ Update [Name Nothing "t"] (Just $ Name Nothing "u")
|
||||
[Set [Name Nothing "a"] (Iden [Name Nothing "b"])]
|
||||
$ Just $ BinOp (Iden [Name Nothing "u",Name Nothing "a"])
|
||||
[Name Nothing ">"] (NumLit "5"))
|
||||
|
||||
> ,(TestStatement ansi2011 "update t set (a,b)=(3,5)"
|
||||
> $ Update [Name Nothing "t"] Nothing
|
||||
> [SetMultiple [[Name Nothing "a"],[Name Nothing "b"]]
|
||||
> [NumLit "3", NumLit "5"]] Nothing)
|
||||
,(TestStatement ansi2011 "update t set (a,b)=(3,5)"
|
||||
$ Update [Name Nothing "t"] Nothing
|
||||
[SetMultiple [[Name Nothing "a"],[Name Nothing "b"]]
|
||||
[NumLit "3", NumLit "5"]] Nothing)
|
||||
|
||||
|
||||
|
||||
{-
|
||||
14.15 <set clause list>
|
||||
|
||||
<set clause list> ::=
|
||||
|
@ -539,6 +548,7 @@ declare local temporary table t (a int) [on commit {preserve | delete} rows]
|
|||
|
||||
<hold locator statement> ::=
|
||||
HOLD LOCATOR <locator reference> [ { <comma> <locator reference> }... ]
|
||||
-}
|
||||
|
||||
|
||||
> ]
|
||||
]
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
432
tools/Language/SQL/SimpleSQL/ScalarExprs.hs
Normal file
432
tools/Language/SQL/SimpleSQL/ScalarExprs.hs
Normal file
|
@ -0,0 +1,432 @@
|
|||
|
||||
-- Tests for parsing scalar expressions
|
||||
|
||||
module Language.SQL.SimpleSQL.ScalarExprs (scalarExprTests) where
|
||||
|
||||
import Language.SQL.SimpleSQL.TestTypes
|
||||
import Language.SQL.SimpleSQL.Syntax
|
||||
|
||||
scalarExprTests :: TestItem
|
||||
scalarExprTests = Group "scalarExprTests"
|
||||
[literals
|
||||
,identifiers
|
||||
,star
|
||||
,parameter
|
||||
,dots
|
||||
,app
|
||||
,caseexp
|
||||
,convertfun
|
||||
,operators
|
||||
,parens
|
||||
,subqueries
|
||||
,aggregates
|
||||
,windowFunctions
|
||||
,functionsWithReservedNames
|
||||
]
|
||||
|
||||
literals :: TestItem
|
||||
literals = Group "literals" $ map (uncurry (TestScalarExpr ansi2011))
|
||||
[("3", NumLit "3")
|
||||
,("3.", NumLit "3.")
|
||||
,("3.3", NumLit "3.3")
|
||||
,(".3", NumLit ".3")
|
||||
,("3.e3", NumLit "3.e3")
|
||||
,("3.3e3", NumLit "3.3e3")
|
||||
,(".3e3", NumLit ".3e3")
|
||||
,("3e3", NumLit "3e3")
|
||||
,("3e+3", NumLit "3e+3")
|
||||
,("3e-3", NumLit "3e-3")
|
||||
,("'string'", StringLit "'" "'" "string")
|
||||
,("'string with a '' quote'", StringLit "'" "'" "string with a '' quote")
|
||||
,("'1'", StringLit "'" "'" "1")
|
||||
,("interval '3' day"
|
||||
,IntervalLit Nothing "3" (Itf "day" Nothing) Nothing)
|
||||
,("interval '3' day (3)"
|
||||
,IntervalLit Nothing "3" (Itf "day" $ Just (3,Nothing)) Nothing)
|
||||
,("interval '3 weeks'", TypedLit (TypeName [Name Nothing "interval"]) "3 weeks")
|
||||
]
|
||||
|
||||
identifiers :: TestItem
|
||||
identifiers = Group "identifiers" $ map (uncurry (TestScalarExpr ansi2011))
|
||||
[("iden1", Iden [Name Nothing "iden1"])
|
||||
--,("t.a", Iden2 "t" "a")
|
||||
,("\"quoted identifier\"", Iden [Name (Just ("\"","\"")) "quoted identifier"])
|
||||
,("\"from\"", Iden [Name (Just ("\"","\"")) "from"])
|
||||
]
|
||||
|
||||
star :: TestItem
|
||||
star = Group "star" $ map (uncurry (TestScalarExpr ansi2011))
|
||||
[("*", Star)
|
||||
--,("t.*", Star2 "t")
|
||||
--,("ROW(t.*,42)", App "ROW" [Star2 "t", NumLit "42"])
|
||||
]
|
||||
|
||||
parameter :: TestItem
|
||||
parameter = Group "parameter"
|
||||
[TestScalarExpr ansi2011 "?" Parameter
|
||||
,TestScalarExpr postgres "$13" $ PositionalArg 13]
|
||||
|
||||
|
||||
dots :: TestItem
|
||||
dots = Group "dot" $ map (uncurry (TestScalarExpr ansi2011))
|
||||
[("t.a", Iden [Name Nothing "t",Name Nothing "a"])
|
||||
,("t.*", BinOp (Iden [Name Nothing "t"]) [Name Nothing "."] Star)
|
||||
,("a.b.c", Iden [Name Nothing "a",Name Nothing "b",Name Nothing "c"])
|
||||
,("ROW(t.*,42)", App [Name Nothing "ROW"] [BinOp (Iden [Name Nothing "t"]) [Name Nothing "."] Star, NumLit "42"])
|
||||
]
|
||||
|
||||
app :: TestItem
|
||||
app = Group "app" $ map (uncurry (TestScalarExpr ansi2011))
|
||||
[("f()", App [Name Nothing "f"] [])
|
||||
,("f(a)", App [Name Nothing "f"] [Iden [Name Nothing "a"]])
|
||||
,("f(a,b)", App [Name Nothing "f"] [Iden [Name Nothing "a"], Iden [Name Nothing "b"]])
|
||||
]
|
||||
|
||||
caseexp :: TestItem
|
||||
caseexp = Group "caseexp" $ map (uncurry (TestScalarExpr ansi2011))
|
||||
[("case a when 1 then 2 end"
|
||||
,Case (Just $ Iden [Name Nothing "a"]) [([NumLit "1"]
|
||||
,NumLit "2")] Nothing)
|
||||
|
||||
,("case a when 1 then 2 when 3 then 4 end"
|
||||
,Case (Just $ Iden [Name Nothing "a"]) [([NumLit "1"], NumLit "2")
|
||||
,([NumLit "3"], NumLit "4")] Nothing)
|
||||
|
||||
,("case a when 1 then 2 when 3 then 4 else 5 end"
|
||||
,Case (Just $ Iden [Name Nothing "a"]) [([NumLit "1"], NumLit "2")
|
||||
,([NumLit "3"], NumLit "4")]
|
||||
(Just $ NumLit "5"))
|
||||
|
||||
,("case when a=1 then 2 when a=3 then 4 else 5 end"
|
||||
,Case Nothing [([BinOp (Iden [Name Nothing "a"]) [Name Nothing "="] (NumLit "1")], NumLit "2")
|
||||
,([BinOp (Iden [Name Nothing "a"]) [Name Nothing "="] (NumLit "3")], NumLit "4")]
|
||||
(Just $ NumLit "5"))
|
||||
|
||||
,("case a when 1,2 then 10 when 3,4 then 20 end"
|
||||
,Case (Just $ Iden [Name Nothing "a"]) [([NumLit "1",NumLit "2"]
|
||||
,NumLit "10")
|
||||
,([NumLit "3",NumLit "4"]
|
||||
,NumLit "20")]
|
||||
Nothing)
|
||||
|
||||
]
|
||||
|
||||
convertfun :: TestItem
|
||||
convertfun = Group "convert" $ map (uncurry (TestScalarExpr sqlserver))
|
||||
[("CONVERT(varchar, 25.65)"
|
||||
,Convert (TypeName [Name Nothing "varchar"]) (NumLit "25.65") Nothing)
|
||||
,("CONVERT(datetime, '2017-08-25')"
|
||||
,Convert (TypeName [Name Nothing "datetime"]) (StringLit "'" "'" "2017-08-25") Nothing)
|
||||
,("CONVERT(varchar, '2017-08-25', 101)"
|
||||
,Convert (TypeName [Name Nothing "varchar"]) (StringLit "'" "'" "2017-08-25") (Just 101))
|
||||
]
|
||||
|
||||
operators :: TestItem
|
||||
operators = Group "operators"
|
||||
[binaryOperators
|
||||
,unaryOperators
|
||||
,casts
|
||||
,miscOps]
|
||||
|
||||
binaryOperators :: TestItem
|
||||
binaryOperators = Group "binaryOperators" $ map (uncurry (TestScalarExpr ansi2011))
|
||||
[("a + b", BinOp (Iden [Name Nothing "a"]) [Name Nothing "+"] (Iden [Name Nothing "b"]))
|
||||
-- sanity check fixities
|
||||
-- todo: add more fixity checking
|
||||
|
||||
,("a + b * c"
|
||||
,BinOp (Iden [Name Nothing "a"]) [Name Nothing "+"]
|
||||
(BinOp (Iden [Name Nothing "b"]) [Name Nothing "*"] (Iden [Name Nothing "c"])))
|
||||
|
||||
,("a * b + c"
|
||||
,BinOp (BinOp (Iden [Name Nothing "a"]) [Name Nothing "*"] (Iden [Name Nothing "b"]))
|
||||
[Name Nothing "+"] (Iden [Name Nothing "c"]))
|
||||
]
|
||||
|
||||
unaryOperators :: TestItem
|
||||
unaryOperators = Group "unaryOperators" $ map (uncurry (TestScalarExpr ansi2011))
|
||||
[("not a", PrefixOp [Name Nothing "not"] $ Iden [Name Nothing "a"])
|
||||
,("not not a", PrefixOp [Name Nothing "not"] $ PrefixOp [Name Nothing "not"] $ Iden [Name Nothing "a"])
|
||||
,("+a", PrefixOp [Name Nothing "+"] $ Iden [Name Nothing "a"])
|
||||
,("-a", PrefixOp [Name Nothing "-"] $ Iden [Name Nothing "a"])
|
||||
]
|
||||
|
||||
|
||||
casts :: TestItem
|
||||
casts = Group "operators" $ map (uncurry (TestScalarExpr ansi2011))
|
||||
[("cast('1' as int)"
|
||||
,Cast (StringLit "'" "'" "1") $ TypeName [Name Nothing "int"])
|
||||
|
||||
,("int '3'"
|
||||
,TypedLit (TypeName [Name Nothing "int"]) "3")
|
||||
|
||||
,("cast('1' as double precision)"
|
||||
,Cast (StringLit "'" "'" "1") $ TypeName [Name Nothing "double precision"])
|
||||
|
||||
,("cast('1' as float(8))"
|
||||
,Cast (StringLit "'" "'" "1") $ PrecTypeName [Name Nothing "float"] 8)
|
||||
|
||||
,("cast('1' as decimal(15,2))"
|
||||
,Cast (StringLit "'" "'" "1") $ PrecScaleTypeName [Name Nothing "decimal"] 15 2)
|
||||
|
||||
|
||||
,("double precision '3'"
|
||||
,TypedLit (TypeName [Name Nothing "double precision"]) "3")
|
||||
]
|
||||
|
||||
subqueries :: TestItem
|
||||
subqueries = Group "unaryOperators" $ map (uncurry (TestScalarExpr ansi2011))
|
||||
[("exists (select a from t)", SubQueryExpr SqExists ms)
|
||||
,("(select a from t)", SubQueryExpr SqSq ms)
|
||||
|
||||
,("a in (select a from t)"
|
||||
,In True (Iden [Name Nothing "a"]) (InQueryExpr ms))
|
||||
|
||||
,("a not in (select a from t)"
|
||||
,In False (Iden [Name Nothing "a"]) (InQueryExpr ms))
|
||||
|
||||
,("a > all (select a from t)"
|
||||
,QuantifiedComparison (Iden [Name Nothing "a"]) [Name Nothing ">"] CPAll ms)
|
||||
|
||||
,("a = some (select a from t)"
|
||||
,QuantifiedComparison (Iden [Name Nothing "a"]) [Name Nothing "="] CPSome ms)
|
||||
|
||||
,("a <= any (select a from t)"
|
||||
,QuantifiedComparison (Iden [Name Nothing "a"]) [Name Nothing "<="] CPAny ms)
|
||||
]
|
||||
where
|
||||
ms = makeSelect
|
||||
{qeSelectList = [(Iden [Name Nothing "a"],Nothing)]
|
||||
,qeFrom = [TRSimple [Name Nothing "t"]]
|
||||
}
|
||||
|
||||
miscOps :: TestItem
|
||||
miscOps = Group "unaryOperators" $ map (uncurry (TestScalarExpr ansi2011))
|
||||
[("a in (1,2,3)"
|
||||
,In True (Iden [Name Nothing "a"]) $ InList $ map NumLit ["1","2","3"])
|
||||
|
||||
,("a is null", PostfixOp [Name Nothing "is null"] (Iden [Name Nothing "a"]))
|
||||
,("a is not null", PostfixOp [Name Nothing "is not null"] (Iden [Name Nothing "a"]))
|
||||
,("a is true", PostfixOp [Name Nothing "is true"] (Iden [Name Nothing "a"]))
|
||||
,("a is not true", PostfixOp [Name Nothing "is not true"] (Iden [Name Nothing "a"]))
|
||||
,("a is false", PostfixOp [Name Nothing "is false"] (Iden [Name Nothing "a"]))
|
||||
,("a is not false", PostfixOp [Name Nothing "is not false"] (Iden [Name Nothing "a"]))
|
||||
,("a is unknown", PostfixOp [Name Nothing "is unknown"] (Iden [Name Nothing "a"]))
|
||||
,("a is not unknown", PostfixOp [Name Nothing "is not unknown"] (Iden [Name Nothing "a"]))
|
||||
,("a is distinct from b", BinOp (Iden [Name Nothing "a"]) [Name Nothing "is distinct from"] (Iden [Name Nothing "b"]))
|
||||
|
||||
,("a is not distinct from b"
|
||||
,BinOp (Iden [Name Nothing "a"]) [Name Nothing "is not distinct from"] (Iden [Name Nothing "b"]))
|
||||
|
||||
,("a like b", BinOp (Iden [Name Nothing "a"]) [Name Nothing "like"] (Iden [Name Nothing "b"]))
|
||||
,("a not like b", BinOp (Iden [Name Nothing "a"]) [Name Nothing "not like"] (Iden [Name Nothing "b"]))
|
||||
,("a is similar to b", BinOp (Iden [Name Nothing "a"]) [Name Nothing "is similar to"] (Iden [Name Nothing "b"]))
|
||||
|
||||
,("a is not similar to b"
|
||||
,BinOp (Iden [Name Nothing "a"]) [Name Nothing "is not similar to"] (Iden [Name Nothing "b"]))
|
||||
|
||||
,("a overlaps b", BinOp (Iden [Name Nothing "a"]) [Name Nothing "overlaps"] (Iden [Name Nothing "b"]))
|
||||
|
||||
|
||||
-- special operators
|
||||
|
||||
,("a between b and c", SpecialOp [Name Nothing "between"] [Iden [Name Nothing "a"]
|
||||
,Iden [Name Nothing "b"]
|
||||
,Iden [Name Nothing "c"]])
|
||||
|
||||
,("a not between b and c", SpecialOp [Name Nothing "not between"] [Iden [Name Nothing "a"]
|
||||
,Iden [Name Nothing "b"]
|
||||
,Iden [Name Nothing "c"]])
|
||||
,("(1,2)"
|
||||
,SpecialOp [Name Nothing "rowctor"] [NumLit "1", NumLit "2"])
|
||||
|
||||
|
||||
-- keyword special operators
|
||||
|
||||
,("extract(day from t)"
|
||||
, SpecialOpK [Name Nothing "extract"] (Just $ Iden [Name Nothing "day"]) [("from", Iden [Name Nothing "t"])])
|
||||
|
||||
,("substring(x from 1 for 2)"
|
||||
,SpecialOpK [Name Nothing "substring"] (Just $ Iden [Name Nothing "x"]) [("from", NumLit "1")
|
||||
,("for", NumLit "2")])
|
||||
|
||||
,("substring(x from 1)"
|
||||
,SpecialOpK [Name Nothing "substring"] (Just $ Iden [Name Nothing "x"]) [("from", NumLit "1")])
|
||||
|
||||
,("substring(x for 2)"
|
||||
,SpecialOpK [Name Nothing "substring"] (Just $ Iden [Name Nothing "x"]) [("for", NumLit "2")])
|
||||
|
||||
,("substring(x from 1 for 2 collate C)"
|
||||
,SpecialOpK [Name Nothing "substring"] (Just $ Iden [Name Nothing "x"])
|
||||
[("from", NumLit "1")
|
||||
,("for", Collate (NumLit "2") [Name Nothing "C"])])
|
||||
|
||||
-- this doesn't work because of a overlap in the 'in' parser
|
||||
|
||||
,("POSITION( string1 IN string2 )"
|
||||
,SpecialOpK [Name Nothing "position"] (Just $ Iden [Name Nothing "string1"]) [("in", Iden [Name Nothing "string2"])])
|
||||
|
||||
,("CONVERT(char_value USING conversion_char_name)"
|
||||
,SpecialOpK [Name Nothing "convert"] (Just $ Iden [Name Nothing "char_value"])
|
||||
[("using", Iden [Name Nothing "conversion_char_name"])])
|
||||
|
||||
,("TRANSLATE(char_value USING translation_name)"
|
||||
,SpecialOpK [Name Nothing "translate"] (Just $ Iden [Name Nothing "char_value"])
|
||||
[("using", Iden [Name Nothing "translation_name"])])
|
||||
|
||||
{-
|
||||
OVERLAY(string PLACING embedded_string FROM start
|
||||
[FOR length])
|
||||
-}
|
||||
|
||||
,("OVERLAY(string PLACING embedded_string FROM start)"
|
||||
,SpecialOpK [Name Nothing "overlay"] (Just $ Iden [Name Nothing "string"])
|
||||
[("placing", Iden [Name Nothing "embedded_string"])
|
||||
,("from", Iden [Name Nothing "start"])])
|
||||
|
||||
,("OVERLAY(string PLACING embedded_string FROM start FOR length)"
|
||||
,SpecialOpK [Name Nothing "overlay"] (Just $ Iden [Name Nothing "string"])
|
||||
[("placing", Iden [Name Nothing "embedded_string"])
|
||||
,("from", Iden [Name Nothing "start"])
|
||||
,("for", Iden [Name Nothing "length"])])
|
||||
|
||||
{-
|
||||
TRIM( [ [{LEADING | TRAILING | BOTH}] [removal_char] FROM ]
|
||||
target_string
|
||||
[COLLATE collation_name] )
|
||||
-}
|
||||
|
||||
|
||||
|
||||
,("trim(from target_string)"
|
||||
,SpecialOpK [Name Nothing "trim"] Nothing
|
||||
[("both", StringLit "'" "'" " ")
|
||||
,("from", Iden [Name Nothing "target_string"])])
|
||||
|
||||
,("trim(leading from target_string)"
|
||||
,SpecialOpK [Name Nothing "trim"] Nothing
|
||||
[("leading", StringLit "'" "'" " ")
|
||||
,("from", Iden [Name Nothing "target_string"])])
|
||||
|
||||
,("trim(trailing from target_string)"
|
||||
,SpecialOpK [Name Nothing "trim"] Nothing
|
||||
[("trailing", StringLit "'" "'" " ")
|
||||
,("from", Iden [Name Nothing "target_string"])])
|
||||
|
||||
,("trim(both from target_string)"
|
||||
,SpecialOpK [Name Nothing "trim"] Nothing
|
||||
[("both", StringLit "'" "'" " ")
|
||||
,("from", Iden [Name Nothing "target_string"])])
|
||||
|
||||
|
||||
,("trim(leading 'x' from target_string)"
|
||||
,SpecialOpK [Name Nothing "trim"] Nothing
|
||||
[("leading", StringLit "'" "'" "x")
|
||||
,("from", Iden [Name Nothing "target_string"])])
|
||||
|
||||
,("trim(trailing 'y' from target_string)"
|
||||
,SpecialOpK [Name Nothing "trim"] Nothing
|
||||
[("trailing", StringLit "'" "'" "y")
|
||||
,("from", Iden [Name Nothing "target_string"])])
|
||||
|
||||
,("trim(both 'z' from target_string collate C)"
|
||||
,SpecialOpK [Name Nothing "trim"] Nothing
|
||||
[("both", StringLit "'" "'" "z")
|
||||
,("from", Collate (Iden [Name Nothing "target_string"]) [Name Nothing "C"])])
|
||||
|
||||
,("trim(leading from target_string)"
|
||||
,SpecialOpK [Name Nothing "trim"] Nothing
|
||||
[("leading", StringLit "'" "'" " ")
|
||||
,("from", Iden [Name Nothing "target_string"])])
|
||||
|
||||
|
||||
]
|
||||
|
||||
aggregates :: TestItem
|
||||
aggregates = Group "aggregates" $ map (uncurry (TestScalarExpr ansi2011))
|
||||
[("count(*)",App [Name Nothing "count"] [Star])
|
||||
|
||||
,("sum(a order by a)"
|
||||
,AggregateApp [Name Nothing "sum"] SQDefault [Iden [Name Nothing "a"]]
|
||||
[SortSpec (Iden [Name Nothing "a"]) DirDefault NullsOrderDefault] Nothing)
|
||||
|
||||
,("sum(all a)"
|
||||
,AggregateApp [Name Nothing "sum"] All [Iden [Name Nothing "a"]] [] Nothing)
|
||||
|
||||
,("count(distinct a)"
|
||||
,AggregateApp [Name Nothing "count"] Distinct [Iden [Name Nothing "a"]] [] Nothing)
|
||||
]
|
||||
|
||||
windowFunctions :: TestItem
|
||||
windowFunctions = Group "windowFunctions" $ map (uncurry (TestScalarExpr ansi2011))
|
||||
[("max(a) over ()", WindowApp [Name Nothing "max"] [Iden [Name Nothing "a"]] [] [] Nothing)
|
||||
,("count(*) over ()", WindowApp [Name Nothing "count"] [Star] [] [] Nothing)
|
||||
|
||||
,("max(a) over (partition by b)"
|
||||
,WindowApp [Name Nothing "max"] [Iden [Name Nothing "a"]] [Iden [Name Nothing "b"]] [] Nothing)
|
||||
|
||||
,("max(a) over (partition by b,c)"
|
||||
,WindowApp [Name Nothing "max"] [Iden [Name Nothing "a"]] [Iden [Name Nothing "b"],Iden [Name Nothing "c"]] [] Nothing)
|
||||
|
||||
,("sum(a) over (order by b)"
|
||||
,WindowApp [Name Nothing "sum"] [Iden [Name Nothing "a"]] []
|
||||
[SortSpec (Iden [Name Nothing "b"]) DirDefault NullsOrderDefault] Nothing)
|
||||
|
||||
,("sum(a) over (order by b desc,c)"
|
||||
,WindowApp [Name Nothing "sum"] [Iden [Name Nothing "a"]] []
|
||||
[SortSpec (Iden [Name Nothing "b"]) Desc NullsOrderDefault
|
||||
,SortSpec (Iden [Name Nothing "c"]) DirDefault NullsOrderDefault] Nothing)
|
||||
|
||||
,("sum(a) over (partition by b order by c)"
|
||||
,WindowApp [Name Nothing "sum"] [Iden [Name Nothing "a"]] [Iden [Name Nothing "b"]]
|
||||
[SortSpec (Iden [Name Nothing "c"]) DirDefault NullsOrderDefault] Nothing)
|
||||
|
||||
,("sum(a) over (partition by b order by c range unbounded preceding)"
|
||||
,WindowApp [Name Nothing "sum"] [Iden [Name Nothing "a"]] [Iden [Name Nothing "b"]]
|
||||
[SortSpec (Iden [Name Nothing "c"]) DirDefault NullsOrderDefault]
|
||||
$ Just $ FrameFrom FrameRange UnboundedPreceding)
|
||||
|
||||
,("sum(a) over (partition by b order by c range 5 preceding)"
|
||||
,WindowApp [Name Nothing "sum"] [Iden [Name Nothing "a"]] [Iden [Name Nothing "b"]]
|
||||
[SortSpec (Iden [Name Nothing "c"]) DirDefault NullsOrderDefault]
|
||||
$ Just $ FrameFrom FrameRange $ Preceding (NumLit "5"))
|
||||
|
||||
,("sum(a) over (partition by b order by c range current row)"
|
||||
,WindowApp [Name Nothing "sum"] [Iden [Name Nothing "a"]] [Iden [Name Nothing "b"]]
|
||||
[SortSpec (Iden [Name Nothing "c"]) DirDefault NullsOrderDefault]
|
||||
$ Just $ FrameFrom FrameRange Current)
|
||||
|
||||
,("sum(a) over (partition by b order by c rows 5 following)"
|
||||
,WindowApp [Name Nothing "sum"] [Iden [Name Nothing "a"]] [Iden [Name Nothing "b"]]
|
||||
[SortSpec (Iden [Name Nothing "c"]) DirDefault NullsOrderDefault]
|
||||
$ Just $ FrameFrom FrameRows $ Following (NumLit "5"))
|
||||
|
||||
,("sum(a) over (partition by b order by c range unbounded following)"
|
||||
,WindowApp [Name Nothing "sum"] [Iden [Name Nothing "a"]] [Iden [Name Nothing "b"]]
|
||||
[SortSpec (Iden [Name Nothing "c"]) DirDefault NullsOrderDefault]
|
||||
$ Just $ FrameFrom FrameRange UnboundedFollowing)
|
||||
|
||||
,("sum(a) over (partition by b order by c \n\
|
||||
\range between 5 preceding and 5 following)"
|
||||
,WindowApp [Name Nothing "sum"] [Iden [Name Nothing "a"]] [Iden [Name Nothing "b"]]
|
||||
[SortSpec (Iden [Name Nothing "c"]) DirDefault NullsOrderDefault]
|
||||
$ Just $ FrameBetween FrameRange
|
||||
(Preceding (NumLit "5"))
|
||||
(Following (NumLit "5")))
|
||||
|
||||
]
|
||||
|
||||
parens :: TestItem
|
||||
parens = Group "parens" $ map (uncurry (TestScalarExpr ansi2011))
|
||||
[("(a)", Parens (Iden [Name Nothing "a"]))
|
||||
,("(a + b)", Parens (BinOp (Iden [Name Nothing "a"]) [Name Nothing "+"] (Iden [Name Nothing "b"])))
|
||||
]
|
||||
|
||||
functionsWithReservedNames :: TestItem
|
||||
functionsWithReservedNames = Group "functionsWithReservedNames" $ map t
|
||||
["abs"
|
||||
,"char_length"
|
||||
]
|
||||
where
|
||||
t fn = TestScalarExpr ansi2011 (fn ++ "(a)") $ App [Name Nothing fn] [Iden [Name Nothing "a"]]
|
||||
|
|
@ -1,428 +0,0 @@
|
|||
|
||||
Tests for parsing scalar expressions
|
||||
|
||||
> module Language.SQL.SimpleSQL.ScalarExprs (scalarExprTests) where
|
||||
|
||||
> import Language.SQL.SimpleSQL.TestTypes
|
||||
> import Language.SQL.SimpleSQL.Syntax
|
||||
|
||||
> scalarExprTests :: TestItem
|
||||
> scalarExprTests = Group "scalarExprTests"
|
||||
> [literals
|
||||
> ,identifiers
|
||||
> ,star
|
||||
> ,parameter
|
||||
> ,dots
|
||||
> ,app
|
||||
> ,caseexp
|
||||
> ,convertfun
|
||||
> ,operators
|
||||
> ,parens
|
||||
> ,subqueries
|
||||
> ,aggregates
|
||||
> ,windowFunctions
|
||||
> ,functionsWithReservedNames
|
||||
> ]
|
||||
|
||||
> literals :: TestItem
|
||||
> literals = Group "literals" $ map (uncurry (TestScalarExpr ansi2011))
|
||||
> [("3", NumLit "3")
|
||||
> ,("3.", NumLit "3.")
|
||||
> ,("3.3", NumLit "3.3")
|
||||
> ,(".3", NumLit ".3")
|
||||
> ,("3.e3", NumLit "3.e3")
|
||||
> ,("3.3e3", NumLit "3.3e3")
|
||||
> ,(".3e3", NumLit ".3e3")
|
||||
> ,("3e3", NumLit "3e3")
|
||||
> ,("3e+3", NumLit "3e+3")
|
||||
> ,("3e-3", NumLit "3e-3")
|
||||
> ,("'string'", StringLit "'" "'" "string")
|
||||
> ,("'string with a '' quote'", StringLit "'" "'" "string with a '' quote")
|
||||
> ,("'1'", StringLit "'" "'" "1")
|
||||
> ,("interval '3' day"
|
||||
> ,IntervalLit Nothing "3" (Itf "day" Nothing) Nothing)
|
||||
> ,("interval '3' day (3)"
|
||||
> ,IntervalLit Nothing "3" (Itf "day" $ Just (3,Nothing)) Nothing)
|
||||
> ,("interval '3 weeks'", TypedLit (TypeName [Name Nothing "interval"]) "3 weeks")
|
||||
> ]
|
||||
|
||||
> identifiers :: TestItem
|
||||
> identifiers = Group "identifiers" $ map (uncurry (TestScalarExpr ansi2011))
|
||||
> [("iden1", Iden [Name Nothing "iden1"])
|
||||
> --,("t.a", Iden2 "t" "a")
|
||||
> ,("\"quoted identifier\"", Iden [Name (Just ("\"","\"")) "quoted identifier"])
|
||||
> ,("\"from\"", Iden [Name (Just ("\"","\"")) "from"])
|
||||
> ]
|
||||
|
||||
> star :: TestItem
|
||||
> star = Group "star" $ map (uncurry (TestScalarExpr ansi2011))
|
||||
> [("*", Star)
|
||||
> --,("t.*", Star2 "t")
|
||||
> --,("ROW(t.*,42)", App "ROW" [Star2 "t", NumLit "42"])
|
||||
> ]
|
||||
|
||||
> parameter :: TestItem
|
||||
> parameter = Group "parameter"
|
||||
> [TestScalarExpr ansi2011 "?" Parameter
|
||||
> ,TestScalarExpr postgres "$13" $ PositionalArg 13]
|
||||
|
||||
|
||||
> dots :: TestItem
|
||||
> dots = Group "dot" $ map (uncurry (TestScalarExpr ansi2011))
|
||||
> [("t.a", Iden [Name Nothing "t",Name Nothing "a"])
|
||||
> ,("t.*", BinOp (Iden [Name Nothing "t"]) [Name Nothing "."] Star)
|
||||
> ,("a.b.c", Iden [Name Nothing "a",Name Nothing "b",Name Nothing "c"])
|
||||
> ,("ROW(t.*,42)", App [Name Nothing "ROW"] [BinOp (Iden [Name Nothing "t"]) [Name Nothing "."] Star, NumLit "42"])
|
||||
> ]
|
||||
|
||||
> app :: TestItem
|
||||
> app = Group "app" $ map (uncurry (TestScalarExpr ansi2011))
|
||||
> [("f()", App [Name Nothing "f"] [])
|
||||
> ,("f(a)", App [Name Nothing "f"] [Iden [Name Nothing "a"]])
|
||||
> ,("f(a,b)", App [Name Nothing "f"] [Iden [Name Nothing "a"], Iden [Name Nothing "b"]])
|
||||
> ]
|
||||
|
||||
> caseexp :: TestItem
|
||||
> caseexp = Group "caseexp" $ map (uncurry (TestScalarExpr ansi2011))
|
||||
> [("case a when 1 then 2 end"
|
||||
> ,Case (Just $ Iden [Name Nothing "a"]) [([NumLit "1"]
|
||||
> ,NumLit "2")] Nothing)
|
||||
|
||||
> ,("case a when 1 then 2 when 3 then 4 end"
|
||||
> ,Case (Just $ Iden [Name Nothing "a"]) [([NumLit "1"], NumLit "2")
|
||||
> ,([NumLit "3"], NumLit "4")] Nothing)
|
||||
|
||||
> ,("case a when 1 then 2 when 3 then 4 else 5 end"
|
||||
> ,Case (Just $ Iden [Name Nothing "a"]) [([NumLit "1"], NumLit "2")
|
||||
> ,([NumLit "3"], NumLit "4")]
|
||||
> (Just $ NumLit "5"))
|
||||
|
||||
> ,("case when a=1 then 2 when a=3 then 4 else 5 end"
|
||||
> ,Case Nothing [([BinOp (Iden [Name Nothing "a"]) [Name Nothing "="] (NumLit "1")], NumLit "2")
|
||||
> ,([BinOp (Iden [Name Nothing "a"]) [Name Nothing "="] (NumLit "3")], NumLit "4")]
|
||||
> (Just $ NumLit "5"))
|
||||
|
||||
> ,("case a when 1,2 then 10 when 3,4 then 20 end"
|
||||
> ,Case (Just $ Iden [Name Nothing "a"]) [([NumLit "1",NumLit "2"]
|
||||
> ,NumLit "10")
|
||||
> ,([NumLit "3",NumLit "4"]
|
||||
> ,NumLit "20")]
|
||||
> Nothing)
|
||||
|
||||
> ]
|
||||
|
||||
> convertfun :: TestItem
|
||||
> convertfun = Group "convert" $ map (uncurry (TestScalarExpr sqlserver))
|
||||
> [("CONVERT(varchar, 25.65)"
|
||||
> ,Convert (TypeName [Name Nothing "varchar"]) (NumLit "25.65") Nothing)
|
||||
> ,("CONVERT(datetime, '2017-08-25')"
|
||||
> ,Convert (TypeName [Name Nothing "datetime"]) (StringLit "'" "'" "2017-08-25") Nothing)
|
||||
> ,("CONVERT(varchar, '2017-08-25', 101)"
|
||||
> ,Convert (TypeName [Name Nothing "varchar"]) (StringLit "'" "'" "2017-08-25") (Just 101))
|
||||
> ]
|
||||
|
||||
> operators :: TestItem
|
||||
> operators = Group "operators"
|
||||
> [binaryOperators
|
||||
> ,unaryOperators
|
||||
> ,casts
|
||||
> ,miscOps]
|
||||
|
||||
> binaryOperators :: TestItem
|
||||
> binaryOperators = Group "binaryOperators" $ map (uncurry (TestScalarExpr ansi2011))
|
||||
> [("a + b", BinOp (Iden [Name Nothing "a"]) [Name Nothing "+"] (Iden [Name Nothing "b"]))
|
||||
> -- sanity check fixities
|
||||
> -- todo: add more fixity checking
|
||||
|
||||
> ,("a + b * c"
|
||||
> ,BinOp (Iden [Name Nothing "a"]) [Name Nothing "+"]
|
||||
> (BinOp (Iden [Name Nothing "b"]) [Name Nothing "*"] (Iden [Name Nothing "c"])))
|
||||
|
||||
> ,("a * b + c"
|
||||
> ,BinOp (BinOp (Iden [Name Nothing "a"]) [Name Nothing "*"] (Iden [Name Nothing "b"]))
|
||||
> [Name Nothing "+"] (Iden [Name Nothing "c"]))
|
||||
> ]
|
||||
|
||||
> unaryOperators :: TestItem
|
||||
> unaryOperators = Group "unaryOperators" $ map (uncurry (TestScalarExpr ansi2011))
|
||||
> [("not a", PrefixOp [Name Nothing "not"] $ Iden [Name Nothing "a"])
|
||||
> ,("not not a", PrefixOp [Name Nothing "not"] $ PrefixOp [Name Nothing "not"] $ Iden [Name Nothing "a"])
|
||||
> ,("+a", PrefixOp [Name Nothing "+"] $ Iden [Name Nothing "a"])
|
||||
> ,("-a", PrefixOp [Name Nothing "-"] $ Iden [Name Nothing "a"])
|
||||
> ]
|
||||
|
||||
|
||||
> casts :: TestItem
|
||||
> casts = Group "operators" $ map (uncurry (TestScalarExpr ansi2011))
|
||||
> [("cast('1' as int)"
|
||||
> ,Cast (StringLit "'" "'" "1") $ TypeName [Name Nothing "int"])
|
||||
|
||||
> ,("int '3'"
|
||||
> ,TypedLit (TypeName [Name Nothing "int"]) "3")
|
||||
|
||||
> ,("cast('1' as double precision)"
|
||||
> ,Cast (StringLit "'" "'" "1") $ TypeName [Name Nothing "double precision"])
|
||||
|
||||
> ,("cast('1' as float(8))"
|
||||
> ,Cast (StringLit "'" "'" "1") $ PrecTypeName [Name Nothing "float"] 8)
|
||||
|
||||
> ,("cast('1' as decimal(15,2))"
|
||||
> ,Cast (StringLit "'" "'" "1") $ PrecScaleTypeName [Name Nothing "decimal"] 15 2)
|
||||
|
||||
|
||||
> ,("double precision '3'"
|
||||
> ,TypedLit (TypeName [Name Nothing "double precision"]) "3")
|
||||
> ]
|
||||
|
||||
> subqueries :: TestItem
|
||||
> subqueries = Group "unaryOperators" $ map (uncurry (TestScalarExpr ansi2011))
|
||||
> [("exists (select a from t)", SubQueryExpr SqExists ms)
|
||||
> ,("(select a from t)", SubQueryExpr SqSq ms)
|
||||
|
||||
> ,("a in (select a from t)"
|
||||
> ,In True (Iden [Name Nothing "a"]) (InQueryExpr ms))
|
||||
|
||||
> ,("a not in (select a from t)"
|
||||
> ,In False (Iden [Name Nothing "a"]) (InQueryExpr ms))
|
||||
|
||||
> ,("a > all (select a from t)"
|
||||
> ,QuantifiedComparison (Iden [Name Nothing "a"]) [Name Nothing ">"] CPAll ms)
|
||||
|
||||
> ,("a = some (select a from t)"
|
||||
> ,QuantifiedComparison (Iden [Name Nothing "a"]) [Name Nothing "="] CPSome ms)
|
||||
|
||||
> ,("a <= any (select a from t)"
|
||||
> ,QuantifiedComparison (Iden [Name Nothing "a"]) [Name Nothing "<="] CPAny ms)
|
||||
> ]
|
||||
> where
|
||||
> ms = makeSelect
|
||||
> {qeSelectList = [(Iden [Name Nothing "a"],Nothing)]
|
||||
> ,qeFrom = [TRSimple [Name Nothing "t"]]
|
||||
> }
|
||||
|
||||
> miscOps :: TestItem
|
||||
> miscOps = Group "unaryOperators" $ map (uncurry (TestScalarExpr ansi2011))
|
||||
> [("a in (1,2,3)"
|
||||
> ,In True (Iden [Name Nothing "a"]) $ InList $ map NumLit ["1","2","3"])
|
||||
|
||||
> ,("a is null", PostfixOp [Name Nothing "is null"] (Iden [Name Nothing "a"]))
|
||||
> ,("a is not null", PostfixOp [Name Nothing "is not null"] (Iden [Name Nothing "a"]))
|
||||
> ,("a is true", PostfixOp [Name Nothing "is true"] (Iden [Name Nothing "a"]))
|
||||
> ,("a is not true", PostfixOp [Name Nothing "is not true"] (Iden [Name Nothing "a"]))
|
||||
> ,("a is false", PostfixOp [Name Nothing "is false"] (Iden [Name Nothing "a"]))
|
||||
> ,("a is not false", PostfixOp [Name Nothing "is not false"] (Iden [Name Nothing "a"]))
|
||||
> ,("a is unknown", PostfixOp [Name Nothing "is unknown"] (Iden [Name Nothing "a"]))
|
||||
> ,("a is not unknown", PostfixOp [Name Nothing "is not unknown"] (Iden [Name Nothing "a"]))
|
||||
> ,("a is distinct from b", BinOp (Iden [Name Nothing "a"]) [Name Nothing "is distinct from"] (Iden [Name Nothing "b"]))
|
||||
|
||||
> ,("a is not distinct from b"
|
||||
> ,BinOp (Iden [Name Nothing "a"]) [Name Nothing "is not distinct from"] (Iden [Name Nothing "b"]))
|
||||
|
||||
> ,("a like b", BinOp (Iden [Name Nothing "a"]) [Name Nothing "like"] (Iden [Name Nothing "b"]))
|
||||
> ,("a not like b", BinOp (Iden [Name Nothing "a"]) [Name Nothing "not like"] (Iden [Name Nothing "b"]))
|
||||
> ,("a is similar to b", BinOp (Iden [Name Nothing "a"]) [Name Nothing "is similar to"] (Iden [Name Nothing "b"]))
|
||||
|
||||
> ,("a is not similar to b"
|
||||
> ,BinOp (Iden [Name Nothing "a"]) [Name Nothing "is not similar to"] (Iden [Name Nothing "b"]))
|
||||
|
||||
> ,("a overlaps b", BinOp (Iden [Name Nothing "a"]) [Name Nothing "overlaps"] (Iden [Name Nothing "b"]))
|
||||
|
||||
|
||||
special operators
|
||||
|
||||
> ,("a between b and c", SpecialOp [Name Nothing "between"] [Iden [Name Nothing "a"]
|
||||
> ,Iden [Name Nothing "b"]
|
||||
> ,Iden [Name Nothing "c"]])
|
||||
|
||||
> ,("a not between b and c", SpecialOp [Name Nothing "not between"] [Iden [Name Nothing "a"]
|
||||
> ,Iden [Name Nothing "b"]
|
||||
> ,Iden [Name Nothing "c"]])
|
||||
> ,("(1,2)"
|
||||
> ,SpecialOp [Name Nothing "rowctor"] [NumLit "1", NumLit "2"])
|
||||
|
||||
|
||||
keyword special operators
|
||||
|
||||
> ,("extract(day from t)"
|
||||
> , SpecialOpK [Name Nothing "extract"] (Just $ Iden [Name Nothing "day"]) [("from", Iden [Name Nothing "t"])])
|
||||
|
||||
> ,("substring(x from 1 for 2)"
|
||||
> ,SpecialOpK [Name Nothing "substring"] (Just $ Iden [Name Nothing "x"]) [("from", NumLit "1")
|
||||
> ,("for", NumLit "2")])
|
||||
|
||||
> ,("substring(x from 1)"
|
||||
> ,SpecialOpK [Name Nothing "substring"] (Just $ Iden [Name Nothing "x"]) [("from", NumLit "1")])
|
||||
|
||||
> ,("substring(x for 2)"
|
||||
> ,SpecialOpK [Name Nothing "substring"] (Just $ Iden [Name Nothing "x"]) [("for", NumLit "2")])
|
||||
|
||||
> ,("substring(x from 1 for 2 collate C)"
|
||||
> ,SpecialOpK [Name Nothing "substring"] (Just $ Iden [Name Nothing "x"])
|
||||
> [("from", NumLit "1")
|
||||
> ,("for", Collate (NumLit "2") [Name Nothing "C"])])
|
||||
|
||||
this doesn't work because of a overlap in the 'in' parser
|
||||
|
||||
> ,("POSITION( string1 IN string2 )"
|
||||
> ,SpecialOpK [Name Nothing "position"] (Just $ Iden [Name Nothing "string1"]) [("in", Iden [Name Nothing "string2"])])
|
||||
|
||||
> ,("CONVERT(char_value USING conversion_char_name)"
|
||||
> ,SpecialOpK [Name Nothing "convert"] (Just $ Iden [Name Nothing "char_value"])
|
||||
> [("using", Iden [Name Nothing "conversion_char_name"])])
|
||||
|
||||
> ,("TRANSLATE(char_value USING translation_name)"
|
||||
> ,SpecialOpK [Name Nothing "translate"] (Just $ Iden [Name Nothing "char_value"])
|
||||
> [("using", Iden [Name Nothing "translation_name"])])
|
||||
|
||||
OVERLAY(string PLACING embedded_string FROM start
|
||||
[FOR length])
|
||||
|
||||
> ,("OVERLAY(string PLACING embedded_string FROM start)"
|
||||
> ,SpecialOpK [Name Nothing "overlay"] (Just $ Iden [Name Nothing "string"])
|
||||
> [("placing", Iden [Name Nothing "embedded_string"])
|
||||
> ,("from", Iden [Name Nothing "start"])])
|
||||
|
||||
> ,("OVERLAY(string PLACING embedded_string FROM start FOR length)"
|
||||
> ,SpecialOpK [Name Nothing "overlay"] (Just $ Iden [Name Nothing "string"])
|
||||
> [("placing", Iden [Name Nothing "embedded_string"])
|
||||
> ,("from", Iden [Name Nothing "start"])
|
||||
> ,("for", Iden [Name Nothing "length"])])
|
||||
|
||||
TRIM( [ [{LEADING | TRAILING | BOTH}] [removal_char] FROM ]
|
||||
target_string
|
||||
[COLLATE collation_name] )
|
||||
|
||||
|
||||
|
||||
> ,("trim(from target_string)"
|
||||
> ,SpecialOpK [Name Nothing "trim"] Nothing
|
||||
> [("both", StringLit "'" "'" " ")
|
||||
> ,("from", Iden [Name Nothing "target_string"])])
|
||||
|
||||
> ,("trim(leading from target_string)"
|
||||
> ,SpecialOpK [Name Nothing "trim"] Nothing
|
||||
> [("leading", StringLit "'" "'" " ")
|
||||
> ,("from", Iden [Name Nothing "target_string"])])
|
||||
|
||||
> ,("trim(trailing from target_string)"
|
||||
> ,SpecialOpK [Name Nothing "trim"] Nothing
|
||||
> [("trailing", StringLit "'" "'" " ")
|
||||
> ,("from", Iden [Name Nothing "target_string"])])
|
||||
|
||||
> ,("trim(both from target_string)"
|
||||
> ,SpecialOpK [Name Nothing "trim"] Nothing
|
||||
> [("both", StringLit "'" "'" " ")
|
||||
> ,("from", Iden [Name Nothing "target_string"])])
|
||||
|
||||
|
||||
> ,("trim(leading 'x' from target_string)"
|
||||
> ,SpecialOpK [Name Nothing "trim"] Nothing
|
||||
> [("leading", StringLit "'" "'" "x")
|
||||
> ,("from", Iden [Name Nothing "target_string"])])
|
||||
|
||||
> ,("trim(trailing 'y' from target_string)"
|
||||
> ,SpecialOpK [Name Nothing "trim"] Nothing
|
||||
> [("trailing", StringLit "'" "'" "y")
|
||||
> ,("from", Iden [Name Nothing "target_string"])])
|
||||
|
||||
> ,("trim(both 'z' from target_string collate C)"
|
||||
> ,SpecialOpK [Name Nothing "trim"] Nothing
|
||||
> [("both", StringLit "'" "'" "z")
|
||||
> ,("from", Collate (Iden [Name Nothing "target_string"]) [Name Nothing "C"])])
|
||||
|
||||
> ,("trim(leading from target_string)"
|
||||
> ,SpecialOpK [Name Nothing "trim"] Nothing
|
||||
> [("leading", StringLit "'" "'" " ")
|
||||
> ,("from", Iden [Name Nothing "target_string"])])
|
||||
|
||||
|
||||
> ]
|
||||
|
||||
> aggregates :: TestItem
|
||||
> aggregates = Group "aggregates" $ map (uncurry (TestScalarExpr ansi2011))
|
||||
> [("count(*)",App [Name Nothing "count"] [Star])
|
||||
|
||||
> ,("sum(a order by a)"
|
||||
> ,AggregateApp [Name Nothing "sum"] SQDefault [Iden [Name Nothing "a"]]
|
||||
> [SortSpec (Iden [Name Nothing "a"]) DirDefault NullsOrderDefault] Nothing)
|
||||
|
||||
> ,("sum(all a)"
|
||||
> ,AggregateApp [Name Nothing "sum"] All [Iden [Name Nothing "a"]] [] Nothing)
|
||||
|
||||
> ,("count(distinct a)"
|
||||
> ,AggregateApp [Name Nothing "count"] Distinct [Iden [Name Nothing "a"]] [] Nothing)
|
||||
> ]
|
||||
|
||||
> windowFunctions :: TestItem
|
||||
> windowFunctions = Group "windowFunctions" $ map (uncurry (TestScalarExpr ansi2011))
|
||||
> [("max(a) over ()", WindowApp [Name Nothing "max"] [Iden [Name Nothing "a"]] [] [] Nothing)
|
||||
> ,("count(*) over ()", WindowApp [Name Nothing "count"] [Star] [] [] Nothing)
|
||||
|
||||
> ,("max(a) over (partition by b)"
|
||||
> ,WindowApp [Name Nothing "max"] [Iden [Name Nothing "a"]] [Iden [Name Nothing "b"]] [] Nothing)
|
||||
|
||||
> ,("max(a) over (partition by b,c)"
|
||||
> ,WindowApp [Name Nothing "max"] [Iden [Name Nothing "a"]] [Iden [Name Nothing "b"],Iden [Name Nothing "c"]] [] Nothing)
|
||||
|
||||
> ,("sum(a) over (order by b)"
|
||||
> ,WindowApp [Name Nothing "sum"] [Iden [Name Nothing "a"]] []
|
||||
> [SortSpec (Iden [Name Nothing "b"]) DirDefault NullsOrderDefault] Nothing)
|
||||
|
||||
> ,("sum(a) over (order by b desc,c)"
|
||||
> ,WindowApp [Name Nothing "sum"] [Iden [Name Nothing "a"]] []
|
||||
> [SortSpec (Iden [Name Nothing "b"]) Desc NullsOrderDefault
|
||||
> ,SortSpec (Iden [Name Nothing "c"]) DirDefault NullsOrderDefault] Nothing)
|
||||
|
||||
> ,("sum(a) over (partition by b order by c)"
|
||||
> ,WindowApp [Name Nothing "sum"] [Iden [Name Nothing "a"]] [Iden [Name Nothing "b"]]
|
||||
> [SortSpec (Iden [Name Nothing "c"]) DirDefault NullsOrderDefault] Nothing)
|
||||
|
||||
> ,("sum(a) over (partition by b order by c range unbounded preceding)"
|
||||
> ,WindowApp [Name Nothing "sum"] [Iden [Name Nothing "a"]] [Iden [Name Nothing "b"]]
|
||||
> [SortSpec (Iden [Name Nothing "c"]) DirDefault NullsOrderDefault]
|
||||
> $ Just $ FrameFrom FrameRange UnboundedPreceding)
|
||||
|
||||
> ,("sum(a) over (partition by b order by c range 5 preceding)"
|
||||
> ,WindowApp [Name Nothing "sum"] [Iden [Name Nothing "a"]] [Iden [Name Nothing "b"]]
|
||||
> [SortSpec (Iden [Name Nothing "c"]) DirDefault NullsOrderDefault]
|
||||
> $ Just $ FrameFrom FrameRange $ Preceding (NumLit "5"))
|
||||
|
||||
> ,("sum(a) over (partition by b order by c range current row)"
|
||||
> ,WindowApp [Name Nothing "sum"] [Iden [Name Nothing "a"]] [Iden [Name Nothing "b"]]
|
||||
> [SortSpec (Iden [Name Nothing "c"]) DirDefault NullsOrderDefault]
|
||||
> $ Just $ FrameFrom FrameRange Current)
|
||||
|
||||
> ,("sum(a) over (partition by b order by c rows 5 following)"
|
||||
> ,WindowApp [Name Nothing "sum"] [Iden [Name Nothing "a"]] [Iden [Name Nothing "b"]]
|
||||
> [SortSpec (Iden [Name Nothing "c"]) DirDefault NullsOrderDefault]
|
||||
> $ Just $ FrameFrom FrameRows $ Following (NumLit "5"))
|
||||
|
||||
> ,("sum(a) over (partition by b order by c range unbounded following)"
|
||||
> ,WindowApp [Name Nothing "sum"] [Iden [Name Nothing "a"]] [Iden [Name Nothing "b"]]
|
||||
> [SortSpec (Iden [Name Nothing "c"]) DirDefault NullsOrderDefault]
|
||||
> $ Just $ FrameFrom FrameRange UnboundedFollowing)
|
||||
|
||||
> ,("sum(a) over (partition by b order by c \n\
|
||||
> \range between 5 preceding and 5 following)"
|
||||
> ,WindowApp [Name Nothing "sum"] [Iden [Name Nothing "a"]] [Iden [Name Nothing "b"]]
|
||||
> [SortSpec (Iden [Name Nothing "c"]) DirDefault NullsOrderDefault]
|
||||
> $ Just $ FrameBetween FrameRange
|
||||
> (Preceding (NumLit "5"))
|
||||
> (Following (NumLit "5")))
|
||||
|
||||
> ]
|
||||
|
||||
> parens :: TestItem
|
||||
> parens = Group "parens" $ map (uncurry (TestScalarExpr ansi2011))
|
||||
> [("(a)", Parens (Iden [Name Nothing "a"]))
|
||||
> ,("(a + b)", Parens (BinOp (Iden [Name Nothing "a"]) [Name Nothing "+"] (Iden [Name Nothing "b"])))
|
||||
> ]
|
||||
|
||||
> functionsWithReservedNames :: TestItem
|
||||
> functionsWithReservedNames = Group "functionsWithReservedNames" $ map t
|
||||
> ["abs"
|
||||
> ,"char_length"
|
||||
> ]
|
||||
> where
|
||||
> t fn = TestScalarExpr ansi2011 (fn ++ "(a)") $ App [Name Nothing fn] [Iden [Name Nothing "a"]]
|
||||
|
107
tools/Language/SQL/SimpleSQL/TableRefs.hs
Normal file
107
tools/Language/SQL/SimpleSQL/TableRefs.hs
Normal file
|
@ -0,0 +1,107 @@
|
|||
|
||||
{-
|
||||
These are the tests for parsing focusing on the from part of query
|
||||
expression
|
||||
-}
|
||||
|
||||
module Language.SQL.SimpleSQL.TableRefs (tableRefTests) where
|
||||
|
||||
import Language.SQL.SimpleSQL.TestTypes
|
||||
import Language.SQL.SimpleSQL.Syntax
|
||||
|
||||
|
||||
tableRefTests :: TestItem
|
||||
tableRefTests = Group "tableRefTests" $ map (uncurry (TestQueryExpr ansi2011))
|
||||
[("select a from t"
|
||||
,ms [TRSimple [Name Nothing "t"]])
|
||||
|
||||
,("select a from f(a)"
|
||||
,ms [TRFunction [Name Nothing "f"] [Iden [Name Nothing "a"]]])
|
||||
|
||||
,("select a from t,u"
|
||||
,ms [TRSimple [Name Nothing "t"], TRSimple [Name Nothing "u"]])
|
||||
|
||||
,("select a from s.t"
|
||||
,ms [TRSimple [Name Nothing "s", Name Nothing "t"]])
|
||||
|
||||
-- these lateral queries make no sense but the syntax is valid
|
||||
|
||||
,("select a from lateral a"
|
||||
,ms [TRLateral $ TRSimple [Name Nothing "a"]])
|
||||
|
||||
,("select a from lateral a,b"
|
||||
,ms [TRLateral $ TRSimple [Name Nothing "a"], TRSimple [Name Nothing "b"]])
|
||||
|
||||
,("select a from a, lateral b"
|
||||
,ms [TRSimple [Name Nothing "a"], TRLateral $ TRSimple [Name Nothing "b"]])
|
||||
|
||||
,("select a from a natural join lateral b"
|
||||
,ms [TRJoin (TRSimple [Name Nothing "a"]) True JInner
|
||||
(TRLateral $ TRSimple [Name Nothing "b"])
|
||||
Nothing])
|
||||
|
||||
,("select a from lateral a natural join lateral b"
|
||||
,ms [TRJoin (TRLateral $ TRSimple [Name Nothing "a"]) True JInner
|
||||
(TRLateral $ TRSimple [Name Nothing "b"])
|
||||
Nothing])
|
||||
|
||||
|
||||
,("select a from t inner join u on expr"
|
||||
,ms [TRJoin (TRSimple [Name Nothing "t"]) False JInner (TRSimple [Name Nothing "u"])
|
||||
(Just $ JoinOn $ Iden [Name Nothing "expr"])])
|
||||
|
||||
,("select a from t join u on expr"
|
||||
,ms [TRJoin (TRSimple [Name Nothing "t"]) False JInner (TRSimple [Name Nothing "u"])
|
||||
(Just $ JoinOn $ Iden [Name Nothing "expr"])])
|
||||
|
||||
,("select a from t left join u on expr"
|
||||
,ms [TRJoin (TRSimple [Name Nothing "t"]) False JLeft (TRSimple [Name Nothing "u"])
|
||||
(Just $ JoinOn $ Iden [Name Nothing "expr"])])
|
||||
|
||||
,("select a from t right join u on expr"
|
||||
,ms [TRJoin (TRSimple [Name Nothing "t"]) False JRight (TRSimple [Name Nothing "u"])
|
||||
(Just $ JoinOn $ Iden [Name Nothing "expr"])])
|
||||
|
||||
,("select a from t full join u on expr"
|
||||
,ms [TRJoin (TRSimple [Name Nothing "t"]) False JFull (TRSimple [Name Nothing "u"])
|
||||
(Just $ JoinOn $ Iden [Name Nothing "expr"])])
|
||||
|
||||
,("select a from t cross join u"
|
||||
,ms [TRJoin (TRSimple [Name Nothing "t"]) False
|
||||
JCross (TRSimple [Name Nothing "u"]) Nothing])
|
||||
|
||||
,("select a from t natural inner join u"
|
||||
,ms [TRJoin (TRSimple [Name Nothing "t"]) True JInner (TRSimple [Name Nothing "u"])
|
||||
Nothing])
|
||||
|
||||
,("select a from t inner join u using(a,b)"
|
||||
,ms [TRJoin (TRSimple [Name Nothing "t"]) False JInner (TRSimple [Name Nothing "u"])
|
||||
(Just $ JoinUsing [Name Nothing "a", Name Nothing "b"])])
|
||||
|
||||
,("select a from (select a from t)"
|
||||
,ms [TRQueryExpr $ ms [TRSimple [Name Nothing "t"]]])
|
||||
|
||||
,("select a from t as u"
|
||||
,ms [TRAlias (TRSimple [Name Nothing "t"]) (Alias (Name Nothing "u") Nothing)])
|
||||
|
||||
,("select a from t u"
|
||||
,ms [TRAlias (TRSimple [Name Nothing "t"]) (Alias (Name Nothing "u") Nothing)])
|
||||
|
||||
,("select a from t u(b)"
|
||||
,ms [TRAlias (TRSimple [Name Nothing "t"]) (Alias (Name Nothing "u") $ Just [Name Nothing "b"])])
|
||||
|
||||
,("select a from (t cross join u) as u"
|
||||
,ms [TRAlias (TRParens $
|
||||
TRJoin (TRSimple [Name Nothing "t"]) False JCross (TRSimple [Name Nothing "u"]) Nothing)
|
||||
(Alias (Name Nothing "u") Nothing)])
|
||||
-- todo: not sure if the associativity is correct
|
||||
|
||||
,("select a from t cross join u cross join v",
|
||||
ms [TRJoin
|
||||
(TRJoin (TRSimple [Name Nothing "t"]) False
|
||||
JCross (TRSimple [Name Nothing "u"]) Nothing)
|
||||
False JCross (TRSimple [Name Nothing "v"]) Nothing])
|
||||
]
|
||||
where
|
||||
ms f = makeSelect {qeSelectList = [(Iden [Name Nothing "a"],Nothing)]
|
||||
,qeFrom = f}
|
|
@ -1,105 +0,0 @@
|
|||
|
||||
These are the tests for parsing focusing on the from part of query
|
||||
expression
|
||||
|
||||
> module Language.SQL.SimpleSQL.TableRefs (tableRefTests) where
|
||||
|
||||
> import Language.SQL.SimpleSQL.TestTypes
|
||||
> import Language.SQL.SimpleSQL.Syntax
|
||||
|
||||
|
||||
> tableRefTests :: TestItem
|
||||
> tableRefTests = Group "tableRefTests" $ map (uncurry (TestQueryExpr ansi2011))
|
||||
> [("select a from t"
|
||||
> ,ms [TRSimple [Name Nothing "t"]])
|
||||
|
||||
> ,("select a from f(a)"
|
||||
> ,ms [TRFunction [Name Nothing "f"] [Iden [Name Nothing "a"]]])
|
||||
|
||||
> ,("select a from t,u"
|
||||
> ,ms [TRSimple [Name Nothing "t"], TRSimple [Name Nothing "u"]])
|
||||
|
||||
> ,("select a from s.t"
|
||||
> ,ms [TRSimple [Name Nothing "s", Name Nothing "t"]])
|
||||
|
||||
these lateral queries make no sense but the syntax is valid
|
||||
|
||||
> ,("select a from lateral a"
|
||||
> ,ms [TRLateral $ TRSimple [Name Nothing "a"]])
|
||||
|
||||
> ,("select a from lateral a,b"
|
||||
> ,ms [TRLateral $ TRSimple [Name Nothing "a"], TRSimple [Name Nothing "b"]])
|
||||
|
||||
> ,("select a from a, lateral b"
|
||||
> ,ms [TRSimple [Name Nothing "a"], TRLateral $ TRSimple [Name Nothing "b"]])
|
||||
|
||||
> ,("select a from a natural join lateral b"
|
||||
> ,ms [TRJoin (TRSimple [Name Nothing "a"]) True JInner
|
||||
> (TRLateral $ TRSimple [Name Nothing "b"])
|
||||
> Nothing])
|
||||
|
||||
> ,("select a from lateral a natural join lateral b"
|
||||
> ,ms [TRJoin (TRLateral $ TRSimple [Name Nothing "a"]) True JInner
|
||||
> (TRLateral $ TRSimple [Name Nothing "b"])
|
||||
> Nothing])
|
||||
|
||||
|
||||
> ,("select a from t inner join u on expr"
|
||||
> ,ms [TRJoin (TRSimple [Name Nothing "t"]) False JInner (TRSimple [Name Nothing "u"])
|
||||
> (Just $ JoinOn $ Iden [Name Nothing "expr"])])
|
||||
|
||||
> ,("select a from t join u on expr"
|
||||
> ,ms [TRJoin (TRSimple [Name Nothing "t"]) False JInner (TRSimple [Name Nothing "u"])
|
||||
> (Just $ JoinOn $ Iden [Name Nothing "expr"])])
|
||||
|
||||
> ,("select a from t left join u on expr"
|
||||
> ,ms [TRJoin (TRSimple [Name Nothing "t"]) False JLeft (TRSimple [Name Nothing "u"])
|
||||
> (Just $ JoinOn $ Iden [Name Nothing "expr"])])
|
||||
|
||||
> ,("select a from t right join u on expr"
|
||||
> ,ms [TRJoin (TRSimple [Name Nothing "t"]) False JRight (TRSimple [Name Nothing "u"])
|
||||
> (Just $ JoinOn $ Iden [Name Nothing "expr"])])
|
||||
|
||||
> ,("select a from t full join u on expr"
|
||||
> ,ms [TRJoin (TRSimple [Name Nothing "t"]) False JFull (TRSimple [Name Nothing "u"])
|
||||
> (Just $ JoinOn $ Iden [Name Nothing "expr"])])
|
||||
|
||||
> ,("select a from t cross join u"
|
||||
> ,ms [TRJoin (TRSimple [Name Nothing "t"]) False
|
||||
> JCross (TRSimple [Name Nothing "u"]) Nothing])
|
||||
|
||||
> ,("select a from t natural inner join u"
|
||||
> ,ms [TRJoin (TRSimple [Name Nothing "t"]) True JInner (TRSimple [Name Nothing "u"])
|
||||
> Nothing])
|
||||
|
||||
> ,("select a from t inner join u using(a,b)"
|
||||
> ,ms [TRJoin (TRSimple [Name Nothing "t"]) False JInner (TRSimple [Name Nothing "u"])
|
||||
> (Just $ JoinUsing [Name Nothing "a", Name Nothing "b"])])
|
||||
|
||||
> ,("select a from (select a from t)"
|
||||
> ,ms [TRQueryExpr $ ms [TRSimple [Name Nothing "t"]]])
|
||||
|
||||
> ,("select a from t as u"
|
||||
> ,ms [TRAlias (TRSimple [Name Nothing "t"]) (Alias (Name Nothing "u") Nothing)])
|
||||
|
||||
> ,("select a from t u"
|
||||
> ,ms [TRAlias (TRSimple [Name Nothing "t"]) (Alias (Name Nothing "u") Nothing)])
|
||||
|
||||
> ,("select a from t u(b)"
|
||||
> ,ms [TRAlias (TRSimple [Name Nothing "t"]) (Alias (Name Nothing "u") $ Just [Name Nothing "b"])])
|
||||
|
||||
> ,("select a from (t cross join u) as u"
|
||||
> ,ms [TRAlias (TRParens $
|
||||
> TRJoin (TRSimple [Name Nothing "t"]) False JCross (TRSimple [Name Nothing "u"]) Nothing)
|
||||
> (Alias (Name Nothing "u") Nothing)])
|
||||
> -- todo: not sure if the associativity is correct
|
||||
|
||||
> ,("select a from t cross join u cross join v",
|
||||
> ms [TRJoin
|
||||
> (TRJoin (TRSimple [Name Nothing "t"]) False
|
||||
> JCross (TRSimple [Name Nothing "u"]) Nothing)
|
||||
> False JCross (TRSimple [Name Nothing "v"]) Nothing])
|
||||
> ]
|
||||
> where
|
||||
> ms f = makeSelect {qeSelectList = [(Iden [Name Nothing "a"],Nothing)]
|
||||
> ,qeFrom = f}
|
43
tools/Language/SQL/SimpleSQL/TestTypes.hs
Normal file
43
tools/Language/SQL/SimpleSQL/TestTypes.hs
Normal file
|
@ -0,0 +1,43 @@
|
|||
|
||||
{-
|
||||
This is the types used to define the tests as pure data. See the
|
||||
Tests.hs module for the 'interpreter'.
|
||||
-}
|
||||
|
||||
module Language.SQL.SimpleSQL.TestTypes
|
||||
(TestItem(..)
|
||||
,module Language.SQL.SimpleSQL.Dialect
|
||||
) where
|
||||
|
||||
import Language.SQL.SimpleSQL.Syntax
|
||||
import Language.SQL.SimpleSQL.Lex (Token)
|
||||
import Language.SQL.SimpleSQL.Dialect
|
||||
|
||||
{-
|
||||
TODO: maybe make the dialect args into [dialect], then each test
|
||||
checks all the dialects mentioned work, and all the dialects not
|
||||
mentioned give a parse error. Not sure if this will be too awkward due
|
||||
to lots of tricky exceptions/variationsx.
|
||||
-}
|
||||
|
||||
data TestItem = Group String [TestItem]
|
||||
| TestScalarExpr Dialect String ScalarExpr
|
||||
| TestQueryExpr Dialect String QueryExpr
|
||||
| TestStatement Dialect String Statement
|
||||
| TestStatements Dialect String [Statement]
|
||||
|
||||
{-
|
||||
this just checks the sql parses without error, mostly just a
|
||||
intermediate when I'm too lazy to write out the parsed AST. These
|
||||
should all be TODO to convert to a testqueryexpr test.
|
||||
-}
|
||||
|
||||
| ParseQueryExpr Dialect String
|
||||
|
||||
-- check that the string given fails to parse
|
||||
|
||||
| ParseQueryExprFails Dialect String
|
||||
| ParseScalarExprFails Dialect String
|
||||
| LexTest Dialect String [Token]
|
||||
| LexFails Dialect String
|
||||
deriving (Eq,Show)
|
|
@ -1,37 +0,0 @@
|
|||
|
||||
This is the types used to define the tests as pure data. See the
|
||||
Tests.lhs module for the 'interpreter'.
|
||||
|
||||
> module Language.SQL.SimpleSQL.TestTypes
|
||||
> (TestItem(..)
|
||||
> ,module Language.SQL.SimpleSQL.Dialect
|
||||
> ) where
|
||||
|
||||
> import Language.SQL.SimpleSQL.Syntax
|
||||
> import Language.SQL.SimpleSQL.Lex (Token)
|
||||
> import Language.SQL.SimpleSQL.Dialect
|
||||
|
||||
TODO: maybe make the dialect args into [dialect], then each test
|
||||
checks all the dialects mentioned work, and all the dialects not
|
||||
mentioned give a parse error. Not sure if this will be too awkward due
|
||||
to lots of tricky exceptions/variationsx.
|
||||
|
||||
> data TestItem = Group String [TestItem]
|
||||
> | TestScalarExpr Dialect String ScalarExpr
|
||||
> | TestQueryExpr Dialect String QueryExpr
|
||||
> | TestStatement Dialect String Statement
|
||||
> | TestStatements Dialect String [Statement]
|
||||
|
||||
this just checks the sql parses without error, mostly just a
|
||||
intermediate when I'm too lazy to write out the parsed AST. These
|
||||
should all be TODO to convert to a testqueryexpr test.
|
||||
|
||||
> | ParseQueryExpr Dialect String
|
||||
|
||||
check that the string given fails to parse
|
||||
|
||||
> | ParseQueryExprFails Dialect String
|
||||
> | ParseScalarExprFails Dialect String
|
||||
> | LexTest Dialect String [Token]
|
||||
> | LexFails Dialect String
|
||||
> deriving (Eq,Show)
|
175
tools/Language/SQL/SimpleSQL/Tests.hs
Normal file
175
tools/Language/SQL/SimpleSQL/Tests.hs
Normal file
|
@ -0,0 +1,175 @@
|
|||
|
||||
{-
|
||||
This is the main tests module which exposes the test data plus the
|
||||
Test.Framework tests. It also contains the code which converts the
|
||||
test data to the Test.Framework tests.
|
||||
-}
|
||||
|
||||
module Language.SQL.SimpleSQL.Tests
|
||||
(testData
|
||||
,tests
|
||||
,TestItem(..)
|
||||
) where
|
||||
|
||||
import qualified Test.Tasty as T
|
||||
import qualified Test.Tasty.HUnit as H
|
||||
|
||||
--import Language.SQL.SimpleSQL.Syntax
|
||||
import Language.SQL.SimpleSQL.Pretty
|
||||
import Language.SQL.SimpleSQL.Parse
|
||||
import Language.SQL.SimpleSQL.Lex
|
||||
|
||||
import Language.SQL.SimpleSQL.TestTypes
|
||||
|
||||
import Language.SQL.SimpleSQL.FullQueries
|
||||
import Language.SQL.SimpleSQL.GroupBy
|
||||
import Language.SQL.SimpleSQL.Postgres
|
||||
import Language.SQL.SimpleSQL.QueryExprComponents
|
||||
import Language.SQL.SimpleSQL.QueryExprs
|
||||
import Language.SQL.SimpleSQL.TableRefs
|
||||
import Language.SQL.SimpleSQL.ScalarExprs
|
||||
import Language.SQL.SimpleSQL.Odbc
|
||||
import Language.SQL.SimpleSQL.Tpch
|
||||
import Language.SQL.SimpleSQL.LexerTests
|
||||
import Language.SQL.SimpleSQL.EmptyStatement
|
||||
import Language.SQL.SimpleSQL.CreateIndex
|
||||
|
||||
import Language.SQL.SimpleSQL.SQL2011Queries
|
||||
import Language.SQL.SimpleSQL.SQL2011AccessControl
|
||||
import Language.SQL.SimpleSQL.SQL2011Bits
|
||||
import Language.SQL.SimpleSQL.SQL2011DataManipulation
|
||||
import Language.SQL.SimpleSQL.SQL2011Schema
|
||||
|
||||
import Language.SQL.SimpleSQL.MySQL
|
||||
import Language.SQL.SimpleSQL.Oracle
|
||||
import Language.SQL.SimpleSQL.CustomDialect
|
||||
|
||||
|
||||
{-
|
||||
Order the tests to start from the simplest first. This is also the
|
||||
order on the generated documentation.
|
||||
-}
|
||||
|
||||
testData :: TestItem
|
||||
testData =
|
||||
Group "parserTest"
|
||||
[lexerTests
|
||||
,scalarExprTests
|
||||
,odbcTests
|
||||
,queryExprComponentTests
|
||||
,queryExprsTests
|
||||
,tableRefTests
|
||||
,groupByTests
|
||||
,fullQueriesTests
|
||||
,postgresTests
|
||||
,tpchTests
|
||||
,sql2011QueryTests
|
||||
,sql2011DataManipulationTests
|
||||
,sql2011SchemaTests
|
||||
,sql2011AccessControlTests
|
||||
,sql2011BitsTests
|
||||
,mySQLTests
|
||||
,oracleTests
|
||||
,customDialectTests
|
||||
,emptyStatementTests
|
||||
,createIndexTests
|
||||
]
|
||||
|
||||
tests :: T.TestTree
|
||||
tests = itemToTest testData
|
||||
|
||||
--runTests :: IO ()
|
||||
--runTests = void $ H.runTestTT $ itemToTest testData
|
||||
|
||||
itemToTest :: TestItem -> T.TestTree
|
||||
itemToTest (Group nm ts) =
|
||||
T.testGroup nm $ map itemToTest ts
|
||||
itemToTest (TestScalarExpr d str expected) =
|
||||
toTest parseScalarExpr prettyScalarExpr d str expected
|
||||
itemToTest (TestQueryExpr d str expected) =
|
||||
toTest parseQueryExpr prettyQueryExpr d str expected
|
||||
itemToTest (TestStatement d str expected) =
|
||||
toTest parseStatement prettyStatement d str expected
|
||||
itemToTest (TestStatements d str expected) =
|
||||
toTest parseStatements prettyStatements d str expected
|
||||
itemToTest (ParseQueryExpr d str) =
|
||||
toPTest parseQueryExpr prettyQueryExpr d str
|
||||
|
||||
itemToTest (ParseQueryExprFails d str) =
|
||||
toFTest parseQueryExpr prettyQueryExpr d str
|
||||
|
||||
itemToTest (ParseScalarExprFails d str) =
|
||||
toFTest parseScalarExpr prettyScalarExpr d str
|
||||
|
||||
itemToTest (LexTest d s ts) = makeLexerTest d s ts
|
||||
itemToTest (LexFails d s) = makeLexingFailsTest d s
|
||||
|
||||
makeLexerTest :: Dialect -> String -> [Token] -> T.TestTree
|
||||
makeLexerTest d s ts = H.testCase s $ do
|
||||
let lx = either (error . show) id $ lexSQL d "" Nothing s
|
||||
H.assertEqual "" ts $ map snd lx
|
||||
let s' = prettyTokens d $ map snd lx
|
||||
H.assertEqual "pretty print" s s'
|
||||
|
||||
makeLexingFailsTest :: Dialect -> String -> T.TestTree
|
||||
makeLexingFailsTest d s = H.testCase s $ do
|
||||
case lexSQL d "" Nothing s of
|
||||
Right x -> H.assertFailure $ "lexing should have failed: " ++ s ++ "\ngot: " ++ show x
|
||||
Left _ -> return ()
|
||||
|
||||
|
||||
toTest :: (Eq a, Show a) =>
|
||||
(Dialect -> String -> Maybe (Int,Int) -> String -> Either ParseError a)
|
||||
-> (Dialect -> a -> String)
|
||||
-> Dialect
|
||||
-> String
|
||||
-> a
|
||||
-> T.TestTree
|
||||
toTest parser pp d str expected = H.testCase str $ do
|
||||
let egot = parser d "" Nothing str
|
||||
case egot of
|
||||
Left e -> H.assertFailure $ peFormattedError e
|
||||
Right got -> do
|
||||
H.assertEqual "" expected got
|
||||
let str' = pp d got
|
||||
let egot' = parser d "" Nothing str'
|
||||
case egot' of
|
||||
Left e' -> H.assertFailure $ "pp roundtrip"
|
||||
++ "\n" ++ str'
|
||||
++ peFormattedError e'
|
||||
Right got' -> H.assertEqual
|
||||
("pp roundtrip" ++ "\n" ++ str')
|
||||
expected got'
|
||||
|
||||
toPTest :: (Eq a, Show a) =>
|
||||
(Dialect -> String -> Maybe (Int,Int) -> String -> Either ParseError a)
|
||||
-> (Dialect -> a -> String)
|
||||
-> Dialect
|
||||
-> String
|
||||
-> T.TestTree
|
||||
toPTest parser pp d str = H.testCase str $ do
|
||||
let egot = parser d "" Nothing str
|
||||
case egot of
|
||||
Left e -> H.assertFailure $ peFormattedError e
|
||||
Right got -> do
|
||||
let str' = pp d got
|
||||
let egot' = parser d "" Nothing str'
|
||||
case egot' of
|
||||
Left e' -> H.assertFailure $ "pp roundtrip "
|
||||
++ "\n" ++ str' ++ "\n"
|
||||
++ peFormattedError e'
|
||||
Right _got' -> return ()
|
||||
|
||||
|
||||
toFTest :: (Eq a, Show a) =>
|
||||
(Dialect -> String -> Maybe (Int,Int) -> String -> Either ParseError a)
|
||||
-> (Dialect -> a -> String)
|
||||
-> Dialect
|
||||
-> String
|
||||
-> T.TestTree
|
||||
toFTest parser _pp d str = H.testCase str $ do
|
||||
let egot = parser d "" Nothing str
|
||||
case egot of
|
||||
Left _e -> return ()
|
||||
Right _got ->
|
||||
H.assertFailure $ "parse didn't fail: " ++ show d ++ "\n" ++ str
|
|
@ -1,171 +0,0 @@
|
|||
|
||||
This is the main tests module which exposes the test data plus the
|
||||
Test.Framework tests. It also contains the code which converts the
|
||||
test data to the Test.Framework tests.
|
||||
|
||||
> module Language.SQL.SimpleSQL.Tests
|
||||
> (testData
|
||||
> ,tests
|
||||
> ,TestItem(..)
|
||||
> ) where
|
||||
|
||||
> import qualified Test.Tasty as T
|
||||
> import qualified Test.Tasty.HUnit as H
|
||||
|
||||
> --import Language.SQL.SimpleSQL.Syntax
|
||||
> import Language.SQL.SimpleSQL.Pretty
|
||||
> import Language.SQL.SimpleSQL.Parse
|
||||
> import Language.SQL.SimpleSQL.Lex
|
||||
|
||||
> import Language.SQL.SimpleSQL.TestTypes
|
||||
|
||||
> import Language.SQL.SimpleSQL.FullQueries
|
||||
> import Language.SQL.SimpleSQL.GroupBy
|
||||
> import Language.SQL.SimpleSQL.Postgres
|
||||
> import Language.SQL.SimpleSQL.QueryExprComponents
|
||||
> import Language.SQL.SimpleSQL.QueryExprs
|
||||
> import Language.SQL.SimpleSQL.TableRefs
|
||||
> import Language.SQL.SimpleSQL.ScalarExprs
|
||||
> import Language.SQL.SimpleSQL.Odbc
|
||||
> import Language.SQL.SimpleSQL.Tpch
|
||||
> import Language.SQL.SimpleSQL.LexerTests
|
||||
> import Language.SQL.SimpleSQL.EmptyStatement
|
||||
> import Language.SQL.SimpleSQL.CreateIndex
|
||||
|
||||
> import Language.SQL.SimpleSQL.SQL2011Queries
|
||||
> import Language.SQL.SimpleSQL.SQL2011AccessControl
|
||||
> import Language.SQL.SimpleSQL.SQL2011Bits
|
||||
> import Language.SQL.SimpleSQL.SQL2011DataManipulation
|
||||
> import Language.SQL.SimpleSQL.SQL2011Schema
|
||||
|
||||
> import Language.SQL.SimpleSQL.MySQL
|
||||
> import Language.SQL.SimpleSQL.Oracle
|
||||
> import Language.SQL.SimpleSQL.CustomDialect
|
||||
|
||||
|
||||
Order the tests to start from the simplest first. This is also the
|
||||
order on the generated documentation.
|
||||
|
||||
> testData :: TestItem
|
||||
> testData =
|
||||
> Group "parserTest"
|
||||
> [lexerTests
|
||||
> ,scalarExprTests
|
||||
> ,odbcTests
|
||||
> ,queryExprComponentTests
|
||||
> ,queryExprsTests
|
||||
> ,tableRefTests
|
||||
> ,groupByTests
|
||||
> ,fullQueriesTests
|
||||
> ,postgresTests
|
||||
> ,tpchTests
|
||||
> ,sql2011QueryTests
|
||||
> ,sql2011DataManipulationTests
|
||||
> ,sql2011SchemaTests
|
||||
> ,sql2011AccessControlTests
|
||||
> ,sql2011BitsTests
|
||||
> ,mySQLTests
|
||||
> ,oracleTests
|
||||
> ,customDialectTests
|
||||
> ,emptyStatementTests
|
||||
> ,createIndexTests
|
||||
> ]
|
||||
|
||||
> tests :: T.TestTree
|
||||
> tests = itemToTest testData
|
||||
|
||||
> --runTests :: IO ()
|
||||
> --runTests = void $ H.runTestTT $ itemToTest testData
|
||||
|
||||
> itemToTest :: TestItem -> T.TestTree
|
||||
> itemToTest (Group nm ts) =
|
||||
> T.testGroup nm $ map itemToTest ts
|
||||
> itemToTest (TestScalarExpr d str expected) =
|
||||
> toTest parseScalarExpr prettyScalarExpr d str expected
|
||||
> itemToTest (TestQueryExpr d str expected) =
|
||||
> toTest parseQueryExpr prettyQueryExpr d str expected
|
||||
> itemToTest (TestStatement d str expected) =
|
||||
> toTest parseStatement prettyStatement d str expected
|
||||
> itemToTest (TestStatements d str expected) =
|
||||
> toTest parseStatements prettyStatements d str expected
|
||||
> itemToTest (ParseQueryExpr d str) =
|
||||
> toPTest parseQueryExpr prettyQueryExpr d str
|
||||
|
||||
> itemToTest (ParseQueryExprFails d str) =
|
||||
> toFTest parseQueryExpr prettyQueryExpr d str
|
||||
|
||||
> itemToTest (ParseScalarExprFails d str) =
|
||||
> toFTest parseScalarExpr prettyScalarExpr d str
|
||||
|
||||
> itemToTest (LexTest d s ts) = makeLexerTest d s ts
|
||||
> itemToTest (LexFails d s) = makeLexingFailsTest d s
|
||||
|
||||
> makeLexerTest :: Dialect -> String -> [Token] -> T.TestTree
|
||||
> makeLexerTest d s ts = H.testCase s $ do
|
||||
> let lx = either (error . show) id $ lexSQL d "" Nothing s
|
||||
> H.assertEqual "" ts $ map snd lx
|
||||
> let s' = prettyTokens d $ map snd lx
|
||||
> H.assertEqual "pretty print" s s'
|
||||
|
||||
> makeLexingFailsTest :: Dialect -> String -> T.TestTree
|
||||
> makeLexingFailsTest d s = H.testCase s $ do
|
||||
> case lexSQL d "" Nothing s of
|
||||
> Right x -> H.assertFailure $ "lexing should have failed: " ++ s ++ "\ngot: " ++ show x
|
||||
> Left _ -> return ()
|
||||
|
||||
|
||||
> toTest :: (Eq a, Show a) =>
|
||||
> (Dialect -> String -> Maybe (Int,Int) -> String -> Either ParseError a)
|
||||
> -> (Dialect -> a -> String)
|
||||
> -> Dialect
|
||||
> -> String
|
||||
> -> a
|
||||
> -> T.TestTree
|
||||
> toTest parser pp d str expected = H.testCase str $ do
|
||||
> let egot = parser d "" Nothing str
|
||||
> case egot of
|
||||
> Left e -> H.assertFailure $ peFormattedError e
|
||||
> Right got -> do
|
||||
> H.assertEqual "" expected got
|
||||
> let str' = pp d got
|
||||
> let egot' = parser d "" Nothing str'
|
||||
> case egot' of
|
||||
> Left e' -> H.assertFailure $ "pp roundtrip"
|
||||
> ++ "\n" ++ str'
|
||||
> ++ peFormattedError e'
|
||||
> Right got' -> H.assertEqual
|
||||
> ("pp roundtrip" ++ "\n" ++ str')
|
||||
> expected got'
|
||||
|
||||
> toPTest :: (Eq a, Show a) =>
|
||||
> (Dialect -> String -> Maybe (Int,Int) -> String -> Either ParseError a)
|
||||
> -> (Dialect -> a -> String)
|
||||
> -> Dialect
|
||||
> -> String
|
||||
> -> T.TestTree
|
||||
> toPTest parser pp d str = H.testCase str $ do
|
||||
> let egot = parser d "" Nothing str
|
||||
> case egot of
|
||||
> Left e -> H.assertFailure $ peFormattedError e
|
||||
> Right got -> do
|
||||
> let str' = pp d got
|
||||
> let egot' = parser d "" Nothing str'
|
||||
> case egot' of
|
||||
> Left e' -> H.assertFailure $ "pp roundtrip "
|
||||
> ++ "\n" ++ str' ++ "\n"
|
||||
> ++ peFormattedError e'
|
||||
> Right _got' -> return ()
|
||||
|
||||
|
||||
> toFTest :: (Eq a, Show a) =>
|
||||
> (Dialect -> String -> Maybe (Int,Int) -> String -> Either ParseError a)
|
||||
> -> (Dialect -> a -> String)
|
||||
> -> Dialect
|
||||
> -> String
|
||||
> -> T.TestTree
|
||||
> toFTest parser _pp d str = H.testCase str $ do
|
||||
> let egot = parser d "" Nothing str
|
||||
> case egot of
|
||||
> Left _e -> return ()
|
||||
> Right _got ->
|
||||
> H.assertFailure $ "parse didn't fail: " ++ show d ++ "\n" ++ str
|
685
tools/Language/SQL/SimpleSQL/Tpch.hs
Normal file
685
tools/Language/SQL/SimpleSQL/Tpch.hs
Normal file
|
@ -0,0 +1,685 @@
|
|||
|
||||
{-
|
||||
Some tests for parsing the tpch queries
|
||||
|
||||
The changes made to the official syntax are:
|
||||
1. replace the set rowcount with ansi standard fetch first n rows only
|
||||
2. replace the create view, query, drop view sequence with a query
|
||||
using a common table expression
|
||||
-}
|
||||
|
||||
module Language.SQL.SimpleSQL.Tpch (tpchTests,tpchQueries) where
|
||||
|
||||
import Language.SQL.SimpleSQL.TestTypes
|
||||
|
||||
tpchTests :: TestItem
|
||||
tpchTests =
|
||||
Group "parse tpch"
|
||||
$ map (ParseQueryExpr ansi2011 . snd) tpchQueries
|
||||
|
||||
tpchQueries :: [(String,String)]
|
||||
tpchQueries =
|
||||
[("Q1","\n\
|
||||
\select\n\
|
||||
\ l_returnflag,\n\
|
||||
\ l_linestatus,\n\
|
||||
\ sum(l_quantity) as sum_qty,\n\
|
||||
\ sum(l_extendedprice) as sum_base_price,\n\
|
||||
\ sum(l_extendedprice * (1 - l_discount)) as sum_disc_price,\n\
|
||||
\ sum(l_extendedprice * (1 - l_discount) * (1 + l_tax)) as sum_charge,\n\
|
||||
\ avg(l_quantity) as avg_qty,\n\
|
||||
\ avg(l_extendedprice) as avg_price,\n\
|
||||
\ avg(l_discount) as avg_disc,\n\
|
||||
\ count(*) as count_order\n\
|
||||
\from\n\
|
||||
\ lineitem\n\
|
||||
\where\n\
|
||||
\ l_shipdate <= date '1998-12-01' - interval '63' day (3)\n\
|
||||
\group by\n\
|
||||
\ l_returnflag,\n\
|
||||
\ l_linestatus\n\
|
||||
\order by\n\
|
||||
\ l_returnflag,\n\
|
||||
\ l_linestatus")
|
||||
,("Q2","\n\
|
||||
\select\n\
|
||||
\ s_acctbal,\n\
|
||||
\ s_name,\n\
|
||||
\ n_name,\n\
|
||||
\ p_partkey,\n\
|
||||
\ p_mfgr,\n\
|
||||
\ s_address,\n\
|
||||
\ s_phone,\n\
|
||||
\ s_comment\n\
|
||||
\from\n\
|
||||
\ part,\n\
|
||||
\ supplier,\n\
|
||||
\ partsupp,\n\
|
||||
\ nation,\n\
|
||||
\ region\n\
|
||||
\where\n\
|
||||
\ p_partkey = ps_partkey\n\
|
||||
\ and s_suppkey = ps_suppkey\n\
|
||||
\ and p_size = 15\n\
|
||||
\ and p_type like '%BRASS'\n\
|
||||
\ and s_nationkey = n_nationkey\n\
|
||||
\ and n_regionkey = r_regionkey\n\
|
||||
\ and r_name = 'EUROPE'\n\
|
||||
\ and ps_supplycost = (\n\
|
||||
\ select\n\
|
||||
\ min(ps_supplycost)\n\
|
||||
\ from\n\
|
||||
\ partsupp,\n\
|
||||
\ supplier,\n\
|
||||
\ nation,\n\
|
||||
\ region\n\
|
||||
\ where\n\
|
||||
\ p_partkey = ps_partkey\n\
|
||||
\ and s_suppkey = ps_suppkey\n\
|
||||
\ and s_nationkey = n_nationkey\n\
|
||||
\ and n_regionkey = r_regionkey\n\
|
||||
\ and r_name = 'EUROPE'\n\
|
||||
\ )\n\
|
||||
\order by\n\
|
||||
\ s_acctbal desc,\n\
|
||||
\ n_name,\n\
|
||||
\ s_name,\n\
|
||||
\ p_partkey\n\
|
||||
\fetch first 100 rows only")
|
||||
,("Q3","\n\
|
||||
\ select\n\
|
||||
\ l_orderkey,\n\
|
||||
\ sum(l_extendedprice * (1 - l_discount)) as revenue,\n\
|
||||
\ o_orderdate,\n\
|
||||
\ o_shippriority\n\
|
||||
\ from\n\
|
||||
\ customer,\n\
|
||||
\ orders,\n\
|
||||
\ lineitem\n\
|
||||
\ where\n\
|
||||
\ c_mktsegment = 'MACHINERY'\n\
|
||||
\ and c_custkey = o_custkey\n\
|
||||
\ and l_orderkey = o_orderkey\n\
|
||||
\ and o_orderdate < date '1995-03-21'\n\
|
||||
\ and l_shipdate > date '1995-03-21'\n\
|
||||
\ group by\n\
|
||||
\ l_orderkey,\n\
|
||||
\ o_orderdate,\n\
|
||||
\ o_shippriority\n\
|
||||
\ order by\n\
|
||||
\ revenue desc,\n\
|
||||
\ o_orderdate\n\
|
||||
\ fetch first 10 rows only")
|
||||
,("Q4","\n\
|
||||
\ select\n\
|
||||
\ o_orderpriority,\n\
|
||||
\ count(*) as order_count\n\
|
||||
\ from\n\
|
||||
\ orders\n\
|
||||
\ where\n\
|
||||
\ o_orderdate >= date '1996-03-01'\n\
|
||||
\ and o_orderdate < date '1996-03-01' + interval '3' month\n\
|
||||
\ and exists (\n\
|
||||
\ select\n\
|
||||
\ *\n\
|
||||
\ from\n\
|
||||
\ lineitem\n\
|
||||
\ where\n\
|
||||
\ l_orderkey = o_orderkey\n\
|
||||
\ and l_commitdate < l_receiptdate\n\
|
||||
\ )\n\
|
||||
\ group by\n\
|
||||
\ o_orderpriority\n\
|
||||
\ order by\n\
|
||||
\ o_orderpriority")
|
||||
,("Q5","\n\
|
||||
\ select\n\
|
||||
\ n_name,\n\
|
||||
\ sum(l_extendedprice * (1 - l_discount)) as revenue\n\
|
||||
\ from\n\
|
||||
\ customer,\n\
|
||||
\ orders,\n\
|
||||
\ lineitem,\n\
|
||||
\ supplier,\n\
|
||||
\ nation,\n\
|
||||
\ region\n\
|
||||
\ where\n\
|
||||
\ c_custkey = o_custkey\n\
|
||||
\ and l_orderkey = o_orderkey\n\
|
||||
\ and l_suppkey = s_suppkey\n\
|
||||
\ and c_nationkey = s_nationkey\n\
|
||||
\ and s_nationkey = n_nationkey\n\
|
||||
\ and n_regionkey = r_regionkey\n\
|
||||
\ and r_name = 'EUROPE'\n\
|
||||
\ and o_orderdate >= date '1997-01-01'\n\
|
||||
\ and o_orderdate < date '1997-01-01' + interval '1' year\n\
|
||||
\ group by\n\
|
||||
\ n_name\n\
|
||||
\ order by\n\
|
||||
\ revenue desc")
|
||||
,("Q6","\n\
|
||||
\ select\n\
|
||||
\ sum(l_extendedprice * l_discount) as revenue\n\
|
||||
\ from\n\
|
||||
\ lineitem\n\
|
||||
\ where\n\
|
||||
\ l_shipdate >= date '1997-01-01'\n\
|
||||
\ and l_shipdate < date '1997-01-01' + interval '1' year\n\
|
||||
\ and l_discount between 0.07 - 0.01 and 0.07 + 0.01\n\
|
||||
\ and l_quantity < 24")
|
||||
,("Q7","\n\
|
||||
\ select\n\
|
||||
\ supp_nation,\n\
|
||||
\ cust_nation,\n\
|
||||
\ l_year,\n\
|
||||
\ sum(volume) as revenue\n\
|
||||
\ from\n\
|
||||
\ (\n\
|
||||
\ select\n\
|
||||
\ n1.n_name as supp_nation,\n\
|
||||
\ n2.n_name as cust_nation,\n\
|
||||
\ extract(year from l_shipdate) as l_year,\n\
|
||||
\ l_extendedprice * (1 - l_discount) as volume\n\
|
||||
\ from\n\
|
||||
\ supplier,\n\
|
||||
\ lineitem,\n\
|
||||
\ orders,\n\
|
||||
\ customer,\n\
|
||||
\ nation n1,\n\
|
||||
\ nation n2\n\
|
||||
\ where\n\
|
||||
\ s_suppkey = l_suppkey\n\
|
||||
\ and o_orderkey = l_orderkey\n\
|
||||
\ and c_custkey = o_custkey\n\
|
||||
\ and s_nationkey = n1.n_nationkey\n\
|
||||
\ and c_nationkey = n2.n_nationkey\n\
|
||||
\ and (\n\
|
||||
\ (n1.n_name = 'PERU' and n2.n_name = 'IRAQ')\n\
|
||||
\ or (n1.n_name = 'IRAQ' and n2.n_name = 'PERU')\n\
|
||||
\ )\n\
|
||||
\ and l_shipdate between date '1995-01-01' and date '1996-12-31'\n\
|
||||
\ ) as shipping\n\
|
||||
\ group by\n\
|
||||
\ supp_nation,\n\
|
||||
\ cust_nation,\n\
|
||||
\ l_year\n\
|
||||
\ order by\n\
|
||||
\ supp_nation,\n\
|
||||
\ cust_nation,\n\
|
||||
\ l_year")
|
||||
,("Q8","\n\
|
||||
\ select\n\
|
||||
\ o_year,\n\
|
||||
\ sum(case\n\
|
||||
\ when nation = 'IRAQ' then volume\n\
|
||||
\ else 0\n\
|
||||
\ end) / sum(volume) as mkt_share\n\
|
||||
\ from\n\
|
||||
\ (\n\
|
||||
\ select\n\
|
||||
\ extract(year from o_orderdate) as o_year,\n\
|
||||
\ l_extendedprice * (1 - l_discount) as volume,\n\
|
||||
\ n2.n_name as nation\n\
|
||||
\ from\n\
|
||||
\ part,\n\
|
||||
\ supplier,\n\
|
||||
\ lineitem,\n\
|
||||
\ orders,\n\
|
||||
\ customer,\n\
|
||||
\ nation n1,\n\
|
||||
\ nation n2,\n\
|
||||
\ region\n\
|
||||
\ where\n\
|
||||
\ p_partkey = l_partkey\n\
|
||||
\ and s_suppkey = l_suppkey\n\
|
||||
\ and l_orderkey = o_orderkey\n\
|
||||
\ and o_custkey = c_custkey\n\
|
||||
\ and c_nationkey = n1.n_nationkey\n\
|
||||
\ and n1.n_regionkey = r_regionkey\n\
|
||||
\ and r_name = 'MIDDLE EAST'\n\
|
||||
\ and s_nationkey = n2.n_nationkey\n\
|
||||
\ and o_orderdate between date '1995-01-01' and date '1996-12-31'\n\
|
||||
\ and p_type = 'STANDARD ANODIZED BRASS'\n\
|
||||
\ ) as all_nations\n\
|
||||
\ group by\n\
|
||||
\ o_year\n\
|
||||
\ order by\n\
|
||||
\ o_year")
|
||||
,("Q9","\n\
|
||||
\ select\n\
|
||||
\ nation,\n\
|
||||
\ o_year,\n\
|
||||
\ sum(amount) as sum_profit\n\
|
||||
\ from\n\
|
||||
\ (\n\
|
||||
\ select\n\
|
||||
\ n_name as nation,\n\
|
||||
\ extract(year from o_orderdate) as o_year,\n\
|
||||
\ l_extendedprice * (1 - l_discount) - ps_supplycost * l_quantity as amount\n\
|
||||
\ from\n\
|
||||
\ part,\n\
|
||||
\ supplier,\n\
|
||||
\ lineitem,\n\
|
||||
\ partsupp,\n\
|
||||
\ orders,\n\
|
||||
\ nation\n\
|
||||
\ where\n\
|
||||
\ s_suppkey = l_suppkey\n\
|
||||
\ and ps_suppkey = l_suppkey\n\
|
||||
\ and ps_partkey = l_partkey\n\
|
||||
\ and p_partkey = l_partkey\n\
|
||||
\ and o_orderkey = l_orderkey\n\
|
||||
\ and s_nationkey = n_nationkey\n\
|
||||
\ and p_name like '%antique%'\n\
|
||||
\ ) as profit\n\
|
||||
\ group by\n\
|
||||
\ nation,\n\
|
||||
\ o_year\n\
|
||||
\ order by\n\
|
||||
\ nation,\n\
|
||||
\ o_year desc")
|
||||
,("Q10","\n\
|
||||
\ select\n\
|
||||
\ c_custkey,\n\
|
||||
\ c_name,\n\
|
||||
\ sum(l_extendedprice * (1 - l_discount)) as revenue,\n\
|
||||
\ c_acctbal,\n\
|
||||
\ n_name,\n\
|
||||
\ c_address,\n\
|
||||
\ c_phone,\n\
|
||||
\ c_comment\n\
|
||||
\ from\n\
|
||||
\ customer,\n\
|
||||
\ orders,\n\
|
||||
\ lineitem,\n\
|
||||
\ nation\n\
|
||||
\ where\n\
|
||||
\ c_custkey = o_custkey\n\
|
||||
\ and l_orderkey = o_orderkey\n\
|
||||
\ and o_orderdate >= date '1993-12-01'\n\
|
||||
\ and o_orderdate < date '1993-12-01' + interval '3' month\n\
|
||||
\ and l_returnflag = 'R'\n\
|
||||
\ and c_nationkey = n_nationkey\n\
|
||||
\ group by\n\
|
||||
\ c_custkey,\n\
|
||||
\ c_name,\n\
|
||||
\ c_acctbal,\n\
|
||||
\ c_phone,\n\
|
||||
\ n_name,\n\
|
||||
\ c_address,\n\
|
||||
\ c_comment\n\
|
||||
\ order by\n\
|
||||
\ revenue desc\n\
|
||||
\ fetch first 20 rows only")
|
||||
,("Q11","\n\
|
||||
\ select\n\
|
||||
\ ps_partkey,\n\
|
||||
\ sum(ps_supplycost * ps_availqty) as value\n\
|
||||
\ from\n\
|
||||
\ partsupp,\n\
|
||||
\ supplier,\n\
|
||||
\ nation\n\
|
||||
\ where\n\
|
||||
\ ps_suppkey = s_suppkey\n\
|
||||
\ and s_nationkey = n_nationkey\n\
|
||||
\ and n_name = 'CHINA'\n\
|
||||
\ group by\n\
|
||||
\ ps_partkey having\n\
|
||||
\ sum(ps_supplycost * ps_availqty) > (\n\
|
||||
\ select\n\
|
||||
\ sum(ps_supplycost * ps_availqty) * 0.0001000000\n\
|
||||
\ from\n\
|
||||
\ partsupp,\n\
|
||||
\ supplier,\n\
|
||||
\ nation\n\
|
||||
\ where\n\
|
||||
\ ps_suppkey = s_suppkey\n\
|
||||
\ and s_nationkey = n_nationkey\n\
|
||||
\ and n_name = 'CHINA'\n\
|
||||
\ )\n\
|
||||
\ order by\n\
|
||||
\ value desc")
|
||||
,("Q12","\n\
|
||||
\ select\n\
|
||||
\ l_shipmode,\n\
|
||||
\ sum(case\n\
|
||||
\ when o_orderpriority = '1-URGENT'\n\
|
||||
\ or o_orderpriority = '2-HIGH'\n\
|
||||
\ then 1\n\
|
||||
\ else 0\n\
|
||||
\ end) as high_line_count,\n\
|
||||
\ sum(case\n\
|
||||
\ when o_orderpriority <> '1-URGENT'\n\
|
||||
\ and o_orderpriority <> '2-HIGH'\n\
|
||||
\ then 1\n\
|
||||
\ else 0\n\
|
||||
\ end) as low_line_count\n\
|
||||
\ from\n\
|
||||
\ orders,\n\
|
||||
\ lineitem\n\
|
||||
\ where\n\
|
||||
\ o_orderkey = l_orderkey\n\
|
||||
\ and l_shipmode in ('AIR', 'RAIL')\n\
|
||||
\ and l_commitdate < l_receiptdate\n\
|
||||
\ and l_shipdate < l_commitdate\n\
|
||||
\ and l_receiptdate >= date '1994-01-01'\n\
|
||||
\ and l_receiptdate < date '1994-01-01' + interval '1' year\n\
|
||||
\ group by\n\
|
||||
\ l_shipmode\n\
|
||||
\ order by\n\
|
||||
\ l_shipmode")
|
||||
,("Q13","\n\
|
||||
\ select\n\
|
||||
\ c_count,\n\
|
||||
\ count(*) as custdist\n\
|
||||
\ from\n\
|
||||
\ (\n\
|
||||
\ select\n\
|
||||
\ c_custkey,\n\
|
||||
\ count(o_orderkey)\n\
|
||||
\ from\n\
|
||||
\ customer left outer join orders on\n\
|
||||
\ c_custkey = o_custkey\n\
|
||||
\ and o_comment not like '%pending%requests%'\n\
|
||||
\ group by\n\
|
||||
\ c_custkey\n\
|
||||
\ ) as c_orders (c_custkey, c_count)\n\
|
||||
\ group by\n\
|
||||
\ c_count\n\
|
||||
\ order by\n\
|
||||
\ custdist desc,\n\
|
||||
\ c_count desc")
|
||||
,("Q14","\n\
|
||||
\ select\n\
|
||||
\ 100.00 * sum(case\n\
|
||||
\ when p_type like 'PROMO%'\n\
|
||||
\ then l_extendedprice * (1 - l_discount)\n\
|
||||
\ else 0\n\
|
||||
\ end) / sum(l_extendedprice * (1 - l_discount)) as promo_revenue\n\
|
||||
\ from\n\
|
||||
\ lineitem,\n\
|
||||
\ part\n\
|
||||
\ where\n\
|
||||
\ l_partkey = p_partkey\n\
|
||||
\ and l_shipdate >= date '1994-12-01'\n\
|
||||
\ and l_shipdate < date '1994-12-01' + interval '1' month")
|
||||
,("Q15","\n\
|
||||
\ /*create view revenue0 (supplier_no, total_revenue) as\n\
|
||||
\ select\n\
|
||||
\ l_suppkey,\n\
|
||||
\ sum(l_extendedprice * (1 - l_discount))\n\
|
||||
\ from\n\
|
||||
\ lineitem\n\
|
||||
\ where\n\
|
||||
\ l_shipdate >= date '1995-06-01'\n\
|
||||
\ and l_shipdate < date '1995-06-01' + interval '3' month\n\
|
||||
\ group by\n\
|
||||
\ l_suppkey;*/\n\
|
||||
\ with\n\
|
||||
\ revenue0 as\n\
|
||||
\ (select\n\
|
||||
\ l_suppkey as supplier_no,\n\
|
||||
\ sum(l_extendedprice * (1 - l_discount)) as total_revenue\n\
|
||||
\ from\n\
|
||||
\ lineitem\n\
|
||||
\ where\n\
|
||||
\ l_shipdate >= date '1995-06-01'\n\
|
||||
\ and l_shipdate < date '1995-06-01' + interval '3' month\n\
|
||||
\ group by\n\
|
||||
\ l_suppkey)\n\
|
||||
\ select\n\
|
||||
\ s_suppkey,\n\
|
||||
\ s_name,\n\
|
||||
\ s_address,\n\
|
||||
\ s_phone,\n\
|
||||
\ total_revenue\n\
|
||||
\ from\n\
|
||||
\ supplier,\n\
|
||||
\ revenue0\n\
|
||||
\ where\n\
|
||||
\ s_suppkey = supplier_no\n\
|
||||
\ and total_revenue = (\n\
|
||||
\ select\n\
|
||||
\ max(total_revenue)\n\
|
||||
\ from\n\
|
||||
\ revenue0\n\
|
||||
\ )\n\
|
||||
\ order by\n\
|
||||
\ s_suppkey")
|
||||
,("Q16","\n\
|
||||
\ select\n\
|
||||
\ p_brand,\n\
|
||||
\ p_type,\n\
|
||||
\ p_size,\n\
|
||||
\ count(distinct ps_suppkey) as supplier_cnt\n\
|
||||
\ from\n\
|
||||
\ partsupp,\n\
|
||||
\ part\n\
|
||||
\ where\n\
|
||||
\ p_partkey = ps_partkey\n\
|
||||
\ and p_brand <> 'Brand#15'\n\
|
||||
\ and p_type not like 'MEDIUM BURNISHED%'\n\
|
||||
\ and p_size in (39, 26, 18, 45, 19, 1, 3, 9)\n\
|
||||
\ and ps_suppkey not in (\n\
|
||||
\ select\n\
|
||||
\ s_suppkey\n\
|
||||
\ from\n\
|
||||
\ supplier\n\
|
||||
\ where\n\
|
||||
\ s_comment like '%Customer%Complaints%'\n\
|
||||
\ )\n\
|
||||
\ group by\n\
|
||||
\ p_brand,\n\
|
||||
\ p_type,\n\
|
||||
\ p_size\n\
|
||||
\ order by\n\
|
||||
\ supplier_cnt desc,\n\
|
||||
\ p_brand,\n\
|
||||
\ p_type,\n\
|
||||
\ p_size")
|
||||
,("Q17","\n\
|
||||
\ select\n\
|
||||
\ sum(l_extendedprice) / 7.0 as avg_yearly\n\
|
||||
\ from\n\
|
||||
\ lineitem,\n\
|
||||
\ part\n\
|
||||
\ where\n\
|
||||
\ p_partkey = l_partkey\n\
|
||||
\ and p_brand = 'Brand#52'\n\
|
||||
\ and p_container = 'JUMBO CAN'\n\
|
||||
\ and l_quantity < (\n\
|
||||
\ select\n\
|
||||
\ 0.2 * avg(l_quantity)\n\
|
||||
\ from\n\
|
||||
\ lineitem\n\
|
||||
\ where\n\
|
||||
\ l_partkey = p_partkey\n\
|
||||
\ )")
|
||||
,("Q18","\n\
|
||||
\ select\n\
|
||||
\ c_name,\n\
|
||||
\ c_custkey,\n\
|
||||
\ o_orderkey,\n\
|
||||
\ o_orderdate,\n\
|
||||
\ o_totalprice,\n\
|
||||
\ sum(l_quantity)\n\
|
||||
\ from\n\
|
||||
\ customer,\n\
|
||||
\ orders,\n\
|
||||
\ lineitem\n\
|
||||
\ where\n\
|
||||
\ o_orderkey in (\n\
|
||||
\ select\n\
|
||||
\ l_orderkey\n\
|
||||
\ from\n\
|
||||
\ lineitem\n\
|
||||
\ group by\n\
|
||||
\ l_orderkey having\n\
|
||||
\ sum(l_quantity) > 313\n\
|
||||
\ )\n\
|
||||
\ and c_custkey = o_custkey\n\
|
||||
\ and o_orderkey = l_orderkey\n\
|
||||
\ group by\n\
|
||||
\ c_name,\n\
|
||||
\ c_custkey,\n\
|
||||
\ o_orderkey,\n\
|
||||
\ o_orderdate,\n\
|
||||
\ o_totalprice\n\
|
||||
\ order by\n\
|
||||
\ o_totalprice desc,\n\
|
||||
\ o_orderdate\n\
|
||||
\ fetch first 100 rows only")
|
||||
,("Q19","\n\
|
||||
\ select\n\
|
||||
\ sum(l_extendedprice* (1 - l_discount)) as revenue\n\
|
||||
\ from\n\
|
||||
\ lineitem,\n\
|
||||
\ part\n\
|
||||
\ where\n\
|
||||
\ (\n\
|
||||
\ p_partkey = l_partkey\n\
|
||||
\ and p_brand = 'Brand#43'\n\
|
||||
\ and p_container in ('SM CASE', 'SM BOX', 'SM PACK', 'SM PKG')\n\
|
||||
\ and l_quantity >= 3 and l_quantity <= 3 + 10\n\
|
||||
\ and p_size between 1 and 5\n\
|
||||
\ and l_shipmode in ('AIR', 'AIR REG')\n\
|
||||
\ and l_shipinstruct = 'DELIVER IN PERSON'\n\
|
||||
\ )\n\
|
||||
\ or\n\
|
||||
\ (\n\
|
||||
\ p_partkey = l_partkey\n\
|
||||
\ and p_brand = 'Brand#25'\n\
|
||||
\ and p_container in ('MED BAG', 'MED BOX', 'MED PKG', 'MED PACK')\n\
|
||||
\ and l_quantity >= 10 and l_quantity <= 10 + 10\n\
|
||||
\ and p_size between 1 and 10\n\
|
||||
\ and l_shipmode in ('AIR', 'AIR REG')\n\
|
||||
\ and l_shipinstruct = 'DELIVER IN PERSON'\n\
|
||||
\ )\n\
|
||||
\ or\n\
|
||||
\ (\n\
|
||||
\ p_partkey = l_partkey\n\
|
||||
\ and p_brand = 'Brand#24'\n\
|
||||
\ and p_container in ('LG CASE', 'LG BOX', 'LG PACK', 'LG PKG')\n\
|
||||
\ and l_quantity >= 22 and l_quantity <= 22 + 10\n\
|
||||
\ and p_size between 1 and 15\n\
|
||||
\ and l_shipmode in ('AIR', 'AIR REG')\n\
|
||||
\ and l_shipinstruct = 'DELIVER IN PERSON'\n\
|
||||
\ )")
|
||||
,("Q20","\n\
|
||||
\ select\n\
|
||||
\ s_name,\n\
|
||||
\ s_address\n\
|
||||
\ from\n\
|
||||
\ supplier,\n\
|
||||
\ nation\n\
|
||||
\ where\n\
|
||||
\ s_suppkey in (\n\
|
||||
\ select\n\
|
||||
\ ps_suppkey\n\
|
||||
\ from\n\
|
||||
\ partsupp\n\
|
||||
\ where\n\
|
||||
\ ps_partkey in (\n\
|
||||
\ select\n\
|
||||
\ p_partkey\n\
|
||||
\ from\n\
|
||||
\ part\n\
|
||||
\ where\n\
|
||||
\ p_name like 'lime%'\n\
|
||||
\ )\n\
|
||||
\ and ps_availqty > (\n\
|
||||
\ select\n\
|
||||
\ 0.5 * sum(l_quantity)\n\
|
||||
\ from\n\
|
||||
\ lineitem\n\
|
||||
\ where\n\
|
||||
\ l_partkey = ps_partkey\n\
|
||||
\ and l_suppkey = ps_suppkey\n\
|
||||
\ and l_shipdate >= date '1994-01-01'\n\
|
||||
\ and l_shipdate < date '1994-01-01' + interval '1' year\n\
|
||||
\ )\n\
|
||||
\ )\n\
|
||||
\ and s_nationkey = n_nationkey\n\
|
||||
\ and n_name = 'VIETNAM'\n\
|
||||
\ order by\n\
|
||||
\ s_name")
|
||||
,("Q21","\n\
|
||||
\ select\n\
|
||||
\ s_name,\n\
|
||||
\ count(*) as numwait\n\
|
||||
\ from\n\
|
||||
\ supplier,\n\
|
||||
\ lineitem l1,\n\
|
||||
\ orders,\n\
|
||||
\ nation\n\
|
||||
\ where\n\
|
||||
\ s_suppkey = l1.l_suppkey\n\
|
||||
\ and o_orderkey = l1.l_orderkey\n\
|
||||
\ and o_orderstatus = 'F'\n\
|
||||
\ and l1.l_receiptdate > l1.l_commitdate\n\
|
||||
\ and exists (\n\
|
||||
\ select\n\
|
||||
\ *\n\
|
||||
\ from\n\
|
||||
\ lineitem l2\n\
|
||||
\ where\n\
|
||||
\ l2.l_orderkey = l1.l_orderkey\n\
|
||||
\ and l2.l_suppkey <> l1.l_suppkey\n\
|
||||
\ )\n\
|
||||
\ and not exists (\n\
|
||||
\ select\n\
|
||||
\ *\n\
|
||||
\ from\n\
|
||||
\ lineitem l3\n\
|
||||
\ where\n\
|
||||
\ l3.l_orderkey = l1.l_orderkey\n\
|
||||
\ and l3.l_suppkey <> l1.l_suppkey\n\
|
||||
\ and l3.l_receiptdate > l3.l_commitdate\n\
|
||||
\ )\n\
|
||||
\ and s_nationkey = n_nationkey\n\
|
||||
\ and n_name = 'INDIA'\n\
|
||||
\ group by\n\
|
||||
\ s_name\n\
|
||||
\ order by\n\
|
||||
\ numwait desc,\n\
|
||||
\ s_name\n\
|
||||
\ fetch first 100 rows only")
|
||||
,("Q22","\n\
|
||||
\ select\n\
|
||||
\ cntrycode,\n\
|
||||
\ count(*) as numcust,\n\
|
||||
\ sum(c_acctbal) as totacctbal\n\
|
||||
\ from\n\
|
||||
\ (\n\
|
||||
\ select\n\
|
||||
\ substring(c_phone from 1 for 2) as cntrycode,\n\
|
||||
\ c_acctbal\n\
|
||||
\ from\n\
|
||||
\ customer\n\
|
||||
\ where\n\
|
||||
\ substring(c_phone from 1 for 2) in\n\
|
||||
\ ('41', '28', '39', '21', '24', '29', '44')\n\
|
||||
\ and c_acctbal > (\n\
|
||||
\ select\n\
|
||||
\ avg(c_acctbal)\n\
|
||||
\ from\n\
|
||||
\ customer\n\
|
||||
\ where\n\
|
||||
\ c_acctbal > 0.00\n\
|
||||
\ and substring(c_phone from 1 for 2) in\n\
|
||||
\ ('41', '28', '39', '21', '24', '29', '44')\n\
|
||||
\ )\n\
|
||||
\ and not exists (\n\
|
||||
\ select\n\
|
||||
\ *\n\
|
||||
\ from\n\
|
||||
\ orders\n\
|
||||
\ where\n\
|
||||
\ o_custkey = c_custkey\n\
|
||||
\ )\n\
|
||||
\ ) as custsale\n\
|
||||
\ group by\n\
|
||||
\ cntrycode\n\
|
||||
\ order by\n\
|
||||
\ cntrycode")
|
||||
]
|
|
@ -1,683 +0,0 @@
|
|||
|
||||
Some tests for parsing the tpch queries
|
||||
|
||||
The changes made to the official syntax are:
|
||||
1. replace the set rowcount with ansi standard fetch first n rows only
|
||||
2. replace the create view, query, drop view sequence with a query
|
||||
using a common table expression
|
||||
|
||||
> module Language.SQL.SimpleSQL.Tpch (tpchTests,tpchQueries) where
|
||||
|
||||
> import Language.SQL.SimpleSQL.TestTypes
|
||||
|
||||
> tpchTests :: TestItem
|
||||
> tpchTests =
|
||||
> Group "parse tpch"
|
||||
> $ map (ParseQueryExpr ansi2011 . snd) tpchQueries
|
||||
|
||||
> tpchQueries :: [(String,String)]
|
||||
> tpchQueries =
|
||||
> [("Q1","\n\
|
||||
> \select\n\
|
||||
> \ l_returnflag,\n\
|
||||
> \ l_linestatus,\n\
|
||||
> \ sum(l_quantity) as sum_qty,\n\
|
||||
> \ sum(l_extendedprice) as sum_base_price,\n\
|
||||
> \ sum(l_extendedprice * (1 - l_discount)) as sum_disc_price,\n\
|
||||
> \ sum(l_extendedprice * (1 - l_discount) * (1 + l_tax)) as sum_charge,\n\
|
||||
> \ avg(l_quantity) as avg_qty,\n\
|
||||
> \ avg(l_extendedprice) as avg_price,\n\
|
||||
> \ avg(l_discount) as avg_disc,\n\
|
||||
> \ count(*) as count_order\n\
|
||||
> \from\n\
|
||||
> \ lineitem\n\
|
||||
> \where\n\
|
||||
> \ l_shipdate <= date '1998-12-01' - interval '63' day (3)\n\
|
||||
> \group by\n\
|
||||
> \ l_returnflag,\n\
|
||||
> \ l_linestatus\n\
|
||||
> \order by\n\
|
||||
> \ l_returnflag,\n\
|
||||
> \ l_linestatus")
|
||||
> ,("Q2","\n\
|
||||
> \select\n\
|
||||
> \ s_acctbal,\n\
|
||||
> \ s_name,\n\
|
||||
> \ n_name,\n\
|
||||
> \ p_partkey,\n\
|
||||
> \ p_mfgr,\n\
|
||||
> \ s_address,\n\
|
||||
> \ s_phone,\n\
|
||||
> \ s_comment\n\
|
||||
> \from\n\
|
||||
> \ part,\n\
|
||||
> \ supplier,\n\
|
||||
> \ partsupp,\n\
|
||||
> \ nation,\n\
|
||||
> \ region\n\
|
||||
> \where\n\
|
||||
> \ p_partkey = ps_partkey\n\
|
||||
> \ and s_suppkey = ps_suppkey\n\
|
||||
> \ and p_size = 15\n\
|
||||
> \ and p_type like '%BRASS'\n\
|
||||
> \ and s_nationkey = n_nationkey\n\
|
||||
> \ and n_regionkey = r_regionkey\n\
|
||||
> \ and r_name = 'EUROPE'\n\
|
||||
> \ and ps_supplycost = (\n\
|
||||
> \ select\n\
|
||||
> \ min(ps_supplycost)\n\
|
||||
> \ from\n\
|
||||
> \ partsupp,\n\
|
||||
> \ supplier,\n\
|
||||
> \ nation,\n\
|
||||
> \ region\n\
|
||||
> \ where\n\
|
||||
> \ p_partkey = ps_partkey\n\
|
||||
> \ and s_suppkey = ps_suppkey\n\
|
||||
> \ and s_nationkey = n_nationkey\n\
|
||||
> \ and n_regionkey = r_regionkey\n\
|
||||
> \ and r_name = 'EUROPE'\n\
|
||||
> \ )\n\
|
||||
> \order by\n\
|
||||
> \ s_acctbal desc,\n\
|
||||
> \ n_name,\n\
|
||||
> \ s_name,\n\
|
||||
> \ p_partkey\n\
|
||||
> \fetch first 100 rows only")
|
||||
> ,("Q3","\n\
|
||||
> \ select\n\
|
||||
> \ l_orderkey,\n\
|
||||
> \ sum(l_extendedprice * (1 - l_discount)) as revenue,\n\
|
||||
> \ o_orderdate,\n\
|
||||
> \ o_shippriority\n\
|
||||
> \ from\n\
|
||||
> \ customer,\n\
|
||||
> \ orders,\n\
|
||||
> \ lineitem\n\
|
||||
> \ where\n\
|
||||
> \ c_mktsegment = 'MACHINERY'\n\
|
||||
> \ and c_custkey = o_custkey\n\
|
||||
> \ and l_orderkey = o_orderkey\n\
|
||||
> \ and o_orderdate < date '1995-03-21'\n\
|
||||
> \ and l_shipdate > date '1995-03-21'\n\
|
||||
> \ group by\n\
|
||||
> \ l_orderkey,\n\
|
||||
> \ o_orderdate,\n\
|
||||
> \ o_shippriority\n\
|
||||
> \ order by\n\
|
||||
> \ revenue desc,\n\
|
||||
> \ o_orderdate\n\
|
||||
> \ fetch first 10 rows only")
|
||||
> ,("Q4","\n\
|
||||
> \ select\n\
|
||||
> \ o_orderpriority,\n\
|
||||
> \ count(*) as order_count\n\
|
||||
> \ from\n\
|
||||
> \ orders\n\
|
||||
> \ where\n\
|
||||
> \ o_orderdate >= date '1996-03-01'\n\
|
||||
> \ and o_orderdate < date '1996-03-01' + interval '3' month\n\
|
||||
> \ and exists (\n\
|
||||
> \ select\n\
|
||||
> \ *\n\
|
||||
> \ from\n\
|
||||
> \ lineitem\n\
|
||||
> \ where\n\
|
||||
> \ l_orderkey = o_orderkey\n\
|
||||
> \ and l_commitdate < l_receiptdate\n\
|
||||
> \ )\n\
|
||||
> \ group by\n\
|
||||
> \ o_orderpriority\n\
|
||||
> \ order by\n\
|
||||
> \ o_orderpriority")
|
||||
> ,("Q5","\n\
|
||||
> \ select\n\
|
||||
> \ n_name,\n\
|
||||
> \ sum(l_extendedprice * (1 - l_discount)) as revenue\n\
|
||||
> \ from\n\
|
||||
> \ customer,\n\
|
||||
> \ orders,\n\
|
||||
> \ lineitem,\n\
|
||||
> \ supplier,\n\
|
||||
> \ nation,\n\
|
||||
> \ region\n\
|
||||
> \ where\n\
|
||||
> \ c_custkey = o_custkey\n\
|
||||
> \ and l_orderkey = o_orderkey\n\
|
||||
> \ and l_suppkey = s_suppkey\n\
|
||||
> \ and c_nationkey = s_nationkey\n\
|
||||
> \ and s_nationkey = n_nationkey\n\
|
||||
> \ and n_regionkey = r_regionkey\n\
|
||||
> \ and r_name = 'EUROPE'\n\
|
||||
> \ and o_orderdate >= date '1997-01-01'\n\
|
||||
> \ and o_orderdate < date '1997-01-01' + interval '1' year\n\
|
||||
> \ group by\n\
|
||||
> \ n_name\n\
|
||||
> \ order by\n\
|
||||
> \ revenue desc")
|
||||
> ,("Q6","\n\
|
||||
> \ select\n\
|
||||
> \ sum(l_extendedprice * l_discount) as revenue\n\
|
||||
> \ from\n\
|
||||
> \ lineitem\n\
|
||||
> \ where\n\
|
||||
> \ l_shipdate >= date '1997-01-01'\n\
|
||||
> \ and l_shipdate < date '1997-01-01' + interval '1' year\n\
|
||||
> \ and l_discount between 0.07 - 0.01 and 0.07 + 0.01\n\
|
||||
> \ and l_quantity < 24")
|
||||
> ,("Q7","\n\
|
||||
> \ select\n\
|
||||
> \ supp_nation,\n\
|
||||
> \ cust_nation,\n\
|
||||
> \ l_year,\n\
|
||||
> \ sum(volume) as revenue\n\
|
||||
> \ from\n\
|
||||
> \ (\n\
|
||||
> \ select\n\
|
||||
> \ n1.n_name as supp_nation,\n\
|
||||
> \ n2.n_name as cust_nation,\n\
|
||||
> \ extract(year from l_shipdate) as l_year,\n\
|
||||
> \ l_extendedprice * (1 - l_discount) as volume\n\
|
||||
> \ from\n\
|
||||
> \ supplier,\n\
|
||||
> \ lineitem,\n\
|
||||
> \ orders,\n\
|
||||
> \ customer,\n\
|
||||
> \ nation n1,\n\
|
||||
> \ nation n2\n\
|
||||
> \ where\n\
|
||||
> \ s_suppkey = l_suppkey\n\
|
||||
> \ and o_orderkey = l_orderkey\n\
|
||||
> \ and c_custkey = o_custkey\n\
|
||||
> \ and s_nationkey = n1.n_nationkey\n\
|
||||
> \ and c_nationkey = n2.n_nationkey\n\
|
||||
> \ and (\n\
|
||||
> \ (n1.n_name = 'PERU' and n2.n_name = 'IRAQ')\n\
|
||||
> \ or (n1.n_name = 'IRAQ' and n2.n_name = 'PERU')\n\
|
||||
> \ )\n\
|
||||
> \ and l_shipdate between date '1995-01-01' and date '1996-12-31'\n\
|
||||
> \ ) as shipping\n\
|
||||
> \ group by\n\
|
||||
> \ supp_nation,\n\
|
||||
> \ cust_nation,\n\
|
||||
> \ l_year\n\
|
||||
> \ order by\n\
|
||||
> \ supp_nation,\n\
|
||||
> \ cust_nation,\n\
|
||||
> \ l_year")
|
||||
> ,("Q8","\n\
|
||||
> \ select\n\
|
||||
> \ o_year,\n\
|
||||
> \ sum(case\n\
|
||||
> \ when nation = 'IRAQ' then volume\n\
|
||||
> \ else 0\n\
|
||||
> \ end) / sum(volume) as mkt_share\n\
|
||||
> \ from\n\
|
||||
> \ (\n\
|
||||
> \ select\n\
|
||||
> \ extract(year from o_orderdate) as o_year,\n\
|
||||
> \ l_extendedprice * (1 - l_discount) as volume,\n\
|
||||
> \ n2.n_name as nation\n\
|
||||
> \ from\n\
|
||||
> \ part,\n\
|
||||
> \ supplier,\n\
|
||||
> \ lineitem,\n\
|
||||
> \ orders,\n\
|
||||
> \ customer,\n\
|
||||
> \ nation n1,\n\
|
||||
> \ nation n2,\n\
|
||||
> \ region\n\
|
||||
> \ where\n\
|
||||
> \ p_partkey = l_partkey\n\
|
||||
> \ and s_suppkey = l_suppkey\n\
|
||||
> \ and l_orderkey = o_orderkey\n\
|
||||
> \ and o_custkey = c_custkey\n\
|
||||
> \ and c_nationkey = n1.n_nationkey\n\
|
||||
> \ and n1.n_regionkey = r_regionkey\n\
|
||||
> \ and r_name = 'MIDDLE EAST'\n\
|
||||
> \ and s_nationkey = n2.n_nationkey\n\
|
||||
> \ and o_orderdate between date '1995-01-01' and date '1996-12-31'\n\
|
||||
> \ and p_type = 'STANDARD ANODIZED BRASS'\n\
|
||||
> \ ) as all_nations\n\
|
||||
> \ group by\n\
|
||||
> \ o_year\n\
|
||||
> \ order by\n\
|
||||
> \ o_year")
|
||||
> ,("Q9","\n\
|
||||
> \ select\n\
|
||||
> \ nation,\n\
|
||||
> \ o_year,\n\
|
||||
> \ sum(amount) as sum_profit\n\
|
||||
> \ from\n\
|
||||
> \ (\n\
|
||||
> \ select\n\
|
||||
> \ n_name as nation,\n\
|
||||
> \ extract(year from o_orderdate) as o_year,\n\
|
||||
> \ l_extendedprice * (1 - l_discount) - ps_supplycost * l_quantity as amount\n\
|
||||
> \ from\n\
|
||||
> \ part,\n\
|
||||
> \ supplier,\n\
|
||||
> \ lineitem,\n\
|
||||
> \ partsupp,\n\
|
||||
> \ orders,\n\
|
||||
> \ nation\n\
|
||||
> \ where\n\
|
||||
> \ s_suppkey = l_suppkey\n\
|
||||
> \ and ps_suppkey = l_suppkey\n\
|
||||
> \ and ps_partkey = l_partkey\n\
|
||||
> \ and p_partkey = l_partkey\n\
|
||||
> \ and o_orderkey = l_orderkey\n\
|
||||
> \ and s_nationkey = n_nationkey\n\
|
||||
> \ and p_name like '%antique%'\n\
|
||||
> \ ) as profit\n\
|
||||
> \ group by\n\
|
||||
> \ nation,\n\
|
||||
> \ o_year\n\
|
||||
> \ order by\n\
|
||||
> \ nation,\n\
|
||||
> \ o_year desc")
|
||||
> ,("Q10","\n\
|
||||
> \ select\n\
|
||||
> \ c_custkey,\n\
|
||||
> \ c_name,\n\
|
||||
> \ sum(l_extendedprice * (1 - l_discount)) as revenue,\n\
|
||||
> \ c_acctbal,\n\
|
||||
> \ n_name,\n\
|
||||
> \ c_address,\n\
|
||||
> \ c_phone,\n\
|
||||
> \ c_comment\n\
|
||||
> \ from\n\
|
||||
> \ customer,\n\
|
||||
> \ orders,\n\
|
||||
> \ lineitem,\n\
|
||||
> \ nation\n\
|
||||
> \ where\n\
|
||||
> \ c_custkey = o_custkey\n\
|
||||
> \ and l_orderkey = o_orderkey\n\
|
||||
> \ and o_orderdate >= date '1993-12-01'\n\
|
||||
> \ and o_orderdate < date '1993-12-01' + interval '3' month\n\
|
||||
> \ and l_returnflag = 'R'\n\
|
||||
> \ and c_nationkey = n_nationkey\n\
|
||||
> \ group by\n\
|
||||
> \ c_custkey,\n\
|
||||
> \ c_name,\n\
|
||||
> \ c_acctbal,\n\
|
||||
> \ c_phone,\n\
|
||||
> \ n_name,\n\
|
||||
> \ c_address,\n\
|
||||
> \ c_comment\n\
|
||||
> \ order by\n\
|
||||
> \ revenue desc\n\
|
||||
> \ fetch first 20 rows only")
|
||||
> ,("Q11","\n\
|
||||
> \ select\n\
|
||||
> \ ps_partkey,\n\
|
||||
> \ sum(ps_supplycost * ps_availqty) as value\n\
|
||||
> \ from\n\
|
||||
> \ partsupp,\n\
|
||||
> \ supplier,\n\
|
||||
> \ nation\n\
|
||||
> \ where\n\
|
||||
> \ ps_suppkey = s_suppkey\n\
|
||||
> \ and s_nationkey = n_nationkey\n\
|
||||
> \ and n_name = 'CHINA'\n\
|
||||
> \ group by\n\
|
||||
> \ ps_partkey having\n\
|
||||
> \ sum(ps_supplycost * ps_availqty) > (\n\
|
||||
> \ select\n\
|
||||
> \ sum(ps_supplycost * ps_availqty) * 0.0001000000\n\
|
||||
> \ from\n\
|
||||
> \ partsupp,\n\
|
||||
> \ supplier,\n\
|
||||
> \ nation\n\
|
||||
> \ where\n\
|
||||
> \ ps_suppkey = s_suppkey\n\
|
||||
> \ and s_nationkey = n_nationkey\n\
|
||||
> \ and n_name = 'CHINA'\n\
|
||||
> \ )\n\
|
||||
> \ order by\n\
|
||||
> \ value desc")
|
||||
> ,("Q12","\n\
|
||||
> \ select\n\
|
||||
> \ l_shipmode,\n\
|
||||
> \ sum(case\n\
|
||||
> \ when o_orderpriority = '1-URGENT'\n\
|
||||
> \ or o_orderpriority = '2-HIGH'\n\
|
||||
> \ then 1\n\
|
||||
> \ else 0\n\
|
||||
> \ end) as high_line_count,\n\
|
||||
> \ sum(case\n\
|
||||
> \ when o_orderpriority <> '1-URGENT'\n\
|
||||
> \ and o_orderpriority <> '2-HIGH'\n\
|
||||
> \ then 1\n\
|
||||
> \ else 0\n\
|
||||
> \ end) as low_line_count\n\
|
||||
> \ from\n\
|
||||
> \ orders,\n\
|
||||
> \ lineitem\n\
|
||||
> \ where\n\
|
||||
> \ o_orderkey = l_orderkey\n\
|
||||
> \ and l_shipmode in ('AIR', 'RAIL')\n\
|
||||
> \ and l_commitdate < l_receiptdate\n\
|
||||
> \ and l_shipdate < l_commitdate\n\
|
||||
> \ and l_receiptdate >= date '1994-01-01'\n\
|
||||
> \ and l_receiptdate < date '1994-01-01' + interval '1' year\n\
|
||||
> \ group by\n\
|
||||
> \ l_shipmode\n\
|
||||
> \ order by\n\
|
||||
> \ l_shipmode")
|
||||
> ,("Q13","\n\
|
||||
> \ select\n\
|
||||
> \ c_count,\n\
|
||||
> \ count(*) as custdist\n\
|
||||
> \ from\n\
|
||||
> \ (\n\
|
||||
> \ select\n\
|
||||
> \ c_custkey,\n\
|
||||
> \ count(o_orderkey)\n\
|
||||
> \ from\n\
|
||||
> \ customer left outer join orders on\n\
|
||||
> \ c_custkey = o_custkey\n\
|
||||
> \ and o_comment not like '%pending%requests%'\n\
|
||||
> \ group by\n\
|
||||
> \ c_custkey\n\
|
||||
> \ ) as c_orders (c_custkey, c_count)\n\
|
||||
> \ group by\n\
|
||||
> \ c_count\n\
|
||||
> \ order by\n\
|
||||
> \ custdist desc,\n\
|
||||
> \ c_count desc")
|
||||
> ,("Q14","\n\
|
||||
> \ select\n\
|
||||
> \ 100.00 * sum(case\n\
|
||||
> \ when p_type like 'PROMO%'\n\
|
||||
> \ then l_extendedprice * (1 - l_discount)\n\
|
||||
> \ else 0\n\
|
||||
> \ end) / sum(l_extendedprice * (1 - l_discount)) as promo_revenue\n\
|
||||
> \ from\n\
|
||||
> \ lineitem,\n\
|
||||
> \ part\n\
|
||||
> \ where\n\
|
||||
> \ l_partkey = p_partkey\n\
|
||||
> \ and l_shipdate >= date '1994-12-01'\n\
|
||||
> \ and l_shipdate < date '1994-12-01' + interval '1' month")
|
||||
> ,("Q15","\n\
|
||||
> \ /*create view revenue0 (supplier_no, total_revenue) as\n\
|
||||
> \ select\n\
|
||||
> \ l_suppkey,\n\
|
||||
> \ sum(l_extendedprice * (1 - l_discount))\n\
|
||||
> \ from\n\
|
||||
> \ lineitem\n\
|
||||
> \ where\n\
|
||||
> \ l_shipdate >= date '1995-06-01'\n\
|
||||
> \ and l_shipdate < date '1995-06-01' + interval '3' month\n\
|
||||
> \ group by\n\
|
||||
> \ l_suppkey;*/\n\
|
||||
> \ with\n\
|
||||
> \ revenue0 as\n\
|
||||
> \ (select\n\
|
||||
> \ l_suppkey as supplier_no,\n\
|
||||
> \ sum(l_extendedprice * (1 - l_discount)) as total_revenue\n\
|
||||
> \ from\n\
|
||||
> \ lineitem\n\
|
||||
> \ where\n\
|
||||
> \ l_shipdate >= date '1995-06-01'\n\
|
||||
> \ and l_shipdate < date '1995-06-01' + interval '3' month\n\
|
||||
> \ group by\n\
|
||||
> \ l_suppkey)\n\
|
||||
> \ select\n\
|
||||
> \ s_suppkey,\n\
|
||||
> \ s_name,\n\
|
||||
> \ s_address,\n\
|
||||
> \ s_phone,\n\
|
||||
> \ total_revenue\n\
|
||||
> \ from\n\
|
||||
> \ supplier,\n\
|
||||
> \ revenue0\n\
|
||||
> \ where\n\
|
||||
> \ s_suppkey = supplier_no\n\
|
||||
> \ and total_revenue = (\n\
|
||||
> \ select\n\
|
||||
> \ max(total_revenue)\n\
|
||||
> \ from\n\
|
||||
> \ revenue0\n\
|
||||
> \ )\n\
|
||||
> \ order by\n\
|
||||
> \ s_suppkey")
|
||||
> ,("Q16","\n\
|
||||
> \ select\n\
|
||||
> \ p_brand,\n\
|
||||
> \ p_type,\n\
|
||||
> \ p_size,\n\
|
||||
> \ count(distinct ps_suppkey) as supplier_cnt\n\
|
||||
> \ from\n\
|
||||
> \ partsupp,\n\
|
||||
> \ part\n\
|
||||
> \ where\n\
|
||||
> \ p_partkey = ps_partkey\n\
|
||||
> \ and p_brand <> 'Brand#15'\n\
|
||||
> \ and p_type not like 'MEDIUM BURNISHED%'\n\
|
||||
> \ and p_size in (39, 26, 18, 45, 19, 1, 3, 9)\n\
|
||||
> \ and ps_suppkey not in (\n\
|
||||
> \ select\n\
|
||||
> \ s_suppkey\n\
|
||||
> \ from\n\
|
||||
> \ supplier\n\
|
||||
> \ where\n\
|
||||
> \ s_comment like '%Customer%Complaints%'\n\
|
||||
> \ )\n\
|
||||
> \ group by\n\
|
||||
> \ p_brand,\n\
|
||||
> \ p_type,\n\
|
||||
> \ p_size\n\
|
||||
> \ order by\n\
|
||||
> \ supplier_cnt desc,\n\
|
||||
> \ p_brand,\n\
|
||||
> \ p_type,\n\
|
||||
> \ p_size")
|
||||
> ,("Q17","\n\
|
||||
> \ select\n\
|
||||
> \ sum(l_extendedprice) / 7.0 as avg_yearly\n\
|
||||
> \ from\n\
|
||||
> \ lineitem,\n\
|
||||
> \ part\n\
|
||||
> \ where\n\
|
||||
> \ p_partkey = l_partkey\n\
|
||||
> \ and p_brand = 'Brand#52'\n\
|
||||
> \ and p_container = 'JUMBO CAN'\n\
|
||||
> \ and l_quantity < (\n\
|
||||
> \ select\n\
|
||||
> \ 0.2 * avg(l_quantity)\n\
|
||||
> \ from\n\
|
||||
> \ lineitem\n\
|
||||
> \ where\n\
|
||||
> \ l_partkey = p_partkey\n\
|
||||
> \ )")
|
||||
> ,("Q18","\n\
|
||||
> \ select\n\
|
||||
> \ c_name,\n\
|
||||
> \ c_custkey,\n\
|
||||
> \ o_orderkey,\n\
|
||||
> \ o_orderdate,\n\
|
||||
> \ o_totalprice,\n\
|
||||
> \ sum(l_quantity)\n\
|
||||
> \ from\n\
|
||||
> \ customer,\n\
|
||||
> \ orders,\n\
|
||||
> \ lineitem\n\
|
||||
> \ where\n\
|
||||
> \ o_orderkey in (\n\
|
||||
> \ select\n\
|
||||
> \ l_orderkey\n\
|
||||
> \ from\n\
|
||||
> \ lineitem\n\
|
||||
> \ group by\n\
|
||||
> \ l_orderkey having\n\
|
||||
> \ sum(l_quantity) > 313\n\
|
||||
> \ )\n\
|
||||
> \ and c_custkey = o_custkey\n\
|
||||
> \ and o_orderkey = l_orderkey\n\
|
||||
> \ group by\n\
|
||||
> \ c_name,\n\
|
||||
> \ c_custkey,\n\
|
||||
> \ o_orderkey,\n\
|
||||
> \ o_orderdate,\n\
|
||||
> \ o_totalprice\n\
|
||||
> \ order by\n\
|
||||
> \ o_totalprice desc,\n\
|
||||
> \ o_orderdate\n\
|
||||
> \ fetch first 100 rows only")
|
||||
> ,("Q19","\n\
|
||||
> \ select\n\
|
||||
> \ sum(l_extendedprice* (1 - l_discount)) as revenue\n\
|
||||
> \ from\n\
|
||||
> \ lineitem,\n\
|
||||
> \ part\n\
|
||||
> \ where\n\
|
||||
> \ (\n\
|
||||
> \ p_partkey = l_partkey\n\
|
||||
> \ and p_brand = 'Brand#43'\n\
|
||||
> \ and p_container in ('SM CASE', 'SM BOX', 'SM PACK', 'SM PKG')\n\
|
||||
> \ and l_quantity >= 3 and l_quantity <= 3 + 10\n\
|
||||
> \ and p_size between 1 and 5\n\
|
||||
> \ and l_shipmode in ('AIR', 'AIR REG')\n\
|
||||
> \ and l_shipinstruct = 'DELIVER IN PERSON'\n\
|
||||
> \ )\n\
|
||||
> \ or\n\
|
||||
> \ (\n\
|
||||
> \ p_partkey = l_partkey\n\
|
||||
> \ and p_brand = 'Brand#25'\n\
|
||||
> \ and p_container in ('MED BAG', 'MED BOX', 'MED PKG', 'MED PACK')\n\
|
||||
> \ and l_quantity >= 10 and l_quantity <= 10 + 10\n\
|
||||
> \ and p_size between 1 and 10\n\
|
||||
> \ and l_shipmode in ('AIR', 'AIR REG')\n\
|
||||
> \ and l_shipinstruct = 'DELIVER IN PERSON'\n\
|
||||
> \ )\n\
|
||||
> \ or\n\
|
||||
> \ (\n\
|
||||
> \ p_partkey = l_partkey\n\
|
||||
> \ and p_brand = 'Brand#24'\n\
|
||||
> \ and p_container in ('LG CASE', 'LG BOX', 'LG PACK', 'LG PKG')\n\
|
||||
> \ and l_quantity >= 22 and l_quantity <= 22 + 10\n\
|
||||
> \ and p_size between 1 and 15\n\
|
||||
> \ and l_shipmode in ('AIR', 'AIR REG')\n\
|
||||
> \ and l_shipinstruct = 'DELIVER IN PERSON'\n\
|
||||
> \ )")
|
||||
> ,("Q20","\n\
|
||||
> \ select\n\
|
||||
> \ s_name,\n\
|
||||
> \ s_address\n\
|
||||
> \ from\n\
|
||||
> \ supplier,\n\
|
||||
> \ nation\n\
|
||||
> \ where\n\
|
||||
> \ s_suppkey in (\n\
|
||||
> \ select\n\
|
||||
> \ ps_suppkey\n\
|
||||
> \ from\n\
|
||||
> \ partsupp\n\
|
||||
> \ where\n\
|
||||
> \ ps_partkey in (\n\
|
||||
> \ select\n\
|
||||
> \ p_partkey\n\
|
||||
> \ from\n\
|
||||
> \ part\n\
|
||||
> \ where\n\
|
||||
> \ p_name like 'lime%'\n\
|
||||
> \ )\n\
|
||||
> \ and ps_availqty > (\n\
|
||||
> \ select\n\
|
||||
> \ 0.5 * sum(l_quantity)\n\
|
||||
> \ from\n\
|
||||
> \ lineitem\n\
|
||||
> \ where\n\
|
||||
> \ l_partkey = ps_partkey\n\
|
||||
> \ and l_suppkey = ps_suppkey\n\
|
||||
> \ and l_shipdate >= date '1994-01-01'\n\
|
||||
> \ and l_shipdate < date '1994-01-01' + interval '1' year\n\
|
||||
> \ )\n\
|
||||
> \ )\n\
|
||||
> \ and s_nationkey = n_nationkey\n\
|
||||
> \ and n_name = 'VIETNAM'\n\
|
||||
> \ order by\n\
|
||||
> \ s_name")
|
||||
> ,("Q21","\n\
|
||||
> \ select\n\
|
||||
> \ s_name,\n\
|
||||
> \ count(*) as numwait\n\
|
||||
> \ from\n\
|
||||
> \ supplier,\n\
|
||||
> \ lineitem l1,\n\
|
||||
> \ orders,\n\
|
||||
> \ nation\n\
|
||||
> \ where\n\
|
||||
> \ s_suppkey = l1.l_suppkey\n\
|
||||
> \ and o_orderkey = l1.l_orderkey\n\
|
||||
> \ and o_orderstatus = 'F'\n\
|
||||
> \ and l1.l_receiptdate > l1.l_commitdate\n\
|
||||
> \ and exists (\n\
|
||||
> \ select\n\
|
||||
> \ *\n\
|
||||
> \ from\n\
|
||||
> \ lineitem l2\n\
|
||||
> \ where\n\
|
||||
> \ l2.l_orderkey = l1.l_orderkey\n\
|
||||
> \ and l2.l_suppkey <> l1.l_suppkey\n\
|
||||
> \ )\n\
|
||||
> \ and not exists (\n\
|
||||
> \ select\n\
|
||||
> \ *\n\
|
||||
> \ from\n\
|
||||
> \ lineitem l3\n\
|
||||
> \ where\n\
|
||||
> \ l3.l_orderkey = l1.l_orderkey\n\
|
||||
> \ and l3.l_suppkey <> l1.l_suppkey\n\
|
||||
> \ and l3.l_receiptdate > l3.l_commitdate\n\
|
||||
> \ )\n\
|
||||
> \ and s_nationkey = n_nationkey\n\
|
||||
> \ and n_name = 'INDIA'\n\
|
||||
> \ group by\n\
|
||||
> \ s_name\n\
|
||||
> \ order by\n\
|
||||
> \ numwait desc,\n\
|
||||
> \ s_name\n\
|
||||
> \ fetch first 100 rows only")
|
||||
> ,("Q22","\n\
|
||||
> \ select\n\
|
||||
> \ cntrycode,\n\
|
||||
> \ count(*) as numcust,\n\
|
||||
> \ sum(c_acctbal) as totacctbal\n\
|
||||
> \ from\n\
|
||||
> \ (\n\
|
||||
> \ select\n\
|
||||
> \ substring(c_phone from 1 for 2) as cntrycode,\n\
|
||||
> \ c_acctbal\n\
|
||||
> \ from\n\
|
||||
> \ customer\n\
|
||||
> \ where\n\
|
||||
> \ substring(c_phone from 1 for 2) in\n\
|
||||
> \ ('41', '28', '39', '21', '24', '29', '44')\n\
|
||||
> \ and c_acctbal > (\n\
|
||||
> \ select\n\
|
||||
> \ avg(c_acctbal)\n\
|
||||
> \ from\n\
|
||||
> \ customer\n\
|
||||
> \ where\n\
|
||||
> \ c_acctbal > 0.00\n\
|
||||
> \ and substring(c_phone from 1 for 2) in\n\
|
||||
> \ ('41', '28', '39', '21', '24', '29', '44')\n\
|
||||
> \ )\n\
|
||||
> \ and not exists (\n\
|
||||
> \ select\n\
|
||||
> \ *\n\
|
||||
> \ from\n\
|
||||
> \ orders\n\
|
||||
> \ where\n\
|
||||
> \ o_custkey = c_custkey\n\
|
||||
> \ )\n\
|
||||
> \ ) as custsale\n\
|
||||
> \ group by\n\
|
||||
> \ cntrycode\n\
|
||||
> \ order by\n\
|
||||
> \ cntrycode")
|
||||
> ]
|
Loading…
Add table
Add a link
Reference in a new issue