PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
pg_stat_statements.c File Reference
#include "postgres.h"
#include <math.h>
#include <sys/stat.h>
#include <unistd.h>
#include "access/hash.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/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, DestReceiver *dest, char *completionTag)
 
static uint32 pgss_hash_fn (const void *key, Size keysize)
 
static int pgss_match_fn (const void *key1, const void *key2, Size keysize)
 
static uint32 pgss_hash_string (const char *str, int len)
 
static void pgss_store (const char *query, uint32 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 = 0x20140125
 
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

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

Definition at line 2336 of file pg_stat_statements.c.

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

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

Definition at line 2338 of file pg_stat_statements.c.

Referenced by JumbleExpr(), and JumbleRangeTable().

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

Definition at line 106 of file pg_stat_statements.c.

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

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

Definition at line 105 of file pg_stat_statements.c.

Referenced by pgss_shmem_startup().

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

Definition at line 111 of file pg_stat_statements.c.

Referenced by AppendJumble(), and pgss_post_parse_analyze().

#define PG_STAT_STATEMENTS_COLS   23 /* maximum of above */

Definition at line 1333 of file pg_stat_statements.c.

Referenced by pg_stat_statements_internal().

#define PG_STAT_STATEMENTS_COLS_V1_0   14

Definition at line 1329 of file pg_stat_statements.c.

Referenced by pg_stat_statements_internal().

#define PG_STAT_STATEMENTS_COLS_V1_1   18

Definition at line 1330 of file pg_stat_statements.c.

Referenced by pg_stat_statements_internal().

#define PG_STAT_STATEMENTS_COLS_V1_2   19

Definition at line 1331 of file pg_stat_statements.c.

Referenced by pg_stat_statements_internal().

#define PG_STAT_STATEMENTS_COLS_V1_3   23

Definition at line 1332 of file pg_stat_statements.c.

Referenced by pg_stat_statements_internal().

#define PGSS_DUMP_FILE   PGSTAT_STAT_PERMANENT_DIRECTORY "/pg_stat_statements.stat"

Definition at line 84 of file pg_stat_statements.c.

Referenced by pgss_shmem_shutdown(), and pgss_shmem_startup().

#define pgss_enabled ( )
#define PGSS_TEXT_FILE   PG_STAT_TMP_DIR "/pgss_query_texts.stat"
#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
#define SpinLockAcquire(lock)
Definition: spin.h:62
#define SpinLockRelease(lock)
Definition: spin.h:64

Definition at line 269 of file pg_stat_statements.c.

Referenced by entry_reset(), and gc_qtexts().

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

Definition at line 108 of file pg_stat_statements.c.

Referenced by entry_dealloc().

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

Definition at line 109 of file pg_stat_statements.c.

Referenced by entry_dealloc().

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

Definition at line 107 of file pg_stat_statements.c.

Referenced by entry_dealloc().

#define USAGE_EXEC (   duration)    (1.0)

Definition at line 103 of file pg_stat_statements.c.

Referenced by pgss_store().

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

Definition at line 104 of file pg_stat_statements.c.

Referenced by entry_alloc(), and pgss_store().

Typedef Documentation

Enumeration Type Documentation

Enumerator
PGSS_TRACK_NONE 
PGSS_TRACK_TOP 
PGSS_TRACK_ALL 

Definition at line 244 of file pg_stat_statements.c.

245 {
246  PGSS_TRACK_NONE, /* track no statements */
247  PGSS_TRACK_TOP, /* only top level statements */
248  PGSS_TRACK_ALL /* all statements, including nested ones */
PGSSTrackLevel
Enumerator
PGSS_V1_0 
PGSS_V1_1 
PGSS_V1_2 
PGSS_V1_3 

Definition at line 116 of file pg_stat_statements.c.

Function Documentation

void _PG_fini ( void  )

Definition at line 435 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.

436 {
437  /* Uninstall hooks. */
445 }
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:73
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:69
ExecutorRun_hook_type ExecutorRun_hook
Definition: execMain.c:70
ExecutorEnd_hook_type ExecutorEnd_hook
Definition: execMain.c:72
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:71
post_parse_analyze_hook_type post_parse_analyze_hook
Definition: analyze.c:49
void _PG_init ( void  )

Definition at line 339 of file pg_stat_statements.c.

References DefineCustomBoolVariable(), DefineCustomEnumVariable(), DefineCustomIntVariable(), EmitWarningsOnPlaceholders(), ExecutorEnd_hook, ExecutorFinish_hook, ExecutorRun_hook, ExecutorStart_hook, NULL, 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.

340 {
341  /*
342  * In order to create our shared memory area, we have to be loaded via
343  * shared_preload_libraries. If not, fall out without hooking into any of
344  * the main system. (We don't throw error here because it seems useful to
345  * allow the pg_stat_statements functions to be created even when the
346  * module isn't active. The functions must protect themselves against
347  * being called then, however.)
348  */
350  return;
351 
352  /*
353  * Define (or redefine) custom GUC variables.
354  */
355  DefineCustomIntVariable("pg_stat_statements.max",
356  "Sets the maximum number of statements tracked by pg_stat_statements.",
357  NULL,
358  &pgss_max,
359  5000,
360  100,
361  INT_MAX,
363  0,
364  NULL,
365  NULL,
366  NULL);
367 
368  DefineCustomEnumVariable("pg_stat_statements.track",
369  "Selects which statements are tracked by pg_stat_statements.",
370  NULL,
371  &pgss_track,
374  PGC_SUSET,
375  0,
376  NULL,
377  NULL,
378  NULL);
379 
380  DefineCustomBoolVariable("pg_stat_statements.track_utility",
381  "Selects whether utility commands are tracked by pg_stat_statements.",
382  NULL,
384  true,
385  PGC_SUSET,
386  0,
387  NULL,
388  NULL,
389  NULL);
390 
391  DefineCustomBoolVariable("pg_stat_statements.save",
392  "Save pg_stat_statements statistics across server shutdowns.",
393  NULL,
394  &pgss_save,
395  true,
396  PGC_SIGHUP,
397  0,
398  NULL,
399  NULL,
400  NULL);
401 
402  EmitWarningsOnPlaceholders("pg_stat_statements");
403 
404  /*
405  * Request additional shared resources. (These are no-ops if we're not in
406  * the postmaster process.) We'll allocate or attach to the shared
407  * resources in pgss_shmem_startup().
408  */
410  RequestNamedLWLockTranche("pg_stat_statements", 1);
411 
412  /*
413  * Install hooks.
414  */
429 }
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:7731
void RequestAddinShmemSpace(Size size)
Definition: ipci.c:69
bool process_shared_preload_libraries_in_progress
Definition: miscinit.c:1417
void RequestNamedLWLockTranche(const char *tranche_name, int num_lwlocks)
Definition: lwlock.c:627
static ProcessUtility_hook_type prev_ProcessUtility
static void pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, DestReceiver *dest, char *completionTag)
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:73
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:7816
ExecutorStart_hook_type ExecutorStart_hook
Definition: execMain.c:69
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:70
ExecutorEnd_hook_type ExecutorEnd_hook
Definition: execMain.c:72
static void pgss_post_parse_analyze(ParseState *pstate, Query *query)
Definition: guc.h:75
void EmitWarningsOnPlaceholders(const char *className)
Definition: guc.c:7844
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
#define NULL
Definition: c.h:229
static bool pgss_track_utility
static shmem_startup_hook_type prev_shmem_startup_hook
static void pgss_ExecutorFinish(QueryDesc *queryDesc)
ExecutorFinish_hook_type ExecutorFinish_hook
Definition: execMain.c:71
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:7705
post_parse_analyze_hook_type post_parse_analyze_hook
Definition: analyze.c:49
static const struct config_enum_entry track_options[]
static bool pgss_save
static void AppendJumble ( pgssJumbleState jstate,
const unsigned char *  item,
Size  size 
)
static

Definition at line 2302 of file pg_stat_statements.c.

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

2303 {
2304  unsigned char *jumble = jstate->jumble;
2305  Size jumble_len = jstate->jumble_len;
2306 
2307  /*
2308  * Whenever the jumble buffer is full, we hash the current contents and
2309  * reset the buffer to contain just that hash value, thus relying on the
2310  * hash to summarize everything so far.
2311  */
2312  while (size > 0)
2313  {
2314  Size part_size;
2315 
2316  if (jumble_len >= JUMBLE_SIZE)
2317  {
2318  uint32 start_hash = hash_any(jumble, JUMBLE_SIZE);
2319 
2320  memcpy(jumble, &start_hash, sizeof(start_hash));
2321  jumble_len = sizeof(start_hash);
2322  }
2323  part_size = Min(size, JUMBLE_SIZE - jumble_len);
2324  memcpy(jumble + jumble_len, item, part_size);
2325  jumble_len += part_size;
2326  item += part_size;
2327  size -= part_size;
2328  }
2329  jstate->jumble_len = jumble_len;
2330 }
#define Min(x, y)
Definition: c.h:806
unsigned char * jumble
#define JUMBLE_SIZE
unsigned int uint32
Definition: c.h:268
Datum hash_any(register const unsigned char *k, register int keylen)
Definition: hashfunc.c:307
size_t Size
Definition: c.h:356
static int comp_location ( const void *  a,
const void *  b 
)
static

Definition at line 3142 of file pg_stat_statements.c.

Referenced by fill_in_constant_lengths().

3143 {
3144  int l = ((const pgssLocationLen *) a)->location;
3145  int r = ((const pgssLocationLen *) b)->location;
3146 
3147  if (l < r)
3148  return -1;
3149  else if (l > r)
3150  return +1;
3151  else
3152  return 0;
3153 }
static pgssEntry * entry_alloc ( pgssHashKey key,
Size  query_offset,
int  query_len,
int  encoding,
bool  sticky 
)
static

Definition at line 1695 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().

1697 {
1698  pgssEntry *entry;
1699  bool found;
1700 
1701  /* Make space if needed */
1703  entry_dealloc();
1704 
1705  /* Find or create an entry with desired hash code */
1706  entry = (pgssEntry *) hash_search(pgss_hash, key, HASH_ENTER, &found);
1707 
1708  if (!found)
1709  {
1710  /* New entry, initialize it */
1711 
1712  /* reset the statistics */
1713  memset(&entry->counters, 0, sizeof(Counters));
1714  /* set the appropriate initial usage count */
1715  entry->counters.usage = sticky ? pgss->cur_median_usage : USAGE_INIT;
1716  /* re-initialize the mutex each time ... we assume no one using it */
1717  SpinLockInit(&entry->mutex);
1718  /* ... and don't forget the query text metadata */
1719  Assert(query_len >= 0);
1720  entry->query_offset = query_offset;
1721  entry->query_len = query_len;
1722  entry->encoding = encoding;
1723  }
1724 
1725  return entry;
1726 }
#define SpinLockInit(lock)
Definition: spin.h:60
long hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1297
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:885
Counters counters
static pgssSharedState * pgss
static int pgss_max
static void entry_dealloc(void)
static HTAB * pgss_hash
#define USAGE_INIT
static char * encoding
Definition: initdb.c:122
#define Assert(condition)
Definition: c.h:675
static int entry_cmp ( const void *  lhs,
const void *  rhs 
)
static

Definition at line 1732 of file pg_stat_statements.c.

Referenced by entry_dealloc().

1733 {
1734  double l_usage = (*(pgssEntry *const *) lhs)->counters.usage;
1735  double r_usage = (*(pgssEntry *const *) rhs)->counters.usage;
1736 
1737  if (l_usage < r_usage)
1738  return -1;
1739  else if (l_usage > r_usage)
1740  return +1;
1741  else
1742  return 0;
1743 }
static void entry_dealloc ( void  )
static

Definition at line 1751 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, NULL, palloc(), pfree(), qsort, pgssEntry::query_len, STICKY_DECREASE_FACTOR, Counters::usage, USAGE_DEALLOC_PERCENT, and USAGE_DECREASE_FACTOR.

Referenced by entry_alloc().

1752 {
1753  HASH_SEQ_STATUS hash_seq;
1754  pgssEntry **entries;
1755  pgssEntry *entry;
1756  int nvictims;
1757  int i;
1758  Size tottextlen;
1759  int nvalidtexts;
1760 
1761  /*
1762  * Sort entries by usage and deallocate USAGE_DEALLOC_PERCENT of them.
1763  * While we're scanning the table, apply the decay factor to the usage
1764  * values, and update the mean query length.
1765  *
1766  * Note that the mean query length is almost immediately obsolete, since
1767  * we compute it before not after discarding the least-used entries.
1768  * Hopefully, that doesn't affect the mean too much; it doesn't seem worth
1769  * making two passes to get a more current result. Likewise, the new
1770  * cur_median_usage includes the entries we're about to zap.
1771  */
1772 
1773  entries = palloc(hash_get_num_entries(pgss_hash) * sizeof(pgssEntry *));
1774 
1775  i = 0;
1776  tottextlen = 0;
1777  nvalidtexts = 0;
1778 
1779  hash_seq_init(&hash_seq, pgss_hash);
1780  while ((entry = hash_seq_search(&hash_seq)) != NULL)
1781  {
1782  entries[i++] = entry;
1783  /* "Sticky" entries get a different usage decay rate. */
1784  if (entry->counters.calls == 0)
1786  else
1788  /* In the mean length computation, ignore dropped texts. */
1789  if (entry->query_len >= 0)
1790  {
1791  tottextlen += entry->query_len + 1;
1792  nvalidtexts++;
1793  }
1794  }
1795 
1796  /* Sort into increasing order by usage */
1797  qsort(entries, i, sizeof(pgssEntry *), entry_cmp);
1798 
1799  /* Record the (approximate) median usage */
1800  if (i > 0)
1801  pgss->cur_median_usage = entries[i / 2]->counters.usage;
1802  /* Record the mean query length */
1803  if (nvalidtexts > 0)
1804  pgss->mean_query_len = tottextlen / nvalidtexts;
1805  else
1807 
1808  /* Now zap an appropriate fraction of lowest-usage entries */
1809  nvictims = Max(10, i * USAGE_DEALLOC_PERCENT / 100);
1810  nvictims = Min(nvictims, i);
1811 
1812  for (i = 0; i < nvictims; i++)
1813  {
1814  hash_search(pgss_hash, &entries[i]->key, HASH_REMOVE, NULL);
1815  }
1816 
1817  pfree(entries);
1818 }
#define USAGE_DEALLOC_PERCENT
#define Min(x, y)
Definition: c.h:806
static int entry_cmp(const void *lhs, const void *rhs)
long hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1297
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:885
Counters counters
#define ASSUMED_LENGTH_INIT
static pgssSharedState * pgss
void pfree(void *pointer)
Definition: mcxt.c:950
static HTAB * pgss_hash
#define STICKY_DECREASE_FACTOR
#define USAGE_DECREASE_FACTOR
#define Max(x, y)
Definition: c.h:800
#define NULL
Definition: c.h:229
size_t Size
Definition: c.h:356
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1353
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1343
void * palloc(Size size)
Definition: mcxt.c:849
int i
#define qsort(a, b, c, d)
Definition: port.h:440
static void entry_reset ( void  )
static

Definition at line 2252 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(), NULL, PG_BINARY_W, PGSS_TEXT_FILE, and record_gc_qtexts.

Referenced by pg_stat_statements_reset().

2253 {
2254  HASH_SEQ_STATUS hash_seq;
2255  pgssEntry *entry;
2256  FILE *qfile;
2257 
2259 
2260  hash_seq_init(&hash_seq, pgss_hash);
2261  while ((entry = hash_seq_search(&hash_seq)) != NULL)
2262  {
2264  }
2265 
2266  /*
2267  * Write new empty query file, perhaps even creating a new one to recover
2268  * if the file was missing.
2269  */
2271  if (qfile == NULL)
2272  {
2273  ereport(LOG,
2275  errmsg("could not create pg_stat_statement file \"%s\": %m",
2276  PGSS_TEXT_FILE)));
2277  goto done;
2278  }
2279 
2280  /* If ftruncate fails, log it, but it's not a fatal problem */
2281  if (ftruncate(fileno(qfile), 0) != 0)
2282  ereport(LOG,
2284  errmsg("could not truncate pg_stat_statement file \"%s\": %m",
2285  PGSS_TEXT_FILE)));
2286 
2287  FreeFile(qfile);
2288 
2289 done:
2290  pgss->extent = 0;
2291  /* This counts as a query text garbage collection for our purposes */
2292  record_gc_qtexts();
2293 
2295 }
#define PG_BINARY_W
Definition: c.h:1041
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:885
#define LOG
Definition: elog.h:26
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1715
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:2094
#define ereport(elevel, rest)
Definition: elog.h:122
pgssHashKey key
#define ftruncate(a, b)
Definition: win32.h:67
#define NULL
Definition: c.h:229
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1111
#define record_gc_qtexts()
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1353
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1343
int FreeFile(FILE *file)
Definition: fd.c:2277
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define PGSS_TEXT_FILE
static void fill_in_constant_lengths ( pgssJumbleState jstate,
const char *  query,
int  query_loc 
)
static

Definition at line 3042 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().

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

Definition at line 2068 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(), NULL, PG_BINARY_W, PGSS_TEXT_FILE, qtext_fetch(), qtext_load_file(), pgssEntry::query_len, pgssEntry::query_offset, record_gc_qtexts, and unlink().

Referenced by pgss_store().

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

Definition at line 2946 of file pg_stat_statements.c.

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

Referenced by pgss_store().

2948 {
2949  char *norm_query;
2950  int query_len = *query_len_p;
2951  int i,
2952  len_to_wrt, /* Length (in bytes) to write */
2953  quer_loc = 0, /* Source query byte location */
2954  n_quer_loc = 0, /* Normalized query byte location */
2955  last_off = 0, /* Offset from start for previous tok */
2956  last_tok_len = 0; /* Length (in bytes) of that tok */
2957 
2958  /*
2959  * Get constants' lengths (core system only gives us locations). Note
2960  * this also ensures the items are sorted by location.
2961  */
2962  fill_in_constant_lengths(jstate, query, query_loc);
2963 
2964  /* Allocate result buffer */
2965  norm_query = palloc(query_len + 1);
2966 
2967  for (i = 0; i < jstate->clocations_count; i++)
2968  {
2969  int off, /* Offset from start for cur tok */
2970  tok_len; /* Length (in bytes) of that tok */
2971 
2972  off = jstate->clocations[i].location;
2973  /* Adjust recorded location if we're dealing with partial string */
2974  off -= query_loc;
2975 
2976  tok_len = jstate->clocations[i].length;
2977 
2978  if (tok_len < 0)
2979  continue; /* ignore any duplicates */
2980 
2981  /* Copy next chunk (what precedes the next constant) */
2982  len_to_wrt = off - last_off;
2983  len_to_wrt -= last_tok_len;
2984 
2985  Assert(len_to_wrt >= 0);
2986  memcpy(norm_query + n_quer_loc, query + quer_loc, len_to_wrt);
2987  n_quer_loc += len_to_wrt;
2988 
2989  /* And insert a '?' in place of the constant token */
2990  norm_query[n_quer_loc++] = '?';
2991 
2992  quer_loc = off + tok_len;
2993  last_off = off;
2994  last_tok_len = tok_len;
2995  }
2996 
2997  /*
2998  * We've copied up until the last ignorable constant. Copy over the
2999  * remaining bytes of the original query string.
3000  */
3001  len_to_wrt = query_len - quer_loc;
3002 
3003  Assert(len_to_wrt >= 0);
3004  memcpy(norm_query + n_quer_loc, query + quer_loc, len_to_wrt);
3005  n_quer_loc += len_to_wrt;
3006 
3007  Assert(n_quer_loc <= query_len);
3008  norm_query[n_quer_loc] = '\0';
3009 
3010  *query_len_p = n_quer_loc;
3011  return norm_query;
3012 }
pgssLocationLen * clocations
static void fill_in_constant_lengths(pgssJumbleState *jstate, const char *query, int query_loc)
#define Assert(condition)
Definition: c.h:675
void * palloc(Size size)
Definition: mcxt.c:849
int i
static void JumbleExpr ( pgssJumbleState jstate,
Node node 
)
static

Definition at line 2441 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, TableSampleClause::args, MinMaxExpr::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, 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, InferenceElem::infercollid, InferenceElem::inferopclass, JoinExpr::isNatural, JoinExpr::jointype, JumbleQuery(), JoinExpr::larg, SetOperationStmt::larg, RowCompareExpr::largs, lfirst, lfirst_int, Const::location, XmlExpr::named_args, FieldStore::newvals, nodeTag, NULL, SortGroupClause::nulls_first, NullTest::nulltesttype, OnConflictExpr::onConflictSet, OnConflictExpr::onConflictWhere, MinMaxExpr::op, SQLValueFunction::op, XmlExpr::op, SetOperationStmt::op, OpExpr::opno, ScalarArrayOpExpr::opno, WindowClause::orderClause, 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, 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_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, SQLValueFunction::typmod, ScalarArrayOpExpr::useOr, Var::varattno, Var::varlevelsup, Var::varno, WARNING, WindowFunc::winfnoid, WindowFunc::winref, and WindowClause::winref.

Referenced by JumbleQuery(), and JumbleRangeTable().

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

Definition at line 2351 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, NULL, 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().

2352 {
2353  Assert(IsA(query, Query));
2354  Assert(query->utilityStmt == NULL);
2355 
2356  APP_JUMB(query->commandType);
2357  /* resultRelation is usually predictable from commandType */
2358  JumbleExpr(jstate, (Node *) query->cteList);
2359  JumbleRangeTable(jstate, query->rtable);
2360  JumbleExpr(jstate, (Node *) query->jointree);
2361  JumbleExpr(jstate, (Node *) query->targetList);
2362  JumbleExpr(jstate, (Node *) query->onConflict);
2363  JumbleExpr(jstate, (Node *) query->returningList);
2364  JumbleExpr(jstate, (Node *) query->groupClause);
2365  JumbleExpr(jstate, (Node *) query->groupingSets);
2366  JumbleExpr(jstate, query->havingQual);
2367  JumbleExpr(jstate, (Node *) query->windowClause);
2368  JumbleExpr(jstate, (Node *) query->distinctClause);
2369  JumbleExpr(jstate, (Node *) query->sortClause);
2370  JumbleExpr(jstate, query->limitOffset);
2371  JumbleExpr(jstate, query->limitCount);
2372  /* we ignore rowMarks */
2373  JumbleExpr(jstate, query->setOperations);
2374 }
Node * limitOffset
Definition: parsenodes.h:149
static void JumbleExpr(pgssJumbleState *jstate, Node *node)
#define IsA(nodeptr, _type_)
Definition: nodes.h:557
List * sortClause
Definition: parsenodes.h:147
FromExpr * jointree
Definition: parsenodes.h:129
OnConflictExpr * onConflict
Definition: parsenodes.h:133
List * groupingSets
Definition: parsenodes.h:139
Definition: nodes.h:506
Node * utilityStmt
Definition: parsenodes.h:111
List * windowClause
Definition: parsenodes.h:143
List * targetList
Definition: parsenodes.h:131
static void JumbleRangeTable(pgssJumbleState *jstate, List *rtable)
List * rtable
Definition: parsenodes.h:128
List * distinctClause
Definition: parsenodes.h:145
#define APP_JUMB(item)
Node * limitCount
Definition: parsenodes.h:150
List * returningList
Definition: parsenodes.h:135
CmdType commandType
Definition: parsenodes.h:103
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
List * cteList
Definition: parsenodes.h:126
Node * setOperations
Definition: parsenodes.h:154
List * groupClause
Definition: parsenodes.h:137
Node * havingQual
Definition: parsenodes.h:141
static void JumbleRangeTable ( pgssJumbleState jstate,
List rtable 
)
static

Definition at line 2380 of file pg_stat_statements.c.

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

Referenced by JumbleQuery().

2381 {
2382  ListCell *lc;
2383 
2384  foreach(lc, rtable)
2385  {
2387 
2388  APP_JUMB(rte->rtekind);
2389  switch (rte->rtekind)
2390  {
2391  case RTE_RELATION:
2392  APP_JUMB(rte->relid);
2393  JumbleExpr(jstate, (Node *) rte->tablesample);
2394  break;
2395  case RTE_SUBQUERY:
2396  JumbleQuery(jstate, rte->subquery);
2397  break;
2398  case RTE_JOIN:
2399  APP_JUMB(rte->jointype);
2400  break;
2401  case RTE_FUNCTION:
2402  JumbleExpr(jstate, (Node *) rte->functions);
2403  break;
2404  case RTE_TABLEFUNC:
2405  JumbleExpr(jstate, (Node *) rte->tablefunc);
2406  break;
2407  case RTE_VALUES:
2408  JumbleExpr(jstate, (Node *) rte->values_lists);
2409  break;
2410  case RTE_CTE:
2411 
2412  /*
2413  * Depending on the CTE name here isn't ideal, but it's the
2414  * only info we have to identify the referenced WITH item.
2415  */
2416  APP_JUMB_STRING(rte->ctename);
2417  APP_JUMB(rte->ctelevelsup);
2418  break;
2419  default:
2420  elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
2421  break;
2422  }
2423  }
2424 }
static void JumbleExpr(pgssJumbleState *jstate, Node *node)
#define castNode(_type_, nodeptr)
Definition: nodes.h:575
Definition: nodes.h:506
List * values_lists
Definition: parsenodes.h:976
#define APP_JUMB_STRING(str)
#define ERROR
Definition: elog.h:43
TableFunc * tablefunc
Definition: parsenodes.h:971
#define APP_JUMB(item)
static void JumbleQuery(pgssJumbleState *jstate, Query *query)
JoinType jointype
Definition: parsenodes.h:954
#define lfirst(lc)
Definition: pg_list.h:106
List * functions
Definition: parsenodes.h:965
Index ctelevelsup
Definition: parsenodes.h:982
RTEKind rtekind
Definition: parsenodes.h:916
char * ctename
Definition: parsenodes.h:981
Query * subquery
Definition: parsenodes.h:934
#define elog
Definition: elog.h:219
struct TableSampleClause * tablesample
Definition: parsenodes.h:929
static bool need_gc_qtexts ( void  )
static

Definition at line 2021 of file pg_stat_statements.c.

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

Referenced by gc_qtexts(), and pgss_store().

2022 {
2023  Size extent;
2024 
2025  /* Read shared extent pointer */
2026  {
2027  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
2028 
2029  SpinLockAcquire(&s->mutex);
2030  extent = s->extent;
2031  SpinLockRelease(&s->mutex);
2032  }
2033 
2034  /* Don't proceed if file does not exceed 512 bytes per possible entry */
2035  if (extent < 512 * pgss_max)
2036  return false;
2037 
2038  /*
2039  * Don't proceed if file is less than about 50% bloat. Nothing can or
2040  * should be done in the event of unusually large query texts accounting
2041  * for file's large size. We go to the trouble of maintaining the mean
2042  * query length in order to prevent garbage collection from thrashing
2043  * uselessly.
2044  */
2045  if (extent < pgss->mean_query_len * pgss_max * 2)
2046  return false;
2047 
2048  return true;
2049 }
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:356
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  )
Datum pg_stat_statements ( PG_FUNCTION_ARGS  )

Definition at line 1370 of file pg_stat_statements.c.

References pg_stat_statements_internal(), and PGSS_V1_0.

1371 {
1372  /* If it's really API 1.1, we'll figure that out below */
1373  pg_stat_statements_internal(fcinfo, PGSS_V1_0, true);
1374 
1375  return (Datum) 0;
1376 }
static void pg_stat_statements_internal(FunctionCallInfo fcinfo, pgssVersion api_version, bool showtext)
uintptr_t Datum
Definition: postgres.h:372
Datum pg_stat_statements_1_2 ( PG_FUNCTION_ARGS  )

Definition at line 1356 of file pg_stat_statements.c.

References PG_GETARG_BOOL, pg_stat_statements_internal(), and PGSS_V1_2.

1357 {
1358  bool showtext = PG_GETARG_BOOL(0);
1359 
1360  pg_stat_statements_internal(fcinfo, PGSS_V1_2, showtext);
1361 
1362  return (Datum) 0;
1363 }
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:239
static void pg_stat_statements_internal(FunctionCallInfo fcinfo, pgssVersion api_version, bool showtext)
uintptr_t Datum
Definition: postgres.h:372
Datum pg_stat_statements_1_3 ( PG_FUNCTION_ARGS  )

Definition at line 1346 of file pg_stat_statements.c.

References PG_GETARG_BOOL, pg_stat_statements_internal(), and PGSS_V1_3.

1347 {
1348  bool showtext = PG_GETARG_BOOL(0);
1349 
1350  pg_stat_statements_internal(fcinfo, PGSS_V1_3, showtext);
1351 
1352  return (Datum) 0;
1353 }
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:239
static void pg_stat_statements_internal(FunctionCallInfo fcinfo, pgssVersion api_version, bool showtext)
uintptr_t Datum
Definition: postgres.h:372
static void pg_stat_statements_internal ( FunctionCallInfo  fcinfo,
pgssVersion  api_version,
bool  showtext 
)
static

Definition at line 1380 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_superuser(), 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, NULL, 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, superuser(), 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().

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

Definition at line 1318 of file pg_stat_statements.c.

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

1319 {
1320  if (!pgss || !pgss_hash)
1321  ereport(ERROR,
1322  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1323  errmsg("pg_stat_statements must be loaded via shared_preload_libraries")));
1324  entry_reset();
1325  PG_RETURN_VOID();
1326 }
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:309
int errmsg(const char *fmt,...)
Definition: elog.c:797
static void pgss_ExecutorEnd ( QueryDesc queryDesc)
static

Definition at line 921 of file pg_stat_statements.c.

References Instrumentation::bufusage, EState::es_processed, QueryDesc::estate, InstrEndLoop(), NULL, 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().

922 {
923  uint32 queryId = queryDesc->plannedstmt->queryId;
924 
925  if (queryId != 0 && queryDesc->totaltime && pgss_enabled())
926  {
927  /*
928  * Make sure stats accumulation is done. (Note: it's okay if several
929  * levels of hook all do this.)
930  */
931  InstrEndLoop(queryDesc->totaltime);
932 
933  pgss_store(queryDesc->sourceText,
934  queryId,
935  queryDesc->plannedstmt->stmt_location,
936  queryDesc->plannedstmt->stmt_len,
937  queryDesc->totaltime->total * 1000.0, /* convert to msec */
938  queryDesc->estate->es_processed,
939  &queryDesc->totaltime->bufusage,
940  NULL);
941  }
942 
943  if (prev_ExecutorEnd)
944  prev_ExecutorEnd(queryDesc);
945  else
946  standard_ExecutorEnd(queryDesc);
947 }
uint32 queryId
Definition: plannodes.h:47
EState * estate
Definition: execdesc.h:47
static ExecutorEnd_hook_type prev_ExecutorEnd
void standard_ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:462
#define pgss_enabled()
int stmt_len
Definition: plannodes.h:87
void InstrEndLoop(Instrumentation *instr)
Definition: instrument.c:114
int stmt_location
Definition: plannodes.h:86
unsigned int uint32
Definition: c.h:268
BufferUsage bufusage
Definition: instrument.h:63
struct Instrumentation * totaltime
Definition: execdesc.h:54
#define NULL
Definition: c.h:229
uint64 es_processed
Definition: execnodes.h:441
const char * sourceText
Definition: execdesc.h:38
PlannedStmt * plannedstmt
Definition: execdesc.h:37
static void pgss_store(const char *query, uint32 queryId, int query_location, int query_len, double total_time, uint64 rows, const BufferUsage *bufusage, pgssJumbleState *jstate)
static void pgss_ExecutorFinish ( QueryDesc queryDesc)
static

Definition at line 898 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().

899 {
900  nested_level++;
901  PG_TRY();
902  {
904  prev_ExecutorFinish(queryDesc);
905  else
906  standard_ExecutorFinish(queryDesc);
907  nested_level--;
908  }
909  PG_CATCH();
910  {
911  nested_level--;
912  PG_RE_THROW();
913  }
914  PG_END_TRY();
915 }
void standard_ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:402
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
static void pgss_ExecutorRun ( QueryDesc queryDesc,
ScanDirection  direction,
uint64  count,
bool  execute_once 
)
static

Definition at line 874 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().

876 {
877  nested_level++;
878  PG_TRY();
879  {
880  if (prev_ExecutorRun)
881  prev_ExecutorRun(queryDesc, direction, count, execute_once);
882  else
883  standard_ExecutorRun(queryDesc, direction, count, execute_once);
884  nested_level--;
885  }
886  PG_CATCH();
887  {
888  nested_level--;
889  PG_RE_THROW();
890  }
891  PG_END_TRY();
892 }
void standard_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: execMain.c:302
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
static void pgss_ExecutorStart ( QueryDesc queryDesc,
int  eflags 
)
static

Definition at line 840 of file pg_stat_statements.c.

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

Referenced by _PG_init().

841 {
842  if (prev_ExecutorStart)
843  prev_ExecutorStart(queryDesc, eflags);
844  else
845  standard_ExecutorStart(queryDesc, eflags);
846 
847  /*
848  * If query has queryId zero, don't track it. This prevents double
849  * counting of optimizable statements that are directly contained in
850  * utility statements.
851  */
852  if (pgss_enabled() && queryDesc->plannedstmt->queryId != 0)
853  {
854  /*
855  * Set up to track total elapsed time in ExecutorRun. Make sure the
856  * space is allocated in the per-query context so it will go away at
857  * ExecutorEnd.
858  */
859  if (queryDesc->totaltime == NULL)
860  {
861  MemoryContext oldcxt;
862 
863  oldcxt = MemoryContextSwitchTo(queryDesc->estate->es_query_cxt);
864  queryDesc->totaltime = InstrAlloc(1, INSTRUMENT_ALL);
865  MemoryContextSwitchTo(oldcxt);
866  }
867  }
868 }
uint32 queryId
Definition: plannodes.h:47
EState * estate
Definition: execdesc.h:47
void standard_ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:153
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:435
struct Instrumentation * totaltime
Definition: execdesc.h:54
#define NULL
Definition: c.h:229
PlannedStmt * plannedstmt
Definition: execdesc.h:37
static uint32 pgss_hash_fn ( const void *  key,
Size  keysize 
)
static

Definition at line 1069 of file pg_stat_statements.c.

References pgssHashKey::dbid, hash_uint32(), pgssHashKey::queryid, and pgssHashKey::userid.

Referenced by pgss_shmem_startup().

1070 {
1071  const pgssHashKey *k = (const pgssHashKey *) key;
1072 
1073  return hash_uint32((uint32) k->userid) ^
1074  hash_uint32((uint32) k->dbid) ^
1075  hash_uint32((uint32) k->queryid);
1076 }
unsigned int uint32
Definition: c.h:268
Datum hash_uint32(uint32 k)
Definition: hashfunc.c:512
static uint32 pgss_hash_string ( const char *  str,
int  len 
)
static

Definition at line 1101 of file pg_stat_statements.c.

References hash_any().

Referenced by pgss_store().

1102 {
1103  return hash_any((const unsigned char *) str, len);
1104 }
Datum hash_any(register const unsigned char *k, register int keylen)
Definition: hashfunc.c:307
static int pgss_match_fn ( const void *  key1,
const void *  key2,
Size  keysize 
)
static

Definition at line 1082 of file pg_stat_statements.c.

References pgssHashKey::dbid, pgssHashKey::queryid, and pgssHashKey::userid.

Referenced by pgss_shmem_startup().

1083 {
1084  const pgssHashKey *k1 = (const pgssHashKey *) key1;
1085  const pgssHashKey *k2 = (const pgssHashKey *) key2;
1086 
1087  if (k1->userid == k2->userid &&
1088  k1->dbid == k2->dbid &&
1089  k1->queryid == k2->queryid)
1090  return 0;
1091  else
1092  return 1;
1093 }
static Size pgss_memsize ( void  )
static

Definition at line 1667 of file pg_stat_statements.c.

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

Referenced by _PG_init().

1668 {
1669  Size size;
1670 
1671  size = MAXALIGN(sizeof(pgssSharedState));
1672  size = add_size(size, hash_estimate_size(pgss_max, sizeof(pgssEntry)));
1673 
1674  return size;
1675 }
static int pgss_max
Size hash_estimate_size(long num_entries, Size entrysize)
Definition: dynahash.c:711
Size add_size(Size s1, Size s2)
Definition: shmem.c:475
size_t Size
Definition: c.h:356
#define MAXALIGN(LEN)
Definition: c.h:588
static void pgss_post_parse_analyze ( ParseState pstate,
Query query 
)
static

Definition at line 771 of file pg_stat_statements.c.

References Assert, pgssJumbleState::clocations, pgssJumbleState::clocations_buf_size, pgssJumbleState::clocations_count, hash_any(), pgssJumbleState::jumble, pgssJumbleState::jumble_len, JUMBLE_SIZE, JumbleQuery(), NULL, 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().

772 {
773  pgssJumbleState jstate;
774 
776  prev_post_parse_analyze_hook(pstate, query);
777 
778  /* Assert we didn't do this already */
779  Assert(query->queryId == 0);
780 
781  /* Safety check... */
782  if (!pgss || !pgss_hash)
783  return;
784 
785  /*
786  * Utility statements get queryId zero. We do this even in cases where
787  * the statement contains an optimizable statement for which a queryId
788  * could be derived (such as EXPLAIN or DECLARE CURSOR). For such cases,
789  * runtime control will first go through ProcessUtility and then the
790  * executor, and we don't want the executor hooks to do anything, since we
791  * are already measuring the statement's costs at the utility level.
792  */
793  if (query->utilityStmt)
794  {
795  query->queryId = 0;
796  return;
797  }
798 
799  /* Set up workspace for query jumbling */
800  jstate.jumble = (unsigned char *) palloc(JUMBLE_SIZE);
801  jstate.jumble_len = 0;
802  jstate.clocations_buf_size = 32;
803  jstate.clocations = (pgssLocationLen *)
804  palloc(jstate.clocations_buf_size * sizeof(pgssLocationLen));
805  jstate.clocations_count = 0;
806 
807  /* Compute query ID and mark the Query node with it */
808  JumbleQuery(&jstate, query);
809  query->queryId = hash_any(jstate.jumble, jstate.jumble_len);
810 
811  /*
812  * If we are unlucky enough to get a hash of zero, use 1 instead, to
813  * prevent confusion with the utility-statement case.
814  */
815  if (query->queryId == 0)
816  query->queryId = 1;
817 
818  /*
819  * If we were able to identify any ignorable constants, we immediately
820  * create a hash table entry for the query, so that we can record the
821  * normalized form of the query string. If there were no such constants,
822  * the normalized string would be the same as the query text anyway, so
823  * there's no need for an early entry.
824  */
825  if (jstate.clocations_count > 0)
826  pgss_store(pstate->p_sourcetext,
827  query->queryId,
828  query->stmt_location,
829  query->stmt_len,
830  0,
831  0,
832  NULL,
833  &jstate);
834 }
uint32 queryId
Definition: parsenodes.h:107
int stmt_location
Definition: parsenodes.h:171
unsigned char * jumble
#define JUMBLE_SIZE
Node * utilityStmt
Definition: parsenodes.h:111
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:167
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
Datum hash_any(register const unsigned char *k, register int keylen)
Definition: hashfunc.c:307
void * palloc(Size size)
Definition: mcxt.c:849
static void pgss_store(const char *query, uint32 queryId, int query_location, int query_len, double total_time, uint64 rows, const BufferUsage *bufusage, pgssJumbleState *jstate)
int stmt_len
Definition: parsenodes.h:172
static void pgss_ProcessUtility ( PlannedStmt pstmt,
const char *  queryString,
ProcessUtilityContext  context,
ParamListInfo  params,
DestReceiver dest,
char *  completionTag 
)
static

Definition at line 953 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, NULL, 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().

956 {
957  Node *parsetree = pstmt->utilityStmt;
958 
959  /*
960  * If it's an EXECUTE statement, we don't track it and don't increment the
961  * nesting level. This allows the cycles to be charged to the underlying
962  * PREPARE instead (by the Executor hooks), which is much more useful.
963  *
964  * We also don't track execution of PREPARE. If we did, we would get one
965  * hash table entry for the PREPARE (with hash calculated from the query
966  * string), and then a different one with the same query string (but hash
967  * calculated from the query tree) would be used to accumulate costs of
968  * ensuing EXECUTEs. This would be confusing, and inconsistent with other
969  * cases where planning time is not included at all.
970  *
971  * Likewise, we don't track execution of DEALLOCATE.
972  */
973  if (pgss_track_utility && pgss_enabled() &&
974  !IsA(parsetree, ExecuteStmt) &&
975  !IsA(parsetree, PrepareStmt) &&
976  !IsA(parsetree, DeallocateStmt))
977  {
978  instr_time start;
980  uint64 rows;
981  BufferUsage bufusage_start,
982  bufusage;
983 
984  bufusage_start = pgBufferUsage;
985  INSTR_TIME_SET_CURRENT(start);
986 
987  nested_level++;
988  PG_TRY();
989  {
991  prev_ProcessUtility(pstmt, queryString,
992  context, params,
993  dest, completionTag);
994  else
995  standard_ProcessUtility(pstmt, queryString,
996  context, params,
997  dest, completionTag);
998  nested_level--;
999  }
1000  PG_CATCH();
1001  {
1002  nested_level--;
1003  PG_RE_THROW();
1004  }
1005  PG_END_TRY();
1006 
1007  INSTR_TIME_SET_CURRENT(duration);
1008  INSTR_TIME_SUBTRACT(duration, start);
1009 
1010  /* parse command tag to retrieve the number of affected rows. */
1011  if (completionTag &&
1012  strncmp(completionTag, "COPY ", 5) == 0)
1013  rows = pg_strtouint64(completionTag + 5, NULL, 10);
1014  else
1015  rows = 0;
1016 
1017  /* calc differences of buffer counters. */
1018  bufusage.shared_blks_hit =
1020  bufusage.shared_blks_read =
1022  bufusage.shared_blks_dirtied =
1024  bufusage.shared_blks_written =
1026  bufusage.local_blks_hit =
1027  pgBufferUsage.local_blks_hit - bufusage_start.local_blks_hit;
1028  bufusage.local_blks_read =
1030  bufusage.local_blks_dirtied =
1032  bufusage.local_blks_written =
1034  bufusage.temp_blks_read =
1035  pgBufferUsage.temp_blks_read - bufusage_start.temp_blks_read;
1036  bufusage.temp_blks_written =
1039  INSTR_TIME_SUBTRACT(bufusage.blk_read_time, bufusage_start.blk_read_time);
1041  INSTR_TIME_SUBTRACT(bufusage.blk_write_time, bufusage_start.blk_write_time);
1042 
1043  pgss_store(queryString,
1044  0, /* signal that it's a utility stmt */
1045  pstmt->stmt_location,
1046  pstmt->stmt_len,
1047  INSTR_TIME_GET_MILLISEC(duration),
1048  rows,
1049  &bufusage,
1050  NULL);
1051  }
1052  else
1053  {
1054  if (prev_ProcessUtility)
1055  prev_ProcessUtility(pstmt, queryString,
1056  context, params,
1057  dest, completionTag);
1058  else
1059  standard_ProcessUtility(pstmt, queryString,
1060  context, params,
1061  dest, completionTag);
1062  }
1063 }
long local_blks_hit
Definition: instrument.h:25
#define IsA(nodeptr, _type_)
Definition: nodes.h:557
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:506
#define pgss_enabled()
long temp_blks_written
Definition: instrument.h:30
int stmt_len
Definition: plannodes.h:87
int duration
Definition: pgbench.c:99
long shared_blks_written
Definition: instrument.h:24
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:167
int stmt_location
Definition: plannodes.h:86
Node * utilityStmt
Definition: plannodes.h:83
long shared_blks_dirtied
Definition: instrument.h:23
void standard_ProcessUtility(PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, DestReceiver *dest, char *completionTag)
Definition: utility.c:370
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
#define NULL
Definition: c.h:229
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
long shared_blks_hit
Definition: instrument.h:21
long local_blks_written
Definition: instrument.h:28
static void pgss_store(const char *query, uint32 queryId, int query_location, int query_len, double total_time, uint64 rows, const BufferUsage *bufusage, pgssJumbleState *jstate)
#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
static void pgss_shmem_shutdown ( int  code,
Datum  arg 
)
static

Definition at line 675 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, NULL, 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, pgssEntry::query_offset, and unlink().

Referenced by pgss_shmem_startup().

676 {
677  FILE *file;
678  char *qbuffer = NULL;
679  Size qbuffer_size = 0;
680  HASH_SEQ_STATUS hash_seq;
681  int32 num_entries;
682  pgssEntry *entry;
683 
684  /* Don't try to dump during a crash. */
685  if (code)
686  return;
687 
688  /* Safety check ... shouldn't get here unless shmem is set up. */
689  if (!pgss || !pgss_hash)
690  return;
691 
692  /* Don't dump if told not to. */
693  if (!pgss_save)
694  return;
695 
696  file = AllocateFile(PGSS_DUMP_FILE ".tmp", PG_BINARY_W);
697  if (file == NULL)
698  goto error;
699 
700  if (fwrite(&PGSS_FILE_HEADER, sizeof(uint32), 1, file) != 1)
701  goto error;
702  if (fwrite(&PGSS_PG_MAJOR_VERSION, sizeof(uint32), 1, file) != 1)
703  goto error;
704  num_entries = hash_get_num_entries(pgss_hash);
705  if (fwrite(&num_entries, sizeof(int32), 1, file) != 1)
706  goto error;
707 
708  qbuffer = qtext_load_file(&qbuffer_size);
709  if (qbuffer == NULL)
710  goto error;
711 
712  /*
713  * When serializing to disk, we store query texts immediately after their
714  * entry data. Any orphaned query texts are thereby excluded.
715  */
716  hash_seq_init(&hash_seq, pgss_hash);
717  while ((entry = hash_seq_search(&hash_seq)) != NULL)
718  {
719  int len = entry->query_len;
720  char *qstr = qtext_fetch(entry->query_offset, len,
721  qbuffer, qbuffer_size);
722 
723  if (qstr == NULL)
724  continue; /* Ignore any entries with bogus texts */
725 
726  if (fwrite(entry, sizeof(pgssEntry), 1, file) != 1 ||
727  fwrite(qstr, 1, len + 1, file) != len + 1)
728  {
729  /* note: we assume hash_seq_term won't change errno */
730  hash_seq_term(&hash_seq);
731  goto error;
732  }
733  }
734 
735  free(qbuffer);
736  qbuffer = NULL;
737 
738  if (FreeFile(file))
739  {
740  file = NULL;
741  goto error;
742  }
743 
744  /*
745  * Rename file into place, so we atomically replace any old one.
746  */
748 
749  /* Unlink query-texts file; it's not needed while shutdown */
751 
752  return;
753 
754 error:
755  ereport(LOG,
757  errmsg("could not write pg_stat_statement file \"%s\": %m",
758  PGSS_DUMP_FILE ".tmp")));
759  if (qbuffer)
760  free(qbuffer);
761  if (file)
762  FreeFile(file);
763  unlink(PGSS_DUMP_FILE ".tmp");
765 }
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:1041
long hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1297
#define LOG
Definition: elog.h:26
signed int int32
Definition: c.h:256
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:2094
unsigned int uint32
Definition: c.h:268
int unlink(const char *filename)
#define ereport(elevel, rest)
Definition: elog.h:122
int durable_rename(const char *oldfile, const char *newfile, int elevel)
Definition: fd.c:593
#define free(a)
Definition: header.h:65
#define NULL
Definition: c.h:229
size_t Size
Definition: c.h:356
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1353
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1343
int FreeFile(FILE *file)
Definition: fd.c:2277
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:1429
static bool pgss_save
static char * qtext_fetch(Size query_offset, int query_len, char *buffer, Size buffer_size)
static void pgss_shmem_startup ( void  )
static

Definition at line 454 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(), HASHCTL::hash, HASH_COMPARE, HASH_ELEM, HASH_FUNCTION, header(), i, IsUnderPostmaster, pgssEntry::key, HASHCTL::keysize, pgssSharedState::lock, LOG, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), HASHCTL::match, Max, pgssSharedState::mean_query_len, pgssSharedState::mutex, pgssSharedState::n_writers, NULL, on_shmem_exit(), palloc(), pfree(), PG_BINARY_R, PG_BINARY_W, PG_VALID_BE_ENCODING, PGSS_DUMP_FILE, PGSS_FILE_HEADER, pgss_hash_fn(), pgss_match_fn(), pgss_max, PGSS_PG_MAJOR_VERSION, pgss_save, pgss_shmem_shutdown(), PGSS_TEXT_FILE, prev_shmem_startup_hook, pgssEntry::query_len, repalloc(), ShmemInitHash(), ShmemInitStruct(), SpinLockInit, and unlink().

Referenced by _PG_init().

455 {
456  bool found;
457  HASHCTL info;
458  FILE *file = NULL;
459  FILE *qfile = NULL;
460  uint32 header;
461  int32 num;
462  int32 pgver;
463  int32 i;
464  int buffer_size;
465  char *buffer = NULL;
466 
469 
470  /* reset in case this is a restart within the postmaster */
471  pgss = NULL;
472  pgss_hash = NULL;
473 
474  /*
475  * Create or attach to the shared memory state, including hash table
476  */
477  LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE);
478 
479  pgss = ShmemInitStruct("pg_stat_statements",
480  sizeof(pgssSharedState),
481  &found);
482 
483  if (!found)
484  {
485  /* First time through ... */
486  pgss->lock = &(GetNamedLWLockTranche("pg_stat_statements"))->lock;
490  pgss->extent = 0;
491  pgss->n_writers = 0;
492  pgss->gc_count = 0;
493  }
494 
495  memset(&info, 0, sizeof(info));
496  info.keysize = sizeof(pgssHashKey);
497  info.entrysize = sizeof(pgssEntry);
498  info.hash = pgss_hash_fn;
499  info.match = pgss_match_fn;
500  pgss_hash = ShmemInitHash("pg_stat_statements hash",
502  &info,
504 
505  LWLockRelease(AddinShmemInitLock);
506 
507  /*
508  * If we're in the postmaster (or a standalone backend...), set up a shmem
509  * exit hook to dump the statistics to disk.
510  */
511  if (!IsUnderPostmaster)
513 
514  /*
515  * Done if some other process already completed our initialization.
516  */
517  if (found)
518  return;
519 
520  /*
521  * Note: we don't bother with locks here, because there should be no other
522  * processes running when this code is reached.
523  */
524 
525  /* Unlink query text file possibly left over from crash */
527 
528  /* Allocate new query text temp file */
530  if (qfile == NULL)
531  goto write_error;
532 
533  /*
534  * If we were told not to load old statistics, we're done. (Note we do
535  * not try to unlink any old dump file in this case. This seems a bit
536  * questionable but it's the historical behavior.)
537  */
538  if (!pgss_save)
539  {
540  FreeFile(qfile);
541  return;
542  }
543 
544  /*
545  * Attempt to load old statistics from the dump file.
546  */
548  if (file == NULL)
549  {
550  if (errno != ENOENT)
551  goto read_error;
552  /* No existing persisted stats file, so we're done */
553  FreeFile(qfile);
554  return;
555  }
556 
557  buffer_size = 2048;
558  buffer = (char *) palloc(buffer_size);
559 
560  if (fread(&header, sizeof(uint32), 1, file) != 1 ||
561  fread(&pgver, sizeof(uint32), 1, file) != 1 ||
562  fread(&num, sizeof(int32), 1, file) != 1)
563  goto read_error;
564 
565  if (header != PGSS_FILE_HEADER ||
566  pgver != PGSS_PG_MAJOR_VERSION)
567  goto data_error;
568 
569  for (i = 0; i < num; i++)
570  {
571  pgssEntry temp;
572  pgssEntry *entry;
573  Size query_offset;
574 
575  if (fread(&temp, sizeof(pgssEntry), 1, file) != 1)
576  goto read_error;
577 
578  /* Encoding is the only field we can easily sanity-check */
579  if (!PG_VALID_BE_ENCODING(temp.encoding))
580  goto data_error;
581 
582  /* Resize buffer as needed */
583  if (temp.query_len >= buffer_size)
584  {
585  buffer_size = Max(buffer_size * 2, temp.query_len + 1);
586  buffer = repalloc(buffer, buffer_size);
587  }
588 
589  if (fread(buffer, 1, temp.query_len + 1, file) != temp.query_len + 1)
590  goto read_error;
591 
592  /* Should have a trailing null, but let's make sure */
593  buffer[temp.query_len] = '\0';
594 
595  /* Skip loading "sticky" entries */
596  if (temp.counters.calls == 0)
597  continue;
598 
599  /* Store the query text */
600  query_offset = pgss->extent;
601  if (fwrite(buffer, 1, temp.query_len + 1, qfile) != temp.query_len + 1)
602  goto write_error;
603  pgss->extent += temp.query_len + 1;
604 
605  /* make the hashtable entry (discards old entries if too many) */
606  entry = entry_alloc(&temp.key, query_offset, temp.query_len,
607  temp.encoding,
608  false);
609 
610  /* copy in the actual stats */
611  entry->counters = temp.counters;
612  }
613 
614  pfree(buffer);
615  FreeFile(file);
616  FreeFile(qfile);
617 
618  /*
619  * Remove the persisted stats file so it's not included in
620  * backups/replication slaves, etc. A new file will be written on next
621  * shutdown.
622  *
623  * Note: it's okay if the PGSS_TEXT_FILE is included in a basebackup,
624  * because we remove that file on startup; it acts inversely to
625  * PGSS_DUMP_FILE, in that it is only supposed to be around when the
626  * server is running, whereas PGSS_DUMP_FILE is only supposed to be around
627  * when the server is not running. Leaving the file creates no danger of
628  * a newly restored database having a spurious record of execution costs,
629  * which is what we're really concerned about here.
630  */
632 
633  return;
634 
635 read_error:
636  ereport(LOG,
638  errmsg("could not read pg_stat_statement file \"%s\": %m",
639  PGSS_DUMP_FILE)));
640  goto fail;
641 data_error:
642  ereport(LOG,
643  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
644  errmsg("ignoring invalid data in pg_stat_statement file \"%s\"",
645  PGSS_DUMP_FILE)));
646  goto fail;
647 write_error:
648  ereport(LOG,
650  errmsg("could not write pg_stat_statement file \"%s\": %m",
651  PGSS_TEXT_FILE)));
652 fail:
653  if (buffer)
654  pfree(buffer);
655  if (file)
656  FreeFile(file);
657  if (qfile)
658  FreeFile(qfile);
659  /* If possible, throw away the bogus file; ignore any error */
661 
662  /*
663  * Don't unlink PGSS_TEXT_FILE here; it should always be around while the
664  * server is running with pg_stat_statements enabled
665  */
666 }
#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:1041
static int pgss_match_fn(const void *key1, const void *key2, Size keysize)
Counters counters
#define LOG
Definition: elog.h:26
#define PG_BINARY_R
Definition: c.h:1040
signed int int32
Definition: c.h:256
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1715
#define ASSUMED_LENGTH_INIT
static pgssSharedState * pgss
void pfree(void *pointer)
Definition: mcxt.c:950
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:348
bool IsUnderPostmaster
Definition: globals.c:100
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:2094
unsigned int uint32
Definition: c.h:268
int unlink(const char *filename)
#define ereport(elevel, rest)
Definition: elog.h:122
uintptr_t Datum
Definition: postgres.h:372
static void pgss_shmem_shutdown(int code, Datum arg)
Size keysize
Definition: hsearch.h:72
HashCompareFunc match
Definition: hsearch.h:75
pgssHashKey key
#define Max(x, y)
Definition: c.h:800
#define PG_VALID_BE_ENCODING(_enc)
Definition: pg_wchar.h:293
#define NULL
Definition: c.h:229
LWLockPadded * GetNamedLWLockTranche(const char *tranche_name)
Definition: lwlock.c:541
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:207
#define HASH_COMPARE
Definition: hsearch.h:90
size_t Size
Definition: c.h:356
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1111
static uint32 pgss_hash_fn(const void *key, Size keysize)
static void header(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:207
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:963
static shmem_startup_hook_type prev_shmem_startup_hook
int FreeFile(FILE *file)
Definition: fd.c:2277
void * palloc(Size size)
Definition: mcxt.c:849
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
HashValueFunc hash
Definition: hsearch.h:74
#define HASH_FUNCTION
Definition: hsearch.h:89
static void pgss_store ( const char *  query,
uint32  queryId,
int  query_location,
int  query_len,
double  total_time,
uint64  rows,
const BufferUsage bufusage,
pgssJumbleState jstate 
)
static

Definition at line 1117 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(), NULL, 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().

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

Definition at line 1998 of file pg_stat_statements.c.

References NULL.

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

2000 {
2001  /* File read failed? */
2002  if (buffer == NULL)
2003  return NULL;
2004  /* Bogus offset/length? */
2005  if (query_len < 0 ||
2006  query_offset + query_len >= buffer_size)
2007  return NULL;
2008  /* As a further sanity check, make sure there's a trailing null */
2009  if (buffer[query_offset + query_len] != '\0')
2010  return NULL;
2011  /* Looks OK */
2012  return buffer + query_offset;
2013 }
#define NULL
Definition: c.h:229
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:207
static char * qtext_load_file ( Size buffer_size)
static

Definition at line 1921 of file pg_stat_statements.c.

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

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

1922 {
1923  char *buf;
1924  int fd;
1925  struct stat stat;
1926 
1927  fd = OpenTransientFile(PGSS_TEXT_FILE, O_RDONLY | PG_BINARY, 0);
1928  if (fd < 0)
1929  {
1930  if (errno != ENOENT)
1931  ereport(LOG,
1933  errmsg("could not read pg_stat_statement file \"%s\": %m",
1934  PGSS_TEXT_FILE)));
1935  return NULL;
1936  }
1937 
1938  /* Get file length */
1939  if (fstat(fd, &stat))
1940  {
1941  ereport(LOG,
1943  errmsg("could not stat pg_stat_statement file \"%s\": %m",
1944  PGSS_TEXT_FILE)));
1945  CloseTransientFile(fd);
1946  return NULL;
1947  }
1948 
1949  /* Allocate buffer; beware that off_t might be wider than size_t */
1950  if (stat.st_size <= MaxAllocHugeSize)
1951  buf = (char *) malloc(stat.st_size);
1952  else
1953  buf = NULL;
1954  if (buf == NULL)
1955  {
1956  ereport(LOG,
1957  (errcode(ERRCODE_OUT_OF_MEMORY),
1958  errmsg("out of memory"),
1959  errdetail("Could not allocate enough memory to read pg_stat_statement file \"%s\".",
1960  PGSS_TEXT_FILE)));
1961  CloseTransientFile(fd);
1962  return NULL;
1963  }
1964 
1965  /*
1966  * OK, slurp in the file. If we get a short read and errno doesn't get
1967  * set, the reason is probably that garbage collection truncated the file
1968  * since we did the fstat(), so we don't log a complaint --- but we don't
1969  * return the data, either, since it's most likely corrupt due to
1970  * concurrent writes from garbage collection.
1971  */
1972  errno = 0;
1973  if (read(fd, buf, stat.st_size) != stat.st_size)
1974  {
1975  if (errno)
1976  ereport(LOG,
1978  errmsg("could not read pg_stat_statement file \"%s\": %m",
1979  PGSS_TEXT_FILE)));
1980  free(buf);
1981  CloseTransientFile(fd);
1982  return NULL;
1983  }
1984 
1985  CloseTransientFile(fd);
1986 
1987  *buffer_size = stat.st_size;
1988  return buf;
1989 }
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:1038
#define MaxAllocHugeSize
Definition: memutils.h:44
#define malloc(a)
Definition: header.h:50
static char * buf
Definition: pg_test_fsync.c:65
int OpenTransientFile(FileName fileName, int fileFlags, int fileMode)
Definition: fd.c:2144
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:2305
#define free(a)
Definition: header.h:65
#define NULL
Definition: c.h:229
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define PGSS_TEXT_FILE
#define read(a, b, c)
Definition: win32.h:18
static bool qtext_store ( const char *  query,
int  query_len,
Size query_offset,
int *  gc_count 
)
static

Definition at line 1837 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().

1839 {
1840  Size off;
1841  int fd;
1842 
1843  /*
1844  * We use a spinlock to protect extent/n_writers/gc_count, so that
1845  * multiple processes may execute this function concurrently.
1846  */
1847  {
1848  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
1849 
1850  SpinLockAcquire(&s->mutex);
1851  off = s->extent;
1852  s->extent += query_len + 1;
1853  s->n_writers++;
1854  if (gc_count)
1855  *gc_count = s->gc_count;
1856  SpinLockRelease(&s->mutex);
1857  }
1858 
1859  *query_offset = off;
1860 
1861  /* Now write the data into the successfully-reserved part of the file */
1862  fd = OpenTransientFile(PGSS_TEXT_FILE, O_RDWR | O_CREAT | PG_BINARY,
1863  S_IRUSR | S_IWUSR);
1864  if (fd < 0)
1865  goto error;
1866 
1867  if (lseek(fd, off, SEEK_SET) != off)
1868  goto error;
1869 
1870  if (write(fd, query, query_len) != query_len)
1871  goto error;
1872  if (write(fd, "\0", 1) != 1)
1873  goto error;
1874 
1875  CloseTransientFile(fd);
1876 
1877  /* Mark our write complete */
1878  {
1879  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
1880 
1881  SpinLockAcquire(&s->mutex);
1882  s->n_writers--;
1883  SpinLockRelease(&s->mutex);
1884  }
1885 
1886  return true;
1887 
1888 error:
1889  ereport(LOG,
1891  errmsg("could not write pg_stat_statement file \"%s\": %m",
1892  PGSS_TEXT_FILE)));
1893 
1894  if (fd >= 0)
1895  CloseTransientFile(fd);
1896 
1897  /* Mark our write complete */
1898  {
1899  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
1900 
1901  SpinLockAcquire(&s->mutex);
1902  s->n_writers--;
1903  SpinLockRelease(&s->mutex);
1904  }
1905 
1906  return false;
1907 }
static void error(void)
Definition: sql-dyntest.c:147
#define write(a, b, c)
Definition: win32.h:19
#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:1038
static pgssSharedState * pgss
#define SpinLockAcquire(lock)
Definition: spin.h:62
int OpenTransientFile(FileName fileName, int fileFlags, int fileMode)
Definition: fd.c:2144
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:2305
#define SpinLockRelease(lock)
Definition: spin.h:64
size_t Size
Definition: c.h:356
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define PGSS_TEXT_FILE
static void RecordConstLocation ( pgssJumbleState jstate,
int  location 
)
static

Definition at line 2906 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().

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

Variable Documentation

int nested_level = 0
static
PG_MODULE_MAGIC

Definition at line 81 of file pg_stat_statements.c.

pgssSharedState* pgss = NULL
static

Definition at line 239 of file pg_stat_statements.c.

const uint32 PGSS_FILE_HEADER = 0x20140125
static

Definition at line 97 of file pg_stat_statements.c.

Referenced by pgss_shmem_shutdown(), and pgss_shmem_startup().

HTAB* pgss_hash = NULL
static

Definition at line 240 of file pg_stat_statements.c.

int pgss_max
static
const uint32 PGSS_PG_MAJOR_VERSION = PG_VERSION_NUM / 100
static

Definition at line 100 of file pg_stat_statements.c.

Referenced by pgss_shmem_shutdown(), and pgss_shmem_startup().

bool pgss_save
static

Definition at line 262 of file pg_stat_statements.c.

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

int pgss_track
static

Definition at line 260 of file pg_stat_statements.c.

Referenced by _PG_init().

bool pgss_track_utility
static

Definition at line 261 of file pg_stat_statements.c.

Referenced by _PG_init(), and pgss_ProcessUtility().

ExecutorEnd_hook_type prev_ExecutorEnd = NULL
static

Definition at line 235 of file pg_stat_statements.c.

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

ExecutorFinish_hook_type prev_ExecutorFinish = NULL
static

Definition at line 234 of file pg_stat_statements.c.

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

ExecutorRun_hook_type prev_ExecutorRun = NULL
static

Definition at line 233 of file pg_stat_statements.c.

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

ExecutorStart_hook_type prev_ExecutorStart = NULL
static

Definition at line 232 of file pg_stat_statements.c.

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

post_parse_analyze_hook_type prev_post_parse_analyze_hook = NULL
static

Definition at line 231 of file pg_stat_statements.c.

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

ProcessUtility_hook_type prev_ProcessUtility = NULL
static

Definition at line 236 of file pg_stat_statements.c.

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

shmem_startup_hook_type prev_shmem_startup_hook = NULL
static

Definition at line 230 of file pg_stat_statements.c.

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

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}
}
#define NULL
Definition: c.h:229

Definition at line 251 of file pg_stat_statements.c.