查询语言
类型化 SQL:
JOIN、DML 与 Heap DDL。
查询语言为有限的原生子集,包含解析器、名义类型检查、三值逻辑、受 WAL 保护的 DML,以及有界的 Heap DDL。它不是完整的 SQL 方言。
| 类别 | 当前支持 | 当前不支持 |
|---|---|---|
| SELECT | 限定 / 非限定列、通配投影、LIMIT、类型化表达式、AS 别名、后缀 :: 转换 | DISTINCT、窗口函数、投影中的子查询 |
| FROM / JOIN | AS 与简写别名、链式 INNER JOIN … ON、NestedLoopJoin、HashJoin、IndexJoin | 外连接、USING、连接重排、merge join |
| 谓词 | AND / OR / NOT、比较、IS NULL、括号 | IN / BETWEEN / LIKE、子查询 |
| DML | 显式列清单或声明顺序的单行 INSERT、UPDATE、DELETE、可选 WHERE | 默认值、RETURNING、UPSERT |
| ORDER BY | 多源列键、ASC / DESC、NULLS FIRST / LAST | 别名、序号、任意排序表达式 |
| 聚合 | COUNT(*) / COUNT / SUM / MIN / MAX、源列 GROUP BY | HAVING、DISTINCT 聚合、分组表达式、ROLLUP |
| DDL | Heap CREATE TABLE(物理类型 v2)、DROP TABLE、ALTER TABLE(改名、可空 ADD、DROP、SET/DROP NOT NULL)、CREATE/DROP INDEX | PRIMARY KEY / UNIQUE / FK、IF EXISTS、限定名、LSM/范围组合、通用 ALTER COLUMN TYPE |
名义类型
Schema 列同时保留物理表示与可选的名义语义类型。HIR 在比较中要求名义兼容,因此上下文 NULL 类型也不能让 UserId = TeamId 合法。自连接通过查询局部的 RelationBindingId 区分同一 TableId 的两次出现。
physical: UINT64 semantic: UserId UserId ≠ TeamId even when both are u64
NULL 是数据库值
数据库 NULL 是显式的 ScalarValue::Null。Rust Option 留给缺席的子句或元数据。比较遇到 NULL 得到 UNKNOWN;IS NULL / IS NOT NULL 才是显式测试。AND / OR / NOT 使用 SQL 三值逻辑。WHERE 与 JOIN 的 ON 只保留 TRUE,FALSE 与 UNKNOWN 都被拒绝。
Bool(true) → TRUE Bool(false) → FALSE NULL → UNKNOWN NULL = NULL → UNKNOWN NULL IS NULL → TRUE
JOIN
别名会隐藏底层表名。限定列经由暴露的关系名解析;非限定列仅在恰好一个可见关系提供该名时被接受。每个 ON 能看见完整左子树与当前右关系,但不能看见更后的连接。默认算子为 NestedLoopJoin。ANALYZE 之后,两个扫描上的简单等值 INNER JOIN 在代价严格更低时可选 HashJoin 或 Index Nested-Loop Join。算子均按确定性的左主、右次顺序保留重复。
SELECT e.name, m.name
FROM employees e
JOIN employees m ON e.manager_id = m.id
WHERE e.active IS NOT NULL
ORDER BY e.name ASC NULLS LAST
LIMIT 20DML
类型化 DML 使用与堆写入相同的编译器、事务、整页 WAL、回滚与恢复路径。Database::execute 返回查询行或显式 AffectedRows(u64);query 拒绝变更语句。省略的可空 INSERT 列赋值为 NULL;省略的非空列将被拒绝。UPDATE 基于原始行求值全部右侧,因此 SET a = b, b = a 会交换两列。
INSERT INTO users (id, name) VALUES (1, 'Ada');
UPDATE users SET name = 'Ada Lovelace' WHERE id = 1;
DELETE FROM users WHERE name IS NULL;DDL
Heap 上的 CREATE TABLE、DROP TABLE、ALTER TABLE 与 CREATE/DROP INDEX 是事务性的。ALTER 支持改表名 / 列名、可空 ADD、受限 DROP 与 SET/DROP NOT NULL。后缀 :: 转换为精确宽度,没有隐式数值拓宽。LSM 与分区表不在该 SQL DDL 范围内。
CREATE TABLE events (
id BIGINT NOT NULL,
payload BYTEA NOT NULL
);
ALTER TABLE events ADD COLUMN note TEXT;
SELECT id::TEXT, payload FROM events;
DROP TABLE events;排序与聚合
普通计划是 Scan/Join → Filter → Sort → Project → Limit。聚合计划是 Scan/Join → Filter → Aggregate → Limit。键在投影之前、对着完整 FROM / JOIN 作用域解析,所以查询可以按它不返回的列排序。
COUNT(*) 计行;COUNT(column) 忽略 NULL。单独的全局 COUNT(column) 在 SeqScan 上可统计存在性而不物化行。数值 SUM 使用受检算术,并剥去名义含义。MIN / MAX 保留输入 SemanticType。分组键上的 NULL 共享一组,这与表达式里 NULL = NULL 仍为 UNKNOWN 不同。带 GROUP BY 的查询当前拒绝 ORDER BY。
SELECT team_id, COUNT(*), SUM(score), MAX(score)
FROM scores
GROUP BY team_id索引与 ANALYZE
create_index 与 SQL CREATE INDEX 在事务性回填后注册非唯一单列 Heap BTree。DROP INDEX 注销该注册。随后的堆与 SQL DML 会维护已注册索引。符合条件的等值与 IS NULL 谓词可选择点查 IndexScan;经过分析的双侧 Int64/UInt64 边界可选择范围 IndexScan。ANALYZE 为显式操作,DML 不会自动维护统计。
create_index(table, column)
→ transactional backfill
→ register in IndexCatalog
→ DML maintains the index
→ ANALYZE writes a cost snapshot
→ planner may choose IndexScan跨存储写入
create_tables 仍按表组合一个堆文件。范围分区表以及混合 Heap+LSM 目录经协调日志提交。派生列存投影不是权威存储。不提供并发写者。不提供可串行化隔离。