module Database.Sql.Presto.Parser.Token where
import Database.Sql.Type.Query (CastFailureAction(..))
import Database.Sql.Presto.Token
import Database.Sql.Presto.Parser.Internal
import Database.Sql.Position
import qualified Text.Parsec as P
import qualified Text.Parsec.Pos as P
import Data.ByteString.Lazy (ByteString)
import Data.Text.Lazy (Text)
import qualified Data.Text.Lazy as TL
import qualified Data.Map as M
import Data.Semigroup ((<>))
showTok :: (Token, Position, Position) -> String
showTok (t, _, _) = show t
posFromTok :: P.SourcePos ->
(Token, Position, Position) ->
[(Token, Position, Position)] ->
P.SourcePos
posFromTok _ (_, pos, _) _ = flip P.setSourceLine (fromEnum $ positionLine pos)
$ flip P.setSourceColumn (fromEnum $ positionColumn pos)
$ P.initialPos "-"
tokEqualsP :: Token -> Parser Range
tokEqualsP tok = P.tokenPrim showTok posFromTok testTok
where
testTok (tok', s, e) =
if tok == tok'
then Just $ Range s e
else Nothing
tokNotEqualsP :: Token -> Parser Range
tokNotEqualsP tok = P.tokenPrim showTok posFromTok testTok
where
testTok (tok', s, e) =
if tok /= tok'
then Just $ Range s e
else Nothing
testNameTok :: (Token, Position, Position) -> Maybe (Text, Range)
testNameTok (tok, s, e) =
case tok of
TokWord _ name -> Just (name, Range s e)
_ -> Nothing
symbolP :: Text -> Parser Range
symbolP op = tokEqualsP $ TokSymbol op
keywordP :: Text -> Parser Range
keywordP keyword = P.tokenPrim showTok posFromTok testTok
where
testTok (tok, s, e) = case tok of
TokWord False name
| name == keyword -> Just (Range s e)
_ -> Nothing
dotP :: Parser Range
dotP = symbolP "."
starP :: Parser Range
starP = symbolP "*"
plusP :: Parser Range
plusP = symbolP "+"
minusP :: Parser Range
minusP = symbolP "-"
commaP :: Parser Range
commaP = symbolP ","
openP :: Parser Range
openP = symbolP "("
closeP :: Parser Range
closeP = symbolP ")"
openBracketP :: Parser Range
openBracketP = symbolP "["
closeBracketP :: Parser Range
closeBracketP = symbolP "]"
openAngleP :: Parser Range
openAngleP = symbolP "<"
closeAngleP :: Parser Range
closeAngleP = symbolP ">"
questionMarkP :: Parser Range
questionMarkP = symbolP "?"
stringP :: Parser (ByteString, Range)
stringP = P.tokenPrim showTok posFromTok testTok
where
testTok (tok, s, e) = case tok of
TokString string -> Just (string, Range s e)
_ -> Nothing
binaryLiteralP :: Parser (ByteString, Range)
binaryLiteralP = P.tokenPrim showTok posFromTok testTok
where
testTok (tok, s, e) = case tok of
TokBinary bytes -> Just (bytes, Range s e)
_ -> Nothing
numberP :: Parser (Text, Range)
numberP = P.tokenPrim showTok posFromTok testTok
where
testTok (tok, s, e) = case tok of
TokNumber number -> Just (number, Range s e)
_ -> Nothing
typeNameP :: Parser (Text, Range)
typeNameP = P.choice
[ P.try $ multiWordTypeP
, singleWordTypeP
]
where
multiWordTypeP = P.choice
[ do
s <- doubleP
e <- precisionP
return ("double precision", s <> e)
, do
r <- Left <$> timeP P.<|> Right <$> timestampP
_ <- withP
e <- timezoneP
case r of
Left s -> return ("time with time zone", s <> e)
Right s -> return ("timestamp with time zone", s <> e)
]
singleWordTypeP = P.tokenPrim showTok posFromTok testNameTok
intervalFieldP :: Parser (Text, Range)
intervalFieldP = P.tokenPrim showTok posFromTok testTok
where
testTok (tok, s, e) = case tok of
TokWord _ name | TL.toLower name `elem` fields -> Just (TL.toLower name, Range s e)
_ -> Nothing
fields = ["year", "month", "day", "hour", "minute", "second"]
comparisonOperatorP :: Parser (Text, Range)
comparisonOperatorP = P.tokenPrim showTok posFromTok testTok
where
testTok (TokSymbol op, s, e)
| op `elem` ["=", "<>", "!=", "<", "<=", ">", ">="] = Just (op, Range s e)
testTok _ = Nothing
comparisonQuantifierP :: Parser (Text, Range)
comparisonQuantifierP = P.tokenPrim showTok posFromTok testTok
where
testTok (tok, s, e) = case tok of
TokWord _ name | TL.toLower name `elem` quantifiers -> Just (TL.toLower name, Range s e)
_ -> Nothing
quantifiers = ["all", "some", "any"]
extractUnitP :: Parser (Text, Range)
extractUnitP = P.tokenPrim showTok posFromTok testTok
where
testTok (tok, s, e) = case tok of
TokWord _ name | TL.toLower name `elem` units -> Just (TL.toLower name, Range s e)
_ -> Nothing
units = [ "year", "quarter", "month", "week"
, "day", "day_of_month", "day_of_week", "dow", "day_of_year", "doy"
, "year_of_week", "yow"
, "hour", "minute", "second"
, "timezone_hour", "timezone_minute"
]
typedConstantTypeP :: Parser (Text, Range)
typedConstantTypeP = P.choice
[ P.try $ multiWordTypeP
, singleWordTypeP
]
where
multiWordTypeP = do
s <- doubleP
e <- precisionP
return ("double precision", s <> e)
singleWordTypeP = P.tokenPrim showTok posFromTok testTok
testTok (tok, s, e) = case tok of
TokWord _ name | TL.toLower name `elem` types -> Just (TL.toLower name, Range s e)
_ -> Nothing
types = [ "boolean", "bigint", "integer", "smallint", "tinyint"
, "double", "real", "varbinary", "date", "time", "timestamp"
, "hyperloglog", "p4hyperloglog", "joniregexp", "re2jregexp"
, "likepattern", "jsonpath", "color", "json", "codepoints"
, "varchar", "char", "decimal"
]
normalFormP :: Parser (Text, Range)
normalFormP = P.tokenPrim showTok posFromTok testTok
where
testTok (tok, s, e) = case tok of
TokWord _ name | TL.toLower name `elem` forms -> Just (TL.toLower name, Range s e)
_ -> Nothing
forms = [ "nfc", "nfd", "nfkc", "nfkd" ]
possiblyBareFuncP :: Parser (Text, Range, Bool)
possiblyBareFuncP = P.tokenPrim showTok posFromTok testTok
where
testTok (tok, s, e) = case tok of
TokWord _ name | TL.toLower name `M.member` funcs ->
let name' = TL.toLower name
r = Range s e
Just alwaysBare = M.lookup name' funcs
in Just (name', r, alwaysBare)
_ -> Nothing
funcs = M.fromList [ ("current_date", True)
, ("current_time", False)
, ("current_timestamp", False)
, ("localtime", False)
, ("localtimestamp", False)
]
castFuncP :: Parser (CastFailureAction, Range)
castFuncP = P.tokenPrim showTok posFromTok testTok
where
testTok (tok, s, e) = case tok of
TokWord _ name | TL.toLower name == "cast" -> Just (CastFailureError, Range s e)
TokWord _ name | TL.toLower name == "try_cast" -> Just (CastFailureToNull, Range s e)
_ -> Nothing
databaseNameP :: Parser (Text, Range)
databaseNameP = P.tokenPrim showTok posFromTok testTok
where
testTok (tok, s, e) = case tok of
TokWord True name -> Just (name, Range s e)
TokWord False name
| wordCanBeSchemaName (wordInfo name) -> Just (name, Range s e)
_ -> Nothing
schemaNameP :: Parser (Text, Range)
schemaNameP = P.tokenPrim showTok posFromTok testTok
where
testTok (tok, s, e) = case tok of
TokWord True name -> Just (name, Range s e)
TokWord False name
| wordCanBeSchemaName (wordInfo name) -> Just (name, Range s e)
_ -> Nothing
tableNameP :: Parser (Text, Range)
tableNameP = P.tokenPrim showTok posFromTok testTok
where
testTok (tok, s, e) = case tok of
TokWord True name -> Just (name, Range s e)
TokWord False name
| wordCanBeTableName (wordInfo name) -> Just (name, Range s e)
_ -> Nothing
columnNameP :: Parser (Text, Range)
columnNameP = P.tokenPrim showTok posFromTok testTok
where
testTok (tok, s, e) = case tok of
TokWord True name -> Just (name, Range s e)
TokWord False name
| wordCanBeColumnName (wordInfo name) -> Just (name, Range s e)
_ -> Nothing
structFieldNameP :: Parser (Text, Range)
structFieldNameP = P.tokenPrim showTok posFromTok testTok
where
testTok (tok, s, e) = case tok of
TokWord True name -> Just (name, Range s e)
TokWord False name
| wordCanBeColumnName (wordInfo name) -> Just (name, Range s e)
_ -> Nothing
paramNameP :: Parser (Text, Range)
paramNameP = P.tokenPrim showTok posFromTok testTok
where
testTok (tok, s, e) = case tok of
TokWord True name -> Just (name, Range s e)
TokWord False name
| wordCanBeColumnName (wordInfo name) -> Just (name, Range s e)
_ -> Nothing
functionNameP :: Parser (Text, Range)
functionNameP = P.tokenPrim showTok posFromTok testTok
where
testTok (tok, s, e) = case tok of
TokWord True name -> Just (name, Range s e)
TokWord False name
| wordCanBeFunctionName (wordInfo name) ->
Just (name, Range s e)
_ -> Nothing
allP :: Parser Range
allP = keywordP "all"
andP :: Parser Range
andP = keywordP "and"
arrayP :: Parser Range
arrayP = keywordP "array"
asP :: Parser Range
asP = keywordP "as"
ascP :: Parser Range
ascP = keywordP "asc"
atP :: Parser Range
atP = keywordP "at"
bernoulliP :: Parser Range
bernoulliP = keywordP "bernoulli"
betweenP :: Parser Range
betweenP = keywordP "between"
byP :: Parser Range
byP = keywordP "by"
callP :: Parser Range
callP = keywordP "call"
caseP :: Parser Range
caseP = keywordP "case"
crossP :: Parser Range
crossP = keywordP "cross"
cubeP :: Parser Range
cubeP = keywordP "cube"
currentP :: Parser Range
currentP = keywordP "current"
deleteP :: Parser Range
deleteP = keywordP "delete"
descP :: Parser Range
descP = keywordP "desc"
describeP :: Parser Range
describeP = keywordP "describe" P.<|> keywordP "desc"
distinctP :: Parser Range
distinctP = keywordP "distinct"
doubleP :: Parser Range
doubleP = keywordP "double"
dropP :: Parser Range
dropP = keywordP "drop"
elseP :: Parser Range
elseP = keywordP "else"
endP :: Parser Range
endP = keywordP "end"
escapeP :: Parser Range
escapeP = keywordP "escape"
exceptP :: Parser Range
exceptP = keywordP "except"
existsP :: Parser Range
existsP = keywordP "exists"
explainP :: Parser Range
explainP = keywordP "explain"
extractP :: Parser Range
extractP = keywordP "extract"
falseP :: Parser Range
falseP = keywordP "false"
filterP :: Parser Range
filterP = keywordP "filter"
firstP :: Parser Range
firstP = keywordP "first"
followingP :: Parser Range
followingP = keywordP "following"
forP :: Parser Range
forP = keywordP "for"
fromP :: Parser Range
fromP = keywordP "from"
fullP :: Parser Range
fullP = keywordP "full"
grantP :: Parser Range
grantP = keywordP "grant"
groupP :: Parser Range
groupP = keywordP "group"
groupingP :: Parser Range
groupingP = keywordP "grouping"
havingP :: Parser Range
havingP = keywordP "having"
ifP :: Parser Range
ifP = keywordP "if"
intervalP :: Parser Range
intervalP = keywordP "interval"
inP :: Parser Range
inP = keywordP "in"
innerP :: Parser Range
innerP = keywordP "inner"
insertP :: Parser Range
insertP = keywordP "insert"
intersectP :: Parser Range
intersectP = keywordP "intersect"
intoP :: Parser Range
intoP = keywordP "into"
isP :: Parser Range
isP = keywordP "is"
joinP :: Parser Range
joinP = keywordP "join"
lastP :: Parser Range
lastP = keywordP "last"
leftP :: Parser Range
leftP = keywordP "left"
likeP :: Parser Range
likeP = keywordP "like"
limitP :: Parser Range
limitP = keywordP "limit"
mapP :: Parser Range
mapP = keywordP "map"
naturalP :: Parser Range
naturalP = keywordP "natural"
normalizeP :: Parser Range
normalizeP = keywordP "normalize"
notP :: Parser Range
notP = keywordP "not"
nullP :: Parser Range
nullP = keywordP "null"
nullsP :: Parser Range
nullsP = keywordP "nulls"
onP :: Parser Range
onP = keywordP "on"
orP :: Parser Range
orP = keywordP "or"
orderP :: Parser Range
orderP = keywordP "order"
ordinalityP :: Parser Range
ordinalityP = keywordP "ordinality"
outerP :: Parser Range
outerP = keywordP "outer"
overP :: Parser Range
overP = keywordP "over"
partitionP :: Parser Range
partitionP = keywordP "partition"
poissonizedP :: Parser Range
poissonizedP = keywordP "poissonized"
positionP :: Parser Range
positionP = keywordP "position"
precedingP :: Parser Range
precedingP = keywordP "preceding"
precisionP :: Parser Range
precisionP = keywordP "precision"
rangeP :: Parser Range
rangeP = keywordP "range"
revokeP :: Parser Range
revokeP = keywordP "revoke"
rightP :: Parser Range
rightP = keywordP "right"
rollupP :: Parser Range
rollupP = keywordP "rollup"
rowP :: Parser Range
rowP = keywordP "row"
rowsP :: Parser Range
rowsP = keywordP "rows"
selectP :: Parser Range
selectP = keywordP "select"
semicolonP :: Parser Range
semicolonP = symbolP ";"
notSemicolonP :: Parser Range
notSemicolonP = tokNotEqualsP $ TokSymbol ";"
setsP :: Parser Range
setsP = keywordP "sets"
showP :: Parser Range
showP = keywordP "show"
substringP :: Parser Range
substringP = keywordP "substring"
systemP :: Parser Range
systemP = keywordP "system"
tableP :: Parser Range
tableP = keywordP "table"
tableSampleP :: Parser Range
tableSampleP = keywordP "tablesample"
thenP :: Parser Range
thenP = keywordP "then"
timeP :: Parser Range
timeP = keywordP "time"
timestampP :: Parser Range
timestampP = keywordP "timestamp"
timezoneP :: Parser Range
timezoneP = do
s <- keywordP "time"
e <- keywordP "zone"
pure $ s <> e
toP :: Parser Range
toP = keywordP "to"
trueP :: Parser Range
trueP = keywordP "true"
unboundedP :: Parser Range
unboundedP = keywordP "unbounded"
unionP :: Parser Range
unionP = keywordP "union"
unnestP :: Parser Range
unnestP = keywordP "unnest"
usingP :: Parser Range
usingP = keywordP "using"
valuesP :: Parser Range
valuesP = keywordP "values"
viewP :: Parser Range
viewP = keywordP "view"
whenP :: Parser Range
whenP = keywordP "when"
whereP :: Parser Range
whereP = keywordP "where"
withP :: Parser Range
withP = keywordP "with"