PostgreSQL Source Code  git master
pg_stat_statements.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * pg_stat_statements.c
4  * Track statement planning and execution times as well as resource
5  * usage across a whole database cluster.
6  *
7  * Execution costs are totaled for each distinct source query, and kept in
8  * a shared hashtable. (We track only as many distinct queries as will fit
9  * in the designated amount of shared memory.)
10  *
11  * Starting in Postgres 9.2, this module normalized query entries. As of
12  * Postgres 14, the normalization is done by the core if compute_query_id is
13  * enabled, or optionally by third-party modules.
14  *
15  * To facilitate presenting entries to users, we create "representative" query
16  * strings in which constants are replaced with parameter symbols ($n), to
17  * make it clearer what a normalized entry can represent. To save on shared
18  * memory, and to avoid having to truncate oversized query strings, we store
19  * these strings in a temporary external query-texts file. Offsets into this
20  * file are kept in shared memory.
21  *
22  * Note about locking issues: to create or delete an entry in the shared
23  * hashtable, one must hold pgss->lock exclusively. Modifying any field
24  * in an entry except the counters requires the same. To look up an entry,
25  * one must hold the lock shared. To read or update the counters within
26  * an entry, one must hold the lock shared or exclusive (so the entry doesn't
27  * disappear!) and also take the entry's mutex spinlock.
28  * The shared state variable pgss->extent (the next free spot in the external
29  * query-text file) should be accessed only while holding either the
30  * pgss->mutex spinlock, or exclusive lock on pgss->lock. We use the mutex to
31  * allow reserving file space while holding only shared lock on pgss->lock.
32  * Rewriting the entire external query-text file, eg for garbage collection,
33  * requires holding pgss->lock exclusively; this allows individual entries
34  * in the file to be read or written while holding only shared lock.
35  *
36  *
37  * Copyright (c) 2008-2022, PostgreSQL Global Development Group
38  *
39  * IDENTIFICATION
40  * contrib/pg_stat_statements/pg_stat_statements.c
41  *
42  *-------------------------------------------------------------------------
43  */
44 #include "postgres.h"
45 
46 #include <math.h>
47 #include <sys/stat.h>
48 #include <unistd.h>
49 
50 #include "access/parallel.h"
51 #include "catalog/pg_authid.h"
52 #include "common/hashfn.h"
53 #include "executor/instrument.h"
54 #include "funcapi.h"
55 #include "jit/jit.h"
56 #include "mb/pg_wchar.h"
57 #include "miscadmin.h"
58 #include "optimizer/planner.h"
59 #include "parser/analyze.h"
60 #include "parser/parsetree.h"
61 #include "parser/scanner.h"
62 #include "parser/scansup.h"
63 #include "pgstat.h"
64 #include "storage/fd.h"
65 #include "storage/ipc.h"
66 #include "storage/lwlock.h"
67 #include "storage/shmem.h"
68 #include "storage/spin.h"
69 #include "tcop/utility.h"
70 #include "utils/acl.h"
71 #include "utils/builtins.h"
72 #include "utils/queryjumble.h"
73 #include "utils/memutils.h"
74 #include "utils/timestamp.h"
75 
77 
78 /* Location of permanent stats file (valid when database is shut down) */
79 #define PGSS_DUMP_FILE PGSTAT_STAT_PERMANENT_DIRECTORY "/pg_stat_statements.stat"
80 
81 /*
82  * Location of external query text file.
83  */
84 #define PGSS_TEXT_FILE PG_STAT_TMP_DIR "/pgss_query_texts.stat"
85 
86 /* Magic number identifying the stats file format */
87 static const uint32 PGSS_FILE_HEADER = 0x20220408;
88 
89 /* PostgreSQL major version number, changes in which invalidate all entries */
90 static const uint32 PGSS_PG_MAJOR_VERSION = PG_VERSION_NUM / 100;
91 
92 /* XXX: Should USAGE_EXEC reflect execution time and/or buffer usage? */
93 #define USAGE_EXEC(duration) (1.0)
94 #define USAGE_INIT (1.0) /* including initial planning */
95 #define ASSUMED_MEDIAN_INIT (10.0) /* initial assumed median usage */
96 #define ASSUMED_LENGTH_INIT 1024 /* initial assumed mean query length */
97 #define USAGE_DECREASE_FACTOR (0.99) /* decreased every entry_dealloc */
98 #define STICKY_DECREASE_FACTOR (0.50) /* factor for sticky entries */
99 #define USAGE_DEALLOC_PERCENT 5 /* free this % of entries at once */
100 #define IS_STICKY(c) ((c.calls[PGSS_PLAN] + c.calls[PGSS_EXEC]) == 0)
101 
102 /*
103  * Utility statements that pgss_ProcessUtility and pgss_post_parse_analyze
104  * ignores.
105  */
106 #define PGSS_HANDLED_UTILITY(n) (!IsA(n, ExecuteStmt) && \
107  !IsA(n, PrepareStmt) && \
108  !IsA(n, DeallocateStmt))
109 
110 /*
111  * Extension version number, for supporting older extension versions' objects
112  */
113 typedef enum pgssVersion
114 {
121  PGSS_V1_10
123 
124 typedef enum pgssStoreKind
125 {
127 
128  /*
129  * PGSS_PLAN and PGSS_EXEC must be respectively 0 and 1 as they're used to
130  * reference the underlying values in the arrays in the Counters struct,
131  * and this order is required in pg_stat_statements_internal().
132  */
135 
136  PGSS_NUMKIND /* Must be last value of this enum */
138 
139 /*
140  * Hashtable key that defines the identity of a hashtable entry. We separate
141  * queries by user and by database even if they are otherwise identical.
142  *
143  * If you add a new key to this struct, make sure to teach pgss_store() to
144  * zero the padding bytes. Otherwise, things will break, because pgss_hash is
145  * created using HASH_BLOBS, and thus tag_hash is used to hash this.
146 
147  */
148 typedef struct pgssHashKey
149 {
150  Oid userid; /* user OID */
151  Oid dbid; /* database OID */
152  uint64 queryid; /* query identifier */
153  bool toplevel; /* query executed at top level */
155 
156 /*
157  * The actual stats counters kept within pgssEntry.
158  */
159 typedef struct Counters
160 {
161  int64 calls[PGSS_NUMKIND]; /* # of times planned/executed */
162  double total_time[PGSS_NUMKIND]; /* total planning/execution time,
163  * in msec */
164  double min_time[PGSS_NUMKIND]; /* minimum planning/execution time in
165  * msec */
166  double max_time[PGSS_NUMKIND]; /* maximum planning/execution time in
167  * msec */
168  double mean_time[PGSS_NUMKIND]; /* mean planning/execution time in
169  * msec */
170  double sum_var_time[PGSS_NUMKIND]; /* sum of variances in
171  * planning/execution time in msec */
172  int64 rows; /* total # of retrieved or affected rows */
173  int64 shared_blks_hit; /* # of shared buffer hits */
174  int64 shared_blks_read; /* # of shared disk blocks read */
175  int64 shared_blks_dirtied; /* # of shared disk blocks dirtied */
176  int64 shared_blks_written; /* # of shared disk blocks written */
177  int64 local_blks_hit; /* # of local buffer hits */
178  int64 local_blks_read; /* # of local disk blocks read */
179  int64 local_blks_dirtied; /* # of local disk blocks dirtied */
180  int64 local_blks_written; /* # of local disk blocks written */
181  int64 temp_blks_read; /* # of temp blocks read */
182  int64 temp_blks_written; /* # of temp blocks written */
183  double blk_read_time; /* time spent reading blocks, in msec */
184  double blk_write_time; /* time spent writing blocks, in msec */
185  double temp_blk_read_time; /* time spent reading temp blocks, in msec */
186  double temp_blk_write_time; /* time spent writing temp blocks, in
187  * msec */
188  double usage; /* usage factor */
189  int64 wal_records; /* # of WAL records generated */
190  int64 wal_fpi; /* # of WAL full page images generated */
191  uint64 wal_bytes; /* total amount of WAL generated in bytes */
192  int64 jit_functions; /* total number of JIT functions emitted */
193  double jit_generation_time; /* total time to generate jit code */
194  int64 jit_inlining_count; /* number of times inlining time has been
195  * > 0 */
196  double jit_inlining_time; /* total time to inline jit code */
197  int64 jit_optimization_count; /* number of times optimization time
198  * has been > 0 */
199  double jit_optimization_time; /* total time to optimize jit code */
200  int64 jit_emission_count; /* number of times emission time has been
201  * > 0 */
202  double jit_emission_time; /* total time to emit jit code */
204 
205 /*
206  * Global statistics for pg_stat_statements
207  */
208 typedef struct pgssGlobalStats
209 {
210  int64 dealloc; /* # of times entries were deallocated */
211  TimestampTz stats_reset; /* timestamp with all stats reset */
213 
214 /*
215  * Statistics per statement
216  *
217  * Note: in event of a failure in garbage collection of the query text file,
218  * we reset query_offset to zero and query_len to -1. This will be seen as
219  * an invalid state by qtext_fetch().
220  */
221 typedef struct pgssEntry
222 {
223  pgssHashKey key; /* hash key of entry - MUST BE FIRST */
224  Counters counters; /* the statistics for this query */
225  Size query_offset; /* query text offset in external file */
226  int query_len; /* # of valid bytes in query string, or -1 */
227  int encoding; /* query text encoding */
228  slock_t mutex; /* protects the counters only */
230 
231 /*
232  * Global shared state
233  */
234 typedef struct pgssSharedState
235 {
236  LWLock *lock; /* protects hashtable search/modification */
237  double cur_median_usage; /* current median usage in hashtable */
238  Size mean_query_len; /* current mean entry text length */
239  slock_t mutex; /* protects following fields only: */
240  Size extent; /* current extent of query file */
241  int n_writers; /* number of active writers to query file */
242  int gc_count; /* query file garbage collection cycle count */
243  pgssGlobalStats stats; /* global statistics for pgss */
245 
246 /*---- Local variables ----*/
247 
248 /* Current nesting depth of ExecutorRun+ProcessUtility calls */
249 static int exec_nested_level = 0;
250 
251 /* Current nesting depth of planner calls */
252 static int plan_nested_level = 0;
253 
254 /* Saved hook values in case of unload */
264 
265 /* Links to shared memory state */
266 static pgssSharedState *pgss = NULL;
267 static HTAB *pgss_hash = NULL;
268 
269 /*---- GUC variables ----*/
270 
271 typedef enum
272 {
273  PGSS_TRACK_NONE, /* track no statements */
274  PGSS_TRACK_TOP, /* only top level statements */
275  PGSS_TRACK_ALL /* all statements, including nested ones */
277 
278 static const struct config_enum_entry track_options[] =
279 {
280  {"none", PGSS_TRACK_NONE, false},
281  {"top", PGSS_TRACK_TOP, false},
282  {"all", PGSS_TRACK_ALL, false},
283  {NULL, 0, false}
284 };
285 
286 static int pgss_max = 5000; /* max # statements to track */
287 static int pgss_track = PGSS_TRACK_TOP; /* tracking level */
288 static bool pgss_track_utility = true; /* whether to track utility commands */
289 static bool pgss_track_planning = false; /* whether to track planning
290  * duration */
291 static bool pgss_save = true; /* whether to save stats across shutdown */
292 
293 
294 #define pgss_enabled(level) \
295  (!IsParallelWorker() && \
296  (pgss_track == PGSS_TRACK_ALL || \
297  (pgss_track == PGSS_TRACK_TOP && (level) == 0)))
298 
299 #define record_gc_qtexts() \
300  do { \
301  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss; \
302  SpinLockAcquire(&s->mutex); \
303  s->gc_count++; \
304  SpinLockRelease(&s->mutex); \
305  } while(0)
306 
307 /*---- Function declarations ----*/
308 
318 
319 static void pgss_shmem_request(void);
320 static void pgss_shmem_startup(void);
321 static void pgss_shmem_shutdown(int code, Datum arg);
322 static void pgss_post_parse_analyze(ParseState *pstate, Query *query,
323  JumbleState *jstate);
325  const char *query_string,
326  int cursorOptions,
327  ParamListInfo boundParams);
328 static void pgss_ExecutorStart(QueryDesc *queryDesc, int eflags);
329 static void pgss_ExecutorRun(QueryDesc *queryDesc,
330  ScanDirection direction,
331  uint64 count, bool execute_once);
332 static void pgss_ExecutorFinish(QueryDesc *queryDesc);
333 static void pgss_ExecutorEnd(QueryDesc *queryDesc);
334 static void pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
335  bool readOnlyTree,
336  ProcessUtilityContext context, ParamListInfo params,
337  QueryEnvironment *queryEnv,
339 static void pgss_store(const char *query, uint64 queryId,
340  int query_location, int query_len,
341  pgssStoreKind kind,
342  double total_time, uint64 rows,
343  const BufferUsage *bufusage,
344  const WalUsage *walusage,
345  const struct JitInstrumentation *jitusage,
346  JumbleState *jstate);
348  pgssVersion api_version,
349  bool showtext);
350 static Size pgss_memsize(void);
351 static pgssEntry *entry_alloc(pgssHashKey *key, Size query_offset, int query_len,
352  int encoding, bool sticky);
353 static void entry_dealloc(void);
354 static bool qtext_store(const char *query, int query_len,
355  Size *query_offset, int *gc_count);
356 static char *qtext_load_file(Size *buffer_size);
357 static char *qtext_fetch(Size query_offset, int query_len,
358  char *buffer, Size buffer_size);
359 static bool need_gc_qtexts(void);
360 static void gc_qtexts(void);
361 static void entry_reset(Oid userid, Oid dbid, uint64 queryid);
362 static char *generate_normalized_query(JumbleState *jstate, const char *query,
363  int query_loc, int *query_len_p);
364 static void fill_in_constant_lengths(JumbleState *jstate, const char *query,
365  int query_loc);
366 static int comp_location(const void *a, const void *b);
367 
368 
369 /*
370  * Module load callback
371  */
372 void
373 _PG_init(void)
374 {
375  /*
376  * In order to create our shared memory area, we have to be loaded via
377  * shared_preload_libraries. If not, fall out without hooking into any of
378  * the main system. (We don't throw error here because it seems useful to
379  * allow the pg_stat_statements functions to be created even when the
380  * module isn't active. The functions must protect themselves against
381  * being called then, however.)
382  */
384  return;
385 
386  /*
387  * Inform the postmaster that we want to enable query_id calculation if
388  * compute_query_id is set to auto.
389  */
390  EnableQueryId();
391 
392  /*
393  * Define (or redefine) custom GUC variables.
394  */
395  DefineCustomIntVariable("pg_stat_statements.max",
396  "Sets the maximum number of statements tracked by pg_stat_statements.",
397  NULL,
398  &pgss_max,
399  5000,
400  100,
401  INT_MAX / 2,
403  0,
404  NULL,
405  NULL,
406  NULL);
407 
408  DefineCustomEnumVariable("pg_stat_statements.track",
409  "Selects which statements are tracked by pg_stat_statements.",
410  NULL,
411  &pgss_track,
414  PGC_SUSET,
415  0,
416  NULL,
417  NULL,
418  NULL);
419 
420  DefineCustomBoolVariable("pg_stat_statements.track_utility",
421  "Selects whether utility commands are tracked by pg_stat_statements.",
422  NULL,
424  true,
425  PGC_SUSET,
426  0,
427  NULL,
428  NULL,
429  NULL);
430 
431  DefineCustomBoolVariable("pg_stat_statements.track_planning",
432  "Selects whether planning duration is tracked by pg_stat_statements.",
433  NULL,
435  false,
436  PGC_SUSET,
437  0,
438  NULL,
439  NULL,
440  NULL);
441 
442  DefineCustomBoolVariable("pg_stat_statements.save",
443  "Save pg_stat_statements statistics across server shutdowns.",
444  NULL,
445  &pgss_save,
446  true,
447  PGC_SIGHUP,
448  0,
449  NULL,
450  NULL,
451  NULL);
452 
453  MarkGUCPrefixReserved("pg_stat_statements");
454 
455  /*
456  * Install hooks.
457  */
476 }
477 
478 /*
479  * shmem_request hook: request additional shared resources. We'll allocate or
480  * attach to the shared resources in pgss_shmem_startup().
481  */
482 static void
484 {
487 
489  RequestNamedLWLockTranche("pg_stat_statements", 1);
490 }
491 
492 /*
493  * shmem_startup hook: allocate or attach to shared memory,
494  * then load any pre-existing statistics from file.
495  * Also create and load the query-texts file, which is expected to exist
496  * (even if empty) while the module is enabled.
497  */
498 static void
500 {
501  bool found;
502  HASHCTL info;
503  FILE *file = NULL;
504  FILE *qfile = NULL;
505  uint32 header;
506  int32 num;
507  int32 pgver;
508  int32 i;
509  int buffer_size;
510  char *buffer = NULL;
511 
514 
515  /* reset in case this is a restart within the postmaster */
516  pgss = NULL;
517  pgss_hash = NULL;
518 
519  /*
520  * Create or attach to the shared memory state, including hash table
521  */
522  LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE);
523 
524  pgss = ShmemInitStruct("pg_stat_statements",
525  sizeof(pgssSharedState),
526  &found);
527 
528  if (!found)
529  {
530  /* First time through ... */
531  pgss->lock = &(GetNamedLWLockTranche("pg_stat_statements"))->lock;
535  pgss->extent = 0;
536  pgss->n_writers = 0;
537  pgss->gc_count = 0;
538  pgss->stats.dealloc = 0;
540  }
541 
542  info.keysize = sizeof(pgssHashKey);
543  info.entrysize = sizeof(pgssEntry);
544  pgss_hash = ShmemInitHash("pg_stat_statements hash",
546  &info,
548 
549  LWLockRelease(AddinShmemInitLock);
550 
551  /*
552  * If we're in the postmaster (or a standalone backend...), set up a shmem
553  * exit hook to dump the statistics to disk.
554  */
555  if (!IsUnderPostmaster)
557 
558  /*
559  * Done if some other process already completed our initialization.
560  */
561  if (found)
562  return;
563 
564  /*
565  * Note: we don't bother with locks here, because there should be no other
566  * processes running when this code is reached.
567  */
568 
569  /* Unlink query text file possibly left over from crash */
570  unlink(PGSS_TEXT_FILE);
571 
572  /* Allocate new query text temp file */
574  if (qfile == NULL)
575  goto write_error;
576 
577  /*
578  * If we were told not to load old statistics, we're done. (Note we do
579  * not try to unlink any old dump file in this case. This seems a bit
580  * questionable but it's the historical behavior.)
581  */
582  if (!pgss_save)
583  {
584  FreeFile(qfile);
585  return;
586  }
587 
588  /*
589  * Attempt to load old statistics from the dump file.
590  */
592  if (file == NULL)
593  {
594  if (errno != ENOENT)
595  goto read_error;
596  /* No existing persisted stats file, so we're done */
597  FreeFile(qfile);
598  return;
599  }
600 
601  buffer_size = 2048;
602  buffer = (char *) palloc(buffer_size);
603 
604  if (fread(&header, sizeof(uint32), 1, file) != 1 ||
605  fread(&pgver, sizeof(uint32), 1, file) != 1 ||
606  fread(&num, sizeof(int32), 1, file) != 1)
607  goto read_error;
608 
609  if (header != PGSS_FILE_HEADER ||
610  pgver != PGSS_PG_MAJOR_VERSION)
611  goto data_error;
612 
613  for (i = 0; i < num; i++)
614  {
615  pgssEntry temp;
616  pgssEntry *entry;
617  Size query_offset;
618 
619  if (fread(&temp, sizeof(pgssEntry), 1, file) != 1)
620  goto read_error;
621 
622  /* Encoding is the only field we can easily sanity-check */
623  if (!PG_VALID_BE_ENCODING(temp.encoding))
624  goto data_error;
625 
626  /* Resize buffer as needed */
627  if (temp.query_len >= buffer_size)
628  {
629  buffer_size = Max(buffer_size * 2, temp.query_len + 1);
630  buffer = repalloc(buffer, buffer_size);
631  }
632 
633  if (fread(buffer, 1, temp.query_len + 1, file) != temp.query_len + 1)
634  goto read_error;
635 
636  /* Should have a trailing null, but let's make sure */
637  buffer[temp.query_len] = '\0';
638 
639  /* Skip loading "sticky" entries */
640  if (IS_STICKY(temp.counters))
641  continue;
642 
643  /* Store the query text */
644  query_offset = pgss->extent;
645  if (fwrite(buffer, 1, temp.query_len + 1, qfile) != temp.query_len + 1)
646  goto write_error;
647  pgss->extent += temp.query_len + 1;
648 
649  /* make the hashtable entry (discards old entries if too many) */
650  entry = entry_alloc(&temp.key, query_offset, temp.query_len,
651  temp.encoding,
652  false);
653 
654  /* copy in the actual stats */
655  entry->counters = temp.counters;
656  }
657 
658  /* Read global statistics for pg_stat_statements */
659  if (fread(&pgss->stats, sizeof(pgssGlobalStats), 1, file) != 1)
660  goto read_error;
661 
662  pfree(buffer);
663  FreeFile(file);
664  FreeFile(qfile);
665 
666  /*
667  * Remove the persisted stats file so it's not included in
668  * backups/replication standbys, etc. A new file will be written on next
669  * shutdown.
670  *
671  * Note: it's okay if the PGSS_TEXT_FILE is included in a basebackup,
672  * because we remove that file on startup; it acts inversely to
673  * PGSS_DUMP_FILE, in that it is only supposed to be around when the
674  * server is running, whereas PGSS_DUMP_FILE is only supposed to be around
675  * when the server is not running. Leaving the file creates no danger of
676  * a newly restored database having a spurious record of execution costs,
677  * which is what we're really concerned about here.
678  */
679  unlink(PGSS_DUMP_FILE);
680 
681  return;
682 
683 read_error:
684  ereport(LOG,
686  errmsg("could not read file \"%s\": %m",
687  PGSS_DUMP_FILE)));
688  goto fail;
689 data_error:
690  ereport(LOG,
691  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
692  errmsg("ignoring invalid data in file \"%s\"",
693  PGSS_DUMP_FILE)));
694  goto fail;
695 write_error:
696  ereport(LOG,
698  errmsg("could not write file \"%s\": %m",
699  PGSS_TEXT_FILE)));
700 fail:
701  if (buffer)
702  pfree(buffer);
703  if (file)
704  FreeFile(file);
705  if (qfile)
706  FreeFile(qfile);
707  /* If possible, throw away the bogus file; ignore any error */
708  unlink(PGSS_DUMP_FILE);
709 
710  /*
711  * Don't unlink PGSS_TEXT_FILE here; it should always be around while the
712  * server is running with pg_stat_statements enabled
713  */
714 }
715 
716 /*
717  * shmem_shutdown hook: Dump statistics into file.
718  *
719  * Note: we don't bother with acquiring lock, because there should be no
720  * other processes running when this is called.
721  */
722 static void
724 {
725  FILE *file;
726  char *qbuffer = NULL;
727  Size qbuffer_size = 0;
728  HASH_SEQ_STATUS hash_seq;
729  int32 num_entries;
730  pgssEntry *entry;
731 
732  /* Don't try to dump during a crash. */
733  if (code)
734  return;
735 
736  /* Safety check ... shouldn't get here unless shmem is set up. */
737  if (!pgss || !pgss_hash)
738  return;
739 
740  /* Don't dump if told not to. */
741  if (!pgss_save)
742  return;
743 
744  file = AllocateFile(PGSS_DUMP_FILE ".tmp", PG_BINARY_W);
745  if (file == NULL)
746  goto error;
747 
748  if (fwrite(&PGSS_FILE_HEADER, sizeof(uint32), 1, file) != 1)
749  goto error;
750  if (fwrite(&PGSS_PG_MAJOR_VERSION, sizeof(uint32), 1, file) != 1)
751  goto error;
752  num_entries = hash_get_num_entries(pgss_hash);
753  if (fwrite(&num_entries, sizeof(int32), 1, file) != 1)
754  goto error;
755 
756  qbuffer = qtext_load_file(&qbuffer_size);
757  if (qbuffer == NULL)
758  goto error;
759 
760  /*
761  * When serializing to disk, we store query texts immediately after their
762  * entry data. Any orphaned query texts are thereby excluded.
763  */
764  hash_seq_init(&hash_seq, pgss_hash);
765  while ((entry = hash_seq_search(&hash_seq)) != NULL)
766  {
767  int len = entry->query_len;
768  char *qstr = qtext_fetch(entry->query_offset, len,
769  qbuffer, qbuffer_size);
770 
771  if (qstr == NULL)
772  continue; /* Ignore any entries with bogus texts */
773 
774  if (fwrite(entry, sizeof(pgssEntry), 1, file) != 1 ||
775  fwrite(qstr, 1, len + 1, file) != len + 1)
776  {
777  /* note: we assume hash_seq_term won't change errno */
778  hash_seq_term(&hash_seq);
779  goto error;
780  }
781  }
782 
783  /* Dump global statistics for pg_stat_statements */
784  if (fwrite(&pgss->stats, sizeof(pgssGlobalStats), 1, file) != 1)
785  goto error;
786 
787  free(qbuffer);
788  qbuffer = NULL;
789 
790  if (FreeFile(file))
791  {
792  file = NULL;
793  goto error;
794  }
795 
796  /*
797  * Rename file into place, so we atomically replace any old one.
798  */
800 
801  /* Unlink query-texts file; it's not needed while shutdown */
802  unlink(PGSS_TEXT_FILE);
803 
804  return;
805 
806 error:
807  ereport(LOG,
809  errmsg("could not write file \"%s\": %m",
810  PGSS_DUMP_FILE ".tmp")));
811  free(qbuffer);
812  if (file)
813  FreeFile(file);
814  unlink(PGSS_DUMP_FILE ".tmp");
815  unlink(PGSS_TEXT_FILE);
816 }
817 
818 /*
819  * Post-parse-analysis hook: mark query with a queryId
820  */
821 static void
823 {
825  prev_post_parse_analyze_hook(pstate, query, jstate);
826 
827  /* Safety check... */
829  return;
830 
831  /*
832  * Clear queryId for prepared statements related utility, as those will
833  * inherit from the underlying statement's one (except DEALLOCATE which is
834  * entirely untracked).
835  */
836  if (query->utilityStmt)
837  {
839  query->queryId = UINT64CONST(0);
840  return;
841  }
842 
843  /*
844  * If query jumbling were able to identify any ignorable constants, we
845  * immediately create a hash table entry for the query, so that we can
846  * record the normalized form of the query string. If there were no such
847  * constants, the normalized string would be the same as the query text
848  * anyway, so there's no need for an early entry.
849  */
850  if (jstate && jstate->clocations_count > 0)
851  pgss_store(pstate->p_sourcetext,
852  query->queryId,
853  query->stmt_location,
854  query->stmt_len,
855  PGSS_INVALID,
856  0,
857  0,
858  NULL,
859  NULL,
860  NULL,
861  jstate);
862 }
863 
864 /*
865  * Planner hook: forward to regular planner, but measure planning time
866  * if needed.
867  */
868 static PlannedStmt *
870  const char *query_string,
871  int cursorOptions,
872  ParamListInfo boundParams)
873 {
874  PlannedStmt *result;
875 
876  /*
877  * We can't process the query if no query_string is provided, as
878  * pgss_store needs it. We also ignore query without queryid, as it would
879  * be treated as a utility statement, which may not be the case.
880  *
881  * Note that planner_hook can be called from the planner itself, so we
882  * have a specific nesting level for the planner. However, utility
883  * commands containing optimizable statements can also call the planner,
884  * same for regular DML (for instance for underlying foreign key queries).
885  * So testing the planner nesting level only is not enough to detect real
886  * top level planner call.
887  */
889  && pgss_track_planning && query_string
890  && parse->queryId != UINT64CONST(0))
891  {
892  instr_time start;
894  BufferUsage bufusage_start,
895  bufusage;
896  WalUsage walusage_start,
897  walusage;
898 
899  /* We need to track buffer usage as the planner can access them. */
900  bufusage_start = pgBufferUsage;
901 
902  /*
903  * Similarly the planner could write some WAL records in some cases
904  * (e.g. setting a hint bit with those being WAL-logged)
905  */
906  walusage_start = pgWalUsage;
907  INSTR_TIME_SET_CURRENT(start);
908 
910  PG_TRY();
911  {
912  if (prev_planner_hook)
913  result = prev_planner_hook(parse, query_string, cursorOptions,
914  boundParams);
915  else
916  result = standard_planner(parse, query_string, cursorOptions,
917  boundParams);
918  }
919  PG_FINALLY();
920  {
922  }
923  PG_END_TRY();
924 
927 
928  /* calc differences of buffer counters. */
929  memset(&bufusage, 0, sizeof(BufferUsage));
930  BufferUsageAccumDiff(&bufusage, &pgBufferUsage, &bufusage_start);
931 
932  /* calc differences of WAL counters. */
933  memset(&walusage, 0, sizeof(WalUsage));
934  WalUsageAccumDiff(&walusage, &pgWalUsage, &walusage_start);
935 
936  pgss_store(query_string,
937  parse->queryId,
938  parse->stmt_location,
939  parse->stmt_len,
940  PGSS_PLAN,
942  0,
943  &bufusage,
944  &walusage,
945  NULL,
946  NULL);
947  }
948  else
949  {
950  if (prev_planner_hook)
951  result = prev_planner_hook(parse, query_string, cursorOptions,
952  boundParams);
953  else
954  result = standard_planner(parse, query_string, cursorOptions,
955  boundParams);
956  }
957 
958  return result;
959 }
960 
961 /*
962  * ExecutorStart hook: start up tracking if needed
963  */
964 static void
965 pgss_ExecutorStart(QueryDesc *queryDesc, int eflags)
966 {
967  if (prev_ExecutorStart)
968  prev_ExecutorStart(queryDesc, eflags);
969  else
970  standard_ExecutorStart(queryDesc, eflags);
971 
972  /*
973  * If query has queryId zero, don't track it. This prevents double
974  * counting of optimizable statements that are directly contained in
975  * utility statements.
976  */
977  if (pgss_enabled(exec_nested_level) && queryDesc->plannedstmt->queryId != UINT64CONST(0))
978  {
979  /*
980  * Set up to track total elapsed time in ExecutorRun. Make sure the
981  * space is allocated in the per-query context so it will go away at
982  * ExecutorEnd.
983  */
984  if (queryDesc->totaltime == NULL)
985  {
986  MemoryContext oldcxt;
987 
988  oldcxt = MemoryContextSwitchTo(queryDesc->estate->es_query_cxt);
989  queryDesc->totaltime = InstrAlloc(1, INSTRUMENT_ALL, false);
990  MemoryContextSwitchTo(oldcxt);
991  }
992  }
993 }
994 
995 /*
996  * ExecutorRun hook: all we need do is track nesting depth
997  */
998 static void
999 pgss_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count,
1000  bool execute_once)
1001 {
1003  PG_TRY();
1004  {
1005  if (prev_ExecutorRun)
1006  prev_ExecutorRun(queryDesc, direction, count, execute_once);
1007  else
1008  standard_ExecutorRun(queryDesc, direction, count, execute_once);
1009  }
1010  PG_FINALLY();
1011  {
1013  }
1014  PG_END_TRY();
1015 }
1016 
1017 /*
1018  * ExecutorFinish hook: all we need do is track nesting depth
1019  */
1020 static void
1022 {
1024  PG_TRY();
1025  {
1026  if (prev_ExecutorFinish)
1027  prev_ExecutorFinish(queryDesc);
1028  else
1029  standard_ExecutorFinish(queryDesc);
1030  }
1031  PG_FINALLY();
1032  {
1034  }
1035  PG_END_TRY();
1036 }
1037 
1038 /*
1039  * ExecutorEnd hook: store results if needed
1040  */
1041 static void
1043 {
1044  uint64 queryId = queryDesc->plannedstmt->queryId;
1045 
1046  if (queryId != UINT64CONST(0) && queryDesc->totaltime &&
1048  {
1049  /*
1050  * Make sure stats accumulation is done. (Note: it's okay if several
1051  * levels of hook all do this.)
1052  */
1053  InstrEndLoop(queryDesc->totaltime);
1054 
1055  pgss_store(queryDesc->sourceText,
1056  queryId,
1057  queryDesc->plannedstmt->stmt_location,
1058  queryDesc->plannedstmt->stmt_len,
1059  PGSS_EXEC,
1060  queryDesc->totaltime->total * 1000.0, /* convert to msec */
1061  queryDesc->estate->es_processed,
1062  &queryDesc->totaltime->bufusage,
1063  &queryDesc->totaltime->walusage,
1064  queryDesc->estate->es_jit ? &queryDesc->estate->es_jit->instr : NULL,
1065  NULL);
1066  }
1067 
1068  if (prev_ExecutorEnd)
1069  prev_ExecutorEnd(queryDesc);
1070  else
1071  standard_ExecutorEnd(queryDesc);
1072 }
1073 
1074 /*
1075  * ProcessUtility hook
1076  */
1077 static void
1078 pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
1079  bool readOnlyTree,
1080  ProcessUtilityContext context,
1081  ParamListInfo params, QueryEnvironment *queryEnv,
1083 {
1084  Node *parsetree = pstmt->utilityStmt;
1085  uint64 saved_queryId = pstmt->queryId;
1086  int saved_stmt_location = pstmt->stmt_location;
1087  int saved_stmt_len = pstmt->stmt_len;
1088 
1089  /*
1090  * Force utility statements to get queryId zero. We do this even in cases
1091  * where the statement contains an optimizable statement for which a
1092  * queryId could be derived (such as EXPLAIN or DECLARE CURSOR). For such
1093  * cases, runtime control will first go through ProcessUtility and then
1094  * the executor, and we don't want the executor hooks to do anything,
1095  * since we are already measuring the statement's costs at the utility
1096  * level.
1097  *
1098  * Note that this is only done if pg_stat_statements is enabled and
1099  * configured to track utility statements, in the unlikely possibility
1100  * that user configured another extension to handle utility statements
1101  * only.
1102  */
1104  pstmt->queryId = UINT64CONST(0);
1105 
1106  /*
1107  * If it's an EXECUTE statement, we don't track it and don't increment the
1108  * nesting level. This allows the cycles to be charged to the underlying
1109  * PREPARE instead (by the Executor hooks), which is much more useful.
1110  *
1111  * We also don't track execution of PREPARE. If we did, we would get one
1112  * hash table entry for the PREPARE (with hash calculated from the query
1113  * string), and then a different one with the same query string (but hash
1114  * calculated from the query tree) would be used to accumulate costs of
1115  * ensuing EXECUTEs. This would be confusing, and inconsistent with other
1116  * cases where planning time is not included at all.
1117  *
1118  * Likewise, we don't track execution of DEALLOCATE.
1119  */
1121  PGSS_HANDLED_UTILITY(parsetree))
1122  {
1123  instr_time start;
1125  uint64 rows;
1126  BufferUsage bufusage_start,
1127  bufusage;
1128  WalUsage walusage_start,
1129  walusage;
1130 
1131  bufusage_start = pgBufferUsage;
1132  walusage_start = pgWalUsage;
1133  INSTR_TIME_SET_CURRENT(start);
1134 
1136  PG_TRY();
1137  {
1138  if (prev_ProcessUtility)
1139  prev_ProcessUtility(pstmt, queryString, readOnlyTree,
1140  context, params, queryEnv,
1141  dest, qc);
1142  else
1143  standard_ProcessUtility(pstmt, queryString, readOnlyTree,
1144  context, params, queryEnv,
1145  dest, qc);
1146  }
1147  PG_FINALLY();
1148  {
1150  }
1151  PG_END_TRY();
1152 
1153  /*
1154  * CAUTION: do not access the *pstmt data structure again below here.
1155  * If it was a ROLLBACK or similar, that data structure may have been
1156  * freed. We must copy everything we still need into local variables,
1157  * which we did above.
1158  *
1159  * For the same reason, we can't risk restoring pstmt->queryId to its
1160  * former value, which'd otherwise be a good idea.
1161  */
1162 
1164  INSTR_TIME_SUBTRACT(duration, start);
1165 
1166  /*
1167  * Track the total number of rows retrieved or affected by the utility
1168  * statements of COPY, FETCH, CREATE TABLE AS, CREATE MATERIALIZED
1169  * VIEW, REFRESH MATERIALIZED VIEW and SELECT INTO.
1170  */
1171  rows = (qc && (qc->commandTag == CMDTAG_COPY ||
1172  qc->commandTag == CMDTAG_FETCH ||
1173  qc->commandTag == CMDTAG_SELECT ||
1174  qc->commandTag == CMDTAG_REFRESH_MATERIALIZED_VIEW)) ?
1175  qc->nprocessed : 0;
1176 
1177  /* calc differences of buffer counters. */
1178  memset(&bufusage, 0, sizeof(BufferUsage));
1179  BufferUsageAccumDiff(&bufusage, &pgBufferUsage, &bufusage_start);
1180 
1181  /* calc differences of WAL counters. */
1182  memset(&walusage, 0, sizeof(WalUsage));
1183  WalUsageAccumDiff(&walusage, &pgWalUsage, &walusage_start);
1184 
1185  pgss_store(queryString,
1186  saved_queryId,
1187  saved_stmt_location,
1188  saved_stmt_len,
1189  PGSS_EXEC,
1191  rows,
1192  &bufusage,
1193  &walusage,
1194  NULL,
1195  NULL);
1196  }
1197  else
1198  {
1199  if (prev_ProcessUtility)
1200  prev_ProcessUtility(pstmt, queryString, readOnlyTree,
1201  context, params, queryEnv,
1202  dest, qc);
1203  else
1204  standard_ProcessUtility(pstmt, queryString, readOnlyTree,
1205  context, params, queryEnv,
1206  dest, qc);
1207  }
1208 }
1209 
1210 /*
1211  * Store some statistics for a statement.
1212  *
1213  * If jstate is not NULL then we're trying to create an entry for which
1214  * we have no statistics as yet; we just want to record the normalized
1215  * query string. total_time, rows, bufusage and walusage are ignored in this
1216  * case.
1217  *
1218  * If kind is PGSS_PLAN or PGSS_EXEC, its value is used as the array position
1219  * for the arrays in the Counters field.
1220  */
1221 static void
1222 pgss_store(const char *query, uint64 queryId,
1223  int query_location, int query_len,
1224  pgssStoreKind kind,
1225  double total_time, uint64 rows,
1226  const BufferUsage *bufusage,
1227  const WalUsage *walusage,
1228  const struct JitInstrumentation *jitusage,
1229  JumbleState *jstate)
1230 {
1231  pgssHashKey key;
1232  pgssEntry *entry;
1233  char *norm_query = NULL;
1234  int encoding = GetDatabaseEncoding();
1235 
1236  Assert(query != NULL);
1237 
1238  /* Safety check... */
1239  if (!pgss || !pgss_hash)
1240  return;
1241 
1242  /*
1243  * Nothing to do if compute_query_id isn't enabled and no other module
1244  * computed a query identifier.
1245  */
1246  if (queryId == UINT64CONST(0))
1247  return;
1248 
1249  /*
1250  * Confine our attention to the relevant part of the string, if the query
1251  * is a portion of a multi-statement source string, and update query
1252  * location and length if needed.
1253  */
1254  query = CleanQuerytext(query, &query_location, &query_len);
1255 
1256  /* Set up key for hashtable search */
1257 
1258  /* memset() is required when pgssHashKey is without padding only */
1259  memset(&key, 0, sizeof(pgssHashKey));
1260 
1261  key.userid = GetUserId();
1262  key.dbid = MyDatabaseId;
1263  key.queryid = queryId;
1264  key.toplevel = (exec_nested_level == 0);
1265 
1266  /* Lookup the hash table entry with shared lock. */
1268 
1269  entry = (pgssEntry *) hash_search(pgss_hash, &key, HASH_FIND, NULL);
1270 
1271  /* Create new entry, if not present */
1272  if (!entry)
1273  {
1274  Size query_offset;
1275  int gc_count;
1276  bool stored;
1277  bool do_gc;
1278 
1279  /*
1280  * Create a new, normalized query string if caller asked. We don't
1281  * need to hold the lock while doing this work. (Note: in any case,
1282  * it's possible that someone else creates a duplicate hashtable entry
1283  * in the interval where we don't hold the lock below. That case is
1284  * handled by entry_alloc.)
1285  */
1286  if (jstate)
1287  {
1289  norm_query = generate_normalized_query(jstate, query,
1290  query_location,
1291  &query_len);
1293  }
1294 
1295  /* Append new query text to file with only shared lock held */
1296  stored = qtext_store(norm_query ? norm_query : query, query_len,
1297  &query_offset, &gc_count);
1298 
1299  /*
1300  * Determine whether we need to garbage collect external query texts
1301  * while the shared lock is still held. This micro-optimization
1302  * avoids taking the time to decide this while holding exclusive lock.
1303  */
1304  do_gc = need_gc_qtexts();
1305 
1306  /* Need exclusive lock to make a new hashtable entry - promote */
1309 
1310  /*
1311  * A garbage collection may have occurred while we weren't holding the
1312  * lock. In the unlikely event that this happens, the query text we
1313  * stored above will have been garbage collected, so write it again.
1314  * This should be infrequent enough that doing it while holding
1315  * exclusive lock isn't a performance problem.
1316  */
1317  if (!stored || pgss->gc_count != gc_count)
1318  stored = qtext_store(norm_query ? norm_query : query, query_len,
1319  &query_offset, NULL);
1320 
1321  /* If we failed to write to the text file, give up */
1322  if (!stored)
1323  goto done;
1324 
1325  /* OK to create a new hashtable entry */
1326  entry = entry_alloc(&key, query_offset, query_len, encoding,
1327  jstate != NULL);
1328 
1329  /* If needed, perform garbage collection while exclusive lock held */
1330  if (do_gc)
1331  gc_qtexts();
1332  }
1333 
1334  /* Increment the counts, except when jstate is not NULL */
1335  if (!jstate)
1336  {
1337  /*
1338  * Grab the spinlock while updating the counters (see comment about
1339  * locking rules at the head of the file)
1340  */
1341  volatile pgssEntry *e = (volatile pgssEntry *) entry;
1342 
1343  Assert(kind == PGSS_PLAN || kind == PGSS_EXEC);
1344 
1345  SpinLockAcquire(&e->mutex);
1346 
1347  /* "Unstick" entry if it was previously sticky */
1348  if (IS_STICKY(e->counters))
1349  e->counters.usage = USAGE_INIT;
1350 
1351  e->counters.calls[kind] += 1;
1352  e->counters.total_time[kind] += total_time;
1353 
1354  if (e->counters.calls[kind] == 1)
1355  {
1356  e->counters.min_time[kind] = total_time;
1357  e->counters.max_time[kind] = total_time;
1358  e->counters.mean_time[kind] = total_time;
1359  }
1360  else
1361  {
1362  /*
1363  * Welford's method for accurately computing variance. See
1364  * <http://www.johndcook.com/blog/standard_deviation/>
1365  */
1366  double old_mean = e->counters.mean_time[kind];
1367 
1368  e->counters.mean_time[kind] +=
1369  (total_time - old_mean) / e->counters.calls[kind];
1370  e->counters.sum_var_time[kind] +=
1371  (total_time - old_mean) * (total_time - e->counters.mean_time[kind]);
1372 
1373  /* calculate min and max time */
1374  if (e->counters.min_time[kind] > total_time)
1375  e->counters.min_time[kind] = total_time;
1376  if (e->counters.max_time[kind] < total_time)
1377  e->counters.max_time[kind] = total_time;
1378  }
1379  e->counters.rows += rows;
1380  e->counters.shared_blks_hit += bufusage->shared_blks_hit;
1381  e->counters.shared_blks_read += bufusage->shared_blks_read;
1382  e->counters.shared_blks_dirtied += bufusage->shared_blks_dirtied;
1383  e->counters.shared_blks_written += bufusage->shared_blks_written;
1384  e->counters.local_blks_hit += bufusage->local_blks_hit;
1385  e->counters.local_blks_read += bufusage->local_blks_read;
1386  e->counters.local_blks_dirtied += bufusage->local_blks_dirtied;
1387  e->counters.local_blks_written += bufusage->local_blks_written;
1388  e->counters.temp_blks_read += bufusage->temp_blks_read;
1389  e->counters.temp_blks_written += bufusage->temp_blks_written;
1390  e->counters.blk_read_time += INSTR_TIME_GET_MILLISEC(bufusage->blk_read_time);
1391  e->counters.blk_write_time += INSTR_TIME_GET_MILLISEC(bufusage->blk_write_time);
1392  e->counters.temp_blk_read_time += INSTR_TIME_GET_MILLISEC(bufusage->temp_blk_read_time);
1393  e->counters.temp_blk_write_time += INSTR_TIME_GET_MILLISEC(bufusage->temp_blk_write_time);
1394  e->counters.usage += USAGE_EXEC(total_time);
1395  e->counters.wal_records += walusage->wal_records;
1396  e->counters.wal_fpi += walusage->wal_fpi;
1397  e->counters.wal_bytes += walusage->wal_bytes;
1398  if (jitusage)
1399  {
1400  e->counters.jit_functions += jitusage->created_functions;
1401  e->counters.jit_generation_time += INSTR_TIME_GET_MILLISEC(jitusage->generation_counter);
1402 
1404  e->counters.jit_inlining_count++;
1405  e->counters.jit_inlining_time += INSTR_TIME_GET_MILLISEC(jitusage->inlining_counter);
1406 
1408  e->counters.jit_optimization_count++;
1409  e->counters.jit_optimization_time += INSTR_TIME_GET_MILLISEC(jitusage->optimization_counter);
1410 
1412  e->counters.jit_emission_count++;
1413  e->counters.jit_emission_time += INSTR_TIME_GET_MILLISEC(jitusage->emission_counter);
1414  }
1415 
1416  SpinLockRelease(&e->mutex);
1417  }
1418 
1419 done:
1421 
1422  /* We postpone this clean-up until we're out of the lock */
1423  if (norm_query)
1424  pfree(norm_query);
1425 }
1426 
1427 /*
1428  * Reset statement statistics corresponding to userid, dbid, and queryid.
1429  */
1430 Datum
1432 {
1433  Oid userid;
1434  Oid dbid;
1435  uint64 queryid;
1436 
1437  userid = PG_GETARG_OID(0);
1438  dbid = PG_GETARG_OID(1);
1439  queryid = (uint64) PG_GETARG_INT64(2);
1440 
1441  entry_reset(userid, dbid, queryid);
1442 
1443  PG_RETURN_VOID();
1444 }
1445 
1446 /*
1447  * Reset statement statistics.
1448  */
1449 Datum
1451 {
1452  entry_reset(0, 0, 0);
1453 
1454  PG_RETURN_VOID();
1455 }
1456 
1457 /* Number of output arguments (columns) for various API versions */
1458 #define PG_STAT_STATEMENTS_COLS_V1_0 14
1459 #define PG_STAT_STATEMENTS_COLS_V1_1 18
1460 #define PG_STAT_STATEMENTS_COLS_V1_2 19
1461 #define PG_STAT_STATEMENTS_COLS_V1_3 23
1462 #define PG_STAT_STATEMENTS_COLS_V1_8 32
1463 #define PG_STAT_STATEMENTS_COLS_V1_9 33
1464 #define PG_STAT_STATEMENTS_COLS_V1_10 43
1465 #define PG_STAT_STATEMENTS_COLS 43 /* maximum of above */
1466 
1467 /*
1468  * Retrieve statement statistics.
1469  *
1470  * The SQL API of this function has changed multiple times, and will likely
1471  * do so again in future. To support the case where a newer version of this
1472  * loadable module is being used with an old SQL declaration of the function,
1473  * we continue to support the older API versions. For 1.2 and later, the
1474  * expected API version is identified by embedding it in the C name of the
1475  * function. Unfortunately we weren't bright enough to do that for 1.1.
1476  */
1477 Datum
1479 {
1480  bool showtext = PG_GETARG_BOOL(0);
1481 
1482  pg_stat_statements_internal(fcinfo, PGSS_V1_10, showtext);
1483 
1484  return (Datum) 0;
1485 }
1486 
1487 Datum
1489 {
1490  bool showtext = PG_GETARG_BOOL(0);
1491 
1492  pg_stat_statements_internal(fcinfo, PGSS_V1_9, showtext);
1493 
1494  return (Datum) 0;
1495 }
1496 
1497 Datum
1499 {
1500  bool showtext = PG_GETARG_BOOL(0);
1501 
1502  pg_stat_statements_internal(fcinfo, PGSS_V1_8, showtext);
1503 
1504  return (Datum) 0;
1505 }
1506 
1507 Datum
1509 {
1510  bool showtext = PG_GETARG_BOOL(0);
1511 
1512  pg_stat_statements_internal(fcinfo, PGSS_V1_3, showtext);
1513 
1514  return (Datum) 0;
1515 }
1516 
1517 Datum
1519 {
1520  bool showtext = PG_GETARG_BOOL(0);
1521 
1522  pg_stat_statements_internal(fcinfo, PGSS_V1_2, showtext);
1523 
1524  return (Datum) 0;
1525 }
1526 
1527 /*
1528  * Legacy entry point for pg_stat_statements() API versions 1.0 and 1.1.
1529  * This can be removed someday, perhaps.
1530  */
1531 Datum
1533 {
1534  /* If it's really API 1.1, we'll figure that out below */
1535  pg_stat_statements_internal(fcinfo, PGSS_V1_0, true);
1536 
1537  return (Datum) 0;
1538 }
1539 
1540 /* Common code for all versions of pg_stat_statements() */
1541 static void
1543  pgssVersion api_version,
1544  bool showtext)
1545 {
1546  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
1547  Oid userid = GetUserId();
1548  bool is_allowed_role = false;
1549  char *qbuffer = NULL;
1550  Size qbuffer_size = 0;
1551  Size extent = 0;
1552  int gc_count = 0;
1553  HASH_SEQ_STATUS hash_seq;
1554  pgssEntry *entry;
1555 
1556  /*
1557  * Superusers or roles with the privileges of pg_read_all_stats members
1558  * are allowed
1559  */
1560  is_allowed_role = has_privs_of_role(userid, ROLE_PG_READ_ALL_STATS);
1561 
1562  /* hash table must exist already */
1563  if (!pgss || !pgss_hash)
1564  ereport(ERROR,
1565  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1566  errmsg("pg_stat_statements must be loaded via shared_preload_libraries")));
1567 
1568  InitMaterializedSRF(fcinfo, 0);
1569 
1570  /*
1571  * Check we have the expected number of output arguments. Aside from
1572  * being a good safety check, we need a kluge here to detect API version
1573  * 1.1, which was wedged into the code in an ill-considered way.
1574  */
1575  switch (rsinfo->setDesc->natts)
1576  {
1578  if (api_version != PGSS_V1_0)
1579  elog(ERROR, "incorrect number of output arguments");
1580  break;
1582  /* pg_stat_statements() should have told us 1.0 */
1583  if (api_version != PGSS_V1_0)
1584  elog(ERROR, "incorrect number of output arguments");
1585  api_version = PGSS_V1_1;
1586  break;
1588  if (api_version != PGSS_V1_2)
1589  elog(ERROR, "incorrect number of output arguments");
1590  break;
1592  if (api_version != PGSS_V1_3)
1593  elog(ERROR, "incorrect number of output arguments");
1594  break;
1596  if (api_version != PGSS_V1_8)
1597  elog(ERROR, "incorrect number of output arguments");
1598  break;
1600  if (api_version != PGSS_V1_9)
1601  elog(ERROR, "incorrect number of output arguments");
1602  break;
1604  if (api_version != PGSS_V1_10)
1605  elog(ERROR, "incorrect number of output arguments");
1606  break;
1607  default:
1608  elog(ERROR, "incorrect number of output arguments");
1609  }
1610 
1611  /*
1612  * We'd like to load the query text file (if needed) while not holding any
1613  * lock on pgss->lock. In the worst case we'll have to do this again
1614  * after we have the lock, but it's unlikely enough to make this a win
1615  * despite occasional duplicated work. We need to reload if anybody
1616  * writes to the file (either a retail qtext_store(), or a garbage
1617  * collection) between this point and where we've gotten shared lock. If
1618  * a qtext_store is actually in progress when we look, we might as well
1619  * skip the speculative load entirely.
1620  */
1621  if (showtext)
1622  {
1623  int n_writers;
1624 
1625  /* Take the mutex so we can examine variables */
1626  {
1627  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
1628 
1629  SpinLockAcquire(&s->mutex);
1630  extent = s->extent;
1631  n_writers = s->n_writers;
1632  gc_count = s->gc_count;
1633  SpinLockRelease(&s->mutex);
1634  }
1635 
1636  /* No point in loading file now if there are active writers */
1637  if (n_writers == 0)
1638  qbuffer = qtext_load_file(&qbuffer_size);
1639  }
1640 
1641  /*
1642  * Get shared lock, load or reload the query text file if we must, and
1643  * iterate over the hashtable entries.
1644  *
1645  * With a large hash table, we might be holding the lock rather longer
1646  * than one could wish. However, this only blocks creation of new hash
1647  * table entries, and the larger the hash table the less likely that is to
1648  * be needed. So we can hope this is okay. Perhaps someday we'll decide
1649  * we need to partition the hash table to limit the time spent holding any
1650  * one lock.
1651  */
1653 
1654  if (showtext)
1655  {
1656  /*
1657  * Here it is safe to examine extent and gc_count without taking the
1658  * mutex. Note that although other processes might change
1659  * pgss->extent just after we look at it, the strings they then write
1660  * into the file cannot yet be referenced in the hashtable, so we
1661  * don't care whether we see them or not.
1662  *
1663  * If qtext_load_file fails, we just press on; we'll return NULL for
1664  * every query text.
1665  */
1666  if (qbuffer == NULL ||
1667  pgss->extent != extent ||
1668  pgss->gc_count != gc_count)
1669  {
1670  free(qbuffer);
1671  qbuffer = qtext_load_file(&qbuffer_size);
1672  }
1673  }
1674 
1675  hash_seq_init(&hash_seq, pgss_hash);
1676  while ((entry = hash_seq_search(&hash_seq)) != NULL)
1677  {
1679  bool nulls[PG_STAT_STATEMENTS_COLS];
1680  int i = 0;
1681  Counters tmp;
1682  double stddev;
1683  int64 queryid = entry->key.queryid;
1684 
1685  memset(values, 0, sizeof(values));
1686  memset(nulls, 0, sizeof(nulls));
1687 
1688  values[i++] = ObjectIdGetDatum(entry->key.userid);
1689  values[i++] = ObjectIdGetDatum(entry->key.dbid);
1690  if (api_version >= PGSS_V1_9)
1691  values[i++] = BoolGetDatum(entry->key.toplevel);
1692 
1693  if (is_allowed_role || entry->key.userid == userid)
1694  {
1695  if (api_version >= PGSS_V1_2)
1696  values[i++] = Int64GetDatumFast(queryid);
1697 
1698  if (showtext)
1699  {
1700  char *qstr = qtext_fetch(entry->query_offset,
1701  entry->query_len,
1702  qbuffer,
1703  qbuffer_size);
1704 
1705  if (qstr)
1706  {
1707  char *enc;
1708 
1709  enc = pg_any_to_server(qstr,
1710  entry->query_len,
1711  entry->encoding);
1712 
1714 
1715  if (enc != qstr)
1716  pfree(enc);
1717  }
1718  else
1719  {
1720  /* Just return a null if we fail to find the text */
1721  nulls[i++] = true;
1722  }
1723  }
1724  else
1725  {
1726  /* Query text not requested */
1727  nulls[i++] = true;
1728  }
1729  }
1730  else
1731  {
1732  /* Don't show queryid */
1733  if (api_version >= PGSS_V1_2)
1734  nulls[i++] = true;
1735 
1736  /*
1737  * Don't show query text, but hint as to the reason for not doing
1738  * so if it was requested
1739  */
1740  if (showtext)
1741  values[i++] = CStringGetTextDatum("<insufficient privilege>");
1742  else
1743  nulls[i++] = true;
1744  }
1745 
1746  /* copy counters to a local variable to keep locking time short */
1747  {
1748  volatile pgssEntry *e = (volatile pgssEntry *) entry;
1749 
1750  SpinLockAcquire(&e->mutex);
1751  tmp = e->counters;
1752  SpinLockRelease(&e->mutex);
1753  }
1754 
1755  /* Skip entry if unexecuted (ie, it's a pending "sticky" entry) */
1756  if (IS_STICKY(tmp))
1757  continue;
1758 
1759  /* Note that we rely on PGSS_PLAN being 0 and PGSS_EXEC being 1. */
1760  for (int kind = 0; kind < PGSS_NUMKIND; kind++)
1761  {
1762  if (kind == PGSS_EXEC || api_version >= PGSS_V1_8)
1763  {
1764  values[i++] = Int64GetDatumFast(tmp.calls[kind]);
1765  values[i++] = Float8GetDatumFast(tmp.total_time[kind]);
1766  }
1767 
1768  if ((kind == PGSS_EXEC && api_version >= PGSS_V1_3) ||
1769  api_version >= PGSS_V1_8)
1770  {
1771  values[i++] = Float8GetDatumFast(tmp.min_time[kind]);
1772  values[i++] = Float8GetDatumFast(tmp.max_time[kind]);
1773  values[i++] = Float8GetDatumFast(tmp.mean_time[kind]);
1774 
1775  /*
1776  * Note we are calculating the population variance here, not
1777  * the sample variance, as we have data for the whole
1778  * population, so Bessel's correction is not used, and we
1779  * don't divide by tmp.calls - 1.
1780  */
1781  if (tmp.calls[kind] > 1)
1782  stddev = sqrt(tmp.sum_var_time[kind] / tmp.calls[kind]);
1783  else
1784  stddev = 0.0;
1785  values[i++] = Float8GetDatumFast(stddev);
1786  }
1787  }
1788  values[i++] = Int64GetDatumFast(tmp.rows);
1791  if (api_version >= PGSS_V1_1)
1796  if (api_version >= PGSS_V1_1)
1801  if (api_version >= PGSS_V1_1)
1802  {
1805  }
1806  if (api_version >= PGSS_V1_10)
1807  {
1810  }
1811  if (api_version >= PGSS_V1_8)
1812  {
1813  char buf[256];
1814  Datum wal_bytes;
1815 
1817  values[i++] = Int64GetDatumFast(tmp.wal_fpi);
1818 
1819  snprintf(buf, sizeof buf, UINT64_FORMAT, tmp.wal_bytes);
1820 
1821  /* Convert to numeric. */
1822  wal_bytes = DirectFunctionCall3(numeric_in,
1824  ObjectIdGetDatum(0),
1825  Int32GetDatum(-1));
1826  values[i++] = wal_bytes;
1827  }
1828  if (api_version >= PGSS_V1_10)
1829  {
1838  }
1839 
1840  Assert(i == (api_version == PGSS_V1_0 ? PG_STAT_STATEMENTS_COLS_V1_0 :
1841  api_version == PGSS_V1_1 ? PG_STAT_STATEMENTS_COLS_V1_1 :
1842  api_version == PGSS_V1_2 ? PG_STAT_STATEMENTS_COLS_V1_2 :
1843  api_version == PGSS_V1_3 ? PG_STAT_STATEMENTS_COLS_V1_3 :
1844  api_version == PGSS_V1_8 ? PG_STAT_STATEMENTS_COLS_V1_8 :
1845  api_version == PGSS_V1_9 ? PG_STAT_STATEMENTS_COLS_V1_9 :
1846  api_version == PGSS_V1_10 ? PG_STAT_STATEMENTS_COLS_V1_10 :
1847  -1 /* fail if you forget to update this assert */ ));
1848 
1849  tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls);
1850  }
1851 
1853 
1854  free(qbuffer);
1855 }
1856 
1857 /* Number of output arguments (columns) for pg_stat_statements_info */
1858 #define PG_STAT_STATEMENTS_INFO_COLS 2
1859 
1860 /*
1861  * Return statistics of pg_stat_statements.
1862  */
1863 Datum
1865 {
1866  pgssGlobalStats stats;
1867  TupleDesc tupdesc;
1869  bool nulls[PG_STAT_STATEMENTS_INFO_COLS] = {0};
1870 
1871  if (!pgss || !pgss_hash)
1872  ereport(ERROR,
1873  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1874  errmsg("pg_stat_statements must be loaded via shared_preload_libraries")));
1875 
1876  /* Build a tuple descriptor for our result type */
1877  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
1878  elog(ERROR, "return type must be a row type");
1879 
1880  /* Read global statistics for pg_stat_statements */
1881  {
1882  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
1883 
1884  SpinLockAcquire(&s->mutex);
1885  stats = s->stats;
1886  SpinLockRelease(&s->mutex);
1887  }
1888 
1889  values[0] = Int64GetDatum(stats.dealloc);
1891 
1893 }
1894 
1895 /*
1896  * Estimate shared memory space needed.
1897  */
1898 static Size
1900 {
1901  Size size;
1902 
1903  size = MAXALIGN(sizeof(pgssSharedState));
1904  size = add_size(size, hash_estimate_size(pgss_max, sizeof(pgssEntry)));
1905 
1906  return size;
1907 }
1908 
1909 /*
1910  * Allocate a new hashtable entry.
1911  * caller must hold an exclusive lock on pgss->lock
1912  *
1913  * "query" need not be null-terminated; we rely on query_len instead
1914  *
1915  * If "sticky" is true, make the new entry artificially sticky so that it will
1916  * probably still be there when the query finishes execution. We do this by
1917  * giving it a median usage value rather than the normal value. (Strictly
1918  * speaking, query strings are normalized on a best effort basis, though it
1919  * would be difficult to demonstrate this even under artificial conditions.)
1920  *
1921  * Note: despite needing exclusive lock, it's not an error for the target
1922  * entry to already exist. This is because pgss_store releases and
1923  * reacquires lock after failing to find a match; so someone else could
1924  * have made the entry while we waited to get exclusive lock.
1925  */
1926 static pgssEntry *
1927 entry_alloc(pgssHashKey *key, Size query_offset, int query_len, int encoding,
1928  bool sticky)
1929 {
1930  pgssEntry *entry;
1931  bool found;
1932 
1933  /* Make space if needed */
1935  entry_dealloc();
1936 
1937  /* Find or create an entry with desired hash code */
1938  entry = (pgssEntry *) hash_search(pgss_hash, key, HASH_ENTER, &found);
1939 
1940  if (!found)
1941  {
1942  /* New entry, initialize it */
1943 
1944  /* reset the statistics */
1945  memset(&entry->counters, 0, sizeof(Counters));
1946  /* set the appropriate initial usage count */
1947  entry->counters.usage = sticky ? pgss->cur_median_usage : USAGE_INIT;
1948  /* re-initialize the mutex each time ... we assume no one using it */
1949  SpinLockInit(&entry->mutex);
1950  /* ... and don't forget the query text metadata */
1951  Assert(query_len >= 0);
1952  entry->query_offset = query_offset;
1953  entry->query_len = query_len;
1954  entry->encoding = encoding;
1955  }
1956 
1957  return entry;
1958 }
1959 
1960 /*
1961  * qsort comparator for sorting into increasing usage order
1962  */
1963 static int
1964 entry_cmp(const void *lhs, const void *rhs)
1965 {
1966  double l_usage = (*(pgssEntry *const *) lhs)->counters.usage;
1967  double r_usage = (*(pgssEntry *const *) rhs)->counters.usage;
1968 
1969  if (l_usage < r_usage)
1970  return -1;
1971  else if (l_usage > r_usage)
1972  return +1;
1973  else
1974  return 0;
1975 }
1976 
1977 /*
1978  * Deallocate least-used entries.
1979  *
1980  * Caller must hold an exclusive lock on pgss->lock.
1981  */
1982 static void
1984 {
1985  HASH_SEQ_STATUS hash_seq;
1986  pgssEntry **entries;
1987  pgssEntry *entry;
1988  int nvictims;
1989  int i;
1990  Size tottextlen;
1991  int nvalidtexts;
1992 
1993  /*
1994  * Sort entries by usage and deallocate USAGE_DEALLOC_PERCENT of them.
1995  * While we're scanning the table, apply the decay factor to the usage
1996  * values, and update the mean query length.
1997  *
1998  * Note that the mean query length is almost immediately obsolete, since
1999  * we compute it before not after discarding the least-used entries.
2000  * Hopefully, that doesn't affect the mean too much; it doesn't seem worth
2001  * making two passes to get a more current result. Likewise, the new
2002  * cur_median_usage includes the entries we're about to zap.
2003  */
2004 
2005  entries = palloc(hash_get_num_entries(pgss_hash) * sizeof(pgssEntry *));
2006 
2007  i = 0;
2008  tottextlen = 0;
2009  nvalidtexts = 0;
2010 
2011  hash_seq_init(&hash_seq, pgss_hash);
2012  while ((entry = hash_seq_search(&hash_seq)) != NULL)
2013  {
2014  entries[i++] = entry;
2015  /* "Sticky" entries get a different usage decay rate. */
2016  if (IS_STICKY(entry->counters))
2018  else
2020  /* In the mean length computation, ignore dropped texts. */
2021  if (entry->query_len >= 0)
2022  {
2023  tottextlen += entry->query_len + 1;
2024  nvalidtexts++;
2025  }
2026  }
2027 
2028  /* Sort into increasing order by usage */
2029  qsort(entries, i, sizeof(pgssEntry *), entry_cmp);
2030 
2031  /* Record the (approximate) median usage */
2032  if (i > 0)
2033  pgss->cur_median_usage = entries[i / 2]->counters.usage;
2034  /* Record the mean query length */
2035  if (nvalidtexts > 0)
2036  pgss->mean_query_len = tottextlen / nvalidtexts;
2037  else
2039 
2040  /* Now zap an appropriate fraction of lowest-usage entries */
2041  nvictims = Max(10, i * USAGE_DEALLOC_PERCENT / 100);
2042  nvictims = Min(nvictims, i);
2043 
2044  for (i = 0; i < nvictims; i++)
2045  {
2046  hash_search(pgss_hash, &entries[i]->key, HASH_REMOVE, NULL);
2047  }
2048 
2049  pfree(entries);
2050 
2051  /* Increment the number of times entries are deallocated */
2052  {
2053  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
2054 
2055  SpinLockAcquire(&s->mutex);
2056  s->stats.dealloc += 1;
2057  SpinLockRelease(&s->mutex);
2058  }
2059 }
2060 
2061 /*
2062  * Given a query string (not necessarily null-terminated), allocate a new
2063  * entry in the external query text file and store the string there.
2064  *
2065  * If successful, returns true, and stores the new entry's offset in the file
2066  * into *query_offset. Also, if gc_count isn't NULL, *gc_count is set to the
2067  * number of garbage collections that have occurred so far.
2068  *
2069  * On failure, returns false.
2070  *
2071  * At least a shared lock on pgss->lock must be held by the caller, so as
2072  * to prevent a concurrent garbage collection. Share-lock-holding callers
2073  * should pass a gc_count pointer to obtain the number of garbage collections,
2074  * so that they can recheck the count after obtaining exclusive lock to
2075  * detect whether a garbage collection occurred (and removed this entry).
2076  */
2077 static bool
2078 qtext_store(const char *query, int query_len,
2079  Size *query_offset, int *gc_count)
2080 {
2081  Size off;
2082  int fd;
2083 
2084  /*
2085  * We use a spinlock to protect extent/n_writers/gc_count, so that
2086  * multiple processes may execute this function concurrently.
2087  */
2088  {
2089  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
2090 
2091  SpinLockAcquire(&s->mutex);
2092  off = s->extent;
2093  s->extent += query_len + 1;
2094  s->n_writers++;
2095  if (gc_count)
2096  *gc_count = s->gc_count;
2097  SpinLockRelease(&s->mutex);
2098  }
2099 
2100  *query_offset = off;
2101 
2102  /*
2103  * Don't allow the file to grow larger than what qtext_load_file can
2104  * (theoretically) handle. This has been seen to be reachable on 32-bit
2105  * platforms.
2106  */
2107  if (unlikely(query_len >= MaxAllocHugeSize - off))
2108  {
2109  errno = EFBIG; /* not quite right, but it'll do */
2110  fd = -1;
2111  goto error;
2112  }
2113 
2114  /* Now write the data into the successfully-reserved part of the file */
2115  fd = OpenTransientFile(PGSS_TEXT_FILE, O_RDWR | O_CREAT | PG_BINARY);
2116  if (fd < 0)
2117  goto error;
2118 
2119  if (pg_pwrite(fd, query, query_len, off) != query_len)
2120  goto error;
2121  if (pg_pwrite(fd, "\0", 1, off + query_len) != 1)
2122  goto error;
2123 
2125 
2126  /* Mark our write complete */
2127  {
2128  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
2129 
2130  SpinLockAcquire(&s->mutex);
2131  s->n_writers--;
2132  SpinLockRelease(&s->mutex);
2133  }
2134 
2135  return true;
2136 
2137 error:
2138  ereport(LOG,
2140  errmsg("could not write file \"%s\": %m",
2141  PGSS_TEXT_FILE)));
2142 
2143  if (fd >= 0)
2145 
2146  /* Mark our write complete */
2147  {
2148  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
2149 
2150  SpinLockAcquire(&s->mutex);
2151  s->n_writers--;
2152  SpinLockRelease(&s->mutex);
2153  }
2154 
2155  return false;
2156 }
2157 
2158 /*
2159  * Read the external query text file into a malloc'd buffer.
2160  *
2161  * Returns NULL (without throwing an error) if unable to read, eg
2162  * file not there or insufficient memory.
2163  *
2164  * On success, the buffer size is also returned into *buffer_size.
2165  *
2166  * This can be called without any lock on pgss->lock, but in that case
2167  * the caller is responsible for verifying that the result is sane.
2168  */
2169 static char *
2170 qtext_load_file(Size *buffer_size)
2171 {
2172  char *buf;
2173  int fd;
2174  struct stat stat;
2175  Size nread;
2176 
2178  if (fd < 0)
2179  {
2180  if (errno != ENOENT)
2181  ereport(LOG,
2183  errmsg("could not read file \"%s\": %m",
2184  PGSS_TEXT_FILE)));
2185  return NULL;
2186  }
2187 
2188  /* Get file length */
2189  if (fstat(fd, &stat))
2190  {
2191  ereport(LOG,
2193  errmsg("could not stat file \"%s\": %m",
2194  PGSS_TEXT_FILE)));
2196  return NULL;
2197  }
2198 
2199  /* Allocate buffer; beware that off_t might be wider than size_t */
2200  if (stat.st_size <= MaxAllocHugeSize)
2201  buf = (char *) malloc(stat.st_size);
2202  else
2203  buf = NULL;
2204  if (buf == NULL)
2205  {
2206  ereport(LOG,
2207  (errcode(ERRCODE_OUT_OF_MEMORY),
2208  errmsg("out of memory"),
2209  errdetail("Could not allocate enough memory to read file \"%s\".",
2210  PGSS_TEXT_FILE)));
2212  return NULL;
2213  }
2214 
2215  /*
2216  * OK, slurp in the file. Windows fails if we try to read more than
2217  * INT_MAX bytes at once, and other platforms might not like that either,
2218  * so read a very large file in 1GB segments.
2219  */
2220  nread = 0;
2221  while (nread < stat.st_size)
2222  {
2223  int toread = Min(1024 * 1024 * 1024, stat.st_size - nread);
2224 
2225  /*
2226  * If we get a short read and errno doesn't get set, the reason is
2227  * probably that garbage collection truncated the file since we did
2228  * the fstat(), so we don't log a complaint --- but we don't return
2229  * the data, either, since it's most likely corrupt due to concurrent
2230  * writes from garbage collection.
2231  */
2232  errno = 0;
2233  if (read(fd, buf + nread, toread) != toread)
2234  {
2235  if (errno)
2236  ereport(LOG,
2238  errmsg("could not read file \"%s\": %m",
2239  PGSS_TEXT_FILE)));
2240  free(buf);
2242  return NULL;
2243  }
2244  nread += toread;
2245  }
2246 
2247  if (CloseTransientFile(fd) != 0)
2248  ereport(LOG,
2250  errmsg("could not close file \"%s\": %m", PGSS_TEXT_FILE)));
2251 
2252  *buffer_size = nread;
2253  return buf;
2254 }
2255 
2256 /*
2257  * Locate a query text in the file image previously read by qtext_load_file().
2258  *
2259  * We validate the given offset/length, and return NULL if bogus. Otherwise,
2260  * the result points to a null-terminated string within the buffer.
2261  */
2262 static char *
2263 qtext_fetch(Size query_offset, int query_len,
2264  char *buffer, Size buffer_size)
2265 {
2266  /* File read failed? */
2267  if (buffer == NULL)
2268  return NULL;
2269  /* Bogus offset/length? */
2270  if (query_len < 0 ||
2271  query_offset + query_len >= buffer_size)
2272  return NULL;
2273  /* As a further sanity check, make sure there's a trailing null */
2274  if (buffer[query_offset + query_len] != '\0')
2275  return NULL;
2276  /* Looks OK */
2277  return buffer + query_offset;
2278 }
2279 
2280 /*
2281  * Do we need to garbage-collect the external query text file?
2282  *
2283  * Caller should hold at least a shared lock on pgss->lock.
2284  */
2285 static bool
2287 {
2288  Size extent;
2289 
2290  /* Read shared extent pointer */
2291  {
2292  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
2293 
2294  SpinLockAcquire(&s->mutex);
2295  extent = s->extent;
2296  SpinLockRelease(&s->mutex);
2297  }
2298 
2299  /*
2300  * Don't proceed if file does not exceed 512 bytes per possible entry.
2301  *
2302  * Here and in the next test, 32-bit machines have overflow hazards if
2303  * pgss_max and/or mean_query_len are large. Force the multiplications
2304  * and comparisons to be done in uint64 arithmetic to forestall trouble.
2305  */
2306  if ((uint64) extent < (uint64) 512 * pgss_max)
2307  return false;
2308 
2309  /*
2310  * Don't proceed if file is less than about 50% bloat. Nothing can or
2311  * should be done in the event of unusually large query texts accounting
2312  * for file's large size. We go to the trouble of maintaining the mean
2313  * query length in order to prevent garbage collection from thrashing
2314  * uselessly.
2315  */
2316  if ((uint64) extent < (uint64) pgss->mean_query_len * pgss_max * 2)
2317  return false;
2318 
2319  return true;
2320 }
2321 
2322 /*
2323  * Garbage-collect orphaned query texts in external file.
2324  *
2325  * This won't be called often in the typical case, since it's likely that
2326  * there won't be too much churn, and besides, a similar compaction process
2327  * occurs when serializing to disk at shutdown or as part of resetting.
2328  * Despite this, it seems prudent to plan for the edge case where the file
2329  * becomes unreasonably large, with no other method of compaction likely to
2330  * occur in the foreseeable future.
2331  *
2332  * The caller must hold an exclusive lock on pgss->lock.
2333  *
2334  * At the first sign of trouble we unlink the query text file to get a clean
2335  * slate (although existing statistics are retained), rather than risk
2336  * thrashing by allowing the same problem case to recur indefinitely.
2337  */
2338 static void
2340 {
2341  char *qbuffer;
2342  Size qbuffer_size;
2343  FILE *qfile = NULL;
2344  HASH_SEQ_STATUS hash_seq;
2345  pgssEntry *entry;
2346  Size extent;
2347  int nentries;
2348 
2349  /*
2350  * When called from pgss_store, some other session might have proceeded
2351  * with garbage collection in the no-lock-held interim of lock strength
2352  * escalation. Check once more that this is actually necessary.
2353  */
2354  if (!need_gc_qtexts())
2355  return;
2356 
2357  /*
2358  * Load the old texts file. If we fail (out of memory, for instance),
2359  * invalidate query texts. Hopefully this is rare. It might seem better
2360  * to leave things alone on an OOM failure, but the problem is that the
2361  * file is only going to get bigger; hoping for a future non-OOM result is
2362  * risky and can easily lead to complete denial of service.
2363  */
2364  qbuffer = qtext_load_file(&qbuffer_size);
2365  if (qbuffer == NULL)
2366  goto gc_fail;
2367 
2368  /*
2369  * We overwrite the query texts file in place, so as to reduce the risk of
2370  * an out-of-disk-space failure. Since the file is guaranteed not to get
2371  * larger, this should always work on traditional filesystems; though we
2372  * could still lose on copy-on-write filesystems.
2373  */
2375  if (qfile == NULL)
2376  {
2377  ereport(LOG,
2379  errmsg("could not write file \"%s\": %m",
2380  PGSS_TEXT_FILE)));
2381  goto gc_fail;
2382  }
2383 
2384  extent = 0;
2385  nentries = 0;
2386 
2387  hash_seq_init(&hash_seq, pgss_hash);
2388  while ((entry = hash_seq_search(&hash_seq)) != NULL)
2389  {
2390  int query_len = entry->query_len;
2391  char *qry = qtext_fetch(entry->query_offset,
2392  query_len,
2393  qbuffer,
2394  qbuffer_size);
2395 
2396  if (qry == NULL)
2397  {
2398  /* Trouble ... drop the text */
2399  entry->query_offset = 0;
2400  entry->query_len = -1;
2401  /* entry will not be counted in mean query length computation */
2402  continue;
2403  }
2404 
2405  if (fwrite(qry, 1, query_len + 1, qfile) != query_len + 1)
2406  {
2407  ereport(LOG,
2409  errmsg("could not write file \"%s\": %m",
2410  PGSS_TEXT_FILE)));
2411  hash_seq_term(&hash_seq);
2412  goto gc_fail;
2413  }
2414 
2415  entry->query_offset = extent;
2416  extent += query_len + 1;
2417  nentries++;
2418  }
2419 
2420  /*
2421  * Truncate away any now-unused space. If this fails for some odd reason,
2422  * we log it, but there's no need to fail.
2423  */
2424  if (ftruncate(fileno(qfile), extent) != 0)
2425  ereport(LOG,
2427  errmsg("could not truncate file \"%s\": %m",
2428  PGSS_TEXT_FILE)));
2429 
2430  if (FreeFile(qfile))
2431  {
2432  ereport(LOG,
2434  errmsg("could not write file \"%s\": %m",
2435  PGSS_TEXT_FILE)));
2436  qfile = NULL;
2437  goto gc_fail;
2438  }
2439 
2440  elog(DEBUG1, "pgss gc of queries file shrunk size from %zu to %zu",
2441  pgss->extent, extent);
2442 
2443  /* Reset the shared extent pointer */
2444  pgss->extent = extent;
2445 
2446  /*
2447  * Also update the mean query length, to be sure that need_gc_qtexts()
2448  * won't still think we have a problem.
2449  */
2450  if (nentries > 0)
2451  pgss->mean_query_len = extent / nentries;
2452  else
2454 
2455  free(qbuffer);
2456 
2457  /*
2458  * OK, count a garbage collection cycle. (Note: even though we have
2459  * exclusive lock on pgss->lock, we must take pgss->mutex for this, since
2460  * other processes may examine gc_count while holding only the mutex.
2461  * Also, we have to advance the count *after* we've rewritten the file,
2462  * else other processes might not realize they read a stale file.)
2463  */
2464  record_gc_qtexts();
2465 
2466  return;
2467 
2468 gc_fail:
2469  /* clean up resources */
2470  if (qfile)
2471  FreeFile(qfile);
2472  free(qbuffer);
2473 
2474  /*
2475  * Since the contents of the external file are now uncertain, mark all
2476  * hashtable entries as having invalid texts.
2477  */
2478  hash_seq_init(&hash_seq, pgss_hash);
2479  while ((entry = hash_seq_search(&hash_seq)) != NULL)
2480  {
2481  entry->query_offset = 0;
2482  entry->query_len = -1;
2483  }
2484 
2485  /*
2486  * Destroy the query text file and create a new, empty one
2487  */
2488  (void) unlink(PGSS_TEXT_FILE);
2490  if (qfile == NULL)
2491  ereport(LOG,
2493  errmsg("could not recreate file \"%s\": %m",
2494  PGSS_TEXT_FILE)));
2495  else
2496  FreeFile(qfile);
2497 
2498  /* Reset the shared extent pointer */
2499  pgss->extent = 0;
2500 
2501  /* Reset mean_query_len to match the new state */
2503 
2504  /*
2505  * Bump the GC count even though we failed.
2506  *
2507  * This is needed to make concurrent readers of file without any lock on
2508  * pgss->lock notice existence of new version of file. Once readers
2509  * subsequently observe a change in GC count with pgss->lock held, that
2510  * forces a safe reopen of file. Writers also require that we bump here,
2511  * of course. (As required by locking protocol, readers and writers don't
2512  * trust earlier file contents until gc_count is found unchanged after
2513  * pgss->lock acquired in shared or exclusive mode respectively.)
2514  */
2515  record_gc_qtexts();
2516 }
2517 
2518 /*
2519  * Release entries corresponding to parameters passed.
2520  */
2521 static void
2522 entry_reset(Oid userid, Oid dbid, uint64 queryid)
2523 {
2524  HASH_SEQ_STATUS hash_seq;
2525  pgssEntry *entry;
2526  FILE *qfile;
2527  long num_entries;
2528  long num_remove = 0;
2529  pgssHashKey key;
2530 
2531  if (!pgss || !pgss_hash)
2532  ereport(ERROR,
2533  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2534  errmsg("pg_stat_statements must be loaded via shared_preload_libraries")));
2535 
2537  num_entries = hash_get_num_entries(pgss_hash);
2538 
2539  if (userid != 0 && dbid != 0 && queryid != UINT64CONST(0))
2540  {
2541  /* If all the parameters are available, use the fast path. */
2542  memset(&key, 0, sizeof(pgssHashKey));
2543  key.userid = userid;
2544  key.dbid = dbid;
2545  key.queryid = queryid;
2546 
2547  /* Remove the key if it exists, starting with the top-level entry */
2548  key.toplevel = false;
2549  entry = (pgssEntry *) hash_search(pgss_hash, &key, HASH_REMOVE, NULL);
2550  if (entry) /* found */
2551  num_remove++;
2552 
2553  /* Also remove entries for top level statements */
2554  key.toplevel = true;
2555 
2556  /* Remove the key if exists */
2557  entry = (pgssEntry *) hash_search(pgss_hash, &key, HASH_REMOVE, NULL);
2558  if (entry) /* found */
2559  num_remove++;
2560  }
2561  else if (userid != 0 || dbid != 0 || queryid != UINT64CONST(0))
2562  {
2563  /* Remove entries corresponding to valid parameters. */
2564  hash_seq_init(&hash_seq, pgss_hash);
2565  while ((entry = hash_seq_search(&hash_seq)) != NULL)
2566  {
2567  if ((!userid || entry->key.userid == userid) &&
2568  (!dbid || entry->key.dbid == dbid) &&
2569  (!queryid || entry->key.queryid == queryid))
2570  {
2571  hash_search(pgss_hash, &entry->key, HASH_REMOVE, NULL);
2572  num_remove++;
2573  }
2574  }
2575  }
2576  else
2577  {
2578  /* Remove all entries. */
2579  hash_seq_init(&hash_seq, pgss_hash);
2580  while ((entry = hash_seq_search(&hash_seq)) != NULL)
2581  {
2582  hash_search(pgss_hash, &entry->key, HASH_REMOVE, NULL);
2583  num_remove++;
2584  }
2585  }
2586 
2587  /* All entries are removed? */
2588  if (num_entries != num_remove)
2589  goto release_lock;
2590 
2591  /*
2592  * Reset global statistics for pg_stat_statements since all entries are
2593  * removed.
2594  */
2595  {
2596  volatile pgssSharedState *s = (volatile pgssSharedState *) pgss;
2597  TimestampTz stats_reset = GetCurrentTimestamp();
2598 
2599  SpinLockAcquire(&s->mutex);
2600  s->stats.dealloc = 0;
2601  s->stats.stats_reset = stats_reset;
2602  SpinLockRelease(&s->mutex);
2603  }
2604 
2605  /*
2606  * Write new empty query file, perhaps even creating a new one to recover
2607  * if the file was missing.
2608  */
2610  if (qfile == NULL)
2611  {
2612  ereport(LOG,
2614  errmsg("could not create file \"%s\": %m",
2615  PGSS_TEXT_FILE)));
2616  goto done;
2617  }
2618 
2619  /* If ftruncate fails, log it, but it's not a fatal problem */
2620  if (ftruncate(fileno(qfile), 0) != 0)
2621  ereport(LOG,
2623  errmsg("could not truncate file \"%s\": %m",
2624  PGSS_TEXT_FILE)));
2625 
2626  FreeFile(qfile);
2627 
2628 done:
2629  pgss->extent = 0;
2630  /* This counts as a query text garbage collection for our purposes */
2631  record_gc_qtexts();
2632 
2633 release_lock:
2635 }
2636 
2637 /*
2638  * Generate a normalized version of the query string that will be used to
2639  * represent all similar queries.
2640  *
2641  * Note that the normalized representation may well vary depending on
2642  * just which "equivalent" query is used to create the hashtable entry.
2643  * We assume this is OK.
2644  *
2645  * If query_loc > 0, then "query" has been advanced by that much compared to
2646  * the original string start, so we need to translate the provided locations
2647  * to compensate. (This lets us avoid re-scanning statements before the one
2648  * of interest, so it's worth doing.)
2649  *
2650  * *query_len_p contains the input string length, and is updated with
2651  * the result string length on exit. The resulting string might be longer
2652  * or shorter depending on what happens with replacement of constants.
2653  *
2654  * Returns a palloc'd string.
2655  */
2656 static char *
2657 generate_normalized_query(JumbleState *jstate, const char *query,
2658  int query_loc, int *query_len_p)
2659 {
2660  char *norm_query;
2661  int query_len = *query_len_p;
2662  int i,
2663  norm_query_buflen, /* Space allowed for norm_query */
2664  len_to_wrt, /* Length (in bytes) to write */
2665  quer_loc = 0, /* Source query byte location */
2666  n_quer_loc = 0, /* Normalized query byte location */
2667  last_off = 0, /* Offset from start for previous tok */
2668  last_tok_len = 0; /* Length (in bytes) of that tok */
2669 
2670  /*
2671  * Get constants' lengths (core system only gives us locations). Note
2672  * this also ensures the items are sorted by location.
2673  */
2674  fill_in_constant_lengths(jstate, query, query_loc);
2675 
2676  /*
2677  * Allow for $n symbols to be longer than the constants they replace.
2678  * Constants must take at least one byte in text form, while a $n symbol
2679  * certainly isn't more than 11 bytes, even if n reaches INT_MAX. We
2680  * could refine that limit based on the max value of n for the current
2681  * query, but it hardly seems worth any extra effort to do so.
2682  */
2683  norm_query_buflen = query_len + jstate->clocations_count * 10;
2684 
2685  /* Allocate result buffer */
2686  norm_query = palloc(norm_query_buflen + 1);
2687 
2688  for (i = 0; i < jstate->clocations_count; i++)
2689  {
2690  int off, /* Offset from start for cur tok */
2691  tok_len; /* Length (in bytes) of that tok */
2692 
2693  off = jstate->clocations[i].location;
2694  /* Adjust recorded location if we're dealing with partial string */
2695  off -= query_loc;
2696 
2697  tok_len = jstate->clocations[i].length;
2698 
2699  if (tok_len < 0)
2700  continue; /* ignore any duplicates */
2701 
2702  /* Copy next chunk (what precedes the next constant) */
2703  len_to_wrt = off - last_off;
2704  len_to_wrt -= last_tok_len;
2705 
2706  Assert(len_to_wrt >= 0);
2707  memcpy(norm_query + n_quer_loc, query + quer_loc, len_to_wrt);
2708  n_quer_loc += len_to_wrt;
2709 
2710  /* And insert a param symbol in place of the constant token */
2711  n_quer_loc += sprintf(norm_query + n_quer_loc, "$%d",
2712  i + 1 + jstate->highest_extern_param_id);
2713 
2714  quer_loc = off + tok_len;
2715  last_off = off;
2716  last_tok_len = tok_len;
2717  }
2718 
2719  /*
2720  * We've copied up until the last ignorable constant. Copy over the
2721  * remaining bytes of the original query string.
2722  */
2723  len_to_wrt = query_len - quer_loc;
2724 
2725  Assert(len_to_wrt >= 0);
2726  memcpy(norm_query + n_quer_loc, query + quer_loc, len_to_wrt);
2727  n_quer_loc += len_to_wrt;
2728 
2729  Assert(n_quer_loc <= norm_query_buflen);
2730  norm_query[n_quer_loc] = '\0';
2731 
2732  *query_len_p = n_quer_loc;
2733  return norm_query;
2734 }
2735 
2736 /*
2737  * Given a valid SQL string and an array of constant-location records,
2738  * fill in the textual lengths of those constants.
2739  *
2740  * The constants may use any allowed constant syntax, such as float literals,
2741  * bit-strings, single-quoted strings and dollar-quoted strings. This is
2742  * accomplished by using the public API for the core scanner.
2743  *
2744  * It is the caller's job to ensure that the string is a valid SQL statement
2745  * with constants at the indicated locations. Since in practice the string
2746  * has already been parsed, and the locations that the caller provides will
2747  * have originated from within the authoritative parser, this should not be
2748  * a problem.
2749  *
2750  * Duplicate constant pointers are possible, and will have their lengths
2751  * marked as '-1', so that they are later ignored. (Actually, we assume the
2752  * lengths were initialized as -1 to start with, and don't change them here.)
2753  *
2754  * If query_loc > 0, then "query" has been advanced by that much compared to
2755  * the original string start, so we need to translate the provided locations
2756  * to compensate. (This lets us avoid re-scanning statements before the one
2757  * of interest, so it's worth doing.)
2758  *
2759  * N.B. There is an assumption that a '-' character at a Const location begins
2760  * a negative numeric constant. This precludes there ever being another
2761  * reason for a constant to start with a '-'.
2762  */
2763 static void
2764 fill_in_constant_lengths(JumbleState *jstate, const char *query,
2765  int query_loc)
2766 {
2767  LocationLen *locs;
2769  core_yy_extra_type yyextra;
2770  core_YYSTYPE yylval;
2771  YYLTYPE yylloc;
2772  int last_loc = -1;
2773  int i;
2774 
2775  /*
2776  * Sort the records by location so that we can process them in order while
2777  * scanning the query text.
2778  */
2779  if (jstate->clocations_count > 1)
2780  qsort(jstate->clocations, jstate->clocations_count,
2781  sizeof(LocationLen), comp_location);
2782  locs = jstate->clocations;
2783 
2784  /* initialize the flex scanner --- should match raw_parser() */
2785  yyscanner = scanner_init(query,
2786  &yyextra,
2787  &ScanKeywords,
2789 
2790  /* we don't want to re-emit any escape string warnings */
2791  yyextra.escape_string_warning = false;
2792 
2793  /* Search for each constant, in sequence */
2794  for (i = 0; i < jstate->clocations_count; i++)
2795  {
2796  int loc = locs[i].location;
2797  int tok;
2798 
2799  /* Adjust recorded location if we're dealing with partial string */
2800  loc -= query_loc;
2801 
2802  Assert(loc >= 0);
2803 
2804  if (loc <= last_loc)
2805  continue; /* Duplicate constant, ignore */
2806 
2807  /* Lex tokens until we find the desired constant */
2808  for (;;)
2809  {
2810  tok = core_yylex(&yylval, &yylloc, yyscanner);
2811 
2812  /* We should not hit end-of-string, but if we do, behave sanely */
2813  if (tok == 0)
2814  break; /* out of inner for-loop */
2815 
2816  /*
2817  * We should find the token position exactly, but if we somehow
2818  * run past it, work with that.
2819  */
2820  if (yylloc >= loc)
2821  {
2822  if (query[loc] == '-')
2823  {
2824  /*
2825  * It's a negative value - this is the one and only case
2826  * where we replace more than a single token.
2827  *
2828  * Do not compensate for the core system's special-case
2829  * adjustment of location to that of the leading '-'
2830  * operator in the event of a negative constant. It is
2831  * also useful for our purposes to start from the minus
2832  * symbol. In this way, queries like "select * from foo
2833  * where bar = 1" and "select * from foo where bar = -2"
2834  * will have identical normalized query strings.
2835  */
2836  tok = core_yylex(&yylval, &yylloc, yyscanner);
2837  if (tok == 0)
2838  break; /* out of inner for-loop */
2839  }
2840 
2841  /*
2842  * We now rely on the assumption that flex has placed a zero
2843  * byte after the text of the current token in scanbuf.
2844  */
2845  locs[i].length = strlen(yyextra.scanbuf + loc);
2846  break; /* out of inner for-loop */
2847  }
2848  }
2849 
2850  /* If we hit end-of-string, give up, leaving remaining lengths -1 */
2851  if (tok == 0)
2852  break;
2853 
2854  last_loc = loc;
2855  }
2856 
2858 }
2859 
2860 /*
2861  * comp_location: comparator for qsorting LocationLen structs by location
2862  */
2863 static int
2864 comp_location(const void *a, const void *b)
2865 {
2866  int l = ((const LocationLen *) a)->location;
2867  int r = ((const LocationLen *) b)->location;
2868 
2869  if (l < r)
2870  return -1;
2871  else if (l > r)
2872  return +1;
2873  else
2874  return 0;
2875 }
bool has_privs_of_role(Oid member, Oid role)
Definition: acl.c:4933
void(* post_parse_analyze_hook_type)(ParseState *pstate, Query *query, JumbleState *jstate)
Definition: analyze.h:22
Datum numeric_in(PG_FUNCTION_ARGS)
Definition: numeric.c:617
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1573
static Datum values[MAXATTR]
Definition: bootstrap.c:156
#define CStringGetTextDatum(s)
Definition: builtins.h:85
unsigned int uint32
Definition: c.h:442
#define Min(x, y)
Definition: c.h:937
#define PG_BINARY_R
Definition: c.h:1211
#define MAXALIGN(LEN)
Definition: c.h:747
signed int int32
Definition: c.h:430
#define Max(x, y)
Definition: c.h:931
#define PG_BINARY
Definition: c.h:1209
#define UINT64_FORMAT
Definition: c.h:485
#define unlikely(x)
Definition: c.h:295
#define PG_BINARY_W
Definition: c.h:1212
size_t Size
Definition: c.h:541
int64 TimestampTz
Definition: timestamp.h:39
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:953
void hash_seq_term(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1507
long hash_get_num_entries(HTAB *hashp)
Definition: dynahash.c:1377
Size hash_estimate_size(long num_entries, Size entrysize)
Definition: dynahash.c:781
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1431
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1421
int errcode_for_file_access(void)
Definition: elog.c:718
int errdetail(const char *fmt,...)
Definition: elog.c:1039
int errcode(int sqlerrcode)
Definition: elog.c:695
int errmsg(const char *fmt,...)
Definition: elog.c:906
#define LOG
Definition: elog.h:27
#define PG_TRY(...)
Definition: elog.h:309
#define PG_END_TRY(...)
Definition: elog.h:334
#define DEBUG1
Definition: elog.h:26
#define ERROR
Definition: elog.h:35
#define PG_FINALLY(...)
Definition: elog.h:326
#define ereport(elevel,...)
Definition: elog.h:145
struct pg_encoding enc
Definition: encode.c:562
ExecutorEnd_hook_type ExecutorEnd_hook
Definition: execMain.c:75
ExecutorFinish_hook_type ExecutorFinish_hook
Definition: execMain.c:74
ExecutorStart_hook_type ExecutorStart_hook
Definition: execMain.c:72
void standard_ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:148
void standard_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: execMain.c:311
ExecutorRun_hook_type ExecutorRun_hook
Definition: execMain.c:73
void standard_ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:470
void standard_ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:410
void(* ExecutorRun_hook_type)(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
Definition: executor.h:69
void(* ExecutorFinish_hook_type)(QueryDesc *queryDesc)
Definition: executor.h:76
void(* ExecutorStart_hook_type)(QueryDesc *queryDesc, int eflags)
Definition: executor.h:65
void(* ExecutorEnd_hook_type)(QueryDesc *queryDesc)
Definition: executor.h:80
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2383
int durable_rename(const char *oldfile, const char *newfile, int elevel)
Definition: fd.c:688
int CloseTransientFile(int fd)
Definition: fd.c:2609
int FreeFile(FILE *file)
Definition: fd.c:2581
int OpenTransientFile(const char *fileName, int fileFlags)
Definition: fd.c:2433
Datum Int64GetDatum(int64 X)
Definition: fmgr.c:1683
#define PG_RETURN_VOID()
Definition: fmgr.h:349
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
#define PG_GETARG_INT64(n)
Definition: fmgr.h:283
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:274
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
#define DirectFunctionCall3(func, arg1, arg2, arg3)
Definition: fmgr.h:646
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
void InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags)
Definition: funcapi.c:76
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:276
@ TYPEFUNC_COMPOSITE
Definition: funcapi.h:149
static Datum HeapTupleGetDatum(const HeapTupleData *tuple)
Definition: funcapi.h:230
bool IsUnderPostmaster
Definition: globals.c:113
Oid MyDatabaseId
Definition: globals.c:89
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:5051
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:4940
void MarkGUCPrefixReserved(const char *className)
Definition: guc.c:5087
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:4966
@ PGC_SUSET
Definition: guc.h:74
@ PGC_POSTMASTER
Definition: guc.h:70
@ PGC_SIGHUP
Definition: guc.h:71
#define free(a)
Definition: header.h:65
#define malloc(a)
Definition: header.h:50
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
@ HASH_FIND
Definition: hsearch.h:113
@ HASH_REMOVE
Definition: hsearch.h:115
@ HASH_ENTER
Definition: hsearch.h:114
#define HASH_ELEM
Definition: hsearch.h:95
#define HASH_BLOBS
Definition: hsearch.h:97
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:89
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:103
#define INSTR_TIME_GET_MILLISEC(t)
Definition: instr_time.h:135
struct timespec instr_time
Definition: instr_time.h:83
void InstrEndLoop(Instrumentation *instr)
Definition: instrument.c:140
Instrumentation * InstrAlloc(int n, int instrument_options, bool async_mode)
Definition: instrument.c:31
WalUsage pgWalUsage
Definition: instrument.c:22
void WalUsageAccumDiff(WalUsage *dst, const WalUsage *add, const WalUsage *sub)
Definition: instrument.c:280
BufferUsage pgBufferUsage
Definition: instrument.c:20
void BufferUsageAccumDiff(BufferUsage *dst, const BufferUsage *add, const BufferUsage *sub)
Definition: instrument.c:246
@ INSTRUMENT_ALL
Definition: instrument.h:63
#define read(a, b, c)
Definition: win32.h:13
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
Definition: ipc.c:361
void(* shmem_startup_hook_type)(void)
Definition: ipc.h:22
shmem_startup_hook_type shmem_startup_hook
Definition: ipci.c:56
void RequestAddinShmemSpace(Size size)
Definition: ipci.c:70
int b
Definition: isn.c:70
int a
Definition: isn.c:69
int i
Definition: isn.c:73
PGDLLIMPORT const ScanKeywordList ScanKeywords
Assert(fmt[strlen(fmt) - 1] !='\n')
LWLockPadded * GetNamedLWLockTranche(const char *tranche_name)
Definition: lwlock.c:596
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1194
void RequestNamedLWLockTranche(const char *tranche_name, int num_lwlocks)
Definition: lwlock.c:692
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1802
@ LW_SHARED
Definition: lwlock.h:113
@ LW_EXCLUSIVE
Definition: lwlock.h:112
char * pg_any_to_server(const char *s, int len, int encoding)
Definition: mbutils.c:676
int GetDatabaseEncoding(void)
Definition: mbutils.c:1210
void pfree(void *pointer)
Definition: mcxt.c:1306
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1321
void * palloc(Size size)
Definition: mcxt.c:1199
#define MaxAllocHugeSize
Definition: memutils.h:45
void(* shmem_request_hook_type)(void)
Definition: miscadmin.h:485
Oid GetUserId(void)
Definition: miscinit.c:497
shmem_request_hook_type shmem_request_hook
Definition: miscinit.c:1768
bool process_shared_preload_libraries_in_progress
Definition: miscinit.c:1765
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:135
post_parse_analyze_hook_type post_parse_analyze_hook
Definition: analyze.c:59
void * arg
const void size_t len
int32 encoding
Definition: pg_database.h:41
static void header(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:208
static int entry_cmp(const void *lhs, const void *rhs)
#define PG_STAT_STATEMENTS_COLS_V1_0
static planner_hook_type prev_planner_hook
@ PGSS_V1_9
@ PGSS_V1_10
@ PGSS_V1_1
@ PGSS_V1_3
@ PGSS_V1_2
@ PGSS_V1_8
@ PGSS_V1_0
static int pgss_track
static bool pgss_track_planning
#define ASSUMED_MEDIAN_INIT
#define PG_STAT_STATEMENTS_INFO_COLS
PG_FUNCTION_INFO_V1(pg_stat_statements_reset)
static ExecutorRun_hook_type prev_ExecutorRun
struct pgssSharedState pgssSharedState
static void pgss_store(const char *query, uint64 queryId, int query_location, int query_len, pgssStoreKind kind, double total_time, uint64 rows, const BufferUsage *bufusage, const WalUsage *walusage, const struct JitInstrumentation *jitusage, JumbleState *jstate)
static void pg_stat_statements_internal(FunctionCallInfo fcinfo, pgssVersion api_version, bool showtext)
#define record_gc_qtexts()
Datum pg_stat_statements_reset_1_7(PG_FUNCTION_ARGS)
static PlannedStmt * pgss_planner(Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams)
static int exec_nested_level
void _PG_init(void)
static void gc_qtexts(void)
#define PG_STAT_STATEMENTS_COLS_V1_8
static int comp_location(const void *a, const void *b)
#define PG_STAT_STATEMENTS_COLS
struct Counters Counters
Datum pg_stat_statements_1_9(PG_FUNCTION_ARGS)
#define PGSS_TEXT_FILE
PGSSTrackLevel
@ PGSS_TRACK_ALL
@ PGSS_TRACK_NONE
@ PGSS_TRACK_TOP
PG_MODULE_MAGIC
static int plan_nested_level
static char * qtext_fetch(Size query_offset, int query_len, char *buffer, Size buffer_size)
static int pgss_max
#define USAGE_DEALLOC_PERCENT
static bool qtext_store(const char *query, int query_len, Size *query_offset, int *gc_count)
Datum pg_stat_statements_1_10(PG_FUNCTION_ARGS)
#define USAGE_EXEC(duration)
#define STICKY_DECREASE_FACTOR
#define IS_STICKY(c)
static const struct config_enum_entry track_options[]
#define PG_STAT_STATEMENTS_COLS_V1_2
Datum pg_stat_statements_reset(PG_FUNCTION_ARGS)
static void pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc)
#define PGSS_DUMP_FILE
static char * qtext_load_file(Size *buffer_size)
static post_parse_analyze_hook_type prev_post_parse_analyze_hook
static bool need_gc_qtexts(void)
#define pgss_enabled(level)
static shmem_startup_hook_type prev_shmem_startup_hook
static shmem_request_hook_type prev_shmem_request_hook
static void entry_reset(Oid userid, Oid dbid, uint64 queryid)
static void pgss_shmem_request(void)
pgssStoreKind
@ PGSS_PLAN
@ PGSS_EXEC
@ PGSS_INVALID
@ PGSS_NUMKIND
static void pgss_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
#define ASSUMED_LENGTH_INIT
#define PG_STAT_STATEMENTS_COLS_V1_3
static Size pgss_memsize(void)
static bool pgss_save
static void pgss_shmem_startup(void)
struct pgssGlobalStats pgssGlobalStats
static const uint32 PGSS_PG_MAJOR_VERSION
Datum pg_stat_statements_1_2(PG_FUNCTION_ARGS)
struct pgssEntry pgssEntry
#define USAGE_DECREASE_FACTOR
static ExecutorStart_hook_type prev_ExecutorStart
Datum pg_stat_statements(PG_FUNCTION_ARGS)
Datum pg_stat_statements_info(PG_FUNCTION_ARGS)
static void entry_dealloc(void)
#define PG_STAT_STATEMENTS_COLS_V1_10
static pgssSharedState * pgss
Datum pg_stat_statements_1_3(PG_FUNCTION_ARGS)
static void pgss_ExecutorFinish(QueryDesc *queryDesc)
static ProcessUtility_hook_type prev_ProcessUtility
#define PG_STAT_STATEMENTS_COLS_V1_1
Datum pg_stat_statements_1_8(PG_FUNCTION_ARGS)
static void pgss_post_parse_analyze(ParseState *pstate, Query *query, JumbleState *jstate)
struct pgssHashKey pgssHashKey
static pgssEntry * entry_alloc(pgssHashKey *key, Size query_offset, int query_len, int encoding, bool sticky)
static void fill_in_constant_lengths(JumbleState *jstate, const char *query, int query_loc)
static bool pgss_track_utility
#define USAGE_INIT
static ExecutorEnd_hook_type prev_ExecutorEnd
#define PG_STAT_STATEMENTS_COLS_V1_9
#define PGSS_HANDLED_UTILITY(n)
static void pgss_ExecutorEnd(QueryDesc *queryDesc)
static char * generate_normalized_query(JumbleState *jstate, const char *query, int query_loc, int *query_len_p)
static void pgss_ExecutorStart(QueryDesc *queryDesc, int eflags)
static HTAB * pgss_hash
static const uint32 PGSS_FILE_HEADER
static void pgss_shmem_shutdown(int code, Datum arg)
static ExecutorFinish_hook_type prev_ExecutorFinish
static char * buf
Definition: pg_test_fsync.c:67
#define PG_VALID_BE_ENCODING(_enc)
Definition: pg_wchar.h:281
int duration
Definition: pgbench.c:183
static core_yyscan_t yyscanner
Definition: pl_scanner.c:106
planner_hook_type planner_hook
Definition: planner.c:75
PlannedStmt * standard_planner(Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams)
Definition: planner.c:283
PlannedStmt *(* planner_hook_type)(Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams)
Definition: planner.h:26
#define sprintf
Definition: port.h:240
#define pg_pwrite
Definition: port.h:226
#define snprintf
Definition: port.h:238
#define qsort(a, b, c, d)
Definition: port.h:445
#define Int64GetDatumFast(X)
Definition: postgres.h:902
uintptr_t Datum
Definition: postgres.h:412
#define Float8GetDatumFast(X)
Definition: postgres.h:904
static Datum BoolGetDatum(bool X)
Definition: postgres.h:450
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:600
static Datum CStringGetDatum(const char *X)
Definition: postgres.h:698
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:560
unsigned int Oid
Definition: postgres_ext.h:31
e
Definition: preproc-init.c:82
static int fd(const char *x, int i)
Definition: preproc-init.c:105
const char * CleanQuerytext(const char *query, int *location, int *len)
Definition: queryjumble.c:63
void EnableQueryId(void)
Definition: queryjumble.c:151
static struct subre * parse(struct vars *v, int stopper, int type, struct state *init, struct state *final)
Definition: regcomp.c:717
int slock_t
Definition: s_lock.h:754
#define YYLTYPE
Definition: scanner.h:44
core_yyscan_t scanner_init(const char *str, core_yy_extra_type *yyext, const ScanKeywordList *keywordlist, const uint16 *keyword_tokens)
void scanner_finish(core_yyscan_t yyscanner)
PGDLLIMPORT const uint16 ScanKeywordTokens[]
void * core_yyscan_t
Definition: scanner.h:121
int core_yylex(core_YYSTYPE *yylval_param, YYLTYPE *yylloc_param, core_yyscan_t yyscanner)
ScanDirection
Definition: sdir.h:23
Size add_size(Size s1, Size s2)
Definition: shmem.c:502
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:396
HTAB * ShmemInitHash(const char *name, long init_size, long max_size, HASHCTL *infoP, int hash_flags)
Definition: shmem.c:341
#define SpinLockInit(lock)
Definition: spin.h:60
#define SpinLockRelease(lock)
Definition: spin.h:64
#define SpinLockAcquire(lock)
Definition: spin.h:62
static void error(void)
Definition: sql-dyntest.c:147
int64 shared_blks_dirtied
Definition: instrument.h:28
int64 local_blks_hit
Definition: instrument.h:30
instr_time temp_blk_write_time
Definition: instrument.h:39
int64 local_blks_written
Definition: instrument.h:33
instr_time blk_write_time
Definition: instrument.h:37
instr_time temp_blk_read_time
Definition: instrument.h:38
int64 temp_blks_read
Definition: instrument.h:34
int64 shared_blks_read
Definition: instrument.h:27
int64 shared_blks_written
Definition: instrument.h:29
int64 temp_blks_written
Definition: instrument.h:35
instr_time blk_read_time
Definition: instrument.h:36
int64 local_blks_read
Definition: instrument.h:31
int64 local_blks_dirtied
Definition: instrument.h:32
int64 shared_blks_hit
Definition: instrument.h:26
int64 temp_blks_written
int64 calls[PGSS_NUMKIND]
int64 shared_blks_written
double jit_generation_time
int64 temp_blks_read
double min_time[PGSS_NUMKIND]
int64 local_blks_written
double sum_var_time[PGSS_NUMKIND]
double temp_blk_read_time
int64 jit_emission_count
double jit_emission_time
int64 shared_blks_hit
double jit_optimization_time
double blk_read_time
int64 jit_optimization_count
double total_time[PGSS_NUMKIND]
double max_time[PGSS_NUMKIND]
int64 shared_blks_dirtied
double mean_time[PGSS_NUMKIND]
double temp_blk_write_time
int64 local_blks_dirtied
int64 jit_inlining_count
int64 shared_blks_read
int64 local_blks_hit
int64 local_blks_read
double jit_inlining_time
double blk_write_time
uint64 es_processed
Definition: execnodes.h:654
struct JitContext * es_jit
Definition: execnodes.h:696
MemoryContext es_query_cxt
Definition: execnodes.h:650
fmNodePtr resultinfo
Definition: fmgr.h:89
Size keysize
Definition: hsearch.h:75
Size entrysize
Definition: hsearch.h:76
Definition: dynahash.c:220
WalUsage walusage
Definition: instrument.h:90
BufferUsage bufusage
Definition: instrument.h:89
JitInstrumentation instr
Definition: jit.h:61
instr_time generation_counter
Definition: jit.h:33
size_t created_functions
Definition: jit.h:30
instr_time optimization_counter
Definition: jit.h:39
instr_time emission_counter
Definition: jit.h:42
instr_time inlining_counter
Definition: jit.h:36
int highest_extern_param_id
Definition: queryjumble.h:50
LocationLen * clocations
Definition: queryjumble.h:41
int clocations_count
Definition: queryjumble.h:47
Definition: lwlock.h:40
Definition: nodes.h:112
const char * p_sourcetext
Definition: parse_node.h:182
int stmt_location
Definition: plannodes.h:96
int stmt_len
Definition: plannodes.h:97
Node * utilityStmt
Definition: plannodes.h:93
uint64 queryId
Definition: plannodes.h:55
uint64 nprocessed
Definition: cmdtag.h:31
CommandTag commandTag
Definition: cmdtag.h:30
const char * sourceText
Definition: execdesc.h:38
EState * estate
Definition: execdesc.h:48
PlannedStmt * plannedstmt
Definition: execdesc.h:37
struct Instrumentation * totaltime
Definition: execdesc.h:55
int stmt_location
Definition: parsenodes.h:202
int stmt_len
Definition: parsenodes.h:203
Node * utilityStmt
Definition: parsenodes.h:134
TupleDesc setDesc
Definition: execnodes.h:332
Tuplestorestate * setResult
Definition: execnodes.h:331
uint64 wal_bytes
Definition: instrument.h:53
int64 wal_fpi
Definition: instrument.h:52
int64 wal_records
Definition: instrument.h:51
Definition: guc.h:168
bool escape_string_warning
Definition: scanner.h:88
char * scanbuf
Definition: scanner.h:72
Counters counters
pgssHashKey key
TimestampTz stats_reset
pgssGlobalStats stats
__int64 st_size
Definition: win32_port.h:275
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, Datum *values, bool *isnull)
Definition: tuplestore.c:750
void standard_ProcessUtility(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc)
Definition: utility.c:547
ProcessUtility_hook_type ProcessUtility_hook
Definition: utility.c:77
void(* ProcessUtility_hook_type)(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc)
Definition: utility.h:71
ProcessUtilityContext
Definition: utility.h:21
static Datum TimestampTzGetDatum(TimestampTz X)
Definition: timestamp.h:52
#define fstat
Definition: win32_port.h:285
#define ftruncate(a, b)
Definition: win32_port.h:82