From 3486bcf9e89d87b59d0e370af098fda38be97209 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 20 Feb 2018 11:23:33 -0500 Subject: [PATCH] Fix pg_dump's logic for eliding sequence limits that match the defaults. The previous coding here applied atoi() to strings that could represent values too large to fit in an int. If the overflowed value happened to match one of the cases it was looking for, it would drop that limit value from the output, leading to incorrect restoration of the sequence. Avoid the unsafe behavior, and also make the logic cleaner by explicitly calculating the default min/max values for the appropriate kind of sequence. Reported and patched by Alexey Bashtanov, though I whacked his patch around a bit. Back-patch to v10 where the faulty logic was added. Discussion: https://postgr.es/m/cb85a9a5-946b-c7c4-9cf2-6cd6e25d7a33@imap.cc --- src/bin/pg_dump/pg_dump.c | 55 +++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 06bbc5033de..0ffb3725e01 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -16843,6 +16843,10 @@ dumpSequence(Archive *fout, TableInfo *tbinfo) *seqtype; bool cycled; bool is_ascending; + int64 default_minv, + default_maxv; + char bufm[32], + bufx[32]; PQExpBuffer query = createPQExpBuffer(); PQExpBuffer delqry = createPQExpBuffer(); PQExpBuffer labelq = createPQExpBuffer(); @@ -16912,40 +16916,41 @@ dumpSequence(Archive *fout, TableInfo *tbinfo) cache = PQgetvalue(res, 0, 5); cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0); - is_ascending = incby[0] != '-'; - - if (is_ascending && atoi(minv) == 1) - minv = NULL; - if (!is_ascending && atoi(maxv) == -1) - maxv = NULL; - + /* Calculate default limits for a sequence of this type */ + is_ascending = (incby[0] != '-'); if (strcmp(seqtype, "smallint") == 0) { - if (!is_ascending && atoi(minv) == PG_INT16_MIN) - minv = NULL; - if (is_ascending && atoi(maxv) == PG_INT16_MAX) - maxv = NULL; + default_minv = is_ascending ? 1 : PG_INT16_MIN; + default_maxv = is_ascending ? PG_INT16_MAX : -1; } else if (strcmp(seqtype, "integer") == 0) { - if (!is_ascending && atoi(minv) == PG_INT32_MIN) - minv = NULL; - if (is_ascending && atoi(maxv) == PG_INT32_MAX) - maxv = NULL; + default_minv = is_ascending ? 1 : PG_INT32_MIN; + default_maxv = is_ascending ? PG_INT32_MAX : -1; } else if (strcmp(seqtype, "bigint") == 0) { - char bufm[100], - bufx[100]; - - snprintf(bufm, sizeof(bufm), INT64_FORMAT, PG_INT64_MIN); - snprintf(bufx, sizeof(bufx), INT64_FORMAT, PG_INT64_MAX); - - if (!is_ascending && strcmp(minv, bufm) == 0) - minv = NULL; - if (is_ascending && strcmp(maxv, bufx) == 0) - maxv = NULL; + default_minv = is_ascending ? 1 : PG_INT64_MIN; + default_maxv = is_ascending ? PG_INT64_MAX : -1; } + else + { + exit_horribly(NULL, "unrecognized sequence type: %s\n", seqtype); + 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; /* * DROP must be fully qualified in case same name appears in pg_catalog