PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
pg_stat_statements.c File Reference
#include "postgres.h"
#include <math.h>
#include <sys/stat.h>
#include <unistd.h>
#include "access/parallel.h"
#include "catalog/pg_authid.h"
#include "common/int.h"
#include "executor/instrument.h"
#include "funcapi.h"
#include "jit/jit.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "nodes/queryjumble.h"
#include "optimizer/planner.h"
#include "parser/analyze.h"
#include "parser/scanner.h"
#include "pgstat.h"
#include "storage/fd.h"
#include "storage/ipc.h"
#include "storage/lwlock.h"
#include "storage/shmem.h"
#include "storage/spin.h"
#include "tcop/utility.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
#include "utils/timestamp.h"
Include dependency graph for pg_stat_statements.c:

Go to the source code of this file.

Data Structures

struct  pgssHashKey
 
struct  Counters
 
struct  pgssGlobalStats
 
struct  pgssEntry
 
struct  pgssSharedState
 

Macros

#define PGSS_DUMP_FILE   PGSTAT_STAT_PERMANENT_DIRECTORY "/pg_stat_statements.stat"
 
#define PGSS_TEXT_FILE   PG_STAT_TMP_DIR "/pgss_query_texts.stat"
 
#define USAGE_EXEC(duration)   (1.0)
 
#define USAGE_INIT   (1.0) /* including initial planning */
 
#define ASSUMED_MEDIAN_INIT   (10.0) /* initial assumed median usage */
 
#define ASSUMED_LENGTH_INIT   1024 /* initial assumed mean query length */
 
#define USAGE_DECREASE_FACTOR   (0.99) /* decreased every entry_dealloc */
 
#define STICKY_DECREASE_FACTOR   (0.50) /* factor for sticky entries */
 
#define USAGE_DEALLOC_PERCENT   5 /* free this % of entries at once */
 
#define IS_STICKY(c)   ((c.calls[PGSS_PLAN] + c.calls[PGSS_EXEC]) == 0)
 
#define PGSS_NUMKIND   (PGSS_EXEC + 1)
 
#define pgss_enabled(level)
 
#define record_gc_qtexts()
 
#define PG_STAT_STATEMENTS_COLS_V1_0   14
 
#define PG_STAT_STATEMENTS_COLS_V1_1   18
 
#define PG_STAT_STATEMENTS_COLS_V1_2   19
 
#define PG_STAT_STATEMENTS_COLS_V1_3   23
 
#define PG_STAT_STATEMENTS_COLS_V1_8   32
 
#define PG_STAT_STATEMENTS_COLS_V1_9   33
 
#define PG_STAT_STATEMENTS_COLS_V1_10   43
 
#define PG_STAT_STATEMENTS_COLS_V1_11   49
 
#define PG_STAT_STATEMENTS_COLS_V1_12   52
 
#define PG_STAT_STATEMENTS_COLS   52 /* maximum of above */
 
#define PG_STAT_STATEMENTS_INFO_COLS   2
 
#define SINGLE_ENTRY_RESET(e)
 

Typedefs

typedef enum pgssVersion pgssVersion
 
typedef enum pgssStoreKind pgssStoreKind
 
typedef struct pgssHashKey pgssHashKey
 
typedef struct Counters Counters
 
typedef struct pgssGlobalStats pgssGlobalStats
 
typedef struct pgssEntry pgssEntry
 
typedef struct pgssSharedState pgssSharedState
 

Enumerations

enum  pgssVersion {
  PGSS_V1_0 = 0 , PGSS_V1_1 , PGSS_V1_2 , PGSS_V1_3 ,
  PGSS_V1_8 , PGSS_V1_9 , PGSS_V1_10 , PGSS_V1_11 ,
  PGSS_V1_12
}
 
enum  pgssStoreKind { PGSS_INVALID = -1 , PGSS_PLAN = 0 , PGSS_EXEC }
 
enum  PGSSTrackLevel { PGSS_TRACK_NONE , PGSS_TRACK_TOP , PGSS_TRACK_ALL }
 

Functions

 PG_MODULE_MAGIC_EXT (.name="pg_stat_statements",.version=PG_VERSION)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_reset)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_reset_1_7)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_reset_1_11)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_1_2)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_1_3)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_1_8)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_1_9)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_1_10)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_1_11)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_1_12)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_info)
 
static void pgss_shmem_request (void)
 
static void pgss_shmem_startup (void)
 
static void pgss_shmem_shutdown (int code, Datum arg)
 
static void pgss_post_parse_analyze (ParseState *pstate, Query *query, JumbleState *jstate)
 
static PlannedStmtpgss_planner (Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams)
 
static bool pgss_ExecutorStart (QueryDesc *queryDesc, int eflags)
 
static void pgss_ExecutorRun (QueryDesc *queryDesc, ScanDirection direction, uint64 count)
 
static void pgss_ExecutorFinish (QueryDesc *queryDesc)
 
static void pgss_ExecutorEnd (QueryDesc *queryDesc)
 
static void pgss_ProcessUtility (PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc)
 
static void pgss_store (const char *query, uint64 queryId, int query_location, int query_len, pgssStoreKind kind, double total_time, uint64 rows, const BufferUsage *bufusage, const WalUsage *walusage, const struct JitInstrumentation *jitusage, JumbleState *jstate, int parallel_workers_to_launch, int parallel_workers_launched)
 
static void pg_stat_statements_internal (FunctionCallInfo fcinfo, pgssVersion api_version, bool showtext)
 
static Size pgss_memsize (void)
 
static pgssEntryentry_alloc (pgssHashKey *key, Size query_offset, int query_len, int encoding, bool sticky)
 
static void entry_dealloc (void)
 
static bool qtext_store (const char *query, int query_len, Size *query_offset, int *gc_count)
 
static char * qtext_load_file (Size *buffer_size)
 
static char * qtext_fetch (Size query_offset, int query_len, char *buffer, Size buffer_size)
 
static bool need_gc_qtexts (void)
 
static void gc_qtexts (void)
 
static TimestampTz entry_reset (Oid userid, Oid dbid, uint64 queryid, bool minmax_only)
 
static char * generate_normalized_query (JumbleState *jstate, const char *query, int query_loc, int *query_len_p)
 
static void fill_in_constant_lengths (JumbleState *jstate, const char *query, int query_loc)
 
static int comp_location (const void *a, const void *b)
 
void _PG_init (void)
 
Datum pg_stat_statements_reset_1_7 (PG_FUNCTION_ARGS)
 
Datum pg_stat_statements_reset_1_11 (PG_FUNCTION_ARGS)
 
Datum pg_stat_statements_reset (PG_FUNCTION_ARGS)
 
Datum pg_stat_statements_1_12 (PG_FUNCTION_ARGS)
 
Datum pg_stat_statements_1_11 (PG_FUNCTION_ARGS)
 
Datum pg_stat_statements_1_10 (PG_FUNCTION_ARGS)
 
Datum pg_stat_statements_1_9 (PG_FUNCTION_ARGS)
 
Datum pg_stat_statements_1_8 (PG_FUNCTION_ARGS)
 
Datum pg_stat_statements_1_3 (PG_FUNCTION_ARGS)
 
Datum pg_stat_statements_1_2 (PG_FUNCTION_ARGS)
 
Datum pg_stat_statements (PG_FUNCTION_ARGS)
 
Datum pg_stat_statements_info (PG_FUNCTION_ARGS)
 
static int entry_cmp (const void *lhs, const void *rhs)
 

Variables

static const uint32 PGSS_FILE_HEADER = 0x20220408
 
static const uint32 PGSS_PG_MAJOR_VERSION = PG_VERSION_NUM / 100
 
static int nesting_level = 0
 
static shmem_request_hook_type prev_shmem_request_hook = NULL
 
static shmem_startup_hook_type prev_shmem_startup_hook = NULL
 
static post_parse_analyze_hook_type prev_post_parse_analyze_hook = NULL
 
static planner_hook_type prev_planner_hook = NULL
 
static ExecutorStart_hook_type prev_ExecutorStart = NULL
 
static ExecutorRun_hook_type prev_ExecutorRun = NULL
 
static ExecutorFinish_hook_type prev_ExecutorFinish = NULL
 
static ExecutorEnd_hook_type prev_ExecutorEnd = NULL
 
static ProcessUtility_hook_type prev_ProcessUtility = NULL
 
static pgssSharedStatepgss = NULL
 
static HTABpgss_hash = NULL
 
static const struct config_enum_entry track_options []
 
static int pgss_max = 5000
 
static int pgss_track = PGSS_TRACK_TOP
 
static bool pgss_track_utility = true
 
static bool pgss_track_planning = false
 
static bool pgss_save = true
 

Macro Definition Documentation

◆ ASSUMED_LENGTH_INIT

#define ASSUMED_LENGTH_INIT   1024 /* initial assumed mean query length */

Definition at line 97 of file pg_stat_statements.c.

◆ ASSUMED_MEDIAN_INIT

#define ASSUMED_MEDIAN_INIT   (10.0) /* initial assumed median usage */

Definition at line 96 of file pg_stat_statements.c.

◆ IS_STICKY

#define IS_STICKY (   c)    ((c.calls[PGSS_PLAN] + c.calls[PGSS_EXEC]) == 0)

Definition at line 101 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS

#define PG_STAT_STATEMENTS_COLS   52 /* maximum of above */

Definition at line 1573 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_0

#define PG_STAT_STATEMENTS_COLS_V1_0   14

Definition at line 1564 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_1

#define PG_STAT_STATEMENTS_COLS_V1_1   18

Definition at line 1565 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_10

#define PG_STAT_STATEMENTS_COLS_V1_10   43

Definition at line 1570 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_11

#define PG_STAT_STATEMENTS_COLS_V1_11   49

Definition at line 1571 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_12

#define PG_STAT_STATEMENTS_COLS_V1_12   52

Definition at line 1572 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_2

#define PG_STAT_STATEMENTS_COLS_V1_2   19

Definition at line 1566 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_3

#define PG_STAT_STATEMENTS_COLS_V1_3   23

Definition at line 1567 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_8

#define PG_STAT_STATEMENTS_COLS_V1_8   32

Definition at line 1568 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_9

#define PG_STAT_STATEMENTS_COLS_V1_9   33

Definition at line 1569 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_INFO_COLS

#define PG_STAT_STATEMENTS_INFO_COLS   2

Definition at line 2021 of file pg_stat_statements.c.

◆ PGSS_DUMP_FILE

#define PGSS_DUMP_FILE   PGSTAT_STAT_PERMANENT_DIRECTORY "/pg_stat_statements.stat"

Definition at line 80 of file pg_stat_statements.c.

◆ pgss_enabled

#define pgss_enabled (   level)
Value:
(pgss_track == PGSS_TRACK_TOP && (level) == 0)))
#define IsParallelWorker()
Definition: parallel.h:60
static int pgss_track
@ PGSS_TRACK_ALL
@ PGSS_TRACK_TOP

Definition at line 302 of file pg_stat_statements.c.

◆ PGSS_NUMKIND

#define PGSS_NUMKIND   (PGSS_EXEC + 1)

Definition at line 132 of file pg_stat_statements.c.

◆ PGSS_TEXT_FILE

#define PGSS_TEXT_FILE   PG_STAT_TMP_DIR "/pgss_query_texts.stat"

Definition at line 85 of file pg_stat_statements.c.

◆ record_gc_qtexts

#define record_gc_qtexts ( )
Value:
do { \
SpinLockAcquire(&pgss->mutex); \
pgss->gc_count++; \
SpinLockRelease(&pgss->mutex); \
} while(0)
static pgssSharedState * pgss

Definition at line 307 of file pg_stat_statements.c.

◆ SINGLE_ENTRY_RESET

#define SINGLE_ENTRY_RESET (   e)
Value:
if (e) { \
if (minmax_only) { \
/* When requested reset only min/max statistics of an entry */ \
for (int kind = 0; kind < PGSS_NUMKIND; kind++) \
{ \
e->counters.max_time[kind] = 0; \
e->counters.min_time[kind] = 0; \
} \
e->minmax_stats_since = stats_reset; \
} \
else \
{ \
/* Remove the key otherwise */ \
hash_search(pgss_hash, &e->key, HASH_REMOVE, NULL); \
num_remove++; \
} \
}
@ HASH_REMOVE
Definition: hsearch.h:115
#define PGSS_NUMKIND
static HTAB * pgss_hash
e
Definition: preproc-init.c:82

Definition at line 2659 of file pg_stat_statements.c.

◆ STICKY_DECREASE_FACTOR

#define STICKY_DECREASE_FACTOR   (0.50) /* factor for sticky entries */

Definition at line 99 of file pg_stat_statements.c.

◆ USAGE_DEALLOC_PERCENT

#define USAGE_DEALLOC_PERCENT   5 /* free this % of entries at once */

Definition at line 100 of file pg_stat_statements.c.

◆ USAGE_DECREASE_FACTOR

#define USAGE_DECREASE_FACTOR   (0.99) /* decreased every entry_dealloc */

Definition at line 98 of file pg_stat_statements.c.

◆ USAGE_EXEC

#define USAGE_EXEC (   duration)    (1.0)

Definition at line 94 of file pg_stat_statements.c.

◆ USAGE_INIT

#define USAGE_INIT   (1.0) /* including initial planning */

Definition at line 95 of file pg_stat_statements.c.

Typedef Documentation

◆ Counters

typedef struct Counters Counters

◆ pgssEntry

typedef struct pgssEntry pgssEntry

◆ pgssGlobalStats

◆ pgssHashKey

typedef struct pgssHashKey pgssHashKey

◆ pgssSharedState

◆ pgssStoreKind

◆ pgssVersion

typedef enum pgssVersion pgssVersion

Enumeration Type Documentation

◆ pgssStoreKind

Enumerator
PGSS_INVALID 
PGSS_PLAN 
PGSS_EXEC 

Definition at line 119 of file pg_stat_statements.c.

120{
121 PGSS_INVALID = -1,
122
123 /*
124 * PGSS_PLAN and PGSS_EXEC must be respectively 0 and 1 as they're used to
125 * reference the underlying values in the arrays in the Counters struct,
126 * and this order is required in pg_stat_statements_internal().
127 */
128 PGSS_PLAN = 0,
129 PGSS_EXEC,
pgssStoreKind
@ PGSS_PLAN
@ PGSS_EXEC
@ PGSS_INVALID

◆ PGSSTrackLevel

Enumerator
PGSS_TRACK_NONE 
PGSS_TRACK_TOP 
PGSS_TRACK_ALL 

Definition at line 280 of file pg_stat_statements.c.

281{
282 PGSS_TRACK_NONE, /* track no statements */
283 PGSS_TRACK_TOP, /* only top level statements */
284 PGSS_TRACK_ALL, /* all statements, including nested ones */
PGSSTrackLevel
@ PGSS_TRACK_NONE

◆ pgssVersion

Enumerator
PGSS_V1_0 
PGSS_V1_1 
PGSS_V1_2 
PGSS_V1_3 
PGSS_V1_8 
PGSS_V1_9 
PGSS_V1_10 
PGSS_V1_11 
PGSS_V1_12 

Definition at line 106 of file pg_stat_statements.c.

107{
108 PGSS_V1_0 = 0,
109 PGSS_V1_1,
110 PGSS_V1_2,
111 PGSS_V1_3,
112 PGSS_V1_8,
113 PGSS_V1_9,
@ PGSS_V1_9
@ PGSS_V1_10
@ PGSS_V1_12
@ PGSS_V1_1
@ PGSS_V1_11
@ PGSS_V1_3
@ PGSS_V1_2
@ PGSS_V1_8
@ PGSS_V1_0

Function Documentation

◆ _PG_init()

void _PG_init ( void  )

Definition at line 385 of file pg_stat_statements.c.

386{
387 /*
388 * In order to create our shared memory area, we have to be loaded via
389 * shared_preload_libraries. If not, fall out without hooking into any of
390 * the main system. (We don't throw error here because it seems useful to
391 * allow the pg_stat_statements functions to be created even when the
392 * module isn't active. The functions must protect themselves against
393 * being called then, however.)
394 */
396 return;
397
398 /*
399 * Inform the postmaster that we want to enable query_id calculation if
400 * compute_query_id is set to auto.
401 */
403
404 /*
405 * Define (or redefine) custom GUC variables.
406 */
407 DefineCustomIntVariable("pg_stat_statements.max",
408 "Sets the maximum number of statements tracked by pg_stat_statements.",
409 NULL,
410 &pgss_max,
411 5000,
412 100,
413 INT_MAX / 2,
415 0,
416 NULL,
417 NULL,
418 NULL);
419
420 DefineCustomEnumVariable("pg_stat_statements.track",
421 "Selects which statements are tracked by pg_stat_statements.",
422 NULL,
423 &pgss_track,
426 PGC_SUSET,
427 0,
428 NULL,
429 NULL,
430 NULL);
431
432 DefineCustomBoolVariable("pg_stat_statements.track_utility",
433 "Selects whether utility commands are tracked by pg_stat_statements.",
434 NULL,
436 true,
437 PGC_SUSET,
438 0,
439 NULL,
440 NULL,
441 NULL);
442
443 DefineCustomBoolVariable("pg_stat_statements.track_planning",
444 "Selects whether planning duration is tracked by pg_stat_statements.",
445 NULL,
447 false,
448 PGC_SUSET,
449 0,
450 NULL,
451 NULL,
452 NULL);
453
454 DefineCustomBoolVariable("pg_stat_statements.save",
455 "Save pg_stat_statements statistics across server shutdowns.",
456 NULL,
457 &pgss_save,
458 true,
460 0,
461 NULL,
462 NULL,
463 NULL);
464
465 MarkGUCPrefixReserved("pg_stat_statements");
466
467 /*
468 * Install hooks.
469 */
488}
ExecutorEnd_hook_type ExecutorEnd_hook
Definition: execMain.c:73
ExecutorFinish_hook_type ExecutorFinish_hook
Definition: execMain.c:72
ExecutorStart_hook_type ExecutorStart_hook
Definition: execMain.c:70
ExecutorRun_hook_type ExecutorRun_hook
Definition: execMain.c:71
void DefineCustomEnumVariable(const char *name, const char *short_desc, const char *long_desc, int *valueAddr, int bootValue, const struct config_enum_entry *options, GucContext context, int flags, GucEnumCheckHook check_hook, GucEnumAssignHook assign_hook, GucShowHook show_hook)
Definition: guc.c:5244
void DefineCustomBoolVariable(const char *name, const char *short_desc, const char *long_desc, bool *valueAddr, bool bootValue, GucContext context, int flags, GucBoolCheckHook check_hook, GucBoolAssignHook assign_hook, GucShowHook show_hook)
Definition: guc.c:5133
void MarkGUCPrefixReserved(const char *className)
Definition: guc.c:5280
void DefineCustomIntVariable(const char *name, const char *short_desc, const char *long_desc, int *valueAddr, int bootValue, int minValue, int maxValue, GucContext context, int flags, GucIntCheckHook check_hook, GucIntAssignHook assign_hook, GucShowHook show_hook)
Definition: guc.c:5159
@ PGC_SUSET
Definition: guc.h:78
@ PGC_POSTMASTER
Definition: guc.h:74
@ PGC_SIGHUP
Definition: guc.h:75
shmem_startup_hook_type shmem_startup_hook
Definition: ipci.c:59
shmem_request_hook_type shmem_request_hook
Definition: miscinit.c:1840
bool process_shared_preload_libraries_in_progress
Definition: miscinit.c:1837
post_parse_analyze_hook_type post_parse_analyze_hook
Definition: analyze.c:59
static planner_hook_type prev_planner_hook
static bool pgss_track_planning
static ExecutorRun_hook_type prev_ExecutorRun
static PlannedStmt * pgss_planner(Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams)
static int pgss_max
static const struct config_enum_entry track_options[]
static void pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc)
static post_parse_analyze_hook_type prev_post_parse_analyze_hook
static shmem_startup_hook_type prev_shmem_startup_hook
static shmem_request_hook_type prev_shmem_request_hook
static void pgss_shmem_request(void)
static bool pgss_save
static void pgss_shmem_startup(void)
static bool pgss_ExecutorStart(QueryDesc *queryDesc, int eflags)
static ExecutorStart_hook_type prev_ExecutorStart
static void pgss_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count)
static void pgss_ExecutorFinish(QueryDesc *queryDesc)
static ProcessUtility_hook_type prev_ProcessUtility
static void pgss_post_parse_analyze(ParseState *pstate, Query *query, JumbleState *jstate)
static bool pgss_track_utility
static ExecutorEnd_hook_type prev_ExecutorEnd
static void pgss_ExecutorEnd(QueryDesc *queryDesc)
static ExecutorFinish_hook_type prev_ExecutorFinish
planner_hook_type planner_hook
Definition: planner.c:73
void EnableQueryId(void)
ProcessUtility_hook_type ProcessUtility_hook
Definition: utility.c:70

References DefineCustomBoolVariable(), DefineCustomEnumVariable(), DefineCustomIntVariable(), EnableQueryId(), ExecutorEnd_hook, ExecutorFinish_hook, ExecutorRun_hook, ExecutorStart_hook, MarkGUCPrefixReserved(), PGC_POSTMASTER, PGC_SIGHUP, PGC_SUSET, pgss_ExecutorEnd(), pgss_ExecutorFinish(), pgss_ExecutorRun(), pgss_ExecutorStart(), pgss_max, pgss_planner(), pgss_post_parse_analyze(), pgss_ProcessUtility(), pgss_save, pgss_shmem_request(), pgss_shmem_startup(), pgss_track, pgss_track_planning, PGSS_TRACK_TOP, pgss_track_utility, planner_hook, post_parse_analyze_hook, prev_ExecutorEnd, prev_ExecutorFinish, prev_ExecutorRun, prev_ExecutorStart, prev_planner_hook, prev_post_parse_analyze_hook, prev_ProcessUtility, prev_shmem_request_hook, prev_shmem_startup_hook, process_shared_preload_libraries_in_progress, ProcessUtility_hook, shmem_request_hook, shmem_startup_hook, and track_options.

◆ comp_location()

static int comp_location ( const void *  a,
const void *  b 
)
static

Definition at line 3080 of file pg_stat_statements.c.

3081{
3082 int l = ((const LocationLen *) a)->location;
3083 int r = ((const LocationLen *) b)->location;
3084
3085 return pg_cmp_s32(l, r);
3086}
static int pg_cmp_s32(int32 a, int32 b)
Definition: int.h:646
int b
Definition: isn.c:74
int a
Definition: isn.c:73

References a, b, and pg_cmp_s32().

Referenced by fill_in_constant_lengths().

◆ entry_alloc()

static pgssEntry * entry_alloc ( pgssHashKey key,
Size  query_offset,
int  query_len,
int  encoding,
bool  sticky 
)
static

Definition at line 2086 of file pg_stat_statements.c.

2088{
2089 pgssEntry *entry;
2090 bool found;
2091
2092 /* Make space if needed */
2094 entry_dealloc();
2095
2096 /* Find or create an entry with desired hash code */
2097 entry = (pgssEntry *) hash_search(pgss_hash, key, HASH_ENTER, &found);
2098
2099 if (!found)
2100 {
2101 /* New entry, initialize it */
2102
2103 /* reset the statistics */
2104 memset(&entry->counters, 0, sizeof(Counters));
2105 /* set the appropriate initial usage count */
2106 entry->counters.usage = sticky ? pgss->cur_median_usage : USAGE_INIT;
2107 /* re-initialize the mutex each time ... we assume no one using it */
2108 SpinLockInit(&entry->mutex);
2109 /* ... and don't forget the query text metadata */
2110 Assert(query_len >= 0);
2111 entry->query_offset = query_offset;
2112 entry->query_len = query_len;
2113 entry->encoding = encoding;
2115 entry->minmax_stats_since = entry->stats_since;
2116 }
2117
2118 return entry;
2119}
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1645
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:956
long hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1342
Assert(PointerIsAligned(start, uint64))
@ HASH_ENTER
Definition: hsearch.h:114
int32 encoding
Definition: pg_database.h:41
static void entry_dealloc(void)
#define USAGE_INIT
#define SpinLockInit(lock)
Definition: spin.h:57
Counters counters
TimestampTz minmax_stats_since
TimestampTz stats_since

References Assert(), pgssEntry::counters, pgssSharedState::cur_median_usage, pgssEntry::encoding, encoding, entry_dealloc(), GetCurrentTimestamp(), HASH_ENTER, hash_get_num_entries(), hash_search(), sort-test::key, pgssEntry::minmax_stats_since, pgssEntry::mutex, pgss, pgss_hash, pgss_max, pgssEntry::query_len, pgssEntry::query_offset, SpinLockInit, pgssEntry::stats_since, Counters::usage, and USAGE_INIT.

Referenced by pgss_shmem_startup(), and pgss_store().

◆ entry_cmp()

static int entry_cmp ( const void *  lhs,
const void *  rhs 
)
static

Definition at line 2125 of file pg_stat_statements.c.

2126{
2127 double l_usage = (*(pgssEntry *const *) lhs)->counters.usage;
2128 double r_usage = (*(pgssEntry *const *) rhs)->counters.usage;
2129
2130 if (l_usage < r_usage)
2131 return -1;
2132 else if (l_usage > r_usage)
2133 return +1;
2134 else
2135 return 0;
2136}

Referenced by entry_dealloc().

◆ entry_dealloc()

static void entry_dealloc ( void  )
static

Definition at line 2144 of file pg_stat_statements.c.

2145{
2146 HASH_SEQ_STATUS hash_seq;
2147 pgssEntry **entries;
2148 pgssEntry *entry;
2149 int nvictims;
2150 int i;
2151 Size tottextlen;
2152 int nvalidtexts;
2153
2154 /*
2155 * Sort entries by usage and deallocate USAGE_DEALLOC_PERCENT of them.
2156 * While we're scanning the table, apply the decay factor to the usage
2157 * values, and update the mean query length.
2158 *
2159 * Note that the mean query length is almost immediately obsolete, since
2160 * we compute it before not after discarding the least-used entries.
2161 * Hopefully, that doesn't affect the mean too much; it doesn't seem worth
2162 * making two passes to get a more current result. Likewise, the new
2163 * cur_median_usage includes the entries we're about to zap.
2164 */
2165
2166 entries = palloc(hash_get_num_entries(pgss_hash) * sizeof(pgssEntry *));
2167
2168 i = 0;
2169 tottextlen = 0;
2170 nvalidtexts = 0;
2171
2172 hash_seq_init(&hash_seq, pgss_hash);
2173 while ((entry = hash_seq_search(&hash_seq)) != NULL)
2174 {
2175 entries[i++] = entry;
2176 /* "Sticky" entries get a different usage decay rate. */
2177 if (IS_STICKY(entry->counters))
2179 else
2181 /* In the mean length computation, ignore dropped texts. */
2182 if (entry->query_len >= 0)
2183 {
2184 tottextlen += entry->query_len + 1;
2185 nvalidtexts++;
2186 }
2187 }
2188
2189 /* Sort into increasing order by usage */
2190 qsort(entries, i, sizeof(pgssEntry *), entry_cmp);
2191
2192 /* Record the (approximate) median usage */
2193 if (i > 0)
2194 pgss->cur_median_usage = entries[i / 2]->counters.usage;
2195 /* Record the mean query length */
2196 if (nvalidtexts > 0)
2197 pgss->mean_query_len = tottextlen / nvalidtexts;
2198 else
2200
2201 /* Now zap an appropriate fraction of lowest-usage entries */
2202 nvictims = Max(10, i * USAGE_DEALLOC_PERCENT / 100);
2203 nvictims = Min(nvictims, i);
2204
2205 for (i = 0; i < nvictims; i++)
2206 {
2207 hash_search(pgss_hash, &entries[i]->key, HASH_REMOVE, NULL);
2208 }
2209
2210 pfree(entries);
2211
2212 /* Increment the number of times entries are deallocated */
2214 pgss->stats.dealloc += 1;
2216}
#define Min(x, y)
Definition: c.h:975
#define Max(x, y)
Definition: c.h:969
size_t Size
Definition: c.h:576
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1421
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1386
int i
Definition: isn.c:77
void pfree(void *pointer)
Definition: mcxt.c:2152
void * palloc(Size size)
Definition: mcxt.c:1945
static int entry_cmp(const void *lhs, const void *rhs)
#define USAGE_DEALLOC_PERCENT
#define STICKY_DECREASE_FACTOR
#define IS_STICKY(c)
#define ASSUMED_LENGTH_INIT
#define USAGE_DECREASE_FACTOR
#define qsort(a, b, c, d)
Definition: port.h:479
#define SpinLockRelease(lock)
Definition: spin.h:61
#define SpinLockAcquire(lock)
Definition: spin.h:59
pgssGlobalStats stats

References ASSUMED_LENGTH_INIT, pgssEntry::counters, pgssSharedState::cur_median_usage, pgssGlobalStats::dealloc, entry_cmp(), hash_get_num_entries(), HASH_REMOVE, hash_search(), hash_seq_init(), hash_seq_search(), i, IS_STICKY, sort-test::key, Max, pgssSharedState::mean_query_len, Min, pgssSharedState::mutex, palloc(), pfree(), pgss, pgss_hash, qsort, pgssEntry::query_len, SpinLockAcquire, SpinLockRelease, pgssSharedState::stats, STICKY_DECREASE_FACTOR, Counters::usage, USAGE_DEALLOC_PERCENT, and USAGE_DECREASE_FACTOR.

Referenced by entry_alloc().

◆ entry_reset()

static TimestampTz entry_reset ( Oid  userid,
Oid  dbid,
uint64  queryid,
bool  minmax_only 
)
static

Definition at line 2682 of file pg_stat_statements.c.

2683{
2684 HASH_SEQ_STATUS hash_seq;
2685 pgssEntry *entry;
2686 FILE *qfile;
2687 long num_entries;
2688 long num_remove = 0;
2690 TimestampTz stats_reset;
2691
2692 if (!pgss || !pgss_hash)
2693 ereport(ERROR,
2694 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2695 errmsg("pg_stat_statements must be loaded via \"shared_preload_libraries\"")));
2696
2698 num_entries = hash_get_num_entries(pgss_hash);
2699
2700 stats_reset = GetCurrentTimestamp();
2701
2702 if (userid != 0 && dbid != 0 && queryid != UINT64CONST(0))
2703 {
2704 /* If all the parameters are available, use the fast path. */
2705 memset(&key, 0, sizeof(pgssHashKey));
2706 key.userid = userid;
2707 key.dbid = dbid;
2708 key.queryid = queryid;
2709
2710 /*
2711 * Reset the entry if it exists, starting with the non-top-level
2712 * entry.
2713 */
2714 key.toplevel = false;
2715 entry = (pgssEntry *) hash_search(pgss_hash, &key, HASH_FIND, NULL);
2716
2717 SINGLE_ENTRY_RESET(entry);
2718
2719 /* Also reset the top-level entry if it exists. */
2720 key.toplevel = true;
2721 entry = (pgssEntry *) hash_search(pgss_hash, &key, HASH_FIND, NULL);
2722
2723 SINGLE_ENTRY_RESET(entry);
2724 }
2725 else if (userid != 0 || dbid != 0 || queryid != UINT64CONST(0))
2726 {
2727 /* Reset entries corresponding to valid parameters. */
2728 hash_seq_init(&hash_seq, pgss_hash);
2729 while ((entry = hash_seq_search(&hash_seq)) != NULL)
2730 {
2731 if ((!userid || entry->key.userid == userid) &&
2732 (!dbid || entry->key.dbid == dbid) &&
2733 (!queryid || entry->key.queryid == queryid))
2734 {
2735 SINGLE_ENTRY_RESET(entry);
2736 }
2737 }
2738 }
2739 else
2740 {
2741 /* Reset all entries. */
2742 hash_seq_init(&hash_seq, pgss_hash);
2743 while ((entry = hash_seq_search(&hash_seq)) != NULL)
2744 {
2745 SINGLE_ENTRY_RESET(entry);
2746 }
2747 }
2748
2749 /* All entries are removed? */
2750 if (num_entries != num_remove)
2751 goto release_lock;
2752
2753 /*
2754 * Reset global statistics for pg_stat_statements since all entries are
2755 * removed.
2756 */
2758 pgss->stats.dealloc = 0;
2759 pgss->stats.stats_reset = stats_reset;
2761
2762 /*
2763 * Write new empty query file, perhaps even creating a new one to recover
2764 * if the file was missing.
2765 */
2767 if (qfile == NULL)
2768 {
2769 ereport(LOG,
2771 errmsg("could not create file \"%s\": %m",
2772 PGSS_TEXT_FILE)));
2773 goto done;
2774 }
2775
2776 /* If ftruncate fails, log it, but it's not a fatal problem */
2777 if (ftruncate(fileno(qfile), 0) != 0)
2778 ereport(LOG,
2780 errmsg("could not truncate file \"%s\": %m",
2781 PGSS_TEXT_FILE)));
2782
2783 FreeFile(qfile);
2784
2785done:
2786 pgss->extent = 0;
2787 /* This counts as a query text garbage collection for our purposes */
2789
2790release_lock:
2792
2793 return stats_reset;
2794}
#define PG_BINARY_W
Definition: c.h:1247
#define UINT64CONST(x)
Definition: c.h:517
int64 TimestampTz
Definition: timestamp.h:39
int errcode_for_file_access(void)
Definition: elog.c:877
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define LOG
Definition: elog.h:31
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
int FreeFile(FILE *file)
Definition: fd.c:2843
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2644
@ HASH_FIND
Definition: hsearch.h:113
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1182
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1902
@ LW_EXCLUSIVE
Definition: lwlock.h:114
#define SINGLE_ENTRY_RESET(e)
#define record_gc_qtexts()
#define PGSS_TEXT_FILE
pgssHashKey key
TimestampTz stats_reset

References AllocateFile(), pgssHashKey::dbid, pgssGlobalStats::dealloc, ereport, errcode(), errcode_for_file_access(), errmsg(), ERROR, pgssSharedState::extent, FreeFile(), GetCurrentTimestamp(), HASH_FIND, hash_get_num_entries(), hash_search(), hash_seq_init(), hash_seq_search(), pgssEntry::key, sort-test::key, pgssSharedState::lock, LOG, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), pgssSharedState::mutex, PG_BINARY_W, pgss, pgss_hash, PGSS_TEXT_FILE, pgssHashKey::queryid, record_gc_qtexts, SINGLE_ENTRY_RESET, SpinLockAcquire, SpinLockRelease, pgssSharedState::stats, pgssGlobalStats::stats_reset, UINT64CONST, and pgssHashKey::userid.

Referenced by pg_stat_statements_reset(), pg_stat_statements_reset_1_11(), and pg_stat_statements_reset_1_7().

◆ fill_in_constant_lengths()

static void fill_in_constant_lengths ( JumbleState jstate,
const char *  query,
int  query_loc 
)
static

Definition at line 2980 of file pg_stat_statements.c.

2982{
2983 LocationLen *locs;
2984 core_yyscan_t yyscanner;
2986 core_YYSTYPE yylval;
2988 int last_loc = -1;
2989 int i;
2990
2991 /*
2992 * Sort the records by location so that we can process them in order while
2993 * scanning the query text.
2994 */
2995 if (jstate->clocations_count > 1)
2996 qsort(jstate->clocations, jstate->clocations_count,
2997 sizeof(LocationLen), comp_location);
2998 locs = jstate->clocations;
2999
3000 /* initialize the flex scanner --- should match raw_parser() */
3001 yyscanner = scanner_init(query,
3002 &yyextra,
3003 &ScanKeywords,
3005
3006 /* we don't want to re-emit any escape string warnings */
3007 yyextra.escape_string_warning = false;
3008
3009 /* Search for each constant, in sequence */
3010 for (i = 0; i < jstate->clocations_count; i++)
3011 {
3012 int loc = locs[i].location;
3013 int tok;
3014
3015 /* Adjust recorded location if we're dealing with partial string */
3016 loc -= query_loc;
3017
3018 Assert(loc >= 0);
3019
3020 if (loc <= last_loc)
3021 continue; /* Duplicate constant, ignore */
3022
3023 /* Lex tokens until we find the desired constant */
3024 for (;;)
3025 {
3026 tok = core_yylex(&yylval, &yylloc, yyscanner);
3027
3028 /* We should not hit end-of-string, but if we do, behave sanely */
3029 if (tok == 0)
3030 break; /* out of inner for-loop */
3031
3032 /*
3033 * We should find the token position exactly, but if we somehow
3034 * run past it, work with that.
3035 */
3036 if (yylloc >= loc)
3037 {
3038 if (query[loc] == '-')
3039 {
3040 /*
3041 * It's a negative value - this is the one and only case
3042 * where we replace more than a single token.
3043 *
3044 * Do not compensate for the core system's special-case
3045 * adjustment of location to that of the leading '-'
3046 * operator in the event of a negative constant. It is
3047 * also useful for our purposes to start from the minus
3048 * symbol. In this way, queries like "select * from foo
3049 * where bar = 1" and "select * from foo where bar = -2"
3050 * will have identical normalized query strings.
3051 */
3052 tok = core_yylex(&yylval, &yylloc, yyscanner);
3053 if (tok == 0)
3054 break; /* out of inner for-loop */
3055 }
3056
3057 /*
3058 * We now rely on the assumption that flex has placed a zero
3059 * byte after the text of the current token in scanbuf.
3060 */
3061 locs[i].length = strlen(yyextra.scanbuf + loc);
3062 break; /* out of inner for-loop */
3063 }
3064 }
3065
3066 /* If we hit end-of-string, give up, leaving remaining lengths -1 */
3067 if (tok == 0)
3068 break;
3069
3070 last_loc = loc;
3071 }
3072
3073 scanner_finish(yyscanner);
3074}
PGDLLIMPORT const ScanKeywordList ScanKeywords
static int comp_location(const void *a, const void *b)
const char * YYLTYPE
core_yyscan_t scanner_init(const char *str, core_yy_extra_type *yyext, const ScanKeywordList *keywordlist, const uint16 *keyword_tokens)
Definition: scan.l:1249
#define yylloc
Definition: scan.l:1122
void scanner_finish(core_yyscan_t yyscanner)
Definition: scan.l:1291
#define yyextra
Definition: scan.l:1118
const uint16 ScanKeywordTokens[]
Definition: scan.l:81
void * core_yyscan_t
Definition: scanner.h:121
int core_yylex(core_YYSTYPE *yylval_param, YYLTYPE *yylloc_param, core_yyscan_t yyscanner)
LocationLen * clocations
Definition: queryjumble.h:47
int clocations_count
Definition: queryjumble.h:53

References Assert(), JumbleState::clocations, JumbleState::clocations_count, comp_location(), core_yylex(), i, LocationLen::length, LocationLen::location, qsort, ScanKeywords, ScanKeywordTokens, scanner_finish(), scanner_init(), yyextra, and yylloc.

Referenced by generate_normalized_query().

◆ gc_qtexts()

static void gc_qtexts ( void  )
static

Definition at line 2480 of file pg_stat_statements.c.

2481{
2482 char *qbuffer;
2483 Size qbuffer_size;
2484 FILE *qfile = NULL;
2485 HASH_SEQ_STATUS hash_seq;
2486 pgssEntry *entry;
2487 Size extent;
2488 int nentries;
2489
2490 /*
2491 * When called from pgss_store, some other session might have proceeded
2492 * with garbage collection in the no-lock-held interim of lock strength
2493 * escalation. Check once more that this is actually necessary.
2494 */
2495 if (!need_gc_qtexts())
2496 return;
2497
2498 /*
2499 * Load the old texts file. If we fail (out of memory, for instance),
2500 * invalidate query texts. Hopefully this is rare. It might seem better
2501 * to leave things alone on an OOM failure, but the problem is that the
2502 * file is only going to get bigger; hoping for a future non-OOM result is
2503 * risky and can easily lead to complete denial of service.
2504 */
2505 qbuffer = qtext_load_file(&qbuffer_size);
2506 if (qbuffer == NULL)
2507 goto gc_fail;
2508
2509 /*
2510 * We overwrite the query texts file in place, so as to reduce the risk of
2511 * an out-of-disk-space failure. Since the file is guaranteed not to get
2512 * larger, this should always work on traditional filesystems; though we
2513 * could still lose on copy-on-write filesystems.
2514 */
2516 if (qfile == NULL)
2517 {
2518 ereport(LOG,
2520 errmsg("could not write file \"%s\": %m",
2521 PGSS_TEXT_FILE)));
2522 goto gc_fail;
2523 }
2524
2525 extent = 0;
2526 nentries = 0;
2527
2528 hash_seq_init(&hash_seq, pgss_hash);
2529 while ((entry = hash_seq_search(&hash_seq)) != NULL)
2530 {
2531 int query_len = entry->query_len;
2532 char *qry = qtext_fetch(entry->query_offset,
2533 query_len,
2534 qbuffer,
2535 qbuffer_size);
2536
2537 if (qry == NULL)
2538 {
2539 /* Trouble ... drop the text */
2540 entry->query_offset = 0;
2541 entry->query_len = -1;
2542 /* entry will not be counted in mean query length computation */
2543 continue;
2544 }
2545
2546 if (fwrite(qry, 1, query_len + 1, qfile) != query_len + 1)
2547 {
2548 ereport(LOG,
2550 errmsg("could not write file \"%s\": %m",
2551 PGSS_TEXT_FILE)));
2552 hash_seq_term(&hash_seq);
2553 goto gc_fail;
2554 }
2555
2556 entry->query_offset = extent;
2557 extent += query_len + 1;
2558 nentries++;
2559 }
2560
2561 /*
2562 * Truncate away any now-unused space. If this fails for some odd reason,
2563 * we log it, but there's no need to fail.
2564 */
2565 if (ftruncate(fileno(qfile), extent) != 0)
2566 ereport(LOG,
2568 errmsg("could not truncate file \"%s\": %m",
2569 PGSS_TEXT_FILE)));
2570
2571 if (FreeFile(qfile))
2572 {
2573 ereport(LOG,
2575 errmsg("could not write file \"%s\": %m",
2576 PGSS_TEXT_FILE)));
2577 qfile = NULL;
2578 goto gc_fail;
2579 }
2580
2581 elog(DEBUG1, "pgss gc of queries file shrunk size from %zu to %zu",
2582 pgss->extent, extent);
2583
2584 /* Reset the shared extent pointer */
2585 pgss->extent = extent;
2586
2587 /*
2588 * Also update the mean query length, to be sure that need_gc_qtexts()
2589 * won't still think we have a problem.
2590 */
2591 if (nentries > 0)
2592 pgss->mean_query_len = extent / nentries;
2593 else
2595
2596 free(qbuffer);
2597
2598 /*
2599 * OK, count a garbage collection cycle. (Note: even though we have
2600 * exclusive lock on pgss->lock, we must take pgss->mutex for this, since
2601 * other processes may examine gc_count while holding only the mutex.
2602 * Also, we have to advance the count *after* we've rewritten the file,
2603 * else other processes might not realize they read a stale file.)
2604 */
2606
2607 return;
2608
2609gc_fail:
2610 /* clean up resources */
2611 if (qfile)
2612 FreeFile(qfile);
2613 free(qbuffer);
2614
2615 /*
2616 * Since the contents of the external file are now uncertain, mark all
2617 * hashtable entries as having invalid texts.
2618 */
2619 hash_seq_init(&hash_seq, pgss_hash);
2620 while ((entry = hash_seq_search(&hash_seq)) != NULL)
2621 {
2622 entry->query_offset = 0;
2623 entry->query_len = -1;
2624 }
2625
2626 /*
2627 * Destroy the query text file and create a new, empty one
2628 */
2629 (void) unlink(PGSS_TEXT_FILE);
2631 if (qfile == NULL)
2632 ereport(LOG,
2634 errmsg("could not recreate file \"%s\": %m",
2635 PGSS_TEXT_FILE)));
2636 else
2637 FreeFile(qfile);
2638
2639 /* Reset the shared extent pointer */
2640 pgss->extent = 0;
2641
2642 /* Reset mean_query_len to match the new state */
2644
2645 /*
2646 * Bump the GC count even though we failed.
2647 *
2648 * This is needed to make concurrent readers of file without any lock on
2649 * pgss->lock notice existence of new version of file. Once readers
2650 * subsequently observe a change in GC count with pgss->lock held, that
2651 * forces a safe reopen of file. Writers also require that we bump here,
2652 * of course. (As required by locking protocol, readers and writers don't
2653 * trust earlier file contents until gc_count is found unchanged after
2654 * pgss->lock acquired in shared or exclusive mode respectively.)
2655 */
2657}
void hash_seq_term(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1515
#define DEBUG1
Definition: elog.h:30
#define elog(elevel,...)
Definition: elog.h:225
#define free(a)
Definition: header.h:65
static char * qtext_fetch(Size query_offset, int query_len, char *buffer, Size buffer_size)
static char * qtext_load_file(Size *buffer_size)
static bool need_gc_qtexts(void)

References AllocateFile(), ASSUMED_LENGTH_INIT, DEBUG1, elog, ereport, errcode_for_file_access(), errmsg(), pgssSharedState::extent, free, FreeFile(), hash_seq_init(), hash_seq_search(), hash_seq_term(), LOG, pgssSharedState::mean_query_len, need_gc_qtexts(), PG_BINARY_W, pgss, pgss_hash, PGSS_TEXT_FILE, qtext_fetch(), qtext_load_file(), pgssEntry::query_len, pgssEntry::query_offset, and record_gc_qtexts.

Referenced by pgss_store().

◆ generate_normalized_query()

static char * generate_normalized_query ( JumbleState jstate,
const char *  query,
int  query_loc,
int *  query_len_p 
)
static

Definition at line 2816 of file pg_stat_statements.c.

2818{
2819 char *norm_query;
2820 int query_len = *query_len_p;
2821 int i,
2822 norm_query_buflen, /* Space allowed for norm_query */
2823 len_to_wrt, /* Length (in bytes) to write */
2824 quer_loc = 0, /* Source query byte location */
2825 n_quer_loc = 0, /* Normalized query byte location */
2826 last_off = 0, /* Offset from start for previous tok */
2827 last_tok_len = 0; /* Length (in bytes) of that tok */
2828 bool in_squashed = false; /* in a run of squashed consts? */
2829 int skipped_constants = 0; /* Position adjustment of later
2830 * constants after squashed ones */
2831
2832
2833 /*
2834 * Get constants' lengths (core system only gives us locations). Note
2835 * this also ensures the items are sorted by location.
2836 */
2837 fill_in_constant_lengths(jstate, query, query_loc);
2838
2839 /*
2840 * Allow for $n symbols to be longer than the constants they replace.
2841 * Constants must take at least one byte in text form, while a $n symbol
2842 * certainly isn't more than 11 bytes, even if n reaches INT_MAX. We
2843 * could refine that limit based on the max value of n for the current
2844 * query, but it hardly seems worth any extra effort to do so.
2845 *
2846 * Note this also gives enough room for the commented-out ", ..." list
2847 * syntax used by constant squashing.
2848 */
2849 norm_query_buflen = query_len + jstate->clocations_count * 10;
2850
2851 /* Allocate result buffer */
2852 norm_query = palloc(norm_query_buflen + 1);
2853
2854 for (i = 0; i < jstate->clocations_count; i++)
2855 {
2856 int off, /* Offset from start for cur tok */
2857 tok_len; /* Length (in bytes) of that tok */
2858
2859 off = jstate->clocations[i].location;
2860
2861 /* Adjust recorded location if we're dealing with partial string */
2862 off -= query_loc;
2863
2864 tok_len = jstate->clocations[i].length;
2865
2866 if (tok_len < 0)
2867 continue; /* ignore any duplicates */
2868
2869 /*
2870 * What to do next depends on whether we're squashing constant lists,
2871 * and whether we're already in a run of such constants.
2872 */
2873 if (!jstate->clocations[i].squashed)
2874 {
2875 /*
2876 * This location corresponds to a constant not to be squashed.
2877 * Print what comes before the constant ...
2878 */
2879 len_to_wrt = off - last_off;
2880 len_to_wrt -= last_tok_len;
2881
2882 Assert(len_to_wrt >= 0);
2883
2884 memcpy(norm_query + n_quer_loc, query + quer_loc, len_to_wrt);
2885 n_quer_loc += len_to_wrt;
2886
2887 /* ... and then a param symbol replacing the constant itself */
2888 n_quer_loc += sprintf(norm_query + n_quer_loc, "$%d",
2889 i + 1 + jstate->highest_extern_param_id - skipped_constants);
2890
2891 /* In case previous constants were merged away, stop doing that */
2892 in_squashed = false;
2893 }
2894 else if (!in_squashed)
2895 {
2896 /*
2897 * This location is the start position of a run of constants to be
2898 * squashed, so we need to print the representation of starting a
2899 * group of stashed constants.
2900 *
2901 * Print what comes before the constant ...
2902 */
2903 len_to_wrt = off - last_off;
2904 len_to_wrt -= last_tok_len;
2905 Assert(len_to_wrt >= 0);
2906 Assert(i + 1 < jstate->clocations_count);
2907 Assert(jstate->clocations[i + 1].squashed);
2908 memcpy(norm_query + n_quer_loc, query + quer_loc, len_to_wrt);
2909 n_quer_loc += len_to_wrt;
2910
2911 /* ... and then start a run of squashed constants */
2912 n_quer_loc += sprintf(norm_query + n_quer_loc, "$%d /*, ... */",
2913 i + 1 + jstate->highest_extern_param_id - skipped_constants);
2914
2915 /* The next location will match the block below, to end the run */
2916 in_squashed = true;
2917
2918 skipped_constants++;
2919 }
2920 else
2921 {
2922 /*
2923 * The second location of a run of squashable elements; this
2924 * indicates its end.
2925 */
2926 in_squashed = false;
2927 }
2928
2929 /* Otherwise the constant is squashed away -- move forward */
2930 quer_loc = off + tok_len;
2931 last_off = off;
2932 last_tok_len = tok_len;
2933 }
2934
2935 /*
2936 * We've copied up until the last ignorable constant. Copy over the
2937 * remaining bytes of the original query string.
2938 */
2939 len_to_wrt = query_len - quer_loc;
2940
2941 Assert(len_to_wrt >= 0);
2942 memcpy(norm_query + n_quer_loc, query + quer_loc, len_to_wrt);
2943 n_quer_loc += len_to_wrt;
2944
2945 Assert(n_quer_loc <= norm_query_buflen);
2946 norm_query[n_quer_loc] = '\0';
2947
2948 *query_len_p = n_quer_loc;
2949 return norm_query;
2950}
static void fill_in_constant_lengths(JumbleState *jstate, const char *query, int query_loc)
#define sprintf
Definition: port.h:241
int highest_extern_param_id
Definition: queryjumble.h:56
bool squashed
Definition: queryjumble.h:31

References Assert(), JumbleState::clocations, JumbleState::clocations_count, fill_in_constant_lengths(), JumbleState::highest_extern_param_id, i, LocationLen::length, LocationLen::location, palloc(), sprintf, and LocationLen::squashed.

Referenced by pgss_store().

◆ need_gc_qtexts()

static bool need_gc_qtexts ( void  )
static

Definition at line 2431 of file pg_stat_statements.c.

2432{
2433 Size extent;
2434
2435 /* Read shared extent pointer */
2437 extent = pgss->extent;
2439
2440 /*
2441 * Don't proceed if file does not exceed 512 bytes per possible entry.
2442 *
2443 * Here and in the next test, 32-bit machines have overflow hazards if
2444 * pgss_max and/or mean_query_len are large. Force the multiplications
2445 * and comparisons to be done in uint64 arithmetic to forestall trouble.
2446 */
2447 if ((uint64) extent < (uint64) 512 * pgss_max)
2448 return false;
2449
2450 /*
2451 * Don't proceed if file is less than about 50% bloat. Nothing can or
2452 * should be done in the event of unusually large query texts accounting
2453 * for file's large size. We go to the trouble of maintaining the mean
2454 * query length in order to prevent garbage collection from thrashing
2455 * uselessly.
2456 */
2457 if ((uint64) extent < (uint64) pgss->mean_query_len * pgss_max * 2)
2458 return false;
2459
2460 return true;
2461}
uint64_t uint64
Definition: c.h:503

References pgssSharedState::extent, pgssSharedState::mean_query_len, pgssSharedState::mutex, pgss, pgss_max, SpinLockAcquire, and SpinLockRelease.

Referenced by gc_qtexts(), and pgss_store().

◆ PG_FUNCTION_INFO_V1() [1/12]

PG_FUNCTION_INFO_V1 ( pg_stat_statements  )

◆ PG_FUNCTION_INFO_V1() [2/12]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_10  )

◆ PG_FUNCTION_INFO_V1() [3/12]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_11  )

◆ PG_FUNCTION_INFO_V1() [4/12]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_12  )

◆ PG_FUNCTION_INFO_V1() [5/12]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_2  )

◆ PG_FUNCTION_INFO_V1() [6/12]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_3  )

◆ PG_FUNCTION_INFO_V1() [7/12]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_8  )

◆ PG_FUNCTION_INFO_V1() [8/12]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_9  )

◆ PG_FUNCTION_INFO_V1() [9/12]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_info  )

◆ PG_FUNCTION_INFO_V1() [10/12]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_reset  )

◆ PG_FUNCTION_INFO_V1() [11/12]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_reset_1_11  )

◆ PG_FUNCTION_INFO_V1() [12/12]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_reset_1_7  )

◆ PG_MODULE_MAGIC_EXT()

PG_MODULE_MAGIC_EXT ( name = "pg_stat_statements",
version = PG_VERSION 
)

◆ pg_stat_statements()

Datum pg_stat_statements ( PG_FUNCTION_ARGS  )

Definition at line 1660 of file pg_stat_statements.c.

1661{
1662 /* If it's really API 1.1, we'll figure that out below */
1664
1665 return (Datum) 0;
1666}
static void pg_stat_statements_internal(FunctionCallInfo fcinfo, pgssVersion api_version, bool showtext)
uintptr_t Datum
Definition: postgres.h:69

References pg_stat_statements_internal(), and PGSS_V1_0.

◆ pg_stat_statements_1_10()

Datum pg_stat_statements_1_10 ( PG_FUNCTION_ARGS  )

Definition at line 1606 of file pg_stat_statements.c.

1607{
1608 bool showtext = PG_GETARG_BOOL(0);
1609
1610 pg_stat_statements_internal(fcinfo, PGSS_V1_10, showtext);
1611
1612 return (Datum) 0;
1613}
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:274

References PG_GETARG_BOOL, pg_stat_statements_internal(), and PGSS_V1_10.

◆ pg_stat_statements_1_11()

Datum pg_stat_statements_1_11 ( PG_FUNCTION_ARGS  )

Definition at line 1596 of file pg_stat_statements.c.

1597{
1598 bool showtext = PG_GETARG_BOOL(0);
1599
1600 pg_stat_statements_internal(fcinfo, PGSS_V1_11, showtext);
1601
1602 return (Datum) 0;
1603}

References PG_GETARG_BOOL, pg_stat_statements_internal(), and PGSS_V1_11.

◆ pg_stat_statements_1_12()

Datum pg_stat_statements_1_12 ( PG_FUNCTION_ARGS  )

Definition at line 1586 of file pg_stat_statements.c.

1587{
1588 bool showtext = PG_GETARG_BOOL(0);
1589
1590 pg_stat_statements_internal(fcinfo, PGSS_V1_12, showtext);
1591
1592 return (Datum) 0;
1593}

References PG_GETARG_BOOL, pg_stat_statements_internal(), and PGSS_V1_12.

◆ pg_stat_statements_1_2()

Datum pg_stat_statements_1_2 ( PG_FUNCTION_ARGS  )

Definition at line 1646 of file pg_stat_statements.c.

1647{
1648 bool showtext = PG_GETARG_BOOL(0);
1649
1650 pg_stat_statements_internal(fcinfo, PGSS_V1_2, showtext);
1651
1652 return (Datum) 0;
1653}

References PG_GETARG_BOOL, pg_stat_statements_internal(), and PGSS_V1_2.

◆ pg_stat_statements_1_3()

Datum pg_stat_statements_1_3 ( PG_FUNCTION_ARGS  )

Definition at line 1636 of file pg_stat_statements.c.

1637{
1638 bool showtext = PG_GETARG_BOOL(0);
1639
1640 pg_stat_statements_internal(fcinfo, PGSS_V1_3, showtext);
1641
1642 return (Datum) 0;
1643}

References PG_GETARG_BOOL, pg_stat_statements_internal(), and PGSS_V1_3.

◆ pg_stat_statements_1_8()

Datum pg_stat_statements_1_8 ( PG_FUNCTION_ARGS  )

Definition at line 1626 of file pg_stat_statements.c.

1627{
1628 bool showtext = PG_GETARG_BOOL(0);
1629
1630 pg_stat_statements_internal(fcinfo, PGSS_V1_8, showtext);
1631
1632 return (Datum) 0;
1633}

References PG_GETARG_BOOL, pg_stat_statements_internal(), and PGSS_V1_8.

◆ pg_stat_statements_1_9()

Datum pg_stat_statements_1_9 ( PG_FUNCTION_ARGS  )

Definition at line 1616 of file pg_stat_statements.c.

1617{
1618 bool showtext = PG_GETARG_BOOL(0);
1619
1620 pg_stat_statements_internal(fcinfo, PGSS_V1_9, showtext);
1621
1622 return (Datum) 0;
1623}

References PG_GETARG_BOOL, pg_stat_statements_internal(), and PGSS_V1_9.

◆ pg_stat_statements_info()

Datum pg_stat_statements_info ( PG_FUNCTION_ARGS  )

Definition at line 2027 of file pg_stat_statements.c.

2028{
2029 pgssGlobalStats stats;
2030 TupleDesc tupdesc;
2032 bool nulls[PG_STAT_STATEMENTS_INFO_COLS] = {0};
2033
2034 if (!pgss || !pgss_hash)
2035 ereport(ERROR,
2036 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2037 errmsg("pg_stat_statements must be loaded via \"shared_preload_libraries\"")));
2038
2039 /* Build a tuple descriptor for our result type */
2040 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
2041 elog(ERROR, "return type must be a row type");
2042
2043 /* Read global statistics for pg_stat_statements */
2045 stats = pgss->stats;
2047
2048 values[0] = Int64GetDatum(stats.dealloc);
2050
2052}
static Datum values[MAXATTR]
Definition: bootstrap.c:151
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1807
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:276
@ TYPEFUNC_COMPOSITE
Definition: funcapi.h:149
static Datum HeapTupleGetDatum(const HeapTupleData *tuple)
Definition: funcapi.h:230
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1117
#define PG_STAT_STATEMENTS_INFO_COLS
static Datum TimestampTzGetDatum(TimestampTz X)
Definition: timestamp.h:52

References pgssGlobalStats::dealloc, elog, ereport, errcode(), errmsg(), ERROR, get_call_result_type(), heap_form_tuple(), HeapTupleGetDatum(), Int64GetDatum(), pgssSharedState::mutex, PG_RETURN_DATUM, PG_STAT_STATEMENTS_INFO_COLS, pgss, pgss_hash, SpinLockAcquire, SpinLockRelease, pgssSharedState::stats, pgssGlobalStats::stats_reset, TimestampTzGetDatum(), TYPEFUNC_COMPOSITE, and values.

◆ pg_stat_statements_internal()

static void pg_stat_statements_internal ( FunctionCallInfo  fcinfo,
pgssVersion  api_version,
bool  showtext 
)
static

Definition at line 1670 of file pg_stat_statements.c.

1673{
1674 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1675 Oid userid = GetUserId();
1676 bool is_allowed_role = false;
1677 char *qbuffer = NULL;
1678 Size qbuffer_size = 0;
1679 Size extent = 0;
1680 int gc_count = 0;
1681 HASH_SEQ_STATUS hash_seq;
1682 pgssEntry *entry;
1683
1684 /*
1685 * Superusers or roles with the privileges of pg_read_all_stats members
1686 * are allowed
1687 */
1688 is_allowed_role = has_privs_of_role(userid, ROLE_PG_READ_ALL_STATS);
1689
1690 /* hash table must exist already */
1691 if (!pgss || !pgss_hash)
1692 ereport(ERROR,
1693 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1694 errmsg("pg_stat_statements must be loaded via \"shared_preload_libraries\"")));
1695
1696 InitMaterializedSRF(fcinfo, 0);
1697
1698 /*
1699 * Check we have the expected number of output arguments. Aside from
1700 * being a good safety check, we need a kluge here to detect API version
1701 * 1.1, which was wedged into the code in an ill-considered way.
1702 */
1703 switch (rsinfo->setDesc->natts)
1704 {
1706 if (api_version != PGSS_V1_0)
1707 elog(ERROR, "incorrect number of output arguments");
1708 break;
1710 /* pg_stat_statements() should have told us 1.0 */
1711 if (api_version != PGSS_V1_0)
1712 elog(ERROR, "incorrect number of output arguments");
1713 api_version = PGSS_V1_1;
1714 break;
1716 if (api_version != PGSS_V1_2)
1717 elog(ERROR, "incorrect number of output arguments");
1718 break;
1720 if (api_version != PGSS_V1_3)
1721 elog(ERROR, "incorrect number of output arguments");
1722 break;
1724 if (api_version != PGSS_V1_8)
1725 elog(ERROR, "incorrect number of output arguments");
1726 break;
1728 if (api_version != PGSS_V1_9)
1729 elog(ERROR, "incorrect number of output arguments");
1730 break;
1732 if (api_version != PGSS_V1_10)
1733 elog(ERROR, "incorrect number of output arguments");
1734 break;
1736 if (api_version != PGSS_V1_11)
1737 elog(ERROR, "incorrect number of output arguments");
1738 break;
1740 if (api_version != PGSS_V1_12)
1741 elog(ERROR, "incorrect number of output arguments");
1742 break;
1743 default:
1744 elog(ERROR, "incorrect number of output arguments");
1745 }
1746
1747 /*
1748 * We'd like to load the query text file (if needed) while not holding any
1749 * lock on pgss->lock. In the worst case we'll have to do this again
1750 * after we have the lock, but it's unlikely enough to make this a win
1751 * despite occasional duplicated work. We need to reload if anybody
1752 * writes to the file (either a retail qtext_store(), or a garbage
1753 * collection) between this point and where we've gotten shared lock. If
1754 * a qtext_store is actually in progress when we look, we might as well
1755 * skip the speculative load entirely.
1756 */
1757 if (showtext)
1758 {
1759 int n_writers;
1760
1761 /* Take the mutex so we can examine variables */
1763 extent = pgss->extent;
1764 n_writers = pgss->n_writers;
1765 gc_count = pgss->gc_count;
1767
1768 /* No point in loading file now if there are active writers */
1769 if (n_writers == 0)
1770 qbuffer = qtext_load_file(&qbuffer_size);
1771 }
1772
1773 /*
1774 * Get shared lock, load or reload the query text file if we must, and
1775 * iterate over the hashtable entries.
1776 *
1777 * With a large hash table, we might be holding the lock rather longer
1778 * than one could wish. However, this only blocks creation of new hash
1779 * table entries, and the larger the hash table the less likely that is to
1780 * be needed. So we can hope this is okay. Perhaps someday we'll decide
1781 * we need to partition the hash table to limit the time spent holding any
1782 * one lock.
1783 */
1785
1786 if (showtext)
1787 {
1788 /*
1789 * Here it is safe to examine extent and gc_count without taking the
1790 * mutex. Note that although other processes might change
1791 * pgss->extent just after we look at it, the strings they then write
1792 * into the file cannot yet be referenced in the hashtable, so we
1793 * don't care whether we see them or not.
1794 *
1795 * If qtext_load_file fails, we just press on; we'll return NULL for
1796 * every query text.
1797 */
1798 if (qbuffer == NULL ||
1799 pgss->extent != extent ||
1800 pgss->gc_count != gc_count)
1801 {
1802 free(qbuffer);
1803 qbuffer = qtext_load_file(&qbuffer_size);
1804 }
1805 }
1806
1807 hash_seq_init(&hash_seq, pgss_hash);
1808 while ((entry = hash_seq_search(&hash_seq)) != NULL)
1809 {
1811 bool nulls[PG_STAT_STATEMENTS_COLS];
1812 int i = 0;
1813 Counters tmp;
1814 double stddev;
1815 int64 queryid = entry->key.queryid;
1816 TimestampTz stats_since;
1817 TimestampTz minmax_stats_since;
1818
1819 memset(values, 0, sizeof(values));
1820 memset(nulls, 0, sizeof(nulls));
1821
1822 values[i++] = ObjectIdGetDatum(entry->key.userid);
1823 values[i++] = ObjectIdGetDatum(entry->key.dbid);
1824 if (api_version >= PGSS_V1_9)
1825 values[i++] = BoolGetDatum(entry->key.toplevel);
1826
1827 if (is_allowed_role || entry->key.userid == userid)
1828 {
1829 if (api_version >= PGSS_V1_2)
1830 values[i++] = Int64GetDatumFast(queryid);
1831
1832 if (showtext)
1833 {
1834 char *qstr = qtext_fetch(entry->query_offset,
1835 entry->query_len,
1836 qbuffer,
1837 qbuffer_size);
1838
1839 if (qstr)
1840 {
1841 char *enc;
1842
1843 enc = pg_any_to_server(qstr,
1844 entry->query_len,
1845 entry->encoding);
1846
1848
1849 if (enc != qstr)
1850 pfree(enc);
1851 }
1852 else
1853 {
1854 /* Just return a null if we fail to find the text */
1855 nulls[i++] = true;
1856 }
1857 }
1858 else
1859 {
1860 /* Query text not requested */
1861 nulls[i++] = true;
1862 }
1863 }
1864 else
1865 {
1866 /* Don't show queryid */
1867 if (api_version >= PGSS_V1_2)
1868 nulls[i++] = true;
1869
1870 /*
1871 * Don't show query text, but hint as to the reason for not doing
1872 * so if it was requested
1873 */
1874 if (showtext)
1875 values[i++] = CStringGetTextDatum("<insufficient privilege>");
1876 else
1877 nulls[i++] = true;
1878 }
1879
1880 /* copy counters to a local variable to keep locking time short */
1881 SpinLockAcquire(&entry->mutex);
1882 tmp = entry->counters;
1883 SpinLockRelease(&entry->mutex);
1884
1885 /*
1886 * The spinlock is not required when reading these two as they are
1887 * always updated when holding pgss->lock exclusively.
1888 */
1889 stats_since = entry->stats_since;
1890 minmax_stats_since = entry->minmax_stats_since;
1891
1892 /* Skip entry if unexecuted (ie, it's a pending "sticky" entry) */
1893 if (IS_STICKY(tmp))
1894 continue;
1895
1896 /* Note that we rely on PGSS_PLAN being 0 and PGSS_EXEC being 1. */
1897 for (int kind = 0; kind < PGSS_NUMKIND; kind++)
1898 {
1899 if (kind == PGSS_EXEC || api_version >= PGSS_V1_8)
1900 {
1901 values[i++] = Int64GetDatumFast(tmp.calls[kind]);
1902 values[i++] = Float8GetDatumFast(tmp.total_time[kind]);
1903 }
1904
1905 if ((kind == PGSS_EXEC && api_version >= PGSS_V1_3) ||
1906 api_version >= PGSS_V1_8)
1907 {
1908 values[i++] = Float8GetDatumFast(tmp.min_time[kind]);
1909 values[i++] = Float8GetDatumFast(tmp.max_time[kind]);
1910 values[i++] = Float8GetDatumFast(tmp.mean_time[kind]);
1911
1912 /*
1913 * Note we are calculating the population variance here, not
1914 * the sample variance, as we have data for the whole
1915 * population, so Bessel's correction is not used, and we
1916 * don't divide by tmp.calls - 1.
1917 */
1918 if (tmp.calls[kind] > 1)
1919 stddev = sqrt(tmp.sum_var_time[kind] / tmp.calls[kind]);
1920 else
1921 stddev = 0.0;
1922 values[i++] = Float8GetDatumFast(stddev);
1923 }
1924 }
1925 values[i++] = Int64GetDatumFast(tmp.rows);
1928 if (api_version >= PGSS_V1_1)
1933 if (api_version >= PGSS_V1_1)
1938 if (api_version >= PGSS_V1_1)
1939 {
1942 }
1943 if (api_version >= PGSS_V1_11)
1944 {
1947 }
1948 if (api_version >= PGSS_V1_10)
1949 {
1952 }
1953 if (api_version >= PGSS_V1_8)
1954 {
1955 char buf[256];
1956 Datum wal_bytes;
1957
1960
1961 snprintf(buf, sizeof buf, UINT64_FORMAT, tmp.wal_bytes);
1962
1963 /* Convert to numeric. */
1964 wal_bytes = DirectFunctionCall3(numeric_in,
1967 Int32GetDatum(-1));
1968 values[i++] = wal_bytes;
1969 }
1970 if (api_version >= PGSS_V1_12)
1971 {
1973 }
1974 if (api_version >= PGSS_V1_10)
1975 {
1984 }
1985 if (api_version >= PGSS_V1_11)
1986 {
1989 }
1990 if (api_version >= PGSS_V1_12)
1991 {
1994 }
1995 if (api_version >= PGSS_V1_11)
1996 {
1997 values[i++] = TimestampTzGetDatum(stats_since);
1998 values[i++] = TimestampTzGetDatum(minmax_stats_since);
1999 }
2000
2001 Assert(i == (api_version == PGSS_V1_0 ? PG_STAT_STATEMENTS_COLS_V1_0 :
2002 api_version == PGSS_V1_1 ? PG_STAT_STATEMENTS_COLS_V1_1 :
2003 api_version == PGSS_V1_2 ? PG_STAT_STATEMENTS_COLS_V1_2 :
2004 api_version == PGSS_V1_3 ? PG_STAT_STATEMENTS_COLS_V1_3 :
2005 api_version == PGSS_V1_8 ? PG_STAT_STATEMENTS_COLS_V1_8 :
2006 api_version == PGSS_V1_9 ? PG_STAT_STATEMENTS_COLS_V1_9 :
2007 api_version == PGSS_V1_10 ? PG_STAT_STATEMENTS_COLS_V1_10 :
2008 api_version == PGSS_V1_11 ? PG_STAT_STATEMENTS_COLS_V1_11 :
2009 api_version == PGSS_V1_12 ? PG_STAT_STATEMENTS_COLS_V1_12 :
2010 -1 /* fail if you forget to update this assert */ ));
2011
2012 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
2013 }
2014
2016
2017 free(qbuffer);
2018}
bool has_privs_of_role(Oid member, Oid role)
Definition: acl.c:5268
Datum numeric_in(PG_FUNCTION_ARGS)
Definition: numeric.c:637
#define CStringGetTextDatum(s)
Definition: builtins.h:97
int64_t int64
Definition: c.h:499
#define UINT64_FORMAT
Definition: c.h:521
enc
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition: fmgr.h:686
void InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags)
Definition: funcapi.c:76
@ LW_SHARED
Definition: lwlock.h:115
char * pg_any_to_server(const char *s, int len, int encoding)
Definition: mbutils.c:676
Oid GetUserId(void)
Definition: miscinit.c:520
#define PG_STAT_STATEMENTS_COLS_V1_0
#define PG_STAT_STATEMENTS_COLS_V1_8
#define PG_STAT_STATEMENTS_COLS
#define PG_STAT_STATEMENTS_COLS_V1_11
#define PG_STAT_STATEMENTS_COLS_V1_2
#define PG_STAT_STATEMENTS_COLS_V1_12
#define PG_STAT_STATEMENTS_COLS_V1_3
#define PG_STAT_STATEMENTS_COLS_V1_10
#define PG_STAT_STATEMENTS_COLS_V1_1
#define PG_STAT_STATEMENTS_COLS_V1_9
static char * buf
Definition: pg_test_fsync.c:72
#define snprintf
Definition: port.h:239
#define Int64GetDatumFast(X)
Definition: postgres.h:559
#define Float8GetDatumFast(X)
Definition: postgres.h:561
static Datum BoolGetDatum(bool X)
Definition: postgres.h:107
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:355
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:217
unsigned int Oid
Definition: postgres_ext.h:30
int64 temp_blks_written
int64 calls[PGSS_NUMKIND]
int64 wal_buffers_full
int64 parallel_workers_launched
int64 shared_blks_written
double jit_generation_time
int64 temp_blks_read
double min_time[PGSS_NUMKIND]
int64 local_blks_written
double sum_var_time[PGSS_NUMKIND]
double temp_blk_read_time
double local_blk_write_time
int64 jit_emission_count
int64 jit_deform_count
double jit_emission_time
int64 shared_blks_hit
double local_blk_read_time
double jit_optimization_time
double shared_blk_write_time
int64 jit_optimization_count
double total_time[PGSS_NUMKIND]
double max_time[PGSS_NUMKIND]
int64 shared_blks_dirtied
double mean_time[PGSS_NUMKIND]
double temp_blk_write_time
int64 local_blks_dirtied
int64 jit_inlining_count
int64 shared_blks_read
int64 local_blks_hit
double jit_deform_time
int64 parallel_workers_to_launch
int64 local_blks_read
double shared_blk_read_time
double jit_inlining_time
fmNodePtr resultinfo
Definition: fmgr.h:89
TupleDesc setDesc
Definition: execnodes.h:359
Tuplestorestate * setResult
Definition: execnodes.h:358
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
Definition: tuplestore.c:784

References Assert(), BoolGetDatum(), buf, Counters::calls, pgssEntry::counters, CStringGetDatum(), CStringGetTextDatum, pgssHashKey::dbid, DirectFunctionCall3, elog, enc, pgssEntry::encoding, ereport, errcode(), errmsg(), ERROR, pgssSharedState::extent, Float8GetDatumFast, free, pgssSharedState::gc_count, GetUserId(), has_privs_of_role(), hash_seq_init(), hash_seq_search(), i, InitMaterializedSRF(), Int32GetDatum(), Int64GetDatumFast, IS_STICKY, Counters::jit_deform_count, Counters::jit_deform_time, Counters::jit_emission_count, Counters::jit_emission_time, Counters::jit_functions, Counters::jit_generation_time, Counters::jit_inlining_count, Counters::jit_inlining_time, Counters::jit_optimization_count, Counters::jit_optimization_time, pgssEntry::key, Counters::local_blk_read_time, Counters::local_blk_write_time, Counters::local_blks_dirtied, Counters::local_blks_hit, Counters::local_blks_read, Counters::local_blks_written, pgssSharedState::lock, LW_SHARED, LWLockAcquire(), LWLockRelease(), Counters::max_time, Counters::mean_time, Counters::min_time, pgssEntry::minmax_stats_since, pgssEntry::mutex, pgssSharedState::mutex, pgssSharedState::n_writers, TupleDescData::natts, numeric_in(), ObjectIdGetDatum(), Counters::parallel_workers_launched, Counters::parallel_workers_to_launch, pfree(), pg_any_to_server(), PG_STAT_STATEMENTS_COLS, PG_STAT_STATEMENTS_COLS_V1_0, PG_STAT_STATEMENTS_COLS_V1_1, PG_STAT_STATEMENTS_COLS_V1_10, PG_STAT_STATEMENTS_COLS_V1_11, PG_STAT_STATEMENTS_COLS_V1_12, PG_STAT_STATEMENTS_COLS_V1_2, PG_STAT_STATEMENTS_COLS_V1_3, PG_STAT_STATEMENTS_COLS_V1_8, PG_STAT_STATEMENTS_COLS_V1_9, pgss, PGSS_EXEC, pgss_hash, PGSS_NUMKIND, PGSS_V1_0, PGSS_V1_1, PGSS_V1_10, PGSS_V1_11, PGSS_V1_12, PGSS_V1_2, PGSS_V1_3, PGSS_V1_8, PGSS_V1_9, qtext_fetch(), qtext_load_file(), pgssEntry::query_len, pgssEntry::query_offset, pgssHashKey::queryid, FunctionCallInfoBaseData::resultinfo, Counters::rows, ReturnSetInfo::setDesc, ReturnSetInfo::setResult, Counters::shared_blk_read_time, Counters::shared_blk_write_time, Counters::shared_blks_dirtied, Counters::shared_blks_hit, Counters::shared_blks_read, Counters::shared_blks_written, snprintf, SpinLockAcquire, SpinLockRelease, pgssEntry::stats_since, Counters::sum_var_time, Counters::temp_blk_read_time, Counters::temp_blk_write_time, Counters::temp_blks_read, Counters::temp_blks_written, TimestampTzGetDatum(), pgssHashKey::toplevel, Counters::total_time, tuplestore_putvalues(), UINT64_FORMAT, pgssHashKey::userid, values, Counters::wal_buffers_full, Counters::wal_bytes, Counters::wal_fpi, and Counters::wal_records.

Referenced by pg_stat_statements(), pg_stat_statements_1_10(), pg_stat_statements_1_11(), pg_stat_statements_1_12(), pg_stat_statements_1_2(), pg_stat_statements_1_3(), pg_stat_statements_1_8(), and pg_stat_statements_1_9().

◆ pg_stat_statements_reset()

Datum pg_stat_statements_reset ( PG_FUNCTION_ARGS  )

Definition at line 1556 of file pg_stat_statements.c.

1557{
1558 entry_reset(0, 0, 0, false);
1559
1561}
#define PG_RETURN_VOID()
Definition: fmgr.h:349
static TimestampTz entry_reset(Oid userid, Oid dbid, uint64 queryid, bool minmax_only)

References entry_reset(), and PG_RETURN_VOID.

◆ pg_stat_statements_reset_1_11()

Datum pg_stat_statements_reset_1_11 ( PG_FUNCTION_ARGS  )

Definition at line 1537 of file pg_stat_statements.c.

1538{
1539 Oid userid;
1540 Oid dbid;
1541 uint64 queryid;
1542 bool minmax_only;
1543
1544 userid = PG_GETARG_OID(0);
1545 dbid = PG_GETARG_OID(1);
1546 queryid = (uint64) PG_GETARG_INT64(2);
1547 minmax_only = PG_GETARG_BOOL(3);
1548
1549 PG_RETURN_TIMESTAMPTZ(entry_reset(userid, dbid, queryid, minmax_only));
1550}
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
#define PG_GETARG_INT64(n)
Definition: fmgr.h:283
#define PG_RETURN_TIMESTAMPTZ(x)
Definition: timestamp.h:68

References entry_reset(), PG_GETARG_BOOL, PG_GETARG_INT64, PG_GETARG_OID, and PG_RETURN_TIMESTAMPTZ.

◆ pg_stat_statements_reset_1_7()

Datum pg_stat_statements_reset_1_7 ( PG_FUNCTION_ARGS  )

Definition at line 1521 of file pg_stat_statements.c.

1522{
1523 Oid userid;
1524 Oid dbid;
1525 uint64 queryid;
1526
1527 userid = PG_GETARG_OID(0);
1528 dbid = PG_GETARG_OID(1);
1529 queryid = (uint64) PG_GETARG_INT64(2);
1530
1531 entry_reset(userid, dbid, queryid, false);
1532
1534}

References entry_reset(), PG_GETARG_INT64, PG_GETARG_OID, and PG_RETURN_VOID.

◆ pgss_ExecutorEnd()

static void pgss_ExecutorEnd ( QueryDesc queryDesc)
static

Definition at line 1077 of file pg_stat_statements.c.

1078{
1079 uint64 queryId = queryDesc->plannedstmt->queryId;
1080
1081 if (queryId != UINT64CONST(0) && queryDesc->totaltime &&
1083 {
1084 /*
1085 * Make sure stats accumulation is done. (Note: it's okay if several
1086 * levels of hook all do this.)
1087 */
1088 InstrEndLoop(queryDesc->totaltime);
1089
1090 pgss_store(queryDesc->sourceText,
1091 queryId,
1092 queryDesc->plannedstmt->stmt_location,
1093 queryDesc->plannedstmt->stmt_len,
1094 PGSS_EXEC,
1095 queryDesc->totaltime->total * 1000.0, /* convert to msec */
1096 queryDesc->estate->es_total_processed,
1097 &queryDesc->totaltime->bufusage,
1098 &queryDesc->totaltime->walusage,
1099 queryDesc->estate->es_jit ? &queryDesc->estate->es_jit->instr : NULL,
1100 NULL,
1103 }
1104
1105 if (prev_ExecutorEnd)
1106 prev_ExecutorEnd(queryDesc);
1107 else
1108 standard_ExecutorEnd(queryDesc);
1109}
void standard_ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:547
void InstrEndLoop(Instrumentation *instr)
Definition: instrument.c:140
static void pgss_store(const char *query, uint64 queryId, int query_location, int query_len, pgssStoreKind kind, double total_time, uint64 rows, const BufferUsage *bufusage, const WalUsage *walusage, const struct JitInstrumentation *jitusage, JumbleState *jstate, int parallel_workers_to_launch, int parallel_workers_launched)
#define pgss_enabled(level)
static int nesting_level
int es_parallel_workers_to_launch
Definition: execnodes.h:745
struct JitContext * es_jit
Definition: execnodes.h:763
uint64 es_total_processed
Definition: execnodes.h:714
int es_parallel_workers_launched
Definition: execnodes.h:747
WalUsage walusage
Definition: instrument.h:93
BufferUsage bufusage
Definition: instrument.h:92
JitInstrumentation instr
Definition: jit.h:62
ParseLoc stmt_len
Definition: plannodes.h:145
ParseLoc stmt_location
Definition: plannodes.h:143
uint64 queryId
Definition: plannodes.h:56
const char * sourceText
Definition: execdesc.h:39
EState * estate
Definition: execdesc.h:49
PlannedStmt * plannedstmt
Definition: execdesc.h:37
struct Instrumentation * totaltime
Definition: execdesc.h:56

References Instrumentation::bufusage, EState::es_jit, EState::es_parallel_workers_launched, EState::es_parallel_workers_to_launch, EState::es_total_processed, QueryDesc::estate, JitContext::instr, InstrEndLoop(), nesting_level, pgss_enabled, PGSS_EXEC, pgss_store(), QueryDesc::plannedstmt, prev_ExecutorEnd, PlannedStmt::queryId, QueryDesc::sourceText, standard_ExecutorEnd(), PlannedStmt::stmt_len, PlannedStmt::stmt_location, Instrumentation::total, QueryDesc::totaltime, UINT64CONST, and Instrumentation::walusage.

Referenced by _PG_init().

◆ pgss_ExecutorFinish()

static void pgss_ExecutorFinish ( QueryDesc queryDesc)
static

Definition at line 1056 of file pg_stat_statements.c.

1057{
1058 nesting_level++;
1059 PG_TRY();
1060 {
1062 prev_ExecutorFinish(queryDesc);
1063 else
1064 standard_ExecutorFinish(queryDesc);
1065 }
1066 PG_FINALLY();
1067 {
1068 nesting_level--;
1069 }
1070 PG_END_TRY();
1071}
#define PG_TRY(...)
Definition: elog.h:371
#define PG_END_TRY(...)
Definition: elog.h:396
#define PG_FINALLY(...)
Definition: elog.h:388
void standard_ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:484

References nesting_level, PG_END_TRY, PG_FINALLY, PG_TRY, prev_ExecutorFinish, and standard_ExecutorFinish().

Referenced by _PG_init().

◆ pgss_ExecutorRun()

static void pgss_ExecutorRun ( QueryDesc queryDesc,
ScanDirection  direction,
uint64  count 
)
static

Definition at line 1035 of file pg_stat_statements.c.

1036{
1037 nesting_level++;
1038 PG_TRY();
1039 {
1040 if (prev_ExecutorRun)
1041 prev_ExecutorRun(queryDesc, direction, count);
1042 else
1043 standard_ExecutorRun(queryDesc, direction, count);
1044 }
1045 PG_FINALLY();
1046 {
1047 nesting_level--;
1048 }
1049 PG_END_TRY();
1050}
void standard_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count)
Definition: execMain.c:375

References nesting_level, PG_END_TRY, PG_FINALLY, PG_TRY, prev_ExecutorRun, and standard_ExecutorRun().

Referenced by _PG_init().

◆ pgss_ExecutorStart()

static bool pgss_ExecutorStart ( QueryDesc queryDesc,
int  eflags 
)
static

Definition at line 993 of file pg_stat_statements.c.

994{
995 bool plan_valid;
996
998 plan_valid = prev_ExecutorStart(queryDesc, eflags);
999 else
1000 plan_valid = standard_ExecutorStart(queryDesc, eflags);
1001
1002 /* The plan may have become invalid during standard_ExecutorStart() */
1003 if (!plan_valid)
1004 return false;
1005
1006 /*
1007 * If query has queryId zero, don't track it. This prevents double
1008 * counting of optimizable statements that are directly contained in
1009 * utility statements.
1010 */
1011 if (pgss_enabled(nesting_level) && queryDesc->plannedstmt->queryId != UINT64CONST(0))
1012 {
1013 /*
1014 * Set up to track total elapsed time in ExecutorRun. Make sure the
1015 * space is allocated in the per-query context so it will go away at
1016 * ExecutorEnd.
1017 */
1018 if (queryDesc->totaltime == NULL)
1019 {
1020 MemoryContext oldcxt;
1021
1022 oldcxt = MemoryContextSwitchTo(queryDesc->estate->es_query_cxt);
1023 queryDesc->totaltime = InstrAlloc(1, INSTRUMENT_ALL, false);
1024 MemoryContextSwitchTo(oldcxt);
1025 }
1026 }
1027
1028 return true;
1029}
bool standard_ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:151
Instrumentation * InstrAlloc(int n, int instrument_options, bool async_mode)
Definition: instrument.c:31
@ INSTRUMENT_ALL
Definition: instrument.h:66
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
MemoryContext es_query_cxt
Definition: execnodes.h:708

References EState::es_query_cxt, QueryDesc::estate, InstrAlloc(), INSTRUMENT_ALL, MemoryContextSwitchTo(), nesting_level, pgss_enabled, QueryDesc::plannedstmt, prev_ExecutorStart, PlannedStmt::queryId, standard_ExecutorStart(), QueryDesc::totaltime, and UINT64CONST.

Referenced by _PG_init().

◆ pgss_memsize()

static Size pgss_memsize ( void  )
static

Definition at line 2058 of file pg_stat_statements.c.

2059{
2060 Size size;
2061
2062 size = MAXALIGN(sizeof(pgssSharedState));
2063 size = add_size(size, hash_estimate_size(pgss_max, sizeof(pgssEntry)));
2064
2065 return size;
2066}
#define MAXALIGN(LEN)
Definition: c.h:782
Size hash_estimate_size(long num_entries, Size entrysize)
Definition: dynahash.c:784
Size add_size(Size s1, Size s2)
Definition: shmem.c:493

References add_size(), hash_estimate_size(), MAXALIGN, and pgss_max.

Referenced by pgss_shmem_request().

◆ pgss_planner()

static PlannedStmt * pgss_planner ( Query parse,
const char *  query_string,
int  cursorOptions,
ParamListInfo  boundParams 
)
static

Definition at line 888 of file pg_stat_statements.c.

892{
893 PlannedStmt *result;
894
895 /*
896 * We can't process the query if no query_string is provided, as
897 * pgss_store needs it. We also ignore query without queryid, as it would
898 * be treated as a utility statement, which may not be the case.
899 */
901 && pgss_track_planning && query_string
902 && parse->queryId != UINT64CONST(0))
903 {
906 BufferUsage bufusage_start,
907 bufusage;
908 WalUsage walusage_start,
909 walusage;
910
911 /* We need to track buffer usage as the planner can access them. */
912 bufusage_start = pgBufferUsage;
913
914 /*
915 * Similarly the planner could write some WAL records in some cases
916 * (e.g. setting a hint bit with those being WAL-logged)
917 */
918 walusage_start = pgWalUsage;
920
922 PG_TRY();
923 {
925 result = prev_planner_hook(parse, query_string, cursorOptions,
926 boundParams);
927 else
928 result = standard_planner(parse, query_string, cursorOptions,
929 boundParams);
930 }
931 PG_FINALLY();
932 {
934 }
935 PG_END_TRY();
936
939
940 /* calc differences of buffer counters. */
941 memset(&bufusage, 0, sizeof(BufferUsage));
942 BufferUsageAccumDiff(&bufusage, &pgBufferUsage, &bufusage_start);
943
944 /* calc differences of WAL counters. */
945 memset(&walusage, 0, sizeof(WalUsage));
946 WalUsageAccumDiff(&walusage, &pgWalUsage, &walusage_start);
947
948 pgss_store(query_string,
949 parse->queryId,
950 parse->stmt_location,
951 parse->stmt_len,
952 PGSS_PLAN,
954 0,
955 &bufusage,
956 &walusage,
957 NULL,
958 NULL,
959 0,
960 0);
961 }
962 else
963 {
964 /*
965 * Even though we're not tracking plan time for this statement, we
966 * must still increment the nesting level, to ensure that functions
967 * evaluated during planning are not seen as top-level calls.
968 */
970 PG_TRY();
971 {
973 result = prev_planner_hook(parse, query_string, cursorOptions,
974 boundParams);
975 else
976 result = standard_planner(parse, query_string, cursorOptions,
977 boundParams);
978 }
979 PG_FINALLY();
980 {
982 }
983 PG_END_TRY();
984 }
985
986 return result;
987}
return str start
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:122
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:181
#define INSTR_TIME_GET_MILLISEC(t)
Definition: instr_time.h:191
WalUsage pgWalUsage
Definition: instrument.c:22
void WalUsageAccumDiff(WalUsage *dst, const WalUsage *add, const WalUsage *sub)
Definition: instrument.c:287
BufferUsage pgBufferUsage
Definition: instrument.c:20
void BufferUsageAccumDiff(BufferUsage *dst, const BufferUsage *add, const BufferUsage *sub)
Definition: instrument.c:248
static int duration
Definition: pgbench.c:175
PlannedStmt * standard_planner(Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams)
Definition: planner.c:302
static struct subre * parse(struct vars *v, int stopper, int type, struct state *init, struct state *final)
Definition: regcomp.c:717

References BufferUsageAccumDiff(), duration, INSTR_TIME_GET_MILLISEC, INSTR_TIME_SET_CURRENT, INSTR_TIME_SUBTRACT, nesting_level, parse(), PG_END_TRY, PG_FINALLY, PG_TRY, pgBufferUsage, pgss_enabled, PGSS_PLAN, pgss_store(), pgss_track_planning, pgWalUsage, prev_planner_hook, standard_planner(), start, UINT64CONST, and WalUsageAccumDiff().

Referenced by _PG_init().

◆ pgss_post_parse_analyze()

static void pgss_post_parse_analyze ( ParseState pstate,
Query query,
JumbleState jstate 
)
static

Definition at line 836 of file pg_stat_statements.c.

837{
839 prev_post_parse_analyze_hook(pstate, query, jstate);
840
841 /* Safety check... */
843 return;
844
845 /*
846 * If it's EXECUTE, clear the queryId so that stats will accumulate for
847 * the underlying PREPARE. But don't do this if we're not tracking
848 * utility statements, to avoid messing up another extension that might be
849 * tracking them.
850 */
851 if (query->utilityStmt)
852 {
854 {
855 query->queryId = UINT64CONST(0);
856 return;
857 }
858 }
859
860 /*
861 * If query jumbling were able to identify any ignorable constants, we
862 * immediately create a hash table entry for the query, so that we can
863 * record the normalized form of the query string. If there were no such
864 * constants, the normalized string would be the same as the query text
865 * anyway, so there's no need for an early entry.
866 */
867 if (jstate && jstate->clocations_count > 0)
868 pgss_store(pstate->p_sourcetext,
869 query->queryId,
870 query->stmt_location,
871 query->stmt_len,
873 0,
874 0,
875 NULL,
876 NULL,
877 NULL,
878 jstate,
879 0,
880 0);
881}
#define IsA(nodeptr, _type_)
Definition: nodes.h:164
const char * p_sourcetext
Definition: parse_node.h:209
Node * utilityStmt
Definition: parsenodes.h:136
ParseLoc stmt_location
Definition: parsenodes.h:249

References JumbleState::clocations_count, IsA, nesting_level, ParseState::p_sourcetext, pgss, pgss_enabled, pgss_hash, PGSS_INVALID, pgss_store(), pgss_track_utility, prev_post_parse_analyze_hook, Query::stmt_location, UINT64CONST, and Query::utilityStmt.

Referenced by _PG_init().

◆ pgss_ProcessUtility()

static void pgss_ProcessUtility ( PlannedStmt pstmt,
const char *  queryString,
bool  readOnlyTree,
ProcessUtilityContext  context,
ParamListInfo  params,
QueryEnvironment queryEnv,
DestReceiver dest,
QueryCompletion qc 
)
static

Definition at line 1115 of file pg_stat_statements.c.

1120{
1121 Node *parsetree = pstmt->utilityStmt;
1122 uint64 saved_queryId = pstmt->queryId;
1123 int saved_stmt_location = pstmt->stmt_location;
1124 int saved_stmt_len = pstmt->stmt_len;
1126
1127 /*
1128 * Force utility statements to get queryId zero. We do this even in cases
1129 * where the statement contains an optimizable statement for which a
1130 * queryId could be derived (such as EXPLAIN or DECLARE CURSOR). For such
1131 * cases, runtime control will first go through ProcessUtility and then
1132 * the executor, and we don't want the executor hooks to do anything,
1133 * since we are already measuring the statement's costs at the utility
1134 * level.
1135 *
1136 * Note that this is only done if pg_stat_statements is enabled and
1137 * configured to track utility statements, in the unlikely possibility
1138 * that user configured another extension to handle utility statements
1139 * only.
1140 */
1141 if (enabled)
1142 pstmt->queryId = UINT64CONST(0);
1143
1144 /*
1145 * If it's an EXECUTE statement, we don't track it and don't increment the
1146 * nesting level. This allows the cycles to be charged to the underlying
1147 * PREPARE instead (by the Executor hooks), which is much more useful.
1148 *
1149 * We also don't track execution of PREPARE. If we did, we would get one
1150 * hash table entry for the PREPARE (with hash calculated from the query
1151 * string), and then a different one with the same query string (but hash
1152 * calculated from the query tree) would be used to accumulate costs of
1153 * ensuing EXECUTEs. This would be confusing. Since PREPARE doesn't
1154 * actually run the planner (only parse+rewrite), its costs are generally
1155 * pretty negligible and it seems okay to just ignore it.
1156 */
1157 if (enabled &&
1158 !IsA(parsetree, ExecuteStmt) &&
1159 !IsA(parsetree, PrepareStmt))
1160 {
1163 uint64 rows;
1164 BufferUsage bufusage_start,
1165 bufusage;
1166 WalUsage walusage_start,
1167 walusage;
1168
1169 bufusage_start = pgBufferUsage;
1170 walusage_start = pgWalUsage;
1172
1173 nesting_level++;
1174 PG_TRY();
1175 {
1177 prev_ProcessUtility(pstmt, queryString, readOnlyTree,
1178 context, params, queryEnv,
1179 dest, qc);
1180 else
1181 standard_ProcessUtility(pstmt, queryString, readOnlyTree,
1182 context, params, queryEnv,
1183 dest, qc);
1184 }
1185 PG_FINALLY();
1186 {
1187 nesting_level--;
1188 }
1189 PG_END_TRY();
1190
1191 /*
1192 * CAUTION: do not access the *pstmt data structure again below here.
1193 * If it was a ROLLBACK or similar, that data structure may have been
1194 * freed. We must copy everything we still need into local variables,
1195 * which we did above.
1196 *
1197 * For the same reason, we can't risk restoring pstmt->queryId to its
1198 * former value, which'd otherwise be a good idea.
1199 */
1200
1203
1204 /*
1205 * Track the total number of rows retrieved or affected by the utility
1206 * statements of COPY, FETCH, CREATE TABLE AS, CREATE MATERIALIZED
1207 * VIEW, REFRESH MATERIALIZED VIEW and SELECT INTO.
1208 */
1209 rows = (qc && (qc->commandTag == CMDTAG_COPY ||
1210 qc->commandTag == CMDTAG_FETCH ||
1211 qc->commandTag == CMDTAG_SELECT ||
1212 qc->commandTag == CMDTAG_REFRESH_MATERIALIZED_VIEW)) ?
1213 qc->nprocessed : 0;
1214
1215 /* calc differences of buffer counters. */
1216 memset(&bufusage, 0, sizeof(BufferUsage));
1217 BufferUsageAccumDiff(&bufusage, &pgBufferUsage, &bufusage_start);
1218
1219 /* calc differences of WAL counters. */
1220 memset(&walusage, 0, sizeof(WalUsage));
1221 WalUsageAccumDiff(&walusage, &pgWalUsage, &walusage_start);
1222
1223 pgss_store(queryString,
1224 saved_queryId,
1225 saved_stmt_location,
1226 saved_stmt_len,
1227 PGSS_EXEC,
1229 rows,
1230 &bufusage,
1231 &walusage,
1232 NULL,
1233 NULL,
1234 0,
1235 0);
1236 }
1237 else
1238 {
1239 /*
1240 * Even though we're not tracking execution time for this statement,
1241 * we must still increment the nesting level, to ensure that functions
1242 * evaluated within it are not seen as top-level calls. But don't do
1243 * so for EXECUTE; that way, when control reaches pgss_planner or
1244 * pgss_ExecutorStart, we will treat the costs as top-level if
1245 * appropriate. Likewise, don't bump for PREPARE, so that parse
1246 * analysis will treat the statement as top-level if appropriate.
1247 *
1248 * To be absolutely certain we don't mess up the nesting level,
1249 * evaluate the bump_level condition just once.
1250 */
1251 bool bump_level =
1252 !IsA(parsetree, ExecuteStmt) &&
1253 !IsA(parsetree, PrepareStmt);
1254
1255 if (bump_level)
1256 nesting_level++;
1257 PG_TRY();
1258 {
1260 prev_ProcessUtility(pstmt, queryString, readOnlyTree,
1261 context, params, queryEnv,
1262 dest, qc);
1263 else
1264 standard_ProcessUtility(pstmt, queryString, readOnlyTree,
1265 context, params, queryEnv,
1266 dest, qc);
1267 }
1268 PG_FINALLY();
1269 {
1270 if (bump_level)
1271 nesting_level--;
1272 }
1273 PG_END_TRY();
1274 }
1275}
Definition: nodes.h:135
Node * utilityStmt
Definition: plannodes.h:139
uint64 nprocessed
Definition: cmdtag.h:32
CommandTag commandTag
Definition: cmdtag.h:31
void standard_ProcessUtility(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc)
Definition: utility.c:543

References BufferUsageAccumDiff(), QueryCompletion::commandTag, generate_unaccent_rules::dest, duration, INSTR_TIME_GET_MILLISEC, INSTR_TIME_SET_CURRENT, INSTR_TIME_SUBTRACT, IsA, nesting_level, QueryCompletion::nprocessed, PG_END_TRY, PG_FINALLY, PG_TRY, pgBufferUsage, pgss_enabled, PGSS_EXEC, pgss_store(), pgss_track_utility, pgWalUsage, prev_ProcessUtility, PlannedStmt::queryId, standard_ProcessUtility(), start, PlannedStmt::stmt_len, PlannedStmt::stmt_location, UINT64CONST, PlannedStmt::utilityStmt, and WalUsageAccumDiff().

Referenced by _PG_init().

◆ pgss_shmem_request()

static void pgss_shmem_request ( void  )
static

Definition at line 495 of file pg_stat_statements.c.

496{
499
501 RequestNamedLWLockTranche("pg_stat_statements", 1);
502}
void RequestAddinShmemSpace(Size size)
Definition: ipci.c:75
void RequestNamedLWLockTranche(const char *tranche_name, int num_lwlocks)
Definition: lwlock.c:684
static Size pgss_memsize(void)

References pgss_memsize(), prev_shmem_request_hook, RequestAddinShmemSpace(), and RequestNamedLWLockTranche().

Referenced by _PG_init().

◆ pgss_shmem_shutdown()

static void pgss_shmem_shutdown ( int  code,
Datum  arg 
)
static

Definition at line 737 of file pg_stat_statements.c.

738{
739 FILE *file;
740 char *qbuffer = NULL;
741 Size qbuffer_size = 0;
742 HASH_SEQ_STATUS hash_seq;
743 int32 num_entries;
744 pgssEntry *entry;
745
746 /* Don't try to dump during a crash. */
747 if (code)
748 return;
749
750 /* Safety check ... shouldn't get here unless shmem is set up. */
751 if (!pgss || !pgss_hash)
752 return;
753
754 /* Don't dump if told not to. */
755 if (!pgss_save)
756 return;
757
759 if (file == NULL)
760 goto error;
761
762 if (fwrite(&PGSS_FILE_HEADER, sizeof(uint32), 1, file) != 1)
763 goto error;
764 if (fwrite(&PGSS_PG_MAJOR_VERSION, sizeof(uint32), 1, file) != 1)
765 goto error;
766 num_entries = hash_get_num_entries(pgss_hash);
767 if (fwrite(&num_entries, sizeof(int32), 1, file) != 1)
768 goto error;
769
770 qbuffer = qtext_load_file(&qbuffer_size);
771 if (qbuffer == NULL)
772 goto error;
773
774 /*
775 * When serializing to disk, we store query texts immediately after their
776 * entry data. Any orphaned query texts are thereby excluded.
777 */
778 hash_seq_init(&hash_seq, pgss_hash);
779 while ((entry = hash_seq_search(&hash_seq)) != NULL)
780 {
781 int len = entry->query_len;
782 char *qstr = qtext_fetch(entry->query_offset, len,
783 qbuffer, qbuffer_size);
784
785 if (qstr == NULL)
786 continue; /* Ignore any entries with bogus texts */
787
788 if (fwrite(entry, sizeof(pgssEntry), 1, file) != 1 ||
789 fwrite(qstr, 1, len + 1, file) != len + 1)
790 {
791 /* note: we assume hash_seq_term won't change errno */
792 hash_seq_term(&hash_seq);
793 goto error;
794 }
795 }
796
797 /* Dump global statistics for pg_stat_statements */
798 if (fwrite(&pgss->stats, sizeof(pgssGlobalStats), 1, file) != 1)
799 goto error;
800
801 free(qbuffer);
802 qbuffer = NULL;
803
804 if (FreeFile(file))
805 {
806 file = NULL;
807 goto error;
808 }
809
810 /*
811 * Rename file into place, so we atomically replace any old one.
812 */
814
815 /* Unlink query-texts file; it's not needed while shutdown */
816 unlink(PGSS_TEXT_FILE);
817
818 return;
819
820error:
821 ereport(LOG,
823 errmsg("could not write file \"%s\": %m",
824 PGSS_DUMP_FILE ".tmp")));
825 free(qbuffer);
826 if (file)
827 FreeFile(file);
828 unlink(PGSS_DUMP_FILE ".tmp");
829 unlink(PGSS_TEXT_FILE);
830}
int32_t int32
Definition: c.h:498
uint32_t uint32
Definition: c.h:502
int durable_rename(const char *oldfile, const char *newfile, int elevel)
Definition: fd.c:782
const void size_t len
#define PGSS_DUMP_FILE
static const uint32 PGSS_PG_MAJOR_VERSION
static const uint32 PGSS_FILE_HEADER
static void error(void)
Definition: sql-dyntest.c:147

References AllocateFile(), durable_rename(), ereport, errcode_for_file_access(), errmsg(), error(), free, FreeFile(), hash_get_num_entries(), hash_seq_init(), hash_seq_search(), hash_seq_term(), len, LOG, PG_BINARY_W, pgss, PGSS_DUMP_FILE, PGSS_FILE_HEADER, pgss_hash, PGSS_PG_MAJOR_VERSION, pgss_save, PGSS_TEXT_FILE, qtext_fetch(), qtext_load_file(), pgssEntry::query_len, pgssEntry::query_offset, and pgssSharedState::stats.

Referenced by pgss_shmem_startup().

◆ pgss_shmem_startup()

static void pgss_shmem_startup ( void  )
static

Definition at line 511 of file pg_stat_statements.c.

512{
513 bool found;
514 HASHCTL info;
515 FILE *file = NULL;
516 FILE *qfile = NULL;
517 uint32 header;
518 int32 num;
519 int32 pgver;
520 int32 i;
521 int buffer_size;
522 char *buffer = NULL;
523
526
527 /* reset in case this is a restart within the postmaster */
528 pgss = NULL;
529 pgss_hash = NULL;
530
531 /*
532 * Create or attach to the shared memory state, including hash table
533 */
534 LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE);
535
536 pgss = ShmemInitStruct("pg_stat_statements",
537 sizeof(pgssSharedState),
538 &found);
539
540 if (!found)
541 {
542 /* First time through ... */
543 pgss->lock = &(GetNamedLWLockTranche("pg_stat_statements"))->lock;
547 pgss->extent = 0;
548 pgss->n_writers = 0;
549 pgss->gc_count = 0;
550 pgss->stats.dealloc = 0;
552 }
553
554 info.keysize = sizeof(pgssHashKey);
555 info.entrysize = sizeof(pgssEntry);
556 pgss_hash = ShmemInitHash("pg_stat_statements hash",
558 &info,
560
561 LWLockRelease(AddinShmemInitLock);
562
563 /*
564 * If we're in the postmaster (or a standalone backend...), set up a shmem
565 * exit hook to dump the statistics to disk.
566 */
569
570 /*
571 * Done if some other process already completed our initialization.
572 */
573 if (found)
574 return;
575
576 /*
577 * Note: we don't bother with locks here, because there should be no other
578 * processes running when this code is reached.
579 */
580
581 /* Unlink query text file possibly left over from crash */
582 unlink(PGSS_TEXT_FILE);
583
584 /* Allocate new query text temp file */
586 if (qfile == NULL)
587 goto write_error;
588
589 /*
590 * If we were told not to load old statistics, we're done. (Note we do
591 * not try to unlink any old dump file in this case. This seems a bit
592 * questionable but it's the historical behavior.)
593 */
594 if (!pgss_save)
595 {
596 FreeFile(qfile);
597 return;
598 }
599
600 /*
601 * Attempt to load old statistics from the dump file.
602 */
604 if (file == NULL)
605 {
606 if (errno != ENOENT)
607 goto read_error;
608 /* No existing persisted stats file, so we're done */
609 FreeFile(qfile);
610 return;
611 }
612
613 buffer_size = 2048;
614 buffer = (char *) palloc(buffer_size);
615
616 if (fread(&header, sizeof(uint32), 1, file) != 1 ||
617 fread(&pgver, sizeof(uint32), 1, file) != 1 ||
618 fread(&num, sizeof(int32), 1, file) != 1)
619 goto read_error;
620
621 if (header != PGSS_FILE_HEADER ||
622 pgver != PGSS_PG_MAJOR_VERSION)
623 goto data_error;
624
625 for (i = 0; i < num; i++)
626 {
627 pgssEntry temp;
628 pgssEntry *entry;
629 Size query_offset;
630
631 if (fread(&temp, sizeof(pgssEntry), 1, file) != 1)
632 goto read_error;
633
634 /* Encoding is the only field we can easily sanity-check */
636 goto data_error;
637
638 /* Resize buffer as needed */
639 if (temp.query_len >= buffer_size)
640 {
641 buffer_size = Max(buffer_size * 2, temp.query_len + 1);
642 buffer = repalloc(buffer, buffer_size);
643 }
644
645 if (fread(buffer, 1, temp.query_len + 1, file) != temp.query_len + 1)
646 goto read_error;
647
648 /* Should have a trailing null, but let's make sure */
649 buffer[temp.query_len] = '\0';
650
651 /* Skip loading "sticky" entries */
652 if (IS_STICKY(temp.counters))
653 continue;
654
655 /* Store the query text */
656 query_offset = pgss->extent;
657 if (fwrite(buffer, 1, temp.query_len + 1, qfile) != temp.query_len + 1)
658 goto write_error;
659 pgss->extent += temp.query_len + 1;
660
661 /* make the hashtable entry (discards old entries if too many) */
662 entry = entry_alloc(&temp.key, query_offset, temp.query_len,
663 temp.encoding,
664 false);
665
666 /* copy in the actual stats */
667 entry->counters = temp.counters;
668 entry->stats_since = temp.stats_since;
670 }
671
672 /* Read global statistics for pg_stat_statements */
673 if (fread(&pgss->stats, sizeof(pgssGlobalStats), 1, file) != 1)
674 goto read_error;
675
676 pfree(buffer);
677 FreeFile(file);
678 FreeFile(qfile);
679
680 /*
681 * Remove the persisted stats file so it's not included in
682 * backups/replication standbys, etc. A new file will be written on next
683 * shutdown.
684 *
685 * Note: it's okay if the PGSS_TEXT_FILE is included in a basebackup,
686 * because we remove that file on startup; it acts inversely to
687 * PGSS_DUMP_FILE, in that it is only supposed to be around when the
688 * server is running, whereas PGSS_DUMP_FILE is only supposed to be around
689 * when the server is not running. Leaving the file creates no danger of
690 * a newly restored database having a spurious record of execution costs,
691 * which is what we're really concerned about here.
692 */
693 unlink(PGSS_DUMP_FILE);
694
695 return;
696
697read_error:
698 ereport(LOG,
700 errmsg("could not read file \"%s\": %m",
702 goto fail;
703data_error:
704 ereport(LOG,
705 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
706 errmsg("ignoring invalid data in file \"%s\"",
708 goto fail;
709write_error:
710 ereport(LOG,
712 errmsg("could not write file \"%s\": %m",
714fail:
715 if (buffer)
716 pfree(buffer);
717 if (file)
718 FreeFile(file);
719 if (qfile)
720 FreeFile(qfile);
721 /* If possible, throw away the bogus file; ignore any error */
722 unlink(PGSS_DUMP_FILE);
723
724 /*
725 * Don't unlink PGSS_TEXT_FILE here; it should always be around while the
726 * server is running with pg_stat_statements enabled
727 */
728}
#define PG_BINARY_R
Definition: c.h:1246
bool IsUnderPostmaster
Definition: globals.c:121
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:365
LWLockPadded * GetNamedLWLockTranche(const char *tranche_name)
Definition: lwlock.c:587
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:2172
#define ASSUMED_MEDIAN_INIT
struct pgssEntry pgssEntry
struct pgssHashKey pgssHashKey
static pgssEntry * entry_alloc(pgssHashKey *key, Size query_offset, int query_len, int encoding, bool sticky)
static void pgss_shmem_shutdown(int code, Datum arg)
#define PG_VALID_BE_ENCODING(_enc)
Definition: pg_wchar.h:281
HTAB * ShmemInitHash(const char *name, long init_size, long max_size, HASHCTL *infoP, int hash_flags)
Definition: shmem.c:332
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:387
Size keysize
Definition: hsearch.h:75
Size entrysize
Definition: hsearch.h:76

References AllocateFile(), ASSUMED_LENGTH_INIT, ASSUMED_MEDIAN_INIT, pgssEntry::counters, pgssSharedState::cur_median_usage, pgssGlobalStats::dealloc, pgssEntry::encoding, entry_alloc(), HASHCTL::entrysize, ereport, errcode(), errcode_for_file_access(), errmsg(), pgssSharedState::extent, FreeFile(), pgssSharedState::gc_count, GetCurrentTimestamp(), GetNamedLWLockTranche(), HASH_BLOBS, HASH_ELEM, i, IS_STICKY, IsUnderPostmaster, pgssEntry::key, HASHCTL::keysize, pgssSharedState::lock, LOG, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), Max, pgssSharedState::mean_query_len, pgssEntry::minmax_stats_since, pgssSharedState::mutex, pgssSharedState::n_writers, on_shmem_exit(), palloc(), pfree(), PG_BINARY_R, PG_BINARY_W, PG_VALID_BE_ENCODING, pgss, PGSS_DUMP_FILE, PGSS_FILE_HEADER, pgss_hash, pgss_max, PGSS_PG_MAJOR_VERSION, pgss_save, pgss_shmem_shutdown(), PGSS_TEXT_FILE, prev_shmem_startup_hook, pgssEntry::query_len, repalloc(), ShmemInitHash(), ShmemInitStruct(), SpinLockInit, pgssSharedState::stats, pgssGlobalStats::stats_reset, and pgssEntry::stats_since.

Referenced by _PG_init().

◆ pgss_store()

static void pgss_store ( const char *  query,
uint64  queryId,
int  query_location,
int  query_len,
pgssStoreKind  kind,
double  total_time,
uint64  rows,
const BufferUsage bufusage,
const WalUsage walusage,
const struct JitInstrumentation jitusage,
JumbleState jstate,
int  parallel_workers_to_launch,
int  parallel_workers_launched 
)
static

Definition at line 1289 of file pg_stat_statements.c.

1299{
1301 pgssEntry *entry;
1302 char *norm_query = NULL;
1304
1305 Assert(query != NULL);
1306
1307 /* Safety check... */
1308 if (!pgss || !pgss_hash)
1309 return;
1310
1311 /*
1312 * Nothing to do if compute_query_id isn't enabled and no other module
1313 * computed a query identifier.
1314 */
1315 if (queryId == UINT64CONST(0))
1316 return;
1317
1318 /*
1319 * Confine our attention to the relevant part of the string, if the query
1320 * is a portion of a multi-statement source string, and update query
1321 * location and length if needed.
1322 */
1323 query = CleanQuerytext(query, &query_location, &query_len);
1324
1325 /* Set up key for hashtable search */
1326
1327 /* clear padding */
1328 memset(&key, 0, sizeof(pgssHashKey));
1329
1330 key.userid = GetUserId();
1331 key.dbid = MyDatabaseId;
1332 key.queryid = queryId;
1333 key.toplevel = (nesting_level == 0);
1334
1335 /* Lookup the hash table entry with shared lock. */
1337
1338 entry = (pgssEntry *) hash_search(pgss_hash, &key, HASH_FIND, NULL);
1339
1340 /* Create new entry, if not present */
1341 if (!entry)
1342 {
1343 Size query_offset;
1344 int gc_count;
1345 bool stored;
1346 bool do_gc;
1347
1348 /*
1349 * Create a new, normalized query string if caller asked. We don't
1350 * need to hold the lock while doing this work. (Note: in any case,
1351 * it's possible that someone else creates a duplicate hashtable entry
1352 * in the interval where we don't hold the lock below. That case is
1353 * handled by entry_alloc.)
1354 */
1355 if (jstate)
1356 {
1358 norm_query = generate_normalized_query(jstate, query,
1359 query_location,
1360 &query_len);
1362 }
1363
1364 /* Append new query text to file with only shared lock held */
1365 stored = qtext_store(norm_query ? norm_query : query, query_len,
1366 &query_offset, &gc_count);
1367
1368 /*
1369 * Determine whether we need to garbage collect external query texts
1370 * while the shared lock is still held. This micro-optimization
1371 * avoids taking the time to decide this while holding exclusive lock.
1372 */
1373 do_gc = need_gc_qtexts();
1374
1375 /* Need exclusive lock to make a new hashtable entry - promote */
1378
1379 /*
1380 * A garbage collection may have occurred while we weren't holding the
1381 * lock. In the unlikely event that this happens, the query text we
1382 * stored above will have been garbage collected, so write it again.
1383 * This should be infrequent enough that doing it while holding
1384 * exclusive lock isn't a performance problem.
1385 */
1386 if (!stored || pgss->gc_count != gc_count)
1387 stored = qtext_store(norm_query ? norm_query : query, query_len,
1388 &query_offset, NULL);
1389
1390 /* If we failed to write to the text file, give up */
1391 if (!stored)
1392 goto done;
1393
1394 /* OK to create a new hashtable entry */
1395 entry = entry_alloc(&key, query_offset, query_len, encoding,
1396 jstate != NULL);
1397
1398 /* If needed, perform garbage collection while exclusive lock held */
1399 if (do_gc)
1400 gc_qtexts();
1401 }
1402
1403 /* Increment the counts, except when jstate is not NULL */
1404 if (!jstate)
1405 {
1406 Assert(kind == PGSS_PLAN || kind == PGSS_EXEC);
1407
1408 /*
1409 * Grab the spinlock while updating the counters (see comment about
1410 * locking rules at the head of the file)
1411 */
1412 SpinLockAcquire(&entry->mutex);
1413
1414 /* "Unstick" entry if it was previously sticky */
1415 if (IS_STICKY(entry->counters))
1416 entry->counters.usage = USAGE_INIT;
1417
1418 entry->counters.calls[kind] += 1;
1419 entry->counters.total_time[kind] += total_time;
1420
1421 if (entry->counters.calls[kind] == 1)
1422 {
1423 entry->counters.min_time[kind] = total_time;
1424 entry->counters.max_time[kind] = total_time;
1425 entry->counters.mean_time[kind] = total_time;
1426 }
1427 else
1428 {
1429 /*
1430 * Welford's method for accurately computing variance. See
1431 * <http://www.johndcook.com/blog/standard_deviation/>
1432 */
1433 double old_mean = entry->counters.mean_time[kind];
1434
1435 entry->counters.mean_time[kind] +=
1436 (total_time - old_mean) / entry->counters.calls[kind];
1437 entry->counters.sum_var_time[kind] +=
1438 (total_time - old_mean) * (total_time - entry->counters.mean_time[kind]);
1439
1440 /*
1441 * Calculate min and max time. min = 0 and max = 0 means that the
1442 * min/max statistics were reset
1443 */
1444 if (entry->counters.min_time[kind] == 0
1445 && entry->counters.max_time[kind] == 0)
1446 {
1447 entry->counters.min_time[kind] = total_time;
1448 entry->counters.max_time[kind] = total_time;
1449 }
1450 else
1451 {
1452 if (entry->counters.min_time[kind] > total_time)
1453 entry->counters.min_time[kind] = total_time;
1454 if (entry->counters.max_time[kind] < total_time)
1455 entry->counters.max_time[kind] = total_time;
1456 }
1457 }
1458 entry->counters.rows += rows;
1459 entry->counters.shared_blks_hit += bufusage->shared_blks_hit;
1460 entry->counters.shared_blks_read += bufusage->shared_blks_read;
1463 entry->counters.local_blks_hit += bufusage->local_blks_hit;
1464 entry->counters.local_blks_read += bufusage->local_blks_read;
1467 entry->counters.temp_blks_read += bufusage->temp_blks_read;
1468 entry->counters.temp_blks_written += bufusage->temp_blks_written;
1475 entry->counters.usage += USAGE_EXEC(total_time);
1476 entry->counters.wal_records += walusage->wal_records;
1477 entry->counters.wal_fpi += walusage->wal_fpi;
1478 entry->counters.wal_bytes += walusage->wal_bytes;
1479 entry->counters.wal_buffers_full += walusage->wal_buffers_full;
1480 if (jitusage)
1481 {
1482 entry->counters.jit_functions += jitusage->created_functions;
1484
1486 entry->counters.jit_deform_count++;
1488
1492
1496
1500 }
1501
1502 /* parallel worker counters */
1503 entry->counters.parallel_workers_to_launch += parallel_workers_to_launch;
1504 entry->counters.parallel_workers_launched += parallel_workers_launched;
1505
1506 SpinLockRelease(&entry->mutex);
1507 }
1508
1509done:
1511
1512 /* We postpone this clean-up until we're out of the lock */
1513 if (norm_query)
1514 pfree(norm_query);
1515}
Oid MyDatabaseId
Definition: globals.c:95
int GetDatabaseEncoding(void)
Definition: mbutils.c:1261
static void gc_qtexts(void)
static bool qtext_store(const char *query, int query_len, Size *query_offset, int *gc_count)
#define USAGE_EXEC(duration)
static char * generate_normalized_query(JumbleState *jstate, const char *query, int query_loc, int *query_len_p)
const char * CleanQuerytext(const char *query, int *location, int *len)
instr_time local_blk_read_time
Definition: instrument.h:38
int64 shared_blks_dirtied
Definition: instrument.h:28
int64 local_blks_hit
Definition: instrument.h:30
instr_time temp_blk_write_time
Definition: instrument.h:41
instr_time shared_blk_read_time
Definition: instrument.h:36
instr_time shared_blk_write_time
Definition: instrument.h:37
int64 local_blks_written
Definition: instrument.h:33
instr_time temp_blk_read_time
Definition: instrument.h:40
instr_time local_blk_write_time
Definition: instrument.h:39
int64 temp_blks_read
Definition: instrument.h:34
int64 shared_blks_read
Definition: instrument.h:27
int64 shared_blks_written
Definition: instrument.h:29
int64 temp_blks_written
Definition: instrument.h:35
int64 local_blks_read
Definition: instrument.h:31
int64 local_blks_dirtied
Definition: instrument.h:32
int64 shared_blks_hit
Definition: instrument.h:26
instr_time generation_counter
Definition: jit.h:33
size_t created_functions
Definition: jit.h:30
instr_time optimization_counter
Definition: jit.h:42
instr_time deform_counter
Definition: jit.h:36
instr_time emission_counter
Definition: jit.h:45
instr_time inlining_counter
Definition: jit.h:39
int64 wal_buffers_full
Definition: instrument.h:56
uint64 wal_bytes
Definition: instrument.h:55
int64 wal_fpi
Definition: instrument.h:54
int64 wal_records
Definition: instrument.h:53

References Assert(), Counters::calls, CleanQuerytext(), pgssEntry::counters, JitInstrumentation::created_functions, JitInstrumentation::deform_counter, JitInstrumentation::emission_counter, encoding, entry_alloc(), pgssSharedState::gc_count, gc_qtexts(), generate_normalized_query(), JitInstrumentation::generation_counter, GetDatabaseEncoding(), GetUserId(), HASH_FIND, hash_search(), JitInstrumentation::inlining_counter, INSTR_TIME_GET_MILLISEC, IS_STICKY, Counters::jit_deform_count, Counters::jit_deform_time, Counters::jit_emission_count, Counters::jit_emission_time, Counters::jit_functions, Counters::jit_generation_time, Counters::jit_inlining_count, Counters::jit_inlining_time, Counters::jit_optimization_count, Counters::jit_optimization_time, sort-test::key, Counters::local_blk_read_time, BufferUsage::local_blk_read_time, Counters::local_blk_write_time, BufferUsage::local_blk_write_time, Counters::local_blks_dirtied, BufferUsage::local_blks_dirtied, Counters::local_blks_hit, BufferUsage::local_blks_hit, Counters::local_blks_read, BufferUsage::local_blks_read, Counters::local_blks_written, BufferUsage::local_blks_written, pgssSharedState::lock, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), Counters::max_time, Counters::mean_time, Counters::min_time, pgssEntry::mutex, MyDatabaseId, need_gc_qtexts(), nesting_level, JitInstrumentation::optimization_counter, Counters::parallel_workers_launched, Counters::parallel_workers_to_launch, pfree(), pgss, PGSS_EXEC, pgss_hash, PGSS_PLAN, qtext_store(), Counters::rows, Counters::shared_blk_read_time, BufferUsage::shared_blk_read_time, Counters::shared_blk_write_time, BufferUsage::shared_blk_write_time, Counters::shared_blks_dirtied, BufferUsage::shared_blks_dirtied, Counters::shared_blks_hit, BufferUsage::shared_blks_hit, Counters::shared_blks_read, BufferUsage::shared_blks_read, Counters::shared_blks_written, BufferUsage::shared_blks_written, SpinLockAcquire, SpinLockRelease, Counters::sum_var_time, Counters::temp_blk_read_time, BufferUsage::temp_blk_read_time, Counters::temp_blk_write_time, BufferUsage::temp_blk_write_time, Counters::temp_blks_read, BufferUsage::temp_blks_read, Counters::temp_blks_written, BufferUsage::temp_blks_written, Counters::total_time, UINT64CONST, Counters::usage, USAGE_EXEC, USAGE_INIT, Counters::wal_buffers_full, WalUsage::wal_buffers_full, Counters::wal_bytes, WalUsage::wal_bytes, Counters::wal_fpi, WalUsage::wal_fpi, Counters::wal_records, and WalUsage::wal_records.

Referenced by pgss_ExecutorEnd(), pgss_planner(), pgss_post_parse_analyze(), and pgss_ProcessUtility().

◆ qtext_fetch()

static char * qtext_fetch ( Size  query_offset,
int  query_len,
char *  buffer,
Size  buffer_size 
)
static

Definition at line 2408 of file pg_stat_statements.c.

2410{
2411 /* File read failed? */
2412 if (buffer == NULL)
2413 return NULL;
2414 /* Bogus offset/length? */
2415 if (query_len < 0 ||
2416 query_offset + query_len >= buffer_size)
2417 return NULL;
2418 /* As a further sanity check, make sure there's a trailing null */
2419 if (buffer[query_offset + query_len] != '\0')
2420 return NULL;
2421 /* Looks OK */
2422 return buffer + query_offset;
2423}

Referenced by gc_qtexts(), pg_stat_statements_internal(), and pgss_shmem_shutdown().

◆ qtext_load_file()

static char * qtext_load_file ( Size buffer_size)
static

Definition at line 2315 of file pg_stat_statements.c.

2316{
2317 char *buf;
2318 int fd;
2319 struct stat stat;
2320 Size nread;
2321
2323 if (fd < 0)
2324 {
2325 if (errno != ENOENT)
2326 ereport(LOG,
2328 errmsg("could not read file \"%s\": %m",
2329 PGSS_TEXT_FILE)));
2330 return NULL;
2331 }
2332
2333 /* Get file length */
2334 if (fstat(fd, &stat))
2335 {
2336 ereport(LOG,
2338 errmsg("could not stat file \"%s\": %m",
2339 PGSS_TEXT_FILE)));
2341 return NULL;
2342 }
2343
2344 /* Allocate buffer; beware that off_t might be wider than size_t */
2346 buf = (char *) malloc(stat.st_size);
2347 else
2348 buf = NULL;
2349 if (buf == NULL)
2350 {
2351 ereport(LOG,
2352 (errcode(ERRCODE_OUT_OF_MEMORY),
2353 errmsg("out of memory"),
2354 errdetail("Could not allocate enough memory to read file \"%s\".",
2355 PGSS_TEXT_FILE)));
2357 return NULL;
2358 }
2359
2360 /*
2361 * OK, slurp in the file. Windows fails if we try to read more than
2362 * INT_MAX bytes at once, and other platforms might not like that either,
2363 * so read a very large file in 1GB segments.
2364 */
2365 nread = 0;
2366 while (nread < stat.st_size)
2367 {
2368 int toread = Min(1024 * 1024 * 1024, stat.st_size - nread);
2369
2370 /*
2371 * If we get a short read and errno doesn't get set, the reason is
2372 * probably that garbage collection truncated the file since we did
2373 * the fstat(), so we don't log a complaint --- but we don't return
2374 * the data, either, since it's most likely corrupt due to concurrent
2375 * writes from garbage collection.
2376 */
2377 errno = 0;
2378 if (read(fd, buf + nread, toread) != toread)
2379 {
2380 if (errno)
2381 ereport(LOG,
2383 errmsg("could not read file \"%s\": %m",
2384 PGSS_TEXT_FILE)));
2385 free(buf);
2387 return NULL;
2388 }
2389 nread += toread;
2390 }
2391
2392 if (CloseTransientFile(fd) != 0)
2393 ereport(LOG,
2395 errmsg("could not close file \"%s\": %m", PGSS_TEXT_FILE)));
2396
2397 *buffer_size = nread;
2398 return buf;
2399}
#define PG_BINARY
Definition: c.h:1244
int errdetail(const char *fmt,...)
Definition: elog.c:1204
int CloseTransientFile(int fd)
Definition: fd.c:2871
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2694
#define malloc(a)
Definition: header.h:50
#define read(a, b, c)
Definition: win32.h:13
#define MaxAllocHugeSize
Definition: memutils.h:48
static int fd(const char *x, int i)
Definition: preproc-init.c:105
__int64 st_size
Definition: win32_port.h:263
#define fstat
Definition: win32_port.h:273

References buf, CloseTransientFile(), ereport, errcode(), errcode_for_file_access(), errdetail(), errmsg(), fd(), free, fstat, LOG, malloc, MaxAllocHugeSize, Min, OpenTransientFile(), PG_BINARY, PGSS_TEXT_FILE, read, and stat::st_size.

Referenced by gc_qtexts(), pg_stat_statements_internal(), and pgss_shmem_shutdown().

◆ qtext_store()

static bool qtext_store ( const char *  query,
int  query_len,
Size query_offset,
int *  gc_count 
)
static

Definition at line 2235 of file pg_stat_statements.c.

2237{
2238 Size off;
2239 int fd;
2240
2241 /*
2242 * We use a spinlock to protect extent/n_writers/gc_count, so that
2243 * multiple processes may execute this function concurrently.
2244 */
2246 off = pgss->extent;
2247 pgss->extent += query_len + 1;
2248 pgss->n_writers++;
2249 if (gc_count)
2250 *gc_count = pgss->gc_count;
2252
2253 *query_offset = off;
2254
2255 /*
2256 * Don't allow the file to grow larger than what qtext_load_file can
2257 * (theoretically) handle. This has been seen to be reachable on 32-bit
2258 * platforms.
2259 */
2260 if (unlikely(query_len >= MaxAllocHugeSize - off))
2261 {
2262 errno = EFBIG; /* not quite right, but it'll do */
2263 fd = -1;
2264 goto error;
2265 }
2266
2267 /* Now write the data into the successfully-reserved part of the file */
2268 fd = OpenTransientFile(PGSS_TEXT_FILE, O_RDWR | O_CREAT | PG_BINARY);
2269 if (fd < 0)
2270 goto error;
2271
2272 if (pg_pwrite(fd, query, query_len, off) != query_len)
2273 goto error;
2274 if (pg_pwrite(fd, "\0", 1, off + query_len) != 1)
2275 goto error;
2276
2278
2279 /* Mark our write complete */
2281 pgss->n_writers--;
2283
2284 return true;
2285
2286error:
2287 ereport(LOG,
2289 errmsg("could not write file \"%s\": %m",
2290 PGSS_TEXT_FILE)));
2291
2292 if (fd >= 0)
2294
2295 /* Mark our write complete */
2297 pgss->n_writers--;
2299
2300 return false;
2301}
#define unlikely(x)
Definition: c.h:347
#define pg_pwrite
Definition: port.h:227

References CloseTransientFile(), ereport, errcode_for_file_access(), errmsg(), error(), pgssSharedState::extent, fd(), pgssSharedState::gc_count, LOG, MaxAllocHugeSize, pgssSharedState::mutex, pgssSharedState::n_writers, OpenTransientFile(), PG_BINARY, pg_pwrite, pgss, PGSS_TEXT_FILE, SpinLockAcquire, SpinLockRelease, and unlikely.

Referenced by pgss_store().

Variable Documentation

◆ nesting_level

◆ pgss

◆ PGSS_FILE_HEADER

const uint32 PGSS_FILE_HEADER = 0x20220408
static

Definition at line 88 of file pg_stat_statements.c.

Referenced by pgss_shmem_shutdown(), and pgss_shmem_startup().

◆ pgss_hash

◆ pgss_max

int pgss_max = 5000
static

◆ PGSS_PG_MAJOR_VERSION

const uint32 PGSS_PG_MAJOR_VERSION = PG_VERSION_NUM / 100
static

Definition at line 91 of file pg_stat_statements.c.

Referenced by pgss_shmem_shutdown(), and pgss_shmem_startup().

◆ pgss_save

bool pgss_save = true
static

Definition at line 300 of file pg_stat_statements.c.

Referenced by _PG_init(), pgss_shmem_shutdown(), and pgss_shmem_startup().

◆ pgss_track

int pgss_track = PGSS_TRACK_TOP
static

Definition at line 296 of file pg_stat_statements.c.

Referenced by _PG_init().

◆ pgss_track_planning

bool pgss_track_planning = false
static

Definition at line 298 of file pg_stat_statements.c.

Referenced by _PG_init(), and pgss_planner().

◆ pgss_track_utility

bool pgss_track_utility = true
static

Definition at line 297 of file pg_stat_statements.c.

Referenced by _PG_init(), pgss_post_parse_analyze(), and pgss_ProcessUtility().

◆ prev_ExecutorEnd

ExecutorEnd_hook_type prev_ExecutorEnd = NULL
static

Definition at line 271 of file pg_stat_statements.c.

Referenced by _PG_init(), and pgss_ExecutorEnd().

◆ prev_ExecutorFinish

ExecutorFinish_hook_type prev_ExecutorFinish = NULL
static

Definition at line 270 of file pg_stat_statements.c.

Referenced by _PG_init(), and pgss_ExecutorFinish().

◆ prev_ExecutorRun

ExecutorRun_hook_type prev_ExecutorRun = NULL
static

Definition at line 269 of file pg_stat_statements.c.

Referenced by _PG_init(), and pgss_ExecutorRun().

◆ prev_ExecutorStart

ExecutorStart_hook_type prev_ExecutorStart = NULL
static

Definition at line 268 of file pg_stat_statements.c.

Referenced by _PG_init(), and pgss_ExecutorStart().

◆ prev_planner_hook

planner_hook_type prev_planner_hook = NULL
static

Definition at line 267 of file pg_stat_statements.c.

Referenced by _PG_init(), and pgss_planner().

◆ prev_post_parse_analyze_hook

post_parse_analyze_hook_type prev_post_parse_analyze_hook = NULL
static

Definition at line 266 of file pg_stat_statements.c.

Referenced by _PG_init(), and pgss_post_parse_analyze().

◆ prev_ProcessUtility

ProcessUtility_hook_type prev_ProcessUtility = NULL
static

Definition at line 272 of file pg_stat_statements.c.

Referenced by _PG_init(), and pgss_ProcessUtility().

◆ prev_shmem_request_hook

shmem_request_hook_type prev_shmem_request_hook = NULL
static

Definition at line 264 of file pg_stat_statements.c.

Referenced by _PG_init(), and pgss_shmem_request().

◆ prev_shmem_startup_hook

shmem_startup_hook_type prev_shmem_startup_hook = NULL
static

Definition at line 265 of file pg_stat_statements.c.

Referenced by _PG_init(), and pgss_shmem_startup().

◆ track_options

const struct config_enum_entry track_options[]
static
Initial value:
=
{
{"none", PGSS_TRACK_NONE, false},
{"top", PGSS_TRACK_TOP, false},
{"all", PGSS_TRACK_ALL, false},
{NULL, 0, false}
}

Definition at line 287 of file pg_stat_statements.c.

Referenced by _PG_init().