diff --git a/Language/SQL/SimpleSQL/Parser.lhs b/Language/SQL/SimpleSQL/Parser.lhs index dd56105..5a82efb 100644 --- a/Language/SQL/SimpleSQL/Parser.lhs +++ b/Language/SQL/SimpleSQL/Parser.lhs @@ -12,6 +12,7 @@ > import Data.Char > import Text.Parsec hiding (ParseError) > import qualified Text.Parsec as P +> import Text.Parsec.Perm > import Language.SQL.SimpleSQL.Syntax > import Language.SQL.SimpleSQL.Fixity @@ -572,11 +573,26 @@ where, having, limit, offset). > <*> option Asc (choice [Asc <$ keyword_ "asc" > ,Desc <$ keyword_ "desc"]) -> limit :: P ScalarExpr -> limit = keywordScalarExpr "limit" +allows offset and fetch in either order ++ postgresql offset without row(s) and limit instead of fetch also + +> offsetFetch :: P (Maybe ScalarExpr, Maybe ScalarExpr) +> offsetFetch = permute ((,) <$?> (Nothing, Just <$> offset) +> <|?> (Nothing, Just <$> fetch)) > offset :: P ScalarExpr -> offset = keywordScalarExpr "offset" +> offset = try (keyword_ "offset") *> scalarExpr +> <* option () (try $ choice [try (keyword_ "rows"),keyword_ "row"]) + +> fetch :: P ScalarExpr +> fetch = choice [ansiFetch, limit] +> where +> ansiFetch = try (keyword_ "fetch") >> +> choice [keyword_ "first",keyword_ "next"] +> *> scalarExpr +> <* choice [keyword_ "rows",keyword_ "row"] +> <* keyword_ "only" +> limit = try (keyword_ "limit") *> scalarExpr == common table expressions @@ -601,7 +617,7 @@ and union, etc.. > >>= optionSuffix queryExprSuffix] > where > select = try (keyword_ "select") >> -> Select +> mkSelect > <$> (fromMaybe All <$> duplicates) > <*> selectList > <*> option [] from @@ -609,8 +625,9 @@ and union, etc.. > <*> option [] sgroupBy > <*> optionMaybe having > <*> option [] orderBy -> <*> optionMaybe limit -> <*> optionMaybe offset +> <*> offsetFetch +> mkSelect d sl f w g h od (ofs,fe) = +> Select d sl f w g h od ofs fe > values = try (keyword_ "values") > >> Values <$> commaSep (parens (commaSep scalarExpr)) > table = try (keyword_ "table") >> Table <$> name @@ -698,7 +715,7 @@ keyword parser also > blacklist :: [String] > blacklist = > ["select", "as", "from", "where", "having", "group", "order" -> ,"limit", "offset" +> ,"limit", "offset", "fetch" > ,"inner", "left", "right", "full", "natural", "join" > ,"cross", "on", "using", "lateral" > ,"when", "then", "case", "end", "in" diff --git a/Language/SQL/SimpleSQL/Pretty.lhs b/Language/SQL/SimpleSQL/Pretty.lhs index ebb7a7f..bc40e19 100644 --- a/Language/SQL/SimpleSQL/Pretty.lhs +++ b/Language/SQL/SimpleSQL/Pretty.lhs @@ -149,7 +149,7 @@ = query expressions > queryExpr :: QueryExpr -> Doc -> queryExpr (Select d sl fr wh gb hv od lm off) = +> queryExpr (Select d sl fr wh gb hv od off fe) = > sep [text "select" > ,case d of > All -> empty @@ -160,8 +160,9 @@ > ,grpBy gb > ,maybeScalarExpr "having" hv > ,orderBy od -> ,maybeScalarExpr "limit" lm -> ,maybeScalarExpr "offset" off +> ,maybe empty (\e -> text "offset" <+> scalarExpr e <+> text "rows") off +> ,maybe empty (\e -> text "fetch next" <+> scalarExpr e +> <+> text "rows only") fe > ] > queryExpr (CombineQueryExpr q1 ct d c q2) = > sep [queryExpr q1 diff --git a/Language/SQL/SimpleSQL/Syntax.lhs b/Language/SQL/SimpleSQL/Syntax.lhs index 1734346..862a16b 100644 --- a/Language/SQL/SimpleSQL/Syntax.lhs +++ b/Language/SQL/SimpleSQL/Syntax.lhs @@ -145,8 +145,8 @@ > ,qeGroupBy :: [ScalarExpr] > ,qeHaving :: Maybe ScalarExpr > ,qeOrderBy :: [(ScalarExpr,Direction)] -> ,qeLimit :: Maybe ScalarExpr > ,qeOffset :: Maybe ScalarExpr +> ,qeFetch :: Maybe ScalarExpr > } > | CombineQueryExpr > {qe0 :: QueryExpr @@ -177,8 +177,8 @@ I'm not sure if this is valid syntax or not. > ,qeGroupBy = [] > ,qeHaving = Nothing > ,qeOrderBy = [] -> ,qeLimit = Nothing -> ,qeOffset = Nothing} +> ,qeOffset = Nothing +> ,qeFetch = Nothing} > -- | represents the Distinct or All keywords, which can be used diff --git a/TODO b/TODO index b2ed8c7..1c114f2 100644 --- a/TODO +++ b/TODO @@ -1,33 +1,17 @@ next release: -ansi standard versions of limit and offset - -OFFSET start { ROW | ROWS } -FETCH { FIRST | NEXT } [ count ] { ROW | ROWS } ONLY --> + fix the abstract syntax to match this instead of postgres -(keep the postgres syntax version parser) -in the postgresql docs, the start and count must be in parens unless - they are a single integer - -select * from generate_series(0,99) offset 5 fetch next 5 row only; -select * from generate_series(0,99) offset 5; -select * from generate_series(0,99) fetch next 5 row only; - -+ sql server top syntax - -more dots: implement as dot operator more symbolic operators, array access a[5]? don't think this is standard sql, if not, leave for now. There is something about arrays in sql:2008 +row ctor: row(a,b) is fine, but also when there is 2 or more elements, + the word row can be omitted: (a,b) fix lateral binding issue -row ctor: row(a,b) is fine, but also when there is 2 or more elements, - the word row can be omitted: (a,b) window frames and named windows @@ -74,6 +58,8 @@ review abstract syntax (e.g. combine App with SpecialOp?) Later general tasks: +sql server top syntax + extended string literals, escapes and other flavours (like pg and oracle custom delimiters) diff --git a/tools/Language/SQL/SimpleSQL/QueryExprComponents.lhs b/tools/Language/SQL/SimpleSQL/QueryExprComponents.lhs index 452da03..a7f4dfe 100644 --- a/tools/Language/SQL/SimpleSQL/QueryExprComponents.lhs +++ b/tools/Language/SQL/SimpleSQL/QueryExprComponents.lhs @@ -126,18 +126,22 @@ These are a few misc tests which don't fit anywhere else. > limit :: TestItem > limit = Group "limit" $ map (uncurry TestQueryExpr) -> [("select a from t limit 10" -> ,ms (Just $ NumLit "10") Nothing) - -> ,("select a from t limit 10 offset 10" -> ,ms (Just $ NumLit "10") (Just $ NumLit "10")) +> [-- 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")) > ] > where -> ms l o = makeSelect +> ms o l = makeSelect > {qeSelectList = [(Nothing,Iden "a")] > ,qeFrom = [TRSimple "t"] -> ,qeLimit = l -> ,qeOffset = o} +> ,qeOffset = o +> ,qeFetch = l} > combos :: TestItem > combos = Group "combos" $ map (uncurry TestQueryExpr)