Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit d479d00

Browse filesBrowse 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
Copy full SHA for d479d00

File tree

Expand file treeCollapse file tree

3 files changed

+120
-5
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+120
-5
lines changed

‎src/backend/executor/execTuples.c

Copy file name to clipboardExpand all lines: src/backend/executor/execTuples.c
+35-5Lines changed: 35 additions & 5 deletions
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

Copy file name to clipboardExpand all lines: src/test/regress/expected/update.out
+53Lines changed: 53 additions & 0 deletions
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

Copy file name to clipboardExpand all lines: src/test/regress/sql/update.sql
+32Lines changed: 32 additions & 0 deletions
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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.