Files
ChuBlog/chusql-engine/src/ChuSQL/Syntax/Parser.hs
T

656 lines
19 KiB
Haskell
Raw Normal View History

2026-09-19 19:22:50 +08:00
{-# LANGUAGE ImportQualifiedPost #-}
2026-10-01 20:48:38 +08:00
module ChuSQL.Syntax.Parser (parseStatement, parseExpression) where
2026-09-19 19:22:50 +08:00
2026-10-01 20:48:38 +08:00
import ChuSQL.Model (Column (..), ColumnType (..), Value (..), plainColumn)
2026-09-22 21:26:54 +08:00
import ChuSQL.Syntax.AST
2026-10-01 20:48:38 +08:00
import Control.Monad (void)
2026-09-19 19:22:50 +08:00
import Control.Monad.Combinators.Expr (Operator (..), makeExprParser)
2026-10-01 20:48:38 +08:00
import Data.Char (isAlpha, isAlphaNum, isHexDigit, isSpace, toLower, toUpper)
import Data.List (intercalate)
2026-09-19 19:22:50 +08:00
import Data.Maybe (fromMaybe)
import Data.Void (Void)
import Text.Megaparsec
import Text.Megaparsec.Char
import Text.Megaparsec.Char.Lexer qualified as Lxr
2026-09-24 21:28:49 +08:00
-- SQL 解析:词法 + 语法,把文本变成语句树。
2026-09-19 19:22:50 +08:00
type Parser = Parsec Void String
2026-09-24 21:28:49 +08:00
-- | 跳过空白
2026-09-19 19:22:50 +08:00
sc :: Parser ()
2026-10-01 20:48:38 +08:00
sc = Lxr.space space1 (Lxr.skipLineComment "--") (Lxr.skipBlockComment "/*" "*/")
2026-09-19 19:22:50 +08:00
2026-09-24 21:28:49 +08:00
-- | 词后面吃掉空白
2026-09-19 19:22:50 +08:00
lexeme :: Parser a -> Parser a
lexeme = Lxr.lexeme sc
2026-09-24 21:28:49 +08:00
-- | 读一个符号
2026-09-19 19:22:50 +08:00
symbol :: String -> Parser String
symbol = Lxr.symbol sc
2026-09-24 21:28:49 +08:00
-- | 读关键字(不分大小写)
2026-09-19 19:22:50 +08:00
keyword :: String -> Parser ()
keyword k = lexeme $ try $ do
_ <- string' k
notFollowedBy (satisfy isIdentChar)
2026-09-24 21:28:49 +08:00
-- | 读一个名字
2026-09-19 19:22:50 +08:00
identifier :: Parser String
identifier = lexeme $ do
first <- satisfy (\ch -> isAlpha ch || ch == '_')
rest <- many (satisfy isIdentChar)
return (first : rest)
2026-10-01 20:48:38 +08:00
-- | 账号名:裸名字或单引号字符串(账号名允许点与短横线,字符串形式才写得出来)
userName :: Parser String
userName = identifier <|> stringLit
2026-09-24 21:28:49 +08:00
-- | 名字里允许的字符
2026-09-19 19:22:50 +08:00
isIdentChar :: Char -> Bool
isIdentChar ch = isAlphaNum ch || ch == '_'
2026-09-24 21:28:49 +08:00
-- | 读一个整数
2026-09-19 19:22:50 +08:00
integer :: Parser Int
integer = lexeme Lxr.decimal
2026-10-01 20:48:38 +08:00
-- | 读一个浮点数(必须有小数点或指数)
floatLit :: Parser Double
floatLit = lexeme Lxr.float
2026-09-24 21:28:49 +08:00
-- | 读一个字符串字面量
2026-09-19 19:22:50 +08:00
stringLit :: Parser String
stringLit = lexeme $ do
_ <- char '\''
s <- many stringChar
_ <- char '\''
return s
2026-09-24 21:28:49 +08:00
-- | 字符串里的一个字符
2026-09-19 19:22:50 +08:00
stringChar :: Parser Char
stringChar =
choice
[ '\'' <$ try (string "''")
, satisfy (/= '\'')
]
2026-10-01 20:48:38 +08:00
-- | X'ABCD' 形式的二进制字面量,统一存成大写十六进制文本
blobLit :: Parser String
blobLit = lexeme $ do
_ <- char 'x' <|> char 'X'
_ <- char '\''
s <- many (satisfy isHexDigit)
_ <- char '\''
return (map toUpper s)
2026-09-24 21:28:49 +08:00
-- | 升序或降序
2026-09-19 19:22:50 +08:00
sortDir :: Parser SortDir
sortDir = (Desc <$ keyword "desc") <|> (Asc <$ keyword "asc") <|> pure Asc
2026-09-24 21:28:49 +08:00
-- | LIMIT 后面的整数
2026-09-19 19:22:50 +08:00
limitClause :: Parser Int
limitClause = do
keyword "limit"
integer
2026-09-24 21:28:49 +08:00
-- | 能带表名的列名
qualifiedName :: Parser String
qualifiedName = do
first <- identifier
rest <- many (symbol "." *> identifier)
return (intercalate "." (first : rest))
2026-09-24 21:28:49 +08:00
-- | 读一个表达式
2026-09-19 19:22:50 +08:00
expr :: Parser Expr
expr = makeExprParser atom operatorTable
2026-09-24 21:28:49 +08:00
-- | 运算符优先级(从紧到松)
2026-09-19 19:22:50 +08:00
operatorTable :: [[Operator Parser Expr]]
operatorTable =
2026-10-01 20:48:38 +08:00
[ [Prefix (Neg <$ symbol "-")]
, [InfixL (Mul <$ symbol "*"), InfixL (Div <$ symbol "/")]
, [InfixL (Add <$ symbol "+"), InfixL (Sub <$ symbol "-")]
, [ InfixN (Gt <$ symbol ">")
2026-09-19 19:22:50 +08:00
, InfixN (Lt <$ symbol "<")
, InfixN (Eq <$ symbol "=")
]
2026-10-01 20:48:38 +08:00
, [ Postfix inPredicate
, Postfix (IsNotNull <$ try (keyword "is" *> keyword "not" *> keyword "null"))
, Postfix (IsNull <$ (keyword "is" *> keyword "null"))
]
2026-09-19 19:22:50 +08:00
, [InfixL (And <$ keyword "AND")]
2026-09-25 17:41:51 +08:00
, [InfixL (Or <$ keyword "OR")]
2026-09-19 19:22:50 +08:00
]
2026-09-24 21:28:49 +08:00
-- | 最小的表达式单位
2026-09-19 19:22:50 +08:00
atom :: Parser Expr
atom =
choice
2026-10-01 20:48:38 +08:00
[ LitNull <$ keyword "null"
, LitBool True <$ keyword "TRUE"
2026-09-25 17:41:51 +08:00
, LitBool False <$ keyword "FALSE"
2026-10-01 20:48:38 +08:00
, try (LitDate <$> (keyword "date" *> stringLit))
, try (LitTimestamp <$> (keyword "timestamp" *> stringLit))
, try (LitBlob <$> blobLit)
, LitFloat <$> try floatLit
2026-09-25 17:41:51 +08:00
, LitInt <$> integer
2026-09-19 19:22:50 +08:00
, LitStr <$> stringLit
2026-10-01 20:48:38 +08:00
, try aggregateCall
, try existsPredicate
, Col <$> qualifiedName
2026-10-01 20:48:38 +08:00
, try scalarSubquery
2026-09-19 19:22:50 +08:00
, between (symbol "(") (symbol ")") expr
]
2026-10-01 20:48:38 +08:00
-- | [NOT] EXISTS (SELECT ...)
existsPredicate :: Parser Expr
existsPredicate = do
negated <- (True <$ try (keyword "not" *> keyword "exists")) <|> (False <$ keyword "exists")
sq <- between (symbol "(") (symbol ")") subquerySelect
return (ExistsSub sq negated)
-- | 标量子查询:(SELECT ...)
scalarSubquery :: Parser Expr
scalarSubquery = ScalarSub <$> between (symbol "(") (symbol ")") subquerySelect
-- | [NOT] IN (SELECT ...) 或 [NOT] IN (值清单)
inPredicate :: Parser (Expr -> Expr)
inPredicate = do
negated <- (True <$ try (keyword "not" *> keyword "in")) <|> (False <$ keyword "in")
body <-
between (symbol "(") (symbol ")") $
choice
[ Left <$> try subquerySelect
, Right <$> sepBy1 expr (symbol ",")
]
return $ \e -> case body of
Left sq -> InSub e sq negated
Right es -> InList e es negated
-- | 括号里的子查询;对外层列的引用留给语义检查填
subquerySelect :: Parser Subquery
subquerySelect = Subquery <$> selectStatement <*> pure []
-- | 聚合调用:COUNT(*) / COUNT(x) / SUM(x) / AVG(x) / MIN(x) / MAX(x)
aggregateCall :: Parser Expr
aggregateCall =
choice
[ CountAll <$ try (keyword "count" *> between (symbol "(") (symbol ")") (symbol "*"))
, CountOf <$> aggArg "count"
, SumOf <$> aggArg "sum"
, AvgOf <$> aggArg "avg"
, MinOf <$> aggArg "min"
, MaxOf <$> aggArg "max"
]
where
aggArg name = try (keyword name *> between (symbol "(") (symbol ")") expr)
-- | 只认字面量,给 DEFAULT 用
literalValue :: Parser Value
literalValue =
choice
[ VNull <$ keyword "null"
, VBool True <$ keyword "TRUE"
, VBool False <$ keyword "FALSE"
, try (negateLit <$> floatLit)
, VInt <$> integer
, VFloat <$> try floatLit
, VStr <$> stringLit
]
where
negateLit d = VFloat (negate d)
2026-09-19 19:22:50 +08:00
2026-09-24 21:28:49 +08:00
-- | 一个排序列
2026-09-19 19:22:50 +08:00
orderItem :: Parser (String, SortDir)
orderItem = do
col <- qualifiedName
2026-09-19 19:22:50 +08:00
dir <- sortDir
return (col, dir)
2026-09-24 21:28:49 +08:00
-- | ORDER BY 的列表
2026-09-19 19:22:50 +08:00
orderByClause :: Parser [(String, SortDir)]
orderByClause = do
keyword "order"
keyword "by"
sepBy1 orderItem (symbol ",")
2026-10-01 20:48:38 +08:00
-- | GROUP BY 的列表
groupByClause :: Parser [String]
groupByClause = do
keyword "group"
keyword "by"
sepBy1 qualifiedName (symbol ",")
2026-09-24 21:28:49 +08:00
-- | SET 里的一条赋值
2026-09-19 19:22:50 +08:00
assignment :: Parser (String, Expr)
assignment = do
col <- identifier
_ <- symbol "="
e <- expr
return (col, e)
reservedWords :: [String]
reservedWords =
[ "select"
2026-10-01 20:48:38 +08:00
, "as"
, "from"
, "where"
, "order"
, "by"
, "limit"
, "join"
2026-10-01 20:48:38 +08:00
, "left"
, "outer"
, "inner"
, "exists"
, "in"
, "on"
, "and"
, "or"
, "asc"
, "desc"
, "insert"
, "into"
, "values"
, "delete"
, "update"
, "set"
2026-09-24 21:28:49 +08:00
, "create"
, "table"
2026-09-25 14:21:55 +08:00
, "index"
, "drop"
2026-09-25 17:41:51 +08:00
, "alter"
2026-10-01 20:48:38 +08:00
, "add"
, "rename"
, "to"
2026-09-25 17:41:51 +08:00
, "column"
2026-10-01 20:48:38 +08:00
, "user"
, "identified"
, "null"
, "is"
, "not"
, "default"
, "check"
, "unique"
, "primary"
, "key"
, "auto_increment"
, "type"
, "group"
]
2026-09-24 21:28:49 +08:00
-- | 别名(不许用保留字)
aliasName :: Parser String
aliasName = try $ do
name <- identifier
if map toLower name `elem` reservedWords then empty else return name
2026-09-24 21:28:49 +08:00
-- | 表名 + 可选别名
tableRef :: Parser (Maybe String, String)
tableRef = do
2026-10-01 20:48:38 +08:00
tbl <- tableName
mAlias <- optional ((keyword "as" *> aliasName) <|> aliasName)
return (mAlias, tbl)
2026-10-01 20:48:38 +08:00
-- | 连接类型:内连接 / 左外连接
joinKind :: Parser JoinKind
joinKind =
try (keyword "left" *> optional (keyword "outer") *> keyword "join" *> return LeftJoin)
<|> try (keyword "inner" *> keyword "join" *> return InnerJoin)
<|> (keyword "join" *> return InnerJoin)
2026-09-24 21:28:49 +08:00
-- | 一个 JOIN ... ON
2026-10-01 20:48:38 +08:00
joinClause :: Parser (JoinKind, Maybe String, String, Expr)
joinClause = do
2026-10-01 20:48:38 +08:00
kind <- joinKind
(mAlias, tbl) <- tableRef
keyword "on"
cond <- expr
2026-10-01 20:48:38 +08:00
return (kind, mAlias, tbl, cond)
2026-09-24 21:28:49 +08:00
-- | FROM 子句(可含多个 JOIN)
fromClause :: Parser FromClause
fromClause = do
(mAlias, tbl) <- tableRef
joins <- many joinClause
2026-10-01 20:48:38 +08:00
return (foldl (\acc (k, a, t, c) -> FromJoin k acc a t c) (FromTable mAlias tbl) joins)
2026-09-24 21:28:49 +08:00
-- | SELECT 的列清单
2026-10-01 20:48:38 +08:00
selectList :: Parser [(String, Expr)]
2026-09-19 19:22:50 +08:00
selectList =
choice
2026-10-01 20:48:38 +08:00
[ [("*", Col "*")] <$ symbol "*"
, sepBy1 selectItem (symbol ",")
2026-09-19 19:22:50 +08:00
]
2026-10-01 20:48:38 +08:00
-- | 投影标签保留表达式原文
selectItem :: Parser (String, Expr)
selectItem = do
(source, e) <- match expr
pure (case e of Col c -> (c, e); _ -> (reverse (dropWhile isSpace (reverse source)), e))
2026-09-24 21:28:49 +08:00
-- | 读 CREATE TABLE
createTableStatement :: Parser Statement
createTableStatement = do
keyword "create"
keyword "table"
2026-10-01 20:48:38 +08:00
name <- tableName
2026-09-24 21:28:49 +08:00
cols <- between (symbol "(") (symbol ")") (sepBy1 columnDef (symbol ","))
return (CreateTable name cols)
-- | 读 DROP TABLE
dropTableStatement :: Parser Statement
dropTableStatement = do
keyword "drop"
keyword "table"
2026-10-01 20:48:38 +08:00
name <- tableName
2026-09-24 21:28:49 +08:00
return (DropTable name)
2026-09-25 17:41:51 +08:00
-- | 读 CREATE INDEX(列名即索引名)
2026-09-25 14:21:55 +08:00
createIndexStatement :: Parser Statement
createIndexStatement = do
keyword "create"
keyword "index"
keyword "on"
2026-10-01 20:48:38 +08:00
tbl <- tableName
2026-09-25 14:21:55 +08:00
col <- between (symbol "(") (symbol ")") identifier
return (CreateIndex tbl col)
-- | 读 DROP INDEX
dropIndexStatement :: Parser Statement
dropIndexStatement = do
keyword "drop"
keyword "index"
keyword "on"
2026-10-01 20:48:38 +08:00
tbl <- tableName
2026-09-25 14:21:55 +08:00
col <- between (symbol "(") (symbol ")") identifier
return (DropIndex tbl col)
2026-10-01 20:48:38 +08:00
-- | 读 ALTER TABLE:加列、删列、改名、改类型、改默认值、改可空
alterTableStatement :: Parser Statement
alterTableStatement = do
2026-09-25 17:41:51 +08:00
keyword "alter"
keyword "table"
2026-10-01 20:48:38 +08:00
tbl <- tableName
choice
[ do
keyword "add"
void (optional (keyword "column"))
(name, col) <- columnDef
pure (AddColumn tbl (name, col))
, do
keyword "drop"
void (optional (keyword "column"))
DropColumn tbl <$> identifier
, do
keyword "rename"
void (optional (keyword "column"))
old <- identifier
keyword "to"
RenameColumn tbl old <$> identifier
, do
keyword "alter"
void (optional (keyword "column"))
col <- identifier
choice
[ AlterColumnType tbl col <$> (keyword "type" *> columnTypeP)
, try (AlterColumnNull tbl col False <$ (keyword "set" *> keyword "not" *> keyword "null"))
, try (AlterColumnNull tbl col True <$ (keyword "drop" *> keyword "not" *> keyword "null"))
, try (AlterColumnDefault tbl col . Just <$> (keyword "set" *> keyword "default" *> literalValue))
, AlterColumnDefault tbl col Nothing <$ (keyword "drop" *> keyword "default")
]
]
2026-09-25 17:41:51 +08:00
2026-10-01 20:48:38 +08:00
-- | 读 CREATE USER(口令是明文,交给账号服务加盐派生)
createUserStatement :: Parser Statement
createUserStatement = do
keyword "create"
keyword "user"
name <- userName
pw <- identifiedBy
return (CreateUser name pw)
-- | 读 IDENTIFIED BY '口令'
identifiedBy :: Parser String
identifiedBy = do
keyword "identified"
keyword "by"
stringLit
-- | 读 ALTER USER ... IDENTIFIED BY(改一个普通账号的口令)
alterUserStatement :: Parser Statement
alterUserStatement = do
keyword "alter"
keyword "user"
name <- userName
pw <- identifiedBy
return (AlterUser name pw)
-- | 读 DROP USER
dropUserStatement :: Parser Statement
dropUserStatement = do
keyword "drop"
keyword "user"
name <- userName
return (DropUser name)
-- | 读 CREATE ROLE
createRoleStatement :: Parser Statement
createRoleStatement = do
keyword "create"
keyword "role"
CreateRole <$> userName
-- | 读 DROP ROLE
dropRoleStatement :: Parser Statement
dropRoleStatement = do
keyword "drop"
keyword "role"
DropRole <$> userName
-- | 权限名,统一收成大写
privilegeName :: Parser String
privilegeName =
choice
[ "SELECT" <$ keyword "select"
, "INSERT" <$ keyword "insert"
, "UPDATE" <$ keyword "update"
, "DELETE" <$ keyword "delete"
, "ALL" <$ keyword "all"
]
-- | ON 后面的授权对象:* 表示全部表,否则是一张表(可带库前缀)
grantObject :: Parser String
grantObject = ("*" <$ symbol "*") <|> tableName
-- | 读 GRANT:带 ON 的是给角色授权限,不带的是给用户加角色
grantStatement :: Parser Statement
grantStatement = do
keyword "grant"
choice
[ try $ do
privs <- sepBy1 privilegeName (symbol ",")
keyword "on"
obj <- grantObject
keyword "to"
GrantPrivileges privs obj <$> userName
, GrantRole <$> userName <*> (keyword "to" *> sepBy1 userName (symbol ","))
]
-- | 读 REVOKE:与 GRANT 对称
revokeStatement :: Parser Statement
revokeStatement = do
keyword "revoke"
choice
[ try $ do
privs <- sepBy1 privilegeName (symbol ",")
keyword "on"
obj <- grantObject
keyword "from"
RevokePrivileges privs obj <$> userName
, RevokeRole <$> userName <*> (keyword "from" *> sepBy1 userName (symbol ","))
]
-- | 建表时的一列:类型后面跟若干约束
2026-09-24 21:28:49 +08:00
columnDef :: Parser (String, Column)
columnDef = do
name <- identifier
2026-10-01 20:48:38 +08:00
ty <- columnTypeP
mods <- many columnConstraint
return (name, foldl (\c f -> f c) (plainColumn ty) mods)
-- | 一条列约束
columnConstraint :: Parser (Column -> Column)
columnConstraint =
choice
[ try (keyword "not" *> keyword "null" *> pure (\c -> c{columnNullable = False}))
, keyword "null" *> pure (\c -> c{columnNullable = True})
, keyword "auto_increment" *> pure (\c -> c{columnAutoIncrement = True, columnNullable = False})
, try (keyword "primary" *> keyword "key" *> pure (\c -> c{columnPrimaryKey = True, columnUnique = True, columnNullable = False}))
, keyword "unique" *> pure (\c -> c{columnUnique = True})
, keyword "default" *> ((\v c -> c{columnDefault = Just v}) <$> literalValue)
, keyword "check" *> ((\s c -> c{columnCheck = Just s}) <$> checkText)
]
-- | CHECK 后面括号里的表达式原文,交给执行期再解析
checkText :: Parser String
checkText = between (symbol "(") (symbol ")") (match expr) >>= \(source, _) -> pure source
-- | 括号里的长度参数
sizeParen :: Parser Int
sizeParen = try (between (symbol "(") (symbol ")") integer)
2026-09-24 21:28:49 +08:00
-- | 列类型关键字
2026-10-01 20:48:38 +08:00
columnTypeP :: Parser ColumnType
columnTypeP =
choice
[ keyword "integer" >> pure CInt
, keyword "int" >> pure CInt
, keyword "bigint" >> pure CBigInt
, keyword "smallint" >> pure CSmallInt
, (keyword "varchar" >>) (maybe CStr CVarchar <$> optional sizeParen)
, (keyword "char" >>) (maybe (CChar 1) CChar <$> optional sizeParen)
, keyword "text" >> pure CStr
, keyword "str" >> pure CStr
, keyword "boolean" >> pure CBool
, keyword "bool" >> pure CBool
, keyword "float" >> pure CFloat
, keyword "real" >> pure CFloat
, try (keyword "double" *> keyword "precision" *> pure CDouble)
, keyword "double" >> pure CDouble
, (keyword "decimal" >>) decimalType
, (keyword "numeric" >>) decimalType
, keyword "date" >> pure CDate
, keyword "timestamp" >> pure CTimestamp
, keyword "blob" >> pure CBlob
]
-- | DECIMAL 的精度与小数位
decimalType :: Parser ColumnType
decimalType = do
args <- optional (try (between (symbol "(") (symbol ")") decimalArgs))
pure $ case args of
Nothing -> CDecimal 10 0
Just (p, s) -> CDecimal p s
decimalArgs :: Parser (Int, Int)
decimalArgs = do
p <- integer
s <- fromMaybe 0 <$> optional (symbol "," *> integer)
pure (p, s)
2026-09-24 21:28:49 +08:00
-- | 读 SELECT
selectStatement :: Parser Statement
selectStatement = do
keyword "select"
2026-09-19 19:22:50 +08:00
cols <- selectList
2026-10-01 20:48:38 +08:00
fromC <- fromMaybe FromUnit <$> optional (keyword "from" *> fromClause)
2026-09-19 19:22:50 +08:00
mWhere <- optional (keyword "where" *> expr)
2026-10-01 20:48:38 +08:00
groupBy <- fromMaybe [] <$> optional groupByClause
2026-09-19 19:22:50 +08:00
orderBy <- fromMaybe [] <$> optional orderByClause
mLimit <- optional limitClause
2026-10-01 20:48:38 +08:00
pure $ if all (\(name, e) -> e == Col name) cols
then Select (map fst cols) fromC mWhere groupBy orderBy mLimit
else SelectExpr cols fromC mWhere groupBy orderBy mLimit
2026-09-19 19:22:50 +08:00
2026-09-25 17:41:51 +08:00
-- | 读 INSERT,可一次插多行
2026-09-24 21:28:49 +08:00
insertStatement :: Parser Statement
insertStatement = do
2026-09-19 19:22:50 +08:00
keyword "INSERT"
keyword "INTO"
2026-10-01 20:48:38 +08:00
tbl <- tableName
2026-09-19 19:22:50 +08:00
cols <-
between
(symbol "(")
(symbol ")")
(sepBy1 identifier (symbol ","))
keyword "VALUES"
2026-09-25 14:21:55 +08:00
rows <- sepBy1 valueRow (symbol ",")
return (Insert tbl cols rows)
-- | 一行值:一对括号里的若干字面量
valueRow :: Parser [Expr]
2026-10-01 20:48:38 +08:00
valueRow = between (symbol "(") (symbol ")") (sepBy1 expr (symbol ","))
2026-09-19 19:22:50 +08:00
2026-09-24 21:28:49 +08:00
-- | 读 DELETE
deleteStatement :: Parser Statement
deleteStatement = do
2026-09-19 19:22:50 +08:00
keyword "DELETE"
keyword "FROM"
2026-10-01 20:48:38 +08:00
tbl <- tableName
2026-09-19 19:22:50 +08:00
mWhere <- optional (keyword "WHERE" *> expr)
return (Delete tbl mWhere)
2026-09-24 21:28:49 +08:00
-- | 读 UPDATE
updateStatement :: Parser Statement
updateStatement = do
2026-09-19 19:22:50 +08:00
keyword "update"
2026-10-01 20:48:38 +08:00
tbl <- tableName
2026-09-19 19:22:50 +08:00
keyword "set"
assigns <- sepBy1 assignment (symbol ",")
mWhere <- optional (keyword "where" *> expr)
return (Update tbl assigns mWhere)
2026-09-24 21:28:49 +08:00
-- | 解析总入口
parseStatement :: String -> Either String Statement
parseStatement input =
case runParser (sc *> statementP <* sc <* eof) "<query>" input of
2026-09-19 19:22:50 +08:00
Left err -> Left (errorBundlePretty err)
Right q -> Right q
2026-09-24 21:28:49 +08:00
where
statementP =
selectStatement
2026-10-01 20:48:38 +08:00
<|> try (CreateDatabase <$> (keyword "create" *> keyword "database" *> identifier))
<|> try (DropDatabase <$> (keyword "drop" *> keyword "database" *> identifier))
<|> (UseDatabase <$> (keyword "use" *> identifier))
<|> (ShowDatabases <$ (keyword "show" *> keyword "databases"))
2026-09-24 21:28:49 +08:00
<|> insertStatement
<|> deleteStatement
<|> updateStatement
2026-10-01 20:48:38 +08:00
<|> try createUserStatement
<|> try alterUserStatement
<|> try dropUserStatement
<|> try createRoleStatement
<|> try dropRoleStatement
<|> try grantStatement
<|> try revokeStatement
2026-09-25 14:21:55 +08:00
<|> try createIndexStatement
<|> try createTableStatement
<|> try dropIndexStatement
2026-10-01 20:48:38 +08:00
<|> try alterTableStatement
2026-09-24 21:28:49 +08:00
<|> dropTableStatement
2026-10-01 20:48:38 +08:00
-- | 解析一个裸表达式(CHECK 约束原文用)
parseExpression :: String -> Either String Expr
parseExpression input =
case runParser (sc *> expr <* sc <* eof) "<expr>" input of
Left err -> Left (errorBundlePretty err)
Right e -> Right e
-- | 表名至多有一个库前缀。
tableName :: Parser String
tableName = do
first <- identifier
databaseTable <- optional (symbol "." *> identifier)
pure (maybe first (\t -> map toLower first ++ "." ++ t) databaseTable)