add iden keywords and app keywords to the dialect
This commit is contained in:
parent
9f2ff37c54
commit
86f5e203af
|
@ -20,9 +20,17 @@ Data types to represent different dialect options
|
||||||
> data Dialect = Dialect
|
> data Dialect = Dialect
|
||||||
> { -- | The list of reserved keywords
|
> { -- | The list of reserved keywords
|
||||||
> diKeywords :: [String]
|
> diKeywords :: [String]
|
||||||
|
> -- | The list of reserved keywords, which can also be used as
|
||||||
|
> -- | an identifier
|
||||||
|
> ,diIdentifierKeywords :: [String]
|
||||||
|
> -- | The list of reserved keywords, which can also be used as
|
||||||
|
> -- | a function name (including aggregates and window
|
||||||
|
> -- | functions)
|
||||||
|
> ,diAppKeywords :: [String]
|
||||||
> -- | does the dialect support ansi fetch first syntax
|
> -- | does the dialect support ansi fetch first syntax
|
||||||
> ,diFetchFirst :: Bool
|
> ,diFetchFirst :: Bool
|
||||||
> -- | does the dialect support limit keyword (mysql, postgres, ...)
|
> -- | does the dialect support limit keyword (mysql, postgres,
|
||||||
|
> -- | ...)
|
||||||
> ,diLimit :: Bool
|
> ,diLimit :: Bool
|
||||||
> -- | allow parsing ODBC syntax
|
> -- | allow parsing ODBC syntax
|
||||||
> ,diOdbc :: Bool
|
> ,diOdbc :: Bool
|
||||||
|
@ -50,6 +58,8 @@ Data types to represent different dialect options
|
||||||
> -- | ansi sql 2011 dialect
|
> -- | ansi sql 2011 dialect
|
||||||
> ansi2011 :: Dialect
|
> ansi2011 :: Dialect
|
||||||
> ansi2011 = Dialect {diKeywords = ansi2011ReservedKeywords
|
> ansi2011 = Dialect {diKeywords = ansi2011ReservedKeywords
|
||||||
|
> ,diIdentifierKeywords = []
|
||||||
|
> ,diAppKeywords = ["set"]
|
||||||
> ,diFetchFirst = True
|
> ,diFetchFirst = True
|
||||||
> ,diLimit = False
|
> ,diLimit = False
|
||||||
> ,diOdbc = False
|
> ,diOdbc = False
|
||||||
|
@ -104,6 +114,28 @@ mostly, things are keywords to avoid them mistakenly being parsed as
|
||||||
aliases or as identifiers/functions/function-like things (aggs,
|
aliases or as identifiers/functions/function-like things (aggs,
|
||||||
windows, etc.)
|
windows, etc.)
|
||||||
|
|
||||||
|
some rationale for having quite string reserved keywords:
|
||||||
|
|
||||||
|
1. sql has the unusual (these days) feature of quoting identifiers
|
||||||
|
which allows you to use any keyword in any context
|
||||||
|
|
||||||
|
2. the user already has to deal with a very long list of keywords in
|
||||||
|
sql. this is not very user friendly
|
||||||
|
|
||||||
|
3. if the user has to remember which situations which keyword needs
|
||||||
|
quoting, and which it doesn't need quoting, this is also not very
|
||||||
|
user friendly, even if it means less quoting sometimes. E.g. if
|
||||||
|
you only need to quote 'from' in places where it is ambiguous, and
|
||||||
|
you want to take advantage of this, this list of good/not-good
|
||||||
|
places is based on the weirdness of SQL grammar and the
|
||||||
|
implementation details of the parser - and it's especially bad if
|
||||||
|
you are using from as an iden without quotes, and you edit the sql
|
||||||
|
statement, and now from is in a position where it does need
|
||||||
|
quotes, and you get a obscure error message
|
||||||
|
|
||||||
|
4. there is a lot more potential for nice clear error messages
|
||||||
|
keywords are never allowed without quoting
|
||||||
|
|
||||||
> ansi2011ReservedKeywords :: [String]
|
> ansi2011ReservedKeywords :: [String]
|
||||||
> ansi2011ReservedKeywords =
|
> ansi2011ReservedKeywords =
|
||||||
> [--"abs" -- function
|
> [--"abs" -- function
|
||||||
|
|
|
@ -719,22 +719,20 @@ all the scalar expressions which start with an identifier
|
||||||
> idenExpr =
|
> idenExpr =
|
||||||
> -- todo: work out how to left factor this
|
> -- todo: work out how to left factor this
|
||||||
> try (TypedLit <$> typeName <*> singleQuotesOnlyStringTok)
|
> try (TypedLit <$> typeName <*> singleQuotesOnlyStringTok)
|
||||||
> <|> (try keywordFunction <**> app)
|
|
||||||
> <|> (names <**> option Iden app)
|
> <|> (names <**> option Iden app)
|
||||||
|
> <|> keywordFunctionOrIden
|
||||||
> where
|
> where
|
||||||
> -- this is a special case because 'set' is a reserved keyword
|
> -- special cases for keywords that can be parsed as an iden or app
|
||||||
> -- and the names parser won't parse it
|
> keywordFunctionOrIden = try $ do
|
||||||
> -- can't remove it from the reserved keyword list, because
|
> x <- unquotedIdentifierTok [] Nothing
|
||||||
> -- it is used in a lot of places which are ambiguous as a keyword
|
> d <- getState
|
||||||
> -- this approach might be needed with other keywords which look
|
> let i = map toLower x `elem` diIdentifierKeywords d
|
||||||
> -- like identifiers or functions
|
> a = map toLower x `elem` diAppKeywords d
|
||||||
> keywordFunction =
|
> case () of
|
||||||
> let makeKeywordFunction x = if map toLower x `elem` keywordFunctionNames
|
> _ | i && a -> pure [Name Nothing x] <**> option Iden app
|
||||||
> then return [Name Nothing x]
|
> | i -> pure (Iden [Name Nothing x])
|
||||||
> else fail ""
|
> | a -> pure [Name Nothing x] <**> app
|
||||||
> in unquotedIdentifierTok [] Nothing >>= makeKeywordFunction
|
> | otherwise -> fail ""
|
||||||
> keywordFunctionNames = ["set"
|
|
||||||
> ]
|
|
||||||
|
|
||||||
|
|
||||||
=== special
|
=== special
|
||||||
|
|
9
TODO
9
TODO
|
@ -4,6 +4,15 @@ review alters, and think about adding rename versions
|
||||||
which are really common and useful, but not in ansi
|
which are really common and useful, but not in ansi
|
||||||
https://github.com/JakeWheat/simple-sql-parser/issues/20
|
https://github.com/JakeWheat/simple-sql-parser/issues/20
|
||||||
|
|
||||||
|
try to get some control over the pretty printing and the error
|
||||||
|
messages by creating some dumps of pretty printing and error messages,
|
||||||
|
then can rerun these every so often to see how they've changed
|
||||||
|
|
||||||
|
-> expose in the dialect:
|
||||||
|
keywords which can (also?) appear as identifiers in scalar expressions
|
||||||
|
keywords which can (also?) appear as app-likes - this is already implemented
|
||||||
|
|
||||||
|
|
||||||
finish off going through the keyword list
|
finish off going through the keyword list
|
||||||
|
|
||||||
do more examples
|
do more examples
|
||||||
|
|
|
@ -4,8 +4,24 @@
|
||||||
> import Language.SQL.SimpleSQL.TestTypes
|
> import Language.SQL.SimpleSQL.TestTypes
|
||||||
|
|
||||||
> customDialectTests :: TestItem
|
> customDialectTests :: TestItem
|
||||||
> customDialectTests = Group "custom dialect tests" (map (ParseQueryExpr myDialect) sometests
|
> customDialectTests = Group "custom dialect tests" (map (uncurry ParseQueryExpr) passTests
|
||||||
> ++ [ParseScalarExprFails ansi2011 "SELECT DATE('2000-01-01')"])
|
> ++ map (uncurry ParseScalarExprFails) failTests )
|
||||||
> where
|
> where
|
||||||
> myDialect = ansi2011 {diKeywords = filter (/="date") (diKeywords ansi2011)}
|
> failTests = [(ansi2011,"SELECT DATE('2000-01-01')")
|
||||||
> sometests = ["SELECT DATE('2000-01-01')"]
|
> ,(ansi2011,"SELECT DATE")
|
||||||
|
> ,(dateApp,"SELECT DATE")
|
||||||
|
> ,(dateIden,"SELECT DATE('2000-01-01')")
|
||||||
|
> -- show this never being allowed as an alias
|
||||||
|
> ,(ansi2011,"SELECT a date")
|
||||||
|
> ,(dateApp,"SELECT a date")
|
||||||
|
> ,(dateIden,"SELECT a date")
|
||||||
|
> ]
|
||||||
|
> passTests = [(ansi2011,"SELECT a b")
|
||||||
|
> ,(noDateKeyword,"SELECT DATE('2000-01-01')")
|
||||||
|
> ,(noDateKeyword,"SELECT DATE")
|
||||||
|
> ,(dateApp,"SELECT DATE('2000-01-01')")
|
||||||
|
> ,(dateIden,"SELECT DATE")
|
||||||
|
> ]
|
||||||
|
> noDateKeyword = ansi2011 {diKeywords = filter (/="date") (diKeywords ansi2011)}
|
||||||
|
> dateIden = ansi2011 {diIdentifierKeywords = "date" : diIdentifierKeywords ansi2011}
|
||||||
|
> dateApp = ansi2011 {diAppKeywords = "date" : diAppKeywords ansi2011}
|
||||||
|
|
|
@ -14,15 +14,15 @@ cp website/main.css build
|
||||||
cp website/ocean.css build
|
cp website/ocean.css build
|
||||||
|
|
||||||
# index
|
# index
|
||||||
asciidoctor website/index.asciidoc -o - | cabal exec runhaskell website/AddLinks.lhs > build/index.html
|
asciidoctor website/index.asciidoc -o - | cabal -v0 exec runhaskell website/AddLinks.lhs > build/index.html
|
||||||
|
|
||||||
asciidoctor website/supported_sql.asciidoc -o - | cabal exec runhaskell website/AddLinks.lhs > build/supported_sql.html
|
asciidoctor website/supported_sql.asciidoc -o - | cabal -v0 exec runhaskell website/AddLinks.lhs > build/supported_sql.html
|
||||||
|
|
||||||
# tpch sql file
|
# tpch sql file
|
||||||
# pandoc src/tpch.sql -s --highlight-style kate -o tpch.sql.html
|
# pandoc src/tpch.sql -s --highlight-style kate -o tpch.sql.html
|
||||||
# rendered test cases
|
# rendered test cases
|
||||||
# build the parserexe target first to fix the package database
|
# build the parserexe target first to fix the package database
|
||||||
cabal exec runhaskell -- --ghc-arg=-package=pretty-show -itools website/RenderTestCases.lhs > build/test_cases.asciidoc
|
cabal -v0 exec runhaskell -- --ghc-arg=-package=pretty-show -itools website/RenderTestCases.lhs > build/test_cases.asciidoc
|
||||||
|
|
||||||
asciidoctor build/test_cases.asciidoc -o - | \
|
asciidoctor build/test_cases.asciidoc -o - | \
|
||||||
sed -e "s/max-width:62\.5em//g" \
|
sed -e "s/max-width:62\.5em//g" \
|
||||||
|
|
Loading…
Reference in a new issue