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

Go to the source code of this file.

Data Structures

struct  pgssHashKey
 
struct  Counters
 
struct  pgssGlobalStats
 
struct  pgssEntry
 
struct  pgssSharedState
 

Macros

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

Typedefs

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

Enumerations

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

Functions

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

Variables

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

Macro Definition Documentation

◆ ASSUMED_LENGTH_INIT

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

Definition at line 94 of file pg_stat_statements.c.

◆ ASSUMED_MEDIAN_INIT

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

Definition at line 93 of file pg_stat_statements.c.

◆ IS_STICKY

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

Definition at line 98 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS

#define PG_STAT_STATEMENTS_COLS   52 /* maximum of above */

Definition at line 1571 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_0

#define PG_STAT_STATEMENTS_COLS_V1_0   14

Definition at line 1562 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_1

#define PG_STAT_STATEMENTS_COLS_V1_1   18

Definition at line 1563 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_10

#define PG_STAT_STATEMENTS_COLS_V1_10   43

Definition at line 1568 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_11

#define PG_STAT_STATEMENTS_COLS_V1_11   49

Definition at line 1569 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_12

#define PG_STAT_STATEMENTS_COLS_V1_12   52

Definition at line 1570 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_2

#define PG_STAT_STATEMENTS_COLS_V1_2   19

Definition at line 1564 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_3

#define PG_STAT_STATEMENTS_COLS_V1_3   23

Definition at line 1565 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_8

#define PG_STAT_STATEMENTS_COLS_V1_8   32

Definition at line 1566 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_9

#define PG_STAT_STATEMENTS_COLS_V1_9   33

Definition at line 1567 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_INFO_COLS

#define PG_STAT_STATEMENTS_INFO_COLS   2

Definition at line 2019 of file pg_stat_statements.c.

◆ PGSS_DUMP_FILE

#define PGSS_DUMP_FILE   PGSTAT_STAT_PERMANENT_DIRECTORY "/pg_stat_statements.stat"

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

◆ PGSS_NUMKIND

#define PGSS_NUMKIND   (PGSS_EXEC + 1)

Definition at line 129 of file pg_stat_statements.c.

◆ PGSS_TEXT_FILE

#define PGSS_TEXT_FILE   PG_STAT_TMP_DIR "/pgss_query_texts.stat"

Definition at line 82 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 305 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 2657 of file pg_stat_statements.c.

◆ STICKY_DECREASE_FACTOR

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

Definition at line 96 of file pg_stat_statements.c.

◆ USAGE_DEALLOC_PERCENT

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

Definition at line 97 of file pg_stat_statements.c.

◆ USAGE_DECREASE_FACTOR

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

Definition at line 95 of file pg_stat_statements.c.

◆ USAGE_EXEC

#define USAGE_EXEC (   duration)    (1.0)

Definition at line 91 of file pg_stat_statements.c.

◆ USAGE_INIT

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

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

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

◆ PGSSTrackLevel

Enumerator
PGSS_TRACK_NONE 
PGSS_TRACK_TOP 
PGSS_TRACK_ALL 

Definition at line 277 of file pg_stat_statements.c.

278{
279 PGSS_TRACK_NONE, /* track no statements */
280 PGSS_TRACK_TOP, /* only top level statements */
281 PGSS_TRACK_ALL, /* all statements, including nested ones */
PGSSTrackLevel
@ PGSS_TRACK_NONE

◆ pgssVersion

Enumerator
PGSS_V1_0 
PGSS_V1_1 
PGSS_V1_2 
PGSS_V1_3 
PGSS_V1_8 
PGSS_V1_9 
PGSS_V1_10 
PGSS_V1_11 
PGSS_V1_12 

Definition at line 103 of file pg_stat_statements.c.

104{
105 PGSS_V1_0 = 0,
106 PGSS_V1_1,
107 PGSS_V1_2,
108 PGSS_V1_3,
109 PGSS_V1_8,
110 PGSS_V1_9,
@ PGSS_V1_9
@ PGSS_V1_10
@ PGSS_V1_12
@ PGSS_V1_1
@ PGSS_V1_11
@ PGSS_V1_3
@ PGSS_V1_2
@ PGSS_V1_8
@ PGSS_V1_0

Function Documentation

◆ _PG_init()

void _PG_init ( void  )

Definition at line 383 of file pg_stat_statements.c.

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

3022{
3023 int l = ((const LocationLen *) a)->location;
3024 int r = ((const LocationLen *) b)->location;
3025
3026 return pg_cmp_s32(l, r);
3027}
static int pg_cmp_s32(int32 a, int32 b)
Definition: int.h:646
int b
Definition: isn.c:69
int a
Definition: isn.c:68

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

2086{
2087 pgssEntry *entry;
2088 bool found;
2089
2090 /* Make space if needed */
2092 entry_dealloc();
2093
2094 /* Find or create an entry with desired hash code */
2095 entry = (pgssEntry *) hash_search(pgss_hash, key, HASH_ENTER, &found);
2096
2097 if (!found)
2098 {
2099 /* New entry, initialize it */
2100
2101 /* reset the statistics */
2102 memset(&entry->counters, 0, sizeof(Counters));
2103 /* set the appropriate initial usage count */
2104 entry->counters.usage = sticky ? pgss->cur_median_usage : USAGE_INIT;
2105 /* re-initialize the mutex each time ... we assume no one using it */
2106 SpinLockInit(&entry->mutex);
2107 /* ... and don't forget the query text metadata */
2108 Assert(query_len >= 0);
2109 entry->query_offset = query_offset;
2110 entry->query_len = query_len;
2111 entry->encoding = encoding;
2113 entry->minmax_stats_since = entry->stats_since;
2114 }
2115
2116 return entry;
2117}
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1644
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:955
long hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1341
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 2123 of file pg_stat_statements.c.

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

Referenced by entry_dealloc().

◆ entry_dealloc()

static void entry_dealloc ( void  )
static

Definition at line 2142 of file pg_stat_statements.c.

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

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

Referenced by entry_alloc().

◆ entry_reset()

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

Definition at line 2680 of file pg_stat_statements.c.

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

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

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

◆ fill_in_constant_lengths()

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

Definition at line 2921 of file pg_stat_statements.c.

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

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

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

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

Referenced by pgss_store().

◆ generate_normalized_query()

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

Definition at line 2814 of file pg_stat_statements.c.

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

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

Referenced by pgss_store().

◆ need_gc_qtexts()

static bool need_gc_qtexts ( void  )
static

Definition at line 2429 of file pg_stat_statements.c.

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

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

Referenced by gc_qtexts(), and pgss_store().

◆ PG_FUNCTION_INFO_V1() [1/12]

PG_FUNCTION_INFO_V1 ( pg_stat_statements  )

◆ PG_FUNCTION_INFO_V1() [2/12]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_10  )

◆ PG_FUNCTION_INFO_V1() [3/12]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_11  )

◆ PG_FUNCTION_INFO_V1() [4/12]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_12  )

◆ PG_FUNCTION_INFO_V1() [5/12]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_2  )

◆ PG_FUNCTION_INFO_V1() [6/12]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_3  )

◆ PG_FUNCTION_INFO_V1() [7/12]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_8  )

◆ PG_FUNCTION_INFO_V1() [8/12]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_9  )

◆ PG_FUNCTION_INFO_V1() [9/12]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_info  )

◆ PG_FUNCTION_INFO_V1() [10/12]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_reset  )

◆ PG_FUNCTION_INFO_V1() [11/12]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_reset_1_11  )

◆ PG_FUNCTION_INFO_V1() [12/12]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_reset_1_7  )

◆ pg_stat_statements()

Datum pg_stat_statements ( PG_FUNCTION_ARGS  )

Definition at line 1658 of file pg_stat_statements.c.

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

References pg_stat_statements_internal(), and PGSS_V1_0.

◆ pg_stat_statements_1_10()

Datum pg_stat_statements_1_10 ( PG_FUNCTION_ARGS  )

Definition at line 1604 of file pg_stat_statements.c.

1605{
1606 bool showtext = PG_GETARG_BOOL(0);
1607
1608 pg_stat_statements_internal(fcinfo, PGSS_V1_10, showtext);
1609
1610 return (Datum) 0;
1611}
#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 1594 of file pg_stat_statements.c.

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

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

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

References PG_GETARG_BOOL, pg_stat_statements_internal(), and PGSS_V1_12.

◆ pg_stat_statements_1_2()

Datum pg_stat_statements_1_2 ( PG_FUNCTION_ARGS  )

Definition at line 1644 of file pg_stat_statements.c.

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

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

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

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

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

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

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

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

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

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

◆ pg_stat_statements_internal()

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

Definition at line 1668 of file pg_stat_statements.c.

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

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

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

◆ pg_stat_statements_reset()

Datum pg_stat_statements_reset ( PG_FUNCTION_ARGS  )

Definition at line 1554 of file pg_stat_statements.c.

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

References entry_reset(), and PG_RETURN_VOID.

◆ pg_stat_statements_reset_1_11()

Datum pg_stat_statements_reset_1_11 ( PG_FUNCTION_ARGS  )

Definition at line 1535 of file pg_stat_statements.c.

1536{
1537 Oid userid;
1538 Oid dbid;
1539 uint64 queryid;
1540 bool minmax_only;
1541
1542 userid = PG_GETARG_OID(0);
1543 dbid = PG_GETARG_OID(1);
1544 queryid = (uint64) PG_GETARG_INT64(2);
1545 minmax_only = PG_GETARG_BOOL(3);
1546
1547 PG_RETURN_TIMESTAMPTZ(entry_reset(userid, dbid, queryid, minmax_only));
1548}
#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 1519 of file pg_stat_statements.c.

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

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 uint64 queryId = queryDesc->plannedstmt->queryId;
1078
1079 if (queryId != UINT64CONST(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 }
1102
1103 if (prev_ExecutorEnd)
1104 prev_ExecutorEnd(queryDesc);
1105 else
1106 standard_ExecutorEnd(queryDesc);
1107}
void standard_ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:544
void InstrEndLoop(Instrumentation *instr)
Definition: instrument.c:140
static void pgss_store(const char *query, uint64 queryId, int query_location, int query_len, pgssStoreKind kind, double total_time, uint64 rows, const BufferUsage *bufusage, const WalUsage *walusage, const struct JitInstrumentation *jitusage, JumbleState *jstate, int parallel_workers_to_launch, int parallel_workers_launched)
#define pgss_enabled(level)
static int nesting_level
int es_parallel_workers_to_launch
Definition: execnodes.h:739
struct JitContext * es_jit
Definition: execnodes.h:757
uint64 es_total_processed
Definition: execnodes.h:708
int es_parallel_workers_launched
Definition: execnodes.h:741
WalUsage walusage
Definition: instrument.h:93
BufferUsage bufusage
Definition: instrument.h:92
JitInstrumentation instr
Definition: jit.h:62
ParseLoc stmt_len
Definition: plannodes.h:135
ParseLoc stmt_location
Definition: plannodes.h:133
uint64 queryId
Definition: plannodes.h:56
const char * sourceText
Definition: execdesc.h:39
EState * estate
Definition: execdesc.h:49
PlannedStmt * plannedstmt
Definition: execdesc.h:37
struct Instrumentation * totaltime
Definition: execdesc.h:56

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

Referenced by _PG_init().

◆ pgss_ExecutorFinish()

static void pgss_ExecutorFinish ( QueryDesc queryDesc)
static

Definition at line 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:371
#define PG_END_TRY(...)
Definition: elog.h:396
#define PG_FINALLY(...)
Definition: elog.h:388
void standard_ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:481

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:372

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

Referenced by _PG_init().

◆ pgss_ExecutorStart()

static bool pgss_ExecutorStart ( QueryDesc queryDesc,
int  eflags 
)
static

Definition at line 991 of file pg_stat_statements.c.

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

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

Referenced by _PG_init().

◆ pgss_memsize()

static Size pgss_memsize ( void  )
static

Definition at line 2056 of file pg_stat_statements.c.

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

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

890{
891 PlannedStmt *result;
892
893 /*
894 * We can't process the query if no query_string is provided, as
895 * pgss_store needs it. We also ignore query without queryid, as it would
896 * be treated as a utility statement, which may not be the case.
897 */
899 && pgss_track_planning && query_string
900 && parse->queryId != UINT64CONST(0))
901 {
904 BufferUsage bufusage_start,
905 bufusage;
906 WalUsage walusage_start,
907 walusage;
908
909 /* We need to track buffer usage as the planner can access them. */
910 bufusage_start = pgBufferUsage;
911
912 /*
913 * Similarly the planner could write some WAL records in some cases
914 * (e.g. setting a hint bit with those being WAL-logged)
915 */
916 walusage_start = pgWalUsage;
918
920 PG_TRY();
921 {
923 result = prev_planner_hook(parse, query_string, cursorOptions,
924 boundParams);
925 else
926 result = standard_planner(parse, query_string, cursorOptions,
927 boundParams);
928 }
929 PG_FINALLY();
930 {
932 }
933 PG_END_TRY();
934
937
938 /* calc differences of buffer counters. */
939 memset(&bufusage, 0, sizeof(BufferUsage));
940 BufferUsageAccumDiff(&bufusage, &pgBufferUsage, &bufusage_start);
941
942 /* calc differences of WAL counters. */
943 memset(&walusage, 0, sizeof(WalUsage));
944 WalUsageAccumDiff(&walusage, &pgWalUsage, &walusage_start);
945
946 pgss_store(query_string,
947 parse->queryId,
948 parse->stmt_location,
949 parse->stmt_len,
950 PGSS_PLAN,
952 0,
953 &bufusage,
954 &walusage,
955 NULL,
956 NULL,
957 0,
958 0);
959 }
960 else
961 {
962 /*
963 * Even though we're not tracking plan time for this statement, we
964 * must still increment the nesting level, to ensure that functions
965 * evaluated during planning are not seen as top-level calls.
966 */
968 PG_TRY();
969 {
971 result = prev_planner_hook(parse, query_string, cursorOptions,
972 boundParams);
973 else
974 result = standard_planner(parse, query_string, cursorOptions,
975 boundParams);
976 }
977 PG_FINALLY();
978 {
980 }
981 PG_END_TRY();
982 }
983
984 return result;
985}
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:298
static struct subre * parse(struct vars *v, int stopper, int type, struct state *init, struct state *final)
Definition: regcomp.c:717

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

Referenced by _PG_init().

◆ pgss_post_parse_analyze()

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

Definition at line 834 of file pg_stat_statements.c.

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

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

Referenced by _PG_init().

◆ pgss_ProcessUtility()

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

Definition at line 1113 of file pg_stat_statements.c.

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

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

Referenced by _PG_init().

◆ pgss_shmem_request()

static void pgss_shmem_request ( void  )
static

Definition at line 493 of file pg_stat_statements.c.

494{
497
499 RequestNamedLWLockTranche("pg_stat_statements", 1);
500}
void RequestAddinShmemSpace(Size size)
Definition: ipci.c:73
void RequestNamedLWLockTranche(const char *tranche_name, int num_lwlocks)
Definition: lwlock.c:681
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 735 of file pg_stat_statements.c.

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

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

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

Referenced by _PG_init().

◆ pgss_store()

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

Definition at line 1287 of file pg_stat_statements.c.

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

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

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

◆ qtext_fetch()

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

Definition at line 2406 of file pg_stat_statements.c.

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

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

2314{
2315 char *buf;
2316 int fd;
2317 struct stat stat;
2318 Size nread;
2319
2321 if (fd < 0)
2322 {
2323 if (errno != ENOENT)
2324 ereport(LOG,
2326 errmsg("could not read file \"%s\": %m",
2327 PGSS_TEXT_FILE)));
2328 return NULL;
2329 }
2330
2331 /* Get file length */
2332 if (fstat(fd, &stat))
2333 {
2334 ereport(LOG,
2336 errmsg("could not stat file \"%s\": %m",
2337 PGSS_TEXT_FILE)));
2339 return NULL;
2340 }
2341
2342 /* Allocate buffer; beware that off_t might be wider than size_t */
2344 buf = (char *) malloc(stat.st_size);
2345 else
2346 buf = NULL;
2347 if (buf == NULL)
2348 {
2349 ereport(LOG,
2350 (errcode(ERRCODE_OUT_OF_MEMORY),
2351 errmsg("out of memory"),
2352 errdetail("Could not allocate enough memory to read file \"%s\".",
2353 PGSS_TEXT_FILE)));
2355 return NULL;
2356 }
2357
2358 /*
2359 * OK, slurp in the file. Windows fails if we try to read more than
2360 * INT_MAX bytes at once, and other platforms might not like that either,
2361 * so read a very large file in 1GB segments.
2362 */
2363 nread = 0;
2364 while (nread < stat.st_size)
2365 {
2366 int toread = Min(1024 * 1024 * 1024, stat.st_size - nread);
2367
2368 /*
2369 * If we get a short read and errno doesn't get set, the reason is
2370 * probably that garbage collection truncated the file since we did
2371 * the fstat(), so we don't log a complaint --- but we don't return
2372 * the data, either, since it's most likely corrupt due to concurrent
2373 * writes from garbage collection.
2374 */
2375 errno = 0;
2376 if (read(fd, buf + nread, toread) != toread)
2377 {
2378 if (errno)
2379 ereport(LOG,
2381 errmsg("could not read file \"%s\": %m",
2382 PGSS_TEXT_FILE)));
2383 free(buf);
2385 return NULL;
2386 }
2387 nread += toread;
2388 }
2389
2390 if (CloseTransientFile(fd) != 0)
2391 ereport(LOG,
2393 errmsg("could not close file \"%s\": %m", PGSS_TEXT_FILE)));
2394
2395 *buffer_size = nread;
2396 return buf;
2397}
#define PG_BINARY
Definition: c.h:1244
int errdetail(const char *fmt,...)
Definition: elog.c:1203
int CloseTransientFile(int fd)
Definition: fd.c:2831
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2655
#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 2233 of file pg_stat_statements.c.

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

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

Referenced by pgss_store().

Variable Documentation

◆ nesting_level

◆ PG_MODULE_MAGIC

PG_MODULE_MAGIC

Definition at line 74 of file pg_stat_statements.c.

◆ pgss

◆ PGSS_FILE_HEADER

const uint32 PGSS_FILE_HEADER = 0x20220408
static

Definition at line 85 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 88 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 297 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 293 of file pg_stat_statements.c.

Referenced by _PG_init().

◆ pgss_track_planning

bool pgss_track_planning = false
static

Definition at line 295 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 294 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 268 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 267 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 266 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 265 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 264 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 263 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 269 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 261 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 262 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 284 of file pg_stat_statements.c.

Referenced by _PG_init().