PostgreSQL Source Code  git master
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/hashfn.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/parsetree.h"
#include "parser/scanner.h"
#include "parser/scansup.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_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   49 /* 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
}
 
enum  pgssStoreKind { PGSS_INVALID = -1 , PGSS_PLAN = 0 , PGSS_EXEC , PGSS_NUMKIND }
 
enum  PGSSTrackLevel { PGSS_TRACK_NONE , PGSS_TRACK_TOP , PGSS_TRACK_ALL }
 

Functions

 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)
 
 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 void pgss_ExecutorStart (QueryDesc *queryDesc, int eflags)
 
static void pgss_ExecutorRun (QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
 
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)
 
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_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

 PG_MODULE_MAGIC
 
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   49 /* maximum of above */

Definition at line 1552 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_0

#define PG_STAT_STATEMENTS_COLS_V1_0   14

Definition at line 1544 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_1

#define PG_STAT_STATEMENTS_COLS_V1_1   18

Definition at line 1545 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_10

#define PG_STAT_STATEMENTS_COLS_V1_10   43

Definition at line 1550 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_11

#define PG_STAT_STATEMENTS_COLS_V1_11   49

Definition at line 1551 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_2

#define PG_STAT_STATEMENTS_COLS_V1_2   19

Definition at line 1546 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_3

#define PG_STAT_STATEMENTS_COLS_V1_3   23

Definition at line 1547 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_8

#define PG_STAT_STATEMENTS_COLS_V1_8   32

Definition at line 1548 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_9

#define PG_STAT_STATEMENTS_COLS_V1_9   33

Definition at line 1549 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_INFO_COLS

#define PG_STAT_STATEMENTS_INFO_COLS   2

Definition at line 1976 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 297 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 { \
volatile pgssSharedState *s = (volatile pgssSharedState *) pgss; \
SpinLockAcquire(&s->mutex); \
s->gc_count++; \
SpinLockRelease(&s->mutex); \
} while(0)
static pgssSharedState * pgss

Definition at line 302 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
@ PGSS_NUMKIND
static HTAB * pgss_hash
e
Definition: preproc-init.c:82

Definition at line 2638 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 
PGSS_NUMKIND 

Definition at line 118 of file pg_stat_statements.c.

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

◆ PGSSTrackLevel

Enumerator
PGSS_TRACK_NONE 
PGSS_TRACK_TOP 
PGSS_TRACK_ALL 

Definition at line 274 of file pg_stat_statements.c.

275 {
276  PGSS_TRACK_NONE, /* track no statements */
277  PGSS_TRACK_TOP, /* only top level statements */
278  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 

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,
114  PGSS_V1_10,
115  PGSS_V1_11,
116 } pgssVersion;
@ PGSS_V1_9
@ PGSS_V1_10
@ 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 378 of file pg_stat_statements.c.

379 {
380  /*
381  * In order to create our shared memory area, we have to be loaded via
382  * shared_preload_libraries. If not, fall out without hooking into any of
383  * the main system. (We don't throw error here because it seems useful to
384  * allow the pg_stat_statements functions to be created even when the
385  * module isn't active. The functions must protect themselves against
386  * being called then, however.)
387  */
389  return;
390 
391  /*
392  * Inform the postmaster that we want to enable query_id calculation if
393  * compute_query_id is set to auto.
394  */
395  EnableQueryId();
396 
397  /*
398  * Define (or redefine) custom GUC variables.
399  */
400  DefineCustomIntVariable("pg_stat_statements.max",
401  "Sets the maximum number of statements tracked by pg_stat_statements.",
402  NULL,
403  &pgss_max,
404  5000,
405  100,
406  INT_MAX / 2,
408  0,
409  NULL,
410  NULL,
411  NULL);
412 
413  DefineCustomEnumVariable("pg_stat_statements.track",
414  "Selects which statements are tracked by pg_stat_statements.",
415  NULL,
416  &pgss_track,
419  PGC_SUSET,
420  0,
421  NULL,
422  NULL,
423  NULL);
424 
425  DefineCustomBoolVariable("pg_stat_statements.track_utility",
426  "Selects whether utility commands are tracked by pg_stat_statements.",
427  NULL,
429  true,
430  PGC_SUSET,
431  0,
432  NULL,
433  NULL,
434  NULL);
435 
436  DefineCustomBoolVariable("pg_stat_statements.track_planning",
437  "Selects whether planning duration is tracked by pg_stat_statements.",
438  NULL,
440  false,
441  PGC_SUSET,
442  0,
443  NULL,
444  NULL,
445  NULL);
446 
447  DefineCustomBoolVariable("pg_stat_statements.save",
448  "Save pg_stat_statements statistics across server shutdowns.",
449  NULL,
450  &pgss_save,
451  true,
452  PGC_SIGHUP,
453  0,
454  NULL,
455  NULL,
456  NULL);
457 
458  MarkGUCPrefixReserved("pg_stat_statements");
459 
460  /*
461  * Install hooks.
462  */
481 }
ExecutorEnd_hook_type ExecutorEnd_hook
Definition: execMain.c:68
ExecutorFinish_hook_type ExecutorFinish_hook
Definition: execMain.c:67
ExecutorStart_hook_type ExecutorStart_hook
Definition: execMain.c:65
ExecutorRun_hook_type ExecutorRun_hook
Definition: execMain.c:66
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:5196
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:5085
void MarkGUCPrefixReserved(const char *className)
Definition: guc.c:5232
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:5111
@ PGC_SUSET
Definition: guc.h:74
@ PGC_POSTMASTER
Definition: guc.h:70
@ PGC_SIGHUP
Definition: guc.h:71
shmem_startup_hook_type shmem_startup_hook
Definition: ipci.c:59
shmem_request_hook_type shmem_request_hook
Definition: miscinit.c:1781
bool process_shared_preload_libraries_in_progress
Definition: miscinit.c:1778
post_parse_analyze_hook_type post_parse_analyze_hook
Definition: analyze.c:58
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 void pgss_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
static bool pgss_save
static void pgss_shmem_startup(void)
static ExecutorStart_hook_type prev_ExecutorStart
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 void pgss_ExecutorStart(QueryDesc *queryDesc, int eflags)
static ExecutorFinish_hook_type prev_ExecutorFinish
planner_hook_type planner_hook
Definition: planner.c:71
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 3006 of file pg_stat_statements.c.

3007 {
3008  int l = ((const LocationLen *) a)->location;
3009  int r = ((const LocationLen *) b)->location;
3010 
3011  return pg_cmp_s32(l, r);
3012 }
static int pg_cmp_s32(int32 a, int32 b)
Definition: int.h:483
int b
Definition: isn.c:70
int a
Definition: isn.c:69

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 2045 of file pg_stat_statements.c.

2047 {
2048  pgssEntry *entry;
2049  bool found;
2050 
2051  /* Make space if needed */
2053  entry_dealloc();
2054 
2055  /* Find or create an entry with desired hash code */
2056  entry = (pgssEntry *) hash_search(pgss_hash, key, HASH_ENTER, &found);
2057 
2058  if (!found)
2059  {
2060  /* New entry, initialize it */
2061 
2062  /* reset the statistics */
2063  memset(&entry->counters, 0, sizeof(Counters));
2064  /* set the appropriate initial usage count */
2065  entry->counters.usage = sticky ? pgss->cur_median_usage : USAGE_INIT;
2066  /* re-initialize the mutex each time ... we assume no one using it */
2067  SpinLockInit(&entry->mutex);
2068  /* ... and don't forget the query text metadata */
2069  Assert(query_len >= 0);
2070  entry->query_offset = query_offset;
2071  entry->query_len = query_len;
2072  entry->encoding = encoding;
2073  entry->stats_since = GetCurrentTimestamp();
2074  entry->minmax_stats_since = entry->stats_since;
2075  }
2076 
2077  return entry;
2078 }
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1654
#define Assert(condition)
Definition: c.h:858
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
long hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1341
@ 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:60
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 2084 of file pg_stat_statements.c.

2085 {
2086  double l_usage = (*(pgssEntry *const *) lhs)->counters.usage;
2087  double r_usage = (*(pgssEntry *const *) rhs)->counters.usage;
2088 
2089  if (l_usage < r_usage)
2090  return -1;
2091  else if (l_usage > r_usage)
2092  return +1;
2093  else
2094  return 0;
2095 }

Referenced by entry_dealloc().

◆ entry_dealloc()

static void entry_dealloc ( void  )
static

Definition at line 2103 of file pg_stat_statements.c.

2104 {
2105  HASH_SEQ_STATUS hash_seq;
2106  pgssEntry **entries;
2107  pgssEntry *entry;
2108  int nvictims;
2109  int i;
2110  Size tottextlen;
2111  int nvalidtexts;
2112 
2113  /*
2114  * Sort entries by usage and deallocate USAGE_DEALLOC_PERCENT of them.
2115  * While we're scanning the table, apply the decay factor to the usage
2116  * values, and update the mean query length.
2117  *
2118  * Note that the mean query length is almost immediately obsolete, since
2119  * we compute it before not after discarding the least-used entries.
2120  * Hopefully, that doesn't affect the mean too much; it doesn't seem worth
2121  * making two passes to get a more current result. Likewise, the new
2122  * cur_median_usage includes the entries we're about to zap.
2123  */
2124 
2125  entries = palloc(hash_get_num_entries(pgss_hash) * sizeof(pgssEntry *));
2126 
2127  i = 0;
2128  tottextlen = 0;
2129  nvalidtexts = 0;
2130 
2131  hash_seq_init(&hash_seq, pgss_hash);
2132  while ((entry = hash_seq_search(&hash_seq)) != NULL)
2133  {
2134  entries[i++] = entry;
2135  /* "Sticky" entries get a different usage decay rate. */
2136  if (IS_STICKY(entry->counters))
2138  else
2140  /* In the mean length computation, ignore dropped texts. */
2141  if (entry->query_len >= 0)
2142  {
2143  tottextlen += entry->query_len + 1;
2144  nvalidtexts++;
2145  }
2146  }
2147 
2148  /* Sort into increasing order by usage */
2149  qsort(entries, i, sizeof(pgssEntry *), entry_cmp);
2150 
2151  /* Record the (approximate) median usage */
2152  if (i > 0)
2153  pgss->cur_median_usage = entries[i / 2]->counters.usage;
2154  /* Record the mean query length */
2155  if (nvalidtexts > 0)
2156  pgss->mean_query_len = tottextlen / nvalidtexts;
2157  else
2159 
2160  /* Now zap an appropriate fraction of lowest-usage entries */
2161  nvictims = Max(10, i * USAGE_DEALLOC_PERCENT / 100);
2162  nvictims = Min(nvictims, i);
2163 
2164  for (i = 0; i < nvictims; i++)
2165  {
2166  hash_search(pgss_hash, &entries[i]->key, HASH_REMOVE, NULL);
2167  }
2168 
2169  pfree(entries);
2170 
2171  /* Increment the number of times entries are deallocated */
2172  {
2173  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
2174 
2175  SpinLockAcquire(&s->mutex);
2176  s->stats.dealloc += 1;
2177  SpinLockRelease(&s->mutex);
2178  }
2179 }
#define Min(x, y)
Definition: c.h:1004
#define Max(x, y)
Definition: c.h:998
size_t Size
Definition: c.h:605
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1395
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1385
int i
Definition: isn.c:73
void pfree(void *pointer)
Definition: mcxt.c:1520
void * palloc(Size size)
Definition: mcxt.c:1316
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:449
#define SpinLockRelease(lock)
Definition: spin.h:64
#define SpinLockAcquire(lock)
Definition: spin.h:62
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 2661 of file pg_stat_statements.c.

2662 {
2663  HASH_SEQ_STATUS hash_seq;
2664  pgssEntry *entry;
2665  FILE *qfile;
2666  long num_entries;
2667  long num_remove = 0;
2668  pgssHashKey key;
2669  TimestampTz stats_reset;
2670 
2671  if (!pgss || !pgss_hash)
2672  ereport(ERROR,
2673  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2674  errmsg("pg_stat_statements must be loaded via shared_preload_libraries")));
2675 
2677  num_entries = hash_get_num_entries(pgss_hash);
2678 
2679  stats_reset = GetCurrentTimestamp();
2680 
2681  if (userid != 0 && dbid != 0 && queryid != UINT64CONST(0))
2682  {
2683  /* If all the parameters are available, use the fast path. */
2684  memset(&key, 0, sizeof(pgssHashKey));
2685  key.userid = userid;
2686  key.dbid = dbid;
2687  key.queryid = queryid;
2688 
2689  /*
2690  * Reset the entry if it exists, starting with the non-top-level
2691  * entry.
2692  */
2693  key.toplevel = false;
2694  entry = (pgssEntry *) hash_search(pgss_hash, &key, HASH_FIND, NULL);
2695 
2696  SINGLE_ENTRY_RESET(entry);
2697 
2698  /* Also reset the top-level entry if it exists. */
2699  key.toplevel = true;
2700  entry = (pgssEntry *) hash_search(pgss_hash, &key, HASH_FIND, NULL);
2701 
2702  SINGLE_ENTRY_RESET(entry);
2703  }
2704  else if (userid != 0 || dbid != 0 || queryid != UINT64CONST(0))
2705  {
2706  /* Reset entries corresponding to valid parameters. */
2707  hash_seq_init(&hash_seq, pgss_hash);
2708  while ((entry = hash_seq_search(&hash_seq)) != NULL)
2709  {
2710  if ((!userid || entry->key.userid == userid) &&
2711  (!dbid || entry->key.dbid == dbid) &&
2712  (!queryid || entry->key.queryid == queryid))
2713  {
2714  SINGLE_ENTRY_RESET(entry);
2715  }
2716  }
2717  }
2718  else
2719  {
2720  /* Reset all entries. */
2721  hash_seq_init(&hash_seq, pgss_hash);
2722  while ((entry = hash_seq_search(&hash_seq)) != NULL)
2723  {
2724  SINGLE_ENTRY_RESET(entry);
2725  }
2726  }
2727 
2728  /* All entries are removed? */
2729  if (num_entries != num_remove)
2730  goto release_lock;
2731 
2732  /*
2733  * Reset global statistics for pg_stat_statements since all entries are
2734  * removed.
2735  */
2736  {
2737  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
2738 
2739  SpinLockAcquire(&s->mutex);
2740  s->stats.dealloc = 0;
2741  s->stats.stats_reset = stats_reset;
2742  SpinLockRelease(&s->mutex);
2743  }
2744 
2745  /*
2746  * Write new empty query file, perhaps even creating a new one to recover
2747  * if the file was missing.
2748  */
2750  if (qfile == NULL)
2751  {
2752  ereport(LOG,
2754  errmsg("could not create file \"%s\": %m",
2755  PGSS_TEXT_FILE)));
2756  goto done;
2757  }
2758 
2759  /* If ftruncate fails, log it, but it's not a fatal problem */
2760  if (ftruncate(fileno(qfile), 0) != 0)
2761  ereport(LOG,
2763  errmsg("could not truncate file \"%s\": %m",
2764  PGSS_TEXT_FILE)));
2765 
2766  FreeFile(qfile);
2767 
2768 done:
2769  pgss->extent = 0;
2770  /* This counts as a query text garbage collection for our purposes */
2771  record_gc_qtexts();
2772 
2773 release_lock:
2775 
2776  return stats_reset;
2777 }
#define PG_BINARY_W
Definition: c.h:1276
int64 TimestampTz
Definition: timestamp.h:39
int errcode_for_file_access(void)
Definition: elog.c:882
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define LOG
Definition: elog.h:31
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2583
int FreeFile(FILE *file)
Definition: fd.c:2781
@ HASH_FIND
Definition: hsearch.h:113
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1170
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1783
@ LW_EXCLUSIVE
Definition: lwlock.h:114
#define SINGLE_ENTRY_RESET(e)
#define record_gc_qtexts()
#define PGSS_TEXT_FILE
pgssHashKey key
TimestampTz stats_reset
#define ftruncate(a, b)
Definition: win32_port.h:82

References AllocateFile(), pgssHashKey::dbid, pgssGlobalStats::dealloc, ereport, errcode(), errcode_for_file_access(), errmsg(), ERROR, pgssSharedState::extent, FreeFile(), ftruncate, 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, 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 2906 of file pg_stat_statements.c.

2908 {
2909  LocationLen *locs;
2911  core_yy_extra_type yyextra;
2912  core_YYSTYPE yylval;
2913  YYLTYPE yylloc;
2914  int last_loc = -1;
2915  int i;
2916 
2917  /*
2918  * Sort the records by location so that we can process them in order while
2919  * scanning the query text.
2920  */
2921  if (jstate->clocations_count > 1)
2922  qsort(jstate->clocations, jstate->clocations_count,
2923  sizeof(LocationLen), comp_location);
2924  locs = jstate->clocations;
2925 
2926  /* initialize the flex scanner --- should match raw_parser() */
2927  yyscanner = scanner_init(query,
2928  &yyextra,
2929  &ScanKeywords,
2931 
2932  /* we don't want to re-emit any escape string warnings */
2933  yyextra.escape_string_warning = false;
2934 
2935  /* Search for each constant, in sequence */
2936  for (i = 0; i < jstate->clocations_count; i++)
2937  {
2938  int loc = locs[i].location;
2939  int tok;
2940 
2941  /* Adjust recorded location if we're dealing with partial string */
2942  loc -= query_loc;
2943 
2944  Assert(loc >= 0);
2945 
2946  if (loc <= last_loc)
2947  continue; /* Duplicate constant, ignore */
2948 
2949  /* Lex tokens until we find the desired constant */
2950  for (;;)
2951  {
2952  tok = core_yylex(&yylval, &yylloc, yyscanner);
2953 
2954  /* We should not hit end-of-string, but if we do, behave sanely */
2955  if (tok == 0)
2956  break; /* out of inner for-loop */
2957 
2958  /*
2959  * We should find the token position exactly, but if we somehow
2960  * run past it, work with that.
2961  */
2962  if (yylloc >= loc)
2963  {
2964  if (query[loc] == '-')
2965  {
2966  /*
2967  * It's a negative value - this is the one and only case
2968  * where we replace more than a single token.
2969  *
2970  * Do not compensate for the core system's special-case
2971  * adjustment of location to that of the leading '-'
2972  * operator in the event of a negative constant. It is
2973  * also useful for our purposes to start from the minus
2974  * symbol. In this way, queries like "select * from foo
2975  * where bar = 1" and "select * from foo where bar = -2"
2976  * will have identical normalized query strings.
2977  */
2978  tok = core_yylex(&yylval, &yylloc, yyscanner);
2979  if (tok == 0)
2980  break; /* out of inner for-loop */
2981  }
2982 
2983  /*
2984  * We now rely on the assumption that flex has placed a zero
2985  * byte after the text of the current token in scanbuf.
2986  */
2987  locs[i].length = strlen(yyextra.scanbuf + loc);
2988  break; /* out of inner for-loop */
2989  }
2990  }
2991 
2992  /* If we hit end-of-string, give up, leaving remaining lengths -1 */
2993  if (tok == 0)
2994  break;
2995 
2996  last_loc = loc;
2997  }
2998 
3000 }
PGDLLIMPORT const ScanKeywordList ScanKeywords
static int comp_location(const void *a, const void *b)
static core_yyscan_t yyscanner
Definition: pl_scanner.c:106
#define YYLTYPE
Definition: scanner.h:44
core_yyscan_t scanner_init(const char *str, core_yy_extra_type *yyext, const ScanKeywordList *keywordlist, const uint16 *keyword_tokens)
void scanner_finish(core_yyscan_t yyscanner)
PGDLLIMPORT const uint16 ScanKeywordTokens[]
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:41
int clocations_count
Definition: queryjumble.h:47
bool escape_string_warning
Definition: scanner.h:88
char * scanbuf
Definition: scanner.h:72

References Assert, JumbleState::clocations, JumbleState::clocations_count, comp_location(), core_yylex(), core_yy_extra_type::escape_string_warning, i, LocationLen::length, LocationLen::location, qsort, core_yy_extra_type::scanbuf, ScanKeywords, ScanKeywordTokens, scanner_finish(), scanner_init(), YYLTYPE, and yyscanner.

Referenced by generate_normalized_query().

◆ gc_qtexts()

static void gc_qtexts ( void  )
static

Definition at line 2459 of file pg_stat_statements.c.

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

2801 {
2802  char *norm_query;
2803  int query_len = *query_len_p;
2804  int i,
2805  norm_query_buflen, /* Space allowed for norm_query */
2806  len_to_wrt, /* Length (in bytes) to write */
2807  quer_loc = 0, /* Source query byte location */
2808  n_quer_loc = 0, /* Normalized query byte location */
2809  last_off = 0, /* Offset from start for previous tok */
2810  last_tok_len = 0; /* Length (in bytes) of that tok */
2811 
2812  /*
2813  * Get constants' lengths (core system only gives us locations). Note
2814  * this also ensures the items are sorted by location.
2815  */
2816  fill_in_constant_lengths(jstate, query, query_loc);
2817 
2818  /*
2819  * Allow for $n symbols to be longer than the constants they replace.
2820  * Constants must take at least one byte in text form, while a $n symbol
2821  * certainly isn't more than 11 bytes, even if n reaches INT_MAX. We
2822  * could refine that limit based on the max value of n for the current
2823  * query, but it hardly seems worth any extra effort to do so.
2824  */
2825  norm_query_buflen = query_len + jstate->clocations_count * 10;
2826 
2827  /* Allocate result buffer */
2828  norm_query = palloc(norm_query_buflen + 1);
2829 
2830  for (i = 0; i < jstate->clocations_count; i++)
2831  {
2832  int off, /* Offset from start for cur tok */
2833  tok_len; /* Length (in bytes) of that tok */
2834 
2835  off = jstate->clocations[i].location;
2836  /* Adjust recorded location if we're dealing with partial string */
2837  off -= query_loc;
2838 
2839  tok_len = jstate->clocations[i].length;
2840 
2841  if (tok_len < 0)
2842  continue; /* ignore any duplicates */
2843 
2844  /* Copy next chunk (what precedes the next constant) */
2845  len_to_wrt = off - last_off;
2846  len_to_wrt -= last_tok_len;
2847 
2848  Assert(len_to_wrt >= 0);
2849  memcpy(norm_query + n_quer_loc, query + quer_loc, len_to_wrt);
2850  n_quer_loc += len_to_wrt;
2851 
2852  /* And insert a param symbol in place of the constant token */
2853  n_quer_loc += sprintf(norm_query + n_quer_loc, "$%d",
2854  i + 1 + jstate->highest_extern_param_id);
2855 
2856  quer_loc = off + tok_len;
2857  last_off = off;
2858  last_tok_len = tok_len;
2859  }
2860 
2861  /*
2862  * We've copied up until the last ignorable constant. Copy over the
2863  * remaining bytes of the original query string.
2864  */
2865  len_to_wrt = query_len - quer_loc;
2866 
2867  Assert(len_to_wrt >= 0);
2868  memcpy(norm_query + n_quer_loc, query + quer_loc, len_to_wrt);
2869  n_quer_loc += len_to_wrt;
2870 
2871  Assert(n_quer_loc <= norm_query_buflen);
2872  norm_query[n_quer_loc] = '\0';
2873 
2874  *query_len_p = n_quer_loc;
2875  return norm_query;
2876 }
static void fill_in_constant_lengths(JumbleState *jstate, const char *query, int query_loc)
#define sprintf
Definition: port.h:240
int highest_extern_param_id
Definition: queryjumble.h:50

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

Referenced by pgss_store().

◆ need_gc_qtexts()

static bool need_gc_qtexts ( void  )
static

Definition at line 2406 of file pg_stat_statements.c.

2407 {
2408  Size extent;
2409 
2410  /* Read shared extent pointer */
2411  {
2412  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
2413 
2414  SpinLockAcquire(&s->mutex);
2415  extent = s->extent;
2416  SpinLockRelease(&s->mutex);
2417  }
2418 
2419  /*
2420  * Don't proceed if file does not exceed 512 bytes per possible entry.
2421  *
2422  * Here and in the next test, 32-bit machines have overflow hazards if
2423  * pgss_max and/or mean_query_len are large. Force the multiplications
2424  * and comparisons to be done in uint64 arithmetic to forestall trouble.
2425  */
2426  if ((uint64) extent < (uint64) 512 * pgss_max)
2427  return false;
2428 
2429  /*
2430  * Don't proceed if file is less than about 50% bloat. Nothing can or
2431  * should be done in the event of unusually large query texts accounting
2432  * for file's large size. We go to the trouble of maintaining the mean
2433  * query length in order to prevent garbage collection from thrashing
2434  * uselessly.
2435  */
2436  if ((uint64) extent < (uint64) pgss->mean_query_len * pgss_max * 2)
2437  return false;
2438 
2439  return true;
2440 }

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/11]

PG_FUNCTION_INFO_V1 ( pg_stat_statements  )

◆ PG_FUNCTION_INFO_V1() [2/11]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_10  )

◆ PG_FUNCTION_INFO_V1() [3/11]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_11  )

◆ PG_FUNCTION_INFO_V1() [4/11]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_2  )

◆ PG_FUNCTION_INFO_V1() [5/11]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_3  )

◆ PG_FUNCTION_INFO_V1() [6/11]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_8  )

◆ PG_FUNCTION_INFO_V1() [7/11]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_9  )

◆ PG_FUNCTION_INFO_V1() [8/11]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_info  )

◆ PG_FUNCTION_INFO_V1() [9/11]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_reset  )

◆ PG_FUNCTION_INFO_V1() [10/11]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_reset_1_11  )

◆ PG_FUNCTION_INFO_V1() [11/11]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_reset_1_7  )

◆ pg_stat_statements()

Datum pg_stat_statements ( PG_FUNCTION_ARGS  )

Definition at line 1629 of file pg_stat_statements.c.

1630 {
1631  /* If it's really API 1.1, we'll figure that out below */
1632  pg_stat_statements_internal(fcinfo, PGSS_V1_0, true);
1633 
1634  return (Datum) 0;
1635 }
static void pg_stat_statements_internal(FunctionCallInfo fcinfo, pgssVersion api_version, bool showtext)
uintptr_t Datum
Definition: postgres.h:64

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 1575 of file pg_stat_statements.c.

1576 {
1577  bool showtext = PG_GETARG_BOOL(0);
1578 
1579  pg_stat_statements_internal(fcinfo, PGSS_V1_10, showtext);
1580 
1581  return (Datum) 0;
1582 }
#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 1565 of file pg_stat_statements.c.

1566 {
1567  bool showtext = PG_GETARG_BOOL(0);
1568 
1569  pg_stat_statements_internal(fcinfo, PGSS_V1_11, showtext);
1570 
1571  return (Datum) 0;
1572 }

References PG_GETARG_BOOL, pg_stat_statements_internal(), and PGSS_V1_11.

◆ pg_stat_statements_1_2()

Datum pg_stat_statements_1_2 ( PG_FUNCTION_ARGS  )

Definition at line 1615 of file pg_stat_statements.c.

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

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 1605 of file pg_stat_statements.c.

1606 {
1607  bool showtext = PG_GETARG_BOOL(0);
1608 
1609  pg_stat_statements_internal(fcinfo, PGSS_V1_3, showtext);
1610 
1611  return (Datum) 0;
1612 }

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 1595 of file pg_stat_statements.c.

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

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 1585 of file pg_stat_statements.c.

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

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 1982 of file pg_stat_statements.c.

1983 {
1984  pgssGlobalStats stats;
1985  TupleDesc tupdesc;
1987  bool nulls[PG_STAT_STATEMENTS_INFO_COLS] = {0};
1988 
1989  if (!pgss || !pgss_hash)
1990  ereport(ERROR,
1991  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1992  errmsg("pg_stat_statements must be loaded via shared_preload_libraries")));
1993 
1994  /* Build a tuple descriptor for our result type */
1995  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
1996  elog(ERROR, "return type must be a row type");
1997 
1998  /* Read global statistics for pg_stat_statements */
1999  {
2000  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
2001 
2002  SpinLockAcquire(&s->mutex);
2003  stats = s->stats;
2004  SpinLockRelease(&s->mutex);
2005  }
2006 
2007  values[0] = Int64GetDatum(stats.dealloc);
2009 
2011 }
static Datum values[MAXATTR]
Definition: bootstrap.c:152
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:1116
#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 1639 of file pg_stat_statements.c.

1642 {
1643  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1644  Oid userid = GetUserId();
1645  bool is_allowed_role = false;
1646  char *qbuffer = NULL;
1647  Size qbuffer_size = 0;
1648  Size extent = 0;
1649  int gc_count = 0;
1650  HASH_SEQ_STATUS hash_seq;
1651  pgssEntry *entry;
1652 
1653  /*
1654  * Superusers or roles with the privileges of pg_read_all_stats members
1655  * are allowed
1656  */
1657  is_allowed_role = has_privs_of_role(userid, ROLE_PG_READ_ALL_STATS);
1658 
1659  /* hash table must exist already */
1660  if (!pgss || !pgss_hash)
1661  ereport(ERROR,
1662  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1663  errmsg("pg_stat_statements must be loaded via shared_preload_libraries")));
1664 
1665  InitMaterializedSRF(fcinfo, 0);
1666 
1667  /*
1668  * Check we have the expected number of output arguments. Aside from
1669  * being a good safety check, we need a kluge here to detect API version
1670  * 1.1, which was wedged into the code in an ill-considered way.
1671  */
1672  switch (rsinfo->setDesc->natts)
1673  {
1675  if (api_version != PGSS_V1_0)
1676  elog(ERROR, "incorrect number of output arguments");
1677  break;
1679  /* pg_stat_statements() should have told us 1.0 */
1680  if (api_version != PGSS_V1_0)
1681  elog(ERROR, "incorrect number of output arguments");
1682  api_version = PGSS_V1_1;
1683  break;
1685  if (api_version != PGSS_V1_2)
1686  elog(ERROR, "incorrect number of output arguments");
1687  break;
1689  if (api_version != PGSS_V1_3)
1690  elog(ERROR, "incorrect number of output arguments");
1691  break;
1693  if (api_version != PGSS_V1_8)
1694  elog(ERROR, "incorrect number of output arguments");
1695  break;
1697  if (api_version != PGSS_V1_9)
1698  elog(ERROR, "incorrect number of output arguments");
1699  break;
1701  if (api_version != PGSS_V1_10)
1702  elog(ERROR, "incorrect number of output arguments");
1703  break;
1705  if (api_version != PGSS_V1_11)
1706  elog(ERROR, "incorrect number of output arguments");
1707  break;
1708  default:
1709  elog(ERROR, "incorrect number of output arguments");
1710  }
1711 
1712  /*
1713  * We'd like to load the query text file (if needed) while not holding any
1714  * lock on pgss->lock. In the worst case we'll have to do this again
1715  * after we have the lock, but it's unlikely enough to make this a win
1716  * despite occasional duplicated work. We need to reload if anybody
1717  * writes to the file (either a retail qtext_store(), or a garbage
1718  * collection) between this point and where we've gotten shared lock. If
1719  * a qtext_store is actually in progress when we look, we might as well
1720  * skip the speculative load entirely.
1721  */
1722  if (showtext)
1723  {
1724  int n_writers;
1725 
1726  /* Take the mutex so we can examine variables */
1727  {
1728  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
1729 
1730  SpinLockAcquire(&s->mutex);
1731  extent = s->extent;
1732  n_writers = s->n_writers;
1733  gc_count = s->gc_count;
1734  SpinLockRelease(&s->mutex);
1735  }
1736 
1737  /* No point in loading file now if there are active writers */
1738  if (n_writers == 0)
1739  qbuffer = qtext_load_file(&qbuffer_size);
1740  }
1741 
1742  /*
1743  * Get shared lock, load or reload the query text file if we must, and
1744  * iterate over the hashtable entries.
1745  *
1746  * With a large hash table, we might be holding the lock rather longer
1747  * than one could wish. However, this only blocks creation of new hash
1748  * table entries, and the larger the hash table the less likely that is to
1749  * be needed. So we can hope this is okay. Perhaps someday we'll decide
1750  * we need to partition the hash table to limit the time spent holding any
1751  * one lock.
1752  */
1754 
1755  if (showtext)
1756  {
1757  /*
1758  * Here it is safe to examine extent and gc_count without taking the
1759  * mutex. Note that although other processes might change
1760  * pgss->extent just after we look at it, the strings they then write
1761  * into the file cannot yet be referenced in the hashtable, so we
1762  * don't care whether we see them or not.
1763  *
1764  * If qtext_load_file fails, we just press on; we'll return NULL for
1765  * every query text.
1766  */
1767  if (qbuffer == NULL ||
1768  pgss->extent != extent ||
1769  pgss->gc_count != gc_count)
1770  {
1771  free(qbuffer);
1772  qbuffer = qtext_load_file(&qbuffer_size);
1773  }
1774  }
1775 
1776  hash_seq_init(&hash_seq, pgss_hash);
1777  while ((entry = hash_seq_search(&hash_seq)) != NULL)
1778  {
1780  bool nulls[PG_STAT_STATEMENTS_COLS];
1781  int i = 0;
1782  Counters tmp;
1783  double stddev;
1784  int64 queryid = entry->key.queryid;
1785  TimestampTz stats_since;
1786  TimestampTz minmax_stats_since;
1787 
1788  memset(values, 0, sizeof(values));
1789  memset(nulls, 0, sizeof(nulls));
1790 
1791  values[i++] = ObjectIdGetDatum(entry->key.userid);
1792  values[i++] = ObjectIdGetDatum(entry->key.dbid);
1793  if (api_version >= PGSS_V1_9)
1794  values[i++] = BoolGetDatum(entry->key.toplevel);
1795 
1796  if (is_allowed_role || entry->key.userid == userid)
1797  {
1798  if (api_version >= PGSS_V1_2)
1799  values[i++] = Int64GetDatumFast(queryid);
1800 
1801  if (showtext)
1802  {
1803  char *qstr = qtext_fetch(entry->query_offset,
1804  entry->query_len,
1805  qbuffer,
1806  qbuffer_size);
1807 
1808  if (qstr)
1809  {
1810  char *enc;
1811 
1812  enc = pg_any_to_server(qstr,
1813  entry->query_len,
1814  entry->encoding);
1815 
1817 
1818  if (enc != qstr)
1819  pfree(enc);
1820  }
1821  else
1822  {
1823  /* Just return a null if we fail to find the text */
1824  nulls[i++] = true;
1825  }
1826  }
1827  else
1828  {
1829  /* Query text not requested */
1830  nulls[i++] = true;
1831  }
1832  }
1833  else
1834  {
1835  /* Don't show queryid */
1836  if (api_version >= PGSS_V1_2)
1837  nulls[i++] = true;
1838 
1839  /*
1840  * Don't show query text, but hint as to the reason for not doing
1841  * so if it was requested
1842  */
1843  if (showtext)
1844  values[i++] = CStringGetTextDatum("<insufficient privilege>");
1845  else
1846  nulls[i++] = true;
1847  }
1848 
1849  /* copy counters to a local variable to keep locking time short */
1850  {
1851  volatile pgssEntry *e = (volatile pgssEntry *) entry;
1852 
1853  SpinLockAcquire(&e->mutex);
1854  tmp = e->counters;
1855  stats_since = e->stats_since;
1856  minmax_stats_since = e->minmax_stats_since;
1857  SpinLockRelease(&e->mutex);
1858  }
1859 
1860  /* Skip entry if unexecuted (ie, it's a pending "sticky" entry) */
1861  if (IS_STICKY(tmp))
1862  continue;
1863 
1864  /* Note that we rely on PGSS_PLAN being 0 and PGSS_EXEC being 1. */
1865  for (int kind = 0; kind < PGSS_NUMKIND; kind++)
1866  {
1867  if (kind == PGSS_EXEC || api_version >= PGSS_V1_8)
1868  {
1869  values[i++] = Int64GetDatumFast(tmp.calls[kind]);
1870  values[i++] = Float8GetDatumFast(tmp.total_time[kind]);
1871  }
1872 
1873  if ((kind == PGSS_EXEC && api_version >= PGSS_V1_3) ||
1874  api_version >= PGSS_V1_8)
1875  {
1876  values[i++] = Float8GetDatumFast(tmp.min_time[kind]);
1877  values[i++] = Float8GetDatumFast(tmp.max_time[kind]);
1878  values[i++] = Float8GetDatumFast(tmp.mean_time[kind]);
1879 
1880  /*
1881  * Note we are calculating the population variance here, not
1882  * the sample variance, as we have data for the whole
1883  * population, so Bessel's correction is not used, and we
1884  * don't divide by tmp.calls - 1.
1885  */
1886  if (tmp.calls[kind] > 1)
1887  stddev = sqrt(tmp.sum_var_time[kind] / tmp.calls[kind]);
1888  else
1889  stddev = 0.0;
1890  values[i++] = Float8GetDatumFast(stddev);
1891  }
1892  }
1893  values[i++] = Int64GetDatumFast(tmp.rows);
1896  if (api_version >= PGSS_V1_1)
1901  if (api_version >= PGSS_V1_1)
1906  if (api_version >= PGSS_V1_1)
1907  {
1910  }
1911  if (api_version >= PGSS_V1_11)
1912  {
1915  }
1916  if (api_version >= PGSS_V1_10)
1917  {
1920  }
1921  if (api_version >= PGSS_V1_8)
1922  {
1923  char buf[256];
1924  Datum wal_bytes;
1925 
1927  values[i++] = Int64GetDatumFast(tmp.wal_fpi);
1928 
1929  snprintf(buf, sizeof buf, UINT64_FORMAT, tmp.wal_bytes);
1930 
1931  /* Convert to numeric. */
1932  wal_bytes = DirectFunctionCall3(numeric_in,
1934  ObjectIdGetDatum(0),
1935  Int32GetDatum(-1));
1936  values[i++] = wal_bytes;
1937  }
1938  if (api_version >= PGSS_V1_10)
1939  {
1948  }
1949  if (api_version >= PGSS_V1_11)
1950  {
1953  values[i++] = TimestampTzGetDatum(stats_since);
1954  values[i++] = TimestampTzGetDatum(minmax_stats_since);
1955  }
1956 
1957  Assert(i == (api_version == PGSS_V1_0 ? PG_STAT_STATEMENTS_COLS_V1_0 :
1958  api_version == PGSS_V1_1 ? PG_STAT_STATEMENTS_COLS_V1_1 :
1959  api_version == PGSS_V1_2 ? PG_STAT_STATEMENTS_COLS_V1_2 :
1960  api_version == PGSS_V1_3 ? PG_STAT_STATEMENTS_COLS_V1_3 :
1961  api_version == PGSS_V1_8 ? PG_STAT_STATEMENTS_COLS_V1_8 :
1962  api_version == PGSS_V1_9 ? PG_STAT_STATEMENTS_COLS_V1_9 :
1963  api_version == PGSS_V1_10 ? PG_STAT_STATEMENTS_COLS_V1_10 :
1964  api_version == PGSS_V1_11 ? PG_STAT_STATEMENTS_COLS_V1_11 :
1965  -1 /* fail if you forget to update this assert */ ));
1966 
1967  tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
1968  }
1969 
1971 
1972  free(qbuffer);
1973 }
bool has_privs_of_role(Oid member, Oid role)
Definition: acl.c:5128
Datum numeric_in(PG_FUNCTION_ARGS)
Definition: numeric.c:628
#define CStringGetTextDatum(s)
Definition: builtins.h:97
#define UINT64_FORMAT
Definition: c.h:549
enc
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition: fmgr.h:646
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:514
#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_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:73
#define snprintf
Definition: port.h:238
#define Int64GetDatumFast(X)
Definition: postgres.h:554
#define Float8GetDatumFast(X)
Definition: postgres.h:556
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:350
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
unsigned int Oid
Definition: postgres_ext.h:31
int64 temp_blks_written
int64 calls[PGSS_NUMKIND]
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 local_blks_read
double shared_blk_read_time
double jit_inlining_time
fmNodePtr resultinfo
Definition: fmgr.h:89
TupleDesc setDesc
Definition: execnodes.h:340
Tuplestorestate * setResult
Definition: execnodes.h:339
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, const Datum *values, const bool *isnull)
Definition: tuplestore.c:750

References Assert, BoolGetDatum(), buf, Counters::calls, 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, pgssSharedState::mutex, pgssSharedState::n_writers, TupleDescData::natts, numeric_in(), ObjectIdGetDatum(), 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_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_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, 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_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_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 1536 of file pg_stat_statements.c.

1537 {
1538  entry_reset(0, 0, 0, false);
1539 
1540  PG_RETURN_VOID();
1541 }
#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 1517 of file pg_stat_statements.c.

1518 {
1519  Oid userid;
1520  Oid dbid;
1521  uint64 queryid;
1522  bool minmax_only;
1523 
1524  userid = PG_GETARG_OID(0);
1525  dbid = PG_GETARG_OID(1);
1526  queryid = (uint64) PG_GETARG_INT64(2);
1527  minmax_only = PG_GETARG_BOOL(3);
1528 
1529  PG_RETURN_TIMESTAMPTZ(entry_reset(userid, dbid, queryid, minmax_only));
1530 }
#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 1501 of file pg_stat_statements.c.

1502 {
1503  Oid userid;
1504  Oid dbid;
1505  uint64 queryid;
1506 
1507  userid = PG_GETARG_OID(0);
1508  dbid = PG_GETARG_OID(1);
1509  queryid = (uint64) PG_GETARG_INT64(2);
1510 
1511  entry_reset(userid, dbid, queryid, false);
1512 
1513  PG_RETURN_VOID();
1514 }

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 1066 of file pg_stat_statements.c.

1067 {
1068  uint64 queryId = queryDesc->plannedstmt->queryId;
1069 
1070  if (queryId != UINT64CONST(0) && queryDesc->totaltime &&
1072  {
1073  /*
1074  * Make sure stats accumulation is done. (Note: it's okay if several
1075  * levels of hook all do this.)
1076  */
1077  InstrEndLoop(queryDesc->totaltime);
1078 
1079  pgss_store(queryDesc->sourceText,
1080  queryId,
1081  queryDesc->plannedstmt->stmt_location,
1082  queryDesc->plannedstmt->stmt_len,
1083  PGSS_EXEC,
1084  queryDesc->totaltime->total * 1000.0, /* convert to msec */
1085  queryDesc->estate->es_total_processed,
1086  &queryDesc->totaltime->bufusage,
1087  &queryDesc->totaltime->walusage,
1088  queryDesc->estate->es_jit ? &queryDesc->estate->es_jit->instr : NULL,
1089  NULL);
1090  }
1091 
1092  if (prev_ExecutorEnd)
1093  prev_ExecutorEnd(queryDesc);
1094  else
1095  standard_ExecutorEnd(queryDesc);
1096 }
void standard_ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:476
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)
#define pgss_enabled(level)
static int nesting_level
struct JitContext * es_jit
Definition: execnodes.h:716
uint64 es_total_processed
Definition: execnodes.h:673
WalUsage walusage
Definition: instrument.h:92
BufferUsage bufusage
Definition: instrument.h:91
JitInstrumentation instr
Definition: jit.h:64
ParseLoc stmt_len
Definition: plannodes.h:99
ParseLoc stmt_location
Definition: plannodes.h:98
uint64 queryId
Definition: plannodes.h:54
const char * sourceText
Definition: execdesc.h:38
EState * estate
Definition: execdesc.h:48
PlannedStmt * plannedstmt
Definition: execdesc.h:37
struct Instrumentation * totaltime
Definition: execdesc.h:55

References Instrumentation::bufusage, EState::es_jit, 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, and Instrumentation::walusage.

Referenced by _PG_init().

◆ pgss_ExecutorFinish()

static void pgss_ExecutorFinish ( QueryDesc queryDesc)
static

Definition at line 1045 of file pg_stat_statements.c.

1046 {
1047  nesting_level++;
1048  PG_TRY();
1049  {
1050  if (prev_ExecutorFinish)
1051  prev_ExecutorFinish(queryDesc);
1052  else
1053  standard_ExecutorFinish(queryDesc);
1054  }
1055  PG_FINALLY();
1056  {
1057  nesting_level--;
1058  }
1059  PG_END_TRY();
1060 }
#define PG_TRY(...)
Definition: elog.h:370
#define PG_END_TRY(...)
Definition: elog.h:395
#define PG_FINALLY(...)
Definition: elog.h:387
void standard_ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:416

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,
bool  execute_once 
)
static

Definition at line 1023 of file pg_stat_statements.c.

1025 {
1026  nesting_level++;
1027  PG_TRY();
1028  {
1029  if (prev_ExecutorRun)
1030  prev_ExecutorRun(queryDesc, direction, count, execute_once);
1031  else
1032  standard_ExecutorRun(queryDesc, direction, count, execute_once);
1033  }
1034  PG_FINALLY();
1035  {
1036  nesting_level--;
1037  }
1038  PG_END_TRY();
1039 }
void standard_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: execMain.c:308

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

Referenced by _PG_init().

◆ pgss_ExecutorStart()

static void pgss_ExecutorStart ( QueryDesc queryDesc,
int  eflags 
)
static

Definition at line 989 of file pg_stat_statements.c.

990 {
991  if (prev_ExecutorStart)
992  prev_ExecutorStart(queryDesc, eflags);
993  else
994  standard_ExecutorStart(queryDesc, eflags);
995 
996  /*
997  * If query has queryId zero, don't track it. This prevents double
998  * counting of optimizable statements that are directly contained in
999  * utility statements.
1000  */
1001  if (pgss_enabled(nesting_level) && queryDesc->plannedstmt->queryId != UINT64CONST(0))
1002  {
1003  /*
1004  * Set up to track total elapsed time in ExecutorRun. Make sure the
1005  * space is allocated in the per-query context so it will go away at
1006  * ExecutorEnd.
1007  */
1008  if (queryDesc->totaltime == NULL)
1009  {
1010  MemoryContext oldcxt;
1011 
1012  oldcxt = MemoryContextSwitchTo(queryDesc->estate->es_query_cxt);
1013  queryDesc->totaltime = InstrAlloc(1, INSTRUMENT_ALL, false);
1014  MemoryContextSwitchTo(oldcxt);
1015  }
1016  }
1017 }
void standard_ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:141
Instrumentation * InstrAlloc(int n, int instrument_options, bool async_mode)
Definition: instrument.c:31
@ INSTRUMENT_ALL
Definition: instrument.h:65
MemoryContextSwitchTo(old_ctx)
MemoryContext es_query_cxt
Definition: execnodes.h:667

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

Referenced by _PG_init().

◆ pgss_memsize()

static Size pgss_memsize ( void  )
static

Definition at line 2017 of file pg_stat_statements.c.

2018 {
2019  Size size;
2020 
2021  size = MAXALIGN(sizeof(pgssSharedState));
2023 
2024  return size;
2025 }
#define MAXALIGN(LEN)
Definition: c.h:811
Size hash_estimate_size(long num_entries, Size entrysize)
Definition: dynahash.c:783
Size add_size(Size s1, Size s2)
Definition: shmem.c:493
static pg_noinline void Size size
Definition: slab.c:607

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

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 879 of file pg_stat_statements.c.

883 {
884  PlannedStmt *result;
885 
886  /*
887  * We can't process the query if no query_string is provided, as
888  * pgss_store needs it. We also ignore query without queryid, as it would
889  * be treated as a utility statement, which may not be the case.
890  *
891  * Note that planner_hook can be called from the planner itself, so we
892  * have a specific nesting level for the planner. However, utility
893  * commands containing optimizable statements can also call the planner,
894  * same for regular DML (for instance for underlying foreign key queries).
895  * So testing the planner nesting level only is not enough to detect real
896  * top level planner call.
897  */
899  && pgss_track_planning && query_string
900  && parse->queryId != UINT64CONST(0))
901  {
904  BufferUsage bufusage_start,
905  bufusage;
906  WalUsage walusage_start,
907  walusage;
908 
909  /* We need to track buffer usage as the planner can access them. */
910  bufusage_start = pgBufferUsage;
911 
912  /*
913  * Similarly the planner could write some WAL records in some cases
914  * (e.g. setting a hint bit with those being WAL-logged)
915  */
916  walusage_start = pgWalUsage;
918 
919  nesting_level++;
920  PG_TRY();
921  {
922  if (prev_planner_hook)
923  result = prev_planner_hook(parse, query_string, cursorOptions,
924  boundParams);
925  else
926  result = standard_planner(parse, query_string, cursorOptions,
927  boundParams);
928  }
929  PG_FINALLY();
930  {
931  nesting_level--;
932  }
933  PG_END_TRY();
934 
937 
938  /* calc differences of buffer counters. */
939  memset(&bufusage, 0, sizeof(BufferUsage));
940  BufferUsageAccumDiff(&bufusage, &pgBufferUsage, &bufusage_start);
941 
942  /* calc differences of WAL counters. */
943  memset(&walusage, 0, sizeof(WalUsage));
944  WalUsageAccumDiff(&walusage, &pgWalUsage, &walusage_start);
945 
946  pgss_store(query_string,
947  parse->queryId,
948  parse->stmt_location,
949  parse->stmt_len,
950  PGSS_PLAN,
952  0,
953  &bufusage,
954  &walusage,
955  NULL,
956  NULL);
957  }
958  else
959  {
960  /*
961  * Even though we're not tracking plan time for this statement, we
962  * must still increment the nesting level, to ensure that functions
963  * evaluated during planning are not seen as top-level calls.
964  */
965  nesting_level++;
966  PG_TRY();
967  {
968  if (prev_planner_hook)
969  result = prev_planner_hook(parse, query_string, cursorOptions,
970  boundParams);
971  else
972  result = standard_planner(parse, query_string, cursorOptions,
973  boundParams);
974  }
975  PG_FINALLY();
976  {
977  nesting_level--;
978  }
979  PG_END_TRY();
980  }
981 
982  return result;
983 }
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:286
BufferUsage pgBufferUsage
Definition: instrument.c:20
void BufferUsageAccumDiff(BufferUsage *dst, const BufferUsage *add, const BufferUsage *sub)
Definition: instrument.c:248
int duration
Definition: pgbench.c:174
PlannedStmt * standard_planner(Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams)
Definition: planner.c:287
static struct subre * parse(struct vars *v, int stopper, int type, struct state *init, struct state *final)
Definition: regcomp.c:715

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, 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 829 of file pg_stat_statements.c.

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

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, 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 1102 of file pg_stat_statements.c.

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

References BufferUsageAccumDiff(), QueryCompletion::commandTag, context, 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, PlannedStmt::utilityStmt, and WalUsageAccumDiff().

Referenced by _PG_init().

◆ pgss_shmem_request()

static void pgss_shmem_request ( void  )
static

Definition at line 488 of file pg_stat_statements.c.

489 {
492 
494  RequestNamedLWLockTranche("pg_stat_statements", 1);
495 }
void RequestAddinShmemSpace(Size size)
Definition: ipci.c:75
void RequestNamedLWLockTranche(const char *tranche_name, int num_lwlocks)
Definition: lwlock.c:672
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 730 of file pg_stat_statements.c.

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

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

Definition at line 1274 of file pg_stat_statements.c.

1282 {
1283  pgssHashKey key;
1284  pgssEntry *entry;
1285  char *norm_query = NULL;
1286  int encoding = GetDatabaseEncoding();
1287 
1288  Assert(query != NULL);
1289 
1290  /* Safety check... */
1291  if (!pgss || !pgss_hash)
1292  return;
1293 
1294  /*
1295  * Nothing to do if compute_query_id isn't enabled and no other module
1296  * computed a query identifier.
1297  */
1298  if (queryId == UINT64CONST(0))
1299  return;
1300 
1301  /*
1302  * Confine our attention to the relevant part of the string, if the query
1303  * is a portion of a multi-statement source string, and update query
1304  * location and length if needed.
1305  */
1306  query = CleanQuerytext(query, &query_location, &query_len);
1307 
1308  /* Set up key for hashtable search */
1309 
1310  /* clear padding */
1311  memset(&key, 0, sizeof(pgssHashKey));
1312 
1313  key.userid = GetUserId();
1314  key.dbid = MyDatabaseId;
1315  key.queryid = queryId;
1316  key.toplevel = (nesting_level == 0);
1317 
1318  /* Lookup the hash table entry with shared lock. */
1320 
1321  entry = (pgssEntry *) hash_search(pgss_hash, &key, HASH_FIND, NULL);
1322 
1323  /* Create new entry, if not present */
1324  if (!entry)
1325  {
1326  Size query_offset;
1327  int gc_count;
1328  bool stored;
1329  bool do_gc;
1330 
1331  /*
1332  * Create a new, normalized query string if caller asked. We don't
1333  * need to hold the lock while doing this work. (Note: in any case,
1334  * it's possible that someone else creates a duplicate hashtable entry
1335  * in the interval where we don't hold the lock below. That case is
1336  * handled by entry_alloc.)
1337  */
1338  if (jstate)
1339  {
1341  norm_query = generate_normalized_query(jstate, query,
1342  query_location,
1343  &query_len);
1345  }
1346 
1347  /* Append new query text to file with only shared lock held */
1348  stored = qtext_store(norm_query ? norm_query : query, query_len,
1349  &query_offset, &gc_count);
1350 
1351  /*
1352  * Determine whether we need to garbage collect external query texts
1353  * while the shared lock is still held. This micro-optimization
1354  * avoids taking the time to decide this while holding exclusive lock.
1355  */
1356  do_gc = need_gc_qtexts();
1357 
1358  /* Need exclusive lock to make a new hashtable entry - promote */
1361 
1362  /*
1363  * A garbage collection may have occurred while we weren't holding the
1364  * lock. In the unlikely event that this happens, the query text we
1365  * stored above will have been garbage collected, so write it again.
1366  * This should be infrequent enough that doing it while holding
1367  * exclusive lock isn't a performance problem.
1368  */
1369  if (!stored || pgss->gc_count != gc_count)
1370  stored = qtext_store(norm_query ? norm_query : query, query_len,
1371  &query_offset, NULL);
1372 
1373  /* If we failed to write to the text file, give up */
1374  if (!stored)
1375  goto done;
1376 
1377  /* OK to create a new hashtable entry */
1378  entry = entry_alloc(&key, query_offset, query_len, encoding,
1379  jstate != NULL);
1380 
1381  /* If needed, perform garbage collection while exclusive lock held */
1382  if (do_gc)
1383  gc_qtexts();
1384  }
1385 
1386  /* Increment the counts, except when jstate is not NULL */
1387  if (!jstate)
1388  {
1389  /*
1390  * Grab the spinlock while updating the counters (see comment about
1391  * locking rules at the head of the file)
1392  */
1393  volatile pgssEntry *e = (volatile pgssEntry *) entry;
1394 
1395  Assert(kind == PGSS_PLAN || kind == PGSS_EXEC);
1396 
1397  SpinLockAcquire(&e->mutex);
1398 
1399  /* "Unstick" entry if it was previously sticky */
1400  if (IS_STICKY(e->counters))
1401  e->counters.usage = USAGE_INIT;
1402 
1403  e->counters.calls[kind] += 1;
1404  e->counters.total_time[kind] += total_time;
1405 
1406  if (e->counters.calls[kind] == 1)
1407  {
1408  e->counters.min_time[kind] = total_time;
1409  e->counters.max_time[kind] = total_time;
1410  e->counters.mean_time[kind] = total_time;
1411  }
1412  else
1413  {
1414  /*
1415  * Welford's method for accurately computing variance. See
1416  * <http://www.johndcook.com/blog/standard_deviation/>
1417  */
1418  double old_mean = e->counters.mean_time[kind];
1419 
1420  e->counters.mean_time[kind] +=
1421  (total_time - old_mean) / e->counters.calls[kind];
1422  e->counters.sum_var_time[kind] +=
1423  (total_time - old_mean) * (total_time - e->counters.mean_time[kind]);
1424 
1425  /*
1426  * Calculate min and max time. min = 0 and max = 0 means that the
1427  * min/max statistics were reset
1428  */
1429  if (e->counters.min_time[kind] == 0
1430  && e->counters.max_time[kind] == 0)
1431  {
1432  e->counters.min_time[kind] = total_time;
1433  e->counters.max_time[kind] = total_time;
1434  }
1435  else
1436  {
1437  if (e->counters.min_time[kind] > total_time)
1438  e->counters.min_time[kind] = total_time;
1439  if (e->counters.max_time[kind] < total_time)
1440  e->counters.max_time[kind] = total_time;
1441  }
1442  }
1443  e->counters.rows += rows;
1444  e->counters.shared_blks_hit += bufusage->shared_blks_hit;
1445  e->counters.shared_blks_read += bufusage->shared_blks_read;
1446  e->counters.shared_blks_dirtied += bufusage->shared_blks_dirtied;
1447  e->counters.shared_blks_written += bufusage->shared_blks_written;
1448  e->counters.local_blks_hit += bufusage->local_blks_hit;
1449  e->counters.local_blks_read += bufusage->local_blks_read;
1450  e->counters.local_blks_dirtied += bufusage->local_blks_dirtied;
1451  e->counters.local_blks_written += bufusage->local_blks_written;
1452  e->counters.temp_blks_read += bufusage->temp_blks_read;
1453  e->counters.temp_blks_written += bufusage->temp_blks_written;
1454  e->counters.shared_blk_read_time += INSTR_TIME_GET_MILLISEC(bufusage->shared_blk_read_time);
1455  e->counters.shared_blk_write_time += INSTR_TIME_GET_MILLISEC(bufusage->shared_blk_write_time);
1456  e->counters.local_blk_read_time += INSTR_TIME_GET_MILLISEC(bufusage->local_blk_read_time);
1457  e->counters.local_blk_write_time += INSTR_TIME_GET_MILLISEC(bufusage->local_blk_write_time);
1458  e->counters.temp_blk_read_time += INSTR_TIME_GET_MILLISEC(bufusage->temp_blk_read_time);
1459  e->counters.temp_blk_write_time += INSTR_TIME_GET_MILLISEC(bufusage->temp_blk_write_time);
1460  e->counters.usage += USAGE_EXEC(total_time);
1461  e->counters.wal_records += walusage->wal_records;
1462  e->counters.wal_fpi += walusage->wal_fpi;
1463  e->counters.wal_bytes += walusage->wal_bytes;
1464  if (jitusage)
1465  {
1466  e->counters.jit_functions += jitusage->created_functions;
1467  e->counters.jit_generation_time += INSTR_TIME_GET_MILLISEC(jitusage->generation_counter);
1468 
1469  if (INSTR_TIME_GET_MILLISEC(jitusage->deform_counter))
1470  e->counters.jit_deform_count++;
1471  e->counters.jit_deform_time += INSTR_TIME_GET_MILLISEC(jitusage->deform_counter);
1472 
1474  e->counters.jit_inlining_count++;
1475  e->counters.jit_inlining_time += INSTR_TIME_GET_MILLISEC(jitusage->inlining_counter);
1476 
1478  e->counters.jit_optimization_count++;
1479  e->counters.jit_optimization_time += INSTR_TIME_GET_MILLISEC(jitusage->optimization_counter);
1480 
1482  e->counters.jit_emission_count++;
1483  e->counters.jit_emission_time += INSTR_TIME_GET_MILLISEC(jitusage->emission_counter);
1484  }
1485 
1486  SpinLockRelease(&e->mutex);
1487  }
1488 
1489 done:
1491 
1492  /* We postpone this clean-up until we're out of the lock */
1493  if (norm_query)
1494  pfree(norm_query);
1495 }
Oid MyDatabaseId
Definition: globals.c:91
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
uint64 wal_bytes
Definition: instrument.h:55
int64 wal_fpi
Definition: instrument.h:54
int64 wal_records
Definition: instrument.h:53

References Assert, CleanQuerytext(), 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, sort-test::key, BufferUsage::local_blk_read_time, BufferUsage::local_blk_write_time, BufferUsage::local_blks_dirtied, BufferUsage::local_blks_hit, BufferUsage::local_blks_read, BufferUsage::local_blks_written, pgssSharedState::lock, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), MyDatabaseId, need_gc_qtexts(), nesting_level, JitInstrumentation::optimization_counter, pfree(), pgss, PGSS_EXEC, pgss_hash, PGSS_PLAN, qtext_store(), BufferUsage::shared_blk_read_time, BufferUsage::shared_blk_write_time, BufferUsage::shared_blks_dirtied, BufferUsage::shared_blks_hit, BufferUsage::shared_blks_read, BufferUsage::shared_blks_written, SpinLockAcquire, SpinLockRelease, BufferUsage::temp_blk_read_time, BufferUsage::temp_blk_write_time, BufferUsage::temp_blks_read, BufferUsage::temp_blks_written, USAGE_EXEC, USAGE_INIT, WalUsage::wal_bytes, WalUsage::wal_fpi, 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 2383 of file pg_stat_statements.c.

2385 {
2386  /* File read failed? */
2387  if (buffer == NULL)
2388  return NULL;
2389  /* Bogus offset/length? */
2390  if (query_len < 0 ||
2391  query_offset + query_len >= buffer_size)
2392  return NULL;
2393  /* As a further sanity check, make sure there's a trailing null */
2394  if (buffer[query_offset + query_len] != '\0')
2395  return NULL;
2396  /* Looks OK */
2397  return buffer + query_offset;
2398 }

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 2290 of file pg_stat_statements.c.

2291 {
2292  char *buf;
2293  int fd;
2294  struct stat stat;
2295  Size nread;
2296 
2298  if (fd < 0)
2299  {
2300  if (errno != ENOENT)
2301  ereport(LOG,
2303  errmsg("could not read file \"%s\": %m",
2304  PGSS_TEXT_FILE)));
2305  return NULL;
2306  }
2307 
2308  /* Get file length */
2309  if (fstat(fd, &stat))
2310  {
2311  ereport(LOG,
2313  errmsg("could not stat file \"%s\": %m",
2314  PGSS_TEXT_FILE)));
2316  return NULL;
2317  }
2318 
2319  /* Allocate buffer; beware that off_t might be wider than size_t */
2320  if (stat.st_size <= MaxAllocHugeSize)
2321  buf = (char *) malloc(stat.st_size);
2322  else
2323  buf = NULL;
2324  if (buf == NULL)
2325  {
2326  ereport(LOG,
2327  (errcode(ERRCODE_OUT_OF_MEMORY),
2328  errmsg("out of memory"),
2329  errdetail("Could not allocate enough memory to read file \"%s\".",
2330  PGSS_TEXT_FILE)));
2332  return NULL;
2333  }
2334 
2335  /*
2336  * OK, slurp in the file. Windows fails if we try to read more than
2337  * INT_MAX bytes at once, and other platforms might not like that either,
2338  * so read a very large file in 1GB segments.
2339  */
2340  nread = 0;
2341  while (nread < stat.st_size)
2342  {
2343  int toread = Min(1024 * 1024 * 1024, stat.st_size - nread);
2344 
2345  /*
2346  * If we get a short read and errno doesn't get set, the reason is
2347  * probably that garbage collection truncated the file since we did
2348  * the fstat(), so we don't log a complaint --- but we don't return
2349  * the data, either, since it's most likely corrupt due to concurrent
2350  * writes from garbage collection.
2351  */
2352  errno = 0;
2353  if (read(fd, buf + nread, toread) != toread)
2354  {
2355  if (errno)
2356  ereport(LOG,
2358  errmsg("could not read file \"%s\": %m",
2359  PGSS_TEXT_FILE)));
2360  free(buf);
2362  return NULL;
2363  }
2364  nread += toread;
2365  }
2366 
2367  if (CloseTransientFile(fd) != 0)
2368  ereport(LOG,
2370  errmsg("could not close file \"%s\": %m", PGSS_TEXT_FILE)));
2371 
2372  *buffer_size = nread;
2373  return buf;
2374 }
#define PG_BINARY
Definition: c.h:1273
int errdetail(const char *fmt,...)
Definition: elog.c:1205
int CloseTransientFile(int fd)
Definition: fd.c:2809
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2633
#define malloc(a)
Definition: header.h:50
#define read(a, b, c)
Definition: win32.h:13
#define MaxAllocHugeSize
Definition: memutils.h:45
static int fd(const char *x, int i)
Definition: preproc-init.c:105
__int64 st_size
Definition: win32_port.h:273
#define fstat
Definition: win32_port.h:283

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 2198 of file pg_stat_statements.c.

2200 {
2201  Size off;
2202  int fd;
2203 
2204  /*
2205  * We use a spinlock to protect extent/n_writers/gc_count, so that
2206  * multiple processes may execute this function concurrently.
2207  */
2208  {
2209  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
2210 
2211  SpinLockAcquire(&s->mutex);
2212  off = s->extent;
2213  s->extent += query_len + 1;
2214  s->n_writers++;
2215  if (gc_count)
2216  *gc_count = s->gc_count;
2217  SpinLockRelease(&s->mutex);
2218  }
2219 
2220  *query_offset = off;
2221 
2222  /*
2223  * Don't allow the file to grow larger than what qtext_load_file can
2224  * (theoretically) handle. This has been seen to be reachable on 32-bit
2225  * platforms.
2226  */
2227  if (unlikely(query_len >= MaxAllocHugeSize - off))
2228  {
2229  errno = EFBIG; /* not quite right, but it'll do */
2230  fd = -1;
2231  goto error;
2232  }
2233 
2234  /* Now write the data into the successfully-reserved part of the file */
2235  fd = OpenTransientFile(PGSS_TEXT_FILE, O_RDWR | O_CREAT | PG_BINARY);
2236  if (fd < 0)
2237  goto error;
2238 
2239  if (pg_pwrite(fd, query, query_len, off) != query_len)
2240  goto error;
2241  if (pg_pwrite(fd, "\0", 1, off + query_len) != 1)
2242  goto error;
2243 
2245 
2246  /* Mark our write complete */
2247  {
2248  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
2249 
2250  SpinLockAcquire(&s->mutex);
2251  s->n_writers--;
2252  SpinLockRelease(&s->mutex);
2253  }
2254 
2255  return true;
2256 
2257 error:
2258  ereport(LOG,
2260  errmsg("could not write file \"%s\": %m",
2261  PGSS_TEXT_FILE)));
2262 
2263  if (fd >= 0)
2265 
2266  /* Mark our write complete */
2267  {
2268  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
2269 
2270  SpinLockAcquire(&s->mutex);
2271  s->n_writers--;
2272  SpinLockRelease(&s->mutex);
2273  }
2274 
2275  return false;
2276 }
#define unlikely(x)
Definition: c.h:311
#define pg_pwrite
Definition: port.h:226

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

◆ PG_MODULE_MAGIC

PG_MODULE_MAGIC

Definition at line 77 of file pg_stat_statements.c.

◆ 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 294 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 290 of file pg_stat_statements.c.

Referenced by _PG_init().

◆ pgss_track_planning

bool pgss_track_planning = false
static

Definition at line 292 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 291 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 265 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 264 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 263 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 262 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 261 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 260 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 266 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 258 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 259 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 270 of file pg_stat_statements.c.

Referenced by _PG_init().