88 *
99 *
1010 * 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 $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -591,17 +591,23 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
591591 /*
592592 * We really only care about number of attributes and data type.
593593 * 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.
605611 */
606612 var_tupdesc = lookup_rowtype_tupdesc (variable -> vartype , -1 );
607613
@@ -615,7 +621,7 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
615621 slot_tupdesc -> natts ,
616622 var_tupdesc -> natts )));
617623 else if (var_tupdesc -> natts < slot_tupdesc -> natts )
618- needslow = true;
624+ needslow = true; /* need to trim trailing atts */
619625
620626 for (i = 0 ; i < var_tupdesc -> natts ; i ++ )
621627 {
@@ -635,11 +641,7 @@ ExecEvalVar(ExprState *exprstate, ExprContext *econtext,
635641
636642 if (vattr -> attlen != sattr -> attlen ||
637643 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 */
643645 }
644646
645647 ReleaseTupleDesc (var_tupdesc );
@@ -766,7 +768,7 @@ ExecEvalWholeRowVar(ExprState *exprstate, ExprContext *econtext,
766768/* ----------------------------------------------------------------
767769 * ExecEvalWholeRowSlow
768770 *
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
770772 * we can't just copy the subplan's output.
771773 * ----------------------------------------------------------------
772774 */
@@ -779,6 +781,7 @@ ExecEvalWholeRowSlow(ExprState *exprstate, ExprContext *econtext,
779781 HeapTuple tuple ;
780782 TupleDesc var_tupdesc ;
781783 HeapTupleHeader dtuple ;
784+ int i ;
782785
783786 if (isDone )
784787 * isDone = ExprSingleResult ;
@@ -802,18 +805,38 @@ ExecEvalWholeRowSlow(ExprState *exprstate, ExprContext *econtext,
802805 }
803806
804807 /*
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.
811813 */
812814 Assert (variable -> vartype != RECORDOID );
813815 var_tupdesc = lookup_rowtype_tupdesc (variable -> vartype , -1 );
814816
815817 tuple = ExecFetchSlotTuple (slot );
816818
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+
817840 /*
818841 * We have to make a copy of the tuple so we can safely insert the Datum
819842 * overhead fields, which are not set in on-disk tuples; not to mention
@@ -826,7 +849,6 @@ ExecEvalWholeRowSlow(ExprState *exprstate, ExprContext *econtext,
826849 HeapTupleHeaderSetTypeId (dtuple , variable -> vartype );
827850 HeapTupleHeaderSetTypMod (dtuple , variable -> vartypmod );
828851
829- Assert (HeapTupleHeaderGetNatts (dtuple ) >= var_tupdesc -> natts );
830852 HeapTupleHeaderSetNatts (dtuple , var_tupdesc -> natts );
831853
832854 ReleaseTupleDesc (var_tupdesc );
0 commit comments