]> granicus.if.org Git - postgresql/commitdiff
Improve performance of ExecEvalWholeRowVar.
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 26 Mar 2017 23:14:47 +0000 (19:14 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 26 Mar 2017 23:14:57 +0000 (19:14 -0400)
In commit b8d7f053c, we needed to fix ExecEvalWholeRowVar to not change
the state of the slot it's copying.  The initial quick hack at that
required two rounds of tuple construction, which is not very nice.
To fix, add another primitive to tuptoaster.c that does precisely what
we need.  (I initially tried to do this by refactoring one of the
existing functions into two pieces; but it looked like that might hurt
performance for the existing case, and the amount of code that could
be shared is not very large, so I gave up on that.)

Discussion: https://postgr.es/m/26088.1490315792@sss.pgh.pa.us

src/backend/access/heap/tuptoaster.c
src/backend/executor/execExprInterp.c
src/include/access/tuptoaster.h

index 19e704800284a45760d708fd989c6b3c5cef740b..aa5a45ded48eb04c00de4a520670e422fbd767cb 100644 (file)
@@ -1288,6 +1288,74 @@ toast_flatten_tuple_to_datum(HeapTupleHeader tup,
 }
 
 
+/* ----------
+ * toast_build_flattened_tuple -
+ *
+ *     Build a tuple containing no out-of-line toasted fields.
+ *     (This does not eliminate compressed or short-header datums.)
+ *
+ *     This is essentially just like heap_form_tuple, except that it will
+ *     expand any external-data pointers beforehand.
+ *
+ *     It's not very clear whether it would be preferable to decompress
+ *     in-line compressed datums while at it.  For now, we don't.
+ * ----------
+ */
+HeapTuple
+toast_build_flattened_tuple(TupleDesc tupleDesc,
+                                                       Datum *values,
+                                                       bool *isnull)
+{
+       HeapTuple       new_tuple;
+       Form_pg_attribute *att = tupleDesc->attrs;
+       int                     numAttrs = tupleDesc->natts;
+       int                     num_to_free;
+       int                     i;
+       Datum           new_values[MaxTupleAttributeNumber];
+       Pointer         freeable_values[MaxTupleAttributeNumber];
+
+       /*
+        * We can pass the caller's isnull array directly to heap_form_tuple, but
+        * we potentially need to modify the values array.
+        */
+       Assert(numAttrs <= MaxTupleAttributeNumber);
+       memcpy(new_values, values, numAttrs * sizeof(Datum));
+
+       num_to_free = 0;
+       for (i = 0; i < numAttrs; i++)
+       {
+               /*
+                * Look at non-null varlena attributes
+                */
+               if (!isnull[i] && att[i]->attlen == -1)
+               {
+                       struct varlena *new_value;
+
+                       new_value = (struct varlena *) DatumGetPointer(new_values[i]);
+                       if (VARATT_IS_EXTERNAL(new_value))
+                       {
+                               new_value = heap_tuple_fetch_attr(new_value);
+                               new_values[i] = PointerGetDatum(new_value);
+                               freeable_values[num_to_free++] = (Pointer) new_value;
+                       }
+               }
+       }
+
+       /*
+        * Form the reconfigured tuple.
+        */
+       new_tuple = heap_form_tuple(tupleDesc, new_values, isnull);
+
+       /*
+        * Free allocated temp values
+        */
+       for (i = 0; i < num_to_free; i++)
+               pfree(freeable_values[i]);
+
+       return new_tuple;
+}
+
+
 /* ----------
  * toast_compress_datum -
  *
index 02fb29cde3fd332e6a3c7bf59934652b0a18927c..982d16c6c88d8381d13bed0b98804f2190c5054e 100644 (file)
@@ -58,7 +58,7 @@
  */
 #include "postgres.h"
 
-#include "access/htup_details.h"
+#include "access/tuptoaster.h"
 #include "catalog/pg_type.h"
 #include "executor/execExpr.h"
 #include "executor/nodeSubplan.h"
@@ -3508,24 +3508,24 @@ ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
        }
 
        /*
-        * Copy the slot tuple and make sure any toasted fields get detoasted.
+        * Build a composite datum, making sure any toasted fields get detoasted.
         *
-        * (The intermediate copy is a tad annoying here, but we currently have no
-        * primitive that will do the right thing.  Note it is critical that we
-        * not change the slot's state, so we can't use ExecFetchSlotTupleDatum.)
+        * (Note: it is critical that we not change the slot's state here.)
         */
-       tuple = ExecCopySlotTuple(slot);
-       dtuple = (HeapTupleHeader)
-               DatumGetPointer(heap_copy_tuple_as_datum(tuple,
-                                                                                                slot->tts_tupleDescriptor));
-       heap_freetuple(tuple);
+       tuple = toast_build_flattened_tuple(slot->tts_tupleDescriptor,
+                                                                               slot->tts_values,
+                                                                               slot->tts_isnull);
+       dtuple = tuple->t_data;
 
        /*
         * Label the datum with the composite type info we identified before.
+        *
+        * (Note: we could skip doing this by passing op->d.wholerow.tupdesc to
+        * the tuple build step; but that seems a tad risky so let's not.)
         */
        HeapTupleHeaderSetTypeId(dtuple, op->d.wholerow.tupdesc->tdtypeid);
        HeapTupleHeaderSetTypMod(dtuple, op->d.wholerow.tupdesc->tdtypmod);
 
-       *op->resnull = false;
        *op->resvalue = PointerGetDatum(dtuple);
+       *op->resnull = false;
 }
index a6233c386d00b4d5acbaac3c4c79c06fb3e8019b..c7abeed8126e4c3a970cb6d902dc0aebfbe4cb24 100644 (file)
@@ -193,6 +193,17 @@ extern Datum toast_flatten_tuple_to_datum(HeapTupleHeader tup,
                                                         uint32 tup_len,
                                                         TupleDesc tupleDesc);
 
+/* ----------
+ * toast_build_flattened_tuple -
+ *
+ *     Build a tuple containing no out-of-line toasted fields.
+ *     (This does not eliminate compressed or short-header datums.)
+ * ----------
+ */
+extern HeapTuple toast_build_flattened_tuple(TupleDesc tupleDesc,
+                                                       Datum *values,
+                                                       bool *isnull);
+
 /* ----------
  * toast_compress_datum -
  *