A really subtle lexer bug

From: Andrew Gierth <andrew(at)tao11(dot)riddles(dot)org(dot)uk>
To: pgsql-hackers(at)postgresql(dot)org
Subject: A really subtle lexer bug
Date: 2018-08-20 07:38:52
Message-ID: 87va851ppl.fsf@news-spur.riddles.org.uk
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Currently in PG, the precedence of = and <> is supposed to be equal, and
the precedence of unary - is very high.

So, (true=1 between 1 and 1) parses as ((true)=(1 between 1 and 1)),
and (true=-1 between 1 and 1) parses as ((true)=((-1) between 1 and 1)).
All good so far.

(true<>-1 between 1 and 1) parses as ((true<>(-1)) between 1 and 1). ???

The fault here is in the lexer. The input "<>-" is being lexed as an Op
followed by '-' rather than as NOT_EQUAL followed by '-' because it
looks like a match for a multi-character operator, with the - being
thrown back into the input afterwards. So the precedence of <> gets
inflated to that of Op, which is higher than BETWEEN.

More seriously, this also breaks named arguments:

create function f(a integer) returns integer language sql
as $$ select a; $$;

select f(a => 1); -- works
select f(a => -1); -- works
select f(a =>-1); -- ERROR: column "a" does not exist

I guess the fix is to extend the existing special case code that checks
for one character left after removing trailing [+-] and also check for
the two-character ops "<>" ">=" "<=" "=>" "!=".

--
Andrew (irc:RhodiumToad)

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message David Rowley 2018-08-20 07:45:35 Calculate total_table_pages after set_base_rel_sizes()
Previous Message Tatsuro Yamada 2018-08-20 06:51:07 Re: Fix help option of contrib/oid2name