Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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)