Log queries for client-side prepare/execute. Simon Riggs
authorBruce Momjian <bruce@momjian.us>
Tue, 24 May 2005 04:18:04 +0000 (04:18 +0000)
committerBruce Momjian <bruce@momjian.us>
Tue, 24 May 2005 04:18:04 +0000 (04:18 +0000)
Log prepare query during execute.  Bruce Momjian

src/backend/commands/prepare.c
src/backend/tcop/postgres.c

index 2a6cbd77f0a169b3de0ce2e8b32f726f46072da2..ada9d534de305fbf16585d235a0282a3fde0c893 100644 (file)
@@ -10,7 +10,7 @@
  * Copyright (c) 2002-2005, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.36 2005/01/01 05:43:06 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.37 2005/05/24 04:18:04 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -104,9 +104,12 @@ PrepareQuery(PrepareStmt *stmt)
        /* Generate plans for queries.  Snapshot is already set. */
        plan_list = pg_plan_queries(query_list, NULL, false);
 
-       /* Save the results. */
+       /*
+        *      Save the results.  We don't have the query string for this PREPARE,
+        *      but we do have the string we got from the client, so use that.
+        */
        StorePreparedStatement(stmt->name,
-                                                  NULL,        /* text form not available */
+                                                  debug_query_string,
                                                   commandTag,
                                                   query_list,
                                                   plan_list,
index 2872d939ca8fe75d6a1ea6d5907f8e8d2d330e17..3c6c6d992ed12e0f41e5b63336b155f0fbde06b7 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.443 2005/04/21 19:18:13 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.444 2005/05/24 04:18:04 momjian Exp $
  *
  * NOTES
  *       this is the "main" module of the postgres backend and
@@ -82,9 +82,6 @@ bool          Log_disconnections = false;
 
 LogStmtLevel log_statement = LOGSTMT_NONE;
 
-/* flag indicating if the statement satisfies log_statement */
-bool           statement_logged;
-
 /* GUC variable for maximum stack depth (measured in kilobytes) */
 int                    max_stack_depth = 2048;
 
@@ -152,6 +149,8 @@ static int  UseNewLine = 0;         /* Use EOF as query delimiters */
 static int     InteractiveBackend(StringInfo inBuf);
 static int     SocketBackend(StringInfo inBuf);
 static int     ReadCommand(StringInfo inBuf);
+static bool log_after_parse(List *raw_parsetree_list,
+                               const char *query_string, char **prepare_string);
 static void start_xact_command(void);
 static void finish_xact_command(void);
 static void SigHupHandler(SIGNAL_ARGS);
@@ -465,74 +464,94 @@ List *
 pg_parse_query(const char *query_string)
 {
        List       *raw_parsetree_list;
-       ListCell   *parsetree_item;
-
-       statement_logged = false;
-       if (log_statement == LOGSTMT_ALL)
-       {
-               ereport(LOG,
-                               (errmsg("statement: %s", query_string)));
-               statement_logged = true;
-       }
 
        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)
+       if (log_parser_stats)
+               ShowUsage("PARSER STATISTICS");
+
+       return raw_parsetree_list;
+}
+
+static bool
+log_after_parse(List *raw_parsetree_list, const char *query_string,
+                                  char **prepare_string)
+{
+       ListCell   *parsetree_item;
+       bool            log_this_statement = (log_statement == LOGSTMT_ALL);
+
+       *prepare_string = NULL;
+
+       /*      Check if we need to log the statement, and get prepare_string. */
+       foreach(parsetree_item, raw_parsetree_list)
        {
-               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 */
+                       log_this_statement = true;
+
+               commandTag = CreateCommandTag(parsetree);
+               if ((log_statement == LOGSTMT_MOD ||
+                        log_statement == LOGSTMT_DDL) &&
+                       (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)))
+                       log_this_statement = true;
+
+               /*
+                *      For the first EXECUTE we find, record the client statement
+                *      used by the PREPARE.
+                */
+               if (IsA(parsetree, ExecuteStmt))
                {
-                       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)));
-                               statement_logged = true;
-                               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))
+                       ExecuteStmt *stmt = (ExecuteStmt *) parsetree;
+                       PreparedStatement *entry;
+
+                       if ((entry = FetchPreparedStatement(stmt->name, false)) != NULL &&
+                               entry->query_string)
                        {
-                               ereport(LOG,
-                                               (errmsg("statement: %s", query_string)));
-                               statement_logged = true;
-                               break;
+                               *prepare_string = palloc(strlen(entry->query_string) +
+                                                         strlen("  [client PREPARE:  %s]") - 1);
+                               sprintf(*prepare_string, "  [client PREPARE:  %s]",
+                                                         entry->query_string);
                        }
                }
        }
-
-       if (log_parser_stats)
-               ShowUsage("PARSER STATISTICS");
-
-       return raw_parsetree_list;
+       
+       if (log_this_statement)
+       {
+               ereport(LOG,
+                               (errmsg("statement: %s%s", query_string,
+                                               *prepare_string ? *prepare_string : "")));
+               return true;
+       }
+       else
+               return false;
 }
 
+
 /*
  * Given a raw parsetree (gram.y output), and optionally information about
  * types of parameter symbols ($n), perform parse analysis and rule rewriting.
@@ -735,12 +754,13 @@ exec_simple_query(const char *query_string)
        MemoryContext oldcontext;
        List       *parsetree_list;
        ListCell   *parsetree_item;
-       struct timeval start_t,
-                               stop_t;
+       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;
-
+       char            *prepare_string = NULL;
+       bool            was_logged = false;
+       
        /*
         * Report query to various monitoring facilities.
         */
@@ -796,6 +816,10 @@ exec_simple_query(const char *query_string)
         */
        parsetree_list = pg_parse_query(query_string);
 
+       if (log_statement != LOGSTMT_NONE || save_log_min_duration_statement != -1)
+               was_logged = log_after_parse(parsetree_list, query_string,
+                                                                               &prepare_string);
+
        /*
         * Switch back to transaction context to enter the loop.
         */
@@ -1011,10 +1035,11 @@ exec_simple_query(const char *query_string)
                        stop_t.tv_sec--;
                        stop_t.tv_usec += 1000000;
                }
-               usecs = (long) (stop_t.tv_sec - start_t.tv_sec) * 1000000 + (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);
 
                /* Only print duration if we previously printed the statement. */
-               if (statement_logged && save_log_duration)
+               if (was_logged && save_log_duration)
                        ereport(LOG,
                                        (errmsg("duration: %ld.%03ld ms",
                                                (long) ((stop_t.tv_sec - start_t.tv_sec) * 1000 +
@@ -1029,16 +1054,20 @@ exec_simple_query(const char *query_string)
                        (save_log_min_duration_statement > 0 &&
                         usecs >= save_log_min_duration_statement * 1000))
                        ereport(LOG,
-                                       (errmsg("duration: %ld.%03ld ms  statement: %s",
+                                       (errmsg("duration: %ld.%03ld ms  statement: %s%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)));
+                                                       query_string,
+                                                       prepare_string ? prepare_string : "")));
        }
 
        if (save_log_statement_stats)
                ShowUsage("QUERY STATISTICS");
 
+       if (prepare_string != NULL)
+               pfree(prepare_string);
+
        debug_query_string = NULL;
 }
 
@@ -1074,6 +1103,10 @@ exec_parse_message(const char *query_string,     /* string to execute */
        if (save_log_statement_stats)
                ResetUsage();
 
+       if (log_statement == LOGSTMT_ALL)
+               ereport(LOG,
+                               (errmsg("statement: PREPARE %s AS %s", stmt_name, query_string)));
+
        /*
         * Start up a transaction command so we can run parse analysis etc.
         * (Note that this will normally change current memory context.)
@@ -1371,6 +1404,10 @@ exec_bind_message(StringInfo input_message)
        else
                portal = CreatePortal(portal_name, false, false);
 
+       if (log_statement == LOGSTMT_ALL)
+               ereport(LOG,
+                               (errmsg("statement: <BIND> %s", portal_name)));
+
        /*
         * Fetch parameters, if any, and store in the portal's memory context.
         *
@@ -1579,6 +1616,10 @@ exec_execute_message(const char *portal_name, long max_rows)
        bool            is_trans_exit = false;
        bool            completed;
        char            completionTag[COMPLETION_TAG_BUFSIZE];
+       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;
 
        /* Adjust destination to tell printtup.c what to do */
        dest = whereToSendOutput;
@@ -1615,6 +1656,24 @@ exec_execute_message(const char *portal_name, long max_rows)
 
        set_ps_display(portal->commandTag);
 
+       /*
+        * 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 || save_log_min_duration_statement != -1)
+               gettimeofday(&start_t, NULL);
+
+       if (save_log_statement_stats)
+               ResetUsage();
+
+       if (log_statement == LOGSTMT_ALL)
+               /* We have the portal, so output the source query. */
+               ereport(LOG,
+                               (errmsg("statement: EXECUTE %s  [PREPARE:  %s]", portal_name,
+                                               portal->sourceText ? portal->sourceText : "")));
+
        BeginCommand(portal->commandTag, dest);
 
        /* Check for transaction-control commands */
@@ -1709,6 +1768,50 @@ exec_execute_message(const char *portal_name, long max_rows)
                        pq_putemptymessage('s');
        }
 
+       /*
+        * Combine processing here as we need to calculate the query duration
+        * in both instances.
+        */
+       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;
+               }
+               usecs = (long) (stop_t.tv_sec - start_t.tv_sec) * 1000000 +
+                               (long) (stop_t.tv_usec - start_t.tv_usec);
+
+               /* Only print duration if we previously printed the statement. */
+               if (log_statement == LOGSTMT_ALL && 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: EXECUTE %s  [PREPARE:  %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,
+                                                       portal_name,
+                                                       portal->sourceText ? portal->sourceText : "")));
+       }
+
+       if (save_log_statement_stats)
+               ShowUsage("QUERY STATISTICS");
+
        debug_query_string = NULL;
 }