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