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/hash.h"
#include "catalog/pg_authid.h"
#include "executor/instrument.h"
#include "funcapi.h"
#include "mb/pg_wchar.h"
#include "miscadmin.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/spin.h"
#include "tcop/utility.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
Include dependency graph for pg_stat_statements.c:

Go to the source code of this file.

Data Structures

struct  pgssHashKey
 
struct  Counters
 
struct  pgssEntry
 
struct  pgssSharedState
 
struct  pgssLocationLen
 
struct  pgssJumbleState
 

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 JUMBLE_SIZE   1024 /* query serialization buffer size */
 
#define pgss_enabled()
 
#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   23 /* maximum of above */
 
#define APP_JUMB(item)   AppendJumble(jstate, (const unsigned char *) &(item), sizeof(item))
 
#define APP_JUMB_STRING(str)   AppendJumble(jstate, (const unsigned char *) (str), strlen(str) + 1)
 

Typedefs

typedef enum pgssVersion pgssVersion
 
typedef struct pgssHashKey pgssHashKey
 
typedef struct Counters Counters
 
typedef struct pgssEntry pgssEntry
 
typedef struct pgssSharedState pgssSharedState
 
typedef struct pgssLocationLen pgssLocationLen
 
typedef struct pgssJumbleState pgssJumbleState
 

Enumerations

enum  pgssVersion { PGSS_V1_0 = 0, PGSS_V1_1, PGSS_V1_2, PGSS_V1_3 }
 
enum  PGSSTrackLevel { PGSS_TRACK_NONE, PGSS_TRACK_TOP, PGSS_TRACK_ALL }
 

Functions

void _PG_init (void)
 
void _PG_fini (void)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_reset)
 
 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)
 
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)
 
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, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, char *completionTag)
 
static uint64 pgss_hash_string (const char *str, int len)
 
static void pgss_store (const char *query, uint64 queryId, int query_location, int query_len, double total_time, uint64 rows, const BufferUsage *bufusage, pgssJumbleState *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 (void)
 
static void AppendJumble (pgssJumbleState *jstate, const unsigned char *item, Size size)
 
static void JumbleQuery (pgssJumbleState *jstate, Query *query)
 
static void JumbleRangeTable (pgssJumbleState *jstate, List *rtable)
 
static void JumbleExpr (pgssJumbleState *jstate, Node *node)
 
static void RecordConstLocation (pgssJumbleState *jstate, int location)
 
static char * generate_normalized_query (pgssJumbleState *jstate, const char *query, int query_loc, int *query_len_p, int encoding)
 
static void fill_in_constant_lengths (pgssJumbleState *jstate, const char *query, int query_loc)
 
static int comp_location (const void *a, const void *b)
 
Datum pg_stat_statements_reset (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)
 
static int entry_cmp (const void *lhs, const void *rhs)
 

Variables

 PG_MODULE_MAGIC
 
static const uint32 PGSS_FILE_HEADER = 0x20171004
 
static const uint32 PGSS_PG_MAJOR_VERSION = PG_VERSION_NUM / 100
 
static int nested_level = 0
 
static shmem_startup_hook_type prev_shmem_startup_hook = NULL
 
static post_parse_analyze_hook_type prev_post_parse_analyze_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
 
static int pgss_track
 
static bool pgss_track_utility
 
static bool pgss_save
 

Macro Definition Documentation

◆ APP_JUMB

#define APP_JUMB (   item)    AppendJumble(jstate, (const unsigned char *) &(item), sizeof(item))

Definition at line 2321 of file pg_stat_statements.c.

Referenced by JumbleExpr(), JumbleQuery(), and JumbleRangeTable().

◆ APP_JUMB_STRING

#define APP_JUMB_STRING (   str)    AppendJumble(jstate, (const unsigned char *) (str), strlen(str) + 1)

Definition at line 2323 of file pg_stat_statements.c.

Referenced by JumbleExpr(), and JumbleRangeTable().

◆ ASSUMED_LENGTH_INIT

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

Definition at line 108 of file pg_stat_statements.c.

Referenced by entry_dealloc(), gc_qtexts(), and pgss_shmem_startup().

◆ ASSUMED_MEDIAN_INIT

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

Definition at line 107 of file pg_stat_statements.c.

Referenced by pgss_shmem_startup().

◆ JUMBLE_SIZE

#define JUMBLE_SIZE   1024 /* query serialization buffer size */

Definition at line 113 of file pg_stat_statements.c.

Referenced by AppendJumble(), and pgss_post_parse_analyze().

◆ PG_STAT_STATEMENTS_COLS

#define PG_STAT_STATEMENTS_COLS   23 /* maximum of above */

Definition at line 1314 of file pg_stat_statements.c.

Referenced by pg_stat_statements_internal().

◆ PG_STAT_STATEMENTS_COLS_V1_0

#define PG_STAT_STATEMENTS_COLS_V1_0   14

Definition at line 1310 of file pg_stat_statements.c.

Referenced by pg_stat_statements_internal().

◆ PG_STAT_STATEMENTS_COLS_V1_1

#define PG_STAT_STATEMENTS_COLS_V1_1   18

Definition at line 1311 of file pg_stat_statements.c.

Referenced by pg_stat_statements_internal().

◆ PG_STAT_STATEMENTS_COLS_V1_2

#define PG_STAT_STATEMENTS_COLS_V1_2   19

Definition at line 1312 of file pg_stat_statements.c.

Referenced by pg_stat_statements_internal().

◆ PG_STAT_STATEMENTS_COLS_V1_3

#define PG_STAT_STATEMENTS_COLS_V1_3   23

Definition at line 1313 of file pg_stat_statements.c.

Referenced by pg_stat_statements_internal().

◆ PGSS_DUMP_FILE

#define PGSS_DUMP_FILE   PGSTAT_STAT_PERMANENT_DIRECTORY "/pg_stat_statements.stat"

Definition at line 86 of file pg_stat_statements.c.

Referenced by pgss_shmem_shutdown(), and pgss_shmem_startup().

◆ pgss_enabled

#define pgss_enabled ( )

◆ PGSS_TEXT_FILE

#define PGSS_TEXT_FILE   PG_STAT_TMP_DIR "/pgss_query_texts.stat"

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

Referenced by entry_reset(), and gc_qtexts().

◆ STICKY_DECREASE_FACTOR

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

Definition at line 110 of file pg_stat_statements.c.

Referenced by entry_dealloc().

◆ USAGE_DEALLOC_PERCENT

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

Definition at line 111 of file pg_stat_statements.c.

Referenced by entry_dealloc().

◆ USAGE_DECREASE_FACTOR

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

Definition at line 109 of file pg_stat_statements.c.

Referenced by entry_dealloc().

◆ USAGE_EXEC

#define USAGE_EXEC (   duration)    (1.0)

Definition at line 105 of file pg_stat_statements.c.

Referenced by pgss_store().

◆ USAGE_INIT

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

Definition at line 106 of file pg_stat_statements.c.

Referenced by entry_alloc(), and pgss_store().

Typedef Documentation

◆ Counters

◆ pgssEntry

◆ pgssHashKey

◆ pgssJumbleState

◆ pgssLocationLen

◆ pgssSharedState

◆ pgssVersion

Enumeration Type Documentation

◆ PGSSTrackLevel

Enumerator
PGSS_TRACK_NONE 
PGSS_TRACK_TOP 
PGSS_TRACK_ALL 

Definition at line 254 of file pg_stat_statements.c.

255 {
256  PGSS_TRACK_NONE, /* track no statements */
257  PGSS_TRACK_TOP, /* only top level statements */
258  PGSS_TRACK_ALL /* all statements, including nested ones */
PGSSTrackLevel

◆ pgssVersion

Enumerator
PGSS_V1_0 
PGSS_V1_1 
PGSS_V1_2 
PGSS_V1_3 

Definition at line 118 of file pg_stat_statements.c.

Function Documentation

◆ _PG_fini()

void _PG_fini ( void  )

Definition at line 444 of file pg_stat_statements.c.

References ExecutorEnd_hook, ExecutorFinish_hook, ExecutorRun_hook, ExecutorStart_hook, post_parse_analyze_hook, prev_ExecutorEnd, prev_ExecutorFinish, prev_ExecutorRun, prev_ExecutorStart, prev_post_parse_analyze_hook, prev_ProcessUtility, prev_shmem_startup_hook, ProcessUtility_hook, and shmem_startup_hook.

445 {
446  /* Uninstall hooks. */
454 }
static ProcessUtility_hook_type prev_ProcessUtility
static ExecutorRun_hook_type prev_ExecutorRun
static ExecutorEnd_hook_type prev_ExecutorEnd
ProcessUtility_hook_type ProcessUtility_hook
Definition: utility.c:75
static ExecutorStart_hook_type prev_ExecutorStart
static post_parse_analyze_hook_type prev_post_parse_analyze_hook
ExecutorStart_hook_type ExecutorStart_hook
Definition: execMain.c:70
ExecutorRun_hook_type ExecutorRun_hook
Definition: execMain.c:71
ExecutorEnd_hook_type ExecutorEnd_hook
Definition: execMain.c:73
static ExecutorFinish_hook_type prev_ExecutorFinish
shmem_startup_hook_type shmem_startup_hook
Definition: ipci.c:51
static shmem_startup_hook_type prev_shmem_startup_hook
ExecutorFinish_hook_type ExecutorFinish_hook
Definition: execMain.c:72
post_parse_analyze_hook_type post_parse_analyze_hook
Definition: analyze.c:51

◆ _PG_init()

void _PG_init ( void  )

Definition at line 348 of file pg_stat_statements.c.

References DefineCustomBoolVariable(), DefineCustomEnumVariable(), DefineCustomIntVariable(), EmitWarningsOnPlaceholders(), ExecutorEnd_hook, ExecutorFinish_hook, ExecutorRun_hook, ExecutorStart_hook, PGC_POSTMASTER, PGC_SIGHUP, PGC_SUSET, pgss_ExecutorEnd(), pgss_ExecutorFinish(), pgss_ExecutorRun(), pgss_ExecutorStart(), pgss_max, pgss_memsize(), pgss_post_parse_analyze(), pgss_ProcessUtility(), pgss_save, pgss_shmem_startup(), pgss_track, PGSS_TRACK_TOP, pgss_track_utility, post_parse_analyze_hook, prev_ExecutorEnd, prev_ExecutorFinish, prev_ExecutorRun, prev_ExecutorStart, prev_post_parse_analyze_hook, prev_ProcessUtility, prev_shmem_startup_hook, process_shared_preload_libraries_in_progress, ProcessUtility_hook, RequestAddinShmemSpace(), RequestNamedLWLockTranche(), and shmem_startup_hook.

349 {
350  /*
351  * In order to create our shared memory area, we have to be loaded via
352  * shared_preload_libraries. If not, fall out without hooking into any of
353  * the main system. (We don't throw error here because it seems useful to
354  * allow the pg_stat_statements functions to be created even when the
355  * module isn't active. The functions must protect themselves against
356  * being called then, however.)
357  */
359  return;
360 
361  /*
362  * Define (or redefine) custom GUC variables.
363  */
364  DefineCustomIntVariable("pg_stat_statements.max",
365  "Sets the maximum number of statements tracked by pg_stat_statements.",
366  NULL,
367  &pgss_max,
368  5000,
369  100,
370  INT_MAX,
372  0,
373  NULL,
374  NULL,
375  NULL);
376 
377  DefineCustomEnumVariable("pg_stat_statements.track",
378  "Selects which statements are tracked by pg_stat_statements.",
379  NULL,
380  &pgss_track,
383  PGC_SUSET,
384  0,
385  NULL,
386  NULL,
387  NULL);
388 
389  DefineCustomBoolVariable("pg_stat_statements.track_utility",
390  "Selects whether utility commands are tracked by pg_stat_statements.",
391  NULL,
393  true,
394  PGC_SUSET,
395  0,
396  NULL,
397  NULL,
398  NULL);
399 
400  DefineCustomBoolVariable("pg_stat_statements.save",
401  "Save pg_stat_statements statistics across server shutdowns.",
402  NULL,
403  &pgss_save,
404  true,
405  PGC_SIGHUP,
406  0,
407  NULL,
408  NULL,
409  NULL);
410 
411  EmitWarningsOnPlaceholders("pg_stat_statements");
412 
413  /*
414  * Request additional shared resources. (These are no-ops if we're not in
415  * the postmaster process.) We'll allocate or attach to the shared
416  * resources in pgss_shmem_startup().
417  */
419  RequestNamedLWLockTranche("pg_stat_statements", 1);
420 
421  /*
422  * Install hooks.
423  */
438 }
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:8020
void RequestAddinShmemSpace(Size size)
Definition: ipci.c:69
bool process_shared_preload_libraries_in_progress
Definition: miscinit.c:1518
void RequestNamedLWLockTranche(const char *tranche_name, int num_lwlocks)
Definition: lwlock.c:637
static ProcessUtility_hook_type prev_ProcessUtility
static void pgss_shmem_startup(void)
static ExecutorRun_hook_type prev_ExecutorRun
static ExecutorEnd_hook_type prev_ExecutorEnd
ProcessUtility_hook_type ProcessUtility_hook
Definition: utility.c:75
static int pgss_track
static ExecutorStart_hook_type prev_ExecutorStart
static void pgss_ExecutorStart(QueryDesc *queryDesc, int eflags)
static post_parse_analyze_hook_type prev_post_parse_analyze_hook
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:8105
ExecutorStart_hook_type ExecutorStart_hook
Definition: execMain.c:70
static void pgss_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
static int pgss_max
ExecutorRun_hook_type ExecutorRun_hook
Definition: execMain.c:71
ExecutorEnd_hook_type ExecutorEnd_hook
Definition: execMain.c:73
static void pgss_post_parse_analyze(ParseState *pstate, Query *query)
Definition: guc.h:75
void EmitWarningsOnPlaceholders(const char *className)
Definition: guc.c:8133
static ExecutorFinish_hook_type prev_ExecutorFinish
Definition: guc.h:72
static Size pgss_memsize(void)
shmem_startup_hook_type shmem_startup_hook
Definition: ipci.c:51
static bool pgss_track_utility
static void pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, char *completionTag)
static shmem_startup_hook_type prev_shmem_startup_hook
static void pgss_ExecutorFinish(QueryDesc *queryDesc)
ExecutorFinish_hook_type ExecutorFinish_hook
Definition: execMain.c:72
static void pgss_ExecutorEnd(QueryDesc *queryDesc)
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:7994
post_parse_analyze_hook_type post_parse_analyze_hook
Definition: analyze.c:51
static const struct config_enum_entry track_options[]
static bool pgss_save

◆ AppendJumble()

static void AppendJumble ( pgssJumbleState jstate,
const unsigned char *  item,
Size  size 
)
static

Definition at line 2285 of file pg_stat_statements.c.

References DatumGetUInt64, hash_any_extended(), pgssJumbleState::jumble, pgssJumbleState::jumble_len, JUMBLE_SIZE, and Min.

2286 {
2287  unsigned char *jumble = jstate->jumble;
2288  Size jumble_len = jstate->jumble_len;
2289 
2290  /*
2291  * Whenever the jumble buffer is full, we hash the current contents and
2292  * reset the buffer to contain just that hash value, thus relying on the
2293  * hash to summarize everything so far.
2294  */
2295  while (size > 0)
2296  {
2297  Size part_size;
2298 
2299  if (jumble_len >= JUMBLE_SIZE)
2300  {
2301  uint64 start_hash;
2302 
2303  start_hash = DatumGetUInt64(hash_any_extended(jumble,
2304  JUMBLE_SIZE, 0));
2305  memcpy(jumble, &start_hash, sizeof(start_hash));
2306  jumble_len = sizeof(start_hash);
2307  }
2308  part_size = Min(size, JUMBLE_SIZE - jumble_len);
2309  memcpy(jumble + jumble_len, item, part_size);
2310  jumble_len += part_size;
2311  item += part_size;
2312  size -= part_size;
2313  }
2314  jstate->jumble_len = jumble_len;
2315 }
#define Min(x, y)
Definition: c.h:857
unsigned char * jumble
#define JUMBLE_SIZE
#define DatumGetUInt64(X)
Definition: postgres.h:617
size_t Size
Definition: c.h:433
Datum hash_any_extended(register const unsigned char *k, register int keylen, uint64 seed)
Definition: hashfunc.c:634

◆ comp_location()

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

Definition at line 3155 of file pg_stat_statements.c.

Referenced by fill_in_constant_lengths().

3156 {
3157  int l = ((const pgssLocationLen *) a)->location;
3158  int r = ((const pgssLocationLen *) b)->location;
3159 
3160  if (l < r)
3161  return -1;
3162  else if (l > r)
3163  return +1;
3164  else
3165  return 0;
3166 }

◆ entry_alloc()

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

Definition at line 1679 of file pg_stat_statements.c.

References Assert, pgssEntry::counters, pgssSharedState::cur_median_usage, encoding, pgssEntry::encoding, entry_dealloc(), HASH_ENTER, hash_get_num_entries(), hash_search(), pgssEntry::mutex, pgss_max, pgssEntry::query_len, pgssEntry::query_offset, SpinLockInit, Counters::usage, and USAGE_INIT.

Referenced by pgss_shmem_startup(), and pgss_store().

1681 {
1682  pgssEntry *entry;
1683  bool found;
1684 
1685  /* Make space if needed */
1687  entry_dealloc();
1688 
1689  /* Find or create an entry with desired hash code */
1690  entry = (pgssEntry *) hash_search(pgss_hash, key, HASH_ENTER, &found);
1691 
1692  if (!found)
1693  {
1694  /* New entry, initialize it */
1695 
1696  /* reset the statistics */
1697  memset(&entry->counters, 0, sizeof(Counters));
1698  /* set the appropriate initial usage count */
1699  entry->counters.usage = sticky ? pgss->cur_median_usage : USAGE_INIT;
1700  /* re-initialize the mutex each time ... we assume no one using it */
1701  SpinLockInit(&entry->mutex);
1702  /* ... and don't forget the query text metadata */
1703  Assert(query_len >= 0);
1704  entry->query_offset = query_offset;
1705  entry->query_len = query_len;
1706  entry->encoding = encoding;
1707  }
1708 
1709  return entry;
1710 }
#define SpinLockInit(lock)
Definition: spin.h:60
long hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1335
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
Counters counters
static pgssSharedState * pgss
static int pgss_max
static void entry_dealloc(void)
static HTAB * pgss_hash
#define USAGE_INIT
#define Assert(condition)
Definition: c.h:699
int32 encoding
Definition: pg_database.h:33

◆ entry_cmp()

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

Definition at line 1716 of file pg_stat_statements.c.

Referenced by entry_dealloc().

1717 {
1718  double l_usage = (*(pgssEntry *const *) lhs)->counters.usage;
1719  double r_usage = (*(pgssEntry *const *) rhs)->counters.usage;
1720 
1721  if (l_usage < r_usage)
1722  return -1;
1723  else if (l_usage > r_usage)
1724  return +1;
1725  else
1726  return 0;
1727 }

◆ entry_dealloc()

static void entry_dealloc ( void  )
static

Definition at line 1735 of file pg_stat_statements.c.

References ASSUMED_LENGTH_INIT, Counters::calls, pgssEntry::counters, pgssSharedState::cur_median_usage, entry_cmp(), hash_get_num_entries(), HASH_REMOVE, hash_search(), hash_seq_init(), hash_seq_search(), i, Max, pgssSharedState::mean_query_len, Min, palloc(), pfree(), qsort, pgssEntry::query_len, STICKY_DECREASE_FACTOR, Counters::usage, USAGE_DEALLOC_PERCENT, and USAGE_DECREASE_FACTOR.

Referenced by entry_alloc().

1736 {
1737  HASH_SEQ_STATUS hash_seq;
1738  pgssEntry **entries;
1739  pgssEntry *entry;
1740  int nvictims;
1741  int i;
1742  Size tottextlen;
1743  int nvalidtexts;
1744 
1745  /*
1746  * Sort entries by usage and deallocate USAGE_DEALLOC_PERCENT of them.
1747  * While we're scanning the table, apply the decay factor to the usage
1748  * values, and update the mean query length.
1749  *
1750  * Note that the mean query length is almost immediately obsolete, since
1751  * we compute it before not after discarding the least-used entries.
1752  * Hopefully, that doesn't affect the mean too much; it doesn't seem worth
1753  * making two passes to get a more current result. Likewise, the new
1754  * cur_median_usage includes the entries we're about to zap.
1755  */
1756 
1757  entries = palloc(hash_get_num_entries(pgss_hash) * sizeof(pgssEntry *));
1758 
1759  i = 0;
1760  tottextlen = 0;
1761  nvalidtexts = 0;
1762 
1763  hash_seq_init(&hash_seq, pgss_hash);
1764  while ((entry = hash_seq_search(&hash_seq)) != NULL)
1765  {
1766  entries[i++] = entry;
1767  /* "Sticky" entries get a different usage decay rate. */
1768  if (entry->counters.calls == 0)
1770  else
1772  /* In the mean length computation, ignore dropped texts. */
1773  if (entry->query_len >= 0)
1774  {
1775  tottextlen += entry->query_len + 1;
1776  nvalidtexts++;
1777  }
1778  }
1779 
1780  /* Sort into increasing order by usage */
1781  qsort(entries, i, sizeof(pgssEntry *), entry_cmp);
1782 
1783  /* Record the (approximate) median usage */
1784  if (i > 0)
1785  pgss->cur_median_usage = entries[i / 2]->counters.usage;
1786  /* Record the mean query length */
1787  if (nvalidtexts > 0)
1788  pgss->mean_query_len = tottextlen / nvalidtexts;
1789  else
1791 
1792  /* Now zap an appropriate fraction of lowest-usage entries */
1793  nvictims = Max(10, i * USAGE_DEALLOC_PERCENT / 100);
1794  nvictims = Min(nvictims, i);
1795 
1796  for (i = 0; i < nvictims; i++)
1797  {
1798  hash_search(pgss_hash, &entries[i]->key, HASH_REMOVE, NULL);
1799  }
1800 
1801  pfree(entries);
1802 }
#define USAGE_DEALLOC_PERCENT
#define Min(x, y)
Definition: c.h:857
static int entry_cmp(const void *lhs, const void *rhs)
long hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1335
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
Counters counters
#define ASSUMED_LENGTH_INIT
static pgssSharedState * pgss
void pfree(void *pointer)
Definition: mcxt.c:1031
static HTAB * pgss_hash
#define STICKY_DECREASE_FACTOR
#define USAGE_DECREASE_FACTOR
#define Max(x, y)
Definition: c.h:851
size_t Size
Definition: c.h:433
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
void * palloc(Size size)
Definition: mcxt.c:924
int i
#define qsort(a, b, c, d)
Definition: port.h:421

◆ entry_reset()

static void entry_reset ( void  )
static

Definition at line 2235 of file pg_stat_statements.c.

References AllocateFile(), ereport, errcode_for_file_access(), errmsg(), pgssSharedState::extent, FreeFile(), ftruncate, HASH_REMOVE, hash_search(), hash_seq_init(), hash_seq_search(), pgssEntry::key, pgssSharedState::lock, LOG, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), PG_BINARY_W, PGSS_TEXT_FILE, and record_gc_qtexts.

Referenced by pg_stat_statements_reset().

2236 {
2237  HASH_SEQ_STATUS hash_seq;
2238  pgssEntry *entry;
2239  FILE *qfile;
2240 
2242 
2243  hash_seq_init(&hash_seq, pgss_hash);
2244  while ((entry = hash_seq_search(&hash_seq)) != NULL)
2245  {
2246  hash_search(pgss_hash, &entry->key, HASH_REMOVE, NULL);
2247  }
2248 
2249  /*
2250  * Write new empty query file, perhaps even creating a new one to recover
2251  * if the file was missing.
2252  */
2254  if (qfile == NULL)
2255  {
2256  ereport(LOG,
2258  errmsg("could not create pg_stat_statement file \"%s\": %m",
2259  PGSS_TEXT_FILE)));
2260  goto done;
2261  }
2262 
2263  /* If ftruncate fails, log it, but it's not a fatal problem */
2264  if (ftruncate(fileno(qfile), 0) != 0)
2265  ereport(LOG,
2267  errmsg("could not truncate pg_stat_statement file \"%s\": %m",
2268  PGSS_TEXT_FILE)));
2269 
2270  FreeFile(qfile);
2271 
2272 done:
2273  pgss->extent = 0;
2274  /* This counts as a query text garbage collection for our purposes */
2275  record_gc_qtexts();
2276 
2278 }
#define PG_BINARY_W
Definition: c.h:1083
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
#define LOG
Definition: elog.h:26
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1725
static pgssSharedState * pgss
static HTAB * pgss_hash
int errcode_for_file_access(void)
Definition: elog.c:598
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2346
#define ereport(elevel, rest)
Definition: elog.h:122
pgssHashKey key
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1121
#define record_gc_qtexts()
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
int FreeFile(FILE *file)
Definition: fd.c:2538
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define PGSS_TEXT_FILE
#define ftruncate(a, b)
Definition: win32_port.h:60

◆ fill_in_constant_lengths()

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

Definition at line 3055 of file pg_stat_statements.c.

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

Referenced by generate_normalized_query().

3057 {
3058  pgssLocationLen *locs;
3060  core_yy_extra_type yyextra;
3061  core_YYSTYPE yylval;
3062  YYLTYPE yylloc;
3063  int last_loc = -1;
3064  int i;
3065 
3066  /*
3067  * Sort the records by location so that we can process them in order while
3068  * scanning the query text.
3069  */
3070  if (jstate->clocations_count > 1)
3071  qsort(jstate->clocations, jstate->clocations_count,
3072  sizeof(pgssLocationLen), comp_location);
3073  locs = jstate->clocations;
3074 
3075  /* initialize the flex scanner --- should match raw_parser() */
3076  yyscanner = scanner_init(query,
3077  &yyextra,
3078  ScanKeywords,
3079  NumScanKeywords);
3080 
3081  /* we don't want to re-emit any escape string warnings */
3082  yyextra.escape_string_warning = false;
3083 
3084  /* Search for each constant, in sequence */
3085  for (i = 0; i < jstate->clocations_count; i++)
3086  {
3087  int loc = locs[i].location;
3088  int tok;
3089 
3090  /* Adjust recorded location if we're dealing with partial string */
3091  loc -= query_loc;
3092 
3093  Assert(loc >= 0);
3094 
3095  if (loc <= last_loc)
3096  continue; /* Duplicate constant, ignore */
3097 
3098  /* Lex tokens until we find the desired constant */
3099  for (;;)
3100  {
3101  tok = core_yylex(&yylval, &yylloc, yyscanner);
3102 
3103  /* We should not hit end-of-string, but if we do, behave sanely */
3104  if (tok == 0)
3105  break; /* out of inner for-loop */
3106 
3107  /*
3108  * We should find the token position exactly, but if we somehow
3109  * run past it, work with that.
3110  */
3111  if (yylloc >= loc)
3112  {
3113  if (query[loc] == '-')
3114  {
3115  /*
3116  * It's a negative value - this is the one and only case
3117  * where we replace more than a single token.
3118  *
3119  * Do not compensate for the core system's special-case
3120  * adjustment of location to that of the leading '-'
3121  * operator in the event of a negative constant. It is
3122  * also useful for our purposes to start from the minus
3123  * symbol. In this way, queries like "select * from foo
3124  * where bar = 1" and "select * from foo where bar = -2"
3125  * will have identical normalized query strings.
3126  */
3127  tok = core_yylex(&yylval, &yylloc, yyscanner);
3128  if (tok == 0)
3129  break; /* out of inner for-loop */
3130  }
3131 
3132  /*
3133  * We now rely on the assumption that flex has placed a zero
3134  * byte after the text of the current token in scanbuf.
3135  */
3136  locs[i].length = strlen(yyextra.scanbuf + loc);
3137  break; /* out of inner for-loop */
3138  }
3139  }
3140 
3141  /* If we hit end-of-string, give up, leaving remaining lengths -1 */
3142  if (tok == 0)
3143  break;
3144 
3145  last_loc = loc;
3146  }
3147 
3148  scanner_finish(yyscanner);
3149 }
void * core_yyscan_t
Definition: scanner.h:116
const int NumScanKeywords
Definition: keywords.c:45
char * scanbuf
Definition: scanner.h:72
pgssLocationLen * clocations
const ScanKeyword ScanKeywords[]
Definition: keywords.c:41
#define YYLTYPE
Definition: scanner.h:44
static int comp_location(const void *a, const void *b)
int core_yylex(core_YYSTYPE *lvalp, YYLTYPE *llocp, core_yyscan_t yyscanner)
#define Assert(condition)
Definition: c.h:699
core_yyscan_t scanner_init(const char *str, core_yy_extra_type *yyext, const ScanKeyword *keywords, int num_keywords)
static core_yyscan_t yyscanner
Definition: pl_scanner.c:216
int i
bool escape_string_warning
Definition: scanner.h:88
void scanner_finish(core_yyscan_t yyscanner)
#define qsort(a, b, c, d)
Definition: port.h:421

◆ gc_qtexts()

static void gc_qtexts ( void  )
static

Definition at line 2051 of file pg_stat_statements.c.

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_TEXT_FILE, qtext_fetch(), qtext_load_file(), pgssEntry::query_len, pgssEntry::query_offset, and record_gc_qtexts.

Referenced by pgss_store().

2052 {
2053  char *qbuffer;
2054  Size qbuffer_size;
2055  FILE *qfile = NULL;
2056  HASH_SEQ_STATUS hash_seq;
2057  pgssEntry *entry;
2058  Size extent;
2059  int nentries;
2060 
2061  /*
2062  * When called from pgss_store, some other session might have proceeded
2063  * with garbage collection in the no-lock-held interim of lock strength
2064  * escalation. Check once more that this is actually necessary.
2065  */
2066  if (!need_gc_qtexts())
2067  return;
2068 
2069  /*
2070  * Load the old texts file. If we fail (out of memory, for instance),
2071  * invalidate query texts. Hopefully this is rare. It might seem better
2072  * to leave things alone on an OOM failure, but the problem is that the
2073  * file is only going to get bigger; hoping for a future non-OOM result is
2074  * risky and can easily lead to complete denial of service.
2075  */
2076  qbuffer = qtext_load_file(&qbuffer_size);
2077  if (qbuffer == NULL)
2078  goto gc_fail;
2079 
2080  /*
2081  * We overwrite the query texts file in place, so as to reduce the risk of
2082  * an out-of-disk-space failure. Since the file is guaranteed not to get
2083  * larger, this should always work on traditional filesystems; though we
2084  * could still lose on copy-on-write filesystems.
2085  */
2087  if (qfile == NULL)
2088  {
2089  ereport(LOG,
2091  errmsg("could not write pg_stat_statement file \"%s\": %m",
2092  PGSS_TEXT_FILE)));
2093  goto gc_fail;
2094  }
2095 
2096  extent = 0;
2097  nentries = 0;
2098 
2099  hash_seq_init(&hash_seq, pgss_hash);
2100  while ((entry = hash_seq_search(&hash_seq)) != NULL)
2101  {
2102  int query_len = entry->query_len;
2103  char *qry = qtext_fetch(entry->query_offset,
2104  query_len,
2105  qbuffer,
2106  qbuffer_size);
2107 
2108  if (qry == NULL)
2109  {
2110  /* Trouble ... drop the text */
2111  entry->query_offset = 0;
2112  entry->query_len = -1;
2113  /* entry will not be counted in mean query length computation */
2114  continue;
2115  }
2116 
2117  if (fwrite(qry, 1, query_len + 1, qfile) != query_len + 1)
2118  {
2119  ereport(LOG,
2121  errmsg("could not write pg_stat_statement file \"%s\": %m",
2122  PGSS_TEXT_FILE)));
2123  hash_seq_term(&hash_seq);
2124  goto gc_fail;
2125  }
2126 
2127  entry->query_offset = extent;
2128  extent += query_len + 1;
2129  nentries++;
2130  }
2131 
2132  /*
2133  * Truncate away any now-unused space. If this fails for some odd reason,
2134  * we log it, but there's no need to fail.
2135  */
2136  if (ftruncate(fileno(qfile), extent) != 0)
2137  ereport(LOG,
2139  errmsg("could not truncate pg_stat_statement file \"%s\": %m",
2140  PGSS_TEXT_FILE)));
2141 
2142  if (FreeFile(qfile))
2143  {
2144  ereport(LOG,
2146  errmsg("could not write pg_stat_statement file \"%s\": %m",
2147  PGSS_TEXT_FILE)));
2148  qfile = NULL;
2149  goto gc_fail;
2150  }
2151 
2152  elog(DEBUG1, "pgss gc of queries file shrunk size from %zu to %zu",
2153  pgss->extent, extent);
2154 
2155  /* Reset the shared extent pointer */
2156  pgss->extent = extent;
2157 
2158  /*
2159  * Also update the mean query length, to be sure that need_gc_qtexts()
2160  * won't still think we have a problem.
2161  */
2162  if (nentries > 0)
2163  pgss->mean_query_len = extent / nentries;
2164  else
2166 
2167  free(qbuffer);
2168 
2169  /*
2170  * OK, count a garbage collection cycle. (Note: even though we have
2171  * exclusive lock on pgss->lock, we must take pgss->mutex for this, since
2172  * other processes may examine gc_count while holding only the mutex.
2173  * Also, we have to advance the count *after* we've rewritten the file,
2174  * else other processes might not realize they read a stale file.)
2175  */
2176  record_gc_qtexts();
2177 
2178  return;
2179 
2180 gc_fail:
2181  /* clean up resources */
2182  if (qfile)
2183  FreeFile(qfile);
2184  if (qbuffer)
2185  free(qbuffer);
2186 
2187  /*
2188  * Since the contents of the external file are now uncertain, mark all
2189  * hashtable entries as having invalid texts.
2190  */
2191  hash_seq_init(&hash_seq, pgss_hash);
2192  while ((entry = hash_seq_search(&hash_seq)) != NULL)
2193  {
2194  entry->query_offset = 0;
2195  entry->query_len = -1;
2196  }
2197 
2198  /*
2199  * Destroy the query text file and create a new, empty one
2200  */
2201  (void) unlink(PGSS_TEXT_FILE);
2203  if (qfile == NULL)
2204  ereport(LOG,
2206  errmsg("could not write new pg_stat_statement file \"%s\": %m",
2207  PGSS_TEXT_FILE)));
2208  else
2209  FreeFile(qfile);
2210 
2211  /* Reset the shared extent pointer */
2212  pgss->extent = 0;
2213 
2214  /* Reset mean_query_len to match the new state */
2216 
2217  /*
2218  * Bump the GC count even though we failed.
2219  *
2220  * This is needed to make concurrent readers of file without any lock on
2221  * pgss->lock notice existence of new version of file. Once readers
2222  * subsequently observe a change in GC count with pgss->lock held, that
2223  * forces a safe reopen of file. Writers also require that we bump here,
2224  * of course. (As required by locking protocol, readers and writers don't
2225  * trust earlier file contents until gc_count is found unchanged after
2226  * pgss->lock acquired in shared or exclusive mode respectively.)
2227  */
2228  record_gc_qtexts();
2229 }
#define DEBUG1
Definition: elog.h:25
#define PG_BINARY_W
Definition: c.h:1083
#define LOG
Definition: elog.h:26
#define ASSUMED_LENGTH_INIT
static pgssSharedState * pgss
static HTAB * pgss_hash
int errcode_for_file_access(void)
Definition: elog.c:598
static char * qtext_load_file(Size *buffer_size)
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2346
#define ereport(elevel, rest)
Definition: elog.h:122
static bool need_gc_qtexts(void)
#define free(a)
Definition: header.h:65
size_t Size
Definition: c.h:433
#define record_gc_qtexts()
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
int FreeFile(FILE *file)
Definition: fd.c:2538
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define elog
Definition: elog.h:219
#define PGSS_TEXT_FILE
void hash_seq_term(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1465
static char * qtext_fetch(Size query_offset, int query_len, char *buffer, Size buffer_size)
#define ftruncate(a, b)
Definition: win32_port.h:60

◆ generate_normalized_query()

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

Definition at line 2948 of file pg_stat_statements.c.

References Assert, pgssJumbleState::clocations, pgssJumbleState::clocations_count, fill_in_constant_lengths(), pgssJumbleState::highest_extern_param_id, i, pgssLocationLen::length, pgssLocationLen::location, and palloc().

Referenced by pgss_store().

2950 {
2951  char *norm_query;
2952  int query_len = *query_len_p;
2953  int i,
2954  norm_query_buflen, /* Space allowed for norm_query */
2955  len_to_wrt, /* Length (in bytes) to write */
2956  quer_loc = 0, /* Source query byte location */
2957  n_quer_loc = 0, /* Normalized query byte location */
2958  last_off = 0, /* Offset from start for previous tok */
2959  last_tok_len = 0; /* Length (in bytes) of that tok */
2960 
2961  /*
2962  * Get constants' lengths (core system only gives us locations). Note
2963  * this also ensures the items are sorted by location.
2964  */
2965  fill_in_constant_lengths(jstate, query, query_loc);
2966 
2967  /*
2968  * Allow for $n symbols to be longer than the constants they replace.
2969  * Constants must take at least one byte in text form, while a $n symbol
2970  * certainly isn't more than 11 bytes, even if n reaches INT_MAX. We
2971  * could refine that limit based on the max value of n for the current
2972  * query, but it hardly seems worth any extra effort to do so.
2973  */
2974  norm_query_buflen = query_len + jstate->clocations_count * 10;
2975 
2976  /* Allocate result buffer */
2977  norm_query = palloc(norm_query_buflen + 1);
2978 
2979  for (i = 0; i < jstate->clocations_count; i++)
2980  {
2981  int off, /* Offset from start for cur tok */
2982  tok_len; /* Length (in bytes) of that tok */
2983 
2984  off = jstate->clocations[i].location;
2985  /* Adjust recorded location if we're dealing with partial string */
2986  off -= query_loc;
2987 
2988  tok_len = jstate->clocations[i].length;
2989 
2990  if (tok_len < 0)
2991  continue; /* ignore any duplicates */
2992 
2993  /* Copy next chunk (what precedes the next constant) */
2994  len_to_wrt = off - last_off;
2995  len_to_wrt -= last_tok_len;
2996 
2997  Assert(len_to_wrt >= 0);
2998  memcpy(norm_query + n_quer_loc, query + quer_loc, len_to_wrt);
2999  n_quer_loc += len_to_wrt;
3000 
3001  /* And insert a param symbol in place of the constant token */
3002  n_quer_loc += sprintf(norm_query + n_quer_loc, "$%d",
3003  i + 1 + jstate->highest_extern_param_id);
3004 
3005  quer_loc = off + tok_len;
3006  last_off = off;
3007  last_tok_len = tok_len;
3008  }
3009 
3010  /*
3011  * We've copied up until the last ignorable constant. Copy over the
3012  * remaining bytes of the original query string.
3013  */
3014  len_to_wrt = query_len - quer_loc;
3015 
3016  Assert(len_to_wrt >= 0);
3017  memcpy(norm_query + n_quer_loc, query + quer_loc, len_to_wrt);
3018  n_quer_loc += len_to_wrt;
3019 
3020  Assert(n_quer_loc <= norm_query_buflen);
3021  norm_query[n_quer_loc] = '\0';
3022 
3023  *query_len_p = n_quer_loc;
3024  return norm_query;
3025 }
pgssLocationLen * clocations
static void fill_in_constant_lengths(pgssJumbleState *jstate, const char *query, int query_loc)
#define Assert(condition)
Definition: c.h:699
void * palloc(Size size)
Definition: mcxt.c:924
int i

◆ JumbleExpr()

static void JumbleExpr ( pgssJumbleState jstate,
Node node 
)
static

Definition at line 2429 of file pg_stat_statements.c.

References OnConflictExpr::action, Aggref::aggdirectargs, Aggref::aggdistinct, Aggref::aggfilter, WindowFunc::aggfilter, Aggref::aggfnoid, Aggref::aggorder, SetOperationStmt::all, APP_JUMB, APP_JUMB_STRING, OnConflictExpr::arbiterElems, OnConflictExpr::arbiterWhere, NamedArgExpr::arg, FieldSelect::arg, FieldStore::arg, RelabelType::arg, CoerceViaIO::arg, ArrayCoerceExpr::arg, ConvertRowtypeExpr::arg, CollateExpr::arg, CaseExpr::arg, NullTest::arg, BooleanTest::arg, CoerceToDomain::arg, NamedArgExpr::argnumber, generate_unaccent_rules::args, Aggref::args, WindowFunc::args, FuncExpr::args, OpExpr::args, ScalarArrayOpExpr::args, BoolExpr::args, CaseExpr::args, MinMaxExpr::args, TableSampleClause::args, XmlExpr::args, BoolExpr::boolop, BooleanTest::booltesttype, castNode, check_stack_depth(), TableFunc::colexprs, CollateExpr::collOid, OnConflictExpr::constraint, Const::consttype, GroupingSet::content, CommonTableExpr::ctename, CommonTableExpr::ctequery, CurrentOfExpr::cursor_name, CurrentOfExpr::cursor_param, CurrentOfExpr::cvarno, CaseExpr::defresult, TableFunc::docexpr, ArrayCoerceExpr::elemexpr, elog, WindowClause::endOffset, SortGroupClause::eqop, OnConflictExpr::exclRelIndex, OnConflictExpr::exclRelTlist, CaseWhen::expr, InferenceElem::expr, TargetEntry::expr, FieldSelect::fieldnum, WindowClause::frameOptions, FromExpr::fromlist, RangeTblFunction::funcexpr, FuncExpr::funcid, pgssJumbleState::highest_extern_param_id, InferenceElem::infercollid, InferenceElem::inferopclass, JoinExpr::isNatural, JoinExpr::jointype, JumbleQuery(), JoinExpr::larg, SetOperationStmt::larg, RowCompareExpr::largs, lfirst, lfirst_int, lfirst_node, Const::location, XmlExpr::named_args, FieldStore::newvals, nodeTag, SortGroupClause::nulls_first, NullTest::nulltesttype, OnConflictExpr::onConflictSet, OnConflictExpr::onConflictWhere, MinMaxExpr::op, SQLValueFunction::op, XmlExpr::op, SetOperationStmt::op, OpExpr::opno, ScalarArrayOpExpr::opno, WindowClause::orderClause, PARAM_EXTERN, Param::paramid, Param::paramkind, Param::paramtype, WindowClause::partitionClause, JoinExpr::quals, FromExpr::quals, JoinExpr::rarg, SetOperationStmt::rarg, RowCompareExpr::rargs, RowCompareExpr::rctype, RecordConstLocation(), ArrayRef::refassgnexpr, ArrayRef::refexpr, ArrayRef::reflowerindexpr, GroupingFunc::refs, ArrayRef::refupperindexpr, TableSampleClause::repeatable, TargetEntry::resno, TargetEntry::ressortgroupref, CaseWhen::result, RelabelType::resulttype, CoerceViaIO::resulttype, ArrayCoerceExpr::resulttype, ConvertRowtypeExpr::resulttype, CoerceToDomain::resulttype, TableFunc::rowexpr, RangeTblRef::rtindex, JoinExpr::rtindex, NextValueExpr::seqid, SortGroupClause::sortop, WindowClause::startOffset, SubLink::subLinkId, SubLink::subLinkType, SubLink::subselect, T_Aggref, T_ArrayCoerceExpr, T_ArrayExpr, T_ArrayRef, T_BooleanTest, T_BoolExpr, T_CaseExpr, T_CaseTestExpr, T_CoalesceExpr, T_CoerceToDomain, T_CoerceToDomainValue, T_CoerceViaIO, T_CollateExpr, T_CommonTableExpr, T_Const, T_ConvertRowtypeExpr, T_CurrentOfExpr, T_DistinctExpr, T_FieldSelect, T_FieldStore, T_FromExpr, T_FuncExpr, T_GroupingFunc, T_GroupingSet, T_InferenceElem, T_IntList, T_JoinExpr, T_List, T_MinMaxExpr, T_NamedArgExpr, T_NextValueExpr, T_NullIfExpr, T_NullTest, T_OnConflictExpr, T_OpExpr, T_Param, T_RangeTblFunction, T_RangeTblRef, T_RelabelType, T_RowCompareExpr, T_RowExpr, T_ScalarArrayOpExpr, T_SetOperationStmt, T_SetToDefault, T_SortGroupClause, T_SQLValueFunction, T_SubLink, T_TableFunc, T_TableSampleClause, T_TargetEntry, T_Var, T_WindowClause, T_WindowFunc, T_XmlExpr, SubLink::testexpr, SortGroupClause::tleSortGroupRef, TableSampleClause::tsmhandler, Node::type, CaseTestExpr::typeId, CoerceToDomainValue::typeId, SetToDefault::typeId, NextValueExpr::typeId, SQLValueFunction::typmod, ScalarArrayOpExpr::useOr, Var::varattno, Var::varlevelsup, Var::varno, WARNING, WindowFunc::winfnoid, WindowFunc::winref, and WindowClause::winref.

Referenced by JumbleQuery(), and JumbleRangeTable().

2430 {
2431  ListCell *temp;
2432 
2433  if (node == NULL)
2434  return;
2435 
2436  /* Guard against stack overflow due to overly complex expressions */
2438 
2439  /*
2440  * We always emit the node's NodeTag, then any additional fields that are
2441  * considered significant, and then we recurse to any child nodes.
2442  */
2443  APP_JUMB(node->type);
2444 
2445  switch (nodeTag(node))
2446  {
2447  case T_Var:
2448  {
2449  Var *var = (Var *) node;
2450 
2451  APP_JUMB(var->varno);
2452  APP_JUMB(var->varattno);
2453  APP_JUMB(var->varlevelsup);
2454  }
2455  break;
2456  case T_Const:
2457  {
2458  Const *c = (Const *) node;
2459 
2460  /* We jumble only the constant's type, not its value */
2461  APP_JUMB(c->consttype);
2462  /* Also, record its parse location for query normalization */
2463  RecordConstLocation(jstate, c->location);
2464  }
2465  break;
2466  case T_Param:
2467  {
2468  Param *p = (Param *) node;
2469 
2470  APP_JUMB(p->paramkind);
2471  APP_JUMB(p->paramid);
2472  APP_JUMB(p->paramtype);
2473  /* Also, track the highest external Param id */
2474  if (p->paramkind == PARAM_EXTERN &&
2475  p->paramid > jstate->highest_extern_param_id)
2476  jstate->highest_extern_param_id = p->paramid;
2477  }
2478  break;
2479  case T_Aggref:
2480  {
2481  Aggref *expr = (Aggref *) node;
2482 
2483  APP_JUMB(expr->aggfnoid);
2484  JumbleExpr(jstate, (Node *) expr->aggdirectargs);
2485  JumbleExpr(jstate, (Node *) expr->args);
2486  JumbleExpr(jstate, (Node *) expr->aggorder);
2487  JumbleExpr(jstate, (Node *) expr->aggdistinct);
2488  JumbleExpr(jstate, (Node *) expr->aggfilter);
2489  }
2490  break;
2491  case T_GroupingFunc:
2492  {
2493  GroupingFunc *grpnode = (GroupingFunc *) node;
2494 
2495  JumbleExpr(jstate, (Node *) grpnode->refs);
2496  }
2497  break;
2498  case T_WindowFunc:
2499  {
2500  WindowFunc *expr = (WindowFunc *) node;
2501 
2502  APP_JUMB(expr->winfnoid);
2503  APP_JUMB(expr->winref);
2504  JumbleExpr(jstate, (Node *) expr->args);
2505  JumbleExpr(jstate, (Node *) expr->aggfilter);
2506  }
2507  break;
2508  case T_ArrayRef:
2509  {
2510  ArrayRef *aref = (ArrayRef *) node;
2511 
2512  JumbleExpr(jstate, (Node *) aref->refupperindexpr);
2513  JumbleExpr(jstate, (Node *) aref->reflowerindexpr);
2514  JumbleExpr(jstate, (Node *) aref->refexpr);
2515  JumbleExpr(jstate, (Node *) aref->refassgnexpr);
2516  }
2517  break;
2518  case T_FuncExpr:
2519  {
2520  FuncExpr *expr = (FuncExpr *) node;
2521 
2522  APP_JUMB(expr->funcid);
2523  JumbleExpr(jstate, (Node *) expr->args);
2524  }
2525  break;
2526  case T_NamedArgExpr:
2527  {
2528  NamedArgExpr *nae = (NamedArgExpr *) node;
2529 
2530  APP_JUMB(nae->argnumber);
2531  JumbleExpr(jstate, (Node *) nae->arg);
2532  }
2533  break;
2534  case T_OpExpr:
2535  case T_DistinctExpr: /* struct-equivalent to OpExpr */
2536  case T_NullIfExpr: /* struct-equivalent to OpExpr */
2537  {
2538  OpExpr *expr = (OpExpr *) node;
2539 
2540  APP_JUMB(expr->opno);
2541  JumbleExpr(jstate, (Node *) expr->args);
2542  }
2543  break;
2544  case T_ScalarArrayOpExpr:
2545  {
2546  ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
2547 
2548  APP_JUMB(expr->opno);
2549  APP_JUMB(expr->useOr);
2550  JumbleExpr(jstate, (Node *) expr->args);
2551  }
2552  break;
2553  case T_BoolExpr:
2554  {
2555  BoolExpr *expr = (BoolExpr *) node;
2556 
2557  APP_JUMB(expr->boolop);
2558  JumbleExpr(jstate, (Node *) expr->args);
2559  }
2560  break;
2561  case T_SubLink:
2562  {
2563  SubLink *sublink = (SubLink *) node;
2564 
2565  APP_JUMB(sublink->subLinkType);
2566  APP_JUMB(sublink->subLinkId);
2567  JumbleExpr(jstate, (Node *) sublink->testexpr);
2568  JumbleQuery(jstate, castNode(Query, sublink->subselect));
2569  }
2570  break;
2571  case T_FieldSelect:
2572  {
2573  FieldSelect *fs = (FieldSelect *) node;
2574 
2575  APP_JUMB(fs->fieldnum);
2576  JumbleExpr(jstate, (Node *) fs->arg);
2577  }
2578  break;
2579  case T_FieldStore:
2580  {
2581  FieldStore *fstore = (FieldStore *) node;
2582 
2583  JumbleExpr(jstate, (Node *) fstore->arg);
2584  JumbleExpr(jstate, (Node *) fstore->newvals);
2585  }
2586  break;
2587  case T_RelabelType:
2588  {
2589  RelabelType *rt = (RelabelType *) node;
2590 
2591  APP_JUMB(rt->resulttype);
2592  JumbleExpr(jstate, (Node *) rt->arg);
2593  }
2594  break;
2595  case T_CoerceViaIO:
2596  {
2597  CoerceViaIO *cio = (CoerceViaIO *) node;
2598 
2599  APP_JUMB(cio->resulttype);
2600  JumbleExpr(jstate, (Node *) cio->arg);
2601  }
2602  break;
2603  case T_ArrayCoerceExpr:
2604  {
2605  ArrayCoerceExpr *acexpr = (ArrayCoerceExpr *) node;
2606 
2607  APP_JUMB(acexpr->resulttype);
2608  JumbleExpr(jstate, (Node *) acexpr->arg);
2609  JumbleExpr(jstate, (Node *) acexpr->elemexpr);
2610  }
2611  break;
2612  case T_ConvertRowtypeExpr:
2613  {
2614  ConvertRowtypeExpr *crexpr = (ConvertRowtypeExpr *) node;
2615 
2616  APP_JUMB(crexpr->resulttype);
2617  JumbleExpr(jstate, (Node *) crexpr->arg);
2618  }
2619  break;
2620  case T_CollateExpr:
2621  {
2622  CollateExpr *ce = (CollateExpr *) node;
2623 
2624  APP_JUMB(ce->collOid);
2625  JumbleExpr(jstate, (Node *) ce->arg);
2626  }
2627  break;
2628  case T_CaseExpr:
2629  {
2630  CaseExpr *caseexpr = (CaseExpr *) node;
2631 
2632  JumbleExpr(jstate, (Node *) caseexpr->arg);
2633  foreach(temp, caseexpr->args)
2634  {
2635  CaseWhen *when = lfirst_node(CaseWhen, temp);
2636 
2637  JumbleExpr(jstate, (Node *) when->expr);
2638  JumbleExpr(jstate, (Node *) when->result);
2639  }
2640  JumbleExpr(jstate, (Node *) caseexpr->defresult);
2641  }
2642  break;
2643  case T_CaseTestExpr:
2644  {
2645  CaseTestExpr *ct = (CaseTestExpr *) node;
2646 
2647  APP_JUMB(ct->typeId);
2648  }
2649  break;
2650  case T_ArrayExpr:
2651  JumbleExpr(jstate, (Node *) ((ArrayExpr *) node)->elements);
2652  break;
2653  case T_RowExpr:
2654  JumbleExpr(jstate, (Node *) ((RowExpr *) node)->args);
2655  break;
2656  case T_RowCompareExpr:
2657  {
2658  RowCompareExpr *rcexpr = (RowCompareExpr *) node;
2659 
2660  APP_JUMB(rcexpr->rctype);
2661  JumbleExpr(jstate, (Node *) rcexpr->largs);
2662  JumbleExpr(jstate, (Node *) rcexpr->rargs);
2663  }
2664  break;
2665  case T_CoalesceExpr:
2666  JumbleExpr(jstate, (Node *) ((CoalesceExpr *) node)->args);
2667  break;
2668  case T_MinMaxExpr:
2669  {
2670  MinMaxExpr *mmexpr = (MinMaxExpr *) node;
2671 
2672  APP_JUMB(mmexpr->op);
2673  JumbleExpr(jstate, (Node *) mmexpr->args);
2674  }
2675  break;
2676  case T_SQLValueFunction:
2677  {
2678  SQLValueFunction *svf = (SQLValueFunction *) node;
2679 
2680  APP_JUMB(svf->op);
2681  /* type is fully determined by op */
2682  APP_JUMB(svf->typmod);
2683  }
2684  break;
2685  case T_XmlExpr:
2686  {
2687  XmlExpr *xexpr = (XmlExpr *) node;
2688 
2689  APP_JUMB(xexpr->op);
2690  JumbleExpr(jstate, (Node *) xexpr->named_args);
2691  JumbleExpr(jstate, (Node *) xexpr->args);
2692  }
2693  break;
2694  case T_NullTest:
2695  {
2696  NullTest *nt = (NullTest *) node;
2697 
2698  APP_JUMB(nt->nulltesttype);
2699  JumbleExpr(jstate, (Node *) nt->arg);
2700  }
2701  break;
2702  case T_BooleanTest:
2703  {
2704  BooleanTest *bt = (BooleanTest *) node;
2705 
2706  APP_JUMB(bt->booltesttype);
2707  JumbleExpr(jstate, (Node *) bt->arg);
2708  }
2709  break;
2710  case T_CoerceToDomain:
2711  {
2712  CoerceToDomain *cd = (CoerceToDomain *) node;
2713 
2714  APP_JUMB(cd->resulttype);
2715  JumbleExpr(jstate, (Node *) cd->arg);
2716  }
2717  break;
2718  case T_CoerceToDomainValue:
2719  {
2720  CoerceToDomainValue *cdv = (CoerceToDomainValue *) node;
2721 
2722  APP_JUMB(cdv->typeId);
2723  }
2724  break;
2725  case T_SetToDefault:
2726  {
2727  SetToDefault *sd = (SetToDefault *) node;
2728 
2729  APP_JUMB(sd->typeId);
2730  }
2731  break;
2732  case T_CurrentOfExpr:
2733  {
2734  CurrentOfExpr *ce = (CurrentOfExpr *) node;
2735 
2736  APP_JUMB(ce->cvarno);
2737  if (ce->cursor_name)
2739  APP_JUMB(ce->cursor_param);
2740  }
2741  break;
2742  case T_NextValueExpr:
2743  {
2744  NextValueExpr *nve = (NextValueExpr *) node;
2745 
2746  APP_JUMB(nve->seqid);
2747  APP_JUMB(nve->typeId);
2748  }
2749  break;
2750  case T_InferenceElem:
2751  {
2752  InferenceElem *ie = (InferenceElem *) node;
2753 
2754  APP_JUMB(ie->infercollid);
2755  APP_JUMB(ie->inferopclass);
2756  JumbleExpr(jstate, ie->expr);
2757  }
2758  break;
2759  case T_TargetEntry:
2760  {
2761  TargetEntry *tle = (TargetEntry *) node;
2762 
2763  APP_JUMB(tle->resno);
2764  APP_JUMB(tle->ressortgroupref);
2765  JumbleExpr(jstate, (Node *) tle->expr);
2766  }
2767  break;
2768  case T_RangeTblRef:
2769  {
2770  RangeTblRef *rtr = (RangeTblRef *) node;
2771 
2772  APP_JUMB(rtr->rtindex);
2773  }
2774  break;
2775  case T_JoinExpr:
2776  {
2777  JoinExpr *join = (JoinExpr *) node;
2778 
2779  APP_JUMB(join->jointype);
2780  APP_JUMB(join->isNatural);
2781  APP_JUMB(join->rtindex);
2782  JumbleExpr(jstate, join->larg);
2783  JumbleExpr(jstate, join->rarg);
2784  JumbleExpr(jstate, join->quals);
2785  }
2786  break;
2787  case T_FromExpr:
2788  {
2789  FromExpr *from = (FromExpr *) node;
2790 
2791  JumbleExpr(jstate, (Node *) from->fromlist);
2792  JumbleExpr(jstate, from->quals);
2793  }
2794  break;
2795  case T_OnConflictExpr:
2796  {
2797  OnConflictExpr *conf = (OnConflictExpr *) node;
2798 
2799  APP_JUMB(conf->action);
2800  JumbleExpr(jstate, (Node *) conf->arbiterElems);
2801  JumbleExpr(jstate, conf->arbiterWhere);
2802  JumbleExpr(jstate, (Node *) conf->onConflictSet);
2803  JumbleExpr(jstate, conf->onConflictWhere);
2804  APP_JUMB(conf->constraint);
2805  APP_JUMB(conf->exclRelIndex);
2806  JumbleExpr(jstate, (Node *) conf->exclRelTlist);
2807  }
2808  break;
2809  case T_List:
2810  foreach(temp, (List *) node)
2811  {
2812  JumbleExpr(jstate, (Node *) lfirst(temp));
2813  }
2814  break;
2815  case T_IntList:
2816  foreach(temp, (List *) node)
2817  {
2818  APP_JUMB(lfirst_int(temp));
2819  }
2820  break;
2821  case T_SortGroupClause:
2822  {
2823  SortGroupClause *sgc = (SortGroupClause *) node;
2824 
2825  APP_JUMB(sgc->tleSortGroupRef);
2826  APP_JUMB(sgc->eqop);
2827  APP_JUMB(sgc->sortop);
2828  APP_JUMB(sgc->nulls_first);
2829  }
2830  break;
2831  case T_GroupingSet:
2832  {
2833  GroupingSet *gsnode = (GroupingSet *) node;
2834 
2835  JumbleExpr(jstate, (Node *) gsnode->content);
2836  }
2837  break;
2838  case T_WindowClause:
2839  {
2840  WindowClause *wc = (WindowClause *) node;
2841 
2842  APP_JUMB(wc->winref);
2843  APP_JUMB(wc->frameOptions);
2844  JumbleExpr(jstate, (Node *) wc->partitionClause);
2845  JumbleExpr(jstate, (Node *) wc->orderClause);
2846  JumbleExpr(jstate, wc->startOffset);
2847  JumbleExpr(jstate, wc->endOffset);
2848  }
2849  break;
2850  case T_CommonTableExpr:
2851  {
2852  CommonTableExpr *cte = (CommonTableExpr *) node;
2853 
2854  /* we store the string name because RTE_CTE RTEs need it */
2855  APP_JUMB_STRING(cte->ctename);
2856  JumbleQuery(jstate, castNode(Query, cte->ctequery));
2857  }
2858  break;
2859  case T_SetOperationStmt:
2860  {
2861  SetOperationStmt *setop = (SetOperationStmt *) node;
2862 
2863  APP_JUMB(setop->op);
2864  APP_JUMB(setop->all);
2865  JumbleExpr(jstate, setop->larg);
2866  JumbleExpr(jstate, setop->rarg);
2867  }
2868  break;
2869  case T_RangeTblFunction:
2870  {
2871  RangeTblFunction *rtfunc = (RangeTblFunction *) node;
2872 
2873  JumbleExpr(jstate, rtfunc->funcexpr);
2874  }
2875  break;
2876  case T_TableFunc:
2877  {
2878  TableFunc *tablefunc = (TableFunc *) node;
2879 
2880  JumbleExpr(jstate, tablefunc->docexpr);
2881  JumbleExpr(jstate, tablefunc->rowexpr);
2882  JumbleExpr(jstate, (Node *) tablefunc->colexprs);
2883  }
2884  break;
2885  case T_TableSampleClause:
2886  {
2887  TableSampleClause *tsc = (TableSampleClause *) node;
2888 
2889  APP_JUMB(tsc->tsmhandler);
2890  JumbleExpr(jstate, (Node *) tsc->args);
2891  JumbleExpr(jstate, (Node *) tsc->repeatable);
2892  }
2893  break;
2894  default:
2895  /* Only a warning, since we can stumble along anyway */
2896  elog(WARNING, "unrecognized node type: %d",
2897  (int) nodeTag(node));
2898  break;
2899  }
2900 }
List * aggdistinct
Definition: primnodes.h:304
Expr * refassgnexpr
Definition: primnodes.h:411
List * args
Definition: primnodes.h:1075
static void JumbleExpr(pgssJumbleState *jstate, Node *node)
Node * docexpr
Definition: primnodes.h:85
Expr * arg
Definition: primnodes.h:772
Index varlevelsup
Definition: primnodes.h:174
List * content
Definition: parsenodes.h:1277
List * refs
Definition: primnodes.h:344
List * args
Definition: primnodes.h:360
List * args
Definition: primnodes.h:458
#define castNode(_type_, nodeptr)
Definition: nodes.h:586
Oid resulttype
Definition: primnodes.h:816
RowCompareType rctype
Definition: primnodes.h:1039
Index tleSortGroupRef
Definition: parsenodes.h:1207
Expr * arg
Definition: primnodes.h:795
ParamKind paramkind
Definition: primnodes.h:245
Definition: nodes.h:517
List * args
Definition: primnodes.h:302
AttrNumber varattno
Definition: primnodes.h:169
Expr * arg
Definition: primnodes.h:743
List * fromlist
Definition: primnodes.h:1479
Index winref
Definition: primnodes.h:362
Definition: primnodes.h:164
Node * quals
Definition: primnodes.h:1480
SQLValueFunctionOp op
Definition: primnodes.h:1112
#define APP_JUMB_STRING(str)
static void RecordConstLocation(pgssJumbleState *jstate, int location)
List * arbiterElems
Definition: primnodes.h:1498
Node * larg
Definition: primnodes.h:1459
Oid consttype
Definition: primnodes.h:193
Oid funcid
Definition: primnodes.h:450
#define lfirst_int(lc)
Definition: pg_list.h:107
List * partitionClause
Definition: parsenodes.h:1303
BoolExprType boolop
Definition: primnodes.h:563
Expr * arg
Definition: primnodes.h:1188
#define lfirst_node(type, lc)
Definition: pg_list.h:109
#define APP_JUMB(item)
Node * rowexpr
Definition: primnodes.h:86
char * c
NodeTag type
Definition: nodes.h:519
static void JumbleQuery(pgssJumbleState *jstate, Query *query)
List * exclRelTlist
Definition: primnodes.h:1507
List * refupperindexpr
Definition: primnodes.h:404
void check_stack_depth(void)
Definition: postgres.c:3155
List * reflowerindexpr
Definition: primnodes.h:406
List * aggorder
Definition: primnodes.h:303
Expr * arg
Definition: primnodes.h:1211
AttrNumber resno
Definition: primnodes.h:1377
char * cursor_name
Definition: primnodes.h:1286
List * aggdirectargs
Definition: primnodes.h:301
Oid winfnoid
Definition: primnodes.h:356
Expr * arg
Definition: primnodes.h:815
Expr * elemexpr
Definition: primnodes.h:840
Definition: type.h:82
Definition: nodes.h:296
List * newvals
Definition: primnodes.h:773
Definition: nodes.h:148
OnConflictAction action
Definition: primnodes.h:1495
bool isNatural
Definition: primnodes.h:1458
#define WARNING
Definition: elog.h:40
Index varno
Definition: primnodes.h:167
Definition: nodes.h:147
XmlExprOp op
Definition: primnodes.h:1150
Node * startOffset
Definition: parsenodes.h:1306
List * args
Definition: primnodes.h:914
int location
Definition: primnodes.h:204
Node * quals
Definition: primnodes.h:1462
BoolTestType booltesttype
Definition: primnodes.h:1212
Oid resulttype
Definition: primnodes.h:796
NullTestType nulltesttype
Definition: primnodes.h:1189
Oid aggfnoid
Definition: primnodes.h:295
List * colexprs
Definition: primnodes.h:91
List * named_args
Definition: primnodes.h:1152
List * args
Definition: primnodes.h:1154
Node * rarg
Definition: primnodes.h:1460
Expr * arg
Definition: primnodes.h:479
JoinType jointype
Definition: primnodes.h:1457
#define lfirst(lc)
Definition: pg_list.h:106
Expr * aggfilter
Definition: primnodes.h:361
Expr * expr
Definition: primnodes.h:1376
int paramid
Definition: primnodes.h:246
Node * endOffset
Definition: parsenodes.h:1307
Expr * arg
Definition: primnodes.h:881
Expr * aggfilter
Definition: primnodes.h:305
SetOperation op
Definition: parsenodes.h:1599
List * args
Definition: primnodes.h:564
#define nodeTag(nodeptr)
Definition: nodes.h:522
List * orderClause
Definition: parsenodes.h:1304
Node * arbiterWhere
Definition: primnodes.h:1500
List * onConflictSet
Definition: primnodes.h:1504
Index ressortgroupref
Definition: primnodes.h:1379
MinMaxOp op
Definition: primnodes.h:1074
Expr * arg
Definition: primnodes.h:913
Oid opno
Definition: primnodes.h:497
#define elog
Definition: elog.h:219
Expr * result
Definition: primnodes.h:926
List * args
Definition: primnodes.h:503
Expr * defresult
Definition: primnodes.h:915
Expr * expr
Definition: primnodes.h:925
Node * onConflictWhere
Definition: primnodes.h:1505
int rtindex
Definition: primnodes.h:1464
Definition: pg_list.h:45
Oid paramtype
Definition: primnodes.h:247
Expr * refexpr
Definition: primnodes.h:409
Definition: nodes.h:149
AttrNumber fieldnum
Definition: primnodes.h:744

◆ JumbleQuery()

static void JumbleQuery ( pgssJumbleState jstate,
Query query 
)
static

Definition at line 2336 of file pg_stat_statements.c.

References APP_JUMB, Assert, Query::commandType, Query::cteList, Query::distinctClause, Query::groupClause, Query::groupingSets, Query::havingQual, IsA, Query::jointree, JumbleExpr(), JumbleRangeTable(), Query::limitCount, Query::limitOffset, Query::onConflict, Query::returningList, Query::rtable, Query::setOperations, Query::sortClause, Query::targetList, Query::utilityStmt, and Query::windowClause.

Referenced by JumbleExpr(), JumbleRangeTable(), and pgss_post_parse_analyze().

2337 {
2338  Assert(IsA(query, Query));
2339  Assert(query->utilityStmt == NULL);
2340 
2341  APP_JUMB(query->commandType);
2342  /* resultRelation is usually predictable from commandType */
2343  JumbleExpr(jstate, (Node *) query->cteList);
2344  JumbleRangeTable(jstate, query->rtable);
2345  JumbleExpr(jstate, (Node *) query->jointree);
2346  JumbleExpr(jstate, (Node *) query->targetList);
2347  JumbleExpr(jstate, (Node *) query->onConflict);
2348  JumbleExpr(jstate, (Node *) query->returningList);
2349  JumbleExpr(jstate, (Node *) query->groupClause);
2350  JumbleExpr(jstate, (Node *) query->groupingSets);
2351  JumbleExpr(jstate, query->havingQual);
2352  JumbleExpr(jstate, (Node *) query->windowClause);
2353  JumbleExpr(jstate, (Node *) query->distinctClause);
2354  JumbleExpr(jstate, (Node *) query->sortClause);
2355  JumbleExpr(jstate, query->limitOffset);
2356  JumbleExpr(jstate, query->limitCount);
2357  /* we ignore rowMarks */
2358  JumbleExpr(jstate, query->setOperations);
2359 }
Node * limitOffset
Definition: parsenodes.h:160
static void JumbleExpr(pgssJumbleState *jstate, Node *node)
#define IsA(nodeptr, _type_)
Definition: nodes.h:568
List * sortClause
Definition: parsenodes.h:158
FromExpr * jointree
Definition: parsenodes.h:138
OnConflictExpr * onConflict
Definition: parsenodes.h:144
List * groupingSets
Definition: parsenodes.h:150
Definition: nodes.h:517
Node * utilityStmt
Definition: parsenodes.h:120
List * windowClause
Definition: parsenodes.h:154
List * targetList
Definition: parsenodes.h:140
static void JumbleRangeTable(pgssJumbleState *jstate, List *rtable)
List * rtable
Definition: parsenodes.h:137
List * distinctClause
Definition: parsenodes.h:156
#define APP_JUMB(item)
Node * limitCount
Definition: parsenodes.h:161
List * returningList
Definition: parsenodes.h:146
CmdType commandType
Definition: parsenodes.h:112
#define Assert(condition)
Definition: c.h:699
List * cteList
Definition: parsenodes.h:135
Node * setOperations
Definition: parsenodes.h:165
List * groupClause
Definition: parsenodes.h:148
Node * havingQual
Definition: parsenodes.h:152

◆ JumbleRangeTable()

static void JumbleRangeTable ( pgssJumbleState jstate,
List rtable 
)
static

Definition at line 2365 of file pg_stat_statements.c.

References APP_JUMB, APP_JUMB_STRING, RangeTblEntry::ctelevelsup, RangeTblEntry::ctename, elog, RangeTblEntry::enrname, ERROR, RangeTblEntry::functions, RangeTblEntry::jointype, JumbleExpr(), JumbleQuery(), lfirst_node, RangeTblEntry::relid, RTE_CTE, RTE_FUNCTION, RTE_JOIN, RTE_NAMEDTUPLESTORE, RTE_RELATION, RTE_SUBQUERY, RTE_TABLEFUNC, RTE_VALUES, RangeTblEntry::rtekind, RangeTblEntry::subquery, RangeTblEntry::tablefunc, RangeTblEntry::tablesample, and RangeTblEntry::values_lists.

Referenced by JumbleQuery().

2366 {
2367  ListCell *lc;
2368 
2369  foreach(lc, rtable)
2370  {
2372 
2373  APP_JUMB(rte->rtekind);
2374  switch (rte->rtekind)
2375  {
2376  case RTE_RELATION:
2377  APP_JUMB(rte->relid);
2378  JumbleExpr(jstate, (Node *) rte->tablesample);
2379  break;
2380  case RTE_SUBQUERY:
2381  JumbleQuery(jstate, rte->subquery);
2382  break;
2383  case RTE_JOIN:
2384  APP_JUMB(rte->jointype);
2385  break;
2386  case RTE_FUNCTION:
2387  JumbleExpr(jstate, (Node *) rte->functions);
2388  break;
2389  case RTE_TABLEFUNC:
2390  JumbleExpr(jstate, (Node *) rte->tablefunc);
2391  break;
2392  case RTE_VALUES:
2393  JumbleExpr(jstate, (Node *) rte->values_lists);
2394  break;
2395  case RTE_CTE:
2396 
2397  /*
2398  * Depending on the CTE name here isn't ideal, but it's the
2399  * only info we have to identify the referenced WITH item.
2400  */
2401  APP_JUMB_STRING(rte->ctename);
2402  APP_JUMB(rte->ctelevelsup);
2403  break;
2404  case RTE_NAMEDTUPLESTORE:
2405  APP_JUMB_STRING(rte->enrname);
2406  break;
2407  default:
2408  elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
2409  break;
2410  }
2411  }
2412 }
static void JumbleExpr(pgssJumbleState *jstate, Node *node)
Definition: nodes.h:517
List * values_lists
Definition: parsenodes.h:1027
#define APP_JUMB_STRING(str)
#define ERROR
Definition: elog.h:43
TableFunc * tablefunc
Definition: parsenodes.h:1022
#define lfirst_node(type, lc)
Definition: pg_list.h:109
#define APP_JUMB(item)
static void JumbleQuery(pgssJumbleState *jstate, Query *query)
JoinType jointype
Definition: parsenodes.h:1005
char * enrname
Definition: parsenodes.h:1059
List * functions
Definition: parsenodes.h:1016
Index ctelevelsup
Definition: parsenodes.h:1033
RTEKind rtekind
Definition: parsenodes.h:962
char * ctename
Definition: parsenodes.h:1032
Query * subquery
Definition: parsenodes.h:985
#define elog
Definition: elog.h:219
struct TableSampleClause * tablesample
Definition: parsenodes.h:980

◆ need_gc_qtexts()

static bool need_gc_qtexts ( void  )
static

Definition at line 2004 of file pg_stat_statements.c.

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

Referenced by gc_qtexts(), and pgss_store().

2005 {
2006  Size extent;
2007 
2008  /* Read shared extent pointer */
2009  {
2010  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
2011 
2012  SpinLockAcquire(&s->mutex);
2013  extent = s->extent;
2014  SpinLockRelease(&s->mutex);
2015  }
2016 
2017  /* Don't proceed if file does not exceed 512 bytes per possible entry */
2018  if (extent < 512 * pgss_max)
2019  return false;
2020 
2021  /*
2022  * Don't proceed if file is less than about 50% bloat. Nothing can or
2023  * should be done in the event of unusually large query texts accounting
2024  * for file's large size. We go to the trouble of maintaining the mean
2025  * query length in order to prevent garbage collection from thrashing
2026  * uselessly.
2027  */
2028  if (extent < pgss->mean_query_len * pgss_max * 2)
2029  return false;
2030 
2031  return true;
2032 }
static pgssSharedState * pgss
#define SpinLockAcquire(lock)
Definition: spin.h:62
static int pgss_max
#define SpinLockRelease(lock)
Definition: spin.h:64
size_t Size
Definition: c.h:433

◆ PG_FUNCTION_INFO_V1() [1/4]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_reset  )

◆ PG_FUNCTION_INFO_V1() [2/4]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_2  )

◆ PG_FUNCTION_INFO_V1() [3/4]

PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_3  )

◆ PG_FUNCTION_INFO_V1() [4/4]

PG_FUNCTION_INFO_V1 ( pg_stat_statements  )

◆ pg_stat_statements()

Datum pg_stat_statements ( PG_FUNCTION_ARGS  )

Definition at line 1351 of file pg_stat_statements.c.

References pg_stat_statements_internal(), and PGSS_V1_0.

1352 {
1353  /* If it's really API 1.1, we'll figure that out below */
1354  pg_stat_statements_internal(fcinfo, PGSS_V1_0, true);
1355 
1356  return (Datum) 0;
1357 }
static void pg_stat_statements_internal(FunctionCallInfo fcinfo, pgssVersion api_version, bool showtext)
uintptr_t Datum
Definition: postgres.h:365

◆ pg_stat_statements_1_2()

Datum pg_stat_statements_1_2 ( PG_FUNCTION_ARGS  )

Definition at line 1337 of file pg_stat_statements.c.

References PG_GETARG_BOOL, pg_stat_statements_internal(), and PGSS_V1_2.

1338 {
1339  bool showtext = PG_GETARG_BOOL(0);
1340 
1341  pg_stat_statements_internal(fcinfo, PGSS_V1_2, showtext);
1342 
1343  return (Datum) 0;
1344 }
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:244
static void pg_stat_statements_internal(FunctionCallInfo fcinfo, pgssVersion api_version, bool showtext)
uintptr_t Datum
Definition: postgres.h:365

◆ pg_stat_statements_1_3()

Datum pg_stat_statements_1_3 ( PG_FUNCTION_ARGS  )

Definition at line 1327 of file pg_stat_statements.c.

References PG_GETARG_BOOL, pg_stat_statements_internal(), and PGSS_V1_3.

1328 {
1329  bool showtext = PG_GETARG_BOOL(0);
1330 
1331  pg_stat_statements_internal(fcinfo, PGSS_V1_3, showtext);
1332 
1333  return (Datum) 0;
1334 }
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:244
static void pg_stat_statements_internal(FunctionCallInfo fcinfo, pgssVersion api_version, bool showtext)
uintptr_t Datum
Definition: postgres.h:365

◆ pg_stat_statements_internal()

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

Definition at line 1361 of file pg_stat_statements.c.

References ReturnSetInfo::allowedModes, Assert, Counters::blk_read_time, Counters::blk_write_time, Counters::calls, pgssEntry::counters, CStringGetTextDatum, pgssHashKey::dbid, ReturnSetInfo::econtext, ExprContext::ecxt_per_query_memory, elog, enc, pgssEntry::encoding, ereport, errcode(), errmsg(), ERROR, pgssSharedState::extent, Float8GetDatumFast, free, pgssSharedState::gc_count, get_call_result_type(), GetUserId(), hash_seq_init(), hash_seq_search(), i, Int64GetDatumFast, is_member_of_role(), IsA, 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, MemoryContextSwitchTo(), Counters::min_time, pgssEntry::mutex, pgssSharedState::mutex, pgssSharedState::n_writers, 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_2, PG_STAT_STATEMENTS_COLS_V1_3, PGSS_V1_0, PGSS_V1_1, PGSS_V1_2, PGSS_V1_3, qtext_fetch(), qtext_load_file(), pgssEntry::query_len, pgssEntry::query_offset, pgssHashKey::queryid, FunctionCallInfoData::resultinfo, ReturnSetInfo::returnMode, Counters::rows, ReturnSetInfo::setDesc, ReturnSetInfo::setResult, SFRM_Materialize, Counters::shared_blks_dirtied, Counters::shared_blks_hit, Counters::shared_blks_read, Counters::shared_blks_written, SpinLockAcquire, SpinLockRelease, Counters::sum_var_time, Counters::temp_blks_read, Counters::temp_blks_written, Counters::total_time, tuplestore_begin_heap(), tuplestore_donestoring, tuplestore_putvalues(), TYPEFUNC_COMPOSITE, pgssHashKey::userid, values, and work_mem.

Referenced by pg_stat_statements(), pg_stat_statements_1_2(), and pg_stat_statements_1_3().

1364 {
1365  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1366  TupleDesc tupdesc;
1367  Tuplestorestate *tupstore;
1368  MemoryContext per_query_ctx;
1369  MemoryContext oldcontext;
1370  Oid userid = GetUserId();
1371  bool is_allowed_role = false;
1372  char *qbuffer = NULL;
1373  Size qbuffer_size = 0;
1374  Size extent = 0;
1375  int gc_count = 0;
1376  HASH_SEQ_STATUS hash_seq;
1377  pgssEntry *entry;
1378 
1379  /* Superusers or members of pg_read_all_stats members are allowed */
1380  is_allowed_role = is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_STATS);
1381 
1382  /* hash table must exist already */
1383  if (!pgss || !pgss_hash)
1384  ereport(ERROR,
1385  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1386  errmsg("pg_stat_statements must be loaded via shared_preload_libraries")));
1387 
1388  /* check to see if caller supports us returning a tuplestore */
1389  if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
1390  ereport(ERROR,
1391  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1392  errmsg("set-valued function called in context that cannot accept a set")));
1393  if (!(rsinfo->allowedModes & SFRM_Materialize))
1394  ereport(ERROR,
1395  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1396  errmsg("materialize mode required, but it is not " \
1397  "allowed in this context")));
1398 
1399  /* Switch into long-lived context to construct returned data structures */
1400  per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
1401  oldcontext = MemoryContextSwitchTo(per_query_ctx);
1402 
1403  /* Build a tuple descriptor for our result type */
1404  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
1405  elog(ERROR, "return type must be a row type");
1406 
1407  /*
1408  * Check we have the expected number of output arguments. Aside from
1409  * being a good safety check, we need a kluge here to detect API version
1410  * 1.1, which was wedged into the code in an ill-considered way.
1411  */
1412  switch (tupdesc->natts)
1413  {
1415  if (api_version != PGSS_V1_0)
1416  elog(ERROR, "incorrect number of output arguments");
1417  break;
1419  /* pg_stat_statements() should have told us 1.0 */
1420  if (api_version != PGSS_V1_0)
1421  elog(ERROR, "incorrect number of output arguments");
1422  api_version = PGSS_V1_1;
1423  break;
1425  if (api_version != PGSS_V1_2)
1426  elog(ERROR, "incorrect number of output arguments");
1427  break;
1429  if (api_version != PGSS_V1_3)
1430  elog(ERROR, "incorrect number of output arguments");
1431  break;
1432  default:
1433  elog(ERROR, "incorrect number of output arguments");
1434  }
1435 
1436  tupstore = tuplestore_begin_heap(true, false, work_mem);
1437  rsinfo->returnMode = SFRM_Materialize;
1438  rsinfo->setResult = tupstore;
1439  rsinfo->setDesc = tupdesc;
1440 
1441  MemoryContextSwitchTo(oldcontext);
1442 
1443  /*
1444  * We'd like to load the query text file (if needed) while not holding any
1445  * lock on pgss->lock. In the worst case we'll have to do this again
1446  * after we have the lock, but it's unlikely enough to make this a win
1447  * despite occasional duplicated work. We need to reload if anybody
1448  * writes to the file (either a retail qtext_store(), or a garbage
1449  * collection) between this point and where we've gotten shared lock. If
1450  * a qtext_store is actually in progress when we look, we might as well
1451  * skip the speculative load entirely.
1452  */
1453  if (showtext)
1454  {
1455  int n_writers;
1456 
1457  /* Take the mutex so we can examine variables */
1458  {
1459  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
1460 
1461  SpinLockAcquire(&s->mutex);
1462  extent = s->extent;
1463  n_writers = s->n_writers;
1464  gc_count = s->gc_count;
1465  SpinLockRelease(&s->mutex);
1466  }
1467 
1468  /* No point in loading file now if there are active writers */
1469  if (n_writers == 0)
1470  qbuffer = qtext_load_file(&qbuffer_size);
1471  }
1472 
1473  /*
1474  * Get shared lock, load or reload the query text file if we must, and
1475  * iterate over the hashtable entries.
1476  *
1477  * With a large hash table, we might be holding the lock rather longer
1478  * than one could wish. However, this only blocks creation of new hash
1479  * table entries, and the larger the hash table the less likely that is to
1480  * be needed. So we can hope this is okay. Perhaps someday we'll decide
1481  * we need to partition the hash table to limit the time spent holding any
1482  * one lock.
1483  */
1485 
1486  if (showtext)
1487  {
1488  /*
1489  * Here it is safe to examine extent and gc_count without taking the
1490  * mutex. Note that although other processes might change
1491  * pgss->extent just after we look at it, the strings they then write
1492  * into the file cannot yet be referenced in the hashtable, so we
1493  * don't care whether we see them or not.
1494  *
1495  * If qtext_load_file fails, we just press on; we'll return NULL for
1496  * every query text.
1497  */
1498  if (qbuffer == NULL ||
1499  pgss->extent != extent ||
1500  pgss->gc_count != gc_count)
1501  {
1502  if (qbuffer)
1503  free(qbuffer);
1504  qbuffer = qtext_load_file(&qbuffer_size);
1505  }
1506  }
1507 
1508  hash_seq_init(&hash_seq, pgss_hash);
1509  while ((entry = hash_seq_search(&hash_seq)) != NULL)
1510  {
1512  bool nulls[PG_STAT_STATEMENTS_COLS];
1513  int i = 0;
1514  Counters tmp;
1515  double stddev;
1516  int64 queryid = entry->key.queryid;
1517 
1518  memset(values, 0, sizeof(values));
1519  memset(nulls, 0, sizeof(nulls));
1520 
1521  values[i++] = ObjectIdGetDatum(entry->key.userid);
1522  values[i++] = ObjectIdGetDatum(entry->key.dbid);
1523 
1524  if (is_allowed_role || entry->key.userid == userid)
1525  {
1526  if (api_version >= PGSS_V1_2)
1527  values[i++] = Int64GetDatumFast(queryid);
1528 
1529  if (showtext)
1530  {
1531  char *qstr = qtext_fetch(entry->query_offset,
1532  entry->query_len,
1533  qbuffer,
1534  qbuffer_size);
1535 
1536  if (qstr)
1537  {
1538  char *enc;
1539 
1540  enc = pg_any_to_server(qstr,
1541  entry->query_len,
1542  entry->encoding);
1543 
1544  values[i++] = CStringGetTextDatum(enc);
1545 
1546  if (enc != qstr)
1547  pfree(enc);
1548  }
1549  else
1550  {
1551  /* Just return a null if we fail to find the text */
1552  nulls[i++] = true;
1553  }
1554  }
1555  else
1556  {
1557  /* Query text not requested */
1558  nulls[i++] = true;
1559  }
1560  }
1561  else
1562  {
1563  /* Don't show queryid */
1564  if (api_version >= PGSS_V1_2)
1565  nulls[i++] = true;
1566 
1567  /*
1568  * Don't show query text, but hint as to the reason for not doing
1569  * so if it was requested
1570  */
1571  if (showtext)
1572  values[i++] = CStringGetTextDatum("<insufficient privilege>");
1573  else
1574  nulls[i++] = true;
1575  }
1576 
1577  /* copy counters to a local variable to keep locking time short */
1578  {
1579  volatile pgssEntry *e = (volatile pgssEntry *) entry;
1580 
1581  SpinLockAcquire(&e->mutex);
1582  tmp = e->counters;
1583  SpinLockRelease(&e->mutex);
1584  }
1585 
1586  /* Skip entry if unexecuted (ie, it's a pending "sticky" entry) */
1587  if (tmp.calls == 0)
1588  continue;
1589 
1590  values[i++] = Int64GetDatumFast(tmp.calls);
1591  values[i++] = Float8GetDatumFast(tmp.total_time);
1592  if (api_version >= PGSS_V1_3)
1593  {
1594  values[i++] = Float8GetDatumFast(tmp.min_time);
1595  values[i++] = Float8GetDatumFast(tmp.max_time);
1596  values[i++] = Float8GetDatumFast(tmp.mean_time);
1597 
1598  /*
1599  * Note we are calculating the population variance here, not the
1600  * sample variance, as we have data for the whole population, so
1601  * Bessel's correction is not used, and we don't divide by
1602  * tmp.calls - 1.
1603  */
1604  if (tmp.calls > 1)
1605  stddev = sqrt(tmp.sum_var_time / tmp.calls);
1606  else
1607  stddev = 0.0;
1608  values[i++] = Float8GetDatumFast(stddev);
1609  }
1610  values[i++] = Int64GetDatumFast(tmp.rows);
1611  values[i++] = Int64GetDatumFast(tmp.shared_blks_hit);
1612  values[i++] = Int64GetDatumFast(tmp.shared_blks_read);
1613  if (api_version >= PGSS_V1_1)
1614  values[i++] = Int64GetDatumFast(tmp.shared_blks_dirtied);
1615  values[i++] = Int64GetDatumFast(tmp.shared_blks_written);
1616  values[i++] = Int64GetDatumFast(tmp.local_blks_hit);
1617  values[i++] = Int64GetDatumFast(tmp.local_blks_read);
1618  if (api_version >= PGSS_V1_1)
1619  values[i++] = Int64GetDatumFast(tmp.local_blks_dirtied);
1620  values[i++] = Int64GetDatumFast(tmp.local_blks_written);
1621  values[i++] = Int64GetDatumFast(tmp.temp_blks_read);
1622  values[i++] = Int64GetDatumFast(tmp.temp_blks_written);
1623  if (api_version >= PGSS_V1_1)
1624  {
1625  values[i++] = Float8GetDatumFast(tmp.blk_read_time);
1626  values[i++] = Float8GetDatumFast(tmp.blk_write_time);
1627  }
1628 
1629  Assert(i == (api_version == PGSS_V1_0 ? PG_STAT_STATEMENTS_COLS_V1_0 :
1630  api_version == PGSS_V1_1 ? PG_STAT_STATEMENTS_COLS_V1_1 :
1631  api_version == PGSS_V1_2 ? PG_STAT_STATEMENTS_COLS_V1_2 :
1632  api_version == PGSS_V1_3 ? PG_STAT_STATEMENTS_COLS_V1_3 :
1633  -1 /* fail if you forget to update this assert */ ));
1634 
1635  tuplestore_putvalues(tupstore, tupdesc, values, nulls);
1636  }
1637 
1638  /* clean up and return the tuplestore */
1640 
1641  if (qbuffer)
1642  free(qbuffer);
1643 
1644  tuplestore_donestoring(tupstore);
1645 }
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, Datum *values, bool *isnull)
Definition: tuplestore.c:750
#define IsA(nodeptr, _type_)
Definition: nodes.h:568
#define PG_STAT_STATEMENTS_COLS_V1_3
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:211
#define PG_STAT_STATEMENTS_COLS_V1_0
int64 shared_blks_read
int64 local_blks_written
Oid GetUserId(void)
Definition: miscinit.c:379
int64 shared_blks_dirtied
#define tuplestore_donestoring(state)
Definition: tuplestore.h:60
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:575
Counters counters
int64 temp_blks_read
#define PG_STAT_STATEMENTS_COLS_V1_1
unsigned int Oid
Definition: postgres_ext.h:31
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1725
static pgssSharedState * pgss
#define SpinLockAcquire(lock)
Definition: spin.h:62
void pfree(void *pointer)
Definition: mcxt.c:1031
int64 shared_blks_hit
static HTAB * pgss_hash
#define ObjectIdGetDatum(X)
Definition: postgres.h:490
#define ERROR
Definition: elog.h:43
struct pg_encoding enc
Definition: encode.c:522
static char * qtext_load_file(Size *buffer_size)
fmNodePtr resultinfo
Definition: fmgr.h:81
int64 temp_blks_written
int64 shared_blks_written
#define ereport(elevel, rest)
Definition: elog.h:122
#define SpinLockRelease(lock)
Definition: spin.h:64
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
int64 local_blks_read
uintptr_t Datum
Definition: postgres.h:365
double sum_var_time
#define Int64GetDatumFast(X)
Definition: postgres.h:758
int work_mem
Definition: globals.c:122
pgssHashKey key
int allowedModes
Definition: execnodes.h:297
#define PG_STAT_STATEMENTS_COLS
#define free(a)
Definition: header.h:65
bool is_member_of_role(Oid member, Oid role)
Definition: acl.c:4857
#define Float8GetDatumFast(X)
Definition: postgres.h:759
SetFunctionReturnMode returnMode
Definition: execnodes.h:299
double blk_read_time
#define Assert(condition)
Definition: c.h:699
int64 local_blks_dirtied
int64 local_blks_hit
size_t Size
Definition: c.h:433
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1121
double blk_write_time
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:225
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
Tuplestorestate * setResult
Definition: execnodes.h:302
static Datum values[MAXATTR]
Definition: bootstrap.c:164
ExprContext * econtext
Definition: execnodes.h:295
e
Definition: preproc-init.c:82
TupleDesc setDesc
Definition: execnodes.h:303
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
#define CStringGetTextDatum(s)
Definition: builtins.h:95
#define elog
Definition: elog.h:219
char * pg_any_to_server(const char *s, int len, int encoding)
Definition: mbutils.c:561
#define PG_STAT_STATEMENTS_COLS_V1_2
static char * qtext_fetch(Size query_offset, int query_len, char *buffer, Size buffer_size)

◆ pg_stat_statements_reset()

Datum pg_stat_statements_reset ( PG_FUNCTION_ARGS  )

Definition at line 1299 of file pg_stat_statements.c.

References entry_reset(), ereport, errcode(), errmsg(), ERROR, and PG_RETURN_VOID.

1300 {
1301  if (!pgss || !pgss_hash)
1302  ereport(ERROR,
1303  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1304  errmsg("pg_stat_statements must be loaded via shared_preload_libraries")));
1305  entry_reset();
1306  PG_RETURN_VOID();
1307 }
int errcode(int sqlerrcode)
Definition: elog.c:575
static void entry_reset(void)
static pgssSharedState * pgss
static HTAB * pgss_hash
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
#define PG_RETURN_VOID()
Definition: fmgr.h:314
int errmsg(const char *fmt,...)
Definition: elog.c:797

◆ pgss_ExecutorEnd()

static void pgss_ExecutorEnd ( QueryDesc queryDesc)
static

Definition at line 930 of file pg_stat_statements.c.

References Instrumentation::bufusage, EState::es_processed, QueryDesc::estate, InstrEndLoop(), pgss_enabled, pgss_store(), QueryDesc::plannedstmt, prev_ExecutorEnd, PlannedStmt::queryId, QueryDesc::sourceText, standard_ExecutorEnd(), PlannedStmt::stmt_len, PlannedStmt::stmt_location, Instrumentation::total, and QueryDesc::totaltime.

Referenced by _PG_init().

931 {
932  uint64 queryId = queryDesc->plannedstmt->queryId;
933 
934  if (queryId != UINT64CONST(0) && queryDesc->totaltime && pgss_enabled())
935  {
936  /*
937  * Make sure stats accumulation is done. (Note: it's okay if several
938  * levels of hook all do this.)
939  */
940  InstrEndLoop(queryDesc->totaltime);
941 
942  pgss_store(queryDesc->sourceText,
943  queryId,
944  queryDesc->plannedstmt->stmt_location,
945  queryDesc->plannedstmt->stmt_len,
946  queryDesc->totaltime->total * 1000.0, /* convert to msec */
947  queryDesc->estate->es_processed,
948  &queryDesc->totaltime->bufusage,
949  NULL);
950  }
951 
952  if (prev_ExecutorEnd)
953  prev_ExecutorEnd(queryDesc);
954  else
955  standard_ExecutorEnd(queryDesc);
956 }
EState * estate
Definition: execdesc.h:48
static ExecutorEnd_hook_type prev_ExecutorEnd
void standard_ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:470
#define pgss_enabled()
int stmt_len
Definition: plannodes.h:100
void InstrEndLoop(Instrumentation *instr)
Definition: instrument.c:114
int stmt_location
Definition: plannodes.h:99
BufferUsage bufusage
Definition: instrument.h:64
struct Instrumentation * totaltime
Definition: execdesc.h:55
uint64 es_processed
Definition: execnodes.h:529
const char * sourceText
Definition: execdesc.h:38
uint64 queryId
Definition: plannodes.h:47
static void pgss_store(const char *query, uint64 queryId, int query_location, int query_len, double total_time, uint64 rows, const BufferUsage *bufusage, pgssJumbleState *jstate)
PlannedStmt * plannedstmt
Definition: execdesc.h:37

◆ pgss_ExecutorFinish()

static void pgss_ExecutorFinish ( QueryDesc queryDesc)
static

Definition at line 907 of file pg_stat_statements.c.

References nested_level, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, prev_ExecutorFinish, and standard_ExecutorFinish().

Referenced by _PG_init().

908 {
909  nested_level++;
910  PG_TRY();
911  {
913  prev_ExecutorFinish(queryDesc);
914  else
915  standard_ExecutorFinish(queryDesc);
916  nested_level--;
917  }
918  PG_CATCH();
919  {
920  nested_level--;
921  PG_RE_THROW();
922  }
923  PG_END_TRY();
924 }
void standard_ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:410
static ExecutorFinish_hook_type prev_ExecutorFinish
#define PG_CATCH()
Definition: elog.h:293
#define PG_RE_THROW()
Definition: elog.h:314
#define PG_TRY()
Definition: elog.h:284
static int nested_level
#define PG_END_TRY()
Definition: elog.h:300

◆ pgss_ExecutorRun()

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

Definition at line 883 of file pg_stat_statements.c.

References nested_level, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, prev_ExecutorRun, and standard_ExecutorRun().

Referenced by _PG_init().

885 {
886  nested_level++;
887  PG_TRY();
888  {
889  if (prev_ExecutorRun)
890  prev_ExecutorRun(queryDesc, direction, count, execute_once);
891  else
892  standard_ExecutorRun(queryDesc, direction, count, execute_once);
893  nested_level--;
894  }
895  PG_CATCH();
896  {
897  nested_level--;
898  PG_RE_THROW();
899  }
900  PG_END_TRY();
901 }
void standard_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: execMain.c:310
static ExecutorRun_hook_type prev_ExecutorRun
#define PG_CATCH()
Definition: elog.h:293
#define PG_RE_THROW()
Definition: elog.h:314
#define PG_TRY()
Definition: elog.h:284
static int nested_level
#define PG_END_TRY()
Definition: elog.h:300

◆ pgss_ExecutorStart()

static void pgss_ExecutorStart ( QueryDesc queryDesc,
int  eflags 
)
static

Definition at line 849 of file pg_stat_statements.c.

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

Referenced by _PG_init().

850 {
851  if (prev_ExecutorStart)
852  prev_ExecutorStart(queryDesc, eflags);
853  else
854  standard_ExecutorStart(queryDesc, eflags);
855 
856  /*
857  * If query has queryId zero, don't track it. This prevents double
858  * counting of optimizable statements that are directly contained in
859  * utility statements.
860  */
861  if (pgss_enabled() && queryDesc->plannedstmt->queryId != UINT64CONST(0))
862  {
863  /*
864  * Set up to track total elapsed time in ExecutorRun. Make sure the
865  * space is allocated in the per-query context so it will go away at
866  * ExecutorEnd.
867  */
868  if (queryDesc->totaltime == NULL)
869  {
870  MemoryContext oldcxt;
871 
872  oldcxt = MemoryContextSwitchTo(queryDesc->estate->es_query_cxt);
873  queryDesc->totaltime = InstrAlloc(1, INSTRUMENT_ALL);
874  MemoryContextSwitchTo(oldcxt);
875  }
876  }
877 }
EState * estate
Definition: execdesc.h:48
void standard_ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:150
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Instrumentation * InstrAlloc(int n, int instrument_options)
Definition: instrument.c:30
static ExecutorStart_hook_type prev_ExecutorStart
#define pgss_enabled()
MemoryContext es_query_cxt
Definition: execnodes.h:523
struct Instrumentation * totaltime
Definition: execdesc.h:55
uint64 queryId
Definition: plannodes.h:47
PlannedStmt * plannedstmt
Definition: execdesc.h:37

◆ pgss_hash_string()

static uint64 pgss_hash_string ( const char *  str,
int  len 
)
static

Definition at line 1081 of file pg_stat_statements.c.

References DatumGetUInt64, and hash_any_extended().

Referenced by pgss_store().

1082 {
1083  return DatumGetUInt64(hash_any_extended((const unsigned char *) str,
1084  len, 0));
1085 }
#define DatumGetUInt64(X)
Definition: postgres.h:617
Datum hash_any_extended(register const unsigned char *k, register int keylen, uint64 seed)
Definition: hashfunc.c:634

◆ pgss_memsize()

static Size pgss_memsize ( void  )
static

Definition at line 1651 of file pg_stat_statements.c.

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

Referenced by _PG_init().

1652 {
1653  Size size;
1654 
1655  size = MAXALIGN(sizeof(pgssSharedState));
1656  size = add_size(size, hash_estimate_size(pgss_max, sizeof(pgssEntry)));
1657 
1658  return size;
1659 }
static int pgss_max
Size hash_estimate_size(long num_entries, Size entrysize)
Definition: dynahash.c:732
Size add_size(Size s1, Size s2)
Definition: shmem.c:475
size_t Size
Definition: c.h:433
#define MAXALIGN(LEN)
Definition: c.h:652

◆ pgss_post_parse_analyze()

static void pgss_post_parse_analyze ( ParseState pstate,
Query query 
)
static

Definition at line 778 of file pg_stat_statements.c.

References Assert, pgssJumbleState::clocations, pgssJumbleState::clocations_buf_size, pgssJumbleState::clocations_count, DatumGetUInt64, hash_any_extended(), pgssJumbleState::highest_extern_param_id, pgssJumbleState::jumble, pgssJumbleState::jumble_len, JUMBLE_SIZE, JumbleQuery(), ParseState::p_sourcetext, palloc(), pgss_store(), prev_post_parse_analyze_hook, Query::queryId, Query::stmt_len, Query::stmt_location, and Query::utilityStmt.

Referenced by _PG_init().

779 {
780  pgssJumbleState jstate;
781 
783  prev_post_parse_analyze_hook(pstate, query);
784 
785  /* Assert we didn't do this already */
786  Assert(query->queryId == UINT64CONST(0));
787 
788  /* Safety check... */
789  if (!pgss || !pgss_hash)
790  return;
791 
792  /*
793  * Utility statements get queryId zero. We do this even in cases where
794  * the statement contains an optimizable statement for which a queryId
795  * could be derived (such as EXPLAIN or DECLARE CURSOR). For such cases,
796  * runtime control will first go through ProcessUtility and then the
797  * executor, and we don't want the executor hooks to do anything, since we
798  * are already measuring the statement's costs at the utility level.
799  */
800  if (query->utilityStmt)
801  {
802  query->queryId = UINT64CONST(0);
803  return;
804  }
805 
806  /* Set up workspace for query jumbling */
807  jstate.jumble = (unsigned char *) palloc(JUMBLE_SIZE);
808  jstate.jumble_len = 0;
809  jstate.clocations_buf_size = 32;
810  jstate.clocations = (pgssLocationLen *)
811  palloc(jstate.clocations_buf_size * sizeof(pgssLocationLen));
812  jstate.clocations_count = 0;
813  jstate.highest_extern_param_id = 0;
814 
815  /* Compute query ID and mark the Query node with it */
816  JumbleQuery(&jstate, query);
817  query->queryId =
819 
820  /*
821  * If we are unlucky enough to get a hash of zero, use 1 instead, to
822  * prevent confusion with the utility-statement case.
823  */
824  if (query->queryId == UINT64CONST(0))
825  query->queryId = UINT64CONST(1);
826 
827  /*
828  * If we were able to identify any ignorable constants, we immediately
829  * create a hash table entry for the query, so that we can record the
830  * normalized form of the query string. If there were no such constants,
831  * the normalized string would be the same as the query text anyway, so
832  * there's no need for an early entry.
833  */
834  if (jstate.clocations_count > 0)
835  pgss_store(pstate->p_sourcetext,
836  query->queryId,
837  query->stmt_location,
838  query->stmt_len,
839  0,
840  0,
841  NULL,
842  &jstate);
843 }
int stmt_location
Definition: parsenodes.h:181
unsigned char * jumble
#define JUMBLE_SIZE
Node * utilityStmt
Definition: parsenodes.h:120
static post_parse_analyze_hook_type prev_post_parse_analyze_hook
static pgssSharedState * pgss
pgssLocationLen * clocations
static HTAB * pgss_hash
static void JumbleQuery(pgssJumbleState *jstate, Query *query)
const char * p_sourcetext
Definition: parse_node.h:173
uint64 queryId
Definition: parsenodes.h:116
#define DatumGetUInt64(X)
Definition: postgres.h:617
#define Assert(condition)
Definition: c.h:699
void * palloc(Size size)
Definition: mcxt.c:924
static void pgss_store(const char *query, uint64 queryId, int query_location, int query_len, double total_time, uint64 rows, const BufferUsage *bufusage, pgssJumbleState *jstate)
int stmt_len
Definition: parsenodes.h:182
Datum hash_any_extended(register const unsigned char *k, register int keylen, uint64 seed)
Definition: hashfunc.c:634

◆ pgss_ProcessUtility()

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

Definition at line 962 of file pg_stat_statements.c.

References BufferUsage::blk_read_time, BufferUsage::blk_write_time, duration, INSTR_TIME_GET_MILLISEC, INSTR_TIME_SET_CURRENT, INSTR_TIME_SUBTRACT, IsA, BufferUsage::local_blks_dirtied, BufferUsage::local_blks_hit, BufferUsage::local_blks_read, BufferUsage::local_blks_written, nested_level, PG_CATCH, PG_END_TRY, PG_RE_THROW, pg_strtouint64(), PG_TRY, pgBufferUsage, pgss_enabled, pgss_store(), pgss_track_utility, prev_ProcessUtility, BufferUsage::shared_blks_dirtied, BufferUsage::shared_blks_hit, BufferUsage::shared_blks_read, BufferUsage::shared_blks_written, standard_ProcessUtility(), PlannedStmt::stmt_len, PlannedStmt::stmt_location, BufferUsage::temp_blks_read, BufferUsage::temp_blks_written, and PlannedStmt::utilityStmt.

Referenced by _PG_init().

966 {
967  Node *parsetree = pstmt->utilityStmt;
968 
969  /*
970  * If it's an EXECUTE statement, we don't track it and don't increment the
971  * nesting level. This allows the cycles to be charged to the underlying
972  * PREPARE instead (by the Executor hooks), which is much more useful.
973  *
974  * We also don't track execution of PREPARE. If we did, we would get one
975  * hash table entry for the PREPARE (with hash calculated from the query
976  * string), and then a different one with the same query string (but hash
977  * calculated from the query tree) would be used to accumulate costs of
978  * ensuing EXECUTEs. This would be confusing, and inconsistent with other
979  * cases where planning time is not included at all.
980  *
981  * Likewise, we don't track execution of DEALLOCATE.
982  */
983  if (pgss_track_utility && pgss_enabled() &&
984  !IsA(parsetree, ExecuteStmt) &&
985  !IsA(parsetree, PrepareStmt) &&
986  !IsA(parsetree, DeallocateStmt))
987  {
988  instr_time start;
990  uint64 rows;
991  BufferUsage bufusage_start,
992  bufusage;
993 
994  bufusage_start = pgBufferUsage;
995  INSTR_TIME_SET_CURRENT(start);
996 
997  nested_level++;
998  PG_TRY();
999  {
1000  if (prev_ProcessUtility)
1001  prev_ProcessUtility(pstmt, queryString,
1002  context, params, queryEnv,
1003  dest, completionTag);
1004  else
1005  standard_ProcessUtility(pstmt, queryString,
1006  context, params, queryEnv,
1007  dest, completionTag);
1008  nested_level--;
1009  }
1010  PG_CATCH();
1011  {
1012  nested_level--;
1013  PG_RE_THROW();
1014  }
1015  PG_END_TRY();
1016 
1017  INSTR_TIME_SET_CURRENT(duration);
1018  INSTR_TIME_SUBTRACT(duration, start);
1019 
1020  /* parse command tag to retrieve the number of affected rows. */
1021  if (completionTag &&
1022  strncmp(completionTag, "COPY ", 5) == 0)
1023  rows = pg_strtouint64(completionTag + 5, NULL, 10);
1024  else
1025  rows = 0;
1026 
1027  /* calc differences of buffer counters. */
1028  bufusage.shared_blks_hit =
1030  bufusage.shared_blks_read =
1032  bufusage.shared_blks_dirtied =
1034  bufusage.shared_blks_written =
1036  bufusage.local_blks_hit =
1037  pgBufferUsage.local_blks_hit - bufusage_start.local_blks_hit;
1038  bufusage.local_blks_read =
1040  bufusage.local_blks_dirtied =
1042  bufusage.local_blks_written =
1044  bufusage.temp_blks_read =
1045  pgBufferUsage.temp_blks_read - bufusage_start.temp_blks_read;
1046  bufusage.temp_blks_written =
1049  INSTR_TIME_SUBTRACT(bufusage.blk_read_time, bufusage_start.blk_read_time);
1051  INSTR_TIME_SUBTRACT(bufusage.blk_write_time, bufusage_start.blk_write_time);
1052 
1053  pgss_store(queryString,
1054  0, /* signal that it's a utility stmt */
1055  pstmt->stmt_location,
1056  pstmt->stmt_len,
1057  INSTR_TIME_GET_MILLISEC(duration),
1058  rows,
1059  &bufusage,
1060  NULL);
1061  }
1062  else
1063  {
1064  if (prev_ProcessUtility)
1065  prev_ProcessUtility(pstmt, queryString,
1066  context, params, queryEnv,
1067  dest, completionTag);
1068  else
1069  standard_ProcessUtility(pstmt, queryString,
1070  context, params, queryEnv,
1071  dest, completionTag);
1072  }
1073 }
long local_blks_hit
Definition: instrument.h:25
#define IsA(nodeptr, _type_)
Definition: nodes.h:568
long local_blks_dirtied
Definition: instrument.h:27
long local_blks_read
Definition: instrument.h:26
instr_time blk_read_time
Definition: instrument.h:31
static ProcessUtility_hook_type prev_ProcessUtility
#define INSTR_TIME_GET_MILLISEC(t)
Definition: instr_time.h:199
struct timeval instr_time
Definition: instr_time.h:147
long shared_blks_read
Definition: instrument.h:22
Definition: nodes.h:517
#define pgss_enabled()
long temp_blks_written
Definition: instrument.h:30
int stmt_len
Definition: plannodes.h:100
int duration
Definition: pgbench.c:113
long shared_blks_written
Definition: instrument.h:24
void standard_ProcessUtility(PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, char *completionTag)
Definition: utility.c:376
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:167
int stmt_location
Definition: plannodes.h:99
Node * utilityStmt
Definition: plannodes.h:96
long shared_blks_dirtied
Definition: instrument.h:23
long temp_blks_read
Definition: instrument.h:29
uint64 pg_strtouint64(const char *str, char **endptr, int base)
Definition: numutils.c:405
#define PG_CATCH()
Definition: elog.h:293
static bool pgss_track_utility
instr_time blk_write_time
Definition: instrument.h:32
#define PG_RE_THROW()
Definition: elog.h:314
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:153
static void pgss_store(const char *query, uint64 queryId, int query_location, int query_len, double total_time, uint64 rows, const BufferUsage *bufusage, pgssJumbleState *jstate)
long shared_blks_hit
Definition: instrument.h:21
long local_blks_written
Definition: instrument.h:28
#define PG_TRY()
Definition: elog.h:284
static int nested_level
#define PG_END_TRY()
Definition: elog.h:300
BufferUsage pgBufferUsage
Definition: instrument.c:20

◆ pgss_shmem_shutdown()

static void pgss_shmem_shutdown ( int  code,
Datum  arg 
)
static

Definition at line 682 of file pg_stat_statements.c.

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(), LOG, PG_BINARY_W, PGSS_DUMP_FILE, PGSS_FILE_HEADER, PGSS_PG_MAJOR_VERSION, pgss_save, PGSS_TEXT_FILE, qtext_fetch(), qtext_load_file(), pgssEntry::query_len, and pgssEntry::query_offset.

Referenced by pgss_shmem_startup().

683 {
684  FILE *file;
685  char *qbuffer = NULL;
686  Size qbuffer_size = 0;
687  HASH_SEQ_STATUS hash_seq;
688  int32 num_entries;
689  pgssEntry *entry;
690 
691  /* Don't try to dump during a crash. */
692  if (code)
693  return;
694 
695  /* Safety check ... shouldn't get here unless shmem is set up. */
696  if (!pgss || !pgss_hash)
697  return;
698 
699  /* Don't dump if told not to. */
700  if (!pgss_save)
701  return;
702 
703  file = AllocateFile(PGSS_DUMP_FILE ".tmp", PG_BINARY_W);
704  if (file == NULL)
705  goto error;
706 
707  if (fwrite(&PGSS_FILE_HEADER, sizeof(uint32), 1, file) != 1)
708  goto error;
709  if (fwrite(&PGSS_PG_MAJOR_VERSION, sizeof(uint32), 1, file) != 1)
710  goto error;
711  num_entries = hash_get_num_entries(pgss_hash);
712  if (fwrite(&num_entries, sizeof(int32), 1, file) != 1)
713  goto error;
714 
715  qbuffer = qtext_load_file(&qbuffer_size);
716  if (qbuffer == NULL)
717  goto error;
718 
719  /*
720  * When serializing to disk, we store query texts immediately after their
721  * entry data. Any orphaned query texts are thereby excluded.
722  */
723  hash_seq_init(&hash_seq, pgss_hash);
724  while ((entry = hash_seq_search(&hash_seq)) != NULL)
725  {
726  int len = entry->query_len;
727  char *qstr = qtext_fetch(entry->query_offset, len,
728  qbuffer, qbuffer_size);
729 
730  if (qstr == NULL)
731  continue; /* Ignore any entries with bogus texts */
732 
733  if (fwrite(entry, sizeof(pgssEntry), 1, file) != 1 ||
734  fwrite(qstr, 1, len + 1, file) != len + 1)
735  {
736  /* note: we assume hash_seq_term won't change errno */
737  hash_seq_term(&hash_seq);
738  goto error;
739  }
740  }
741 
742  free(qbuffer);
743  qbuffer = NULL;
744 
745  if (FreeFile(file))
746  {
747  file = NULL;
748  goto error;
749  }
750 
751  /*
752  * Rename file into place, so we atomically replace any old one.
753  */
755 
756  /* Unlink query-texts file; it's not needed while shutdown */
757  unlink(PGSS_TEXT_FILE);
758 
759  return;
760 
761 error:
762  ereport(LOG,
764  errmsg("could not write pg_stat_statement file \"%s\": %m",
765  PGSS_DUMP_FILE ".tmp")));
766  if (qbuffer)
767  free(qbuffer);
768  if (file)
769  FreeFile(file);
770  unlink(PGSS_DUMP_FILE ".tmp");
771  unlink(PGSS_TEXT_FILE);
772 }
static void error(void)
Definition: sql-dyntest.c:147
static const uint32 PGSS_PG_MAJOR_VERSION
#define PGSS_DUMP_FILE
#define PG_BINARY_W
Definition: c.h:1083
long hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1335
#define LOG
Definition: elog.h:26
signed int int32
Definition: c.h:313
static pgssSharedState * pgss
static HTAB * pgss_hash
int errcode_for_file_access(void)
Definition: elog.c:598
static char * qtext_load_file(Size *buffer_size)
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2346
unsigned int uint32
Definition: c.h:325
#define ereport(elevel, rest)
Definition: elog.h:122
int durable_rename(const char *oldfile, const char *newfile, int elevel)
Definition: fd.c:601
#define free(a)
Definition: header.h:65
size_t Size
Definition: c.h:433
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
int FreeFile(FILE *file)
Definition: fd.c:2538
int errmsg(const char *fmt,...)
Definition: elog.c:797
static const uint32 PGSS_FILE_HEADER
#define PGSS_TEXT_FILE
void hash_seq_term(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1465
static bool pgss_save
static char * qtext_fetch(Size query_offset, int query_len, char *buffer, Size buffer_size)

◆ pgss_shmem_startup()

static void pgss_shmem_startup ( void  )
static

Definition at line 463 of file pg_stat_statements.c.

References AllocateFile(), ASSUMED_LENGTH_INIT, ASSUMED_MEDIAN_INIT, buffer, Counters::calls, pgssEntry::counters, pgssSharedState::cur_median_usage, pgssEntry::encoding, entry_alloc(), HASHCTL::entrysize, ereport, errcode(), errcode_for_file_access(), errmsg(), pgssSharedState::extent, FreeFile(), pgssSharedState::gc_count, GetNamedLWLockTranche(), HASH_BLOBS, HASH_ELEM, header(), i, 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_DUMP_FILE, PGSS_FILE_HEADER, pgss_max, PGSS_PG_MAJOR_VERSION, pgss_save, pgss_shmem_shutdown(), PGSS_TEXT_FILE, prev_shmem_startup_hook, pgssEntry::query_len, repalloc(), ShmemInitHash(), ShmemInitStruct(), and SpinLockInit.

Referenced by _PG_init().

464 {
465  bool found;
466  HASHCTL info;
467  FILE *file = NULL;
468  FILE *qfile = NULL;
469  uint32 header;
470  int32 num;
471  int32 pgver;
472  int32 i;
473  int buffer_size;
474  char *buffer = NULL;
475 
478 
479  /* reset in case this is a restart within the postmaster */
480  pgss = NULL;
481  pgss_hash = NULL;
482 
483  /*
484  * Create or attach to the shared memory state, including hash table
485  */
486  LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE);
487 
488  pgss = ShmemInitStruct("pg_stat_statements",
489  sizeof(pgssSharedState),
490  &found);
491 
492  if (!found)
493  {
494  /* First time through ... */
495  pgss->lock = &(GetNamedLWLockTranche("pg_stat_statements"))->lock;
499  pgss->extent = 0;
500  pgss->n_writers = 0;
501  pgss->gc_count = 0;
502  }
503 
504  memset(&info, 0, sizeof(info));
505  info.keysize = sizeof(pgssHashKey);
506  info.entrysize = sizeof(pgssEntry);
507  pgss_hash = ShmemInitHash("pg_stat_statements hash",
509  &info,
511 
512  LWLockRelease(AddinShmemInitLock);
513 
514  /*
515  * If we're in the postmaster (or a standalone backend...), set up a shmem
516  * exit hook to dump the statistics to disk.
517  */
518  if (!IsUnderPostmaster)
520 
521  /*
522  * Done if some other process already completed our initialization.
523  */
524  if (found)
525  return;
526 
527  /*
528  * Note: we don't bother with locks here, because there should be no other
529  * processes running when this code is reached.
530  */
531 
532  /* Unlink query text file possibly left over from crash */
533  unlink(PGSS_TEXT_FILE);
534 
535  /* Allocate new query text temp file */
537  if (qfile == NULL)
538  goto write_error;
539 
540  /*
541  * If we were told not to load old statistics, we're done. (Note we do
542  * not try to unlink any old dump file in this case. This seems a bit
543  * questionable but it's the historical behavior.)
544  */
545  if (!pgss_save)
546  {
547  FreeFile(qfile);
548  return;
549  }
550 
551  /*
552  * Attempt to load old statistics from the dump file.
553  */
555  if (file == NULL)
556  {
557  if (errno != ENOENT)
558  goto read_error;
559  /* No existing persisted stats file, so we're done */
560  FreeFile(qfile);
561  return;
562  }
563 
564  buffer_size = 2048;
565  buffer = (char *) palloc(buffer_size);
566 
567  if (fread(&header, sizeof(uint32), 1, file) != 1 ||
568  fread(&pgver, sizeof(uint32), 1, file) != 1 ||
569  fread(&num, sizeof(int32), 1, file) != 1)
570  goto read_error;
571 
572  if (header != PGSS_FILE_HEADER ||
573  pgver != PGSS_PG_MAJOR_VERSION)
574  goto data_error;
575 
576  for (i = 0; i < num; i++)
577  {
578  pgssEntry temp;
579  pgssEntry *entry;
580  Size query_offset;
581 
582  if (fread(&temp, sizeof(pgssEntry), 1, file) != 1)
583  goto read_error;
584 
585  /* Encoding is the only field we can easily sanity-check */
586  if (!PG_VALID_BE_ENCODING(temp.encoding))
587  goto data_error;
588 
589  /* Resize buffer as needed */
590  if (temp.query_len >= buffer_size)
591  {
592  buffer_size = Max(buffer_size * 2, temp.query_len + 1);
593  buffer = repalloc(buffer, buffer_size);
594  }
595 
596  if (fread(buffer, 1, temp.query_len + 1, file) != temp.query_len + 1)
597  goto read_error;
598 
599  /* Should have a trailing null, but let's make sure */
600  buffer[temp.query_len] = '\0';
601 
602  /* Skip loading "sticky" entries */
603  if (temp.counters.calls == 0)
604  continue;
605 
606  /* Store the query text */
607  query_offset = pgss->extent;
608  if (fwrite(buffer, 1, temp.query_len + 1, qfile) != temp.query_len + 1)
609  goto write_error;
610  pgss->extent += temp.query_len + 1;
611 
612  /* make the hashtable entry (discards old entries if too many) */
613  entry = entry_alloc(&temp.key, query_offset, temp.query_len,
614  temp.encoding,
615  false);
616 
617  /* copy in the actual stats */
618  entry->counters = temp.counters;
619  }
620 
621  pfree(buffer);
622  FreeFile(file);
623  FreeFile(qfile);
624 
625  /*
626  * Remove the persisted stats file so it's not included in
627  * backups/replication slaves, etc. A new file will be written on next
628  * shutdown.
629  *
630  * Note: it's okay if the PGSS_TEXT_FILE is included in a basebackup,
631  * because we remove that file on startup; it acts inversely to
632  * PGSS_DUMP_FILE, in that it is only supposed to be around when the
633  * server is running, whereas PGSS_DUMP_FILE is only supposed to be around
634  * when the server is not running. Leaving the file creates no danger of
635  * a newly restored database having a spurious record of execution costs,
636  * which is what we're really concerned about here.
637  */
638  unlink(PGSS_DUMP_FILE);
639 
640  return;
641 
642 read_error:
643  ereport(LOG,
645  errmsg("could not read pg_stat_statement file \"%s\": %m",
646  PGSS_DUMP_FILE)));
647  goto fail;
648 data_error:
649  ereport(LOG,
650  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
651  errmsg("ignoring invalid data in pg_stat_statement file \"%s\"",
652  PGSS_DUMP_FILE)));
653  goto fail;
654 write_error:
655  ereport(LOG,
657  errmsg("could not write pg_stat_statement file \"%s\": %m",
658  PGSS_TEXT_FILE)));
659 fail:
660  if (buffer)
661  pfree(buffer);
662  if (file)
663  FreeFile(file);
664  if (qfile)
665  FreeFile(qfile);
666  /* If possible, throw away the bogus file; ignore any error */
667  unlink(PGSS_DUMP_FILE);
668 
669  /*
670  * Don't unlink PGSS_TEXT_FILE here; it should always be around while the
671  * server is running with pg_stat_statements enabled
672  */
673 }
#define HASH_ELEM
Definition: hsearch.h:87
static const uint32 PGSS_PG_MAJOR_VERSION
#define SpinLockInit(lock)
Definition: spin.h:60
Size entrysize
Definition: hsearch.h:73
#define PGSS_DUMP_FILE
int errcode(int sqlerrcode)
Definition: elog.c:575
struct pgssEntry pgssEntry
#define PG_BINARY_W
Definition: c.h:1083
Counters counters
#define LOG
Definition: elog.h:26
#define PG_BINARY_R
Definition: c.h:1082
signed int int32
Definition: c.h:313
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1725
#define ASSUMED_LENGTH_INIT
static pgssSharedState * pgss
void pfree(void *pointer)
Definition: mcxt.c:1031
static int pgss_max
static HTAB * pgss_hash
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:372
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:359
bool IsUnderPostmaster
Definition: globals.c:110
static pgssEntry * entry_alloc(pgssHashKey *key, Size query_offset, int query_len, int encoding, bool sticky)
int errcode_for_file_access(void)
Definition: elog.c:598
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2346
unsigned int uint32
Definition: c.h:325
#define ereport(elevel, rest)
Definition: elog.h:122
#define HASH_BLOBS
Definition: hsearch.h:88
uintptr_t Datum
Definition: postgres.h:365
static void pgss_shmem_shutdown(int code, Datum arg)
Size keysize
Definition: hsearch.h:72
pgssHashKey key
#define Max(x, y)
Definition: c.h:851
#define PG_VALID_BE_ENCODING(_enc)
Definition: pg_wchar.h:295
LWLockPadded * GetNamedLWLockTranche(const char *tranche_name)
Definition: lwlock.c:551
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215
size_t Size
Definition: c.h:433
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1121
static void header(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:208
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1044
static shmem_startup_hook_type prev_shmem_startup_hook
int FreeFile(FILE *file)
Definition: fd.c:2538
void * palloc(Size size)
Definition: mcxt.c:924
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
static const uint32 PGSS_FILE_HEADER
HTAB * ShmemInitHash(const char *name, long init_size, long max_size, HASHCTL *infoP, int hash_flags)
Definition: shmem.c:317
struct pgssHashKey pgssHashKey
#define PGSS_TEXT_FILE
#define ASSUMED_MEDIAN_INIT
static bool pgss_save

◆ pgss_store()

static void pgss_store ( const char *  query,
uint64  queryId,
int  query_location,
int  query_len,
double  total_time,
uint64  rows,
const BufferUsage bufusage,
pgssJumbleState jstate 
)
static

Definition at line 1098 of file pg_stat_statements.c.

References Assert, BufferUsage::blk_read_time, Counters::blk_read_time, BufferUsage::blk_write_time, Counters::blk_write_time, Counters::calls, pgssEntry::counters, pgssHashKey::dbid, encoding, entry_alloc(), pgssSharedState::gc_count, gc_qtexts(), generate_normalized_query(), GetDatabaseEncoding(), GetUserId(), HASH_FIND, hash_search(), INSTR_TIME_GET_MILLISEC, BufferUsage::local_blks_dirtied, Counters::local_blks_dirtied, BufferUsage::local_blks_hit, Counters::local_blks_hit, BufferUsage::local_blks_read, Counters::local_blks_read, BufferUsage::local_blks_written, Counters::local_blks_written, pgssSharedState::lock, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), Counters::max_time, Counters::mean_time, Counters::min_time, pgssEntry::mutex, MyDatabaseId, need_gc_qtexts(), pfree(), pgss_hash_string(), qtext_store(), pgssHashKey::queryid, Counters::rows, scanner_isspace(), BufferUsage::shared_blks_dirtied, Counters::shared_blks_dirtied, BufferUsage::shared_blks_hit, Counters::shared_blks_hit, BufferUsage::shared_blks_read, Counters::shared_blks_read, BufferUsage::shared_blks_written, Counters::shared_blks_written, SpinLockAcquire, SpinLockRelease, Counters::sum_var_time, BufferUsage::temp_blks_read, Counters::temp_blks_read, BufferUsage::temp_blks_written, Counters::temp_blks_written, Counters::total_time, Counters::usage, USAGE_EXEC, USAGE_INIT, and pgssHashKey::userid.

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

1103 {
1104  pgssHashKey key;
1105  pgssEntry *entry;
1106  char *norm_query = NULL;
1107  int encoding = GetDatabaseEncoding();
1108 
1109  Assert(query != NULL);
1110 
1111  /* Safety check... */
1112  if (!pgss || !pgss_hash)
1113  return;
1114 
1115  /*
1116  * Confine our attention to the relevant part of the string, if the query
1117  * is a portion of a multi-statement source string.
1118  *
1119  * First apply starting offset, unless it's -1 (unknown).
1120  */
1121  if (query_location >= 0)
1122  {
1123  Assert(query_location <= strlen(query));
1124  query += query_location;
1125  /* Length of 0 (or -1) means "rest of string" */
1126  if (query_len <= 0)
1127  query_len = strlen(query);
1128  else
1129  Assert(query_len <= strlen(query));
1130  }
1131  else
1132  {
1133  /* If query location is unknown, distrust query_len as well */
1134  query_location = 0;
1135  query_len = strlen(query);
1136  }
1137 
1138  /*
1139  * Discard leading and trailing whitespace, too. Use scanner_isspace()
1140  * not libc's isspace(), because we want to match the lexer's behavior.
1141  */
1142  while (query_len > 0 && scanner_isspace(query[0]))
1143  query++, query_location++, query_len--;
1144  while (query_len > 0 && scanner_isspace(query[query_len - 1]))
1145  query_len--;
1146 
1147  /*
1148  * For utility statements, we just hash the query string to get an ID.
1149  */
1150  if (queryId == UINT64CONST(0))
1151  queryId = pgss_hash_string(query, query_len);
1152 
1153  /* Set up key for hashtable search */
1154  key.userid = GetUserId();
1155  key.dbid = MyDatabaseId;
1156  key.queryid = queryId;
1157 
1158  /* Lookup the hash table entry with shared lock. */
1160 
1161  entry = (pgssEntry *) hash_search(pgss_hash, &key, HASH_FIND, NULL);
1162 
1163  /* Create new entry, if not present */
1164  if (!entry)
1165  {
1166  Size query_offset;
1167  int gc_count;
1168  bool stored;
1169  bool do_gc;
1170 
1171  /*
1172  * Create a new, normalized query string if caller asked. We don't
1173  * need to hold the lock while doing this work. (Note: in any case,
1174  * it's possible that someone else creates a duplicate hashtable entry
1175  * in the interval where we don't hold the lock below. That case is
1176  * handled by entry_alloc.)
1177  */
1178  if (jstate)
1179  {
1181  norm_query = generate_normalized_query(jstate, query,
1182  query_location,
1183  &query_len,
1184  encoding);
1186  }
1187 
1188  /* Append new query text to file with only shared lock held */
1189  stored = qtext_store(norm_query ? norm_query : query, query_len,
1190  &query_offset, &gc_count);
1191 
1192  /*
1193  * Determine whether we need to garbage collect external query texts
1194  * while the shared lock is still held. This micro-optimization
1195  * avoids taking the time to decide this while holding exclusive lock.
1196  */
1197  do_gc = need_gc_qtexts();
1198 
1199  /* Need exclusive lock to make a new hashtable entry - promote */
1202 
1203  /*
1204  * A garbage collection may have occurred while we weren't holding the
1205  * lock. In the unlikely event that this happens, the query text we
1206  * stored above will have been garbage collected, so write it again.
1207  * This should be infrequent enough that doing it while holding
1208  * exclusive lock isn't a performance problem.
1209  */
1210  if (!stored || pgss->gc_count != gc_count)
1211  stored = qtext_store(norm_query ? norm_query : query, query_len,
1212  &query_offset, NULL);
1213 
1214  /* If we failed to write to the text file, give up */
1215  if (!stored)
1216  goto done;
1217 
1218  /* OK to create a new hashtable entry */
1219  entry = entry_alloc(&key, query_offset, query_len, encoding,
1220  jstate != NULL);
1221 
1222  /* If needed, perform garbage collection while exclusive lock held */
1223  if (do_gc)
1224  gc_qtexts();
1225  }
1226 
1227  /* Increment the counts, except when jstate is not NULL */
1228  if (!jstate)
1229  {
1230  /*
1231  * Grab the spinlock while updating the counters (see comment about
1232  * locking rules at the head of the file)
1233  */
1234  volatile pgssEntry *e = (volatile pgssEntry *) entry;
1235 
1236  SpinLockAcquire(&e->mutex);
1237 
1238  /* "Unstick" entry if it was previously sticky */
1239  if (e->counters.calls == 0)
1240  e->counters.usage = USAGE_INIT;
1241 
1242  e->counters.calls += 1;
1243  e->counters.total_time += total_time;
1244  if (e->counters.calls == 1)
1245  {
1246  e->counters.min_time = total_time;
1247  e->counters.max_time = total_time;
1248  e->counters.mean_time = total_time;
1249  }
1250  else
1251  {
1252  /*
1253  * Welford's method for accurately computing variance. See
1254  * <http://www.johndcook.com/blog/standard_deviation/>
1255  */
1256  double old_mean = e->counters.mean_time;
1257 
1258  e->counters.mean_time +=
1259  (total_time - old_mean) / e->counters.calls;
1260  e->counters.sum_var_time +=
1261  (total_time - old_mean) * (total_time - e->counters.mean_time);
1262 
1263  /* calculate min and max time */
1264  if (e->counters.min_time > total_time)
1265  e->counters.min_time = total_time;
1266  if (e->counters.max_time < total_time)
1267  e->counters.max_time = total_time;
1268  }
1269  e->counters.rows += rows;
1270  e->counters.shared_blks_hit += bufusage->shared_blks_hit;
1271  e->counters.shared_blks_read += bufusage->shared_blks_read;
1274  e->counters.local_blks_hit += bufusage->local_blks_hit;
1275  e->counters.local_blks_read += bufusage->local_blks_read;
1278  e->counters.temp_blks_read += bufusage->temp_blks_read;
1282  e->counters.usage += USAGE_EXEC(total_time);
1283 
1284  SpinLockRelease(&e->mutex);
1285  }
1286 
1287 done:
1289 
1290  /* We postpone this clean-up until we're out of the lock */
1291  if (norm_query)
1292  pfree(norm_query);
1293 }
long local_blks_hit
Definition: instrument.h:25
static uint64 pgss_hash_string(const char *str, int len)
long local_blks_dirtied
Definition: instrument.h:27
long local_blks_read
Definition: instrument.h:26
int64 shared_blks_read
int64 local_blks_written
Oid GetUserId(void)
Definition: miscinit.c:379
instr_time blk_read_time
Definition: instrument.h:31
int64 shared_blks_dirtied
#define INSTR_TIME_GET_MILLISEC(t)
Definition: instr_time.h:199
long shared_blks_read
Definition: instrument.h:22
long temp_blks_written
Definition: instrument.h:30
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
Counters counters
int64 temp_blks_read
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1725
long shared_blks_written
Definition: instrument.h:24
static pgssSharedState * pgss
#define SpinLockAcquire(lock)
Definition: spin.h:62
void pfree(void *pointer)
Definition: mcxt.c:1031
int64 shared_blks_hit
static HTAB * pgss_hash
#define USAGE_EXEC(duration)
static pgssEntry * entry_alloc(pgssHashKey *key, Size query_offset, int query_len, int encoding, bool sticky)
static char * generate_normalized_query(pgssJumbleState *jstate, const char *query, int query_loc, int *query_len_p, int encoding)
long shared_blks_dirtied
Definition: instrument.h:23
long temp_blks_read
Definition: instrument.h:29
int64 temp_blks_written
static bool qtext_store(const char *query, int query_len, Size *query_offset, int *gc_count)
int64 shared_blks_written
#define SpinLockRelease(lock)
Definition: spin.h:64
int64 local_blks_read
static bool need_gc_qtexts(void)
int GetDatabaseEncoding(void)
Definition: mbutils.c:1004
static void gc_qtexts(void)
double sum_var_time
Oid MyDatabaseId
Definition: globals.c:86
bool scanner_isspace(char ch)
Definition: scansup.c:221
#define USAGE_INIT
double blk_read_time
#define Assert(condition)
Definition: c.h:699
int64 local_blks_dirtied
instr_time blk_write_time
Definition: instrument.h:32
int64 local_blks_hit
size_t Size
Definition: c.h:433
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1121
double blk_write_time
int32 encoding
Definition: pg_database.h:33
e
Definition: preproc-init.c:82
long shared_blks_hit
Definition: instrument.h:21
long local_blks_written
Definition: instrument.h:28

◆ qtext_fetch()

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

Definition at line 1981 of file pg_stat_statements.c.

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

1983 {
1984  /* File read failed? */
1985  if (buffer == NULL)
1986  return NULL;
1987  /* Bogus offset/length? */
1988  if (query_len < 0 ||
1989  query_offset + query_len >= buffer_size)
1990  return NULL;
1991  /* As a further sanity check, make sure there's a trailing null */
1992  if (buffer[query_offset + query_len] != '\0')
1993  return NULL;
1994  /* Looks OK */
1995  return buffer + query_offset;
1996 }
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:215

◆ qtext_load_file()

static char * qtext_load_file ( Size buffer_size)
static

Definition at line 1904 of file pg_stat_statements.c.

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

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

1905 {
1906  char *buf;
1907  int fd;
1908  struct stat stat;
1909 
1910  fd = OpenTransientFile(PGSS_TEXT_FILE, O_RDONLY | PG_BINARY);
1911  if (fd < 0)
1912  {
1913  if (errno != ENOENT)
1914  ereport(LOG,
1916  errmsg("could not read pg_stat_statement file \"%s\": %m",
1917  PGSS_TEXT_FILE)));
1918  return NULL;
1919  }
1920 
1921  /* Get file length */
1922  if (fstat(fd, &stat))
1923  {
1924  ereport(LOG,
1926  errmsg("could not stat pg_stat_statement file \"%s\": %m",
1927  PGSS_TEXT_FILE)));
1928  CloseTransientFile(fd);
1929  return NULL;
1930  }
1931 
1932  /* Allocate buffer; beware that off_t might be wider than size_t */
1933  if (stat.st_size <= MaxAllocHugeSize)
1934  buf = (char *) malloc(stat.st_size);
1935  else
1936  buf = NULL;
1937  if (buf == NULL)
1938  {
1939  ereport(LOG,
1940  (errcode(ERRCODE_OUT_OF_MEMORY),
1941  errmsg("out of memory"),
1942  errdetail("Could not allocate enough memory to read pg_stat_statement file \"%s\".",
1943  PGSS_TEXT_FILE)));
1944  CloseTransientFile(fd);
1945  return NULL;
1946  }
1947 
1948  /*
1949  * OK, slurp in the file. If we get a short read and errno doesn't get
1950  * set, the reason is probably that garbage collection truncated the file
1951  * since we did the fstat(), so we don't log a complaint --- but we don't
1952  * return the data, either, since it's most likely corrupt due to
1953  * concurrent writes from garbage collection.
1954  */
1955  errno = 0;
1956  if (read(fd, buf, stat.st_size) != stat.st_size)
1957  {
1958  if (errno)
1959  ereport(LOG,
1961  errmsg("could not read pg_stat_statement file \"%s\": %m",
1962  PGSS_TEXT_FILE)));
1963  free(buf);
1964  CloseTransientFile(fd);
1965  return NULL;
1966  }
1967 
1968  CloseTransientFile(fd);
1969 
1970  *buffer_size = stat.st_size;
1971  return buf;
1972 }
int errcode(int sqlerrcode)
Definition: elog.c:575
#define LOG
Definition: elog.h:26
static int fd(const char *x, int i)
Definition: preproc-init.c:105
#define PG_BINARY
Definition: c.h:1080
#define MaxAllocHugeSize
Definition: memutils.h:44
#define malloc(a)
Definition: header.h:50
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2396
static char * buf
Definition: pg_test_fsync.c:67
int errdetail(const char *fmt,...)
Definition: elog.c:873
int errcode_for_file_access(void)
Definition: elog.c:598
#define ereport(elevel, rest)
Definition: elog.h:122
int CloseTransientFile(int fd)
Definition: fd.c:2566
#define stat(a, b)
Definition: win32_port.h:266
#define free(a)
Definition: header.h:65
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define PGSS_TEXT_FILE
#define read(a, b, c)
Definition: win32.h:13

◆ qtext_store()

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

Definition at line 1821 of file pg_stat_statements.c.

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

Referenced by pgss_store().

1823 {
1824  Size off;
1825  int fd;
1826 
1827  /*
1828  * We use a spinlock to protect extent/n_writers/gc_count, so that
1829  * multiple processes may execute this function concurrently.
1830  */
1831  {
1832  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
1833 
1834  SpinLockAcquire(&s->mutex);
1835  off = s->extent;
1836  s->extent += query_len + 1;
1837  s->n_writers++;
1838  if (gc_count)
1839  *gc_count = s->gc_count;
1840  SpinLockRelease(&s->mutex);
1841  }
1842 
1843  *query_offset = off;
1844 
1845  /* Now write the data into the successfully-reserved part of the file */
1846  fd = OpenTransientFile(PGSS_TEXT_FILE, O_RDWR | O_CREAT | PG_BINARY);
1847  if (fd < 0)
1848  goto error;
1849 
1850  if (lseek(fd, off, SEEK_SET) != off)
1851  goto error;
1852 
1853  if (write(fd, query, query_len) != query_len)
1854  goto error;
1855  if (write(fd, "\0", 1) != 1)
1856  goto error;
1857 
1858  CloseTransientFile(fd);
1859 
1860  /* Mark our write complete */
1861  {
1862  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
1863 
1864  SpinLockAcquire(&s->mutex);
1865  s->n_writers--;
1866  SpinLockRelease(&s->mutex);
1867  }
1868 
1869  return true;
1870 
1871 error:
1872  ereport(LOG,
1874  errmsg("could not write pg_stat_statement file \"%s\": %m",
1875  PGSS_TEXT_FILE)));
1876 
1877  if (fd >= 0)
1878  CloseTransientFile(fd);
1879 
1880  /* Mark our write complete */
1881  {
1882  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
1883 
1884  SpinLockAcquire(&s->mutex);
1885  s->n_writers--;
1886  SpinLockRelease(&s->mutex);
1887  }
1888 
1889  return false;
1890 }
static void error(void)
Definition: sql-dyntest.c:147
#define write(a, b, c)
Definition: win32.h:14
#define LOG
Definition: elog.h:26
static int fd(const char *x, int i)
Definition: preproc-init.c:105
#define PG_BINARY
Definition: c.h:1080
static pgssSharedState * pgss
#define SpinLockAcquire(lock)
Definition: spin.h:62
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2396
int errcode_for_file_access(void)
Definition: elog.c:598
#define ereport(elevel, rest)
Definition: elog.h:122
int CloseTransientFile(int fd)
Definition: fd.c:2566
#define SpinLockRelease(lock)
Definition: spin.h:64
size_t Size
Definition: c.h:433
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define PGSS_TEXT_FILE

◆ RecordConstLocation()

static void RecordConstLocation ( pgssJumbleState jstate,
int  location 
)
static

Definition at line 2907 of file pg_stat_statements.c.

References pgssJumbleState::clocations, pgssJumbleState::clocations_buf_size, pgssJumbleState::clocations_count, pgssLocationLen::length, pgssLocationLen::location, and repalloc().

Referenced by JumbleExpr().

2908 {
2909  /* -1 indicates unknown or undefined location */
2910  if (location >= 0)
2911  {
2912  /* enlarge array if needed */
2913  if (jstate->clocations_count >= jstate->clocations_buf_size)
2914  {
2915  jstate->clocations_buf_size *= 2;
2916  jstate->clocations = (pgssLocationLen *)
2917  repalloc(jstate->clocations,
2918  jstate->clocations_buf_size *
2919  sizeof(pgssLocationLen));
2920  }
2921  jstate->clocations[jstate->clocations_count].location = location;
2922  /* initialize lengths to -1 to simplify fill_in_constant_lengths */
2923  jstate->clocations[jstate->clocations_count].length = -1;
2924  jstate->clocations_count++;
2925  }
2926 }
pgssLocationLen * clocations
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1044

Variable Documentation

◆ nested_level

int nested_level = 0
static

◆ PG_MODULE_MAGIC

PG_MODULE_MAGIC

Definition at line 83 of file pg_stat_statements.c.

◆ pgss

pgssSharedState* pgss = NULL
static

Definition at line 249 of file pg_stat_statements.c.

◆ PGSS_FILE_HEADER

const uint32 PGSS_FILE_HEADER = 0x20171004
static

Definition at line 99 of file pg_stat_statements.c.

Referenced by pgss_shmem_shutdown(), and pgss_shmem_startup().

◆ pgss_hash

HTAB* pgss_hash = NULL
static

Definition at line 250 of file pg_stat_statements.c.

◆ pgss_max

int pgss_max
static

◆ PGSS_PG_MAJOR_VERSION

const uint32 PGSS_PG_MAJOR_VERSION = PG_VERSION_NUM / 100
static

Definition at line 102 of file pg_stat_statements.c.

Referenced by pgss_shmem_shutdown(), and pgss_shmem_startup().

◆ pgss_save

bool pgss_save
static

Definition at line 272 of file pg_stat_statements.c.

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

◆ pgss_track

int pgss_track
static

Definition at line 270 of file pg_stat_statements.c.

Referenced by _PG_init().

◆ pgss_track_utility

bool pgss_track_utility
static

Definition at line 271 of file pg_stat_statements.c.

Referenced by _PG_init(), and pgss_ProcessUtility().

◆ prev_ExecutorEnd

ExecutorEnd_hook_type prev_ExecutorEnd = NULL
static

Definition at line 245 of file pg_stat_statements.c.

Referenced by _PG_fini(), _PG_init(), and pgss_ExecutorEnd().

◆ prev_ExecutorFinish

ExecutorFinish_hook_type prev_ExecutorFinish = NULL
static

Definition at line 244 of file pg_stat_statements.c.

Referenced by _PG_fini(), _PG_init(), and pgss_ExecutorFinish().

◆ prev_ExecutorRun

ExecutorRun_hook_type prev_ExecutorRun = NULL
static

Definition at line 243 of file pg_stat_statements.c.

Referenced by _PG_fini(), _PG_init(), and pgss_ExecutorRun().

◆ prev_ExecutorStart

ExecutorStart_hook_type prev_ExecutorStart = NULL
static

Definition at line 242 of file pg_stat_statements.c.

Referenced by _PG_fini(), _PG_init(), and pgss_ExecutorStart().

◆ prev_post_parse_analyze_hook

post_parse_analyze_hook_type prev_post_parse_analyze_hook = NULL
static

Definition at line 241 of file pg_stat_statements.c.

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

◆ prev_ProcessUtility

ProcessUtility_hook_type prev_ProcessUtility = NULL
static

Definition at line 246 of file pg_stat_statements.c.

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

◆ prev_shmem_startup_hook

shmem_startup_hook_type prev_shmem_startup_hook = NULL
static

Definition at line 240 of file pg_stat_statements.c.

Referenced by _PG_fini(), _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 261 of file pg_stat_statements.c.