overhaul website
This commit is contained in:
parent
45669ed7d3
commit
681cbfc416
56
Makefile
56
Makefile
|
@ -3,6 +3,7 @@
|
|||
|
||||
# there is no real reason to actually use the makefile except for a
|
||||
# very small amount of convenience, apart from the website build
|
||||
# and website consistency checks
|
||||
|
||||
.PHONY : build
|
||||
build :
|
||||
|
@ -19,6 +20,7 @@ test-coverage :
|
|||
.PHONY : clean
|
||||
clean :
|
||||
cabal clean
|
||||
cd website && cabal clean
|
||||
rm -Rf build/
|
||||
|
||||
.PHONY : parserexe
|
||||
|
@ -26,7 +28,7 @@ parserexe :
|
|||
cabal build -fparserexe SimpleSQLParserTool
|
||||
|
||||
.PHONY : all
|
||||
all : build test parserexe
|
||||
all : build test parserexe website
|
||||
|
||||
###############################################
|
||||
|
||||
|
@ -39,39 +41,33 @@ all : build test parserexe
|
|||
website : website-non-haddock build-haddock
|
||||
|
||||
.PHONY : website-non-haddock
|
||||
website-non-haddock : build/main.css build/ocean.css build/index.html build/supported_sql.html \
|
||||
build/test_cases.html build/contributing.html
|
||||
|
||||
website-non-haddock : build/main.css build/main1.css build/index.html \
|
||||
build/supported_sql.html build/test_cases.html
|
||||
|
||||
build/main.css : website/main.css
|
||||
mkdir -p build
|
||||
cp website/main.css build
|
||||
|
||||
build/ocean.css : website/ocean.css
|
||||
# todo: combine main and main1, change the one bit they can't share with sed
|
||||
# to create the additional main1 as part of the build
|
||||
build/main1.css : website/main1.css
|
||||
mkdir -p build
|
||||
cp website/ocean.css build
|
||||
cp website/main1.css build
|
||||
|
||||
build/index.html : website/index.asciidoc website/AddLinks.hs
|
||||
asciidoctor website/index.asciidoc -o - | cabal -v0 exec runhaskell website/AddLinks.hs > build/index.html
|
||||
build/index.html : website/index.md website/template.pandoc
|
||||
mkdir -p build
|
||||
pandoc -s --template website/template.pandoc -V toc-title:"Table of contents" -c main.css -f markdown -t html --toc=true --metadata title="Simple SQL Parser" website/index.md > build/index.html
|
||||
|
||||
build/supported_sql.html : website/supported_sql.asciidoc website/AddLinks.hs
|
||||
asciidoctor website/supported_sql.asciidoc -o - | cabal -v0 exec runhaskell website/AddLinks.hs > build/supported_sql.html
|
||||
build/supported_sql.html : website/supported_sql.md website/template.pandoc
|
||||
mkdir -p build
|
||||
pandoc -s --template website/template.pandoc -V toc-title:"Table of contents" -c main.css -f markdown -t html --toc=true --metadata title="Simple SQL Parser supported SQL" website/supported_sql.md > build/supported_sql.html
|
||||
|
||||
build/contributing.html : website/contributing.asciidoc website/AddLinks.hs
|
||||
asciidoctor website/contributing.asciidoc -o - | cabal -v0 exec runhaskell website/AddLinks.hs > build/contributing.html
|
||||
|
||||
build/test_cases.html : website/RenderTestCases.hs
|
||||
cabal -v0 exec runhaskell -- --ghc-arg=-package=pretty-show -itools website/RenderTestCases.hs > build/test_cases.asciidoc
|
||||
asciidoctor build/test_cases.asciidoc -o - | \
|
||||
sed -e "s/max-width:62\.5em//g" > build/test_cases.html
|
||||
# TODO: reduce the text size on the test cases page
|
||||
# TODO: use scrollbars inside the tables
|
||||
# TODO: make the tables autowidth
|
||||
# -e "s/(code.*)font-size:1em/\1font-size:0.8em/g"
|
||||
rm build/test_cases.asciidoc
|
||||
# the tests don't render right if the TestCases aren't all at the same level
|
||||
# of group nesting, which should be fixed - if this isn't the case, it
|
||||
# will silently not render some of the tests
|
||||
build/test_cases.html : website/RenderTestCases.hs website/template1.pandoc
|
||||
mkdir -p build
|
||||
# no idea why not using --disable-optimisation on cabal build, but putting -O0
|
||||
# in the cabal file (and then cabal appears to say it's still using -O1
|
||||
# is faster
|
||||
cd website/ && cabal build RenderTestCases && cabal run RenderTestCases | pandoc -s -N --template template1.pandoc -V toc-title:"Simple SQL Parser test case examples" -c main1.css -f markdown -t html --toc=true --metadata title="Simple SQL Parse test case examples" > ../build/test_cases.html
|
||||
|
||||
# works here, but not in a recipe. amazing
|
||||
# GHC_VER="$(shell ghc --numeric-version)"
|
||||
|
@ -85,3 +81,13 @@ build-haddock :
|
|||
$(eval GHC_VER="$(shell ghc --numeric-version)")
|
||||
$(eval SSP_VER="$(shell cat simple-sql-parser.cabal |grep -P '^version:' | awk '{print $$2}')")
|
||||
cp -R dist-newstyle/build/x86_64-linux/ghc-${GHC_VER}/simple-sql-parser-${SSP_VER}/doc/html/simple-sql-parser/* build/haddock/
|
||||
|
||||
# check the website pages code snippets
|
||||
.PHONY : doctool
|
||||
doctool :
|
||||
cabal build -fparserexe SimpleSQLParserTool
|
||||
silverbane website/index.md
|
||||
|
||||
.PHONY : really-all
|
||||
really-all : build test parserexe website doctool
|
||||
|
||||
|
|
|
@ -1,40 +1,4 @@
|
|||
|
||||
:toc: right
|
||||
:sectnums:
|
||||
:toclevels: 10
|
||||
:source-highlighter: pygments
|
||||
|
||||
= Contributing
|
||||
|
||||
== Contributing to simple sql parser
|
||||
|
||||
Guidelines:
|
||||
|
||||
If you add something to the public api, follow the pattern already set for haddock.
|
||||
|
||||
If something isn't ANSI SQL, add it under a dialect flag which isn't enabled in the ANSI dialect.
|
||||
|
||||
If you add dialect flags, add them to the appropriate dialects, create a new one if the dialect doesn't already exist. The current dialects are very much WIP, improve them if you see a gap you need fixing.
|
||||
|
||||
Add tests for anything you add, modify or fix.
|
||||
|
||||
Tests should provide examples of SQL that now parses and what it parses to.
|
||||
|
||||
When it's ready, make a pull request on github.
|
||||
|
||||
== Key design notes
|
||||
|
||||
The parsing is done using the Megaparsec library. The parser uses a separate lexer, also implemented with Megaparsec.
|
||||
|
||||
The dialect system was introduced as a way to deal with a messy problem. Users of the library are able to decide what to consider reserved keywords - this is better than asking them to modify the library source.
|
||||
|
||||
A tradeoff is all code that uses the library needs to be prepared to deal with/ignore parts of the abstract syntax which supports all features from all dialects.
|
||||
|
||||
== Legal business
|
||||
|
||||
All contributions remain copyright of the person who wrote them. By contributing to the main repository, including but not limited to via a pull request, the copyright holder agrees to license those contributions under the BSD 3-clause license. This includes all contributions already made to the project.
|
||||
|
||||
== Release checklist
|
||||
# Release checklist
|
||||
|
||||
Check the version in the cabal file - update it if it hasn't already been updated. git grep for any other mentions of the version number that need updating.
|
||||
|
||||
|
@ -42,17 +6,26 @@ Update the changelog, use git diff or similar to try to reduce the chance of mis
|
|||
|
||||
Run the tests (if any fail at the point of thinking about a release, then something has gone horribly wrong ...)
|
||||
|
||||
----
|
||||
~~~~
|
||||
cabal test
|
||||
----
|
||||
~~~~
|
||||
|
||||
Generate the website
|
||||
Do the cabal checks:
|
||||
|
||||
----
|
||||
make website
|
||||
----
|
||||
~~~~
|
||||
cabal update
|
||||
cabal outdated
|
||||
cabal check
|
||||
~~~~
|
||||
|
||||
It's a bit wonky so try running it a second time if it fails.
|
||||
Check everything:
|
||||
|
||||
~~~~
|
||||
make clean
|
||||
make really-all
|
||||
~~~~
|
||||
|
||||
TODO: you need silverbane to check the examples in the index.md.
|
||||
|
||||
Then:
|
||||
|
||||
|
@ -60,64 +33,55 @@ Then:
|
|||
|
||||
* check all the tests are rendered on the example page -> need to find a robust way of doing this, because there are huge numbers and it's impossible to eyeball and tell if it's good unless you somehow spot a problem.
|
||||
|
||||
* check the examples on the main page to check if they need updating
|
||||
|
||||
Do the cabal checks:
|
||||
|
||||
----
|
||||
cabal update
|
||||
cabal outdated
|
||||
cabal check
|
||||
----
|
||||
|
||||
Update stack.yaml to the latest lts - check this page: https://www.stackage.org/ . While updating, check the extra-deps field, if there are any there, see if they can be removed.
|
||||
|
||||
Install latest stack and check it works - maybe the stack.yaml file needs a tweak, maybe the cabal file.
|
||||
|
||||
----
|
||||
~~~~
|
||||
ghcup list
|
||||
ghcup install stack [LATEST FROM THE LIST]
|
||||
ghcup install stack [latest from the list on stackage.org]
|
||||
stack test
|
||||
----
|
||||
~~~~
|
||||
|
||||
Run the tests on the previous 2 ghcs latest point releases, and the latest ghc, each with the latest cabal-install they support (e.g. as of the start of 2024, these three ghc versions are 9.8.1, 9.6.4, 9.4.8). This is now trivial to do with ghcup, amazing progress in Haskell tools in recent years.
|
||||
|
||||
Build the release tarball, run a test with an example using this tarball:
|
||||
|
||||
----
|
||||
~~~~
|
||||
cabal sdist
|
||||
mkdir temp-build
|
||||
# get the path to the tar.gz from the output of cabal sdist
|
||||
cp simple-sql-parser/main/dist-newstyle/sdist/simple-sql-parser-0.X.X.tar.gz temp-build
|
||||
cd temp-build
|
||||
cabal init -n
|
||||
cp ../tools/SimpleSqlParserTool.hs app/Main.hs
|
||||
----
|
||||
cp ../examples/SimpleSQLParserTool.hs app/Main.hs
|
||||
~~~~
|
||||
|
||||
Add these to the build-depends: for the Main in the new cabal file, temp-build.cabal:
|
||||
Add these to the build-depends: for the Main in temp-build.cabal:
|
||||
|
||||
----
|
||||
~~~~
|
||||
simple-sql-parser == 0.X.X,
|
||||
pretty-show,
|
||||
text
|
||||
----
|
||||
~~~~
|
||||
|
||||
Add a cabal.project file containing:
|
||||
----
|
||||
Add a cabal.project.local file containing:
|
||||
|
||||
~~~~
|
||||
packages:
|
||||
./
|
||||
./simple-sql-parser-0.X.X.tar.gz
|
||||
----
|
||||
~~~~
|
||||
|
||||
Run the test:
|
||||
|
||||
----
|
||||
~~~~
|
||||
cabal run temp-build -- parse -c "select 1"
|
||||
----
|
||||
~~~~
|
||||
|
||||
Example of output on success:
|
||||
|
||||
----
|
||||
~~~~
|
||||
$ cabal run temp-build -- parse -c "select 1"
|
||||
Build profile: -w ghc-9.8.1 -O1
|
||||
In order, the following will be built (use -v for more details):
|
||||
|
@ -145,7 +109,7 @@ Building executable 'temp-build' for temp-build-0.1.0.0..
|
|||
, qeFetchFirst = Nothing
|
||||
}
|
||||
]
|
||||
----
|
||||
~~~~
|
||||
|
||||
TODO: hlint?, how to do a spell check, what about automatic code formatting?
|
||||
|
||||
|
@ -156,4 +120,6 @@ Upload candidate to hackage, run a test with example using this package
|
|||
|
||||
If all good, release the candidate - a button on the hackage website.
|
||||
|
||||
when and how do you add a tag to git?
|
||||
|
||||
Todo: try to turn as much of this into a script, with a nice report as possible, order this list properly, say what you need to check in more detail, say what else you need to redo if any steps need actions.
|
|
@ -1,35 +0,0 @@
|
|||
|
||||
import System.IO
|
||||
import System.Environment
|
||||
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
[a] <- getArgs
|
||||
r <- readFile a
|
||||
let ls = lines r
|
||||
a = noAdjacentBlankLines ls
|
||||
b = concat $ combineGroups $ group [] a
|
||||
putStrLn $ unlines b
|
||||
|
||||
noAdjacentBlankLines [] = []
|
||||
noAdjacentBlankLines [a] = [a]
|
||||
noAdjacentBlankLines ("":xs@("":_)) = noAdjacentBlankLines xs
|
||||
noAdjacentBlankLines (x:xs) = x:noAdjacentBlankLines xs
|
||||
|
||||
group :: [String] -> [String] -> [[String]]
|
||||
group acc [] = [acc]
|
||||
group acc ("":xs) = reverse ("":acc) : group [] xs
|
||||
group acc (x:xs) = group (x : acc) xs
|
||||
|
||||
combineGroups :: [[String]] -> [[String]]
|
||||
combineGroups [] = []
|
||||
combineGroups (x@(('<':_):_):xs) | gs <- map trim x
|
||||
, ns <- trim $ unwords gs
|
||||
, length ns < 80 = [ns ++ "\n"] : combineGroups xs
|
||||
combineGroups (x:xs) = x:combineGroups xs
|
||||
|
||||
trim :: String -> String
|
||||
trim = x . x
|
||||
where
|
||||
x = dropWhile (==' ') . reverse
|
|
@ -1,24 +0,0 @@
|
|||
|
||||
--import System.IO
|
||||
import System.Environment
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
[a] <- getArgs
|
||||
r <- readFile a
|
||||
let ls = lines r
|
||||
putStrLn $ unlines $ map dedupeSpaces ls
|
||||
|
||||
|
||||
dedupeSpaces :: String -> String
|
||||
dedupeSpaces [] = []
|
||||
-- don't start until after the leading spaces
|
||||
-- including literate haskell source lines
|
||||
dedupeSpaces xs@(x:_) | x `notElem` " >" = dedupeSpaces' xs
|
||||
dedupeSpaces (x:xs) = x : dedupeSpaces xs
|
||||
|
||||
dedupeSpaces' :: String -> String
|
||||
dedupeSpaces' (' ':xs@(' ':_)) = dedupeSpaces' xs
|
||||
dedupeSpaces' (x:xs) = x : dedupeSpaces' xs
|
||||
dedupeSpaces' [] = []
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
|
||||
|
||||
import Language.SQL.SimpleSQL.ErrorMessages
|
||||
|
||||
|
||||
main :: IO ()
|
||||
main = putStrLn $ pExprs valueExpressions queryExpressions
|
|
@ -1,49 +0,0 @@
|
|||
|
||||
-- Simple example to show parsing some SQL then pretty printing the AST
|
||||
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
import System.Environment
|
||||
import Text.Show.Pretty
|
||||
import System.IO
|
||||
|
||||
import Language.SQL.SimpleSQL.Parse
|
||||
(parseStatements
|
||||
,ParseError
|
||||
,prettyError
|
||||
,ansi2011)
|
||||
|
||||
import Language.SQL.SimpleSQL.Syntax (Statement)
|
||||
import qualified Data.Text as T
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
args <- getArgs
|
||||
case args of
|
||||
[] -> do
|
||||
-- read from stdin
|
||||
c <- getContents
|
||||
doIt c
|
||||
["-s", sql] -> do
|
||||
-- parse arg given
|
||||
doIt sql
|
||||
[f] ->
|
||||
-- read file
|
||||
withFile f ReadMode (\h -> do
|
||||
x <- hGetContents h
|
||||
doIt x)
|
||||
_ -> do
|
||||
putStrLn "use no arguments to stream sql from stdin, e.g.:\n\
|
||||
\ cat some.sql | SimpleSQLParserExample\n\
|
||||
\n\
|
||||
\use -s to parse sql on command line, e.g.:\n\
|
||||
\ SimpleSQLParserExample -s \"select * from t\"\n\
|
||||
\use a single arg to parse a file, e.g.\n\
|
||||
\ SimpleSQLParserExample some.sql"
|
||||
|
||||
doIt :: String -> IO ()
|
||||
doIt src = do
|
||||
let parsed :: Either ParseError [Statement]
|
||||
parsed = parseStatements ansi2011 "" Nothing (T.pack src)
|
||||
either (error . T.unpack . prettyError)
|
||||
(putStrLn . ppShow)
|
||||
parsed
|
|
@ -1,34 +0,0 @@
|
|||
|
||||
-- Little hack to add links to the navigation bars
|
||||
|
||||
main :: IO ()
|
||||
main = interact addLinks
|
||||
|
||||
|
||||
addLinks :: String -> String
|
||||
addLinks [] = error "not found"
|
||||
addLinks ('<':'/':'u':'l':'>':'\n':'<':'/':'d':'i':'v':'>':xs) =
|
||||
"</ul>" ++ linkSection ++ "\n</div>" ++ xs
|
||||
addLinks (x:xs) = x : addLinks xs
|
||||
|
||||
linkSection :: String
|
||||
linkSection =
|
||||
"<hr />\n\
|
||||
\<ul class=\"sectlevel1\">\n\
|
||||
\<div id=\"toctitle\">Links</div>\n\
|
||||
\<li><a href=\"index.html\">Index</a></li>\n\
|
||||
\<li><a href='haddock/index.html'>Haddock</li>\n\
|
||||
\<li><a href=\"supported_sql.html\" class=\"bare\">Supported SQL</a></li>\n\
|
||||
\<li><a href=\"test_cases.html\">Test cases</a></li>\n\
|
||||
\<li><a href=\"contributing.html\">Contributing</a></li>\n\
|
||||
\</ul>\n\
|
||||
\<br />\n\
|
||||
\<ul class=\"sectlevel1\">\n\
|
||||
\<li><a href=\"http://jakewheat.github.io/simple-sql-parser/latest\" class=\"bare\">Homepage</a></li>\n\
|
||||
\<li><a href=\"http://hackage.haskell.org/package/simple-sql-parser\" class=\"bare\">Hackage</a></li>\n\
|
||||
\<li><a href=\"https://github.com/JakeWheat/simple-sql-parser\" class=\"bare\">Repository</a></li>\n\
|
||||
\<li><a href=\"https://github.com/JakeWheat/simple-sql-parser/issues\" class=\"bare\">Bug tracker</a></li>\n\
|
||||
\<li><a href=\"https://github.com/JakeWheat/simple-sql-parser/blob/master/changelog\" class=\"bare\">Changes</a></li>\n\
|
||||
\<li><a href=\"http://jakewheat.github.io/simple-sql-parser/\" class=\"bare\">Other versions</a></li>\n\
|
||||
\</li><li>jakewheat@tutanota.com</li>\n\
|
||||
\</ul>\n"
|
|
@ -1,91 +1,82 @@
|
|||
|
||||
-- Converts the test data to asciidoc
|
||||
-- Converts the test data to markdown
|
||||
-- it uses raw html for the table parts
|
||||
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
import Language.SQL.SimpleSQL.Tests
|
||||
import Text.Show.Pretty
|
||||
import Control.Monad.State
|
||||
import Text.Show.Pretty (ppShow)
|
||||
import qualified Language.SQL.SimpleSQL.Parse as P
|
||||
import qualified Language.SQL.SimpleSQL.Lex as L
|
||||
import Data.List
|
||||
import Control.Monad (when, unless)
|
||||
import Data.Text (Text)
|
||||
import qualified Data.Text as T
|
||||
|
||||
import Prelude hiding (putStrLn)
|
||||
import Data.Text.IO (putStrLn)
|
||||
import qualified Data.Text.Lazy as L
|
||||
import qualified Data.Text.Lazy.IO as L
|
||||
|
||||
data TableItem = Heading Int Text
|
||||
| Row Text Text
|
||||
data TableItem = Heading Int L.Text
|
||||
| Row L.Text L.Text
|
||||
|
||||
doc :: Int -> TestItem -> [TableItem]
|
||||
-- filter out some groups of tests
|
||||
doc n (Group nm _) | "generated" `T.isInfixOf` nm = []
|
||||
doc _ (Group nm _) | "generated" `T.isInfixOf` nm = []
|
||||
doc n (Group nm is) =
|
||||
Heading n nm
|
||||
Heading n (L.fromStrict nm)
|
||||
: concatMap (doc (n + 1)) is
|
||||
doc _ (TestScalarExpr _ str e) =
|
||||
[Row str (T.pack $ ppShow e)]
|
||||
[Row (L.fromStrict str) (L.pack $ ppShow e)]
|
||||
doc _ (TestQueryExpr _ str e) =
|
||||
[Row str (T.pack $ ppShow e)]
|
||||
[Row (L.fromStrict str) (L.pack $ ppShow e)]
|
||||
doc _ (TestStatement _ str e) =
|
||||
[Row str (T.pack $ ppShow e)]
|
||||
[Row (L.fromStrict str) (L.pack $ ppShow e)]
|
||||
doc _ (TestStatements _ str e) =
|
||||
[Row str (T.pack $ ppShow e)]
|
||||
[Row (L.fromStrict str) (L.pack $ ppShow e)]
|
||||
doc _ (ParseQueryExpr d str) =
|
||||
[Row str (showResult $ P.parseQueryExpr d "" Nothing str)]
|
||||
[Row (L.fromStrict str) (showResult $ P.parseQueryExpr d "" Nothing str)]
|
||||
doc _ (ParseQueryExprFails d str) =
|
||||
[Row str (showResult $ P.parseQueryExpr d "" Nothing str)]
|
||||
[Row (L.fromStrict str) (showResult $ P.parseQueryExpr d "" Nothing str)]
|
||||
doc _ (ParseScalarExprFails d str) =
|
||||
[Row str (showResult $ P.parseScalarExpr d "" Nothing str)]
|
||||
[Row (L.fromStrict str) (showResult $ P.parseScalarExpr d "" Nothing str)]
|
||||
|
||||
doc _ (LexTest d str t) =
|
||||
[Row str (showResultL $ L.lexSQL d "" Nothing str)]
|
||||
doc _ (LexTest d str _) =
|
||||
[Row (L.fromStrict str) (showResultL $ L.lexSQL d "" Nothing str)]
|
||||
|
||||
doc _ (LexFails d str) =
|
||||
[Row str (showResultL $ L.lexSQL d "" Nothing str)]
|
||||
[Row (L.fromStrict str) (showResultL $ L.lexSQL d "" Nothing str)]
|
||||
|
||||
showResult :: Show a => Either P.ParseError a -> Text
|
||||
showResult = either (("Left\n" <>) . P.prettyError) (T.pack . ppShow)
|
||||
showResult :: Show a => Either P.ParseError a -> L.Text
|
||||
showResult = either (("Left\n" <>) . L.fromStrict . P.prettyError) (L.pack . ppShow)
|
||||
|
||||
showResultL :: Show a => Either L.ParseError a -> Text
|
||||
showResultL = either (("Left\n" <>) . L.prettyError) (T.pack . ppShow)
|
||||
showResultL :: Show a => Either L.ParseError a -> L.Text
|
||||
showResultL = either (("Left\n" <>) . L.fromStrict . L.prettyError) (L.pack . ppShow)
|
||||
|
||||
|
||||
-- TODO: should put the dialect in the html output
|
||||
|
||||
|
||||
render :: [TableItem] -> IO ()
|
||||
render :: [TableItem] -> L.Text
|
||||
render = go False
|
||||
where
|
||||
go t (Heading level title : is) = do
|
||||
when t $ putStrLn "|==="
|
||||
go _t (Heading level title : is) =
|
||||
"</table>\n"
|
||||
<>
|
||||
-- slight hack
|
||||
when (level > 1) $
|
||||
putStrLn $ "\n" <> T.replicate level "=" <> " " <> title
|
||||
go False is
|
||||
go t (Row sql hask : is) = do
|
||||
unless t $ putStrLn "[cols=\"2\"]\n|==="
|
||||
let sql' = "\n[source,sql]\n----\n" <> sql <> "\n----\n"
|
||||
hask' = "\n[source,haskell]\n----\n" <> hask <> "\n----\n"
|
||||
putStrLn $ "a| " <> escapePipe sql'
|
||||
<> "a| " <> escapePipe hask' <> " "
|
||||
go True is
|
||||
go t [] = when t $ putStrLn "|==="
|
||||
escapePipe t = T.pack $ escapePipe' $ T.unpack t
|
||||
(if (level > 1)
|
||||
then "\n" <> L.replicate (fromIntegral $ level - 1) "#" <> " " <> title <> "\n"
|
||||
else "")
|
||||
<> go False is
|
||||
go t (Row sql hask : is) =
|
||||
(if (not t)
|
||||
then "<table>\n"
|
||||
else "")
|
||||
<> let sql' = "\n~~~~{.sql}\n" <> sql <> "\n~~~~\n"
|
||||
hask' = "\n~~~~{.haskell}\n" <> hask <> "\n~~~~\n"
|
||||
in "<tr><td>\n" <> sql' <> "</td><td>\n" <> hask' <> "</td></tr>\n"
|
||||
<> go True is
|
||||
go _t [] = "</table>\n"
|
||||
{-escapePipe t = T.pack $ escapePipe' $ T.unpack t
|
||||
escapePipe' [] = []
|
||||
escapePipe' ('\\':'|':xs) = '\\' : '\\' : '\\' : '|' : escapePipe' xs
|
||||
escapePipe' ('|':xs) = '\\' : '|' : escapePipe' xs
|
||||
escapePipe' (x:xs) = x : escapePipe' xs
|
||||
escapePipe' (x:xs) = x : escapePipe' xs-}
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
putStrLn "\n:toc:\n\
|
||||
\:toc-placement: macro\n\
|
||||
\:sectnums:\n\
|
||||
\:toclevels: 10\n\
|
||||
\:sectnumlevels: 10\n\
|
||||
\:source-highlighter: pygments\n\n\
|
||||
\= simple-sql-parser examples/test cases\n\n\
|
||||
\toc::[]\n"
|
||||
render $ doc 1 testData
|
||||
main = L.putStrLn $ render $ doc 1 testData
|
||||
|
||||
|
|
|
@ -1,438 +0,0 @@
|
|||
|
||||
:toc: right
|
||||
:sectnums:
|
||||
:toclevels: 10
|
||||
:source-highlighter: pygments
|
||||
|
||||
= simple-sql-parser
|
||||
|
||||
== Overview
|
||||
|
||||
A parser for SQL in Haskell. Also includes a pretty printer which
|
||||
formats output nicely. Current target is to parse most SQL:2011
|
||||
queries, plus a good subset of DDL, non-query DML, transaction
|
||||
management, access control and session management.
|
||||
|
||||
This is the documentation for version 0.7.0. Documentation for other
|
||||
versions is available here:
|
||||
http://jakewheat.github.io/simple-sql-parser/.
|
||||
|
||||
Status: usable for parsing a substantial amount of SQL. Adding support
|
||||
for new SQL is relatively easy. Expect a little bit of churn on the AST
|
||||
types when support for new SQL features is added.
|
||||
|
||||
This version is tested with GHC 9.8.1, 9.6.4, and 9.4.8.
|
||||
|
||||
== Feature support
|
||||
|
||||
* query expressions
|
||||
** select lists
|
||||
** from clause
|
||||
** where clause
|
||||
** group by clause
|
||||
** having clause
|
||||
** order by clause
|
||||
** offset and fetch
|
||||
** set operators
|
||||
** common table expressions
|
||||
** wide range of scalar expressions
|
||||
* DDL (ansi dialect)
|
||||
** create,drop schema
|
||||
** create, alter, drop table
|
||||
** create, drop view
|
||||
** create, alter, drop domain
|
||||
** create, drop assertion
|
||||
** create, alter, drop sequence
|
||||
* non-query DML
|
||||
** delete
|
||||
** truncate
|
||||
** insert
|
||||
** update
|
||||
* Access control
|
||||
** grant, revoke - permissions and roles
|
||||
** create, drop role
|
||||
* Transaction management
|
||||
** begin, commit, rollback, savepoints
|
||||
|
||||
See the link:supported_sql.html[] page for details on
|
||||
the supported SQL.
|
||||
|
||||
Here is all the link:test_cases.html[simple-sql-parser test cases]
|
||||
rendered in a webpage so you can get an idea of what it supports.
|
||||
|
||||
== Examples
|
||||
|
||||
Simple expression:
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
select a + b * c
|
||||
----
|
||||
|
||||
Parsed AST:
|
||||
|
||||
[source,haskell]
|
||||
----
|
||||
Select
|
||||
{ qeSetQuantifier = SQDefault
|
||||
, qeSelectList =
|
||||
[ ( BinOp
|
||||
(Iden [ Name Nothing "a" ])
|
||||
[ Name Nothing "+" ]
|
||||
(BinOp
|
||||
(Iden [ Name Nothing "b" ])
|
||||
[ Name Nothing "*" ]
|
||||
(Iden [ Name Nothing "c" ]))
|
||||
, Nothing
|
||||
)
|
||||
]
|
||||
, qeFrom = []
|
||||
, qeWhere = Nothing
|
||||
, qeGroupBy = []
|
||||
, qeHaving = Nothing
|
||||
, qeOrderBy = []
|
||||
, qeOffset = Nothing
|
||||
, qeFetchFirst = Nothing
|
||||
}
|
||||
----
|
||||
|
||||
TPC-H query 21:
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
select
|
||||
s_name,
|
||||
count(*) as numwait
|
||||
from
|
||||
supplier,
|
||||
lineitem l1,
|
||||
orders,
|
||||
nation
|
||||
where
|
||||
s_suppkey = l1.l_suppkey
|
||||
and o_orderkey = l1.l_orderkey
|
||||
and o_orderstatus = 'F'
|
||||
and l1.l_receiptdate > l1.l_commitdate
|
||||
and exists (
|
||||
select
|
||||
*
|
||||
from
|
||||
lineitem l2
|
||||
where
|
||||
l2.l_orderkey = l1.l_orderkey
|
||||
and l2.l_suppkey <> l1.l_suppkey
|
||||
)
|
||||
and not exists (
|
||||
select
|
||||
*
|
||||
from
|
||||
lineitem l3
|
||||
where
|
||||
l3.l_orderkey = l1.l_orderkey
|
||||
and l3.l_suppkey <> l1.l_suppkey
|
||||
and l3.l_receiptdate > l3.l_commitdate
|
||||
)
|
||||
and s_nationkey = n_nationkey
|
||||
and n_name = 'INDIA'
|
||||
group by
|
||||
s_name
|
||||
order by
|
||||
numwait desc,
|
||||
s_name
|
||||
fetch first 100 rows only;
|
||||
----
|
||||
|
||||
Parsed:
|
||||
|
||||
[source,haskell]
|
||||
----
|
||||
Select
|
||||
{ qeSetQuantifier = SQDefault
|
||||
, qeSelectList =
|
||||
[ ( Iden [ Name Nothing "s_name" ] , Nothing )
|
||||
, ( App [ Name Nothing "count" ] [ Star ]
|
||||
, Just (Name Nothing "numwait")
|
||||
)
|
||||
]
|
||||
, qeFrom =
|
||||
[ TRSimple [ Name Nothing "supplier" ]
|
||||
, TRAlias
|
||||
(TRSimple [ Name Nothing "lineitem" ])
|
||||
(Alias (Name Nothing "l1") Nothing)
|
||||
, TRSimple [ Name Nothing "orders" ]
|
||||
, TRSimple [ Name Nothing "nation" ]
|
||||
]
|
||||
, qeWhere =
|
||||
Just
|
||||
(BinOp
|
||||
(BinOp
|
||||
(BinOp
|
||||
(BinOp
|
||||
(BinOp
|
||||
(BinOp
|
||||
(BinOp
|
||||
(BinOp
|
||||
(Iden [ Name Nothing "s_suppkey" ])
|
||||
[ Name Nothing "=" ]
|
||||
(Iden [ Name Nothing "l1" , Name Nothing "l_suppkey" ]))
|
||||
[ Name Nothing "and" ]
|
||||
(BinOp
|
||||
(Iden [ Name Nothing "o_orderkey" ])
|
||||
[ Name Nothing "=" ]
|
||||
(Iden [ Name Nothing "l1" , Name Nothing "l_orderkey" ])))
|
||||
[ Name Nothing "and" ]
|
||||
(BinOp
|
||||
(Iden [ Name Nothing "o_orderstatus" ])
|
||||
[ Name Nothing "=" ]
|
||||
(StringLit "'" "'" "F")))
|
||||
[ Name Nothing "and" ]
|
||||
(BinOp
|
||||
(Iden [ Name Nothing "l1" , Name Nothing "l_receiptdate" ])
|
||||
[ Name Nothing ">" ]
|
||||
(Iden [ Name Nothing "l1" , Name Nothing "l_commitdate" ])))
|
||||
[ Name Nothing "and" ]
|
||||
(SubQueryExpr
|
||||
SqExists
|
||||
Select
|
||||
{ qeSetQuantifier = SQDefault
|
||||
, qeSelectList = [ ( Star , Nothing ) ]
|
||||
, qeFrom =
|
||||
[ TRAlias
|
||||
(TRSimple [ Name Nothing "lineitem" ])
|
||||
(Alias (Name Nothing "l2") Nothing)
|
||||
]
|
||||
, qeWhere =
|
||||
Just
|
||||
(BinOp
|
||||
(BinOp
|
||||
(Iden [ Name Nothing "l2" , Name Nothing "l_orderkey" ])
|
||||
[ Name Nothing "=" ]
|
||||
(Iden [ Name Nothing "l1" , Name Nothing "l_orderkey" ]))
|
||||
[ Name Nothing "and" ]
|
||||
(BinOp
|
||||
(Iden [ Name Nothing "l2" , Name Nothing "l_suppkey" ])
|
||||
[ Name Nothing "<>" ]
|
||||
(Iden [ Name Nothing "l1" , Name Nothing "l_suppkey" ])))
|
||||
, qeGroupBy = []
|
||||
, qeHaving = Nothing
|
||||
, qeOrderBy = []
|
||||
, qeOffset = Nothing
|
||||
, qeFetchFirst = Nothing
|
||||
}))
|
||||
[ Name Nothing "and" ]
|
||||
(PrefixOp
|
||||
[ Name Nothing "not" ]
|
||||
(SubQueryExpr
|
||||
SqExists
|
||||
Select
|
||||
{ qeSetQuantifier = SQDefault
|
||||
, qeSelectList = [ ( Star , Nothing ) ]
|
||||
, qeFrom =
|
||||
[ TRAlias
|
||||
(TRSimple [ Name Nothing "lineitem" ])
|
||||
(Alias (Name Nothing "l3") Nothing)
|
||||
]
|
||||
, qeWhere =
|
||||
Just
|
||||
(BinOp
|
||||
(BinOp
|
||||
(BinOp
|
||||
(Iden [ Name Nothing "l3" , Name Nothing "l_orderkey" ])
|
||||
[ Name Nothing "=" ]
|
||||
(Iden
|
||||
[ Name Nothing "l1" , Name Nothing "l_orderkey" ]))
|
||||
[ Name Nothing "and" ]
|
||||
(BinOp
|
||||
(Iden [ Name Nothing "l3" , Name Nothing "l_suppkey" ])
|
||||
[ Name Nothing "<>" ]
|
||||
(Iden
|
||||
[ Name Nothing "l1" , Name Nothing "l_suppkey" ])))
|
||||
[ Name Nothing "and" ]
|
||||
(BinOp
|
||||
(Iden [ Name Nothing "l3" , Name Nothing "l_receiptdate" ])
|
||||
[ Name Nothing ">" ]
|
||||
(Iden
|
||||
[ Name Nothing "l3" , Name Nothing "l_commitdate" ])))
|
||||
, qeGroupBy = []
|
||||
, qeHaving = Nothing
|
||||
, qeOrderBy = []
|
||||
, qeOffset = Nothing
|
||||
, qeFetchFirst = Nothing
|
||||
})))
|
||||
[ Name Nothing "and" ]
|
||||
(BinOp
|
||||
(Iden [ Name Nothing "s_nationkey" ])
|
||||
[ Name Nothing "=" ]
|
||||
(Iden [ Name Nothing "n_nationkey" ])))
|
||||
[ Name Nothing "and" ]
|
||||
(BinOp
|
||||
(Iden [ Name Nothing "n_name" ])
|
||||
[ Name Nothing "=" ]
|
||||
(StringLit "'" "'" "INDIA")))
|
||||
, qeGroupBy = [ SimpleGroup (Iden [ Name Nothing "s_name" ]) ]
|
||||
, qeHaving = Nothing
|
||||
, qeOrderBy =
|
||||
[ SortSpec (Iden [ Name Nothing "numwait" ]) Desc NullsOrderDefault
|
||||
, SortSpec
|
||||
(Iden [ Name Nothing "s_name" ]) DirDefault NullsOrderDefault
|
||||
]
|
||||
, qeOffset = Nothing
|
||||
, qeFetchFirst = Just (NumLit "100")
|
||||
}
|
||||
----
|
||||
|
||||
|
||||
Output from the simple-sql-parser pretty printer:
|
||||
|
||||
[source,sql]
|
||||
----
|
||||
select s_name, count(*) as numwait
|
||||
from supplier,
|
||||
lineitem as l1,
|
||||
orders,
|
||||
nation
|
||||
where s_suppkey = l1.l_suppkey
|
||||
and o_orderkey = l1.l_orderkey
|
||||
and o_orderstatus = 'F'
|
||||
and l1.l_receiptdate > l1.l_commitdate
|
||||
and exists (select *
|
||||
from lineitem as l2
|
||||
where l2.l_orderkey = l1.l_orderkey
|
||||
and l2.l_suppkey <> l1.l_suppkey)
|
||||
and not exists (select *
|
||||
from lineitem as l3
|
||||
where l3.l_orderkey = l1.l_orderkey
|
||||
and l3.l_suppkey <> l1.l_suppkey
|
||||
and l3.l_receiptdate > l3.l_commitdate)
|
||||
and s_nationkey = n_nationkey
|
||||
and n_name = 'INDIA'
|
||||
group by s_name
|
||||
order by numwait desc, s_name
|
||||
fetch first 100 rows only;
|
||||
----
|
||||
|
||||
Parsing some SQL and printing the AST:
|
||||
|
||||
[source,haskell]
|
||||
----
|
||||
{-# LANGUAGE OverloadedStrings #-}
|
||||
import System.Environment
|
||||
import Text.Show.Pretty
|
||||
import System.IO
|
||||
|
||||
import Language.SQL.SimpleSQL.Parse
|
||||
(parseStatements
|
||||
,ParseError
|
||||
,prettyError
|
||||
,ansi2011)
|
||||
|
||||
import Language.SQL.SimpleSQL.Syntax (Statement)
|
||||
import qualified Data.Text as T
|
||||
|
||||
main :: IO ()
|
||||
main = do
|
||||
args <- getArgs
|
||||
case args of
|
||||
[] -> do
|
||||
-- read from stdin
|
||||
c <- getContents
|
||||
doIt c
|
||||
["-s", sql] -> do
|
||||
-- parse arg given
|
||||
doIt sql
|
||||
[f] ->
|
||||
-- read file
|
||||
withFile f ReadMode (\h -> do
|
||||
x <- hGetContents h
|
||||
doIt x)
|
||||
_ -> do
|
||||
putStrLn "use no arguments to stream sql from stdin, e.g.:\n\
|
||||
\ cat some.sql | SimpleSQLParserExample\n\
|
||||
\n\
|
||||
\use -s to parse sql on command line, e.g.:\n\
|
||||
\ SimpleSQLParserExample -s \"select * from t\"\n\
|
||||
\use a single arg to parse a file, e.g.\n\
|
||||
\ SimpleSQLParserExample some.sql"
|
||||
|
||||
doIt :: String -> IO ()
|
||||
doIt src = do
|
||||
let parsed :: Either ParseError [Statement]
|
||||
parsed = parseStatements ansi2011 "" Nothing (T.pack src)
|
||||
either (error . T.unpack . prettyError)
|
||||
(putStrLn . ppShow)
|
||||
parsed
|
||||
----
|
||||
|
||||
|
||||
|
||||
== Installation
|
||||
|
||||
Use cabal, stack or your usual system to work with the released package.
|
||||
|
||||
Working with the latest development version:
|
||||
|
||||
----
|
||||
git clone https://github.com/JakeWheat/simple-sql-parser.git
|
||||
cd simple-sql-parser
|
||||
cabal build
|
||||
----
|
||||
|
||||
=== Running the tests
|
||||
|
||||
Get the source using 'cabal unpack' or 'git clone', then change to the
|
||||
source directory.
|
||||
|
||||
You can run the tests using cabal:
|
||||
|
||||
----
|
||||
cabal test
|
||||
----
|
||||
|
||||
Or you can run them directly which gives more options. The tests use
|
||||
tasty, which provides the command line options. --hide-successes
|
||||
with --ansi-tricks=false so it works is a good option to use:
|
||||
|
||||
|
||||
----
|
||||
cabal run test:Tests -- --hide-successes --ansi-tricks=false
|
||||
----
|
||||
|
||||
== Reporting bugs
|
||||
|
||||
Please report bugs here:
|
||||
|
||||
https://github.com/JakeWheat/simple-sql-parser/issues
|
||||
|
||||
A good bug report (or feature request) should have an example of the
|
||||
SQL which is failing.
|
||||
|
||||
Feature requests are welcome, but please note that there is no-one
|
||||
generally available to work on these, so you should either make a pull
|
||||
request, or find someone willing to write the fixes and make a pull
|
||||
request.
|
||||
|
||||
There is a related tutorial on implementing a SQL parser here:
|
||||
http://jakewheat.github.io/intro_to_parsing/ (TODO: this is out of date, hopefully it will be updated at some point)
|
||||
|
||||
== Contributing
|
||||
|
||||
See link:contributing.html[].
|
||||
|
||||
== Links
|
||||
|
||||
* Haddock: link:haddock/index.html[]
|
||||
* Supported SQL: link:supported_sql.html[]
|
||||
* Test cases: link:test_cases.html[simple-sql-parser test cases]
|
||||
* Homepage: http://jakewheat.github.io/simple-sql-parser/latest
|
||||
* Hackage: http://hackage.haskell.org/package/simple-sql-parser
|
||||
* Repository: https://github.com/JakeWheat/simple-sql-parser
|
||||
* Bug tracker: https://github.com/JakeWheat/simple-sql-parser/issues
|
||||
* Changes: https://github.com/JakeWheat/simple-sql-parser/blob/master/changelog
|
||||
* Other versions: http://jakewheat.github.io/simple-sql-parser/
|
||||
* Contact: +++jakewheat@tutanota.com+++
|
||||
|
||||
The simple-sql-parser is a lot less simple than it used to be. If you
|
||||
just need to parse much simpler SQL than this, or want to start with a
|
||||
simpler parser and modify it slightly, you could also look at the
|
||||
basic query parser in the intro_to_parsing project, the code is here:
|
||||
link:https://github.com/JakeWheat/intro_to_parsing/blob/master/SimpleSQLQueryParser0.lhs[SimpleSQLQueryParser] (TODO: this is out of date, hopefully it will be updated at some point).
|
238
website/index.md
Normal file
238
website/index.md
Normal file
|
@ -0,0 +1,238 @@
|
|||
|
||||
# Overview
|
||||
|
||||
A parser for SQL in Haskell. Also includes a pretty printer which
|
||||
formats SQL.
|
||||
|
||||
This is the documentation for version 0.7.0. Documentation for other
|
||||
versions is available here:
|
||||
<http://jakewheat.github.io/simple-sql-parser/>.
|
||||
|
||||
Status: usable for parsing a substantial amount of SQL. Adding support
|
||||
for new SQL is easy. Expect a little bit of churn on the AST types
|
||||
when support for new SQL features is added.
|
||||
|
||||
This version is tested with GHC 9.8.1, 9.6.4, and 9.4.8.
|
||||
|
||||
# Examples
|
||||
|
||||
Parse a SQL statement:
|
||||
|
||||
~~~~{.haskell sb-session='cabal repl --repl-options=-XOverloadedStrings' sb-prompt='ghci> ' sb-no-initial-text=}
|
||||
ghci> import Language.SQL.SimpleSQL.Parse
|
||||
ghci> import qualified Data.Text as T
|
||||
ghci> either (T.unpack . prettyError) show $ parseStatement ansi2011 "" Nothing "select a + b * c"
|
||||
"SelectStatement (Select {qeSetQuantifier = SQDefault, qeSelectList = [(BinOp (Iden [Name Nothing \"a\"]) [Name Nothing \"+\"] (BinOp (Iden [Name Nothing \"b\"]) [Name Nothing \"*\"] (Iden [Name Nothing \"c\"])),Nothing)], qeFrom = [], qeWhere = Nothing, qeGroupBy = [], qeHaving = Nothing, qeOrderBy = [], qeOffset = Nothing, qeFetchFirst = Nothing})"
|
||||
~~~~
|
||||
|
||||
The result printed readably:
|
||||
|
||||
~~~~{.haskell sb-run='cabal run -fparserexe SimpleSQLParserTool -- parse -c "select a + b * c"' sb-cwd='..'}
|
||||
[ SelectStatement
|
||||
Select
|
||||
{ qeSetQuantifier = SQDefault
|
||||
, qeSelectList =
|
||||
[ ( BinOp
|
||||
(Iden [ Name Nothing "a" ])
|
||||
[ Name Nothing "+" ]
|
||||
(BinOp
|
||||
(Iden [ Name Nothing "b" ])
|
||||
[ Name Nothing "*" ]
|
||||
(Iden [ Name Nothing "c" ]))
|
||||
, Nothing
|
||||
)
|
||||
]
|
||||
, qeFrom = []
|
||||
, qeWhere = Nothing
|
||||
, qeGroupBy = []
|
||||
, qeHaving = Nothing
|
||||
, qeOrderBy = []
|
||||
, qeOffset = Nothing
|
||||
, qeFetchFirst = Nothing
|
||||
}
|
||||
]
|
||||
~~~~
|
||||
|
||||
Formatting SQL, TPC-H query 21:
|
||||
|
||||
~~~~{.sql sb-file='tpch21.sql'}
|
||||
select
|
||||
s_name,
|
||||
count(*) as numwait
|
||||
from
|
||||
supplier,
|
||||
lineitem l1,
|
||||
orders,
|
||||
nation
|
||||
where
|
||||
s_suppkey = l1.l_suppkey
|
||||
and o_orderkey = l1.l_orderkey
|
||||
and o_orderstatus = 'F'
|
||||
and l1.l_receiptdate > l1.l_commitdate
|
||||
and exists (
|
||||
select
|
||||
*
|
||||
from
|
||||
lineitem l2
|
||||
where
|
||||
l2.l_orderkey = l1.l_orderkey
|
||||
and l2.l_suppkey <> l1.l_suppkey
|
||||
)
|
||||
and not exists (
|
||||
select
|
||||
*
|
||||
from
|
||||
lineitem l3
|
||||
where
|
||||
l3.l_orderkey = l1.l_orderkey
|
||||
and l3.l_suppkey <> l1.l_suppkey
|
||||
and l3.l_receiptdate > l3.l_commitdate
|
||||
)
|
||||
and s_nationkey = n_nationkey
|
||||
and n_name = 'INDIA'
|
||||
group by
|
||||
s_name
|
||||
order by
|
||||
numwait desc,
|
||||
s_name
|
||||
fetch first 100 rows only;
|
||||
~~~~
|
||||
|
||||
Output from the simple-sql-parser pretty printer:
|
||||
|
||||
~~~~{.haskell sb-run='cabal run -fparserexe SimpleSQLParserTool -- format website/tpch21.sql' sb-cwd='..'}
|
||||
select s_name, count(*) as numwait
|
||||
from supplier,
|
||||
lineitem as l1,
|
||||
orders,
|
||||
nation
|
||||
where s_suppkey = l1.l_suppkey
|
||||
and o_orderkey = l1.l_orderkey
|
||||
and o_orderstatus = 'F'
|
||||
and l1.l_receiptdate > l1.l_commitdate
|
||||
and exists (select *
|
||||
from lineitem as l2
|
||||
where l2.l_orderkey = l1.l_orderkey
|
||||
and l2.l_suppkey <> l1.l_suppkey)
|
||||
and not exists (select *
|
||||
from lineitem as l3
|
||||
where l3.l_orderkey = l1.l_orderkey
|
||||
and l3.l_suppkey <> l1.l_suppkey
|
||||
and l3.l_receiptdate > l3.l_commitdate)
|
||||
and s_nationkey = n_nationkey
|
||||
and n_name = 'INDIA'
|
||||
group by s_name
|
||||
order by numwait desc, s_name
|
||||
fetch first 100 rows only;
|
||||
|
||||
~~~~
|
||||
|
||||
# Supported SQL overview
|
||||
|
||||
* query expressions
|
||||
* select lists
|
||||
* from clause
|
||||
* where clause
|
||||
* group by clause
|
||||
* having clause
|
||||
* order by clause
|
||||
* offset and fetch
|
||||
* set operators
|
||||
* common table expressions
|
||||
* wide range of scalar expressions
|
||||
* DDL (ansi dialect)
|
||||
* create, drop schema
|
||||
* create, alter, drop table
|
||||
* create, drop view
|
||||
* create, alter, drop domain
|
||||
* create, drop assertion
|
||||
* create, alter, drop sequence
|
||||
* non-query DML
|
||||
* delete
|
||||
* truncate
|
||||
* insert
|
||||
* update
|
||||
* Access control
|
||||
* grant, revoke - permissions and roles
|
||||
* create, drop role
|
||||
* Transaction management
|
||||
* begin, commit, rollback, savepoints
|
||||
|
||||
See the [supported_sql.html](supported_sql.html) page for details on the supported SQL.
|
||||
|
||||
Here is all the [test_cases.html](test_cases.html) rendered in a webpage so you can get
|
||||
an idea of what it supports, and what various instances of SQL parse to.
|
||||
|
||||
# Installation
|
||||
|
||||
This package is on hackage, use it in the usual way. You can install
|
||||
the SimpleSQLParserTool demo exe using:
|
||||
|
||||
~~~~
|
||||
cabal install -fparserexe simple-sql-parser
|
||||
~~~~
|
||||
|
||||
# Reporting bugs
|
||||
|
||||
Please report bugs here: <https://github.com/JakeWheat/simple-sql-parser/issues>
|
||||
|
||||
A good bug report (or feature request) should have an example of the
|
||||
SQL which is failing. You can expect bugs to get fixed.
|
||||
|
||||
Feature requests are welcome, but be aware that there is no-one
|
||||
generally available to work on these, so you should either make a pull
|
||||
request, or find someone willing to implement the features and make a
|
||||
pull request.
|
||||
|
||||
There is a related tutorial on implementing a SQL parser here:
|
||||
<http://jakewheat.github.io/intro_to_parsing/> (TODO: this is out of
|
||||
date, in the process of being updated)
|
||||
|
||||
# Modifying the library
|
||||
|
||||
Get the latest development version:
|
||||
|
||||
~~~~
|
||||
git clone https://github.com/JakeWheat/simple-sql-parser.git
|
||||
cd simple-sql-parser
|
||||
cabal build
|
||||
~~~~
|
||||
|
||||
You can run the tests using cabal:
|
||||
|
||||
~~~~
|
||||
cabal test
|
||||
~~~~
|
||||
|
||||
Or use the makefile target
|
||||
|
||||
~~~~
|
||||
make test
|
||||
~~~~
|
||||
|
||||
When you add support for new syntax: add some tests. If you modify or
|
||||
fix something, and it doesn't have tests, add some. If the syntax
|
||||
isn't in ANSI SQL, guard it behind a dialect flag. If you write
|
||||
support for a dialect that isn't mention, add a new dialect.
|
||||
|
||||
Make sure all the tests still pass, then send a pull request on Github.
|
||||
|
||||
# Links
|
||||
|
||||
* Haddock: [haddock/index.html](haddock/index.html)
|
||||
* Supported SQL: [supported_sql.html](supported_sql.html)
|
||||
* Test cases: [test_cases.html](test_cases.html)
|
||||
* Homepage: <http://jakewheat.github.io/simple-sql-parser/latest>
|
||||
* Hackage: <http://hackage.haskell.org/package/simple-sql-parser>
|
||||
* Source repository: <https://github.com/JakeWheat/simple-sql-parser>
|
||||
* Bug tracker: <https://github.com/JakeWheat/simple-sql-parser/issues>
|
||||
* Changes: <https://github.com/JakeWheat/simple-sql-parser/blob/master/changelog>
|
||||
* Other versions: <http://jakewheat.github.io/simple-sql-parser/>
|
||||
* Contact: jakewheat@tutanota.com
|
||||
|
||||
The simple-sql-parser is a lot less simple than it used to be. If you
|
||||
just need to parse much simpler SQL than this, or want to start with a
|
||||
simpler parser and modify it slightly, you could also look at the
|
||||
basic query parser in the intro_to_parsing project, the code is here:
|
||||
<https://github.com/JakeWheat/intro_to_parsing/blob/master/SimpleSQLQueryParser0.lhs>
|
||||
(TODO: this is out of date, in the process of being updated).
|
228
website/main.css
228
website/main.css
|
@ -1,138 +1,116 @@
|
|||
h1, h2 {
|
||||
display:block;
|
||||
background-color: #f0f0f0;
|
||||
border-top: thin #c0c0c0 solid;
|
||||
/*position:relative;*/
|
||||
padding-left:1ex;
|
||||
/*z-index: -10;*/
|
||||
}
|
||||
h1 {
|
||||
font-size: x-large;
|
||||
/*left: -3ex;*/
|
||||
margin-top: 3ex;
|
||||
/*width: 100%;*/
|
||||
}
|
||||
h2 {
|
||||
font-size: large;
|
||||
/*left: -1.5ex;*/
|
||||
margin-top: 1.5ex;
|
||||
/*width: 100%;*/
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0 auto;
|
||||
|
||||
hyphens: auto;
|
||||
overflow-wrap: break-word;
|
||||
text-rendering: optimizeLegibility;
|
||||
font-kerning: normal;
|
||||
color:#000000;
|
||||
|
||||
margin-left: 5em;
|
||||
margin-right: 5em;
|
||||
margin-bottom: 5em;
|
||||
margin-top: 2em;
|
||||
|
||||
left:auto;
|
||||
right:0;
|
||||
margin-right:30em;
|
||||
|
||||
max-width: 120ex;
|
||||
|
||||
}
|
||||
|
||||
pre {
|
||||
padding: 1em;
|
||||
background:#fafafa;
|
||||
}
|
||||
|
||||
code {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size:15px;
|
||||
}
|
||||
|
||||
#TOC {
|
||||
float:right;
|
||||
z-index:10;
|
||||
background-color: #f0f0f0;
|
||||
border: thin #c0c0c0 solid;
|
||||
padding:2ex;
|
||||
}
|
||||
.header {
|
||||
/*position:relative;
|
||||
left: -4ex;*/
|
||||
border-top: thin #c0c0c0 solid;
|
||||
border-bottom: thin #c0c0c0 solid;
|
||||
display:inline;
|
||||
padding: 1ex;
|
||||
background-color: #f0f0f0;
|
||||
font-weight: bold;
|
||||
}
|
||||
.footer {
|
||||
text-align: center;
|
||||
font-size: small;
|
||||
}
|
||||
pre {
|
||||
padding: 0.5ex;
|
||||
}
|
||||
|
||||
|
||||
pre {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
/*
|
||||
.SqlPostgresql pre.sourceCode {
|
||||
padding: 0.5em;
|
||||
background-color: #f0f6f6;
|
||||
}
|
||||
.sql pre.sourceCode {
|
||||
padding: 0.5em;
|
||||
background-color: #f0f6f6;
|
||||
}
|
||||
.GeneratedSql .SqlPostgresql pre.sourceCode, .SqlPostgresql .GeneratedSql pre.sourceCode {
|
||||
padding: 0.5em;
|
||||
background-color: #f0f6e0;
|
||||
}
|
||||
.UnusedSql .SqlPostgresql pre.sourceCode, .SqlPostgresql .UnusedSql pre.sourceCode {
|
||||
padding: 0.5em;
|
||||
background-color: #e9e9e9;
|
||||
}
|
||||
.haskell,.Haskell pre.sourceCode {
|
||||
background-color: #f5f5d9;
|
||||
}
|
||||
|
||||
.sh pre.sourceCode {
|
||||
padding: 0.5em;
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
*/
|
||||
table, tr, td {
|
||||
border-collapse:collapse;
|
||||
cell-padding:2px;
|
||||
cell-spacing:2px;
|
||||
/* padding:2px
|
||||
spacing:2px
|
||||
margin:2px*/
|
||||
vertical-align:top;
|
||||
}
|
||||
td pre {
|
||||
width: 98%;
|
||||
height: 98%;
|
||||
vertical-align:top;
|
||||
}
|
||||
table {
|
||||
width:100%;
|
||||
table-layout:fixed;
|
||||
}
|
||||
td {
|
||||
width: 50%;
|
||||
vertical-align:top;
|
||||
position:fixed;
|
||||
width:25em;
|
||||
left:0;
|
||||
top:0;
|
||||
z-index:1000;
|
||||
height:100%;
|
||||
overflow:auto;
|
||||
}
|
||||
hr {
|
||||
border: 0;
|
||||
color: black;
|
||||
background-color: black;
|
||||
height: 1px;
|
||||
width: 75%;
|
||||
|
||||
left:auto;
|
||||
right:0;
|
||||
|
||||
border-top: 1px solid #858585;
|
||||
border-right-width: 0;
|
||||
border-left: 1px solid #858585;
|
||||
|
||||
margin-top: 0 !important;
|
||||
background: #fafafa;
|
||||
|
||||
border-top-width: 0 !important;
|
||||
border-bottom-width: 0 !important;
|
||||
|
||||
padding-top: 0em;
|
||||
padding-right: 1em;
|
||||
padding-bottom: 1.25em;
|
||||
padding-left: 1em;
|
||||
margin: 0;
|
||||
|
||||
font-size: .9em;
|
||||
font-family:"Noto Serif","Open Sans","DejaVu Sans",sans-serif;
|
||||
font-style: normal;
|
||||
color: #000000;
|
||||
font-weight: 400;
|
||||
|
||||
}
|
||||
|
||||
.tablediv {
|
||||
width:100%;
|
||||
|
||||
#TOC li {
|
||||
list-style: none;
|
||||
line-height:1.3334;
|
||||
margin-top:.3334em
|
||||
}
|
||||
|
||||
/* higlighting kate */
|
||||
#TOC ul {
|
||||
padding-left: 1.3em;
|
||||
|
||||
}
|
||||
#TOC a:not(:hover) {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
h1,h2,h3,h4,h5,h6 {
|
||||
font-family:"Open Sans","DejaVu Sans",sans-serif;
|
||||
font-weight:300;
|
||||
font-style:normal;
|
||||
color:#000000;
|
||||
text-rendering:optimizeLegibility;
|
||||
margin-top:1em;
|
||||
margin-bottom:.5em;
|
||||
line-height:1.0125em
|
||||
}
|
||||
|
||||
h1 {
|
||||
border-top: 1px solid #858585;
|
||||
padding-top:1em;
|
||||
}
|
||||
|
||||
.title {
|
||||
color:#000000;
|
||||
font-size: 3em;
|
||||
border-top: none;
|
||||
padding-top:0em;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight:400;
|
||||
font-style:normal;
|
||||
color: #05117f;
|
||||
}
|
||||
|
||||
hr{border:solid #858585;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em;height:0}
|
||||
|
||||
table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode, table.sourceCode pre
|
||||
{ /*margin: 2; padding: 2; border: 2; */ vertical-align: baseline; border: none; }
|
||||
td.lineNumbers { border-right: 1px solid #AAAAAA; text-align: right; color: #AAAAAA; padding-right: 5px; padding-left: 5px; }
|
||||
td.sourceCode { padding-left: 5px; }
|
||||
pre.sourceCode { }
|
||||
pre.sourceCode span.Normal { }
|
||||
pre.sourceCode span.Keyword { color: #007020; font-weight: bold; }
|
||||
pre.sourceCode span.DataType { color: #902000; }
|
||||
pre.sourceCode span.DecVal { color: #40a070; }
|
||||
pre.sourceCode span.BaseN { color: #40a070; }
|
||||
pre.sourceCode span.Float { color: #40a070; }
|
||||
pre.sourceCode span.Char { color: #4070a0; }
|
||||
pre.sourceCode span.String { color: #4070a0; }
|
||||
pre.sourceCode span.Comment { color: #60a0b0; font-style: italic; }
|
||||
pre.sourceCode span.Others { color: #007020; }
|
||||
pre.sourceCode span.Alert { color: red; font-weight: bold; }
|
||||
pre.sourceCode span.Function { color: #06287e; }
|
||||
pre.sourceCode span.RegionMarker { }
|
||||
pre.sourceCode span.Error { color: red; font-weight: bold; }
|
||||
|
|
130
website/main1.css
Normal file
130
website/main1.css
Normal file
|
@ -0,0 +1,130 @@
|
|||
|
||||
body {
|
||||
margin: 0 auto;
|
||||
|
||||
hyphens: auto;
|
||||
overflow-wrap: break-word;
|
||||
text-rendering: optimizeLegibility;
|
||||
font-kerning: normal;
|
||||
color:#000000;
|
||||
|
||||
margin-left: 5em;
|
||||
margin-right: 5em;
|
||||
margin-bottom: 5em;
|
||||
margin-top: 2em;
|
||||
|
||||
/*left:auto;
|
||||
right:0;
|
||||
margin-right:30em;*/
|
||||
|
||||
/*max-width: 120ex;*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
pre {
|
||||
padding: 1em;
|
||||
background:#fafafa;
|
||||
}
|
||||
|
||||
code {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size:15px;
|
||||
}
|
||||
|
||||
#TOC {
|
||||
/*position:fixed;
|
||||
width:25em;
|
||||
left:0;
|
||||
top:0;
|
||||
z-index:1000;
|
||||
height:100%;
|
||||
overflow:auto;
|
||||
|
||||
left:auto;
|
||||
right:0;
|
||||
|
||||
border-top: 1px solid #858585;
|
||||
border-right-width: 0;
|
||||
border-left: 1px solid #858585;
|
||||
|
||||
margin-top: 0 !important;
|
||||
background: #fafafa;
|
||||
|
||||
border-top-width: 0 !important;
|
||||
border-bottom-width: 0 !important;
|
||||
|
||||
padding-top: 0em;
|
||||
padding-right: 1em;
|
||||
padding-bottom: 1.25em;
|
||||
padding-left: 1em;
|
||||
margin: 0;*/
|
||||
|
||||
font-size: .9em;
|
||||
font-family:"Noto Serif","Open Sans","DejaVu Sans",sans-serif;
|
||||
font-style: normal;
|
||||
color: #000000;
|
||||
font-weight: 400;
|
||||
|
||||
}
|
||||
|
||||
|
||||
#TOC li {
|
||||
list-style: none;
|
||||
line-height:1.3334;
|
||||
margin-top:.3334em
|
||||
}
|
||||
|
||||
#TOC ul {
|
||||
padding-left: 1.3em;
|
||||
|
||||
}
|
||||
#TOC a:not(:hover) {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
h1,h2,h3,h4,h5,h6 {
|
||||
font-family:"Open Sans","DejaVu Sans",sans-serif;
|
||||
font-weight:300;
|
||||
font-style:normal;
|
||||
color:#000000;
|
||||
text-rendering:optimizeLegibility;
|
||||
margin-top:1em;
|
||||
margin-bottom:.5em;
|
||||
line-height:1.0125em
|
||||
}
|
||||
|
||||
/*h1 {
|
||||
border-top: 1px solid #858585;
|
||||
padding-top:1em;
|
||||
}*/
|
||||
|
||||
.title {
|
||||
color:#000000;
|
||||
font-size: 3em;
|
||||
border-top: none;
|
||||
padding-top:0em;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight:400;
|
||||
font-style:normal;
|
||||
color: #05117f;
|
||||
}
|
||||
|
||||
hr{border:solid #858585;border-width:1px 0 0;clear:both;margin:1.25em 0 1.1875em;height:0}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
td {
|
||||
width: 50%;
|
||||
vertical-align: top;
|
||||
border:solid #c5c5c5;
|
||||
border-width:1px;
|
||||
}
|
|
@ -1,546 +0,0 @@
|
|||
/* @group Fundamentals */
|
||||
|
||||
* { margin: 0; padding: 0 }
|
||||
|
||||
/* Is this portable? */
|
||||
html {
|
||||
background-color: white;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
background: white;
|
||||
color: black;
|
||||
text-align: left;
|
||||
min-height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0.8em 0;
|
||||
}
|
||||
|
||||
ul, ol {
|
||||
margin: 0.8em 0 0.8em 2em;
|
||||
}
|
||||
|
||||
dl {
|
||||
margin: 0.8em 0;
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: bold;
|
||||
}
|
||||
dd {
|
||||
margin-left: 2em;
|
||||
}
|
||||
|
||||
a { text-decoration: none; }
|
||||
a[href]:link { color: rgb(196,69,29); }
|
||||
a[href]:visited { color: rgb(171,105,84); }
|
||||
a[href]:hover { text-decoration:underline; }
|
||||
|
||||
/* @end */
|
||||
|
||||
/* @group Fonts & Sizes */
|
||||
|
||||
/* Basic technique & IE workarounds from YUI 3
|
||||
For reasons, see:
|
||||
http://yui.yahooapis.com/3.1.1/build/cssfonts/fonts.css
|
||||
*/
|
||||
|
||||
body {
|
||||
font:13px/1.4 sans-serif;
|
||||
*font-size:small; /* for IE */
|
||||
*font:x-small; /* for IE in quirks mode */
|
||||
}
|
||||
|
||||
h1 { font-size: 146.5%; /* 19pt */ }
|
||||
h2 { font-size: 131%; /* 17pt */ }
|
||||
h3 { font-size: 116%; /* 15pt */ }
|
||||
h4 { font-size: 100%; /* 13pt */ }
|
||||
h5 { font-size: 100%; /* 13pt */ }
|
||||
|
||||
select, input, button, textarea {
|
||||
font:99% sans-serif;
|
||||
}
|
||||
|
||||
table {
|
||||
font-size:inherit;
|
||||
font:100%;
|
||||
}
|
||||
|
||||
pre, code, kbd, samp, tt, .src {
|
||||
font-family:monospace;
|
||||
*font-size:108%;
|
||||
line-height: 124%;
|
||||
}
|
||||
|
||||
.links, .link {
|
||||
font-size: 85%; /* 11pt */
|
||||
}
|
||||
|
||||
#module-header .caption {
|
||||
font-size: 182%; /* 24pt */
|
||||
}
|
||||
|
||||
.info {
|
||||
font-size: 85%; /* 11pt */
|
||||
}
|
||||
|
||||
#table-of-contents, #synopsis {
|
||||
/* font-size: 85%; /* 11pt */
|
||||
}
|
||||
|
||||
|
||||
/* @end */
|
||||
|
||||
/* @group Common */
|
||||
|
||||
.caption, h1, h2, h3, h4, h5, h6 {
|
||||
font-weight: bold;
|
||||
color: rgb(78,98,114);
|
||||
margin: 0.8em 0 0.4em;
|
||||
}
|
||||
|
||||
* + h1, * + h2, * + h3, * + h4, * + h5, * + h6 {
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
h1 + h2, h2 + h3, h3 + h4, h4 + h5, h5 + h6 {
|
||||
margin-top: inherit;
|
||||
}
|
||||
|
||||
ul.links {
|
||||
list-style: none;
|
||||
text-align: left;
|
||||
float: right;
|
||||
display: inline-table;
|
||||
margin: 0 0 0 1em;
|
||||
}
|
||||
|
||||
ul.links li {
|
||||
display: inline;
|
||||
border-left: 1px solid #d5d5d5;
|
||||
white-space: nowrap;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
ul.links li a {
|
||||
padding: 0.2em 0.5em;
|
||||
}
|
||||
|
||||
.hide { display: none; }
|
||||
.show { display: inherit; }
|
||||
.clear { clear: both; }
|
||||
|
||||
.collapser {
|
||||
background-image: url(minus.gif);
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
.expander {
|
||||
background-image: url(plus.gif);
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
p.caption.collapser,
|
||||
p.caption.expander {
|
||||
background-position: 0 0.4em;
|
||||
}
|
||||
.collapser, .expander {
|
||||
padding-left: 14px;
|
||||
margin-left: -14px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
pre {
|
||||
padding: 0.25em;
|
||||
margin: 0.8em 0;
|
||||
background: rgb(229,237,244);
|
||||
overflow: auto;
|
||||
border-bottom: 0.25em solid white;
|
||||
/* white border adds some space below the box to compensate
|
||||
for visual extra space that paragraphs have between baseline
|
||||
and the bounding box */
|
||||
}
|
||||
|
||||
.src {
|
||||
background: #f0f0f0;
|
||||
padding: 0.2em 0.5em;
|
||||
}
|
||||
|
||||
.keyword { font-weight: normal; }
|
||||
.def { font-weight: bold; }
|
||||
|
||||
|
||||
/* @end */
|
||||
|
||||
/* @group Page Structure */
|
||||
|
||||
#content {
|
||||
margin: 0 auto;
|
||||
padding: 0 2em 6em;
|
||||
}
|
||||
|
||||
#package-header {
|
||||
background: rgb(41,56,69);
|
||||
border-top: 5px solid rgb(78,98,114);
|
||||
color: #ddd;
|
||||
padding: 0.2em;
|
||||
position: relative;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#package-header .caption {
|
||||
background: url(hslogo-16.png) no-repeat 0em;
|
||||
color: white;
|
||||
margin: 0 2em;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
padding-left: 2em;
|
||||
}
|
||||
|
||||
#package-header a:link, #package-header a:visited { color: white; }
|
||||
#package-header a:hover { background: rgb(78,98,114); }
|
||||
|
||||
#module-header .caption {
|
||||
color: rgb(78,98,114);
|
||||
font-weight: bold;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
table.info {
|
||||
float: right;
|
||||
padding: 0.5em 1em;
|
||||
border: 1px solid #ddd;
|
||||
color: rgb(78,98,114);
|
||||
background-color: #fff;
|
||||
max-width: 40%;
|
||||
border-spacing: 0;
|
||||
position: relative;
|
||||
top: -0.5em;
|
||||
margin: 0 0 0 2em;
|
||||
}
|
||||
|
||||
.info th {
|
||||
padding: 0 1em 0 0;
|
||||
}
|
||||
|
||||
div#style-menu-holder {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
#style-menu {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
overflow: visible;
|
||||
background: #374c5e;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
right: 0;
|
||||
padding: 0;
|
||||
top: 1.25em;
|
||||
}
|
||||
|
||||
#style-menu li {
|
||||
display: list-item;
|
||||
border-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: #000;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
#style-menu li + li {
|
||||
border-top: 1px solid #919191;
|
||||
}
|
||||
|
||||
#style-menu a {
|
||||
width: 6em;
|
||||
padding: 3px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
#footer {
|
||||
background: #ddd;
|
||||
border-top: 1px solid #aaa;
|
||||
padding: 0.5em 0;
|
||||
color: #666;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 3em;
|
||||
}
|
||||
|
||||
/* @end */
|
||||
|
||||
/* @group Front Matter */
|
||||
|
||||
#table-of-contents {
|
||||
float: right;
|
||||
clear: right;
|
||||
background: #faf9dc;
|
||||
border: 1px solid #d8d7ad;
|
||||
padding: 0.5em 1em;
|
||||
max-width: 20em;
|
||||
margin: 0.5em 0 1em 1em;
|
||||
}
|
||||
|
||||
#table-of-contents .caption {
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#table-of-contents ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#table-of-contents ul ul {
|
||||
margin-left: 2em;
|
||||
}
|
||||
|
||||
#description .caption {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#synopsis {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.no-frame #synopsis {
|
||||
display: block;
|
||||
position: fixed;
|
||||
right: 0;
|
||||
height: 80%;
|
||||
top: 10%;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#synopsis .caption {
|
||||
float: left;
|
||||
width: 29px;
|
||||
color: rgba(255,255,255,0);
|
||||
height: 110px;
|
||||
margin: 0;
|
||||
font-size: 1px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#synopsis p.caption.collapser {
|
||||
background: url(synopsis.png) no-repeat -64px -8px;
|
||||
}
|
||||
|
||||
#synopsis p.caption.expander {
|
||||
background: url(synopsis.png) no-repeat 0px -8px;
|
||||
}
|
||||
|
||||
#synopsis ul {
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
padding: 0.5em;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#synopsis ul ul {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#synopsis ul,
|
||||
#synopsis ul li.src {
|
||||
background-color: #faf9dc;
|
||||
white-space: nowrap;
|
||||
list-style: none;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
/* @end */
|
||||
|
||||
/* @group Main Content */
|
||||
|
||||
#interface div.top { margin: 2em 0; }
|
||||
#interface h1 + div.top,
|
||||
#interface h2 + div.top,
|
||||
#interface h3 + div.top,
|
||||
#interface h4 + div.top,
|
||||
#interface h5 + div.top {
|
||||
margin-top: 1em;
|
||||
}
|
||||
#interface p.src .link {
|
||||
float: right;
|
||||
color: #919191;
|
||||
border-left: 1px solid #919191;
|
||||
background: #f0f0f0;
|
||||
padding: 0 0.5em 0.2em;
|
||||
margin: 0 -0.5em 0 0.5em;
|
||||
}
|
||||
|
||||
#interface table { border-spacing: 2px; }
|
||||
#interface td {
|
||||
vertical-align: top;
|
||||
padding-left: 0.5em;
|
||||
}
|
||||
#interface td.src {
|
||||
white-space: nowrap;
|
||||
}
|
||||
#interface td.doc p {
|
||||
margin: 0;
|
||||
}
|
||||
#interface td.doc p + p {
|
||||
margin-top: 0.8em;
|
||||
}
|
||||
|
||||
.subs dl {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.subs dt {
|
||||
float: left;
|
||||
clear: left;
|
||||
display: block;
|
||||
margin: 1px 0;
|
||||
}
|
||||
|
||||
.subs dd {
|
||||
float: right;
|
||||
width: 90%;
|
||||
display: block;
|
||||
padding-left: 0.5em;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.subs dd.empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.subs dd p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.top p.src {
|
||||
border-top: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.subs, .doc {
|
||||
/* use this selector for one level of indent */
|
||||
padding-left: 2em;
|
||||
}
|
||||
|
||||
.warning {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.arguments {
|
||||
margin-top: -0.4em;
|
||||
}
|
||||
.arguments .caption {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.fields { padding-left: 1em; }
|
||||
|
||||
.fields .caption { display: none; }
|
||||
|
||||
.fields p { margin: 0 0; }
|
||||
|
||||
/* this seems bulky to me
|
||||
.methods, .constructors {
|
||||
background: #f8f8f8;
|
||||
border: 1px solid #eee;
|
||||
}
|
||||
*/
|
||||
|
||||
/* @end */
|
||||
|
||||
/* @group Auxillary Pages */
|
||||
|
||||
#mini {
|
||||
margin: 0 auto;
|
||||
padding: 0 1em 1em;
|
||||
}
|
||||
|
||||
#mini > * {
|
||||
font-size: 93%; /* 12pt */
|
||||
}
|
||||
|
||||
#mini #module-list .caption,
|
||||
#mini #module-header .caption {
|
||||
font-size: 125%; /* 15pt */
|
||||
}
|
||||
|
||||
#mini #interface h1,
|
||||
#mini #interface h2,
|
||||
#mini #interface h3,
|
||||
#mini #interface h4 {
|
||||
font-size: 109%; /* 13pt */
|
||||
margin: 1em 0 0;
|
||||
}
|
||||
|
||||
#mini #interface .top,
|
||||
#mini #interface .src {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#mini #module-list ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#alphabet ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0.5em 0 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#alphabet li {
|
||||
display: inline;
|
||||
margin: 0 0.25em;
|
||||
}
|
||||
|
||||
#alphabet a {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#index .caption,
|
||||
#module-list .caption { font-size: 131%; /* 17pt */ }
|
||||
|
||||
#index table {
|
||||
margin-left: 2em;
|
||||
}
|
||||
|
||||
#index .src {
|
||||
font-weight: bold;
|
||||
}
|
||||
#index .alt {
|
||||
font-size: 77%; /* 10pt */
|
||||
font-style: italic;
|
||||
padding-left: 2em;
|
||||
}
|
||||
|
||||
#index td + td {
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
#module-list ul {
|
||||
list-style: none;
|
||||
margin: 0 0 0 2em;
|
||||
}
|
||||
|
||||
#module-list li {
|
||||
clear: right;
|
||||
}
|
||||
|
||||
#module-list span.collapser,
|
||||
#module-list span.expander {
|
||||
background-position: 0 0.3em;
|
||||
}
|
||||
|
||||
#module-list .package {
|
||||
float: right;
|
||||
}
|
||||
|
||||
/* @end */
|
49
website/render-test-cases.cabal
Normal file
49
website/render-test-cases.cabal
Normal file
|
@ -0,0 +1,49 @@
|
|||
cabal-version: 2.2
|
||||
|
||||
name: simple-sql-parser
|
||||
version: 0.7.0
|
||||
|
||||
executable RenderTestCases
|
||||
main-is: RenderTestCases.hs
|
||||
hs-source-dirs: .,..,../tests
|
||||
Build-Depends: base >=4 && <5,
|
||||
text,
|
||||
megaparsec,
|
||||
prettyprinter,
|
||||
parser-combinators,
|
||||
mtl,
|
||||
containers,
|
||||
tasty,
|
||||
tasty-hunit,
|
||||
pretty-show,
|
||||
default-language: Haskell2010
|
||||
ghc-options: -Wall -O0
|
||||
|
||||
other-modules:
|
||||
Language.SQL.SimpleSQL.CreateIndex
|
||||
Language.SQL.SimpleSQL.CustomDialect
|
||||
Language.SQL.SimpleSQL.Dialect
|
||||
Language.SQL.SimpleSQL.EmptyStatement
|
||||
Language.SQL.SimpleSQL.FullQueries
|
||||
Language.SQL.SimpleSQL.GroupBy
|
||||
Language.SQL.SimpleSQL.Lex
|
||||
Language.SQL.SimpleSQL.LexerTests
|
||||
Language.SQL.SimpleSQL.MySQL
|
||||
Language.SQL.SimpleSQL.Odbc
|
||||
Language.SQL.SimpleSQL.Oracle
|
||||
Language.SQL.SimpleSQL.Parse
|
||||
Language.SQL.SimpleSQL.Postgres
|
||||
Language.SQL.SimpleSQL.Pretty
|
||||
Language.SQL.SimpleSQL.QueryExprComponents
|
||||
Language.SQL.SimpleSQL.QueryExprs
|
||||
Language.SQL.SimpleSQL.SQL2011AccessControl
|
||||
Language.SQL.SimpleSQL.SQL2011Bits
|
||||
Language.SQL.SimpleSQL.SQL2011DataManipulation
|
||||
Language.SQL.SimpleSQL.SQL2011Queries
|
||||
Language.SQL.SimpleSQL.SQL2011Schema
|
||||
Language.SQL.SimpleSQL.ScalarExprs
|
||||
Language.SQL.SimpleSQL.Syntax
|
||||
Language.SQL.SimpleSQL.TableRefs
|
||||
Language.SQL.SimpleSQL.TestTypes
|
||||
Language.SQL.SimpleSQL.Tests
|
||||
Language.SQL.SimpleSQL.Tpch
|
|
@ -1,185 +0,0 @@
|
|||
|
||||
:toc: right
|
||||
:sectnums:
|
||||
:toclevels: 10
|
||||
:source-highlighter: pygments
|
||||
|
||||
= simple-sql-parser supported SQL
|
||||
|
||||
== Overview
|
||||
|
||||
This page has more details on the supported SQL in simple-sql-parser.
|
||||
|
||||
See the link:test_cases.html[simple-sql-parser test cases] page for
|
||||
examples.
|
||||
|
||||
The target dialect of SQL at this time is ISO/ANSI SQL:2011. The
|
||||
parser supports queries, DDL, non-query DML, access control and
|
||||
transaction management syntax. The parser and syntax does not follow
|
||||
the standard grammar closely - they permit a lot of things which the
|
||||
grammar in the standard forbids. The intended usage is that an
|
||||
additional pass over the ast can be made if you want to carefully
|
||||
prohibit everything that the standard doesn't allow.
|
||||
|
||||
Apart from this permissiveness, some work has been put into trying to
|
||||
get good parser error messages.
|
||||
|
||||
== Queries
|
||||
|
||||
=== Select lists
|
||||
|
||||
Supports scalar expressions, aliases with optional 'as'.
|
||||
|
||||
Doesn't support 'select * as (a,b,c) from t' yet.
|
||||
|
||||
=== Set quantifiers on select
|
||||
|
||||
Supports 'select distinct' and explicit 'select all'.
|
||||
|
||||
=== From clause
|
||||
|
||||
* aliases
|
||||
* subqueries
|
||||
* functions
|
||||
* joins
|
||||
- natural
|
||||
- inner
|
||||
- left/right/full outer
|
||||
- cross
|
||||
- on expressions
|
||||
- using lists
|
||||
- lateral
|
||||
|
||||
=== Group by clause
|
||||
|
||||
Supports scalar expressions, group by (), cube, rollup, grouping
|
||||
parentheses and grouping sets with nested grouping expressions.
|
||||
|
||||
=== Order by clause
|
||||
|
||||
Supports scalar expressions, asc/desc and nulls first/last.
|
||||
|
||||
=== Offset and fetch
|
||||
|
||||
Supports 'offset n rows' and 'fetch first n rows only'.
|
||||
|
||||
=== Set operators
|
||||
|
||||
Union, except, intersect + all/distinct and corresponding.
|
||||
|
||||
=== Table value constructor
|
||||
|
||||
For example: values (1,2),(3,4).
|
||||
|
||||
=== Explicit table
|
||||
|
||||
For example: 'table t', which is shorthand for 'select * from t'.
|
||||
|
||||
=== Scalar expressions
|
||||
|
||||
The scalar expressions type and parser is used in many contexts,
|
||||
including:
|
||||
|
||||
* select lists;
|
||||
* where clause expressions;
|
||||
* group by clause expressions;
|
||||
* having clause expressions;
|
||||
* order by clause expressions;
|
||||
* offset and fetch clause expressions;
|
||||
* table value constructors.
|
||||
|
||||
This doesn't exactly follow the ANSI Standards, which have separate
|
||||
grammars for most of these.
|
||||
|
||||
The supported scalar expressions include:
|
||||
|
||||
* basic string literals in single quotes
|
||||
* number literals: digits.digitse+-exp
|
||||
* explicitly typed literal, e.g. int '3'
|
||||
* binary operators
|
||||
- comparisons: = != <> <= >= < >
|
||||
- arithmetic: + - / * % ^
|
||||
- logic: and, or
|
||||
- bitwise: & | (and ^ as above)
|
||||
- string: ||, like, not like
|
||||
- other: overlaps, is similar to, is not similar too, is distinct
|
||||
from, is not distinct from
|
||||
* prefix unary operators
|
||||
- +, -
|
||||
- not
|
||||
- ~
|
||||
* postfix unary
|
||||
- is null, is not null
|
||||
- is true, is not true, is false, is not false, is unknown, is not unknown
|
||||
* other operators
|
||||
- extract (extract(day from dt))
|
||||
- position (position string1 in string2)
|
||||
- substring (substring(x from 2 for 4))
|
||||
- convert (convert(string using conversion))
|
||||
- translate (translate(string using translation))
|
||||
- overlay (overlay (string placing embedded_string from start for
|
||||
length))
|
||||
- trim (trim(leading '_' from s))
|
||||
- between (a between 1 and 5)
|
||||
- in list (a in (1,2,3,4))
|
||||
- cast (cast(a as int))
|
||||
* subqueries
|
||||
- in subquery
|
||||
- any/some/all
|
||||
- exists
|
||||
* case expressions
|
||||
* parentheses
|
||||
* quoted and unquoted identifiers
|
||||
* a.b qualified identifiers
|
||||
* \*, a.*
|
||||
* functions: f(a,b)
|
||||
* aggregates: agg(distinct a order by b)
|
||||
* window functions: sum(x) over (partition by y order by z)
|
||||
plus some explicit frame support (same as in postgres 9.3)
|
||||
* row constructors, e.g. where (a,b) = any (select a,b from t)
|
||||
* ? used in parameterized queries
|
||||
|
||||
== DDL
|
||||
|
||||
* schemas
|
||||
** create, drop + drop restrict
|
||||
|
||||
* tables
|
||||
** create table
|
||||
*** constraints: named, null, unique, primary key, foreign key (matches, on update/delete)
|
||||
*** identity (the weird ansi version), defaults
|
||||
*** defaults
|
||||
** alter table
|
||||
*** defaults, null, set data type, drop column, constraints
|
||||
** drop table + restrict
|
||||
** create, drop view
|
||||
|
||||
** create, alter, drop domain
|
||||
*** defaults, constraints
|
||||
** create, drop assertion
|
||||
** create, alter, drop sequence
|
||||
|
||||
== Non-query DML
|
||||
|
||||
** delete
|
||||
*** delete from
|
||||
*** as alias
|
||||
*** where
|
||||
** truncate
|
||||
*** with identity options
|
||||
** insert
|
||||
*** values, general queries, defaults
|
||||
** update
|
||||
*** including row updates
|
||||
|
||||
== Access Control
|
||||
|
||||
** grant privileges
|
||||
*** all, grant option, table, domain, type, sequence, role, etc.
|
||||
** revoke
|
||||
** create role, drop role
|
||||
|
||||
== Transaction management
|
||||
|
||||
* begin, commit, rollback
|
||||
* savepoints
|
175
website/supported_sql.md
Normal file
175
website/supported_sql.md
Normal file
|
@ -0,0 +1,175 @@
|
|||
# Overview
|
||||
|
||||
This page has more details on the supported SQL in simple-sql-parser.
|
||||
|
||||
See the [simple-sql-parser test cases](test_cases.html) page for
|
||||
examples.
|
||||
|
||||
The target dialect of SQL at this time is ISO/ANSI SQL:2011. The
|
||||
parser supports queries, DDL, non-query DML, access control and
|
||||
transaction management syntax. The parser and syntax does not follow
|
||||
the standard grammar closely - they permit a lot of things which the
|
||||
grammar in the standard forbids. The intended usage is that an
|
||||
additional pass over the ast can be made if you want to carefully
|
||||
prohibit everything that the standard doesn't allow.
|
||||
|
||||
Apart from this permissiveness, some work has been put into trying to
|
||||
get good parser error messages.
|
||||
|
||||
# Queries
|
||||
|
||||
## Select lists
|
||||
|
||||
Supports scalar expressions, aliases with optional 'as'.
|
||||
|
||||
## Set quantifiers on select
|
||||
|
||||
Supports 'select distinct' and explicit 'select all'.
|
||||
|
||||
## From clause
|
||||
|
||||
* aliases
|
||||
* subqueries
|
||||
* functions
|
||||
* joins
|
||||
- natural
|
||||
- inner
|
||||
- left/right/full outer
|
||||
- cross
|
||||
- on expressions
|
||||
- using lists
|
||||
- lateral
|
||||
|
||||
## Group by clause
|
||||
|
||||
Supports scalar expressions, group by (), cube, rollup, grouping
|
||||
parentheses and grouping sets with nested grouping expressions.
|
||||
|
||||
## Order by clause
|
||||
|
||||
Supports scalar expressions, asc/desc and nulls first/last.
|
||||
|
||||
## Offset and fetch
|
||||
|
||||
Supports 'offset n rows' and 'fetch first n rows only'.
|
||||
|
||||
## Set operators
|
||||
|
||||
Union, except, intersect + all/distinct and corresponding.
|
||||
|
||||
## Table value constructor
|
||||
|
||||
Example: 'values (1,2),(3,4)'.
|
||||
|
||||
## Explicit table
|
||||
|
||||
Example: 'table t', which is shorthand for 'select * from t'.
|
||||
|
||||
## Scalar expressions
|
||||
|
||||
The scalar expressions type and parser is used in many contexts,
|
||||
including:
|
||||
|
||||
* select lists;
|
||||
* where clause expressions;
|
||||
* group by clause expressions;
|
||||
* having clause expressions;
|
||||
* order by clause expressions;
|
||||
* offset and fetch clause expressions;
|
||||
* table value constructors.
|
||||
|
||||
This doesn't exactly follow the ANSI Standards, which have separate
|
||||
grammars for most of these.
|
||||
|
||||
The supported scalar expressions include:
|
||||
|
||||
* basic string literals in single quotes
|
||||
* number literals: digits.digitse+-exp
|
||||
* explicitly typed literal, e.g. int '3'
|
||||
* binary operators
|
||||
- comparisons: = != <> <= >= < >
|
||||
- arithmetic: + - / * % ^
|
||||
- logic: and, or
|
||||
- bitwise: & | (and ^ as above)
|
||||
- string: ||, like, not like
|
||||
- other: overlaps, is similar to, is not similar too, is distinct
|
||||
from, is not distinct from
|
||||
* prefix unary operators
|
||||
- +, -
|
||||
- not
|
||||
- ~
|
||||
* postfix unary
|
||||
- is null, is not null
|
||||
- is true, is not true, is false, is not false, is unknown, is not unknown
|
||||
* other operators
|
||||
- extract (extract(day from dt))
|
||||
- position (position string1 in string2)
|
||||
- substring (substring(x from 2 for 4))
|
||||
- convert (convert(string using conversion))
|
||||
- translate (translate(string using translation))
|
||||
- overlay (overlay (string placing embedded_string from start for
|
||||
length))
|
||||
- trim (trim(leading '_' from s))
|
||||
- between (a between 1 and 5)
|
||||
- in list (a in (1,2,3,4))
|
||||
- cast (cast(a as int))
|
||||
* subqueries
|
||||
- in subquery
|
||||
- any/some/all
|
||||
- exists
|
||||
* case expressions
|
||||
* parentheses
|
||||
* quoted and unquoted identifiers
|
||||
* a.b qualified identifiers
|
||||
* \*, a.*
|
||||
* functions: f(a,b)
|
||||
* aggregates: agg(distinct a order by b)
|
||||
* window functions: sum(x) over (partition by y order by z)
|
||||
plus some explicit frame support (same as in postgres 9.3)
|
||||
* row constructors, e.g. where (a,b) = any (select a,b from t)
|
||||
* ? used in parameterized queries
|
||||
|
||||
# DDL
|
||||
|
||||
* schemas
|
||||
* create, drop + drop restrict
|
||||
|
||||
* tables
|
||||
* create table
|
||||
* constraints: named, null, unique, primary key, foreign key (matches, on update/delete)
|
||||
* identity (the weird ansi version), defaults
|
||||
* defaults
|
||||
* alter table
|
||||
* defaults, null, set data type, drop column, constraints
|
||||
* drop table + restrict
|
||||
|
||||
* create, drop view
|
||||
* create, alter, drop domain
|
||||
* defaults, constraints
|
||||
* create, drop assertion
|
||||
* create, alter, drop sequence
|
||||
|
||||
# Non-query DML
|
||||
|
||||
* delete
|
||||
* delete from
|
||||
* as alias
|
||||
* where
|
||||
* truncate
|
||||
* with identity options
|
||||
* insert
|
||||
* values, general queries, defaults
|
||||
* update
|
||||
* including row updates
|
||||
|
||||
# Access Control
|
||||
|
||||
* grant privileges
|
||||
* all, grant option, table, domain, type, sequence, role, etc.
|
||||
* revoke
|
||||
* create role, drop role
|
||||
|
||||
# Transaction management
|
||||
|
||||
* begin, commit, rollback
|
||||
* savepoints
|
93
website/template.pandoc
Normal file
93
website/template.pandoc
Normal file
|
@ -0,0 +1,93 @@
|
|||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="$lang$" xml:lang="$lang$"$if(dir)$ dir="$dir$"$endif$>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="generator" content="pandoc" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
|
||||
$for(author-meta)$
|
||||
<meta name="author" content="$author-meta$" />
|
||||
$endfor$
|
||||
$if(date-meta)$
|
||||
<meta name="dcterms.date" content="$date-meta$" />
|
||||
$endif$
|
||||
$if(keywords)$
|
||||
<meta name="keywords" content="$for(keywords)$$keywords$$sep$, $endfor$" />
|
||||
$endif$
|
||||
$if(description-meta)$
|
||||
<meta name="description" content="$description-meta$" />
|
||||
$endif$
|
||||
<title>$if(title-prefix)$$title-prefix$ – $endif$$pagetitle$</title>
|
||||
<style>
|
||||
$styles.html()$
|
||||
</style>
|
||||
$for(css)$
|
||||
<link rel="stylesheet" href="$css$" />
|
||||
$endfor$
|
||||
$for(header-includes)$
|
||||
$header-includes$
|
||||
$endfor$
|
||||
$if(math)$
|
||||
$if(mathjax)$
|
||||
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
|
||||
$endif$
|
||||
$math$
|
||||
$endif$
|
||||
</head>
|
||||
<body>
|
||||
$for(include-before)$
|
||||
$include-before$
|
||||
$endfor$
|
||||
$if(title)$
|
||||
<header id="title-block-header">
|
||||
<h1 class="title">$title$</h1>
|
||||
$if(subtitle)$
|
||||
<p class="subtitle">$subtitle$</p>
|
||||
$endif$
|
||||
$for(author)$
|
||||
<p class="author">$author$</p>
|
||||
$endfor$
|
||||
$if(date)$
|
||||
<p class="date">$date$</p>
|
||||
$endif$
|
||||
$if(abstract)$
|
||||
<div class="abstract">
|
||||
<div class="abstract-title">$abstract-title$</div>
|
||||
$abstract$
|
||||
</div>
|
||||
$endif$
|
||||
</header>
|
||||
$endif$
|
||||
$body$
|
||||
$for(include-after)$
|
||||
$include-after$
|
||||
$endfor$
|
||||
|
||||
$if(toc)$
|
||||
<nav id="$idprefix$TOC" role="doc-toc">
|
||||
$if(toc-title)$
|
||||
<h2 id="$idprefix$toc-title">$toc-title$</h2>
|
||||
$endif$
|
||||
$table-of-contents$
|
||||
<hr />
|
||||
<h2 id="toc-title">Links</h2>
|
||||
<ul>
|
||||
<li><a href="index.html">Index</a></li>
|
||||
<li><a href='haddock/index.html'>Haddock</li>
|
||||
<li><a href="supported_sql.html">Supported SQL</a></li>
|
||||
<li><a href="test_cases.html">Test cases</a></li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li><a href="http://jakewheat.github.io/simple-sql-parser/latest">Homepage</a></li>
|
||||
<li><a href="http://hackage.haskell.org/package/simple-sql-parser">Hackage</a></li>
|
||||
<li><a href="https://github.com/JakeWheat/simple-sql-parser">Source repository</a></li>
|
||||
<li><a href="https://github.com/JakeWheat/simple-sql-parser/issues">Bug tracker</a></li>
|
||||
<li><a href="https://github.com/JakeWheat/simple-sql-parser/blob/master/changelog">Changes</a></li>
|
||||
<li><a href="http://jakewheat.github.io/simple-sql-parser/">Other versions</a></li>
|
||||
<li>jakewheat@tutanota.com</li>
|
||||
</ul>
|
||||
|
||||
</nav>
|
||||
$endif$
|
||||
|
||||
</body>
|
||||
</html>
|
76
website/template1.pandoc
Normal file
76
website/template1.pandoc
Normal file
|
@ -0,0 +1,76 @@
|
|||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" lang="$lang$" xml:lang="$lang$"$if(dir)$ dir="$dir$"$endif$>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="generator" content="pandoc" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
|
||||
$for(author-meta)$
|
||||
<meta name="author" content="$author-meta$" />
|
||||
$endfor$
|
||||
$if(date-meta)$
|
||||
<meta name="dcterms.date" content="$date-meta$" />
|
||||
$endif$
|
||||
$if(keywords)$
|
||||
<meta name="keywords" content="$for(keywords)$$keywords$$sep$, $endfor$" />
|
||||
$endif$
|
||||
$if(description-meta)$
|
||||
<meta name="description" content="$description-meta$" />
|
||||
$endif$
|
||||
<title>$if(title-prefix)$$title-prefix$ – $endif$$pagetitle$</title>
|
||||
<style>
|
||||
$styles.html()$
|
||||
</style>
|
||||
$for(css)$
|
||||
<link rel="stylesheet" href="$css$" />
|
||||
$endfor$
|
||||
$for(header-includes)$
|
||||
$header-includes$
|
||||
$endfor$
|
||||
$if(math)$
|
||||
$if(mathjax)$
|
||||
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
|
||||
$endif$
|
||||
$math$
|
||||
$endif$
|
||||
</head>
|
||||
<body>
|
||||
$if(toc)$
|
||||
<nav id="$idprefix$TOC" role="doc-toc">
|
||||
$if(toc-title)$
|
||||
<h2 id="$idprefix$toc-title">$toc-title$</h2>
|
||||
$endif$
|
||||
$table-of-contents$
|
||||
</nav>
|
||||
$endif$
|
||||
|
||||
|
||||
$for(include-before)$
|
||||
$include-before$
|
||||
$endfor$
|
||||
$if(title)$
|
||||
<header id="title-block-header">
|
||||
<h1 class="title">$title$</h1>
|
||||
$if(subtitle)$
|
||||
<p class="subtitle">$subtitle$</p>
|
||||
$endif$
|
||||
$for(author)$
|
||||
<p class="author">$author$</p>
|
||||
$endfor$
|
||||
$if(date)$
|
||||
<p class="date">$date$</p>
|
||||
$endif$
|
||||
$if(abstract)$
|
||||
<div class="abstract">
|
||||
<div class="abstract-title">$abstract-title$</div>
|
||||
$abstract$
|
||||
</div>
|
||||
$endif$
|
||||
</header>
|
||||
$endif$
|
||||
$body$
|
||||
$for(include-after)$
|
||||
$include-after$
|
||||
$endfor$
|
||||
|
||||
</body>
|
||||
</html>
|
40
website/tpch21.sql
Normal file
40
website/tpch21.sql
Normal file
|
@ -0,0 +1,40 @@
|
|||
select
|
||||
s_name,
|
||||
count(*) as numwait
|
||||
from
|
||||
supplier,
|
||||
lineitem l1,
|
||||
orders,
|
||||
nation
|
||||
where
|
||||
s_suppkey = l1.l_suppkey
|
||||
and o_orderkey = l1.l_orderkey
|
||||
and o_orderstatus = 'F'
|
||||
and l1.l_receiptdate > l1.l_commitdate
|
||||
and exists (
|
||||
select
|
||||
*
|
||||
from
|
||||
lineitem l2
|
||||
where
|
||||
l2.l_orderkey = l1.l_orderkey
|
||||
and l2.l_suppkey <> l1.l_suppkey
|
||||
)
|
||||
and not exists (
|
||||
select
|
||||
*
|
||||
from
|
||||
lineitem l3
|
||||
where
|
||||
l3.l_orderkey = l1.l_orderkey
|
||||
and l3.l_suppkey <> l1.l_suppkey
|
||||
and l3.l_receiptdate > l3.l_commitdate
|
||||
)
|
||||
and s_nationkey = n_nationkey
|
||||
and n_name = 'INDIA'
|
||||
group by
|
||||
s_name
|
||||
order by
|
||||
numwait desc,
|
||||
s_name
|
||||
fetch first 100 rows only;
|
Loading…
Reference in a new issue