Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 66a4bad

Browse files
committed
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
1 parent 03de518 commit 66a4bad

File tree

3 files changed

+52
-22
lines changed

3 files changed

+52
-22
lines changed

src/backend/executor/nodeModifyTable.c

+17-16
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
#include "storage/bufmgr.h"
5454
#include "storage/lmgr.h"
5555
#include "utils/builtins.h"
56+
#include "utils/datum.h"
5657
#include "utils/memutils.h"
5758
#include "utils/rel.h"
5859

@@ -254,9 +255,6 @@ ExecComputeStoredGenerated(EState *estate, TupleTableSlot *slot)
254255
MemoryContext oldContext;
255256
Datum *values;
256257
bool *nulls;
257-
bool *replaces;
258-
HeapTuple oldtuple, newtuple;
259-
bool should_free;
260258

261259
Assert(tupdesc->constr && tupdesc->constr->has_generated_stored);
262260

@@ -294,11 +292,15 @@ ExecComputeStoredGenerated(EState *estate, TupleTableSlot *slot)
294292

295293
values = palloc(sizeof(*values) * natts);
296294
nulls = palloc(sizeof(*nulls) * natts);
297-
replaces = palloc0(sizeof(*replaces) * natts);
295+
296+
slot_getallattrs(slot);
297+
memcpy(nulls, slot->tts_isnull, sizeof(*nulls) * natts);
298298

299299
for (int i = 0; i < natts; i++)
300300
{
301-
if (TupleDescAttr(tupdesc, i)->attgenerated == ATTRIBUTE_GENERATED_STORED)
301+
Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
302+
303+
if (attr->attgenerated == ATTRIBUTE_GENERATED_STORED)
302304
{
303305
ExprContext *econtext;
304306
Datum val;
@@ -311,20 +313,19 @@ ExecComputeStoredGenerated(EState *estate, TupleTableSlot *slot)
311313

312314
values[i] = val;
313315
nulls[i] = isnull;
314-
replaces[i] = true;
316+
}
317+
else
318+
{
319+
if (!nulls[i])
320+
values[i] = datumCopy(slot->tts_values[i], attr->attbyval, attr->attlen);
315321
}
316322
}
317323

318-
oldtuple = ExecFetchSlotHeapTuple(slot, true, &should_free);
319-
newtuple = heap_modify_tuple(oldtuple, tupdesc, values, nulls, replaces);
320-
/*
321-
* The tuple will be freed by way of the memory context - the slot might
322-
* only be cleared after the context is reset, and we'd thus potentially
323-
* double free.
324-
*/
325-
ExecForceStoreHeapTuple(newtuple, slot, false);
326-
if (should_free)
327-
heap_freetuple(oldtuple);
324+
ExecClearTuple(slot);
325+
memcpy(slot->tts_values, values, sizeof(*values) * natts);
326+
memcpy(slot->tts_isnull, nulls, sizeof(*nulls) * natts);
327+
ExecStoreVirtualTuple(slot);
328+
ExecMaterializeSlot(slot);
328329

329330
MemoryContextSwitchTo(oldContext);
330331
}

src/test/regress/expected/generated.out

+27-4
Original file line numberDiff line numberDiff line change
@@ -226,15 +226,16 @@ NOTICE: merging multiple inherited definitions of column "b"
226226
ERROR: inherited column "b" has a generation conflict
227227
DROP TABLE gtesty;
228228
-- test stored update
229-
CREATE TABLE gtest3 (a int PRIMARY KEY, b int GENERATED ALWAYS AS (a * 3) STORED);
230-
INSERT INTO gtest3 (a) VALUES (1), (2), (3);
229+
CREATE TABLE gtest3 (a int, b int GENERATED ALWAYS AS (a * 3) STORED);
230+
INSERT INTO gtest3 (a) VALUES (1), (2), (3), (NULL);
231231
SELECT * FROM gtest3 ORDER BY a;
232232
a | b
233233
---+---
234234
1 | 3
235235
2 | 6
236236
3 | 9
237-
(3 rows)
237+
|
238+
(4 rows)
238239

239240
UPDATE gtest3 SET a = 22 WHERE a = 2;
240241
SELECT * FROM gtest3 ORDER BY a;
@@ -243,7 +244,29 @@ SELECT * FROM gtest3 ORDER BY a;
243244
1 | 3
244245
3 | 9
245246
22 | 66
246-
(3 rows)
247+
|
248+
(4 rows)
249+
250+
CREATE TABLE gtest3a (a text, b text GENERATED ALWAYS AS (a || '+' || a) STORED);
251+
INSERT INTO gtest3a (a) VALUES ('a'), ('b'), ('c'), (NULL);
252+
SELECT * FROM gtest3a ORDER BY a;
253+
a | b
254+
---+-----
255+
a | a+a
256+
b | b+b
257+
c | c+c
258+
|
259+
(4 rows)
260+
261+
UPDATE gtest3a SET a = 'bb' WHERE a = 'b';
262+
SELECT * FROM gtest3a ORDER BY a;
263+
a | b
264+
----+-------
265+
a | a+a
266+
bb | bb+bb
267+
c | c+c
268+
|
269+
(4 rows)
247270

248271
-- COPY
249272
TRUNCATE gtest1;

src/test/regress/sql/generated.sql

+8-2
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,18 @@ CREATE TABLE gtest1_2 () INHERITS (gtest1, gtesty); -- error
9595
DROP TABLE gtesty;
9696

9797
-- test stored update
98-
CREATE TABLE gtest3 (a int PRIMARY KEY, b int GENERATED ALWAYS AS (a * 3) STORED);
99-
INSERT INTO gtest3 (a) VALUES (1), (2), (3);
98+
CREATE TABLE gtest3 (a int, b int GENERATED ALWAYS AS (a * 3) STORED);
99+
INSERT INTO gtest3 (a) VALUES (1), (2), (3), (NULL);
100100
SELECT * FROM gtest3 ORDER BY a;
101101
UPDATE gtest3 SET a = 22 WHERE a = 2;
102102
SELECT * FROM gtest3 ORDER BY a;
103103

104+
CREATE TABLE gtest3a (a text, b text GENERATED ALWAYS AS (a || '+' || a) STORED);
105+
INSERT INTO gtest3a (a) VALUES ('a'), ('b'), ('c'), (NULL);
106+
SELECT * FROM gtest3a ORDER BY a;
107+
UPDATE gtest3a SET a = 'bb' WHERE a = 'b';
108+
SELECT * FROM gtest3a ORDER BY a;
109+
104110
-- COPY
105111
TRUNCATE gtest1;
106112
INSERT INTO gtest1 (a) VALUES (1), (2);

0 commit comments

Comments
 (0)