8
8
*
9
9
*
10
10
* 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 $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
@@ -68,6 +68,8 @@ static Datum ExecEvalScalarVar(ExprState *exprstate, ExprContext *econtext,
68
68
bool * isNull , ExprDoneCond * isDone );
69
69
static Datum ExecEvalWholeRowVar (ExprState * exprstate , ExprContext * econtext ,
70
70
bool * isNull , ExprDoneCond * isDone );
71
+ static Datum ExecEvalWholeRowSlow (ExprState * exprstate , ExprContext * econtext ,
72
+ bool * isNull , ExprDoneCond * isDone );
71
73
static Datum ExecEvalConst (ExprState * exprstate , ExprContext * econtext ,
72
74
bool * isNull , ExprDoneCond * isDone );
73
75
static Datum ExecEvalParam (ExprState * exprstate , ExprContext * econtext ,
@@ -438,7 +440,8 @@ ExecEvalAggref(AggrefExprState *aggref, ExprContext *econtext,
438
440
*
439
441
* Note: ExecEvalVar is executed only the first time through in a given plan;
440
442
* 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.
442
445
* ----------------------------------------------------------------
443
446
*/
444
447
static Datum
@@ -544,6 +547,7 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
544
547
* the actual tuple type is compatible with it.
545
548
*/
546
549
TupleDesc slot_tupdesc = slot -> tts_tupleDescriptor ;
550
+ bool needslow = false;
547
551
548
552
if (variable -> vartype == RECORDOID )
549
553
{
@@ -561,16 +565,26 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
561
565
* Also, we can ignore type mismatch on columns that are dropped
562
566
* in the destination type, so long as the physical storage
563
567
* 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.
565
577
*/
566
578
var_tupdesc = lookup_rowtype_tupdesc (variable -> vartype , -1 );
567
579
568
- if (var_tupdesc -> natts != slot_tupdesc -> natts )
580
+ if (var_tupdesc -> natts > slot_tupdesc -> natts )
569
581
ereport (ERROR ,
570
582
(errcode (ERRCODE_DATATYPE_MISMATCH ),
571
583
errmsg ("table row type and query-specified row type do not match" ),
572
584
errdetail ("Table row contains %d attributes, but query expects %d." ,
573
585
slot_tupdesc -> natts , var_tupdesc -> natts )));
586
+ else if (var_tupdesc -> natts < slot_tupdesc -> natts )
587
+ needslow = true;
574
588
575
589
for (i = 0 ; i < var_tupdesc -> natts ; i ++ )
576
590
{
@@ -601,7 +615,10 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
601
615
}
602
616
603
617
/* 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 ;
605
622
606
623
/* Fetch the value */
607
624
return ExecEvalWholeRowVar (exprstate , econtext , isNull , isDone );
@@ -698,6 +715,60 @@ ExecEvalWholeRowVar(ExprState *exprstate, ExprContext *econtext,
698
715
return PointerGetDatum (dtuple );
699
716
}
700
717
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
+
701
772
/* ----------------------------------------------------------------
702
773
* ExecEvalConst
703
774
*
0 commit comments