Skip to content

[question] About parse 'ALTER TABLE' in postgreSQL #254

@Kijin-Seija

Description

@Kijin-Seija

Version
latest

The Type of SQL
PostgreSQL

Your Code

class MyVisitor extends AbstractParseTreeVisitor<void> implements PostgreSQLParserVisitor<void> {
  visitAltertablestmt(ctx: any) {
    console.log('visitAltertablestmt', ctx)
  }
  visitAlterdatabasestmt(ctx: any) {
    console.log('visitAlterdatabasestmt', ctx)
  }
  ...
}

const visitor = new MyVisitor()

const tree1 = parser.parse('ALTER TABLE table1')
visitor.visit(tree1) // cannot print 'visitAltertablestmt'

const tree2 = parser.parse('ALTER TABLE table1 DROP column1')
visitor.visit(tree2) // ok, can print 'visitAltertablestmt'

const tree3 = parse.parse('ALTER DATABASE db1')
visitor.visit(tree3) // ok, can print 'visitAlterdatabasestmt'

Problem

在postregreSQL的语法解析时,无法将不完整但有基本结构的ALTER TABLE语法识别为 Altertablestmt 节点。
在对应的antlr4语法文件
https://github.com/DTStack/dt-sql-parser/blob/main/src/grammar/pgsql/PostgreSQLParser.g4
中可以看到,altertablestmt语法要求ALTER TABLE必须要有alter_table_cmds。这意味着最短可识别语句必须至少在tableName后面有一个关键字,比如ALTER TABLE table1 DROP 。如果仅为 ALTER TABLE table1则无法识别


In the syntax parsing of PostgreSQL, an incomplete but fundamentally structured ALTER TABLE syntax cannot be recognized as an Altertablestmt node. In the corresponding ANTLR4 grammar file: https://github.com/DTStack/dt-sql-parser/blob/main/src/grammar/pgsql/PostgreSQLParser.g4 it can be seen that the altertablestmt syntax requires ALTER TABLE to have at least one alter_table_cmds. This means that the shortest recognizable statement must have at least one keyword following the tableName, such as ALTER TABLE table1 DROP. If it is simply ALTER TABLE table1, it cannot be recognized.

altertablestmt
    : KW_ALTER KW_TABLE opt_if_exists? relation_expr (alter_table_cmds | partition_cmd)
    | KW_ALTER KW_TABLE KW_ALL KW_IN KW_TABLESPACE tablespace_name (KW_OWNED KW_BY role_list)? KW_SET KW_TABLESPACE tablespace_name_create opt_nowait?
    | KW_ALTER KW_TABLE opt_if_exists? table_name KW_ATTACH KW_PARTITION qualified_name (
        KW_FOR KW_VALUES partition_bound_spec
        | KW_DEFAULT
    )
    | KW_ALTER KW_TABLE opt_if_exists? table_name KW_DETACH KW_PARTITION qualified_name (
        KW_CONCURRENTLY
        | KW_FINALIZE
    )?
    | KW_ALTER KW_INDEX opt_if_exists? qualified_name (alter_table_cmds | index_partition_cmd)
    | KW_ALTER KW_INDEX KW_ALL KW_IN KW_TABLESPACE tablespace_name (KW_OWNED KW_BY role_list)? KW_SET KW_TABLESPACE tablespace_name_create opt_nowait?
    | KW_ALTER KW_SEQUENCE opt_if_exists? qualified_name alter_table_cmds
    | KW_ALTER KW_VIEW opt_if_exists? view_name alter_table_cmds
    | KW_ALTER KW_MATERIALIZED KW_VIEW opt_if_exists? view_name alter_table_cmds
    | KW_ALTER KW_MATERIALIZED KW_VIEW KW_ALL KW_IN KW_TABLESPACE tablespace_name (
        KW_OWNED KW_BY role_list
    )? KW_SET KW_TABLESPACE tablespace_name_create opt_nowait?
    | KW_ALTER KW_FOREIGN KW_TABLE opt_if_exists? relation_expr alter_table_cmds
    ;

但是,在ALTER DATABASE的语法里就没有这样的限制,只需要 ALTER DATABASE database_name就可以匹配Alterdatabasestmt。


However, in the syntax for ALTER DATABASE, there is no such restriction. Simply using ALTER DATABASE database_name is sufficient to match the Alterdatabasestmt.

alterdatabasestmt
   : KW_ALTER KW_DATABASE database_name (
       (KW_WITH? createdb_opt_list)?
       | createdb_opt_list?
       | (KW_SET KW_TABLESPACE tablespace_name_create)?
   )
   ;

我看了下antlr官方最新的语法也是如此,不知道这样设计的原理是什么。因为对postgreSQL的语法不是完全精通,所以想先提出来讨论一下,如果多数人觉得这里有疑问的话,我会再向https://github.com/antlr/grammars-v4 提issue
p.s.
考虑到官方可能认为ALTER TABLE table不是一个可执行的语句,后面必须跟命令,我去翻了一下Mysql的Alterdatabasestmt,
发现Mysql应该是可以识别的(没有测试)


I checked the latest official ANTLR grammar and it's the same there; I'm not sure what the rationale behind this design is. Since I'm not fully proficient in PostgreSQL syntax, I wanted to bring this up for discussion first. If the majority think there's an issue here, I will consider raising an issue at https://github.com/antlr/grammars-v4.

p.s.
Considering that the official source might regard ALTER TABLE table as not an executable statement and that it must be followed by a command, I looked into MySQL's Alterdatabasestmt. It seems that MySQL should be able to recognize it (though I haven't tested it).

alterTable
    : KW_ALTER KW_TABLE tableName (alterOption (',' alterOption)*)? (
        alterPartitionSpecification alterPartitionSpecification*
    )?
    ;

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinghelp wantedExtra attention is neededquestionFurther information is requested

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions