@@ -113,6 +113,7 @@ static void show_foreignscan_info(ForeignScanState *fsstate, ExplainState *es);
113
113
static void show_eval_params (Bitmapset * bms_params , ExplainState * es );
114
114
static const char * explain_get_index_name (Oid indexId );
115
115
static void show_buffer_usage (ExplainState * es , const BufferUsage * usage );
116
+ static void show_wal_usage (ExplainState * es , const WalUsage * usage );
116
117
static void ExplainIndexScanDetails (Oid indexid , ScanDirection indexorderdir ,
117
118
ExplainState * es );
118
119
static void ExplainScanTarget (Scan * plan , ExplainState * es );
@@ -175,6 +176,8 @@ ExplainQuery(ParseState *pstate, ExplainStmt *stmt,
175
176
es -> costs = defGetBoolean (opt );
176
177
else if (strcmp (opt -> defname , "buffers" ) == 0 )
177
178
es -> buffers = defGetBoolean (opt );
179
+ else if (strcmp (opt -> defname , "wal" ) == 0 )
180
+ es -> wal = defGetBoolean (opt );
178
181
else if (strcmp (opt -> defname , "settings" ) == 0 )
179
182
es -> settings = defGetBoolean (opt );
180
183
else if (strcmp (opt -> defname , "timing" ) == 0 )
@@ -219,6 +222,11 @@ ExplainQuery(ParseState *pstate, ExplainStmt *stmt,
219
222
(errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
220
223
errmsg ("EXPLAIN option BUFFERS requires ANALYZE" )));
221
224
225
+ if (es -> wal && !es -> analyze )
226
+ ereport (ERROR ,
227
+ (errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
228
+ errmsg ("EXPLAIN option WAL requires ANALYZE" )));
229
+
222
230
/* if the timing was not set explicitly, set default value */
223
231
es -> timing = (timing_set ) ? es -> timing : es -> analyze ;
224
232
@@ -506,6 +514,8 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es,
506
514
507
515
if (es -> buffers )
508
516
instrument_option |= INSTRUMENT_BUFFERS ;
517
+ if (es -> wal )
518
+ instrument_option |= INSTRUMENT_WAL ;
509
519
510
520
/*
511
521
* We always collect timing for the entire statement, even when node-level
@@ -1970,12 +1980,14 @@ ExplainNode(PlanState *planstate, List *ancestors,
1970
1980
}
1971
1981
}
1972
1982
1973
- /* Show buffer usage */
1983
+ /* Show buffer/WAL usage */
1974
1984
if (es -> buffers && planstate -> instrument )
1975
1985
show_buffer_usage (es , & planstate -> instrument -> bufusage );
1986
+ if (es -> wal && planstate -> instrument )
1987
+ show_wal_usage (es , & planstate -> instrument -> walusage );
1976
1988
1977
- /* Prepare per-worker buffer usage */
1978
- if (es -> workers_state && es -> buffers && es -> verbose )
1989
+ /* Prepare per-worker buffer/WAL usage */
1990
+ if (es -> workers_state && ( es -> buffers || es -> wal ) && es -> verbose )
1979
1991
{
1980
1992
WorkerInstrumentation * w = planstate -> worker_instrument ;
1981
1993
@@ -1988,7 +2000,10 @@ ExplainNode(PlanState *planstate, List *ancestors,
1988
2000
continue ;
1989
2001
1990
2002
ExplainOpenWorker (n , es );
1991
- show_buffer_usage (es , & instrument -> bufusage );
2003
+ if (es -> buffers )
2004
+ show_buffer_usage (es , & instrument -> bufusage );
2005
+ if (es -> wal )
2006
+ show_wal_usage (es , & instrument -> walusage );
1992
2007
ExplainCloseWorker (n , es );
1993
2008
}
1994
2009
}
@@ -3087,6 +3102,44 @@ show_buffer_usage(ExplainState *es, const BufferUsage *usage)
3087
3102
}
3088
3103
}
3089
3104
3105
+ /*
3106
+ * Show WAL usage details.
3107
+ */
3108
+ static void
3109
+ show_wal_usage (ExplainState * es , const WalUsage * usage )
3110
+ {
3111
+ if (es -> format == EXPLAIN_FORMAT_TEXT )
3112
+ {
3113
+ /* Show only positive counter values. */
3114
+ if ((usage -> wal_records > 0 ) || (usage -> wal_num_fpw > 0 ) ||
3115
+ (usage -> wal_bytes > 0 ))
3116
+ {
3117
+ ExplainIndentText (es );
3118
+ appendStringInfoString (es -> str , "WAL:" );
3119
+
3120
+ if (usage -> wal_records > 0 )
3121
+ appendStringInfo (es -> str , " records=%ld" ,
3122
+ usage -> wal_records );
3123
+ if (usage -> wal_num_fpw > 0 )
3124
+ appendStringInfo (es -> str , " full page writes=%ld" ,
3125
+ usage -> wal_num_fpw );
3126
+ if (usage -> wal_bytes > 0 )
3127
+ appendStringInfo (es -> str , " bytes=" UINT64_FORMAT ,
3128
+ usage -> wal_bytes );
3129
+ appendStringInfoChar (es -> str , '\n' );
3130
+ }
3131
+ }
3132
+ else
3133
+ {
3134
+ ExplainPropertyInteger ("WAL records" , NULL ,
3135
+ usage -> wal_records , es );
3136
+ ExplainPropertyInteger ("WAL full page writes" , NULL ,
3137
+ usage -> wal_num_fpw , es );
3138
+ ExplainPropertyUInteger ("WAL bytes" , NULL ,
3139
+ usage -> wal_bytes , es );
3140
+ }
3141
+ }
3142
+
3090
3143
/*
3091
3144
* Add some additional details about an IndexScan or IndexOnlyScan
3092
3145
*/
@@ -3871,6 +3924,19 @@ ExplainPropertyInteger(const char *qlabel, const char *unit, int64 value,
3871
3924
ExplainProperty (qlabel , unit , buf , true, es );
3872
3925
}
3873
3926
3927
+ /*
3928
+ * Explain an unsigned integer-valued property.
3929
+ */
3930
+ void
3931
+ ExplainPropertyUInteger (const char * qlabel , const char * unit , uint64 value ,
3932
+ ExplainState * es )
3933
+ {
3934
+ char buf [32 ];
3935
+
3936
+ snprintf (buf , sizeof (buf ), UINT64_FORMAT , value );
3937
+ ExplainProperty (qlabel , unit , buf , true, es );
3938
+ }
3939
+
3874
3940
/*
3875
3941
* Explain a float-valued property, using the specified number of
3876
3942
* fractional digits.
0 commit comments