Thread: BUG #17737: An assert failed in execExprInterp.c

BUG #17737: An assert failed in execExprInterp.c

From
PG Bug reporting form
Date:
The following bug has been logged on the website:

Bug reference:      17737
Logged by:          xin wen
Email address:      xinwen@stu.scu.edu.cn
PostgreSQL version: 15.1
Operating system:   Ubuntu 20.04
Description:

When executing the following query:

CREATE TABLE table0 ( column1 INT ) ;
INSERT INTO table0 VALUES ( 1 ), ( 1 ) ;
WITH RECURSIVE table3 ( column0 ) AS ( SELECT column1 FROM table0 UNION
SELECT column0 FROM table3 WHERE column0 < 1 ) SELECT 1 FROM table3 LEFT
JOIN table0 ON TRUE ;

I get a failed assertion with the following stacktrace:

Core was generated by `postgres: postgres test [local] SELECT
'.
Program terminated with signal SIGABRT, Aborted.
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
#1  0x00007fd6183f7859 in __GI_abort () at abort.c:79
#2  0x0000556cb92faa88 in ExceptionalCondition
(conditionName=conditionName@entry=0x556cb944e508 "op->d.fetch.kind ==
slot->tts_ops", errorType=errorType@entry=0x556cb93584a0 "FailedAssertion",
fileName=fileName@entry=0x556cb944e400
"/home/postgres/postgresql-15.1/original_bin-15.1/../src/backend/executor/execExprInterp.c",
lineNumber=lineNumber@entry=1961) at
/home/postgres/postgresql-15.1/original_bin-15.1/../src/backend/utils/error/assert.c:69
#3  0x0000556cb9035935 in CheckOpSlotCompatibility (op=<optimized out>,
op=<optimized out>, slot=<optimized out>) at
/home/postgres/postgresql-15.1/original_bin-15.1/../src/backend/executor/execExprInterp.c:1961
#4  CheckOpSlotCompatibility (slot=<optimized out>, op=<optimized out>,
op=<optimized out>) at
/home/postgres/postgresql-15.1/original_bin-15.1/../src/backend/executor/execExprInterp.c:1936
#5  0x0000556cb90393f1 in ExecInterpExpr (state=0x556cba0bfd60,
econtext=0x556cba0bff68, isnull=<optimized out>) at
/home/postgres/postgresql-15.1/original_bin-15.1/../src/backend/executor/execExprInterp.c:527
#6  0x0000556cb903afb6 in ExecEvalExprSwitchContext (isNull=0x7ffd1ac47c17,
econtext=0x556cba0bff68, state=<optimized out>) at
/home/postgres/postgresql-15.1/original_bin-15.1/../src/include/executor/executor.h:341
#7  ExecQual (econtext=0x556cba0bff68, state=<optimized out>) at
/home/postgres/postgresql-15.1/original_bin-15.1/../src/include/executor/executor.h:410
#8  ExecQualAndReset (econtext=0x556cba0bff68, state=<optimized out>) at
/home/postgres/postgresql-15.1/original_bin-15.1/../src/include/executor/executor.h:427
#9  TupleHashTableMatch (tuple1=<optimized out>, tuple2=tuple2@entry=0x0,
tb=<optimized out>) at
/home/postgres/postgresql-15.1/original_bin-15.1/../src/backend/executor/execGrouping.c:559
#10 0x0000556cb903ca65 in tuplehash_insert_hash_internal (found=<optimized
out>, hash=<optimized out>, key=<optimized out>, tb=<optimized out>) at
/home/postgres/postgresql-15.1/original_bin-15.1/../src/include/lib/simplehash.h:653
#11 tuplehash_insert_hash (found=<optimized out>, hash=<optimized out>,
key=<optimized out>, tb=<optimized out>) at
/home/postgres/postgresql-15.1/original_bin-15.1/../src/include/lib/simplehash.h:774
#12 LookupTupleHashEntry_internal (hashtable=<optimized out>,
hashtable=<optimized out>, hash=2072154383, isnew=0x7ffd1ac47cd7,
slot=0x556cba0bedc0) at
/home/postgres/postgresql-15.1/original_bin-15.1/../src/backend/executor/execGrouping.c:507
#13 LookupTupleHashEntry (hashtable=<optimized out>,
slot=slot@entry=0x556cba0bedc0, isnew=isnew@entry=0x7ffd1ac47cd7,
hash=hash@entry=0x0) at
/home/postgres/postgresql-15.1/original_bin-15.1/../src/backend/executor/execGrouping.c:322
#14 0x0000556cb9073b5e in ExecRecursiveUnion (pstate=0x556cba0be428) at
/home/postgres/postgresql-15.1/original_bin-15.1/../src/backend/executor/nodeRecursiveunion.c:97
#15 0x0000556cb905a0fd in ExecProcNode (node=0x556cba0be428) at
/home/postgres/postgresql-15.1/original_bin-15.1/../src/include/executor/executor.h:259
#16 CteScanNext (node=node@entry=0x556cba0de038) at
/home/postgres/postgresql-15.1/original_bin-15.1/../src/backend/executor/nodeCtescan.c:103
#17 0x0000556cb9048c71 in ExecScanFetch (recheckMtd=0x556cb905a010
<CteScanRecheck>, accessMtd=0x556cb905a020 <CteScanNext>,
node=0x556cba0de038) at
/home/postgres/postgresql-15.1/original_bin-15.1/../src/backend/executor/execScan.c:133
#18 ExecScan (node=0x556cba0de038, accessMtd=0x556cb905a020 <CteScanNext>,
recheckMtd=0x556cb905a010 <CteScanRecheck>) at
/home/postgres/postgresql-15.1/original_bin-15.1/../src/backend/executor/execScan.c:182
#19 0x0000556cb9072f87 in ExecProcNode (node=0x556cba0de038) at
/home/postgres/postgresql-15.1/original_bin-15.1/../src/include/executor/executor.h:259
#20 ExecNestLoop (pstate=0x556cba0bfe50) at
/home/postgres/postgresql-15.1/original_bin-15.1/../src/backend/executor/nodeNestloop.c:109
#21 0x0000556cb903ec93 in ExecProcNode (node=0x556cba0bfe50) at
/home/postgres/postgresql-15.1/original_bin-15.1/../src/include/executor/executor.h:259
#22 ExecutePlan (execute_once=<optimized out>, dest=0x556cba0ce2c0,
direction=<optimized out>, numberTuples=0, sendTuples=<optimized out>,
operation=CMD_SELECT, use_parallel_mode=<optimized out>,
planstate=0x556cba0bfe50, estate=0x556cba0be160) at
/home/postgres/postgresql-15.1/original_bin-15.1/../src/backend/executor/execMain.c:1636
#23 standard_ExecutorRun (queryDesc=0x556cba0045c0, direction=<optimized
out>, count=0, execute_once=<optimized out>) at
/home/postgres/postgresql-15.1/original_bin-15.1/../src/backend/executor/execMain.c:363
#24 0x0000556cb91d1e5f in PortalRunSelect (portal=0x556cba050560,
forward=<optimized out>, count=0, dest=<optimized out>) at
/home/postgres/postgresql-15.1/original_bin-15.1/../src/backend/tcop/pquery.c:924
#25 0x0000556cb91d3431 in PortalRun (portal=portal@entry=0x556cba050560,
count=count@entry=9223372036854775807, isTopLevel=isTopLevel@entry=true,
run_once=run_once@entry=true, dest=dest@entry=0x556cba0ce2c0,
altdest=altdest@entry=0x556cba0ce2c0, qc=0x7ffd1ac480a0) at
/home/postgres/postgresql-15.1/original_bin-15.1/../src/backend/tcop/pquery.c:768
#26 0x0000556cb91cf202 in exec_simple_query ( query_string=0x556cb9fe3010
"WITH RECURSIVE table3 ( column0 ) AS ( SELECT column1 FROM table0 UNION
SELECT column0 FROM table3 WHERE column0 < 1 ) SELECT 1 FROM table3 LEFT
JOIN table0 ON TRUE ;") at
/home/postgres/postgresql-15.1/original_bin-15.1/../src/backend/tcop/postgres.c:1250
#27 0x0000556cb91d0f8c in PostgresMain (dbname=<optimized out>,
username=<optimized out>) at
/home/postgres/postgresql-15.1/original_bin-15.1/../src/backend/tcop/postgres.c:4581
#28 0x0000556cb913de8a in BackendRun (port=<optimized out>, port=<optimized
out>) at
/home/postgres/postgresql-15.1/original_bin-15.1/../src/backend/postmaster/postmaster.c:4504
#29 BackendStartup (port=<optimized out>) at
/home/postgres/postgresql-15.1/original_bin-15.1/../src/backend/postmaster/postmaster.c:4232
#30 ServerLoop () at
/home/postgres/postgresql-15.1/original_bin-15.1/../src/backend/postmaster/postmaster.c:1806
#31 0x0000556cb913effb in PostmasterMain (argc=<optimized out>,
argv=0x556cb9fdd310) at
/home/postgres/postgresql-15.1/original_bin-15.1/../src/backend/postmaster/postmaster.c:1478
#32 0x0000556cb8e69630 in main (argc=3, argv=0x556cb9fdd310) at
/home/postgres/postgresql-15.1/original_bin-15.1/../src/backend/main/main.c:202

I also find this assert failed in 14.6, 13.9 and12.13 using the same
statement.


Re: BUG #17737: An assert failed in execExprInterp.c

From
Tom Lane
Date:
PG Bug reporting form <noreply@postgresql.org> writes:
> When executing the following query:

> CREATE TABLE table0 ( column1 INT ) ;
> INSERT INTO table0 VALUES ( 1 ), ( 1 ) ;
> WITH RECURSIVE table3 ( column0 ) AS ( SELECT column1 FROM table0 UNION
> SELECT column0 FROM table3 WHERE column0 < 1 ) SELECT 1 FROM table3 LEFT
> JOIN table0 ON TRUE ;

> I get a failed assertion with the following stacktrace:

Yeah.  The problem is that LookupTupleHashEntry is being handed
a BufferHeapTuple slot, evidently direct from the scan of table0,
but BuildTupleHashTableExt previously set up the comparison
expression on the assumption that the input would be a MinimalTuple
slot:

    /* build comparator for all columns */
    /* XXX: should we support non-minimal tuples for the inputslot? */
    hashtable->tab_eq_func = ExecBuildGroupingEqual(inputDesc, inputDesc,
                                                    &TTSOpsMinimalTuple, &TTSOpsMinimalTuple,
                                                    ...

AFAICT this has been wrong since we introduced multiple slot types
(I bisected it back to 15d8f8312, but of course that's just the
messenger).

I'm kind of baffled as to how it's escaped detection for this long;
maybe the assertion is overly tight, and the case actually works
in non-assert builds?  If so I'd be inclined to just weaken
CheckOpSlotCompatibility some more.  Otherwise, we need to either
improve execGrouping.c to cope with different input slot types,
or fix nodeRecursiveunion.c to force the supplied slot to be a
minimal one.  That last option seems pretty hacky, and it may fail
to cover some other case.

            regards, tom lane



Re: BUG #17737: An assert failed in execExprInterp.c

From
Tom Lane
Date:
I wrote:
> I'm kind of baffled as to how it's escaped detection for this long;
> maybe the assertion is overly tight, and the case actually works
> in non-assert builds?

A quick test says that indeed this example works in a non-assert
build.  So that may explain the lack of previous reports.  Whether
it'd be okay to weaken this check across-the-board isn't clear to me.

            regards, tom lane



Re: BUG #17737: An assert failed in execExprInterp.c

From
Andres Freund
Date:
Hi,

On 2023-01-05 15:50:03 -0500, Tom Lane wrote:
> PG Bug reporting form <noreply@postgresql.org> writes:
> > When executing the following query:
> 
> > CREATE TABLE table0 ( column1 INT ) ;
> > INSERT INTO table0 VALUES ( 1 ), ( 1 ) ;
> > WITH RECURSIVE table3 ( column0 ) AS ( SELECT column1 FROM table0 UNION
> > SELECT column0 FROM table3 WHERE column0 < 1 ) SELECT 1 FROM table3 LEFT
> > JOIN table0 ON TRUE ;
> 
> > I get a failed assertion with the following stacktrace:
> 
> Yeah.  The problem is that LookupTupleHashEntry is being handed
> a BufferHeapTuple slot, evidently direct from the scan of table0,
> but BuildTupleHashTableExt previously set up the comparison
> expression on the assumption that the input would be a MinimalTuple
> slot:
> 
>     /* build comparator for all columns */
>     /* XXX: should we support non-minimal tuples for the inputslot? */
>     hashtable->tab_eq_func = ExecBuildGroupingEqual(inputDesc, inputDesc,
>                                                     &TTSOpsMinimalTuple, &TTSOpsMinimalTuple,
>                                                     ...
> 
> AFAICT this has been wrong since we introduced multiple slot types
> (I bisected it back to 15d8f8312, but of course that's just the
> messenger).

> I'm kind of baffled as to how it's escaped detection for this long;
> maybe the assertion is overly tight, and the case actually works
> in non-assert builds?

I suspect it might work solely because the columns happen to have already been
deformed. At least that's the case in the example above.

I'll be in a meetings for the next bit, will take a closer look after.

Greetings,

Andres Freund



Re: BUG #17737: An assert failed in execExprInterp.c

From
Andres Freund
Date:
Hi,

On 2023-01-05 15:50:03 -0500, Tom Lane wrote:
> Otherwise, we need to either improve execGrouping.c to cope with different
> input slot types, or fix nodeRecursiveunion.c to force the supplied slot to
> be a minimal one.  That last option seems pretty hacky, and it may fail to
> cover some other case.

I'm not so sure it's a bad idea to force the "input" tuple to minimal in
nodeRecursiveunion.c. Both ->working_table and ->hashtable internally use
minimal tuples. Which afaict means we'll do the conversion twice when we don't
already have minimal tuple, which can't be good for performance. It won't
matter much if the input tuple is a heap slot, but if it's a virtual slot it's
far from cheap.

Greetings,

Andres Freund