PostgreSQL Source Code  git master
pg_stat_statements.c File Reference
#include "postgres.h"
#include <math.h>
#include <sys/stat.h>
#include <unistd.h>
#include "access/parallel.h"
#include "catalog/pg_authid.h"
#include "common/hashfn.h"
#include "executor/instrument.h"
#include "funcapi.h"
#include "jit/jit.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "nodes/queryjumble.h"
#include "optimizer/planner.h"
#include "parser/analyze.h"
#include "parser/parsetree.h"
#include "parser/scanner.h"
#include "parser/scansup.h"
#include "pgstat.h"
#include "storage/fd.h"
#include "storage/ipc.h"
#include "storage/lwlock.h"
#include "storage/shmem.h"
#include "storage/spin.h"
#include "tcop/utility.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
#include "utils/timestamp.h"
Include dependency graph for pg_stat_statements.c:

Go to the source code of this file.

Data Structures

struct  pgssHashKey
 
struct  Counters
 
struct  pgssGlobalStats
 
struct  pgssEntry
 
struct  pgssSharedState
 

Macros

#define PGSS_DUMP_FILE   PGSTAT_STAT_PERMANENT_DIRECTORY "/pg_stat_statements.stat"
 
#define PGSS_TEXT_FILE   PG_STAT_TMP_DIR "/pgss_query_texts.stat"
 
#define USAGE_EXEC(duration)   (1.0)
 
#define USAGE_INIT   (1.0) /* including initial planning */
 
#define ASSUMED_MEDIAN_INIT   (10.0) /* initial assumed median usage */
 
#define ASSUMED_LENGTH_INIT   1024 /* initial assumed mean query length */
 
#define USAGE_DECREASE_FACTOR   (0.99) /* decreased every entry_dealloc */
 
#define STICKY_DECREASE_FACTOR   (0.50) /* factor for sticky entries */
 
#define USAGE_DEALLOC_PERCENT   5 /* free this % of entries at once */
 
#define IS_STICKY(c)   ((c.calls[PGSS_PLAN] + c.calls[PGSS_EXEC]) == 0)
 
#define PGSS_HANDLED_UTILITY(n)
 
#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   45
 
#define PG_STAT_STATEMENTS_COLS   45 /* maximum of above */
 
#define PG_STAT_STATEMENTS_INFO_COLS   2
 

Typedefs

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

Enumerations

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

Functions

 PG_FUNCTION_INFO_V1 (pg_stat_statements_reset)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_reset_1_7)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_1_2)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_1_3)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_1_8)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_1_9)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_1_10)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_1_11)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_info)
 
static void pgss_shmem_request (void)
 
static void pgss_shmem_startup (void)
 
static void pgss_shmem_shutdown (int code, Datum arg)
 
static void pgss_post_parse_analyze (ParseState *pstate, Query *query, JumbleState *jstate)
 
static PlannedStmtpgss_planner (Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams)
 
static void pgss_ExecutorStart (QueryDesc *queryDesc, int eflags)
 
static void pgss_ExecutorRun (QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
 
static void pgss_ExecutorFinish (QueryDesc *queryDesc)
 
static void pgss_ExecutorEnd (QueryDesc *queryDesc)
 
static void pgss_ProcessUtility (PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc)
 
static void pgss_store (const char *query, uint64 queryId, int query_location, int query_len, pgssStoreKind kind, double total_time, uint64 rows, const BufferUsage *bufusage, const WalUsage *walusage, const struct JitInstrumentation *jitusage, JumbleState *jstate)
 
static void pg_stat_statements_internal (FunctionCallInfo fcinfo, pgssVersion api_version, bool showtext)
 
static Size pgss_memsize (void)
 
static pgssEntryentry_alloc (pgssHashKey *key, Size query_offset, int query_len, int encoding, bool sticky)
 
static void entry_dealloc (void)
 
static bool qtext_store (const char *query, int query_len, Size *query_offset, int *gc_count)
 
static char * qtext_load_file (Size *buffer_size)
 
static char * qtext_fetch (Size query_offset, int query_len, char *buffer, Size buffer_size)
 
static bool need_gc_qtexts (void)
 
static void gc_qtexts (void)
 
static void entry_reset (Oid userid, Oid dbid, uint64 queryid)
 
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 (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 exec_nested_level = 0
 
static int plan_nested_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 96 of file pg_stat_statements.c.

◆ ASSUMED_MEDIAN_INIT

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

Definition at line 95 of file pg_stat_statements.c.

◆ IS_STICKY

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

Definition at line 100 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS

#define PG_STAT_STATEMENTS_COLS   45 /* maximum of above */

Definition at line 1474 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_0

#define PG_STAT_STATEMENTS_COLS_V1_0   14

Definition at line 1466 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_1

#define PG_STAT_STATEMENTS_COLS_V1_1   18

Definition at line 1467 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_10

#define PG_STAT_STATEMENTS_COLS_V1_10   43

Definition at line 1472 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_11

#define PG_STAT_STATEMENTS_COLS_V1_11   45

Definition at line 1473 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_2

#define PG_STAT_STATEMENTS_COLS_V1_2   19

Definition at line 1468 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_3

#define PG_STAT_STATEMENTS_COLS_V1_3   23

Definition at line 1469 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_8

#define PG_STAT_STATEMENTS_COLS_V1_8   32

Definition at line 1470 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_COLS_V1_9

#define PG_STAT_STATEMENTS_COLS_V1_9   33

Definition at line 1471 of file pg_stat_statements.c.

◆ PG_STAT_STATEMENTS_INFO_COLS

#define PG_STAT_STATEMENTS_INFO_COLS   2

Definition at line 1887 of file pg_stat_statements.c.

◆ PGSS_DUMP_FILE

#define PGSS_DUMP_FILE   PGSTAT_STAT_PERMANENT_DIRECTORY "/pg_stat_statements.stat"

Definition at line 79 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:61
static int pgss_track
@ PGSS_TRACK_ALL
@ PGSS_TRACK_TOP

Definition at line 298 of file pg_stat_statements.c.

◆ PGSS_HANDLED_UTILITY

#define PGSS_HANDLED_UTILITY (   n)
Value:
(!IsA(n, ExecuteStmt) && \
#define IsA(nodeptr, _type_)
Definition: nodes.h:179

Definition at line 106 of file pg_stat_statements.c.

◆ PGSS_TEXT_FILE

#define PGSS_TEXT_FILE   PG_STAT_TMP_DIR "/pgss_query_texts.stat"

Definition at line 84 of file pg_stat_statements.c.

◆ record_gc_qtexts

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

Definition at line 303 of file pg_stat_statements.c.

◆ STICKY_DECREASE_FACTOR

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

Definition at line 98 of file pg_stat_statements.c.

◆ USAGE_DEALLOC_PERCENT

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

Definition at line 99 of file pg_stat_statements.c.

◆ USAGE_DECREASE_FACTOR

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

Definition at line 97 of file pg_stat_statements.c.

◆ USAGE_EXEC

#define USAGE_EXEC (   duration)    (1.0)

Definition at line 93 of file pg_stat_statements.c.

◆ USAGE_INIT

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

Definition at line 94 of file pg_stat_statements.c.

Typedef Documentation

◆ Counters

typedef struct Counters Counters

◆ pgssEntry

typedef struct pgssEntry pgssEntry

◆ pgssGlobalStats

◆ pgssHashKey

typedef struct pgssHashKey pgssHashKey

◆ pgssSharedState

◆ pgssStoreKind

◆ pgssVersion

typedef enum pgssVersion pgssVersion

Enumeration Type Documentation

◆ pgssStoreKind

Enumerator
PGSS_INVALID 
PGSS_PLAN 
PGSS_EXEC 
PGSS_NUMKIND 

Definition at line 124 of file pg_stat_statements.c.

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

◆ PGSSTrackLevel

Enumerator
PGSS_TRACK_NONE 
PGSS_TRACK_TOP 
PGSS_TRACK_ALL 

Definition at line 275 of file pg_stat_statements.c.

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

◆ pgssVersion

Enumerator
PGSS_V1_0 
PGSS_V1_1 
PGSS_V1_2 
PGSS_V1_3 
PGSS_V1_8 
PGSS_V1_9 
PGSS_V1_10 
PGSS_V1_11 

Definition at line 112 of file pg_stat_statements.c.

113 {
114  PGSS_V1_0 = 0,
115  PGSS_V1_1,
116  PGSS_V1_2,
117  PGSS_V1_3,
118  PGSS_V1_8,
119  PGSS_V1_9,
120  PGSS_V1_10,
121  PGSS_V1_11
122 } pgssVersion;
@ PGSS_V1_9
@ PGSS_V1_10
@ PGSS_V1_1
@ PGSS_V1_11
@ PGSS_V1_3
@ PGSS_V1_2
@ PGSS_V1_8
@ PGSS_V1_0

Function Documentation

◆ _PG_init()

void _PG_init ( void  )

Definition at line 378 of file pg_stat_statements.c.

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

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

2894 {
2895  int l = ((const LocationLen *) a)->location;
2896  int r = ((const LocationLen *) b)->location;
2897 
2898  if (l < r)
2899  return -1;
2900  else if (l > r)
2901  return +1;
2902  else
2903  return 0;
2904 }
int b
Definition: isn.c:70
int a
Definition: isn.c:69

References a, and b.

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

1958 {
1959  pgssEntry *entry;
1960  bool found;
1961 
1962  /* Make space if needed */
1964  entry_dealloc();
1965 
1966  /* Find or create an entry with desired hash code */
1967  entry = (pgssEntry *) hash_search(pgss_hash, key, HASH_ENTER, &found);
1968 
1969  if (!found)
1970  {
1971  /* New entry, initialize it */
1972 
1973  /* reset the statistics */
1974  memset(&entry->counters, 0, sizeof(Counters));
1975  /* set the appropriate initial usage count */
1976  entry->counters.usage = sticky ? pgss->cur_median_usage : USAGE_INIT;
1977  /* re-initialize the mutex each time ... we assume no one using it */
1978  SpinLockInit(&entry->mutex);
1979  /* ... and don't forget the query text metadata */
1980  Assert(query_len >= 0);
1981  entry->query_offset = query_offset;
1982  entry->query_len = query_len;
1983  entry->encoding = encoding;
1984  }
1985 
1986  return entry;
1987 }
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:953
long hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1377
@ HASH_ENTER
Definition: hsearch.h:114
Assert(fmt[strlen(fmt) - 1] !='\n')
int32 encoding
Definition: pg_database.h:41
static void entry_dealloc(void)
#define USAGE_INIT
static HTAB * pgss_hash
#define SpinLockInit(lock)
Definition: spin.h:60
Counters counters

References Assert(), pgssEntry::counters, pgssSharedState::cur_median_usage, pgssEntry::encoding, encoding, entry_dealloc(), HASH_ENTER, hash_get_num_entries(), hash_search(), sort-test::key, pgssEntry::mutex, pgss, pgss_hash, pgss_max, pgssEntry::query_len, pgssEntry::query_offset, SpinLockInit, 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 1993 of file pg_stat_statements.c.

1994 {
1995  double l_usage = (*(pgssEntry *const *) lhs)->counters.usage;
1996  double r_usage = (*(pgssEntry *const *) rhs)->counters.usage;
1997 
1998  if (l_usage < r_usage)
1999  return -1;
2000  else if (l_usage > r_usage)
2001  return +1;
2002  else
2003  return 0;
2004 }

Referenced by entry_dealloc().

◆ entry_dealloc()

static void entry_dealloc ( void  )
static

Definition at line 2012 of file pg_stat_statements.c.

2013 {
2014  HASH_SEQ_STATUS hash_seq;
2015  pgssEntry **entries;
2016  pgssEntry *entry;
2017  int nvictims;
2018  int i;
2019  Size tottextlen;
2020  int nvalidtexts;
2021 
2022  /*
2023  * Sort entries by usage and deallocate USAGE_DEALLOC_PERCENT of them.
2024  * While we're scanning the table, apply the decay factor to the usage
2025  * values, and update the mean query length.
2026  *
2027  * Note that the mean query length is almost immediately obsolete, since
2028  * we compute it before not after discarding the least-used entries.
2029  * Hopefully, that doesn't affect the mean too much; it doesn't seem worth
2030  * making two passes to get a more current result. Likewise, the new
2031  * cur_median_usage includes the entries we're about to zap.
2032  */
2033 
2034  entries = palloc(hash_get_num_entries(pgss_hash) * sizeof(pgssEntry *));
2035 
2036  i = 0;
2037  tottextlen = 0;
2038  nvalidtexts = 0;
2039 
2040  hash_seq_init(&hash_seq, pgss_hash);
2041  while ((entry = hash_seq_search(&hash_seq)) != NULL)
2042  {
2043  entries[i++] = entry;
2044  /* "Sticky" entries get a different usage decay rate. */
2045  if (IS_STICKY(entry->counters))
2047  else
2049  /* In the mean length computation, ignore dropped texts. */
2050  if (entry->query_len >= 0)
2051  {
2052  tottextlen += entry->query_len + 1;
2053  nvalidtexts++;
2054  }
2055  }
2056 
2057  /* Sort into increasing order by usage */
2058  qsort(entries, i, sizeof(pgssEntry *), entry_cmp);
2059 
2060  /* Record the (approximate) median usage */
2061  if (i > 0)
2062  pgss->cur_median_usage = entries[i / 2]->counters.usage;
2063  /* Record the mean query length */
2064  if (nvalidtexts > 0)
2065  pgss->mean_query_len = tottextlen / nvalidtexts;
2066  else
2068 
2069  /* Now zap an appropriate fraction of lowest-usage entries */
2070  nvictims = Max(10, i * USAGE_DEALLOC_PERCENT / 100);
2071  nvictims = Min(nvictims, i);
2072 
2073  for (i = 0; i < nvictims; i++)
2074  {
2075  hash_search(pgss_hash, &entries[i]->key, HASH_REMOVE, NULL);
2076  }
2077 
2078  pfree(entries);
2079 
2080  /* Increment the number of times entries are deallocated */
2081  {
2082  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
2083 
2084  SpinLockAcquire(&s->mutex);
2085  s->stats.dealloc += 1;
2086  SpinLockRelease(&s->mutex);
2087  }
2088 }
#define Min(x, y)
Definition: c.h:993
#define Max(x, y)
Definition: c.h:987
size_t Size
Definition: c.h:594
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1431
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1421
@ HASH_REMOVE
Definition: hsearch.h:115
int i
Definition: isn.c:73
void pfree(void *pointer)
Definition: mcxt.c:1456
void * palloc(Size size)
Definition: mcxt.c:1226
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:445
#define SpinLockRelease(lock)
Definition: spin.h:64
#define SpinLockAcquire(lock)
Definition: spin.h:62
pgssGlobalStats stats

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

Referenced by entry_alloc().

◆ entry_reset()

static void entry_reset ( Oid  userid,
Oid  dbid,
uint64  queryid 
)
static

Definition at line 2551 of file pg_stat_statements.c.

2552 {
2553  HASH_SEQ_STATUS hash_seq;
2554  pgssEntry *entry;
2555  FILE *qfile;
2556  long num_entries;
2557  long num_remove = 0;
2558  pgssHashKey key;
2559 
2560  if (!pgss || !pgss_hash)
2561  ereport(ERROR,
2562  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2563  errmsg("pg_stat_statements must be loaded via shared_preload_libraries")));
2564 
2566  num_entries = hash_get_num_entries(pgss_hash);
2567 
2568  if (userid != 0 && dbid != 0 && queryid != UINT64CONST(0))
2569  {
2570  /* If all the parameters are available, use the fast path. */
2571  memset(&key, 0, sizeof(pgssHashKey));
2572  key.userid = userid;
2573  key.dbid = dbid;
2574  key.queryid = queryid;
2575 
2576  /*
2577  * Remove the key if it exists, starting with the non-top-level entry.
2578  */
2579  key.toplevel = false;
2580  entry = (pgssEntry *) hash_search(pgss_hash, &key, HASH_REMOVE, NULL);
2581  if (entry) /* found */
2582  num_remove++;
2583 
2584  /* Also remove the top-level entry if it exists. */
2585  key.toplevel = true;
2586  entry = (pgssEntry *) hash_search(pgss_hash, &key, HASH_REMOVE, NULL);
2587  if (entry) /* found */
2588  num_remove++;
2589  }
2590  else if (userid != 0 || dbid != 0 || queryid != UINT64CONST(0))
2591  {
2592  /* Remove entries corresponding to valid parameters. */
2593  hash_seq_init(&hash_seq, pgss_hash);
2594  while ((entry = hash_seq_search(&hash_seq)) != NULL)
2595  {
2596  if ((!userid || entry->key.userid == userid) &&
2597  (!dbid || entry->key.dbid == dbid) &&
2598  (!queryid || entry->key.queryid == queryid))
2599  {
2600  hash_search(pgss_hash, &entry->key, HASH_REMOVE, NULL);
2601  num_remove++;
2602  }
2603  }
2604  }
2605  else
2606  {
2607  /* Remove all entries. */
2608  hash_seq_init(&hash_seq, pgss_hash);
2609  while ((entry = hash_seq_search(&hash_seq)) != NULL)
2610  {
2611  hash_search(pgss_hash, &entry->key, HASH_REMOVE, NULL);
2612  num_remove++;
2613  }
2614  }
2615 
2616  /* All entries are removed? */
2617  if (num_entries != num_remove)
2618  goto release_lock;
2619 
2620  /*
2621  * Reset global statistics for pg_stat_statements since all entries are
2622  * removed.
2623  */
2624  {
2625  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
2626  TimestampTz stats_reset = GetCurrentTimestamp();
2627 
2628  SpinLockAcquire(&s->mutex);
2629  s->stats.dealloc = 0;
2630  s->stats.stats_reset = stats_reset;
2631  SpinLockRelease(&s->mutex);
2632  }
2633 
2634  /*
2635  * Write new empty query file, perhaps even creating a new one to recover
2636  * if the file was missing.
2637  */
2639  if (qfile == NULL)
2640  {
2641  ereport(LOG,
2643  errmsg("could not create file \"%s\": %m",
2644  PGSS_TEXT_FILE)));
2645  goto done;
2646  }
2647 
2648  /* If ftruncate fails, log it, but it's not a fatal problem */
2649  if (ftruncate(fileno(qfile), 0) != 0)
2650  ereport(LOG,
2652  errmsg("could not truncate file \"%s\": %m",
2653  PGSS_TEXT_FILE)));
2654 
2655  FreeFile(qfile);
2656 
2657 done:
2658  pgss->extent = 0;
2659  /* This counts as a query text garbage collection for our purposes */
2660  record_gc_qtexts();
2661 
2662 release_lock:
2664 }
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1583
#define PG_BINARY_W
Definition: c.h:1286
int64 TimestampTz
Definition: timestamp.h:39
int errcode_for_file_access(void)
Definition: elog.c:881
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define LOG
Definition: elog.h:31
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2528
int FreeFile(FILE *file)
Definition: fd.c:2726
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1195
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
@ LW_EXCLUSIVE
Definition: lwlock.h:116
#define record_gc_qtexts()
#define PGSS_TEXT_FILE
pgssHashKey key
TimestampTz stats_reset
#define ftruncate(a, b)
Definition: win32_port.h:82

References AllocateFile(), pgssHashKey::dbid, pgssGlobalStats::dealloc, ereport, errcode(), errcode_for_file_access(), errmsg(), ERROR, pgssSharedState::extent, FreeFile(), ftruncate, GetCurrentTimestamp(), hash_get_num_entries(), HASH_REMOVE, 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, SpinLockAcquire, SpinLockRelease, pgssSharedState::stats, pgssGlobalStats::stats_reset, and pgssHashKey::userid.

Referenced by pg_stat_statements_reset(), 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 2793 of file pg_stat_statements.c.

2795 {
2796  LocationLen *locs;
2798  core_yy_extra_type yyextra;
2799  core_YYSTYPE yylval;
2800  YYLTYPE yylloc;
2801  int last_loc = -1;
2802  int i;
2803 
2804  /*
2805  * Sort the records by location so that we can process them in order while
2806  * scanning the query text.
2807  */
2808  if (jstate->clocations_count > 1)
2809  qsort(jstate->clocations, jstate->clocations_count,
2810  sizeof(LocationLen), comp_location);
2811  locs = jstate->clocations;
2812 
2813  /* initialize the flex scanner --- should match raw_parser() */
2814  yyscanner = scanner_init(query,
2815  &yyextra,
2816  &ScanKeywords,
2818 
2819  /* we don't want to re-emit any escape string warnings */
2820  yyextra.escape_string_warning = false;
2821 
2822  /* Search for each constant, in sequence */
2823  for (i = 0; i < jstate->clocations_count; i++)
2824  {
2825  int loc = locs[i].location;
2826  int tok;
2827 
2828  /* Adjust recorded location if we're dealing with partial string */
2829  loc -= query_loc;
2830 
2831  Assert(loc >= 0);
2832 
2833  if (loc <= last_loc)
2834  continue; /* Duplicate constant, ignore */
2835 
2836  /* Lex tokens until we find the desired constant */
2837  for (;;)
2838  {
2839  tok = core_yylex(&yylval, &yylloc, yyscanner);
2840 
2841  /* We should not hit end-of-string, but if we do, behave sanely */
2842  if (tok == 0)
2843  break; /* out of inner for-loop */
2844 
2845  /*
2846  * We should find the token position exactly, but if we somehow
2847  * run past it, work with that.
2848  */
2849  if (yylloc >= loc)
2850  {
2851  if (query[loc] == '-')
2852  {
2853  /*
2854  * It's a negative value - this is the one and only case
2855  * where we replace more than a single token.
2856  *
2857  * Do not compensate for the core system's special-case
2858  * adjustment of location to that of the leading '-'
2859  * operator in the event of a negative constant. It is
2860  * also useful for our purposes to start from the minus
2861  * symbol. In this way, queries like "select * from foo
2862  * where bar = 1" and "select * from foo where bar = -2"
2863  * will have identical normalized query strings.
2864  */
2865  tok = core_yylex(&yylval, &yylloc, yyscanner);
2866  if (tok == 0)
2867  break; /* out of inner for-loop */
2868  }
2869 
2870  /*
2871  * We now rely on the assumption that flex has placed a zero
2872  * byte after the text of the current token in scanbuf.
2873  */
2874  locs[i].length = strlen(yyextra.scanbuf + loc);
2875  break; /* out of inner for-loop */
2876  }
2877  }
2878 
2879  /* If we hit end-of-string, give up, leaving remaining lengths -1 */
2880  if (tok == 0)
2881  break;
2882 
2883  last_loc = loc;
2884  }
2885 
2887 }
PGDLLIMPORT const ScanKeywordList ScanKeywords
static int comp_location(const void *a, const void *b)
static core_yyscan_t yyscanner
Definition: pl_scanner.c:106
#define YYLTYPE
Definition: scanner.h:44
core_yyscan_t scanner_init(const char *str, core_yy_extra_type *yyext, const ScanKeywordList *keywordlist, const uint16 *keyword_tokens)
void scanner_finish(core_yyscan_t yyscanner)
PGDLLIMPORT const uint16 ScanKeywordTokens[]
void * core_yyscan_t
Definition: scanner.h:121
int core_yylex(core_YYSTYPE *yylval_param, YYLTYPE *yylloc_param, core_yyscan_t yyscanner)
LocationLen * clocations
Definition: queryjumble.h:41
int clocations_count
Definition: queryjumble.h:47
bool escape_string_warning
Definition: scanner.h:88
char * scanbuf
Definition: scanner.h:72

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

Referenced by generate_normalized_query().

◆ gc_qtexts()

static void gc_qtexts ( void  )
static

Definition at line 2368 of file pg_stat_statements.c.

2369 {
2370  char *qbuffer;
2371  Size qbuffer_size;
2372  FILE *qfile = NULL;
2373  HASH_SEQ_STATUS hash_seq;
2374  pgssEntry *entry;
2375  Size extent;
2376  int nentries;
2377 
2378  /*
2379  * When called from pgss_store, some other session might have proceeded
2380  * with garbage collection in the no-lock-held interim of lock strength
2381  * escalation. Check once more that this is actually necessary.
2382  */
2383  if (!need_gc_qtexts())
2384  return;
2385 
2386  /*
2387  * Load the old texts file. If we fail (out of memory, for instance),
2388  * invalidate query texts. Hopefully this is rare. It might seem better
2389  * to leave things alone on an OOM failure, but the problem is that the
2390  * file is only going to get bigger; hoping for a future non-OOM result is
2391  * risky and can easily lead to complete denial of service.
2392  */
2393  qbuffer = qtext_load_file(&qbuffer_size);
2394  if (qbuffer == NULL)
2395  goto gc_fail;
2396 
2397  /*
2398  * We overwrite the query texts file in place, so as to reduce the risk of
2399  * an out-of-disk-space failure. Since the file is guaranteed not to get
2400  * larger, this should always work on traditional filesystems; though we
2401  * could still lose on copy-on-write filesystems.
2402  */
2404  if (qfile == NULL)
2405  {
2406  ereport(LOG,
2408  errmsg("could not write file \"%s\": %m",
2409  PGSS_TEXT_FILE)));
2410  goto gc_fail;
2411  }
2412 
2413  extent = 0;
2414  nentries = 0;
2415 
2416  hash_seq_init(&hash_seq, pgss_hash);
2417  while ((entry = hash_seq_search(&hash_seq)) != NULL)
2418  {
2419  int query_len = entry->query_len;
2420  char *qry = qtext_fetch(entry->query_offset,
2421  query_len,
2422  qbuffer,
2423  qbuffer_size);
2424 
2425  if (qry == NULL)
2426  {
2427  /* Trouble ... drop the text */
2428  entry->query_offset = 0;
2429  entry->query_len = -1;
2430  /* entry will not be counted in mean query length computation */
2431  continue;
2432  }
2433 
2434  if (fwrite(qry, 1, query_len + 1, qfile) != query_len + 1)
2435  {
2436  ereport(LOG,
2438  errmsg("could not write file \"%s\": %m",
2439  PGSS_TEXT_FILE)));
2440  hash_seq_term(&hash_seq);
2441  goto gc_fail;
2442  }
2443 
2444  entry->query_offset = extent;
2445  extent += query_len + 1;
2446  nentries++;
2447  }
2448 
2449  /*
2450  * Truncate away any now-unused space. If this fails for some odd reason,
2451  * we log it, but there's no need to fail.
2452  */
2453  if (ftruncate(fileno(qfile), extent) != 0)
2454  ereport(LOG,
2456  errmsg("could not truncate file \"%s\": %m",
2457  PGSS_TEXT_FILE)));
2458 
2459  if (FreeFile(qfile))
2460  {
2461  ereport(LOG,
2463  errmsg("could not write file \"%s\": %m",
2464  PGSS_TEXT_FILE)));
2465  qfile = NULL;
2466  goto gc_fail;
2467  }
2468 
2469  elog(DEBUG1, "pgss gc of queries file shrunk size from %zu to %zu",
2470  pgss->extent, extent);
2471 
2472  /* Reset the shared extent pointer */
2473  pgss->extent = extent;
2474 
2475  /*
2476  * Also update the mean query length, to be sure that need_gc_qtexts()
2477  * won't still think we have a problem.
2478  */
2479  if (nentries > 0)
2480  pgss->mean_query_len = extent / nentries;
2481  else
2483 
2484  free(qbuffer);
2485 
2486  /*
2487  * OK, count a garbage collection cycle. (Note: even though we have
2488  * exclusive lock on pgss->lock, we must take pgss->mutex for this, since
2489  * other processes may examine gc_count while holding only the mutex.
2490  * Also, we have to advance the count *after* we've rewritten the file,
2491  * else other processes might not realize they read a stale file.)
2492  */
2493  record_gc_qtexts();
2494 
2495  return;
2496 
2497 gc_fail:
2498  /* clean up resources */
2499  if (qfile)
2500  FreeFile(qfile);
2501  free(qbuffer);
2502 
2503  /*
2504  * Since the contents of the external file are now uncertain, mark all
2505  * hashtable entries as having invalid texts.
2506  */
2507  hash_seq_init(&hash_seq, pgss_hash);
2508  while ((entry = hash_seq_search(&hash_seq)) != NULL)
2509  {
2510  entry->query_offset = 0;
2511  entry->query_len = -1;
2512  }
2513 
2514  /*
2515  * Destroy the query text file and create a new, empty one
2516  */
2517  (void) unlink(PGSS_TEXT_FILE);
2519  if (qfile == NULL)
2520  ereport(LOG,
2522  errmsg("could not recreate file \"%s\": %m",
2523  PGSS_TEXT_FILE)));
2524  else
2525  FreeFile(qfile);
2526 
2527  /* Reset the shared extent pointer */
2528  pgss->extent = 0;
2529 
2530  /* Reset mean_query_len to match the new state */
2532 
2533  /*
2534  * Bump the GC count even though we failed.
2535  *
2536  * This is needed to make concurrent readers of file without any lock on
2537  * pgss->lock notice existence of new version of file. Once readers
2538  * subsequently observe a change in GC count with pgss->lock held, that
2539  * forces a safe reopen of file. Writers also require that we bump here,
2540  * of course. (As required by locking protocol, readers and writers don't
2541  * trust earlier file contents until gc_count is found unchanged after
2542  * pgss->lock acquired in shared or exclusive mode respectively.)
2543  */
2544  record_gc_qtexts();
2545 }
void hash_seq_term(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1507
#define DEBUG1
Definition: elog.h:30
#define free(a)
Definition: header.h:65
static char * qtext_fetch(Size query_offset, int query_len, char *buffer, Size buffer_size)
static char * qtext_load_file(Size *buffer_size)
static bool need_gc_qtexts(void)

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

Referenced by pgss_store().

◆ generate_normalized_query()

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

Definition at line 2686 of file pg_stat_statements.c.

2688 {
2689  char *norm_query;
2690  int query_len = *query_len_p;
2691  int i,
2692  norm_query_buflen, /* Space allowed for norm_query */
2693  len_to_wrt, /* Length (in bytes) to write */
2694  quer_loc = 0, /* Source query byte location */
2695  n_quer_loc = 0, /* Normalized query byte location */
2696  last_off = 0, /* Offset from start for previous tok */
2697  last_tok_len = 0; /* Length (in bytes) of that tok */
2698 
2699  /*
2700  * Get constants' lengths (core system only gives us locations). Note
2701  * this also ensures the items are sorted by location.
2702  */
2703  fill_in_constant_lengths(jstate, query, query_loc);
2704 
2705  /*
2706  * Allow for $n symbols to be longer than the constants they replace.
2707  * Constants must take at least one byte in text form, while a $n symbol
2708  * certainly isn't more than 11 bytes, even if n reaches INT_MAX. We
2709  * could refine that limit based on the max value of n for the current
2710  * query, but it hardly seems worth any extra effort to do so.
2711  */
2712  norm_query_buflen = query_len + jstate->clocations_count * 10;
2713 
2714  /* Allocate result buffer */
2715  norm_query = palloc(norm_query_buflen + 1);
2716 
2717  for (i = 0; i < jstate->clocations_count; i++)
2718  {
2719  int off, /* Offset from start for cur tok */
2720  tok_len; /* Length (in bytes) of that tok */
2721 
2722  off = jstate->clocations[i].location;
2723  /* Adjust recorded location if we're dealing with partial string */
2724  off -= query_loc;
2725 
2726  tok_len = jstate->clocations[i].length;
2727 
2728  if (tok_len < 0)
2729  continue; /* ignore any duplicates */
2730 
2731  /* Copy next chunk (what precedes the next constant) */
2732  len_to_wrt = off - last_off;
2733  len_to_wrt -= last_tok_len;
2734 
2735  Assert(len_to_wrt >= 0);
2736  memcpy(norm_query + n_quer_loc, query + quer_loc, len_to_wrt);
2737  n_quer_loc += len_to_wrt;
2738 
2739  /* And insert a param symbol in place of the constant token */
2740  n_quer_loc += sprintf(norm_query + n_quer_loc, "$%d",
2741  i + 1 + jstate->highest_extern_param_id);
2742 
2743  quer_loc = off + tok_len;
2744  last_off = off;
2745  last_tok_len = tok_len;
2746  }
2747 
2748  /*
2749  * We've copied up until the last ignorable constant. Copy over the
2750  * remaining bytes of the original query string.
2751  */
2752  len_to_wrt = query_len - quer_loc;
2753 
2754  Assert(len_to_wrt >= 0);
2755  memcpy(norm_query + n_quer_loc, query + quer_loc, len_to_wrt);
2756  n_quer_loc += len_to_wrt;
2757 
2758  Assert(n_quer_loc <= norm_query_buflen);
2759  norm_query[n_quer_loc] = '\0';
2760 
2761  *query_len_p = n_quer_loc;
2762  return norm_query;
2763 }
static void fill_in_constant_lengths(JumbleState *jstate, const char *query, int query_loc)
#define sprintf
Definition: port.h:240
int highest_extern_param_id
Definition: queryjumble.h:50

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

Referenced by pgss_store().

◆ need_gc_qtexts()

static bool need_gc_qtexts ( void  )
static

Definition at line 2315 of file pg_stat_statements.c.

2316 {
2317  Size extent;
2318 
2319  /* Read shared extent pointer */
2320  {
2321  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
2322 
2323  SpinLockAcquire(&s->mutex);
2324  extent = s->extent;
2325  SpinLockRelease(&s->mutex);
2326  }
2327 
2328  /*
2329  * Don't proceed if file does not exceed 512 bytes per possible entry.
2330  *
2331  * Here and in the next test, 32-bit machines have overflow hazards if
2332  * pgss_max and/or mean_query_len are large. Force the multiplications
2333  * and comparisons to be done in uint64 arithmetic to forestall trouble.
2334  */
2335  if ((uint64) extent < (uint64) 512 * pgss_max)
2336  return false;
2337 
2338  /*
2339  * Don't proceed if file is less than about 50% bloat. Nothing can or
2340  * should be done in the event of unusually large query texts accounting
2341  * for file's large size. We go to the trouble of maintaining the mean
2342  * query length in order to prevent garbage collection from thrashing
2343  * uselessly.
2344  */
2345  if ((uint64) extent < (uint64) pgss->mean_query_len * pgss_max * 2)
2346  return false;
2347 
2348  return true;
2349 }

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

PG_FUNCTION_INFO_V1 ( pg_stat_statements  )

◆ PG_FUNCTION_INFO_V1() [2/10]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_10  )

◆ PG_FUNCTION_INFO_V1() [3/10]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_11  )

◆ PG_FUNCTION_INFO_V1() [4/10]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_2  )

◆ PG_FUNCTION_INFO_V1() [5/10]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_3  )

◆ PG_FUNCTION_INFO_V1() [6/10]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_8  )

◆ PG_FUNCTION_INFO_V1() [7/10]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_9  )

◆ PG_FUNCTION_INFO_V1() [8/10]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_info  )

◆ PG_FUNCTION_INFO_V1() [9/10]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_reset  )

◆ PG_FUNCTION_INFO_V1() [10/10]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_reset_1_7  )

◆ pg_stat_statements()

Datum pg_stat_statements ( PG_FUNCTION_ARGS  )

Definition at line 1551 of file pg_stat_statements.c.

1552 {
1553  /* If it's really API 1.1, we'll figure that out below */
1554  pg_stat_statements_internal(fcinfo, PGSS_V1_0, true);
1555 
1556  return (Datum) 0;
1557 }
static void pg_stat_statements_internal(FunctionCallInfo fcinfo, pgssVersion api_version, bool showtext)
uintptr_t Datum
Definition: postgres.h:64

References pg_stat_statements_internal(), and PGSS_V1_0.

◆ pg_stat_statements_1_10()

Datum pg_stat_statements_1_10 ( PG_FUNCTION_ARGS  )

Definition at line 1497 of file pg_stat_statements.c.

1498 {
1499  bool showtext = PG_GETARG_BOOL(0);
1500 
1501  pg_stat_statements_internal(fcinfo, PGSS_V1_10, showtext);
1502 
1503  return (Datum) 0;
1504 }
#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 1487 of file pg_stat_statements.c.

1488 {
1489  bool showtext = PG_GETARG_BOOL(0);
1490 
1491  pg_stat_statements_internal(fcinfo, PGSS_V1_11, showtext);
1492 
1493  return (Datum) 0;
1494 }

References PG_GETARG_BOOL, pg_stat_statements_internal(), and PGSS_V1_11.

◆ pg_stat_statements_1_2()

Datum pg_stat_statements_1_2 ( PG_FUNCTION_ARGS  )

Definition at line 1537 of file pg_stat_statements.c.

1538 {
1539  bool showtext = PG_GETARG_BOOL(0);
1540 
1541  pg_stat_statements_internal(fcinfo, PGSS_V1_2, showtext);
1542 
1543  return (Datum) 0;
1544 }

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

1528 {
1529  bool showtext = PG_GETARG_BOOL(0);
1530 
1531  pg_stat_statements_internal(fcinfo, PGSS_V1_3, showtext);
1532 
1533  return (Datum) 0;
1534 }

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

1518 {
1519  bool showtext = PG_GETARG_BOOL(0);
1520 
1521  pg_stat_statements_internal(fcinfo, PGSS_V1_8, showtext);
1522 
1523  return (Datum) 0;
1524 }

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

1508 {
1509  bool showtext = PG_GETARG_BOOL(0);
1510 
1511  pg_stat_statements_internal(fcinfo, PGSS_V1_9, showtext);
1512 
1513  return (Datum) 0;
1514 }

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

1894 {
1895  pgssGlobalStats stats;
1896  TupleDesc tupdesc;
1898  bool nulls[PG_STAT_STATEMENTS_INFO_COLS] = {0};
1899 
1900  if (!pgss || !pgss_hash)
1901  ereport(ERROR,
1902  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1903  errmsg("pg_stat_statements must be loaded via shared_preload_libraries")));
1904 
1905  /* Build a tuple descriptor for our result type */
1906  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
1907  elog(ERROR, "return type must be a row type");
1908 
1909  /* Read global statistics for pg_stat_statements */
1910  {
1911  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
1912 
1913  SpinLockAcquire(&s->mutex);
1914  stats = s->stats;
1915  SpinLockRelease(&s->mutex);
1916  }
1917 
1918  values[0] = Int64GetDatum(stats.dealloc);
1920 
1922 }
static Datum values[MAXATTR]
Definition: bootstrap.c:156
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1790
#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, Datum *values, bool *isnull)
Definition: heaptuple.c:1108
#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 1561 of file pg_stat_statements.c.

1564 {
1565  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1566  Oid userid = GetUserId();
1567  bool is_allowed_role = false;
1568  char *qbuffer = NULL;
1569  Size qbuffer_size = 0;
1570  Size extent = 0;
1571  int gc_count = 0;
1572  HASH_SEQ_STATUS hash_seq;
1573  pgssEntry *entry;
1574 
1575  /*
1576  * Superusers or roles with the privileges of pg_read_all_stats members
1577  * are allowed
1578  */
1579  is_allowed_role = has_privs_of_role(userid, ROLE_PG_READ_ALL_STATS);
1580 
1581  /* hash table must exist already */
1582  if (!pgss || !pgss_hash)
1583  ereport(ERROR,
1584  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1585  errmsg("pg_stat_statements must be loaded via shared_preload_libraries")));
1586 
1587  InitMaterializedSRF(fcinfo, 0);
1588 
1589  /*
1590  * Check we have the expected number of output arguments. Aside from
1591  * being a good safety check, we need a kluge here to detect API version
1592  * 1.1, which was wedged into the code in an ill-considered way.
1593  */
1594  switch (rsinfo->setDesc->natts)
1595  {
1597  if (api_version != PGSS_V1_0)
1598  elog(ERROR, "incorrect number of output arguments");
1599  break;
1601  /* pg_stat_statements() should have told us 1.0 */
1602  if (api_version != PGSS_V1_0)
1603  elog(ERROR, "incorrect number of output arguments");
1604  api_version = PGSS_V1_1;
1605  break;
1607  if (api_version != PGSS_V1_2)
1608  elog(ERROR, "incorrect number of output arguments");
1609  break;
1611  if (api_version != PGSS_V1_3)
1612  elog(ERROR, "incorrect number of output arguments");
1613  break;
1615  if (api_version != PGSS_V1_8)
1616  elog(ERROR, "incorrect number of output arguments");
1617  break;
1619  if (api_version != PGSS_V1_9)
1620  elog(ERROR, "incorrect number of output arguments");
1621  break;
1623  if (api_version != PGSS_V1_10)
1624  elog(ERROR, "incorrect number of output arguments");
1625  break;
1627  if (api_version != PGSS_V1_11)
1628  elog(ERROR, "incorrect number of output arguments");
1629  break;
1630  default:
1631  elog(ERROR, "incorrect number of output arguments");
1632  }
1633 
1634  /*
1635  * We'd like to load the query text file (if needed) while not holding any
1636  * lock on pgss->lock. In the worst case we'll have to do this again
1637  * after we have the lock, but it's unlikely enough to make this a win
1638  * despite occasional duplicated work. We need to reload if anybody
1639  * writes to the file (either a retail qtext_store(), or a garbage
1640  * collection) between this point and where we've gotten shared lock. If
1641  * a qtext_store is actually in progress when we look, we might as well
1642  * skip the speculative load entirely.
1643  */
1644  if (showtext)
1645  {
1646  int n_writers;
1647 
1648  /* Take the mutex so we can examine variables */
1649  {
1650  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
1651 
1652  SpinLockAcquire(&s->mutex);
1653  extent = s->extent;
1654  n_writers = s->n_writers;
1655  gc_count = s->gc_count;
1656  SpinLockRelease(&s->mutex);
1657  }
1658 
1659  /* No point in loading file now if there are active writers */
1660  if (n_writers == 0)
1661  qbuffer = qtext_load_file(&qbuffer_size);
1662  }
1663 
1664  /*
1665  * Get shared lock, load or reload the query text file if we must, and
1666  * iterate over the hashtable entries.
1667  *
1668  * With a large hash table, we might be holding the lock rather longer
1669  * than one could wish. However, this only blocks creation of new hash
1670  * table entries, and the larger the hash table the less likely that is to
1671  * be needed. So we can hope this is okay. Perhaps someday we'll decide
1672  * we need to partition the hash table to limit the time spent holding any
1673  * one lock.
1674  */
1676 
1677  if (showtext)
1678  {
1679  /*
1680  * Here it is safe to examine extent and gc_count without taking the
1681  * mutex. Note that although other processes might change
1682  * pgss->extent just after we look at it, the strings they then write
1683  * into the file cannot yet be referenced in the hashtable, so we
1684  * don't care whether we see them or not.
1685  *
1686  * If qtext_load_file fails, we just press on; we'll return NULL for
1687  * every query text.
1688  */
1689  if (qbuffer == NULL ||
1690  pgss->extent != extent ||
1691  pgss->gc_count != gc_count)
1692  {
1693  free(qbuffer);
1694  qbuffer = qtext_load_file(&qbuffer_size);
1695  }
1696  }
1697 
1698  hash_seq_init(&hash_seq, pgss_hash);
1699  while ((entry = hash_seq_search(&hash_seq)) != NULL)
1700  {
1702  bool nulls[PG_STAT_STATEMENTS_COLS];
1703  int i = 0;
1704  Counters tmp;
1705  double stddev;
1706  int64 queryid = entry->key.queryid;
1707 
1708  memset(values, 0, sizeof(values));
1709  memset(nulls, 0, sizeof(nulls));
1710 
1711  values[i++] = ObjectIdGetDatum(entry->key.userid);
1712  values[i++] = ObjectIdGetDatum(entry->key.dbid);
1713  if (api_version >= PGSS_V1_9)
1714  values[i++] = BoolGetDatum(entry->key.toplevel);
1715 
1716  if (is_allowed_role || entry->key.userid == userid)
1717  {
1718  if (api_version >= PGSS_V1_2)
1719  values[i++] = Int64GetDatumFast(queryid);
1720 
1721  if (showtext)
1722  {
1723  char *qstr = qtext_fetch(entry->query_offset,
1724  entry->query_len,
1725  qbuffer,
1726  qbuffer_size);
1727 
1728  if (qstr)
1729  {
1730  char *enc;
1731 
1732  enc = pg_any_to_server(qstr,
1733  entry->query_len,
1734  entry->encoding);
1735 
1737 
1738  if (enc != qstr)
1739  pfree(enc);
1740  }
1741  else
1742  {
1743  /* Just return a null if we fail to find the text */
1744  nulls[i++] = true;
1745  }
1746  }
1747  else
1748  {
1749  /* Query text not requested */
1750  nulls[i++] = true;
1751  }
1752  }
1753  else
1754  {
1755  /* Don't show queryid */
1756  if (api_version >= PGSS_V1_2)
1757  nulls[i++] = true;
1758 
1759  /*
1760  * Don't show query text, but hint as to the reason for not doing
1761  * so if it was requested
1762  */
1763  if (showtext)
1764  values[i++] = CStringGetTextDatum("<insufficient privilege>");
1765  else
1766  nulls[i++] = true;
1767  }
1768 
1769  /* copy counters to a local variable to keep locking time short */
1770  {
1771  volatile pgssEntry *e = (volatile pgssEntry *) entry;
1772 
1773  SpinLockAcquire(&e->mutex);
1774  tmp = e->counters;
1775  SpinLockRelease(&e->mutex);
1776  }
1777 
1778  /* Skip entry if unexecuted (ie, it's a pending "sticky" entry) */
1779  if (IS_STICKY(tmp))
1780  continue;
1781 
1782  /* Note that we rely on PGSS_PLAN being 0 and PGSS_EXEC being 1. */
1783  for (int kind = 0; kind < PGSS_NUMKIND; kind++)
1784  {
1785  if (kind == PGSS_EXEC || api_version >= PGSS_V1_8)
1786  {
1787  values[i++] = Int64GetDatumFast(tmp.calls[kind]);
1788  values[i++] = Float8GetDatumFast(tmp.total_time[kind]);
1789  }
1790 
1791  if ((kind == PGSS_EXEC && api_version >= PGSS_V1_3) ||
1792  api_version >= PGSS_V1_8)
1793  {
1794  values[i++] = Float8GetDatumFast(tmp.min_time[kind]);
1795  values[i++] = Float8GetDatumFast(tmp.max_time[kind]);
1796  values[i++] = Float8GetDatumFast(tmp.mean_time[kind]);
1797 
1798  /*
1799  * Note we are calculating the population variance here, not
1800  * the sample variance, as we have data for the whole
1801  * population, so Bessel's correction is not used, and we
1802  * don't divide by tmp.calls - 1.
1803  */
1804  if (tmp.calls[kind] > 1)
1805  stddev = sqrt(tmp.sum_var_time[kind] / tmp.calls[kind]);
1806  else
1807  stddev = 0.0;
1808  values[i++] = Float8GetDatumFast(stddev);
1809  }
1810  }
1811  values[i++] = Int64GetDatumFast(tmp.rows);
1814  if (api_version >= PGSS_V1_1)
1819  if (api_version >= PGSS_V1_1)
1824  if (api_version >= PGSS_V1_1)
1825  {
1828  }
1829  if (api_version >= PGSS_V1_10)
1830  {
1833  }
1834  if (api_version >= PGSS_V1_8)
1835  {
1836  char buf[256];
1837  Datum wal_bytes;
1838 
1840  values[i++] = Int64GetDatumFast(tmp.wal_fpi);
1841 
1842  snprintf(buf, sizeof buf, UINT64_FORMAT, tmp.wal_bytes);
1843 
1844  /* Convert to numeric. */
1845  wal_bytes = DirectFunctionCall3(numeric_in,
1847  ObjectIdGetDatum(0),
1848  Int32GetDatum(-1));
1849  values[i++] = wal_bytes;
1850  }
1851  if (api_version >= PGSS_V1_10)
1852  {
1861  }
1862  if (api_version >= PGSS_V1_11)
1863  {
1866  }
1867 
1868  Assert(i == (api_version == PGSS_V1_0 ? PG_STAT_STATEMENTS_COLS_V1_0 :
1869  api_version == PGSS_V1_1 ? PG_STAT_STATEMENTS_COLS_V1_1 :
1870  api_version == PGSS_V1_2 ? PG_STAT_STATEMENTS_COLS_V1_2 :
1871  api_version == PGSS_V1_3 ? PG_STAT_STATEMENTS_COLS_V1_3 :
1872  api_version == PGSS_V1_8 ? PG_STAT_STATEMENTS_COLS_V1_8 :
1873  api_version == PGSS_V1_9 ? PG_STAT_STATEMENTS_COLS_V1_9 :
1874  api_version == PGSS_V1_10 ? PG_STAT_STATEMENTS_COLS_V1_10 :
1875  api_version == PGSS_V1_11 ? PG_STAT_STATEMENTS_COLS_V1_11 :
1876  -1 /* fail if you forget to update this assert */ ));
1877 
1878  tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
1879  }
1880 
1882 
1883  free(qbuffer);
1884 }
bool has_privs_of_role(Oid member, Oid role)
Definition: acl.c:4961
Datum numeric_in(PG_FUNCTION_ARGS)
Definition: numeric.c:627
#define CStringGetTextDatum(s)
Definition: builtins.h:94
#define UINT64_FORMAT
Definition: c.h:538
enc
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition: fmgr.h:646
void InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags)
Definition: funcapi.c:76
@ LW_SHARED
Definition: lwlock.h:117
char * pg_any_to_server(const char *s, int len, int encoding)
Definition: mbutils.c:677
Oid GetUserId(void)
Definition: miscinit.c:509
#define PG_STAT_STATEMENTS_COLS_V1_0
#define PG_STAT_STATEMENTS_COLS_V1_8
#define PG_STAT_STATEMENTS_COLS
#define PG_STAT_STATEMENTS_COLS_V1_11
#define PG_STAT_STATEMENTS_COLS_V1_2
#define PG_STAT_STATEMENTS_COLS_V1_3
#define PG_STAT_STATEMENTS_COLS_V1_10
#define PG_STAT_STATEMENTS_COLS_V1_1
#define PG_STAT_STATEMENTS_COLS_V1_9
static char * buf
Definition: pg_test_fsync.c:67
#define snprintf
Definition: port.h:238
#define Int64GetDatumFast(X)
Definition: postgres.h:554
#define Float8GetDatumFast(X)
Definition: postgres.h:556
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:350
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
unsigned int Oid
Definition: postgres_ext.h:31
e
Definition: preproc-init.c:82
int64 temp_blks_written
int64 calls[PGSS_NUMKIND]
int64 shared_blks_written
double jit_generation_time
int64 temp_blks_read
double min_time[PGSS_NUMKIND]
int64 local_blks_written
double sum_var_time[PGSS_NUMKIND]
double temp_blk_read_time
int64 jit_emission_count
int64 jit_deform_count
double jit_emission_time
int64 shared_blks_hit
double jit_optimization_time
double blk_read_time
int64 jit_optimization_count
double total_time[PGSS_NUMKIND]
double max_time[PGSS_NUMKIND]
int64 shared_blks_dirtied
double mean_time[PGSS_NUMKIND]
double temp_blk_write_time
int64 local_blks_dirtied
int64 jit_inlining_count
int64 shared_blks_read
int64 local_blks_hit
double jit_deform_time
int64 local_blks_read
double jit_inlining_time
double blk_write_time
fmNodePtr resultinfo
Definition: fmgr.h:89
TupleDesc setDesc
Definition: execnodes.h:334
Tuplestorestate * setResult
Definition: execnodes.h:333
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, Datum *values, bool *isnull)
Definition: tuplestore.c:750

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

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

◆ pg_stat_statements_reset()

Datum pg_stat_statements_reset ( PG_FUNCTION_ARGS  )

Definition at line 1458 of file pg_stat_statements.c.

1459 {
1460  entry_reset(0, 0, 0);
1461 
1462  PG_RETURN_VOID();
1463 }
#define PG_RETURN_VOID()
Definition: fmgr.h:349
static void entry_reset(Oid userid, Oid dbid, uint64 queryid)

References entry_reset(), and PG_RETURN_VOID.

◆ pg_stat_statements_reset_1_7()

Datum pg_stat_statements_reset_1_7 ( PG_FUNCTION_ARGS  )

Definition at line 1439 of file pg_stat_statements.c.

1440 {
1441  Oid userid;
1442  Oid dbid;
1443  uint64 queryid;
1444 
1445  userid = PG_GETARG_OID(0);
1446  dbid = PG_GETARG_OID(1);
1447  queryid = (uint64) PG_GETARG_INT64(2);
1448 
1449  entry_reset(userid, dbid, queryid);
1450 
1451  PG_RETURN_VOID();
1452 }
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
#define PG_GETARG_INT64(n)
Definition: fmgr.h:283

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

1049 {
1050  uint64 queryId = queryDesc->plannedstmt->queryId;
1051 
1052  if (queryId != UINT64CONST(0) && queryDesc->totaltime &&
1054  {
1055  /*
1056  * Make sure stats accumulation is done. (Note: it's okay if several
1057  * levels of hook all do this.)
1058  */
1059  InstrEndLoop(queryDesc->totaltime);
1060 
1061  pgss_store(queryDesc->sourceText,
1062  queryId,
1063  queryDesc->plannedstmt->stmt_location,
1064  queryDesc->plannedstmt->stmt_len,
1065  PGSS_EXEC,
1066  queryDesc->totaltime->total * 1000.0, /* convert to msec */
1067  queryDesc->estate->es_total_processed,
1068  &queryDesc->totaltime->bufusage,
1069  &queryDesc->totaltime->walusage,
1070  queryDesc->estate->es_jit ? &queryDesc->estate->es_jit->instr : NULL,
1071  NULL);
1072  }
1073 
1074  if (prev_ExecutorEnd)
1075  prev_ExecutorEnd(queryDesc);
1076  else
1077  standard_ExecutorEnd(queryDesc);
1078 }
void standard_ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:478
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)
static int exec_nested_level
#define pgss_enabled(level)
struct JitContext * es_jit
Definition: execnodes.h:708
uint64 es_total_processed
Definition: execnodes.h:665
WalUsage walusage
Definition: instrument.h:90
BufferUsage bufusage
Definition: instrument.h:89
JitInstrumentation instr
Definition: jit.h:64
int stmt_location
Definition: plannodes.h:99
int stmt_len
Definition: plannodes.h:100
uint64 queryId
Definition: plannodes.h:55
const char * sourceText
Definition: execdesc.h:38
EState * estate
Definition: execdesc.h:48
PlannedStmt * plannedstmt
Definition: execdesc.h:37
struct Instrumentation * totaltime
Definition: execdesc.h:55

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

Referenced by _PG_init().

◆ pgss_ExecutorFinish()

static void pgss_ExecutorFinish ( QueryDesc queryDesc)
static

Definition at line 1027 of file pg_stat_statements.c.

1028 {
1030  PG_TRY();
1031  {
1032  if (prev_ExecutorFinish)
1033  prev_ExecutorFinish(queryDesc);
1034  else
1035  standard_ExecutorFinish(queryDesc);
1036  }
1037  PG_FINALLY();
1038  {
1040  }
1041  PG_END_TRY();
1042 }
#define PG_TRY(...)
Definition: elog.h:370
#define PG_END_TRY(...)
Definition: elog.h:395
#define PG_FINALLY(...)
Definition: elog.h:387
void standard_ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:418

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

Referenced by _PG_init().

◆ pgss_ExecutorRun()

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

Definition at line 1005 of file pg_stat_statements.c.

1007 {
1009  PG_TRY();
1010  {
1011  if (prev_ExecutorRun)
1012  prev_ExecutorRun(queryDesc, direction, count, execute_once);
1013  else
1014  standard_ExecutorRun(queryDesc, direction, count, execute_once);
1015  }
1016  PG_FINALLY();
1017  {
1019  }
1020  PG_END_TRY();
1021 }
void standard_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: execMain.c:313

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

Referenced by _PG_init().

◆ pgss_ExecutorStart()

static void pgss_ExecutorStart ( QueryDesc queryDesc,
int  eflags 
)
static

Definition at line 971 of file pg_stat_statements.c.

972 {
973  if (prev_ExecutorStart)
974  prev_ExecutorStart(queryDesc, eflags);
975  else
976  standard_ExecutorStart(queryDesc, eflags);
977 
978  /*
979  * If query has queryId zero, don't track it. This prevents double
980  * counting of optimizable statements that are directly contained in
981  * utility statements.
982  */
983  if (pgss_enabled(exec_nested_level) && queryDesc->plannedstmt->queryId != UINT64CONST(0))
984  {
985  /*
986  * Set up to track total elapsed time in ExecutorRun. Make sure the
987  * space is allocated in the per-query context so it will go away at
988  * ExecutorEnd.
989  */
990  if (queryDesc->totaltime == NULL)
991  {
992  MemoryContext oldcxt;
993 
994  oldcxt = MemoryContextSwitchTo(queryDesc->estate->es_query_cxt);
995  queryDesc->totaltime = InstrAlloc(1, INSTRUMENT_ALL, false);
996  MemoryContextSwitchTo(oldcxt);
997  }
998  }
999 }
void standard_ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:149
Instrumentation * InstrAlloc(int n, int instrument_options, bool async_mode)
Definition: instrument.c:31
@ INSTRUMENT_ALL
Definition: instrument.h:63
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:138
MemoryContext es_query_cxt
Definition: execnodes.h:659

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

Referenced by _PG_init().

◆ pgss_memsize()

static Size pgss_memsize ( void  )
static

Definition at line 1928 of file pg_stat_statements.c.

1929 {
1930  Size size;
1931 
1932  size = MAXALIGN(sizeof(pgssSharedState));
1933  size = add_size(size, hash_estimate_size(pgss_max, sizeof(pgssEntry)));
1934 
1935  return size;
1936 }
#define MAXALIGN(LEN)
Definition: c.h:800
Size hash_estimate_size(long num_entries, Size entrysize)
Definition: dynahash.c:781
Size add_size(Size s1, Size s2)
Definition: shmem.c:502

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

879 {
880  PlannedStmt *result;
881 
882  /*
883  * We can't process the query if no query_string is provided, as
884  * pgss_store needs it. We also ignore query without queryid, as it would
885  * be treated as a utility statement, which may not be the case.
886  *
887  * Note that planner_hook can be called from the planner itself, so we
888  * have a specific nesting level for the planner. However, utility
889  * commands containing optimizable statements can also call the planner,
890  * same for regular DML (for instance for underlying foreign key queries).
891  * So testing the planner nesting level only is not enough to detect real
892  * top level planner call.
893  */
895  && pgss_track_planning && query_string
896  && parse->queryId != UINT64CONST(0))
897  {
898  instr_time start;
900  BufferUsage bufusage_start,
901  bufusage;
902  WalUsage walusage_start,
903  walusage;
904 
905  /* We need to track buffer usage as the planner can access them. */
906  bufusage_start = pgBufferUsage;
907 
908  /*
909  * Similarly the planner could write some WAL records in some cases
910  * (e.g. setting a hint bit with those being WAL-logged)
911  */
912  walusage_start = pgWalUsage;
913  INSTR_TIME_SET_CURRENT(start);
914 
916  PG_TRY();
917  {
918  if (prev_planner_hook)
919  result = prev_planner_hook(parse, query_string, cursorOptions,
920  boundParams);
921  else
922  result = standard_planner(parse, query_string, cursorOptions,
923  boundParams);
924  }
925  PG_FINALLY();
926  {
928  }
929  PG_END_TRY();
930 
933 
934  /* calc differences of buffer counters. */
935  memset(&bufusage, 0, sizeof(BufferUsage));
936  BufferUsageAccumDiff(&bufusage, &pgBufferUsage, &bufusage_start);
937 
938  /* calc differences of WAL counters. */
939  memset(&walusage, 0, sizeof(WalUsage));
940  WalUsageAccumDiff(&walusage, &pgWalUsage, &walusage_start);
941 
942  pgss_store(query_string,
943  parse->queryId,
944  parse->stmt_location,
945  parse->stmt_len,
946  PGSS_PLAN,
948  0,
949  &bufusage,
950  &walusage,
951  NULL,
952  NULL);
953  }
954  else
955  {
956  if (prev_planner_hook)
957  result = prev_planner_hook(parse, query_string, cursorOptions,
958  boundParams);
959  else
960  result = standard_planner(parse, query_string, cursorOptions,
961  boundParams);
962  }
963 
964  return result;
965 }
#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:280
BufferUsage pgBufferUsage
Definition: instrument.c:20
void BufferUsageAccumDiff(BufferUsage *dst, const BufferUsage *add, const BufferUsage *sub)
Definition: instrument.c:246
static int plan_nested_level
int duration
Definition: pgbench.c:174
PlannedStmt * standard_planner(Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams)
Definition: planner.c:286
static struct subre * parse(struct vars *v, int stopper, int type, struct state *init, struct state *final)
Definition: regcomp.c:715

References BufferUsageAccumDiff(), duration, exec_nested_level, INSTR_TIME_GET_MILLISEC, INSTR_TIME_SET_CURRENT, INSTR_TIME_SUBTRACT, parse(), PG_END_TRY, PG_FINALLY, PG_TRY, pgBufferUsage, pgss_enabled, PGSS_PLAN, pgss_store(), pgss_track_planning, pgWalUsage, plan_nested_level, prev_planner_hook, standard_planner(), 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 827 of file pg_stat_statements.c.

828 {
830  prev_post_parse_analyze_hook(pstate, query, jstate);
831 
832  /* Safety check... */
834  return;
835 
836  /*
837  * Clear queryId for prepared statements related utility, as those will
838  * inherit from the underlying statement's one.
839  */
840  if (query->utilityStmt)
841  {
843  {
844  query->queryId = UINT64CONST(0);
845  return;
846  }
847  }
848 
849  /*
850  * If query jumbling were able to identify any ignorable constants, we
851  * immediately create a hash table entry for the query, so that we can
852  * record the normalized form of the query string. If there were no such
853  * constants, the normalized string would be the same as the query text
854  * anyway, so there's no need for an early entry.
855  */
856  if (jstate && jstate->clocations_count > 0)
857  pgss_store(pstate->p_sourcetext,
858  query->queryId,
859  query->stmt_location,
860  query->stmt_len,
861  PGSS_INVALID,
862  0,
863  0,
864  NULL,
865  NULL,
866  NULL,
867  jstate);
868 }
#define PGSS_HANDLED_UTILITY(n)
const char * p_sourcetext
Definition: parse_node.h:192
int stmt_location
Definition: parsenodes.h:235
Node * utilityStmt
Definition: parsenodes.h:142

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

Referenced by _PG_init().

◆ pgss_ProcessUtility()

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

Definition at line 1084 of file pg_stat_statements.c.

1089 {
1090  Node *parsetree = pstmt->utilityStmt;
1091  uint64 saved_queryId = pstmt->queryId;
1092  int saved_stmt_location = pstmt->stmt_location;
1093  int saved_stmt_len = pstmt->stmt_len;
1094 
1095  /*
1096  * Force utility statements to get queryId zero. We do this even in cases
1097  * where the statement contains an optimizable statement for which a
1098  * queryId could be derived (such as EXPLAIN or DECLARE CURSOR). For such
1099  * cases, runtime control will first go through ProcessUtility and then
1100  * the executor, and we don't want the executor hooks to do anything,
1101  * since we are already measuring the statement's costs at the utility
1102  * level.
1103  *
1104  * Note that this is only done if pg_stat_statements is enabled and
1105  * configured to track utility statements, in the unlikely possibility
1106  * that user configured another extension to handle utility statements
1107  * only.
1108  */
1110  pstmt->queryId = UINT64CONST(0);
1111 
1112  /*
1113  * If it's an EXECUTE statement, we don't track it and don't increment the
1114  * nesting level. This allows the cycles to be charged to the underlying
1115  * PREPARE instead (by the Executor hooks), which is much more useful.
1116  *
1117  * We also don't track execution of PREPARE. If we did, we would get one
1118  * hash table entry for the PREPARE (with hash calculated from the query
1119  * string), and then a different one with the same query string (but hash
1120  * calculated from the query tree) would be used to accumulate costs of
1121  * ensuing EXECUTEs. This would be confusing, and inconsistent with other
1122  * cases where planning time is not included at all.
1123  */
1125  PGSS_HANDLED_UTILITY(parsetree))
1126  {
1127  instr_time start;
1129  uint64 rows;
1130  BufferUsage bufusage_start,
1131  bufusage;
1132  WalUsage walusage_start,
1133  walusage;
1134 
1135  bufusage_start = pgBufferUsage;
1136  walusage_start = pgWalUsage;
1137  INSTR_TIME_SET_CURRENT(start);
1138 
1140  PG_TRY();
1141  {
1142  if (prev_ProcessUtility)
1143  prev_ProcessUtility(pstmt, queryString, readOnlyTree,
1144  context, params, queryEnv,
1145  dest, qc);
1146  else
1147  standard_ProcessUtility(pstmt, queryString, readOnlyTree,
1148  context, params, queryEnv,
1149  dest, qc);
1150  }
1151  PG_FINALLY();
1152  {
1154  }
1155  PG_END_TRY();
1156 
1157  /*
1158  * CAUTION: do not access the *pstmt data structure again below here.
1159  * If it was a ROLLBACK or similar, that data structure may have been
1160  * freed. We must copy everything we still need into local variables,
1161  * which we did above.
1162  *
1163  * For the same reason, we can't risk restoring pstmt->queryId to its
1164  * former value, which'd otherwise be a good idea.
1165  */
1166 
1168  INSTR_TIME_SUBTRACT(duration, start);
1169 
1170  /*
1171  * Track the total number of rows retrieved or affected by the utility
1172  * statements of COPY, FETCH, CREATE TABLE AS, CREATE MATERIALIZED
1173  * VIEW, REFRESH MATERIALIZED VIEW and SELECT INTO.
1174  */
1175  rows = (qc && (qc->commandTag == CMDTAG_COPY ||
1176  qc->commandTag == CMDTAG_FETCH ||
1177  qc->commandTag == CMDTAG_SELECT ||
1178  qc->commandTag == CMDTAG_REFRESH_MATERIALIZED_VIEW)) ?
1179  qc->nprocessed : 0;
1180 
1181  /* calc differences of buffer counters. */
1182  memset(&bufusage, 0, sizeof(BufferUsage));
1183  BufferUsageAccumDiff(&bufusage, &pgBufferUsage, &bufusage_start);
1184 
1185  /* calc differences of WAL counters. */
1186  memset(&walusage, 0, sizeof(WalUsage));
1187  WalUsageAccumDiff(&walusage, &pgWalUsage, &walusage_start);
1188 
1189  pgss_store(queryString,
1190  saved_queryId,
1191  saved_stmt_location,
1192  saved_stmt_len,
1193  PGSS_EXEC,
1195  rows,
1196  &bufusage,
1197  &walusage,
1198  NULL,
1199  NULL);
1200  }
1201  else
1202  {
1203  if (prev_ProcessUtility)
1204  prev_ProcessUtility(pstmt, queryString, readOnlyTree,
1205  context, params, queryEnv,
1206  dest, qc);
1207  else
1208  standard_ProcessUtility(pstmt, queryString, readOnlyTree,
1209  context, params, queryEnv,
1210  dest, qc);
1211  }
1212 }
Definition: nodes.h:129
Node * utilityStmt
Definition: plannodes.h:96
uint64 nprocessed
Definition: cmdtag.h:33
CommandTag commandTag
Definition: cmdtag.h:32
void standard_ProcessUtility(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc)
Definition: utility.c:547

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

Referenced by _PG_init().

◆ pgss_shmem_request()

static void pgss_shmem_request ( void  )
static

Definition at line 488 of file pg_stat_statements.c.

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

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

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

Referenced by pgss_shmem_startup().

◆ pgss_shmem_startup()

static void pgss_shmem_startup ( void  )
static

Definition at line 504 of file pg_stat_statements.c.

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

Referenced by _PG_init().

◆ pgss_store()

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

Definition at line 1226 of file pg_stat_statements.c.

1234 {
1235  pgssHashKey key;
1236  pgssEntry *entry;
1237  char *norm_query = NULL;
1238  int encoding = GetDatabaseEncoding();
1239 
1240  Assert(query != NULL);
1241 
1242  /* Safety check... */
1243  if (!pgss || !pgss_hash)
1244  return;
1245 
1246  /*
1247  * Nothing to do if compute_query_id isn't enabled and no other module
1248  * computed a query identifier.
1249  */
1250  if (queryId == UINT64CONST(0))
1251  return;
1252 
1253  /*
1254  * Confine our attention to the relevant part of the string, if the query
1255  * is a portion of a multi-statement source string, and update query
1256  * location and length if needed.
1257  */
1258  query = CleanQuerytext(query, &query_location, &query_len);
1259 
1260  /* Set up key for hashtable search */
1261 
1262  /* clear padding */
1263  memset(&key, 0, sizeof(pgssHashKey));
1264 
1265  key.userid = GetUserId();
1266  key.dbid = MyDatabaseId;
1267  key.queryid = queryId;
1268  key.toplevel = (exec_nested_level == 0);
1269 
1270  /* Lookup the hash table entry with shared lock. */
1272 
1273  entry = (pgssEntry *) hash_search(pgss_hash, &key, HASH_FIND, NULL);
1274 
1275  /* Create new entry, if not present */
1276  if (!entry)
1277  {
1278  Size query_offset;
1279  int gc_count;
1280  bool stored;
1281  bool do_gc;
1282 
1283  /*
1284  * Create a new, normalized query string if caller asked. We don't
1285  * need to hold the lock while doing this work. (Note: in any case,
1286  * it's possible that someone else creates a duplicate hashtable entry
1287  * in the interval where we don't hold the lock below. That case is
1288  * handled by entry_alloc.)
1289  */
1290  if (jstate)
1291  {
1293  norm_query = generate_normalized_query(jstate, query,
1294  query_location,
1295  &query_len);
1297  }
1298 
1299  /* Append new query text to file with only shared lock held */
1300  stored = qtext_store(norm_query ? norm_query : query, query_len,
1301  &query_offset, &gc_count);
1302 
1303  /*
1304  * Determine whether we need to garbage collect external query texts
1305  * while the shared lock is still held. This micro-optimization
1306  * avoids taking the time to decide this while holding exclusive lock.
1307  */
1308  do_gc = need_gc_qtexts();
1309 
1310  /* Need exclusive lock to make a new hashtable entry - promote */
1313 
1314  /*
1315  * A garbage collection may have occurred while we weren't holding the
1316  * lock. In the unlikely event that this happens, the query text we
1317  * stored above will have been garbage collected, so write it again.
1318  * This should be infrequent enough that doing it while holding
1319  * exclusive lock isn't a performance problem.
1320  */
1321  if (!stored || pgss->gc_count != gc_count)
1322  stored = qtext_store(norm_query ? norm_query : query, query_len,
1323  &query_offset, NULL);
1324 
1325  /* If we failed to write to the text file, give up */
1326  if (!stored)
1327  goto done;
1328 
1329  /* OK to create a new hashtable entry */
1330  entry = entry_alloc(&key, query_offset, query_len, encoding,
1331  jstate != NULL);
1332 
1333  /* If needed, perform garbage collection while exclusive lock held */
1334  if (do_gc)
1335  gc_qtexts();
1336  }
1337 
1338  /* Increment the counts, except when jstate is not NULL */
1339  if (!jstate)
1340  {
1341  /*
1342  * Grab the spinlock while updating the counters (see comment about
1343  * locking rules at the head of the file)
1344  */
1345  volatile pgssEntry *e = (volatile pgssEntry *) entry;
1346 
1347  Assert(kind == PGSS_PLAN || kind == PGSS_EXEC);
1348 
1349  SpinLockAcquire(&e->mutex);
1350 
1351  /* "Unstick" entry if it was previously sticky */
1352  if (IS_STICKY(e->counters))
1353  e->counters.usage = USAGE_INIT;
1354 
1355  e->counters.calls[kind] += 1;
1356  e->counters.total_time[kind] += total_time;
1357 
1358  if (e->counters.calls[kind] == 1)
1359  {
1360  e->counters.min_time[kind] = total_time;
1361  e->counters.max_time[kind] = total_time;
1362  e->counters.mean_time[kind] = total_time;
1363  }
1364  else
1365  {
1366  /*
1367  * Welford's method for accurately computing variance. See
1368  * <http://www.johndcook.com/blog/standard_deviation/>
1369  */
1370  double old_mean = e->counters.mean_time[kind];
1371 
1372  e->counters.mean_time[kind] +=
1373  (total_time - old_mean) / e->counters.calls[kind];
1374  e->counters.sum_var_time[kind] +=
1375  (total_time - old_mean) * (total_time - e->counters.mean_time[kind]);
1376 
1377  /* calculate min and max time */
1378  if (e->counters.min_time[kind] > total_time)
1379  e->counters.min_time[kind] = total_time;
1380  if (e->counters.max_time[kind] < total_time)
1381  e->counters.max_time[kind] = total_time;
1382  }
1383  e->counters.rows += rows;
1384  e->counters.shared_blks_hit += bufusage->shared_blks_hit;
1385  e->counters.shared_blks_read += bufusage->shared_blks_read;
1386  e->counters.shared_blks_dirtied += bufusage->shared_blks_dirtied;
1387  e->counters.shared_blks_written += bufusage->shared_blks_written;
1388  e->counters.local_blks_hit += bufusage->local_blks_hit;
1389  e->counters.local_blks_read += bufusage->local_blks_read;
1390  e->counters.local_blks_dirtied += bufusage->local_blks_dirtied;
1391  e->counters.local_blks_written += bufusage->local_blks_written;
1392  e->counters.temp_blks_read += bufusage->temp_blks_read;
1393  e->counters.temp_blks_written += bufusage->temp_blks_written;
1394  e->counters.blk_read_time += INSTR_TIME_GET_MILLISEC(bufusage->blk_read_time);
1395  e->counters.blk_write_time += INSTR_TIME_GET_MILLISEC(bufusage->blk_write_time);
1396  e->counters.temp_blk_read_time += INSTR_TIME_GET_MILLISEC(bufusage->temp_blk_read_time);
1397  e->counters.temp_blk_write_time += INSTR_TIME_GET_MILLISEC(bufusage->temp_blk_write_time);
1398  e->counters.usage += USAGE_EXEC(total_time);
1399  e->counters.wal_records += walusage->wal_records;
1400  e->counters.wal_fpi += walusage->wal_fpi;
1401  e->counters.wal_bytes += walusage->wal_bytes;
1402  if (jitusage)
1403  {
1404  e->counters.jit_functions += jitusage->created_functions;
1405  e->counters.jit_generation_time += INSTR_TIME_GET_MILLISEC(jitusage->generation_counter);
1406 
1407  if (INSTR_TIME_GET_MILLISEC(jitusage->deform_counter))
1408  e->counters.jit_deform_count++;
1409  e->counters.jit_deform_time += INSTR_TIME_GET_MILLISEC(jitusage->deform_counter);
1410 
1412  e->counters.jit_inlining_count++;
1413  e->counters.jit_inlining_time += INSTR_TIME_GET_MILLISEC(jitusage->inlining_counter);
1414 
1416  e->counters.jit_optimization_count++;
1417  e->counters.jit_optimization_time += INSTR_TIME_GET_MILLISEC(jitusage->optimization_counter);
1418 
1420  e->counters.jit_emission_count++;
1421  e->counters.jit_emission_time += INSTR_TIME_GET_MILLISEC(jitusage->emission_counter);
1422  }
1423 
1424  SpinLockRelease(&e->mutex);
1425  }
1426 
1427 done:
1429 
1430  /* We postpone this clean-up until we're out of the lock */
1431  if (norm_query)
1432  pfree(norm_query);
1433 }
Oid MyDatabaseId
Definition: globals.c:89
@ HASH_FIND
Definition: hsearch.h:113
int GetDatabaseEncoding(void)
Definition: mbutils.c:1268
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)
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:39
int64 local_blks_written
Definition: instrument.h:33
instr_time blk_write_time
Definition: instrument.h:37
instr_time temp_blk_read_time
Definition: instrument.h:38
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
instr_time blk_read_time
Definition: instrument.h:36
int64 local_blks_read
Definition: instrument.h:31
int64 local_blks_dirtied
Definition: instrument.h:32
int64 shared_blks_hit
Definition: instrument.h:26
instr_time generation_counter
Definition: jit.h:33
size_t created_functions
Definition: jit.h:30
instr_time optimization_counter
Definition: jit.h:42
instr_time deform_counter
Definition: jit.h:36
instr_time emission_counter
Definition: jit.h:45
instr_time inlining_counter
Definition: jit.h:39
uint64 wal_bytes
Definition: instrument.h:53
int64 wal_fpi
Definition: instrument.h:52
int64 wal_records
Definition: instrument.h:51

References Assert(), BufferUsage::blk_read_time, BufferUsage::blk_write_time, CleanQuerytext(), JitInstrumentation::created_functions, JitInstrumentation::deform_counter, JitInstrumentation::emission_counter, encoding, entry_alloc(), exec_nested_level, pgssSharedState::gc_count, gc_qtexts(), generate_normalized_query(), JitInstrumentation::generation_counter, GetDatabaseEncoding(), GetUserId(), HASH_FIND, hash_search(), JitInstrumentation::inlining_counter, INSTR_TIME_GET_MILLISEC, IS_STICKY, sort-test::key, BufferUsage::local_blks_dirtied, BufferUsage::local_blks_hit, BufferUsage::local_blks_read, BufferUsage::local_blks_written, pgssSharedState::lock, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), MyDatabaseId, need_gc_qtexts(), JitInstrumentation::optimization_counter, pfree(), pgss, PGSS_EXEC, pgss_hash, PGSS_PLAN, qtext_store(), BufferUsage::shared_blks_dirtied, BufferUsage::shared_blks_hit, BufferUsage::shared_blks_read, BufferUsage::shared_blks_written, SpinLockAcquire, SpinLockRelease, BufferUsage::temp_blk_read_time, BufferUsage::temp_blk_write_time, BufferUsage::temp_blks_read, BufferUsage::temp_blks_written, USAGE_EXEC, USAGE_INIT, WalUsage::wal_bytes, WalUsage::wal_fpi, and WalUsage::wal_records.

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

◆ qtext_fetch()

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

Definition at line 2292 of file pg_stat_statements.c.

2294 {
2295  /* File read failed? */
2296  if (buffer == NULL)
2297  return NULL;
2298  /* Bogus offset/length? */
2299  if (query_len < 0 ||
2300  query_offset + query_len >= buffer_size)
2301  return NULL;
2302  /* As a further sanity check, make sure there's a trailing null */
2303  if (buffer[query_offset + query_len] != '\0')
2304  return NULL;
2305  /* Looks OK */
2306  return buffer + query_offset;
2307 }

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

2200 {
2201  char *buf;
2202  int fd;
2203  struct stat stat;
2204  Size nread;
2205 
2207  if (fd < 0)
2208  {
2209  if (errno != ENOENT)
2210  ereport(LOG,
2212  errmsg("could not read file \"%s\": %m",
2213  PGSS_TEXT_FILE)));
2214  return NULL;
2215  }
2216 
2217  /* Get file length */
2218  if (fstat(fd, &stat))
2219  {
2220  ereport(LOG,
2222  errmsg("could not stat file \"%s\": %m",
2223  PGSS_TEXT_FILE)));
2225  return NULL;
2226  }
2227 
2228  /* Allocate buffer; beware that off_t might be wider than size_t */
2229  if (stat.st_size <= MaxAllocHugeSize)
2230  buf = (char *) malloc(stat.st_size);
2231  else
2232  buf = NULL;
2233  if (buf == NULL)
2234  {
2235  ereport(LOG,
2236  (errcode(ERRCODE_OUT_OF_MEMORY),
2237  errmsg("out of memory"),
2238  errdetail("Could not allocate enough memory to read file \"%s\".",
2239  PGSS_TEXT_FILE)));
2241  return NULL;
2242  }
2243 
2244  /*
2245  * OK, slurp in the file. Windows fails if we try to read more than
2246  * INT_MAX bytes at once, and other platforms might not like that either,
2247  * so read a very large file in 1GB segments.
2248  */
2249  nread = 0;
2250  while (nread < stat.st_size)
2251  {
2252  int toread = Min(1024 * 1024 * 1024, stat.st_size - nread);
2253 
2254  /*
2255  * If we get a short read and errno doesn't get set, the reason is
2256  * probably that garbage collection truncated the file since we did
2257  * the fstat(), so we don't log a complaint --- but we don't return
2258  * the data, either, since it's most likely corrupt due to concurrent
2259  * writes from garbage collection.
2260  */
2261  errno = 0;
2262  if (read(fd, buf + nread, toread) != toread)
2263  {
2264  if (errno)
2265  ereport(LOG,
2267  errmsg("could not read file \"%s\": %m",
2268  PGSS_TEXT_FILE)));
2269  free(buf);
2271  return NULL;
2272  }
2273  nread += toread;
2274  }
2275 
2276  if (CloseTransientFile(fd) != 0)
2277  ereport(LOG,
2279  errmsg("could not close file \"%s\": %m", PGSS_TEXT_FILE)));
2280 
2281  *buffer_size = nread;
2282  return buf;
2283 }
#define PG_BINARY
Definition: c.h:1283
int errdetail(const char *fmt,...)
Definition: elog.c:1202
int CloseTransientFile(int fd)
Definition: fd.c:2754
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2578
#define malloc(a)
Definition: header.h:50
#define read(a, b, c)
Definition: win32.h:13
#define MaxAllocHugeSize
Definition: memutils.h:45
static int fd(const char *x, int i)
Definition: preproc-init.c:105
__int64 st_size
Definition: win32_port.h:273
#define fstat
Definition: win32_port.h:283

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

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

◆ qtext_store()

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

Definition at line 2107 of file pg_stat_statements.c.

2109 {
2110  Size off;
2111  int fd;
2112 
2113  /*
2114  * We use a spinlock to protect extent/n_writers/gc_count, so that
2115  * multiple processes may execute this function concurrently.
2116  */
2117  {
2118  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
2119 
2120  SpinLockAcquire(&s->mutex);
2121  off = s->extent;
2122  s->extent += query_len + 1;
2123  s->n_writers++;
2124  if (gc_count)
2125  *gc_count = s->gc_count;
2126  SpinLockRelease(&s->mutex);
2127  }
2128 
2129  *query_offset = off;
2130 
2131  /*
2132  * Don't allow the file to grow larger than what qtext_load_file can
2133  * (theoretically) handle. This has been seen to be reachable on 32-bit
2134  * platforms.
2135  */
2136  if (unlikely(query_len >= MaxAllocHugeSize - off))
2137  {
2138  errno = EFBIG; /* not quite right, but it'll do */
2139  fd = -1;
2140  goto error;
2141  }
2142 
2143  /* Now write the data into the successfully-reserved part of the file */
2144  fd = OpenTransientFile(PGSS_TEXT_FILE, O_RDWR | O_CREAT | PG_BINARY);
2145  if (fd < 0)
2146  goto error;
2147 
2148  if (pg_pwrite(fd, query, query_len, off) != query_len)
2149  goto error;
2150  if (pg_pwrite(fd, "\0", 1, off + query_len) != 1)
2151  goto error;
2152 
2154 
2155  /* Mark our write complete */
2156  {
2157  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
2158 
2159  SpinLockAcquire(&s->mutex);
2160  s->n_writers--;
2161  SpinLockRelease(&s->mutex);
2162  }
2163 
2164  return true;
2165 
2166 error:
2167  ereport(LOG,
2169  errmsg("could not write file \"%s\": %m",
2170  PGSS_TEXT_FILE)));
2171 
2172  if (fd >= 0)
2174 
2175  /* Mark our write complete */
2176  {
2177  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
2178 
2179  SpinLockAcquire(&s->mutex);
2180  s->n_writers--;
2181  SpinLockRelease(&s->mutex);
2182  }
2183 
2184  return false;
2185 }
#define unlikely(x)
Definition: c.h:300
#define pg_pwrite
Definition: port.h:226

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

Referenced by pgss_store().

Variable Documentation

◆ exec_nested_level

◆ PG_MODULE_MAGIC

PG_MODULE_MAGIC

Definition at line 76 of file pg_stat_statements.c.

◆ pgss

◆ PGSS_FILE_HEADER

const uint32 PGSS_FILE_HEADER = 0x20220408
static

Definition at line 87 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 90 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 295 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 291 of file pg_stat_statements.c.

Referenced by _PG_init().

◆ pgss_track_planning

bool pgss_track_planning = false
static

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

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

◆ plan_nested_level

int plan_nested_level = 0
static

Definition at line 256 of file pg_stat_statements.c.

Referenced by pgss_planner().

◆ prev_ExecutorEnd

ExecutorEnd_hook_type prev_ExecutorEnd = NULL
static

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

Referenced by _PG_init().