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.

The solution is to tweak the interval rules to avoid shift/reduce
conflicts by removing the broken interval_expr rule and explicitly
specify it's content where necessary.

Original fix by Davi Arnaut, revised and improved rules by Marc Alff
parent d179bb64
...@@ -484,3 +484,46 @@ select atan(10, 20 "p2"); ...@@ -484,3 +484,46 @@ select atan(10, 20 "p2");
ERROR 42000: Incorrect parameters in the call to native function 'atan' ERROR 42000: Incorrect parameters in the call to native function 'atan'
select atan(10 AS p1, 20 AS p2); select atan(10 AS p1, 20 AS p2);
ERROR 42000: Incorrect parameters in the call to native function 'atan' 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^1,0,1,2) + 1;
INTERVAL(1^1,0,1,2) + 1
2
SELECT INTERVAL(1,0+1,2,3) * 5.5;
INTERVAL(1,0+1,2,3) * 5.5
5.5
SELECT INTERVAL(3,3,1+3,4+4) / 0.5;
INTERVAL(3,3,1+3,4+4) / 0.5
2.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*5)/2) + INTERVAL(5,4,3);
INTERVAL(0,(1*5)/2) + INTERVAL(5,4,3)
2
SELECT 1^1 + INTERVAL 1+1 SECOND & 1 + INTERVAL 1+1 SECOND;
1^1 + INTERVAL 1+1 SECOND & 1 + INTERVAL 1+1 SECOND
NULL
SELECT 1%2 - INTERVAL 1^1 SECOND | 1%2 - INTERVAL 1^1 SECOND;
1%2 - INTERVAL 1^1 SECOND | 1%2 - INTERVAL 1^1 SECOND
NULL
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;
...@@ -629,3 +629,31 @@ select atan(10, 20 "p2"); ...@@ -629,3 +629,31 @@ select atan(10, 20 "p2");
-- error ER_WRONG_PARAMETERS_TO_NATIVE_FCT -- error ER_WRONG_PARAMETERS_TO_NATIVE_FCT
select atan(10 AS p1, 20 AS p2); 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^1,0,1,2) + 1;
SELECT INTERVAL(1,0+1,2,3) * 5.5;
SELECT INTERVAL(3,3,1+3,4+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*5)/2) + INTERVAL(5,4,3);
--disable_warnings
SELECT 1^1 + INTERVAL 1+1 SECOND & 1 + INTERVAL 1+1 SECOND;
SELECT 1%2 - INTERVAL 1^1 SECOND | 1%2 - INTERVAL 1^1 SECOND;
--enable_warnings
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;
...@@ -508,10 +508,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); ...@@ -508,10 +508,10 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%pure_parser /* We have threads */ %pure_parser /* We have threads */
/* /*
Currently there are 280 shift/reduce conflicts. Currently there are 177 shift/reduce conflicts.
We should not introduce new conflicts any more. We should not introduce new conflicts any more.
*/ */
%expect 280 %expect 177
/* /*
Comments for TOKENS. Comments for TOKENS.
...@@ -1157,7 +1157,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); ...@@ -1157,7 +1157,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
variable variable_aux bool_pri variable variable_aux bool_pri
predicate bit_expr predicate bit_expr
table_wild simple_expr udf_expr table_wild simple_expr udf_expr
expr_or_default set_expr_or_default interval_expr expr_or_default set_expr_or_default
param_marker geometry_function param_marker geometry_function
signed_literal now_or_signed_literal opt_escape signed_literal now_or_signed_literal opt_escape
sp_opt_default sp_opt_default
...@@ -6569,10 +6569,10 @@ bit_expr: ...@@ -6569,10 +6569,10 @@ bit_expr:
{ $$= new Item_func_plus($1,$3); } { $$= new Item_func_plus($1,$3); }
| bit_expr '-' bit_expr %prec '-' | bit_expr '-' bit_expr %prec '-'
{ $$= new Item_func_minus($1,$3); } { $$= new Item_func_minus($1,$3); }
| bit_expr '+' interval_expr interval %prec '+' | bit_expr '+' INTERVAL_SYM expr interval %prec '+'
{ $$= new Item_date_add_interval($1,$3,$4,0); } { $$= new Item_date_add_interval($1,$4,$5,0); }
| bit_expr '-' interval_expr interval %prec '-' | bit_expr '-' INTERVAL_SYM expr interval %prec '-'
{ $$= new Item_date_add_interval($1,$3,$4,1); } { $$= new Item_date_add_interval($1,$4,$5,1); }
| bit_expr '*' bit_expr %prec '*' | bit_expr '*' bit_expr %prec '*'
{ $$= new Item_func_mul($1,$3); } { $$= new Item_func_mul($1,$3); }
| bit_expr '/' bit_expr %prec '/' | bit_expr '/' bit_expr %prec '/'
...@@ -6622,11 +6622,6 @@ all_or_any: ...@@ -6622,11 +6622,6 @@ all_or_any:
| ANY_SYM { $$ = 0; } | ANY_SYM { $$ = 0; }
; ;
interval_expr:
INTERVAL_SYM expr %prec INTERVAL_SYM
{ $$=$2; }
;
simple_expr: simple_expr:
simple_ident simple_ident
| function_call_keyword | function_call_keyword
...@@ -6722,18 +6717,9 @@ simple_expr: ...@@ -6722,18 +6717,9 @@ simple_expr:
$$= new (YYTHD->mem_root) Item_insert_value(Lex->current_context(), $$= new (YYTHD->mem_root) Item_insert_value(Lex->current_context(),
$3); $3);
} }
| interval_expr interval '+' expr | INTERVAL_SYM expr interval '+' expr %prec INTERVAL_SYM
/* we cannot put interval before - */ /* we cannot put interval before - */
{ $$= new (YYTHD->mem_root) Item_date_add_interval($4,$1,$2,0); } { $$= new (YYTHD->mem_root) Item_date_add_interval($5,$2,$3,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 +6747,23 @@ function_call_keyword: ...@@ -6761,6 +6747,23 @@ function_call_keyword:
{ $$= new (YYTHD->mem_root) Item_func_hour($3); } { $$= new (YYTHD->mem_root) Item_func_hour($3); }
| INSERT '(' expr ',' expr ',' expr ',' expr ')' | INSERT '(' expr ',' expr ',' expr ',' expr ')'
{ $$= new (YYTHD->mem_root) Item_func_insert($3,$5,$7,$9); } { $$= 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 ')' | LEFT '(' expr ',' expr ')'
{ $$= new (YYTHD->mem_root) Item_func_left($3,$5); } { $$= new (YYTHD->mem_root) Item_func_left($3,$5); }
| MINUTE_SYM '(' expr ')' | MINUTE_SYM '(' expr ')'
...@@ -6838,10 +6841,10 @@ function_call_nonkeyword: ...@@ -6838,10 +6841,10 @@ function_call_nonkeyword:
$$= new (YYTHD->mem_root) Item_func_curtime_local($3); $$= new (YYTHD->mem_root) Item_func_curtime_local($3);
Lex->safe_to_cache_query=0; Lex->safe_to_cache_query=0;
} }
| DATE_ADD_INTERVAL '(' expr ',' interval_expr interval ')' | DATE_ADD_INTERVAL '(' expr ',' INTERVAL_SYM expr interval ')' %prec INTERVAL_SYM
{ $$= new (YYTHD->mem_root) Item_date_add_interval($3,$5,$6,0); } { $$= new (YYTHD->mem_root) Item_date_add_interval($3,$6,$7,0); }
| DATE_SUB_INTERVAL '(' expr ',' interval_expr interval ')' | DATE_SUB_INTERVAL '(' expr ',' INTERVAL_SYM expr interval ')' %prec INTERVAL_SYM
{ $$= new (YYTHD->mem_root) Item_date_add_interval($3,$5,$6,1); } { $$= new (YYTHD->mem_root) Item_date_add_interval($3,$6,$7,1); }
| EXTRACT_SYM '(' interval FROM expr ')' | EXTRACT_SYM '(' interval FROM expr ')'
{ $$=new (YYTHD->mem_root) Item_extract( $3, $5); } { $$=new (YYTHD->mem_root) Item_extract( $3, $5); }
| GET_FORMAT '(' date_time_type ',' expr ')' | GET_FORMAT '(' date_time_type ',' expr ')'
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment