Skip to content

Commit 68e4099

Browse files
committed
Extend whole-row Var evaluation to cope with the case that the sub-plan
generating the tuples has resjunk output columns. This is not possible for simple table scans but can happen when evaluating a whole-row Var for a view. Per example from Patryk Kordylewski. The problem exists back to 8.0 but I'm not going to risk back-patching further than 8.2 because of the many changes in this area.
1 parent 42e9e26 commit 68e4099

File tree

1 file changed

+76
-5
lines changed

1 file changed

+76
-5
lines changed

src/backend/executor/execQual.c

Lines changed: 76 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.220 2007/06/11 22:22:40 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.221 2007/08/31 18:33:40 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -68,6 +68,8 @@ static Datum ExecEvalScalarVar(ExprState *exprstate, ExprContext *econtext,
6868
bool *isNull, ExprDoneCond *isDone);
6969
static Datum ExecEvalWholeRowVar(ExprState *exprstate, ExprContext *econtext,
7070
bool *isNull, ExprDoneCond *isDone);
71+
static Datum ExecEvalWholeRowSlow(ExprState *exprstate, ExprContext *econtext,
72+
bool *isNull, ExprDoneCond *isDone);
7173
static Datum ExecEvalConst(ExprState *exprstate, ExprContext *econtext,
7274
bool *isNull, ExprDoneCond *isDone);
7375
static Datum ExecEvalParam(ExprState *exprstate, ExprContext *econtext,
@@ -438,7 +440,8 @@ ExecEvalAggref(AggrefExprState *aggref, ExprContext *econtext,
438440
*
439441
* Note: ExecEvalVar is executed only the first time through in a given plan;
440442
* it changes the ExprState's function pointer to pass control directly to
441-
* ExecEvalScalarVar or ExecEvalWholeRowVar after making one-time checks.
443+
* ExecEvalScalarVar, ExecEvalWholeRowVar, or ExecEvalWholeRowSlow after
444+
* making one-time checks.
442445
* ----------------------------------------------------------------
443446
*/
444447
static Datum
@@ -544,6 +547,7 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
544547
* the actual tuple type is compatible with it.
545548
*/
546549
TupleDesc slot_tupdesc = slot->tts_tupleDescriptor;
550+
bool needslow = false;
547551

548552
if (variable->vartype == RECORDOID)
549553
{
@@ -561,16 +565,26 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
561565
* Also, we can ignore type mismatch on columns that are dropped
562566
* in the destination type, so long as the physical storage
563567
* matches. This is helpful in some cases involving out-of-date
564-
* cached plans.
568+
* cached plans. Also, we have to allow the case that the slot
569+
* has more columns than the Var's type, because we might be
570+
* looking at the output of a subplan that includes resjunk
571+
* columns. (XXX it would be nice to verify that the extra
572+
* columns are all marked resjunk, but we haven't got access to
573+
* the subplan targetlist here...) Resjunk columns should always
574+
* be at the end of a targetlist, so it's sufficient to ignore
575+
* them here; but we need to use ExecEvalWholeRowSlow to get
576+
* rid of them in the eventual output tuples.
565577
*/
566578
var_tupdesc = lookup_rowtype_tupdesc(variable->vartype, -1);
567579

568-
if (var_tupdesc->natts != slot_tupdesc->natts)
580+
if (var_tupdesc->natts > slot_tupdesc->natts)
569581
ereport(ERROR,
570582
(errcode(ERRCODE_DATATYPE_MISMATCH),
571583
errmsg("table row type and query-specified row type do not match"),
572584
errdetail("Table row contains %d attributes, but query expects %d.",
573585
slot_tupdesc->natts, var_tupdesc->natts)));
586+
else if (var_tupdesc->natts < slot_tupdesc->natts)
587+
needslow = true;
574588

575589
for (i = 0; i < var_tupdesc->natts; i++)
576590
{
@@ -601,7 +615,10 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
601615
}
602616

603617
/* Skip the checking on future executions of node */
604-
exprstate->evalfunc = ExecEvalWholeRowVar;
618+
if (needslow)
619+
exprstate->evalfunc = ExecEvalWholeRowSlow;
620+
else
621+
exprstate->evalfunc = ExecEvalWholeRowVar;
605622

606623
/* Fetch the value */
607624
return ExecEvalWholeRowVar(exprstate, econtext, isNull, isDone);
@@ -698,6 +715,60 @@ ExecEvalWholeRowVar(ExprState *exprstate, ExprContext *econtext,
698715
return PointerGetDatum(dtuple);
699716
}
700717

718+
/* ----------------------------------------------------------------
719+
* ExecEvalWholeRowSlow
720+
*
721+
* Returns a Datum for a whole-row variable, in the "slow" case where
722+
* we can't just copy the subplan's output.
723+
* ----------------------------------------------------------------
724+
*/
725+
static Datum
726+
ExecEvalWholeRowSlow(ExprState *exprstate, ExprContext *econtext,
727+
bool *isNull, ExprDoneCond *isDone)
728+
{
729+
Var *variable = (Var *) exprstate->expr;
730+
TupleTableSlot *slot = econtext->ecxt_scantuple;
731+
HeapTuple tuple;
732+
TupleDesc var_tupdesc;
733+
HeapTupleHeader dtuple;
734+
735+
if (isDone)
736+
*isDone = ExprSingleResult;
737+
*isNull = false;
738+
739+
/*
740+
* Currently, the only case handled here is stripping of trailing
741+
* resjunk fields, which we do in a slightly chintzy way by just
742+
* adjusting the tuple's natts header field. Possibly there will someday
743+
* be a need for more-extensive rearrangements, in which case it'd
744+
* be worth disassembling and reassembling the tuple (perhaps use a
745+
* JunkFilter for that?)
746+
*/
747+
Assert(variable->vartype != RECORDOID);
748+
var_tupdesc = lookup_rowtype_tupdesc(variable->vartype, -1);
749+
750+
tuple = ExecFetchSlotTuple(slot);
751+
752+
/*
753+
* We have to make a copy of the tuple so we can safely insert the Datum
754+
* overhead fields, which are not set in on-disk tuples; not to mention
755+
* fooling with its natts field.
756+
*/
757+
dtuple = (HeapTupleHeader) palloc(tuple->t_len);
758+
memcpy((char *) dtuple, (char *) tuple->t_data, tuple->t_len);
759+
760+
HeapTupleHeaderSetDatumLength(dtuple, tuple->t_len);
761+
HeapTupleHeaderSetTypeId(dtuple, variable->vartype);
762+
HeapTupleHeaderSetTypMod(dtuple, variable->vartypmod);
763+
764+
Assert(HeapTupleHeaderGetNatts(dtuple) >= var_tupdesc->natts);
765+
HeapTupleHeaderSetNatts(dtuple, var_tupdesc->natts);
766+
767+
ReleaseTupleDesc(var_tupdesc);
768+
769+
return PointerGetDatum(dtuple);
770+
}
771+
701772
/* ----------------------------------------------------------------
702773
* ExecEvalConst
703774
*

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