27
27
#include <sys/socket.h>
28
28
#include <sys/time.h>
29
29
30
+ #ifdef USE_VALGRIND
31
+ #include <valgrind/valgrind.h>
32
+ #endif
33
+
30
34
#include "access/parallel.h"
31
35
#include "access/printtup.h"
32
36
#include "access/xact.h"
@@ -191,6 +195,36 @@ static void enable_statement_timeout(void);
191
195
static void disable_statement_timeout (void );
192
196
193
197
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
+
194
228
/* ----------------------------------------------------------------
195
229
* routines to obtain user input
196
230
* ----------------------------------------------------------------
@@ -2041,6 +2075,8 @@ exec_bind_message(StringInfo input_message)
2041
2075
if (save_log_statement_stats )
2042
2076
ShowUsage ("BIND MESSAGE STATISTICS" );
2043
2077
2078
+ valgrind_report_error_query (debug_query_string );
2079
+
2044
2080
debug_query_string = NULL ;
2045
2081
}
2046
2082
@@ -2292,6 +2328,8 @@ exec_execute_message(const char *portal_name, long max_rows)
2292
2328
if (save_log_statement_stats )
2293
2329
ShowUsage ("EXECUTE MESSAGE STATISTICS" );
2294
2330
2331
+ valgrind_report_error_query (debug_query_string );
2332
+
2295
2333
debug_query_string = NULL ;
2296
2334
}
2297
2335
@@ -4287,6 +4325,12 @@ PostgresMain(const char *dbname, const char *username)
4287
4325
/* Report the error to the client and/or server log */
4288
4326
EmitErrorReport ();
4289
4327
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
+
4290
4334
/*
4291
4335
* Make sure debug_query_string gets reset before we possibly clobber
4292
4336
* the storage it points at.
@@ -4371,6 +4415,13 @@ PostgresMain(const char *dbname, const char *username)
4371
4415
*/
4372
4416
doing_extended_query_message = false;
4373
4417
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
+
4374
4425
/*
4375
4426
* Release storage left over from prior query cycle, and create a new
4376
4427
* query input buffer in the cleared MessageContext.
@@ -4571,6 +4622,8 @@ PostgresMain(const char *dbname, const char *username)
4571
4622
else
4572
4623
exec_simple_query (query_string );
4573
4624
4625
+ valgrind_report_error_query (query_string );
4626
+
4574
4627
send_ready_for_query = true;
4575
4628
}
4576
4629
break ;
@@ -4600,6 +4653,8 @@ PostgresMain(const char *dbname, const char *username)
4600
4653
4601
4654
exec_parse_message (query_string , stmt_name ,
4602
4655
paramTypes , numParams );
4656
+
4657
+ valgrind_report_error_query (query_string );
4603
4658
}
4604
4659
break ;
4605
4660
@@ -4614,6 +4669,8 @@ PostgresMain(const char *dbname, const char *username)
4614
4669
* the field extraction out-of-line
4615
4670
*/
4616
4671
exec_bind_message (& input_message );
4672
+
4673
+ /* exec_bind_message does valgrind_report_error_query */
4617
4674
break ;
4618
4675
4619
4676
case 'E' : /* execute */
@@ -4631,6 +4688,8 @@ PostgresMain(const char *dbname, const char *username)
4631
4688
pq_getmsgend (& input_message );
4632
4689
4633
4690
exec_execute_message (portal_name , max_rows );
4691
+
4692
+ /* exec_execute_message does valgrind_report_error_query */
4634
4693
}
4635
4694
break ;
4636
4695
@@ -4664,6 +4723,8 @@ PostgresMain(const char *dbname, const char *username)
4664
4723
/* commit the function-invocation transaction */
4665
4724
finish_xact_command ();
4666
4725
4726
+ valgrind_report_error_query ("fastpath function call" );
4727
+
4667
4728
send_ready_for_query = true;
4668
4729
break ;
4669
4730
@@ -4708,6 +4769,8 @@ PostgresMain(const char *dbname, const char *username)
4708
4769
4709
4770
if (whereToSendOutput == DestRemote )
4710
4771
pq_putemptymessage ('3' ); /* CloseComplete */
4772
+
4773
+ valgrind_report_error_query ("CLOSE message" );
4711
4774
}
4712
4775
break ;
4713
4776
@@ -4740,6 +4803,8 @@ PostgresMain(const char *dbname, const char *username)
4740
4803
describe_type )));
4741
4804
break ;
4742
4805
}
4806
+
4807
+ valgrind_report_error_query ("DESCRIBE message" );
4743
4808
}
4744
4809
break ;
4745
4810
@@ -4752,6 +4817,7 @@ PostgresMain(const char *dbname, const char *username)
4752
4817
case 'S' : /* sync */
4753
4818
pq_getmsgend (& input_message );
4754
4819
finish_xact_command ();
4820
+ valgrind_report_error_query ("SYNC message" );
4755
4821
send_ready_for_query = true;
4756
4822
break ;
4757
4823
0 commit comments