比较运算符
This commit is contained in:
1 parent
df47f7da27
commit
9b1c835202
14 files changed
+192
-2
No files matched your search
@@ -28,5 +28,5 @@
|
|||||||
- 改动说明只在交流中记录。
|
- 改动说明只在交流中记录。
|
||||||
|
|
||||||
## 当前重点
|
## 当前重点
|
||||||
- 主线已完成:高级优化器 → 并行查询 → M1 会话隔离 → M2 快照事务 → M3 WAL 与崩溃恢复 → M4 表结构进 WAL → M5 系统表统一命名 → M6 检查点按 LSN 部分截断 → M7 事务写写冲突检测 → M8 事务保存点 → M9 角色继承 → M10 转授权 → M11 FROM 派生表与投影别名 → M12 `WITH` / CTE。
|
- 主线已完成:高级优化器 → 并行查询 → M1 会话隔离 → M2 快照事务 → M3 WAL 与崩溃恢复 → M4 表结构进 WAL → M5 系统表统一命名 → M6 检查点按 LSN 部分截断 → M7 事务写写冲突检测 → M8 事务保存点 → M9 角色继承 → M10 转授权 → M11 FROM 派生表与投影别名 → M12 `WITH` / CTE → M13 比较运算符补全。
|
||||||
- 进度与计数见 `agent_credientials/project-plan.txt`,限制与风险见 `agent_credientials/known-issues.txt`。
|
- 进度与计数见 `agent_credientials/project-plan.txt`,限制与风险见 `agent_credientials/known-issues.txt`。
|
||||||
@@ -327,6 +327,9 @@ substSubqueries db e env = case e of
|
|||||||
Gt a b -> bin Gt a b
|
Gt a b -> bin Gt a b
|
||||||
Lt a b -> bin Lt a b
|
Lt a b -> bin Lt a b
|
||||||
Eq a b -> bin Eq a b
|
Eq a b -> bin Eq a b
|
||||||
|
GtE a b -> bin GtE a b
|
||||||
|
LtE a b -> bin LtE a b
|
||||||
|
NotEq a b -> bin NotEq a b
|
||||||
And a b -> bin And a b
|
And a b -> bin And a b
|
||||||
Or a b -> bin Or a b
|
Or a b -> bin Or a b
|
||||||
IsNull a -> un IsNull a
|
IsNull a -> un IsNull a
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ evalExpr (Neg a) row = do
|
|||||||
evalExpr (Gt a b) row = liftOperator OpGt a b row
|
evalExpr (Gt a b) row = liftOperator OpGt a b row
|
||||||
evalExpr (Lt a b) row = liftOperator OpLt a b row
|
evalExpr (Lt a b) row = liftOperator OpLt a b row
|
||||||
evalExpr (Eq a b) row = liftOperator OpEq a b row
|
evalExpr (Eq a b) row = liftOperator OpEq a b row
|
||||||
|
evalExpr (GtE a b) row = liftOperator OpGtE a b row
|
||||||
|
evalExpr (LtE a b) row = liftOperator OpLtE a b row
|
||||||
|
evalExpr (NotEq a b) row = liftOperator OpNe a b row
|
||||||
evalExpr (And a b) row = liftOperator OpAnd a b row
|
evalExpr (And a b) row = liftOperator OpAnd a b row
|
||||||
evalExpr (Or a b) row = liftOperator OpOr a b row
|
evalExpr (Or a b) row = liftOperator OpOr a b row
|
||||||
evalExpr (IsNull a) row = do
|
evalExpr (IsNull a) row = do
|
||||||
@@ -61,6 +64,9 @@ colsInExpr (Neg a) = colsInExpr a
|
|||||||
colsInExpr (Gt a b) = colsInExpr a ++ colsInExpr b
|
colsInExpr (Gt a b) = colsInExpr a ++ colsInExpr b
|
||||||
colsInExpr (Lt a b) = colsInExpr a ++ colsInExpr b
|
colsInExpr (Lt a b) = colsInExpr a ++ colsInExpr b
|
||||||
colsInExpr (Eq a b) = colsInExpr a ++ colsInExpr b
|
colsInExpr (Eq a b) = colsInExpr a ++ colsInExpr b
|
||||||
|
colsInExpr (GtE a b) = colsInExpr a ++ colsInExpr b
|
||||||
|
colsInExpr (LtE a b) = colsInExpr a ++ colsInExpr b
|
||||||
|
colsInExpr (NotEq a b) = colsInExpr a ++ colsInExpr b
|
||||||
colsInExpr (And a b) = colsInExpr a ++ colsInExpr b
|
colsInExpr (And a b) = colsInExpr a ++ colsInExpr b
|
||||||
colsInExpr (Or a b) = colsInExpr a ++ colsInExpr b
|
colsInExpr (Or a b) = colsInExpr a ++ colsInExpr b
|
||||||
colsInExpr (IsNull a) = colsInExpr a
|
colsInExpr (IsNull a) = colsInExpr a
|
||||||
@@ -87,6 +93,9 @@ hasDivision e = case e of
|
|||||||
Gt a b -> both a b
|
Gt a b -> both a b
|
||||||
Lt a b -> both a b
|
Lt a b -> both a b
|
||||||
Eq a b -> both a b
|
Eq a b -> both a b
|
||||||
|
GtE a b -> both a b
|
||||||
|
LtE a b -> both a b
|
||||||
|
NotEq a b -> both a b
|
||||||
And a b -> both a b
|
And a b -> both a b
|
||||||
Or a b -> both a b
|
Or a b -> both a b
|
||||||
_ -> False
|
_ -> False
|
||||||
@@ -109,6 +118,9 @@ hasSubquery e = case e of
|
|||||||
Gt a b -> both a b
|
Gt a b -> both a b
|
||||||
Lt a b -> both a b
|
Lt a b -> both a b
|
||||||
Eq a b -> both a b
|
Eq a b -> both a b
|
||||||
|
GtE a b -> both a b
|
||||||
|
LtE a b -> both a b
|
||||||
|
NotEq a b -> both a b
|
||||||
And a b -> both a b
|
And a b -> both a b
|
||||||
Or a b -> both a b
|
Or a b -> both a b
|
||||||
IsNull a -> hasSubquery a
|
IsNull a -> hasSubquery a
|
||||||
@@ -140,6 +152,9 @@ aggregatesIn e = case e of
|
|||||||
Gt a b -> both a b
|
Gt a b -> both a b
|
||||||
Lt a b -> both a b
|
Lt a b -> both a b
|
||||||
Eq a b -> both a b
|
Eq a b -> both a b
|
||||||
|
GtE a b -> both a b
|
||||||
|
LtE a b -> both a b
|
||||||
|
NotEq a b -> both a b
|
||||||
And a b -> both a b
|
And a b -> both a b
|
||||||
Or a b -> both a b
|
Or a b -> both a b
|
||||||
IsNull a -> aggregatesIn a
|
IsNull a -> aggregatesIn a
|
||||||
@@ -165,6 +180,9 @@ bareColumns e = case e of
|
|||||||
Gt a b -> both a b
|
Gt a b -> both a b
|
||||||
Lt a b -> both a b
|
Lt a b -> both a b
|
||||||
Eq a b -> both a b
|
Eq a b -> both a b
|
||||||
|
GtE a b -> both a b
|
||||||
|
LtE a b -> both a b
|
||||||
|
NotEq a b -> both a b
|
||||||
And a b -> both a b
|
And a b -> both a b
|
||||||
Or a b -> both a b
|
Or a b -> both a b
|
||||||
IsNull a -> bareColumns a
|
IsNull a -> bareColumns a
|
||||||
|
|||||||
@@ -62,6 +62,9 @@ scaleRows db p x rows = case p of
|
|||||||
_ -> quarter
|
_ -> quarter
|
||||||
Gt _ _ -> quarter
|
Gt _ _ -> quarter
|
||||||
Lt _ _ -> quarter
|
Lt _ _ -> quarter
|
||||||
|
GtE _ _ -> quarter
|
||||||
|
LtE _ _ -> quarter
|
||||||
|
NotEq _ _ -> quarter
|
||||||
And a b -> max 1 (min (scaleRows db a x rows) (scaleRows db b x rows))
|
And a b -> max 1 (min (scaleRows db a x rows) (scaleRows db b x rows))
|
||||||
_ -> quarter
|
_ -> quarter
|
||||||
where
|
where
|
||||||
|
|||||||
@@ -144,6 +144,9 @@ foldConstants (Neg a) = foldNode (Neg (foldConstants a))
|
|||||||
foldConstants (Gt a b) = foldNode (Gt (foldConstants a) (foldConstants b))
|
foldConstants (Gt a b) = foldNode (Gt (foldConstants a) (foldConstants b))
|
||||||
foldConstants (Lt a b) = foldNode (Lt (foldConstants a) (foldConstants b))
|
foldConstants (Lt a b) = foldNode (Lt (foldConstants a) (foldConstants b))
|
||||||
foldConstants (Eq a b) = foldNode (Eq (foldConstants a) (foldConstants b))
|
foldConstants (Eq a b) = foldNode (Eq (foldConstants a) (foldConstants b))
|
||||||
|
foldConstants (GtE a b) = foldNode (GtE (foldConstants a) (foldConstants b))
|
||||||
|
foldConstants (LtE a b) = foldNode (LtE (foldConstants a) (foldConstants b))
|
||||||
|
foldConstants (NotEq a b) = foldNode (NotEq (foldConstants a) (foldConstants b))
|
||||||
foldConstants (And a b) = foldNode (And (foldConstants a) (foldConstants b))
|
foldConstants (And a b) = foldNode (And (foldConstants a) (foldConstants b))
|
||||||
foldConstants (Or a b) = foldNode (Or (foldConstants a) (foldConstants b))
|
foldConstants (Or a b) = foldNode (Or (foldConstants a) (foldConstants b))
|
||||||
foldConstants e = e
|
foldConstants e = e
|
||||||
@@ -180,6 +183,32 @@ rewriteNode db (Filter (Lt (Col k) (LitInt v)) (Scan mAlias t Nothing))
|
|||||||
| worthRange db t (unqualify mAlias k) = Range mAlias t (unqualify mAlias k) Nothing (Just (VInt v, False))
|
| worthRange db t (unqualify mAlias k) = Range mAlias t (unqualify mAlias k) Nothing (Just (VInt v, False))
|
||||||
rewriteNode db (Filter (Lt (Col k) (LitStr v)) (Scan mAlias t Nothing))
|
rewriteNode db (Filter (Lt (Col k) (LitStr v)) (Scan mAlias t Nothing))
|
||||||
| worthRange db t (unqualify mAlias k) = Range mAlias t (unqualify mAlias k) Nothing (Just (VStr v, False))
|
| worthRange db t (unqualify mAlias k) = Range mAlias t (unqualify mAlias k) Nothing (Just (VStr v, False))
|
||||||
|
rewriteNode db (Filter (And (GtE (Col k1) (LitInt lo)) (LtE (Col k2) (LitInt hi))) (Scan mAlias t Nothing))
|
||||||
|
| k1 == k2 && worthRange db t (unqualify mAlias k1) =
|
||||||
|
Range mAlias t (unqualify mAlias k1) (Just (VInt lo, True)) (Just (VInt hi, True))
|
||||||
|
rewriteNode db (Filter (And (GtE (Col k1) (LitInt lo)) (Lt (Col k2) (LitInt hi))) (Scan mAlias t Nothing))
|
||||||
|
| k1 == k2 && worthRange db t (unqualify mAlias k1) =
|
||||||
|
Range mAlias t (unqualify mAlias k1) (Just (VInt lo, True)) (Just (VInt hi, False))
|
||||||
|
rewriteNode db (Filter (And (Gt (Col k1) (LitInt lo)) (LtE (Col k2) (LitInt hi))) (Scan mAlias t Nothing))
|
||||||
|
| k1 == k2 && worthRange db t (unqualify mAlias k1) =
|
||||||
|
Range mAlias t (unqualify mAlias k1) (Just (VInt lo, False)) (Just (VInt hi, True))
|
||||||
|
rewriteNode db (Filter (And (GtE (Col k1) (LitStr lo)) (LtE (Col k2) (LitStr hi))) (Scan mAlias t Nothing))
|
||||||
|
| k1 == k2 && worthRange db t (unqualify mAlias k1) =
|
||||||
|
Range mAlias t (unqualify mAlias k1) (Just (VStr lo, True)) (Just (VStr hi, True))
|
||||||
|
rewriteNode db (Filter (And (GtE (Col k1) (LitStr lo)) (Lt (Col k2) (LitStr hi))) (Scan mAlias t Nothing))
|
||||||
|
| k1 == k2 && worthRange db t (unqualify mAlias k1) =
|
||||||
|
Range mAlias t (unqualify mAlias k1) (Just (VStr lo, True)) (Just (VStr hi, False))
|
||||||
|
rewriteNode db (Filter (And (Gt (Col k1) (LitStr lo)) (LtE (Col k2) (LitStr hi))) (Scan mAlias t Nothing))
|
||||||
|
| k1 == k2 && worthRange db t (unqualify mAlias k1) =
|
||||||
|
Range mAlias t (unqualify mAlias k1) (Just (VStr lo, False)) (Just (VStr hi, True))
|
||||||
|
rewriteNode db (Filter (GtE (Col k) (LitInt v)) (Scan mAlias t Nothing))
|
||||||
|
| worthRange db t (unqualify mAlias k) = Range mAlias t (unqualify mAlias k) (Just (VInt v, True)) Nothing
|
||||||
|
rewriteNode db (Filter (GtE (Col k) (LitStr v)) (Scan mAlias t Nothing))
|
||||||
|
| worthRange db t (unqualify mAlias k) = Range mAlias t (unqualify mAlias k) (Just (VStr v, True)) Nothing
|
||||||
|
rewriteNode db (Filter (LtE (Col k) (LitInt v)) (Scan mAlias t Nothing))
|
||||||
|
| worthRange db t (unqualify mAlias k) = Range mAlias t (unqualify mAlias k) Nothing (Just (VInt v, True))
|
||||||
|
rewriteNode db (Filter (LtE (Col k) (LitStr v)) (Scan mAlias t Nothing))
|
||||||
|
| worthRange db t (unqualify mAlias k) = Range mAlias t (unqualify mAlias k) Nothing (Just (VStr v, True))
|
||||||
rewriteNode db (Filter p (Join kind l r c))
|
rewriteNode db (Filter p (Join kind l r c))
|
||||||
| not (hasDivision p || planHasDivision (Join kind l r c)) =
|
| not (hasDivision p || planHasDivision (Join kind l r c)) =
|
||||||
case kind of
|
case kind of
|
||||||
|
|||||||
@@ -44,6 +44,9 @@ rewriteAggs aggs e = case [label | (label, agg) <- aggs, agg == e] of
|
|||||||
Gt a b -> Gt (go a) (go b)
|
Gt a b -> Gt (go a) (go b)
|
||||||
Lt a b -> Lt (go a) (go b)
|
Lt a b -> Lt (go a) (go b)
|
||||||
Eq a b -> Eq (go a) (go b)
|
Eq a b -> Eq (go a) (go b)
|
||||||
|
GtE a b -> GtE (go a) (go b)
|
||||||
|
LtE a b -> LtE (go a) (go b)
|
||||||
|
NotEq a b -> NotEq (go a) (go b)
|
||||||
And a b -> And (go a) (go b)
|
And a b -> And (go a) (go b)
|
||||||
Or a b -> Or (go a) (go b)
|
Or a b -> Or (go a) (go b)
|
||||||
IsNull a -> IsNull (go a)
|
IsNull a -> IsNull (go a)
|
||||||
|
|||||||
@@ -137,6 +137,9 @@ data Operator
|
|||||||
| OpGt
|
| OpGt
|
||||||
| OpLt
|
| OpLt
|
||||||
| OpEq
|
| OpEq
|
||||||
|
| OpGtE
|
||||||
|
| OpLtE
|
||||||
|
| OpNe
|
||||||
| OpAnd
|
| OpAnd
|
||||||
| OpOr
|
| OpOr
|
||||||
deriving (Show, Eq, Enum, Bounded)
|
deriving (Show, Eq, Enum, Bounded)
|
||||||
@@ -151,6 +154,9 @@ operatorSymbol OpNeg = "-"
|
|||||||
operatorSymbol OpGt = ">"
|
operatorSymbol OpGt = ">"
|
||||||
operatorSymbol OpLt = "<"
|
operatorSymbol OpLt = "<"
|
||||||
operatorSymbol OpEq = "="
|
operatorSymbol OpEq = "="
|
||||||
|
operatorSymbol OpGtE = ">="
|
||||||
|
operatorSymbol OpLtE = "<="
|
||||||
|
operatorSymbol OpNe = "<>"
|
||||||
operatorSymbol OpAnd = "AND"
|
operatorSymbol OpAnd = "AND"
|
||||||
operatorSymbol OpOr = "OR"
|
operatorSymbol OpOr = "OR"
|
||||||
|
|
||||||
@@ -164,6 +170,9 @@ operatorOfExpr (Neg _) = Just OpNeg
|
|||||||
operatorOfExpr (Gt _ _) = Just OpGt
|
operatorOfExpr (Gt _ _) = Just OpGt
|
||||||
operatorOfExpr (Lt _ _) = Just OpLt
|
operatorOfExpr (Lt _ _) = Just OpLt
|
||||||
operatorOfExpr (Eq _ _) = Just OpEq
|
operatorOfExpr (Eq _ _) = Just OpEq
|
||||||
|
operatorOfExpr (GtE _ _) = Just OpGtE
|
||||||
|
operatorOfExpr (LtE _ _) = Just OpLtE
|
||||||
|
operatorOfExpr (NotEq _ _) = Just OpNe
|
||||||
operatorOfExpr (And _ _) = Just OpAnd
|
operatorOfExpr (And _ _) = Just OpAnd
|
||||||
operatorOfExpr (Or _ _) = Just OpOr
|
operatorOfExpr (Or _ _) = Just OpOr
|
||||||
operatorOfExpr _ = Nothing
|
operatorOfExpr _ = Nothing
|
||||||
@@ -175,6 +184,9 @@ executeOperator op vs = case (op, vs) of
|
|||||||
(OpGt, [x, y]) -> compareValues (== GT) x y
|
(OpGt, [x, y]) -> compareValues (== GT) x y
|
||||||
(OpLt, [x, y]) -> compareValues (< EQ) x y
|
(OpLt, [x, y]) -> compareValues (< EQ) x y
|
||||||
(OpEq, [x, y]) -> compareValues (== EQ) x y
|
(OpEq, [x, y]) -> compareValues (== EQ) x y
|
||||||
|
(OpGtE, [x, y]) -> compareValues (>= EQ) x y
|
||||||
|
(OpLtE, [x, y]) -> compareValues (<= EQ) x y
|
||||||
|
(OpNe, [x, y]) -> compareValues (/= EQ) x y
|
||||||
(OpAnd, [x, y]) -> andValues x y
|
(OpAnd, [x, y]) -> andValues x y
|
||||||
(OpOr, [x, y]) -> orValues x y
|
(OpOr, [x, y]) -> orValues x y
|
||||||
(_, [x, y]) | Just a <- arithOf op -> evalArith a x y
|
(_, [x, y]) | Just a <- arithOf op -> evalArith a x y
|
||||||
|
|||||||
@@ -137,6 +137,9 @@ inferExpr db place env (Neg a) = do
|
|||||||
inferExpr db place env (Gt a b) = comparison db place env a b
|
inferExpr db place env (Gt a b) = comparison db place env a b
|
||||||
inferExpr db place env (Lt a b) = comparison db place env a b
|
inferExpr db place env (Lt a b) = comparison db place env a b
|
||||||
inferExpr db place env (Eq a b) = comparison db place env a b
|
inferExpr db place env (Eq a b) = comparison db place env a b
|
||||||
|
inferExpr db place env (GtE a b) = comparison db place env a b
|
||||||
|
inferExpr db place env (LtE a b) = comparison db place env a b
|
||||||
|
inferExpr db place env (NotEq a b) = comparison db place env a b
|
||||||
inferExpr db place env (And a b) = boolean db place env a b
|
inferExpr db place env (And a b) = boolean db place env a b
|
||||||
inferExpr db place env (Or a b) = boolean db place env a b
|
inferExpr db place env (Or a b) = boolean db place env a b
|
||||||
inferExpr db place env (IsNull a) = inferExpr db place env a >> Right (InferType CBool)
|
inferExpr db place env (IsNull a) = inferExpr db place env a >> Right (InferType CBool)
|
||||||
@@ -597,6 +600,9 @@ resolveExpr db env outer f e = case e of
|
|||||||
Gt a b -> binary Gt a b
|
Gt a b -> binary Gt a b
|
||||||
Lt a b -> binary Lt a b
|
Lt a b -> binary Lt a b
|
||||||
Eq a b -> binary Eq a b
|
Eq a b -> binary Eq a b
|
||||||
|
GtE a b -> binary GtE a b
|
||||||
|
LtE a b -> binary LtE a b
|
||||||
|
NotEq a b -> binary NotEq a b
|
||||||
And a b -> binary And a b
|
And a b -> binary And a b
|
||||||
Or a b -> binary Or a b
|
Or a b -> binary Or a b
|
||||||
IsNull a -> IsNull <$> resolveExpr db env outer f a
|
IsNull a -> IsNull <$> resolveExpr db env outer f a
|
||||||
|
|||||||
@@ -107,6 +107,9 @@ data Expr
|
|||||||
| Gt Expr Expr
|
| Gt Expr Expr
|
||||||
| Lt Expr Expr
|
| Lt Expr Expr
|
||||||
| Eq Expr Expr
|
| Eq Expr Expr
|
||||||
|
| GtE Expr Expr
|
||||||
|
| LtE Expr Expr
|
||||||
|
| NotEq Expr Expr
|
||||||
| And Expr Expr
|
| And Expr Expr
|
||||||
| Or Expr Expr
|
| Or Expr Expr
|
||||||
| IsNull Expr
|
| IsNull Expr
|
||||||
|
|||||||
@@ -112,7 +112,10 @@ operatorTable =
|
|||||||
[ [Prefix (Neg <$ symbol "-")]
|
[ [Prefix (Neg <$ symbol "-")]
|
||||||
, [InfixL (Mul <$ symbol "*"), InfixL (Div <$ symbol "/")]
|
, [InfixL (Mul <$ symbol "*"), InfixL (Div <$ symbol "/")]
|
||||||
, [InfixL (Add <$ symbol "+"), InfixL (Sub <$ symbol "-")]
|
, [InfixL (Add <$ symbol "+"), InfixL (Sub <$ symbol "-")]
|
||||||
, [ InfixN (Gt <$ symbol ">")
|
, [ InfixN (NotEq <$ try (symbol "<>" <|> symbol "!="))
|
||||||
|
, InfixN (GtE <$ try (symbol ">="))
|
||||||
|
, InfixN (LtE <$ try (symbol "<="))
|
||||||
|
, InfixN (Gt <$ symbol ">")
|
||||||
, InfixN (Lt <$ symbol "<")
|
, InfixN (Lt <$ symbol "<")
|
||||||
, InfixN (Eq <$ symbol "=")
|
, InfixN (Eq <$ symbol "=")
|
||||||
]
|
]
|
||||||
@@ -695,6 +698,9 @@ expandExpr env e = case e of
|
|||||||
Gt a b -> Gt <$> go a <*> go b
|
Gt a b -> Gt <$> go a <*> go b
|
||||||
Lt a b -> Lt <$> go a <*> go b
|
Lt a b -> Lt <$> go a <*> go b
|
||||||
Eq a b -> Eq <$> go a <*> go b
|
Eq a b -> Eq <$> go a <*> go b
|
||||||
|
GtE a b -> GtE <$> go a <*> go b
|
||||||
|
LtE a b -> LtE <$> go a <*> go b
|
||||||
|
NotEq a b -> NotEq <$> go a <*> go b
|
||||||
And a b -> And <$> go a <*> go b
|
And a b -> And <$> go a <*> go b
|
||||||
Or a b -> Or <$> go a <*> go b
|
Or a b -> Or <$> go a <*> go b
|
||||||
Neg a -> Neg <$> go a
|
Neg a -> Neg <$> go a
|
||||||
|
|||||||
@@ -518,6 +518,90 @@ main = hspec $ do
|
|||||||
it "reports an unknown table for a name that is not a CTE" $ do
|
it "reports an unknown table for a name that is not a CTE" $ do
|
||||||
sql "WITH t AS (SELECT name FROM users) SELECT x.name FROM x" `shouldSatisfy` isLeft
|
sql "WITH t AS (SELECT name FROM users) SELECT x.name FROM x" `shouldSatisfy` isLeft
|
||||||
|
|
||||||
|
describe "ChuSQL.Core.Engine (比较运算符)" $ do
|
||||||
|
-- sql:在默认库上跑 SQL 取结果行
|
||||||
|
let sql input = parseStatement input >>= rowsOf . runStatement testDB
|
||||||
|
-- values:只取结果里的值
|
||||||
|
values input = fmap (map (map snd)) (sql input)
|
||||||
|
|
||||||
|
it "parses >= into GtE" $ do
|
||||||
|
parseStatement "SELECT name FROM users WHERE age >= 18"
|
||||||
|
`shouldBe` Right (Select ["name"] (FromTable Nothing "users") (Just (GtE (Col "age") (LitInt 18))) [] [] Nothing)
|
||||||
|
|
||||||
|
it "parses <= into LtE" $ do
|
||||||
|
parseStatement "SELECT name FROM users WHERE age <= 30"
|
||||||
|
`shouldBe` Right (Select ["name"] (FromTable Nothing "users") (Just (LtE (Col "age") (LitInt 30))) [] [] Nothing)
|
||||||
|
|
||||||
|
it "parses <> and != into the same node" $ do
|
||||||
|
sql "SELECT name FROM users WHERE age <> 17"
|
||||||
|
`shouldBe` sql "SELECT name FROM users WHERE age != 17"
|
||||||
|
values "SELECT name FROM users WHERE age <> 17 ORDER BY name"
|
||||||
|
`shouldBe` Right [[VStr "Alice"], [VStr "Carol"]]
|
||||||
|
|
||||||
|
it "runs >= and <=" $ do
|
||||||
|
values "SELECT name FROM users WHERE age >= 25 ORDER BY name"
|
||||||
|
`shouldBe` Right [[VStr "Alice"], [VStr "Carol"]]
|
||||||
|
values "SELECT name FROM users WHERE age <= 20" `shouldBe` Right [[VStr "Bob"]]
|
||||||
|
|
||||||
|
it "keeps comparisons with NULL three-valued" $ do
|
||||||
|
executeOperator OpGtE [VNull, VInt 1] `shouldBe` Right VNull
|
||||||
|
executeOperator OpLtE [VInt 1, VNull] `shouldBe` Right VNull
|
||||||
|
executeOperator OpNe [VNull, VInt 1] `shouldBe` Right VNull
|
||||||
|
executeOperator OpGtE [VInt 1, VFloat 1.0] `shouldBe` Right (VBool True)
|
||||||
|
executeOperator OpNe [VInt 1, VFloat 1.0] `shouldBe` Right (VBool False)
|
||||||
|
|
||||||
|
it "rewrites >= and <= into an inclusive index range" $ do
|
||||||
|
let stat rows distinct indexes = TableMeta rows [(c, d, False) | (c, d) <- distinct] indexes
|
||||||
|
dbWith m = [("users", Table "users" [("id", TInt), ("name", TStr)] [] (Just m))]
|
||||||
|
indexed = dbWith (stat 10000 [("id", 10000)] ["id"])
|
||||||
|
low = Filter (GtE (Col "id") (LitInt 2)) (Scan Nothing "users" Nothing)
|
||||||
|
both = Filter (And (GtE (Col "id") (LitInt 1)) (LtE (Col "id") (LitInt 3))) (Scan Nothing "users" Nothing)
|
||||||
|
halfOpenTop = Filter (And (GtE (Col "id") (LitInt 1)) (Lt (Col "id") (LitInt 3))) (Scan Nothing "users" Nothing)
|
||||||
|
halfOpenBottom = Filter (And (Gt (Col "id") (LitInt 1)) (LtE (Col "id") (LitInt 3))) (Scan Nothing "users" Nothing)
|
||||||
|
optimize indexed low `shouldBe` Range Nothing "users" "id" (Just (VInt 2, True)) Nothing
|
||||||
|
optimize indexed both
|
||||||
|
`shouldBe` Range Nothing "users" "id" (Just (VInt 1, True)) (Just (VInt 3, True))
|
||||||
|
-- 开区间那一端标记取反
|
||||||
|
optimize indexed halfOpenTop
|
||||||
|
`shouldBe` Range Nothing "users" "id" (Just (VInt 1, True)) (Just (VInt 3, False))
|
||||||
|
optimize indexed halfOpenBottom
|
||||||
|
`shouldBe` Range Nothing "users" "id" (Just (VInt 1, False)) (Just (VInt 3, True))
|
||||||
|
optimize indexed (Filter (LtE (Col "id") (LitInt 9)) (Scan Nothing "users" Nothing))
|
||||||
|
`shouldBe` Range Nothing "users" "id" Nothing (Just (VInt 9, True))
|
||||||
|
-- 统计说索引不划算时保持原样,交给全表扫
|
||||||
|
optimize (dbWith (stat 10000 [("id", 10000)] [])) low `shouldBe` low
|
||||||
|
|
||||||
|
it "uses an inclusive range on the real storage" $ do
|
||||||
|
withTestSession $ \srv -> withServerEnv srv $ do
|
||||||
|
_ <- runIPCStorage (runStatementM (CreateTable "rng_t" [("id", TInt), ("code", TInt)]))
|
||||||
|
_ <-
|
||||||
|
runIPCStorage
|
||||||
|
( runStatementM
|
||||||
|
( Insert
|
||||||
|
"rng_t"
|
||||||
|
["id", "code"]
|
||||||
|
[ [LitInt 1, LitInt 500]
|
||||||
|
, [LitInt 2, LitInt 501]
|
||||||
|
, [LitInt 3, LitInt 502]
|
||||||
|
, [LitInt 4, LitInt 503]
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
_ <- runIPCStorage (runStatementM (CreateIndex "rng_t" "code"))
|
||||||
|
-- ids:按条件取 id,只比较值
|
||||||
|
let ids cond =
|
||||||
|
fmap (map (map snd))
|
||||||
|
<$> runIPCStorage (runStatementM (makeSelect ["id"] "rng_t" (Just cond)))
|
||||||
|
ids (And (GtE (Col "code") (LitInt 501)) (LtE (Col "code") (LitInt 502)))
|
||||||
|
`shouldReturn` Right [[VInt 2], [VInt 3]]
|
||||||
|
-- 闭端含边界、开端不含边界
|
||||||
|
ids (And (Gt (Col "code") (LitInt 501)) (LtE (Col "code") (LitInt 502)))
|
||||||
|
`shouldReturn` Right [[VInt 3]]
|
||||||
|
ids (And (GtE (Col "code") (LitInt 501)) (Lt (Col "code") (LitInt 502)))
|
||||||
|
`shouldReturn` Right [[VInt 2]]
|
||||||
|
ids (And (Gt (Col "code") (LitInt 501)) (Lt (Col "code") (LitInt 502)))
|
||||||
|
`shouldReturn` Right []
|
||||||
|
|
||||||
describe "ChuSQL.Core.Engine (SELECT)" $ do
|
describe "ChuSQL.Core.Engine (SELECT)" $ do
|
||||||
-- sql:在默认库上跑 SQL 取结果行
|
-- sql:在默认库上跑 SQL 取结果行
|
||||||
let sql input = parseStatement input >>= rowsOf . runStatement testDB
|
let sql input = parseStatement input >>= rowsOf . runStatement testDB
|
||||||
@@ -2660,6 +2744,7 @@ planTables op = case op of
|
|||||||
Sort _ x -> planTables x
|
Sort _ x -> planTables x
|
||||||
Limit _ x -> planTables x
|
Limit _ x -> planTables x
|
||||||
Join _ l r _ -> planTables l ++ planTables r
|
Join _ l r _ -> planTables l ++ planTables r
|
||||||
|
Derived _ x -> planTables x
|
||||||
Unit -> []
|
Unit -> []
|
||||||
|
|
||||||
-- | 计划里每个 Join 节点是不是 LEFT JOIN(先序)
|
-- | 计划里每个 Join 节点是不是 LEFT JOIN(先序)
|
||||||
@@ -2671,6 +2756,7 @@ leftJoinKinds (Aggregate _ _ x) = leftJoinKinds x
|
|||||||
leftJoinKinds (Filter _ x) = leftJoinKinds x
|
leftJoinKinds (Filter _ x) = leftJoinKinds x
|
||||||
leftJoinKinds (Sort _ x) = leftJoinKinds x
|
leftJoinKinds (Sort _ x) = leftJoinKinds x
|
||||||
leftJoinKinds (Limit _ x) = leftJoinKinds x
|
leftJoinKinds (Limit _ x) = leftJoinKinds x
|
||||||
|
leftJoinKinds (Derived _ x) = leftJoinKinds x
|
||||||
leftJoinKinds _ = []
|
leftJoinKinds _ = []
|
||||||
|
|
||||||
-- | 取计划里第一个过滤条件
|
-- | 取计划里第一个过滤条件
|
||||||
@@ -2688,6 +2774,7 @@ firstFilterCond (Join _ l r _) = case firstFilterCond l of
|
|||||||
firstFilterCond (Scan _ _ _) = Nothing
|
firstFilterCond (Scan _ _ _) = Nothing
|
||||||
firstFilterCond (Lookup _ _ _ _) = Nothing
|
firstFilterCond (Lookup _ _ _ _) = Nothing
|
||||||
firstFilterCond (Range _ _ _ _ _) = Nothing
|
firstFilterCond (Range _ _ _ _ _) = Nothing
|
||||||
|
firstFilterCond (Derived _ x) = firstFilterCond x
|
||||||
|
|
||||||
-- | 判断计划里是否还有过滤节点
|
-- | 判断计划里是否还有过滤节点
|
||||||
anyFilter :: RelOp -> Bool
|
anyFilter :: RelOp -> Bool
|
||||||
@@ -2702,6 +2789,7 @@ anyFilter (Join _ l r _) = anyFilter l || anyFilter r
|
|||||||
anyFilter (Scan _ _ _) = False
|
anyFilter (Scan _ _ _) = False
|
||||||
anyFilter (Lookup _ _ _ _) = False
|
anyFilter (Lookup _ _ _ _) = False
|
||||||
anyFilter (Range _ _ _ _ _) = False
|
anyFilter (Range _ _ _ _ _) = False
|
||||||
|
anyFilter (Derived _ x) = anyFilter x
|
||||||
|
|
||||||
-- | 去掉计划里的投影节点
|
-- | 去掉计划里的投影节点
|
||||||
stripProjects :: RelOp -> RelOp
|
stripProjects :: RelOp -> RelOp
|
||||||
@@ -2716,6 +2804,7 @@ stripProjects (Join k l r c) = Join k (stripProjects l) (stripProjects r) c
|
|||||||
stripProjects (Scan a t _) = Scan a t Nothing
|
stripProjects (Scan a t _) = Scan a t Nothing
|
||||||
stripProjects (Lookup a t c k) = Lookup a t c k
|
stripProjects (Lookup a t c k) = Lookup a t c k
|
||||||
stripProjects (Range a t c lo hi) = Range a t c lo hi
|
stripProjects (Range a t c lo hi) = Range a t c lo hi
|
||||||
|
stripProjects (Derived a x) = Derived a (stripProjects x)
|
||||||
|
|
||||||
-- | 解析并做投影下推,返回计划
|
-- | 解析并做投影下推,返回计划
|
||||||
projectedPlan :: String -> Either String RelOp
|
projectedPlan :: String -> Either String RelOp
|
||||||
|
|||||||
@@ -300,6 +300,9 @@ exprTables expr = case expr of
|
|||||||
Gt a b -> both a b
|
Gt a b -> both a b
|
||||||
Lt a b -> both a b
|
Lt a b -> both a b
|
||||||
Eq a b -> both a b
|
Eq a b -> both a b
|
||||||
|
GtE a b -> both a b
|
||||||
|
LtE a b -> both a b
|
||||||
|
NotEq a b -> both a b
|
||||||
And a b -> both a b
|
And a b -> both a b
|
||||||
Or a b -> both a b
|
Or a b -> both a b
|
||||||
Neg a -> exprTables a
|
Neg a -> exprTables a
|
||||||
|
|||||||
@@ -661,6 +661,15 @@ privilegeSpec = describe "server privileges" $ do
|
|||||||
authorizeSql service (Ordinary testAccount) "WITH d AS (SELECT product FROM orders) SELECT d.product FROM d"
|
authorizeSql service (Ordinary testAccount) "WITH d AS (SELECT product FROM orders) SELECT d.product FROM d"
|
||||||
`shouldReturn` Left (PrivilegeError "forbidden" "permission denied: SELECT ON orders")
|
`shouldReturn` Left (PrivilegeError "forbidden" "permission denied: SELECT ON orders")
|
||||||
|
|
||||||
|
it "requires the privilege on the table inside a comparison subquery" $ withPrivileges $ \service root -> do
|
||||||
|
_ <- runPrivilegeCommand service root testDatabase (CreateRoleCommand "reader")
|
||||||
|
_ <- runPrivilegeCommand service root testDatabase (GrantPrivilegesCommand ["select"] "users" "reader" False)
|
||||||
|
_ <- runPrivilegeCommand service root testDatabase (GrantRoleCommand "reader" ["alice"])
|
||||||
|
authorizeSql service (Ordinary testAccount) "SELECT name FROM users WHERE id >= (SELECT id FROM users)"
|
||||||
|
`shouldReturn` Right ()
|
||||||
|
authorizeSql service (Ordinary testAccount) "SELECT name FROM users WHERE id >= (SELECT id FROM orders)"
|
||||||
|
`shouldReturn` Left (PrivilegeError "forbidden" "permission denied: SELECT ON orders")
|
||||||
|
|
||||||
it "keeps the role tables on the real storage" $ withIpcStorage $ do
|
it "keeps the role tables on the real storage" $ withIpcStorage $ do
|
||||||
base <- ipcBackend
|
base <- ipcBackend
|
||||||
service <- newPrivileges base
|
service <- newPrivileges base
|
||||||
|
|||||||
@@ -52,6 +52,12 @@ csql -f json -e "SELECT count(*) FROM orders"
|
|||||||
- 投影列可以起别名:`SELECT count(*) AS total FROM orders`,别名就是结果集的列名。`ORDER BY` 仍按来源列解析,要引用派生表的列得写限定名(如 `ORDER BY d.total`)。
|
- 投影列可以起别名:`SELECT count(*) AS total FROM orders`,别名就是结果集的列名。`ORDER BY` 仍按来源列解析,要引用派生表的列得写限定名(如 `ORDER BY d.total`)。
|
||||||
- 鉴权覆盖整棵来源树:查派生表时内层表也要有权限,只有外层引用的表有权限不够。
|
- 鉴权覆盖整棵来源树:查派生表时内层表也要有权限,只有外层引用的表有权限不够。
|
||||||
|
|
||||||
|
比较运算符:
|
||||||
|
|
||||||
|
- 支持 `=`、`<>`(也可写 `!=`)、`>`、`>=`、`<`、`<=`;`<>` 与 `!=` 是同一个运算符。
|
||||||
|
- `>`、`>=`、`<`、`<=` 在列上有索引时会改写成索引范围扫描;`>=` / `<=` 是闭区间,端点值本身也在结果里。
|
||||||
|
- 任一操作数为 `NULL` 时比较结果是 `NULL`,`WHERE` 只保留结果为真的行。
|
||||||
|
|
||||||
公共表表达式:
|
公共表表达式:
|
||||||
|
|
||||||
- `WITH 名字 AS (SELECT …), 另一个 AS (SELECT …) SELECT … FROM 名字` 先定义再引用,名字可以带列清单(`WITH t(who) AS (SELECT name FROM users) …`)。
|
- `WITH 名字 AS (SELECT …), 另一个 AS (SELECT …) SELECT … FROM 名字` 先定义再引用,名字可以带列清单(`WITH t(who) AS (SELECT name FROM users) …`)。
|
||||||
|
|||||||
Reference in new issue
Block a user