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 "catalog/pg_authid.h"
#include "executor/instrument.h"
#include "funcapi.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "parser/analyze.h"
#include "parser/parsetree.h"
#include "parser/scanner.h"
#include "parser/scansup.h"
#include "pgstat.h"
#include "storage/fd.h"
#include "storage/ipc.h"
#include "storage/spin.h"
#include "tcop/utility.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
Include dependency graph for pg_stat_statements.c:

Go to the source code of this file.

Data Structures

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

Macros

#define PGSS_DUMP_FILE   PGSTAT_STAT_PERMANENT_DIRECTORY "/pg_stat_statements.stat"
 
#define PGSS_TEXT_FILE   PG_STAT_TMP_DIR "/pgss_query_texts.stat"
 
#define USAGE_EXEC(duration)   (1.0)
 
#define USAGE_INIT   (1.0) /* including initial planning */
 
#define ASSUMED_MEDIAN_INIT   (10.0) /* initial assumed median usage */
 
#define ASSUMED_LENGTH_INIT   1024 /* initial assumed mean query length */
 
#define USAGE_DECREASE_FACTOR   (0.99) /* decreased every entry_dealloc */
 
#define STICKY_DECREASE_FACTOR   (0.50) /* factor for sticky entries */
 
#define USAGE_DEALLOC_PERCENT   5 /* free this % of entries at once */
 
#define JUMBLE_SIZE   1024 /* query serialization buffer size */
 
#define pgss_enabled()
 
#define record_gc_qtexts()
 
#define PG_STAT_STATEMENTS_COLS_V1_0   14
 
#define PG_STAT_STATEMENTS_COLS_V1_1   18
 
#define PG_STAT_STATEMENTS_COLS_V1_2   19
 
#define PG_STAT_STATEMENTS_COLS_V1_3   23
 
#define PG_STAT_STATEMENTS_COLS   23 /* maximum of above */
 
#define APP_JUMB(item)   AppendJumble(jstate, (const unsigned char *) &(item), sizeof(item))
 
#define APP_JUMB_STRING(str)   AppendJumble(jstate, (const unsigned char *) (str), strlen(str) + 1)
 

Typedefs

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

Enumerations

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

Functions

void _PG_init (void)
 
void _PG_fini (void)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_reset)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_1_2)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements_1_3)
 
 PG_FUNCTION_INFO_V1 (pg_stat_statements)
 
static void pgss_shmem_startup (void)
 
static void pgss_shmem_shutdown (int code, Datum arg)
 
static void pgss_post_parse_analyze (ParseState *pstate, Query *query)
 
static void pgss_ExecutorStart (QueryDesc *queryDesc, int eflags)
 
static void pgss_ExecutorRun (QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
 
static void pgss_ExecutorFinish (QueryDesc *queryDesc)
 
static void pgss_ExecutorEnd (QueryDesc *queryDesc)
 
static void pgss_ProcessUtility (PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, char *completionTag)
 
static 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 2346 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 2348 of file pg_stat_statements.c.

Referenced by JumbleExpr(), and JumbleRangeTable().

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

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

Referenced by pgss_shmem_startup().

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

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

Referenced by pg_stat_statements_internal().

#define PG_STAT_STATEMENTS_COLS_V1_0   14

Definition at line 1336 of file pg_stat_statements.c.

Referenced by pg_stat_statements_internal().

#define PG_STAT_STATEMENTS_COLS_V1_1   18

Definition at line 1337 of file pg_stat_statements.c.

Referenced by pg_stat_statements_internal().

#define PG_STAT_STATEMENTS_COLS_V1_2   19

Definition at line 1338 of file pg_stat_statements.c.

Referenced by pg_stat_statements_internal().

#define PG_STAT_STATEMENTS_COLS_V1_3   23

Definition at line 1339 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 85 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 273 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 109 of file pg_stat_statements.c.

Referenced by entry_dealloc().

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

Definition at line 110 of file pg_stat_statements.c.

Referenced by entry_dealloc().

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

Definition at line 108 of file pg_stat_statements.c.

Referenced by entry_dealloc().

#define USAGE_EXEC (   duration)    (1.0)

Definition at line 104 of file pg_stat_statements.c.

Referenced by pgss_store().

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

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

249 {
250  PGSS_TRACK_NONE, /* track no statements */
251  PGSS_TRACK_TOP, /* only top level statements */
252  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 117 of file pg_stat_statements.c.

Function Documentation

void _PG_fini ( void  )

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

441 {
442  /* Uninstall hooks. */
450 }
static ProcessUtility_hook_type prev_ProcessUtility
static ExecutorRun_hook_type prev_ExecutorRun
static ExecutorEnd_hook_type prev_ExecutorEnd
ProcessUtility_hook_type ProcessUtility_hook
Definition: utility.c:73
static ExecutorStart_hook_type prev_ExecutorStart
static post_parse_analyze_hook_type prev_post_parse_analyze_hook
ExecutorStart_hook_type ExecutorStart_hook
Definition: execMain.c:69
ExecutorRun_hook_type ExecutorRun_hook
Definition: execMain.c:70
ExecutorEnd_hook_type ExecutorEnd_hook
Definition: execMain.c:72
static ExecutorFinish_hook_type prev_ExecutorFinish
shmem_startup_hook_type shmem_startup_hook
Definition: ipci.c:51
static shmem_startup_hook_type prev_shmem_startup_hook
ExecutorFinish_hook_type ExecutorFinish_hook
Definition: execMain.c:71
post_parse_analyze_hook_type post_parse_analyze_hook
Definition: analyze.c:49
void _PG_init ( void  )

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

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

Definition at line 2312 of file pg_stat_statements.c.

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

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

Definition at line 3171 of file pg_stat_statements.c.

Referenced by fill_in_constant_lengths().

3172 {
3173  int l = ((const pgssLocationLen *) a)->location;
3174  int r = ((const pgssLocationLen *) b)->location;
3175 
3176  if (l < r)
3177  return -1;
3178  else if (l > r)
3179  return +1;
3180  else
3181  return 0;
3182 }
static pgssEntry * entry_alloc ( pgssHashKey key,
Size  query_offset,
int  query_len,
int  encoding,
bool  sticky 
)
static

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

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

Definition at line 1742 of file pg_stat_statements.c.

Referenced by entry_dealloc().

1743 {
1744  double l_usage = (*(pgssEntry *const *) lhs)->counters.usage;
1745  double r_usage = (*(pgssEntry *const *) rhs)->counters.usage;
1746 
1747  if (l_usage < r_usage)
1748  return -1;
1749  else if (l_usage > r_usage)
1750  return +1;
1751  else
1752  return 0;
1753 }
static void entry_dealloc ( void  )
static

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

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

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

2263 {
2264  HASH_SEQ_STATUS hash_seq;
2265  pgssEntry *entry;
2266  FILE *qfile;
2267 
2269 
2270  hash_seq_init(&hash_seq, pgss_hash);
2271  while ((entry = hash_seq_search(&hash_seq)) != NULL)
2272  {
2274  }
2275 
2276  /*
2277  * Write new empty query file, perhaps even creating a new one to recover
2278  * if the file was missing.
2279  */
2281  if (qfile == NULL)
2282  {
2283  ereport(LOG,
2285  errmsg("could not create pg_stat_statement file \"%s\": %m",
2286  PGSS_TEXT_FILE)));
2287  goto done;
2288  }
2289 
2290  /* If ftruncate fails, log it, but it's not a fatal problem */
2291  if (ftruncate(fileno(qfile), 0) != 0)
2292  ereport(LOG,
2294  errmsg("could not truncate pg_stat_statement file \"%s\": %m",
2295  PGSS_TEXT_FILE)));
2296 
2297  FreeFile(qfile);
2298 
2299 done:
2300  pgss->extent = 0;
2301  /* This counts as a query text garbage collection for our purposes */
2302  record_gc_qtexts();
2303 
2305 }
#define PG_BINARY_W
Definition: c.h:1041
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:885
#define LOG
Definition: elog.h:26
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1715
static pgssSharedState * pgss
static HTAB * pgss_hash
int errcode_for_file_access(void)
Definition: elog.c:598
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2094
#define ereport(elevel, rest)
Definition: elog.h:122
pgssHashKey key
#define ftruncate(a, b)
Definition: win32.h:59
#define NULL
Definition: c.h:229
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1111
#define record_gc_qtexts()
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1351
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1341
int FreeFile(FILE *file)
Definition: fd.c:2277
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define PGSS_TEXT_FILE
static void fill_in_constant_lengths ( pgssJumbleState jstate,
const char *  query,
int  query_loc 
)
static

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

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

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

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

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

Referenced by pgss_store().

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

Definition at line 2454 of file pg_stat_statements.c.

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

Referenced by JumbleQuery(), and JumbleRangeTable().

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

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

2362 {
2363  Assert(IsA(query, Query));
2364  Assert(query->utilityStmt == NULL);
2365 
2366  APP_JUMB(query->commandType);
2367  /* resultRelation is usually predictable from commandType */
2368  JumbleExpr(jstate, (Node *) query->cteList);
2369  JumbleRangeTable(jstate, query->rtable);
2370  JumbleExpr(jstate, (Node *) query->jointree);
2371  JumbleExpr(jstate, (Node *) query->targetList);
2372  JumbleExpr(jstate, (Node *) query->onConflict);
2373  JumbleExpr(jstate, (Node *) query->returningList);
2374  JumbleExpr(jstate, (Node *) query->groupClause);
2375  JumbleExpr(jstate, (Node *) query->groupingSets);
2376  JumbleExpr(jstate, query->havingQual);
2377  JumbleExpr(jstate, (Node *) query->windowClause);
2378  JumbleExpr(jstate, (Node *) query->distinctClause);
2379  JumbleExpr(jstate, (Node *) query->sortClause);
2380  JumbleExpr(jstate, query->limitOffset);
2381  JumbleExpr(jstate, query->limitCount);
2382  /* we ignore rowMarks */
2383  JumbleExpr(jstate, query->setOperations);
2384 }
Node * limitOffset
Definition: parsenodes.h:158
static void JumbleExpr(pgssJumbleState *jstate, Node *node)
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
List * sortClause
Definition: parsenodes.h:156
FromExpr * jointree
Definition: parsenodes.h:136
OnConflictExpr * onConflict
Definition: parsenodes.h:142
List * groupingSets
Definition: parsenodes.h:148
Definition: nodes.h:509
Node * utilityStmt
Definition: parsenodes.h:118
List * windowClause
Definition: parsenodes.h:152
List * targetList
Definition: parsenodes.h:138
static void JumbleRangeTable(pgssJumbleState *jstate, List *rtable)
List * rtable
Definition: parsenodes.h:135
List * distinctClause
Definition: parsenodes.h:154
#define APP_JUMB(item)
Node * limitCount
Definition: parsenodes.h:159
List * returningList
Definition: parsenodes.h:144
CmdType commandType
Definition: parsenodes.h:110
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
List * cteList
Definition: parsenodes.h:133
Node * setOperations
Definition: parsenodes.h:163
List * groupClause
Definition: parsenodes.h:146
Node * havingQual
Definition: parsenodes.h:150
static void JumbleRangeTable ( pgssJumbleState jstate,
List rtable 
)
static

Definition at line 2390 of file pg_stat_statements.c.

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

Referenced by JumbleQuery().

2391 {
2392  ListCell *lc;
2393 
2394  foreach(lc, rtable)
2395  {
2397 
2398  APP_JUMB(rte->rtekind);
2399  switch (rte->rtekind)
2400  {
2401  case RTE_RELATION:
2402  APP_JUMB(rte->relid);
2403  JumbleExpr(jstate, (Node *) rte->tablesample);
2404  break;
2405  case RTE_SUBQUERY:
2406  JumbleQuery(jstate, rte->subquery);
2407  break;
2408  case RTE_JOIN:
2409  APP_JUMB(rte->jointype);
2410  break;
2411  case RTE_FUNCTION:
2412  JumbleExpr(jstate, (Node *) rte->functions);
2413  break;
2414  case RTE_TABLEFUNC:
2415  JumbleExpr(jstate, (Node *) rte->tablefunc);
2416  break;
2417  case RTE_VALUES:
2418  JumbleExpr(jstate, (Node *) rte->values_lists);
2419  break;
2420  case RTE_CTE:
2421 
2422  /*
2423  * Depending on the CTE name here isn't ideal, but it's the
2424  * only info we have to identify the referenced WITH item.
2425  */
2426  APP_JUMB_STRING(rte->ctename);
2427  APP_JUMB(rte->ctelevelsup);
2428  break;
2429  case RTE_NAMEDTUPLESTORE:
2430  APP_JUMB_STRING(rte->enrname);
2431  break;
2432  default:
2433  elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
2434  break;
2435  }
2436  }
2437 }
static void JumbleExpr(pgssJumbleState *jstate, Node *node)
Definition: nodes.h:509
List * values_lists
Definition: parsenodes.h:989
#define APP_JUMB_STRING(str)
#define ERROR
Definition: elog.h:43
TableFunc * tablefunc
Definition: parsenodes.h:984
#define lfirst_node(type, lc)
Definition: pg_list.h:109
#define APP_JUMB(item)
static void JumbleQuery(pgssJumbleState *jstate, Query *query)
JoinType jointype
Definition: parsenodes.h:967
char * enrname
Definition: parsenodes.h:1009
List * functions
Definition: parsenodes.h:978
Index ctelevelsup
Definition: parsenodes.h:995
RTEKind rtekind
Definition: parsenodes.h:929
char * ctename
Definition: parsenodes.h:994
Query * subquery
Definition: parsenodes.h:947
#define elog
Definition: elog.h:219
struct TableSampleClause * tablesample
Definition: parsenodes.h:942
static bool need_gc_qtexts ( void  )
static

Definition at line 2031 of file pg_stat_statements.c.

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

Referenced by gc_qtexts(), and pgss_store().

2032 {
2033  Size extent;
2034 
2035  /* Read shared extent pointer */
2036  {
2037  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
2038 
2039  SpinLockAcquire(&s->mutex);
2040  extent = s->extent;
2041  SpinLockRelease(&s->mutex);
2042  }
2043 
2044  /* Don't proceed if file does not exceed 512 bytes per possible entry */
2045  if (extent < 512 * pgss_max)
2046  return false;
2047 
2048  /*
2049  * Don't proceed if file is less than about 50% bloat. Nothing can or
2050  * should be done in the event of unusually large query texts accounting
2051  * for file's large size. We go to the trouble of maintaining the mean
2052  * query length in order to prevent garbage collection from thrashing
2053  * uselessly.
2054  */
2055  if (extent < pgss->mean_query_len * pgss_max * 2)
2056  return false;
2057 
2058  return true;
2059 }
static pgssSharedState * pgss
#define SpinLockAcquire(lock)
Definition: spin.h:62
static int pgss_max
#define SpinLockRelease(lock)
Definition: spin.h:64
size_t Size
Definition: c.h:356
PG_FUNCTION_INFO_V1 ( pg_stat_statements_reset  )
PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_2  )
PG_FUNCTION_INFO_V1 ( pg_stat_statements_1_3  )
PG_FUNCTION_INFO_V1 ( pg_stat_statements  )
Datum pg_stat_statements ( PG_FUNCTION_ARGS  )

Definition at line 1377 of file pg_stat_statements.c.

References pg_stat_statements_internal(), and PGSS_V1_0.

1378 {
1379  /* If it's really API 1.1, we'll figure that out below */
1380  pg_stat_statements_internal(fcinfo, PGSS_V1_0, true);
1381 
1382  return (Datum) 0;
1383 }
static void pg_stat_statements_internal(FunctionCallInfo fcinfo, pgssVersion api_version, bool showtext)
uintptr_t Datum
Definition: postgres.h:372
Datum pg_stat_statements_1_2 ( PG_FUNCTION_ARGS  )

Definition at line 1363 of file pg_stat_statements.c.

References PG_GETARG_BOOL, pg_stat_statements_internal(), and PGSS_V1_2.

1364 {
1365  bool showtext = PG_GETARG_BOOL(0);
1366 
1367  pg_stat_statements_internal(fcinfo, PGSS_V1_2, showtext);
1368 
1369  return (Datum) 0;
1370 }
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:239
static void pg_stat_statements_internal(FunctionCallInfo fcinfo, pgssVersion api_version, bool showtext)
uintptr_t Datum
Definition: postgres.h:372
Datum pg_stat_statements_1_3 ( PG_FUNCTION_ARGS  )

Definition at line 1353 of file pg_stat_statements.c.

References PG_GETARG_BOOL, pg_stat_statements_internal(), and PGSS_V1_3.

1354 {
1355  bool showtext = PG_GETARG_BOOL(0);
1356 
1357  pg_stat_statements_internal(fcinfo, PGSS_V1_3, showtext);
1358 
1359  return (Datum) 0;
1360 }
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:239
static void pg_stat_statements_internal(FunctionCallInfo fcinfo, pgssVersion api_version, bool showtext)
uintptr_t Datum
Definition: postgres.h:372
static void pg_stat_statements_internal ( FunctionCallInfo  fcinfo,
pgssVersion  api_version,
bool  showtext 
)
static

Definition at line 1387 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, DEFAULT_ROLE_READ_ALL_STATS, ReturnSetInfo::econtext, ExprContext::ecxt_per_query_memory, elog, enc, pgssEntry::encoding, ereport, errcode(), errmsg(), ERROR, pgssSharedState::extent, Float8GetDatumFast, free, pgssSharedState::gc_count, get_call_result_type(), GetUserId(), hash_seq_init(), hash_seq_search(), i, Int64GetDatumFast, is_member_of_role(), IsA, pgssEntry::key, Counters::local_blks_dirtied, Counters::local_blks_hit, Counters::local_blks_read, Counters::local_blks_written, pgssSharedState::lock, LW_SHARED, LWLockAcquire(), LWLockRelease(), Counters::max_time, Counters::mean_time, MemoryContextSwitchTo(), Counters::min_time, pgssEntry::mutex, pgssSharedState::mutex, pgssSharedState::n_writers, 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, 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().

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

Definition at line 1325 of file pg_stat_statements.c.

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

1326 {
1327  if (!pgss || !pgss_hash)
1328  ereport(ERROR,
1329  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1330  errmsg("pg_stat_statements must be loaded via shared_preload_libraries")));
1331  entry_reset();
1332  PG_RETURN_VOID();
1333 }
int errcode(int sqlerrcode)
Definition: elog.c:575
static void entry_reset(void)
static pgssSharedState * pgss
static HTAB * pgss_hash
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
#define PG_RETURN_VOID()
Definition: fmgr.h:309
int errmsg(const char *fmt,...)
Definition: elog.c:797
static void pgss_ExecutorEnd ( QueryDesc queryDesc)
static

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

928 {
929  uint32 queryId = queryDesc->plannedstmt->queryId;
930 
931  if (queryId != 0 && queryDesc->totaltime && pgss_enabled())
932  {
933  /*
934  * Make sure stats accumulation is done. (Note: it's okay if several
935  * levels of hook all do this.)
936  */
937  InstrEndLoop(queryDesc->totaltime);
938 
939  pgss_store(queryDesc->sourceText,
940  queryId,
941  queryDesc->plannedstmt->stmt_location,
942  queryDesc->plannedstmt->stmt_len,
943  queryDesc->totaltime->total * 1000.0, /* convert to msec */
944  queryDesc->estate->es_processed,
945  &queryDesc->totaltime->bufusage,
946  NULL);
947  }
948 
949  if (prev_ExecutorEnd)
950  prev_ExecutorEnd(queryDesc);
951  else
952  standard_ExecutorEnd(queryDesc);
953 }
uint32 queryId
Definition: plannodes.h:47
EState * estate
Definition: execdesc.h:48
static ExecutorEnd_hook_type prev_ExecutorEnd
void standard_ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:467
#define pgss_enabled()
int stmt_len
Definition: plannodes.h:98
void InstrEndLoop(Instrumentation *instr)
Definition: instrument.c:114
int stmt_location
Definition: plannodes.h:97
unsigned int uint32
Definition: c.h:268
BufferUsage bufusage
Definition: instrument.h:63
struct Instrumentation * totaltime
Definition: execdesc.h:55
#define NULL
Definition: c.h:229
uint64 es_processed
Definition: execnodes.h:454
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 904 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().

905 {
906  nested_level++;
907  PG_TRY();
908  {
910  prev_ExecutorFinish(queryDesc);
911  else
912  standard_ExecutorFinish(queryDesc);
913  nested_level--;
914  }
915  PG_CATCH();
916  {
917  nested_level--;
918  PG_RE_THROW();
919  }
920  PG_END_TRY();
921 }
void standard_ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:407
static ExecutorFinish_hook_type prev_ExecutorFinish
#define PG_CATCH()
Definition: elog.h:293
#define PG_RE_THROW()
Definition: elog.h:314
#define PG_TRY()
Definition: elog.h:284
static int nested_level
#define PG_END_TRY()
Definition: elog.h:300
static void pgss_ExecutorRun ( QueryDesc queryDesc,
ScanDirection  direction,
uint64  count,
bool  execute_once 
)
static

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

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

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

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

Definition at line 1076 of file pg_stat_statements.c.

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

Referenced by pgss_shmem_startup().

1077 {
1078  const pgssHashKey *k = (const pgssHashKey *) key;
1079 
1080  return hash_uint32((uint32) k->userid) ^
1081  hash_uint32((uint32) k->dbid) ^
1082  hash_uint32((uint32) k->queryid);
1083 }
unsigned int uint32
Definition: c.h:268
Datum hash_uint32(uint32 k)
Definition: hashfunc.c:512
static uint32 pgss_hash_string ( const char *  str,
int  len 
)
static

Definition at line 1108 of file pg_stat_statements.c.

References hash_any().

Referenced by pgss_store().

1109 {
1110  return hash_any((const unsigned char *) str, len);
1111 }
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 1089 of file pg_stat_statements.c.

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

Referenced by pgss_shmem_startup().

1090 {
1091  const pgssHashKey *k1 = (const pgssHashKey *) key1;
1092  const pgssHashKey *k2 = (const pgssHashKey *) key2;
1093 
1094  if (k1->userid == k2->userid &&
1095  k1->dbid == k2->dbid &&
1096  k1->queryid == k2->queryid)
1097  return 0;
1098  else
1099  return 1;
1100 }
static Size pgss_memsize ( void  )
static

Definition at line 1677 of file pg_stat_statements.c.

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

Referenced by _PG_init().

1678 {
1679  Size size;
1680 
1681  size = MAXALIGN(sizeof(pgssSharedState));
1682  size = add_size(size, hash_estimate_size(pgss_max, sizeof(pgssEntry)));
1683 
1684  return size;
1685 }
static int pgss_max
Size hash_estimate_size(long num_entries, Size entrysize)
Definition: dynahash.c:711
Size add_size(Size s1, Size s2)
Definition: shmem.c:475
size_t Size
Definition: c.h:356
#define MAXALIGN(LEN)
Definition: c.h:588
static void pgss_post_parse_analyze ( ParseState pstate,
Query query 
)
static

Definition at line 776 of file pg_stat_statements.c.

References Assert, pgssJumbleState::clocations, pgssJumbleState::clocations_buf_size, pgssJumbleState::clocations_count, hash_any(), pgssJumbleState::highest_extern_param_id, 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().

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

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

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

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

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

References AllocateFile(), ASSUMED_LENGTH_INIT, ASSUMED_MEDIAN_INIT, buffer, Counters::calls, pgssEntry::counters, pgssSharedState::cur_median_usage, pgssEntry::encoding, entry_alloc(), HASHCTL::entrysize, ereport, errcode(), errcode_for_file_access(), errmsg(), pgssSharedState::extent, FreeFile(), pgssSharedState::gc_count, GetNamedLWLockTranche(), HASHCTL::hash, HASH_COMPARE, HASH_ELEM, HASH_FUNCTION, header(), i, IsUnderPostmaster, pgssEntry::key, HASHCTL::keysize, pgssSharedState::lock, LOG, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), HASHCTL::match, Max, pgssSharedState::mean_query_len, pgssSharedState::mutex, pgssSharedState::n_writers, NULL, on_shmem_exit(), palloc(), pfree(), PG_BINARY_R, PG_BINARY_W, PG_VALID_BE_ENCODING, PGSS_DUMP_FILE, PGSS_FILE_HEADER, pgss_hash_fn(), pgss_match_fn(), pgss_max, PGSS_PG_MAJOR_VERSION, pgss_save, pgss_shmem_shutdown(), PGSS_TEXT_FILE, prev_shmem_startup_hook, pgssEntry::query_len, repalloc(), ShmemInitHash(), ShmemInitStruct(), SpinLockInit, and unlink().

Referenced by _PG_init().

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

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

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

Definition at line 2008 of file pg_stat_statements.c.

References NULL.

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

2010 {
2011  /* File read failed? */
2012  if (buffer == NULL)
2013  return NULL;
2014  /* Bogus offset/length? */
2015  if (query_len < 0 ||
2016  query_offset + query_len >= buffer_size)
2017  return NULL;
2018  /* As a further sanity check, make sure there's a trailing null */
2019  if (buffer[query_offset + query_len] != '\0')
2020  return NULL;
2021  /* Looks OK */
2022  return buffer + query_offset;
2023 }
#define NULL
Definition: c.h:229
WalTimeSample buffer[LAG_TRACKER_BUFFER_SIZE]
Definition: walsender.c:211
static char * qtext_load_file ( Size buffer_size)
static

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

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

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

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

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

2924 {
2925  /* -1 indicates unknown or undefined location */
2926  if (location >= 0)
2927  {
2928  /* enlarge array if needed */
2929  if (jstate->clocations_count >= jstate->clocations_buf_size)
2930  {
2931  jstate->clocations_buf_size *= 2;
2932  jstate->clocations = (pgssLocationLen *)
2933  repalloc(jstate->clocations,
2934  jstate->clocations_buf_size *
2935  sizeof(pgssLocationLen));
2936  }
2937  jstate->clocations[jstate->clocations_count].location = location;
2938  /* initialize lengths to -1 to simplify fill_in_constant_lengths */
2939  jstate->clocations[jstate->clocations_count].length = -1;
2940  jstate->clocations_count++;
2941  }
2942 }
pgssLocationLen * clocations
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:963

Variable Documentation

int nested_level = 0
static
PG_MODULE_MAGIC

Definition at line 82 of file pg_stat_statements.c.

pgssSharedState* pgss = NULL
static

Definition at line 243 of file pg_stat_statements.c.

const uint32 PGSS_FILE_HEADER = 0x20140125
static

Definition at line 98 of file pg_stat_statements.c.

Referenced by pgss_shmem_shutdown(), and pgss_shmem_startup().

HTAB* pgss_hash = NULL
static

Definition at line 244 of file pg_stat_statements.c.

int pgss_max
static
const uint32 PGSS_PG_MAJOR_VERSION = PG_VERSION_NUM / 100
static

Definition at line 101 of file pg_stat_statements.c.

Referenced by pgss_shmem_shutdown(), and pgss_shmem_startup().

bool pgss_save
static

Definition at line 266 of file pg_stat_statements.c.

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

int pgss_track
static

Definition at line 264 of file pg_stat_statements.c.

Referenced by _PG_init().

bool pgss_track_utility
static

Definition at line 265 of file pg_stat_statements.c.

Referenced by _PG_init(), and pgss_ProcessUtility().

ExecutorEnd_hook_type prev_ExecutorEnd = NULL
static

Definition at line 239 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 238 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 237 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 236 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 235 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 240 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 234 of file pg_stat_statements.c.

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

const struct config_enum_entry track_options[]
static
Initial value:
=
{
{"none", PGSS_TRACK_NONE, false},
{"top", PGSS_TRACK_TOP, false},
{"all", PGSS_TRACK_ALL, false},
{NULL, 0, false}
}
#define NULL
Definition: c.h:229

Definition at line 255 of file pg_stat_statements.c.