mirror of
https://github.com/postgres/postgres.git
synced 2026-05-19 16:57:03 -04:00
pg_dump: Fix gathering of sequence information.
Since commitbd15b7db48, 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 commitbd15b7db48. Bug: #19365 Reported-by: Paveł Tyślacki <pavel.tyslacki@gmail.com> Suggested-by: Tom Lane <tgl@sss.pgh.pa.us> Reviewed-by: Tom Lane <tgl@sss.pgh.pa.us> Discussion: https://postgr.es/m/19365-6245240d8b926327%40postgresql.org Discussion: https://postgr.es/m/2885944.1767029161%40sss.pgh.pa.us Backpatch-through: 18
This commit is contained in:
parent
24cb3a08a4
commit
7a485bd641
2 changed files with 20 additions and 6 deletions
|
|
@ -1794,7 +1794,6 @@ pg_get_sequence_data(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
#define PG_GET_SEQUENCE_DATA_COLS 3
|
#define PG_GET_SEQUENCE_DATA_COLS 3
|
||||||
Oid relid = PG_GETARG_OID(0);
|
Oid relid = PG_GETARG_OID(0);
|
||||||
SeqTable elm;
|
|
||||||
Relation seqrel;
|
Relation seqrel;
|
||||||
Datum values[PG_GET_SEQUENCE_DATA_COLS] = {0};
|
Datum values[PG_GET_SEQUENCE_DATA_COLS] = {0};
|
||||||
bool isnull[PG_GET_SEQUENCE_DATA_COLS] = {0};
|
bool isnull[PG_GET_SEQUENCE_DATA_COLS] = {0};
|
||||||
|
|
@ -1811,13 +1810,15 @@ pg_get_sequence_data(PG_FUNCTION_ARGS)
|
||||||
LSNOID, -1, 0);
|
LSNOID, -1, 0);
|
||||||
resultTupleDesc = BlessTupleDesc(resultTupleDesc);
|
resultTupleDesc = BlessTupleDesc(resultTupleDesc);
|
||||||
|
|
||||||
init_sequence(relid, &elm, &seqrel);
|
seqrel = try_relation_open(relid, AccessShareLock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return all NULLs for sequences for which we lack privileges, other
|
* Return all NULLs for missing sequences, sequences for which we lack
|
||||||
* sessions' temporary sequences, and unlogged sequences on standbys.
|
* privileges, other sessions' temporary sequences, and unlogged sequences
|
||||||
|
* on standbys.
|
||||||
*/
|
*/
|
||||||
if (pg_class_aclcheck(relid, GetUserId(), ACL_SELECT) == ACLCHECK_OK &&
|
if (seqrel && seqrel->rd_rel->relkind == RELKIND_SEQUENCE &&
|
||||||
|
pg_class_aclcheck(relid, GetUserId(), ACL_SELECT) == ACLCHECK_OK &&
|
||||||
!RELATION_IS_OTHER_TEMP(seqrel) &&
|
!RELATION_IS_OTHER_TEMP(seqrel) &&
|
||||||
(RelationIsPermanent(seqrel) || !RecoveryInProgress()))
|
(RelationIsPermanent(seqrel) || !RecoveryInProgress()))
|
||||||
{
|
{
|
||||||
|
|
@ -1838,7 +1839,8 @@ pg_get_sequence_data(PG_FUNCTION_ARGS)
|
||||||
else
|
else
|
||||||
memset(isnull, true, sizeof(isnull));
|
memset(isnull, true, sizeof(isnull));
|
||||||
|
|
||||||
sequence_close(seqrel, NoLock);
|
if (seqrel)
|
||||||
|
relation_close(seqrel, AccessShareLock);
|
||||||
|
|
||||||
resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
|
resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
|
||||||
result = HeapTupleGetDatum(resultHeapTuple);
|
result = HeapTupleGetDatum(resultHeapTuple);
|
||||||
|
|
|
||||||
|
|
@ -137,6 +137,7 @@ typedef struct
|
||||||
int64 cache; /* cache size */
|
int64 cache; /* cache size */
|
||||||
int64 last_value; /* last value of sequence */
|
int64 last_value; /* last value of sequence */
|
||||||
bool is_called; /* whether nextval advances before returning */
|
bool is_called; /* whether nextval advances before returning */
|
||||||
|
bool null_seqtuple; /* did pg_get_sequence_data return nulls? */
|
||||||
} SequenceItem;
|
} SequenceItem;
|
||||||
|
|
||||||
typedef enum OidOptions
|
typedef enum OidOptions
|
||||||
|
|
@ -18959,6 +18960,7 @@ collectSequences(Archive *fout)
|
||||||
sequences[i].cycled = (strcmp(PQgetvalue(res, i, 7), "t") == 0);
|
sequences[i].cycled = (strcmp(PQgetvalue(res, i, 7), "t") == 0);
|
||||||
sequences[i].last_value = strtoi64(PQgetvalue(res, i, 8), NULL, 10);
|
sequences[i].last_value = strtoi64(PQgetvalue(res, i, 8), NULL, 10);
|
||||||
sequences[i].is_called = (strcmp(PQgetvalue(res, i, 9), "t") == 0);
|
sequences[i].is_called = (strcmp(PQgetvalue(res, i, 9), "t") == 0);
|
||||||
|
sequences[i].null_seqtuple = (PQgetisnull(res, i, 8) || PQgetisnull(res, i, 9));
|
||||||
}
|
}
|
||||||
|
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
|
|
@ -19230,6 +19232,10 @@ dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo)
|
||||||
bool called;
|
bool called;
|
||||||
PQExpBuffer query = createPQExpBuffer();
|
PQExpBuffer query = createPQExpBuffer();
|
||||||
|
|
||||||
|
/* needn't bother if not dumping sequence data */
|
||||||
|
if (!fout->dopt->dumpData && !fout->dopt->sequence_data)
|
||||||
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For versions >= 18, the sequence information is gathered in the sorted
|
* For versions >= 18, the sequence information is gathered in the sorted
|
||||||
* array before any calls to dumpSequenceData(). See collectSequences()
|
* array before any calls to dumpSequenceData(). See collectSequences()
|
||||||
|
|
@ -19271,6 +19277,12 @@ dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo)
|
||||||
entry = bsearch(&key, sequences, nsequences,
|
entry = bsearch(&key, sequences, nsequences,
|
||||||
sizeof(SequenceItem), SequenceItemCmp);
|
sizeof(SequenceItem), SequenceItemCmp);
|
||||||
|
|
||||||
|
if (entry->null_seqtuple)
|
||||||
|
pg_fatal("failed to get data for sequence \"%s\"; user may lack "
|
||||||
|
"SELECT privilege on the sequence or the sequence may "
|
||||||
|
"have been concurrently dropped",
|
||||||
|
tbinfo->dobj.name);
|
||||||
|
|
||||||
last = entry->last_value;
|
last = entry->last_value;
|
||||||
called = entry->is_called;
|
called = entry->is_called;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue