8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.260 2010/01/09 20:46:19 tgl Exp $
11
+ * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.261 2010/01/11 15:31:04 tgl Exp $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
@@ -591,17 +591,23 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
591
591
/*
592
592
* We really only care about number of attributes and data type.
593
593
* Also, we can ignore type mismatch on columns that are dropped
594
- * in the destination type, so long as the physical storage
595
- * matches. This is helpful in some cases involving out-of-date
596
- * cached plans. Also, we have to allow the case that the slot
597
- * has more columns than the Var's type, because we might be
598
- * looking at the output of a subplan that includes resjunk
599
- * columns. (XXX it would be nice to verify that the extra
600
- * columns are all marked resjunk, but we haven't got access to
601
- * the subplan targetlist here...) Resjunk columns should always
602
- * be at the end of a targetlist, so it's sufficient to ignore
603
- * them here; but we need to use ExecEvalWholeRowSlow to get rid
604
- * of them in the eventual output tuples.
594
+ * in the destination type, so long as (1) the physical storage
595
+ * matches or (2) the actual column value is NULL. Case (1) is
596
+ * helpful in some cases involving out-of-date cached plans, while
597
+ * case (2) is expected behavior in situations such as an INSERT
598
+ * into a table with dropped columns (the planner typically
599
+ * generates an INT4 NULL regardless of the dropped column type).
600
+ * If we find a dropped column and cannot verify that case (1)
601
+ * holds, we have to use ExecEvalWholeRowSlow to check (2) for
602
+ * each row. Also, we have to allow the case that the slot has
603
+ * more columns than the Var's type, because we might be looking
604
+ * at the output of a subplan that includes resjunk columns.
605
+ * (XXX it would be nice to verify that the extra columns are all
606
+ * marked resjunk, but we haven't got access to the subplan
607
+ * targetlist here...) Resjunk columns should always be at the end
608
+ * of a targetlist, so it's sufficient to ignore them here; but we
609
+ * need to use ExecEvalWholeRowSlow to get rid of them in the
610
+ * eventual output tuples.
605
611
*/
606
612
var_tupdesc = lookup_rowtype_tupdesc (variable -> vartype , -1 );
607
613
@@ -615,7 +621,7 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
615
621
slot_tupdesc -> natts ,
616
622
var_tupdesc -> natts )));
617
623
else if (var_tupdesc -> natts < slot_tupdesc -> natts )
618
- needslow = true;
624
+ needslow = true; /* need to trim trailing atts */
619
625
620
626
for (i = 0 ; i < var_tupdesc -> natts ; i ++ )
621
627
{
@@ -635,11 +641,7 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
635
641
636
642
if (vattr -> attlen != sattr -> attlen ||
637
643
vattr -> attalign != sattr -> attalign )
638
- ereport (ERROR ,
639
- (errcode (ERRCODE_DATATYPE_MISMATCH ),
640
- errmsg ("table row type and query-specified row type do not match" ),
641
- errdetail ("Physical storage mismatch on dropped attribute at ordinal position %d." ,
642
- i + 1 )));
644
+ needslow = true; /* need runtime check for null */
643
645
}
644
646
645
647
ReleaseTupleDesc (var_tupdesc );
@@ -766,7 +768,7 @@ ExecEvalWholeRowVar(ExprState *exprstate, ExprContext *econtext,
766
768
/* ----------------------------------------------------------------
767
769
* ExecEvalWholeRowSlow
768
770
*
769
- * Returns a Datum for a whole-row variable, in the "slow" case where
771
+ * Returns a Datum for a whole-row variable, in the "slow" cases where
770
772
* we can't just copy the subplan's output.
771
773
* ----------------------------------------------------------------
772
774
*/
@@ -779,6 +781,7 @@ ExecEvalWholeRowSlow(ExprState *exprstate, ExprContext *econtext,
779
781
HeapTuple tuple ;
780
782
TupleDesc var_tupdesc ;
781
783
HeapTupleHeader dtuple ;
784
+ int i ;
782
785
783
786
if (isDone )
784
787
* isDone = ExprSingleResult ;
@@ -802,18 +805,38 @@ ExecEvalWholeRowSlow(ExprState *exprstate, ExprContext *econtext,
802
805
}
803
806
804
807
/*
805
- * Currently, the only case handled here is stripping of trailing resjunk
806
- * fields, which we do in a slightly chintzy way by just adjusting the
807
- * tuple's natts header field. Possibly there will someday be a need for
808
- * more-extensive rearrangements, in which case it'd be worth
809
- * disassembling and reassembling the tuple (perhaps use a JunkFilter for
810
- * that?)
808
+ * Currently, the only data modification case handled here is stripping of
809
+ * trailing resjunk fields, which we do in a slightly chintzy way by just
810
+ * adjusting the tuple's natts header field. Possibly there will someday
811
+ * be a need for more-extensive rearrangements, in which case we'd
812
+ * probably use tupconvert.c.
811
813
*/
812
814
Assert (variable -> vartype != RECORDOID );
813
815
var_tupdesc = lookup_rowtype_tupdesc (variable -> vartype , -1 );
814
816
815
817
tuple = ExecFetchSlotTuple (slot );
816
818
819
+ Assert (HeapTupleHeaderGetNatts (tuple -> t_data ) >= var_tupdesc -> natts );
820
+
821
+ /* Check to see if any dropped attributes are non-null */
822
+ for (i = 0 ; i < var_tupdesc -> natts ; i ++ )
823
+ {
824
+ Form_pg_attribute vattr = var_tupdesc -> attrs [i ];
825
+ Form_pg_attribute sattr = slot -> tts_tupleDescriptor -> attrs [i ];
826
+
827
+ if (!vattr -> attisdropped )
828
+ continue ; /* already checked non-dropped cols */
829
+ if (heap_attisnull (tuple , i + 1 ))
830
+ continue ; /* null is always okay */
831
+ if (vattr -> attlen != sattr -> attlen ||
832
+ vattr -> attalign != sattr -> attalign )
833
+ ereport (ERROR ,
834
+ (errcode (ERRCODE_DATATYPE_MISMATCH ),
835
+ errmsg ("table row type and query-specified row type do not match" ),
836
+ errdetail ("Physical storage mismatch on dropped attribute at ordinal position %d." ,
837
+ i + 1 )));
838
+ }
839
+
817
840
/*
818
841
* We have to make a copy of the tuple so we can safely insert the Datum
819
842
* overhead fields, which are not set in on-disk tuples; not to mention
@@ -826,7 +849,6 @@ ExecEvalWholeRowSlow(ExprState *exprstate, ExprContext *econtext,
826
849
HeapTupleHeaderSetTypeId (dtuple , variable -> vartype );
827
850
HeapTupleHeaderSetTypMod (dtuple , variable -> vartypmod );
828
851
829
- Assert (HeapTupleHeaderGetNatts (dtuple ) >= var_tupdesc -> natts );
830
852
HeapTupleHeaderSetNatts (dtuple , var_tupdesc -> natts );
831
853
832
854
ReleaseTupleDesc (var_tupdesc );
0 commit comments