Re: fix for BUG #3720: wrong results at using ltree

Tom Lane <tgl@sss.pgh.pa.us>

From: Tom Lane <tgl@sss.pgh.pa.us>
To: Nikita Glukhov <n.gluhov@postgrespro.ru>
Cc: Pgsql Hackers <pgsql-hackers@postgresql.org>, Filip Rembiałkowski <filip.rembialkowski@gmail.com>, Tomas Vondra <tomas.vondra@2ndquadrant.com>, Alexander Korotkov <a.korotkov@postgrespro.ru>, Oleg Bartunov <obartunov@postgrespro.ru>, Thomas Munro <thomas.munro@gmail.com>, Teodor Sigaev <teodor@sigaev.ru>
Date: 2020-03-31T15:47:30Z
Lists: pgsql-hackers
I wrote:
> I've marked this RFC, and will push tomorrow unless somebody wants
> to object to the loss of backwards compatibility.

And done.  I noticed in some final testing that it's possible to
make this code take a long time by forcing it to backtrack a lot:

regression=# SELECT (('1' || repeat('.1', 65534))::ltree) ~ '*.*.x';
 ?column? 
----------
 f
(1 row)

Time: 54015.421 ms (00:54.015)

so I threw in a CHECK_FOR_INTERRUPTS().  Maybe it'd be worth trying
to optimize such cases, but I'm not sure that it'd ever matter for
real-world cases with reasonable-size label strings.

The old implementation seems to handle that particular case well,
evidently because it more-or-less folds adjacent stars together.
However, before anyone starts complaining about regressions, they
should note that it's really easy to get the old code to fail
via stack overflow:

regression=# SELECT (('1' || repeat('.1', 65534))::ltree) ~ '*.!1.*';
ERROR:  stack depth limit exceeded

(That's as of five minutes ago, before that it dumped core.)
So I don't feel bad about the tradeoff.  At least now we have
simple, visibly correct code that could serve as a starting
point for optimization if anyone feels the need to.

			regards, tom lane



Commits

  1. Back-patch addition of stack overflow and interrupt checks for lquery.

  2. Fix lquery's NOT handling, and add ability to quantify non-'*' items.

  3. Improve error messages in ltree_in and lquery_in.

  4. Fix lquery's behavior for consecutive '*' items.

  5. Protect against overflow of ltree.numlevel and lquery.numlevel.