QUAL Pushdown causes ERROR on syntactically and semantically correct SQL Query

Поиск
Список
Период
Сортировка
От Hans Buschmann
Тема QUAL Pushdown causes ERROR on syntactically and semantically correct SQL Query
Дата
Msg-id 97e79a26f4544c2ea1039041dc7732ab@nidsa.net
обсуждение исходный текст
Ответы Re: QUAL Pushdown causes ERROR on syntactically and semantically correct SQL Query  ("David G. Johnston" <david.g.johnston@gmail.com>)
Re: QUAL Pushdown causes ERROR on syntactically and semantically correct SQL Query  (Tom Lane <tgl@sss.pgh.pa.us>)
Список pgsql-hackers

I have reworked the case of BUG #17842 to include the data and the questions for further investigation.


qualstest_data contais the data export with --insert (to test it on other DB systems)

qualstest_query contains the failing query and a short introduction to the data.


The problem is NOT to correct the query to a working case, but to show a fundamental problem with qual pushdown.


On pg16b1 (same on 15.3) the explain of the second query produces:


qualstest=#
qualstest=#
qualstest=# explain -- select * from ( -- select count(*) from ( -- select length(sel) from (
qualstest-# select * from (
qualstest(# select
qualstest(#  onum
qualstest(# ,vname
qualstest(# ,vlen
qualstest(# ,nlen
qualstest(# ,olen
qualstest(# ,NULLIF(vlen-olen,0) as delta_len
qualstest(# from (
qualstest(# select *
qualstest(# ,('0'||split_part(split_part(nline,'(',2),')',1))::smallint as nlen
qualstest(# ,('0'||split_part(split_part(oline,'(',2),')',1))::smallint as olen
qualstest(# from newcol
qualstest(# join oldcol on onum=nnum
qualstest(# join (
qualstest(# select
qualstest(#  vnum
qualstest(# ,split_part(vline,' ',1) as vname
qualstest(# ,('0'||split_part(split_part(vline,'(',2),')',1))::smallint as vlen
qualstest(# from varcol
qualstest(# ) qv on nline like '%'||vname||'%'
qualstest(# where nline not like '%KEY%'
qualstest(# ) qj
qualstest(# --limit 30
qualstest(# where vlen!=olen
qualstest(# ) qcomp
qualstest-# where
qualstest-# nlen > 0
qualstest-# ;
                                                                                                 QUERY PLAN              
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Hash Join  (cost=90.37..10257.60 rows=2188 width=44)
   Hash Cond: (newcol.nnum = oldcol.onum)
   Join Filter: ((('0'::text || split_part(split_part(varcol.vline, '('::text, 2), ')'::text, 1)))::smallint <> (('0'::text || split_part(split_part(oldcol.oline, '('::text, 2), ')'::text, 1)))::smallint)
   ->  Nested Loop  (cost=0.00..10008.26 rows=2199 width=73)
         Join Filter: (newcol.nline ~~ (('%'::text || split_part(varcol.vline, ' '::text, 1)) || '%'::text))
         ->  Seq Scan on newcol  (cost=0.00..98.23 rows=738 width=36)
               Filter: ((nline !~~ '%KEY%'::text) AND ((('0'::text || split_part(split_part(nline, '('::text, 2), ')'::text, 1)))::smallint > 0))
         ->  Materialize  (cost=0.00..14.94 rows=596 width=37)
               ->  Seq Scan on varcol  (cost=0.00..11.96 rows=596 width=37)
   ->  Hash  (cost=60.72..60.72 rows=2372 width=44)
         ->  Seq Scan on oldcol  (cost=0.00..60.72 rows=2372 width=44)
(11 Zeilen)


qualstest=#
qualstest=# select version ();
                            version
---------------------------------------------------------------
 PostgreSQL 16beta1, compiled by Visual C++ build 1934, 64-bit
(1 Zeile)

on execution:
FEHLER:  ungültige Eingabesyntax für Typ smallint: »08,2«


ANALYSIS:

The join conditions matches all rows from oldcol and newcol, which then are filtered by inner join with only the varchar columns from varcol. Therefore the lines

,('0'||split_part(split_part(nline,'(',2),')',1))::smallint as nlen
,('0'||split_part(split_part(oline,'(',2),')',1))::smallint as olen

should be applied only to filtered results known to have smallint values between the parentesis in varchar definitions.

This is done correctly in the first (full) query without the final where clause.

When the where nlen > 0 comes into play, the plan is changed and the filter qual is applied to all lines.
There are other lines where the cast is not possible and the query fails with above error.

The fundamental problem is that quals should not be pushed down for tuples not in the result set, when the operation classes of these quals could error out.

Some operator classes have no runtime errors (like cast from smallint to int), but when such an error is possible, they should not be applied to tuples not part of the joined result set!

I stumbled over the error by adding this harmless where clause (where nlen > 0) to a just working query and got the error.

Other where-clauses (where nnum < 100) cause the same error.

Operator classes which could error out should not be applied for filtering columns from relations, which are not the outermost relation in joins and could be eliminated by another join.

These queries are syntactically and semantically correct but the postgre implementations causes them to error out.
This is very surprising for the SQL User!

The problem seems to exist also in certain backbranches.

Hans Buschmann


Вложения

В списке pgsql-hackers по дате отправления:

Предыдущее
От: Evan Jones
Дата:
Сообщение: [PATCH] pg_regress.c: Fix "make check" on Mac OS X: Pass DYLD_LIBRARY_PATH
Следующее
От: Heikki Linnakangas
Дата:
Сообщение: Let's make PostgreSQL multi-threaded