Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 292176a

Browse files
committed
Improve ExecEvalVar's handling of whole-row variables in cases where the
rowtype contains dropped columns. Sometimes the input tuple will be formed from a select targetlist in which dropped columns are filled with a NULL of an arbitrary type (the planner typically uses INT4, since it can't tell what type the dropped column really was). So we need to relax the rowtype compatibility check to not insist on physical compatibility if the actual column value is NULL. In principle we might need to do this for functions returning composite types, too (see tupledesc_match()). In practice there doesn't seem to be a bug there, probably because the function will be using the same cached rowtype descriptor as the caller. Fixing that code path would require significant rearrangement, so I left it alone for now. Per complaint from Filip Rembialkowski.
1 parent ccaad19 commit 292176a

File tree

1 file changed

+48
-26
lines changed

1 file changed

+48
-26
lines changed

src/backend/executor/execQual.c

+48-26
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.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

Comments
 (0)