Обсуждение: BUG #17826: An assert failed in /src/backend/optimizer/util/var.c

Поиск
Список
Период
Сортировка

BUG #17826: An assert failed in /src/backend/optimizer/util/var.c

От
PG Bug reporting form
Дата:
The following bug has been logged on the website:

Bug reference:      17826
Logged by:          Anban Company
Email address:      xinwen@stu.scu.edu.cn
PostgreSQL version: 15.2
Operating system:   Ubuntu 20.04
Description:

When executing the following query:

WITH table1 AS ( SELECT 1 ) SELECT 1 FROM ( SELECT RANK ( ) OVER ( ) column0
FROM table1 JOIN table1 AS alias0 ON TRUE ) AS alias1 WHERE ( CASE WHEN ( 1
IN ( SELECT 1 ) ) THEN 1 END = column0 ) ;

I get a failed assertion with the following stacktrace:

Core was generated by `postgres: postgres postgres [local] SELECT
'.
Program terminated with signal SIGABRT, Aborted.
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
#1  0x00007f68a29b6859 in __GI_abort () at abort.c:79
#2  0x0000555d7a2db598 in ExceptionalCondition
(conditionName=conditionName@entry=0x555d7a44c828 "!IsA(node, SubPlan)",
errorType=errorType@entry=0x555d7a3394a0 "FailedAssertion",
fileName=fileName@entry=0x555d7a4504b8
"/home/postgres/postgresql-15.2/original_bin-15.2/../src/backend/optimizer/util/var.c",
lineNumber=lineNumber@entry=872) at
/home/postgres/postgresql-15.2/original_bin-15.2/../src/backend/utils/error/assert.c:69
#3  0x0000555d7a105c41 in flatten_join_alias_vars_mutator
(node=0x555d7aa0f518, context=0x7fff50b0c980) at
/home/postgres/postgresql-15.2/original_bin-15.2/../src/backend/optimizer/util/var.c:872
#4  0x0000555d7a08cba9 in expression_tree_mutator (node=0x555d7aa07eb0,
mutator=0x555d7a1057a0 <flatten_join_alias_vars_mutator>,
context=0x7fff50b0c980) at
/home/postgres/postgresql-15.2/original_bin-15.2/../src/backend/nodes/nodeFuncs.c:3320
#5  0x0000555d7a08cff6 in expression_tree_mutator (node=0x555d7aa0f888,
mutator=0x555d7a1057a0 <flatten_join_alias_vars_mutator>,
context=0x7fff50b0c980) at
/home/postgres/postgresql-15.2/original_bin-15.2/../src/backend/nodes/nodeFuncs.c:3165
#6  0x0000555d7a08cef9 in expression_tree_mutator (node=0x555d7aa07e58,
mutator=0x555d7a1057a0 <flatten_join_alias_vars_mutator>,
context=0x7fff50b0c980) at
/home/postgres/postgresql-15.2/original_bin-15.2/../src/backend/nodes/nodeFuncs.c:3137
#7  0x0000555d7a08cff6 in expression_tree_mutator (node=0x555d7aa11ba0,
mutator=0x555d7a1057a0 <flatten_join_alias_vars_mutator>,
context=0x7fff50b0c980) at
/home/postgres/postgresql-15.2/original_bin-15.2/../src/backend/nodes/nodeFuncs.c:3165
#8  0x0000555d7a08ccab in expression_tree_mutator (node=0x555d7aa11400,
mutator=0x555d7a1057a0 <flatten_join_alias_vars_mutator>,
context=0x7fff50b0c980) at
/home/postgres/postgresql-15.2/original_bin-15.2/../src/backend/nodes/nodeFuncs.c:2780
#9  0x0000555d7a08cff6 in expression_tree_mutator (node=0x555d7aa11bf8,
mutator=mutator@entry=0x555d7a1057a0 <flatten_join_alias_vars_mutator>,
context=context@entry=0x7fff50b0c980) at
/home/postgres/postgresql-15.2/original_bin-15.2/../src/backend/nodes/nodeFuncs.c:3165
#10 0x0000555d7a105821 in flatten_join_alias_vars_mutator (node=<optimized
out>, context=context@entry=0x7fff50b0c980) at
/home/postgres/postgresql-15.2/original_bin-15.2/../src/backend/optimizer/util/var.c:878
#11 0x0000555d7a10602e in flatten_join_alias_vars (query=<optimized out>,
node=<optimized out>) at
/home/postgres/postgresql-15.2/original_bin-15.2/../src/backend/optimizer/util/var.c:744
#12 0x0000555d7a0d4b79 in preprocess_expression
(root=root@entry=0x555d7aa11ca8, expr=<optimized out>, kind=kind@entry=1) at
/home/postgres/postgresql-15.2/original_bin-15.2/../src/backend/optimizer/plan/planner.c:1105
#13 0x0000555d7a0dcb8c in subquery_planner (glob=<optimized out>,
parse=parse@entry=0x555d7aa10058,
parent_root=parent_root@entry=0x555d7aa05f78,
hasRecursion=hasRecursion@entry=false, tuple_fraction=0) at
/home/postgres/postgresql-15.2/original_bin-15.2/../src/backend/optimizer/plan/planner.c:829
#14 0x0000555d7a0ac11e in set_subquery_pathlist (rte=<optimized out>,
rti=<optimized out>, rel=<optimized out>, root=<optimized out>) at
/home/postgres/postgresql-15.2/original_bin-15.2/../src/backend/optimizer/path/allpaths.c:2601
#15 set_rel_size (root=<optimized out>, rel=<optimized out>, rti=<optimized
out>, rte=<optimized out>) at
/home/postgres/postgresql-15.2/original_bin-15.2/../src/backend/optimizer/path/allpaths.c:425
#16 0x0000555d7a0ae980 in set_base_rel_sizes (root=<optimized out>) at
/home/postgres/postgresql-15.2/original_bin-15.2/../src/backend/optimizer/path/allpaths.c:326
#17 make_one_rel (root=root@entry=0x555d7aa05f78,
joinlist=joinlist@entry=0x555d7aa0fe18) at
/home/postgres/postgresql-15.2/original_bin-15.2/../src/backend/optimizer/path/allpaths.c:188
#18 0x0000555d7a0d4976 in query_planner (root=root@entry=0x555d7aa05f78,
qp_callback=qp_callback@entry=0x555d7a0d5990 <standard_qp_callback>,
qp_extra=qp_extra@entry=0x7fff50b0ccb0) at
/home/postgres/postgresql-15.2/original_bin-15.2/../src/backend/optimizer/plan/planmain.c:276
#19 0x0000555d7a0da4f9 in grouping_planner (root=<optimized out>,
tuple_fraction=<optimized out>) at
/home/postgres/postgresql-15.2/original_bin-15.2/../src/backend/optimizer/plan/planner.c:1470
#20 0x0000555d7a0dd145 in subquery_planner (glob=glob@entry=0x555d7aa047d8,
parse=parse@entry=0x555d7aa02e98, parent_root=parent_root@entry=0x0,
hasRecursion=hasRecursion@entry=false,
tuple_fraction=tuple_fraction@entry=0) at
/home/postgres/postgresql-15.2/original_bin-15.2/../src/backend/optimizer/plan/planner.c:1047
#21 0x0000555d7a0dd5a3 in standard_planner (parse=0x555d7aa02e98,
query_string=<optimized out>, cursorOptions=2048, boundParams=<optimized
out>) at
/home/postgres/postgresql-15.2/original_bin-15.2/../src/backend/optimizer/plan/planner.c:406
#22 0x0000555d7a1af74c in pg_plan_query (querytree=0x555d7aa02e98,
query_string=0x555d7a93c010 "WITH table1 AS ( SELECT 1 ) SELECT 1 FROM (
SELECT RANK ( ) OVER ( ) column46 FROM table1 JOIN table1 AS alias0 ON TRUE
) AS alias1 WHERE ( CASE WHEN ( 1 IN ( SELECT 1 ) ) THEN 1 END = column46 )
;", cursorOptions=2048, boundParams=0x0) at
/home/postgres/postgresql-15.2/original_bin-15.2/../src/backend/tcop/postgres.c:883
#23 0x0000555d7a1af841 in pg_plan_queries (querytrees=0x555d7aa05f20,
query_string=query_string@entry=0x555d7a93c010 "WITH table1 AS ( SELECT 1 )
SELECT 1 FROM ( SELECT RANK ( ) OVER ( ) column46 FROM table1 JOIN table1 AS
alias0 ON TRUE ) AS alias1 WHERE ( CASE WHEN ( 1 IN ( SELECT 1 ) ) THEN 1
END = column46 ) ;", cursorOptions=cursorOptions@entry=2048,
boundParams=boundParams@entry=0x0) at
/home/postgres/postgresql-15.2/original_bin-15.2/../src/backend/tcop/postgres.c:975
#24 0x0000555d7a1afc4f in exec_simple_query ( query_string=0x555d7a93c010
"WITH table1 AS ( SELECT 1 ) SELECT 1 FROM ( SELECT RANK ( ) OVER ( )
column46 FROM table1 JOIN table1 AS alias0 ON TRUE ) AS alias1 WHERE ( CASE
WHEN ( 1 IN ( SELECT 1 ) ) THEN 1 END = column46 ) ;") at
/home/postgres/postgresql-15.2/original_bin-15.2/../src/backend/tcop/postgres.c:1169
#25 0x0000555d7a1b17fc in PostgresMain (dbname=<optimized out>,
username=<optimized out>) at
/home/postgres/postgresql-15.2/original_bin-15.2/../src/backend/tcop/postgres.c:4593
#26 0x0000555d7a11e5aa in BackendRun (port=<optimized out>, port=<optimized
out>) at
/home/postgres/postgresql-15.2/original_bin-15.2/../src/backend/postmaster/postmaster.c:4511
#27 BackendStartup (port=<optimized out>) at
/home/postgres/postgresql-15.2/original_bin-15.2/../src/backend/postmaster/postmaster.c:4239
#28 ServerLoop () at
/home/postgres/postgresql-15.2/original_bin-15.2/../src/backend/postmaster/postmaster.c:1806
#29 0x0000555d7a11f71b in PostmasterMain (argc=<optimized out>,
argv=0x555d7a936310) at
/home/postgres/postgresql-15.2/original_bin-15.2/../src/backend/postmaster/postmaster.c:1478
#30 0x0000555d79e49510 in main (argc=3, argv=0x555d7a936310) at
/home/postgres/postgresql-15.2/original_bin-15.2/../src/backend/main/main.c:202


Re: BUG #17826: An assert failed in /src/backend/optimizer/util/var.c

От
Tom Lane
Дата:
PG Bug reporting form <noreply@postgresql.org> writes:
> When executing the following query:

> WITH table1 AS ( SELECT 1 ) SELECT 1 FROM ( SELECT RANK ( ) OVER ( ) column0
> FROM table1 JOIN table1 AS alias0 ON TRUE ) AS alias1 WHERE ( CASE WHEN ( 1
> IN ( SELECT 1 ) ) THEN 1 END = column0 ) ;

> I get a failed assertion with the following stacktrace:

The assertion is complaining about a SubPlan that has gotten pushed down
into the subquery, where it should not have been.  Tracing through it,
the blame appears to fall on commit 9d9c02ccd, which added this rather
astonishing bit of coding:

            if (!rinfo->pseudoconstant &&
                qual_is_pushdown_safe(subquery, rti, rinfo, &safetyInfo))
            {
                /* Push it down */
                subquery_push_qual(subquery, rte, rti, clause);
            }
            else
            {
+               /*
+                * Since we can't push the qual down into the subquery, check
+                * if it happens to reference a window function.  If so then
+                * it might be useful to use for the WindowAgg's runCondition.
+                */
+               if (!subquery->hasWindowFuncs ||
+                   check_and_push_window_quals(subquery, rte, rti, clause,
+                                               &run_cond_attrs))

In other words, after qual_is_pushdown_safe has rejected a qual as being
unsafe to push down, check_and_push_window_quals merrily does it anyway,
apparently on the theory that window functions are exempt from all rules.
How is this even a little bit sane?

We could fix the given problem by adding a duplicative contain_subplans
check in check_and_push_window_quals, but first I want to see an argument
why it's okay to ignore any of the other things qual_is_pushdown_safe is
checking for, because I think this is dangerously broken on every single
count.  My druthers would be to remove check_and_push_window_quals
altogether.

            regards, tom lane



Re: BUG #17826: An assert failed in /src/backend/optimizer/util/var.c

От
David Rowley
Дата:
On Fri, 10 Mar 2023 at 05:09, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> In other words, after qual_is_pushdown_safe has rejected a qual as being
> unsafe to push down, check_and_push_window_quals merrily does it anyway,
> apparently on the theory that window functions are exempt from all rules.
> How is this even a little bit sane?

I don't think it is.  I've not looked in detail yet, but I think we
might be able to do something in check_output_expressions() so that we
track the targetIsInAllPartitionLists() separately.  Maybe
unsafeColumns[] needs to become an enum type that has UNSAFE, SAFE,
WINDOW_RUNCONDITION_ONLY and then change things so we never make a
runCondition when the qual is UNSAFE.

Anyway, I'll give it more thought and aim to come up with a patch
early next week.

David



Re: BUG #17826: An assert failed in /src/backend/optimizer/util/var.c

От
Tom Lane
Дата:
David Rowley <dgrowleyml@gmail.com> writes:
> On Fri, 10 Mar 2023 at 05:09, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>> How is this even a little bit sane?

> I don't think it is.  I've not looked in detail yet, but I think we
> might be able to do something in check_output_expressions() so that we
> track the targetIsInAllPartitionLists() separately.  Maybe
> unsafeColumns[] needs to become an enum type that has UNSAFE, SAFE,
> WINDOW_RUNCONDITION_ONLY and then change things so we never make a
> runCondition when the qual is UNSAFE.

> Anyway, I'll give it more thought and aim to come up with a patch
> early next week.

Why can't we simply *remove* all this logic from subquery pushdown?

I would expect that what happens in useful cases is that we push down
the (safe) qual and then during planning of the subquery we see a WHERE
clause matching the window run condition and work with that.  So this
all seems redundant, quite aside from being faulty.

            regards, tom lane



Re: BUG #17826: An assert failed in /src/backend/optimizer/util/var.c

От
David Rowley
Дата:
On Sun, 12 Mar 2023 at 06:24, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> Why can't we simply *remove* all this logic from subquery pushdown?
>
> I would expect that what happens in useful cases is that we push down
> the (safe) qual and then during planning of the subquery we see a WHERE
> clause matching the window run condition and work with that.  So this
> all seems redundant, quite aside from being faulty.

hmm, sorry, I can't quite make sense of that.

It is only possible to either leave such quals in the outer query in
the WHERE clause or make them run conditions of some WindowClause in
the subquery. They can never be legally in the WHERE clause of the
subquery as window functions cannot be evaluated in the WHERE clause.
So I'm not really sure what the point of temporarily putting it in the
subqueries WHERE clause would be if we just later unconditionally move
it to become a WindowClause run condition.   If we're pushing it down,
then we need to validate that the qual definitely can become a run
condition qual, why not just make it that when it passes the
validation?

David



Re: BUG #17826: An assert failed in /src/backend/optimizer/util/var.c

От
Tom Lane
Дата:
David Rowley <dgrowleyml@gmail.com> writes:
> It is only possible to either leave such quals in the outer query in
> the WHERE clause or make them run conditions of some WindowClause in
> the subquery. They can never be legally in the WHERE clause of the
> subquery as window functions cannot be evaluated in the WHERE clause.

Ah, got it.  So basically, the quals that we want are excluded by
check_output_expressions' point 4 (since they reference window
function output columns rather than partitioning columns).  I think
we need them to satisfy every other property that's checked in this
code, though.  Now I agree that we need to refactor a bit -- we
don't want to have to re-check all of these conditions.

            regards, tom lane



Re: BUG #17826: An assert failed in /src/backend/optimizer/util/var.c

От
David Rowley
Дата:
On Mon, 13 Mar 2023 at 10:43, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>
> David Rowley <dgrowleyml@gmail.com> writes:
> > It is only possible to either leave such quals in the outer query in
> > the WHERE clause or make them run conditions of some WindowClause in
> > the subquery. They can never be legally in the WHERE clause of the
> > subquery as window functions cannot be evaluated in the WHERE clause.
>
> Ah, got it.  So basically, the quals that we want are excluded by
> check_output_expressions' point 4 (since they reference window
> function output columns rather than partitioning columns).  I think
> we need them to satisfy every other property that's checked in this
> code, though.  Now I agree that we need to refactor a bit -- we
> don't want to have to re-check all of these conditions.

OK, patch attached.

I've coded it so the only safety hazard that we can ignore for run
conditions is the column is in all WindowClause PARTITION BYs. I
believe the DISTINCT ON column not in the sort list is still a hazard.

The attached also fixes the issue with making a run condition when the
window func contains a volatile func, e.g:

explain select * from (select oid,count(random()) over (order by oid)
c from pg_class) c where c < 10;

I think this is ok to back patch to v15 as the pushdown_safety_info
struct is static.  I think it'd be ok to widen that type to int
instead of unsigned char, I just didn't.

I probably need to do a bit more indenting work.  I'll look again tomorrow.

David

Вложения

Re: BUG #17826: An assert failed in /src/backend/optimizer/util/var.c

От
Tom Lane
Дата:
David Rowley <dgrowleyml@gmail.com> writes:
> On Mon, 13 Mar 2023 at 10:43, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>> Ah, got it.  So basically, the quals that we want are excluded by
>> check_output_expressions' point 4 (since they reference window
>> function output columns rather than partitioning columns).  I think
>> we need them to satisfy every other property that's checked in this
>> code, though.  Now I agree that we need to refactor a bit -- we
>> don't want to have to re-check all of these conditions.

> OK, patch attached.

This looks good to me.  As a matter of style, I'd capitalize the
enum constant names, but I think it's OK otherwise.

> I probably need to do a bit more indenting work.  I'll look again tomorrow.

Yeah, this looks like pgindent might not like it as-is.

            regards, tom lane



Re: BUG #17826: An assert failed in /src/backend/optimizer/util/var.c

От
David Rowley
Дата:
On Fri, 17 Mar 2023 at 07:59, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>
> David Rowley <dgrowleyml@gmail.com> writes:
> > OK, patch attached.
>
> This looks good to me.  As a matter of style, I'd capitalize the
> enum constant names, but I think it's OK otherwise.

Thanks. I had been doing a bit more work on it and it looks very
slightly different from when you saw it. Agreed with the capitals in
the enum values.

I also found had to disallow subqueries in the WindowFunc. That
required a subplan check inside find_window_run_conditions().

I kinda also wanted to do the attached so that the logic to push or
not to push was more centralised.  I just couldn't figure out exactly
why we don't push down pseudoconstant quals, therefore, was unable to
document that sufficiently in the header comment in
qual_is_pushdown_safe(). I thought we might as well talk about that
while on the topic as what I've just committed does not really take
any measures to explain it.

The attached patch is graded for the assistance of discussion only.

David

Вложения

Re: BUG #17826: An assert failed in /src/backend/optimizer/util/var.c

От
Tom Lane
Дата:
David Rowley <dgrowleyml@gmail.com> writes:
> I kinda also wanted to do the attached so that the logic to push or
> not to push was more centralised.  I just couldn't figure out exactly
> why we don't push down pseudoconstant quals, therefore, was unable to
> document that sufficiently in the header comment in
> qual_is_pushdown_safe().

A pseudoconstant qual turns into a filtering Result node with a one-time
condition that controls whether it runs the child plan at all.  You want
to put those as high in the plan tree as possible, so that they cut off
the maximum possible amount of work when the one-time condition is false.
So pushing one down into a subplan would be downright counterproductive.

            regards, tom lane