Precedence of NOT LIKE, NOT BETWEEN, etc - Mailing list pgsql-hackers
From | Tom Lane |
---|---|
Subject | Precedence of NOT LIKE, NOT BETWEEN, etc |
Date | |
Msg-id | 9543.1424720597@sss.pgh.pa.us Whole thread Raw |
Responses |
Re: Precedence of NOT LIKE, NOT BETWEEN, etc
Re: Precedence of NOT LIKE, NOT BETWEEN, etc |
List | pgsql-hackers |
While fooling around with testing operator precedence warnings, I discovered that there's some existing precedence behavior that's not at all what I expected. Consider these examples (all done in 9.4; this is longstanding behavior): regression=# SELECT 1 < '(3,4)'::point LIKE 42.0; ERROR: operator does not exist: point ~~ numeric LINE 1: SELECT 1 < '(3,4)'::point LIKE 42.0; ^ regression=# SELECT 1 < '(3,4)'::point NOT LIKE 42.0; ERROR: operator does not exist: integer < point LINE 1: SELECT 1 < '(3,4)'::point NOT LIKE 42.0; ^ regression=# SELECT 1 LIKE '(3,4)'::point < 42.0; ERROR: operator does not exist: integer ~~ point LINE 1: SELECT 1 LIKE '(3,4)'::point < 42.0; ^ regression=# SELECT 1 NOT LIKE '(3,4)'::point < 42.0; ERROR: operator does not exist: integer !~~ point LINE 1: SELECT 1 NOT LIKE '(3,4)'::point < 42.0; ^ These queries are silly of course, the point is just to expose which operator the parser thinks binds more tightly. And what we have above is: LIKE binds more tightly than <, in either combination. NOT LIKE binds less tightly than < if < is on the left, but more tightly than < if < is on the right. This seems like a bug; it's certainly not what you'd call intuitive. The cause, if I'm understanding the Bison manual correctly, is that the NOT token has lower precedence than '<', so at the critical point where it has scanned 1 < '(3,4)'::point and has to either reduce that (thus binding < more tightly) or shift, it looks at the lookahead token which is either LIKE or NOT in the first two examples above. LIKE has higher priority than '<' so in the first example it shifts; but NOT has lower priority than '<' so in the second example it reduces. The other productions starting with "a_expr NOT ..." also have the same problem; that includes NOT ILIKE, NOT SIMILAR TO, NOT BETWEEN, and NOT IN. I'm not seeing any terribly pleasing ways to fix this. Aside from the option of doing nothing, it seems like these are the choices: 1. We could hack base_yylex() to reduce NOT LIKE to a single token which could be given the same precedence as LIKE. Ditto for the other four cases. This would result in nice behavior for these cases, but as Robert has correctly pointed out, hacks in base_yylex() risk creating other poorly-understood behaviors. 2. We could change the precedence levels so that LIKE/ILIKE/SIMILAR, BETWEEN, and IN all have precedence just above NOT, which would pretty much mask the problem since there would be no other tokens with in-between precedence levels. In the context of the operator precedence changes I proposed earlier, this would mean inserting the IS tests and comparison operators between IN_P and POSTFIXOP rather than where the single-character comparison ops live now. We would likely also have to flatten LIKE/BETWEEN/IN into a single %nonassoc precedence level to avoid having weird interactions among them. This isn't terribly attractive because it would risk larger behavioral changes than the previous proposal. Thoughts? regards, tom lane
pgsql-hackers by date: