aboutsummaryrefslogtreecommitdiff
path: root/src/backend/tcop/postgres.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/tcop/postgres.c')
-rw-r--r--src/backend/tcop/postgres.c166
1 files changed, 97 insertions, 69 deletions
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 1048d2fa1c6..fcc6591f7c0 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.321 2003/04/17 22:26:01 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.322 2003/04/19 00:02:29 tgl Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@@ -133,7 +133,9 @@ static const char *CreateCommandTag(Node *parsetree);
/* ----------------
* InteractiveBackend() is called for user interactive connections
- * the string entered by the user is placed in its parameter inBuf.
+ *
+ * the string entered by the user is placed in its parameter inBuf,
+ * and we act like a Q message was received.
*
* EOF is returned if end-of-file input is seen; time to shut down.
* ----------------
@@ -155,6 +157,7 @@ InteractiveBackend(StringInfo inBuf)
/* Reset inBuf to empty */
inBuf->len = 0;
inBuf->data[0] = '\0';
+ inBuf->cursor = 0;
for (;;)
{
@@ -214,6 +217,9 @@ InteractiveBackend(StringInfo inBuf)
break;
}
+ /* Add '\0' to make it look the same as message case. */
+ appendStringInfoChar(inBuf, (char) '\0');
+
/*
* if the query echo flag was given, print the query..
*/
@@ -227,66 +233,79 @@ InteractiveBackend(StringInfo inBuf)
/* ----------------
* SocketBackend() Is called for frontend-backend connections
*
- * If the input is a query (case 'Q') then the string entered by
- * the user is placed in its parameter inBuf.
- *
- * If the input is a fastpath function call (case 'F') then
- * the function call is processed in HandleFunctionRequest()
- * (now called from PostgresMain()).
+ * Returns the message type code, and loads message body data into inBuf.
*
* EOF is returned if the connection is lost.
* ----------------
*/
-
static int
SocketBackend(StringInfo inBuf)
{
int qtype;
/*
- * get input from the frontend
+ * Get message type code from the frontend.
*/
qtype = pq_getbyte();
+ if (qtype == EOF) /* frontend disconnected */
+ {
+ elog(COMMERROR, "unexpected EOF on client connection");
+ return qtype;
+ }
+
+ /*
+ * Validate message type code before trying to read body; if we have
+ * lost sync, better to say "command unknown" than to run out of memory
+ * because we used garbage as a length word.
+ */
switch (qtype)
{
- case EOF:
- /* frontend disconnected */
+ case 'Q': /* simple query */
+ if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
+ {
+ /* old style without length word; convert */
+ if (pq_getstring(inBuf))
+ {
+ elog(COMMERROR, "unexpected EOF on client connection");
+ return EOF;
+ }
+ }
break;
- /*
- * 'Q': user entered a query
- */
- case 'Q':
- if (pq_getstr(inBuf))
- return EOF;
+ case 'F': /* fastpath function call */
break;
- /*
- * 'F': calling user/system functions
- */
- case 'F':
- if (pq_getstr(inBuf))
- return EOF; /* ignore "string" at start of F message */
+ case 'X': /* terminate */
break;
- /*
- * 'X': frontend is exiting
- */
- case 'X':
+ case 'd': /* copy data */
+ case 'c': /* copy done */
+ case 'f': /* copy fail */
+ /* Accept but ignore these messages, per protocol spec */
break;
+ default:
/*
- * otherwise we got garbage from the frontend.
- *
- * XXX are we certain that we want to do an elog(FATAL) here?
- * -cim 1/24/90
+ * Otherwise we got garbage from the frontend. We treat this
+ * as fatal because we have probably lost message boundary sync,
+ * and there's no good way to recover.
*/
- default:
elog(FATAL, "Socket command type %c unknown", qtype);
break;
}
+ /*
+ * In protocol version 3, all frontend messages have a length word
+ * next after the type code; we can read the message contents
+ * independently of the type.
+ */
+ if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
+ {
+ if (pq_getmessage(inBuf, 0))
+ return EOF; /* suitable message already logged */
+ }
+
return qtype;
}
@@ -1220,19 +1239,17 @@ int
PostgresMain(int argc, char *argv[], const char *username)
{
int flag;
-
const char *DBName = NULL;
+ char *potential_DataDir = NULL;
bool secure;
int errs = 0;
int debug_flag = 0;
GucContext ctx;
GucSource gucsource;
char *tmp;
-
int firstchar;
StringInfo parser_input;
-
- char *potential_DataDir = NULL;
+ bool send_rfq;
/*
* Catch standard options before doing much else. This even works on
@@ -1815,7 +1832,7 @@ PostgresMain(int argc, char *argv[], const char *username)
if (!IsUnderPostmaster)
{
puts("\nPOSTGRES backend interactive interface ");
- puts("$Revision: 1.321 $ $Date: 2003/04/17 22:26:01 $\n");
+ puts("$Revision: 1.322 $ $Date: 2003/04/19 00:02:29 $\n");
}
/*
@@ -1902,6 +1919,8 @@ PostgresMain(int argc, char *argv[], const char *username)
PG_SETMASK(&UnBlockSig);
+ send_rfq = true; /* initially, or after error */
+
/*
* Non-error queries loop here.
*/
@@ -1922,7 +1941,11 @@ PostgresMain(int argc, char *argv[], const char *username)
*
* Note: this includes fflush()'ing the last of the prior output.
*/
- ReadyForQuery(whereToSendOutput);
+ if (send_rfq)
+ {
+ ReadyForQuery(whereToSendOutput);
+ send_rfq = false;
+ }
/* ----------
* Tell the statistics collector what we've collected
@@ -1986,20 +2009,36 @@ PostgresMain(int argc, char *argv[], const char *username)
*/
switch (firstchar)
{
+ case 'Q': /* simple query */
/*
- * 'F' indicates a fastpath call.
- */
- case 'F':
- /* ----------
- * Tell the collector what we're doing
- * ----------
+ * Process the query string.
+ *
+ * Note: transaction command start/end is now done within
+ * pg_exec_query_string(), not here.
*/
+ if (log_statement_stats)
+ ResetUsage();
+
+ pgstat_report_activity(parser_input->data);
+
+ pg_exec_query_string(parser_input,
+ whereToSendOutput,
+ QueryContext);
+
+ if (log_statement_stats)
+ ShowUsage("QUERY STATISTICS");
+
+ send_rfq = true;
+ break;
+
+ case 'F': /* fastpath function call */
+ /* Tell the collector what we're doing */
pgstat_report_activity("<FASTPATH> function call");
/* start an xact for this function invocation */
start_xact_command();
- if (HandleFunctionRequest() == EOF)
+ if (HandleFunctionRequest(parser_input) == EOF)
{
/* lost frontend connection during F message input */
@@ -2015,29 +2054,8 @@ PostgresMain(int argc, char *argv[], const char *username)
/* commit the function-invocation transaction */
finish_xact_command(false);
- break;
-
- /*
- * 'Q' indicates a user query
- */
- case 'Q':
- /*
- * otherwise, process the input string.
- *
- * Note: transaction command start/end is now done within
- * pg_exec_query_string(), not here.
- */
- if (log_statement_stats)
- ResetUsage();
- pgstat_report_activity(parser_input->data);
-
- pg_exec_query_string(parser_input,
- whereToSendOutput,
- QueryContext);
-
- if (log_statement_stats)
- ShowUsage("QUERY STATISTICS");
+ send_rfq = true;
break;
/*
@@ -2064,8 +2082,18 @@ PostgresMain(int argc, char *argv[], const char *username)
*/
proc_exit(0);
+ case 'd': /* copy data */
+ case 'c': /* copy done */
+ case 'f': /* copy fail */
+ /*
+ * Accept but ignore these messages, per protocol spec;
+ * we probably got here because a COPY failed, and the
+ * frontend is still sending data.
+ */
+ break;
+
default:
- elog(ERROR, "unknown frontend message was received");
+ elog(FATAL, "Socket command type %c unknown", firstchar);
}
#ifdef MEMORY_CONTEXT_CHECKING