2727#include <sys/socket.h>
2828#include <sys/time.h>
2929
30+ #ifdef USE_VALGRIND
31+ #include <valgrind/valgrind.h>
32+ #endif
33+
3034#include "access/parallel.h"
3135#include "access/printtup.h"
3236#include "access/xact.h"
@@ -191,6 +195,36 @@ static void enable_statement_timeout(void);
191195static void disable_statement_timeout (void );
192196
193197
198+ /* ----------------------------------------------------------------
199+ * infrastructure for valgrind debugging
200+ * ----------------------------------------------------------------
201+ */
202+ #ifdef USE_VALGRIND
203+ /* This variable should be set at the top of the main loop. */
204+ static unsigned int old_valgrind_error_count ;
205+
206+ /*
207+ * If Valgrind detected any errors since old_valgrind_error_count was updated,
208+ * report the current query as the cause. This should be called at the end
209+ * of message processing.
210+ */
211+ static void
212+ valgrind_report_error_query (const char * query )
213+ {
214+ unsigned int valgrind_error_count = VALGRIND_COUNT_ERRORS ;
215+
216+ if (unlikely (valgrind_error_count != old_valgrind_error_count ) &&
217+ query != NULL )
218+ VALGRIND_PRINTF ("Valgrind detected %u error(s) during execution of \"%s\"\n" ,
219+ valgrind_error_count - old_valgrind_error_count ,
220+ query );
221+ }
222+
223+ #else /* !USE_VALGRIND */
224+ #define valgrind_report_error_query (query ) ((void) 0)
225+ #endif /* USE_VALGRIND */
226+
227+
194228/* ----------------------------------------------------------------
195229 * routines to obtain user input
196230 * ----------------------------------------------------------------
@@ -2041,6 +2075,8 @@ exec_bind_message(StringInfo input_message)
20412075 if (save_log_statement_stats )
20422076 ShowUsage ("BIND MESSAGE STATISTICS" );
20432077
2078+ valgrind_report_error_query (debug_query_string );
2079+
20442080 debug_query_string = NULL ;
20452081}
20462082
@@ -2292,6 +2328,8 @@ exec_execute_message(const char *portal_name, long max_rows)
22922328 if (save_log_statement_stats )
22932329 ShowUsage ("EXECUTE MESSAGE STATISTICS" );
22942330
2331+ valgrind_report_error_query (debug_query_string );
2332+
22952333 debug_query_string = NULL ;
22962334}
22972335
@@ -4287,6 +4325,12 @@ PostgresMain(const char *dbname, const char *username)
42874325 /* Report the error to the client and/or server log */
42884326 EmitErrorReport ();
42894327
4328+ /*
4329+ * If Valgrind noticed something during the erroneous query, print the
4330+ * query string, assuming we have one.
4331+ */
4332+ valgrind_report_error_query (debug_query_string );
4333+
42904334 /*
42914335 * Make sure debug_query_string gets reset before we possibly clobber
42924336 * the storage it points at.
@@ -4371,6 +4415,13 @@ PostgresMain(const char *dbname, const char *username)
43714415 */
43724416 doing_extended_query_message = false;
43734417
4418+ /*
4419+ * For valgrind reporting purposes, the "current query" begins here.
4420+ */
4421+ #ifdef USE_VALGRIND
4422+ old_valgrind_error_count = VALGRIND_COUNT_ERRORS ;
4423+ #endif
4424+
43744425 /*
43754426 * Release storage left over from prior query cycle, and create a new
43764427 * query input buffer in the cleared MessageContext.
@@ -4571,6 +4622,8 @@ PostgresMain(const char *dbname, const char *username)
45714622 else
45724623 exec_simple_query (query_string );
45734624
4625+ valgrind_report_error_query (query_string );
4626+
45744627 send_ready_for_query = true;
45754628 }
45764629 break ;
@@ -4600,6 +4653,8 @@ PostgresMain(const char *dbname, const char *username)
46004653
46014654 exec_parse_message (query_string , stmt_name ,
46024655 paramTypes , numParams );
4656+
4657+ valgrind_report_error_query (query_string );
46034658 }
46044659 break ;
46054660
@@ -4614,6 +4669,8 @@ PostgresMain(const char *dbname, const char *username)
46144669 * the field extraction out-of-line
46154670 */
46164671 exec_bind_message (& input_message );
4672+
4673+ /* exec_bind_message does valgrind_report_error_query */
46174674 break ;
46184675
46194676 case 'E' : /* execute */
@@ -4631,6 +4688,8 @@ PostgresMain(const char *dbname, const char *username)
46314688 pq_getmsgend (& input_message );
46324689
46334690 exec_execute_message (portal_name , max_rows );
4691+
4692+ /* exec_execute_message does valgrind_report_error_query */
46344693 }
46354694 break ;
46364695
@@ -4664,6 +4723,8 @@ PostgresMain(const char *dbname, const char *username)
46644723 /* commit the function-invocation transaction */
46654724 finish_xact_command ();
46664725
4726+ valgrind_report_error_query ("fastpath function call" );
4727+
46674728 send_ready_for_query = true;
46684729 break ;
46694730
@@ -4708,6 +4769,8 @@ PostgresMain(const char *dbname, const char *username)
47084769
47094770 if (whereToSendOutput == DestRemote )
47104771 pq_putemptymessage ('3' ); /* CloseComplete */
4772+
4773+ valgrind_report_error_query ("CLOSE message" );
47114774 }
47124775 break ;
47134776
@@ -4740,6 +4803,8 @@ PostgresMain(const char *dbname, const char *username)
47404803 describe_type )));
47414804 break ;
47424805 }
4806+
4807+ valgrind_report_error_query ("DESCRIBE message" );
47434808 }
47444809 break ;
47454810
@@ -4752,6 +4817,7 @@ PostgresMain(const char *dbname, const char *username)
47524817 case 'S' : /* sync */
47534818 pq_getmsgend (& input_message );
47544819 finish_xact_command ();
4820+ valgrind_report_error_query ("SYNC message" );
47554821 send_ready_for_query = true;
47564822 break ;
47574823
0 commit comments