ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

SpacetimeDB SQL:2016 一致性测试引擎 sqltest:架构、使用与已知问题清单

2026/9/13 10:10:23 拓冰建站 浏览量
SpacetimeDB SQL:2016 一致性测试引擎 sqltest:架构、使用与已知问题清单 SpacetimeDB SQL:2016 一致性测试引擎 sqltest架构、使用与已知问题清单【免费下载链接】SpacetimeDBDevelopment at the speed of light项目地址: https://gitcode.com/GitHub_Trending/sp/SpacetimeDB导读本文介绍 SpacetimeDB 仓库中专门用于检验其 SQL 引擎是否符合 SQL:2016 标准的内部测试 crate——sqltest位于 crates/sqltest。该 crate 以 PostgreSQL 与 SQLite 作为对照引擎把同一套基于 SQL:2016 特性分类Feature Taxonomy的测试用例同时跑在三套引擎上从而量化 SpacetimeDB 的 SQL 符合程度并沉淀出一份可追溯的“已知问题清单”。读完本文你将掌握该测试框架的目录结构、三引擎对比架构、命令行用法、PostgreSQL 前置环境配置以及 README 中记录的六大兼容性问题的来龙去脉。什么是 sqltestSpacetimeDB 的 SQL:2016 一致性测试器sqltest是一个**内部专用Internal Crate**的 SQL 集成测试工具其定位在 Cargo.toml 中描述为 Sql integration test for SpacetimeDB在 README 中明确说明其目标This crate check the conformance of SpacetimeDB to SQL:2016也就是说它并不测试业务功能而是回答一个基础问题SpacetimeDB 的 SQL 方言距离 SQL:2016 国际标准有多远。它没有对外发布publish false且被标注为不稳定、可能随时变化仅供仓库内部开发与回归验证使用。在实现上它 fork 自 RisingLight 数据库社区的sqllogictest-rs工具链见 main.rs 的注释并针对 SpacetimeDB 做了深度定制核心依赖包括sqllogictest标准 sqllogictest 格式的解析与运行器spacetimedb-lib、spacetimedb-core、spacetimedb-sats直接驱动 SpacetimeDB 自身存储引擎执行 SQLtokio-postgres/postgres-types/rusqlite分别驱动 PostgreSQL 与 SQLite 作为对照引擎quick-junit生成 JUnit XML 格式测试报告便于接入 CIclap命令行参数解析。三引擎对照架构同一份用例三种实现sqltest 最核心的设计思想是对照测试cross-engine validation同一批.slt用例文件可以被投喂给三种不同的引擎执行用引擎间的结果一致性来交叉验证 SpacetimeDB 的行为。三种引擎由 main.rs 中的DbType枚举定义可通过--engine参数选择引擎实现文件说明SpacetimeDB默认space.rs使用TestDB::durable()创建内存/持久化测试实例走spacetimedb::sql::execute::run真实执行路径Sqlitesqlite.rs基于rusqlite在临时目录中创建临时库Postgrespg.rs通过tokio-postgres连接本地TestSpace数据库三个实现都实现sqllogictest::AsyncDBtrait并在 db.rs 的DBRunner枚举中统一分发 SQL。值得注意的细节是SpacetimeDB 引擎在 space.rs 中通过ModuleSubscriptions::for_test_new_runtime创建订阅运行时再调用run执行 SQL 并收集列类型Kind与行数据也就是说它走的是与生产环境基本一致的执行链路而非 mock。列类型映射把三种引擎的元数据归一化由于三套引擎的数据类型体系不同sqltest 定义了一个统一的列类型Kind见 space.rs用单个字符标识 sqllogictest 中的类型B→BoolT→StringI→ 整数类型R→ 浮点类型!→ Sum / Product / Ref 等组合类型?→ ArrayPostgreSQL 一侧在 pg.rs 做了更细的类型翻译VARCHAR/TEXT/BPCHAR/NAME/UNKNOWN→ StringINT2/INT4/INT8→ 对应位宽整数FLOAT4/FLOAT8→ F32/F64DATE/TIME/TIMESTAMP/TIMESTAMPTZ统一按字符串输出。输出归一化让三引擎结果可对齐为了让三种引擎的输出可以直接逐字比较sqltest 做了大量归一化工作这些细节本身就是理解“符合性”含义的关键布尔值统一输出为1/0见 space.rs 注释For compat with sqlitePG 侧在 pg.rs 也做了同样处理字符串统一带单引号输出如health1浮点数用 Rust 的{:?}格式输出保证三端格式一致空结果集返回StatementComplete(0)有结果集时返回DBOutput::Rows。测试资产从标准特性分类到可执行用例sqltest 的测试用例不是手写的零散 SQL而是从SQL:2016 标准附录 FAnnex F: SQL feature taxonomy中系统化推导出来的整个流水线可见于目录结构crates/sqltest/ ├── standards/2016/ # 按特性编号组织的 YAML 用例源 │ ├── features.yml # 标准特性分类表mandatory 等分级 │ ├── E/ # 核心特性E011 数值、E021 字符、E031 标识符、E051 查询规格... │ ├── F/ # 核心扩展 │ ├── S/ # 模式相关 │ └── T/ # 临时相关 ├── test/ │ ├── sql_2016/ # 由 YAML 生成/对齐的 .slt 可执行用例 │ └── basic/ # 基础冒烟用例insert/select/delete/joins/where ├── build_standard.py # 从 standards YAML 构建用例的脚本 ├── reformat.sh # 用例格式化 └── override_with_output.sh # 用实际输出回写用例features.yml标准的“目录”features.yml 逐条记录了 SQL:2016 附录 F 的特性分类并按mandatory强制特性分级例如E011: Numeric data types数值类型含 INTEGER/SMALLINT/REAL/DOUBLE PRECISION/FLOAT/DECIMAL/NUMERIC 等子特性E021: Character string types字符类型含 CHARACTER 及其全部拼写、VARCHAR、字符字面量、CHARACTER_LENGTH/OCTET_LENGTH/SUBSTRING/UPPER/LOWER/TRIM/POSITION等函数E031: Identifiers标识符规则E051: Basic query specificationSELECT DISTINCT、GROUP BY、HAVING、限定*等。standards YAML与标准一一对应的用例源每个特性对应一个*.tests.yml逐条列出该特性的测试 SQL。例如 E021-01.tests.yml 中CHAR(8 CHARACTERS)、CHAR(8 OCTETS)、CHAR、CHARACTER(8)等所有拼写形式都有对应条目每条用feature:/id:/sql:三段式描述。.slt 可执行用例带预期结果与跳过标记.slt文件是真正喂给运行器的格式分为三类记录statement ok/statement error断言语句执行成败query 类型串 [rowsort]查询并断言结果集类型串如IT整数文本、TIinclude嵌入其他用例文件如 select.slt 首行include ./test_data.slt。对于已知不支持的语法用例会以注释形式保留并标注对应的 issue 编号例如 E021_01.slt# (UNSUPPORTED: issue 1) statement ok # CREATE TABLE TABLE_E021_01_01_02 ( A CHAR ( 8 CHARACTERS ) )这样既保留了标准的完整性又明确记录了 SpacetimeDB 的偏离点。sqllogictest 格式还支持condition标签skipif/onlyifmain.rs 中实现了should_skip逻辑可针对不同引擎名SpacetimeDB/Sqlite/Postgres做条件跳过。命令行用法运行、覆盖与格式化sqltest 是一个独立的 Rust 二进制#[tokio::main]通过 main.rs 的 clap 参数定义参数说明默认值files位置参数必填测试文件的 glob 模式支持./test/**/*.slt这种写法无-e, --engine ENGINE引擎SpacetimeDB/Sqlite/PostgresSpacetimeDB--color WHEN输出颜色auto/always/neverauto-j, --jobs N并行测试每个测试文件会创建一个独立数据库串行--override用数据库的真实输出回写覆盖测试文件关闭--format仅格式化测试文件不执行 SQL关闭典型用法示例# 用默认的 SpacetimeDB 引擎运行全部 SQL:2016 与基础用例 cargo run --coloralways ./test/**/*.slt # 指定引擎 cargo run --coloralways ./test/**/*.slt --engine Sqlite cargo run --coloralways ./test/**/*.slt --engine Postgres # 只跑某个特性 cargo run ./test/sql_2016/E021_*.slt # 用实际输出更新用例文件 cargo run ./test/**/*.slt --override # 仅格式化 cargo run ./test/**/*.slt --format仓库还提供了便捷脚本 run_all_sequential.sh其内部等价于cargo run --coloralways ./test/**/*.slt --engine $1另外两个配套脚本 override_with_output.sh 与 reformat.sh 分别对应--override与--format的工作流。--override的实现细节在 main.rs它会先写临时.temp文件、剥离多余换行再原子重命名回原文件并支持嵌套include文件的递归回写。运行结果与 JUnit 报告运行器会实时输出每个文件的进度[OK]/[SKIP]/[FAILED]含耗时毫秒数最终汇总出 FAILED / SKIP / OK / PASS 百分比 / Elapsed 统计见 main.rs。同时每个用例都会被包装成TestCase写入quick-junit的TestSuite套件名sqllogictest失败用例带有完整的系统错误信息方便 CI 解析与归档。并行模式说明--jobs支持并行执行其设计约束在参数说明中写得很清楚每个测试文件会创建独立的数据库实例One database will be created for each test file因此并行不会产生跨文件的状态污染。从 main.rs 可以看到每个文件都通过Runner::new(|| open_db(engine))惰性创建自己的连接。前置条件PostgreSQL 环境配置README 中关于环境的说明非常简短但关键Setup PGCreate a database calledTestSpace对应的实现位于 pg.rsPG 引擎启动时使用tokio_postgres::connect(postgresql://postgreslocalhost/TestSpace, NoTls)连接本地 PostgreSQL因此运行--engine Postgres前必须本机启动 PostgreSQL 服务创建名为TestSpace的数据库当前用户postgres可免密或通过本地认证访问。连接建立后sqltest 会先执行一段SQL_DROP存储过程pg.rs清空所有非系统 schema 与role_%开头的角色确保测试环境干净可复现。SQLite 引擎则不需要任何外部服务在临时目录中自动创建库文件sqlite.rs。已知问题清单SpacetimeDB 与 SQL:2016 的偏离点README 的核心章节以“Issues”形式记录了一致性测试执行中发现的问题每类问题都标注了分类标签。这是全文最有价值的部分以下逐条展开并补充源码层面的证据。UNSUPPORTED: issue 1 —CHARACTERS/OCTETS长度单位不受支持CREATE TABLE TABLE_E021_01_01_02 ( A CHAR ( 8 CHARACTERS ) ) CREATE TABLE TABLE_E021_01_01_02 ( A CHAR ( 8 OCTETS ) )SQL:2016 的E021-01特性要求CHAR/CHARACTER支持显式长度单位CHARACTERS表示字符数、OCTETS表示字节数。PG 和 SQLite 都没有实现该语法因此 SpacetimeDB 也选择了不支持。从用例文件 E021_01.slt 可以看出CHAR(8)、CHAR、CHARACTER(8)等基础拼写都是statement ok通过的唯独带长度单位的写法被注释跳过。UNSUPPORTED: issue 2 —CHAR VARYING拼写不受支持CREATE TABLE TABLE_E021_02_01_02 ( A CHAR VARING ( 8 CHARACTERS ) )E021-02特性要求CHARACTER VARYING类型支持全部拼写形式包括CHAR VARYING、CHARACTER VARYING、VARCHAR。由于PG 与 SQLite 均未实现该拼写被列为不支持。注意用例中保留了原文档的拼写错误VARING这正说明了这条用例来自标准特性描述、尚未在 SpacetimeDB 侧启用。UNSUPPORTED: issue 3 — 重命名 select 列表的AS (C, D)语法SELECT * AS ( C , D ) FROM TABLE_E051_07_01_01SQL:2016 允许在 select 列表中通过AS (C, D)一次性重命名多个列对应E051-09等重命名特性。该写法在PG 与 SQLite 上都是语法错误因此 SpacetimeDB 同样不支持。REPLACED: issue 4 —CURRENT_TIME与timetz类型SELECT CURRENT_TIME这条被标记为REPLACED被替换而非 UNSUPPORTED因为问题不在 SQL 语法本身而是参考实现 PG 官方明确不建议使用timetz带时区的TIME类型其 wiki 上将其标注为 Dont use EVER。既然对照引擎 PG 都放弃了该类型SpacetimeDB 的CURRENT_TIME语义也就以 PG 的现行行为为准相关用例从“必须符合标准”调整为“以 PG 实现为参照”。UNSUPPORTED: issue 5 —CASE的WHEN子句中列表比较SELECT CASE 0 WHEN 2 , 2 THEN 1 ENDSQL 标准允许CASE x WHEN v1, v2 THEN ...形式的简写等价于x v1 OR x v2。该写法在PG 与 SQLite 上都是语法错误因此 SpacetimeDB 亦不支持。WRONG: issue 6 — 无时区TIME到TIMESTAMP的隐式转换SELECT CAST ( CAST ( 01:02:03 AS TIME ) AS TIMESTAMP )这条被标记为WRONG行为错误是清单中唯一一条“三引擎行为都不正确”的案例PG因缺乏时区信息而报错失败SQLite给出一个无意义的返回值1因此在 SpacetimeDB 中该转换同样不可靠属于需要标准仲裁的语义盲区。问题清单的管理意义从源码可以看到这套“已知问题清单”并不是一次性产物而是与用例文件强耦合的活文档每个 issue 的编号issue 1~issue 6都出现在 test/sql_2016 目录对应.slt文件的注释中如# (UNSUPPORTED: issue 1) statement ok。当未来某个特性在 SpacetimeDB 中落地时只需把对应注释行解除注释、跑通用例再同步更新 README 清单即可。这种“文档 — 用例 — 引擎实现”三方联动的方式保证了符合性追踪不会失真。从测试驱动看 SpacetimeDB 的 SQL 演进路径综合来看sqltest 为 SpacetimeDB 的 SQL 引擎提供了三层价值符合性度量以 SQL:2016 附录 F 的特性分类为纲系统化回答“哪些特性已支持、哪些未支持”跨引擎一致性通过 SQLite / PostgreSQL 双对照引擎交叉验证避免自说自话README 中几乎每个 UNSUPPORTED 条目都注明“PG 与 SQLite 也未实现”这为 SpacetimeDB 的取舍提供了行业依据回归保障基础用例集test/basic与--override回写机制让 SQL 引擎的每次变更都能被快速验证JUnit 输出则可无缝接入 CI 流水线。如果你希望在本地验证 SpacetimeDB 的 SQL 能力最直接的入口就是运行cargo run -p sqltest --coloralways ./test/**/*.slt并结合--engine Sqlite/--engine Postgres需先创建TestSpace数据库观察三种引擎在同一批用例上的表现差异。对于深入实现细节的读者建议从 db.rs、space.rs、pg.rs 三个适配器读起它们共同构成了 sqltest 的三引擎抽象核心。【免费下载链接】SpacetimeDBDevelopment at the speed of light项目地址: https://gitcode.com/GitHub_Trending/sp/SpacetimeDB创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考