ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

AlaSQL 在 Chakra 引擎上的 SQL Logic Test 兼容性测试报告解读

AlaSQL 在 Chakra 引擎上的 SQL Logic Test 兼容性测试报告解读 嵌入式数据库数据工程【免费下载链接】alasqlAlaSQL.js - JavaScript SQL database for browser and Node.js. Handles both traditional relational tables and nested JSON data (NoSQL). Export, store, and import data from localStorage, IndexedDB, or Excel.项目地址https://gitcode.com/gh_mirrors/al/alasql点击查看免费下载导读本文以 AlaSQL 仓库中存档的 SQLlogic Chakra 测试报告 为骨架逐层拆解这份 2016 年 3 月生成的跨引擎 SQL 兼容性测试日志包括测试的运行环境与版本快照、SQLite 对标方法、190 个测试文件与 168 万余条断言的组织方式、失败样本的分类规律以及最终 90% 通过率的统计口径。读完本文你将理解如何阅读 AlaSQL 的 SQL 一致性测试产物、如何从失败样本反推实现弱点NULL 传播、类型转换、聚合函数、JOIN/GROUP BY 等并能借助仓库源码定位对应实现模块。一、报告背景一次以 SQLite 为镜像的引擎级回归测试这份报告的全称是SQLlogictest results for AlaSQL - on Chakra v6.0.0-pre5记录的是一次在Microsoft ChakraEdge 的 JS 引擎v6.0.0-pre5上运行的 SQL 一致性测试。报告中明确写下了运行时刻与目标版本2016-03-01T15:19:47.954Z target: alasql0.2.3-develop-1216被测对象alasql0.2.3-develop-1216即当时的开发分支版本运行环境Chakra v6.0.0-pre5。同目录下的 Chakra.md 记录了同一环境上普通单元测试套件的输出其中 Environment detected 显示isNode: true、alasqlPath: C:\Users\mrw\git\alasql\dist可以推断这套 logictest 是跑在Node.js 宿主上的 Chakra 引擎而非浏览器这对理解错误信息中的 Unable to get property xxx of undefined or null reference 这类 Chakra 特有报错有帮助——它对应 V8 里的Cannot read property xxx of undefined。报告中明确说明This is a subset of the total 622 tests. Results from 190 test files.即完整 SQLLogicTest 套件共有 622 个测试文件本次在 Chakra 上执行了其中 190 个文件属于一次受控的子集运行。同套件的跨引擎对照仓库test/!testlog/目录下还保留着同一套测试在不同引擎/环境下的结果SQLlogic.mdalasql0.3.2 时代、620 个文件的全量运行以及 Chrome.md、Firefox.md、Edge.md、IE.md、Safari.md 等浏览器运行日志。将这些文件对照阅读可以纵向观察 AlaSQL 兼容性的演进横向对比同一 SQL 语句在不同 JS 引擎上的失败差异——例如 Chakra 报告中的 Unable to get property 0 of undefined or null reference 在 Node/V8 的 SQLlogic.md 中对应的是 Cannot read property 0 of undefined错误本质相同只是引擎措辞不同。二、测试方法与结果格式看懂每一段日志2.1 Mimic sqlite 的含义每个测试文件块都以_Mimic sqlite_开头。这表示运行方式是将SQLite 作为参考实现oracleSQLLogicTest 套件中的每条 SQL 语句先在 SQLite 上执行得到期望结果再交给 AlaSQL 执行得到实际结果两者逐条对比。这与本仓库 test128-B.js 中注释 Test 128-B CROSS JOIN with parentheses (sqllogictest) 以及 test130-B.js 中 Test complex case from sqllogictest 的做法一脉相承——仓库把 sqllogictest 的典型反例沉淀成了常规回归用例。2.2 三种结果标记★全对该文件全部通过并伴随一行sqlite N OK: path摘要例如#### ★ Ran 7 tests as _sqlite_ * 100% was OK sqlite 7 OK: ./test/evidence/slt_lang_reindex.test☓有失败该文件存在至少一条失败用例随后列出每个失败样例的 SQL 语句与实际报错/差异。无标记极少数文件既无失败样例也无统计如#132 ./test/index/view/10/slt_good_0.test只记录了耗时。2.3 每个文件块的统计字段每个测试文件块末尾给出四组数据它们是评估兼容性的最小单元字段含义示例Ran N tests as _sqlite_该文件实际执行的断言数Ran 216 tests as _sqlite_N skipped因前置语句失败setup 失败而跳过的用例数148 skippedN failed与 SQLite 期望不一致的用例数19 failedN% was OK通过率22% was OKTime该文件耗时Time: 501.461ms当某条用于**准备数据setup**的语句失败时日志会打印 Fail found for statement setting up data so skipping rest of tests后续依赖该数据的用例被整体跳过——这就是 skipped 数量庞大的直接原因例如 test/index/view/10/slt_good_0.test 中CREATE VIEW ... IN (SELECT ...)触发Unable to get property columns of undefined or null reference后一次跳过 7,698 条用例。2.4 失败样例的三类输出报告中每条失败样例都是SQL 语句 差异描述的格式归纳起来有五种典型形态结果值不一致Expected: [0] but got [0.500]——期望是0实际得到0.500行数不一致10 results returned but expected 9或1000 results returned but expected 491期望报错但未报错Expected to get an error but did not语义完整性未达 SQLite 标准引擎级运行时异常Unable to get property t1 of undefined or null reference、g is undefined、Unable to get property toString of undefined or null reference解析失败Parse error on line 1: ...后附 Jison 解析器的期望 token 列表例如Expecting EOF, WITH, RPAR, PIVOT, ...。特别注意日志末尾的Please note that repetetive errors are not always printed again说明重复错误不会重复打印——即列出的样例只是各类失败的代表不是完整清单实际失败数以统计字段为准。三、总结果与分布90% 通过率的由来报告末尾的## Final result汇总了整次运行* Total tested: 1,683,641 * Failed tests: 114,412 * Skipped tests: 53,316 * Final score: 90 % was OK Total script time: 12842129.664ms值得说明的计算口径1,683,641是 190 个文件 Ran N tests 的总和总通过率按(Total tested − Failed) / Total tested计算约为 90%但 skipped 的 53,316 条不在基数内因此 90% 是已执行断言的通过率而非全部用例的通过率。总脚本耗时约 12,842 秒约 3.6 小时主要被大规模 index 测试占据——单个文件如#147 ./test/index/view/10000/slt_good_0.test就耗时 3,477,844ms约 58 分钟。3.1 各功能域的通过率梯度把 190 个文件的% was OK按测试类别汇总可以画出一条清晰的兼容性曲线类别代表文件通过率区间平均表现evidence语法特性in1、in2、aggfunc、createview、droptable 等22% ~ 92%中等index/between、commute、delete、in、orderby、orderby_nosort大量slt_good_*.test99% ~ 100%优秀index/randomrandom/10、random/100、random/100090% ~ 96%良好index/viewview/10、view/100、view/1000、view/100004% ~ 97%波动极大random/aggregatesaggregates/slt_good_0 ~ 983% ~ 86%待改进random/groupbygroupby/slt_good_0 ~ 953% ~ 94%薄弱random/exprexpr/slt_good_0 ~ 978% ~ 88%薄弱random/selectselect/slt_good_0 ~ 984% ~ 87%中等综合 select1/select2/select3select1 ~ select389% ~ 100%良好规律非常明显纯 WHERE 过滤 BETWEEN/IN/ORDER BY 的 index 类测试几乎全绿而涉及 NULL 语义、类型转换、聚合、GROUP BY 和视图的测试是主要失分点。四、失败样本深度剖析从错误反推实现弱点这一节挑选报告中出现频率最高、最具代表性的失败模式逐一说明其背后的 SQL 语义并结合仓库源码给出排查方向。4.1 NULL 与 CAST 语义CAST(NULL AS INTEGER)应为 NULL 却得到 0这是全报告出现次数最多的单点问题遍布 random/aggregates、random/expr、random/select、random/groupby 几乎所有文件SELECT DISTINCT - CAST ( NULL AS INTEGER ) AS col2 FROM tab0 WHERE NULL IS NULL Expected: [NULL] but got [0] SELECT ALL CAST ( NULL AS INTEGER ), ( COUNT ( * ) ) FROM tab0 WHERE NOT 26 IS NULL Expected: [NULL,10] but got [0,10]SQLite 语义中CAST(NULL AS INTEGER)的结果是 NULL且 NULL 参与四则运算应传播 NULLNULL 1 NULL。而当时 AlaSQL 在 Chakra 上的行为是把CAST(NULL AS INTEGER)当成0直接破坏了 NULL 传播链进而引发连锁差异SELECT CAST ( NULL AS INTEGER ) col1 - 68 col0 * col2 AS col2 FROM tab2 Expected: [NULL,NULL,NULL] but got [1041,2569,4349]从源码结构看CAST 与类型转换相关的实现集中在 59convert.jsNULL 传播与三值逻辑相关逻辑在 50expression.js 与 57case.js 中。若想复现排查可以先用本地版本执行alasql(SELECT CAST(NULL AS INTEGER))观察返回值是0还是NULL。4.2 一元负号与 NULL 聚合-MIN(col)应为 NULL 却得到-73SELECT ALL - MIN ( ALL 73 ) AS col4 FROM tab0 cor0 WHERE NOT 35 NULL Expected: [NULL] but got [-73]当 WHERE 条件过滤掉全部行时MIN/MAX/SUM 等聚合函数应返回 NULLSQLite 行为而当时实现返回了具体数值或对常量聚合直接求值。同类还包括SELECT MIN ( 67 ), 63 / - CAST ( - COUNT ( * ) AS INTEGER ) AS col2 Expected: [67,63] but got [67,NULL]聚合函数定义可查看 55functions.js空集聚合的边界行为是排查重点。4.3 整数除法SQLite 整除 vs JavaScript 浮点大量形如下面的失败揭示了一个 JS 移植 SQL 引擎的经典问题——除法结果的取整策略SELECT DISTINCT 20 / - 97 FROM tab0 Expected: [0] but got [-0.206] SELECT ALL 55 / ( COUNT ( * ) ) FROM tab0 cor0 WHERE col5 IS NOT NULL Expected: [5] but got [5.500] SELECT - 40 / col2 AS col2 FROM tab2 AS cor0 Expected: [-1,-1,0] but got [-0.690,-1,-1.739]SQLite 的/在操作数都是整数时执行整数除法截断而 JavaScript 的/总是产生浮点数。这一差异在报告 148 号文件aggregates/slt_good_0到 187 号文件random/select/slt_good_9之间反复出现是最容易量化的兼容性缺口。相关除法与运算逻辑可在 50expression.js 中定位。4.4 隐式类型转换CAST(NULL AS REAL)直接抛错SELECT CAST ( NULL AS REAL ) FROM tab0 AS cor0 WHERE NOT NULL IS NOT NULL Wrong conversion type SELECT - CAST ( NULL AS REAL ) - 63 - 61 FROM tab1 Wrong conversion type报告中的Wrong conversion type是引擎级异常对应 Chakra 抛出的类型转换错误并非 SQL 层面的预期结果。说明 REAL/浮点类型的 NULL 转换在当时实现中未覆盖。同时还有一个典型报错g is undefined出现在对聚合结果做 CAST 的场景SELECT CAST ( SUM ( ALL - 37 ) AS INTEGER ) AS col2 FROM tab0 AS cor0 g is undefined从报错形式可以推断这是聚合/CAST 求值链中某个变量g未初始化属于实现缺陷而非语义差异。4.5 IN 与子查询列引用被当作表名evidence 目录下的in1.test、in2.test暴露了一个解析层面的问题SELECT 1 IN t1 Unable to get property t1 of undefined or null reference SELECT 1 FROM t1 WHERE 1 IN (SELECT 1,2) Expected to get an error but did not第一条期望1 IN t1t1 为单列表时按列语义处理实际却把t1当作对象访问导致运行时异常第二条1 IN (SELECT 1,2)在 SQLite 中应因子查询返回多列而报错AlaSQL 却静默通过了——说明当时对 IN 子句的参数校验不严。IN/EXISTS 相关实现位于 41exists.js 与 50expression.js。4.6 触发器与视图DDL 对象的生命周期缺陷evidence 与 index/view 两类测试集中暴露了 AlaSQL 在对象级 DDL上的不成熟CREATE TRIGGER t1r1 UPDATE ON t1 BEGIN SELECT 1; END; Expected to get an error but did not -- SQLite 不允许无 FOR EACH ROW 的触发器 DROP TRIGGER t1r1 Unable to get property beforeinsert of undefined or null reference -- 内部 beforeinsert 钩子未初始化 CREATE VIEW view_1_tab0_153 AS SELECT pk, col0 FROM tab0 WHERE col0 IN (SELECT col3 ...) Unable to get property columns of undefined or null reference -- 视图元数据缺失beforeinsert、columns这类内部属性名可以在 71trigger.js、24view.js 中找到对应结构报告显示 DROP TRIGGER 与复杂 CREATE VIEW 在当时版本上会触发 Chakra 的空引用异常。同时视图查询本身也存在结果全为 NULL的系统性问题如Expected: [1,4,5,7,9] but got [NULL,NULL,NULL,NULL,NULL]说明视图在当时的实现中并未真正物化或正确投影查询结果。4.7 GROUP BY分组后列引用全部丢失random/groupby 系列是全报告通过率最低的域53% ~ 70%代表性失败SELECT - tab1.col0 * 84 38 AS col2 FROM tab1 GROUP BY tab1.col0 Expected: [-1810,-2314,-6850] but got [NULL,NULL,NULL] SELECT ALL tab2.col1 col2 FROM tab2 GROUP BY col1 Expected: [41,59,61] but got [NULL,NULL,NULL] SELECT col0, - col0 AS col0 FROM tab0 AS cor0 GROUP BY col0, col2 Expected: [26,-26,43,-43,83,-83] but got [26,43,83]三类典型问题分组键上的表达式无法求值、分组后的非聚合列引用返回 NULL、同一列以两种形式出现在 SELECT 中时被去重。分组实现位于 423groupby.jsHAVING 相关在 425having.js。4.8 笛卡尔积与 DISTINCT结果行数系统性偏少random/select 中反复出现N results returned but expected M且 M 恰好是 N 的倍数SELECT DISTINCT * FROM tab0, tab0 cor0 WHERE NULL IS NULL 18 results returned but expected 54 -- 3×3 表笛卡尔积应为 9 行却只返回 3 行 SELECT DISTINCT * FROM tab2 AS cor0 CROSS JOIN tab0 AS cor1 18 results returned but expected 54 SELECT DISTINCT * FROM tab2, tab2 AS cor0, tab2 AS cor1, tab1, tab0 AS cor2 45 results returned but expected 3645可以看出当时的SELECT DISTINCT *在多表笛卡尔积场景下先做了行去重再求积导致行数系统性缩水。CROSS JOIN 的多表组合也有解析问题SELECT ALL * FROM tab1 cor0 CROSS JOIN tab1, tab2 AS cor1 Parse error on line 1: ... cor0 CROSS JOIN tab1, tab2 AS cor1 Expecting LITERAL, BRALITERAL, EOF, WITH, AS, RPAR, PIVOT, UNPIVOT, ...即CROSS JOIN 后接逗号分隔多表的语法在当时的 alasqlparser.jison 文法中不被接受。JOIN 执行逻辑可查 421join.js 与 39dojoin.js。4.9 标量相关子查询与 CASE列顺序与条件求值偏差综合文件 select2.test / select3.test 中的失败则偏向复杂查询编排SELECT a, (SELECT count(*) FROM t1 AS x WHERE x.bt1.b), ... FROM t1 WHERE a IS NULL Expected: [NULL,1,NULL,114,NULL,18,NULL,207] but got [NULL,18,NULL,207,NULL,1,NULL,114]行数相同但列顺序错乱——子查询结果被放错了列位而CASE WHEN ... ELSE 555 END类的用例出现 hash 不一致说明 CASE 分支求值顺序与 SQLite 存在差异。相关实现见 57case.js 与 38query.js。五、测试文件的路径语义与复现方法报告中每个文件块的标题都带原始路径例如./test/index/between/10/slt_good_0.test。路径分段含义如下evidence/手工编写、覆盖特定 SQL 特性的证据用例in、aggregate 函数、触发器、视图、索引等index/按 SQL 特性分组的自动化用例between、commute、delete、in、orderby、orderby_nosort、random、view数字10/100/1000/10000表示表行数规模random/随机生成的表达式expr、聚合aggregates、分组groupby、选择select压力用例select1/2/3.test综合查询用例。这些.test文件由外部的 alasql-logictest 项目托管仓库内无法直接运行但 AlaSQL 已将 sqllogictest 的典型反例沉淀进常规测试可在仓库内直接复现与回归test128-B.jsCROSS JOIN with parentheses (sqllogictest)test130-B.js来自 sqllogictest 的复杂组合查询用例。此外测试入口为 test/test.jspackage.json 中的test-ci脚本会串联格式检查、单元测试与安装验证见 package.json 的scripts.test-ci。想本地快速验证某条失败 SQL可直接通过 AlaSQL 的 Node API 执行const alasql require(alasql); console.log(alasql(SELECT CAST(NULL AS INTEGER))); // 验证 NULL 转换语义 console.log(alasql(SELECT DISTINCT 20 / - 97)); // 验证整数除法 console.log(alasql(SELECT * FROM tab0, tab0 cor0)); // 验证笛卡尔积以报告中的失败语句为输入、SQLite 输出为期望即可构造最小复现用例。六、结论这份测试报告告诉我们什么6.1 报告的价值定位这份存档不是修复清单而是一份兼容性体检单它量化了 AlaSQL 在 Chakra 引擎上对 SQLite 语义的符合程度并把每条差异精确到语句级。将它与 SQLlogic.mdalasql0.3.2620 文件全量对照可以看到从 0.2.3-develop-1216 到 0.3.2 期间兼容性的演化轨迹将它与 Chrome.md 等浏览器日志对照可以区分SQL 语义缺口与引擎平台差异两类问题。6.2 失败模式的优先级排序从出现频率与影响面综合来看当时的失分点可归为四档NULL 三值逻辑与 CAST 语义CAST(NULL AS INTEGER)→ 0、NULL 传播中断——影响面最大波及 aggregates/expr/select/groupby 全部域整数除法与类型系统/的截断语义、Wrong conversion type、g is undefined——影响表达式求值GROUP BY / 视图 / 触发器 / 相关子查询——影响中大型查询与 DDL 对象其中 groupby 通过率低至 53%view 系列波动 4% ~ 97%多表笛卡尔积与 DISTINCT、CROSS JOIN 文法——影响多表查询的正确性。6.3 可验证的源码落点对应上述问题仓库内的排查入口分别是NULL/类型转换见 59convert.js、50expression.js聚合函数见 55functions.js分组与 HAVING 见 423groupby.js、425having.jsJOIN 见 421join.js、39dojoin.js视图与触发器见 24view.js、71trigger.js文法见 alasqlparser.jison。这些模块共同决定了 AlaSQL 对 SQLite 语义的符合度也是后续版本迭代中逐个修复的重点对象。参考资料仓库内测试日志SQLlogic Chakra本文主体数据来源测试日志SQLlogic全量对照Chakra 环境单元测试日志sqllogictest 反例回归CROSS JOINsqllogictest 反例回归复杂查询测试入口package.json 测试脚本赞分享嵌入式数据库数据工程【免费下载链接】alasqlAlaSQL.js - JavaScript SQL database for browser and Node.js. Handles both traditional relational tables and nested JSON data (NoSQL). Export, store, and import data from localStorage, IndexedDB, or Excel.项目地址https://gitcode.com/gh_mirrors/al/alasql点击查看免费下载相关推荐微信QQ TIM防撤回补丁5分钟装好撤回的消息也能留个底微信QQ TIM防撤回补丁5分钟装好撤回的消息也能留个底 凌晨一点工作群里客户发来一段需求确认你刚复制到一半屏幕弹出一行灰字——对方撤回了一条消息桌面应用即时通讯3个窗口克隆技巧用OnTopReplica重新定义Windows多任务工作流3个窗口克隆技巧用OnTopReplica重新定义Windows多任务工作流 在数字时代的办公环境中我们常常陷入多窗口切换的困境一边查看监控数据一边编写百元 ESP32-C3 AI 机器狗搭建全记录唤醒对话、表情屏、动作库一次配齐百元 ESP32 C3 AI 机器狗搭建全记录唤醒对话、表情屏、动作库一次配齐 一块 ESP32 C3 主控不到百元的全部物料就能做出一只听得见唤醒词、聊人工智能大模型语音交互助手嵌入式物联网智能硬件MCP 服务上一篇【限时开放】装备库升级让沙发发如虎添翼的五大生态工具下一篇【限时免费】 Yi-Coder项目深度解析自然语言转SQL的完整实现指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表