PostgreSQL Source Code  git master
pg_stat_statements.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * pg_stat_statements.c
4  * Track statement planning and execution times as well as resource
5  * usage across a whole database cluster.
6  *
7  * Execution costs are totaled for each distinct source query, and kept in
8  * a shared hashtable. (We track only as many distinct queries as will fit
9  * in the designated amount of shared memory.)
10  *
11  * As of Postgres 9.2, this module normalizes query entries. Normalization
12  * is a process whereby similar queries, typically differing only in their
13  * constants (though the exact rules are somewhat more subtle than that) are
14  * recognized as equivalent, and are tracked as a single entry. This is
15  * particularly useful for non-prepared queries.
16  *
17  * Normalization is implemented by fingerprinting queries, selectively
18  * serializing those fields of each query tree's nodes that are judged to be
19  * essential to the query. This is referred to as a query jumble. This is
20  * distinct from a regular serialization in that various extraneous
21  * information is ignored as irrelevant or not essential to the query, such
22  * as the collations of Vars and, most notably, the values of constants.
23  *
24  * This jumble is acquired at the end of parse analysis of each query, and
25  * a 64-bit hash of it is stored into the query's Query.queryId field.
26  * The server then copies this value around, making it available in plan
27  * tree(s) generated from the query. The executor can then use this value
28  * to blame query costs on the proper queryId.
29  *
30  * To facilitate presenting entries to users, we create "representative" query
31  * strings in which constants are replaced with parameter symbols ($n), to
32  * make it clearer what a normalized entry can represent. To save on shared
33  * memory, and to avoid having to truncate oversized query strings, we store
34  * these strings in a temporary external query-texts file. Offsets into this
35  * file are kept in shared memory.
36  *
37  * Note about locking issues: to create or delete an entry in the shared
38  * hashtable, one must hold pgss->lock exclusively. Modifying any field
39  * in an entry except the counters requires the same. To look up an entry,
40  * one must hold the lock shared. To read or update the counters within
41  * an entry, one must hold the lock shared or exclusive (so the entry doesn't
42  * disappear!) and also take the entry's mutex spinlock.
43  * The shared state variable pgss->extent (the next free spot in the external
44  * query-text file) should be accessed only while holding either the
45  * pgss->mutex spinlock, or exclusive lock on pgss->lock. We use the mutex to
46  * allow reserving file space while holding only shared lock on pgss->lock.
47  * Rewriting the entire external query-text file, eg for garbage collection,
48  * requires holding pgss->lock exclusively; this allows individual entries
49  * in the file to be read or written while holding only shared lock.
50  *
51  *
52  * Copyright (c) 2008-2020, PostgreSQL Global Development Group
53  *
54  * IDENTIFICATION
55  * contrib/pg_stat_statements/pg_stat_statements.c
56  *
57  *-------------------------------------------------------------------------
58  */
59 #include "postgres.h"
60 
61 #include <math.h>
62 #include <sys/stat.h>
63 #include <unistd.h>
64 
65 #include "catalog/pg_authid.h"
66 #include "common/hashfn.h"
67 #include "executor/instrument.h"
68 #include "funcapi.h"
69 #include "mb/pg_wchar.h"
70 #include "miscadmin.h"
71 #include "optimizer/planner.h"
72 #include "parser/analyze.h"
73 #include "parser/parsetree.h"
74 #include "parser/scanner.h"
75 #include "parser/scansup.h"
76 #include "pgstat.h"
77 #include "storage/fd.h"
78 #include "storage/ipc.h"
79 #include "storage/spin.h"
80 #include "tcop/utility.h"
81 #include "utils/acl.h"
82 #include "utils/builtins.h"
83 #include "utils/memutils.h"
84 
86 
87 /* Location of permanent stats file (valid when database is shut down) */
88 #define PGSS_DUMP_FILE PGSTAT_STAT_PERMANENT_DIRECTORY "/pg_stat_statements.stat"
89 
90 /*
91  * Location of external query text file. We don't keep it in the core
92  * system's stats_temp_directory. The core system can safely use that GUC
93  * setting, because the statistics collector temp file paths are set only once
94  * as part of changing the GUC, but pg_stat_statements has no way of avoiding
95  * race conditions. Besides, we only expect modest, infrequent I/O for query
96  * strings, so placing the file on a faster filesystem is not compelling.
97  */
98 #define PGSS_TEXT_FILE PG_STAT_TMP_DIR "/pgss_query_texts.stat"
99 
100 /* Magic number identifying the stats file format */
101 static const uint32 PGSS_FILE_HEADER = 0x20171004;
102 
103 /* PostgreSQL major version number, changes in which invalidate all entries */
104 static const uint32 PGSS_PG_MAJOR_VERSION = PG_VERSION_NUM / 100;
105 
106 /* XXX: Should USAGE_EXEC reflect execution time and/or buffer usage? */
107 #define USAGE_EXEC(duration) (1.0)
108 #define USAGE_INIT (1.0) /* including initial planning */
109 #define ASSUMED_MEDIAN_INIT (10.0) /* initial assumed median usage */
110 #define ASSUMED_LENGTH_INIT 1024 /* initial assumed mean query length */
111 #define USAGE_DECREASE_FACTOR (0.99) /* decreased every entry_dealloc */
112 #define STICKY_DECREASE_FACTOR (0.50) /* factor for sticky entries */
113 #define USAGE_DEALLOC_PERCENT 5 /* free this % of entries at once */
114 #define IS_STICKY(c) ((c.calls[PGSS_PLAN] + c.calls[PGSS_EXEC]) == 0)
115 
116 #define JUMBLE_SIZE 1024 /* query serialization buffer size */
117 
118 /*
119  * Extension version number, for supporting older extension versions' objects
120  */
121 typedef enum pgssVersion
122 {
128 } pgssVersion;
129 
130 typedef enum pgssStoreKind
131 {
133 
134  /*
135  * PGSS_PLAN and PGSS_EXEC must be respectively 0 and 1 as they're used to
136  * reference the underlying values in the arrays in the Counters struct,
137  * and this order is required in pg_stat_statements_internal().
138  */
141 
142  PGSS_NUMKIND /* Must be last value of this enum */
143 } pgssStoreKind;
144 
145 /*
146  * Hashtable key that defines the identity of a hashtable entry. We separate
147  * queries by user and by database even if they are otherwise identical.
148  *
149  * Right now, this structure contains no padding. If you add any, make sure
150  * to teach pgss_store() to zero the padding bytes. Otherwise, things will
151  * break, because pgss_hash is created using HASH_BLOBS, and thus tag_hash
152  * is used to hash this.
153  */
154 typedef struct pgssHashKey
155 {
156  Oid userid; /* user OID */
157  Oid dbid; /* database OID */
158  uint64 queryid; /* query identifier */
159 } pgssHashKey;
160 
161 /*
162  * The actual stats counters kept within pgssEntry.
163  */
164 typedef struct Counters
165 {
166  int64 calls[PGSS_NUMKIND]; /* # of times planned/executed */
167  double total_time[PGSS_NUMKIND]; /* total planning/execution time,
168  * in msec */
169  double min_time[PGSS_NUMKIND]; /* minimum planning/execution time in
170  * msec */
171  double max_time[PGSS_NUMKIND]; /* maximum planning/execution time in
172  * msec */
173  double mean_time[PGSS_NUMKIND]; /* mean planning/execution time in
174  * msec */
175  double sum_var_time[PGSS_NUMKIND]; /* sum of variances in
176  * planning/execution time in msec */
177  int64 rows; /* total # of retrieved or affected rows */
178  int64 shared_blks_hit; /* # of shared buffer hits */
179  int64 shared_blks_read; /* # of shared disk blocks read */
180  int64 shared_blks_dirtied; /* # of shared disk blocks dirtied */
181  int64 shared_blks_written; /* # of shared disk blocks written */
182  int64 local_blks_hit; /* # of local buffer hits */
183  int64 local_blks_read; /* # of local disk blocks read */
184  int64 local_blks_dirtied; /* # of local disk blocks dirtied */
185  int64 local_blks_written; /* # of local disk blocks written */
186  int64 temp_blks_read; /* # of temp blocks read */
187  int64 temp_blks_written; /* # of temp blocks written */
188  double blk_read_time; /* time spent reading, in msec */
189  double blk_write_time; /* time spent writing, in msec */
190  double usage; /* usage factor */
191  int64 wal_records; /* # of WAL records generated */
192  int64 wal_fpi; /* # of WAL full page images generated */
193  uint64 wal_bytes; /* total amount of WAL bytes generated */
194 } Counters;
195 
196 /*
197  * Statistics per statement
198  *
199  * Note: in event of a failure in garbage collection of the query text file,
200  * we reset query_offset to zero and query_len to -1. This will be seen as
201  * an invalid state by qtext_fetch().
202  */
203 typedef struct pgssEntry
204 {
205  pgssHashKey key; /* hash key of entry - MUST BE FIRST */
206  Counters counters; /* the statistics for this query */
207  Size query_offset; /* query text offset in external file */
208  int query_len; /* # of valid bytes in query string, or -1 */
209  int encoding; /* query text encoding */
210  slock_t mutex; /* protects the counters only */
211 } pgssEntry;
212 
213 /*
214  * Global shared state
215  */
216 typedef struct pgssSharedState
217 {
218  LWLock *lock; /* protects hashtable search/modification */
219  double cur_median_usage; /* current median usage in hashtable */
220  Size mean_query_len; /* current mean entry text length */
221  slock_t mutex; /* protects following fields only: */
222  Size extent; /* current extent of query file */
223  int n_writers; /* number of active writers to query file */
224  int gc_count; /* query file garbage collection cycle count */
226 
227 /*
228  * Struct for tracking locations/lengths of constants during normalization
229  */
230 typedef struct pgssLocationLen
231 {
232  int location; /* start offset in query text */
233  int length; /* length in bytes, or -1 to ignore */
235 
236 /*
237  * Working state for computing a query jumble and producing a normalized
238  * query string
239  */
240 typedef struct pgssJumbleState
241 {
242  /* Jumble of current query tree */
243  unsigned char *jumble;
244 
245  /* Number of bytes used in jumble[] */
247 
248  /* Array of locations of constants that should be removed */
250 
251  /* Allocated length of clocations array */
253 
254  /* Current number of valid entries in clocations array */
256 
257  /* highest Param id we've seen, in order to start normalization correctly */
260 
261 /*---- Local variables ----*/
262 
263 /* Current nesting depth of ExecutorRun+ProcessUtility calls */
264 static int exec_nested_level = 0;
265 
266 /* Current nesting depth of planner calls */
267 static int plan_nested_level = 0;
268 
269 /* Saved hook values in case of unload */
278 
279 /* Links to shared memory state */
280 static pgssSharedState *pgss = NULL;
281 static HTAB *pgss_hash = NULL;
282 
283 /*---- GUC variables ----*/
284 
285 typedef enum
286 {
287  PGSS_TRACK_NONE, /* track no statements */
288  PGSS_TRACK_TOP, /* only top level statements */
289  PGSS_TRACK_ALL /* all statements, including nested ones */
291 
292 static const struct config_enum_entry track_options[] =
293 {
294  {"none", PGSS_TRACK_NONE, false},
295  {"top", PGSS_TRACK_TOP, false},
296  {"all", PGSS_TRACK_ALL, false},
297  {NULL, 0, false}
298 };
299 
300 static int pgss_max; /* max # statements to track */
301 static int pgss_track; /* tracking level */
302 static bool pgss_track_utility; /* whether to track utility commands */
303 static bool pgss_track_planning; /* whether to track planning duration */
304 static bool pgss_save; /* whether to save stats across shutdown */
305 
306 
307 #define pgss_enabled(level) \
308  (pgss_track == PGSS_TRACK_ALL || \
309  (pgss_track == PGSS_TRACK_TOP && (level) == 0))
310 
311 #define record_gc_qtexts() \
312  do { \
313  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss; \
314  SpinLockAcquire(&s->mutex); \
315  s->gc_count++; \
316  SpinLockRelease(&s->mutex); \
317  } while(0)
318 
319 /*---- Function declarations ----*/
320 
321 void _PG_init(void);
322 void _PG_fini(void);
323 
330 
331 static void pgss_shmem_startup(void);
332 static void pgss_shmem_shutdown(int code, Datum arg);
333 static void pgss_post_parse_analyze(ParseState *pstate, Query *query);
335  const char *query_string,
336  int cursorOptions,
337  ParamListInfo boundParams);
338 static void pgss_ExecutorStart(QueryDesc *queryDesc, int eflags);
339 static void pgss_ExecutorRun(QueryDesc *queryDesc,
340  ScanDirection direction,
341  uint64 count, bool execute_once);
342 static void pgss_ExecutorFinish(QueryDesc *queryDesc);
343 static void pgss_ExecutorEnd(QueryDesc *queryDesc);
344 static void pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
345  ProcessUtilityContext context, ParamListInfo params,
346  QueryEnvironment *queryEnv,
348 static uint64 pgss_hash_string(const char *str, int len);
349 static void pgss_store(const char *query, uint64 queryId,
350  int query_location, int query_len,
351  pgssStoreKind kind,
352  double total_time, uint64 rows,
353  const BufferUsage *bufusage,
354  const WalUsage *walusage,
355  pgssJumbleState *jstate);
357  pgssVersion api_version,
358  bool showtext);
359 static Size pgss_memsize(void);
360 static pgssEntry *entry_alloc(pgssHashKey *key, Size query_offset, int query_len,
361  int encoding, bool sticky);
362 static void entry_dealloc(void);
363 static bool qtext_store(const char *query, int query_len,
364  Size *query_offset, int *gc_count);
365 static char *qtext_load_file(Size *buffer_size);
366 static char *qtext_fetch(Size query_offset, int query_len,
367  char *buffer, Size buffer_size);
368 static bool need_gc_qtexts(void);
369 static void gc_qtexts(void);
370 static void entry_reset(Oid userid, Oid dbid, uint64 queryid);
371 static void AppendJumble(pgssJumbleState *jstate,
372  const unsigned char *item, Size size);
373 static void JumbleQuery(pgssJumbleState *jstate, Query *query);
374 static void JumbleRangeTable(pgssJumbleState *jstate, List *rtable);
375 static void JumbleRowMarks(pgssJumbleState *jstate, List *rowMarks);
376 static void JumbleExpr(pgssJumbleState *jstate, Node *node);
377 static void RecordConstLocation(pgssJumbleState *jstate, int location);
378 static char *generate_normalized_query(pgssJumbleState *jstate, const char *query,
379  int query_loc, int *query_len_p);
380 static void fill_in_constant_lengths(pgssJumbleState *jstate, const char *query,
381  int query_loc);
382 static int comp_location(const void *a, const void *b);
383 
384 
385 /*
386  * Module load callback
387  */
388 void
389 _PG_init(void)
390 {
391  /*
392  * In order to create our shared memory area, we have to be loaded via
393  * shared_preload_libraries. If not, fall out without hooking into any of
394  * the main system. (We don't throw error here because it seems useful to
395  * allow the pg_stat_statements functions to be created even when the
396  * module isn't active. The functions must protect themselves against
397  * being called then, however.)
398  */
400  return;
401 
402  /*
403  * Define (or redefine) custom GUC variables.
404  */
405  DefineCustomIntVariable("pg_stat_statements.max",
406  "Sets the maximum number of statements tracked by pg_stat_statements.",
407  NULL,
408  &pgss_max,
409  5000,
410  100,
411  INT_MAX,
413  0,
414  NULL,
415  NULL,
416  NULL);
417 
418  DefineCustomEnumVariable("pg_stat_statements.track",
419  "Selects which statements are tracked by pg_stat_statements.",
420  NULL,
421  &pgss_track,
423  track_options,
424  PGC_SUSET,
425  0,
426  NULL,
427  NULL,
428  NULL);
429 
430  DefineCustomBoolVariable("pg_stat_statements.track_utility",
431  "Selects whether utility commands are tracked by pg_stat_statements.",
432  NULL,
434  true,
435  PGC_SUSET,
436  0,
437  NULL,
438  NULL,
439  NULL);
440 
441  DefineCustomBoolVariable("pg_stat_statements.track_planning",
442  "Selects whether planning duration is tracked by pg_stat_statements.",
443  NULL,
445  false,
446  PGC_SUSET,
447  0,
448  NULL,
449  NULL,
450  NULL);
451 
452  DefineCustomBoolVariable("pg_stat_statements.save",
453  "Save pg_stat_statements statistics across server shutdowns.",
454  NULL,
455  &pgss_save,
456  true,
457  PGC_SIGHUP,
458  0,
459  NULL,
460  NULL,
461  NULL);
462 
463  EmitWarningsOnPlaceholders("pg_stat_statements");
464 
465  /*
466  * Request additional shared resources. (These are no-ops if we're not in
467  * the postmaster process.) We'll allocate or attach to the shared
468  * resources in pgss_shmem_startup().
469  */
471  RequestNamedLWLockTranche("pg_stat_statements", 1);
472 
473  /*
474  * Install hooks.
475  */
492 }
493 
494 /*
495  * Module unload callback
496  */
497 void
498 _PG_fini(void)
499 {
500  /* Uninstall hooks. */
509 }
510 
511 /*
512  * shmem_startup hook: allocate or attach to shared memory,
513  * then load any pre-existing statistics from file.
514  * Also create and load the query-texts file, which is expected to exist
515  * (even if empty) while the module is enabled.
516  */
517 static void
519 {
520  bool found;
521  HASHCTL info;
522  FILE *file = NULL;
523  FILE *qfile = NULL;
524  uint32 header;
525  int32 num;
526  int32 pgver;
527  int32 i;
528  int buffer_size;
529  char *buffer = NULL;
530 
533 
534  /* reset in case this is a restart within the postmaster */
535  pgss = NULL;
536  pgss_hash = NULL;
537 
538  /*
539  * Create or attach to the shared memory state, including hash table
540  */
541  LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE);
542 
543  pgss = ShmemInitStruct("pg_stat_statements",
544  sizeof(pgssSharedState),
545  &found);
546 
547  if (!found)
548  {
549  /* First time through ... */
550  pgss->lock = &(GetNamedLWLockTranche("pg_stat_statements"))->lock;
553  SpinLockInit(&pgss->mutex);
554  pgss->extent = 0;
555  pgss->n_writers = 0;
556  pgss->gc_count = 0;
557  }
558 
559  memset(&info, 0, sizeof(info));
560  info.keysize = sizeof(pgssHashKey);
561  info.entrysize = sizeof(pgssEntry);
562  pgss_hash = ShmemInitHash("pg_stat_statements hash",
564  &info,
566 
567  LWLockRelease(AddinShmemInitLock);
568 
569  /*
570  * If we're in the postmaster (or a standalone backend...), set up a shmem
571  * exit hook to dump the statistics to disk.
572  */
573  if (!IsUnderPostmaster)
575 
576  /*
577  * Done if some other process already completed our initialization.
578  */
579  if (found)
580  return;
581 
582  /*
583  * Note: we don't bother with locks here, because there should be no other
584  * processes running when this code is reached.
585  */
586 
587  /* Unlink query text file possibly left over from crash */
588  unlink(PGSS_TEXT_FILE);
589 
590  /* Allocate new query text temp file */
592  if (qfile == NULL)
593  goto write_error;
594 
595  /*
596  * If we were told not to load old statistics, we're done. (Note we do
597  * not try to unlink any old dump file in this case. This seems a bit
598  * questionable but it's the historical behavior.)
599  */
600  if (!pgss_save)
601  {
602  FreeFile(qfile);
603  return;
604  }
605 
606  /*
607  * Attempt to load old statistics from the dump file.
608  */
610  if (file == NULL)
611  {
612  if (errno != ENOENT)
613  goto read_error;
614  /* No existing persisted stats file, so we're done */
615  FreeFile(qfile);
616  return;
617  }
618 
619  buffer_size = 2048;
620  buffer = (char *) palloc(buffer_size);
621 
622  if (fread(&header, sizeof(uint32), 1, file) != 1 ||
623  fread(&pgver, sizeof(uint32), 1, file) != 1 ||
624  fread(&num, sizeof(int32), 1, file) != 1)
625  goto read_error;
626 
627  if (header != PGSS_FILE_HEADER ||
628  pgver != PGSS_PG_MAJOR_VERSION)
629  goto data_error;
630 
631  for (i = 0; i < num; i++)
632  {
633  pgssEntry temp;
634  pgssEntry *entry;
635  Size query_offset;
636 
637  if (fread(&temp, sizeof(pgssEntry), 1, file) != 1)
638  goto read_error;
639 
640  /* Encoding is the only field we can easily sanity-check */
641  if (!PG_VALID_BE_ENCODING(temp.encoding))
642  goto data_error;
643 
644  /* Resize buffer as needed */
645  if (temp.query_len >= buffer_size)
646  {
647  buffer_size = Max(buffer_size * 2, temp.query_len + 1);
648  buffer = repalloc(buffer, buffer_size);
649  }
650 
651  if (fread(buffer, 1, temp.query_len + 1, file) != temp.query_len + 1)
652  goto read_error;
653 
654  /* Should have a trailing null, but let's make sure */
655  buffer[temp.query_len] = '\0';
656 
657  /* Skip loading "sticky" entries */
658  if (IS_STICKY(temp.counters))
659  continue;
660 
661  /* Store the query text */
662  query_offset = pgss->extent;
663  if (fwrite(buffer, 1, temp.query_len + 1, qfile) != temp.query_len + 1)
664  goto write_error;
665  pgss->extent += temp.query_len + 1;
666 
667  /* make the hashtable entry (discards old entries if too many) */
668  entry = entry_alloc(&temp.key, query_offset, temp.query_len,
669  temp.encoding,
670  false);
671 
672  /* copy in the actual stats */
673  entry->counters = temp.counters;
674  }
675 
676  pfree(buffer);
677  FreeFile(file);
678  FreeFile(qfile);
679 
680  /*
681  * Remove the persisted stats file so it's not included in
682  * backups/replication standbys, etc. A new file will be written on next
683  * shutdown.
684  *
685  * Note: it's okay if the PGSS_TEXT_FILE is included in a basebackup,
686  * because we remove that file on startup; it acts inversely to
687  * PGSS_DUMP_FILE, in that it is only supposed to be around when the
688  * server is running, whereas PGSS_DUMP_FILE is only supposed to be around
689  * when the server is not running. Leaving the file creates no danger of
690  * a newly restored database having a spurious record of execution costs,
691  * which is what we're really concerned about here.
692  */
693  unlink(PGSS_DUMP_FILE);
694 
695  return;
696 
697 read_error:
698  ereport(LOG,
700  errmsg("could not read file \"%s\": %m",
701  PGSS_DUMP_FILE)));
702  goto fail;
703 data_error:
704  ereport(LOG,
705  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
706  errmsg("ignoring invalid data in file \"%s\"",
707  PGSS_DUMP_FILE)));
708  goto fail;
709 write_error:
710  ereport(LOG,
712  errmsg("could not write file \"%s\": %m",
713  PGSS_TEXT_FILE)));
714 fail:
715  if (buffer)
716  pfree(buffer);
717  if (file)
718  FreeFile(file);
719  if (qfile)
720  FreeFile(qfile);
721  /* If possible, throw away the bogus file; ignore any error */
722  unlink(PGSS_DUMP_FILE);
723 
724  /*
725  * Don't unlink PGSS_TEXT_FILE here; it should always be around while the
726  * server is running with pg_stat_statements enabled
727  */
728 }
729 
730 /*
731  * shmem_shutdown hook: Dump statistics into file.
732  *
733  * Note: we don't bother with acquiring lock, because there should be no
734  * other processes running when this is called.
735  */
736 static void
738 {
739  FILE *file;
740  char *qbuffer = NULL;
741  Size qbuffer_size = 0;
742  HASH_SEQ_STATUS hash_seq;
743  int32 num_entries;
744  pgssEntry *entry;
745 
746  /* Don't try to dump during a crash. */
747  if (code)
748  return;
749 
750  /* Safety check ... shouldn't get here unless shmem is set up. */
751  if (!pgss || !pgss_hash)
752  return;
753 
754  /* Don't dump if told not to. */
755  if (!pgss_save)
756  return;
757 
758  file = AllocateFile(PGSS_DUMP_FILE ".tmp", PG_BINARY_W);
759  if (file == NULL)
760  goto error;
761 
762  if (fwrite(&PGSS_FILE_HEADER, sizeof(uint32), 1, file) != 1)
763  goto error;
764  if (fwrite(&PGSS_PG_MAJOR_VERSION, sizeof(uint32), 1, file) != 1)
765  goto error;
766  num_entries = hash_get_num_entries(pgss_hash);
767  if (fwrite(&num_entries, sizeof(int32), 1, file) != 1)
768  goto error;
769 
770  qbuffer = qtext_load_file(&qbuffer_size);
771  if (qbuffer == NULL)
772  goto error;
773 
774  /*
775  * When serializing to disk, we store query texts immediately after their
776  * entry data. Any orphaned query texts are thereby excluded.
777  */
778  hash_seq_init(&hash_seq, pgss_hash);
779  while ((entry = hash_seq_search(&hash_seq)) != NULL)
780  {
781  int len = entry->query_len;
782  char *qstr = qtext_fetch(entry->query_offset, len,
783  qbuffer, qbuffer_size);
784 
785  if (qstr == NULL)
786  continue; /* Ignore any entries with bogus texts */
787 
788  if (fwrite(entry, sizeof(pgssEntry), 1, file) != 1 ||
789  fwrite(qstr, 1, len + 1, file) != len + 1)
790  {
791  /* note: we assume hash_seq_term won't change errno */
792  hash_seq_term(&hash_seq);
793  goto error;
794  }
795  }
796 
797  free(qbuffer);
798  qbuffer = NULL;
799 
800  if (FreeFile(file))
801  {
802  file = NULL;
803  goto error;
804  }
805 
806  /*
807  * Rename file into place, so we atomically replace any old one.
808  */
810 
811  /* Unlink query-texts file; it's not needed while shutdown */
812  unlink(PGSS_TEXT_FILE);
813 
814  return;
815 
816 error:
817  ereport(LOG,
819  errmsg("could not write file \"%s\": %m",
820  PGSS_DUMP_FILE ".tmp")));
821  if (qbuffer)
822  free(qbuffer);
823  if (file)
824  FreeFile(file);
825  unlink(PGSS_DUMP_FILE ".tmp");
826  unlink(PGSS_TEXT_FILE);
827 }
828 
829 /*
830  * Post-parse-analysis hook: mark query with a queryId
831  */
832 static void
834 {
835  pgssJumbleState jstate;
836 
838  prev_post_parse_analyze_hook(pstate, query);
839 
840  /* Assert we didn't do this already */
841  Assert(query->queryId == UINT64CONST(0));
842 
843  /* Safety check... */
844  if (!pgss || !pgss_hash || !pgss_enabled(exec_nested_level))
845  return;
846 
847  /*
848  * Utility statements get queryId zero. We do this even in cases where
849  * the statement contains an optimizable statement for which a queryId
850  * could be derived (such as EXPLAIN or DECLARE CURSOR). For such cases,
851  * runtime control will first go through ProcessUtility and then the
852  * executor, and we don't want the executor hooks to do anything, since we
853  * are already measuring the statement's costs at the utility level.
854  */
855  if (query->utilityStmt)
856  {
857  query->queryId = UINT64CONST(0);
858  return;
859  }
860 
861  /* Set up workspace for query jumbling */
862  jstate.jumble = (unsigned char *) palloc(JUMBLE_SIZE);
863  jstate.jumble_len = 0;
864  jstate.clocations_buf_size = 32;
865  jstate.clocations = (pgssLocationLen *)
866  palloc(jstate.clocations_buf_size * sizeof(pgssLocationLen));
867  jstate.clocations_count = 0;
868  jstate.highest_extern_param_id = 0;
869 
870  /* Compute query ID and mark the Query node with it */
871  JumbleQuery(&jstate, query);
872  query->queryId =
874 
875  /*
876  * If we are unlucky enough to get a hash of zero, use 1 instead, to
877  * prevent confusion with the utility-statement case.
878  */
879  if (query->queryId == UINT64CONST(0))
880  query->queryId = UINT64CONST(1);
881 
882  /*
883  * If we were able to identify any ignorable constants, we immediately
884  * create a hash table entry for the query, so that we can record the
885  * normalized form of the query string. If there were no such constants,
886  * the normalized string would be the same as the query text anyway, so
887  * there's no need for an early entry.
888  */
889  if (jstate.clocations_count > 0)
890  pgss_store(pstate->p_sourcetext,
891  query->queryId,
892  query->stmt_location,
893  query->stmt_len,
894  PGSS_INVALID,
895  0,
896  0,
897  NULL,
898  NULL,
899  &jstate);
900 }
901 
902 /*
903  * Planner hook: forward to regular planner, but measure planning time
904  * if needed.
905  */
906 static PlannedStmt *
908  const char *query_string,
909  int cursorOptions,
910  ParamListInfo boundParams)
911 {
912  PlannedStmt *result;
913 
914  /*
915  * We can't process the query if no query_string is provided, as
916  * pgss_store needs it. We also ignore query without queryid, as it would
917  * be treated as a utility statement, which may not be the case.
918  *
919  * Note that planner_hook can be called from the planner itself, so we
920  * have a specific nesting level for the planner. However, utility
921  * commands containing optimizable statements can also call the planner,
922  * same for regular DML (for instance for underlying foreign key queries).
923  * So testing the planner nesting level only is not enough to detect real
924  * top level planner call.
925  */
927  && pgss_track_planning && query_string
928  && parse->queryId != UINT64CONST(0))
929  {
930  instr_time start;
932  BufferUsage bufusage_start,
933  bufusage;
934  WalUsage walusage_start,
935  walusage;
936 
937  /* We need to track buffer usage as the planner can access them. */
938  bufusage_start = pgBufferUsage;
939 
940  /*
941  * Similarly the planner could write some WAL records in some cases
942  * (e.g. setting a hint bit with those being WAL-logged)
943  */
944  walusage_start = pgWalUsage;
945  INSTR_TIME_SET_CURRENT(start);
946 
948  PG_TRY();
949  {
950  if (prev_planner_hook)
951  result = prev_planner_hook(parse, query_string, cursorOptions,
952  boundParams);
953  else
954  result = standard_planner(parse, query_string, cursorOptions,
955  boundParams);
956  }
957  PG_FINALLY();
958  {
960  }
961  PG_END_TRY();
962 
963  INSTR_TIME_SET_CURRENT(duration);
964  INSTR_TIME_SUBTRACT(duration, start);
965 
966  /* calc differences of buffer counters. */
967  memset(&bufusage, 0, sizeof(BufferUsage));
968  BufferUsageAccumDiff(&bufusage, &pgBufferUsage, &bufusage_start);
969 
970  /* calc differences of WAL counters. */
971  memset(&walusage, 0, sizeof(WalUsage));
972  WalUsageAccumDiff(&walusage, &pgWalUsage, &walusage_start);
973 
974  pgss_store(query_string,
975  parse->queryId,
976  parse->stmt_location,
977  parse->stmt_len,
978  PGSS_PLAN,
979  INSTR_TIME_GET_MILLISEC(duration),
980  0,
981  &bufusage,
982  &walusage,
983  NULL);
984  }
985  else
986  {
987  if (prev_planner_hook)
988  result = prev_planner_hook(parse, query_string, cursorOptions,
989  boundParams);
990  else
991  result = standard_planner(parse, query_string, cursorOptions,
992  boundParams);
993  }
994 
995  return result;
996 }
997 
998 /*
999  * ExecutorStart hook: start up tracking if needed
1000  */
1001 static void
1002 pgss_ExecutorStart(QueryDesc *queryDesc, int eflags)
1003 {
1004  if (prev_ExecutorStart)
1005  prev_ExecutorStart(queryDesc, eflags);
1006  else
1007  standard_ExecutorStart(queryDesc, eflags);
1008 
1009  /*
1010  * If query has queryId zero, don't track it. This prevents double
1011  * counting of optimizable statements that are directly contained in
1012  * utility statements.
1013  */
1014  if (pgss_enabled(exec_nested_level) && queryDesc->plannedstmt->queryId != UINT64CONST(0))
1015  {
1016  /*
1017  * Set up to track total elapsed time in ExecutorRun. Make sure the
1018  * space is allocated in the per-query context so it will go away at
1019  * ExecutorEnd.
1020  */
1021  if (queryDesc->totaltime == NULL)
1022  {
1023  MemoryContext oldcxt;
1024 
1025  oldcxt = MemoryContextSwitchTo(queryDesc->estate->es_query_cxt);
1026  queryDesc->totaltime = InstrAlloc(1, INSTRUMENT_ALL);
1027  MemoryContextSwitchTo(oldcxt);
1028  }
1029  }
1030 }
1031 
1032 /*
1033  * ExecutorRun hook: all we need do is track nesting depth
1034  */
1035 static void
1036 pgss_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count,
1037  bool execute_once)
1038 {
1040  PG_TRY();
1041  {
1042  if (prev_ExecutorRun)
1043  prev_ExecutorRun(queryDesc, direction, count, execute_once);
1044  else
1045  standard_ExecutorRun(queryDesc, direction, count, execute_once);
1046  }
1047  PG_FINALLY();
1048  {
1050  }
1051  PG_END_TRY();
1052 }
1053 
1054 /*
1055  * ExecutorFinish hook: all we need do is track nesting depth
1056  */
1057 static void
1059 {
1061  PG_TRY();
1062  {
1063  if (prev_ExecutorFinish)
1064  prev_ExecutorFinish(queryDesc);
1065  else
1066  standard_ExecutorFinish(queryDesc);
1067  }
1068  PG_FINALLY();
1069  {
1071  }
1072  PG_END_TRY();
1073 }
1074 
1075 /*
1076  * ExecutorEnd hook: store results if needed
1077  */
1078 static void
1080 {
1081  uint64 queryId = queryDesc->plannedstmt->queryId;
1082 
1083  if (queryId != UINT64CONST(0) && queryDesc->totaltime &&
1085  {
1086  /*
1087  * Make sure stats accumulation is done. (Note: it's okay if several
1088  * levels of hook all do this.)
1089  */
1090  InstrEndLoop(queryDesc->totaltime);
1091 
1092  pgss_store(queryDesc->sourceText,
1093  queryId,
1094  queryDesc->plannedstmt->stmt_location,
1095  queryDesc->plannedstmt->stmt_len,
1096  PGSS_EXEC,
1097  queryDesc->totaltime->total * 1000.0, /* convert to msec */
1098  queryDesc->estate->es_processed,
1099  &queryDesc->totaltime->bufusage,
1100  &queryDesc->totaltime->walusage,
1101  NULL);
1102  }
1103 
1104  if (prev_ExecutorEnd)
1105  prev_ExecutorEnd(queryDesc);
1106  else
1107  standard_ExecutorEnd(queryDesc);
1108 }
1109 
1110 /*
1111  * ProcessUtility hook
1112  */
1113 static void
1114 pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
1115  ProcessUtilityContext context,
1116  ParamListInfo params, QueryEnvironment *queryEnv,
1118 {
1119  Node *parsetree = pstmt->utilityStmt;
1120 
1121  /*
1122  * If it's an EXECUTE statement, we don't track it and don't increment the
1123  * nesting level. This allows the cycles to be charged to the underlying
1124  * PREPARE instead (by the Executor hooks), which is much more useful.
1125  *
1126  * We also don't track execution of PREPARE. If we did, we would get one
1127  * hash table entry for the PREPARE (with hash calculated from the query
1128  * string), and then a different one with the same query string (but hash
1129  * calculated from the query tree) would be used to accumulate costs of
1130  * ensuing EXECUTEs. This would be confusing, and inconsistent with other
1131  * cases where planning time is not included at all.
1132  *
1133  * Likewise, we don't track execution of DEALLOCATE.
1134  */
1136  !IsA(parsetree, ExecuteStmt) &&
1137  !IsA(parsetree, PrepareStmt) &&
1138  !IsA(parsetree, DeallocateStmt))
1139  {
1140  instr_time start;
1142  uint64 rows;
1143  BufferUsage bufusage_start,
1144  bufusage;
1145  WalUsage walusage_start,
1146  walusage;
1147 
1148  bufusage_start = pgBufferUsage;
1149  walusage_start = pgWalUsage;
1150  INSTR_TIME_SET_CURRENT(start);
1151 
1153  PG_TRY();
1154  {
1155  if (prev_ProcessUtility)
1156  prev_ProcessUtility(pstmt, queryString,
1157  context, params, queryEnv,
1158  dest, qc);
1159  else
1160  standard_ProcessUtility(pstmt, queryString,
1161  context, params, queryEnv,
1162  dest, qc);
1163  }
1164  PG_FINALLY();
1165  {
1167  }
1168  PG_END_TRY();
1169 
1170  INSTR_TIME_SET_CURRENT(duration);
1171  INSTR_TIME_SUBTRACT(duration, start);
1172 
1173  /*
1174  * Track the total number of rows retrieved or affected by
1175  * the utility statements of COPY, FETCH, CREATE TABLE AS,
1176  * CREATE MATERIALIZED VIEW and SELECT INTO.
1177  */
1178  rows = (qc && (qc->commandTag == CMDTAG_COPY ||
1179  qc->commandTag == CMDTAG_FETCH ||
1180  qc->commandTag == CMDTAG_SELECT)) ?
1181  qc->nprocessed : 0;
1182 
1183  /* calc differences of buffer counters. */
1184  memset(&bufusage, 0, sizeof(BufferUsage));
1185  BufferUsageAccumDiff(&bufusage, &pgBufferUsage, &bufusage_start);
1186 
1187  /* calc differences of WAL counters. */
1188  memset(&walusage, 0, sizeof(WalUsage));
1189  WalUsageAccumDiff(&walusage, &pgWalUsage, &walusage_start);
1190 
1191  pgss_store(queryString,
1192  0, /* signal that it's a utility stmt */
1193  pstmt->stmt_location,
1194  pstmt->stmt_len,
1195  PGSS_EXEC,
1196  INSTR_TIME_GET_MILLISEC(duration),
1197  rows,
1198  &bufusage,
1199  &walusage,
1200  NULL);
1201  }
1202  else
1203  {
1204  if (prev_ProcessUtility)
1205  prev_ProcessUtility(pstmt, queryString,
1206  context, params, queryEnv,
1207  dest, qc);
1208  else
1209  standard_ProcessUtility(pstmt, queryString,
1210  context, params, queryEnv,
1211  dest, qc);
1212  }
1213 }
1214 
1215 /*
1216  * Given an arbitrarily long query string, produce a hash for the purposes of
1217  * identifying the query, without normalizing constants. Used when hashing
1218  * utility statements.
1219  */
1220 static uint64
1221 pgss_hash_string(const char *str, int len)
1222 {
1223  return DatumGetUInt64(hash_any_extended((const unsigned char *) str,
1224  len, 0));
1225 }
1226 
1227 /*
1228  * Store some statistics for a statement.
1229  *
1230  * If queryId is 0 then this is a utility statement and we should compute
1231  * a suitable queryId internally.
1232  *
1233  * If jstate is not NULL then we're trying to create an entry for which
1234  * we have no statistics as yet; we just want to record the normalized
1235  * query string. total_time, rows, bufusage and walusage are ignored in this
1236  * case.
1237  *
1238  * If kind is PGSS_PLAN or PGSS_EXEC, its value is used as the array position
1239  * for the arrays in the Counters field.
1240  */
1241 static void
1242 pgss_store(const char *query, uint64 queryId,
1243  int query_location, int query_len,
1244  pgssStoreKind kind,
1245  double total_time, uint64 rows,
1246  const BufferUsage *bufusage,
1247  const WalUsage *walusage,
1248  pgssJumbleState *jstate)
1249 {
1250  pgssHashKey key;
1251  pgssEntry *entry;
1252  char *norm_query = NULL;
1253  int encoding = GetDatabaseEncoding();
1254 
1255  Assert(query != NULL);
1256 
1257  /* Safety check... */
1258  if (!pgss || !pgss_hash)
1259  return;
1260 
1261  /*
1262  * Confine our attention to the relevant part of the string, if the query
1263  * is a portion of a multi-statement source string.
1264  *
1265  * First apply starting offset, unless it's -1 (unknown).
1266  */
1267  if (query_location >= 0)
1268  {
1269  Assert(query_location <= strlen(query));
1270  query += query_location;
1271  /* Length of 0 (or -1) means "rest of string" */
1272  if (query_len <= 0)
1273  query_len = strlen(query);
1274  else
1275  Assert(query_len <= strlen(query));
1276  }
1277  else
1278  {
1279  /* If query location is unknown, distrust query_len as well */
1280  query_location = 0;
1281  query_len = strlen(query);
1282  }
1283 
1284  /*
1285  * Discard leading and trailing whitespace, too. Use scanner_isspace()
1286  * not libc's isspace(), because we want to match the lexer's behavior.
1287  */
1288  while (query_len > 0 && scanner_isspace(query[0]))
1289  query++, query_location++, query_len--;
1290  while (query_len > 0 && scanner_isspace(query[query_len - 1]))
1291  query_len--;
1292 
1293  /*
1294  * For utility statements, we just hash the query string to get an ID.
1295  */
1296  if (queryId == UINT64CONST(0))
1297  {
1298  queryId = pgss_hash_string(query, query_len);
1299 
1300  /*
1301  * If we are unlucky enough to get a hash of zero(invalid), use
1302  * queryID as 2 instead, queryID 1 is already in use for normal
1303  * statements.
1304  */
1305  if (queryId == UINT64CONST(0))
1306  queryId = UINT64CONST(2);
1307  }
1308 
1309  /* Set up key for hashtable search */
1310  key.userid = GetUserId();
1311  key.dbid = MyDatabaseId;
1312  key.queryid = queryId;
1313 
1314  /* Lookup the hash table entry with shared lock. */
1315  LWLockAcquire(pgss->lock, LW_SHARED);
1316 
1317  entry = (pgssEntry *) hash_search(pgss_hash, &key, HASH_FIND, NULL);
1318 
1319  /* Create new entry, if not present */
1320  if (!entry)
1321  {
1322  Size query_offset;
1323  int gc_count;
1324  bool stored;
1325  bool do_gc;
1326 
1327  /*
1328  * Create a new, normalized query string if caller asked. We don't
1329  * need to hold the lock while doing this work. (Note: in any case,
1330  * it's possible that someone else creates a duplicate hashtable entry
1331  * in the interval where we don't hold the lock below. That case is
1332  * handled by entry_alloc.)
1333  */
1334  if (jstate)
1335  {
1336  LWLockRelease(pgss->lock);
1337  norm_query = generate_normalized_query(jstate, query,
1338  query_location,
1339  &query_len);
1340  LWLockAcquire(pgss->lock, LW_SHARED);
1341  }
1342 
1343  /* Append new query text to file with only shared lock held */
1344  stored = qtext_store(norm_query ? norm_query : query, query_len,
1345  &query_offset, &gc_count);
1346 
1347  /*
1348  * Determine whether we need to garbage collect external query texts
1349  * while the shared lock is still held. This micro-optimization
1350  * avoids taking the time to decide this while holding exclusive lock.
1351  */
1352  do_gc = need_gc_qtexts();
1353 
1354  /* Need exclusive lock to make a new hashtable entry - promote */
1355  LWLockRelease(pgss->lock);
1357 
1358  /*
1359  * A garbage collection may have occurred while we weren't holding the
1360  * lock. In the unlikely event that this happens, the query text we
1361  * stored above will have been garbage collected, so write it again.
1362  * This should be infrequent enough that doing it while holding
1363  * exclusive lock isn't a performance problem.
1364  */
1365  if (!stored || pgss->gc_count != gc_count)
1366  stored = qtext_store(norm_query ? norm_query : query, query_len,
1367  &query_offset, NULL);
1368 
1369  /* If we failed to write to the text file, give up */
1370  if (!stored)
1371  goto done;
1372 
1373  /* OK to create a new hashtable entry */
1374  entry = entry_alloc(&key, query_offset, query_len, encoding,
1375  jstate != NULL);
1376 
1377  /* If needed, perform garbage collection while exclusive lock held */
1378  if (do_gc)
1379  gc_qtexts();
1380  }
1381 
1382  /* Increment the counts, except when jstate is not NULL */
1383  if (!jstate)
1384  {
1385  /*
1386  * Grab the spinlock while updating the counters (see comment about
1387  * locking rules at the head of the file)
1388  */
1389  volatile pgssEntry *e = (volatile pgssEntry *) entry;
1390 
1391  Assert(kind == PGSS_PLAN || kind == PGSS_EXEC);
1392 
1393  SpinLockAcquire(&e->mutex);
1394 
1395  /* "Unstick" entry if it was previously sticky */
1396  if (IS_STICKY(e->counters))
1397  e->counters.usage = USAGE_INIT;
1398 
1399  e->counters.calls[kind] += 1;
1400  e->counters.total_time[kind] += total_time;
1401 
1402  if (e->counters.calls[kind] == 1)
1403  {
1404  e->counters.min_time[kind] = total_time;
1405  e->counters.max_time[kind] = total_time;
1406  e->counters.mean_time[kind] = total_time;
1407  }
1408  else
1409  {
1410  /*
1411  * Welford's method for accurately computing variance. See
1412  * <http://www.johndcook.com/blog/standard_deviation/>
1413  */
1414  double old_mean = e->counters.mean_time[kind];
1415 
1416  e->counters.mean_time[kind] +=
1417  (total_time - old_mean) / e->counters.calls[kind];
1418  e->counters.sum_var_time[kind] +=
1419  (total_time - old_mean) * (total_time - e->counters.mean_time[kind]);
1420 
1421  /* calculate min and max time */
1422  if (e->counters.min_time[kind] > total_time)
1423  e->counters.min_time[kind] = total_time;
1424  if (e->counters.max_time[kind] < total_time)
1425  e->counters.max_time[kind] = total_time;
1426  }
1427  e->counters.rows += rows;
1428  e->counters.shared_blks_hit += bufusage->shared_blks_hit;
1429  e->counters.shared_blks_read += bufusage->shared_blks_read;
1432  e->counters.local_blks_hit += bufusage->local_blks_hit;
1433  e->counters.local_blks_read += bufusage->local_blks_read;
1436  e->counters.temp_blks_read += bufusage->temp_blks_read;
1440  e->counters.usage += USAGE_EXEC(total_time);
1441  e->counters.wal_records += walusage->wal_records;
1442  e->counters.wal_fpi += walusage->wal_fpi;
1443  e->counters.wal_bytes += walusage->wal_bytes;
1444 
1445  SpinLockRelease(&e->mutex);
1446  }
1447 
1448 done:
1449  LWLockRelease(pgss->lock);
1450 
1451  /* We postpone this clean-up until we're out of the lock */
1452  if (norm_query)
1453  pfree(norm_query);
1454 }
1455 
1456 /*
1457  * Reset statement statistics corresponding to userid, dbid, and queryid.
1458  */
1459 Datum
1461 {
1462  Oid userid;
1463  Oid dbid;
1464  uint64 queryid;
1465 
1466  userid = PG_GETARG_OID(0);
1467  dbid = PG_GETARG_OID(1);
1468  queryid = (uint64) PG_GETARG_INT64(2);
1469 
1470  entry_reset(userid, dbid, queryid);
1471 
1472  PG_RETURN_VOID();
1473 }
1474 
1475 /*
1476  * Reset statement statistics.
1477  */
1478 Datum
1480 {
1481  entry_reset(0, 0, 0);
1482 
1483  PG_RETURN_VOID();
1484 }
1485 
1486 /* Number of output arguments (columns) for various API versions */
1487 #define PG_STAT_STATEMENTS_COLS_V1_0 14
1488 #define PG_STAT_STATEMENTS_COLS_V1_1 18
1489 #define PG_STAT_STATEMENTS_COLS_V1_2 19
1490 #define PG_STAT_STATEMENTS_COLS_V1_3 23
1491 #define PG_STAT_STATEMENTS_COLS_V1_8 32
1492 #define PG_STAT_STATEMENTS_COLS 32 /* maximum of above */
1493 
1494 /*
1495  * Retrieve statement statistics.
1496  *
1497  * The SQL API of this function has changed multiple times, and will likely
1498  * do so again in future. To support the case where a newer version of this
1499  * loadable module is being used with an old SQL declaration of the function,
1500  * we continue to support the older API versions. For 1.2 and later, the
1501  * expected API version is identified by embedding it in the C name of the
1502  * function. Unfortunately we weren't bright enough to do that for 1.1.
1503  */
1504 Datum
1506 {
1507  bool showtext = PG_GETARG_BOOL(0);
1508 
1509  pg_stat_statements_internal(fcinfo, PGSS_V1_8, showtext);
1510 
1511  return (Datum) 0;
1512 }
1513 
1514 Datum
1516 {
1517  bool showtext = PG_GETARG_BOOL(0);
1518 
1519  pg_stat_statements_internal(fcinfo, PGSS_V1_3, showtext);
1520 
1521  return (Datum) 0;
1522 }
1523 
1524 Datum
1526 {
1527  bool showtext = PG_GETARG_BOOL(0);
1528 
1529  pg_stat_statements_internal(fcinfo, PGSS_V1_2, showtext);
1530 
1531  return (Datum) 0;
1532 }
1533 
1534 /*
1535  * Legacy entry point for pg_stat_statements() API versions 1.0 and 1.1.
1536  * This can be removed someday, perhaps.
1537  */
1538 Datum
1540 {
1541  /* If it's really API 1.1, we'll figure that out below */
1542  pg_stat_statements_internal(fcinfo, PGSS_V1_0, true);
1543 
1544  return (Datum) 0;
1545 }
1546 
1547 /* Common code for all versions of pg_stat_statements() */
1548 static void
1550  pgssVersion api_version,
1551  bool showtext)
1552 {
1553  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1554  TupleDesc tupdesc;
1555  Tuplestorestate *tupstore;
1556  MemoryContext per_query_ctx;
1557  MemoryContext oldcontext;
1558  Oid userid = GetUserId();
1559  bool is_allowed_role = false;
1560  char *qbuffer = NULL;
1561  Size qbuffer_size = 0;
1562  Size extent = 0;
1563  int gc_count = 0;
1564  HASH_SEQ_STATUS hash_seq;
1565  pgssEntry *entry;
1566 
1567  /* Superusers or members of pg_read_all_stats members are allowed */
1568  is_allowed_role = is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_STATS);
1569 
1570  /* hash table must exist already */
1571  if (!pgss || !pgss_hash)
1572  ereport(ERROR,
1573  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1574  errmsg("pg_stat_statements must be loaded via shared_preload_libraries")));
1575 
1576  /* check to see if caller supports us returning a tuplestore */
1577  if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
1578  ereport(ERROR,
1579  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1580  errmsg("set-valued function called in context that cannot accept a set")));
1581  if (!(rsinfo->allowedModes & SFRM_Materialize))
1582  ereport(ERROR,
1583  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1584  errmsg("materialize mode required, but it is not allowed in this context")));
1585 
1586  /* Switch into long-lived context to construct returned data structures */
1587  per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
1588  oldcontext = MemoryContextSwitchTo(per_query_ctx);
1589 
1590  /* Build a tuple descriptor for our result type */
1591  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
1592  elog(ERROR, "return type must be a row type");
1593 
1594  /*
1595  * Check we have the expected number of output arguments. Aside from
1596  * being a good safety check, we need a kluge here to detect API version
1597  * 1.1, which was wedged into the code in an ill-considered way.
1598  */
1599  switch (tupdesc->natts)
1600  {
1602  if (api_version != PGSS_V1_0)
1603  elog(ERROR, "incorrect number of output arguments");
1604  break;
1606  /* pg_stat_statements() should have told us 1.0 */
1607  if (api_version != PGSS_V1_0)
1608  elog(ERROR, "incorrect number of output arguments");
1609  api_version = PGSS_V1_1;
1610  break;
1612  if (api_version != PGSS_V1_2)
1613  elog(ERROR, "incorrect number of output arguments");
1614  break;
1616  if (api_version != PGSS_V1_3)
1617  elog(ERROR, "incorrect number of output arguments");
1618  break;
1620  if (api_version != PGSS_V1_8)
1621  elog(ERROR, "incorrect number of output arguments");
1622  break;
1623  default:
1624  elog(ERROR, "incorrect number of output arguments");
1625  }
1626 
1627  tupstore = tuplestore_begin_heap(true, false, work_mem);
1628  rsinfo->returnMode = SFRM_Materialize;
1629  rsinfo->setResult = tupstore;
1630  rsinfo->setDesc = tupdesc;
1631 
1632  MemoryContextSwitchTo(oldcontext);
1633 
1634  /*
1635  * We'd like to load the query text file (if needed) while not holding any
1636  * lock on pgss->lock. In the worst case we'll have to do this again
1637  * after we have the lock, but it's unlikely enough to make this a win
1638  * despite occasional duplicated work. We need to reload if anybody
1639  * writes to the file (either a retail qtext_store(), or a garbage
1640  * collection) between this point and where we've gotten shared lock. If
1641  * a qtext_store is actually in progress when we look, we might as well
1642  * skip the speculative load entirely.
1643  */
1644  if (showtext)
1645  {
1646  int n_writers;
1647 
1648  /* Take the mutex so we can examine variables */
1649  {
1650  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
1651 
1652  SpinLockAcquire(&s->mutex);
1653  extent = s->extent;
1654  n_writers = s->n_writers;
1655  gc_count = s->gc_count;
1656  SpinLockRelease(&s->mutex);
1657  }
1658 
1659  /* No point in loading file now if there are active writers */
1660  if (n_writers == 0)
1661  qbuffer = qtext_load_file(&qbuffer_size);
1662  }
1663 
1664  /*
1665  * Get shared lock, load or reload the query text file if we must, and
1666  * iterate over the hashtable entries.
1667  *
1668  * With a large hash table, we might be holding the lock rather longer
1669  * than one could wish. However, this only blocks creation of new hash
1670  * table entries, and the larger the hash table the less likely that is to
1671  * be needed. So we can hope this is okay. Perhaps someday we'll decide
1672  * we need to partition the hash table to limit the time spent holding any
1673  * one lock.
1674  */
1675  LWLockAcquire(pgss->lock, LW_SHARED);
1676 
1677  if (showtext)
1678  {
1679  /*
1680  * Here it is safe to examine extent and gc_count without taking the
1681  * mutex. Note that although other processes might change
1682  * pgss->extent just after we look at it, the strings they then write
1683  * into the file cannot yet be referenced in the hashtable, so we
1684  * don't care whether we see them or not.
1685  *
1686  * If qtext_load_file fails, we just press on; we'll return NULL for
1687  * every query text.
1688  */
1689  if (qbuffer == NULL ||
1690  pgss->extent != extent ||
1691  pgss->gc_count != gc_count)
1692  {
1693  if (qbuffer)
1694  free(qbuffer);
1695  qbuffer = qtext_load_file(&qbuffer_size);
1696  }
1697  }
1698 
1699  hash_seq_init(&hash_seq, pgss_hash);
1700  while ((entry = hash_seq_search(&hash_seq)) != NULL)
1701  {
1703  bool nulls[PG_STAT_STATEMENTS_COLS];
1704  int i = 0;
1705  Counters tmp;
1706  double stddev;
1707  int64 queryid = entry->key.queryid;
1708 
1709  memset(values, 0, sizeof(values));
1710  memset(nulls, 0, sizeof(nulls));
1711 
1712  values[i++] = ObjectIdGetDatum(entry->key.userid);
1713  values[i++] = ObjectIdGetDatum(entry->key.dbid);
1714 
1715  if (is_allowed_role || entry->key.userid == userid)
1716  {
1717  if (api_version >= PGSS_V1_2)
1718  values[i++] = Int64GetDatumFast(queryid);
1719 
1720  if (showtext)
1721  {
1722  char *qstr = qtext_fetch(entry->query_offset,
1723  entry->query_len,
1724  qbuffer,
1725  qbuffer_size);
1726 
1727  if (qstr)
1728  {
1729  char *enc;
1730 
1731  enc = pg_any_to_server(qstr,
1732  entry->query_len,
1733  entry->encoding);
1734 
1735  values[i++] = CStringGetTextDatum(enc);
1736 
1737  if (enc != qstr)
1738  pfree(enc);
1739  }
1740  else
1741  {
1742  /* Just return a null if we fail to find the text */
1743  nulls[i++] = true;
1744  }
1745  }
1746  else
1747  {
1748  /* Query text not requested */
1749  nulls[i++] = true;
1750  }
1751  }
1752  else
1753  {
1754  /* Don't show queryid */
1755  if (api_version >= PGSS_V1_2)
1756  nulls[i++] = true;
1757 
1758  /*
1759  * Don't show query text, but hint as to the reason for not doing
1760  * so if it was requested
1761  */
1762  if (showtext)
1763  values[i++] = CStringGetTextDatum("<insufficient privilege>");
1764  else
1765  nulls[i++] = true;
1766  }
1767 
1768  /* copy counters to a local variable to keep locking time short */
1769  {
1770  volatile pgssEntry *e = (volatile pgssEntry *) entry;
1771 
1772  SpinLockAcquire(&e->mutex);
1773  tmp = e->counters;
1774  SpinLockRelease(&e->mutex);
1775  }
1776 
1777  /* Skip entry if unexecuted (ie, it's a pending "sticky" entry) */
1778  if (IS_STICKY(tmp))
1779  continue;
1780 
1781  /* Note that we rely on PGSS_PLAN being 0 and PGSS_EXEC being 1. */
1782  for (int kind = 0; kind < PGSS_NUMKIND; kind++)
1783  {
1784  if (kind == PGSS_EXEC || api_version >= PGSS_V1_8)
1785  {
1786  values[i++] = Int64GetDatumFast(tmp.calls[kind]);
1787  values[i++] = Float8GetDatumFast(tmp.total_time[kind]);
1788  }
1789 
1790  if ((kind == PGSS_EXEC && api_version >= PGSS_V1_3) ||
1791  api_version >= PGSS_V1_8)
1792  {
1793  values[i++] = Float8GetDatumFast(tmp.min_time[kind]);
1794  values[i++] = Float8GetDatumFast(tmp.max_time[kind]);
1795  values[i++] = Float8GetDatumFast(tmp.mean_time[kind]);
1796 
1797  /*
1798  * Note we are calculating the population variance here, not
1799  * the sample variance, as we have data for the whole
1800  * population, so Bessel's correction is not used, and we
1801  * don't divide by tmp.calls - 1.
1802  */
1803  if (tmp.calls[kind] > 1)
1804  stddev = sqrt(tmp.sum_var_time[kind] / tmp.calls[kind]);
1805  else
1806  stddev = 0.0;
1807  values[i++] = Float8GetDatumFast(stddev);
1808  }
1809  }
1810  values[i++] = Int64GetDatumFast(tmp.rows);
1811  values[i++] = Int64GetDatumFast(tmp.shared_blks_hit);
1812  values[i++] = Int64GetDatumFast(tmp.shared_blks_read);
1813  if (api_version >= PGSS_V1_1)
1814  values[i++] = Int64GetDatumFast(tmp.shared_blks_dirtied);
1815  values[i++] = Int64GetDatumFast(tmp.shared_blks_written);
1816  values[i++] = Int64GetDatumFast(tmp.local_blks_hit);
1817  values[i++] = Int64GetDatumFast(tmp.local_blks_read);
1818  if (api_version >= PGSS_V1_1)
1819  values[i++] = Int64GetDatumFast(tmp.local_blks_dirtied);
1820  values[i++] = Int64GetDatumFast(tmp.local_blks_written);
1821  values[i++] = Int64GetDatumFast(tmp.temp_blks_read);
1822  values[i++] = Int64GetDatumFast(tmp.temp_blks_written);
1823  if (api_version >= PGSS_V1_1)
1824  {
1825  values[i++] = Float8GetDatumFast(tmp.blk_read_time);
1826  values[i++] = Float8GetDatumFast(tmp.blk_write_time);
1827  }
1828  if (api_version >= PGSS_V1_8)
1829  {
1830  char buf[256];
1831  Datum wal_bytes;
1832 
1833  values[i++] = Int64GetDatumFast(tmp.wal_records);
1834  values[i++] = Int64GetDatumFast(tmp.wal_fpi);
1835 
1836  snprintf(buf, sizeof buf, UINT64_FORMAT, tmp.wal_bytes);
1837 
1838  /* Convert to numeric. */
1839  wal_bytes = DirectFunctionCall3(numeric_in,
1840  CStringGetDatum(buf),
1841  ObjectIdGetDatum(0),
1842  Int32GetDatum(-1));
1843  values[i++] = wal_bytes;
1844  }
1845 
1846  Assert(i == (api_version == PGSS_V1_0 ? PG_STAT_STATEMENTS_COLS_V1_0 :
1847  api_version == PGSS_V1_1 ? PG_STAT_STATEMENTS_COLS_V1_1 :
1848  api_version == PGSS_V1_2 ? PG_STAT_STATEMENTS_COLS_V1_2 :
1849  api_version == PGSS_V1_3 ? PG_STAT_STATEMENTS_COLS_V1_3 :
1850  api_version == PGSS_V1_8 ? PG_STAT_STATEMENTS_COLS_V1_8 :
1851  -1 /* fail if you forget to update this assert */ ));
1852 
1853  tuplestore_putvalues(tupstore, tupdesc, values, nulls);
1854  }
1855 
1856  /* clean up and return the tuplestore */
1857  LWLockRelease(pgss->lock);
1858 
1859  if (qbuffer)
1860  free(qbuffer);
1861 
1862  tuplestore_donestoring(tupstore);
1863 }
1864 
1865 /*
1866  * Estimate shared memory space needed.
1867  */
1868 static Size
1870 {
1871  Size size;
1872 
1873  size = MAXALIGN(sizeof(pgssSharedState));
1874  size = add_size(size, hash_estimate_size(pgss_max, sizeof(pgssEntry)));
1875 
1876  return size;
1877 }
1878 
1879 /*
1880  * Allocate a new hashtable entry.
1881  * caller must hold an exclusive lock on pgss->lock
1882  *
1883  * "query" need not be null-terminated; we rely on query_len instead
1884  *
1885  * If "sticky" is true, make the new entry artificially sticky so that it will
1886  * probably still be there when the query finishes execution. We do this by
1887  * giving it a median usage value rather than the normal value. (Strictly
1888  * speaking, query strings are normalized on a best effort basis, though it
1889  * would be difficult to demonstrate this even under artificial conditions.)
1890  *
1891  * Note: despite needing exclusive lock, it's not an error for the target
1892  * entry to already exist. This is because pgss_store releases and
1893  * reacquires lock after failing to find a match; so someone else could
1894  * have made the entry while we waited to get exclusive lock.
1895  */
1896 static pgssEntry *
1897 entry_alloc(pgssHashKey *key, Size query_offset, int query_len, int encoding,
1898  bool sticky)
1899 {
1900  pgssEntry *entry;
1901  bool found;
1902 
1903  /* Make space if needed */
1904  while (hash_get_num_entries(pgss_hash) >= pgss_max)
1905  entry_dealloc();
1906 
1907  /* Find or create an entry with desired hash code */
1908  entry = (pgssEntry *) hash_search(pgss_hash, key, HASH_ENTER, &found);
1909 
1910  if (!found)
1911  {
1912  /* New entry, initialize it */
1913 
1914  /* reset the statistics */
1915  memset(&entry->counters, 0, sizeof(Counters));
1916  /* set the appropriate initial usage count */
1917  entry->counters.usage = sticky ? pgss->cur_median_usage : USAGE_INIT;
1918  /* re-initialize the mutex each time ... we assume no one using it */
1919  SpinLockInit(&entry->mutex);
1920  /* ... and don't forget the query text metadata */
1921  Assert(query_len >= 0);
1922  entry->query_offset = query_offset;
1923  entry->query_len = query_len;
1924  entry->encoding = encoding;
1925  }
1926 
1927  return entry;
1928 }
1929 
1930 /*
1931  * qsort comparator for sorting into increasing usage order
1932  */
1933 static int
1934 entry_cmp(const void *lhs, const void *rhs)
1935 {
1936  double l_usage = (*(pgssEntry *const *) lhs)->counters.usage;
1937  double r_usage = (*(pgssEntry *const *) rhs)->counters.usage;
1938 
1939  if (l_usage < r_usage)
1940  return -1;
1941  else if (l_usage > r_usage)
1942  return +1;
1943  else
1944  return 0;
1945 }
1946 
1947 /*
1948  * Deallocate least-used entries.
1949  *
1950  * Caller must hold an exclusive lock on pgss->lock.
1951  */
1952 static void
1954 {
1955  HASH_SEQ_STATUS hash_seq;
1956  pgssEntry **entries;
1957  pgssEntry *entry;
1958  int nvictims;
1959  int i;
1960  Size tottextlen;
1961  int nvalidtexts;
1962 
1963  /*
1964  * Sort entries by usage and deallocate USAGE_DEALLOC_PERCENT of them.
1965  * While we're scanning the table, apply the decay factor to the usage
1966  * values, and update the mean query length.
1967  *
1968  * Note that the mean query length is almost immediately obsolete, since
1969  * we compute it before not after discarding the least-used entries.
1970  * Hopefully, that doesn't affect the mean too much; it doesn't seem worth
1971  * making two passes to get a more current result. Likewise, the new
1972  * cur_median_usage includes the entries we're about to zap.
1973  */
1974 
1975  entries = palloc(hash_get_num_entries(pgss_hash) * sizeof(pgssEntry *));
1976 
1977  i = 0;
1978  tottextlen = 0;
1979  nvalidtexts = 0;
1980 
1981  hash_seq_init(&hash_seq, pgss_hash);
1982  while ((entry = hash_seq_search(&hash_seq)) != NULL)
1983  {
1984  entries[i++] = entry;
1985  /* "Sticky" entries get a different usage decay rate. */
1986  if (IS_STICKY(entry->counters))
1988  else
1990  /* In the mean length computation, ignore dropped texts. */
1991  if (entry->query_len >= 0)
1992  {
1993  tottextlen += entry->query_len + 1;
1994  nvalidtexts++;
1995  }
1996  }
1997 
1998  /* Sort into increasing order by usage */
1999  qsort(entries, i, sizeof(pgssEntry *), entry_cmp);
2000 
2001  /* Record the (approximate) median usage */
2002  if (i > 0)
2003  pgss->cur_median_usage = entries[i / 2]->counters.usage;
2004  /* Record the mean query length */
2005  if (nvalidtexts > 0)
2006  pgss->mean_query_len = tottextlen / nvalidtexts;
2007  else
2009 
2010  /* Now zap an appropriate fraction of lowest-usage entries */
2011  nvictims = Max(10, i * USAGE_DEALLOC_PERCENT / 100);
2012  nvictims = Min(nvictims, i);
2013 
2014  for (i = 0; i < nvictims; i++)
2015  {
2016  hash_search(pgss_hash, &entries[i]->key, HASH_REMOVE, NULL);
2017  }
2018 
2019  pfree(entries);
2020 }
2021 
2022 /*
2023  * Given a query string (not necessarily null-terminated), allocate a new
2024  * entry in the external query text file and store the string there.
2025  *
2026  * If successful, returns true, and stores the new entry's offset in the file
2027  * into *query_offset. Also, if gc_count isn't NULL, *gc_count is set to the
2028  * number of garbage collections that have occurred so far.
2029  *
2030  * On failure, returns false.
2031  *
2032  * At least a shared lock on pgss->lock must be held by the caller, so as
2033  * to prevent a concurrent garbage collection. Share-lock-holding callers
2034  * should pass a gc_count pointer to obtain the number of garbage collections,
2035  * so that they can recheck the count after obtaining exclusive lock to
2036  * detect whether a garbage collection occurred (and removed this entry).
2037  */
2038 static bool
2039 qtext_store(const char *query, int query_len,
2040  Size *query_offset, int *gc_count)
2041 {
2042  Size off;
2043  int fd;
2044 
2045  /*
2046  * We use a spinlock to protect extent/n_writers/gc_count, so that
2047  * multiple processes may execute this function concurrently.
2048  */
2049  {
2050  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
2051 
2052  SpinLockAcquire(&s->mutex);
2053  off = s->extent;
2054  s->extent += query_len + 1;
2055  s->n_writers++;
2056  if (gc_count)
2057  *gc_count = s->gc_count;
2058  SpinLockRelease(&s->mutex);
2059  }
2060 
2061  *query_offset = off;
2062 
2063  /* Now write the data into the successfully-reserved part of the file */
2064  fd = OpenTransientFile(PGSS_TEXT_FILE, O_RDWR | O_CREAT | PG_BINARY);
2065  if (fd < 0)
2066  goto error;
2067 
2068  if (pg_pwrite(fd, query, query_len, off) != query_len)
2069  goto error;
2070  if (pg_pwrite(fd, "\0", 1, off + query_len) != 1)
2071  goto error;
2072 
2073  CloseTransientFile(fd);
2074 
2075  /* Mark our write complete */
2076  {
2077  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
2078 
2079  SpinLockAcquire(&s->mutex);
2080  s->n_writers--;
2081  SpinLockRelease(&s->mutex);
2082  }
2083 
2084  return true;
2085 
2086 error:
2087  ereport(LOG,
2089  errmsg("could not write file \"%s\": %m",
2090  PGSS_TEXT_FILE)));
2091 
2092  if (fd >= 0)
2093  CloseTransientFile(fd);
2094 
2095  /* Mark our write complete */
2096  {
2097  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
2098 
2099  SpinLockAcquire(&s->mutex);
2100  s->n_writers--;
2101  SpinLockRelease(&s->mutex);
2102  }
2103 
2104  return false;
2105 }
2106 
2107 /*
2108  * Read the external query text file into a malloc'd buffer.
2109  *
2110  * Returns NULL (without throwing an error) if unable to read, eg
2111  * file not there or insufficient memory.
2112  *
2113  * On success, the buffer size is also returned into *buffer_size.
2114  *
2115  * This can be called without any lock on pgss->lock, but in that case
2116  * the caller is responsible for verifying that the result is sane.
2117  */
2118 static char *
2119 qtext_load_file(Size *buffer_size)
2120 {
2121  char *buf;
2122  int fd;
2123  struct stat stat;
2124 
2125  fd = OpenTransientFile(PGSS_TEXT_FILE, O_RDONLY | PG_BINARY);
2126  if (fd < 0)
2127  {
2128  if (errno != ENOENT)
2129  ereport(LOG,
2131  errmsg("could not read file \"%s\": %m",
2132  PGSS_TEXT_FILE)));
2133  return NULL;
2134  }
2135 
2136  /* Get file length */
2137  if (fstat(fd, &stat))
2138  {
2139  ereport(LOG,
2141  errmsg("could not stat file \"%s\": %m",
2142  PGSS_TEXT_FILE)));
2143  CloseTransientFile(fd);
2144  return NULL;
2145  }
2146 
2147  /* Allocate buffer; beware that off_t might be wider than size_t */
2148  if (stat.st_size <= MaxAllocHugeSize)
2149  buf = (char *) malloc(stat.st_size);
2150  else
2151  buf = NULL;
2152  if (buf == NULL)
2153  {
2154  ereport(LOG,
2155  (errcode(ERRCODE_OUT_OF_MEMORY),
2156  errmsg("out of memory"),
2157  errdetail("Could not allocate enough memory to read file \"%s\".",
2158  PGSS_TEXT_FILE)));
2159  CloseTransientFile(fd);
2160  return NULL;
2161  }
2162 
2163  /*
2164  * OK, slurp in the file. If we get a short read and errno doesn't get
2165  * set, the reason is probably that garbage collection truncated the file
2166  * since we did the fstat(), so we don't log a complaint --- but we don't
2167  * return the data, either, since it's most likely corrupt due to
2168  * concurrent writes from garbage collection.
2169  */
2170  errno = 0;
2171  if (read(fd, buf, stat.st_size) != stat.st_size)
2172  {
2173  if (errno)
2174  ereport(LOG,
2176  errmsg("could not read file \"%s\": %m",
2177  PGSS_TEXT_FILE)));
2178  free(buf);
2179  CloseTransientFile(fd);
2180  return NULL;
2181  }
2182 
2183  if (CloseTransientFile(fd) != 0)
2184  ereport(LOG,
2186  errmsg("could not close file \"%s\": %m", PGSS_TEXT_FILE)));
2187 
2188  *buffer_size = stat.st_size;
2189  return buf;
2190 }
2191 
2192 /*
2193  * Locate a query text in the file image previously read by qtext_load_file().
2194  *
2195  * We validate the given offset/length, and return NULL if bogus. Otherwise,
2196  * the result points to a null-terminated string within the buffer.
2197  */
2198 static char *
2199 qtext_fetch(Size query_offset, int query_len,
2200  char *buffer, Size buffer_size)
2201 {
2202  /* File read failed? */
2203  if (buffer == NULL)
2204  return NULL;
2205  /* Bogus offset/length? */
2206  if (query_len < 0 ||
2207  query_offset + query_len >= buffer_size)
2208  return NULL;
2209  /* As a further sanity check, make sure there's a trailing null */
2210  if (buffer[query_offset + query_len] != '\0')
2211  return NULL;
2212  /* Looks OK */
2213  return buffer + query_offset;
2214 }
2215 
2216 /*
2217  * Do we need to garbage-collect the external query text file?
2218  *
2219  * Caller should hold at least a shared lock on pgss->lock.
2220  */
2221 static bool
2223 {
2224  Size extent;
2225 
2226  /* Read shared extent pointer */
2227  {
2228  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
2229 
2230  SpinLockAcquire(&s->mutex);
2231  extent = s->extent;
2232  SpinLockRelease(&s->mutex);
2233  }
2234 
2235  /* Don't proceed if file does not exceed 512 bytes per possible entry */
2236  if (extent < 512 * pgss_max)
2237  return false;
2238 
2239  /*
2240  * Don't proceed if file is less than about 50% bloat. Nothing can or
2241  * should be done in the event of unusually large query texts accounting
2242  * for file's large size. We go to the trouble of maintaining the mean
2243  * query length in order to prevent garbage collection from thrashing
2244  * uselessly.
2245  */
2246  if (extent < pgss->mean_query_len * pgss_max * 2)
2247  return false;
2248 
2249  return true;
2250 }
2251 
2252 /*
2253  * Garbage-collect orphaned query texts in external file.
2254  *
2255  * This won't be called often in the typical case, since it's likely that
2256  * there won't be too much churn, and besides, a similar compaction process
2257  * occurs when serializing to disk at shutdown or as part of resetting.
2258  * Despite this, it seems prudent to plan for the edge case where the file
2259  * becomes unreasonably large, with no other method of compaction likely to
2260  * occur in the foreseeable future.
2261  *
2262  * The caller must hold an exclusive lock on pgss->lock.
2263  *
2264  * At the first sign of trouble we unlink the query text file to get a clean
2265  * slate (although existing statistics are retained), rather than risk
2266  * thrashing by allowing the same problem case to recur indefinitely.
2267  */
2268 static void
2270 {
2271  char *qbuffer;
2272  Size qbuffer_size;
2273  FILE *qfile = NULL;
2274  HASH_SEQ_STATUS hash_seq;
2275  pgssEntry *entry;
2276  Size extent;
2277  int nentries;
2278 
2279  /*
2280  * When called from pgss_store, some other session might have proceeded
2281  * with garbage collection in the no-lock-held interim of lock strength
2282  * escalation. Check once more that this is actually necessary.
2283  */
2284  if (!need_gc_qtexts())
2285  return;
2286 
2287  /*
2288  * Load the old texts file. If we fail (out of memory, for instance),
2289  * invalidate query texts. Hopefully this is rare. It might seem better
2290  * to leave things alone on an OOM failure, but the problem is that the
2291  * file is only going to get bigger; hoping for a future non-OOM result is
2292  * risky and can easily lead to complete denial of service.
2293  */
2294  qbuffer = qtext_load_file(&qbuffer_size);
2295  if (qbuffer == NULL)
2296  goto gc_fail;
2297 
2298  /*
2299  * We overwrite the query texts file in place, so as to reduce the risk of
2300  * an out-of-disk-space failure. Since the file is guaranteed not to get
2301  * larger, this should always work on traditional filesystems; though we
2302  * could still lose on copy-on-write filesystems.
2303  */
2305  if (qfile == NULL)
2306  {
2307  ereport(LOG,
2309  errmsg("could not write file \"%s\": %m",
2310  PGSS_TEXT_FILE)));
2311  goto gc_fail;
2312  }
2313 
2314  extent = 0;
2315  nentries = 0;
2316 
2317  hash_seq_init(&hash_seq, pgss_hash);
2318  while ((entry = hash_seq_search(&hash_seq)) != NULL)
2319  {
2320  int query_len = entry->query_len;
2321  char *qry = qtext_fetch(entry->query_offset,
2322  query_len,
2323  qbuffer,
2324  qbuffer_size);
2325 
2326  if (qry == NULL)
2327  {
2328  /* Trouble ... drop the text */
2329  entry->query_offset = 0;
2330  entry->query_len = -1;
2331  /* entry will not be counted in mean query length computation */
2332  continue;
2333  }
2334 
2335  if (fwrite(qry, 1, query_len + 1, qfile) != query_len + 1)
2336  {
2337  ereport(LOG,
2339  errmsg("could not write file \"%s\": %m",
2340  PGSS_TEXT_FILE)));
2341  hash_seq_term(&hash_seq);
2342  goto gc_fail;
2343  }
2344 
2345  entry->query_offset = extent;
2346  extent += query_len + 1;
2347  nentries++;
2348  }
2349 
2350  /*
2351  * Truncate away any now-unused space. If this fails for some odd reason,
2352  * we log it, but there's no need to fail.
2353  */
2354  if (ftruncate(fileno(qfile), extent) != 0)
2355  ereport(LOG,
2357  errmsg("could not truncate file \"%s\": %m",
2358  PGSS_TEXT_FILE)));
2359 
2360  if (FreeFile(qfile))
2361  {
2362  ereport(LOG,
2364  errmsg("could not write file \"%s\": %m",
2365  PGSS_TEXT_FILE)));
2366  qfile = NULL;
2367  goto gc_fail;
2368  }
2369 
2370  elog(DEBUG1, "pgss gc of queries file shrunk size from %zu to %zu",
2371  pgss->extent, extent);
2372 
2373  /* Reset the shared extent pointer */
2374  pgss->extent = extent;
2375 
2376  /*
2377  * Also update the mean query length, to be sure that need_gc_qtexts()
2378  * won't still think we have a problem.
2379  */
2380  if (nentries > 0)
2381  pgss->mean_query_len = extent / nentries;
2382  else
2384 
2385  free(qbuffer);
2386 
2387  /*
2388  * OK, count a garbage collection cycle. (Note: even though we have
2389  * exclusive lock on pgss->lock, we must take pgss->mutex for this, since
2390  * other processes may examine gc_count while holding only the mutex.
2391  * Also, we have to advance the count *after* we've rewritten the file,
2392  * else other processes might not realize they read a stale file.)
2393  */
2394  record_gc_qtexts();
2395 
2396  return;
2397 
2398 gc_fail:
2399  /* clean up resources */
2400  if (qfile)
2401  FreeFile(qfile);
2402  if (qbuffer)
2403  free(qbuffer);
2404 
2405  /*
2406  * Since the contents of the external file are now uncertain, mark all
2407  * hashtable entries as having invalid texts.
2408  */
2409  hash_seq_init(&hash_seq, pgss_hash);
2410  while ((entry = hash_seq_search(&hash_seq)) != NULL)
2411  {
2412  entry->query_offset = 0;
2413  entry->query_len = -1;
2414  }
2415 
2416  /*
2417  * Destroy the query text file and create a new, empty one
2418  */
2419  (void) unlink(PGSS_TEXT_FILE);
2421  if (qfile == NULL)
2422  ereport(LOG,
2424  errmsg("could not recreate file \"%s\": %m",
2425  PGSS_TEXT_FILE)));
2426  else
2427  FreeFile(qfile);
2428 
2429  /* Reset the shared extent pointer */
2430  pgss->extent = 0;
2431 
2432  /* Reset mean_query_len to match the new state */
2434 
2435  /*
2436  * Bump the GC count even though we failed.
2437  *
2438  * This is needed to make concurrent readers of file without any lock on
2439  * pgss->lock notice existence of new version of file. Once readers
2440  * subsequently observe a change in GC count with pgss->lock held, that
2441  * forces a safe reopen of file. Writers also require that we bump here,
2442  * of course. (As required by locking protocol, readers and writers don't
2443  * trust earlier file contents until gc_count is found unchanged after
2444  * pgss->lock acquired in shared or exclusive mode respectively.)
2445  */
2446  record_gc_qtexts();
2447 }
2448 
2449 /*
2450  * Release entries corresponding to parameters passed.
2451  */
2452 static void
2454 {
2455  HASH_SEQ_STATUS hash_seq;
2456  pgssEntry *entry;
2457  FILE *qfile;
2458  long num_entries;
2459  long num_remove = 0;
2460  pgssHashKey key;
2461 
2462  if (!pgss || !pgss_hash)
2463  ereport(ERROR,
2464  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2465  errmsg("pg_stat_statements must be loaded via shared_preload_libraries")));
2466 
2468  num_entries = hash_get_num_entries(pgss_hash);
2469 
2470  if (userid != 0 && dbid != 0 && queryid != UINT64CONST(0))
2471  {
2472  /* If all the parameters are available, use the fast path. */
2473  key.userid = userid;
2474  key.dbid = dbid;
2475  key.queryid = queryid;
2476 
2477  /* Remove the key if exists */
2478  entry = (pgssEntry *) hash_search(pgss_hash, &key, HASH_REMOVE, NULL);
2479  if (entry) /* found */
2480  num_remove++;
2481  }
2482  else if (userid != 0 || dbid != 0 || queryid != UINT64CONST(0))
2483  {
2484  /* Remove entries corresponding to valid parameters. */
2485  hash_seq_init(&hash_seq, pgss_hash);
2486  while ((entry = hash_seq_search(&hash_seq)) != NULL)
2487  {
2488  if ((!userid || entry->key.userid == userid) &&
2489  (!dbid || entry->key.dbid == dbid) &&
2490  (!queryid || entry->key.queryid == queryid))
2491  {
2492  hash_search(pgss_hash, &entry->key, HASH_REMOVE, NULL);
2493  num_remove++;
2494  }
2495  }
2496  }
2497  else
2498  {
2499  /* Remove all entries. */
2500  hash_seq_init(&hash_seq, pgss_hash);
2501  while ((entry = hash_seq_search(&hash_seq)) != NULL)
2502  {
2503  hash_search(pgss_hash, &entry->key, HASH_REMOVE, NULL);
2504  num_remove++;
2505  }
2506  }
2507 
2508  /* All entries are removed? */
2509  if (num_entries != num_remove)
2510  goto release_lock;
2511 
2512  /*
2513  * Write new empty query file, perhaps even creating a new one to recover
2514  * if the file was missing.
2515  */
2517  if (qfile == NULL)
2518  {
2519  ereport(LOG,
2521  errmsg("could not create file \"%s\": %m",
2522  PGSS_TEXT_FILE)));
2523  goto done;
2524  }
2525 
2526  /* If ftruncate fails, log it, but it's not a fatal problem */
2527  if (ftruncate(fileno(qfile), 0) != 0)
2528  ereport(LOG,
2530  errmsg("could not truncate file \"%s\": %m",
2531  PGSS_TEXT_FILE)));
2532 
2533  FreeFile(qfile);
2534 
2535 done:
2536  pgss->extent = 0;
2537  /* This counts as a query text garbage collection for our purposes */
2538  record_gc_qtexts();
2539 
2540 release_lock:
2541  LWLockRelease(pgss->lock);
2542 }
2543 
2544 /*
2545  * AppendJumble: Append a value that is substantive in a given query to
2546  * the current jumble.
2547  */
2548 static void
2549 AppendJumble(pgssJumbleState *jstate, const unsigned char *item, Size size)
2550 {
2551  unsigned char *jumble = jstate->jumble;
2552  Size jumble_len = jstate->jumble_len;
2553 
2554  /*
2555  * Whenever the jumble buffer is full, we hash the current contents and
2556  * reset the buffer to contain just that hash value, thus relying on the
2557  * hash to summarize everything so far.
2558  */
2559  while (size > 0)
2560  {
2561  Size part_size;
2562 
2563  if (jumble_len >= JUMBLE_SIZE)
2564  {
2565  uint64 start_hash;
2566 
2567  start_hash = DatumGetUInt64(hash_any_extended(jumble,
2568  JUMBLE_SIZE, 0));
2569  memcpy(jumble, &start_hash, sizeof(start_hash));
2570  jumble_len = sizeof(start_hash);
2571  }
2572  part_size = Min(size, JUMBLE_SIZE - jumble_len);
2573  memcpy(jumble + jumble_len, item, part_size);
2574  jumble_len += part_size;
2575  item += part_size;
2576  size -= part_size;
2577  }
2578  jstate->jumble_len = jumble_len;
2579 }
2580 
2581 /*
2582  * Wrappers around AppendJumble to encapsulate details of serialization
2583  * of individual local variable elements.
2584  */
2585 #define APP_JUMB(item) \
2586  AppendJumble(jstate, (const unsigned char *) &(item), sizeof(item))
2587 #define APP_JUMB_STRING(str) \
2588  AppendJumble(jstate, (const unsigned char *) (str), strlen(str) + 1)
2589 
2590 /*
2591  * JumbleQuery: Selectively serialize the query tree, appending significant
2592  * data to the "query jumble" while ignoring nonsignificant data.
2593  *
2594  * Rule of thumb for what to include is that we should ignore anything not
2595  * semantically significant (such as alias names) as well as anything that can
2596  * be deduced from child nodes (else we'd just be double-hashing that piece
2597  * of information).
2598  */
2599 static void
2601 {
2602  Assert(IsA(query, Query));
2603  Assert(query->utilityStmt == NULL);
2604 
2605  APP_JUMB(query->commandType);
2606  /* resultRelation is usually predictable from commandType */
2607  JumbleExpr(jstate, (Node *) query->cteList);
2608  JumbleRangeTable(jstate, query->rtable);
2609  JumbleExpr(jstate, (Node *) query->jointree);
2610  JumbleExpr(jstate, (Node *) query->targetList);
2611  JumbleExpr(jstate, (Node *) query->onConflict);
2612  JumbleExpr(jstate, (Node *) query->returningList);
2613  JumbleExpr(jstate, (Node *) query->groupClause);
2614  JumbleExpr(jstate, (Node *) query->groupingSets);
2615  JumbleExpr(jstate, query->havingQual);
2616  JumbleExpr(jstate, (Node *) query->windowClause);
2617  JumbleExpr(jstate, (Node *) query->distinctClause);
2618  JumbleExpr(jstate, (Node *) query->sortClause);
2619  JumbleExpr(jstate, query->limitOffset);
2620  JumbleExpr(jstate, query->limitCount);
2621  JumbleRowMarks(jstate, query->rowMarks);
2622  JumbleExpr(jstate, query->setOperations);
2623 }
2624 
2625 /*
2626  * Jumble a range table
2627  */
2628 static void
2630 {
2631  ListCell *lc;
2632 
2633  foreach(lc, rtable)
2634  {
2636 
2637  APP_JUMB(rte->rtekind);
2638  switch (rte->rtekind)
2639  {
2640  case RTE_RELATION:
2641  APP_JUMB(rte->relid);
2642  JumbleExpr(jstate, (Node *) rte->tablesample);
2643  break;
2644  case RTE_SUBQUERY:
2645  JumbleQuery(jstate, rte->subquery);
2646  break;
2647  case RTE_JOIN:
2648  APP_JUMB(rte->jointype);
2649  break;
2650  case RTE_FUNCTION:
2651  JumbleExpr(jstate, (Node *) rte->functions);
2652  break;
2653  case RTE_TABLEFUNC:
2654  JumbleExpr(jstate, (Node *) rte->tablefunc);
2655  break;
2656  case RTE_VALUES:
2657  JumbleExpr(jstate, (Node *) rte->values_lists);
2658  break;
2659  case RTE_CTE:
2660 
2661  /*
2662  * Depending on the CTE name here isn't ideal, but it's the
2663  * only info we have to identify the referenced WITH item.
2664  */
2665  APP_JUMB_STRING(rte->ctename);
2666  APP_JUMB(rte->ctelevelsup);
2667  break;
2668  case RTE_NAMEDTUPLESTORE:
2669  APP_JUMB_STRING(rte->enrname);
2670  break;
2671  case RTE_RESULT:
2672  break;
2673  default:
2674  elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
2675  break;
2676  }
2677  }
2678 }
2679 
2680 /*
2681  * Jumble a rowMarks list
2682  */
2683 static void
2685 {
2686  ListCell *lc;
2687 
2688  foreach(lc, rowMarks)
2689  {
2690  RowMarkClause *rowmark = lfirst_node(RowMarkClause, lc);
2691 
2692  if (!rowmark->pushedDown)
2693  {
2694  APP_JUMB(rowmark->rti);
2695  APP_JUMB(rowmark->strength);
2696  APP_JUMB(rowmark->waitPolicy);
2697  }
2698  }
2699 }
2700 
2701 /*
2702  * Jumble an expression tree
2703  *
2704  * In general this function should handle all the same node types that
2705  * expression_tree_walker() does, and therefore it's coded to be as parallel
2706  * to that function as possible. However, since we are only invoked on
2707  * queries immediately post-parse-analysis, we need not handle node types
2708  * that only appear in planning.
2709  *
2710  * Note: the reason we don't simply use expression_tree_walker() is that the
2711  * point of that function is to support tree walkers that don't care about
2712  * most tree node types, but here we care about all types. We should complain
2713  * about any unrecognized node type.
2714  */
2715 static void
2717 {
2718  ListCell *temp;
2719 
2720  if (node == NULL)
2721  return;
2722 
2723  /* Guard against stack overflow due to overly complex expressions */
2725 
2726  /*
2727  * We always emit the node's NodeTag, then any additional fields that are
2728  * considered significant, and then we recurse to any child nodes.
2729  */
2730  APP_JUMB(node->type);
2731 
2732  switch (nodeTag(node))
2733  {
2734  case T_Var:
2735  {
2736  Var *var = (Var *) node;
2737 
2738  APP_JUMB(var->varno);
2739  APP_JUMB(var->varattno);
2740  APP_JUMB(var->varlevelsup);
2741  }
2742  break;
2743  case T_Const:
2744  {
2745  Const *c = (Const *) node;
2746 
2747  /* We jumble only the constant's type, not its value */
2748  APP_JUMB(c->consttype);
2749  /* Also, record its parse location for query normalization */
2750  RecordConstLocation(jstate, c->location);
2751  }
2752  break;
2753  case T_Param:
2754  {
2755  Param *p = (Param *) node;
2756 
2757  APP_JUMB(p->paramkind);
2758  APP_JUMB(p->paramid);
2759  APP_JUMB(p->paramtype);
2760  /* Also, track the highest external Param id */
2761  if (p->paramkind == PARAM_EXTERN &&
2762  p->paramid > jstate->highest_extern_param_id)
2763  jstate->highest_extern_param_id = p->paramid;
2764  }
2765  break;
2766  case T_Aggref:
2767  {
2768  Aggref *expr = (Aggref *) node;
2769 
2770  APP_JUMB(expr->aggfnoid);
2771  JumbleExpr(jstate, (Node *) expr->aggdirectargs);
2772  JumbleExpr(jstate, (Node *) expr->args);
2773  JumbleExpr(jstate, (Node *) expr->aggorder);
2774  JumbleExpr(jstate, (Node *) expr->aggdistinct);
2775  JumbleExpr(jstate, (Node *) expr->aggfilter);
2776  }
2777  break;
2778  case T_GroupingFunc:
2779  {
2780  GroupingFunc *grpnode = (GroupingFunc *) node;
2781 
2782  JumbleExpr(jstate, (Node *) grpnode->refs);
2783  }
2784  break;
2785  case T_WindowFunc:
2786  {
2787  WindowFunc *expr = (WindowFunc *) node;
2788 
2789  APP_JUMB(expr->winfnoid);
2790  APP_JUMB(expr->winref);
2791  JumbleExpr(jstate, (Node *) expr->args);
2792  JumbleExpr(jstate, (Node *) expr->aggfilter);
2793  }
2794  break;
2795  case T_SubscriptingRef:
2796  {
2797  SubscriptingRef *sbsref = (SubscriptingRef *) node;
2798 
2799  JumbleExpr(jstate, (Node *) sbsref->refupperindexpr);
2800  JumbleExpr(jstate, (Node *) sbsref->reflowerindexpr);
2801  JumbleExpr(jstate, (Node *) sbsref->refexpr);
2802  JumbleExpr(jstate, (Node *) sbsref->refassgnexpr);
2803  }
2804  break;
2805  case T_FuncExpr:
2806  {
2807  FuncExpr *expr = (FuncExpr *) node;
2808 
2809  APP_JUMB(expr->funcid);
2810  JumbleExpr(jstate, (Node *) expr->args);
2811  }
2812  break;
2813  case T_NamedArgExpr:
2814  {
2815  NamedArgExpr *nae = (NamedArgExpr *) node;
2816 
2817  APP_JUMB(nae->argnumber);
2818  JumbleExpr(jstate, (Node *) nae->arg);
2819  }
2820  break;
2821  case T_OpExpr:
2822  case T_DistinctExpr: /* struct-equivalent to OpExpr */
2823  case T_NullIfExpr: /* struct-equivalent to OpExpr */
2824  {
2825  OpExpr *expr = (OpExpr *) node;
2826 
2827  APP_JUMB(expr->opno);
2828  JumbleExpr(jstate, (Node *) expr->args);
2829  }
2830  break;
2831  case T_ScalarArrayOpExpr:
2832  {
2833  ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
2834 
2835  APP_JUMB(expr->opno);
2836  APP_JUMB(expr->useOr);
2837  JumbleExpr(jstate, (Node *) expr->args);
2838  }
2839  break;
2840  case T_BoolExpr:
2841  {
2842  BoolExpr *expr = (BoolExpr *) node;
2843 
2844  APP_JUMB(expr->boolop);
2845  JumbleExpr(jstate, (Node *) expr->args);
2846  }
2847  break;
2848  case T_SubLink:
2849  {
2850  SubLink *sublink = (SubLink *) node;
2851 
2852  APP_JUMB(sublink->subLinkType);
2853  APP_JUMB(sublink->subLinkId);
2854  JumbleExpr(jstate, (Node *) sublink->testexpr);
2855  JumbleQuery(jstate, castNode(Query, sublink->subselect));
2856  }
2857  break;
2858  case T_FieldSelect:
2859  {
2860  FieldSelect *fs = (FieldSelect *) node;
2861 
2862  APP_JUMB(fs->fieldnum);
2863  JumbleExpr(jstate, (Node *) fs->arg);
2864  }
2865  break;
2866  case T_FieldStore:
2867  {
2868  FieldStore *fstore = (FieldStore *) node;
2869 
2870  JumbleExpr(jstate, (Node *) fstore->arg);
2871  JumbleExpr(jstate, (Node *) fstore->newvals);
2872  }
2873  break;
2874  case T_RelabelType:
2875  {
2876  RelabelType *rt = (RelabelType *) node;
2877 
2878  APP_JUMB(rt->resulttype);
2879  JumbleExpr(jstate, (Node *) rt->arg);
2880  }
2881  break;
2882  case T_CoerceViaIO:
2883  {
2884  CoerceViaIO *cio = (CoerceViaIO *) node;
2885 
2886  APP_JUMB(cio->resulttype);
2887  JumbleExpr(jstate, (Node *) cio->arg);
2888  }
2889  break;
2890  case T_ArrayCoerceExpr:
2891  {
2892  ArrayCoerceExpr *acexpr = (ArrayCoerceExpr *) node;
2893 
2894  APP_JUMB(acexpr->resulttype);
2895  JumbleExpr(jstate, (Node *) acexpr->arg);
2896  JumbleExpr(jstate, (Node *) acexpr->elemexpr);
2897  }
2898  break;
2899  case T_ConvertRowtypeExpr:
2900  {
2901  ConvertRowtypeExpr *crexpr = (ConvertRowtypeExpr *) node;
2902 
2903  APP_JUMB(crexpr->resulttype);
2904  JumbleExpr(jstate, (Node *) crexpr->arg);
2905  }
2906  break;
2907  case T_CollateExpr:
2908  {
2909  CollateExpr *ce = (CollateExpr *) node;
2910 
2911  APP_JUMB(ce->collOid);
2912  JumbleExpr(jstate, (Node *) ce->arg);
2913  }
2914  break;
2915  case T_CaseExpr:
2916  {
2917  CaseExpr *caseexpr = (CaseExpr *) node;
2918 
2919  JumbleExpr(jstate, (Node *) caseexpr->arg);
2920  foreach(temp, caseexpr->args)
2921  {
2922  CaseWhen *when = lfirst_node(CaseWhen, temp);
2923 
2924  JumbleExpr(jstate, (Node *) when->expr);
2925  JumbleExpr(jstate, (Node *) when->result);
2926  }
2927  JumbleExpr(jstate, (Node *) caseexpr->defresult);
2928  }
2929  break;
2930  case T_CaseTestExpr:
2931  {
2932  CaseTestExpr *ct = (CaseTestExpr *) node;
2933 
2934  APP_JUMB(ct->typeId);
2935  }
2936  break;
2937  case T_ArrayExpr:
2938  JumbleExpr(jstate, (Node *) ((ArrayExpr *) node)->elements);
2939  break;
2940  case T_RowExpr:
2941  JumbleExpr(jstate, (Node *) ((RowExpr *) node)->args);
2942  break;
2943  case T_RowCompareExpr:
2944  {
2945  RowCompareExpr *rcexpr = (RowCompareExpr *) node;
2946 
2947  APP_JUMB(rcexpr->rctype);
2948  JumbleExpr(jstate, (Node *) rcexpr->largs);
2949  JumbleExpr(jstate, (Node *) rcexpr->rargs);
2950  }
2951  break;
2952  case T_CoalesceExpr:
2953  JumbleExpr(jstate, (Node *) ((CoalesceExpr *) node)->args);
2954  break;
2955  case T_MinMaxExpr:
2956  {
2957  MinMaxExpr *mmexpr = (MinMaxExpr *) node;
2958 
2959  APP_JUMB(mmexpr->op);
2960  JumbleExpr(jstate, (Node *) mmexpr->args);
2961  }
2962  break;
2963  case T_SQLValueFunction:
2964  {
2965  SQLValueFunction *svf = (SQLValueFunction *) node;
2966 
2967  APP_JUMB(svf->op);
2968  /* type is fully determined by op */
2969  APP_JUMB(svf->typmod);
2970  }
2971  break;
2972  case T_XmlExpr:
2973  {
2974  XmlExpr *xexpr = (XmlExpr *) node;
2975 
2976  APP_JUMB(xexpr->op);
2977  JumbleExpr(jstate, (Node *) xexpr->named_args);
2978  JumbleExpr(jstate, (Node *) xexpr->args);
2979  }
2980  break;
2981  case T_NullTest:
2982  {
2983  NullTest *nt = (NullTest *) node;
2984 
2985  APP_JUMB(nt->nulltesttype);
2986  JumbleExpr(jstate, (Node *) nt->arg);
2987  }
2988  break;
2989  case T_BooleanTest:
2990  {
2991  BooleanTest *bt = (BooleanTest *) node;
2992 
2993  APP_JUMB(bt->booltesttype);
2994  JumbleExpr(jstate, (Node *) bt->arg);
2995  }
2996  break;
2997  case T_CoerceToDomain:
2998  {
2999  CoerceToDomain *cd = (CoerceToDomain *) node;
3000 
3001  APP_JUMB(cd->resulttype);
3002  JumbleExpr(jstate, (Node *) cd->arg);
3003  }
3004  break;
3005  case T_CoerceToDomainValue:
3006  {
3007  CoerceToDomainValue *cdv = (CoerceToDomainValue *) node;
3008 
3009  APP_JUMB(cdv->typeId);
3010  }
3011  break;
3012  case T_SetToDefault:
3013  {
3014  SetToDefault *sd = (SetToDefault *) node;
3015 
3016  APP_JUMB(sd->typeId);
3017  }
3018  break;
3019  case T_CurrentOfExpr:
3020  {
3021  CurrentOfExpr *ce = (CurrentOfExpr *) node;
3022 
3023  APP_JUMB(ce->cvarno);
3024  if (ce->cursor_name)
3026  APP_JUMB(ce->cursor_param);
3027  }
3028  break;
3029  case T_NextValueExpr:
3030  {
3031  NextValueExpr *nve = (NextValueExpr *) node;
3032 
3033  APP_JUMB(nve->seqid);
3034  APP_JUMB(nve->typeId);
3035  }
3036  break;
3037  case T_InferenceElem:
3038  {
3039  InferenceElem *ie = (InferenceElem *) node;
3040 
3041  APP_JUMB(ie->infercollid);
3042  APP_JUMB(ie->inferopclass);
3043  JumbleExpr(jstate, ie->expr);
3044  }
3045  break;
3046  case T_TargetEntry:
3047  {
3048  TargetEntry *tle = (TargetEntry *) node;
3049 
3050  APP_JUMB(tle->resno);
3051  APP_JUMB(tle->ressortgroupref);
3052  JumbleExpr(jstate, (Node *) tle->expr);
3053  }
3054  break;
3055  case T_RangeTblRef:
3056  {
3057  RangeTblRef *rtr = (RangeTblRef *) node;
3058 
3059  APP_JUMB(rtr->rtindex);
3060  }
3061  break;
3062  case T_JoinExpr:
3063  {
3064  JoinExpr *join = (JoinExpr *) node;
3065 
3066  APP_JUMB(join->jointype);
3067  APP_JUMB(join->isNatural);
3068  APP_JUMB(join->rtindex);
3069  JumbleExpr(jstate, join->larg);
3070  JumbleExpr(jstate, join->rarg);
3071  JumbleExpr(jstate, join->quals);
3072  }
3073  break;
3074  case T_FromExpr:
3075  {
3076  FromExpr *from = (FromExpr *) node;
3077 
3078  JumbleExpr(jstate, (Node *) from->fromlist);
3079  JumbleExpr(jstate, from->quals);
3080  }
3081  break;
3082  case T_OnConflictExpr:
3083  {
3084  OnConflictExpr *conf = (OnConflictExpr *) node;
3085 
3086  APP_JUMB(conf->action);
3087  JumbleExpr(jstate, (Node *) conf->arbiterElems);
3088  JumbleExpr(jstate, conf->arbiterWhere);
3089  JumbleExpr(jstate, (Node *) conf->onConflictSet);
3090  JumbleExpr(jstate, conf->onConflictWhere);
3091  APP_JUMB(conf->constraint);
3092  APP_JUMB(conf->exclRelIndex);
3093  JumbleExpr(jstate, (Node *) conf->exclRelTlist);
3094  }
3095  break;
3096  case T_List:
3097  foreach(temp, (List *) node)
3098  {
3099  JumbleExpr(jstate, (Node *) lfirst(temp));
3100  }
3101  break;
3102  case T_IntList:
3103  foreach(temp, (List *) node)
3104  {
3105  APP_JUMB(lfirst_int(temp));
3106  }
3107  break;
3108  case T_SortGroupClause:
3109  {
3110  SortGroupClause *sgc = (SortGroupClause *) node;
3111 
3112  APP_JUMB(sgc->tleSortGroupRef);
3113  APP_JUMB(sgc->eqop);
3114  APP_JUMB(sgc->sortop);
3115  APP_JUMB(sgc->nulls_first);
3116  }
3117  break;
3118  case T_GroupingSet:
3119  {
3120  GroupingSet *gsnode = (GroupingSet *) node;
3121 
3122  JumbleExpr(jstate, (Node *) gsnode->content);
3123  }
3124  break;
3125  case T_WindowClause:
3126  {
3127  WindowClause *wc = (WindowClause *) node;
3128 
3129  APP_JUMB(wc->winref);
3130  APP_JUMB(wc->frameOptions);
3131  JumbleExpr(jstate, (Node *) wc->partitionClause);
3132  JumbleExpr(jstate, (Node *) wc->orderClause);
3133  JumbleExpr(jstate, wc->startOffset);
3134  JumbleExpr(jstate, wc->endOffset);
3135  }
3136  break;
3137  case T_CommonTableExpr:
3138  {
3139  CommonTableExpr *cte = (CommonTableExpr *) node;
3140 
3141  /* we store the string name because RTE_CTE RTEs need it */
3142  APP_JUMB_STRING(cte->ctename);
3143  APP_JUMB(cte->ctematerialized);
3144  JumbleQuery(jstate, castNode(Query, cte->ctequery));
3145  }
3146  break;
3147  case T_SetOperationStmt:
3148  {
3149  SetOperationStmt *setop = (SetOperationStmt *) node;
3150 
3151  APP_JUMB(setop->op);
3152  APP_JUMB(setop->all);
3153  JumbleExpr(jstate, setop->larg);
3154  JumbleExpr(jstate, setop->rarg);
3155  }
3156  break;
3157  case T_RangeTblFunction:
3158  {
3159  RangeTblFunction *rtfunc = (RangeTblFunction *) node;
3160 
3161  JumbleExpr(jstate, rtfunc->funcexpr);
3162  }
3163  break;
3164  case T_TableFunc:
3165  {
3166  TableFunc *tablefunc = (TableFunc *) node;
3167 
3168  JumbleExpr(jstate, tablefunc->docexpr);
3169  JumbleExpr(jstate, tablefunc->rowexpr);
3170  JumbleExpr(jstate, (Node *) tablefunc->colexprs);
3171  }
3172  break;
3173  case T_TableSampleClause:
3174  {
3175  TableSampleClause *tsc = (TableSampleClause *) node;
3176 
3177  APP_JUMB(tsc->tsmhandler);
3178  JumbleExpr(jstate, (Node *) tsc->args);
3179  JumbleExpr(jstate, (Node *) tsc->repeatable);
3180  }
3181  break;
3182  default:
3183  /* Only a warning, since we can stumble along anyway */
3184  elog(WARNING, "unrecognized node type: %d",
3185  (int) nodeTag(node));
3186  break;
3187  }
3188 }
3189 
3190 /*
3191  * Record location of constant within query string of query tree
3192  * that is currently being walked.
3193  */
3194 static void
3195 RecordConstLocation(pgssJumbleState *jstate, int location)
3196 {
3197  /* -1 indicates unknown or undefined location */
3198  if (location >= 0)
3199  {
3200  /* enlarge array if needed */
3201  if (jstate->clocations_count >= jstate->clocations_buf_size)
3202  {
3203  jstate->clocations_buf_size *= 2;
3204  jstate->clocations = (pgssLocationLen *)
3205  repalloc(jstate->clocations,
3206  jstate->clocations_buf_size *
3207  sizeof(pgssLocationLen));
3208  }
3209  jstate->clocations[jstate->clocations_count].location = location;
3210  /* initialize lengths to -1 to simplify fill_in_constant_lengths */
3211  jstate->clocations[jstate->clocations_count].length = -1;
3212  jstate->clocations_count++;
3213  }
3214 }
3215 
3216 /*
3217  * Generate a normalized version of the query string that will be used to
3218  * represent all similar queries.
3219  *
3220  * Note that the normalized representation may well vary depending on
3221  * just which "equivalent" query is used to create the hashtable entry.
3222  * We assume this is OK.
3223  *
3224  * If query_loc > 0, then "query" has been advanced by that much compared to
3225  * the original string start, so we need to translate the provided locations
3226  * to compensate. (This lets us avoid re-scanning statements before the one
3227  * of interest, so it's worth doing.)
3228  *
3229  * *query_len_p contains the input string length, and is updated with
3230  * the result string length on exit. The resulting string might be longer
3231  * or shorter depending on what happens with replacement of constants.
3232  *
3233  * Returns a palloc'd string.
3234  */
3235 static char *
3236 generate_normalized_query(pgssJumbleState *jstate, const char *query,
3237  int query_loc, int *query_len_p)
3238 {
3239  char *norm_query;
3240  int query_len = *query_len_p;
3241  int i,
3242  norm_query_buflen, /* Space allowed for norm_query */
3243  len_to_wrt, /* Length (in bytes) to write */
3244  quer_loc = 0, /* Source query byte location */
3245  n_quer_loc = 0, /* Normalized query byte location */
3246  last_off = 0, /* Offset from start for previous tok */
3247  last_tok_len = 0; /* Length (in bytes) of that tok */
3248 
3249  /*
3250  * Get constants' lengths (core system only gives us locations). Note
3251  * this also ensures the items are sorted by location.
3252  */
3253  fill_in_constant_lengths(jstate, query, query_loc);
3254 
3255  /*
3256  * Allow for $n symbols to be longer than the constants they replace.
3257  * Constants must take at least one byte in text form, while a $n symbol
3258  * certainly isn't more than 11 bytes, even if n reaches INT_MAX. We
3259  * could refine that limit based on the max value of n for the current
3260  * query, but it hardly seems worth any extra effort to do so.
3261  */
3262  norm_query_buflen = query_len + jstate->clocations_count * 10;
3263 
3264  /* Allocate result buffer */
3265  norm_query = palloc(norm_query_buflen + 1);
3266 
3267  for (i = 0; i < jstate->clocations_count; i++)
3268  {
3269  int off, /* Offset from start for cur tok */
3270  tok_len; /* Length (in bytes) of that tok */
3271 
3272  off = jstate->clocations[i].location;
3273  /* Adjust recorded location if we're dealing with partial string */
3274  off -= query_loc;
3275 
3276  tok_len = jstate->clocations[i].length;
3277 
3278  if (tok_len < 0)
3279  continue; /* ignore any duplicates */
3280 
3281  /* Copy next chunk (what precedes the next constant) */
3282  len_to_wrt = off - last_off;
3283  len_to_wrt -= last_tok_len;
3284 
3285  Assert(len_to_wrt >= 0);
3286  memcpy(norm_query + n_quer_loc, query + quer_loc, len_to_wrt);
3287  n_quer_loc += len_to_wrt;
3288 
3289  /* And insert a param symbol in place of the constant token */
3290  n_quer_loc += sprintf(norm_query + n_quer_loc, "$%d",
3291  i + 1 + jstate->highest_extern_param_id);
3292 
3293  quer_loc = off + tok_len;
3294  last_off = off;
3295  last_tok_len = tok_len;
3296  }
3297 
3298  /*
3299  * We've copied up until the last ignorable constant. Copy over the
3300  * remaining bytes of the original query string.
3301  */
3302  len_to_wrt = query_len - quer_loc;
3303 
3304  Assert(len_to_wrt >= 0);
3305  memcpy(norm_query + n_quer_loc, query + quer_loc, len_to_wrt);
3306  n_quer_loc += len_to_wrt;
3307 
3308  Assert(n_quer_loc <= norm_query_buflen);
3309  norm_query[n_quer_loc] = '\0';
3310 
3311  *query_len_p = n_quer_loc;
3312  return norm_query;
3313 }
3314 
3315 /*
3316  * Given a valid SQL string and an array of constant-location records,
3317  * fill in the textual lengths of those constants.
3318  *
3319  * The constants may use any allowed constant syntax, such as float literals,
3320  * bit-strings, single-quoted strings and dollar-quoted strings. This is
3321  * accomplished by using the public API for the core scanner.
3322  *
3323  * It is the caller's job to ensure that the string is a valid SQL statement
3324  * with constants at the indicated locations. Since in practice the string
3325  * has already been parsed, and the locations that the caller provides will
3326  * have originated from within the authoritative parser, this should not be
3327  * a problem.
3328  *
3329  * Duplicate constant pointers are possible, and will have their lengths
3330  * marked as '-1', so that they are later ignored. (Actually, we assume the
3331  * lengths were initialized as -1 to start with, and don't change them here.)
3332  *
3333  * If query_loc > 0, then "query" has been advanced by that much compared to
3334  * the original string start, so we need to translate the provided locations
3335  * to compensate. (This lets us avoid re-scanning statements before the one
3336  * of interest, so it's worth doing.)
3337  *
3338  * N.B. There is an assumption that a '-' character at a Const location begins
3339  * a negative numeric constant. This precludes there ever being another
3340  * reason for a constant to start with a '-'.
3341  */
3342 static void
3343 fill_in_constant_lengths(pgssJumbleState *jstate, const char *query,
3344  int query_loc)
3345 {
3346  pgssLocationLen *locs;
3348  core_yy_extra_type yyextra;
3349  core_YYSTYPE yylval;
3350  YYLTYPE yylloc;
3351  int last_loc = -1;
3352  int i;
3353 
3354  /*
3355  * Sort the records by location so that we can process them in order while
3356  * scanning the query text.
3357  */
3358  if (jstate->clocations_count > 1)
3359  qsort(jstate->clocations, jstate->clocations_count,
3360  sizeof(pgssLocationLen), comp_location);
3361  locs = jstate->clocations;
3362 
3363  /* initialize the flex scanner --- should match raw_parser() */
3364  yyscanner = scanner_init(query,
3365  &yyextra,
3366  &ScanKeywords,
3368 
3369  /* we don't want to re-emit any escape string warnings */
3370  yyextra.escape_string_warning = false;
3371 
3372  /* Search for each constant, in sequence */
3373  for (i = 0; i < jstate->clocations_count; i++)
3374  {
3375  int loc = locs[i].location;
3376  int tok;
3377 
3378  /* Adjust recorded location if we're dealing with partial string */
3379  loc -= query_loc;
3380 
3381  Assert(loc >= 0);
3382 
3383  if (loc <= last_loc)
3384  continue; /* Duplicate constant, ignore */
3385 
3386  /* Lex tokens until we find the desired constant */
3387  for (;;)
3388  {
3389  tok = core_yylex(&yylval, &yylloc, yyscanner);
3390 
3391  /* We should not hit end-of-string, but if we do, behave sanely */
3392  if (tok == 0)
3393  break; /* out of inner for-loop */
3394 
3395  /*
3396  * We should find the token position exactly, but if we somehow
3397  * run past it, work with that.
3398  */
3399  if (yylloc >= loc)
3400  {
3401  if (query[loc] == '-')
3402  {
3403  /*
3404  * It's a negative value - this is the one and only case
3405  * where we replace more than a single token.
3406  *
3407  * Do not compensate for the core system's special-case
3408  * adjustment of location to that of the leading '-'
3409  * operator in the event of a negative constant. It is
3410  * also useful for our purposes to start from the minus
3411  * symbol. In this way, queries like "select * from foo
3412  * where bar = 1" and "select * from foo where bar = -2"
3413  * will have identical normalized query strings.
3414  */
3415  tok = core_yylex(&yylval, &yylloc, yyscanner);
3416  if (tok == 0)
3417  break; /* out of inner for-loop */
3418  }
3419 
3420  /*
3421  * We now rely on the assumption that flex has placed a zero
3422  * byte after the text of the current token in scanbuf.
3423  */
3424  locs[i].length = strlen(yyextra.scanbuf + loc);
3425  break; /* out of inner for-loop */
3426  }
3427  }
3428 
3429  /* If we hit end-of-string, give up, leaving remaining lengths -1 */
3430  if (tok == 0)
3431  break;
3432 
3433  last_loc = loc;
3434  }
3435 
3436  scanner_finish(yyscanner);
3437 }
3438 
3439 /*
3440  * comp_location: comparator for qsorting pgssLocationLen structs by location
3441  */
3442 static int
3443 comp_location(const void *a, const void *b)
3444 {
3445  int l = ((const pgssLocationLen *) a)->location;
3446  int r = ((const pgssLocationLen *) b)->location;
3447 
3448  if (l < r)
3449  return -1;
3450  else if (l > r)
3451  return +1;
3452  else
3453  return 0;
3454 }
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, Datum *values, bool *isnull)
Definition: tuplestore.c:750
List * aggdistinct
Definition: primnodes.h:321
Node * limitOffset
Definition: parsenodes.h:160
int slock_t
Definition: s_lock.h:934
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:8854
void(* ExecutorRun_hook_type)(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: executor.h:69
long local_blks_hit
Definition: instrument.h:25
List * args
Definition: primnodes.h:1109
void standard_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: execMain.c:312
void _PG_init(void)
Definition: lwlock.h:31
static uint64 pgss_hash_string(const char *str, int len)
static void JumbleExpr(pgssJumbleState *jstate, Node *node)
#define IsA(nodeptr, _type_)
Definition: nodes.h:579
Node * docexpr
Definition: primnodes.h:87
void RequestAddinShmemSpace(Size size)
Definition: ipci.c:71
long local_blks_dirtied
Definition: instrument.h:27
#define PG_STAT_STATEMENTS_COLS_V1_3
#define DEBUG1
Definition: elog.h:25
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:205
Expr * arg
Definition: primnodes.h:794
Index varlevelsup
Definition: primnodes.h:191
void(* ProcessUtility_hook_type)(PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc)
Definition: utility.h:71
double total_time[PGSS_NUMKIND]
long local_blks_read
Definition: instrument.h:26
WalUsage walusage
Definition: instrument.h:75
#define PG_STAT_STATEMENTS_COLS_V1_8
int stmt_location
Definition: parsenodes.h:181
List * sortClause
Definition: parsenodes.h:158
EState * estate
Definition: execdesc.h:48
List * content
Definition: parsenodes.h:1328
List * refs
Definition: primnodes.h:361
void * core_yyscan_t
Definition: scanner.h:121
List * args
Definition: primnodes.h:377
#define HASH_ELEM
Definition: hsearch.h:85
List * args
Definition: primnodes.h:477
static void JumbleRowMarks(pgssJumbleState *jstate, List *rowMarks)
static void error(void)
Definition: sql-dyntest.c:147
#define PG_STAT_STATEMENTS_COLS_V1_0
bool process_shared_preload_libraries_in_progress
Definition: miscinit.c:1596
#define USAGE_DEALLOC_PERCENT
int64 shared_blks_read
static const uint32 PGSS_PG_MAJOR_VERSION
FromExpr * jointree
Definition: parsenodes.h:138
int64 local_blks_written
Definition: guc.h:165
void RequestNamedLWLockTranche(const char *tranche_name, int num_lwlocks)
Definition: lwlock.c:705
Oid GetUserId(void)
Definition: miscinit.c:476
OnConflictExpr * onConflict
Definition: parsenodes.h:144
instr_time blk_read_time
Definition: instrument.h:31
#define castNode(_type_, nodeptr)
Definition: nodes.h:597
static ProcessUtility_hook_type prev_ProcessUtility
struct pgssSharedState pgssSharedState
static void AppendJumble(pgssJumbleState *jstate, const unsigned char *item, Size size)
WalUsage pgWalUsage
Definition: instrument.c:22
int64 shared_blks_dirtied
Datum pg_stat_statements_1_8(PG_FUNCTION_ARGS)
static void pgss_shmem_startup(void)
#define SpinLockInit(lock)
Definition: spin.h:60
#define INSTR_TIME_GET_MILLISEC(t)
Definition: instr_time.h:202
Oid resulttype
Definition: primnodes.h:838
PGDLLIMPORT const uint16 ScanKeywordTokens[]
struct timeval instr_time
Definition: instr_time.h:150
PlannedStmt *(* planner_hook_type)(Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams)
Definition: planner.h:26
RowCompareType rctype
Definition: primnodes.h:1073
long shared_blks_read
Definition: instrument.h:22
void standard_ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:152
#define Min(x, y)
Definition: c.h:928
double max_time[PGSS_NUMKIND]
#define tuplestore_donestoring(state)
Definition: tuplestore.h:60
void WalUsageAccumDiff(WalUsage *dst, const WalUsage *add, const WalUsage *sub)
Definition: instrument.c:255
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
static ExecutorRun_hook_type prev_ExecutorRun
Index tleSortGroupRef
Definition: parsenodes.h:1258
Expr * arg
Definition: primnodes.h:817
List * groupingSets
Definition: parsenodes.h:150
static ExecutorEnd_hook_type prev_ExecutorEnd
Size entrysize
Definition: hsearch.h:72
#define PGSS_DUMP_FILE
ParamKind paramkind
Definition: primnodes.h:262
ProcessUtility_hook_type ProcessUtility_hook
Definition: utility.c:75
#define pgss_enabled(level)
Definition: nodes.h:528
static int pgss_track
static int entry_cmp(const void *lhs, const void *rhs)
int errcode(int sqlerrcode)
Definition: elog.c:610
void standard_ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:471
struct pgssEntry pgssEntry
#define PG_BINARY_W
Definition: c.h:1216
ProcessUtilityContext
Definition: utility.h:20
Instrumentation * InstrAlloc(int n, int instrument_options)
Definition: instrument.c:31
List * args
Definition: primnodes.h:319
static ExecutorStart_hook_type prev_ExecutorStart
void(* ExecutorFinish_hook_type)(QueryDesc *queryDesc)
Definition: executor.h:76
AttrNumber varattno
Definition: primnodes.h:186
Expr * arg
Definition: primnodes.h:765
long hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1347
static void pgss_store(const char *query, uint64 queryId, int query_location, int query_len, pgssStoreKind kind, double total_time, uint64 rows, const BufferUsage *bufusage, const WalUsage *walusage, pgssJumbleState *jstate)
List * fromlist
Definition: primnodes.h:1513
unsigned char * jumble
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:274
long temp_blks_written
Definition: instrument.h:30
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:919
Counters counters
static void pgss_ExecutorStart(QueryDesc *queryDesc, int eflags)
static int exec_nested_level
int64 temp_blks_read
#define JUMBLE_SIZE
#define PG_STAT_STATEMENTS_COLS_V1_1
#define LOG
Definition: elog.h:26
unsigned int Oid
Definition: postgres_ext.h:31
List * rowMarks
Definition: parsenodes.h:164
Index winref
Definition: primnodes.h:379
Node * utilityStmt
Definition: parsenodes.h:120
static post_parse_analyze_hook_type prev_post_parse_analyze_hook
Definition: primnodes.h:181
static Datum hash_any_extended(const unsigned char *k, int keylen, uint64 seed)
Definition: hashfn.h:37
List * refupperindexpr
Definition: primnodes.h:422
#define PG_BINARY_R
Definition: c.h:1215
static int fd(const char *x, int i)
Definition: preproc-init.c:105
#define PG_BINARY
Definition: c.h:1213
int stmt_len
Definition: plannodes.h:90
char * scanbuf
Definition: scanner.h:72
List * values_lists
Definition: parsenodes.h:1075
Node * quals
Definition: primnodes.h:1514
ssize_t pg_pwrite(int fd, const void *buf, size_t nbyte, off_t offset)
Definition: pwrite.c:27
void standard_ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:411
SQLValueFunctionOp op
Definition: primnodes.h:1146
int duration
Definition: pgbench.c:147
LockClauseStrength strength
Definition: parsenodes.h:1384
Datum pg_stat_statements_1_3(PG_FUNCTION_ARGS)
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:8939
#define MaxAllocHugeSize
Definition: memutils.h:44
signed int int32
Definition: c.h:363
#define APP_JUMB_STRING(str)
List * windowClause
Definition: parsenodes.h:154
void BufferUsageAccumDiff(BufferUsage *dst, const BufferUsage *add, const BufferUsage *sub)
Definition: instrument.c:225
List * targetList
Definition: parsenodes.h:140
static void RecordConstLocation(pgssJumbleState *jstate, int location)
List * arbiterElems
Definition: primnodes.h:1532
static void JumbleRangeTable(pgssJumbleState *jstate, List *rtable)
ExecutorStart_hook_type ExecutorStart_hook
Definition: execMain.c:70
static planner_hook_type prev_planner_hook
void InstrEndLoop(Instrumentation *instr)
Definition: instrument.c:121
Node * larg
Definition: primnodes.h:1493
PGDLLIMPORT const ScanKeywordList ScanKeywords
#define malloc(a)
Definition: header.h:50
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1812
#define ASSUMED_LENGTH_INIT
static bool pgss_track_planning
Oid consttype
Definition: primnodes.h:210
#define sprintf
Definition: port.h:217
long shared_blks_written
Definition: instrument.h:24
static pgssSharedState * pgss
#define SpinLockAcquire(lock)
Definition: spin.h:62
Definition: dynahash.c:218
#define fstat
Definition: win32_port.h:274
static void pgss_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
void pfree(void *pointer)
Definition: mcxt.c:1057
MemoryContext es_query_cxt
Definition: execnodes.h:559
int64 shared_blks_hit
pgssLocationLen * clocations
static int pgss_max
static void entry_dealloc(void)
List * rtable
Definition: parsenodes.h:137
static HTAB * pgss_hash
List * distinctClause
Definition: parsenodes.h:156
Oid funcid
Definition: primnodes.h:469
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
uint64 nprocessed
Definition: cmdtag.h:31
ExecutorRun_hook_type ExecutorRun_hook
Definition: execMain.c:71
ExecutorEnd_hook_type ExecutorEnd_hook
Definition: execMain.c:73
void standard_ProcessUtility(PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc)
Definition: utility.c:541
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2372
static void pgss_post_parse_analyze(ParseState *pstate, Query *query)
struct pg_encoding enc
Definition: encode.c:562
fmNodePtr resultinfo
Definition: fmgr.h:89
static void pg_stat_statements_internal(FunctionCallInfo fcinfo, pgssVersion api_version, bool showtext)
TableFunc * tablefunc
Definition: parsenodes.h:1070
#define lfirst_int(lc)
Definition: pg_list.h:170
List * partitionClause
Definition: parsenodes.h:1354
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:170
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:392
BoolExprType boolop
Definition: primnodes.h:582
Definition: guc.h:75
void EmitWarningsOnPlaceholders(const char *className)
Definition: guc.c:8967
Expr * arg
Definition: primnodes.h:1222
long wal_records
Definition: instrument.h:37
#define lfirst_node(type, lc)
Definition: pg_list.h:172
#define USAGE_EXEC(duration)
#define APP_JUMB(item)
Node * rowexpr
Definition: primnodes.h:88
Node * limitCount
Definition: parsenodes.h:161
char * c
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:361
int stmt_location
Definition: plannodes.h:89
pgssStoreKind
NodeTag type
Definition: nodes.h:530
static char * buf
Definition: pg_test_fsync.c:68
static void JumbleQuery(pgssJumbleState *jstate, Query *query)
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
List * exclRelTlist
Definition: primnodes.h:1541
void check_stack_depth(void)
Definition: postgres.c:3312
bool IsUnderPostmaster
Definition: globals.c:109
JoinType jointype
Definition: parsenodes.h:1050
void(* shmem_startup_hook_type)(void)
Definition: ipc.h:22
List * aggorder
Definition: primnodes.h:320
static pgssEntry * entry_alloc(pgssHashKey *key, Size query_offset, int query_len, int encoding, bool sticky)
int errdetail(const char *fmt,...)
Definition: elog.c:954
Expr * arg
Definition: primnodes.h:1245
int errcode_for_file_access(void)
Definition: elog.c:633
ScanDirection
Definition: sdir.h:22
AttrNumber resno
Definition: primnodes.h:1411
#define CStringGetDatum(X)
Definition: postgres.h:578
Node * utilityStmt
Definition: plannodes.h:86
static char * qtext_load_file(Size *buffer_size)
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2322
long shared_blks_dirtied
Definition: instrument.h:23
char * cursor_name
Definition: primnodes.h:1320
#define YYLTYPE
Definition: scanner.h:44
unsigned int uint32
Definition: c.h:375
List * aggdirectargs
Definition: primnodes.h:318
#define IS_STICKY(c)
static ExecutorFinish_hook_type prev_ExecutorFinish
void _PG_fini(void)
Oid winfnoid
Definition: primnodes.h:373
planner_hook_type planner_hook
Definition: planner.c:74
Expr * arg
Definition: primnodes.h:837
__int64 st_size
Definition: win32_port.h:265
Datum numeric_in(PG_FUNCTION_ARGS)
Definition: numeric.c:621
const char * p_sourcetext
Definition: parse_node.h:179
long temp_blks_read
Definition: instrument.h:29
Expr * elemexpr
Definition: primnodes.h:862
Definition: type.h:82
List * returningList
Definition: parsenodes.h:146
int64 temp_blks_written
Datum pg_stat_statements_reset(PG_FUNCTION_ARGS)
static bool qtext_store(const char *query, int query_len, Size *query_offset, int *gc_count)
int64 shared_blks_written
#define STICKY_DECREASE_FACTOR
char * enrname
Definition: parsenodes.h:1109
#define USAGE_DECREASE_FACTOR
int durable_rename(const char *oldfile, const char *newfile, int elevel)
Definition: fd.c:659
Definition: nodes.h:299
List * newvals
Definition: primnodes.h:795
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition: fmgr.h:628
Definition: guc.h:72
Definition: nodes.h:154
OnConflictAction action
Definition: primnodes.h:1529
bool isNatural
Definition: primnodes.h:1492
core_yyscan_t scanner_init(const char *str, core_yy_extra_type *yyext, const ScanKeywordList *keywordlist, const uint16 *keyword_tokens)
static PlannedStmt * pgss_planner(Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams)
static Size pgss_memsize(void)
uint64 queryId
Definition: parsenodes.h:116
int CloseTransientFile(int fd)
Definition: fd.c:2549
#define WARNING
Definition: elog.h:40
shmem_startup_hook_type shmem_startup_hook
Definition: ipci.c:53
Index varno
Definition: primnodes.h:184
Definition: nodes.h:153
Size hash_estimate_size(long num_entries, Size entrysize)
Definition: dynahash.c:745
static void fill_in_constant_lengths(pgssJumbleState *jstate, const char *query, int query_loc)
XmlExprOp op
Definition: primnodes.h:1184
static int comp_location(const void *a, const void *b)
Node * startOffset
Definition: parsenodes.h:1357
#define SpinLockRelease(lock)
Definition: spin.h:64
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
#define HASH_BLOBS
Definition: hsearch.h:86
int64 local_blks_read
List * args
Definition: primnodes.h:936
static bool need_gc_qtexts(void)
#define PG_FINALLY()
Definition: elog.h:312
int location
Definition: primnodes.h:221
Node * quals
Definition: primnodes.h:1496
BoolTestType booltesttype
Definition: primnodes.h:1246
uintptr_t Datum
Definition: postgres.h:367
Datum pg_stat_statements_reset_1_7(PG_FUNCTION_ARGS)
int GetDatabaseEncoding(void)
Definition: mbutils.c:1151
static void pgss_shmem_shutdown(int code, Datum arg)
static void gc_qtexts(void)
static void pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc)
Size add_size(Size s1, Size s2)
Definition: shmem.c:498
struct pgssLocationLen pgssLocationLen
double mean_time[PGSS_NUMKIND]
Oid MyDatabaseId
Definition: globals.c:85
PGSSTrackLevel
#define Int64GetDatumFast(X)
Definition: postgres.h:760
static void entry_reset(Oid userid, Oid dbid, uint64 queryid)
bool scanner_isspace(char ch)
Definition: scansup.c:117
Size keysize
Definition: hsearch.h:71
Oid resulttype
Definition: primnodes.h:818
int work_mem
Definition: globals.c:121
BufferUsage bufusage
Definition: instrument.h:74
#define USAGE_INIT
int core_yylex(core_YYSTYPE *lvalp, YYLTYPE *llocp, core_yyscan_t yyscanner)
NullTestType nulltesttype
Definition: primnodes.h:1223
static zic_t const max_time
Definition: zic.c:584
pgssHashKey key
Oid aggfnoid
Definition: primnodes.h:312
CommandTag commandTag
Definition: cmdtag.h:30
List * colexprs
Definition: primnodes.h:93
List * named_args
Definition: primnodes.h:1186
#define ereport(elevel,...)
Definition: elog.h:144
int allowedModes
Definition: execnodes.h:304
#define PG_STAT_STATEMENTS_COLS
#define free(a)
Definition: header.h:65
CmdType commandType
Definition: parsenodes.h:112
List * args
Definition: primnodes.h:1188
int64 calls[PGSS_NUMKIND]
#define PG_RETURN_VOID()
Definition: fmgr.h:348
bool is_member_of_role(Oid member, Oid role)
Definition: acl.c:4916
#define Float8GetDatumFast(X)
Definition: postgres.h:761
#define DatumGetUInt64(X)
Definition: postgres.h:634
SetFunctionReturnMode returnMode
Definition: execnodes.h:306
double min_time[PGSS_NUMKIND]
struct Instrumentation * totaltime
Definition: execdesc.h:55
#define Max(x, y)
Definition: c.h:922
void(* ExecutorEnd_hook_type)(QueryDesc *queryDesc)
Definition: executor.h:80
double blk_read_time
Node * rarg
Definition: primnodes.h:1494
#define PG_VALID_BE_ENCODING(_enc)
Definition: pg_wchar.h:295
Expr * arg
Definition: primnodes.h:498
JoinType jointype
Definition: primnodes.h:1491
static bool pgss_track_utility
#define Assert(condition)
Definition: c.h:746
#define lfirst(lc)
Definition: pg_list.h:169
LWLockPadded * GetNamedLWLockTranche(const char *tranche_name)
Definition: lwlock.c:599
CTEMaterialize ctematerialized
Definition: parsenodes.h:1453
List * functions
Definition: parsenodes.h:1064
Expr * aggfilter
Definition: primnodes.h:378
int64 local_blks_dirtied
Expr * expr
Definition: primnodes.h:1410
int paramid
Definition: primnodes.h:263
uint64 es_processed
Definition: execnodes.h:563
PG_MODULE_MAGIC
instr_time blk_write_time
Definition: instrument.h:32
int64 local_blks_hit
size_t Size
Definition: c.h:474
struct Counters Counters
Node * endOffset
Definition: parsenodes.h:1358
long wal_fpi
Definition: instrument.h:38
Expr * arg
Definition: primnodes.h:903
Expr * aggfilter
Definition: primnodes.h:322
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1208
SetOperation op
Definition: parsenodes.h:1659
double blk_write_time
Index ctelevelsup
Definition: parsenodes.h:1081
#define MAXALIGN(LEN)
Definition: c.h:699
#define record_gc_qtexts()
LockWaitPolicy waitPolicy
Definition: parsenodes.h:1385
struct pgssJumbleState pgssJumbleState
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1401
int32 encoding
Definition: pg_database.h:41
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:232
void(* post_parse_analyze_hook_type)(ParseState *pstate, Query *query)
Definition: analyze.h:20
List * args
Definition: primnodes.h:583
static void header(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:210
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1070
double sum_var_time[PGSS_NUMKIND]
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1391
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:156
static int plan_nested_level
#define nodeTag(nodeptr)
Definition: nodes.h:533
Tuplestorestate * setResult
Definition: execnodes.h:309
static shmem_startup_hook_type prev_shmem_startup_hook
const char * sourceText
Definition: execdesc.h:38
RTEKind rtekind
Definition: parsenodes.h:977
static core_yyscan_t yyscanner
Definition: pl_scanner.c:106
int FreeFile(FILE *file)
Definition: fd.c:2521
static Datum values[MAXATTR]
Definition: bootstrap.c:165
List * orderClause
Definition: parsenodes.h:1355
Node * arbiterWhere
Definition: primnodes.h:1534
Expr * refassgnexpr
Definition: primnodes.h:430
ExprContext * econtext
Definition: execnodes.h:302
#define Int32GetDatum(X)
Definition: postgres.h:479
char * ctename
Definition: parsenodes.h:1080
List * cteList
Definition: parsenodes.h:135
Node * setOperations
Definition: parsenodes.h:166
e
Definition: preproc-init.c:82
Query * subquery
Definition: parsenodes.h:1012
List * groupClause
Definition: parsenodes.h:148
TupleDesc setDesc
Definition: execnodes.h:310
static void pgss_ExecutorFinish(QueryDesc *queryDesc)
void * palloc(Size size)
Definition: mcxt.c:950
uint64 queryId
Definition: plannodes.h:48
int errmsg(const char *fmt,...)
Definition: elog.c:821
long shared_blks_hit
Definition: instrument.h:21
Datum pg_stat_statements(PG_FUNCTION_ARGS)
void(* ExecutorStart_hook_type)(QueryDesc *queryDesc, int eflags)
Definition: executor.h:65
long local_blks_written
Definition: instrument.h:28
List * reflowerindexpr
Definition: primnodes.h:424
#define elog(elevel,...)
Definition: elog.h:214
int i
PlannedStmt * standard_planner(Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams)
Definition: planner.c:280
List * onConflictSet
Definition: primnodes.h:1538
bool escape_string_warning
Definition: scanner.h:88
static const uint32 PGSS_FILE_HEADER
Index ressortgroupref
Definition: primnodes.h:1413
#define CStringGetTextDatum(s)
Definition: builtins.h:86
void * arg
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
MinMaxOp op
Definition: primnodes.h:1108
void scanner_finish(core_yyscan_t yyscanner)
Expr * refexpr
Definition: primnodes.h:427
ExecutorFinish_hook_type ExecutorFinish_hook
Definition: execMain.c:72
Expr * arg
Definition: primnodes.h:935
Oid opno
Definition: primnodes.h:516
HTAB * ShmemInitHash(const char *name, long init_size, long max_size, HASHCTL *infoP, int hash_flags)
Definition: shmem.c:337
Expr * result
Definition: primnodes.h:948
struct pgssHashKey pgssHashKey
PlannedStmt * plannedstmt
Definition: execdesc.h:37
#define qsort(a, b, c, d)
Definition: port.h:497
List * args
Definition: primnodes.h:522
uint64 wal_bytes
Definition: instrument.h:39
Node * havingQual
Definition: parsenodes.h:152
Expr * defresult
Definition: primnodes.h:937
char * pg_any_to_server(const char *s, int len, int encoding)
Definition: mbutils.c:619
Expr * expr
Definition: primnodes.h:947
#define PG_TRY()
Definition: elog.h:295
static zic_t const min_time
Definition: zic.c:583
#define PG_GETARG_INT64(n)
Definition: fmgr.h:282
static void pgss_ExecutorEnd(QueryDesc *queryDesc)
Node * onConflictWhere
Definition: primnodes.h:1539
#define PGSS_TEXT_FILE
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:8828
int rtindex
Definition: primnodes.h:1498
Definition: pg_list.h:50
#define snprintf
Definition: port.h:215
struct TableSampleClause * tablesample
Definition: parsenodes.h:1007
int stmt_len
Definition: parsenodes.h:182
#define UINT64_FORMAT
Definition: c.h:418
static char * generate_normalized_query(pgssJumbleState *jstate, const char *query, int query_loc, int *query_len_p)
Oid paramtype
Definition: primnodes.h:264
post_parse_analyze_hook_type post_parse_analyze_hook
Definition: analyze.c:51
Datum pg_stat_statements_1_2(PG_FUNCTION_ARGS)
#define PG_END_TRY()
Definition: elog.h:320
#define ASSUMED_MEDIAN_INIT
#define read(a, b, c)
Definition: win32.h:13
void hash_seq_term(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1477
static const struct config_enum_entry track_options[]
BufferUsage pgBufferUsage
Definition: instrument.c:20
#define PG_STAT_STATEMENTS_COLS_V1_2
static bool pgss_save
static char * qtext_fetch(Size query_offset, int query_len, char *buffer, Size buffer_size)
PG_FUNCTION_INFO_V1(pg_stat_statements_reset)
static struct subre * parse(struct vars *, int, int, struct state *, struct state *)
Definition: regcomp.c:648
Definition: nodes.h:155
AttrNumber fieldnum
Definition: primnodes.h:766
#define ftruncate(a, b)
Definition: win32_port.h:65