Skip to content

Commit d479d00

Browse files
committed
Don't crash on reference to an un-available system column.
Adopt a more consistent policy about what slot-type-specific getsysattr functions should do when system attributes are not available. To wit, they should all throw the same user-oriented error, rather than variously crashing or emitting developer-oriented messages. This closes a identifiable problem in commits a71cfc5 and 3fb9310 (in v13 and v12), so back-patch into those branches, along with a test case to try to ensure we don't break it again. It is not known that any of the former crash cases are reachable in HEAD, but this seems like a good safety improvement in any case. Discussion: https://postgr.es/m/141051591267657@mail.yandex.ru
1 parent 197d33c commit d479d00

File tree

3 files changed

+120
-5
lines changed

3 files changed

+120
-5
lines changed

src/backend/executor/execTuples.c

+35-5
Original file line numberDiff line numberDiff line change
@@ -122,20 +122,28 @@ tts_virtual_clear(TupleTableSlot *slot)
122122
}
123123

124124
/*
125-
* Attribute values are readily available in tts_values and tts_isnull array
126-
* in a VirtualTupleTableSlot. So there should be no need to call either of the
127-
* following two functions.
125+
* VirtualTupleTableSlots always have fully populated tts_values and
126+
* tts_isnull arrays. So this function should never be called.
128127
*/
129128
static void
130129
tts_virtual_getsomeattrs(TupleTableSlot *slot, int natts)
131130
{
132131
elog(ERROR, "getsomeattrs is not required to be called on a virtual tuple table slot");
133132
}
134133

134+
/*
135+
* VirtualTupleTableSlots never provide system attributes (except those
136+
* handled generically, such as tableoid). We generally shouldn't get
137+
* here, but provide a user-friendly message if we do.
138+
*/
135139
static Datum
136140
tts_virtual_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
137141
{
138-
elog(ERROR, "virtual tuple table slot does not have system attributes");
142+
Assert(!TTS_EMPTY(slot));
143+
144+
ereport(ERROR,
145+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
146+
errmsg("cannot retrieve a system column in this context")));
139147

140148
return 0; /* silence compiler warnings */
141149
}
@@ -335,6 +343,15 @@ tts_heap_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
335343

336344
Assert(!TTS_EMPTY(slot));
337345

346+
/*
347+
* In some code paths it's possible to get here with a non-materialized
348+
* slot, in which case we can't retrieve system columns.
349+
*/
350+
if (!hslot->tuple)
351+
ereport(ERROR,
352+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
353+
errmsg("cannot retrieve a system column in this context")));
354+
338355
return heap_getsysattr(hslot->tuple, attnum,
339356
slot->tts_tupleDescriptor, isnull);
340357
}
@@ -497,7 +514,11 @@ tts_minimal_getsomeattrs(TupleTableSlot *slot, int natts)
497514
static Datum
498515
tts_minimal_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
499516
{
500-
elog(ERROR, "minimal tuple table slot does not have system attributes");
517+
Assert(!TTS_EMPTY(slot));
518+
519+
ereport(ERROR,
520+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
521+
errmsg("cannot retrieve a system column in this context")));
501522

502523
return 0; /* silence compiler warnings */
503524
}
@@ -681,6 +702,15 @@ tts_buffer_heap_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
681702

682703
Assert(!TTS_EMPTY(slot));
683704

705+
/*
706+
* In some code paths it's possible to get here with a non-materialized
707+
* slot, in which case we can't retrieve system columns.
708+
*/
709+
if (!bslot->base.tuple)
710+
ereport(ERROR,
711+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
712+
errmsg("cannot retrieve a system column in this context")));
713+
684714
return heap_getsysattr(bslot->base.tuple, attnum,
685715
slot->tts_tupleDescriptor, isnull);
686716
}

src/test/regress/expected/update.out

+53
Original file line numberDiff line numberDiff line change
@@ -795,6 +795,59 @@ DETAIL: Failing row contains (a, 10).
795795
-- ok
796796
UPDATE list_default set a = 'x' WHERE a = 'd';
797797
DROP TABLE list_parted;
798+
-- Test retrieval of system columns with non-consistent partition row types.
799+
-- This is only partially supported, as seen in the results.
800+
create table utrtest (a int, b text) partition by list (a);
801+
create table utr1 (a int check (a in (1)), q text, b text);
802+
create table utr2 (a int check (a in (2)), b text);
803+
alter table utr1 drop column q;
804+
alter table utrtest attach partition utr1 for values in (1);
805+
alter table utrtest attach partition utr2 for values in (2);
806+
insert into utrtest values (1, 'foo')
807+
returning *, tableoid::regclass, xmin = pg_current_xact_id()::xid as xmin_ok;
808+
a | b | tableoid | xmin_ok
809+
---+-----+----------+---------
810+
1 | foo | utr1 | t
811+
(1 row)
812+
813+
insert into utrtest values (2, 'bar')
814+
returning *, tableoid::regclass, xmin = pg_current_xact_id()::xid as xmin_ok; -- fails
815+
ERROR: cannot retrieve a system column in this context
816+
insert into utrtest values (2, 'bar')
817+
returning *, tableoid::regclass;
818+
a | b | tableoid
819+
---+-----+----------
820+
2 | bar | utr2
821+
(1 row)
822+
823+
update utrtest set b = b || b from (values (1), (2)) s(x) where a = s.x
824+
returning *, tableoid::regclass, xmin = pg_current_xact_id()::xid as xmin_ok;
825+
a | b | x | tableoid | xmin_ok
826+
---+--------+---+----------+---------
827+
1 | foofoo | 1 | utr1 | t
828+
2 | barbar | 2 | utr2 | t
829+
(2 rows)
830+
831+
update utrtest set a = 3 - a from (values (1), (2)) s(x) where a = s.x
832+
returning *, tableoid::regclass, xmin = pg_current_xact_id()::xid as xmin_ok; -- fails
833+
ERROR: cannot retrieve a system column in this context
834+
update utrtest set a = 3 - a from (values (1), (2)) s(x) where a = s.x
835+
returning *, tableoid::regclass;
836+
a | b | x | tableoid
837+
---+--------+---+----------
838+
2 | foofoo | 1 | utr2
839+
1 | barbar | 2 | utr1
840+
(2 rows)
841+
842+
delete from utrtest
843+
returning *, tableoid::regclass, xmax = pg_current_xact_id()::xid as xmax_ok;
844+
a | b | tableoid | xmax_ok
845+
---+--------+----------+---------
846+
1 | barbar | utr1 | t
847+
2 | foofoo | utr2 | t
848+
(2 rows)
849+
850+
drop table utrtest;
798851
--------------
799852
-- Some more update-partition-key test scenarios below. This time use list
800853
-- partitions.

src/test/regress/sql/update.sql

+32
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,38 @@ UPDATE list_default set a = 'x' WHERE a = 'd';
502502

503503
DROP TABLE list_parted;
504504

505+
-- Test retrieval of system columns with non-consistent partition row types.
506+
-- This is only partially supported, as seen in the results.
507+
508+
create table utrtest (a int, b text) partition by list (a);
509+
create table utr1 (a int check (a in (1)), q text, b text);
510+
create table utr2 (a int check (a in (2)), b text);
511+
alter table utr1 drop column q;
512+
alter table utrtest attach partition utr1 for values in (1);
513+
alter table utrtest attach partition utr2 for values in (2);
514+
515+
insert into utrtest values (1, 'foo')
516+
returning *, tableoid::regclass, xmin = pg_current_xact_id()::xid as xmin_ok;
517+
insert into utrtest values (2, 'bar')
518+
returning *, tableoid::regclass, xmin = pg_current_xact_id()::xid as xmin_ok; -- fails
519+
insert into utrtest values (2, 'bar')
520+
returning *, tableoid::regclass;
521+
522+
update utrtest set b = b || b from (values (1), (2)) s(x) where a = s.x
523+
returning *, tableoid::regclass, xmin = pg_current_xact_id()::xid as xmin_ok;
524+
525+
update utrtest set a = 3 - a from (values (1), (2)) s(x) where a = s.x
526+
returning *, tableoid::regclass, xmin = pg_current_xact_id()::xid as xmin_ok; -- fails
527+
528+
update utrtest set a = 3 - a from (values (1), (2)) s(x) where a = s.x
529+
returning *, tableoid::regclass;
530+
531+
delete from utrtest
532+
returning *, tableoid::regclass, xmax = pg_current_xact_id()::xid as xmax_ok;
533+
534+
drop table utrtest;
535+
536+
505537
--------------
506538
-- Some more update-partition-key test scenarios below. This time use list
507539
-- partitions.

0 commit comments

Comments
 (0)