On Wed, Jul 13, 2005 at 09:52:20AM +0800, Christopher Kings-Lynne wrote:
> The 8.0.2 jdbc driver uses real prepared statements instead of faked 
> ones.  The problem is the new protocol (that the 8.0.2 driver users) has 
> a bug where protocol-prepared queries don't get logged properly.
> I don't know if it's been fixed...

It's not in 8.0.3, but I was having the same problems with DBD::Pg so
I backported some of it and also changed the code so that it listed the
values of the bind parameters, so you get something like

LOG:  statement: SELECT sr.name,sr.seq_region_id, sr.length, 1 FROM seq_region 
sr  WHERE sr.name = $1 AND sr.coord_system_id = $2
LOG:  binding: "dbdpg_2" with 2 parameters
LOG:  bind "dbdpg_2" $1 = "20"
LOG:  bind "dbdpg_2" $2 = "1"
LOG:  statement: EXECUTE   [PREPARE:  SELECT sr.name,sr.seq_region_id, 
sr.length, 1 FROM seq_region sr  WHERE sr.name = $1 AND sr.coord_system_id = $2]
LOG:  duration: 0.164 ms

I've attached a patch in case anyone finds it useful.

    -Mark
*** postgresql-8.0.3/src/backend/tcop/postgres.c        2005-07-13 
09:42:04.997669193 +0100
--- postgresql-8.0.3/src/backend/tcop/postgres.c        2005-07-13 
09:34:24.618195580 +0100
***************
*** 1370,1375 ****
--- 1370,1378 ----
        else
                portal = CreatePortal(portal_name, false, false);
  
+       if (log_statement == LOGSTMT_ALL)
+         ereport(LOG, (errmsg("binding: \"%s\" with %d parameters", stmt_name, 
numParams)));
+ 
        /*
         * Fetch parameters, if any, and store in the portal's memory context.
         *
***************
*** 1428,1433 ****
--- 1431,1439 ----
                                         * grotty but is a big win when dealing 
with very
                                         * large parameter strings.
                                         */
+                                       if (log_statement == LOGSTMT_ALL)
+                                         ereport(LOG, (errmsg("bind \"%s\" $%d 
= \"%s\"", stmt_name, i+1, pvalue)));
+ 
                                        pbuf.data = (char *) pvalue;
                                        pbuf.maxlen = plength + 1;
                                        pbuf.len = plength;
***************
*** 1578,1583 ****
--- 1584,1593 ----
        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;
***************
*** 1614,1619 ****
--- 1624,1647 ----
  
        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 */
***************
*** 1708,1713 ****
--- 1736,1785 ----
                        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;
  }
  
---------------------------(end of broadcast)---------------------------
TIP 9: In versions below 8.0, the planner will ignore your desire to
       choose an index scan if your joining column's datatypes do not
       match

Reply via email to