> >>1. change the type of "log_statement" option from boolean to string,

> >>with allowed values of "all, mod, ddl, none" with default "none".

OK, here is a patch that implements #1.  Here is sample output:

        test=> set client_min_messages = 'log';
        SET
        test=> set log_statement = 'mod';
        SET
        test=> select 1;
         ?column?
        ----------
                1
        (1 row)

        test=> update test set x=1;
        LOG:  statement: update test set x=1;
        ERROR:  relation "test" does not exist
        test=> update test set x=1;
        LOG:  statement: update test set x=1;
        ERROR:  relation "test" does not exist
        test=> copy test from '/tmp/x';
        LOG:  statement: copy test from '/tmp/x';
        ERROR:  relation "test" does not exist
        test=> copy test to  '/tmp/x';
        ERROR:  relation "test" does not exist
        test=> prepare xx as select 1;
        PREPARE
        test=> prepare xx as update x set y=1;
        LOG:  statement: prepare xx as update x set y=1;
        ERROR:  relation "x" does not exist
        test=> explain analyze select 1;;
                                             QUERY PLAN
        ------------------------------------------------------------------------------------
         Result  (cost=0.00..0.01 rows=1 width=0) (actual time=0.006..0.007 rows=1 loops=1)
         Total runtime: 0.046 ms
        (2 rows)

        test=> explain analyze update test set x=1;
        LOG:  statement: explain analyze update test set x=1;
        ERROR:  relation "test" does not exist
        test=> explain update test set x=1;
        ERROR:  relation "test" does not exist

It checks PREPARE and EXECUTE ANALYZE too.  The log_statement values are
'none', 'mod', 'ddl', and 'all'.  For 'all', it prints before the query
is parsed, and for ddl/mod, it does it right after parsing using the
node tag (or command tag for CREATE/ALTER/DROP), so any non-parse errors
will print after the log line.
This commit is contained in:
Bruce Momjian 2004-04-07 05:05:50 +00:00
parent e5170860ee
commit 6a25c6e1d1
6 changed files with 158 additions and 47 deletions

View File

@ -1,5 +1,5 @@
<!--
$PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.257 2004/04/05 03:02:03 momjian Exp $
$PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.258 2004/04/07 05:05:49 momjian Exp $
-->
<Chapter Id="runtime">
@ -2121,12 +2121,21 @@ SET ENABLE_SEQSCAN TO OFF;
</varlistentry>
<varlistentry id="guc-log-statement" xreflabel="log_statement">
<term><varname>log_statement</varname> (<type>boolean</type>)</term>
<term><varname>log_statement</varname> (<type>string</type>)</term>
<listitem>
<para>
Causes each SQL statement to be logged. The default is
off. Only superusers can disable this option if it has been
enabled by an administrator.
Controls which SQL statement are logged. Valid values are
<literal>all</>, <literal>ddl</>, <literal>mod</>, and
<literal>none</>. <literal>ddl</> logs all data definition
commands like <literal>CREATE</>, <literal>ALTER</>, and
<literal>DROP</> commands. <literal>mod</> logs all
<literal>ddl</> statements, plus <literal>INSERT</>,
<literal>UPDATE</>, <literal>DELETE</>, <literal>TRUNCATE</>,
and <literal>COPY FROM</>. <literal>PREPARE</> and
<literal>EXPLAIN ANALYZE</> statements are also considered for
appropriate commands. The default is <literal>none</>. Only
superusers can reduce the detail of this option if it has been
set by an administrator.
</para>
<note>

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.397 2004/03/24 22:40:29 tgl Exp $
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.398 2004/04/07 05:05:49 momjian Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@ -87,6 +87,8 @@ bool InError = false;
/* flag for logging end of session */
bool Log_disconnections = false;
LogStmtLevel log_statement = LOGSTMT_NONE;
/*
* Flags for expensive function optimization -- JMH 3/9/92
*/
@ -471,9 +473,10 @@ 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)
if (log_statement == LOGSTMT_ALL)
ereport(LOG,
(errmsg("statement: %s", query_string)));
@ -482,6 +485,51 @@ pg_parse_query(const char *query_string)
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");
@ -2488,7 +2536,7 @@ PostgresMain(int argc, char *argv[], const char *username)
SetConfigOption("log_disconnections", "true", debug_context, gucsource);
}
if (debug_flag >= 2)
SetConfigOption("log_statement", "true", debug_context, gucsource);
SetConfigOption("log_statement", "all", debug_context, gucsource);
if (debug_flag >= 3)
SetConfigOption("debug_print_parse", "true", debug_context, gucsource);
if (debug_flag >= 4)

View File

@ -10,7 +10,7 @@
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.197 2004/04/05 03:02:07 momjian Exp $
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.198 2004/04/07 05:05:50 momjian Exp $
*
*--------------------------------------------------------------------
*/
@ -86,18 +86,22 @@ static const char *assign_facility(const char *facility,
bool doit, GucSource source);
#endif
static const char *assign_defaultxactisolevel(const char *newval,
bool doit, GucSource source);
static const char *assign_log_min_messages(const char *newval,
bool doit, GucSource source);
static const char *assign_defaultxactisolevel(const char *newval, bool doit,
GucSource source);
static const char *assign_log_min_messages(const char *newval, bool doit,
GucSource source);
static const char *assign_client_min_messages(const char *newval,
bool doit, GucSource source);
static const char *assign_min_error_statement(const char *newval, bool doit,
GucSource source);
static const char *assign_msglvl(int *var, const char *newval,
bool doit, GucSource source);
static const char *assign_msglvl(int *var, const char *newval, bool doit,
GucSource source);
static const char *assign_log_error_verbosity(const char *newval, bool doit,
GucSource source);
static const char *assign_log_statement(const char *newval, bool doit,
GucSource source);
static const char *assign_log_stmtlvl(int *var, const char *newval,
bool doit, GucSource source);
static bool assign_phony_autocommit(bool newval, bool doit, GucSource source);
@ -107,7 +111,6 @@ static bool assign_phony_autocommit(bool newval, bool doit, GucSource source);
#ifdef USE_ASSERT_CHECKING
bool assert_enabled = true;
#endif
bool log_statement = false;
bool log_duration = false;
bool Debug_print_plan = false;
bool Debug_print_parse = false;
@ -145,6 +148,7 @@ int log_min_duration_statement = -1;
static char *client_min_messages_str;
static char *log_min_messages_str;
static char *log_error_verbosity_str;
static char *log_statement_str;
static char *log_min_error_statement_str;
static char *log_destination_string;
static bool phony_autocommit;
@ -527,14 +531,6 @@ static struct config_bool ConfigureNamesBool[] =
&ExitOnAnyError,
false, NULL, NULL
},
{
{"log_statement", PGC_USERLIMIT, LOGGING_WHAT,
gettext_noop("Logs each SQL statement."),
NULL
},
&log_statement,
false, NULL, NULL
},
{
{"log_duration", PGC_USERLIMIT, LOGGING_WHAT,
gettext_noop("Logs the duration each completed SQL statement."),
@ -1442,6 +1438,14 @@ static struct config_string ConfigureNamesString[] =
&log_error_verbosity_str,
"default", assign_log_error_verbosity, NULL
},
{
{"log_statement", PGC_USERLIMIT, LOGGING_WHAT,
gettext_noop("Sets the type of statements logged."),
gettext_noop("Valid values are \"none\", \"mod\", \"ddl\", and \"all\".")
},
&log_statement_str,
"none", assign_log_statement, NULL
},
{
{"log_min_error_statement", PGC_USERLIMIT, LOGGING_WHEN,
@ -2007,14 +2011,11 @@ InitializeGUCOptions(void)
struct config_string *conf = (struct config_string *) gconf;
char *str;
/*
* Check to make sure we only have valid
* PGC_USERLIMITs
*/
/* Check to make sure we only have valid PGC_USERLIMITs */
Assert(conf->gen.context != PGC_USERLIMIT ||
conf->assign_hook == assign_log_min_messages ||
conf->assign_hook == assign_client_min_messages ||
conf->assign_hook == assign_min_error_statement);
conf->assign_hook == assign_min_error_statement ||
conf->assign_hook == assign_log_statement);
*conf->variable = NULL;
conf->reset_val = NULL;
conf->session_val = NULL;
@ -3025,15 +3026,23 @@ set_config_option(const char *name, const char *value,
if (record->context == PGC_USERLIMIT &&
IsUnderPostmaster && !superuser())
{
int old_int_value,
new_int_value;
int var_value, reset_value, new_value;
const char * (*var_hook) (int *var, const char *newval,
bool doit, GucSource source);
/* all USERLIMIT strings are message levels */
assign_msglvl(&new_int_value, newval,
true, source);
assign_msglvl(&old_int_value, conf->reset_val,
true, source);
if (new_int_value > old_int_value)
if (conf->assign_hook == assign_log_statement)
var_hook = assign_log_stmtlvl;
else
var_hook = assign_msglvl;
(*var_hook) (&new_value, newval, true, source);
(*var_hook) (&reset_value, conf->reset_val, true,
source);
(*var_hook) (&var_value, *conf->variable, true,
source);
/* Limit non-superuser changes */
if (new_value > reset_value)
{
/* Limit non-superuser changes */
if (source > PGC_S_UNPRIVILEGED)
@ -3046,10 +3055,9 @@ set_config_option(const char *name, const char *value,
return false;
}
}
/* Allow change if admin should override */
assign_msglvl(&old_int_value, *conf->variable,
true, source);
if (new_int_value < old_int_value)
if (new_value < var_value)
{
if (source < PGC_S_UNPRIVILEGED &&
record->source > PGC_S_UNPRIVILEGED)
@ -4652,6 +4660,40 @@ assign_log_error_verbosity(const char *newval, bool doit, GucSource source)
return newval; /* OK */
}
static const char *
assign_log_statement(const char *newval, bool doit, GucSource source)
{
return (assign_log_stmtlvl((int *)&log_statement, newval, doit, source));
}
static const char *
assign_log_stmtlvl(int *var, const char *newval, bool doit, GucSource source)
{
if (strcasecmp(newval, "none") == 0)
{
if (doit)
(*var) = LOGSTMT_NONE;
}
else if (strcasecmp(newval, "mod") == 0)
{
if (doit)
(*var) = LOGSTMT_MOD;
}
else if (strcasecmp(newval, "ddl") == 0)
{
if (doit)
(*var) = LOGSTMT_DDL;
}
else if (strcasecmp(newval, "all") == 0)
{
if (doit)
(*var) = LOGSTMT_ALL;
}
else
return NULL; /* fail */
return newval; /* OK */
}
static bool
assign_phony_autocommit(bool newval, bool doit, GucSource source)
{

View File

@ -191,7 +191,7 @@
# %s=session start timestamp
# %x=stop here in non-session processes
# %%='%'
#log_statement = false
#log_statement = 'none' # none, mod, ddl, all
#log_hostname = false

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/tcop/tcopprot.h,v 1.63 2004/03/24 22:40:29 tgl Exp $
* $PostgreSQL: pgsql/src/include/tcop/tcopprot.h,v 1.64 2004/04/07 05:05:50 momjian Exp $
*
* OLD COMMENTS
* This file was created so that other c files could get the two
@ -35,6 +35,19 @@ extern DLLIMPORT const char *debug_query_string;
extern char *rendezvous_name;
extern int max_stack_depth;
/* GUC-configurable parameters */
typedef enum
{
/* Reverse order so GUC USERLIMIT is easier */
LOGSTMT_ALL, /* log all statements */
LOGSTMT_DDL, /* log data definition statements */
LOGSTMT_MOD, /* log modification statements, plus DDL */
LOGSTMT_NONE /* log no statements */
} LogStmtLevel;
extern LogStmtLevel log_statement;
#ifndef BOOTSTRAP_INCLUDE
extern List *pg_parse_and_rewrite(const char *query_string,

View File

@ -7,7 +7,7 @@
* Copyright (c) 2000-2003, PostgreSQL Global Development Group
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
* $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.44 2004/01/19 19:04:40 tgl Exp $
* $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.45 2004/04/07 05:05:50 momjian Exp $
*--------------------------------------------------------------------
*/
#ifndef GUC_H
@ -103,7 +103,6 @@ typedef enum
} GucSource;
/* GUC vars that are actually declared in guc.c, rather than elsewhere */
extern bool log_statement;
extern bool log_duration;
extern bool Debug_print_plan;
extern bool Debug_print_parse;