Replies: 22 comments 7 replies
-
Are there any support plans in the near future? |
Beta Was this translation helpful? Give feedback.
-
I just came across this context completion requirement and would like to know if there is any intention to implement this feature in the near future or the approximate time to do so. |
Beta Was this translation helpful? Give feedback.
-
We will implement this feature in December. We haven't started doing this yet because we are still rechecking the sql grammar files, which takes a lot of time. |
Beta Was this translation helpful? Give feedback.
-
Which sql language do you need to implement this feature in? If you need implement this feature in one of the languages in flink,hive,spark or trino, we can support it in the near future |
Beta Was this translation helpful? Give feedback.
-
This is good news. Looking forward to it! |
Beta Was this translation helpful? Give feedback.
-
It's great to hear from you. All of those you mentioned above are in demand, even mysql, and it's really exciting to hear that new features are coming |
Beta Was this translation helpful? Give feedback.
-
上下文 ex: |
Beta Was this translation helpful? Give feedback.
-
请问这一块需要社区支持吗? |
Beta Was this translation helpful? Give feedback.
-
How should monaco get the position of the cursor, please? I didn't find the api for it, but it does have this function |
Beta Was this translation helpful? Give feedback.
-
// 获取 monaco-editor 实例
var editor = monaco.editor.create(document.getElementById('container'), {
value: 'function hello() {\n\talert("Hello, world!");\n}',
language: 'javascript'
});
// 获取光标位置
var position = editor.getPosition();
console.log(position); |
Beta Was this translation helpful? Give feedback.
-
@zhi-zhi-zhi 事实上这个功能已经支持了,目前 dt-sql-parser 的自动补全功能通过引入 antlr4-c3 实现。 你可以通过调用
@zhi-zhi-zhi 非常欢迎来自社区的 PR。 但是在此之前,我们需要先讨论一下该功能,以保证该功能实现后符合我们的期望。 需要实现什么?
SELECT * FROM |
CREATE TABLE tb1 (id int);
CREATE TABLE tb2 (id int);
CREATE TABLE tb3 (id int);
SELECT * FROM | 事实上,对于使用自动补全功能的用户来说,除了想要知道指定位置应该填什么类型,还需要知道该类型对应有哪些实体?比如此例中的光标位置,在此位置做自动补全功能时,除了需要知道该位置要填表名,还需要知道当前上下文中有哪些表名。 那么此时我们需要一个功能去收集sql文本上下文中出现的所有表名,在本例中应该收集到 一般情况下,在实际业务场景中,这些信息应该由数据库/计算引擎的元数据提供,但即使有元数据支持,此功能仍然具有意义,因为当前上下文中的 DDL 语句可能并未执行,也就是说当前上下文中可能包含元数据中不包含的信息。比如建表语句未执行前,元数据中没有该表的信息,但是我们可以在sql上下文中获取。 有哪些类型需要收集?参照 注意事项需要考虑多种情况,例如:
CREATE TABLE tb1 (id int);
ALTER TABLE tb1 RENAME TO tb2;
CREATE TABLE tb (
sum(age) as col int
) 这里无法列举出全部情况,因为不同的sql类型的语法具有差异。 如何实现?
|
Beta Was this translation helpful? Give feedback.
-
我想通过后端接口获取到db.tb, tb.column补全列表; 如用户输入: use a_db;
SELECT *
FROM a_table
INNER JOIN b_db.b_table AS b ON a_table.<cursor_1> = b.<cursor_2>
WHERE <cursor_3> 在光标处,目前我获取到的补全上下文信息,只有以下信息: {
"syntaxContextType": "column",
"wordRanges": [
{
"text": " ",
"startIndex": 28,
"stopIndex": 28,
"line": 3,
"startColumn": 6,
"stopColumn": 6
}
]
} 但是我无法请求后端得到当前应该输入的字段列表,因为后端无法得知需要什么表下面字段列表,也就是上下文信息中缺少更多信息,如果是以下这样,那就可以完成后端获取数据。 上述SQL中包含了,a_db.a_table以及 b_db.b_table,且b_table 有一个别名b. 对于 <cursor_1>,仅需要补全a_table下的字段: {
"syntaxContextType": "column",
"wordRanges": [
{
// 其他属性省略
"tables": [{"db": "a_db", "tb": "a_table"}]
}
]
} 对于 <cursor_2>,仅需要补全b_table(别名b)下的字段: {
"syntaxContextType": "column",
"wordRanges": [
{
// 其他属性省略
"tables": [{"db": "b_db", "tb": "b_table"}]
}
]
} 对于 <cursor_3>,需要补全a_table和b_table下的字段: {
"syntaxContextType": "column",
"wordRanges": [
{
// 其他属性省略
"tables": [{"db": "b_db", "tb": "b_table"}, {"db": "b_db", "tb": "b_table"}]
}
]
} 还有一些更为复杂的场景: 如包含子查询和别名(b_table -> bbb -> b),其中最初的b_table是后端需要的真实的表名,且其来自于b_db。 use a_db;
SELECT *
FROM a_table
INNER JOIN (
SELECT * FROM b_db.b_table bbb LIMIT 100
) b ON a_table.<cursor_1> = b.<cursor_2>
WHERE <cursor_3> 当然,除此之外,自动感知上下文中的库、表和字段也很重要。 |
Beta Was this translation helpful? Give feedback.
-
@Shu-Ji 目前自动补全功能提供的上下文信息,是一个wordRange 数组,而在 wordRange 中,并没有提到该 word 是什么类型,这实际上是因为 dt-sql-parser 也无法确认对应的类型。 很多数据库/大数据引擎都具有三层结构,比如 Trino 有 表名的自动补全当输入为: SELECT * FROM a<cursor pos> 此时光标位置可能的输入类型有: 当输入为 SELECT * FROM a.b<cursor pos> 此时 a 就可能是 这在理论上也似乎无法确认(最起码对我来说,没想到什么好办法),如果你有什么更好的点子可以告诉我们。 字段的自动补全事实上,dt-sql-parser 能够获取到 wordRanges 数组是依靠位置,即对于表名的补全来说,所需要的信息在位置上一定与当前补全位置相邻。另外,wordRanges 数组中的 token 与补全位置的 token 一定在同一个 Antlr4.parserRuleContext 下。 字段的自动补全在此基础上变得复杂了起来,由于位置的关系,dt-sql-parser 无法直接感知到关于对应表名的上下文信息。 另外如你所说,这需要考虑很多复杂的情况,比如子查询,表别名,当然也包括 这个功能相当重要,但是这都需要额外的开发,基于上下文的自动补全功能实际上需要语义分析的支持,Antlr4 本身则只支持词法分析和语法分析。又因为每一种 SQL 的语法各不相同,所以在做语义分析时,需要每一种 SQL 单独支持,即使实现起来并不困难(理论上),但这仍然需要大量的时间。 这个功能目前在我们的计划中,但是并不是最高优先级,最近的开发计划还是集中在支持更多类型的 SQL 上,比如 另外,我们非常欢迎来自社区的 PR 或者说是需要社区的帮助。 |
Beta Was this translation helpful? Give feedback.
-
@Shu-Ji 此功能支持后,可能对字段的补全有所帮助。即你可以一次性获取上下文中出现的所有的表名,从后端接口中获取所有的表的元数据,当当前的 这显然不是最终的解决方案,但是可能值得一试。 |
Beta Was this translation helpful? Give feedback.
-
这是一个好办法期待,期待! |
Beta Was this translation helpful? Give feedback.
-
如果能取到当前文档中所有的库名和表名,那也很好了,因为至少可以补全了,只是补全列表中会出现相对无关的条目,不过问题不大,基本解决问题了。(尝试了一下MySqlParserVisitor模式,在语法不正确的时候,无法visit table等信息,会报语法错误,如何把光标处当成正确的字符,让解析器通过呢?) 有一些阿里同学的参考文章: 还有一些后端的lsp项目中,基本都提供光标处的自动补全功能;如: @kissycn 这位同学都激动的彪中文了🐮,这个功能真的对于编辑器来说是很刚需 |
Beta Was this translation helpful? Give feedback.
-
@Shu-Ji 这个问题确实值得思考,你所提到的参考文章是很好的思路。
@kissycn 关于这个功能的实现时间,我可能需要说声抱歉,之前暂定是 12 月份实现此功能,但是目前看来是没办法做到了,主要是因为年底了,emmm 琐事有点多。 |
Beta Was this translation helpful? Give feedback.
-
理解,理解,年底大家事情都多! |
Beta Was this translation helpful? Give feedback.
-
尝试了一下MySqlParserVisitor模式,在语法不正确的时候,无法visit table等信息,会报语法错误,如何把光标处当成正确的字符,让解析器通过呢? |
Beta Was this translation helpful? Give feedback.
-
或许我们可以通过Antlr4 ErrorStrategy (即 Antlr4 提供的自定义错误处理策略接口)来做到这件事,此前我在这个 pr #230 中已经修改过ErrorStrategy ,但是并不涉及错误恢复策略的改动。 对于 Antlr4 ErrorStrategy 我只是略微了解不是太熟悉,目前没有更多进展,这只是一个可能可行的方案。 另外想要在错误处进行恢复也要分多种情况,对于有结构性错误的语句在理论上很难恢复,因为很难预料语句原本是什么样子的。 |
Beta Was this translation helpful? Give feedback.
-
为什么要收集这些信息?目前主要作用是为自动补全功能提供必要的信息,在实际业务场景中,这些信息应该由数据库/计算引擎的元数据提供。但是当前上下文中可能包含引擎元数据中不包含的信息,比如建表语句未执行前,元数据中没有该表的信息,但是我们可以在sql上下文中获取。 需要收集什么?从此功能的定位来看,所有可以用 DDL 语句创建的都需要被收集,比如表名、库名等,下文中统一称之为实体(Entity)。 实现思路上下文中出现的实体都将被平铺在数组中输出,这样更易于查询。可以将输出结果类比为果篮,将实体类比为解析树上的果子,此功能就是在语法树上将果子摘下来放到同一个果篮中。 实体需要包含哪些信息?对于一个实体,其内部需要包含的信息有
关于实体所属的语句,可以理解为解析树上的枝桠,在输出结果中所有的实体都将平铺输出,这样的结构无法表达实体之间的联系,比如 除了通过所属语句来连接不同的实体以外,还可以直接附加有关联的其他实体到本实体上,比如上例中, interface EntityContext {
readonly syntaxContextType: SyntaxContextType;
readonly text: string;
readonly position: WordPosition;
readonly belongStmt: StmtContext;
relatedEntities?: EntityContext[];
columns?: EntityContext[];
} 语句需要包含哪些信息?
因为语句之间可以有很深的嵌套关系,所以语句的父语句信息在某些情况下是必要的,另外语句的根语句则是一个指向最外层语句的指针,这可以在很多情况下降低查找的难度。 根语句一般指一条独立(当前上下文中不作为其他语句的字句)且完整的语句, 例如 除此之外,在最顶层会有一个通用的语句节点,这是一种兜底策略,主要是为了处理语句类型没有被访问收集,但是语句内部包含实体的情况,此时语句内部实体中附加语句信息会指向这个通用节点,它除了没有明确的语句类型以外,其他信息都与正常的语句相同且有效。 interface StmtContext {
readonly stmtContextType: StmtContextType;
readonly position: TextPosition;
readonly rootStmt?: StmtContext | null;
readonly parentStmt?: StmtContext | null;
} 具体实现
CREATE TABLE new_tb AS
SELECT
old_tb1.column1,
old_tb2.column2
FROM
old_tb1
JOIN
old_tb2 ON old_tb1.id = old_tb2.id
WHERE
old_tb1.column1 = 'value' 对于这段 sql (MySQL),用一个简化的语法树表示: 当使用 listener 访问这棵树上的节点时,语句暂存栈和实体暂存栈的变化如下图所示: 关键的过程节点
这样做是为了以一条独立语句为单位来聚合/组合语句下的所有实体信息,但是这种策略会导致部分实体间的关联关系被忽略,所以实际上这里 是在平衡分析的复杂度和实体间关联关系的丰富度。换句话说, 何时从实体栈中弹出实体,决定了聚合/组合实体的复杂度也决定了实体间关联关系的丰富度。 聚合和组合实体信息聚合和组合的逻辑应该是最复杂的,聚合和组合实际上是把同一个独立语句中出现的实体联系起来,这需要考虑很多复杂的情况,目前只开发了极为简单的情况下的实体聚合/组合逻辑。 依照上述策略,最后生成的结果如图所示,输出结果中仅包含实体,对应的 stmt 信息可以通过实体的 |
Beta Was this translation helpful? Give feedback.
-
我这边根据之前业务需求的逻辑,简单写了一个demo。 https://github.com/Kijin-Seija/dt-sql-parser-analyse-demo 应该可以解决一部分上面提出的问题。 我这边也有业务需求,主要方向是PostgreSQL。如果方便的话,我很乐意参与讨论和共建,或者作为一个plugin支持。 Based on the previous business requirements, I've written a simple demo. https://github.com/Kijin-Seija/dt-sql-parser-analyse-demo It should be able to address some of the issues mentioned above. I also have business requirements, mainly focused on PostgreSQL. If it's convenient, I'd be happy to participate in discussions and collaboration, or to support as a plugin. |
Beta Was this translation helpful? Give feedback.
-
分析出当前sql内容中新创建的 catalog名/schema名/表名/视图名/函数名/字段名,用于自动补全
Beta Was this translation helpful? Give feedback.
All reactions