diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/access/common/tupconvert.c | 22 | ||||
-rw-r--r-- | src/backend/executor/execExprInterp.c | 34 | ||||
-rw-r--r-- | src/test/regress/expected/rowtypes.out | 9 | ||||
-rw-r--r-- | src/test/regress/sql/rowtypes.sql | 5 |
4 files changed, 48 insertions, 22 deletions
diff --git a/src/backend/access/common/tupconvert.c b/src/backend/access/common/tupconvert.c index a4012525d80..392a49b522d 100644 --- a/src/backend/access/common/tupconvert.c +++ b/src/backend/access/common/tupconvert.c @@ -138,13 +138,14 @@ convert_tuples_by_position(TupleDesc indesc, nincols, noutcols))); /* - * Check to see if the map is one-to-one, in which case we need not do - * the tuple conversion. That's not enough though if either source or - * destination (tuples) contains OIDs; we'd need conversion in that case - * to inject the right OID into the tuple datum. + * Check to see if the map is one-to-one, in which case we need not do a + * tuple conversion. We must also insist that both tupdescs either + * specify or don't specify an OID column, else we need a conversion to + * add/remove space for that. (For some callers, presence or absence of + * an OID column perhaps would not really matter, but let's be safe.) */ if (indesc->natts == outdesc->natts && - !indesc->tdhasoid && !outdesc->tdhasoid) + indesc->tdhasoid == outdesc->tdhasoid) { for (i = 0; i < n; i++) { @@ -215,13 +216,14 @@ convert_tuples_by_name(TupleDesc indesc, attrMap = convert_tuples_by_name_map(indesc, outdesc, msg); /* - * Check to see if the map is one-to-one, in which case we need not do - * the tuple conversion. That's not enough though if either source or - * destination (tuples) contains OIDs; we'd need conversion in that case - * to inject the right OID into the tuple datum. + * Check to see if the map is one-to-one, in which case we need not do a + * tuple conversion. We must also insist that both tupdescs either + * specify or don't specify an OID column, else we need a conversion to + * add/remove space for that. (For some callers, presence or absence of + * an OID column perhaps would not really matter, but let's be safe.) */ if (indesc->natts == outdesc->natts && - !indesc->tdhasoid && !outdesc->tdhasoid) + indesc->tdhasoid == outdesc->tdhasoid) { same = true; for (i = 0; i < n; i++) diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c index 22eb81edadf..fed0052fc6d 100644 --- a/src/backend/executor/execExprInterp.c +++ b/src/backend/executor/execExprInterp.c @@ -2840,21 +2840,31 @@ ExecEvalConvertRowtype(ExprState *state, ExprEvalStep *op, ExprContext *econtext MemoryContextSwitchTo(old_cxt); } - /* - * No-op if no conversion needed (not clear this can happen here). - */ - if (op->d.convert_rowtype.map == NULL) - return; - - /* - * do_convert_tuple needs a HeapTuple not a bare HeapTupleHeader. - */ + /* Following steps need a HeapTuple not a bare HeapTupleHeader */ tmptup.t_len = HeapTupleHeaderGetDatumLength(tuple); tmptup.t_data = tuple; - result = do_convert_tuple(&tmptup, op->d.convert_rowtype.map); - - *op->resvalue = HeapTupleGetDatum(result); + if (op->d.convert_rowtype.map != NULL) + { + /* Full conversion with attribute rearrangement needed */ + result = do_convert_tuple(&tmptup, op->d.convert_rowtype.map); + /* Result already has appropriate composite-datum header fields */ + *op->resvalue = HeapTupleGetDatum(result); + } + else + { + /* + * The tuple is physically compatible as-is, but we need to insert the + * destination rowtype OID in its composite-datum header field, so we + * have to copy it anyway. heap_copy_tuple_as_datum() is convenient + * for this since it will both make the physical copy and insert the + * correct composite header fields. Note that we aren't expecting to + * have to flatten any toasted fields: the input was a composite + * datum, so it shouldn't contain any. So heap_copy_tuple_as_datum() + * is overkill here, but its check for external fields is cheap. + */ + *op->resvalue = heap_copy_tuple_as_datum(&tmptup, outdesc); + } } /* diff --git a/src/test/regress/expected/rowtypes.out b/src/test/regress/expected/rowtypes.out index 4acbc9aac80..43b36f6566d 100644 --- a/src/test/regress/expected/rowtypes.out +++ b/src/test/regress/expected/rowtypes.out @@ -657,6 +657,15 @@ select row_to_json(r) from (select q2,q1 from tt1 offset 0) r; {"q2":0,"q1":0} (3 rows) +-- check no-op rowtype conversions +create temp table tt3 () inherits(tt2); +insert into tt3 values(33,44); +select row_to_json(tt3::tt2::tt1) from tt3; + row_to_json +------------------- + {"q1":33,"q2":44} +(1 row) + -- -- IS [NOT] NULL should not recurse into nested composites (bug #14235) -- diff --git a/src/test/regress/sql/rowtypes.sql b/src/test/regress/sql/rowtypes.sql index 0d9c62b486d..8d63060500a 100644 --- a/src/test/regress/sql/rowtypes.sql +++ b/src/test/regress/sql/rowtypes.sql @@ -287,6 +287,11 @@ create temp table tt2 () inherits(tt1); insert into tt2 values(0,0); select row_to_json(r) from (select q2,q1 from tt1 offset 0) r; +-- check no-op rowtype conversions +create temp table tt3 () inherits(tt2); +insert into tt3 values(33,44); +select row_to_json(tt3::tt2::tt1) from tt3; + -- -- IS [NOT] NULL should not recurse into nested composites (bug #14235) -- |