Skip to content

Commit 297d627

Browse files
committed
Fix heap_getattr() handling of fast defaults.
Previously heap_getattr() returned NULL for attributes with a fast default value (c.f. 16828d5), as it had no handling whatsoever for that case. A previous fix, 7636e5c, attempted to fix issues caused by this oversight, but just expanding OLD tuples for triggers doesn't actually solve the underlying issue. One known consequence of this bug is that the check for HOT updates can return the wrong result, when a previously fast-default'ed column is set to NULL. Which in turn means that an index over a column with fast default'ed columns might be corrupt if the underlying column(s) allow NULLs. Fix by handling fast default columns in heap_getattr(), remove now superfluous expansion in GetTupleForTrigger(). Author: Andres Freund Discussion: https://postgr.es/m/20190201162404.onngi77f26baem4g@alap3.anarazel.de Backpatch: 11, where fast defaults were introduced
1 parent 77173d0 commit 297d627

File tree

5 files changed

+52
-9
lines changed

5 files changed

+52
-9
lines changed

src/backend/access/common/heaptuple.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@
8080
/*
8181
* Return the missing value of an attribute, or NULL if there isn't one.
8282
*/
83-
static Datum
83+
Datum
8484
getmissingattr(TupleDesc tupleDesc,
8585
int attnum, bool *isnull)
8686
{

src/backend/commands/trigger.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3396,10 +3396,7 @@ ltrmark:;
33963396
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
33973397
}
33983398

3399-
if (HeapTupleHeaderGetNatts(tuple.t_data) < relation->rd_att->natts)
3400-
result = heap_expand_tuple(&tuple, relation->rd_att);
3401-
else
3402-
result = heap_copytuple(&tuple);
3399+
result = heap_copytuple(&tuple);
34033400
ReleaseBuffer(buffer);
34043401

34053402
return result;

src/include/access/htup_details.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -783,10 +783,7 @@ extern Datum fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc,
783783
((attnum) > 0) ? \
784784
( \
785785
((attnum) > (int) HeapTupleHeaderGetNatts((tup)->t_data)) ? \
786-
( \
787-
(*(isnull) = true), \
788-
(Datum)NULL \
789-
) \
786+
getmissingattr((tupleDesc), (attnum), (isnull)) \
790787
: \
791788
fastgetattr((tup), (attnum), (tupleDesc), (isnull)) \
792789
) \
@@ -807,6 +804,8 @@ extern Datum nocachegetattr(HeapTuple tup, int attnum,
807804
TupleDesc att);
808805
extern Datum heap_getsysattr(HeapTuple tup, int attnum, TupleDesc tupleDesc,
809806
bool *isnull);
807+
extern Datum getmissingattr(TupleDesc tupleDesc,
808+
int attnum, bool *isnull);
810809
extern HeapTuple heap_copytuple(HeapTuple tuple);
811810
extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest);
812811
extern Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc);

src/test/regress/expected/fast_default.out

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,33 @@ SELECT * FROM vtype2;
770770
2 | yyy
771771
(2 rows)
772772

773+
-- Ensure that defaults are checked when evaluating whether HOT update
774+
-- is possible, this was broken for a while:
775+
-- https://postgr.es/m/20190202133521.ylauh3ckqa7colzj%40alap3.anarazel.de
776+
BEGIN;
777+
CREATE TABLE t();
778+
INSERT INTO t DEFAULT VALUES;
779+
ALTER TABLE t ADD COLUMN a int DEFAULT 1;
780+
CREATE INDEX ON t(a);
781+
-- set column with a default 1 to NULL, due to a bug that wasn't
782+
-- noticed has heap_getattr buggily returned NULL for default columns
783+
UPDATE t SET a = NULL;
784+
-- verify that index and non-index scans show the same result
785+
SET LOCAL enable_seqscan = true;
786+
SELECT * FROM t WHERE a IS NULL;
787+
a
788+
---
789+
790+
(1 row)
791+
792+
SET LOCAL enable_seqscan = false;
793+
SELECT * FROM t WHERE a IS NULL;
794+
a
795+
---
796+
797+
(1 row)
798+
799+
ROLLBACK;
773800
-- cleanup
774801
DROP TABLE vtype;
775802
DROP TABLE vtype2;

src/test/regress/sql/fast_default.sql

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,26 @@ ALTER TABLE vtype2 ALTER COLUMN b TYPE varchar(20) USING b::varchar(20);
505505
SELECT * FROM vtype2;
506506

507507

508+
-- Ensure that defaults are checked when evaluating whether HOT update
509+
-- is possible, this was broken for a while:
510+
-- https://postgr.es/m/20190202133521.ylauh3ckqa7colzj%40alap3.anarazel.de
511+
BEGIN;
512+
CREATE TABLE t();
513+
INSERT INTO t DEFAULT VALUES;
514+
ALTER TABLE t ADD COLUMN a int DEFAULT 1;
515+
CREATE INDEX ON t(a);
516+
-- set column with a default 1 to NULL, due to a bug that wasn't
517+
-- noticed has heap_getattr buggily returned NULL for default columns
518+
UPDATE t SET a = NULL;
519+
520+
-- verify that index and non-index scans show the same result
521+
SET LOCAL enable_seqscan = true;
522+
SELECT * FROM t WHERE a IS NULL;
523+
SET LOCAL enable_seqscan = false;
524+
SELECT * FROM t WHERE a IS NULL;
525+
ROLLBACK;
526+
527+
508528
-- cleanup
509529
DROP TABLE vtype;
510530
DROP TABLE vtype2;

0 commit comments

Comments
 (0)