Here is an attempt at adding a new function that returns the sequence tuple
and using that to avoid querying each sequence relation individually in
dumpSequenceData().
If we instead wanted to change pg_sequence_last_value() to return both
is_called and last_value, I think we could modify the pg_sequences system
view to use a LATERAL subquery, i.e.,
SELECT
...
CASE
WHEN L.is_called THEN L.last_value
ELSE NULL
END AS last_value
FROM pg_sequence S
...
JOIN LATERAL pg_sequence_last_value(S.seqrelid) L ON true
...
That doesn't seem so bad, and it'd avoid an extra pg_proc entry, but it
would probably break anything that calls pg_sequence_last_value() directly.
Thoughts?
--
nathan
>From c5e139efdae92c3902daee886075b509a0720368 Mon Sep 17 00:00:00 2001
From: Nathan Bossart <[email protected]>
Date: Mon, 15 Jul 2024 13:13:05 -0500
Subject: [PATCH v4 1/4] parse sequence information
---
src/bin/pg_dump/pg_dump.c | 64 ++++++++++++++++-----------------------
1 file changed, 26 insertions(+), 38 deletions(-)
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index b8b1888bd3..bbcbe581aa 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -17198,18 +17198,16 @@ dumpSequence(Archive *fout, const TableInfo *tbinfo)
{
DumpOptions *dopt = fout->dopt;
PGresult *res;
- char *startv,
- *incby,
- *maxv,
- *minv,
- *cache,
- *seqtype;
+ char seqtype[10];
bool cycled;
bool is_ascending;
int64 default_minv,
- default_maxv;
- char bufm[32],
- bufx[32];
+ default_maxv,
+ minv,
+ maxv,
+ startv,
+ incby,
+ cache;
PQExpBuffer query = createPQExpBuffer();
PQExpBuffer delqry = createPQExpBuffer();
char *qseqname;
@@ -17251,16 +17249,21 @@ dumpSequence(Archive *fout, const TableInfo *tbinfo)
PQntuples(res)),
tbinfo->dobj.name, PQntuples(res));
- seqtype = PQgetvalue(res, 0, 0);
- startv = PQgetvalue(res, 0, 1);
- incby = PQgetvalue(res, 0, 2);
- maxv = PQgetvalue(res, 0, 3);
- minv = PQgetvalue(res, 0, 4);
- cache = PQgetvalue(res, 0, 5);
+ Assert(strlen(PQgetvalue(res, 0, 0)) < sizeof(seqtype));
+ strncpy(seqtype, PQgetvalue(res, 0, 0), sizeof(seqtype));
+ seqtype[sizeof(seqtype) - 1] = '\0';
+
+ startv = strtoi64(PQgetvalue(res, 0, 1), NULL, 10);
+ incby = strtoi64(PQgetvalue(res, 0, 2), NULL, 10);
+ maxv = strtoi64(PQgetvalue(res, 0, 3), NULL, 10);
+ minv = strtoi64(PQgetvalue(res, 0, 4), NULL, 10);
+ cache = strtoi64(PQgetvalue(res, 0, 5), NULL, 10);
cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
+ PQclear(res);
+
/* Calculate default limits for a sequence of this type */
- is_ascending = (incby[0] != '-');
+ is_ascending = (incby >= 0);
if (strcmp(seqtype, "smallint") == 0)
{
default_minv = is_ascending ? 1 : PG_INT16_MIN;
@@ -17282,19 +17285,6 @@ dumpSequence(Archive *fout, const TableInfo *tbinfo)
default_minv = default_maxv = 0; /* keep compiler quiet
*/
}
- /*
- * 64-bit strtol() isn't very portable, so convert the limits to strings
- * and compare that way.
- */
- snprintf(bufm, sizeof(bufm), INT64_FORMAT, default_minv);
- snprintf(bufx, sizeof(bufx), INT64_FORMAT, default_maxv);
-
- /* Don't print minv/maxv if they match the respective default limit */
- if (strcmp(minv, bufm) == 0)
- minv = NULL;
- if (strcmp(maxv, bufx) == 0)
- maxv = NULL;
-
/*
* Identity sequences are not to be dropped separately.
*/
@@ -17346,22 +17336,22 @@ dumpSequence(Archive *fout, const TableInfo *tbinfo)
appendPQExpBuffer(query, " AS %s\n", seqtype);
}
- appendPQExpBuffer(query, " START WITH %s\n", startv);
+ appendPQExpBuffer(query, " START WITH " INT64_FORMAT "\n", startv);
- appendPQExpBuffer(query, " INCREMENT BY %s\n", incby);
+ appendPQExpBuffer(query, " INCREMENT BY " INT64_FORMAT "\n", incby);
- if (minv)
- appendPQExpBuffer(query, " MINVALUE %s\n", minv);
+ if (minv != default_minv)
+ appendPQExpBuffer(query, " MINVALUE " INT64_FORMAT "\n",
minv);
else
appendPQExpBufferStr(query, " NO MINVALUE\n");
- if (maxv)
- appendPQExpBuffer(query, " MAXVALUE %s\n", maxv);
+ if (maxv != default_maxv)
+ appendPQExpBuffer(query, " MAXVALUE " INT64_FORMAT "\n",
maxv);
else
appendPQExpBufferStr(query, " NO MAXVALUE\n");
appendPQExpBuffer(query,
- " CACHE %s%s",
+ " CACHE " INT64_FORMAT "%s",
cache, (cycled ? "\n CYCLE" : ""));
if (tbinfo->is_identity_sequence)
@@ -17448,8 +17438,6 @@ dumpSequence(Archive *fout, const TableInfo *tbinfo)
tbinfo->dobj.namespace->dobj.name,
tbinfo->rolname,
tbinfo->dobj.catId, 0,
tbinfo->dobj.dumpId);
- PQclear(res);
-
destroyPQExpBuffer(query);
destroyPQExpBuffer(delqry);
free(qseqname);
--
2.39.3 (Apple Git-146)
>From b7fcaba2c5eef8824153c263c2df516783f0225b Mon Sep 17 00:00:00 2001
From: Nathan Bossart <[email protected]>
Date: Tue, 9 Jul 2024 14:06:23 -0500
Subject: [PATCH v4 2/4] cache sequence information
---
src/bin/pg_dump/pg_dump.c | 155 +++++++++++++++++++++++++------
src/tools/pgindent/typedefs.list | 1 +
2 files changed, 128 insertions(+), 28 deletions(-)
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index bbcbe581aa..a54e32c7be 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -104,6 +104,18 @@ typedef struct
RelFileNumber toast_index_relfilenumber; /* toast table index
filenode */
} BinaryUpgradeClassOidItem;
+typedef struct
+{
+ Oid oid; /* sequence OID */
+ char seqtype[10]; /* data type of sequence */
+ bool cycled; /* whether sequence cycles */
+ int64 minv; /* minimum value */
+ int64 maxv; /* maximum value */
+ int64 startv; /* start value */
+ int64 incby; /* increment value */
+ int64 cache; /* cache size */
+} SequenceItem;
+
typedef enum OidOptions
{
zeroIsError = 1,
@@ -173,6 +185,10 @@ static int nseclabels = 0;
static BinaryUpgradeClassOidItem *binaryUpgradeClassOids = NULL;
static int nbinaryUpgradeClassOids = 0;
+/* sorted table of sequences */
+static SequenceItem *sequences = NULL;
+static int nsequences = 0;
+
/*
* The default number of rows per INSERT when
* --inserts is specified without --rows-per-insert
@@ -270,6 +286,7 @@ static void dumpTable(Archive *fout, const TableInfo
*tbinfo);
static void dumpTableSchema(Archive *fout, const TableInfo *tbinfo);
static void dumpTableAttach(Archive *fout, const TableAttachInfo *attachinfo);
static void dumpAttrDef(Archive *fout, const AttrDefInfo *adinfo);
+static void collectSequences(Archive *fout);
static void dumpSequence(Archive *fout, const TableInfo *tbinfo);
static void dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo);
static void dumpIndex(Archive *fout, const IndxInfo *indxinfo);
@@ -992,6 +1009,9 @@ main(int argc, char **argv)
if (dopt.binary_upgrade)
collectBinaryUpgradeClassOids(fout);
+ /* Collect sequence information. */
+ collectSequences(fout);
+
/* Lastly, create dummy objects to represent the section boundaries */
boundaryObjs = createBoundaryObjects();
@@ -17189,6 +17209,71 @@ dumpTableConstraintComment(Archive *fout, const
ConstraintInfo *coninfo)
free(qtabname);
}
+/*
+ * bsearch() comparator for SequenceItem
+ */
+static int
+SequenceItemCmp(const void *p1, const void *p2)
+{
+ SequenceItem v1 = *((const SequenceItem *) p1);
+ SequenceItem v2 = *((const SequenceItem *) p2);
+
+ return pg_cmp_u32(v1.oid, v2.oid);
+}
+
+/*
+ * collectSequences
+ *
+ * Construct a table of sequence information. This table is sorted by OID for
+ * speed in lookup.
+ */
+static void
+collectSequences(Archive *fout)
+{
+ PGresult *res;
+ const char *query;
+
+ /*
+ * Before Postgres 10, sequence metadata is in the sequence itself. We
+ * could likely make use of the sorted table with some extra effort, but
+ * for now it seems unlikely to be worth it.
+ */
+ if (fout->remoteVersion < 100000)
+ return;
+
+ query = "SELECT seqrelid, format_type(seqtypid, NULL), "
+ "seqstart, seqincrement, "
+ "seqmax, seqmin, "
+ "seqcache, seqcycle "
+ "FROM pg_catalog.pg_sequence "
+ "ORDER BY seqrelid";
+
+ res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
+
+ nsequences = PQntuples(res);
+ sequences = (SequenceItem *) pg_malloc(nsequences *
sizeof(SequenceItem));
+
+ for (int i = 0; i < nsequences; i++)
+ {
+ size_t seqtype_sz = sizeof(((SequenceItem *)
0)->seqtype);
+
+ sequences[i].oid = atooid(PQgetvalue(res, i, 0));
+
+ Assert(strlen(PQgetvalue(res, i, 1)) < seqtype_sz);
+ strncpy(sequences[i].seqtype, PQgetvalue(res, i, 1),
seqtype_sz);
+ sequences[i].seqtype[seqtype_sz - 1] = '\0';
+
+ sequences[i].startv = strtoi64(PQgetvalue(res, i, 2), NULL, 10);
+ sequences[i].incby = strtoi64(PQgetvalue(res, i, 3), NULL, 10);
+ sequences[i].maxv = strtoi64(PQgetvalue(res, i, 4), NULL, 10);
+ sequences[i].minv = strtoi64(PQgetvalue(res, i, 5), NULL, 10);
+ sequences[i].cache = strtoi64(PQgetvalue(res, i, 6), NULL, 10);
+ sequences[i].cycled = (strcmp(PQgetvalue(res, i, 7), "t") == 0);
+ }
+
+ PQclear(res);
+}
+
/*
* dumpSequence
* write the declaration (not data) of one user-defined sequence
@@ -17197,7 +17282,6 @@ static void
dumpSequence(Archive *fout, const TableInfo *tbinfo)
{
DumpOptions *dopt = fout->dopt;
- PGresult *res;
char seqtype[10];
bool cycled;
bool is_ascending;
@@ -17215,19 +17299,34 @@ dumpSequence(Archive *fout, const TableInfo *tbinfo)
qseqname = pg_strdup(fmtId(tbinfo->dobj.name));
+ /*
+ * For versions >= 10, the sequence information is gathered in a sorted
+ * table before any calls to dumpSequence(). See collectSequences() for
+ * more information.
+ */
if (fout->remoteVersion >= 100000)
{
- appendPQExpBuffer(query,
- "SELECT format_type(seqtypid,
NULL), "
- "seqstart, seqincrement, "
- "seqmax, seqmin, "
- "seqcache, seqcycle "
- "FROM pg_catalog.pg_sequence "
- "WHERE seqrelid = '%u'::oid",
- tbinfo->dobj.catId.oid);
+ SequenceItem key = {0};
+ SequenceItem *entry;
+
+ Assert(sequences);
+
+ key.oid = tbinfo->dobj.catId.oid;
+ entry = bsearch(&key, sequences, nsequences,
+ sizeof(SequenceItem),
SequenceItemCmp);
+
+ strncpy(seqtype, entry->seqtype, sizeof(seqtype));
+ startv = entry->startv;
+ incby = entry->incby;
+ maxv = entry->maxv;
+ minv = entry->minv;
+ cache = entry->cache;
+ cycled = entry->cycled;
}
else
{
+ PGresult *res;
+
/*
* Before PostgreSQL 10, sequence metadata is in the sequence
itself.
*
@@ -17239,28 +17338,28 @@ dumpSequence(Archive *fout, const TableInfo *tbinfo)
"start_value, increment_by,
max_value, min_value, "
"cache_value, is_cycled FROM
%s",
fmtQualifiedDumpable(tbinfo));
- }
-
- res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
- if (PQntuples(res) != 1)
- pg_fatal(ngettext("query to get data of sequence \"%s\"
returned %d row (expected 1)",
- "query to get data of
sequence \"%s\" returned %d rows (expected 1)",
- PQntuples(res)),
- tbinfo->dobj.name, PQntuples(res));
-
- Assert(strlen(PQgetvalue(res, 0, 0)) < sizeof(seqtype));
- strncpy(seqtype, PQgetvalue(res, 0, 0), sizeof(seqtype));
- seqtype[sizeof(seqtype) - 1] = '\0';
+ res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
- startv = strtoi64(PQgetvalue(res, 0, 1), NULL, 10);
- incby = strtoi64(PQgetvalue(res, 0, 2), NULL, 10);
- maxv = strtoi64(PQgetvalue(res, 0, 3), NULL, 10);
- minv = strtoi64(PQgetvalue(res, 0, 4), NULL, 10);
- cache = strtoi64(PQgetvalue(res, 0, 5), NULL, 10);
- cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
+ if (PQntuples(res) != 1)
+ pg_fatal(ngettext("query to get data of sequence \"%s\"
returned %d row (expected 1)",
+ "query to get data of
sequence \"%s\" returned %d rows (expected 1)",
+ PQntuples(res)),
+ tbinfo->dobj.name, PQntuples(res));
+
+ Assert(strlen(PQgetvalue(res, 0, 0)) < sizeof(seqtype));
+ strncpy(seqtype, PQgetvalue(res, 0, 0), sizeof(seqtype));
+ seqtype[sizeof(seqtype) - 1] = '\0';
+
+ startv = strtoi64(PQgetvalue(res, 0, 1), NULL, 10);
+ incby = strtoi64(PQgetvalue(res, 0, 2), NULL, 10);
+ maxv = strtoi64(PQgetvalue(res, 0, 3), NULL, 10);
+ minv = strtoi64(PQgetvalue(res, 0, 4), NULL, 10);
+ cache = strtoi64(PQgetvalue(res, 0, 5), NULL, 10);
+ cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0);
- PQclear(res);
+ PQclear(res);
+ }
/* Calculate default limits for a sequence of this type */
is_ascending = (incby >= 0);
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index b4d7f9217c..a09adcfb90 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -2572,6 +2572,7 @@ SeqScan
SeqScanState
SeqTable
SeqTableData
+SequenceItem
SerCommitSeqNo
SerialControl
SerialIOData
--
2.39.3 (Apple Git-146)
>From 86f0b7c26be5bd257a5039bdfbe127983e1228c7 Mon Sep 17 00:00:00 2001
From: Nathan Bossart <[email protected]>
Date: Wed, 17 Jul 2024 17:09:03 -0500
Subject: [PATCH v4 3/4] introduce pg_sequence_read_tuple
XXX: NEEDS CATVERSION BUMP
---
src/backend/commands/sequence.c | 62 ++++++++++++++++++++++++++
src/include/catalog/pg_proc.dat | 6 +++
src/test/regress/expected/sequence.out | 7 +++
src/test/regress/sql/sequence.sql | 3 ++
4 files changed, 78 insertions(+)
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 9f28d40466..45c4cb3936 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -1773,6 +1773,68 @@ pg_sequence_parameters(PG_FUNCTION_ARGS)
return HeapTupleGetDatum(heap_form_tuple(tupdesc, values, isnull));
}
+
+/*
+ * Return the sequence tuple.
+ *
+ * This is primarily intended for use by pg_dump to gather sequence data
+ * without needing to individually query each sequence relation.
+ */
+Datum
+pg_sequence_read_tuple(PG_FUNCTION_ARGS)
+{
+ Oid relid = PG_GETARG_OID(0);
+ SeqTable elm;
+ Relation seqrel;
+ Datum values[SEQ_COL_LASTCOL];
+ bool isnull[SEQ_COL_LASTCOL];
+ TupleDesc resultTupleDesc;
+ HeapTuple resultHeapTuple;
+ Datum result;
+
+ resultTupleDesc = CreateTemplateTupleDesc(SEQ_COL_LASTCOL);
+ TupleDescInitEntry(resultTupleDesc, (AttrNumber) 1, "last_value",
+ INT8OID, -1, 0);
+ TupleDescInitEntry(resultTupleDesc, (AttrNumber) 2, "log_cnt",
+ INT8OID, -1, 0);
+ TupleDescInitEntry(resultTupleDesc, (AttrNumber) 3, "is_called",
+ BOOLOID, -1, 0);
+ resultTupleDesc = BlessTupleDesc(resultTupleDesc);
+
+ init_sequence(relid, &elm, &seqrel);
+
+ /*
+ * Return all NULLs for sequences for which we lack privileges, other
+ * sessions' temporary sequences, and unlogged sequences on standbys.
+ */
+ if (pg_class_aclcheck(relid, GetUserId(), ACL_SELECT | ACL_USAGE) ==
ACLCHECK_OK &&
+ !RELATION_IS_OTHER_TEMP(seqrel) &&
+ (RelationIsPermanent(seqrel) || !RecoveryInProgress()))
+ {
+ Buffer buf;
+ HeapTupleData seqtuple;
+ Form_pg_sequence_data seq;
+
+ seq = read_seq_tuple(seqrel, &buf, &seqtuple);
+
+ memset(isnull, false, sizeof(isnull));
+ values[0] = Int64GetDatum(seq->last_value);
+ values[1] = Int64GetDatum(seq->log_cnt);
+ values[2] = BoolGetDatum(seq->is_called);
+
+ UnlockReleaseBuffer(buf);
+ }
+ else
+ memset(isnull, true, sizeof(isnull));
+
+ sequence_close(seqrel, NoLock);
+
+ resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
+ result = HeapTupleGetDatum(resultHeapTuple);
+ PG_RETURN_DATUM(result);
+}
+
+
/*
* Return the last value from the sequence
*
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 73d9cf8582..a16aec302e 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -3329,6 +3329,12 @@
proname => 'pg_sequence_last_value', provolatile => 'v', proparallel => 'u',
prorettype => 'int8', proargtypes => 'regclass',
prosrc => 'pg_sequence_last_value' },
+{ oid => '9876', descr => 'return sequence tuple, for use by pg_dump',
+ proname => 'pg_sequence_read_tuple', provolatile => 'v', proparallel => 'u',
+ prorettype => 'record', proargtypes => 'regclass',
+ proallargtypes => '{regclass,int8,int8,bool}', proargmodes => '{i,o,o,o}',
+ proargnames => '{sequence_oid,last_value,log_cnt,is_called}',
+ prosrc => 'pg_sequence_read_tuple' },
{ oid => '275', descr => 'return the next oid for a system table',
proname => 'pg_nextoid', provolatile => 'v', proparallel => 'u',
diff --git a/src/test/regress/expected/sequence.out
b/src/test/regress/expected/sequence.out
index 2b47b7796b..e749c4574e 100644
--- a/src/test/regress/expected/sequence.out
+++ b/src/test/regress/expected/sequence.out
@@ -839,4 +839,11 @@ SELECT nextval('test_seq1');
3
(1 row)
+-- pg_sequence_read_tuple
+SELECT * FROM pg_sequence_read_tuple('test_seq1');
+ last_value | log_cnt | is_called
+------------+---------+-----------
+ 10 | 32 | t
+(1 row)
+
DROP SEQUENCE test_seq1;
diff --git a/src/test/regress/sql/sequence.sql
b/src/test/regress/sql/sequence.sql
index 674f5f1f66..ea447938ae 100644
--- a/src/test/regress/sql/sequence.sql
+++ b/src/test/regress/sql/sequence.sql
@@ -413,4 +413,7 @@ SELECT nextval('test_seq1');
SELECT nextval('test_seq1');
SELECT nextval('test_seq1');
+-- pg_sequence_read_tuple
+SELECT * FROM pg_sequence_read_tuple('test_seq1');
+
DROP SEQUENCE test_seq1;
--
2.39.3 (Apple Git-146)
>From d22c7281416280480b91cff02330a858946364ad Mon Sep 17 00:00:00 2001
From: Nathan Bossart <[email protected]>
Date: Wed, 17 Jul 2024 22:13:08 -0500
Subject: [PATCH v4 4/4] cache sequence data
---
src/bin/pg_dump/pg_dump.c | 91 +++++++++++++++++++++++++++++----------
1 file changed, 68 insertions(+), 23 deletions(-)
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index a54e32c7be..14019907db 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -114,6 +114,8 @@ typedef struct
int64 startv; /* start value */
int64 incby; /* increment value */
int64 cache; /* cache size */
+ int64 last_value; /* last value of sequence */
+ bool is_called; /* whether nextval advances
before returning */
} SequenceItem;
typedef enum OidOptions
@@ -17237,16 +17239,30 @@ collectSequences(Archive *fout)
* Before Postgres 10, sequence metadata is in the sequence itself. We
* could likely make use of the sorted table with some extra effort, but
* for now it seems unlikely to be worth it.
+ *
+ * Since version 18, we can gather the sequence data in this query with
+ * pg_sequence_read_tuple(), but we only do so for non-schema-only
dumps.
*/
if (fout->remoteVersion < 100000)
return;
-
- query = "SELECT seqrelid, format_type(seqtypid, NULL), "
- "seqstart, seqincrement, "
- "seqmax, seqmin, "
- "seqcache, seqcycle "
- "FROM pg_catalog.pg_sequence "
- "ORDER BY seqrelid";
+ else if (fout->remoteVersion < 180000 ||
+ (fout->dopt->schemaOnly && !fout->dopt->sequence_data))
+ query = "SELECT seqrelid, format_type(seqtypid, NULL), "
+ "seqstart, seqincrement, "
+ "seqmax, seqmin, "
+ "seqcache, seqcycle, "
+ "NULL, 'f' "
+ "FROM pg_catalog.pg_sequence "
+ "ORDER BY seqrelid";
+ else
+ query = "SELECT seqrelid, format_type(seqtypid, NULL), "
+ "seqstart, seqincrement, "
+ "seqmax, seqmin, "
+ "seqcache, seqcycle, "
+ "last_value, is_called "
+ "FROM pg_catalog.pg_sequence, "
+ "pg_sequence_read_tuple(seqrelid) "
+ "ORDER BY seqrelid;";
res = ExecuteSqlQuery(fout, query, PGRES_TUPLES_OK);
@@ -17269,6 +17285,8 @@ collectSequences(Archive *fout)
sequences[i].minv = strtoi64(PQgetvalue(res, i, 5), NULL, 10);
sequences[i].cache = strtoi64(PQgetvalue(res, i, 6), NULL, 10);
sequences[i].cycled = (strcmp(PQgetvalue(res, i, 7), "t") == 0);
+ sequences[i].last_value = strtoi64(PQgetvalue(res, i, 8), NULL,
10);
+ sequences[i].is_called = (strcmp(PQgetvalue(res, i, 9), "t") ==
0);
}
PQclear(res);
@@ -17550,30 +17568,59 @@ static void
dumpSequenceData(Archive *fout, const TableDataInfo *tdinfo)
{
TableInfo *tbinfo = tdinfo->tdtable;
- PGresult *res;
- char *last;
+ int64 last;
bool called;
PQExpBuffer query = createPQExpBuffer();
- appendPQExpBuffer(query,
- "SELECT last_value, is_called FROM
%s",
- fmtQualifiedDumpable(tbinfo));
+ /*
+ * For versions >= 18, the sequence information is gathered in the
sorted
+ * array before any calls to dumpSequenceData(). See collectSequences()
+ * for more information.
+ *
+ * For older versions, we have to query the sequence relations
+ * individually.
+ */
+ if (fout->remoteVersion < 180000)
+ {
+ PGresult *res;
- res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
+ appendPQExpBuffer(query,
+ "SELECT last_value, is_called
FROM %s",
+ fmtQualifiedDumpable(tbinfo));
- if (PQntuples(res) != 1)
- pg_fatal(ngettext("query to get data of sequence \"%s\"
returned %d row (expected 1)",
- "query to get data of
sequence \"%s\" returned %d rows (expected 1)",
- PQntuples(res)),
- tbinfo->dobj.name, PQntuples(res));
+ res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
- last = PQgetvalue(res, 0, 0);
- called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
+ if (PQntuples(res) != 1)
+ pg_fatal(ngettext("query to get data of sequence \"%s\"
returned %d row (expected 1)",
+ "query to get data of
sequence \"%s\" returned %d rows (expected 1)",
+ PQntuples(res)),
+ tbinfo->dobj.name, PQntuples(res));
+
+ last = strtoi64(PQgetvalue(res, 0, 0), NULL, 10);
+ called = (strcmp(PQgetvalue(res, 0, 1), "t") == 0);
+
+ PQclear(res);
+ }
+ else
+ {
+ SequenceItem key = {0};
+ SequenceItem *entry;
+
+ Assert(sequences);
+ Assert(tbinfo->dobj.catId.oid);
+
+ key.oid = tbinfo->dobj.catId.oid;
+ entry = bsearch(&key, sequences, nsequences,
+ sizeof(SequenceItem),
SequenceItemCmp);
+
+ last = entry->last_value;
+ called = entry->is_called;
+ }
resetPQExpBuffer(query);
appendPQExpBufferStr(query, "SELECT pg_catalog.setval(");
appendStringLiteralAH(query, fmtQualifiedDumpable(tbinfo), fout);
- appendPQExpBuffer(query, ", %s, %s);\n",
+ appendPQExpBuffer(query, ", " INT64_FORMAT ", %s);\n",
last, (called ? "true" : "false"));
if (tdinfo->dobj.dump & DUMP_COMPONENT_DATA)
@@ -17587,8 +17634,6 @@ dumpSequenceData(Archive *fout, const TableDataInfo
*tdinfo)
.deps =
&(tbinfo->dobj.dumpId),
.nDeps = 1));
- PQclear(res);
-
destroyPQExpBuffer(query);
}
--
2.39.3 (Apple Git-146)