Be more aggressive in avoiding tuple conversion.
authorRobert Haas <rhaas@postgresql.org>
Wed, 25 Jan 2017 02:53:38 +0000 (21:53 -0500)
committerRobert Haas <rhaas@postgresql.org>
Wed, 25 Jan 2017 02:53:38 +0000 (21:53 -0500)
According to the comments in tupconvert.c, it's necessary to perform
tuple conversion when either table has OIDs, and this was previously
checked by ensuring that the tdtypeid value matched between the tables
in question.  However, that's overly stringent: we have access to
tdhasoid and can test directly whether OIDs are present, which lets us
avoid conversion in cases where the type OIDs are different but the
tuple descriptors are entirely the same (and neither has OIDs).  This
is useful to the partitioning code, which can thereby avoid converting
tuples when inserting into a partition whose columns appear in the
same order as the parent columns, the normal case.  It's possible
for the tuple routing code to avoid some additional overhead in this
case as well, so do that, too.

It's not clear whether it would be OK to skip this when both tables
have OIDs: do callers count on this to build a new tuple (losing the
previous OID) in such instances?  Until we figure it out, leave the
behavior in that case alone.

Amit Langote, reviewed by me.

src/backend/access/common/tupconvert.c
src/backend/catalog/partition.c

index b17ceafa6ef373fd01454e06cb63c8e1596b09d2..a4012525d8099e482004d76f3b490a9570286424 100644 (file)
@@ -138,12 +138,13 @@ convert_tuples_by_position(TupleDesc indesc,
                           nincols, noutcols)));
 
    /*
-    * Check to see if the map is one-to-one and the tuple types are the same.
-    * (We check the latter because if they're not, we want to do conversion
-    * 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
+    * 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.
     */
    if (indesc->natts == outdesc->natts &&
-       indesc->tdtypeid == outdesc->tdtypeid)
+       !indesc->tdhasoid && !outdesc->tdhasoid)
    {
        for (i = 0; i < n; i++)
        {
@@ -214,12 +215,13 @@ 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 and the tuple types are the same.
-    * (We check the latter because if they're not, we want to do conversion
-    * 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
+    * 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.
     */
    if (indesc->natts == outdesc->natts &&
-       indesc->tdtypeid == outdesc->tdtypeid)
+       !indesc->tdhasoid && !outdesc->tdhasoid)
    {
        same = true;
        for (i = 0; i < n; i++)
index 7be60529c5369d29b4bb0b5beaa4efd3886afdf7..4bcef587637f0f42c451db522fea4606923205b5 100644 (file)
@@ -1700,12 +1700,11 @@ get_partition_for_tuple(PartitionDispatch *pd,
            return -1;
        }
 
-       if (myslot != NULL)
+       if (myslot != NULL && map != NULL)
        {
            HeapTuple   tuple = ExecFetchSlotTuple(slot);
 
            ExecClearTuple(myslot);
-           Assert(map != NULL);
            tuple = do_convert_tuple(tuple, map);
            ExecStoreTuple(tuple, myslot, InvalidBuffer, true);
            slot = myslot;