postgres.git / summary / log / commit / refs

commit    2812059d3eeaa05ef98dc2e2cc71a716967aeeb8
Author:   Nathan Bossart <nathan@postgresql.org>
Date:     Mon May 13 20:53:50 2024 +0000

    Fix pg_sequence_last_value() for unlogged sequences on standbys.
    
    Presently, when this function is called for an unlogged sequence on
    a standby server, it will error out with a message like
    
    	ERROR:  could not open file "base/5/16388": No such file or directory
    
    Since the pg_sequences system view uses pg_sequence_last_value(),
    it can error similarly.  To fix, modify the function to return NULL
    for unlogged sequences on standby servers.  Since this bug is
    present on all versions since v15, this approach is preferable to
    making the ERROR nicer because we need to repair the pg_sequences
    view without modifying its definition on released versions.  For
    consistency, this commit also modifies the function to return NULL
    for other sessions' temporary sequences.  The pg_sequences view
    already appropriately filters out such sequences, so there's no bug
    there, but we might as well offer some defense in case someone
    invokes this function directly.
    
    Unlogged sequences were first introduced in v15, but temporary
    sequences are much older, so while the fix for unlogged sequences
    is only back-patched to v15, the temporary sequence portion is
    back-patched to all supported versions.
    
    We could also remove the privilege check in the pg_sequences view
    definition in v18 if we modify this function to return NULL for
    sequences for which the current user lacks privileges, but that is
    left as a future exercise for when v18 development begins.
    
    Reviewed-by: Tom Lane, Michael Paquier
    Discussion: https://postgr.es/m/20240501005730.GA594666%40nathanxps13
    Backpatch-through: 12


src/backend/commands/sequence.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c index 0577184f82b..daaf8ee3d44 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -1857,11 +1857,8 @@ pg_sequence_last_value(PG_FUNCTION_ARGS) Oid relid = PG_GETARG_OID(0); SeqTable elm; Relation seqrel; - Buffer buf; - HeapTupleData seqtuple; - Form_pg_sequence_data seq; - bool is_called; - int64 result; + bool is_called = false; + int64 result = 0; /* open and lock sequence */ init_sequence(relid, &elm, &seqrel); @@ -1872,12 +1869,24 @@ pg_sequence_last_value(PG_FUNCTION_ARGS) errmsg("permission denied for sequence %s", RelationGetRelationName(seqrel)))); - seq = read_seq_tuple(seqrel, &buf, &seqtuple); + /* + * We return NULL for other sessions' temporary sequences. The + * pg_sequences system view already filters those out, but this offers a + * defense against ERRORs in case someone invokes this function directly. + */ + if (!RELATION_IS_OTHER_TEMP(seqrel)) + { + Buffer buf; + HeapTupleData seqtuple; + Form_pg_sequence_data seq; - is_called = seq->is_called; - result = seq->last_value; + seq = read_seq_tuple(seqrel, &buf, &seqtuple); - UnlockReleaseBuffer(buf); + is_called = seq->is_called; + result = seq->last_value; + + UnlockReleaseBuffer(buf); + } relation_close(seqrel, NoLock); if (is_called) [parent: 157b1e6b41b4]