Marko Kreen <marko@l-t.ee> writes:
> I can still reproduce it:
> marko=# SELECT 5 & ~6;
> ERROR: Unable to identify a right operator '&' for type 'int4'
> You may need to add parentheses or an explicit cast
Correct, we did not rejigger the operator precedence.
I played around with this a little bit, and find that the attached patch
makes the above case work as desired --- essentially, it changes things
so that
a_expr Op Op a_expr
will be parsed as
a_expr Op (Op a_expr)
not
(a_expr Op) Op a_expr
which is what you get now because Op is marked left-associative.
Now, this is a situation where we can't fix one case without breaking
another, namely the case where you really DID want the first Op to be
parsed as a postfix operator. Thus the problem moves over to here:
regression=# select 4! ~ 10;
ERROR: Unable to identify an operator '!' for types 'int4' and 'int4'
You will have to retype this query using an explicit cast
regression=# select (4!) ~ 10;
?column?
----------
f
(1 row)
whereas this worked without parens in 7.0.
Given the infrequency of use of postfix operators compared to prefix,
I am inclined to think that we should change the grammar to make the
latter easier to use at the expense of the former. On the other hand,
it seems there's a pretty large risk of backwards-incompatibility here.
Comments?
BTW, the regress tests do not break, so they contain no examples where
it makes a difference.
regards, tom lane
*** src/backend/parser/gram.y.orig Sat Jan 20 12:37:52 2001
--- src/backend/parser/gram.y Sat Jan 20 13:03:17 2001
***************
*** 383,388 ****
--- 383,389 ----
%nonassoc OVERLAPS
%nonassoc BETWEEN
%nonassoc IN
+ %left POSTFIXOP /* dummy for postfix Op rules */
%left Op /* multi-character ops and user-defined operators */
%nonassoc NOTNULL
%nonassoc ISNULL
***************
*** 4312,4320 ****
{ $$ = makeA_Expr(OP, "+", NULL, $2); }
| '-' a_expr %prec UMINUS
{ $$ = doNegate($2); }
! | '%' a_expr
{ $$ = makeA_Expr(OP, "%", NULL, $2); }
! | '^' a_expr
{ $$ = makeA_Expr(OP, "^", NULL, $2); }
| a_expr '%'
{ $$ = makeA_Expr(OP, "%", $1, NULL); }
--- 4313,4321 ----
{ $$ = makeA_Expr(OP, "+", NULL, $2); }
| '-' a_expr %prec UMINUS
{ $$ = doNegate($2); }
! | '%' a_expr %prec UMINUS
{ $$ = makeA_Expr(OP, "%", NULL, $2); }
! | '^' a_expr %prec UMINUS
{ $$ = makeA_Expr(OP, "^", NULL, $2); }
| a_expr '%'
{ $$ = makeA_Expr(OP, "%", $1, NULL); }
***************
*** 4353,4361 ****
| a_expr Op a_expr
{ $$ = makeA_Expr(OP, $2, $1, $3); }
! | Op a_expr
{ $$ = makeA_Expr(OP, $1, NULL, $2); }
! | a_expr Op
{ $$ = makeA_Expr(OP, $2, $1, NULL); }
| a_expr AND a_expr
--- 4354,4362 ----
| a_expr Op a_expr
{ $$ = makeA_Expr(OP, $2, $1, $3); }
! | Op a_expr %prec UMINUS
{ $$ = makeA_Expr(OP, $1, NULL, $2); }
! | a_expr Op %prec POSTFIXOP
{ $$ = makeA_Expr(OP, $2, $1, NULL); }
| a_expr AND a_expr
***************
*** 4560,4568 ****
{ $$ = makeA_Expr(OP, "+", NULL, $2); }
| '-' b_expr %prec UMINUS
{ $$ = doNegate($2); }
! | '%' b_expr
{ $$ = makeA_Expr(OP, "%", NULL, $2); }
! | '^' b_expr
{ $$ = makeA_Expr(OP, "^", NULL, $2); }
| b_expr '%'
{ $$ = makeA_Expr(OP, "%", $1, NULL); }
--- 4561,4569 ----
{ $$ = makeA_Expr(OP, "+", NULL, $2); }
| '-' b_expr %prec UMINUS
{ $$ = doNegate($2); }
! | '%' b_expr %prec UMINUS
{ $$ = makeA_Expr(OP, "%", NULL, $2); }
! | '^' b_expr %prec UMINUS
{ $$ = makeA_Expr(OP, "^", NULL, $2); }
| b_expr '%'
{ $$ = makeA_Expr(OP, "%", $1, NULL); }
***************
*** 4589,4597 ****
| b_expr Op b_expr
{ $$ = makeA_Expr(OP, $2, $1, $3); }
! | Op b_expr
{ $$ = makeA_Expr(OP, $1, NULL, $2); }
! | b_expr Op
{ $$ = makeA_Expr(OP, $2, $1, NULL); }
;
--- 4590,4598 ----
| b_expr Op b_expr
{ $$ = makeA_Expr(OP, $2, $1, $3); }
! | Op b_expr %prec UMINUS
{ $$ = makeA_Expr(OP, $1, NULL, $2); }
! | b_expr Op %prec POSTFIXOP
{ $$ = makeA_Expr(OP, $2, $1, NULL); }
;