List:Commits« Previous MessageNext Message »
From:Marc Alff Date:November 30 2007 1:12am
Subject:Re: bk commit into 6.0 tree (davi:1.2691) BUG#22312
View as plain text  
Hi Davi

Congratulations on finding a fix for this issue which has been plaguing
the grammar for so long.

I am asking for minor changes, see below,
so a new patch needs to be prepared for 5.1 (and will be approved right
away).

Regards,
Marc

Davi Arnaut wrote:
> Below is the list of changes that have just been committed into a local
> 6.0 repository of davi. When davi does a push these changes will
> be propagated to the main repository and, within 24 hours after the
> push, to the public repository.
> For information on how to access the public repository
> see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
> 
> ChangeSet@stripped, 2007-11-26 10:28:57-02:00, davi@stripped +3 -0
>   Bug#22312 Syntax error in expression with INTERVAL()
>   
>   Parser rejects valid INTERVAL() expressions when associated with
>   arithmetic operators. The problem is the way in which the expression
>   and interval grammar rules were organized caused shift/reduce conflicts,
>   partly due to the expression parenthesis recursion.
>   
>   The solution is to tweak the interval() and expression recursion rules
>   to avoid the shift/reduce conflicts. The changes are kept small enough
>   because the expression rule is fragile but very crucial.
> 
>   mysql-test/r/parser.result@stripped, 2007-11-26 10:28:51-02:00, davi@stripped +37 -0
>     Add test case result for Bug#22312
> 
>   mysql-test/t/parser.test@stripped, 2007-11-26 10:28:51-02:00, davi@stripped +23 -0
>     Add test case for Bug#22312
> 
>   sql/sql_yacc.yy@stripped, 2007-11-26 10:28:51-02:00, davi@stripped +11 -15
>     Resolve shift/reduce conflicts by reorganizing the interval
>     expression and expression recursion rules.
> 
> diff -Nrup a/mysql-test/r/parser.result b/mysql-test/r/parser.result
> --- a/mysql-test/r/parser.result	2007-08-09 20:30:56 -03:00
> +++ b/mysql-test/r/parser.result	2007-11-26 10:28:51 -02:00
> @@ -484,3 +484,40 @@ select atan(10, 20 "p2");
>  ERROR 42000: Incorrect parameters in the call to native function 'atan'
>  select atan(10 AS p1, 20 AS p2);
>  ERROR 42000: Incorrect parameters in the call to native function 'atan'
> +DROP TABLE IF EXISTS t1;
> +SELECT STR_TO_DATE('10:00 PM', '%h:%i %p') + INTERVAL 10 MINUTE;
> +STR_TO_DATE('10:00 PM', '%h:%i %p') + INTERVAL 10 MINUTE
> +NULL
> +SELECT STR_TO_DATE('10:00 PM', '%h:%i %p') + INTERVAL (INTERVAL(1,2,3) + 1) MINUTE;
> +STR_TO_DATE('10:00 PM', '%h:%i %p') + INTERVAL (INTERVAL(1,2,3) + 1) MINUTE
> +NULL
> +SELECT "1997-12-31 23:59:59" + INTERVAL 1 SECOND;
> +"1997-12-31 23:59:59" + INTERVAL 1 SECOND
> +1998-01-01 00:00:00
> +SELECT 1 + INTERVAL(1,0,1,2) + 1;
> +1 + INTERVAL(1,0,1,2) + 1
> +4
> +SELECT INTERVAL(1,0,1,2) + 1;
> +INTERVAL(1,0,1,2) + 1
> +3
> +SELECT INTERVAL(1,0,2,3) * 5.5;
> +INTERVAL(1,0,2,3) * 5.5
> +5.5
> +SELECT INTERVAL(3,3,1,4) / 0.5;
> +INTERVAL(3,3,1,4) / 0.5
> +4.0000
> +SELECT (INTERVAL(1,0,1,2) + 5) * 7 + INTERVAL(1,0,1,2) / 2;
> +(INTERVAL(1,0,1,2) + 5) * 7 + INTERVAL(1,0,1,2) / 2
> +50.0000
> +SELECT INTERVAL(1,0,1,2) + 1, 5 * INTERVAL(1,0,1,2);
> +INTERVAL(1,0,1,2) + 1	5 * INTERVAL(1,0,1,2)
> +3	10
> +SELECT INTERVAL(0,1) + INTERVAL(5,4,3);
> +INTERVAL(0,1) + INTERVAL(5,4,3)
> +2
> +CREATE TABLE t1 (a INT, b DATETIME);
> +INSERT INTO t1 VALUES (INTERVAL(3,2,1) + 1, "1997-12-31 23:59:59" + INTERVAL 1
> SECOND);
> +SELECT * FROM t1 WHERE a = INTERVAL(3,2,1) + 1;
> +a	b
> +3	1998-01-01 00:00:00
> +DROP TABLE t1;
> diff -Nrup a/mysql-test/t/parser.test b/mysql-test/t/parser.test
> --- a/mysql-test/t/parser.test	2007-08-09 20:30:56 -03:00
> +++ b/mysql-test/t/parser.test	2007-11-26 10:28:51 -02:00
> @@ -629,3 +629,26 @@ select atan(10, 20 "p2");
>  -- error ER_WRONG_PARAMETERS_TO_NATIVE_FCT
>  select atan(10 AS p1, 20 AS p2);
>  
> +#
> +# Bug#22312 Syntax error in expression with INTERVAL()
> +#
> +
> +--disable_warnings
> +DROP TABLE IF EXISTS t1;
> +--enable_warnings
> +
> +SELECT STR_TO_DATE('10:00 PM', '%h:%i %p') + INTERVAL 10 MINUTE;
> +SELECT STR_TO_DATE('10:00 PM', '%h:%i %p') + INTERVAL (INTERVAL(1,2,3) + 1) MINUTE;
> +SELECT "1997-12-31 23:59:59" + INTERVAL 1 SECOND;
> +SELECT 1 + INTERVAL(1,0,1,2) + 1;
> +SELECT INTERVAL(1,0,1,2) + 1;
> +SELECT INTERVAL(1,0,2,3) * 5.5;
> +SELECT INTERVAL(3,3,1,4) / 0.5;
> +SELECT (INTERVAL(1,0,1,2) + 5) * 7 + INTERVAL(1,0,1,2) / 2;
> +SELECT INTERVAL(1,0,1,2) + 1, 5 * INTERVAL(1,0,1,2);
> +SELECT INTERVAL(0,1) + INTERVAL(5,4,3);
> +
> +CREATE TABLE t1 (a INT, b DATETIME);
> +INSERT INTO t1 VALUES (INTERVAL(3,2,1) + 1, "1997-12-31 23:59:59" + INTERVAL 1
> SECOND);
> +SELECT * FROM t1 WHERE a = INTERVAL(3,2,1) + 1;
> +DROP TABLE t1;
> diff -Nrup a/sql/sql_yacc.yy b/sql/sql_yacc.yy
> --- a/sql/sql_yacc.yy	2007-11-23 11:37:37 -02:00
> +++ b/sql/sql_yacc.yy	2007-11-26 10:28:51 -02:00
> @@ -512,10 +512,10 @@ bool my_yyoverflow(short **a, YYSTYPE **
>  
>  %pure_parser                                    /* We have threads */
>  /*
> -  Currently there are 279 shift/reduce conflicts.
> +  Currently there are 219 shift/reduce conflicts.
>    We should not introduce new conflicts any more.
>  */
> -%expect 279
> +%expect 219
>  

Brilliant.

I tried myself to resolve this bug earlier, as did others,
but could not pass the 55 reduce/reduce conflicts lurking in the code.



>  /*
>     Comments for TOKENS.
> @@ -6796,12 +6796,6 @@ simple_expr:
>            { 
>              $$= new (YYTHD->mem_root) Item_singlerow_subselect($2); 
>            }
> -        | '(' expr ')' { $$= $2; }
> -        | '(' expr ',' expr_list ')'
> -          {
> -            $4->push_front($2);
> -            $$= new (YYTHD->mem_root) Item_row(*$4);
> -          }
>          | ROW_SYM '(' expr ',' expr_list ')'
>            {
>              $5->push_front($3);
> @@ -6863,14 +6857,16 @@ simple_expr:
>          | interval_expr interval '+' expr
>            /* we cannot put interval before - */
>            { $$= new (YYTHD->mem_root) Item_date_add_interval($4,$1,$2,0); }
> -        | interval_expr
> +        | INTERVAL_SYM '(' expr ',' expr_list ')'
>            {
> -            if ($1->type() != Item::ROW_ITEM)
> -            {
> -              my_parse_error(ER(ER_SYNTAX_ERROR));
> -              MYSQL_YYABORT;
> -            }
> -            $$= new (YYTHD->mem_root) Item_func_interval((Item_row *)$1);
> +            $5->push_front($3);
> +            Item_row *item= new (YYTHD->mem_root) Item_row(*$5);
> +            $$= new (YYTHD->mem_root) Item_func_interval((Item_row *)item);
> +          }

Agreed with the principle:
the conflicts are resolved by in lining the rules for the INTERVAL
function here, instead of using the (broken) interval_expr

There is however more to it, see below.

> +        | '(' expr ')' { $$= $2; }

Ok, Scalar expressions (code was just moved)


> +        | '(' expr_list ')'
> +          {
> +            $$= new (YYTHD->mem_root) Item_row(*$2);
>            }

This rule should not have been changed:
- "(a)" is always a scalar expression, only "(a, b)" are ROW expressions
- it conflicts with the previous rule, since the parser has 2 choices
for "(a)"

Ok, changing it back the original code (expr ',' expr_list),
the conflicts are back ...

After a couple of tweaks, I came up with this alternate patch instead,
which pushes further your idea of in lining rules in the INTERVAL()
function grammar.

What I propose for grammar change is :

> malff@lambda:~/TREE/mysql-5.1-review-22312/sql> bk diffs -u *.yy
> ===== sql_yacc.yy 1.610 vs edited =====
> --- 1.610/sql/sql_yacc.yy       2007-11-28 09:08:26 -07:00
> +++ edited/sql_yacc.yy  2007-11-29 16:56:33 -07:00
> @@ -508,10 +508,10 @@ bool my_yyoverflow(short **a, YYSTYPE **
> 
>  %pure_parser                                    /* We have threads */
>  /*
> -  Currently there are 280 shift/reduce conflicts.
> +  Currently there are 219 shift/reduce conflicts.
>    We should not introduce new conflicts any more.
>  */
> -%expect 280
> +%expect 219
> 
>  /*
>     Comments for TOKENS.
> @@ -6725,15 +6725,6 @@ simple_expr:
>          | interval_expr interval '+' expr
>            /* we cannot put interval before - */
>            { $$= new (YYTHD->mem_root) Item_date_add_interval($4,$1,$2,0); }
> -        | interval_expr
> -          {
> -            if ($1->type() != Item::ROW_ITEM)
> -            {
> -              my_parse_error(ER(ER_SYNTAX_ERROR));
> -              MYSQL_YYABORT;
> -            }
> -            $$= new (YYTHD->mem_root) Item_func_interval((Item_row *)$1);
> -          }
>          ;
> 
>  /*
> @@ -6761,6 +6752,23 @@ function_call_keyword:
>            { $$= new (YYTHD->mem_root) Item_func_hour($3); }
>          | INSERT '(' expr ',' expr ',' expr ',' expr ')'
>            { $$= new (YYTHD->mem_root) Item_func_insert($3,$5,$7,$9); }
> +        | INTERVAL_SYM '(' expr ',' expr ')' %prec INTERVAL_SYM
> +          {
> +            THD *thd= YYTHD;
> +            List<Item> *list= new (thd->mem_root) List<Item>;
> +            list->push_front($5);
> +            list->push_front($3);
> +            Item_row *item= new (thd->mem_root) Item_row(*list);
> +            $$= new (thd->mem_root) Item_func_interval(item);
> +          }
> +        | INTERVAL_SYM '(' expr ',' expr ',' expr_list ')' %prec INTERVAL_SYM
> +          {
> +            THD *thd= YYTHD;
> +            $7->push_front($5);
> +            $7->push_front($3);
> +            Item_row *item= new (thd->mem_root) Item_row(*$7);
> +            $$= new (thd->mem_root) Item_func_interval(item);
> +          }
>          | LEFT '(' expr ',' expr ')'
>            { $$= new (YYTHD->mem_root) Item_func_left($3,$5); }
>          | MINUTE_SYM '(' expr ')'

---

Please consider this fix instead for sql_yacc.yy, use your tests (all
good), and prepare a patch for 5.1 instead of 6.0: now that the rule for
 ROW expressions is not changed, the risk is much lower, and this
cleanup will help maintenance a lot.

Not to be fixed in 5.0 (the issue is minor, has a work-around, and the
grammar too different)

Optional:
the rule interval_expr was artificial, and can be removed by in lining
the content (just adjust the $N values accordingly where it's used).

Thanks,
Marc.

Thread
bk commit into 6.0 tree (davi:1.2691) BUG#22312Davi Arnaut26 Nov
  • Re: bk commit into 6.0 tree (davi:1.2691) BUG#22312Marc Alff30 Nov
    • Re: bk commit into 6.0 tree (davi:1.2691) BUG#22312Davi Arnaut30 Nov