Andrew Dunstan wrote:
> >>Here are some options:
> >>
> >>1. change the type of "log_statement" option from boolean to string, 
> >>with allowed values of "all, mod, ddl, none" with default "none".
> >>2. same as 1. but make boolean true values synonyms for "all" and 
> >>boolean false values synonyms for "none".
> >>3. keep "log_statement" option as now and add a new option 
> >>"log_statement_level" with the same options as 1. but default to "all", 
> >>which will have no effect unless "log_statement" is true.
> >>    
> >>
> >
> >I like 1.

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.

-- 
  Bruce Momjian                        |  http://candle.pha.pa.us
  [EMAIL PROTECTED]               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073
Index: doc/src/sgml/runtime.sgml
===================================================================
RCS file: /cvsroot/pgsql-server/doc/src/sgml/runtime.sgml,v
retrieving revision 1.257
diff -c -c -r1.257 runtime.sgml
*** doc/src/sgml/runtime.sgml   5 Apr 2004 03:02:03 -0000       1.257
--- doc/src/sgml/runtime.sgml   6 Apr 2004 03:56:08 -0000
***************
*** 2121,2132 ****
       </varlistentry>
  
       <varlistentry id="guc-log-statement" xreflabel="log_statement">
!       <term><varname>log_statement</varname> (<type>boolean</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.
         </para>
  
         <note>
--- 2121,2141 ----
       </varlistentry>
  
       <varlistentry id="guc-log-statement" xreflabel="log_statement">
!       <term><varname>log_statement</varname> (<type>string</type>)</term>
        <listitem>
         <para>
!         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>
Index: src/backend/tcop/postgres.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/tcop/postgres.c,v
retrieving revision 1.397
diff -c -c -r1.397 postgres.c
*** src/backend/tcop/postgres.c 24 Mar 2004 22:40:29 -0000      1.397
--- src/backend/tcop/postgres.c 6 Apr 2004 03:56:11 -0000
***************
*** 87,92 ****
--- 87,94 ----
  /* 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,479 ****
  List *
  pg_parse_query(const char *query_string)
  {
!       List       *raw_parsetree_list;
  
!       if (log_statement)
                ereport(LOG,
                                (errmsg("statement: %s", query_string)));
  
--- 473,482 ----
  List *
  pg_parse_query(const char *query_string)
  {
!       List       *raw_parsetree_list,
!                          *parsetree_item;
  
!       if (log_statement == LOGSTMT_ALL)
                ereport(LOG,
                                (errmsg("statement: %s", query_string)));
  
***************
*** 482,487 ****
--- 485,535 ----
  
        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,2494 ****
                SetConfigOption("log_disconnections", "true", debug_context, 
gucsource);
        }
        if (debug_flag >= 2)
!               SetConfigOption("log_statement", "true", debug_context, gucsource);
        if (debug_flag >= 3)
                SetConfigOption("debug_print_parse", "true", debug_context, gucsource);
        if (debug_flag >= 4)
--- 2536,2542 ----
                SetConfigOption("log_disconnections", "true", debug_context, 
gucsource);
        }
        if (debug_flag >= 2)
!               SetConfigOption("log_statement", "all", debug_context, gucsource);
        if (debug_flag >= 3)
                SetConfigOption("debug_print_parse", "true", debug_context, gucsource);
        if (debug_flag >= 4)
Index: src/backend/utils/misc/guc.c
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/utils/misc/guc.c,v
retrieving revision 1.197
diff -c -c -r1.197 guc.c
*** src/backend/utils/misc/guc.c        5 Apr 2004 03:02:07 -0000       1.197
--- src/backend/utils/misc/guc.c        6 Apr 2004 03:56:14 -0000
***************
*** 86,103 ****
                                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_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_log_error_verbosity(const char *newval, bool doit,
                                                   GucSource source);
  static bool assign_phony_autocommit(bool newval, bool doit, GucSource source);
  
  
--- 86,107 ----
                                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_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_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,113 ****
  #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;
--- 111,116 ----
***************
*** 145,150 ****
--- 148,154 ----
  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;
***************
*** 528,541 ****
                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."),
                        NULL
--- 532,537 ----
***************
*** 1442,1447 ****
--- 1438,1451 ----
                &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,2020 ****
                                        struct config_string *conf = (struct 
config_string *) gconf;
                                        char       *str;
  
!                                       /*
!                                        * 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->variable = NULL;
                                        conf->reset_val = NULL;
                                        conf->session_val = NULL;
--- 2011,2021 ----
                                        struct config_string *conf = (struct 
config_string *) gconf;
                                        char       *str;
  
!                                       /* 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_min_error_statement ||
!                                                  conf->assign_hook == 
assign_log_statement);
                                        *conf->variable = NULL;
                                        conf->reset_val = NULL;
                                        conf->session_val = NULL;
***************
*** 3025,3039 ****
                                        if (record->context == PGC_USERLIMIT &&
                                                IsUnderPostmaster && !superuser())
                                        {
!                                               int                     old_int_value,
!                                                                       new_int_value;
  
!                                               /* 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)
                                                {
                                                        /* Limit non-superuser changes 
*/
                                                        if (source > 
PGC_S_UNPRIVILEGED)
--- 3026,3048 ----
                                        if (record->context == PGC_USERLIMIT &&
                                                IsUnderPostmaster && !superuser())
                                        {
!                                               int             var_value, 
reset_value, new_value;
!                                               const char * (*var_hook) (int *var, 
const char *newval,
!                                                                       bool doit, 
GucSource source);
!     
!                                               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,3055 ****
                                                                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 (source < 
PGC_S_UNPRIVILEGED &&
                                                                record->source > 
PGC_S_UNPRIVILEGED)
--- 3055,3063 ----
                                                                return false;
                                                        }
                                                }
! 
!                                               /* Allow change if admin should 
override */
!                                               if (new_value < var_value)
                                                {
                                                        if (source < 
PGC_S_UNPRIVILEGED &&
                                                                record->source > 
PGC_S_UNPRIVILEGED)
***************
*** 4646,4651 ****
--- 4654,4693 ----
        {
                if (doit)
                        Log_error_verbosity = PGERROR_VERBOSE;
+       }
+       else
+               return NULL;                    /* fail */
+       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 */
Index: src/backend/utils/misc/postgresql.conf.sample
===================================================================
RCS file: /cvsroot/pgsql-server/src/backend/utils/misc/postgresql.conf.sample,v
retrieving revision 1.112
diff -c -c -r1.112 postgresql.conf.sample
*** src/backend/utils/misc/postgresql.conf.sample       5 Apr 2004 03:02:08 -0000      
 1.112
--- src/backend/utils/misc/postgresql.conf.sample       6 Apr 2004 03:56:14 -0000
***************
*** 191,197 ****
                                # %s=session start timestamp
                                # %x=stop here in non-session processes
                                # %%='%'
! #log_statement = false
  #log_hostname = false
  
  
--- 191,197 ----
                                # %s=session start timestamp
                                # %x=stop here in non-session processes
                                # %%='%'
! #log_statement = 'none'               # none, mod, ddl, all
  #log_hostname = false
  
  
Index: src/include/tcop/tcopprot.h
===================================================================
RCS file: /cvsroot/pgsql-server/src/include/tcop/tcopprot.h,v
retrieving revision 1.63
diff -c -c -r1.63 tcopprot.h
*** src/include/tcop/tcopprot.h 24 Mar 2004 22:40:29 -0000      1.63
--- src/include/tcop/tcopprot.h 6 Apr 2004 03:56:14 -0000
***************
*** 35,40 ****
--- 35,53 ----
  extern char *rendezvous_name;
  extern int    max_stack_depth;
  
+ /* GUC-configurable parameters */
+ 
+ typedef enum
+ {
+       /* Reverse order so GUC USERLIMIT is easier */
+       LOGSTMT_ALL = 0,                        /* log all statements, can not be -1 */
+       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,
Index: src/include/utils/guc.h
===================================================================
RCS file: /cvsroot/pgsql-server/src/include/utils/guc.h,v
retrieving revision 1.44
diff -c -c -r1.44 guc.h
*** src/include/utils/guc.h     19 Jan 2004 19:04:40 -0000      1.44
--- src/include/utils/guc.h     6 Apr 2004 03:56:15 -0000
***************
*** 103,109 ****
  } 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;
--- 103,108 ----
---------------------------(end of broadcast)---------------------------
TIP 7: don't forget to increase your free space map settings

Reply via email to