#include "postgres.h"#include <unistd.h>#include "access/hash.h"#include "executor/instrument.h"#include "funcapi.h"#include "mb/pg_wchar.h"#include "miscadmin.h"#include "parser/analyze.h"#include "parser/parsetree.h"#include "parser/scanner.h"#include "pgstat.h"#include "storage/fd.h"#include "storage/ipc.h"#include "storage/spin.h"#include "tcop/utility.h"#include "utils/builtins.h"
Go to the source code of this file.
Data Structures | |
| struct | pgssHashKey |
| struct | Counters |
| struct | pgssEntry |
| struct | pgssSharedState |
| struct | pgssLocationLen |
| struct | pgssJumbleState |
Defines | |
| #define | PGSS_DUMP_FILE "global/pg_stat_statements.stat" |
| #define | USAGE_EXEC(duration) (1.0) |
| #define | USAGE_INIT (1.0) |
| #define | ASSUMED_MEDIAN_INIT (10.0) |
| #define | USAGE_DECREASE_FACTOR (0.99) |
| #define | STICKY_DECREASE_FACTOR (0.50) |
| #define | USAGE_DEALLOC_PERCENT 5 |
| #define | JUMBLE_SIZE 1024 |
| #define | pgss_enabled() |
| #define | PG_STAT_STATEMENTS_COLS_V1_0 14 |
| #define | PG_STAT_STATEMENTS_COLS 18 |
| #define | APP_JUMB(item) AppendJumble(jstate, (const unsigned char *) &(item), sizeof(item)) |
| #define | APP_JUMB_STRING(str) AppendJumble(jstate, (const unsigned char *) (str), strlen(str) + 1) |
Typedefs | |
| typedef struct pgssHashKey | pgssHashKey |
| typedef struct Counters | Counters |
| typedef struct pgssEntry | pgssEntry |
| typedef struct pgssSharedState | pgssSharedState |
| typedef struct pgssLocationLen | pgssLocationLen |
| typedef struct pgssJumbleState | pgssJumbleState |
Enumerations | |
| enum | PGSSTrackLevel { PGSS_TRACK_NONE, PGSS_TRACK_TOP, PGSS_TRACK_ALL } |
Functions | |
| void | _PG_init (void) |
| void | _PG_fini (void) |
| Datum | pg_stat_statements_reset (PG_FUNCTION_ARGS) |
| Datum | pg_stat_statements (PG_FUNCTION_ARGS) |
| PG_FUNCTION_INFO_V1 (pg_stat_statements_reset) | |
| PG_FUNCTION_INFO_V1 (pg_stat_statements) | |
| static void | pgss_shmem_startup (void) |
| static void | pgss_shmem_shutdown (int code, Datum arg) |
| static void | pgss_post_parse_analyze (ParseState *pstate, Query *query) |
| static void | pgss_ExecutorStart (QueryDesc *queryDesc, int eflags) |
| static void | pgss_ExecutorRun (QueryDesc *queryDesc, ScanDirection direction, long count) |
| static void | pgss_ExecutorFinish (QueryDesc *queryDesc) |
| static void | pgss_ExecutorEnd (QueryDesc *queryDesc) |
| static void | pgss_ProcessUtility (Node *parsetree, const char *queryString, ProcessUtilityContext context, ParamListInfo params, DestReceiver *dest, char *completionTag) |
| static uint32 | pgss_hash_fn (const void *key, Size keysize) |
| static int | pgss_match_fn (const void *key1, const void *key2, Size keysize) |
| static uint32 | pgss_hash_string (const char *str) |
| static void | pgss_store (const char *query, uint32 queryId, double total_time, uint64 rows, const BufferUsage *bufusage, pgssJumbleState *jstate) |
| static Size | pgss_memsize (void) |
| static pgssEntry * | entry_alloc (pgssHashKey *key, const char *query, int query_len, bool sticky) |
| static void | entry_dealloc (void) |
| static void | entry_reset (void) |
| static void | AppendJumble (pgssJumbleState *jstate, const unsigned char *item, Size size) |
| static void | JumbleQuery (pgssJumbleState *jstate, Query *query) |
| static void | JumbleRangeTable (pgssJumbleState *jstate, List *rtable) |
| static void | JumbleExpr (pgssJumbleState *jstate, Node *node) |
| static void | RecordConstLocation (pgssJumbleState *jstate, int location) |
| static char * | generate_normalized_query (pgssJumbleState *jstate, const char *query, int *query_len_p, int encoding) |
| static void | fill_in_constant_lengths (pgssJumbleState *jstate, const char *query) |
| static int | comp_location (const void *a, const void *b) |
| static int | entry_cmp (const void *lhs, const void *rhs) |
Variables | |
| PG_MODULE_MAGIC | |
| static const uint32 | PGSS_FILE_HEADER = 0x20120328 |
| static int | nested_level = 0 |
| static shmem_startup_hook_type | prev_shmem_startup_hook = NULL |
| static post_parse_analyze_hook_type | prev_post_parse_analyze_hook = NULL |
| static ExecutorStart_hook_type | prev_ExecutorStart = NULL |
| static ExecutorRun_hook_type | prev_ExecutorRun = NULL |
| static ExecutorFinish_hook_type | prev_ExecutorFinish = NULL |
| static ExecutorEnd_hook_type | prev_ExecutorEnd = NULL |
| static ProcessUtility_hook_type | prev_ProcessUtility = NULL |
| static pgssSharedState * | pgss = NULL |
| static HTAB * | pgss_hash = NULL |
| static struct config_enum_entry | track_options [] |
| static int | pgss_max |
| static int | pgss_track |
| static bool | pgss_track_utility |
| static bool | pgss_save |
| #define APP_JUMB | ( | item | ) | AppendJumble(jstate, (const unsigned char *) &(item), sizeof(item)) |
Definition at line 1395 of file pg_stat_statements.c.
Referenced by JumbleExpr(), JumbleQuery(), and JumbleRangeTable().
| #define APP_JUMB_STRING | ( | str | ) | AppendJumble(jstate, (const unsigned char *) (str), strlen(str) + 1) |
Definition at line 1397 of file pg_stat_statements.c.
Referenced by JumbleExpr(), and JumbleRangeTable().
| #define ASSUMED_MEDIAN_INIT (10.0) |
Definition at line 75 of file pg_stat_statements.c.
| #define JUMBLE_SIZE 1024 |
Definition at line 80 of file pg_stat_statements.c.
Referenced by AppendJumble(), and pgss_post_parse_analyze().
| #define PG_STAT_STATEMENTS_COLS 18 |
Definition at line 1072 of file pg_stat_statements.c.
Referenced by pg_stat_statements().
| #define PG_STAT_STATEMENTS_COLS_V1_0 14 |
Definition at line 1071 of file pg_stat_statements.c.
Referenced by pg_stat_statements().
| #define PGSS_DUMP_FILE "global/pg_stat_statements.stat" |
Definition at line 67 of file pg_stat_statements.c.
Referenced by pgss_shmem_shutdown(), and pgss_shmem_startup().
| #define pgss_enabled | ( | ) |
(pgss_track == PGSS_TRACK_ALL || \ (pgss_track == PGSS_TRACK_TOP && nested_level == 0))
Definition at line 218 of file pg_stat_statements.c.
Referenced by pgss_ExecutorEnd(), pgss_ExecutorStart(), and pgss_ProcessUtility().
| #define STICKY_DECREASE_FACTOR (0.50) |
Definition at line 77 of file pg_stat_statements.c.
| #define USAGE_DEALLOC_PERCENT 5 |
Definition at line 78 of file pg_stat_statements.c.
Referenced by entry_dealloc().
| #define USAGE_DECREASE_FACTOR (0.99) |
Definition at line 76 of file pg_stat_statements.c.
| #define USAGE_EXEC | ( | duration | ) | (1.0) |
Definition at line 73 of file pg_stat_statements.c.
Referenced by pgss_store().
| #define USAGE_INIT (1.0) |
Definition at line 74 of file pg_stat_statements.c.
| typedef struct pgssHashKey pgssHashKey |
| typedef struct pgssJumbleState pgssJumbleState |
| typedef struct pgssLocationLen pgssLocationLen |
| typedef struct pgssSharedState pgssSharedState |
| enum PGSSTrackLevel |
Definition at line 197 of file pg_stat_statements.c.
{
PGSS_TRACK_NONE, /* track no statements */
PGSS_TRACK_TOP, /* only top level statements */
PGSS_TRACK_ALL /* all statements, including nested ones */
} PGSSTrackLevel;
| void _PG_fini | ( | void | ) |
Definition at line 369 of file pg_stat_statements.c.
References ExecutorEnd_hook, ExecutorFinish_hook, ExecutorRun_hook, ExecutorStart_hook, post_parse_analyze_hook, prev_ExecutorEnd, prev_ExecutorFinish, prev_ExecutorRun, prev_ExecutorStart, prev_post_parse_analyze_hook, prev_ProcessUtility, prev_shmem_startup_hook, ProcessUtility_hook, and shmem_startup_hook.
{
/* Uninstall hooks. */
shmem_startup_hook = prev_shmem_startup_hook;
post_parse_analyze_hook = prev_post_parse_analyze_hook;
ExecutorStart_hook = prev_ExecutorStart;
ExecutorRun_hook = prev_ExecutorRun;
ExecutorFinish_hook = prev_ExecutorFinish;
ExecutorEnd_hook = prev_ExecutorEnd;
ProcessUtility_hook = prev_ProcessUtility;
}
| void _PG_init | ( | void | ) |
Definition at line 273 of file pg_stat_statements.c.
References DefineCustomBoolVariable(), DefineCustomEnumVariable(), DefineCustomIntVariable(), EmitWarningsOnPlaceholders(), ExecutorEnd_hook, ExecutorFinish_hook, ExecutorRun_hook, ExecutorStart_hook, NULL, PGC_POSTMASTER, PGC_SIGHUP, PGC_SUSET, pgss_max, pgss_memsize(), pgss_save, pgss_track, PGSS_TRACK_TOP, pgss_track_utility, post_parse_analyze_hook, prev_ExecutorEnd, prev_ExecutorFinish, prev_ExecutorRun, prev_ExecutorStart, prev_post_parse_analyze_hook, prev_ProcessUtility, prev_shmem_startup_hook, process_shared_preload_libraries_in_progress, ProcessUtility_hook, RequestAddinLWLocks(), RequestAddinShmemSpace(), and shmem_startup_hook.
{
/*
* In order to create our shared memory area, we have to be loaded via
* shared_preload_libraries. If not, fall out without hooking into any of
* the main system. (We don't throw error here because it seems useful to
* allow the pg_stat_statements functions to be created even when the
* module isn't active. The functions must protect themselves against
* being called then, however.)
*/
if (!process_shared_preload_libraries_in_progress)
return;
/*
* Define (or redefine) custom GUC variables.
*/
DefineCustomIntVariable("pg_stat_statements.max",
"Sets the maximum number of statements tracked by pg_stat_statements.",
NULL,
&pgss_max,
1000,
100,
INT_MAX,
PGC_POSTMASTER,
0,
NULL,
NULL,
NULL);
DefineCustomEnumVariable("pg_stat_statements.track",
"Selects which statements are tracked by pg_stat_statements.",
NULL,
&pgss_track,
PGSS_TRACK_TOP,
track_options,
PGC_SUSET,
0,
NULL,
NULL,
NULL);
DefineCustomBoolVariable("pg_stat_statements.track_utility",
"Selects whether utility commands are tracked by pg_stat_statements.",
NULL,
&pgss_track_utility,
true,
PGC_SUSET,
0,
NULL,
NULL,
NULL);
DefineCustomBoolVariable("pg_stat_statements.save",
"Save pg_stat_statements statistics across server shutdowns.",
NULL,
&pgss_save,
true,
PGC_SIGHUP,
0,
NULL,
NULL,
NULL);
EmitWarningsOnPlaceholders("pg_stat_statements");
/*
* Request additional shared resources. (These are no-ops if we're not in
* the postmaster process.) We'll allocate or attach to the shared
* resources in pgss_shmem_startup().
*/
RequestAddinShmemSpace(pgss_memsize());
RequestAddinLWLocks(1);
/*
* Install hooks.
*/
prev_shmem_startup_hook = shmem_startup_hook;
shmem_startup_hook = pgss_shmem_startup;
prev_post_parse_analyze_hook = post_parse_analyze_hook;
post_parse_analyze_hook = pgss_post_parse_analyze;
prev_ExecutorStart = ExecutorStart_hook;
ExecutorStart_hook = pgss_ExecutorStart;
prev_ExecutorRun = ExecutorRun_hook;
ExecutorRun_hook = pgss_ExecutorRun;
prev_ExecutorFinish = ExecutorFinish_hook;
ExecutorFinish_hook = pgss_ExecutorFinish;
prev_ExecutorEnd = ExecutorEnd_hook;
ExecutorEnd_hook = pgss_ExecutorEnd;
prev_ProcessUtility = ProcessUtility_hook;
ProcessUtility_hook = pgss_ProcessUtility;
}
| static void AppendJumble | ( | pgssJumbleState * | jstate, | |
| const unsigned char * | item, | |||
| Size | size | |||
| ) | [static] |
Definition at line 1361 of file pg_stat_statements.c.
References hash_any(), pgssJumbleState::jumble, pgssJumbleState::jumble_len, JUMBLE_SIZE, and Min.
{
unsigned char *jumble = jstate->jumble;
Size jumble_len = jstate->jumble_len;
/*
* Whenever the jumble buffer is full, we hash the current contents and
* reset the buffer to contain just that hash value, thus relying on the
* hash to summarize everything so far.
*/
while (size > 0)
{
Size part_size;
if (jumble_len >= JUMBLE_SIZE)
{
uint32 start_hash = hash_any(jumble, JUMBLE_SIZE);
memcpy(jumble, &start_hash, sizeof(start_hash));
jumble_len = sizeof(start_hash);
}
part_size = Min(size, JUMBLE_SIZE - jumble_len);
memcpy(jumble + jumble_len, item, part_size);
jumble_len += part_size;
item += part_size;
size -= part_size;
}
jstate->jumble_len = jumble_len;
}
| static int comp_location | ( | const void * | a, | |
| const void * | b | |||
| ) | [static] |
Definition at line 2114 of file pg_stat_statements.c.
Referenced by fill_in_constant_lengths().
{
int l = ((const pgssLocationLen *) a)->location;
int r = ((const pgssLocationLen *) b)->location;
if (l < r)
return -1;
else if (l > r)
return +1;
else
return 0;
}
| static pgssEntry * entry_alloc | ( | pgssHashKey * | key, | |
| const char * | query, | |||
| int | query_len, | |||
| bool | sticky | |||
| ) | [static] |
Definition at line 1237 of file pg_stat_statements.c.
References Assert, pgssEntry::counters, pgssSharedState::cur_median_usage, entry_dealloc(), HASH_ENTER, hash_get_num_entries(), hash_search(), pgssEntry::mutex, pgss_max, pgssEntry::query, pgssEntry::query_len, SpinLockInit, and Counters::usage.
Referenced by pgss_shmem_startup(), and pgss_store().
{
pgssEntry *entry;
bool found;
/* Make space if needed */
while (hash_get_num_entries(pgss_hash) >= pgss_max)
entry_dealloc();
/* Find or create an entry with desired hash code */
entry = (pgssEntry *) hash_search(pgss_hash, key, HASH_ENTER, &found);
if (!found)
{
/* New entry, initialize it */
/* reset the statistics */
memset(&entry->counters, 0, sizeof(Counters));
/* set the appropriate initial usage count */
entry->counters.usage = sticky ? pgss->cur_median_usage : USAGE_INIT;
/* re-initialize the mutex each time ... we assume no one using it */
SpinLockInit(&entry->mutex);
/* ... and don't forget the query text */
Assert(query_len >= 0 && query_len < pgss->query_size);
entry->query_len = query_len;
memcpy(entry->query, query, query_len);
entry->query[query_len] = '\0';
}
return entry;
}
| static int entry_cmp | ( | const void * | lhs, | |
| const void * | rhs | |||
| ) | [static] |
Definition at line 1273 of file pg_stat_statements.c.
Referenced by entry_dealloc().
| static void entry_dealloc | ( | void | ) | [static] |
Definition at line 1291 of file pg_stat_statements.c.
References Counters::calls, pgssEntry::counters, pgssSharedState::cur_median_usage, entry_cmp(), hash_get_num_entries(), HASH_REMOVE, hash_search(), hash_seq_init(), hash_seq_search(), i, Max, Min, NULL, palloc(), pfree(), qsort, Counters::usage, and USAGE_DEALLOC_PERCENT.
Referenced by entry_alloc().
{
HASH_SEQ_STATUS hash_seq;
pgssEntry **entries;
pgssEntry *entry;
int nvictims;
int i;
/*
* Sort entries by usage and deallocate USAGE_DEALLOC_PERCENT of them.
* While we're scanning the table, apply the decay factor to the usage
* values.
*/
entries = palloc(hash_get_num_entries(pgss_hash) * sizeof(pgssEntry *));
i = 0;
hash_seq_init(&hash_seq, pgss_hash);
while ((entry = hash_seq_search(&hash_seq)) != NULL)
{
entries[i++] = entry;
/* "Sticky" entries get a different usage decay rate. */
if (entry->counters.calls == 0)
entry->counters.usage *= STICKY_DECREASE_FACTOR;
else
entry->counters.usage *= USAGE_DECREASE_FACTOR;
}
qsort(entries, i, sizeof(pgssEntry *), entry_cmp);
/* Also, record the (approximate) median usage */
if (i > 0)
pgss->cur_median_usage = entries[i / 2]->counters.usage;
nvictims = Max(10, i * USAGE_DEALLOC_PERCENT / 100);
nvictims = Min(nvictims, i);
for (i = 0; i < nvictims; i++)
{
hash_search(pgss_hash, &entries[i]->key, HASH_REMOVE, NULL);
}
pfree(entries);
}
| static void entry_reset | ( | void | ) | [static] |
Definition at line 1340 of file pg_stat_statements.c.
References HASH_REMOVE, hash_search(), hash_seq_init(), hash_seq_search(), pgssEntry::key, pgssSharedState::lock, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), and NULL.
Referenced by pg_stat_statements_reset().
{
HASH_SEQ_STATUS hash_seq;
pgssEntry *entry;
LWLockAcquire(pgss->lock, LW_EXCLUSIVE);
hash_seq_init(&hash_seq, pgss_hash);
while ((entry = hash_seq_search(&hash_seq)) != NULL)
{
hash_search(pgss_hash, &entry->key, HASH_REMOVE, NULL);
}
LWLockRelease(pgss->lock);
}
| static void fill_in_constant_lengths | ( | pgssJumbleState * | jstate, | |
| const char * | query | |||
| ) | [static] |
Definition at line 2021 of file pg_stat_statements.c.
References Assert, pgssJumbleState::clocations, pgssJumbleState::clocations_count, comp_location(), core_yylex(), i, pgssLocationLen::length, pgssLocationLen::location, NumScanKeywords, qsort, core_yy_extra_type::scanbuf, ScanKeywords, scanner_finish(), scanner_init(), YYLTYPE, and yyscanner.
Referenced by generate_normalized_query().
{
pgssLocationLen *locs;
core_yyscan_t yyscanner;
core_yy_extra_type yyextra;
core_YYSTYPE yylval;
YYLTYPE yylloc;
int last_loc = -1;
int i;
/*
* Sort the records by location so that we can process them in order while
* scanning the query text.
*/
if (jstate->clocations_count > 1)
qsort(jstate->clocations, jstate->clocations_count,
sizeof(pgssLocationLen), comp_location);
locs = jstate->clocations;
/* initialize the flex scanner --- should match raw_parser() */
yyscanner = scanner_init(query,
&yyextra,
ScanKeywords,
NumScanKeywords);
/* Search for each constant, in sequence */
for (i = 0; i < jstate->clocations_count; i++)
{
int loc = locs[i].location;
int tok;
Assert(loc >= 0);
if (loc <= last_loc)
continue; /* Duplicate constant, ignore */
/* Lex tokens until we find the desired constant */
for (;;)
{
tok = core_yylex(&yylval, &yylloc, yyscanner);
/* We should not hit end-of-string, but if we do, behave sanely */
if (tok == 0)
break; /* out of inner for-loop */
/*
* We should find the token position exactly, but if we somehow
* run past it, work with that.
*/
if (yylloc >= loc)
{
if (query[loc] == '-')
{
/*
* It's a negative value - this is the one and only case
* where we replace more than a single token.
*
* Do not compensate for the core system's special-case
* adjustment of location to that of the leading '-'
* operator in the event of a negative constant. It is
* also useful for our purposes to start from the minus
* symbol. In this way, queries like "select * from foo
* where bar = 1" and "select * from foo where bar = -2"
* will have identical normalized query strings.
*/
tok = core_yylex(&yylval, &yylloc, yyscanner);
if (tok == 0)
break; /* out of inner for-loop */
}
/*
* We now rely on the assumption that flex has placed a zero
* byte after the text of the current token in scanbuf.
*/
locs[i].length = strlen(yyextra.scanbuf + loc);
break; /* out of inner for-loop */
}
}
/* If we hit end-of-string, give up, leaving remaining lengths -1 */
if (tok == 0)
break;
last_loc = loc;
}
scanner_finish(yyscanner);
}
| static char * generate_normalized_query | ( | pgssJumbleState * | jstate, | |
| const char * | query, | |||
| int * | query_len_p, | |||
| int | encoding | |||
| ) | [static] |
Definition at line 1915 of file pg_stat_statements.c.
References Assert, pgssJumbleState::clocations, pgssJumbleState::clocations_count, fill_in_constant_lengths(), i, pgssLocationLen::length, pgssLocationLen::location, Min, palloc(), pg_encoding_mbcliplen(), and pgssSharedState::query_size.
Referenced by pgss_store().
{
char *norm_query;
int query_len = *query_len_p;
int max_output_len;
int i,
len_to_wrt, /* Length (in bytes) to write */
quer_loc = 0, /* Source query byte location */
n_quer_loc = 0, /* Normalized query byte location */
last_off = 0, /* Offset from start for previous tok */
last_tok_len = 0; /* Length (in bytes) of that tok */
/*
* Get constants' lengths (core system only gives us locations). Note
* this also ensures the items are sorted by location.
*/
fill_in_constant_lengths(jstate, query);
/* Allocate result buffer, ensuring we limit result to allowed size */
max_output_len = Min(query_len, pgss->query_size - 1);
norm_query = palloc(max_output_len);
for (i = 0; i < jstate->clocations_count; i++)
{
int off, /* Offset from start for cur tok */
tok_len; /* Length (in bytes) of that tok */
off = jstate->clocations[i].location;
tok_len = jstate->clocations[i].length;
if (tok_len < 0)
continue; /* ignore any duplicates */
/* Copy next chunk, or as much as will fit */
len_to_wrt = off - last_off;
len_to_wrt -= last_tok_len;
len_to_wrt = Min(len_to_wrt, max_output_len - n_quer_loc);
Assert(len_to_wrt >= 0);
memcpy(norm_query + n_quer_loc, query + quer_loc, len_to_wrt);
n_quer_loc += len_to_wrt;
if (n_quer_loc < max_output_len)
norm_query[n_quer_loc++] = '?';
quer_loc = off + tok_len;
last_off = off;
last_tok_len = tok_len;
/* If we run out of space, might as well stop iterating */
if (n_quer_loc >= max_output_len)
break;
}
/*
* We've copied up until the last ignorable constant. Copy over the
* remaining bytes of the original query string, or at least as much as
* will fit.
*/
len_to_wrt = query_len - quer_loc;
len_to_wrt = Min(len_to_wrt, max_output_len - n_quer_loc);
Assert(len_to_wrt >= 0);
memcpy(norm_query + n_quer_loc, query + quer_loc, len_to_wrt);
n_quer_loc += len_to_wrt;
/*
* If we ran out of space, we need to do an encoding-aware truncation,
* just to make sure we don't have an incomplete character at the end.
*/
if (n_quer_loc >= max_output_len)
query_len = pg_encoding_mbcliplen(encoding,
norm_query,
n_quer_loc,
pgss->query_size - 1);
else
query_len = n_quer_loc;
*query_len_p = query_len;
return norm_query;
}
| static void JumbleExpr | ( | pgssJumbleState * | jstate, | |
| Node * | node | |||
| ) | [static] |
Definition at line 1495 of file pg_stat_statements.c.
References Aggref::aggdistinct, Aggref::aggfnoid, Aggref::aggorder, SetOperationStmt::all, APP_JUMB, APP_JUMB_STRING, CoerceToDomain::arg, BooleanTest::arg, NullTest::arg, CaseExpr::arg, CollateExpr::arg, ConvertRowtypeExpr::arg, ArrayCoerceExpr::arg, CoerceViaIO::arg, RelabelType::arg, FieldStore::arg, FieldSelect::arg, NamedArgExpr::arg, NamedArgExpr::argnumber, XmlExpr::args, MinMaxExpr::args, CaseExpr::args, BoolExpr::args, ScalarArrayOpExpr::args, OpExpr::args, FuncExpr::args, WindowFunc::args, Aggref::args, Assert, BoolExpr::boolop, BooleanTest::booltesttype, check_stack_depth(), CollateExpr::collOid, Const::consttype, CommonTableExpr::ctename, CommonTableExpr::ctequery, CurrentOfExpr::cursor_name, CurrentOfExpr::cursor_param, CurrentOfExpr::cvarno, CaseExpr::defresult, elog, WindowClause::endOffset, SortGroupClause::eqop, TargetEntry::expr, CaseWhen::expr, FieldSelect::fieldnum, WindowClause::frameOptions, FromExpr::fromlist, FuncExpr::funcid, IsA, JoinExpr::isNatural, JoinExpr::jointype, JumbleQuery(), SetOperationStmt::larg, JoinExpr::larg, RowCompareExpr::largs, lfirst, Const::location, XmlExpr::named_args, FieldStore::newvals, nodeTag, NULL, SortGroupClause::nulls_first, NullTest::nulltesttype, SetOperationStmt::op, XmlExpr::op, MinMaxExpr::op, ScalarArrayOpExpr::opno, OpExpr::opno, WindowClause::orderClause, Param::paramid, Param::paramkind, Param::paramtype, WindowClause::partitionClause, FromExpr::quals, JoinExpr::quals, SetOperationStmt::rarg, JoinExpr::rarg, RowCompareExpr::rargs, RowCompareExpr::rctype, RecordConstLocation(), ArrayRef::refassgnexpr, ArrayRef::refexpr, ArrayRef::reflowerindexpr, ArrayRef::refupperindexpr, TargetEntry::resno, TargetEntry::ressortgroupref, CaseWhen::result, CoerceToDomain::resulttype, ConvertRowtypeExpr::resulttype, ArrayCoerceExpr::resulttype, CoerceViaIO::resulttype, RelabelType::resulttype, JoinExpr::rtindex, RangeTblRef::rtindex, SortGroupClause::sortop, WindowClause::startOffset, SubLink::subLinkType, SubLink::subselect, T_Aggref, T_ArrayCoerceExpr, T_ArrayExpr, T_ArrayRef, T_BooleanTest, T_BoolExpr, T_CaseExpr, T_CaseTestExpr, T_CoalesceExpr, T_CoerceToDomain, T_CoerceToDomainValue, T_CoerceViaIO, T_CollateExpr, T_CommonTableExpr, T_Const, T_ConvertRowtypeExpr, T_CurrentOfExpr, T_DistinctExpr, T_FieldSelect, T_FieldStore, T_FromExpr, T_FuncExpr, T_JoinExpr, T_List, T_MinMaxExpr, T_NamedArgExpr, T_NullIfExpr, T_NullTest, T_OpExpr, T_Param, T_RangeTblRef, T_RelabelType, T_RowCompareExpr, T_RowExpr, T_ScalarArrayOpExpr, T_SetOperationStmt, T_SetToDefault, T_SortGroupClause, T_SubLink, T_TargetEntry, T_Var, T_WindowClause, T_WindowFunc, T_XmlExpr, SubLink::testexpr, SortGroupClause::tleSortGroupRef, Node::type, SetToDefault::typeId, CoerceToDomainValue::typeId, CaseTestExpr::typeId, ScalarArrayOpExpr::useOr, Var::varattno, Var::varlevelsup, Var::varno, WARNING, WindowFunc::winfnoid, WindowClause::winref, and WindowFunc::winref.
Referenced by JumbleQuery(), and JumbleRangeTable().
{
ListCell *temp;
if (node == NULL)
return;
/* Guard against stack overflow due to overly complex expressions */
check_stack_depth();
/*
* We always emit the node's NodeTag, then any additional fields that are
* considered significant, and then we recurse to any child nodes.
*/
APP_JUMB(node->type);
switch (nodeTag(node))
{
case T_Var:
{
Var *var = (Var *) node;
APP_JUMB(var->varno);
APP_JUMB(var->varattno);
APP_JUMB(var->varlevelsup);
}
break;
case T_Const:
{
Const *c = (Const *) node;
/* We jumble only the constant's type, not its value */
APP_JUMB(c->consttype);
/* Also, record its parse location for query normalization */
RecordConstLocation(jstate, c->location);
}
break;
case T_Param:
{
Param *p = (Param *) node;
APP_JUMB(p->paramkind);
APP_JUMB(p->paramid);
APP_JUMB(p->paramtype);
}
break;
case T_Aggref:
{
Aggref *expr = (Aggref *) node;
APP_JUMB(expr->aggfnoid);
JumbleExpr(jstate, (Node *) expr->args);
JumbleExpr(jstate, (Node *) expr->aggorder);
JumbleExpr(jstate, (Node *) expr->aggdistinct);
}
break;
case T_WindowFunc:
{
WindowFunc *expr = (WindowFunc *) node;
APP_JUMB(expr->winfnoid);
APP_JUMB(expr->winref);
JumbleExpr(jstate, (Node *) expr->args);
}
break;
case T_ArrayRef:
{
ArrayRef *aref = (ArrayRef *) node;
JumbleExpr(jstate, (Node *) aref->refupperindexpr);
JumbleExpr(jstate, (Node *) aref->reflowerindexpr);
JumbleExpr(jstate, (Node *) aref->refexpr);
JumbleExpr(jstate, (Node *) aref->refassgnexpr);
}
break;
case T_FuncExpr:
{
FuncExpr *expr = (FuncExpr *) node;
APP_JUMB(expr->funcid);
JumbleExpr(jstate, (Node *) expr->args);
}
break;
case T_NamedArgExpr:
{
NamedArgExpr *nae = (NamedArgExpr *) node;
APP_JUMB(nae->argnumber);
JumbleExpr(jstate, (Node *) nae->arg);
}
break;
case T_OpExpr:
case T_DistinctExpr: /* struct-equivalent to OpExpr */
case T_NullIfExpr: /* struct-equivalent to OpExpr */
{
OpExpr *expr = (OpExpr *) node;
APP_JUMB(expr->opno);
JumbleExpr(jstate, (Node *) expr->args);
}
break;
case T_ScalarArrayOpExpr:
{
ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
APP_JUMB(expr->opno);
APP_JUMB(expr->useOr);
JumbleExpr(jstate, (Node *) expr->args);
}
break;
case T_BoolExpr:
{
BoolExpr *expr = (BoolExpr *) node;
APP_JUMB(expr->boolop);
JumbleExpr(jstate, (Node *) expr->args);
}
break;
case T_SubLink:
{
SubLink *sublink = (SubLink *) node;
APP_JUMB(sublink->subLinkType);
JumbleExpr(jstate, (Node *) sublink->testexpr);
JumbleQuery(jstate, (Query *) sublink->subselect);
}
break;
case T_FieldSelect:
{
FieldSelect *fs = (FieldSelect *) node;
APP_JUMB(fs->fieldnum);
JumbleExpr(jstate, (Node *) fs->arg);
}
break;
case T_FieldStore:
{
FieldStore *fstore = (FieldStore *) node;
JumbleExpr(jstate, (Node *) fstore->arg);
JumbleExpr(jstate, (Node *) fstore->newvals);
}
break;
case T_RelabelType:
{
RelabelType *rt = (RelabelType *) node;
APP_JUMB(rt->resulttype);
JumbleExpr(jstate, (Node *) rt->arg);
}
break;
case T_CoerceViaIO:
{
CoerceViaIO *cio = (CoerceViaIO *) node;
APP_JUMB(cio->resulttype);
JumbleExpr(jstate, (Node *) cio->arg);
}
break;
case T_ArrayCoerceExpr:
{
ArrayCoerceExpr *acexpr = (ArrayCoerceExpr *) node;
APP_JUMB(acexpr->resulttype);
JumbleExpr(jstate, (Node *) acexpr->arg);
}
break;
case T_ConvertRowtypeExpr:
{
ConvertRowtypeExpr *crexpr = (ConvertRowtypeExpr *) node;
APP_JUMB(crexpr->resulttype);
JumbleExpr(jstate, (Node *) crexpr->arg);
}
break;
case T_CollateExpr:
{
CollateExpr *ce = (CollateExpr *) node;
APP_JUMB(ce->collOid);
JumbleExpr(jstate, (Node *) ce->arg);
}
break;
case T_CaseExpr:
{
CaseExpr *caseexpr = (CaseExpr *) node;
JumbleExpr(jstate, (Node *) caseexpr->arg);
foreach(temp, caseexpr->args)
{
CaseWhen *when = (CaseWhen *) lfirst(temp);
Assert(IsA(when, CaseWhen));
JumbleExpr(jstate, (Node *) when->expr);
JumbleExpr(jstate, (Node *) when->result);
}
JumbleExpr(jstate, (Node *) caseexpr->defresult);
}
break;
case T_CaseTestExpr:
{
CaseTestExpr *ct = (CaseTestExpr *) node;
APP_JUMB(ct->typeId);
}
break;
case T_ArrayExpr:
JumbleExpr(jstate, (Node *) ((ArrayExpr *) node)->elements);
break;
case T_RowExpr:
JumbleExpr(jstate, (Node *) ((RowExpr *) node)->args);
break;
case T_RowCompareExpr:
{
RowCompareExpr *rcexpr = (RowCompareExpr *) node;
APP_JUMB(rcexpr->rctype);
JumbleExpr(jstate, (Node *) rcexpr->largs);
JumbleExpr(jstate, (Node *) rcexpr->rargs);
}
break;
case T_CoalesceExpr:
JumbleExpr(jstate, (Node *) ((CoalesceExpr *) node)->args);
break;
case T_MinMaxExpr:
{
MinMaxExpr *mmexpr = (MinMaxExpr *) node;
APP_JUMB(mmexpr->op);
JumbleExpr(jstate, (Node *) mmexpr->args);
}
break;
case T_XmlExpr:
{
XmlExpr *xexpr = (XmlExpr *) node;
APP_JUMB(xexpr->op);
JumbleExpr(jstate, (Node *) xexpr->named_args);
JumbleExpr(jstate, (Node *) xexpr->args);
}
break;
case T_NullTest:
{
NullTest *nt = (NullTest *) node;
APP_JUMB(nt->nulltesttype);
JumbleExpr(jstate, (Node *) nt->arg);
}
break;
case T_BooleanTest:
{
BooleanTest *bt = (BooleanTest *) node;
APP_JUMB(bt->booltesttype);
JumbleExpr(jstate, (Node *) bt->arg);
}
break;
case T_CoerceToDomain:
{
CoerceToDomain *cd = (CoerceToDomain *) node;
APP_JUMB(cd->resulttype);
JumbleExpr(jstate, (Node *) cd->arg);
}
break;
case T_CoerceToDomainValue:
{
CoerceToDomainValue *cdv = (CoerceToDomainValue *) node;
APP_JUMB(cdv->typeId);
}
break;
case T_SetToDefault:
{
SetToDefault *sd = (SetToDefault *) node;
APP_JUMB(sd->typeId);
}
break;
case T_CurrentOfExpr:
{
CurrentOfExpr *ce = (CurrentOfExpr *) node;
APP_JUMB(ce->cvarno);
if (ce->cursor_name)
APP_JUMB_STRING(ce->cursor_name);
APP_JUMB(ce->cursor_param);
}
break;
case T_TargetEntry:
{
TargetEntry *tle = (TargetEntry *) node;
APP_JUMB(tle->resno);
APP_JUMB(tle->ressortgroupref);
JumbleExpr(jstate, (Node *) tle->expr);
}
break;
case T_RangeTblRef:
{
RangeTblRef *rtr = (RangeTblRef *) node;
APP_JUMB(rtr->rtindex);
}
break;
case T_JoinExpr:
{
JoinExpr *join = (JoinExpr *) node;
APP_JUMB(join->jointype);
APP_JUMB(join->isNatural);
APP_JUMB(join->rtindex);
JumbleExpr(jstate, join->larg);
JumbleExpr(jstate, join->rarg);
JumbleExpr(jstate, join->quals);
}
break;
case T_FromExpr:
{
FromExpr *from = (FromExpr *) node;
JumbleExpr(jstate, (Node *) from->fromlist);
JumbleExpr(jstate, from->quals);
}
break;
case T_List:
foreach(temp, (List *) node)
{
JumbleExpr(jstate, (Node *) lfirst(temp));
}
break;
case T_SortGroupClause:
{
SortGroupClause *sgc = (SortGroupClause *) node;
APP_JUMB(sgc->tleSortGroupRef);
APP_JUMB(sgc->eqop);
APP_JUMB(sgc->sortop);
APP_JUMB(sgc->nulls_first);
}
break;
case T_WindowClause:
{
WindowClause *wc = (WindowClause *) node;
APP_JUMB(wc->winref);
APP_JUMB(wc->frameOptions);
JumbleExpr(jstate, (Node *) wc->partitionClause);
JumbleExpr(jstate, (Node *) wc->orderClause);
JumbleExpr(jstate, wc->startOffset);
JumbleExpr(jstate, wc->endOffset);
}
break;
case T_CommonTableExpr:
{
CommonTableExpr *cte = (CommonTableExpr *) node;
/* we store the string name because RTE_CTE RTEs need it */
APP_JUMB_STRING(cte->ctename);
JumbleQuery(jstate, (Query *) cte->ctequery);
}
break;
case T_SetOperationStmt:
{
SetOperationStmt *setop = (SetOperationStmt *) node;
APP_JUMB(setop->op);
APP_JUMB(setop->all);
JumbleExpr(jstate, setop->larg);
JumbleExpr(jstate, setop->rarg);
}
break;
default:
/* Only a warning, since we can stumble along anyway */
elog(WARNING, "unrecognized node type: %d",
(int) nodeTag(node));
break;
}
}
| static void JumbleQuery | ( | pgssJumbleState * | jstate, | |
| Query * | query | |||
| ) | [static] |
Definition at line 1410 of file pg_stat_statements.c.
References APP_JUMB, Assert, Query::commandType, Query::cteList, Query::distinctClause, Query::groupClause, Query::havingQual, IsA, Query::jointree, JumbleExpr(), JumbleRangeTable(), Query::limitCount, Query::limitOffset, NULL, Query::returningList, Query::rtable, Query::setOperations, Query::sortClause, Query::targetList, Query::utilityStmt, and Query::windowClause.
Referenced by JumbleExpr(), JumbleRangeTable(), and pgss_post_parse_analyze().
{
Assert(IsA(query, Query));
Assert(query->utilityStmt == NULL);
APP_JUMB(query->commandType);
/* resultRelation is usually predictable from commandType */
JumbleExpr(jstate, (Node *) query->cteList);
JumbleRangeTable(jstate, query->rtable);
JumbleExpr(jstate, (Node *) query->jointree);
JumbleExpr(jstate, (Node *) query->targetList);
JumbleExpr(jstate, (Node *) query->returningList);
JumbleExpr(jstate, (Node *) query->groupClause);
JumbleExpr(jstate, query->havingQual);
JumbleExpr(jstate, (Node *) query->windowClause);
JumbleExpr(jstate, (Node *) query->distinctClause);
JumbleExpr(jstate, (Node *) query->sortClause);
JumbleExpr(jstate, query->limitOffset);
JumbleExpr(jstate, query->limitCount);
/* we ignore rowMarks */
JumbleExpr(jstate, query->setOperations);
}
| static void JumbleRangeTable | ( | pgssJumbleState * | jstate, | |
| List * | rtable | |||
| ) | [static] |
Definition at line 1437 of file pg_stat_statements.c.
References APP_JUMB, APP_JUMB_STRING, Assert, RangeTblEntry::ctelevelsup, RangeTblEntry::ctename, elog, ERROR, RangeTblEntry::funcexpr, IsA, RangeTblEntry::jointype, JumbleExpr(), JumbleQuery(), lfirst, RangeTblEntry::relid, RTE_CTE, RTE_FUNCTION, RTE_JOIN, RTE_RELATION, RTE_SUBQUERY, RTE_VALUES, RangeTblEntry::rtekind, RangeTblEntry::subquery, and RangeTblEntry::values_lists.
Referenced by JumbleQuery().
{
ListCell *lc;
foreach(lc, rtable)
{
RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
Assert(IsA(rte, RangeTblEntry));
APP_JUMB(rte->rtekind);
switch (rte->rtekind)
{
case RTE_RELATION:
APP_JUMB(rte->relid);
break;
case RTE_SUBQUERY:
JumbleQuery(jstate, rte->subquery);
break;
case RTE_JOIN:
APP_JUMB(rte->jointype);
break;
case RTE_FUNCTION:
JumbleExpr(jstate, rte->funcexpr);
break;
case RTE_VALUES:
JumbleExpr(jstate, (Node *) rte->values_lists);
break;
case RTE_CTE:
/*
* Depending on the CTE name here isn't ideal, but it's the
* only info we have to identify the referenced WITH item.
*/
APP_JUMB_STRING(rte->ctename);
APP_JUMB(rte->ctelevelsup);
break;
default:
elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
break;
}
}
}
| PG_FUNCTION_INFO_V1 | ( | pg_stat_statements_reset | ) |
| PG_FUNCTION_INFO_V1 | ( | pg_stat_statements | ) |
| Datum pg_stat_statements | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1078 of file pg_stat_statements.c.
References ReturnSetInfo::allowedModes, Assert, Counters::blk_read_time, Counters::blk_write_time, Counters::calls, pgssEntry::counters, CStringGetTextDatum, pgssHashKey::dbid, ReturnSetInfo::econtext, ExprContext::ecxt_per_query_memory, elog, pgssHashKey::encoding, ereport, errcode(), errmsg(), ERROR, Float8GetDatumFast, get_call_result_type(), GetDatabaseEncoding(), GetUserId(), hash_seq_init(), hash_seq_search(), i, Int64GetDatumFast, is_superuser(), IsA, pgssEntry::key, Counters::local_blks_dirtied, Counters::local_blks_hit, Counters::local_blks_read, Counters::local_blks_written, pgssSharedState::lock, LW_SHARED, LWLockAcquire(), LWLockRelease(), MemoryContextSwitchTo(), pgssEntry::mutex, NULL, ObjectIdGetDatum, pfree(), pg_do_encoding_conversion(), PG_STAT_STATEMENTS_COLS, PG_STAT_STATEMENTS_COLS_V1_0, pgssEntry::query, pgssEntry::query_len, ReturnSetInfo::returnMode, Counters::rows, ReturnSetInfo::setDesc, ReturnSetInfo::setResult, SFRM_Materialize, Counters::shared_blks_dirtied, Counters::shared_blks_hit, Counters::shared_blks_read, Counters::shared_blks_written, SpinLockAcquire, SpinLockRelease, superuser(), Counters::temp_blks_read, Counters::temp_blks_written, Counters::total_time, tuplestore_begin_heap(), tuplestore_donestoring, tuplestore_putvalues(), TYPEFUNC_COMPOSITE, pgssHashKey::userid, values, and work_mem.
{
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
TupleDesc tupdesc;
Tuplestorestate *tupstore;
MemoryContext per_query_ctx;
MemoryContext oldcontext;
Oid userid = GetUserId();
bool is_superuser = superuser();
HASH_SEQ_STATUS hash_seq;
pgssEntry *entry;
bool sql_supports_v1_1_counters = true;
if (!pgss || !pgss_hash)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("pg_stat_statements must be loaded via shared_preload_libraries")));
/* check to see if caller supports us returning a tuplestore */
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("set-valued function called in context that cannot accept a set")));
if (!(rsinfo->allowedModes & SFRM_Materialize))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("materialize mode required, but it is not " \
"allowed in this context")));
/* Build a tuple descriptor for our result type */
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
elog(ERROR, "return type must be a row type");
if (tupdesc->natts == PG_STAT_STATEMENTS_COLS_V1_0)
sql_supports_v1_1_counters = false;
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
oldcontext = MemoryContextSwitchTo(per_query_ctx);
tupstore = tuplestore_begin_heap(true, false, work_mem);
rsinfo->returnMode = SFRM_Materialize;
rsinfo->setResult = tupstore;
rsinfo->setDesc = tupdesc;
MemoryContextSwitchTo(oldcontext);
LWLockAcquire(pgss->lock, LW_SHARED);
hash_seq_init(&hash_seq, pgss_hash);
while ((entry = hash_seq_search(&hash_seq)) != NULL)
{
Datum values[PG_STAT_STATEMENTS_COLS];
bool nulls[PG_STAT_STATEMENTS_COLS];
int i = 0;
Counters tmp;
memset(values, 0, sizeof(values));
memset(nulls, 0, sizeof(nulls));
values[i++] = ObjectIdGetDatum(entry->key.userid);
values[i++] = ObjectIdGetDatum(entry->key.dbid);
if (is_superuser || entry->key.userid == userid)
{
char *qstr;
qstr = (char *)
pg_do_encoding_conversion((unsigned char *) entry->query,
entry->query_len,
entry->key.encoding,
GetDatabaseEncoding());
values[i++] = CStringGetTextDatum(qstr);
if (qstr != entry->query)
pfree(qstr);
}
else
values[i++] = CStringGetTextDatum("<insufficient privilege>");
/* copy counters to a local variable to keep locking time short */
{
volatile pgssEntry *e = (volatile pgssEntry *) entry;
SpinLockAcquire(&e->mutex);
tmp = e->counters;
SpinLockRelease(&e->mutex);
}
/* Skip entry if unexecuted (ie, it's a pending "sticky" entry) */
if (tmp.calls == 0)
continue;
values[i++] = Int64GetDatumFast(tmp.calls);
values[i++] = Float8GetDatumFast(tmp.total_time);
values[i++] = Int64GetDatumFast(tmp.rows);
values[i++] = Int64GetDatumFast(tmp.shared_blks_hit);
values[i++] = Int64GetDatumFast(tmp.shared_blks_read);
if (sql_supports_v1_1_counters)
values[i++] = Int64GetDatumFast(tmp.shared_blks_dirtied);
values[i++] = Int64GetDatumFast(tmp.shared_blks_written);
values[i++] = Int64GetDatumFast(tmp.local_blks_hit);
values[i++] = Int64GetDatumFast(tmp.local_blks_read);
if (sql_supports_v1_1_counters)
values[i++] = Int64GetDatumFast(tmp.local_blks_dirtied);
values[i++] = Int64GetDatumFast(tmp.local_blks_written);
values[i++] = Int64GetDatumFast(tmp.temp_blks_read);
values[i++] = Int64GetDatumFast(tmp.temp_blks_written);
if (sql_supports_v1_1_counters)
{
values[i++] = Float8GetDatumFast(tmp.blk_read_time);
values[i++] = Float8GetDatumFast(tmp.blk_write_time);
}
Assert(i == (sql_supports_v1_1_counters ?
PG_STAT_STATEMENTS_COLS : PG_STAT_STATEMENTS_COLS_V1_0));
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
}
LWLockRelease(pgss->lock);
/* clean up and return the tuplestore */
tuplestore_donestoring(tupstore);
return (Datum) 0;
}
| Datum pg_stat_statements_reset | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1061 of file pg_stat_statements.c.
References entry_reset(), ereport, errcode(), errmsg(), ERROR, and PG_RETURN_VOID.
{
if (!pgss || !pgss_hash)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("pg_stat_statements must be loaded via shared_preload_libraries")));
entry_reset();
PG_RETURN_VOID();
}
| static void pgss_ExecutorEnd | ( | QueryDesc * | queryDesc | ) | [static] |
Definition at line 757 of file pg_stat_statements.c.
References Instrumentation::bufusage, EState::es_processed, QueryDesc::estate, InstrEndLoop(), NULL, pgss_enabled, pgss_store(), QueryDesc::plannedstmt, prev_ExecutorEnd, PlannedStmt::queryId, QueryDesc::sourceText, standard_ExecutorEnd(), Instrumentation::total, and QueryDesc::totaltime.
{
uint32 queryId = queryDesc->plannedstmt->queryId;
if (queryId != 0 && queryDesc->totaltime && pgss_enabled())
{
/*
* Make sure stats accumulation is done. (Note: it's okay if several
* levels of hook all do this.)
*/
InstrEndLoop(queryDesc->totaltime);
pgss_store(queryDesc->sourceText,
queryId,
queryDesc->totaltime->total * 1000.0, /* convert to msec */
queryDesc->estate->es_processed,
&queryDesc->totaltime->bufusage,
NULL);
}
if (prev_ExecutorEnd)
prev_ExecutorEnd(queryDesc);
else
standard_ExecutorEnd(queryDesc);
}
| static void pgss_ExecutorFinish | ( | QueryDesc * | queryDesc | ) | [static] |
Definition at line 734 of file pg_stat_statements.c.
References nested_level, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, prev_ExecutorFinish, and standard_ExecutorFinish().
{
nested_level++;
PG_TRY();
{
if (prev_ExecutorFinish)
prev_ExecutorFinish(queryDesc);
else
standard_ExecutorFinish(queryDesc);
nested_level--;
}
PG_CATCH();
{
nested_level--;
PG_RE_THROW();
}
PG_END_TRY();
}
| static void pgss_ExecutorRun | ( | QueryDesc * | queryDesc, | |
| ScanDirection | direction, | |||
| long | count | |||
| ) | [static] |
Definition at line 711 of file pg_stat_statements.c.
References nested_level, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, prev_ExecutorRun, and standard_ExecutorRun().
{
nested_level++;
PG_TRY();
{
if (prev_ExecutorRun)
prev_ExecutorRun(queryDesc, direction, count);
else
standard_ExecutorRun(queryDesc, direction, count);
nested_level--;
}
PG_CATCH();
{
nested_level--;
PG_RE_THROW();
}
PG_END_TRY();
}
| static void pgss_ExecutorStart | ( | QueryDesc * | queryDesc, | |
| int | eflags | |||
| ) | [static] |
Definition at line 677 of file pg_stat_statements.c.
References EState::es_query_cxt, QueryDesc::estate, InstrAlloc(), INSTRUMENT_ALL, MemoryContextSwitchTo(), NULL, pgss_enabled, QueryDesc::plannedstmt, prev_ExecutorStart, PlannedStmt::queryId, standard_ExecutorStart(), and QueryDesc::totaltime.
{
if (prev_ExecutorStart)
prev_ExecutorStart(queryDesc, eflags);
else
standard_ExecutorStart(queryDesc, eflags);
/*
* If query has queryId zero, don't track it. This prevents double
* counting of optimizable statements that are directly contained in
* utility statements.
*/
if (pgss_enabled() && queryDesc->plannedstmt->queryId != 0)
{
/*
* Set up to track total elapsed time in ExecutorRun. Make sure the
* space is allocated in the per-query context so it will go away at
* ExecutorEnd.
*/
if (queryDesc->totaltime == NULL)
{
MemoryContext oldcxt;
oldcxt = MemoryContextSwitchTo(queryDesc->estate->es_query_cxt);
queryDesc->totaltime = InstrAlloc(1, INSTRUMENT_ALL);
MemoryContextSwitchTo(oldcxt);
}
}
}
Definition at line 898 of file pg_stat_statements.c.
References pgssHashKey::dbid, hash_uint32(), pgssHashKey::queryid, and pgssHashKey::userid.
{
const pgssHashKey *k = (const pgssHashKey *) key;
/* we don't bother to include encoding in the hash */
return hash_uint32((uint32) k->userid) ^
hash_uint32((uint32) k->dbid) ^
hash_uint32((uint32) k->queryid);
}
| static uint32 pgss_hash_string | ( | const char * | str | ) | [static] |
Definition at line 932 of file pg_stat_statements.c.
References hash_any().
Referenced by pgss_ProcessUtility().
{
return hash_any((const unsigned char *) str, strlen(str));
}
| static int pgss_match_fn | ( | const void * | key1, | |
| const void * | key2, | |||
| Size | keysize | |||
| ) | [static] |
Definition at line 912 of file pg_stat_statements.c.
References pgssHashKey::dbid, pgssHashKey::encoding, pgssHashKey::queryid, and pgssHashKey::userid.
{
const pgssHashKey *k1 = (const pgssHashKey *) key1;
const pgssHashKey *k2 = (const pgssHashKey *) key2;
if (k1->userid == k2->userid &&
k1->dbid == k2->dbid &&
k1->encoding == k2->encoding &&
k1->queryid == k2->queryid)
return 0;
else
return 1;
}
| static Size pgss_memsize | ( | void | ) | [static] |
Definition at line 1207 of file pg_stat_statements.c.
References add_size(), hash_estimate_size(), MAXALIGN, offsetof, pgss_max, and pgstat_track_activity_query_size.
Referenced by _PG_init().
{
Size size;
Size entrysize;
size = MAXALIGN(sizeof(pgssSharedState));
entrysize = offsetof(pgssEntry, query) +pgstat_track_activity_query_size;
size = add_size(size, hash_estimate_size(pgss_max, entrysize));
return size;
}
| static void pgss_post_parse_analyze | ( | ParseState * | pstate, | |
| Query * | query | |||
| ) | [static] |
Definition at line 613 of file pg_stat_statements.c.
References Assert, pgssJumbleState::clocations, pgssJumbleState::clocations_buf_size, pgssJumbleState::clocations_count, hash_any(), pgssJumbleState::jumble, pgssJumbleState::jumble_len, JUMBLE_SIZE, JumbleQuery(), NULL, ParseState::p_sourcetext, palloc(), pgss_store(), Query::queryId, and Query::utilityStmt.
{
pgssJumbleState jstate;
/* Assert we didn't do this already */
Assert(query->queryId == 0);
/* Safety check... */
if (!pgss || !pgss_hash)
return;
/*
* Utility statements get queryId zero. We do this even in cases where
* the statement contains an optimizable statement for which a queryId
* could be derived (such as EXPLAIN or DECLARE CURSOR). For such cases,
* runtime control will first go through ProcessUtility and then the
* executor, and we don't want the executor hooks to do anything, since we
* are already measuring the statement's costs at the utility level.
*/
if (query->utilityStmt)
{
query->queryId = 0;
return;
}
/* Set up workspace for query jumbling */
jstate.jumble = (unsigned char *) palloc(JUMBLE_SIZE);
jstate.jumble_len = 0;
jstate.clocations_buf_size = 32;
jstate.clocations = (pgssLocationLen *)
palloc(jstate.clocations_buf_size * sizeof(pgssLocationLen));
jstate.clocations_count = 0;
/* Compute query ID and mark the Query node with it */
JumbleQuery(&jstate, query);
query->queryId = hash_any(jstate.jumble, jstate.jumble_len);
/*
* If we are unlucky enough to get a hash of zero, use 1 instead, to
* prevent confusion with the utility-statement case.
*/
if (query->queryId == 0)
query->queryId = 1;
/*
* If we were able to identify any ignorable constants, we immediately
* create a hash table entry for the query, so that we can record the
* normalized form of the query string. If there were no such constants,
* the normalized string would be the same as the query text anyway, so
* there's no need for an early entry.
*/
if (jstate.clocations_count > 0)
pgss_store(pstate->p_sourcetext,
query->queryId,
0,
0,
NULL,
&jstate);
}
| static void pgss_ProcessUtility | ( | Node * | parsetree, | |
| const char * | queryString, | |||
| ProcessUtilityContext | context, | |||
| ParamListInfo | params, | |||
| DestReceiver * | dest, | |||
| char * | completionTag | |||
| ) | [static] |
Definition at line 787 of file pg_stat_statements.c.
References BufferUsage::blk_read_time, BufferUsage::blk_write_time, duration, INSTR_TIME_GET_MILLISEC, INSTR_TIME_SET_CURRENT, INSTR_TIME_SUBTRACT, IsA, BufferUsage::local_blks_dirtied, BufferUsage::local_blks_hit, BufferUsage::local_blks_read, BufferUsage::local_blks_written, nested_level, NULL, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, pgBufferUsage, pgss_enabled, pgss_hash_string(), pgss_store(), pgss_track_utility, prev_ProcessUtility, BufferUsage::shared_blks_dirtied, BufferUsage::shared_blks_hit, BufferUsage::shared_blks_read, BufferUsage::shared_blks_written, standard_ProcessUtility(), BufferUsage::temp_blks_read, and BufferUsage::temp_blks_written.
{
/*
* If it's an EXECUTE statement, we don't track it and don't increment the
* nesting level. This allows the cycles to be charged to the underlying
* PREPARE instead (by the Executor hooks), which is much more useful.
*
* We also don't track execution of PREPARE. If we did, we would get one
* hash table entry for the PREPARE (with hash calculated from the query
* string), and then a different one with the same query string (but hash
* calculated from the query tree) would be used to accumulate costs of
* ensuing EXECUTEs. This would be confusing, and inconsistent with other
* cases where planning time is not included at all.
*/
if (pgss_track_utility && pgss_enabled() &&
!IsA(parsetree, ExecuteStmt) &&
!IsA(parsetree, PrepareStmt))
{
instr_time start;
instr_time duration;
uint64 rows = 0;
BufferUsage bufusage_start,
bufusage;
uint32 queryId;
bufusage_start = pgBufferUsage;
INSTR_TIME_SET_CURRENT(start);
nested_level++;
PG_TRY();
{
if (prev_ProcessUtility)
prev_ProcessUtility(parsetree, queryString,
context, params,
dest, completionTag);
else
standard_ProcessUtility(parsetree, queryString,
context, params,
dest, completionTag);
nested_level--;
}
PG_CATCH();
{
nested_level--;
PG_RE_THROW();
}
PG_END_TRY();
INSTR_TIME_SET_CURRENT(duration);
INSTR_TIME_SUBTRACT(duration, start);
/* parse command tag to retrieve the number of affected rows. */
if (completionTag &&
sscanf(completionTag, "COPY " UINT64_FORMAT, &rows) != 1)
rows = 0;
/* calc differences of buffer counters. */
bufusage.shared_blks_hit =
pgBufferUsage.shared_blks_hit - bufusage_start.shared_blks_hit;
bufusage.shared_blks_read =
pgBufferUsage.shared_blks_read - bufusage_start.shared_blks_read;
bufusage.shared_blks_dirtied =
pgBufferUsage.shared_blks_dirtied - bufusage_start.shared_blks_dirtied;
bufusage.shared_blks_written =
pgBufferUsage.shared_blks_written - bufusage_start.shared_blks_written;
bufusage.local_blks_hit =
pgBufferUsage.local_blks_hit - bufusage_start.local_blks_hit;
bufusage.local_blks_read =
pgBufferUsage.local_blks_read - bufusage_start.local_blks_read;
bufusage.local_blks_dirtied =
pgBufferUsage.local_blks_dirtied - bufusage_start.local_blks_dirtied;
bufusage.local_blks_written =
pgBufferUsage.local_blks_written - bufusage_start.local_blks_written;
bufusage.temp_blks_read =
pgBufferUsage.temp_blks_read - bufusage_start.temp_blks_read;
bufusage.temp_blks_written =
pgBufferUsage.temp_blks_written - bufusage_start.temp_blks_written;
bufusage.blk_read_time = pgBufferUsage.blk_read_time;
INSTR_TIME_SUBTRACT(bufusage.blk_read_time, bufusage_start.blk_read_time);
bufusage.blk_write_time = pgBufferUsage.blk_write_time;
INSTR_TIME_SUBTRACT(bufusage.blk_write_time, bufusage_start.blk_write_time);
/* For utility statements, we just hash the query string directly */
queryId = pgss_hash_string(queryString);
pgss_store(queryString,
queryId,
INSTR_TIME_GET_MILLISEC(duration),
rows,
&bufusage,
NULL);
}
else
{
if (prev_ProcessUtility)
prev_ProcessUtility(parsetree, queryString,
context, params,
dest, completionTag);
else
standard_ProcessUtility(parsetree, queryString,
context, params,
dest, completionTag);
}
}
| static void pgss_shmem_shutdown | ( | int | code, | |
| Datum | arg | |||
| ) | [static] |
Definition at line 543 of file pg_stat_statements.c.
References AllocateFile(), ereport, errcode_for_file_access(), errmsg(), error(), FreeFile(), hash_get_num_entries(), hash_seq_init(), hash_seq_search(), LOG, NULL, offsetof, PG_BINARY_W, PGSS_DUMP_FILE, PGSS_FILE_HEADER, pgss_save, pgssEntry::query, pgssEntry::query_len, and unlink().
Referenced by pgss_shmem_startup().
{
FILE *file;
HASH_SEQ_STATUS hash_seq;
int32 num_entries;
pgssEntry *entry;
/* Don't try to dump during a crash. */
if (code)
return;
/* Safety check ... shouldn't get here unless shmem is set up. */
if (!pgss || !pgss_hash)
return;
/* Don't dump if told not to. */
if (!pgss_save)
return;
file = AllocateFile(PGSS_DUMP_FILE ".tmp", PG_BINARY_W);
if (file == NULL)
goto error;
if (fwrite(&PGSS_FILE_HEADER, sizeof(uint32), 1, file) != 1)
goto error;
num_entries = hash_get_num_entries(pgss_hash);
if (fwrite(&num_entries, sizeof(int32), 1, file) != 1)
goto error;
hash_seq_init(&hash_seq, pgss_hash);
while ((entry = hash_seq_search(&hash_seq)) != NULL)
{
int len = entry->query_len;
if (fwrite(entry, offsetof(pgssEntry, mutex), 1, file) != 1 ||
fwrite(entry->query, 1, len, file) != len)
goto error;
}
if (FreeFile(file))
{
file = NULL;
goto error;
}
/*
* Rename file into place, so we atomically replace the old one.
*/
if (rename(PGSS_DUMP_FILE ".tmp", PGSS_DUMP_FILE) != 0)
ereport(LOG,
(errcode_for_file_access(),
errmsg("could not rename pg_stat_statement file \"%s\": %m",
PGSS_DUMP_FILE ".tmp")));
return;
error:
ereport(LOG,
(errcode_for_file_access(),
errmsg("could not write pg_stat_statement file \"%s\": %m",
PGSS_DUMP_FILE ".tmp")));
if (file)
FreeFile(file);
unlink(PGSS_DUMP_FILE ".tmp");
}
| static void pgss_shmem_startup | ( | void | ) | [static] |
Definition at line 386 of file pg_stat_statements.c.
References AddinShmemInitLock, AllocateFile(), Counters::calls, pgssEntry::counters, pgssSharedState::cur_median_usage, pgssHashKey::encoding, entry_alloc(), HASHCTL::entrysize, ereport, errcode_for_file_access(), errmsg(), error(), FreeFile(), HASHCTL::hash, HASH_COMPARE, HASH_ELEM, HASH_FUNCTION, i, IsUnderPostmaster, pgssEntry::key, HASHCTL::keysize, pgssSharedState::lock, LOG, LW_EXCLUSIVE, LWLockAcquire(), LWLockAssign(), LWLockRelease(), HASHCTL::match, NULL, offsetof, on_shmem_exit(), palloc(), pfree(), PG_BINARY_R, pg_encoding_mbcliplen(), PG_VALID_BE_ENCODING, PGSS_DUMP_FILE, PGSS_FILE_HEADER, pgss_max, pgss_save, pgss_shmem_shutdown(), pgstat_track_activity_query_size, prev_shmem_startup_hook, pgssEntry::query_len, pgssSharedState::query_size, repalloc(), ShmemInitHash(), ShmemInitStruct(), and unlink().
{
bool found;
HASHCTL info;
FILE *file;
uint32 header;
int32 num;
int32 i;
int query_size;
int buffer_size;
char *buffer = NULL;
if (prev_shmem_startup_hook)
prev_shmem_startup_hook();
/* reset in case this is a restart within the postmaster */
pgss = NULL;
pgss_hash = NULL;
/*
* Create or attach to the shared memory state, including hash table
*/
LWLockAcquire(AddinShmemInitLock, LW_EXCLUSIVE);
pgss = ShmemInitStruct("pg_stat_statements",
sizeof(pgssSharedState),
&found);
if (!found)
{
/* First time through ... */
pgss->lock = LWLockAssign();
pgss->query_size = pgstat_track_activity_query_size;
pgss->cur_median_usage = ASSUMED_MEDIAN_INIT;
}
/* Be sure everyone agrees on the hash table entry size */
query_size = pgss->query_size;
memset(&info, 0, sizeof(info));
info.keysize = sizeof(pgssHashKey);
info.entrysize = offsetof(pgssEntry, query) +query_size;
info.hash = pgss_hash_fn;
info.match = pgss_match_fn;
pgss_hash = ShmemInitHash("pg_stat_statements hash",
pgss_max, pgss_max,
&info,
HASH_ELEM | HASH_FUNCTION | HASH_COMPARE);
LWLockRelease(AddinShmemInitLock);
/*
* If we're in the postmaster (or a standalone backend...), set up a shmem
* exit hook to dump the statistics to disk.
*/
if (!IsUnderPostmaster)
on_shmem_exit(pgss_shmem_shutdown, (Datum) 0);
/*
* Attempt to load old statistics from the dump file, if this is the first
* time through and we weren't told not to.
*/
if (found || !pgss_save)
return;
/*
* Note: we don't bother with locks here, because there should be no other
* processes running when this code is reached.
*/
file = AllocateFile(PGSS_DUMP_FILE, PG_BINARY_R);
if (file == NULL)
{
if (errno == ENOENT)
return; /* ignore not-found error */
goto error;
}
buffer_size = query_size;
buffer = (char *) palloc(buffer_size);
if (fread(&header, sizeof(uint32), 1, file) != 1 ||
header != PGSS_FILE_HEADER ||
fread(&num, sizeof(int32), 1, file) != 1)
goto error;
for (i = 0; i < num; i++)
{
pgssEntry temp;
pgssEntry *entry;
if (fread(&temp, offsetof(pgssEntry, mutex), 1, file) != 1)
goto error;
/* Encoding is the only field we can easily sanity-check */
if (!PG_VALID_BE_ENCODING(temp.key.encoding))
goto error;
/* Previous incarnation might have had a larger query_size */
if (temp.query_len >= buffer_size)
{
buffer = (char *) repalloc(buffer, temp.query_len + 1);
buffer_size = temp.query_len + 1;
}
if (fread(buffer, 1, temp.query_len, file) != temp.query_len)
goto error;
buffer[temp.query_len] = '\0';
/* Skip loading "sticky" entries */
if (temp.counters.calls == 0)
continue;
/* Clip to available length if needed */
if (temp.query_len >= query_size)
temp.query_len = pg_encoding_mbcliplen(temp.key.encoding,
buffer,
temp.query_len,
query_size - 1);
/* make the hashtable entry (discards old entries if too many) */
entry = entry_alloc(&temp.key, buffer, temp.query_len, false);
/* copy in the actual stats */
entry->counters = temp.counters;
}
pfree(buffer);
FreeFile(file);
/*
* Remove the file so it's not included in backups/replication slaves,
* etc. A new file will be written on next shutdown.
*/
unlink(PGSS_DUMP_FILE);
return;
error:
ereport(LOG,
(errcode_for_file_access(),
errmsg("could not read pg_stat_statement file \"%s\": %m",
PGSS_DUMP_FILE)));
if (buffer)
pfree(buffer);
if (file)
FreeFile(file);
/* If possible, throw away the bogus file; ignore any error */
unlink(PGSS_DUMP_FILE);
}
| static void pgss_store | ( | const char * | query, | |
| uint32 | queryId, | |||
| double | total_time, | |||
| uint64 | rows, | |||
| const BufferUsage * | bufusage, | |||
| pgssJumbleState * | jstate | |||
| ) | [static] |
Definition at line 945 of file pg_stat_statements.c.
References Assert, BufferUsage::blk_read_time, Counters::blk_read_time, BufferUsage::blk_write_time, Counters::blk_write_time, Counters::calls, pgssEntry::counters, pgssHashKey::dbid, pgssHashKey::encoding, entry_alloc(), generate_normalized_query(), GetDatabaseEncoding(), GetUserId(), HASH_FIND, hash_search(), INSTR_TIME_GET_MILLISEC, BufferUsage::local_blks_dirtied, Counters::local_blks_dirtied, BufferUsage::local_blks_hit, Counters::local_blks_hit, BufferUsage::local_blks_read, Counters::local_blks_read, BufferUsage::local_blks_written, Counters::local_blks_written, pgssSharedState::lock, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), pgssEntry::mutex, MyDatabaseId, NULL, pfree(), pg_encoding_mbcliplen(), pgssSharedState::query_size, pgssHashKey::queryid, Counters::rows, BufferUsage::shared_blks_dirtied, Counters::shared_blks_dirtied, BufferUsage::shared_blks_hit, Counters::shared_blks_hit, BufferUsage::shared_blks_read, Counters::shared_blks_read, BufferUsage::shared_blks_written, Counters::shared_blks_written, SpinLockAcquire, SpinLockRelease, BufferUsage::temp_blks_read, Counters::temp_blks_read, BufferUsage::temp_blks_written, Counters::temp_blks_written, Counters::total_time, Counters::usage, USAGE_EXEC, and pgssHashKey::userid.
Referenced by pgss_ExecutorEnd(), pgss_post_parse_analyze(), and pgss_ProcessUtility().
{
pgssHashKey key;
pgssEntry *entry;
char *norm_query = NULL;
Assert(query != NULL);
/* Safety check... */
if (!pgss || !pgss_hash)
return;
/* Set up key for hashtable search */
key.userid = GetUserId();
key.dbid = MyDatabaseId;
key.encoding = GetDatabaseEncoding();
key.queryid = queryId;
/* Lookup the hash table entry with shared lock. */
LWLockAcquire(pgss->lock, LW_SHARED);
entry = (pgssEntry *) hash_search(pgss_hash, &key, HASH_FIND, NULL);
/* Create new entry, if not present */
if (!entry)
{
int query_len;
/*
* We'll need exclusive lock to make a new entry. There is no point
* in holding shared lock while we normalize the string, though.
*/
LWLockRelease(pgss->lock);
query_len = strlen(query);
if (jstate)
{
/* Normalize the string if enabled */
norm_query = generate_normalized_query(jstate, query,
&query_len,
key.encoding);
/* Acquire exclusive lock as required by entry_alloc() */
LWLockAcquire(pgss->lock, LW_EXCLUSIVE);
entry = entry_alloc(&key, norm_query, query_len, true);
}
else
{
/*
* We're just going to store the query string as-is; but we have
* to truncate it if over-length.
*/
if (query_len >= pgss->query_size)
query_len = pg_encoding_mbcliplen(key.encoding,
query,
query_len,
pgss->query_size - 1);
/* Acquire exclusive lock as required by entry_alloc() */
LWLockAcquire(pgss->lock, LW_EXCLUSIVE);
entry = entry_alloc(&key, query, query_len, false);
}
}
/* Increment the counts, except when jstate is not NULL */
if (!jstate)
{
/*
* Grab the spinlock while updating the counters (see comment about
* locking rules at the head of the file)
*/
volatile pgssEntry *e = (volatile pgssEntry *) entry;
SpinLockAcquire(&e->mutex);
/* "Unstick" entry if it was previously sticky */
if (e->counters.calls == 0)
e->counters.usage = USAGE_INIT;
e->counters.calls += 1;
e->counters.total_time += total_time;
e->counters.rows += rows;
e->counters.shared_blks_hit += bufusage->shared_blks_hit;
e->counters.shared_blks_read += bufusage->shared_blks_read;
e->counters.shared_blks_dirtied += bufusage->shared_blks_dirtied;
e->counters.shared_blks_written += bufusage->shared_blks_written;
e->counters.local_blks_hit += bufusage->local_blks_hit;
e->counters.local_blks_read += bufusage->local_blks_read;
e->counters.local_blks_dirtied += bufusage->local_blks_dirtied;
e->counters.local_blks_written += bufusage->local_blks_written;
e->counters.temp_blks_read += bufusage->temp_blks_read;
e->counters.temp_blks_written += bufusage->temp_blks_written;
e->counters.blk_read_time += INSTR_TIME_GET_MILLISEC(bufusage->blk_read_time);
e->counters.blk_write_time += INSTR_TIME_GET_MILLISEC(bufusage->blk_write_time);
e->counters.usage += USAGE_EXEC(total_time);
SpinLockRelease(&e->mutex);
}
LWLockRelease(pgss->lock);
/* We postpone this pfree until we're out of the lock */
if (norm_query)
pfree(norm_query);
}
| static void RecordConstLocation | ( | pgssJumbleState * | jstate, | |
| int | location | |||
| ) | [static] |
Definition at line 1880 of file pg_stat_statements.c.
References pgssJumbleState::clocations, pgssJumbleState::clocations_buf_size, pgssJumbleState::clocations_count, pgssLocationLen::length, pgssLocationLen::location, and repalloc().
Referenced by JumbleExpr().
{
/* -1 indicates unknown or undefined location */
if (location >= 0)
{
/* enlarge array if needed */
if (jstate->clocations_count >= jstate->clocations_buf_size)
{
jstate->clocations_buf_size *= 2;
jstate->clocations = (pgssLocationLen *)
repalloc(jstate->clocations,
jstate->clocations_buf_size *
sizeof(pgssLocationLen));
}
jstate->clocations[jstate->clocations_count].location = location;
/* initialize lengths to -1 to simplify fill_in_constant_lengths */
jstate->clocations[jstate->clocations_count].length = -1;
jstate->clocations_count++;
}
}
int nested_level = 0 [static] |
Definition at line 180 of file pg_stat_statements.c.
Referenced by pgss_ExecutorFinish(), pgss_ExecutorRun(), and pgss_ProcessUtility().
Definition at line 64 of file pg_stat_statements.c.
pgssSharedState* pgss = NULL [static] |
Definition at line 192 of file pg_stat_statements.c.
const uint32 PGSS_FILE_HEADER = 0x20120328 [static] |
Definition at line 70 of file pg_stat_statements.c.
Referenced by pgss_shmem_shutdown(), and pgss_shmem_startup().
Definition at line 193 of file pg_stat_statements.c.
int pgss_max [static] |
Definition at line 212 of file pg_stat_statements.c.
Referenced by _PG_init(), entry_alloc(), pgss_memsize(), and pgss_shmem_startup().
Definition at line 215 of file pg_stat_statements.c.
Referenced by _PG_init(), pgss_shmem_shutdown(), and pgss_shmem_startup().
int pgss_track [static] |
Definition at line 213 of file pg_stat_statements.c.
Referenced by _PG_init().
bool pgss_track_utility [static] |
Definition at line 214 of file pg_stat_statements.c.
Referenced by _PG_init(), and pgss_ProcessUtility().
ExecutorEnd_hook_type prev_ExecutorEnd = NULL [static] |
Definition at line 188 of file pg_stat_statements.c.
Referenced by _PG_fini(), _PG_init(), and pgss_ExecutorEnd().
ExecutorFinish_hook_type prev_ExecutorFinish = NULL [static] |
Definition at line 187 of file pg_stat_statements.c.
Referenced by _PG_fini(), _PG_init(), and pgss_ExecutorFinish().
ExecutorRun_hook_type prev_ExecutorRun = NULL [static] |
Definition at line 186 of file pg_stat_statements.c.
Referenced by _PG_fini(), _PG_init(), and pgss_ExecutorRun().
ExecutorStart_hook_type prev_ExecutorStart = NULL [static] |
Definition at line 185 of file pg_stat_statements.c.
Referenced by _PG_fini(), _PG_init(), and pgss_ExecutorStart().
post_parse_analyze_hook_type prev_post_parse_analyze_hook = NULL [static] |
Definition at line 184 of file pg_stat_statements.c.
Referenced by _PG_fini(), and _PG_init().
ProcessUtility_hook_type prev_ProcessUtility = NULL [static] |
Definition at line 189 of file pg_stat_statements.c.
Referenced by _PG_fini(), _PG_init(), and pgss_ProcessUtility().
shmem_startup_hook_type prev_shmem_startup_hook = NULL [static] |
Definition at line 183 of file pg_stat_statements.c.
Referenced by _PG_fini(), _PG_init(), and pgss_shmem_startup().
struct config_enum_entry track_options[] [static] |
{
{"none", PGSS_TRACK_NONE, false},
{"top", PGSS_TRACK_TOP, false},
{"all", PGSS_TRACK_ALL, false},
{NULL, 0, false}
}
Definition at line 204 of file pg_stat_statements.c.
1.7.1