Thanks to visit codestin.com
Credit goes to doxygen.postgresql.org

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/int.h"
#include "executor/instrument.h"
#include "funcapi.h"
#include "jit/jit.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "nodes/queryjumble.h"
#include "optimizer/planner.h"
#include "parser/analyze.h"
#include "parser/scanner.h"
#include "pgstat.h"
#include "storage/fd.h"
#include "storage/ipc.h"
#include "storage/lwlock.h"
#include "storage/shmem.h"
#include "storage/spin.h"
#include "tcop/utility.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
#include "utils/timestamp.h"
Include dependency graph for pg_stat_statements.c:

Go to the source code of this file.

Data Structures

struct  pgssHashKey
 
struct  Counters
 
struct  pgssGlobalStats
 
struct  pgssEntry
 
struct  pgssSharedState
 

Macros

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

Typedefs

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

Enumerations

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

Functions

 PG_MODULE_MAGIC_EXT (.name="pg_stat_statements",.version=PG_VERSION)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_reset)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_reset_1_7)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_reset_1_11)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_1_2)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_1_3)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_1_8)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_1_9)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_1_10)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_1_11)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_1_12)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_1_13)
 
 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)
 
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, int64 queryId, int query_location, int query_len, pgssStoreKind kind, double total_time, uint64 rows, const BufferUsage *bufusage, const WalUsage *walusage, const struct JitInstrumentation *jitusage, JumbleState *jstate, int parallel_workers_to_launch, int parallel_workers_launched, PlannedStmtOrigin planOrigin)
 
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, int64 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_13 (PG_FUNCTION_ARGS)
 
Datum pg_stat_statements_1_12 (PG_FUNCTION_ARGS)
 
Datum pg_stat_statements_1_11 (PG_FUNCTION_ARGS)
 
Datum pg_stat_statements_1_10 (PG_FUNCTION_ARGS)
 
Datum pg_stat_statements_1_9 (PG_FUNCTION_ARGS)
 
Datum pg_stat_statements_1_8 (PG_FUNCTION_ARGS)
 
Datum pg_stat_statements_1_3 (PG_FUNCTION_ARGS)
 
Datum pg_stat_statements_1_2 (PG_FUNCTION_ARGS)
 
Datum pg_stat_statements (PG_FUNCTION_ARGS)
 
Datum pg_stat_statements_info (PG_FUNCTION_ARGS)
 
static int entry_cmp (const void *lhs, const void *rhs)
 

Variables

static const uint32 PGSS_FILE_HEADER = 0x20250731
 
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   54 /* maximum of above */

Definition at line 1581 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_0

#define PG_STAT_STATEMENTS_COLS_V1_0   14

Definition at line 1571 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_1

#define PG_STAT_STATEMENTS_COLS_V1_1   18

Definition at line 1572 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_10

#define PG_STAT_STATEMENTS_COLS_V1_10   43

Definition at line 1577 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_11

#define PG_STAT_STATEMENTS_COLS_V1_11   49

Definition at line 1578 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_12

#define PG_STAT_STATEMENTS_COLS_V1_12   52

Definition at line 1579 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_13

#define PG_STAT_STATEMENTS_COLS_V1_13   54

Definition at line 1580 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_2

#define PG_STAT_STATEMENTS_COLS_V1_2   19

Definition at line 1573 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_3

#define PG_STAT_STATEMENTS_COLS_V1_3   23

Definition at line 1574 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_8

#define PG_STAT_STATEMENTS_COLS_V1_8   32

Definition at line 1575 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_9

#define PG_STAT_STATEMENTS_COLS_V1_9   33

Definition at line 1576 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_INFO_COLS

#define PG_STAT_STATEMENTS_INFO_COLS   2

Definition at line 2049 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 304 of file pg_stat_statements.c.

◆ PGSS_NUMKIND

#define PGSS_NUMKIND   (PGSS_EXEC + 1)

Definition at line 133 of file pg_stat_statements.c.

◆ PGSS_TEXT_FILE

#define PGSS_TEXT_FILE   PG_STAT_TMP_DIR "/pgss_query_texts.stat"

Definition at line 85 of file pg_stat_statements.c.

◆ record_gc_qtexts

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

Definition at line 309 of file pg_stat_statements.c.

◆ SINGLE_ENTRY_RESET

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

Definition at line 2687 of file pg_stat_statements.c.

◆ STICKY_DECREASE_FACTOR

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

Definition at line 99 of file pg_stat_statements.c.

◆ USAGE_DEALLOC_PERCENT

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

Definition at line 100 of file pg_stat_statements.c.

◆ USAGE_DECREASE_FACTOR

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

Definition at line 98 of file pg_stat_statements.c.

◆ USAGE_EXEC

#define USAGE_EXEC (   duration)    (1.0)

Definition at line 94 of file pg_stat_statements.c.

◆ USAGE_INIT

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

Definition at line 95 of file pg_stat_statements.c.

Typedef Documentation

◆ Counters

typedef struct Counters Counters

◆ pgssEntry

typedef struct pgssEntry pgssEntry

◆ pgssGlobalStats

◆ pgssHashKey

typedef struct pgssHashKey pgssHashKey

◆ pgssSharedState

◆ pgssStoreKind

◆ pgssVersion

typedef enum pgssVersion pgssVersion

Enumeration Type Documentation

◆ pgssStoreKind

Enumerator
PGSS_INVALID 
PGSS_PLAN 
PGSS_EXEC 

Definition at line 120 of file pg_stat_statements.c.

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

◆ PGSSTrackLevel

Enumerator
PGSS_TRACK_NONE 
PGSS_TRACK_TOP 
PGSS_TRACK_ALL 

Definition at line 282 of file pg_stat_statements.c.

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

◆ pgssVersion

Enumerator
PGSS_V1_0 
PGSS_V1_1 
PGSS_V1_2 
PGSS_V1_3 
PGSS_V1_8 
PGSS_V1_9 
PGSS_V1_10 
PGSS_V1_11 
PGSS_V1_12 
PGSS_V1_13 

Definition at line 106 of file pg_stat_statements.c.

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

Function Documentation

◆ _PG_init()

void _PG_init ( void  )

Definition at line 389 of file pg_stat_statements.c.

390{
391 /*
392 * In order to create our shared memory area, we have to be loaded via
393 * shared_preload_libraries. If not, fall out without hooking into any of
394 * the main system. (We don't throw error here because it seems useful to
395 * allow the pg_stat_statements functions to be created even when the
396 * module isn't active. The functions must protect themselves against
397 * being called then, however.)
398 */
400 return;
401
402 /*
403 * Inform the postmaster that we want to enable query_id calculation if
404 * compute_query_id is set to auto.
405 */
407
408 /*
409 * Define (or redefine) custom GUC variables.
410 */
411 DefineCustomIntVariable("pg_stat_statements.max",
412 "Sets the maximum number of statements tracked by pg_stat_statements.",
413 NULL,
414 &pgss_max,
415 5000,
416 100,
417 INT_MAX / 2,
419 0,
420 NULL,
421 NULL,
422 NULL);
423
424 DefineCustomEnumVariable("pg_stat_statements.track",
425 "Selects which statements are tracked by pg_stat_statements.",
426 NULL,
427 &pgss_track,
430 PGC_SUSET,
431 0,
432 NULL,
433 NULL,
434 NULL);
435
436 DefineCustomBoolVariable("pg_stat_statements.track_utility",
437 "Selects whether utility commands are tracked by pg_stat_statements.",
438 NULL,
440 true,
441 PGC_SUSET,
442 0,
443 NULL,
444 NULL,
445 NULL);
446
447 DefineCustomBoolVariable("pg_stat_statements.track_planning",
448 "Selects whether planning duration is tracked by pg_stat_statements.",
449 NULL,
451 false,
452 PGC_SUSET,
453 0,
454 NULL,
455 NULL,
456 NULL);
457
458 DefineCustomBoolVariable("pg_stat_statements.save",
459 "Save pg_stat_statements statistics across server shutdowns.",
460 NULL,
461 &pgss_save,
462 true,
464 0,
465 NULL,
466 NULL,
467 NULL);
468
469 MarkGUCPrefixReserved("pg_stat_statements");
470
471 /*
472 * Install hooks.
473 */
492}
ExecutorEnd_hook_type ExecutorEnd_hook
Definition: execMain.c:71
ExecutorFinish_hook_type ExecutorFinish_hook
Definition: execMain.c:70
ExecutorStart_hook_type ExecutorStart_hook
Definition: execMain.c:68
ExecutorRun_hook_type ExecutorRun_hook
Definition: execMain.c:69
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:5265
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:5154
void MarkGUCPrefixReserved(const char *className)
Definition: guc.c:5301
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:5180
@ PGC_SUSET
Definition: guc.h:78
@ PGC_POSTMASTER
Definition: guc.h:74
@ PGC_SIGHUP
Definition: guc.h:75
shmem_startup_hook_type shmem_startup_hook
Definition: ipci.c:58
shmem_request_hook_type shmem_request_hook
Definition: miscinit.c:1789
bool process_shared_preload_libraries_in_progress
Definition: miscinit.c:1786
post_parse_analyze_hook_type post_parse_analyze_hook
Definition: analyze.c:67
static planner_hook_type prev_planner_hook
static bool pgss_track_planning
static ExecutorRun_hook_type prev_ExecutorRun
static PlannedStmt * pgss_planner(Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams)
static int pgss_max
static const struct config_enum_entry track_options[]
static void pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc)
static post_parse_analyze_hook_type prev_post_parse_analyze_hook
static shmem_startup_hook_type prev_shmem_startup_hook
static shmem_request_hook_type prev_shmem_request_hook
static void pgss_shmem_request(void)
static bool pgss_save
static void pgss_shmem_startup(void)
static ExecutorStart_hook_type prev_ExecutorStart
static void pgss_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count)
static void pgss_ExecutorFinish(QueryDesc *queryDesc)
static ProcessUtility_hook_type prev_ProcessUtility
static void pgss_post_parse_analyze(ParseState *pstate, Query *query, JumbleState *jstate)
static bool pgss_track_utility
static ExecutorEnd_hook_type prev_ExecutorEnd
static void pgss_ExecutorEnd(QueryDesc *queryDesc)
static void pgss_ExecutorStart(QueryDesc *queryDesc, int eflags)
static ExecutorFinish_hook_type prev_ExecutorFinish
planner_hook_type planner_hook
Definition: planner.c:74
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 3071 of file pg_stat_statements.c.

3072{
3073 int l = ((const LocationLen *) a)->location;
3074 int r = ((const LocationLen *) b)->location;
3075
3076 return pg_cmp_s32(l, r);
3077}
static int pg_cmp_s32(int32 a, int32 b)
Definition: int.h:646
int b
Definition: isn.c:74
int a
Definition: isn.c:73

References a, b, and pg_cmp_s32().

Referenced by fill_in_constant_lengths().

◆ entry_alloc()

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

Definition at line 2114 of file pg_stat_statements.c.

2116{
2117 pgssEntry *entry;
2118 bool found;
2119
2120 /* Make space if needed */
2122 entry_dealloc();
2123
2124 /* Find or create an entry with desired hash code */
2125 entry = (pgssEntry *) hash_search(pgss_hash, key, HASH_ENTER, &found);
2126
2127 if (!found)
2128 {
2129 /* New entry, initialize it */
2130
2131 /* reset the statistics */
2132 memset(&entry->counters, 0, sizeof(Counters));
2133 /* set the appropriate initial usage count */
2134 entry->counters.usage = sticky ? pgss->cur_median_usage : USAGE_INIT;
2135 /* re-initialize the mutex each time ... we assume no one using it */
2136 SpinLockInit(&entry->mutex);
2137 /* ... and don't forget the query text metadata */
2138 Assert(query_len >= 0);
2139 entry->query_offset = query_offset;
2140 entry->query_len = query_len;
2141 entry->encoding = encoding;
2143 entry->minmax_stats_since = entry->stats_since;
2144 }
2145
2146 return entry;
2147}
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1645
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:952
int64 hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1336
Assert(PointerIsAligned(start, uint64))
@ HASH_ENTER
Definition: hsearch.h:114
int32 encoding
Definition: pg_database.h:41
static void entry_dealloc(void)
#define USAGE_INIT
#define SpinLockInit(lock)
Definition: spin.h:57
Counters counters
TimestampTz minmax_stats_since
TimestampTz stats_since

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

Referenced by pgss_shmem_startup(), and pgss_store().

◆ entry_cmp()

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

Definition at line 2153 of file pg_stat_statements.c.

2154{
2155 double l_usage = (*(pgssEntry *const *) lhs)->counters.usage;
2156 double r_usage = (*(pgssEntry *const *) rhs)->counters.usage;
2157
2158 if (l_usage < r_usage)
2159 return -1;
2160 else if (l_usage > r_usage)
2161 return +1;
2162 else
2163 return 0;
2164}

Referenced by entry_dealloc().

◆ entry_dealloc()

static void entry_dealloc ( void  )
static

Definition at line 2172 of file pg_stat_statements.c.

2173{
2174 HASH_SEQ_STATUS hash_seq;
2175 pgssEntry **entries;
2176 pgssEntry *entry;
2177 int nvictims;
2178 int i;
2179 Size tottextlen;
2180 int nvalidtexts;
2181
2182 /*
2183 * Sort entries by usage and deallocate USAGE_DEALLOC_PERCENT of them.
2184 * While we're scanning the table, apply the decay factor to the usage
2185 * values, and update the mean query length.
2186 *
2187 * Note that the mean query length is almost immediately obsolete, since
2188 * we compute it before not after discarding the least-used entries.
2189 * Hopefully, that doesn't affect the mean too much; it doesn't seem worth
2190 * making two passes to get a more current result. Likewise, the new
2191 * cur_median_usage includes the entries we're about to zap.
2192 */
2193
2194 entries = palloc(hash_get_num_entries(pgss_hash) * sizeof(pgssEntry *));
2195
2196 i = 0;
2197 tottextlen = 0;
2198 nvalidtexts = 0;
2199
2200 hash_seq_init(&hash_seq, pgss_hash);
2201 while ((entry = hash_seq_search(&hash_seq)) != NULL)
2202 {
2203 entries[i++] = entry;
2204 /* "Sticky" entries get a different usage decay rate. */
2205 if (IS_STICKY(entry->counters))
2207 else
2209 /* In the mean length computation, ignore dropped texts. */
2210 if (entry->query_len >= 0)
2211 {
2212 tottextlen += entry->query_len + 1;
2213 nvalidtexts++;
2214 }
2215 }
2216
2217 /* Sort into increasing order by usage */
2218 qsort(entries, i, sizeof(pgssEntry *), entry_cmp);
2219
2220 /* Record the (approximate) median usage */
2221 if (i > 0)
2222 pgss->cur_median_usage = entries[i / 2]->counters.usage;
2223 /* Record the mean query length */
2224 if (nvalidtexts > 0)
2225 pgss->mean_query_len = tottextlen / nvalidtexts;
2226 else
2228
2229 /* Now zap an appropriate fraction of lowest-usage entries */
2230 nvictims = Max(10, i * USAGE_DEALLOC_PERCENT / 100);
2231 nvictims = Min(nvictims, i);
2232
2233 for (i = 0; i < nvictims; i++)
2234 {
2235 hash_search(pgss_hash, &entries[i]->key, HASH_REMOVE, NULL);
2236 }
2237
2238 pfree(entries);
2239
2240 /* Increment the number of times entries are deallocated */
2242 pgss->stats.dealloc += 1;
2244}
#define Min(x, y)
Definition: c.h:1004
#define Max(x, y)
Definition: c.h:998
size_t Size
Definition: c.h:611
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1415
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1380
int i
Definition: isn.c:77
void pfree(void *pointer)
Definition: mcxt.c:1594
void * palloc(Size size)
Definition: mcxt.c:1365
static int entry_cmp(const void *lhs, const void *rhs)
#define USAGE_DEALLOC_PERCENT
#define STICKY_DECREASE_FACTOR
#define IS_STICKY(c)
#define ASSUMED_LENGTH_INIT
#define USAGE_DECREASE_FACTOR
#define qsort(a, b, c, d)
Definition: port.h:479
#define SpinLockRelease(lock)
Definition: spin.h:61
#define SpinLockAcquire(lock)
Definition: spin.h:59
pgssGlobalStats stats

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

Referenced by entry_alloc().

◆ entry_reset()

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

Definition at line 2710 of file pg_stat_statements.c.

2711{
2712 HASH_SEQ_STATUS hash_seq;
2713 pgssEntry *entry;
2714 FILE *qfile;
2715 int64 num_entries;
2716 int64 num_remove = 0;
2718 TimestampTz stats_reset;
2719
2720 if (!pgss || !pgss_hash)
2721 ereport(ERROR,
2722 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2723 errmsg("pg_stat_statements must be loaded via \"shared_preload_libraries\"")));
2724
2726 num_entries = hash_get_num_entries(pgss_hash);
2727
2728 stats_reset = GetCurrentTimestamp();
2729
2730 if (userid != 0 && dbid != 0 && queryid != INT64CONST(0))
2731 {
2732 /* If all the parameters are available, use the fast path. */
2733 memset(&key, 0, sizeof(pgssHashKey));
2734 key.userid = userid;
2735 key.dbid = dbid;
2736 key.queryid = queryid;
2737
2738 /*
2739 * Reset the entry if it exists, starting with the non-top-level
2740 * entry.
2741 */
2742 key.toplevel = false;
2743 entry = (pgssEntry *) hash_search(pgss_hash, &key, HASH_FIND, NULL);
2744
2745 SINGLE_ENTRY_RESET(entry);
2746
2747 /* Also reset the top-level entry if it exists. */
2748 key.toplevel = true;
2749 entry = (pgssEntry *) hash_search(pgss_hash, &key, HASH_FIND, NULL);
2750
2751 SINGLE_ENTRY_RESET(entry);
2752 }
2753 else if (userid != 0 || dbid != 0 || queryid != INT64CONST(0))
2754 {
2755 /* Reset entries corresponding to valid parameters. */
2756 hash_seq_init(&hash_seq, pgss_hash);
2757 while ((entry = hash_seq_search(&hash_seq)) != NULL)
2758 {
2759 if ((!userid || entry->key.userid == userid) &&
2760 (!dbid || entry->key.dbid == dbid) &&
2761 (!queryid || entry->key.queryid == queryid))
2762 {
2763 SINGLE_ENTRY_RESET(entry);
2764 }
2765 }
2766 }
2767 else
2768 {
2769 /* Reset all entries. */
2770 hash_seq_init(&hash_seq, pgss_hash);
2771 while ((entry = hash_seq_search(&hash_seq)) != NULL)
2772 {
2773 SINGLE_ENTRY_RESET(entry);
2774 }
2775 }
2776
2777 /* All entries are removed? */
2778 if (num_entries != num_remove)
2779 goto release_lock;
2780
2781 /*
2782 * Reset global statistics for pg_stat_statements since all entries are
2783 * removed.
2784 */
2786 pgss->stats.dealloc = 0;
2787 pgss->stats.stats_reset = stats_reset;
2789
2790 /*
2791 * Write new empty query file, perhaps even creating a new one to recover
2792 * if the file was missing.
2793 */
2795 if (qfile == NULL)
2796 {
2797 ereport(LOG,
2799 errmsg("could not create file \"%s\": %m",
2800 PGSS_TEXT_FILE)));
2801 goto done;
2802 }
2803
2804 /* If ftruncate fails, log it, but it's not a fatal problem */
2805 if (ftruncate(fileno(qfile), 0) != 0)
2806 ereport(LOG,
2808 errmsg("could not truncate file \"%s\": %m",
2809 PGSS_TEXT_FILE)));
2810
2811 FreeFile(qfile);
2812
2813done:
2814 pgss->extent = 0;
2815 /* This counts as a query text garbage collection for our purposes */
2817
2818release_lock:
2820
2821 return stats_reset;
2822}
#define INT64CONST(x)
Definition: c.h:553
int64_t int64
Definition: c.h:536
#define PG_BINARY_W
Definition: c.h:1276
int64 TimestampTz
Definition: timestamp.h:39
int errcode_for_file_access(void)
Definition: elog.c:877
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define LOG
Definition: elog.h:31
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:150
int FreeFile(FILE *file)
Definition: fd.c:2840
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2641
@ HASH_FIND
Definition: hsearch.h:113
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1174
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1894
@ LW_EXCLUSIVE
Definition: lwlock.h:112
#define SINGLE_ENTRY_RESET(e)
#define record_gc_qtexts()
#define PGSS_TEXT_FILE
pgssHashKey key
TimestampTz stats_reset

References AllocateFile(), pgssHashKey::dbid, pgssGlobalStats::dealloc, ereport, errcode(), errcode_for_file_access(), errmsg(), ERROR, pgssSharedState::extent, FreeFile(), GetCurrentTimestamp(), HASH_FIND, hash_get_num_entries(), hash_search(), hash_seq_init(), hash_seq_search(), INT64CONST, 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 2968 of file pg_stat_statements.c.

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

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

Referenced by generate_normalized_query().

◆ gc_qtexts()

static void gc_qtexts ( void  )
static

Definition at line 2508 of file pg_stat_statements.c.

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

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

Referenced by pgss_store().

◆ generate_normalized_query()

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

Definition at line 2844 of file pg_stat_statements.c.

2846{
2847 char *norm_query;
2848 int query_len = *query_len_p;
2849 int norm_query_buflen, /* Space allowed for norm_query */
2850 len_to_wrt, /* Length (in bytes) to write */
2851 quer_loc = 0, /* Source query byte location */
2852 n_quer_loc = 0, /* Normalized query byte location */
2853 last_off = 0, /* Offset from start for previous tok */
2854 last_tok_len = 0; /* Length (in bytes) of that tok */
2855 int num_constants_replaced = 0;
2856
2857 /*
2858 * Get constants' lengths (core system only gives us locations). Note
2859 * this also ensures the items are sorted by location.
2860 */
2861 fill_in_constant_lengths(jstate, query, query_loc);
2862
2863 /*
2864 * Allow for $n symbols to be longer than the constants they replace.
2865 * Constants must take at least one byte in text form, while a $n symbol
2866 * certainly isn't more than 11 bytes, even if n reaches INT_MAX. We
2867 * could refine that limit based on the max value of n for the current
2868 * query, but it hardly seems worth any extra effort to do so.
2869 */
2870 norm_query_buflen = query_len + jstate->clocations_count * 10;
2871
2872 /* Allocate result buffer */
2873 norm_query = palloc(norm_query_buflen + 1);
2874
2875 for (int i = 0; i < jstate->clocations_count; i++)
2876 {
2877 int off, /* Offset from start for cur tok */
2878 tok_len; /* Length (in bytes) of that tok */
2879
2880 /*
2881 * If we have an external param at this location, but no lists are
2882 * being squashed across the query, then we skip here; this will make
2883 * us print the characters found in the original query that represent
2884 * the parameter in the next iteration (or after the loop is done),
2885 * which is a bit odd but seems to work okay in most cases.
2886 */
2887 if (jstate->clocations[i].extern_param && !jstate->has_squashed_lists)
2888 continue;
2889
2890 off = jstate->clocations[i].location;
2891
2892 /* Adjust recorded location if we're dealing with partial string */
2893 off -= query_loc;
2894
2895 tok_len = jstate->clocations[i].length;
2896
2897 if (tok_len < 0)
2898 continue; /* ignore any duplicates */
2899
2900 /* Copy next chunk (what precedes the next constant) */
2901 len_to_wrt = off - last_off;
2902 len_to_wrt -= last_tok_len;
2903 Assert(len_to_wrt >= 0);
2904 memcpy(norm_query + n_quer_loc, query + quer_loc, len_to_wrt);
2905 n_quer_loc += len_to_wrt;
2906
2907 /*
2908 * And insert a param symbol in place of the constant token; and, if
2909 * we have a squashable list, insert a placeholder comment starting
2910 * from the list's second value.
2911 */
2912 n_quer_loc += sprintf(norm_query + n_quer_loc, "$%d%s",
2913 num_constants_replaced + 1 + jstate->highest_extern_param_id,
2914 jstate->clocations[i].squashed ? " /*, ... */" : "");
2915 num_constants_replaced++;
2916
2917 /* move forward */
2918 quer_loc = off + tok_len;
2919 last_off = off;
2920 last_tok_len = tok_len;
2921 }
2922
2923 /*
2924 * We've copied up until the last ignorable constant. Copy over the
2925 * remaining bytes of the original query string.
2926 */
2927 len_to_wrt = query_len - quer_loc;
2928
2929 Assert(len_to_wrt >= 0);
2930 memcpy(norm_query + n_quer_loc, query + quer_loc, len_to_wrt);
2931 n_quer_loc += len_to_wrt;
2932
2933 Assert(n_quer_loc <= norm_query_buflen);
2934 norm_query[n_quer_loc] = '\0';
2935
2936 *query_len_p = n_quer_loc;
2937 return norm_query;
2938}
static void fill_in_constant_lengths(JumbleState *jstate, const char *query, int query_loc)
#define sprintf
Definition: port.h:241
bool has_squashed_lists
Definition: queryjumble.h:65
int highest_extern_param_id
Definition: queryjumble.h:62
bool squashed
Definition: queryjumble.h:28
bool extern_param
Definition: queryjumble.h:31

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

Referenced by pgss_store().

◆ need_gc_qtexts()

static bool need_gc_qtexts ( void  )
static

Definition at line 2459 of file pg_stat_statements.c.

2460{
2461 Size extent;
2462
2463 /* Read shared extent pointer */
2465 extent = pgss->extent;
2467
2468 /*
2469 * Don't proceed if file does not exceed 512 bytes per possible entry.
2470 *
2471 * Here and in the next test, 32-bit machines have overflow hazards if
2472 * pgss_max and/or mean_query_len are large. Force the multiplications
2473 * and comparisons to be done in uint64 arithmetic to forestall trouble.
2474 */
2475 if ((uint64) extent < (uint64) 512 * pgss_max)
2476 return false;
2477
2478 /*
2479 * Don't proceed if file is less than about 50% bloat. Nothing can or
2480 * should be done in the event of unusually large query texts accounting
2481 * for file's large size. We go to the trouble of maintaining the mean
2482 * query length in order to prevent garbage collection from thrashing
2483 * uselessly.
2484 */
2485 if ((uint64) extent < (uint64) pgss->mean_query_len * pgss_max * 2)
2486 return false;
2487
2488 return true;
2489}
uint64_t uint64
Definition: c.h:540

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

PG_FUNCTION_INFO_V1 ( pg_stat_statements  )

◆ PG_FUNCTION_INFO_V1() [2/13]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_10  )

◆ PG_FUNCTION_INFO_V1() [3/13]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_11  )

◆ PG_FUNCTION_INFO_V1() [4/13]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_12  )

◆ PG_FUNCTION_INFO_V1() [5/13]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_13  )

◆ PG_FUNCTION_INFO_V1() [6/13]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_2  )

◆ PG_FUNCTION_INFO_V1() [7/13]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_3  )

◆ PG_FUNCTION_INFO_V1() [8/13]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_8  )

◆ PG_FUNCTION_INFO_V1() [9/13]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_9  )

◆ PG_FUNCTION_INFO_V1() [10/13]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_info  )

◆ PG_FUNCTION_INFO_V1() [11/13]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_reset  )

◆ PG_FUNCTION_INFO_V1() [12/13]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_reset_1_11  )

◆ PG_FUNCTION_INFO_V1() [13/13]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_reset_1_7  )

◆ PG_MODULE_MAGIC_EXT()

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

◆ pg_stat_statements()

Datum pg_stat_statements ( PG_FUNCTION_ARGS  )

Definition at line 1678 of file pg_stat_statements.c.

1679{
1680 /* If it's really API 1.1, we'll figure that out below */
1682
1683 return (Datum) 0;
1684}
static void pg_stat_statements_internal(FunctionCallInfo fcinfo, pgssVersion api_version, bool showtext)
uint64_t Datum
Definition: postgres.h:70

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

1625{
1626 bool showtext = PG_GETARG_BOOL(0);
1627
1628 pg_stat_statements_internal(fcinfo, PGSS_V1_10, showtext);
1629
1630 return (Datum) 0;
1631}
#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 1614 of file pg_stat_statements.c.

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

References PG_GETARG_BOOL, pg_stat_statements_internal(), and PGSS_V1_11.

◆ pg_stat_statements_1_12()

Datum pg_stat_statements_1_12 ( PG_FUNCTION_ARGS  )

Definition at line 1604 of file pg_stat_statements.c.

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

References PG_GETARG_BOOL, pg_stat_statements_internal(), and PGSS_V1_12.

◆ pg_stat_statements_1_13()

Datum pg_stat_statements_1_13 ( PG_FUNCTION_ARGS  )

Definition at line 1594 of file pg_stat_statements.c.

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

References PG_GETARG_BOOL, pg_stat_statements_internal(), and PGSS_V1_13.

◆ pg_stat_statements_1_2()

Datum pg_stat_statements_1_2 ( PG_FUNCTION_ARGS  )

Definition at line 1664 of file pg_stat_statements.c.

1665{
1666 bool showtext = PG_GETARG_BOOL(0);
1667
1668 pg_stat_statements_internal(fcinfo, PGSS_V1_2, showtext);
1669
1670 return (Datum) 0;
1671}

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

1655{
1656 bool showtext = PG_GETARG_BOOL(0);
1657
1658 pg_stat_statements_internal(fcinfo, PGSS_V1_3, showtext);
1659
1660 return (Datum) 0;
1661}

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

1645{
1646 bool showtext = PG_GETARG_BOOL(0);
1647
1648 pg_stat_statements_internal(fcinfo, PGSS_V1_8, showtext);
1649
1650 return (Datum) 0;
1651}

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

1635{
1636 bool showtext = PG_GETARG_BOOL(0);
1637
1638 pg_stat_statements_internal(fcinfo, PGSS_V1_9, showtext);
1639
1640 return (Datum) 0;
1641}

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

2056{
2057 pgssGlobalStats stats;
2058 TupleDesc tupdesc;
2060 bool nulls[PG_STAT_STATEMENTS_INFO_COLS] = {0};
2061
2062 if (!pgss || !pgss_hash)
2063 ereport(ERROR,
2064 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2065 errmsg("pg_stat_statements must be loaded via \"shared_preload_libraries\"")));
2066
2067 /* Build a tuple descriptor for our result type */
2068 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
2069 elog(ERROR, "return type must be a row type");
2070
2071 /* Read global statistics for pg_stat_statements */
2073 stats = pgss->stats;
2075
2076 values[0] = Int64GetDatum(stats.dealloc);
2078
2080}
static Datum values[MAXATTR]
Definition: bootstrap.c:153
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:276
@ TYPEFUNC_COMPOSITE
Definition: funcapi.h:149
static Datum HeapTupleGetDatum(const HeapTupleData *tuple)
Definition: funcapi.h:230
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1117
#define PG_STAT_STATEMENTS_INFO_COLS
static Datum Int64GetDatum(int64 X)
Definition: postgres.h:403
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 1688 of file pg_stat_statements.c.

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

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

Referenced by pg_stat_statements(), pg_stat_statements_1_10(), pg_stat_statements_1_11(), pg_stat_statements_1_12(), pg_stat_statements_1_13(), 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 1563 of file pg_stat_statements.c.

1564{
1565 entry_reset(0, 0, 0, false);
1566
1568}
#define PG_RETURN_VOID()
Definition: fmgr.h:349
static TimestampTz entry_reset(Oid userid, Oid dbid, int64 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 1544 of file pg_stat_statements.c.

1545{
1546 Oid userid;
1547 Oid dbid;
1548 int64 queryid;
1549 bool minmax_only;
1550
1551 userid = PG_GETARG_OID(0);
1552 dbid = PG_GETARG_OID(1);
1553 queryid = PG_GETARG_INT64(2);
1554 minmax_only = PG_GETARG_BOOL(3);
1555
1556 PG_RETURN_TIMESTAMPTZ(entry_reset(userid, dbid, queryid, minmax_only));
1557}
#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 1528 of file pg_stat_statements.c.

1529{
1530 Oid userid;
1531 Oid dbid;
1532 int64 queryid;
1533
1534 userid = PG_GETARG_OID(0);
1535 dbid = PG_GETARG_OID(1);
1536 queryid = PG_GETARG_INT64(2);
1537
1538 entry_reset(userid, dbid, queryid, false);
1539
1541}

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

1076{
1077 int64 queryId = queryDesc->plannedstmt->queryId;
1078
1079 if (queryId != INT64CONST(0) && queryDesc->totaltime &&
1081 {
1082 /*
1083 * Make sure stats accumulation is done. (Note: it's okay if several
1084 * levels of hook all do this.)
1085 */
1086 InstrEndLoop(queryDesc->totaltime);
1087
1088 pgss_store(queryDesc->sourceText,
1089 queryId,
1090 queryDesc->plannedstmt->stmt_location,
1091 queryDesc->plannedstmt->stmt_len,
1092 PGSS_EXEC,
1093 queryDesc->totaltime->total * 1000.0, /* convert to msec */
1094 queryDesc->estate->es_total_processed,
1095 &queryDesc->totaltime->bufusage,
1096 &queryDesc->totaltime->walusage,
1097 queryDesc->estate->es_jit ? &queryDesc->estate->es_jit->instr : NULL,
1098 NULL,
1101 queryDesc->plannedstmt->planOrigin);
1102 }
1103
1104 if (prev_ExecutorEnd)
1105 prev_ExecutorEnd(queryDesc);
1106 else
1107 standard_ExecutorEnd(queryDesc);
1108}
void standard_ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:475
void InstrEndLoop(Instrumentation *instr)
Definition: instrument.c:140
#define pgss_enabled(level)
static int nesting_level
static void pgss_store(const char *query, int64 queryId, int query_location, int query_len, pgssStoreKind kind, double total_time, uint64 rows, const BufferUsage *bufusage, const WalUsage *walusage, const struct JitInstrumentation *jitusage, JumbleState *jstate, int parallel_workers_to_launch, int parallel_workers_launched, PlannedStmtOrigin planOrigin)
int es_parallel_workers_to_launch
Definition: execnodes.h:746
struct JitContext * es_jit
Definition: execnodes.h:764
uint64 es_total_processed
Definition: execnodes.h:716
int es_parallel_workers_launched
Definition: execnodes.h:748
WalUsage walusage
Definition: instrument.h:93
BufferUsage bufusage
Definition: instrument.h:92
JitInstrumentation instr
Definition: jit.h:62
int64 queryId
Definition: plannodes.h:71
ParseLoc stmt_len
Definition: plannodes.h:156
PlannedStmtOrigin planOrigin
Definition: plannodes.h:77
ParseLoc stmt_location
Definition: plannodes.h:154
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_parallel_workers_launched, EState::es_parallel_workers_to_launch, EState::es_total_processed, QueryDesc::estate, JitContext::instr, InstrEndLoop(), INT64CONST, nesting_level, pgss_enabled, PGSS_EXEC, pgss_store(), QueryDesc::plannedstmt, PlannedStmt::planOrigin, 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 1054 of file pg_stat_statements.c.

1055{
1056 nesting_level++;
1057 PG_TRY();
1058 {
1060 prev_ExecutorFinish(queryDesc);
1061 else
1062 standard_ExecutorFinish(queryDesc);
1063 }
1064 PG_FINALLY();
1065 {
1066 nesting_level--;
1067 }
1068 PG_END_TRY();
1069}
#define PG_TRY(...)
Definition: elog.h:372
#define PG_END_TRY(...)
Definition: elog.h:397
#define PG_FINALLY(...)
Definition: elog.h:389
void standard_ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:415

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

Referenced by _PG_init().

◆ pgss_ExecutorRun()

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

Definition at line 1033 of file pg_stat_statements.c.

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

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

1000{
1002 prev_ExecutorStart(queryDesc, eflags);
1003 else
1004 standard_ExecutorStart(queryDesc, eflags);
1005
1006 /*
1007 * If query has queryId zero, don't track it. This prevents double
1008 * counting of optimizable statements that are directly contained in
1009 * utility statements.
1010 */
1011 if (pgss_enabled(nesting_level) && queryDesc->plannedstmt->queryId != INT64CONST(0))
1012 {
1013 /*
1014 * Set up to track total elapsed time in ExecutorRun. Make sure the
1015 * space is allocated in the per-query context so it will go away at
1016 * ExecutorEnd.
1017 */
1018 if (queryDesc->totaltime == NULL)
1019 {
1020 MemoryContext oldcxt;
1021
1022 oldcxt = MemoryContextSwitchTo(queryDesc->estate->es_query_cxt);
1023 queryDesc->totaltime = InstrAlloc(1, INSTRUMENT_ALL, false);
1024 MemoryContextSwitchTo(oldcxt);
1025 }
1026 }
1027}
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:66
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
MemoryContext es_query_cxt
Definition: execnodes.h:710

References EState::es_query_cxt, QueryDesc::estate, InstrAlloc(), INSTRUMENT_ALL, INT64CONST, 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 2086 of file pg_stat_statements.c.

2087{
2088 Size size;
2089
2090 size = MAXALIGN(sizeof(pgssSharedState));
2091 size = add_size(size, hash_estimate_size(pgss_max, sizeof(pgssEntry)));
2092
2093 return size;
2094}
#define MAXALIGN(LEN)
Definition: c.h:811
Size hash_estimate_size(int64 num_entries, Size entrysize)
Definition: dynahash.c:783
Size add_size(Size s1, Size s2)
Definition: shmem.c:493

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

Referenced by pgss_shmem_request().

◆ pgss_planner()

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

Definition at line 893 of file pg_stat_statements.c.

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

References BufferUsageAccumDiff(), duration, INSTR_TIME_GET_MILLISEC, INSTR_TIME_SET_CURRENT, INSTR_TIME_SUBTRACT, INT64CONST, nesting_level, parse(), PG_END_TRY, PG_FINALLY, PG_TRY, pgBufferUsage, pgss_enabled, PGSS_PLAN, pgss_store(), pgss_track_planning, pgWalUsage, PlannedStmt::planOrigin, 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 840 of file pg_stat_statements.c.

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

References JumbleState::clocations_count, INT64CONST, IsA, nesting_level, ParseState::p_sourcetext, pgss, pgss_enabled, pgss_hash, PGSS_INVALID, pgss_store(), pgss_track_utility, PLAN_STMT_UNKNOWN, 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 1114 of file pg_stat_statements.c.

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

References BufferUsageAccumDiff(), QueryCompletion::commandTag, generate_unaccent_rules::dest, duration, INSTR_TIME_GET_MILLISEC, INSTR_TIME_SET_CURRENT, INSTR_TIME_SUBTRACT, INT64CONST, IsA, nesting_level, QueryCompletion::nprocessed, PG_END_TRY, PG_FINALLY, PG_TRY, pgBufferUsage, pgss_enabled, PGSS_EXEC, pgss_store(), pgss_track_utility, pgWalUsage, PlannedStmt::planOrigin, 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 499 of file pg_stat_statements.c.

500{
503
505 RequestNamedLWLockTranche("pg_stat_statements", 1);
506}
void RequestAddinShmemSpace(Size size)
Definition: ipci.c:74
void RequestNamedLWLockTranche(const char *tranche_name, int num_lwlocks)
Definition: lwlock.c:649
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 741 of file pg_stat_statements.c.

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

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

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

Referenced by _PG_init().

◆ pgss_store()

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

Definition at line 1289 of file pg_stat_statements.c.

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

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

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

◆ qtext_fetch()

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

Definition at line 2436 of file pg_stat_statements.c.

2438{
2439 /* File read failed? */
2440 if (buffer == NULL)
2441 return NULL;
2442 /* Bogus offset/length? */
2443 if (query_len < 0 ||
2444 query_offset + query_len >= buffer_size)
2445 return NULL;
2446 /* As a further sanity check, make sure there's a trailing null */
2447 if (buffer[query_offset + query_len] != '\0')
2448 return NULL;
2449 /* Looks OK */
2450 return buffer + query_offset;
2451}

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

2344{
2345 char *buf;
2346 int fd;
2347 struct stat stat;
2348 Size nread;
2349
2351 if (fd < 0)
2352 {
2353 if (errno != ENOENT)
2354 ereport(LOG,
2356 errmsg("could not read file \"%s\": %m",
2357 PGSS_TEXT_FILE)));
2358 return NULL;
2359 }
2360
2361 /* Get file length */
2362 if (fstat(fd, &stat))
2363 {
2364 ereport(LOG,
2366 errmsg("could not stat file \"%s\": %m",
2367 PGSS_TEXT_FILE)));
2369 return NULL;
2370 }
2371
2372 /* Allocate buffer; beware that off_t might be wider than size_t */
2374 buf = (char *) malloc(stat.st_size);
2375 else
2376 buf = NULL;
2377 if (buf == NULL)
2378 {
2379 ereport(LOG,
2380 (errcode(ERRCODE_OUT_OF_MEMORY),
2381 errmsg("out of memory"),
2382 errdetail("Could not allocate enough memory to read file \"%s\".",
2383 PGSS_TEXT_FILE)));
2385 return NULL;
2386 }
2387
2388 /*
2389 * OK, slurp in the file. Windows fails if we try to read more than
2390 * INT_MAX bytes at once, and other platforms might not like that either,
2391 * so read a very large file in 1GB segments.
2392 */
2393 nread = 0;
2394 while (nread < stat.st_size)
2395 {
2396 int toread = Min(1024 * 1024 * 1024, stat.st_size - nread);
2397
2398 /*
2399 * If we get a short read and errno doesn't get set, the reason is
2400 * probably that garbage collection truncated the file since we did
2401 * the fstat(), so we don't log a complaint --- but we don't return
2402 * the data, either, since it's most likely corrupt due to concurrent
2403 * writes from garbage collection.
2404 */
2405 errno = 0;
2406 if (read(fd, buf + nread, toread) != toread)
2407 {
2408 if (errno)
2409 ereport(LOG,
2411 errmsg("could not read file \"%s\": %m",
2412 PGSS_TEXT_FILE)));
2413 free(buf);
2415 return NULL;
2416 }
2417 nread += toread;
2418 }
2419
2420 if (CloseTransientFile(fd) != 0)
2421 ereport(LOG,
2423 errmsg("could not close file \"%s\": %m", PGSS_TEXT_FILE)));
2424
2425 *buffer_size = nread;
2426 return buf;
2427}
#define PG_BINARY
Definition: c.h:1273
int errdetail(const char *fmt,...)
Definition: elog.c:1207
int CloseTransientFile(int fd)
Definition: fd.c:2868
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2691
#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:263
#define fstat
Definition: win32_port.h:273

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

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

◆ qtext_store()

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

Definition at line 2263 of file pg_stat_statements.c.

2265{
2266 Size off;
2267 int fd;
2268
2269 /*
2270 * We use a spinlock to protect extent/n_writers/gc_count, so that
2271 * multiple processes may execute this function concurrently.
2272 */
2274 off = pgss->extent;
2275 pgss->extent += query_len + 1;
2276 pgss->n_writers++;
2277 if (gc_count)
2278 *gc_count = pgss->gc_count;
2280
2281 *query_offset = off;
2282
2283 /*
2284 * Don't allow the file to grow larger than what qtext_load_file can
2285 * (theoretically) handle. This has been seen to be reachable on 32-bit
2286 * platforms.
2287 */
2288 if (unlikely(query_len >= MaxAllocHugeSize - off))
2289 {
2290 errno = EFBIG; /* not quite right, but it'll do */
2291 fd = -1;
2292 goto error;
2293 }
2294
2295 /* Now write the data into the successfully-reserved part of the file */
2296 fd = OpenTransientFile(PGSS_TEXT_FILE, O_RDWR | O_CREAT | PG_BINARY);
2297 if (fd < 0)
2298 goto error;
2299
2300 if (pg_pwrite(fd, query, query_len, off) != query_len)
2301 goto error;
2302 if (pg_pwrite(fd, "\0", 1, off + query_len) != 1)
2303 goto error;
2304
2306
2307 /* Mark our write complete */
2309 pgss->n_writers--;
2311
2312 return true;
2313
2314error:
2315 ereport(LOG,
2317 errmsg("could not write file \"%s\": %m",
2318 PGSS_TEXT_FILE)));
2319
2320 if (fd >= 0)
2322
2323 /* Mark our write complete */
2325 pgss->n_writers--;
2327
2328 return false;
2329}
#define unlikely(x)
Definition: c.h:403
#define pg_pwrite
Definition: port.h:227

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

Referenced by pgss_store().

Variable Documentation

◆ nesting_level

◆ pgss

◆ PGSS_FILE_HEADER

const uint32 PGSS_FILE_HEADER = 0x20250731
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 302 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 298 of file pg_stat_statements.c.

Referenced by _PG_init().

◆ pgss_track_planning

bool pgss_track_planning = false
static

Definition at line 300 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 299 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 273 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 272 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 271 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 270 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 269 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 268 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 274 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 266 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 267 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 289 of file pg_stat_statements.c.

Referenced by _PG_init().