Re: Exec statement logging - Mailing list pgsql-patches

From Bruce Momjian
Subject Re: Exec statement logging
Date
Msg-id 200505162240.j4GMeer13928@candle.pha.pa.us
Whole thread Raw
In response to Re: Exec statement logging  (Tom Lane <tgl@sss.pgh.pa.us>)
Responses Re: Exec statement logging
Re: Exec statement logging
List pgsql-patches
Tom Lane wrote:
> Bruce Momjian <pgman@candle.pha.pa.us> writes:
> > a null for the prepare string.  Also, rather than change the API for
> > pg_parse_query(), I use a global variable that I check after the
> > function call.
>
> This is horribly ugly and will doubtless lead to pfree crashes.  What

Agreed, it needs work.  I modified the patch to use malloc/free so that
you can always free the memory at the top of the function.

> was the point again?

Simon said that the EXECUTE is pretty useless for debugging unless we
show the prepare query.  His patch shows the prepare query for
client-side prepare, but not for server side when using the
PREPARE/EXECUTE commands --- seems we should display it in both cases.

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073
Index: src/backend/commands/prepare.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/commands/prepare.c,v
retrieving revision 1.36
diff -c -c -r1.36 prepare.c
*** src/backend/commands/prepare.c    1 Jan 2005 05:43:06 -0000    1.36
--- src/backend/commands/prepare.c    16 May 2005 22:36:58 -0000
***************
*** 104,112 ****
      /* Generate plans for queries.    Snapshot is already set. */
      plan_list = pg_plan_queries(query_list, NULL, false);

!     /* Save the results. */
      StorePreparedStatement(stmt->name,
!                            NULL,    /* text form not available */
                             commandTag,
                             query_list,
                             plan_list,
--- 104,115 ----
      /* Generate plans for queries.    Snapshot is already set. */
      plan_list = pg_plan_queries(query_list, NULL, false);

!     /*
!      *    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,
!                            debug_query_string,
                             commandTag,
                             query_list,
                             plan_list,
Index: src/backend/tcop/postgres.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/tcop/postgres.c,v
retrieving revision 1.443
diff -c -c -r1.443 postgres.c
*** src/backend/tcop/postgres.c    21 Apr 2005 19:18:13 -0000    1.443
--- src/backend/tcop/postgres.c    16 May 2005 22:37:00 -0000
***************
*** 73,78 ****
--- 73,79 ----
   */
  const char *debug_query_string; /* for pgmonitor and
                                   * log_min_error_statement */
+ char *prepare_string = NULL;        /* used for passing PREPARE source string */

  /* Note: whereToSendOutput is initialized for the bootstrap/standalone case */
  CommandDest whereToSendOutput = Debug;
***************
*** 467,504 ****
      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)
      {
          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) ||
--- 468,527 ----
      List       *raw_parsetree_list;
      ListCell   *parsetree_item;

+     /* reset prepare_string */
+     if (prepare_string != NULL)
+         free(prepare_string);
+     prepare_string = NULL;
+
      statement_logged = false;

      if (log_parser_stats)
          ResetUsage();

      raw_parsetree_list = raw_parser(query_string);

!     if (log_statement == LOGSTMT_ALL ||
!         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 (IsA(parsetree, ExecuteStmt))
+             {
+                 ExecuteStmt *stmt = (ExecuteStmt *) parsetree;
+                 PreparedStatement *entry;

+                 /*
+                  *    For the first EXECUTE we find before printing the
+                  *    statement string, find the client statement that
+                  *    generated the PREPARE.
+                  */
+                 if ((entry = FetchPreparedStatement(stmt->name, false)) != NULL)
+                 {
+                     if (prepare_string == NULL && entry->query_string)
+                     {
+                         /* must use malloc() so it can be unconditionally freed */
+                         prepare_string = malloc(strlen(entry->query_string) +
+                                       strlen("  [client PREPARE:  %s]") - 1);
+                         sprintf(prepare_string, "  [client PREPARE:  %s]",
+                                       entry->query_string);
+                     }
+                 }
+             }
+
              if (log_statement == LOGSTMT_MOD &&
                  (IsA(parsetree, InsertStmt) ||
                   IsA(parsetree, UpdateStmt) ||
***************
*** 508,531 ****
                    ((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,
!                         (errmsg("statement: %s", query_string)));
                  statement_logged = true;
                  break;
              }
          }
      }

      if (log_parser_stats)
          ShowUsage("PARSER STATISTICS");
--- 531,566 ----
                    ((CopyStmt *) parsetree)->is_from)))    /* COPY FROM */
              {
                  ereport(LOG,
!                         (errmsg("statement: %s%s", query_string,
!                                 prepare_string ? prepare_string : "")));
                  statement_logged = true;
                  break;
              }
              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)))
              {
                  ereport(LOG,
!                         (errmsg("statement: %s%s", query_string,
!                                 prepare_string ? prepare_string : "")));
                  statement_logged = true;
                  break;
              }
          }
      }
+
+     if (log_statement == LOGSTMT_ALL)
+     {
+         ereport(LOG,
+                 (errmsg("statement: %s%s", query_string,
+                                 prepare_string ? prepare_string : "")));
+         statement_logged = true;
+     }

      if (log_parser_stats)
          ShowUsage("PARSER STATISTICS");
***************
*** 740,746 ****
      bool        save_log_duration = log_duration;
      int            save_log_min_duration_statement = log_min_duration_statement;
      bool        save_log_statement_stats = log_statement_stats;
!
      /*
       * Report query to various monitoring facilities.
       */
--- 775,782 ----
      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       *my_prepare_string = NULL;
!
      /*
       * Report query to various monitoring facilities.
       */
***************
*** 796,801 ****
--- 832,841 ----
       */
      parsetree_list = pg_parse_query(query_string);

+     /* If EXECUTE generated a PREPARE source, record it for later */
+     if (prepare_string != NULL)
+         my_prepare_string = pstrdup(prepare_string);
+
      /*
       * Switch back to transaction context to enter the loop.
       */
***************
*** 1029,1039 ****
              (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)
--- 1069,1080 ----
              (save_log_min_duration_statement > 0 &&
               usecs >= save_log_min_duration_statement * 1000))
              ereport(LOG,
!                     (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,
!                             prepare_string ? prepare_string : "")));
      }

      if (save_log_statement_stats)

pgsql-patches by date:

Previous
From: Tom Lane
Date:
Subject: Re: Exec statement logging
Next
From: Bruce Momjian
Date:
Subject: Re: Exec statement logging