fix: #436 improve SQL keyword suggestions - #485
Conversation
|
|
| const candidates = this.collectSuggestionCandidates( | ||
| sqlParserIns, | ||
| parseTree, | ||
| caretTokenIndex | ||
| ); |
There was a problem hiding this comment.
collectSuggestionCandidates 在最坏情况下会跑 3 次 collectCandidates(整棵树 + 语句树 + 仅在首次缓存的语句起始 token 集)。常见未切片场景是 2 次。对大 SQL 输入这是可感知的额外开销。建议补充一个针对大输入的 benchmark,确认回归在可接受范围。
There was a problem hiding this comment.
三次 collectCandidates 是「两层隔离」保证正确性的刻意设计——Issue 436 之前的单次 C3 正是把下一条语句的 SELECT/CREATE/INSERT 混进当前补全的根源。三步各司其职:
- program —— 保留外层 rule path、syntax 候选与上下文;
- statement 子树 —— 过滤下一条语句的起始关键字,保留
LOCK IN SHARE MODE等组合关键字; - token 0(仅首次,缓存在
_statementStartTokenTypes) —— 得到语句起始关键字集合,只删 SELECT/CREATE/INSERT 这类起始词。
调用次数:首次最多 3 次,后续 2 次,分号后或无需隔离 1 次。
不能砍掉 statement 那次,否则退化回 Issue 436 之前的错误(复核确认会丢 MySQL LOCK IN SHARE MODE、Impala WITH SERDEPROPERTIES,嵌套查询也会重新混入顶层起始关键字)。
性能 A/B 对比(热启动 50 次取中位数):
| 场景 | 修复前 | 修复后 |
|---|---|---|
SELECT ... WHERE ... (无分号末尾) |
0.78 ms / 93 关键词 | 1.75 ms / 28 关键词 |
60 行 SELECT 的 FROM 之后 |
3.6 ms | 5.8 ms |
额外成本就是一次等量 statement C3,毫秒级,误报的 SELECT/INSERT/CREATE 全部消失(93→28),可接受。
benchmark 方面:benchmark:release 冷启动的 clearATNCache() 存在预先存在的内存泄漏(每次 +30MB 无法 GC,累积 OOM),与本次改动无关,故改用手工测量;OOM 我会另开 issue 跟进。
结论:接受首次 3 次、后续 2 次的实现。
| const children = parseTree.children; | ||
| if (!children?.length) return parseTree; | ||
|
|
||
| for (let index = children.length - 1; index >= 0; index--) { |
There was a problem hiding this comment.
你这里是只向下看一层,它假设 program 的直接子节点就是语句。一旦文法把语句包了一层中间规则(如 program → batch → statement,或 list 规则),收窄会静默回退到整棵树,修复悄悄失效且无报错,确认下这个链路在这种情况下是否有问题?是否需要加一条断言/测试守护该假设?
There was a problem hiding this comment.
已经加了守护测试:suggestion.test.ts 的用例遍历全部方言,断言 SELECT * FROM t; SELECT * FROM u 解析出的 program 直接子节点恰好是两个 statement。
所有方言 grammar 都是 program: (statement SEMI?)* 扁平结构,直接子节点即语句;只向下看一层是刻意的,避免误选嵌套语句/子查询(见 getSuggestionParseTree 上方注释)。
若未来引入中间规则,这条测试会立即失败暴露,不会静默回退。
换行不会触发补全提示,空格会触发。测试了下,修改后按空格依旧是可以出发补全提示的。 |
本次改动
Fixes #436 优化光标位置的 SQL 关键字补全:
SELECT等下一语句起始关键字keywordFilter回调,支持调用方自定义过滤API 使用方式
keywordFilter针对最终生成的关键字执行:true:保留关键字false:移除关键字效果展示
https://liuxy0551.github.io/monaco-sql-languages/
当前语句关键字补全
补全列表只包含当前查询合法的续写关键字,不再出现
SELECT等下一语句起始关键字。输入部分关键字后的补全
输入
s后,只展示SORT、SORT BY等符合当前位置的候选项。测试