← Back to team overview

maria-developers team mailing list archive

Re: 4ddf606debf: MDEV-30151 parse error 1=2 not between/in

 

Hi, Alexander,

I'm not sure I understand everything you did there, so questions below

On Dec 28, Alexander Barkov wrote:
> revision-id: 4ddf606debf (mariadb-10.3.37-59-g4ddf606debf)
> parent(s): 8f30973234d
> author: Alexander Barkov
> committer: Alexander Barkov
> timestamp: 2022-12-13 10:35:16 +0400
> message:
> 
> MDEV-30151 parse error 1=2 not between/in
> 
> diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
> index 1f6485dac6a..ca614ff63e9 100644
> --- a/sql/sql_yacc.yy
> +++ b/sql/sql_yacc.yy
> @@ -1687,7 +1687,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
>  
>  %left   PREC_BELOW_NOT
>  
> -%nonassoc NOT_SYM
> +/* The precendence of boolean NOT is in fact here. See the comment below. */
> +
>  %left   '=' EQUAL_SYM GE '>' LE '<' NE
>  %nonassoc IS
>  %right BETWEEN_SYM
> @@ -1699,6 +1700,24 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
>  %left   '*' '/' '%' DIV_SYM MOD_SYM
>  %left   '^'
>  %left   MYSQL_CONCAT_SYM
> +/*
> +  Boolean negation has a special branch in "expr" starting with NOT_SYM.
> +  The precedence of logical negation is determined by the grammar itself
> +  (without using Bison terminal symbol precedence) in this order
> +  - Boolean factor (i.e. logical AND)
> +  - Boolean NOT
> +  - Boolean test (such as '=', IS NULL, IS TRUE)
> +
> +  But we also need a precedence for NOT_SYM in other contexts,
> +  to shift (without reduce) in these cases:
> +     predicate <here> NOT IN ...
> +     predicate <here> NOT BETWEEN ...
> +     predicate <here> NOT LIKE ...
> +     predicate <here> NOT REGEXP ...
> +  If the precedence of NOT_SYM was low, it would reduce immediately
> +  after scanning "predicate" and then produce a syntax error on "NOT".
> +*/
> +%nonassoc NOT_SYM
>  %nonassoc NEG '~' NOT2_SYM BINARY
>  %nonassoc COLLATE_SYM
>  
> @@ -1938,6 +1957,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
>          literal insert_ident order_ident temporal_literal
>          simple_ident expr sum_expr in_sum_expr
>          variable variable_aux
> +        boolean_test boolean_factor
>          predicate bit_expr parenthesized_expr
>          table_wild simple_expr column_default_non_parenthesized_expr udf_expr
>          primary_expr string_factor_expr mysql_concatenation_expr
> @@ -9840,79 +9860,87 @@ expr:
>                  MYSQL_YYABORT;
>              }
>            }
> -        | NOT_SYM expr %prec NOT_SYM
> +        | boolean_factor

what does that achieve?

> +        ;
> +
> +boolean_factor:
> +          NOT_SYM boolean_factor
>            {
>              $$= negate_expression(thd, $2);
>              if (unlikely($$ == NULL))
>                MYSQL_YYABORT;
>            }
> -        | expr IS TRUE_SYM %prec IS
> +        | boolean_test %prec PREC_BELOW_NOT
> +        ;
> +
> +boolean_test:
> +          boolean_test IS TRUE_SYM %prec IS
>            {
>              $$= new (thd->mem_root) Item_func_istrue(thd, $1);
>              if (unlikely($$ == NULL))
>                MYSQL_YYABORT;
>            }
> -        | expr IS not TRUE_SYM %prec IS
> +        | boolean_test IS not TRUE_SYM %prec IS
>            {
>              $$= new (thd->mem_root) Item_func_isnottrue(thd, $1);
>              if (unlikely($$ == NULL))
>                MYSQL_YYABORT;
>            }
> -        | expr IS FALSE_SYM %prec IS
> +        | boolean_test IS FALSE_SYM %prec IS
>            {
>              $$= new (thd->mem_root) Item_func_isfalse(thd, $1);
>              if (unlikely($$ == NULL))
>                MYSQL_YYABORT;
>            }
> -        | expr IS not FALSE_SYM %prec IS
> +        | boolean_test IS not FALSE_SYM %prec IS
>            {
>              $$= new (thd->mem_root) Item_func_isnotfalse(thd, $1);
>              if (unlikely($$ == NULL))
>                MYSQL_YYABORT;
>            }
> -        | expr IS UNKNOWN_SYM %prec IS
> +        | boolean_test IS UNKNOWN_SYM %prec IS
>            {
>              $$= new (thd->mem_root) Item_func_isnull(thd, $1);
>              if (unlikely($$ == NULL))
>                MYSQL_YYABORT;
>            }
> -        | expr IS not UNKNOWN_SYM %prec IS
> +        | boolean_test IS not UNKNOWN_SYM %prec IS
>            {
>              $$= new (thd->mem_root) Item_func_isnotnull(thd, $1);
>              if (unlikely($$ == NULL))
>                MYSQL_YYABORT;
>            }
> -        | expr IS NULL_SYM %prec PREC_BELOW_NOT
> +        | boolean_test IS NULL_SYM %prec PREC_BELOW_NOT

can you try %prec IS here?
I suspect that if this affects anything, it'll cause bugs

>            {
>              $$= new (thd->mem_root) Item_func_isnull(thd, $1);
>              if (unlikely($$ == NULL))
>                MYSQL_YYABORT;
>            }
> -        | expr IS not NULL_SYM %prec IS
> +        | boolean_test IS not NULL_SYM %prec IS
>            {
>              $$= new (thd->mem_root) Item_func_isnotnull(thd, $1);
>              if (unlikely($$ == NULL))
>                MYSQL_YYABORT;
>            }
> -        | expr EQUAL_SYM predicate %prec EQUAL_SYM
> +        | boolean_test EQUAL_SYM predicate %prec EQUAL_SYM
>            {
>              $$= new (thd->mem_root) Item_func_equal(thd, $1, $3);
>              if (unlikely($$ == NULL))
>                MYSQL_YYABORT;
>            }
> -        | expr comp_op predicate %prec '='
> +        | boolean_test comp_op predicate %prec '='
>            {
>              $$= (*$2)(0)->create(thd, $1, $3);
>              if (unlikely($$ == NULL))
>                MYSQL_YYABORT;
>            }
> -        | expr comp_op all_or_any '(' subselect ')' %prec '='
> +        | boolean_test comp_op all_or_any '(' subselect ')' %prec '='
>            {
>              $$= all_any_subquery_creator(thd, $1, $2, $3, $5);
>              if (unlikely($$ == NULL))
>                MYSQL_YYABORT;
>            }
> -        | predicate
> +        | predicate %prec BETWEEN_SYM
>          ;
>  

Regards,
Sergei
VP of MariaDB Server Engineering
and security@xxxxxxxxxxx