Help fixing a bug in tsql

25 views
Skip to first unread message

garym

unread,
Mar 28, 2018, 3:06:06 PM3/28/18
to antlr-di...@googlegroups.com

Hi.


I'm playing with the tsql grammar forking it for Sybase.


I have a real world case supported by SQLServer and ASE not addressed in the grammar's test cases which is causing a parse error.


The rule null_notnull seems to be not handled properly due to the invalid syntax "GETDATE() + GETDATE()". Not being quite sure on debugging grammars in antlr4, I'm not sure how rule null_notnull is being handled, the error refers to a missing ")"


The DEFAULT syntax should be any expression that results in a single value.


I need some appreciated help supporting DEFAULT's syntax.


Unsuccessful experiments resulting in the same error, changing constant_expression rule to:

 | function_call (PLUS function_call)*    
 | expression
 | expression*


The column definition in the db:
[C4] varchar(14) DEFAULT CONVERT(char(8), GETDATE(), 112) + substring(CONVERT(char(8), GETDATE(), 8), 1, 2) + substring(CONVERT(char(8), GETDATE(), 8), 4, 2) + substring(CONVERT(char(8), GETDATE(), 8), 7, 2)/* Current Datetime*/ NOT NULL,


The simplified test case is:

CREATE TABLE T1 (
  [C8] varchar(14) DEFAULT GETDATE() + GETDATE() NOT NULL,
);


The error is: line 13:49 extraneous input 'NOT' expecting


The offending parse tree:( ) [line 13, offset 298:304]) NOT [line 13, offset 278:284]) [line 13, offset 278:284]) [line 13, offset 261:264]) <missing ')'> [line 12, offset 239:244]) [line 12, offset 239:244]) [line 12, offset 239:244])

The Rules:

column_definition
    : id (data_type | AS expression) (COLLATE id)? null_notnull?
      ((CONSTRAINT constraint=id)? null_or_default null_or_default?
       | IDENTITY (L_PAREN seed=DECIM_VAL ',' increment=DECIM_VAL R_PAREN)? (NOT FOR REPLICATION)?)?
      ROWGUIDCOL?
      column_constraint*
    ;
null_or_default
    :(null_notnull | DEFAULT constant_expression (WITH VALUES)?)
    ;
null_notnull
    : NOT? NULL
    ;
constant_expression
    : NULL
    | constant
    // system functions: https://msdn.microsoft.com/en-us/library/ms187786.aspx
    | function_call 
    | LOCAL_ID         // TODO: remove.
    | L_PAREN constant_expression R_PAREN
    ;

garym

unread,
Mar 29, 2018, 3:58:41 AM3/29/18
to antlr-discussion
An edit....   

I found the bug above column_definition in column_def_table_constraints.
The issue is the parser drops into the table_constraint rule due to a DEFAULT token.  It seems the grammar is not complete, its huge grammar and a laborious to create. Authors did a great job !!!

Fixing it tomorrow..

column_def_table_constraint
    : column_definition
    | materialized_column_definition
    | table_constraint
    ;
table_constraint
    : (CONSTRAINT constraint=id)?
       ((PRIMARY KEY | UNIQUE) clustered? '(' column_name_list_with_order ')' index_options? (ON id)?
         | CHECK (NOT FOR REPLICATION)? '(' search_condition ')'
         | DEFAULT '('?  (STRING | PLUS | function_call | DECIMAL)+ ')'? FOR id
         | FOREIGN KEY '(' fk = column_name_list ')' REFERENCES table_name ('(' pk = column_name_list')')? on_delete? on_update?)
    ;

garym

unread,
Mar 29, 2018, 7:32:34 PM3/29/18
to antlr-di...@googlegroups.com
This looks like a fix for case:

[C8] VARCHAR (14) DEFAULT GETDATE() + GETDATE() +10  NOT NULL,
[C9] VARCHAR (14) DEFAULT GETDATE() + GETDATE() +10  NOT NULL,
[C10] VARCHAR (14) DEFAULT GETDATE() + GETDATE() +10  NOT NULL


TSQLPArser.g4:

table_constraint
    : (CONSTRAINT constraint=id)?
       ((PRIMARY KEY | UNIQUE) clustered? '(' column_name_list_with_order ')' index_options? (ON id)?
         | CHECK (NOT FOR REPLICATION)? '(' search_condition ')'
         | FOREIGN KEY '(' fk = column_name_list ')' REFERENCES table_name ('(' pk = column_name_list')')? on_delete? on_update?)
    ;


column_def_table_constraints
    : '(' column_def_table_constraint (',' column_def_table_constraint)* ')' 
    | column_def_table_constraint (',' column_def_table_constraint)* 
    ;

constant_expression
    : constant
    | constant_expression op=('*' | '/' | '%') constant_expression
    | constant_expression op=('+' | '-' | '&' | '^' | '|' | '||') constant_expression    
    | function_call
    | LOCAL_ID         // TODO: remove.
    | '(' constant_expression ')'
    ;

Reply all
Reply to author
Forward
0 new messages