Fix pg_dump's logic for eliding sequence limits that match the defaults.
authorTom Lane
Tue, 20 Feb 2018 16:23:34 +0000 (11:23 -0500)
committerTom Lane
Tue, 20 Feb 2018 16:23:34 +0000 (11:23 -0500)
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

index 34156bfe4e5080f28772355d37fbb0d456960eaa..6453e808cb58e70aebebecb9f09ec19fa68f0695 100644 (file)
@@ -16337,6 +16337,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();
@@ -16406,40 +16410,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];
+       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 */
+   }
 
-       snprintf(bufm, sizeof(bufm), INT64_FORMAT, PG_INT64_MIN);
-       snprintf(bufx, sizeof(bufx), INT64_FORMAT, PG_INT64_MAX);
+   /*
+    * 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);
 
-       if (!is_ascending && strcmp(minv, bufm) == 0)
-           minv = NULL;
-       if (is_ascending && strcmp(maxv, bufx) == 0)
-           maxv = NULL;
-   }
+   /* 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