Thread
Commits
-
Fix lexing of standard multi-character operators in edge cases.
- d64fad666992 10.6 landed
- 5b4555f90c08 11.0 landed
- a40631a920ac 12.0 landed
- af988d13012f 9.5.15 landed
- 5ec70a928621 9.6.11 landed
-
A really subtle lexer bug
Andrew Gierth <andrew@tao11.riddles.org.uk> — 2018-08-20T07:38:52Z
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)
-
Re: A really subtle lexer bug
Andrew Gierth <andrew@tao11.riddles.org.uk> — 2018-08-20T16:58:49Z
>>>>> "Andrew" == Andrew Gierth <andrew@tao11.riddles.org.uk> writes: Andrew> select f(a =>-1); -- ERROR: column "a" does not exist Andrew> I guess the fix is to extend the existing special case code Andrew> that checks for one character left after removing trailing [+-] Andrew> and also check for the two-character ops "<>" ">=" "<=" "=>" Andrew> "!=". Patch attached. This fixes two bugs: first the mis-lexing of two-char ops as mentioned originally; second, the O(N^3) lexing time of strings of - or + characters is reduced to O(N^2) (in practice it's better than O(N^2) once N gets large because the bison stack gets blown out, ending the loop early). -- Andrew (irc:RhodiumToad)
-
Re: A really subtle lexer bug
Andrew Gierth <andrew@tao11.riddles.org.uk> — 2018-08-21T05:47:47Z
>>>>> "Andrew" == Andrew Gierth <andrew@tao11.riddles.org.uk> writes: Andrew> Patch attached. Andrew> This fixes two bugs: I'm going to split this into two patches, since the O(N^3) fix can be backpatched further than the operator token fix; the latter bug was introduced in 9.5 when operator precedences were corrected, while the former has been there forever. (But don't wait for me to post those before commenting on either issue) -- Andrew (irc:RhodiumToad)
-
Re: A really subtle lexer bug
Tom Lane <tgl@sss.pgh.pa.us> — 2018-08-23T14:55:15Z
Andrew Gierth <andrew@tao11.riddles.org.uk> writes: > "Andrew" == Andrew Gierth <andrew@tao11.riddles.org.uk> writes: > Andrew> I guess the fix is to extend the existing special case code > Andrew> that checks for one character left after removing trailing [+-] > Andrew> and also check for the two-character ops "<>" ">=" "<=" "=>" > Andrew> "!=". > Patch attached. > This fixes two bugs: first the mis-lexing of two-char ops as mentioned > originally; second, the O(N^3) lexing time of strings of - or + > characters is reduced to O(N^2) (in practice it's better than O(N^2) > once N gets large because the bison stack gets blown out, ending the > loop early). Looks reasonable offhand (didn't test). A couple of thoughts: * Some regression tests exercising these code paths might be a good thing. * There should likely be a comment near where EQUALS_GREATER and friends are defined, pointing out that if we add any more multi-character operators with special precedences, this code has to be taught about them. regards, tom lane
-
Re: A really subtle lexer bug
Andrew Gierth <andrew@tao11.riddles.org.uk> — 2018-08-23T15:29:23Z
>>>>> "Tom" == Tom Lane <tgl@sss.pgh.pa.us> writes: >> Patch attached. >> This fixes two bugs: first the mis-lexing of two-char ops as mentioned >> originally; second, the O(N^3) lexing time of strings of - or + >> characters is reduced to O(N^2) (in practice it's better than O(N^2) >> once N gets large because the bison stack gets blown out, ending the >> loop early). Tom> Looks reasonable offhand (didn't test). A couple of thoughts: Tom> * Some regression tests exercising these code paths might be a Tom> good thing. Agreed. Any preferences where they should go? Tom> * There should likely be a comment near where EQUALS_GREATER and Tom> friends are defined, pointing out that if we add any more Tom> multi-character operators with special precedences, this code has Tom> to be taught about them. Agreed; will do this. -- Andrew (irc:RhodiumToad)
-
Re: A really subtle lexer bug
Tom Lane <tgl@sss.pgh.pa.us> — 2018-08-23T15:54:30Z
Andrew Gierth <andrew@tao11.riddles.org.uk> writes: > "Tom" == Tom Lane <tgl@sss.pgh.pa.us> writes: > Tom> * Some regression tests exercising these code paths might be a > Tom> good thing. > Agreed. Any preferences where they should go? There's not really a "lexer/grammar" test script. Maybe you could drop it into create_operator.sql, especially if you need to make any funny operators to test with? regards, tom lane
-
Re: A really subtle lexer bug
Andrew Gierth <andrew@tao11.riddles.org.uk> — 2018-08-23T18:43:50Z
Here's what I will push unless there's something important I missed. I split the regression tests between create_operator.sql and polymorphism.sql, because => is really "named argument syntax" rather than an operator as such, and polymorphism.sql is where the existing tests were for that. I tried to keep the three lexers as closely matched as possible, even though psqlscan.l doesn't actually need some of the changes. -- Andrew (irc:RhodiumToad)
-
Re: A really subtle lexer bug
Tom Lane <tgl@sss.pgh.pa.us> — 2018-08-23T19:05:53Z
Andrew Gierth <andrew@tao11.riddles.org.uk> writes: > Here's what I will push unless there's something important I missed. Stylistic nitpick: I don't especially like "continue" as the body of a for-loop. How about instead of this: for (nchars--; nchars > 1 && (yytext[nchars - 1] == '+' || yytext[nchars - 1] == '-'); nchars--) continue; do this: do { nchars--; } while (nchars > 1 && (yytext[nchars - 1] == '+' || yytext[nchars - 1] == '-')); That's a clearer separation between loop action and loop test, and it makes it more obvious that you're relying on the loop condition to be true at the start. Also, I'm not entirely convinced that replacing the strchr() with a handmade equivalent is a good idea. Some versions of strchr() are pretty quick. No objections beyond that. regards, tom lane