From d479d00285255d422a2b38f1cfaa35808968a08c Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Thu, 22 Apr 2021 17:30:42 -0400 Subject: 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 a71cfc56b and 3fb93103a (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 --- src/backend/executor/execTuples.c | 40 ++++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) (limited to 'src/backend/executor') diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c index 73c35df9c96..f4478028431 100644 --- a/src/backend/executor/execTuples.c +++ b/src/backend/executor/execTuples.c @@ -122,9 +122,8 @@ tts_virtual_clear(TupleTableSlot *slot) } /* - * Attribute values are readily available in tts_values and tts_isnull array - * in a VirtualTupleTableSlot. So there should be no need to call either of the - * following two functions. + * VirtualTupleTableSlots always have fully populated tts_values and + * tts_isnull arrays. So this function should never be called. */ static void tts_virtual_getsomeattrs(TupleTableSlot *slot, int natts) @@ -132,10 +131,19 @@ tts_virtual_getsomeattrs(TupleTableSlot *slot, int natts) elog(ERROR, "getsomeattrs is not required to be called on a virtual tuple table slot"); } +/* + * VirtualTupleTableSlots never provide system attributes (except those + * handled generically, such as tableoid). We generally shouldn't get + * here, but provide a user-friendly message if we do. + */ static Datum tts_virtual_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull) { - elog(ERROR, "virtual tuple table slot does not have system attributes"); + Assert(!TTS_EMPTY(slot)); + + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot retrieve a system column in this context"))); return 0; /* silence compiler warnings */ } @@ -335,6 +343,15 @@ tts_heap_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull) Assert(!TTS_EMPTY(slot)); + /* + * In some code paths it's possible to get here with a non-materialized + * slot, in which case we can't retrieve system columns. + */ + if (!hslot->tuple) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot retrieve a system column in this context"))); + return heap_getsysattr(hslot->tuple, attnum, slot->tts_tupleDescriptor, isnull); } @@ -497,7 +514,11 @@ tts_minimal_getsomeattrs(TupleTableSlot *slot, int natts) static Datum tts_minimal_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull) { - elog(ERROR, "minimal tuple table slot does not have system attributes"); + Assert(!TTS_EMPTY(slot)); + + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot retrieve a system column in this context"))); return 0; /* silence compiler warnings */ } @@ -681,6 +702,15 @@ tts_buffer_heap_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull) Assert(!TTS_EMPTY(slot)); + /* + * In some code paths it's possible to get here with a non-materialized + * slot, in which case we can't retrieve system columns. + */ + if (!bslot->base.tuple) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot retrieve a system column in this context"))); + return heap_getsysattr(bslot->base.tuple, attnum, slot->tts_tupleDescriptor, isnull); } -- cgit v1.2.3