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)
 
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 2335 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 2337 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 1332 of file pg_stat_statements.c.

Referenced by pg_stat_statements_internal().

#define PG_STAT_STATEMENTS_COLS_V1_0   14

Definition at line 1328 of file pg_stat_statements.c.

Referenced by pg_stat_statements_internal().

#define PG_STAT_STATEMENTS_COLS_V1_1   18

Definition at line 1329 of file pg_stat_statements.c.

Referenced by pg_stat_statements_internal().

#define PG_STAT_STATEMENTS_COLS_V1_2   19

Definition at line 1330 of file pg_stat_statements.c.

Referenced by pg_stat_statements_internal().

#define PG_STAT_STATEMENTS_COLS_V1_3   23

Definition at line 1331 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:68
ExecutorRun_hook_type ExecutorRun_hook
Definition: execMain.c:69
ExecutorEnd_hook_type ExecutorEnd_hook
Definition: execMain.c:71
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:70
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:7713
void RequestAddinShmemSpace(Size size)
Definition: ipci.c:69
bool process_shared_preload_libraries_in_progress
Definition: miscinit.c:1401
void RequestNamedLWLockTranche(const char *tranche_name, int num_lwlocks)
Definition: lwlock.c:626
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:7798
ExecutorStart_hook_type ExecutorStart_hook
Definition: execMain.c:68
static int pgss_max
ExecutorRun_hook_type ExecutorRun_hook
Definition: execMain.c:69
ExecutorEnd_hook_type ExecutorEnd_hook
Definition: execMain.c:71
static void pgss_post_parse_analyze(ParseState *pstate, Query *query)
Definition: guc.h:75
void EmitWarningsOnPlaceholders(const char *className)
Definition: guc.c:7826
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:226
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:70
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:7687
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 pgss_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count)
static void AppendJumble ( pgssJumbleState jstate,
const unsigned char *  item,
Size  size 
)
static

Definition at line 2301 of file pg_stat_statements.c.

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

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

Definition at line 3129 of file pg_stat_statements.c.

Referenced by fill_in_constant_lengths().

3130 {
3131  int l = ((const pgssLocationLen *) a)->location;
3132  int r = ((const pgssLocationLen *) b)->location;
3133 
3134  if (l < r)
3135  return -1;
3136  else if (l > r)
3137  return +1;
3138  else
3139  return 0;
3140 }
static pgssEntry * entry_alloc ( pgssHashKey key,
Size  query_offset,
int  query_len,
int  encoding,
bool  sticky 
)
static

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

1696 {
1697  pgssEntry *entry;
1698  bool found;
1699 
1700  /* Make space if needed */
1702  entry_dealloc();
1703 
1704  /* Find or create an entry with desired hash code */
1705  entry = (pgssEntry *) hash_search(pgss_hash, key, HASH_ENTER, &found);
1706 
1707  if (!found)
1708  {
1709  /* New entry, initialize it */
1710 
1711  /* reset the statistics */
1712  memset(&entry->counters, 0, sizeof(Counters));
1713  /* set the appropriate initial usage count */
1714  entry->counters.usage = sticky ? pgss->cur_median_usage : USAGE_INIT;
1715  /* re-initialize the mutex each time ... we assume no one using it */
1716  SpinLockInit(&entry->mutex);
1717  /* ... and don't forget the query text metadata */
1718  Assert(query_len >= 0);
1719  entry->query_offset = query_offset;
1720  entry->query_len = query_len;
1721  entry->encoding = encoding;
1722  }
1723 
1724  return entry;
1725 }
#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:121
#define Assert(condition)
Definition: c.h:670
static int entry_cmp ( const void *  lhs,
const void *  rhs 
)
static

Definition at line 1731 of file pg_stat_statements.c.

Referenced by entry_dealloc().

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

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

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

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

2252 {
2253  HASH_SEQ_STATUS hash_seq;
2254  pgssEntry *entry;
2255  FILE *qfile;
2256 
2258 
2259  hash_seq_init(&hash_seq, pgss_hash);
2260  while ((entry = hash_seq_search(&hash_seq)) != NULL)
2261  {
2263  }
2264 
2265  /*
2266  * Write new empty query file, perhaps even creating a new one to recover
2267  * if the file was missing.
2268  */
2270  if (qfile == NULL)
2271  {
2272  ereport(LOG,
2274  errmsg("could not create pg_stat_statement file \"%s\": %m",
2275  PGSS_TEXT_FILE)));
2276  goto done;
2277  }
2278 
2279  /* If ftruncate fails, log it, but it's not a fatal problem */
2280  if (ftruncate(fileno(qfile), 0) != 0)
2281  ereport(LOG,
2283  errmsg("could not truncate pg_stat_statement file \"%s\": %m",
2284  PGSS_TEXT_FILE)));
2285 
2286  FreeFile(qfile);
2287 
2288 done:
2289  pgss->extent = 0;
2290  /* This counts as a query text garbage collection for our purposes */
2291  record_gc_qtexts();
2292 
2294 }
#define PG_BINARY_W
Definition: c.h:1040
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:1714
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:2043
#define ereport(elevel, rest)
Definition: elog.h:122
pgssHashKey key
#define ftruncate(a, b)
Definition: win32.h:67
#define NULL
Definition: c.h:226
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
#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:2226
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 3029 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().

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

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

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

Definition at line 2437 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(), CollateExpr::collOid, OnConflictExpr::constraint, Const::consttype, GroupingSet::content, CommonTableExpr::ctename, CommonTableExpr::ctequery, CurrentOfExpr::cursor_name, CurrentOfExpr::cursor_param, CurrentOfExpr::cvarno, CaseExpr::defresult, 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, 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_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().

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

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

2351 {
2352  Assert(IsA(query, Query));
2353  Assert(query->utilityStmt == NULL);
2354 
2355  APP_JUMB(query->commandType);
2356  /* resultRelation is usually predictable from commandType */
2357  JumbleExpr(jstate, (Node *) query->cteList);
2358  JumbleRangeTable(jstate, query->rtable);
2359  JumbleExpr(jstate, (Node *) query->jointree);
2360  JumbleExpr(jstate, (Node *) query->targetList);
2361  JumbleExpr(jstate, (Node *) query->onConflict);
2362  JumbleExpr(jstate, (Node *) query->returningList);
2363  JumbleExpr(jstate, (Node *) query->groupClause);
2364  JumbleExpr(jstate, (Node *) query->groupingSets);
2365  JumbleExpr(jstate, query->havingQual);
2366  JumbleExpr(jstate, (Node *) query->windowClause);
2367  JumbleExpr(jstate, (Node *) query->distinctClause);
2368  JumbleExpr(jstate, (Node *) query->sortClause);
2369  JumbleExpr(jstate, query->limitOffset);
2370  JumbleExpr(jstate, query->limitCount);
2371  /* we ignore rowMarks */
2372  JumbleExpr(jstate, query->setOperations);
2373 }
Node * limitOffset
Definition: parsenodes.h:149
static void JumbleExpr(pgssJumbleState *jstate, Node *node)
#define IsA(nodeptr, _type_)
Definition: nodes.h:559
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:508
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:226
#define Assert(condition)
Definition: c.h:670
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 2379 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_VALUES, RangeTblEntry::rtekind, RangeTblEntry::subquery, RangeTblEntry::tablesample, and RangeTblEntry::values_lists.

Referenced by JumbleQuery().

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

Definition at line 2020 of file pg_stat_statements.c.

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

Referenced by gc_qtexts(), and pgss_store().

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

References pg_stat_statements_internal(), and PGSS_V1_0.

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

Definition at line 1355 of file pg_stat_statements.c.

References PG_GETARG_BOOL, pg_stat_statements_internal(), and PGSS_V1_2.

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

Definition at line 1345 of file pg_stat_statements.c.

References PG_GETARG_BOOL, pg_stat_statements_internal(), and PGSS_V1_3.

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

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

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

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

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

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

921 {
922  uint32 queryId = queryDesc->plannedstmt->queryId;
923 
924  if (queryId != 0 && queryDesc->totaltime && pgss_enabled())
925  {
926  /*
927  * Make sure stats accumulation is done. (Note: it's okay if several
928  * levels of hook all do this.)
929  */
930  InstrEndLoop(queryDesc->totaltime);
931 
932  pgss_store(queryDesc->sourceText,
933  queryId,
934  queryDesc->plannedstmt->stmt_location,
935  queryDesc->plannedstmt->stmt_len,
936  queryDesc->totaltime->total * 1000.0, /* convert to msec */
937  queryDesc->estate->es_processed,
938  &queryDesc->totaltime->bufusage,
939  NULL);
940  }
941 
942  if (prev_ExecutorEnd)
943  prev_ExecutorEnd(queryDesc);
944  else
945  standard_ExecutorEnd(queryDesc);
946 }
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:448
#define pgss_enabled()
int stmt_len
Definition: plannodes.h:84
void InstrEndLoop(Instrumentation *instr)
Definition: instrument.c:114
int stmt_location
Definition: plannodes.h:83
unsigned int uint32
Definition: c.h:265
BufferUsage bufusage
Definition: instrument.h:63
struct Instrumentation * totaltime
Definition: execdesc.h:51
#define NULL
Definition: c.h:226
uint64 es_processed
Definition: execnodes.h:403
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 897 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().

898 {
899  nested_level++;
900  PG_TRY();
901  {
903  prev_ExecutorFinish(queryDesc);
904  else
905  standard_ExecutorFinish(queryDesc);
906  nested_level--;
907  }
908  PG_CATCH();
909  {
910  nested_level--;
911  PG_RE_THROW();
912  }
913  PG_END_TRY();
914 }
void standard_ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:388
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 
)
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().

875 {
876  nested_level++;
877  PG_TRY();
878  {
879  if (prev_ExecutorRun)
880  prev_ExecutorRun(queryDesc, direction, count);
881  else
882  standard_ExecutorRun(queryDesc, direction, count);
883  nested_level--;
884  }
885  PG_CATCH();
886  {
887  nested_level--;
888  PG_RE_THROW();
889  }
890  PG_END_TRY();
891 }
static ExecutorRun_hook_type prev_ExecutorRun
void standard_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count)
Definition: execMain.c:295
#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:147
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:397
struct Instrumentation * totaltime
Definition: execdesc.h:51
#define NULL
Definition: c.h:226
PlannedStmt * plannedstmt
Definition: execdesc.h:37
static uint32 pgss_hash_fn ( const void *  key,
Size  keysize 
)
static

Definition at line 1068 of file pg_stat_statements.c.

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

Referenced by pgss_shmem_startup().

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

Definition at line 1100 of file pg_stat_statements.c.

References hash_any().

Referenced by pgss_store().

1101 {
1102  return hash_any((const unsigned char *) str, len);
1103 }
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 1081 of file pg_stat_statements.c.

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

Referenced by pgss_shmem_startup().

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

Definition at line 1666 of file pg_stat_statements.c.

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

Referenced by _PG_init().

1667 {
1668  Size size;
1669 
1670  size = MAXALIGN(sizeof(pgssSharedState));
1671  size = add_size(size, hash_estimate_size(pgss_max, sizeof(pgssEntry)));
1672 
1673  return size;
1674 }
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:352
#define MAXALIGN(LEN)
Definition: c.h:583
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:226
#define Assert(condition)
Definition: c.h:670
Datum hash_any(register const unsigned char *k, register int keylen)
Definition: hashfunc.c:307
void * palloc(Size size)
Definition: mcxt.c:891
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 952 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().

955 {
956  Node *parsetree = pstmt->utilityStmt;
957 
958  /*
959  * If it's an EXECUTE statement, we don't track it and don't increment the
960  * nesting level. This allows the cycles to be charged to the underlying
961  * PREPARE instead (by the Executor hooks), which is much more useful.
962  *
963  * We also don't track execution of PREPARE. If we did, we would get one
964  * hash table entry for the PREPARE (with hash calculated from the query
965  * string), and then a different one with the same query string (but hash
966  * calculated from the query tree) would be used to accumulate costs of
967  * ensuing EXECUTEs. This would be confusing, and inconsistent with other
968  * cases where planning time is not included at all.
969  *
970  * Likewise, we don't track execution of DEALLOCATE.
971  */
972  if (pgss_track_utility && pgss_enabled() &&
973  !IsA(parsetree, ExecuteStmt) &&
974  !IsA(parsetree, PrepareStmt) &&
975  !IsA(parsetree, DeallocateStmt))
976  {
977  instr_time start;
979  uint64 rows;
980  BufferUsage bufusage_start,
981  bufusage;
982 
983  bufusage_start = pgBufferUsage;
984  INSTR_TIME_SET_CURRENT(start);
985 
986  nested_level++;
987  PG_TRY();
988  {
990  prev_ProcessUtility(pstmt, queryString,
991  context, params,
992  dest, completionTag);
993  else
994  standard_ProcessUtility(pstmt, queryString,
995  context, params,
996  dest, completionTag);
997  nested_level--;
998  }
999  PG_CATCH();
1000  {
1001  nested_level--;
1002  PG_RE_THROW();
1003  }
1004  PG_END_TRY();
1005 
1006  INSTR_TIME_SET_CURRENT(duration);
1007  INSTR_TIME_SUBTRACT(duration, start);
1008 
1009  /* parse command tag to retrieve the number of affected rows. */
1010  if (completionTag &&
1011  strncmp(completionTag, "COPY ", 5) == 0)
1012  rows = pg_strtouint64(completionTag + 5, NULL, 10);
1013  else
1014  rows = 0;
1015 
1016  /* calc differences of buffer counters. */
1017  bufusage.shared_blks_hit =
1019  bufusage.shared_blks_read =
1021  bufusage.shared_blks_dirtied =
1023  bufusage.shared_blks_written =
1025  bufusage.local_blks_hit =
1026  pgBufferUsage.local_blks_hit - bufusage_start.local_blks_hit;
1027  bufusage.local_blks_read =
1029  bufusage.local_blks_dirtied =
1031  bufusage.local_blks_written =
1033  bufusage.temp_blks_read =
1034  pgBufferUsage.temp_blks_read - bufusage_start.temp_blks_read;
1035  bufusage.temp_blks_written =
1038  INSTR_TIME_SUBTRACT(bufusage.blk_read_time, bufusage_start.blk_read_time);
1040  INSTR_TIME_SUBTRACT(bufusage.blk_write_time, bufusage_start.blk_write_time);
1041 
1042  pgss_store(queryString,
1043  0, /* signal that it's a utility stmt */
1044  pstmt->stmt_location,
1045  pstmt->stmt_len,
1046  INSTR_TIME_GET_MILLISEC(duration),
1047  rows,
1048  &bufusage,
1049  NULL);
1050  }
1051  else
1052  {
1053  if (prev_ProcessUtility)
1054  prev_ProcessUtility(pstmt, queryString,
1055  context, params,
1056  dest, completionTag);
1057  else
1058  standard_ProcessUtility(pstmt, queryString,
1059  context, params,
1060  dest, completionTag);
1061  }
1062 }
long local_blks_hit
Definition: instrument.h:25
#define IsA(nodeptr, _type_)
Definition: nodes.h:559
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:508
#define pgss_enabled()
long temp_blks_written
Definition: instrument.h:30
int stmt_len
Definition: plannodes.h:84
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:83
Node * utilityStmt
Definition: plannodes.h:80
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:226
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:1040
long hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1297
#define LOG
Definition: elog.h:26
signed int int32
Definition: c.h:253
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:2043
unsigned int uint32
Definition: c.h:265
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:60
#define NULL
Definition: c.h:226
size_t Size
Definition: c.h:352
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:2226
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, 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:1040
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:1039
signed int int32
Definition: c.h:253
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1714
#define ASSUMED_LENGTH_INIT
static pgssSharedState * pgss
void pfree(void *pointer)
Definition: mcxt.c:992
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:2043
unsigned int uint32
Definition: c.h:265
int unlink(const char *filename)
#define ereport(elevel, rest)
Definition: elog.h:122
uintptr_t Datum
Definition: postgres.h:374
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:795
#define PG_VALID_BE_ENCODING(_enc)
Definition: pg_wchar.h:293
#define NULL
Definition: c.h:226
LWLockPadded * GetNamedLWLockTranche(const char *tranche_name)
Definition: lwlock.c:540
#define HASH_COMPARE
Definition: hsearch.h:90
size_t Size
Definition: c.h:352
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
static uint32 pgss_hash_fn(const void *key, Size keysize)
static void header(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:205
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1021
static shmem_startup_hook_type prev_shmem_startup_hook
int FreeFile(FILE *file)
Definition: fd.c:2226
void * palloc(Size size)
Definition: mcxt.c:891
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 1116 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().

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

References NULL.

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

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

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

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

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

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

2894 {
2895  /* -1 indicates unknown or undefined location */
2896  if (location >= 0)
2897  {
2898  /* enlarge array if needed */
2899  if (jstate->clocations_count >= jstate->clocations_buf_size)
2900  {
2901  jstate->clocations_buf_size *= 2;
2902  jstate->clocations = (pgssLocationLen *)
2903  repalloc(jstate->clocations,
2904  jstate->clocations_buf_size *
2905  sizeof(pgssLocationLen));
2906  }
2907  jstate->clocations[jstate->clocations_count].location = location;
2908  /* initialize lengths to -1 to simplify fill_in_constant_lengths */
2909  jstate->clocations[jstate->clocations_count].length = -1;
2910  jstate->clocations_count++;
2911  }
2912 }
pgssLocationLen * clocations
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1021

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

Definition at line 251 of file pg_stat_statements.c.