实现基本关系代数运算,JOIN跨表查询

This commit is contained in:
LIm1tZz7 committed 2026-09-19 22:42:22 +08:00
1 parent a9ef1ef3e2
commit cae66f0731
15 files changed
+411 -124

No files matched your search

Whitespace-only changes.
+39
View File
@@ -0,0 +1,39 @@
module ChuSQL.Algebra.Eval where
import ChuSQL.Algebra.Op
import ChuSQL.Model
import ChuSQL.SQLSyntax.Expr (evalCondForRow)
import ChuSQL.SQLSyntax.Sort (sortRows)
import Control.Monad (filterM)
-- 投影
project :: [String] -> Row -> Row
project ["*"] row = row
project cs row = [(c, v) | (c, v) <- row, c `elem` cs]
-- 执行关系代数运算
addPrefix :: String -> Row -> Row
addPrefix prefix = map (\(k, v) -> (prefix ++ k, v))
evalRelOp :: Database -> RelOp -> Either String [Row]
evalRelOp db (Scan mAlias tbl) = do
table <- maybe (Left ("unknown table: " ++ tbl)) Right (lookup tbl db)
let prefix = maybe "" (++ ".") mAlias
Right (map (addPrefix prefix) (tableRows table))
evalRelOp db (Filter e op) = do
rows <- evalRelOp db op
filterM (evalCondForRow e) rows
evalRelOp db (Project cols op) = do
rows <- evalRelOp db op
Right (map (project cols) rows)
evalRelOp db (Sort spec op) = do
rows <- evalRelOp db op
Right (sortRows spec rows)
evalRelOp db (Limit n op) = do
rows <- evalRelOp db op
Right (take n rows)
evalRelOp db (Join left right cond) = do
lrows <- evalRelOp db left
rrows <- evalRelOp db right
let cross = [l ++ r | l <- lrows, r <- rrows] -- 笛卡尔积
filterM (evalCondForRow cond) cross
+13
View File
@@ -0,0 +1,13 @@
module ChuSQL.Algebra.Op where
import ChuSQL.SQLSyntax.AST (Expr, SortDir)
-- 关系代数算子
data RelOp
= Scan (Maybe String) String
| Filter Expr RelOp
| Project [String] RelOp
| Sort [(String, SortDir)] RelOp
| Limit Int RelOp
| Join RelOp RelOp Expr
deriving (Show, Eq)
@@ -0,0 +1,73 @@
module ChuSQL.Algebra.Planner where
import ChuSQL.Algebra.Op
import ChuSQL.Model
import ChuSQL.SQLSyntax.AST
-- * 存在性检查
checkColumns :: [String] -> [String] -> Either String ()
checkColumns available requested =
case [c | c <- requested, c /= "*", c `notElem` available] of
[] -> Right ()
(c : _) -> Left ("unknown column: " ++ c)
checkFrom :: Database -> FromClause -> Either String ()
checkFrom db (FromTable _ tbl) =
case lookup tbl db of
Just _ -> Right ()
Nothing -> Left ("unknown table: " ++ tbl)
checkFrom db (FromJoin left _ tbl _) = do
_ <- checkFrom db left
case lookup tbl db of
Just _ -> Right ()
Nothing -> Left ("unknown table: " ++ tbl)
-- | 收集 FromClause 里所有可用的列名
availableColumns :: Database -> FromClause -> Either String [String]
availableColumns db (FromTable mAlias tbl) = do
table <- maybe (Left ("unknown table: " ++ tbl)) Right (lookup tbl db)
let prefix = maybe "" (++ ".") mAlias
Right (map (prefix ++) (tableCols table))
availableColumns db (FromJoin left mAlias tbl _) = do
lcols <- availableColumns db left
table <- maybe (Left ("unknown table: " ++ tbl)) Right (lookup tbl db)
let prefix = maybe "" (++ ".") mAlias
Right (lcols ++ map (prefix ++) (tableCols table))
-- | 检查数据库列明
checkColumnsFrom :: Database -> FromClause -> [String] -> Either String ()
checkColumnsFrom db fromC requested = do
available <- availableColumns db fromC
checkColumns available requested
-- 内部查询语句转执行计划
fromToRelOp :: FromClause -> RelOp
fromToRelOp (FromTable mAlias tbl) = Scan mAlias tbl
fromToRelOp (FromJoin left mAlias tbl cond) =
Join (fromToRelOp left) (Scan mAlias tbl) cond
translate :: Database -> Query -> Either String RelOp
translate db q = case q of
Select
{ selectCols = cols
, selectFrom = fromC
, selectWhere = mWhere
, selectOrderBy = orderBy
, selectLimit = mLimit
} -> do
-- 检查所有表和列
_ <- checkFrom db fromC
_ <- checkColumnsFrom db fromC cols
_ <- checkColumnsFrom db fromC (map fst orderBy)
let base = fromToRelOp fromC
filtered = case mWhere of
Nothing -> base
Just w -> Filter w base
sorted = case orderBy of
[] -> filtered
spec -> Sort spec filtered
limited = case mLimit of
Nothing -> sorted
Just n -> Limit n sorted
Right (Project cols limited)
_ -> Left "only SELECT is supported by translate"