Commit bb698c25 authored by Tom Lane's avatar Tom Lane

Fix pg_restore to handle the 'set max oid' entry correctly in archives

dumped by pg_dump -o.  Per bug report posted by Bruce; fix is from
Philip Warner, reviewed by Tom Lane.
parent 3dfe8024
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* *
* *
* IDENTIFICATION * 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 * Modifications - 28-Jun-2000 - pjw@rhyme.com.au
* *
...@@ -62,6 +62,11 @@ ...@@ -62,6 +62,11 @@
* backup file; prior version was restoring schema in data-only * backup file; prior version was restoring schema in data-only
* restores. Added enum to make code easier to understand. * 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) ...@@ -1917,6 +1922,13 @@ _tocEntryRequired(TocEntry *te, RestoreOptions *ropt)
res = res & ~REQ_DATA; 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 */ /* Mask it if we only want schema */
if (ropt->schemaOnly) if (ropt->schemaOnly)
res = res & REQ_SCHEMA; res = res & REQ_SCHEMA;
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* Implements the basic DB functions used by the archiver. * Implements the basic DB functions used by the archiver.
* *
* IDENTIFICATION * 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 * NOTES
* *
...@@ -17,6 +17,14 @@ ...@@ -17,6 +17,14 @@
* *
* - Avoid forcing table name to lower case in FixupBlobXrefs! * - 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); ...@@ -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 PGconn *_connectDB(ArchiveHandle *AH, const char *newdbname, const char *newUser);
static int _executeSqlCommand(ArchiveHandle *AH, PGconn *conn, PQExpBuffer qry, char *desc); static int _executeSqlCommand(ArchiveHandle *AH, PGconn *conn, PQExpBuffer qry, char *desc);
static void notice_processor(void *arg, const char *message); 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) ...@@ -534,206 +544,229 @@ _executeSqlCommand(ArchiveHandle *AH, PGconn *conn, PQExpBuffer qry, char *desc)
return strlen(qry->data); return strlen(qry->data);
} }
/* Convenience function to send one or more queries. Monitors result to handle COPY statements */ /*
int * Used by ExecuteSqlCommandBuf to send one buffered line when running a COPY command.
ExecuteSqlCommandBuf(ArchiveHandle *AH, void *qryv, int bufLen) */
static char*
_sendCopyLine( ArchiveHandle *AH, char *qry, char *eos)
{ {
int loc; int loc; /* Location of next newline */
int pos = 0; int pos = 0; /* Current position */
int sPos = 0; int sPos = 0; /* Last pos of a slash char */
char *qry = (char *) qryv; int isEnd = 0;
int isEnd = 0;
char *eos = qry + bufLen;
/* /* loop to find unquoted newline ending the line of COPY data */
* fprintf(stderr, "\n\n*****\n for (;;) {
* Buffer:\n\n%s\n*******************\n\n", qry); loc = strcspn(&qry[pos], "\n") + pos;
*/
/* If we're in COPY IN mode, then just break it into lines and send... */ /* If no match, then wait */
if (AH->pgCopyIn) if (loc >= (eos - qry)) /* None found */
{
for (;;)
{ {
appendBinaryPQExpBuffer(AH->pgCopyBuf, qry, (eos - qry));
return eos;
}
/* Find a lf */ /*
loc = strcspn(&qry[pos], "\n") + pos; * fprintf(stderr, "Found cr at %d, prev char was %c, next was
pos = 0; * %c\n", loc, qry[loc-1], qry[loc+1]);
*/
/* 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]);
*/
/* Count the number of preceding slashes */ /* Count the number of preceding slashes */
sPos = loc; sPos = loc;
while (sPos > 0 && qry[sPos - 1] == '\\') while (sPos > 0 && qry[sPos - 1] == '\\')
sPos--; sPos--;
sPos = loc - sPos; sPos = loc - sPos;
/* /*
* If an odd number of preceding slashes, then \n was escaped * If an odd number of preceding slashes, then \n was escaped
* so set the next search pos, and restart (if any left). * so set the next search pos, and loop (if any left).
*/ */
if ((sPos & 1) == 1) if ((sPos & 1) == 1)
{
/* fprintf(stderr, "cr was escaped\n"); */
pos = loc + 1;
if (pos >= (eos - qry))
{ {
/* fprintf(stderr, "cr was escaped\n"); */ appendBinaryPQExpBuffer(AH->pgCopyBuf, qry, (eos - qry));
pos = loc + 1; return eos;
if (pos >= (eos - qry))
{
appendBinaryPQExpBuffer(AH->pgCopyBuf, qry, (eos - qry));
break;
}
} }
else } else {
{ break;
/* We got a good cr */ }
qry[loc] = '\0'; }
appendPQExpBuffer(AH->pgCopyBuf, "%s\n", qry);
qry += loc + 1;
isEnd = (strcmp(AH->pgCopyBuf->data, "\\.\n") == 0);
/*--------- /* We found an unquoted newline */
* fprintf(stderr, "Sending '%s' via qry[loc] = '\0';
* COPY (at end = %d)\n\n", AH->pgCopyBuf->data, isEnd); 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");
/* resetPQExpBuffer(AH->pgCopyBuf);
* fprintf(stderr, "Buffer is '%s'\n",
* AH->pgCopyBuf->data);
*/
if (isEnd) /*
{ * fprintf(stderr, "Buffer is '%s'\n",
if (PQendcopy(AH->connection) != 0) * AH->pgCopyBuf->data);
die_horribly(AH, modulename, "error returned by PQendcopy\n"); */
AH->pgCopyIn = 0; if (isEnd)
break; {
} 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 */ return qry + loc + 1;
if (qry >= eos) }
break;
} /*
} * 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 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
* The following is a mini state machine to assess then of of an * unquoted, un commented semi-colon.
* 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", * fprintf(stderr, "Buffer at start is: '%s'\n\n",
* AH->sqlBuf->data); * AH->sqlBuf->data);
*/ */
for (pos = 0; pos < (eos - qry); pos++) for (pos = 0; pos < (eos - qry); pos++)
{ {
appendPQExpBufferChar(AH->sqlBuf, qry[pos]); appendPQExpBufferChar(AH->sqlBuf, qry[pos]);
/* fprintf(stderr, " %c",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) if (qry[pos] == ';' && AH->sqlparse.braceDepth == 0)
{ {
/* Send It & reset the buffer */ /* Send It & reset the buffer */
/* /*
* fprintf(stderr, " sending: '%s'\n\n", * fprintf(stderr, " sending: '%s'\n\n",
* AH->sqlBuf->data); * AH->sqlBuf->data);
*/ */
ExecuteSqlCommand(AH, AH->sqlBuf, "could not execute query", false); ExecuteSqlCommand(AH, AH->sqlBuf, "could not execute query", false);
resetPQExpBuffer(AH->sqlBuf); resetPQExpBuffer(AH->sqlBuf);
AH->sqlparse.lastChar = '\0'; AH->sqlparse.lastChar = '\0';
}
else /* 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;
/* fprintf(stderr,"[startquote]\n"); */ AH->sqlparse.quoteChar = qry[pos];
AH->sqlparse.state = SQL_IN_QUOTE; AH->sqlparse.backSlash = 0;
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];
} }
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') if (qry[pos] == '\n')
AH->sqlparse.state = SQL_SCAN; AH->sqlparse.state = SQL_SCAN;
break; break;
case SQL_IN_EXT_COMMENT: case SQL_IN_EXT_COMMENT:
if (AH->sqlparse.lastChar == '*' && qry[pos] == '/') if (AH->sqlparse.lastChar == '*' && qry[pos] == '/')
AH->sqlparse.state = SQL_SCAN; AH->sqlparse.state = SQL_SCAN;
break; break;
case SQL_IN_QUOTE: case SQL_IN_QUOTE:
if (!AH->sqlparse.backSlash && AH->sqlparse.quoteChar == qry[pos]) if (!AH->sqlparse.backSlash && AH->sqlparse.quoteChar == qry[pos])
{ {
/* fprintf(stderr,"[endquote]\n"); */ /* fprintf(stderr,"[endquote]\n"); */
AH->sqlparse.state = SQL_SCAN; AH->sqlparse.state = SQL_SCAN;
} }
else else
{ {
if (qry[pos] == '\\') if (qry[pos] == '\\')
{ {
if (AH->sqlparse.lastChar == '\\') if (AH->sqlparse.lastChar == '\\')
AH->sqlparse.backSlash = !AH->sqlparse.backSlash; AH->sqlparse.backSlash = !AH->sqlparse.backSlash;
else
AH->sqlparse.backSlash = 1;
}
else 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; return 1;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment