Skip to content

Commit 7a485bd

Browse files
pg_dump: Fix gathering of sequence information.
Since commit bd15b7d, pg_dump uses pg_get_sequence_data() (née pg_sequence_read_tuple()) to gather all sequence data in a single query as opposed to a query per sequence. Two related bugs have been identified: * If the user lacks appropriate privileges on the sequence, pg_dump generates a setval() command with garbage values instead of failing as expected. * pg_dump can fail due to a concurrently dropped sequence, even if the dropped sequence's data isn't part of the dump. This commit fixes the above issues by 1) teaching pg_get_sequence_data() to return nulls instead of erroring for a missing sequence and 2) teaching pg_dump to fail if it tries to dump the data of a sequence for which pg_get_sequence_data() returned nulls. Note that pg_dump may still fail due to a concurrently dropped sequence, but it should now only do so when the sequence data is part of the dump. This matches the behavior before commit bd15b7d. Bug: #19365 Reported-by: Paveł Tyślacki <[email protected]> Suggested-by: Tom Lane <[email protected]> Reviewed-by: Tom Lane <[email protected]> Discussion: https://postgr.es/m/19365-6245240d8b926327%40postgresql.org Discussion: https://postgr.es/m/2885944.1767029161%40sss.pgh.pa.us Backpatch-through: 18
1 parent 24cb3a0 commit 7a485bd

File tree

2 files changed

+20
-6
lines changed

2 files changed

+20
-6
lines changed

src/backend/commands/sequence.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1794,7 +1794,6 @@ pg_get_sequence_data(PG_FUNCTION_ARGS)
17941794
{
17951795
#define PG_GET_SEQUENCE_DATA_COLS 3
17961796
Oid relid = PG_GETARG_OID(0);
1797-
SeqTable elm;
17981797
Relation seqrel;
17991798
Datum values[PG_GET_SEQUENCE_DATA_COLS] = {0};
18001799
bool isnull[PG_GET_SEQUENCE_DATA_COLS] = {0};
@@ -1811,13 +1810,15 @@ pg_get_sequence_data(PG_FUNCTION_ARGS)
18111810
LSNOID, -1, 0);
18121811
resultTupleDesc = BlessTupleDesc(resultTupleDesc);
18131812

1814-
init_sequence(relid, &elm, &seqrel);
1813+
seqrel = try_relation_open(relid, AccessShareLock);
18151814

18161815
/*
1817-
* Return all NULLs for sequences for which we lack privileges, other
1818-
* sessions' temporary sequences, and unlogged sequences on standbys.
1816+
* Return all NULLs for missing sequences, sequences for which we lack
1817+
* privileges, other sessions' temporary sequences, and unlogged sequences
1818+
* on standbys.
18191819
*/
1820-
if (pg_class_aclcheck(relid, GetUserId(), ACL_SELECT) == ACLCHECK_OK &&
1820+
if (seqrel && seqrel->rd_rel->relkind == RELKIND_SEQUENCE &&
1821+
pg_class_aclcheck(relid, GetUserId(), ACL_SELECT) == ACLCHECK_OK &&
18211822
!RELATION_IS_OTHER_TEMP(seqrel) &&
18221823
(RelationIsPermanent(seqrel) || !RecoveryInProgress()))
18231824
{
@@ -1838,7 +1839,8 @@ pg_get_sequence_data(PG_FUNCTION_ARGS)
18381839
else
18391840
memset(isnull, true, sizeof(isnull));
18401841

1841-
sequence_close(seqrel, NoLock);
1842+
if (seqrel)
1843+
relation_close(seqrel, AccessShareLock);
18421844

18431845
resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
18441846
result = HeapTupleGetDatum(resultHeapTuple);

src/bin/pg_dump/pg_dump.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ typedef struct
137137
int64 cache; /* cache size */
138138
int64 last_value; /* last value of sequence */
139139
bool is_called; /* whether nextval advances before returning */
140+
bool null_seqtuple; /* did pg_get_sequence_data return nulls? */
140141
} SequenceItem;
141142

142143
typedef enum OidOptions
@@ -18959,6 +18960,7 @@ collectSequences(Archive *fout)
1895918960
sequences[i].cycled = (strcmp(PQgetvalue(res, i, 7), "t") == 0);
1896018961
sequences[i].last_value = strtoi64(PQgetvalue(res, i, 8), NULL, 10);
1896118962
sequences[i].is_called = (strcmp(PQgetvalue(res, i, 9), "t") == 0);
18963+
sequences[i].null_seqtuple = (PQgetisnull(res, i, 8) || PQgetisnull(res, i, 9));
1896218964
}
1896318965

1896418966
PQclear(res);
@@ -19230,6 +19232,10 @@ dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo)
1923019232
bool called;
1923119233
PQExpBuffer query = createPQExpBuffer();
1923219234

19235+
/* needn't bother if not dumping sequence data */
19236+
if (!fout->dopt->dumpData && !fout->dopt->sequence_data)
19237+
return;
19238+
1923319239
/*
1923419240
* For versions >= 18, the sequence information is gathered in the sorted
1923519241
* array before any calls to dumpSequenceData(). See collectSequences()
@@ -19271,6 +19277,12 @@ dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo)
1927119277
entry = bsearch(&key, sequences, nsequences,
1927219278
sizeof(SequenceItem), SequenceItemCmp);
1927319279

19280+
if (entry->null_seqtuple)
19281+
pg_fatal("failed to get data for sequence \"%s\"; user may lack "
19282+
"SELECT privilege on the sequence or the sequence may "
19283+
"have been concurrently dropped",
19284+
tbinfo->dobj.name);
19285+
1927419286
last = entry->last_value;
1927519287
called = entry->is_called;
1927619288
}

0 commit comments

Comments
 (0)