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