OSDN Git Service

Fix pg_restore to handle the 'set max oid' entry correctly in archives
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 18 Jan 2002 17:13:51 +0000 (17:13 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
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 4c99d51..675da67 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 - pjw@rhyme.com.au
  *
  *             backup file; prior version was restoring schema in data-only
  *             restores. Added enum to make code easier to understand.
  *
+ * Modifications - 18-Jan-2002 - pjw@rhyme.com.au
+ *       - Modified _tocEntryRequired to handle '<Init>/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: <Init> type with <Max OID> name; this is part of
+     * a DATA restore even though it has SQL.
+     */
+       if (  ( strcmp(te->desc, "<Init>") == 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 aeea9d0..ff31b47 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 - pjw@rhyme.com.au
+ *
+ *    - 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;