Fix pg_restore to handle the 'set max oid' entry correctly in archives
authorTom Lane
Fri, 18 Jan 2002 17:13:51 +0000 (17:13 +0000)
committerTom Lane
Fri, 18 Jan 2002 17:13:51 +0000 (17:13 +0000)
dumped by pg_dump -o.  Per bug report posted by Bruce; fix is from
Philip Warner, reviewed by Tom Lane.

src/bin/pg_dump/pg_backup_archiver.c
src/bin/pg_dump/pg_backup_db.c

index 4c99d51bfedd7f23e0321517c7e5335208e7b5b3..675da67d9c80893b37afa27c5594f3a40ef5d0d3 100644 (file)
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *     $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.38 2001/11/08 04:05:12 tgl Exp $
+ *     $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.39 2002/01/18 17:13:50 tgl Exp $
  *
  * Modifications - 28-Jun-2000 - [email protected]
  *
  *     backup file; prior version was restoring schema in data-only
  *     restores. Added enum to make code easier to understand.
  *
+ * Modifications - 18-Jan-2002 - [email protected]
+ *   - Modified _tocEntryRequired to handle '/Max OID' as a special
+ *         case (ie. as a DATA item) as per bugs reported by Bruce Momjian
+ *     around 17-Jan-2002.
+ *
  *-------------------------------------------------------------------------
  */
 
@@ -1917,6 +1922,13 @@ _tocEntryRequired(TocEntry *te, RestoreOptions *ropt)
            res = res & ~REQ_DATA;
    }
 
+    /* Special case:  type with  name; this is part of
+     * a DATA restore even though it has SQL.
+     */
+   if (  ( strcmp(te->desc, "") == 0 ) && ( strcmp(te->name, "Max OID") == 0) ) {
+       res = REQ_DATA;
+   }
+
    /* Mask it if we only want schema */
    if (ropt->schemaOnly)
        res = res & REQ_SCHEMA;
index aeea9d02c88b06a56daa3fce474fe58285d89722..ff31b4789e7387d539fb9867c6bd57d607e27fc8 100644 (file)
@@ -5,7 +5,7 @@
  * Implements the basic DB functions used by the archiver.
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_db.c,v 1.29 2001/10/25 05:49:52 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_backup_db.c,v 1.30 2002/01/18 17:13:51 tgl Exp $
  *
  * NOTES
  *
  *
  *   - Avoid forcing table name to lower case in FixupBlobXrefs!
  *
+ *
+ * Modifications - 18-Jan-2002 - [email protected]
+ *
+ *    - Split ExecuteSqlCommandBuf into 3 routines for (slightly) improved 
+ *     clarity. Modify loop to cater for COPY commands buried in the SQL
+ *     command buffer (prev version assumed COPY command was executed
+ *     in prior call). This was to fix the buf in the 'set max oid' code.
+ *
  *-------------------------------------------------------------------------
  */
 
@@ -43,6 +51,8 @@ static void _check_database_version(ArchiveHandle *AH, bool ignoreVersion);
 static PGconn *_connectDB(ArchiveHandle *AH, const char *newdbname, const char *newUser);
 static int _executeSqlCommand(ArchiveHandle *AH, PGconn *conn, PQExpBuffer qry, char *desc);
 static void notice_processor(void *arg, const char *message);
+static char* _sendSQLLine( ArchiveHandle *AH, char *qry, char *eos);
+static char* _sendCopyLine( ArchiveHandle *AH, char *qry, char *eos);
 
 
 /*
@@ -534,206 +544,229 @@ _executeSqlCommand(ArchiveHandle *AH, PGconn *conn, PQExpBuffer qry, char *desc)
    return strlen(qry->data);
 }
 
-/* Convenience function to send one or more queries. Monitors result to handle COPY statements */
-int
-ExecuteSqlCommandBuf(ArchiveHandle *AH, void *qryv, int bufLen)
+/* 
+ * Used by ExecuteSqlCommandBuf to send one buffered line when running a COPY command.
+ */
+static char*
+_sendCopyLine( ArchiveHandle *AH, char *qry, char *eos) 
 {
-   int         loc;
-   int         pos = 0;
-   int         sPos = 0;
-   char       *qry = (char *) qryv;
-   int         isEnd = 0;
-   char       *eos = qry + bufLen;
+   int         loc; /* Location of next newline */
+    int            pos = 0; /* Current position */ 
+   int         sPos = 0; /* Last pos of a slash char */
+    int         isEnd = 0;
 
-   /*
-    * fprintf(stderr, "\n\n*****\n
-    * Buffer:\n\n%s\n*******************\n\n", qry);
-    */
+   /* loop to find unquoted newline ending the line of COPY data */
+    for (;;) {
+       loc = strcspn(&qry[pos], "\n") + pos;
 
-   /* If we're in COPY IN mode, then just break it into lines and send... */
-   if (AH->pgCopyIn)
-   {
-       for (;;)
+       /* If no match, then wait */
+       if (loc >= (eos - qry))     /* None found */
        {
+           appendBinaryPQExpBuffer(AH->pgCopyBuf, qry, (eos - qry));
+           return eos;
+       }
 
-           /* Find a lf */
-           loc = strcspn(&qry[pos], "\n") + pos;
-           pos = 0;
-
-           /* If no match, then wait */
-           if (loc >= (eos - qry))     /* None found */
-           {
-               appendBinaryPQExpBuffer(AH->pgCopyBuf, qry, (eos - qry));
-               break;
-           };
-
-           /*
-            * fprintf(stderr, "Found cr at %d, prev char was %c, next was
-            * %c\n", loc, qry[loc-1], qry[loc+1]);
-            */
+       /*
+        * fprintf(stderr, "Found cr at %d, prev char was %c, next was
+        * %c\n", loc, qry[loc-1], qry[loc+1]);
+        */
 
-           /* Count the number of preceding slashes */
-           sPos = loc;
-           while (sPos > 0 && qry[sPos - 1] == '\\')
-               sPos--;
+       /* Count the number of preceding slashes */
+       sPos = loc;
+       while (sPos > 0 && qry[sPos - 1] == '\\')
+           sPos--;
 
-           sPos = loc - sPos;
+       sPos = loc - sPos;
 
-           /*
-            * If an odd number of preceding slashes, then \n was escaped
-            * so set the next search pos, and restart (if any left).
-            */
-           if ((sPos & 1) == 1)
+       /*
+        * If an odd number of preceding slashes, then \n was escaped
+        * so set the next search pos, and loop (if any left).
+        */
+       if ((sPos & 1) == 1)
+       {
+           /* fprintf(stderr, "cr was escaped\n"); */
+           pos = loc + 1;
+           if (pos >= (eos - qry))
            {
-               /* fprintf(stderr, "cr was escaped\n"); */
-               pos = loc + 1;
-               if (pos >= (eos - qry))
-               {
-                   appendBinaryPQExpBuffer(AH->pgCopyBuf, qry, (eos - qry));
-                   break;
-               }
+               appendBinaryPQExpBuffer(AH->pgCopyBuf, qry, (eos - qry));
+               return eos;
            }
-           else
-           {
-               /* We got a good cr */
-               qry[loc] = '\0';
-               appendPQExpBuffer(AH->pgCopyBuf, "%s\n", qry);
-               qry += loc + 1;
-               isEnd = (strcmp(AH->pgCopyBuf->data, "\\.\n") == 0);
+       } else {
+           break;
+       }
+   }
 
-               /*---------
-                * fprintf(stderr, "Sending '%s' via
-                *      COPY (at end = %d)\n\n", AH->pgCopyBuf->data, isEnd);
-                *---------
-                */
+   /* We found an unquoted newline */
+   qry[loc] = '\0';
+   appendPQExpBuffer(AH->pgCopyBuf, "%s\n", qry);
+   isEnd = (strcmp(AH->pgCopyBuf->data, "\\.\n") == 0);
 
-               if (PQputline(AH->connection, AH->pgCopyBuf->data) != 0)
-                   die_horribly(AH, modulename, "error returned by PQputline\n");
+   /*---------
+    * fprintf(stderr, "Sending '%s' via
+    *      COPY (at end = %d)\n\n", AH->pgCopyBuf->data, isEnd);
+    *---------
+    */
 
-               resetPQExpBuffer(AH->pgCopyBuf);
+   if (PQputline(AH->connection, AH->pgCopyBuf->data) != 0)
+       die_horribly(AH, modulename, "error returned by PQputline\n");
 
-               /*
-                * fprintf(stderr, "Buffer is '%s'\n",
-                * AH->pgCopyBuf->data);
-                */
+   resetPQExpBuffer(AH->pgCopyBuf);
 
-               if (isEnd)
-               {
-                   if (PQendcopy(AH->connection) != 0)
-                       die_horribly(AH, modulename, "error returned by PQendcopy\n");
+   /*
+    * fprintf(stderr, "Buffer is '%s'\n",
+    * AH->pgCopyBuf->data);
+    */
 
-                   AH->pgCopyIn = 0;
-                   break;
-               }
+   if (isEnd)
+   {
+       if (PQendcopy(AH->connection) != 0)
+           die_horribly(AH, modulename, "error returned by PQendcopy\n");
 
-           }
+       AH->pgCopyIn = 0;
+   }
 
-           /* Make sure we're not past the original buffer end */
-           if (qry >= eos)
-               break;
+   return qry + loc + 1;
+}
 
-       }
-   }
+/* 
+ * Used by ExecuteSqlCommandBuf to send one buffered line of SQL (not data for the copy command).
+ */
+static char*
+_sendSQLLine( ArchiveHandle *AH, char *qry, char *eos) 
+{
+    int            pos = 0; /* Current position */ 
 
-   /* We may have finished Copy In, and have a non-empty buffer */
-   if (!AH->pgCopyIn)
-   {
-       /*
-        * The following is a mini state machine to assess then of of an
-        * SQL statement. It really only needs to parse good SQL, or at
-        * least that's the theory... End-of-statement is assumed to be an
-        * unquoted, un commented semi-colon.
-        */
+   /*
+    * The following is a mini state machine to assess the end of an
+    * SQL statement. It really only needs to parse good SQL, or at
+    * least that's the theory... End-of-statement is assumed to be an
+    * unquoted, un commented semi-colon.
+    */
 
-       /*
-        * fprintf(stderr, "Buffer at start is: '%s'\n\n",
-        * AH->sqlBuf->data);
-        */
+   /*
+    * fprintf(stderr, "Buffer at start is: '%s'\n\n",
+    * AH->sqlBuf->data);
+    */
 
-       for (pos = 0; pos < (eos - qry); pos++)
-       {
-           appendPQExpBufferChar(AH->sqlBuf, qry[pos]);
-           /* fprintf(stderr, " %c",qry[pos]); */
+   for (pos = 0; pos < (eos - qry); pos++)
+   {
+       appendPQExpBufferChar(AH->sqlBuf, qry[pos]);
+       /* fprintf(stderr, " %c",qry[pos]); */
 
-           switch (AH->sqlparse.state)
-           {
+       switch (AH->sqlparse.state)
+       {
 
-               case SQL_SCAN:  /* Default state == 0, set in _allocAH */
+           case SQL_SCAN:  /* Default state == 0, set in _allocAH */
 
-                   if (qry[pos] == ';' && AH->sqlparse.braceDepth == 0)
-                   {
-                       /* Send It & reset the buffer */
-
-                       /*
-                        * fprintf(stderr, "    sending: '%s'\n\n",
-                        * AH->sqlBuf->data);
-                        */
-                       ExecuteSqlCommand(AH, AH->sqlBuf, "could not execute query", false);
-                       resetPQExpBuffer(AH->sqlBuf);
-                       AH->sqlparse.lastChar = '\0';
-                   }
-                   else
+               if (qry[pos] == ';' && AH->sqlparse.braceDepth == 0)
+               {
+                   /* Send It & reset the buffer */
+
+                   /*
+                    * fprintf(stderr, "    sending: '%s'\n\n",
+                    * AH->sqlBuf->data);
+                    */
+                   ExecuteSqlCommand(AH, AH->sqlBuf, "could not execute query", false);
+                   resetPQExpBuffer(AH->sqlBuf);
+                   AH->sqlparse.lastChar = '\0';
+
+                   /* Remove any following newlines - so that embedded COPY commands don't get a 
+                    * starting newline.
+                    */
+                   pos++;
+                   for ( ; pos < (eos - qry) && qry[pos] == '\n' ; pos++ ) ;
+
+                   /* We've got our line, so exit */
+                   return qry + pos;
+               }
+               else
+               {
+                   if (qry[pos] == '"' || qry[pos] == '\'')
                    {
-                       if (qry[pos] == '"' || qry[pos] == '\'')
-                       {
-                           /* fprintf(stderr,"[startquote]\n"); */
-                           AH->sqlparse.state = SQL_IN_QUOTE;
-                           AH->sqlparse.quoteChar = qry[pos];
-                           AH->sqlparse.backSlash = 0;
-                       }
-                       else if (qry[pos] == '-' && AH->sqlparse.lastChar == '-')
-                           AH->sqlparse.state = SQL_IN_SQL_COMMENT;
-                       else if (qry[pos] == '*' && AH->sqlparse.lastChar == '/')
-                           AH->sqlparse.state = SQL_IN_EXT_COMMENT;
-                       else if (qry[pos] == '(')
-                           AH->sqlparse.braceDepth++;
-                       else if (qry[pos] == ')')
-                           AH->sqlparse.braceDepth--;
-
-                       AH->sqlparse.lastChar = qry[pos];
+                       /* fprintf(stderr,"[startquote]\n"); */
+                       AH->sqlparse.state = SQL_IN_QUOTE;
+                       AH->sqlparse.quoteChar = qry[pos];
+                       AH->sqlparse.backSlash = 0;
                    }
+                   else if (qry[pos] == '-' && AH->sqlparse.lastChar == '-')
+                       AH->sqlparse.state = SQL_IN_SQL_COMMENT;
+                   else if (qry[pos] == '*' && AH->sqlparse.lastChar == '/')
+                       AH->sqlparse.state = SQL_IN_EXT_COMMENT;
+                   else if (qry[pos] == '(')
+                       AH->sqlparse.braceDepth++;
+                   else if (qry[pos] == ')')
+                       AH->sqlparse.braceDepth--;
+
+                   AH->sqlparse.lastChar = qry[pos];
+               }
 
-                   break;
+               break;
 
-               case SQL_IN_SQL_COMMENT:
+           case SQL_IN_SQL_COMMENT:
 
-                   if (qry[pos] == '\n')
-                       AH->sqlparse.state = SQL_SCAN;
-                   break;
+               if (qry[pos] == '\n')
+                   AH->sqlparse.state = SQL_SCAN;
+               break;
 
-               case SQL_IN_EXT_COMMENT:
+           case SQL_IN_EXT_COMMENT:
 
-                   if (AH->sqlparse.lastChar == '*' && qry[pos] == '/')
-                       AH->sqlparse.state = SQL_SCAN;
-                   break;
+               if (AH->sqlparse.lastChar == '*' && qry[pos] == '/')
+                   AH->sqlparse.state = SQL_SCAN;
+               break;
 
-               case SQL_IN_QUOTE:
+           case SQL_IN_QUOTE:
 
-                   if (!AH->sqlparse.backSlash && AH->sqlparse.quoteChar == qry[pos])
-                   {
-                       /* fprintf(stderr,"[endquote]\n"); */
-                       AH->sqlparse.state = SQL_SCAN;
-                   }
-                   else
-                   {
+               if (!AH->sqlparse.backSlash && AH->sqlparse.quoteChar == qry[pos])
+               {
+                   /* fprintf(stderr,"[endquote]\n"); */
+                   AH->sqlparse.state = SQL_SCAN;
+               }
+               else
+               {
 
-                       if (qry[pos] == '\\')
-                       {
-                           if (AH->sqlparse.lastChar == '\\')
-                               AH->sqlparse.backSlash = !AH->sqlparse.backSlash;
-                           else
-                               AH->sqlparse.backSlash = 1;
-                       }
+                   if (qry[pos] == '\\')
+                   {
+                       if (AH->sqlparse.lastChar == '\\')
+                           AH->sqlparse.backSlash = !AH->sqlparse.backSlash;
                        else
-                           AH->sqlparse.backSlash = 0;
+                           AH->sqlparse.backSlash = 1;
                    }
-                   break;
+                   else
+                       AH->sqlparse.backSlash = 0;
+               }
+               break;
 
-           }
-           AH->sqlparse.lastChar = qry[pos];
-           /* fprintf(stderr, "\n"); */
        }
+       AH->sqlparse.lastChar = qry[pos];
+       /* fprintf(stderr, "\n"); */
+   }
 
+    /* If we get here, we've processed entire string with no complete SQL stmt */
+    return eos;
+
+}
+
+
+/* Convenience function to send one or more queries. Monitors result to handle COPY statements */
+int
+ExecuteSqlCommandBuf(ArchiveHandle *AH, void *qryv, int bufLen)
+{
+   char       *qry = (char *) qryv;
+   char       *eos = qry + bufLen;
+
+   /*
+    * fprintf(stderr, "\n\n*****\n
+    * Buffer:\n\n%s\n*******************\n\n", qry);
+    */
+
+   /* Could switch between command and COPY IN mode at each line */
+   while (qry < eos)
+   {
+       if (AH->pgCopyIn) {
+           qry = _sendCopyLine(AH, qry, eos);
+       } else {
+           qry = _sendSQLLine(AH, qry, eos);
+       }
    }
 
    return 1;