diff --git a/Makefile b/Makefile
index b80b28f..c637ab7 100644
--- a/Makefile
+++ b/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
+
diff --git a/website/contributing.asciidoc b/release_checklist
similarity index 66%
rename from website/contributing.asciidoc
rename to release_checklist
index 1afe3cd..9d4d8a3 100644
--- a/website/contributing.asciidoc
+++ b/release_checklist
@@ -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.
diff --git a/tests/Filter.hs b/tests/Filter.hs
deleted file mode 100644
index 6ddc96d..0000000
--- a/tests/Filter.hs
+++ /dev/null
@@ -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
diff --git a/tests/FilterSpaces.hs b/tests/FilterSpaces.hs
deleted file mode 100644
index db1d0ca..0000000
--- a/tests/FilterSpaces.hs
+++ /dev/null
@@ -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' [] = []
-
diff --git a/tests/ShowErrors.hs b/tests/ShowErrors.hs
deleted file mode 100644
index a7b1153..0000000
--- a/tests/ShowErrors.hs
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-import Language.SQL.SimpleSQL.ErrorMessages
-
-
-main :: IO ()
-main = putStrLn $ pExprs valueExpressions queryExpressions
diff --git a/tests/SimpleSQLParserExample.hs b/tests/SimpleSQLParserExample.hs
deleted file mode 100644
index 02ad111..0000000
--- a/tests/SimpleSQLParserExample.hs
+++ /dev/null
@@ -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
diff --git a/website/AddLinks.hs b/website/AddLinks.hs
deleted file mode 100644
index 53ddcf1..0000000
--- a/website/AddLinks.hs
+++ /dev/null
@@ -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) =
- "" ++ linkSection ++ "\n" ++ xs
-addLinks (x:xs) = x : addLinks xs
-
-linkSection :: String
-linkSection =
- "
\n\
- \\n\
- \ \n\
- \\n"
diff --git a/website/RenderTestCases.hs b/website/RenderTestCases.hs
index 5c3425a..d42fd69 100644
--- a/website/RenderTestCases.hs
+++ b/website/RenderTestCases.hs
@@ -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) =
+ "\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 "\n"
+ else "")
+ <> let sql' = "\n~~~~{.sql}\n" <> sql <> "\n~~~~\n"
+ hask' = "\n~~~~{.haskell}\n" <> hask <> "\n~~~~\n"
+ in "\n" <> sql' <> " \n" <> hask' <> " \n"
+ <> go True is
+ go _t [] = "
\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
+
diff --git a/website/index.asciidoc b/website/index.asciidoc
deleted file mode 100644
index 3c9232e..0000000
--- a/website/index.asciidoc
+++ /dev/null
@@ -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).
diff --git a/website/index.md b/website/index.md
new file mode 100644
index 0000000..af37adc
--- /dev/null
+++ b/website/index.md
@@ -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:
+ .
+
+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:
+
+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:
+ (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:
+* Hackage:
+* Source repository:
+* Bug tracker:
+* Changes:
+* Other versions:
+* 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:
+
+(TODO: this is out of date, in the process of being updated).
diff --git a/website/main.css b/website/main.css
index 355afea..3755417 100644
--- a/website/main.css
+++ b/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;
+ 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;
+
}
-pre {
- background-color: #f0f0f0;
+#TOC li {
+ list-style: none;
+ line-height:1.3334;
+ margin-top:.3334em
}
-/*
-.SqlPostgresql pre.sourceCode {
- padding: 0.5em;
- background-color: #f0f6f6;
+#TOC ul {
+ padding-left: 1.3em;
+
}
-.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;
+#TOC a:not(:hover) {
+ text-decoration: none;
}
-.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;
- overflow:auto;
-}
-hr {
- border: 0;
- color: black;
- background-color: black;
- height: 1px;
- width: 75%;
+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
}
-.tablediv {
- width:100%;
+h1 {
+border-top: 1px solid #858585;
+padding-top:1em;
}
-/* higlighting kate */
+.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; }
diff --git a/website/main1.css b/website/main1.css
new file mode 100644
index 0000000..0ef65f8
--- /dev/null
+++ b/website/main1.css
@@ -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;
+}
diff --git a/website/ocean.css b/website/ocean.css
deleted file mode 100644
index 4223870..0000000
--- a/website/ocean.css
+++ /dev/null
@@ -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 */
diff --git a/website/render-test-cases.cabal b/website/render-test-cases.cabal
new file mode 100644
index 0000000..79d9a54
--- /dev/null
+++ b/website/render-test-cases.cabal
@@ -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
diff --git a/website/supported_sql.asciidoc b/website/supported_sql.asciidoc
deleted file mode 100644
index 778a317..0000000
--- a/website/supported_sql.asciidoc
+++ /dev/null
@@ -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
diff --git a/website/supported_sql.md b/website/supported_sql.md
new file mode 100644
index 0000000..0c90503
--- /dev/null
+++ b/website/supported_sql.md
@@ -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
diff --git a/website/template.pandoc b/website/template.pandoc
new file mode 100644
index 0000000..1572ead
--- /dev/null
+++ b/website/template.pandoc
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+$for(author-meta)$
+
+$endfor$
+$if(date-meta)$
+
+$endif$
+$if(keywords)$
+
+$endif$
+$if(description-meta)$
+
+$endif$
+ $if(title-prefix)$$title-prefix$ – $endif$$pagetitle$
+
+$for(css)$
+
+$endfor$
+$for(header-includes)$
+ $header-includes$
+$endfor$
+$if(math)$
+$if(mathjax)$
+
+$endif$
+ $math$
+$endif$
+
+
+$for(include-before)$
+$include-before$
+$endfor$
+$if(title)$
+
+$endif$
+$body$
+$for(include-after)$
+$include-after$
+$endfor$
+
+$if(toc)$
+
+$if(toc-title)$
+$toc-title$
+$endif$
+$table-of-contents$
+
+Links
+
+
+
+
+$endif$
+
+
+
diff --git a/website/template1.pandoc b/website/template1.pandoc
new file mode 100644
index 0000000..c93c195
--- /dev/null
+++ b/website/template1.pandoc
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+$for(author-meta)$
+
+$endfor$
+$if(date-meta)$
+
+$endif$
+$if(keywords)$
+
+$endif$
+$if(description-meta)$
+
+$endif$
+ $if(title-prefix)$$title-prefix$ – $endif$$pagetitle$
+
+$for(css)$
+
+$endfor$
+$for(header-includes)$
+ $header-includes$
+$endfor$
+$if(math)$
+$if(mathjax)$
+
+$endif$
+ $math$
+$endif$
+
+
+$if(toc)$
+
+$if(toc-title)$
+$toc-title$
+$endif$
+$table-of-contents$
+
+$endif$
+
+
+$for(include-before)$
+$include-before$
+$endfor$
+$if(title)$
+
+$endif$
+$body$
+$for(include-after)$
+$include-after$
+$endfor$
+
+
+
diff --git a/website/tpch21.sql b/website/tpch21.sql
new file mode 100644
index 0000000..8de4c93
--- /dev/null
+++ b/website/tpch21.sql
@@ -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;