Commit c0ac38d0 authored by Bruce Momjian's avatar Bruce Momjian

Log queries for client-side prepare/execute. Simon Riggs

Log prepare query during execute.  Bruce Momjian
parent f534820d
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* Copyright (c) 2002-2005, PostgreSQL Global Development Group * Copyright (c) 2002-2005, PostgreSQL Global Development Group
* *
* IDENTIFICATION * 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) ...@@ -104,9 +104,12 @@ PrepareQuery(PrepareStmt *stmt)
/* Generate plans for queries. Snapshot is already set. */ /* Generate plans for queries. Snapshot is already set. */
plan_list = pg_plan_queries(query_list, NULL, false); 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, StorePreparedStatement(stmt->name,
NULL, /* text form not available */ debug_query_string,
commandTag, commandTag,
query_list, query_list,
plan_list, plan_list,
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* this is the "main" module of the postgres backend and * this is the "main" module of the postgres backend and
...@@ -82,9 +82,6 @@ bool Log_disconnections = false; ...@@ -82,9 +82,6 @@ bool Log_disconnections = false;
LogStmtLevel log_statement = LOGSTMT_NONE; 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) */ /* GUC variable for maximum stack depth (measured in kilobytes) */
int max_stack_depth = 2048; int max_stack_depth = 2048;
...@@ -152,6 +149,8 @@ static int UseNewLine = 0; /* Use EOF as query delimiters */ ...@@ -152,6 +149,8 @@ static int UseNewLine = 0; /* Use EOF as query delimiters */
static int InteractiveBackend(StringInfo inBuf); static int InteractiveBackend(StringInfo inBuf);
static int SocketBackend(StringInfo inBuf); static int SocketBackend(StringInfo inBuf);
static int ReadCommand(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 start_xact_command(void);
static void finish_xact_command(void); static void finish_xact_command(void);
static void SigHupHandler(SIGNAL_ARGS); static void SigHupHandler(SIGNAL_ARGS);
...@@ -465,74 +464,94 @@ List * ...@@ -465,74 +464,94 @@ List *
pg_parse_query(const char *query_string) pg_parse_query(const char *query_string)
{ {
List *raw_parsetree_list; 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) if (log_parser_stats)
ResetUsage(); ResetUsage();
raw_parsetree_list = raw_parser(query_string); raw_parsetree_list = raw_parser(query_string);
/* do log_statement tests for mod and ddl */ if (log_parser_stats)
if (log_statement == LOGSTMT_MOD || ShowUsage("PARSER STATISTICS");
log_statement == LOGSTMT_DDL)
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); ExecuteStmt *stmt = (ExecuteStmt *) parsetree;
const char *commandTag; PreparedStatement *entry;
if (IsA(parsetree, ExplainStmt) && if ((entry = FetchPreparedStatement(stmt->name, false)) != NULL &&
((ExplainStmt *) parsetree)->analyze) entry->query_string)
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))
{ {
ereport(LOG, *prepare_string = palloc(strlen(entry->query_string) +
(errmsg("statement: %s", query_string))); strlen(" [client PREPARE: %s]") - 1);
statement_logged = true; sprintf(*prepare_string, " [client PREPARE: %s]",
break; entry->query_string);
} }
} }
} }
if (log_parser_stats) if (log_this_statement)
ShowUsage("PARSER STATISTICS"); {
ereport(LOG,
return raw_parsetree_list; (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 * Given a raw parsetree (gram.y output), and optionally information about
* types of parameter symbols ($n), perform parse analysis and rule rewriting. * types of parameter symbols ($n), perform parse analysis and rule rewriting.
...@@ -735,12 +754,13 @@ exec_simple_query(const char *query_string) ...@@ -735,12 +754,13 @@ exec_simple_query(const char *query_string)
MemoryContext oldcontext; MemoryContext oldcontext;
List *parsetree_list; List *parsetree_list;
ListCell *parsetree_item; ListCell *parsetree_item;
struct timeval start_t, struct timeval start_t, stop_t;
stop_t;
bool save_log_duration = log_duration; bool save_log_duration = log_duration;
int save_log_min_duration_statement = log_min_duration_statement; int save_log_min_duration_statement = log_min_duration_statement;
bool save_log_statement_stats = log_statement_stats; bool save_log_statement_stats = log_statement_stats;
char *prepare_string = NULL;
bool was_logged = false;
/* /*
* Report query to various monitoring facilities. * Report query to various monitoring facilities.
*/ */
...@@ -796,6 +816,10 @@ exec_simple_query(const char *query_string) ...@@ -796,6 +816,10 @@ exec_simple_query(const char *query_string)
*/ */
parsetree_list = pg_parse_query(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. * Switch back to transaction context to enter the loop.
*/ */
...@@ -1011,10 +1035,11 @@ exec_simple_query(const char *query_string) ...@@ -1011,10 +1035,11 @@ exec_simple_query(const char *query_string)
stop_t.tv_sec--; stop_t.tv_sec--;
stop_t.tv_usec += 1000000; 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. */ /* Only print duration if we previously printed the statement. */
if (statement_logged && save_log_duration) if (was_logged && save_log_duration)
ereport(LOG, ereport(LOG,
(errmsg("duration: %ld.%03ld ms", (errmsg("duration: %ld.%03ld ms",
(long) ((stop_t.tv_sec - start_t.tv_sec) * 1000 + (long) ((stop_t.tv_sec - start_t.tv_sec) * 1000 +
...@@ -1029,16 +1054,20 @@ exec_simple_query(const char *query_string) ...@@ -1029,16 +1054,20 @@ exec_simple_query(const char *query_string)
(save_log_min_duration_statement > 0 && (save_log_min_duration_statement > 0 &&
usecs >= save_log_min_duration_statement * 1000)) usecs >= save_log_min_duration_statement * 1000))
ereport(LOG, 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 + (long) ((stop_t.tv_sec - start_t.tv_sec) * 1000 +
(stop_t.tv_usec - start_t.tv_usec) / 1000), (stop_t.tv_usec - start_t.tv_usec) / 1000),
(long) (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) if (save_log_statement_stats)
ShowUsage("QUERY STATISTICS"); ShowUsage("QUERY STATISTICS");
if (prepare_string != NULL)
pfree(prepare_string);
debug_query_string = NULL; debug_query_string = NULL;
} }
...@@ -1074,6 +1103,10 @@ exec_parse_message(const char *query_string, /* string to execute */ ...@@ -1074,6 +1103,10 @@ exec_parse_message(const char *query_string, /* string to execute */
if (save_log_statement_stats) if (save_log_statement_stats)
ResetUsage(); 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. * Start up a transaction command so we can run parse analysis etc.
* (Note that this will normally change current memory context.) * (Note that this will normally change current memory context.)
...@@ -1371,6 +1404,10 @@ exec_bind_message(StringInfo input_message) ...@@ -1371,6 +1404,10 @@ exec_bind_message(StringInfo input_message)
else else
portal = CreatePortal(portal_name, false, false); 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. * 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) ...@@ -1579,6 +1616,10 @@ exec_execute_message(const char *portal_name, long max_rows)
bool is_trans_exit = false; bool is_trans_exit = false;
bool completed; bool completed;
char completionTag[COMPLETION_TAG_BUFSIZE]; 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 */ /* Adjust destination to tell printtup.c what to do */
dest = whereToSendOutput; dest = whereToSendOutput;
...@@ -1615,6 +1656,24 @@ exec_execute_message(const char *portal_name, long max_rows) ...@@ -1615,6 +1656,24 @@ exec_execute_message(const char *portal_name, long max_rows)
set_ps_display(portal->commandTag); 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); BeginCommand(portal->commandTag, dest);
/* Check for transaction-control commands */ /* Check for transaction-control commands */
...@@ -1709,6 +1768,50 @@ exec_execute_message(const char *portal_name, long max_rows) ...@@ -1709,6 +1768,50 @@ exec_execute_message(const char *portal_name, long max_rows)
pq_putemptymessage('s'); 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; debug_query_string = NULL;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment