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