]> granicus.if.org Git - postgresql/blobdiff - src/backend/tcop/postgres.c
* Most changes are to fix warnings issued when compiling win32
[postgresql] / src / backend / tcop / postgres.c
index dd235e8765aa3fa373f1fe434ef07e4dae30d854..1affe7d49b9f8c3cf0f0a6cd379b30589e755a3e 100644 (file)
@@ -3,12 +3,12 @@
  * postgres.c
  *       POSTGRES C Backend Interface
  *
- * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.341 2003/05/09 15:57:24 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.400 2004/04/19 17:42:58 momjian Exp $
  *
  * NOTES
  *       this is the "main" module of the postgres backend and
@@ -68,7 +68,6 @@
 extern int     optind;
 extern char *optarg;
 
-
 /* ----------------
  *             global variables
  * ----------------
@@ -85,18 +84,32 @@ sigjmp_buf  Warn_restart;
 bool           Warn_restart_ready = false;
 bool           InError = false;
 
-extern bool    autocommit;
+/* flag for logging end of session */
+bool        Log_disconnections = false;
+
+LogStmtLevel log_statement = LOGSTMT_NONE;
 
 /*
  * Flags for expensive function optimization -- JMH 3/9/92
  */
 int                    XfuncMode = 0;
 
+/* GUC variable for maximum stack depth (measured in kilobytes) */
+int                    max_stack_depth = 2048;
+
+
 /* ----------------
  *             private variables
  * ----------------
  */
 
+/* max_stack_depth converted to bytes for speed of checking */
+static int     max_stack_depth_bytes = 2048*1024;
+
+/* stack base pointer (initialized by PostgresMain) */
+static char *stack_base_ptr = NULL;
+
+
 /*
  * Flag to mark SIGHUP. Whenever the main loop comes around it
  * will reread the configuration file. (Better than doing the
@@ -135,6 +148,7 @@ static bool EchoQuery = false;      /* default don't echo */
 #ifndef TCOP_DONTUSENEWLINE
 static int     UseNewLine = 1;         /* Use newlines query delimiters (the
                                                                 * default) */
+
 #else
 static int     UseNewLine = 0;         /* Use EOF as query delimiters */
 #endif   /* TCOP_DONTUSENEWLINE */
@@ -148,9 +162,10 @@ static int InteractiveBackend(StringInfo inBuf);
 static int     SocketBackend(StringInfo inBuf);
 static int     ReadCommand(StringInfo inBuf);
 static void start_xact_command(void);
-static void finish_xact_command(bool forceCommit);
+static void finish_xact_command(void);
 static void SigHupHandler(SIGNAL_ARGS);
 static void FloatExceptionHandler(SIGNAL_ARGS);
+static void log_disconnections(int code, Datum arg);
 
 
 /* ----------------------------------------------------------------
@@ -277,14 +292,16 @@ SocketBackend(StringInfo inBuf)
 
        if (qtype == EOF)                       /* frontend disconnected */
        {
-               elog(COMMERROR, "unexpected EOF on client connection");
+               ereport(COMMERROR,
+                               (errcode(ERRCODE_PROTOCOL_VIOLATION),
+                                errmsg("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.
+        * lost sync, better to say "command unknown" than to run out of
+        * memory because we used garbage as a length word.
         *
         * This also gives us a place to set the doing_extended_query_message
         * flag as soon as possible.
@@ -298,7 +315,9 @@ SocketBackend(StringInfo inBuf)
                                /* old style without length word; convert */
                                if (pq_getstring(inBuf))
                                {
-                                       elog(COMMERROR, "unexpected EOF on client connection");
+                                       ereport(COMMERROR,
+                                                       (errcode(ERRCODE_PROTOCOL_VIOLATION),
+                                                errmsg("unexpected EOF on client connection")));
                                        return EOF;
                                }
                        }
@@ -311,6 +330,7 @@ SocketBackend(StringInfo inBuf)
 
                case 'X':                               /* terminate */
                        doing_extended_query_message = false;
+                       ignore_till_sync = false;
                        break;
 
                case 'B':                               /* bind */
@@ -322,7 +342,9 @@ SocketBackend(StringInfo inBuf)
                        doing_extended_query_message = true;
                        /* these are only legal in protocol 3 */
                        if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
-                               elog(FATAL, "Socket command type %c unknown", qtype);
+                               ereport(FATAL,
+                                               (errcode(ERRCODE_PROTOCOL_VIOLATION),
+                                        errmsg("invalid frontend message type %d", qtype)));
                        break;
 
                case 'S':                               /* sync */
@@ -332,7 +354,9 @@ SocketBackend(StringInfo inBuf)
                        doing_extended_query_message = false;
                        /* only legal in protocol 3 */
                        if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
-                               elog(FATAL, "Socket command type %c unknown", qtype);
+                               ereport(FATAL,
+                                               (errcode(ERRCODE_PROTOCOL_VIOLATION),
+                                        errmsg("invalid frontend message type %d", qtype)));
                        break;
 
                case 'd':                               /* copy data */
@@ -341,16 +365,21 @@ SocketBackend(StringInfo inBuf)
                        doing_extended_query_message = false;
                        /* these are only legal in protocol 3 */
                        if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
-                               elog(FATAL, "Socket command type %c unknown", qtype);
+                               ereport(FATAL,
+                                               (errcode(ERRCODE_PROTOCOL_VIOLATION),
+                                        errmsg("invalid frontend message type %d", qtype)));
                        break;
 
                default:
+
                        /*
-                        * 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.
+                        * 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.
                         */
-                       elog(FATAL, "Socket command type %c unknown", qtype);
+                       ereport(FATAL,
+                                       (errcode(ERRCODE_PROTOCOL_VIOLATION),
+                                        errmsg("invalid frontend message type %d", qtype)));
                        break;
        }
 
@@ -380,7 +409,7 @@ ReadCommand(StringInfo inBuf)
 {
        int                     result;
 
-       if (IsUnderPostmaster)
+       if (whereToSendOutput == Remote)
                result = SocketBackend(inBuf);
        else
                result = InteractiveBackend(inBuf);
@@ -398,9 +427,9 @@ ReadCommand(StringInfo inBuf)
  * but it is still needed for parsing of SQL function bodies.
  */
 List *
-pg_parse_and_rewrite(const char *query_string, /* string to execute */
+pg_parse_and_rewrite(const char *query_string, /* string to execute */
                                         Oid *paramTypes,       /* parameter types */
-                                        int numParams) /* number of parameters */
+                                        int numParams)         /* number of parameters */
 {
        List       *raw_parsetree_list;
        List       *querytree_list;
@@ -444,16 +473,63 @@ pg_parse_and_rewrite(const char *query_string, /* string to execute */
 List *
 pg_parse_query(const char *query_string)
 {
-       List       *raw_parsetree_list;
+       List       *raw_parsetree_list,
+                          *parsetree_item;
 
-       if (log_statement)
-               elog(LOG, "query: %s", query_string);
+       if (log_statement == LOGSTMT_ALL)
+               ereport(LOG,
+                               (errmsg("statement: %s", query_string)));
 
        if (log_parser_stats)
                ResetUsage();
 
        raw_parsetree_list = raw_parser(query_string);
 
+       /* do log_statement tests for mod and ddl */
+       if (log_statement == LOGSTMT_MOD ||
+               log_statement == LOGSTMT_DDL)
+       {
+               foreach(parsetree_item, raw_parsetree_list)
+               {
+                       Node       *parsetree = (Node *) lfirst(parsetree_item);
+                       const char *commandTag;
+       
+                       if (IsA(parsetree, ExplainStmt) &&
+                               ((ExplainStmt *)parsetree)->analyze)
+                               parsetree = (Node *)(((ExplainStmt *)parsetree)->query);
+                       
+                       if (IsA(parsetree, PrepareStmt))
+                               parsetree = (Node *)(((PrepareStmt *)parsetree)->query);
+                       
+                       if (IsA(parsetree, SelectStmt))
+                               continue;       /* optimization for frequent command */
+                               
+                       if (log_statement == LOGSTMT_MOD &&
+                               (IsA(parsetree, InsertStmt) ||
+                                IsA(parsetree, UpdateStmt) ||
+                                IsA(parsetree, DeleteStmt) ||
+                                IsA(parsetree, TruncateStmt) ||
+                                (IsA(parsetree, CopyStmt) &&
+                                 ((CopyStmt *)parsetree)->is_from)))   /* COPY FROM */
+                       {
+                               ereport(LOG,
+                                               (errmsg("statement: %s", query_string)));
+                               break;
+                       }
+                       commandTag = CreateCommandTag(parsetree);
+                       if (strncmp(commandTag, "CREATE ", strlen("CREATE ")) == 0 ||
+                               strncmp(commandTag, "ALTER ", strlen("ALTER ")) == 0 ||
+                               strncmp(commandTag, "DROP ", strlen("DROP ")) == 0 ||
+                               IsA(parsetree, GrantStmt) ||    /* GRANT or REVOKE */
+                               IsA(parsetree, CommentStmt))
+                       {
+                               ereport(LOG,
+                                               (errmsg("statement: %s", query_string)));
+                               break;
+                       }
+               }
+       }
+
        if (log_parser_stats)
                ShowUsage("PARSER STATISTICS");
 
@@ -506,15 +582,15 @@ pg_rewrite_queries(List *querytree_list)
                ResetUsage();
 
        /*
-        * rewritten queries are collected in new_list.  Note there may be more
-        * or fewer than in the original list.
+        * rewritten queries are collected in new_list.  Note there may be
+        * more or fewer than in the original list.
         */
        foreach(list_item, querytree_list)
        {
                Query      *querytree = (Query *) lfirst(list_item);
 
                if (Debug_print_parse)
-                       elog_node_display(LOG, "parse tree", querytree,
+                       elog_node_display(DEBUG1, "parse tree", querytree,
                                                          Debug_pretty_print);
 
                if (querytree->commandType == CMD_UTILITY)
@@ -545,13 +621,13 @@ pg_rewrite_queries(List *querytree_list)
        new_list = (List *) copyObject(querytree_list);
        /* This checks both copyObject() and the equal() routines... */
        if (!equal(new_list, querytree_list))
-               elog(WARNING, "pg_rewrite_queries: copyObject failed on parse tree");
+               elog(WARNING, "copyObject() failed to produce an equal parse tree");
        else
                querytree_list = new_list;
 #endif
 
        if (Debug_print_rewritten)
-               elog_node_display(LOG, "rewritten parse tree", querytree_list,
+               elog_node_display(DEBUG1, "rewritten parse tree", querytree_list,
                                                  Debug_pretty_print);
 
        return querytree_list;
@@ -589,7 +665,7 @@ pg_plan_query(Query *querytree)
 #ifdef NOT_USED
                /* This checks both copyObject() and the equal() routines... */
                if (!equal(new_plan, plan))
-                       elog(WARNING, "pg_plan_query: copyObject failed on plan tree");
+                       elog(WARNING, "copyObject() failed to produce an equal plan tree");
                else
 #endif
                        plan = new_plan;
@@ -600,7 +676,7 @@ pg_plan_query(Query *querytree)
         * Print plan if debugging.
         */
        if (Debug_print_plan)
-               elog_node_display(LOG, "plan", plan, Debug_pretty_print);
+               elog_node_display(DEBUG1, "plan", plan, Debug_pretty_print);
 
        return plan;
 }
@@ -657,13 +733,14 @@ pg_plan_queries(List *querytrees, bool needSnapshot)
 static void
 exec_simple_query(const char *query_string)
 {
-       CommandDest     dest = whereToSendOutput;
+       CommandDest dest = whereToSendOutput;
        MemoryContext oldcontext;
        List       *parsetree_list,
                           *parsetree_item;
        struct timeval start_t,
                                stop_t;
        bool            save_log_duration = log_duration;
+       int                     save_log_min_duration_statement = log_min_duration_statement;
        bool            save_log_statement_stats = log_statement_stats;
 
        /*
@@ -674,11 +751,12 @@ exec_simple_query(const char *query_string)
        pgstat_report_activity(query_string);
 
        /*
-        * We use save_log_duration so "SET log_duration = true" doesn't
-        * report incorrect time because gettimeofday() wasn't called.
-        * Similarly, log_statement_stats has to be captured once.
+        * We use save_log_* so "SET log_duration = true"  and "SET
+        * log_min_duration_statement = true" don't report incorrect time
+        * because gettimeofday() wasn't called. Similarly,
+        * log_statement_stats has to be captured once.
         */
-       if (save_log_duration)
+       if (save_log_duration || save_log_min_duration_statement != -1)
                gettimeofday(&start_t, NULL);
 
        if (save_log_statement_stats)
@@ -694,10 +772,10 @@ exec_simple_query(const char *query_string)
        start_xact_command();
 
        /*
-        * Zap any pre-existing unnamed statement.  (While not strictly
-        * necessary, it seems best to define simple-Query mode as if it
-        * used the unnamed statement and portal; this ensures we recover
-        * any storage used by prior unnamed operations.)
+        * Zap any pre-existing unnamed statement.      (While not strictly
+        * necessary, it seems best to define simple-Query mode as if it used
+        * the unnamed statement and portal; this ensures we recover any
+        * storage used by prior unnamed operations.)
         */
        unnamed_stmt_pstmt = NULL;
        if (unnamed_stmt_context)
@@ -740,10 +818,10 @@ exec_simple_query(const char *query_string)
                int16           format;
 
                /*
-                * Get the command name for use in status display (it also becomes the
-                * default completion tag, down inside PortalRun).  Set ps_status and
-                * do any special start-of-SQL-command processing needed by the
-                * destination.
+                * Get the command name for use in status display (it also becomes
+                * the default completion tag, down inside PortalRun).  Set
+                * ps_status and do any special start-of-SQL-command processing
+                * needed by the destination.
                 */
                commandTag = CreateCommandTag(parsetree);
 
@@ -773,8 +851,10 @@ exec_simple_query(const char *query_string)
                        }
 
                        if (!allowit)
-                               elog(ERROR, "current transaction is aborted, "
-                                        "queries ignored until end of transaction block");
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),
+                                                errmsg("current transaction is aborted, "
+                                        "commands ignored until end of transaction block")));
                }
 
                /* Make sure we are in a transaction command */
@@ -799,8 +879,8 @@ exec_simple_query(const char *query_string)
                CHECK_FOR_INTERRUPTS();
 
                /*
-                * Create unnamed portal to run the query or queries in.
-                * If there already is one, silently drop it.
+                * Create unnamed portal to run the query or queries in. If there
+                * already is one, silently drop it.
                 */
                portal = CreatePortal("", true, true);
 
@@ -818,9 +898,9 @@ exec_simple_query(const char *query_string)
 
                /*
                 * Select the appropriate output format: text unless we are doing
-                * a FETCH from a binary cursor.  (Pretty grotty to have to do this
-                * here --- but it avoids grottiness in other places.  Ah, the joys
-                * of backward compatibility...)
+                * a FETCH from a binary cursor.  (Pretty grotty to have to do
+                * this here --- but it avoids grottiness in other places.      Ah,
+                * the joys of backward compatibility...)
                 */
                format = 0;                             /* TEXT is default */
                if (IsA(parsetree, FetchStmt))
@@ -833,7 +913,7 @@ exec_simple_query(const char *query_string)
 
                                if (PortalIsValid(fportal) &&
                                        (fportal->cursorOptions & CURSOR_OPT_BINARY))
-                                       format = 1;             /* BINARY */
+                                       format = 1; /* BINARY */
                        }
                }
                PortalSetResultFormat(portal, 1, &format);
@@ -849,7 +929,8 @@ exec_simple_query(const char *query_string)
                MemoryContextSwitchTo(oldcontext);
 
                /*
-                * Run the portal to completion, and then drop it (and the receiver).
+                * Run the portal to completion, and then drop it (and the
+                * receiver).
                 */
                (void) PortalRun(portal,
                                                 FETCH_ALL,
@@ -857,42 +938,39 @@ exec_simple_query(const char *query_string)
                                                 receiver,
                                                 completionTag);
 
-               (*receiver->destroy) (receiver);
+               (*receiver->rDestroy) (receiver);
 
                PortalDrop(portal, false);
 
-
-               if (IsA(parsetree, TransactionStmt) ||
-                       IsA(parsetree, VariableSetStmt) ||
-                       IsA(parsetree, VariableShowStmt) ||
-                       IsA(parsetree, VariableResetStmt))
+               if (IsA(parsetree, TransactionStmt))
                {
                        /*
-                        * If this was a transaction control statement or a variable
-                        * set/show/reset statement, commit it.  We will start a
-                        * new xact command for the next command (if any).
+                        * If this was a transaction control statement, commit it. We
+                        * will start a new xact command for the next command (if
+                        * any).
                         */
-                       finish_xact_command(true);
+                       finish_xact_command();
                }
-               else if (lnext(parsetree_item) == NIL || !autocommit)
+               else if (lnext(parsetree_item) == NIL)
                {
                        /*
-                        * If this is the last parsetree of the query string, close down
-                        * transaction statement before reporting command-complete.  This
-                        * is so that any end-of-transaction errors are reported before
-                        * the command-complete message is issued, to avoid confusing
-                        * clients who will expect either a command-complete message or an
-                        * error, not one and then the other.  But for compatibility with
-                        * historical Postgres behavior, we do not force a transaction
-                        * boundary between queries appearing in a single query string.
+                        * If this is the last parsetree of the query string, close
+                        * down transaction statement before reporting
+                        * command-complete.  This is so that any end-of-transaction
+                        * errors are reported before the command-complete message is
+                        * issued, to avoid confusing clients who will expect either a
+                        * command-complete message or an error, not one and then the
+                        * other.  But for compatibility with historical Postgres
+                        * behavior, we do not force a transaction boundary between
+                        * queries appearing in a single query string.
                         */
-                       finish_xact_command(false);
+                       finish_xact_command();
                }
                else
                {
                        /*
-                        * We need a CommandCounterIncrement after every query,
-                        * except those that start or end a transaction block.
+                        * We need a CommandCounterIncrement after every query, except
+                        * those that start or end a transaction block.
                         */
                        CommandCounterIncrement();
                }
@@ -907,6 +985,11 @@ exec_simple_query(const char *query_string)
                EndCommand(completionTag, dest);
        }                                                       /* end loop over parsetrees */
 
+       /*
+        * Close down transaction statement, if one is open.
+        */
+       finish_xact_command();
+
        /*
         * If there were no parsetrees, return EmptyQueryResponse message.
         */
@@ -916,24 +999,41 @@ exec_simple_query(const char *query_string)
        QueryContext = NULL;
 
        /*
-        * Close down transaction statement, if one is open.
-        */
-       finish_xact_command(false);
-
-       /*
-        * Finish up monitoring.
+        * Combine processing here as we need to calculate the query duration
+        * in both instances.
         */
-       if (save_log_duration)
+       if (save_log_duration || save_log_min_duration_statement != -1)
        {
+               long            usecs;
+
                gettimeofday(&stop_t, NULL);
                if (stop_t.tv_usec < start_t.tv_usec)
                {
                        stop_t.tv_sec--;
                        stop_t.tv_usec += 1000000;
                }
-               elog(LOG, "duration: %ld.%06ld sec",
-                        (long) (stop_t.tv_sec - start_t.tv_sec),
-                        (long) (stop_t.tv_usec - start_t.tv_usec));
+               usecs = (long) (stop_t.tv_sec - start_t.tv_sec) * 1000000 + (long) (stop_t.tv_usec - start_t.tv_usec);
+
+               if (save_log_duration)
+                       ereport(LOG,
+                                       (errmsg("duration: %ld.%03ld ms",
+                                                       (long) ((stop_t.tv_sec - start_t.tv_sec) * 1000 +
+                                                       (stop_t.tv_usec - start_t.tv_usec) / 1000),
+                                                       (long) (stop_t.tv_usec - start_t.tv_usec) % 1000)));
+
+               /*
+                * Output a duration_statement to the log if the query has exceeded
+                * the min duration, or if we are to print all durations.
+                */
+               if (save_log_min_duration_statement == 0 ||
+                       (save_log_min_duration_statement > 0 &&
+                        usecs >= save_log_min_duration_statement * 1000))
+                       ereport(LOG,
+                                       (errmsg("duration: %ld.%03ld ms  statement: %s",
+                                                       (long) ((stop_t.tv_sec - start_t.tv_sec) * 1000 +
+                                                       (stop_t.tv_usec - start_t.tv_usec) / 1000),
+                                                       (long) (stop_t.tv_usec - start_t.tv_usec) % 1000,
+                                                       query_string)));
        }
 
        if (save_log_statement_stats)
@@ -950,8 +1050,8 @@ exec_simple_query(const char *query_string)
 static void
 exec_parse_message(const char *query_string,   /* string to execute */
                                   const char *stmt_name,               /* name for prepared stmt */
-                                  Oid *paramTypes,                             /* parameter types */
-                                  int numParams)                               /* number of parameters */
+                                  Oid *paramTypes,             /* parameter types */
+                                  int numParams)               /* number of parameters */
 {
        MemoryContext oldcontext;
        List       *parsetree_list;
@@ -984,16 +1084,16 @@ exec_parse_message(const char *query_string,     /* string to execute */
        /*
         * Switch to appropriate context for constructing parsetrees.
         *
-        * We have two strategies depending on whether the prepared statement
-        * is named or not.  For a named prepared statement, we do parsing
-        * in MessageContext and copy the finished trees into the prepared
-        * statement's private context; then the reset of MessageContext releases
-        * temporary space used by parsing and planning.  For an unnamed prepared
-        * statement, we assume the statement isn't going to hang around long,
-        * so getting rid of temp space quickly is probably not worth the costs
-        * of copying parse/plan trees.  So in this case, we set up a special
-        * context for the unnamed statement, and do all the parsing/planning
-        * therein.
+        * We have two strategies depending on whether the prepared statement is
+        * named or not.  For a named prepared statement, we do parsing in
+        * MessageContext and copy the finished trees into the prepared
+        * statement's private context; then the reset of MessageContext
+        * releases temporary space used by parsing and planning.  For an
+        * unnamed prepared statement, we assume the statement isn't going to
+        * hang around long, so getting rid of temp space quickly is probably
+        * not worth the costs of copying parse/plan trees.  So in this case,
+        * we set up a special context for the unnamed statement, and do all
+        * the parsing/planning therein.
         */
        is_named = (stmt_name[0] != '\0');
        if (is_named)
@@ -1030,17 +1130,19 @@ exec_parse_message(const char *query_string,    /* string to execute */
        parsetree_list = pg_parse_query(query_string);
 
        /*
-        * We only allow a single user statement in a prepared statement.
-        * This is mainly to keep the protocol simple --- otherwise we'd need
-        * to worry about multiple result tupdescs and things like that.
+        * We only allow a single user statement in a prepared statement. This
+        * is mainly to keep the protocol simple --- otherwise we'd need to
+        * worry about multiple result tupdescs and things like that.
         */
        if (length(parsetree_list) > 1)
-               elog(ERROR, "Cannot insert multiple commands into a prepared statement");
+               ereport(ERROR,
+                               (errcode(ERRCODE_SYNTAX_ERROR),
+                                errmsg("cannot insert multiple commands into a prepared statement")));
 
        if (parsetree_list != NIL)
        {
-               Node   *parsetree = (Node *) lfirst(parsetree_list);
-               int             i;
+               Node       *parsetree = (Node *) lfirst(parsetree_list);
+               int                     i;
 
                /*
                 * Get the command name for possible use in status display.
@@ -1049,10 +1151,10 @@ exec_parse_message(const char *query_string,    /* string to execute */
 
                /*
                 * If we are in an aborted transaction, reject all commands except
-                * COMMIT/ROLLBACK.  It is important that this test occur before we
-                * try to do parse analysis, rewrite, or planning, since all those
-                * phases try to do database accesses, which may fail in abort
-                * state. (It might be safe to allow some additional utility
+                * COMMIT/ROLLBACK.  It is important that this test occur before
+                * we try to do parse analysis, rewrite, or planning, since all
+                * those phases try to do database accesses, which may fail in
+                * abort state. (It might be safe to allow some additional utility
                 * commands in this state, but not many...)
                 */
                if (IsAbortedTransactionBlockState())
@@ -1069,8 +1171,10 @@ exec_parse_message(const char *query_string,     /* string to execute */
                        }
 
                        if (!allowit)
-                               elog(ERROR, "current transaction is aborted, "
-                                        "queries ignored until end of transaction block");
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),
+                                                errmsg("current transaction is aborted, "
+                                        "commands ignored until end of transaction block")));
                }
 
                /*
@@ -1092,11 +1196,13 @@ exec_parse_message(const char *query_string,    /* string to execute */
                param_list = NIL;
                for (i = 0; i < numParams; i++)
                {
-                       Oid             ptype = paramTypes[i];
+                       Oid                     ptype = paramTypes[i];
 
                        if (ptype == InvalidOid || ptype == UNKNOWNOID)
-                               elog(ERROR, "Could not determine datatype of parameter $%d",
-                                        i + 1);
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_INDETERMINATE_DATATYPE),
+                                 errmsg("could not determine data type of parameter $%d",
+                                                i + 1)));
                        param_list = lappendo(param_list, ptype);
                }
 
@@ -1109,7 +1215,7 @@ exec_parse_message(const char *query_string,      /* string to execute */
        }
        else
        {
-               /* Empty input string.  This is legal. */
+               /* Empty input string.  This is legal. */
                commandTag = NULL;
                querytree_list = NIL;
                plantree_list = NIL;
@@ -1153,9 +1259,10 @@ exec_parse_message(const char *query_string,     /* string to execute */
        QueryContext = NULL;
 
        /*
-        * We do NOT close the open transaction command here; that only happens
-        * when the client sends Sync.  Instead, do CommandCounterIncrement just
-        * in case something happened during parse/plan.
+        * We do NOT close the open transaction command here; that only
+        * happens when the client sends Sync.  Instead, do
+        * CommandCounterIncrement just in case something happened during
+        * parse/plan.
         */
        CommandCounterIncrement();
 
@@ -1196,9 +1303,9 @@ exec_bind_message(StringInfo input_message)
        set_ps_display("BIND");
 
        /*
-        * Start up a transaction command so we can call functions etc.
-        * (Note that this will normally change current memory context.)
-        * Nothing happens if we are already in one.
+        * Start up a transaction command so we can call functions etc. (Note
+        * that this will normally change current memory context.) Nothing
+        * happens if we are already in one.
         */
        start_xact_command();
 
@@ -1222,8 +1329,10 @@ exec_bind_message(StringInfo input_message)
        numParams = pq_getmsgint(input_message, 2);
 
        if (numPFormats > 1 && numPFormats != numParams)
-               elog(ERROR, "BIND message has %d parameter formats but %d parameters",
-                        numPFormats, numParams);
+               ereport(ERROR,
+                               (errcode(ERRCODE_PROTOCOL_VIOLATION),
+               errmsg("bind message has %d parameter formats but %d parameters",
+                          numPFormats, numParams)));
 
        /* Find prepared statement */
        if (stmt_name[0] != '\0')
@@ -1233,12 +1342,16 @@ exec_bind_message(StringInfo input_message)
                /* special-case the unnamed statement */
                pstmt = unnamed_stmt_pstmt;
                if (!pstmt)
-                       elog(ERROR, "Unnamed prepared statement does not exist");
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_UNDEFINED_PSTATEMENT),
+                                  errmsg("unnamed prepared statement does not exist")));
        }
 
        if (numParams != length(pstmt->argtype_list))
-               elog(ERROR, "Bind message supplies %d parameters, but prepared statement \"%s\" requires %d",
-                        numParams, stmt_name, length(pstmt->argtype_list));
+               ereport(ERROR,
+                               (errcode(ERRCODE_PROTOCOL_VIOLATION),
+                                errmsg("bind message supplies %d parameters, but prepared statement \"%s\" requires %d",
+                                       numParams, stmt_name, length(pstmt->argtype_list))));
 
        /*
         * Create the portal.  Allow silent replacement of an existing portal
@@ -1259,19 +1372,16 @@ exec_bind_message(StringInfo input_message)
        /*
         * Fetch parameters, if any, and store in the portal's memory context.
         *
-        * In an aborted transaction, we can't risk calling user-defined functions,
-        * but we can't fail to Bind either, so bind all parameters to null values.
+        * In an aborted transaction, we can't risk calling user-defined
+        * functions, but we can't fail to Bind either, so bind all parameters
+        * to null values.
         */
        if (numParams > 0)
        {
-               bool    isaborted = IsAbortedTransactionBlockState();
-               StringInfoData pbuf;
-               List   *l;
+               bool            isaborted = IsAbortedTransactionBlockState();
+               List       *l;
                MemoryContext oldContext;
 
-               /* Note that the string buffer lives in MessageContext */
-               initStringInfo(&pbuf);
-
                oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
 
                params = (ParamListInfo)
@@ -1289,14 +1399,7 @@ exec_bind_message(StringInfo input_message)
 
                        if (!isNull)
                        {
-                               /* Reset pbuf to empty, and insert raw data into it */
-                               pbuf.len = 0;
-                               pbuf.data[0] = '\0';
-                               pbuf.cursor = 0;
-
-                               appendBinaryStringInfo(&pbuf,
-                                                                          pq_getmsgbytes(input_message, plength),
-                                                                          plength);
+                               const char *pvalue = pq_getmsgbytes(input_message, plength);
 
                                if (isaborted)
                                {
@@ -1305,14 +1408,33 @@ exec_bind_message(StringInfo input_message)
                                }
                                else
                                {
-                                       int16   pformat;
+                                       int16           pformat;
+                                       StringInfoData pbuf;
+                                       char            csave;
 
                                        if (numPFormats > 1)
                                                pformat = pformats[i];
                                        else if (numPFormats > 0)
                                                pformat = pformats[0];
                                        else
-                                               pformat = 0;            /* default = text */
+                                               pformat = 0;    /* default = text */
+
+                                       /*
+                                        * Rather than copying data around, we just set up a
+                                        * phony StringInfo pointing to the correct portion of
+                                        * the message buffer.  We assume we can scribble on
+                                        * the message buffer so as to maintain the convention
+                                        * that StringInfos have a trailing null.  This is
+                                        * grotty but is a big win when dealing with very
+                                        * large parameter strings.
+                                        */
+                                       pbuf.data = (char *) pvalue;
+                                       pbuf.maxlen = plength + 1;
+                                       pbuf.len = plength;
+                                       pbuf.cursor = 0;
+
+                                       csave = pbuf.data[plength];
+                                       pbuf.data[plength] = '\0';
 
                                        if (pformat == 0)
                                        {
@@ -1321,12 +1443,10 @@ exec_bind_message(StringInfo input_message)
                                                char       *pstring;
 
                                                getTypeInputInfo(ptype, &typInput, &typElem);
+
                                                /*
-                                                * Since stringinfo.c keeps a trailing null in
-                                                * place even for binary data, the contents of
-                                                * pbuf are a valid C string.  We have to do
-                                                * encoding conversion before calling the typinput
-                                                * routine, though.
+                                                * We have to do encoding conversion before
+                                                * calling the typinput routine.
                                                 */
                                                pstring = (char *)
                                                        pg_client_to_server((unsigned char *) pbuf.data,
@@ -1342,13 +1462,37 @@ exec_bind_message(StringInfo input_message)
                                        }
                                        else if (pformat == 1)
                                        {
-                                               /* XXX something similar to above */
-                                               elog(ERROR, "Binary BIND not implemented yet");
+                                               Oid                     typReceive;
+                                               Oid                     typElem;
+
+                                               /*
+                                                * Call the parameter type's binary input
+                                                * converter
+                                                */
+                                               getTypeBinaryInputInfo(ptype, &typReceive, &typElem);
+
+                                               params[i].value =
+                                                       OidFunctionCall2(typReceive,
+                                                                                        PointerGetDatum(&pbuf),
+                                                                                        ObjectIdGetDatum(typElem));
+
+                                               /* Trouble if it didn't eat the whole buffer */
+                                               if (pbuf.cursor != pbuf.len)
+                                                       ereport(ERROR,
+                                                                       (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+                                                                        errmsg("incorrect binary data format in bind parameter %d",
+                                                                                       i + 1)));
                                        }
                                        else
                                        {
-                                               elog(ERROR, "Invalid format code %d", pformat);
+                                               ereport(ERROR,
+                                                               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                                                                errmsg("unsupported format code: %d",
+                                                                               pformat)));
                                        }
+
+                                       /* Restore message buffer contents */
+                                       pbuf.data[plength] = csave;
                                }
                        }
 
@@ -1402,7 +1546,7 @@ exec_bind_message(StringInfo input_message)
 static void
 exec_execute_message(const char *portal_name, long max_rows)
 {
-       CommandDest     dest;
+       CommandDest dest;
        DestReceiver *receiver;
        Portal          portal;
        bool            is_trans_stmt = false;
@@ -1417,10 +1561,13 @@ exec_execute_message(const char *portal_name, long max_rows)
 
        portal = GetPortalByName(portal_name);
        if (!PortalIsValid(portal))
-               elog(ERROR, "Portal \"%s\" not found", portal_name);
+               ereport(ERROR,
+                               (errcode(ERRCODE_UNDEFINED_CURSOR),
+                                errmsg("portal \"%s\" does not exist", portal_name)));
 
        /*
-        * If the original query was a null string, just return EmptyQueryResponse.
+        * If the original query was a null string, just return
+        * EmptyQueryResponse.
         */
        if (portal->commandTag == NULL)
        {
@@ -1447,7 +1594,7 @@ exec_execute_message(const char *portal_name, long max_rows)
        /* Check for transaction-control commands */
        if (length(portal->parseTrees) == 1)
        {
-               Query *query = (Query *) lfirst(portal->parseTrees);
+               Query      *query = (Query *) lfirst(portal->parseTrees);
 
                if (query->commandType == CMD_UTILITY &&
                        query->utilityStmt != NULL &&
@@ -1463,14 +1610,15 @@ exec_execute_message(const char *portal_name, long max_rows)
        }
 
        /*
-        * Create dest receiver in MessageContext (we don't want it in transaction
-        * context, because that may get deleted if portal contains VACUUM).
+        * Create dest receiver in MessageContext (we don't want it in
+        * transaction context, because that may get deleted if portal
+        * contains VACUUM).
         */
        receiver = CreateDestReceiver(dest, portal);
 
        /*
-        * Ensure we are in a transaction command (this should normally be
-        * the case already due to prior BIND).
+        * Ensure we are in a transaction command (this should normally be the
+        * case already due to prior BIND).
         */
        start_xact_command();
 
@@ -1481,8 +1629,10 @@ exec_execute_message(const char *portal_name, long max_rows)
        if (IsAbortedTransactionBlockState())
        {
                if (!is_trans_exit)
-                       elog(ERROR, "current transaction is aborted, "
-                                "queries ignored until end of transaction block");
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),
+                                        errmsg("current transaction is aborted, "
+                                        "commands ignored until end of transaction block")));
        }
 
        /* Check for cancel signal before we start execution */
@@ -1500,23 +1650,24 @@ exec_execute_message(const char *portal_name, long max_rows)
                                                  receiver,
                                                  completionTag);
 
-       (*receiver->destroy) (receiver);
+       (*receiver->rDestroy) (receiver);
 
        if (completed)
        {
                if (is_trans_stmt)
                {
                        /*
-                        * If this was a transaction control statement, commit it.  We will
-                        * start a new xact command for the next command (if any).
+                        * If this was a transaction control statement, commit it.      We
+                        * will start a new xact command for the next command (if
+                        * any).
                         */
-                       finish_xact_command(true);
+                       finish_xact_command();
                }
                else
                {
                        /*
-                        * We need a CommandCounterIncrement after every query,
-                        * except those that start or end a transaction block.
+                        * We need a CommandCounterIncrement after every query, except
+                        * those that start or end a transaction block.
                         */
                        CommandCounterIncrement();
                }
@@ -1555,7 +1706,9 @@ exec_describe_statement_message(const char *stmt_name)
                /* special-case the unnamed statement */
                pstmt = unnamed_stmt_pstmt;
                if (!pstmt)
-                       elog(ERROR, "Unnamed prepared statement does not exist");
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_UNDEFINED_PSTATEMENT),
+                                  errmsg("unnamed prepared statement does not exist")));
        }
 
        if (whereToSendOutput != Remote)
@@ -1564,7 +1717,7 @@ exec_describe_statement_message(const char *stmt_name)
        /*
         * First describe the parameters...
         */
-       pq_beginmessage(&buf, 't');             /* parameter description message type */
+       pq_beginmessage(&buf, 't'); /* parameter description message type */
        pq_sendint(&buf, length(pstmt->argtype_list), 2);
 
        foreach(l, pstmt->argtype_list)
@@ -1581,7 +1734,7 @@ exec_describe_statement_message(const char *stmt_name)
        tupdesc = FetchPreparedStatementResultDesc(pstmt);
        if (tupdesc)
        {
-               List   *targetlist;
+               List       *targetlist;
 
                if (ChoosePortalStrategy(pstmt->query_list) == PORTAL_ONE_SELECT)
                        targetlist = ((Query *) lfirst(pstmt->query_list))->targetList;
@@ -1606,14 +1759,16 @@ exec_describe_portal_message(const char *portal_name)
 
        portal = GetPortalByName(portal_name);
        if (!PortalIsValid(portal))
-               elog(ERROR, "Portal \"%s\" not found", portal_name);
+               ereport(ERROR,
+                               (errcode(ERRCODE_UNDEFINED_CURSOR),
+                                errmsg("portal \"%s\" does not exist", portal_name)));
 
        if (whereToSendOutput != Remote)
                return;                                 /* can't actually do anything... */
 
        if (portal->tupDesc)
        {
-               List   *targetlist;
+               List       *targetlist;
 
                if (portal->strategy == PORTAL_ONE_SELECT)
                        targetlist = ((Query *) lfirst(portal->parseTrees))->targetList;
@@ -1635,8 +1790,9 @@ start_xact_command(void)
 {
        if (!xact_started)
        {
-               elog(DEBUG2, "StartTransactionCommand");
-               StartTransactionCommand(false);
+               ereport(DEBUG3,
+                               (errmsg_internal("StartTransactionCommand")));
+               StartTransactionCommand();
 
                /* Set statement timeout running, if any */
                if (StatementTimeout > 0)
@@ -1647,7 +1803,7 @@ start_xact_command(void)
 }
 
 static void
-finish_xact_command(bool forceCommit)
+finish_xact_command(void)
 {
        if (xact_started)
        {
@@ -1658,12 +1814,19 @@ finish_xact_command(bool forceCommit)
                disable_sig_alarm(true);
 
                /* Now commit the command */
-               elog(DEBUG2, "CommitTransactionCommand");
+               ereport(DEBUG3,
+                               (errmsg_internal("CommitTransactionCommand")));
+
+               CommitTransactionCommand();
 
-               CommitTransactionCommand(forceCommit);
+#ifdef MEMORY_CONTEXT_CHECKING
+               /* Check all memory contexts that weren't freed during commit */
+               /* (those that were, were checked before being deleted) */
+               MemoryContextCheck(TopMemoryContext);
+#endif
 
 #ifdef SHOW_MEMORY_STATS
-               /* Print mem stats at each commit for leak tracking */
+               /* Print mem stats after each commit for leak tracking */
                if (ShowStats)
                        MemoryContextStats(TopMemoryContext);
 #endif
@@ -1688,12 +1851,20 @@ void
 quickdie(SIGNAL_ARGS)
 {
        PG_SETMASK(&BlockSig);
-       elog(WARNING, "Message from PostgreSQL backend:"
-                "\n\tThe Postmaster has informed me that some other backend"
-                "\n\tdied abnormally and possibly corrupted shared memory."
-                "\n\tI have rolled back the current transaction and am"
-          "\n\tgoing to terminate your database system connection and exit."
-       "\n\tPlease reconnect to the database system and repeat your query.");
+
+       /*
+        * Ideally this should be ereport(FATAL), but then we'd not get
+        * control back (perhaps could fix by doing local sigsetjmp?)
+        */
+       ereport(WARNING,
+                       (errcode(ERRCODE_CRASH_SHUTDOWN),
+               errmsg("terminating connection because of crash of another server process"),
+          errdetail("The postmaster has commanded this server process to roll back"
+                                " the current transaction and exit, because another"
+                                " server process exited abnormally and possibly corrupted"
+                                " shared memory."),
+                        errhint("In a moment you should be able to reconnect to the"
+                                        " database and repeat your command.")));
 
        /*
         * DO NOT proc_exit() -- we're here because shared memory may be
@@ -1705,7 +1876,6 @@ quickdie(SIGNAL_ARGS)
         * random backend.      This is necessary precisely because we don't clean
         * up our shared memory state.
         */
-
        exit(1);
 }
 
@@ -1806,9 +1976,12 @@ StatementCancelHandler(SIGNAL_ARGS)
 static void
 FloatExceptionHandler(SIGNAL_ARGS)
 {
-       elog(ERROR, "floating point exception!"
-                " The last floating point operation either exceeded legal ranges"
-                " or was a divide by zero");
+       ereport(ERROR,
+                       (errcode(ERRCODE_FLOATING_POINT_EXCEPTION),
+                        errmsg("floating-point exception"),
+                  errdetail("An invalid floating-point operation was signaled. "
+                                        "This probably means an out-of-range result or an "
+                                        "invalid operation, such as division by zero.")));
 }
 
 /* SIGHUP: set flag to re-read config file at next convenient time */
@@ -1839,50 +2012,113 @@ ProcessInterrupts(void)
                QueryCancelPending = false;             /* ProcDie trumps QueryCancel */
                ImmediateInterruptOK = false;   /* not idle anymore */
                DisableNotifyInterrupt();
-               elog(FATAL, "This connection has been terminated by the administrator.");
+               ereport(FATAL,
+                               (errcode(ERRCODE_ADMIN_SHUTDOWN),
+                errmsg("terminating connection due to administrator command")));
        }
        if (QueryCancelPending)
        {
                QueryCancelPending = false;
                ImmediateInterruptOK = false;   /* not idle anymore */
                DisableNotifyInterrupt();
-               elog(ERROR, "Query was canceled.");
+               ereport(ERROR,
+                               (errcode(ERRCODE_QUERY_CANCELED),
+                                errmsg("canceling query due to user request")));
        }
        /* If we get here, do nothing (probably, QueryCancelPending was reset) */
 }
 
 
+/*
+ * check_stack_depth: check for excessively deep recursion
+ *
+ * This should be called someplace in any recursive routine that might possibly
+ * recurse deep enough to overflow the stack.  Most Unixen treat stack
+ * overflow as an unrecoverable SIGSEGV, so we want to error out ourselves
+ * before hitting the hardware limit.  Unfortunately we have no direct way
+ * to detect the hardware limit, so we have to rely on the admin to set a
+ * GUC variable for it ...
+ */
+void
+check_stack_depth(void)
+{
+       char    stack_top_loc;
+       int             stack_depth;
+
+       /*
+        * Compute distance from PostgresMain's local variables to my own
+        *
+        * Note: in theory stack_depth should be ptrdiff_t or some such, but
+        * since the whole point of this code is to bound the value to something
+        * much less than integer-sized, int should work fine.
+        */
+       stack_depth = (int) (stack_base_ptr - &stack_top_loc);
+       /*
+        * Take abs value, since stacks grow up on some machines, down on others
+        */
+       if (stack_depth < 0)
+               stack_depth = -stack_depth;
+       /*
+        * Trouble?
+        *
+        * The test on stack_base_ptr prevents us from erroring out if called
+        * during process setup or in a non-backend process.  Logically it should
+        * be done first, but putting it here avoids wasting cycles during normal
+        * cases.
+        */
+       if (stack_depth > max_stack_depth_bytes &&
+               stack_base_ptr != NULL)
+       {
+               ereport(ERROR,
+                               (errcode(ERRCODE_STATEMENT_TOO_COMPLEX),
+                                errmsg("stack depth limit exceeded"),
+                                errhint("Increase the configuration parameter \"max_stack_depth\".")));
+       }
+}
+
+/* GUC assign hook to update max_stack_depth_bytes from max_stack_depth */
+bool
+assign_max_stack_depth(int newval, bool doit, GucSource source)
+{
+       /* Range check was already handled by guc.c */
+       if (doit)
+               max_stack_depth_bytes = newval * 1024;
+       return true;
+}
+
+
 static void
 usage(char *progname)
 {
-       printf("%s is the PostgreSQL stand-alone backend.  It is not\nintended to be used by normal users.\n\n", progname);
+       printf(gettext("%s is the PostgreSQL stand-alone backend.  It is not\nintended to be used by normal users.\n\n"), progname);
 
-       printf("Usage:\n  %s [OPTION]... [DBNAME]\n\n", progname);
-       printf("Options:\n");
+       printf(gettext("Usage:\n  %s [OPTION]... [DBNAME]\n\n"), progname);
+       printf(gettext("Options:\n"));
 #ifdef USE_ASSERT_CHECKING
-       printf("  -A 1|0          enable/disable run-time assert checking\n");
+       printf(gettext("  -A 1|0          enable/disable run-time assert checking\n"));
 #endif
-       printf("  -B NBUFFERS     number of shared buffers (default %d)\n", DEF_NBUFFERS);
-       printf("  -c NAME=VALUE   set run-time parameter\n");
-       printf("  -d 0-5          debugging level (0 is off)\n");
-       printf("  -D DATADIR      database directory\n");
-       printf("  -e              use European date format\n");
-       printf("  -E              echo query before execution\n");
-       printf("  -F              turn fsync off\n");
-       printf("  -N              do not use newline as interactive query delimiter\n");
-       printf("  -o FILENAME     send stdout and stderr to given file\n");
-       printf("  -P              disable system indexes\n");
-       printf("  -s              show statistics after each query\n");
-       printf("  -S SORT-MEM     set amount of memory for sorts (in kbytes)\n");
-       printf("  --help          show this help, then exit\n");
-       printf("  --version       output version information, then exit\n");
-       printf("\nDeveloper options:\n");
-       printf("  -f s|i|n|m|h    forbid use of some plan types\n");
-       printf("  -i              do not execute queries\n");
-       printf("  -O              allow system table structure changes\n");
-       printf("  -t pa|pl|ex     show timings after each query\n");
-       printf("  -W NUM          wait NUM seconds to allow attach from a debugger\n");
-       printf("\nReport bugs to <pgsql-bugs@postgresql.org>.\n");
+       printf(gettext("  -B NBUFFERS     number of shared buffers\n"));
+       printf(gettext("  -c NAME=VALUE   set run-time parameter\n"));
+       printf(gettext("  -d 0-5          debugging level (0 is off)\n"));
+       printf(gettext("  -D DATADIR      database directory\n"));
+       printf(gettext("  -e              use European date input format (DMY)\n"));
+       printf(gettext("  -E              echo query before execution\n"));
+       printf(gettext("  -F              turn fsync off\n"));
+       printf(gettext("  -N              do not use newline as interactive query delimiter\n"));
+       printf(gettext("  -o FILENAME     send stdout and stderr to given file\n"));
+       printf(gettext("  -P              disable system indexes\n"));
+       printf(gettext("  -s              show statistics after each query\n"));
+       printf(gettext("  -S WORK-MEM     set amount of memory for sorts (in kbytes)\n"));
+       printf(gettext("  --describe-config  describe configuration parameters, then exit\n"));
+       printf(gettext("  --help          show this help, then exit\n"));
+       printf(gettext("  --version       output version information, then exit\n"));
+       printf(gettext("\nDeveloper options:\n"));
+       printf(gettext("  -f s|i|n|m|h    forbid use of some plan types\n"));
+       printf(gettext("  -i              do not execute queries\n"));
+       printf(gettext("  -O              allow system table structure changes\n"));
+       printf(gettext("  -t pa|pl|ex     show timings after each query\n"));
+       printf(gettext("  -W NUM          wait NUM seconds to allow attach from a debugger\n"));
+       printf(gettext("\nReport bugs to <pgsql-bugs@postgresql.org>.\n"));
 }
 
 
@@ -1906,12 +2142,14 @@ PostgresMain(int argc, char *argv[], const char *username)
        bool            secure;
        int                     errs = 0;
        int                     debug_flag = 0;
-       GucContext      ctx;
+       GucContext      ctx,
+                               debug_context;
        GucSource       gucsource;
        char       *tmp;
        int                     firstchar;
-       StringInfo      input_message;
-       bool            send_rfq;
+       char            stack_base;
+       StringInfoData  input_message;
+       volatile bool send_rfq = true;
 
        /*
         * Catch standard options before doing much else.  This even works on
@@ -1935,7 +2173,6 @@ PostgresMain(int argc, char *argv[], const char *username)
         * initialize globals (already done if under postmaster, but not if
         * standalone; cheap enough to do over)
         */
-
        MyProcPid = getpid();
 
        /*
@@ -1950,13 +2187,15 @@ PostgresMain(int argc, char *argv[], const char *username)
 
        SetProcessingMode(InitProcessing);
 
+       /* Set up reference point for stack depth checking */
+       stack_base_ptr = &stack_base;
+
        /*
         * Set default values for command-line options.
         */
-       Noversion = false;
        EchoQuery = false;
 
-       if (!IsUnderPostmaster /* when exec || ExecBackend*/)
+       if (!IsUnderPostmaster)
        {
                InitializeGUCOptions();
                potential_DataDir = getenv("PGDATA");
@@ -1981,17 +2220,19 @@ PostgresMain(int argc, char *argv[], const char *username)
 
        /* all options are allowed until '-p' */
        secure = true;
-       ctx = PGC_POSTMASTER;
+       ctx = debug_context = PGC_POSTMASTER;
        gucsource = PGC_S_ARGV;         /* initial switches came from command line */
 
-       while ((flag = getopt(argc, argv, "A:B:c:CD:d:Eef:FiNOPo:p:S:st:v:W:x:-:")) != -1)
+       while ((flag = getopt(argc, argv, "A:B:c:D:d:Eef:FiNOPo:p:S:st:v:W:x:-:")) != -1)
                switch (flag)
                {
                        case 'A':
 #ifdef USE_ASSERT_CHECKING
                                SetConfigOption("debug_assertions", optarg, ctx, gucsource);
 #else
-                               elog(WARNING, "Assert checking is not compiled in");
+                               ereport(WARNING,
+                                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                                errmsg("assert checking is not compiled in")));
 #endif
                                break;
 
@@ -2003,14 +2244,6 @@ PostgresMain(int argc, char *argv[], const char *username)
                                SetConfigOption("shared_buffers", optarg, ctx, gucsource);
                                break;
 
-                       case 'C':
-
-                               /*
-                                * don't print version string
-                                */
-                               Noversion = true;
-                               break;
-
                        case 'D':                       /* PGDATA directory */
                                if (secure)
                                        potential_DataDir = optarg;
@@ -2018,25 +2251,38 @@ PostgresMain(int argc, char *argv[], const char *username)
 
                        case 'd':                       /* debug level */
                                {
-                                       debug_flag = atoi(optarg);
-                                       /* Set server debugging level. */
-                                       if (atoi(optarg) != 0)
+                                       /*
+                                        * Client option can't decrease debug level. We have
+                                        * to do the test here because we group priv and
+                                        * client set GUC calls below, after we know the final
+                                        * debug value.
+                                        */
+                                       if (ctx != PGC_BACKEND || atoi(optarg) > debug_flag)
                                        {
-                                               char       *debugstr = palloc(strlen("debug") + strlen(optarg) + 1);
-
-                                               sprintf(debugstr, "debug%s", optarg);
-                                               SetConfigOption("log_min_messages", debugstr, ctx, gucsource);
-                                               pfree(debugstr);
+                                               debug_flag = atoi(optarg);
+                                               debug_context = ctx;    /* save context for use
+                                                                                                * below */
+                                               /* Set server debugging level. */
+                                               if (debug_flag != 0)
+                                               {
+                                                       char       *debugstr = palloc(strlen("debug") + strlen(optarg) + 1);
+
+                                                       sprintf(debugstr, "debug%s", optarg);
+                                                       SetConfigOption("log_min_messages", debugstr, ctx, gucsource);
+                                                       pfree(debugstr);
+
+                                               }
+                                               else
 
+                                                       /*
+                                                        * -d0 allows user to prevent postmaster debug
+                                                        * from propagating to backend.  It would be
+                                                        * nice to set it to the postgresql.conf value
+                                                        * here.
+                                                        */
+                                                       SetConfigOption("log_min_messages", "notice",
+                                                                                       ctx, gucsource);
                                        }
-                                       else
-                                               /*
-                                                * -d0 allows user to prevent postmaster debug
-                                                * from propagating to backend.  It would be nice
-                                                * to set it to the postgresql.conf value here.
-                                                */
-                                               SetConfigOption("log_min_messages", "notice",
-                                                                               ctx, gucsource);
                                }
                                break;
 
@@ -2051,7 +2297,7 @@ PostgresMain(int argc, char *argv[], const char *username)
                        case 'e':
 
                                /*
-                                * Use european date formats.
+                                * Use European date input format (DMY)
                                 */
                                SetConfigOption("datestyle", "euro", ctx, gucsource);
                                break;
@@ -2118,9 +2364,12 @@ PostgresMain(int argc, char *argv[], const char *username)
 
                                /*
                                 * ignore system indexes
+                                *
+                                * As of PG 7.4 this is safe to allow from the client,
+                                * since it only disables reading the system indexes,
+                                * not writing them.  Worst case consequence is slowness.
                                 */
-                               if (secure)             /* XXX safe to allow from client??? */
-                                       IgnoreSystemIndexes(true);
+                               IgnoreSystemIndexes(true);
                                break;
 
                        case 'o':
@@ -2133,28 +2382,14 @@ PostgresMain(int argc, char *argv[], const char *username)
                                break;
 
                        case 'p':
-
                                /*
                                 * p - special flag passed if backend was forked by a
                                 * postmaster.
                                 */
                                if (secure)
                                {
-#ifdef EXEC_BACKEND
-                                       char *p;
-                                       int     i;
-                                       int PMcanAcceptConnections;     /* will eventually be global or static, when fork */
-                                       
-                                       sscanf(optarg, "%d,%d,%d,%p,", &MyProcPort->sock, &PMcanAcceptConnections,
-                                                                       &UsedShmemSegID, &UsedShmemSegAddr);
-                                       /* Grab dbname as last param */
-                                       for (i = 0, p = optarg-1; i < 4 && p; i++)
-                                               p = strchr(p+1, ',');
-                                       if (i == 4 && p)
-                                               dbname = strdup(p+1);
-#else
                                        dbname = strdup(optarg);
-#endif
+
                                        secure = false;         /* subsequent switches are NOT
                                                                                 * secure */
                                        ctx = PGC_BACKEND;
@@ -2167,7 +2402,7 @@ PostgresMain(int argc, char *argv[], const char *username)
                                /*
                                 * S - amount of sort memory to use in 1k bytes
                                 */
-                               SetConfigOption("sort_mem", optarg, ctx, gucsource);
+                               SetConfigOption("work_mem", optarg, ctx, gucsource);
                                break;
 
                        case 's':
@@ -2175,7 +2410,7 @@ PostgresMain(int argc, char *argv[], const char *username)
                                /*
                                 * s - report usage statistics (timings) after each query
                                 */
-                               SetConfigOption("show_statement_stats", "true", ctx, gucsource);
+                               SetConfigOption("log_statement_stats", "true", ctx, gucsource);
                                break;
 
                        case 't':
@@ -2201,7 +2436,7 @@ PostgresMain(int argc, char *argv[], const char *username)
                                                        errs++;
                                                break;
                                        case 'e':
-                                               tmp = "show_executor_stats";
+                                               tmp = "log_executor_stats";
                                                break;
                                        default:
                                                errs++;
@@ -2221,7 +2456,7 @@ PostgresMain(int argc, char *argv[], const char *username)
                                /*
                                 * wait N seconds to allow attach from a debugger
                                 */
-                               sleep(atoi(optarg));
+                               pg_usleep(atoi(optarg)*1000000L);
                                break;
 
                        case 'x':
@@ -2267,9 +2502,15 @@ PostgresMain(int argc, char *argv[], const char *username)
                                        if (!value)
                                        {
                                                if (flag == '-')
-                                                       elog(ERROR, "--%s requires argument", optarg);
+                                                       ereport(ERROR,
+                                                                       (errcode(ERRCODE_SYNTAX_ERROR),
+                                                                        errmsg("--%s requires a value",
+                                                                                       optarg)));
                                                else
-                                                       elog(ERROR, "-c %s requires argument", optarg);
+                                                       ereport(ERROR,
+                                                                       (errcode(ERRCODE_SYNTAX_ERROR),
+                                                                        errmsg("-c %s requires a value",
+                                                                                       optarg)));
                                        }
 
                                        SetConfigOption(name, value, ctx, gucsource);
@@ -2286,27 +2527,30 @@ PostgresMain(int argc, char *argv[], const char *username)
 
 
        /*
-        * -d is not the same as setting
-        * log_min_messages because it enables other
-        * output options.
+        * -d is not the same as setting log_min_messages because it enables
+        * other output options.
         */
        if (debug_flag >= 1)
-               SetConfigOption("log_connections", "true", ctx, gucsource);
+       {
+               SetConfigOption("log_connections", "true", debug_context, gucsource);
+               SetConfigOption("log_disconnections", "true", debug_context, gucsource);
+       }
        if (debug_flag >= 2)
-               SetConfigOption("log_statement", "true", ctx, gucsource);
+               SetConfigOption("log_statement", "all", debug_context, gucsource);
        if (debug_flag >= 3)
-               SetConfigOption("debug_print_parse", "true", ctx, gucsource);
+               SetConfigOption("debug_print_parse", "true", debug_context, gucsource);
        if (debug_flag >= 4)
-               SetConfigOption("debug_print_plan", "true", ctx, gucsource);
+               SetConfigOption("debug_print_plan", "true", debug_context, gucsource);
        if (debug_flag >= 5)
-               SetConfigOption("debug_print_rewritten", "true", ctx, gucsource);
+               SetConfigOption("debug_print_rewritten", "true", debug_context, gucsource);
 
        /*
-        * Process any additional GUC variable settings passed in startup packet.
+        * Process any additional GUC variable settings passed in startup
+        * packet.
         */
        if (MyProcPort != NULL)
        {
-               List   *gucopts = MyProcPort->guc_options;
+               List       *gucopts = MyProcPort->guc_options;
 
                while (gucopts)
                {
@@ -2319,6 +2563,12 @@ PostgresMain(int argc, char *argv[], const char *username)
                        gucopts = lnext(gucopts);
                        SetConfigOption(name, value, PGC_BACKEND, PGC_S_CLIENT);
                }
+
+               /*
+                * set up handler to log session end.
+                */
+               if (IsUnderPostmaster && Log_disconnections)
+                       on_proc_exit(log_disconnections,0);
        }
 
        /*
@@ -2327,18 +2577,21 @@ PostgresMain(int argc, char *argv[], const char *username)
        if (log_statement_stats &&
                (log_parser_stats || log_planner_stats || log_executor_stats))
        {
-               elog(WARNING, "Query statistics are disabled because parser, planner, or executor statistics are on.");
-               SetConfigOption("show_statement_stats", "false", ctx, gucsource);
+               ereport(WARNING,
+                               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                                errmsg("statement-level statistics are disabled because parser, planner, or executor statistics are on")));
+               SetConfigOption("log_statement_stats", "false", ctx, gucsource);
        }
 
-       if (!IsUnderPostmaster)
+       if (!IsUnderPostmaster || ExecBackend)
        {
                if (!potential_DataDir)
                {
-                       fprintf(stderr, "%s does not know where to find the database system "
-                          "data.  You must specify the directory that contains the "
-                               "database system either by specifying the -D invocation "
-                        "option or by setting the PGDATA environment variable.\n\n",
+                       fprintf(stderr,
+                                       gettext("%s does not know where to find the database system data.\n"
+                                                       "You must specify the directory that contains the database system\n"
+                                                       "either by specifying the -D invocation option or by setting the\n"
+                                                       "PGDATA environment variable.\n"),
                                        argv[0]);
                        proc_exit(1);
                }
@@ -2346,9 +2599,14 @@ PostgresMain(int argc, char *argv[], const char *username)
        }
        Assert(DataDir);
 
+       /* Acquire configuration parameters */
+       if (IsUnderPostmaster)
+       {
 #ifdef EXEC_BACKEND
-       read_nondefault_variables();
+               read_nondefault_variables();
 #endif
+       } else
+               ProcessConfigFile(PGC_POSTMASTER);
 
        /*
         * Set up signal handlers and masks.
@@ -2364,12 +2622,11 @@ PostgresMain(int argc, char *argv[], const char *username)
         * course, this isn't an issue for signals that are locally generated,
         * such as SIGALRM and SIGPIPE.)
         */
-
        pqsignal(SIGHUP, SigHupHandler);        /* set flag to read config file */
        pqsignal(SIGINT, StatementCancelHandler);       /* cancel current query */
        pqsignal(SIGTERM, die);         /* cancel current query and exit */
        pqsignal(SIGQUIT, quickdie);    /* hard crash time */
-       pqsignal(SIGALRM, handle_sig_alarm);    /* timeout conditions */
+       pqsignal(SIGALRM, handle_sig_alarm);            /* timeout conditions */
 
        /*
         * Ignore failure to write to frontend. Note: if frontend closes
@@ -2407,32 +2664,35 @@ PostgresMain(int argc, char *argv[], const char *username)
                /* noninteractive case: nothing should be left after switches */
                if (errs || argc != optind || dbname == NULL)
                {
-                       elog(WARNING, "%s: invalid command line arguments\nTry -? for help.",
-                                argv[0]);
-                       proc_exit(0);           /* not 1, that causes system-wide
-                                                                * restart... */
+                       ereport(FATAL,
+                                       (errcode(ERRCODE_SYNTAX_ERROR),
+                                        errmsg("invalid command-line arguments for server process"),
+                                        errhint("Try \"%s --help\" for more information.", argv[0])));
                }
+
+               XLOGPathInit();
+
                BaseInit();
-#ifdef EXECBACKEND
-               AttachSharedMemoryAndSemaphores();
-#endif
        }
        else
        {
                /* interactive case: database name can be last arg on command line */
                if (errs || argc - optind > 1)
                {
-                       elog(WARNING, "%s: invalid command line arguments\nTry -? for help.",
-                                argv[0]);
-                       proc_exit(1);
+                       ereport(FATAL,
+                                       (errcode(ERRCODE_SYNTAX_ERROR),
+                                        errmsg("%s: invalid command-line arguments",
+                                                       argv[0]),
+                                        errhint("Try \"%s --help\" for more information.", argv[0])));
                }
                else if (argc - optind == 1)
                        dbname = argv[optind];
                else if ((dbname = username) == NULL)
                {
-                       elog(WARNING, "%s: user name undefined and no database specified",
-                                argv[0]);
-                       proc_exit(1);
+                       ereport(FATAL,
+                                       (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                                        errmsg("%s: no database nor user name specified",
+                                                       argv[0])));
                }
 
                /*
@@ -2440,8 +2700,9 @@ PostgresMain(int argc, char *argv[], const char *username)
                 * pathname.  (If under postmaster, this was done already.)
                 */
                if (FindExec(pg_pathname, argv[0], "postgres") < 0)
-                       elog(FATAL, "%s: could not locate executable, bailing out...",
-                                argv[0]);
+                       ereport(FATAL,
+                                       (errmsg("%s: could not locate postgres executable",
+                                                       argv[0])));
 
                /*
                 * Validate we have been given a reasonable-looking DataDir (if
@@ -2452,8 +2713,7 @@ PostgresMain(int argc, char *argv[], const char *username)
                /*
                 * Create lockfile for data directory.
                 */
-               if (!CreateDataDirLockFile(DataDir, false))
-                       proc_exit(1);
+               CreateDataDirLockFile(DataDir, false);
 
                XLOGPathInit();
                BaseInit();
@@ -2473,14 +2733,6 @@ PostgresMain(int argc, char *argv[], const char *username)
                on_shmem_exit(DumpFreeSpaceMap, 0);
        }
 
-       /*
-        * Set up additional info.
-        */
-
-#ifdef CYR_RECODE
-       SetCharSet();
-#endif
-
        /*
         * General initialization.
         *
@@ -2488,7 +2740,8 @@ PostgresMain(int argc, char *argv[], const char *username)
         * putting it inside InitPostgres() instead.  In particular, anything
         * that involves database access should be there, not here.
         */
-       elog(DEBUG2, "InitPostgres");
+       ereport(DEBUG3,
+                       (errmsg_internal("InitPostgres")));
        InitPostgres(dbname, username);
 
        SetProcessingMode(NormalProcessing);
@@ -2508,11 +2761,9 @@ PostgresMain(int argc, char *argv[], const char *username)
                /* Need not flush since ReadyForQuery will do it. */
        }
 
-       if (!IsUnderPostmaster)
-       {
-               puts("\nPOSTGRES backend interactive interface ");
-               puts("$Revision: 1.341 $ $Date: 2003/05/09 15:57:24 $\n");
-       }
+       /* Welcome banner for standalone case */
+       if (whereToSendOutput == Debug)
+               printf("\nPostgreSQL stand-alone backend %s\n", PG_VERSION);
 
        /*
         * Create the memory context we will use in the main loop.
@@ -2549,15 +2800,15 @@ PostgresMain(int argc, char *argv[], const char *username)
                 *
                 * Make sure we're not interrupted while cleaning up.  Also forget
                 * any pending QueryCancel request, since we're aborting anyway.
-                * Force InterruptHoldoffCount to a known state in case we elog'd
-                * from inside a holdoff section.
+                * Force InterruptHoldoffCount to a known state in case we
+                * ereport'd from inside a holdoff section.
                 */
                ImmediateInterruptOK = false;
                QueryCancelPending = false;
                InterruptHoldoffCount = 1;
                CritSectionCount = 0;   /* should be unnecessary, but... */
                disable_sig_alarm(true);
-               QueryCancelPending = false;     /* again in case timeout occurred */
+               QueryCancelPending = false;             /* again in case timeout occurred */
                DisableNotifyInterrupt();
                debug_query_string = NULL;
 
@@ -2570,7 +2821,8 @@ PostgresMain(int argc, char *argv[], const char *username)
                MemoryContextSwitchTo(ErrorContext);
 
                /* Do the recovery */
-               elog(DEBUG1, "AbortCurrentTransaction");
+               ereport(DEBUG2,
+                               (errmsg_internal("AbortCurrentTransaction")));
                AbortCurrentTransaction();
 
                /*
@@ -2579,6 +2831,7 @@ PostgresMain(int argc, char *argv[], const char *username)
                 */
                MemoryContextSwitchTo(TopMemoryContext);
                MemoryContextResetAndDeleteChildren(ErrorContext);
+               ActivePortal = NULL;
                PortalContext = NULL;
                QueryContext = NULL;
 
@@ -2589,9 +2842,15 @@ PostgresMain(int argc, char *argv[], const char *username)
                InError = false;
                xact_started = false;
 
+               /*
+                * Clear flag that causes accounting for cost based vacuum.
+                */
+               VacuumCostActive = false;
+
                /*
                 * If we were handling an extended-query-protocol message,
-                * initiate skip till next Sync.
+                * initiate skip till next Sync.  This also causes us not to issue
+                * ReadyForQuery (until we get Sync).
                 */
                if (doing_extended_query_message)
                        ignore_till_sync = true;
@@ -2602,11 +2861,12 @@ PostgresMain(int argc, char *argv[], const char *username)
                RESUME_INTERRUPTS();
        }
 
-       Warn_restart_ready = true;      /* we can now handle elog(ERROR) */
+       Warn_restart_ready = true;      /* we can now handle ereport(ERROR) */
 
        PG_SETMASK(&UnBlockSig);
 
-       send_rfq = true;                        /* initially, or after error */
+       if (!ignore_till_sync)
+               send_rfq = true;                /* initially, or after error */
 
        /*
         * Non-error queries loop here.
@@ -2615,8 +2875,8 @@ PostgresMain(int argc, char *argv[], const char *username)
        for (;;)
        {
                /*
-                * At top of loop, reset extended-query-message flag, so that
-                * any errors encountered in "idle" state don't provoke skip.
+                * At top of loop, reset extended-query-message flag, so that any
+                * errors encountered in "idle" state don't provoke skip.
                 */
                doing_extended_query_message = false;
 
@@ -2627,35 +2887,36 @@ PostgresMain(int argc, char *argv[], const char *username)
                MemoryContextSwitchTo(MessageContext);
                MemoryContextResetAndDeleteChildren(MessageContext);
 
-               input_message = makeStringInfo();
+               initStringInfo(&input_message);
 
                /*
-                * (1) tell the frontend we're ready for a new query.
+                * (1) If we've reached idle state, tell the frontend we're ready
+                * for a new query.
                 *
                 * Note: this includes fflush()'ing the last of the prior output.
+                *
+                * This is also a good time to send collected statistics to the
+                * collector, and to update the PS stats display.  We avoid doing
+                * those every time through the message loop because it'd slow down
+                * processing of batched messages.
                 */
                if (send_rfq)
                {
-                       ReadyForQuery(whereToSendOutput);
-                       send_rfq = false;
-               }
+                       pgstat_report_tabstat();
 
-               /* ----------
-                * Tell the statistics collector what we've collected
-                * so far.
-                * ----------
-                */
-               pgstat_report_tabstat();
+                       if (IsTransactionOrTransactionBlock())
+                       {
+                               set_ps_display("idle in transaction");
+                               pgstat_report_activity("<IDLE> in transaction");
+                       }
+                       else
+                       {
+                               set_ps_display("idle");
+                               pgstat_report_activity("<IDLE>");
+                       }
 
-               if (IsTransactionBlock())
-               {
-                       set_ps_display("idle in transaction");
-                       pgstat_report_activity("<IDLE> in transaction");
-               }
-               else
-               {
-                       set_ps_display("idle");
-                       pgstat_report_activity("<IDLE>");
+                       ReadyForQuery(whereToSendOutput);
+                       send_rfq = false;
                }
 
                /*
@@ -2677,7 +2938,10 @@ PostgresMain(int argc, char *argv[], const char *username)
                /*
                 * (3) read a command (loop blocks here)
                 */
-               firstchar = ReadCommand(input_message);
+                if (!in_fatal_exit)
+                       firstchar = ReadCommand(&input_message);
+               else
+                       firstchar = EOF;
 
                /*
                 * (4) disable async signal conditions again.
@@ -2694,13 +2958,18 @@ PostgresMain(int argc, char *argv[], const char *username)
                if (got_SIGHUP)
                {
                        got_SIGHUP = false;
+#ifdef EXEC_BACKEND
+                       read_nondefault_variables();
+#else
                        ProcessConfigFile(PGC_SIGHUP);
+#endif
                }
 
                /*
-                * (6) process the command.  But ignore it if we're skipping till Sync.
+                * (6) process the command.  But ignore it if we're skipping till
+                * Sync.
                 */
-               if (ignore_till_sync)
+               if (ignore_till_sync && firstchar != EOF)
                        continue;
 
                switch (firstchar)
@@ -2709,8 +2978,8 @@ PostgresMain(int argc, char *argv[], const char *username)
                                {
                                        const char *query_string;
 
-                                       query_string = pq_getmsgstring(input_message);
-                                       pq_getmsgend(input_message);
+                                       query_string = pq_getmsgstring(&input_message);
+                                       pq_getmsgend(&input_message);
 
                                        exec_simple_query(query_string);
 
@@ -2725,18 +2994,18 @@ PostgresMain(int argc, char *argv[], const char *username)
                                        int                     numParams;
                                        Oid                *paramTypes = NULL;
 
-                                       stmt_name = pq_getmsgstring(input_message);
-                                       query_string = pq_getmsgstring(input_message);
-                                       numParams = pq_getmsgint(input_message, 2);
+                                       stmt_name = pq_getmsgstring(&input_message);
+                                       query_string = pq_getmsgstring(&input_message);
+                                       numParams = pq_getmsgint(&input_message, 2);
                                        if (numParams > 0)
                                        {
-                                               int             i;
+                                               int                     i;
 
                                                paramTypes = (Oid *) palloc(numParams * sizeof(Oid));
                                                for (i = 0; i < numParams; i++)
-                                                       paramTypes[i] = pq_getmsgint(input_message, 4);
+                                                       paramTypes[i] = pq_getmsgint(&input_message, 4);
                                        }
-                                       pq_getmsgend(input_message);
+                                       pq_getmsgend(&input_message);
 
                                        exec_parse_message(query_string, stmt_name,
                                                                           paramTypes, numParams);
@@ -2744,21 +3013,22 @@ PostgresMain(int argc, char *argv[], const char *username)
                                break;
 
                        case 'B':                       /* bind */
+
                                /*
-                                * this message is complex enough that it seems best to put
-                                * the field extraction out-of-line
+                                * this message is complex enough that it seems best to
+                                * put the field extraction out-of-line
                                 */
-                               exec_bind_message(input_message);
+                               exec_bind_message(&input_message);
                                break;
 
                        case 'E':                       /* execute */
                                {
                                        const char *portal_name;
-                                       int             max_rows;
+                                       int                     max_rows;
 
-                                       portal_name = pq_getmsgstring(input_message);
-                                       max_rows = pq_getmsgint(input_message, 4);
-                                       pq_getmsgend(input_message);
+                                       portal_name = pq_getmsgstring(&input_message);
+                                       max_rows = pq_getmsgint(&input_message, 4);
+                                       pq_getmsgend(&input_message);
 
                                        exec_execute_message(portal_name, max_rows);
                                }
@@ -2771,12 +3041,15 @@ PostgresMain(int argc, char *argv[], const char *username)
                                /* start an xact for this function invocation */
                                start_xact_command();
 
-                               if (HandleFunctionRequest(input_message) == EOF)
+                               /* switch back to message context */
+                               MemoryContextSwitchTo(MessageContext);
+
+                               if (HandleFunctionRequest(&input_message) == EOF)
                                {
                                        /* lost frontend connection during F message input */
 
                                        /*
-                                        * Reset whereToSendOutput to prevent elog from
+                                        * Reset whereToSendOutput to prevent ereport from
                                         * attempting to send any more messages to client.
                                         */
                                        if (whereToSendOutput == Remote)
@@ -2786,19 +3059,19 @@ PostgresMain(int argc, char *argv[], const char *username)
                                }
 
                                /* commit the function-invocation transaction */
-                               finish_xact_command(false);
+                               finish_xact_command();
 
                                send_rfq = true;
                                break;
 
-                       case 'C':                               /* close */
+                       case 'C':                       /* close */
                                {
-                                       int             close_type;
+                                       int                     close_type;
                                        const char *close_target;
 
-                                       close_type = pq_getmsgbyte(input_message);
-                                       close_target = pq_getmsgstring(input_message);
-                                       pq_getmsgend(input_message);
+                                       close_type = pq_getmsgbyte(&input_message);
+                                       close_target = pq_getmsgstring(&input_message);
+                                       pq_getmsgend(&input_message);
 
                                        switch (close_type)
                                        {
@@ -2827,24 +3100,26 @@ PostgresMain(int argc, char *argv[], const char *username)
                                                        }
                                                        break;
                                                default:
-                                                       elog(ERROR, "Invalid Close message subtype %d",
-                                                                close_type);
+                                                       ereport(ERROR,
+                                                                       (errcode(ERRCODE_PROTOCOL_VIOLATION),
+                                                          errmsg("invalid CLOSE message subtype %d",
+                                                                         close_type)));
                                                        break;
                                        }
 
                                        if (whereToSendOutput == Remote)
-                                               pq_putemptymessage('3'); /* CloseComplete */
+                                               pq_putemptymessage('3');                /* CloseComplete */
                                }
                                break;
 
                        case 'D':                       /* describe */
                                {
-                                       int             describe_type;
+                                       int                     describe_type;
                                        const char *describe_target;
 
-                                       describe_type = pq_getmsgbyte(input_message);
-                                       describe_target = pq_getmsgstring(input_message);
-                                       pq_getmsgend(input_message);
+                                       describe_type = pq_getmsgbyte(&input_message);
+                                       describe_target = pq_getmsgstring(&input_message);
+                                       pq_getmsgend(&input_message);
 
                                        switch (describe_type)
                                        {
@@ -2855,22 +3130,24 @@ PostgresMain(int argc, char *argv[], const char *username)
                                                        exec_describe_portal_message(describe_target);
                                                        break;
                                                default:
-                                                       elog(ERROR, "Invalid Describe message subtype %d",
-                                                                describe_type);
+                                                       ereport(ERROR,
+                                                                       (errcode(ERRCODE_PROTOCOL_VIOLATION),
+                                                       errmsg("invalid DESCRIBE message subtype %d",
+                                                                  describe_type)));
                                                        break;
                                        }
                                }
                                break;
 
-                       case 'H':                               /* flush */
-                               pq_getmsgend(input_message);
+                       case 'H':                       /* flush */
+                               pq_getmsgend(&input_message);
                                if (whereToSendOutput == Remote)
                                        pq_flush();
                                break;
 
-                       case 'S':                               /* sync */
-                               pq_getmsgend(input_message);
-                               finish_xact_command(false);
+                       case 'S':                       /* sync */
+                               pq_getmsgend(&input_message);
+                               finish_xact_command();
                                send_rfq = true;
                                break;
 
@@ -2883,8 +3160,8 @@ PostgresMain(int argc, char *argv[], const char *username)
                        case EOF:
 
                                /*
-                                * Reset whereToSendOutput to prevent elog from attempting
-                                * to send any more messages to client.
+                                * Reset whereToSendOutput to prevent ereport from
+                                * attempting to send any more messages to client.
                                 */
                                if (whereToSendOutput == Remote)
                                        whereToSendOutput = None;
@@ -2896,30 +3173,26 @@ PostgresMain(int argc, char *argv[], const char *username)
                                 * Otherwise it will fail to be called during other
                                 * backend-shutdown scenarios.
                                 */
-                               proc_exit(0);
+                               proc_exit(!in_fatal_exit ? 0 : proc_exit_inprogress ||
+                                                                                               !IsUnderPostmaster);
+
+                       case 'd':                       /* copy data */
+                       case 'c':                       /* copy done */
+                       case 'f':                       /* copy fail */
 
-                       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
+                                * 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(FATAL, "Socket command type %c unknown", firstchar);
+                               ereport(FATAL,
+                                               (errcode(ERRCODE_PROTOCOL_VIOLATION),
+                                                errmsg("invalid frontend message type %d",
+                                                               firstchar)));
                }
-
-#ifdef MEMORY_CONTEXT_CHECKING
-
-               /*
-                * Check all memory after each backend loop.  This is a rather
-                * weird place to do it, perhaps.
-                */
-               MemoryContextCheck(TopMemoryContext);
-#endif
        }                                                       /* end of input-reading loop */
 
        /* can't get here because the above loop never exits */
@@ -2934,8 +3207,8 @@ PostgresMain(int argc, char *argv[], const char *username)
 #include <sys/resource.h>
 #endif   /* HAVE_GETRUSAGE */
 
-struct rusage Save_r;
-struct timeval Save_t;
+static struct rusage Save_r;
+static struct timeval Save_t;
 
 void
 ResetUsage(void)
@@ -2992,9 +3265,9 @@ ShowUsage(const char *title)
                                         (long) (elapse_t.tv_sec - Save_t.tv_sec),
                                         (long) (elapse_t.tv_usec - Save_t.tv_usec),
                                         (long) (r.ru_utime.tv_sec - Save_r.ru_utime.tv_sec),
-                                        (long) (r.ru_utime.tv_usec - Save_r.ru_utime.tv_usec),
+                                  (long) (r.ru_utime.tv_usec - Save_r.ru_utime.tv_usec),
                                         (long) (r.ru_stime.tv_sec - Save_r.ru_stime.tv_sec),
-                                        (long) (r.ru_stime.tv_usec - Save_r.ru_stime.tv_usec));
+                                 (long) (r.ru_stime.tv_usec - Save_r.ru_stime.tv_usec));
        appendStringInfo(&str,
                                         "!\t[%ld.%06ld user %ld.%06ld sys total]\n",
                                         (long) user.tv_sec,
@@ -3038,7 +3311,64 @@ ShowUsage(const char *title)
        if (str.data[str.len - 1] == '\n')
                str.data[--str.len] = '\0';
 
-       elog(LOG, "%s\n%s", title, str.data);
+       ereport(LOG,
+                       (errmsg_internal("%s", title),
+                        errdetail("%s", str.data)));
 
        pfree(str.data);
 }
+
+/*
+ * on_proc_exit handler to log end of session
+ */
+static void 
+log_disconnections(int code, Datum arg)
+{
+       Port *port = MyProcPort;
+       struct timeval end;
+       int  hours, minutes, seconds;
+
+       char session_time[20];
+       char uname[6+NAMEDATALEN];
+       char dbname[10+NAMEDATALEN];
+       char remote_host[7 + NI_MAXHOST];
+       char remote_port[7 + NI_MAXSERV];
+      
+       snprintf(uname, sizeof(uname)," user=%s",port->user_name);
+       snprintf(dbname, sizeof(dbname)," database=%s",port->database_name);
+       snprintf(remote_host,sizeof(remote_host)," host=%s",
+                        port->remote_host);
+       snprintf(remote_port,sizeof(remote_port)," port=%s",port->remote_port);
+
+
+       gettimeofday(&end,NULL);
+
+       if (end.tv_usec < port->session_start.tv_usec)
+       {
+               end.tv_sec--;
+               end.tv_usec += 1000000;
+       }
+       end.tv_sec -= port->session_start.tv_sec;
+       end.tv_usec -= port->session_start.tv_usec;
+
+       hours = end.tv_sec / 3600;
+       end.tv_sec %= 3600;
+       minutes = end.tv_sec / 60;
+       seconds = end.tv_sec % 60;
+
+       /* if time has gone backwards for some reason say so, or print time */
+
+       if (end.tv_sec < 0)
+               snprintf(session_time,sizeof(session_time),"negative!");
+       else
+               /* for stricter accuracy here we could round - this is close enough */
+               snprintf(session_time, sizeof(session_time),
+                        "%d:%02d:%02d.%02d",
+                        hours, minutes, seconds, (int) (end.tv_usec/10000));
+      
+       ereport(
+               LOG,
+               (errmsg("disconnection: session time: %s%s%s%s%s",
+                               session_time,uname,dbname,remote_host,remote_port)));
+
+}