aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/common/tupconvert.c22
-rw-r--r--src/backend/executor/execExprInterp.c34
-rw-r--r--src/test/regress/expected/rowtypes.out9
-rw-r--r--src/test/regress/sql/rowtypes.sql5
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)
--