79 #define PGSS_DUMP_FILE PGSTAT_STAT_PERMANENT_DIRECTORY "/pg_stat_statements.stat"
84 #define PGSS_TEXT_FILE PG_STAT_TMP_DIR "/pgss_query_texts.stat"
93 #define USAGE_EXEC(duration) (1.0)
94 #define USAGE_INIT (1.0)
95 #define ASSUMED_MEDIAN_INIT (10.0)
96 #define ASSUMED_LENGTH_INIT 1024
97 #define USAGE_DECREASE_FACTOR (0.99)
98 #define STICKY_DECREASE_FACTOR (0.50)
99 #define USAGE_DEALLOC_PERCENT 5
100 #define IS_STICKY(c) ((c.calls[PGSS_PLAN] + c.calls[PGSS_EXEC]) == 0)
106 #define PGSS_HANDLED_UTILITY(n) (!IsA(n, ExecuteStmt) && \
107 !IsA(n, PrepareStmt) && \
108 !IsA(n, DeallocateStmt))
293 #define pgss_enabled(level) \
294 (!IsParallelWorker() && \
295 (pgss_track == PGSS_TRACK_ALL || \
296 (pgss_track == PGSS_TRACK_TOP && (level) == 0)))
298 #define record_gc_qtexts() \
300 volatile pgssSharedState *s = (volatile pgssSharedState *) pgss; \
301 SpinLockAcquire(&s->mutex); \
303 SpinLockRelease(&s->mutex); \
326 const char *query_string,
332 uint64 count,
bool execute_once);
340 static void pgss_store(
const char *query, uint64 queryId,
341 int query_location,
int query_len,
343 double total_time, uint64 rows,
355 static bool qtext_store(
const char *query,
int query_len,
356 Size *query_offset,
int *gc_count);
359 char *buffer,
Size buffer_size);
364 int query_loc,
int *query_len_p);
397 "Sets the maximum number of statements tracked by pg_stat_statements.",
410 "Selects which statements are tracked by pg_stat_statements.",
422 "Selects whether utility commands are tracked by pg_stat_statements.",
433 "Selects whether planning duration is tracked by pg_stat_statements.",
444 "Save pg_stat_statements statistics across server shutdowns.",
603 buffer = (
char *)
palloc(buffer_size);
606 fread(&pgver,
sizeof(
uint32), 1, file) != 1 ||
607 fread(&num,
sizeof(
int32), 1, file) != 1)
614 for (
i = 0;
i < num;
i++)
620 if (fread(&temp,
sizeof(
pgssEntry), 1, file) != 1)
631 buffer =
repalloc(buffer, buffer_size);
687 errmsg(
"could not read file \"%s\": %m",
692 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
693 errmsg(
"ignoring invalid data in file \"%s\"",
699 errmsg(
"could not write file \"%s\": %m",
727 char *qbuffer = NULL;
728 Size qbuffer_size = 0;
754 if (fwrite(&num_entries,
sizeof(
int32), 1, file) != 1)
770 qbuffer, qbuffer_size);
775 if (fwrite(entry,
sizeof(
pgssEntry), 1, file) != 1 ||
776 fwrite(qstr, 1,
len + 1, file) !=
len + 1)
810 errmsg(
"could not write file \"%s\": %m",
841 query->
queryId = UINT64CONST(0);
872 const char *query_string,
892 &&
parse->queryId != UINT64CONST(0))
935 memset(&walusage, 0,
sizeof(
WalUsage));
940 parse->stmt_location,
1048 if (queryId != UINT64CONST(0) && queryDesc->
totaltime &&
1087 uint64 saved_queryId = pstmt->
queryId;
1104 pstmt->
queryId = UINT64CONST(0);
1140 context, params, queryEnv,
1144 context, params, queryEnv,
1161 rows = (qc && (qc->
commandTag == CMDTAG_COPY ||
1164 qc->
commandTag == CMDTAG_REFRESH_MATERIALIZED_VIEW)) ?
1172 memset(&walusage, 0,
sizeof(
WalUsage));
1191 context, params, queryEnv,
1195 context, params, queryEnv,
1213 int query_location,
int query_len,
1215 double total_time, uint64 rows,
1223 char *norm_query = NULL;
1236 if (queryId == UINT64CONST(0))
1253 key.queryid = queryId;
1286 stored =
qtext_store(norm_query ? norm_query : query, query_len,
1287 &query_offset, &gc_count);
1308 stored =
qtext_store(norm_query ? norm_query : query, query_len,
1309 &query_offset, NULL);
1341 e->counters.calls[kind] += 1;
1342 e->counters.total_time[kind] += total_time;
1344 if (
e->counters.calls[kind] == 1)
1346 e->counters.min_time[kind] = total_time;
1347 e->counters.max_time[kind] = total_time;
1348 e->counters.mean_time[kind] = total_time;
1356 double old_mean =
e->counters.mean_time[kind];
1358 e->counters.mean_time[kind] +=
1359 (total_time - old_mean) /
e->counters.calls[kind];
1360 e->counters.sum_var_time[kind] +=
1361 (total_time - old_mean) * (total_time -
e->counters.mean_time[kind]);
1364 if (
e->counters.min_time[kind] > total_time)
1365 e->counters.min_time[kind] = total_time;
1366 if (
e->counters.max_time[kind] < total_time)
1367 e->counters.max_time[kind] = total_time;
1369 e->counters.rows += rows;
1386 e->counters.wal_fpi += walusage->
wal_fpi;
1387 e->counters.wal_bytes += walusage->
wal_bytes;
1394 e->counters.jit_inlining_count++;
1398 e->counters.jit_optimization_count++;
1402 e->counters.jit_emission_count++;
1448 #define PG_STAT_STATEMENTS_COLS_V1_0 14
1449 #define PG_STAT_STATEMENTS_COLS_V1_1 18
1450 #define PG_STAT_STATEMENTS_COLS_V1_2 19
1451 #define PG_STAT_STATEMENTS_COLS_V1_3 23
1452 #define PG_STAT_STATEMENTS_COLS_V1_8 32
1453 #define PG_STAT_STATEMENTS_COLS_V1_9 33
1454 #define PG_STAT_STATEMENTS_COLS_V1_10 43
1455 #define PG_STAT_STATEMENTS_COLS 43
1538 bool is_allowed_role =
false;
1539 char *qbuffer = NULL;
1540 Size qbuffer_size = 0;
1555 (
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1556 errmsg(
"pg_stat_statements must be loaded via shared_preload_libraries")));
1569 elog(
ERROR,
"incorrect number of output arguments");
1574 elog(
ERROR,
"incorrect number of output arguments");
1579 elog(
ERROR,
"incorrect number of output arguments");
1583 elog(
ERROR,
"incorrect number of output arguments");
1587 elog(
ERROR,
"incorrect number of output arguments");
1591 elog(
ERROR,
"incorrect number of output arguments");
1595 elog(
ERROR,
"incorrect number of output arguments");
1598 elog(
ERROR,
"incorrect number of output arguments");
1656 if (qbuffer == NULL ||
1677 memset(nulls, 0,
sizeof(nulls));
1684 if (is_allowed_role || entry->
key.
userid == userid)
1772 if (tmp.
calls[kind] > 1)
1850 #define PG_STAT_STATEMENTS_INFO_COLS 2
1865 (
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1866 errmsg(
"pg_stat_statements must be loaded via shared_preload_libraries")));
1870 elog(
ERROR,
"return type must be a row type");
1873 MemSet(nulls, 0,
sizeof(nulls));
1961 double l_usage = (*(
pgssEntry *
const *) lhs)->counters.usage;
1962 double r_usage = (*(
pgssEntry *
const *) rhs)->counters.usage;
1964 if (l_usage < r_usage)
1966 else if (l_usage > r_usage)
2009 entries[
i++] = entry;
2030 if (nvalidtexts > 0)
2037 nvictims =
Min(nvictims,
i);
2039 for (
i = 0;
i < nvictims;
i++)
2074 Size *query_offset,
int *gc_count)
2088 s->
extent += query_len + 1;
2095 *query_offset = off;
2102 if (
pg_pwrite(
fd, query, query_len, off) != query_len)
2123 errmsg(
"could not write file \"%s\": %m",
2163 if (errno != ENOENT)
2166 errmsg(
"could not read file \"%s\": %m",
2176 errmsg(
"could not stat file \"%s\": %m",
2190 (
errcode(ERRCODE_OUT_OF_MEMORY),
2192 errdetail(
"Could not allocate enough memory to read file \"%s\".",
2216 if (
read(
fd,
buf + nread, toread) != toread)
2221 errmsg(
"could not read file \"%s\": %m",
2235 *buffer_size = nread;
2247 char *buffer,
Size buffer_size)
2253 if (query_len < 0 ||
2254 query_offset + query_len >= buffer_size)
2257 if (buffer[query_offset + query_len] !=
'\0')
2260 return buffer + query_offset;
2293 if (extent < pgss->mean_query_len *
pgss_max * 2)
2342 if (qbuffer == NULL)
2356 errmsg(
"could not write file \"%s\": %m",
2382 if (fwrite(qry, 1, query_len + 1, qfile) != query_len + 1)
2386 errmsg(
"could not write file \"%s\": %m",
2393 extent += query_len + 1;
2401 if (
ftruncate(fileno(qfile), extent) != 0)
2404 errmsg(
"could not truncate file \"%s\": %m",
2411 errmsg(
"could not write file \"%s\": %m",
2417 elog(
DEBUG1,
"pgss gc of queries file shrunk size from %zu to %zu",
2471 errmsg(
"could not recreate file \"%s\": %m",
2506 long num_remove = 0;
2511 (
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
2512 errmsg(
"pg_stat_statements must be loaded via shared_preload_libraries")));
2517 if (userid != 0 && dbid != 0 && queryid != UINT64CONST(0))
2521 key.userid = userid;
2523 key.queryid = queryid;
2526 key.toplevel =
false;
2532 key.toplevel =
true;
2539 else if (userid != 0 || dbid != 0 || queryid != UINT64CONST(0))
2545 if ((!userid || entry->
key.
userid == userid) &&
2546 (!dbid || entry->
key.
dbid == dbid) &&
2566 if (num_entries != num_remove)
2592 errmsg(
"could not create file \"%s\": %m",
2601 errmsg(
"could not truncate file \"%s\": %m",
2636 int query_loc,
int *query_len_p)
2639 int query_len = *query_len_p;
2664 norm_query =
palloc(norm_query_buflen + 1);
2681 len_to_wrt = off - last_off;
2682 len_to_wrt -= last_tok_len;
2685 memcpy(norm_query + n_quer_loc, query + quer_loc, len_to_wrt);
2686 n_quer_loc += len_to_wrt;
2689 n_quer_loc +=
sprintf(norm_query + n_quer_loc,
"$%d",
2692 quer_loc = off + tok_len;
2694 last_tok_len = tok_len;
2701 len_to_wrt = query_len - quer_loc;
2704 memcpy(norm_query + n_quer_loc, query + quer_loc, len_to_wrt);
2705 n_quer_loc += len_to_wrt;
2707 Assert(n_quer_loc <= norm_query_buflen);
2708 norm_query[n_quer_loc] =
'\0';
2710 *query_len_p = n_quer_loc;
2782 if (loc <= last_loc)
2800 if (query[loc] ==
'-')
bool has_privs_of_role(Oid member, Oid role)
void(* post_parse_analyze_hook_type)(ParseState *pstate, Query *query, JumbleState *jstate)
Datum numeric_in(PG_FUNCTION_ARGS)
TimestampTz GetCurrentTimestamp(void)
static Datum values[MAXATTR]
#define CStringGetTextDatum(s)
#define MemSet(start, val, len)
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
void hash_seq_term(HASH_SEQ_STATUS *status)
long hash_get_num_entries(HTAB *hashp)
Size hash_estimate_size(long num_entries, Size entrysize)
void * hash_seq_search(HASH_SEQ_STATUS *status)
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
int errcode_for_file_access(void)
int errdetail(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
ExecutorEnd_hook_type ExecutorEnd_hook
ExecutorFinish_hook_type ExecutorFinish_hook
ExecutorStart_hook_type ExecutorStart_hook
void standard_ExecutorStart(QueryDesc *queryDesc, int eflags)
void standard_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
ExecutorRun_hook_type ExecutorRun_hook
void standard_ExecutorEnd(QueryDesc *queryDesc)
void standard_ExecutorFinish(QueryDesc *queryDesc)
void(* ExecutorRun_hook_type)(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once)
void(* ExecutorFinish_hook_type)(QueryDesc *queryDesc)
void(* ExecutorStart_hook_type)(QueryDesc *queryDesc, int eflags)
void(* ExecutorEnd_hook_type)(QueryDesc *queryDesc)
FILE * AllocateFile(const char *name, const char *mode)
int durable_rename(const char *oldfile, const char *newfile, int elevel)
int CloseTransientFile(int fd)
int OpenTransientFile(const char *fileName, int fileFlags)
Datum Int64GetDatum(int64 X)
#define PG_GETARG_INT64(n)
#define PG_GETARG_BOOL(n)
#define PG_RETURN_DATUM(x)
#define DirectFunctionCall3(func, arg1, arg2, arg3)
void SetSingleFuncCall(FunctionCallInfo fcinfo, bits32 flags)
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
#define HeapTupleGetDatum(tuple)
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)
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)
void MarkGUCPrefixReserved(const char *className)
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)
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
#define INSTR_TIME_SET_CURRENT(t)
#define INSTR_TIME_SUBTRACT(x, y)
struct timeval instr_time
#define INSTR_TIME_GET_MILLISEC(t)
void InstrEndLoop(Instrumentation *instr)
Instrumentation * InstrAlloc(int n, int instrument_options, bool async_mode)
void WalUsageAccumDiff(WalUsage *dst, const WalUsage *add, const WalUsage *sub)
BufferUsage pgBufferUsage
void BufferUsageAccumDiff(BufferUsage *dst, const BufferUsage *add, const BufferUsage *sub)
void on_shmem_exit(pg_on_exit_callback function, Datum arg)
void(* shmem_startup_hook_type)(void)
shmem_startup_hook_type shmem_startup_hook
void RequestAddinShmemSpace(Size size)
PGDLLIMPORT const ScanKeywordList ScanKeywords
Assert(fmt[strlen(fmt) - 1] !='\n')
LWLockPadded * GetNamedLWLockTranche(const char *tranche_name)
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
void RequestNamedLWLockTranche(const char *tranche_name, int num_lwlocks)
void LWLockRelease(LWLock *lock)
char * pg_any_to_server(const char *s, int len, int encoding)
int GetDatabaseEncoding(void)
void pfree(void *pointer)
void * repalloc(void *pointer, Size size)
void(* shmem_request_hook_type)(void)
shmem_request_hook_type shmem_request_hook
bool process_shared_preload_libraries_in_progress
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
post_parse_analyze_hook_type post_parse_analyze_hook
static void header(const char *fmt,...) pg_attribute_printf(1
static int entry_cmp(const void *lhs, const void *rhs)
#define PG_STAT_STATEMENTS_COLS_V1_0
static planner_hook_type prev_planner_hook
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
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
Datum pg_stat_statements_1_9(PG_FUNCTION_ARGS)
static int plan_nested_level
static char * qtext_fetch(Size query_offset, int query_len, char *buffer, Size buffer_size)
#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
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)
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)
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 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
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 const uint32 PGSS_FILE_HEADER
static void pgss_shmem_shutdown(int code, Datum arg)
static ExecutorFinish_hook_type prev_ExecutorFinish
#define PG_VALID_BE_ENCODING(_enc)
static core_yyscan_t yyscanner
planner_hook_type planner_hook
PlannedStmt * standard_planner(Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams)
PlannedStmt *(* planner_hook_type)(Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams)
ssize_t pg_pwrite(int fd, const void *buf, size_t nbyte, off_t offset)
#define qsort(a, b, c, d)
#define Int64GetDatumFast(X)
#define CStringGetDatum(X)
#define Float8GetDatumFast(X)
#define ObjectIdGetDatum(X)
static int fd(const char *x, int i)
const char * CleanQuerytext(const char *query, int *location, int *len)
static struct subre * parse(struct vars *, int, int, struct state *, struct state *)
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[]
int core_yylex(core_YYSTYPE *lvalp, YYLTYPE *llocp, core_yyscan_t yyscanner)
Size add_size(Size s1, Size s2)
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
HTAB * ShmemInitHash(const char *name, long init_size, long max_size, HASHCTL *infoP, int hash_flags)
#define SpinLockInit(lock)
#define SpinLockRelease(lock)
#define SpinLockAcquire(lock)
int64 shared_blks_dirtied
instr_time temp_blk_write_time
instr_time blk_write_time
instr_time temp_blk_read_time
int64 shared_blks_written
int64 calls[PGSS_NUMKIND]
int64 shared_blks_written
double jit_generation_time
double min_time[PGSS_NUMKIND]
double sum_var_time[PGSS_NUMKIND]
double temp_blk_read_time
double jit_optimization_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
struct JitContext * es_jit
MemoryContext es_query_cxt
instr_time generation_counter
instr_time optimization_counter
instr_time emission_counter
instr_time inlining_counter
int highest_extern_param_id
const char * p_sourcetext
PlannedStmt * plannedstmt
struct Instrumentation * totaltime
Tuplestorestate * setResult
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, Datum *values, bool *isnull)
void standard_ProcessUtility(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc)
ProcessUtility_hook_type ProcessUtility_hook
void(* ProcessUtility_hook_type)(PlannedStmt *pstmt, const char *queryString, bool readOnlyTree, ProcessUtilityContext context, ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest, QueryCompletion *qc)
#define TimestampTzGetDatum(X)