diff options
author | Peter Eisentraut <peter@eisentraut.org> | 2019-05-15 19:37:52 +0200 |
---|---|---|
committer | Peter Eisentraut <peter@eisentraut.org> | 2019-05-22 18:41:53 +0200 |
commit | 66a4bad83aaa6613a45a00a488c04427f9969fb4 (patch) | |
tree | ccb6a7ebbe8db2a9d8bedc27c63edb0f70db26c0 /src/backend/executor/nodeModifyTable.c | |
parent | 03de5187d50af67d154a47cf00899290dca13003 (diff) | |
download | postgresql-66a4bad83aaa6613a45a00a488c04427f9969fb4.tar.gz postgresql-66a4bad83aaa6613a45a00a488c04427f9969fb4.zip |
Convert ExecComputeStoredGenerated to use tuple slots
This code was still using the old style of forming a heap tuple rather
than using tuple slots. This would be less efficient if a non-heap
access method was used. And using tuple slots is actually quite a bit
faster when using heap as well.
Also add some test cases for generated columns with null values and
with varlena values. This lack of coverage was discovered while
working on this patch.
Discussion: https://www.postgresql.org/message-id/flat/20190331025744.ugbsyks7czfcoksd%40alap3.anarazel.de
Diffstat (limited to 'src/backend/executor/nodeModifyTable.c')
-rw-r--r-- | src/backend/executor/nodeModifyTable.c | 33 |
1 files changed, 17 insertions, 16 deletions
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index d545bbce8a2..d3a0dece5ad 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -53,6 +53,7 @@ #include "storage/bufmgr.h" #include "storage/lmgr.h" #include "utils/builtins.h" +#include "utils/datum.h" #include "utils/memutils.h" #include "utils/rel.h" @@ -254,9 +255,6 @@ ExecComputeStoredGenerated(EState *estate, TupleTableSlot *slot) MemoryContext oldContext; Datum *values; bool *nulls; - bool *replaces; - HeapTuple oldtuple, newtuple; - bool should_free; Assert(tupdesc->constr && tupdesc->constr->has_generated_stored); @@ -294,11 +292,15 @@ ExecComputeStoredGenerated(EState *estate, TupleTableSlot *slot) values = palloc(sizeof(*values) * natts); nulls = palloc(sizeof(*nulls) * natts); - replaces = palloc0(sizeof(*replaces) * natts); + + slot_getallattrs(slot); + memcpy(nulls, slot->tts_isnull, sizeof(*nulls) * natts); for (int i = 0; i < natts; i++) { - if (TupleDescAttr(tupdesc, i)->attgenerated == ATTRIBUTE_GENERATED_STORED) + Form_pg_attribute attr = TupleDescAttr(tupdesc, i); + + if (attr->attgenerated == ATTRIBUTE_GENERATED_STORED) { ExprContext *econtext; Datum val; @@ -311,20 +313,19 @@ ExecComputeStoredGenerated(EState *estate, TupleTableSlot *slot) values[i] = val; nulls[i] = isnull; - replaces[i] = true; + } + else + { + if (!nulls[i]) + values[i] = datumCopy(slot->tts_values[i], attr->attbyval, attr->attlen); } } - oldtuple = ExecFetchSlotHeapTuple(slot, true, &should_free); - newtuple = heap_modify_tuple(oldtuple, tupdesc, values, nulls, replaces); - /* - * The tuple will be freed by way of the memory context - the slot might - * only be cleared after the context is reset, and we'd thus potentially - * double free. - */ - ExecForceStoreHeapTuple(newtuple, slot, false); - if (should_free) - heap_freetuple(oldtuple); + ExecClearTuple(slot); + memcpy(slot->tts_values, values, sizeof(*values) * natts); + memcpy(slot->tts_isnull, nulls, sizeof(*nulls) * natts); + ExecStoreVirtualTuple(slot); + ExecMaterializeSlot(slot); MemoryContextSwitchTo(oldContext); } |