* 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.
+ *
*-------------------------------------------------------------------------
*/
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);
/*
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;