2026-09-19 19:22:50 +08:00
|
|
|
module Main where
|
|
|
|
|
|
2026-09-21 23:44:37 +08:00
|
|
|
import ChuSQL.Algebra.Op (RelOp (..))
|
|
|
|
|
import ChuSQL.Algebra.Optimize (optimize)
|
|
|
|
|
import ChuSQL.Algebra.Planner (translate)
|
2026-09-19 19:22:50 +08:00
|
|
|
import ChuSQL.Model
|
2026-09-19 22:42:22 +08:00
|
|
|
import ChuSQL.SQLSyntax.AST
|
2026-09-21 23:44:37 +08:00
|
|
|
import ChuSQL.SQLSyntax.Executor
|
2026-09-19 22:42:22 +08:00
|
|
|
import ChuSQL.SQLSyntax.Parser
|
2026-09-19 19:22:50 +08:00
|
|
|
|
|
|
|
|
users :: Table
|
|
|
|
|
users =
|
|
|
|
|
Table
|
|
|
|
|
{ tableName = "users"
|
2026-09-21 23:44:37 +08:00
|
|
|
, tableCols = ["id", "name", "age"]
|
2026-09-19 19:22:50 +08:00
|
|
|
, tableRows =
|
2026-09-21 23:44:37 +08:00
|
|
|
[ [("id", VInt 1), ("name", VStr "Alice"), ("age", VInt 25)]
|
|
|
|
|
, [("id", VInt 2), ("name", VStr "Bob"), ("age", VInt 17)]
|
|
|
|
|
, [("id", VInt 3), ("name", VStr "Carol"), ("age", VInt 30)]
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
orders :: Table
|
|
|
|
|
orders =
|
|
|
|
|
Table
|
|
|
|
|
{ tableName = "orders"
|
|
|
|
|
, tableCols = ["id", "user_id", "product"]
|
|
|
|
|
, tableRows =
|
|
|
|
|
[ [("id", VInt 1), ("user_id", VInt 1), ("product", VStr "Book")]
|
|
|
|
|
, [("id", VInt 2), ("user_id", VInt 2), ("product", VStr "Pen")]
|
|
|
|
|
, [("id", VInt 3), ("user_id", VInt 1), ("product", VStr "Cup")]
|
2026-09-19 19:22:50 +08:00
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
db :: Database
|
2026-09-21 23:44:37 +08:00
|
|
|
db = [("users", users), ("orders", orders)]
|
2026-09-19 19:22:50 +08:00
|
|
|
|
|
|
|
|
-- runQuery 返回 (更新后的数据库, 结果行);演示只关心结果行
|
|
|
|
|
rowsOf :: Either String (Database, [Row]) -> Either String [Row]
|
|
|
|
|
rowsOf = fmap snd
|
|
|
|
|
|
|
|
|
|
main :: IO ()
|
|
|
|
|
main = do
|
2026-09-21 23:44:37 +08:00
|
|
|
putStrLn "==================== Parser Test ====================="
|
2026-09-19 19:22:50 +08:00
|
|
|
let q1 = makeSelect ["name"] "users" (Just (Gt (Col "age") (LitInt 18)))
|
|
|
|
|
print (rowsOf (runQuery db q1))
|
|
|
|
|
|
|
|
|
|
let q2 = makeSelect ["*"] "users" Nothing
|
|
|
|
|
print (rowsOf (runQuery db q2))
|
|
|
|
|
|
|
|
|
|
let q3 = makeSelect ["name"] "nonexistent" Nothing
|
|
|
|
|
print (rowsOf (runQuery db q3))
|
|
|
|
|
|
|
|
|
|
let q4 =
|
|
|
|
|
makeSelect
|
|
|
|
|
["name"]
|
|
|
|
|
"users"
|
|
|
|
|
( Just
|
|
|
|
|
( Or
|
|
|
|
|
(Lt (Col "age") (LitInt 18))
|
|
|
|
|
(Gt (Col "age") (LitInt 30))
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
print (rowsOf (runQuery db q4))
|
|
|
|
|
|
|
|
|
|
-- 解析 SQL 文本,再交给执行引擎
|
|
|
|
|
let parsed = parseQuery "SELECT name FROM users WHERE age > 18 AND name = 'Alice'"
|
|
|
|
|
print (rowsOf (parsed >>= runQuery db))
|
2026-09-21 23:44:37 +08:00
|
|
|
|
|
|
|
|
putStrLn "\n==================== Optimizer ====================="
|
|
|
|
|
let planSql =
|
|
|
|
|
"SELECT u.name, o.product FROM users u \
|
|
|
|
|
\JOIN orders o ON u.id = o.user_id WHERE u.age > 18"
|
|
|
|
|
case parseQuery planSql of
|
|
|
|
|
Left err -> putStrLn err
|
|
|
|
|
Right query -> case translate db query of
|
|
|
|
|
Left err -> putStrLn err
|
|
|
|
|
Right plan -> do
|
|
|
|
|
putStrLn "--- plan before optimization ---"
|
|
|
|
|
putStrLn (dump 0 plan)
|
|
|
|
|
putStrLn "--- plan after optimization ---"
|
|
|
|
|
putStrLn (dump 0 (optimize db plan))
|
|
|
|
|
putStrLn "--- rows ---"
|
|
|
|
|
print (rowsOf (runQuery db query))
|
|
|
|
|
|
|
|
|
|
dump :: Int -> RelOp -> String
|
|
|
|
|
dump ind op = case op of
|
|
|
|
|
Scan a t ->
|
|
|
|
|
pad ++ "Scan " ++ show a ++ " " ++ show t
|
|
|
|
|
Filter e x ->
|
|
|
|
|
pad ++ "Filter " ++ show e ++ "\n" ++ dump (ind + 1) x
|
|
|
|
|
Project c x ->
|
|
|
|
|
pad ++ "Project " ++ show c ++ "\n" ++ dump (ind + 1) x
|
|
|
|
|
Sort s x ->
|
|
|
|
|
pad ++ "Sort " ++ show s ++ "\n" ++ dump (ind + 1) x
|
|
|
|
|
Limit n x ->
|
|
|
|
|
pad ++ "Limit " ++ show n ++ "\n" ++ dump (ind + 1) x
|
|
|
|
|
Join l r c ->
|
|
|
|
|
pad
|
|
|
|
|
++ "Join on "
|
|
|
|
|
++ show c
|
|
|
|
|
++ "\n"
|
|
|
|
|
++ dump (ind + 1) l
|
|
|
|
|
++ "\n"
|
|
|
|
|
++ dump (ind + 1) r
|
|
|
|
|
where
|
|
|
|
|
pad = replicate (ind * 2) ' '
|