Skip to content

Commit cd8ba91

Browse files
committed
Fix bug with whole-row references to append subplans.
ExecEvalWholeRowVar incorrectly supposed that it could "bless" the source TupleTableSlot just once per query. But if the input is coming from an Append (or, perhaps, other cases?) more than one slot might be returned over the query run. This led to "record type has not been registered" errors when a composite datum was extracted from a non-blessed slot. This bug has been there a long time; I guess it escaped notice because when dealing with subqueries the planner tends to expand whole-row Vars into RowExprs, which don't have the same problem. It is possible to trigger the problem in all active branches, though, as illustrated by the added regression test.
1 parent 2865d59 commit cd8ba91

File tree

3 files changed

+47
-14
lines changed

3 files changed

+47
-14
lines changed

src/backend/executor/execQual.c

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -704,7 +704,6 @@ ExecEvalWholeRowVar(WholeRowVarExprState *wrvstate, ExprContext *econtext,
704704
{
705705
Var *variable = (Var *) wrvstate->xprstate.expr;
706706
TupleTableSlot *slot;
707-
TupleDesc slot_tupdesc;
708707
bool needslow = false;
709708

710709
if (isDone)
@@ -794,25 +793,14 @@ ExecEvalWholeRowVar(WholeRowVarExprState *wrvstate, ExprContext *econtext,
794793
if (wrvstate->wrv_junkFilter != NULL)
795794
slot = ExecFilterJunk(wrvstate->wrv_junkFilter, slot);
796795

797-
slot_tupdesc = slot->tts_tupleDescriptor;
798-
799796
/*
800-
* If it's a RECORD Var, we'll use the slot's type ID info. It's likely
801-
* that the slot's type is also RECORD; if so, make sure it's been
802-
* "blessed", so that the Datum can be interpreted later.
803-
*
804797
* If the Var identifies a named composite type, we must check that the
805798
* actual tuple type is compatible with it.
806799
*/
807-
if (variable->vartype == RECORDOID)
808-
{
809-
if (slot_tupdesc->tdtypeid == RECORDOID &&
810-
slot_tupdesc->tdtypmod < 0)
811-
assign_record_type_typmod(slot_tupdesc);
812-
}
813-
else
800+
if (variable->vartype != RECORDOID)
814801
{
815802
TupleDesc var_tupdesc;
803+
TupleDesc slot_tupdesc;
816804
int i;
817805

818806
/*
@@ -829,6 +817,8 @@ ExecEvalWholeRowVar(WholeRowVarExprState *wrvstate, ExprContext *econtext,
829817
*/
830818
var_tupdesc = lookup_rowtype_tupdesc(variable->vartype, -1);
831819

820+
slot_tupdesc = slot->tts_tupleDescriptor;
821+
832822
if (var_tupdesc->natts != slot_tupdesc->natts)
833823
ereport(ERROR,
834824
(errcode(ERRCODE_DATATYPE_MISMATCH),
@@ -886,6 +876,7 @@ ExecEvalWholeRowFast(WholeRowVarExprState *wrvstate, ExprContext *econtext,
886876
{
887877
Var *variable = (Var *) wrvstate->xprstate.expr;
888878
TupleTableSlot *slot;
879+
TupleDesc slot_tupdesc;
889880
HeapTupleHeader dtuple;
890881

891882
if (isDone)
@@ -913,6 +904,20 @@ ExecEvalWholeRowFast(WholeRowVarExprState *wrvstate, ExprContext *econtext,
913904
if (wrvstate->wrv_junkFilter != NULL)
914905
slot = ExecFilterJunk(wrvstate->wrv_junkFilter, slot);
915906

907+
/*
908+
* If it's a RECORD Var, we'll use the slot's type ID info. It's likely
909+
* that the slot's type is also RECORD; if so, make sure it's been
910+
* "blessed", so that the Datum can be interpreted later. (Note: we must
911+
* do this here, not in ExecEvalWholeRowVar, because some plan trees may
912+
* return different slots at different times. We have to be ready to
913+
* bless additional slots during the run.)
914+
*/
915+
slot_tupdesc = slot->tts_tupleDescriptor;
916+
if (variable->vartype == RECORDOID &&
917+
slot_tupdesc->tdtypeid == RECORDOID &&
918+
slot_tupdesc->tdtypmod < 0)
919+
assign_record_type_typmod(slot_tupdesc);
920+
916921
/*
917922
* Copy the slot tuple and make sure any toasted fields get detoasted.
918923
*/

src/test/regress/expected/subselect.out

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -765,3 +765,21 @@ select * from int4_tbl o where (f1, f1) in
765765
(1 row)
766766

767767
reset enable_hashjoin;
768+
--
769+
-- check for over-optimization of whole-row Var referencing an Append plan
770+
--
771+
select (select q from
772+
(select 1,2,3 where f1 > 0
773+
union all
774+
select 4,5,6.0 where f1 <= 0
775+
) q )
776+
from int4_tbl;
777+
?column?
778+
-----------
779+
(4,5,6.0)
780+
(1,2,3)
781+
(4,5,6.0)
782+
(1,2,3)
783+
(4,5,6.0)
784+
(5 rows)
785+

src/test/regress/sql/subselect.sql

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,3 +427,13 @@ select * from int4_tbl o where (f1, f1) in
427427
select * from int4_tbl o where (f1, f1) in
428428
(select f1, generate_series(1,2) / 10 g from int4_tbl i group by f1);
429429
reset enable_hashjoin;
430+
431+
--
432+
-- check for over-optimization of whole-row Var referencing an Append plan
433+
--
434+
select (select q from
435+
(select 1,2,3 where f1 > 0
436+
union all
437+
select 4,5,6.0 where f1 <= 0
438+
) q )
439+
from int4_tbl;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy