PG-186: Add support to monitor query execution plan.
parent
aa0ca050d5
commit
e0fc683810
2
Makefile
2
Makefile
|
@ -11,7 +11,7 @@ PGFILEDESC = "pg_stat_monitor - execution statistics of SQL statements"
|
||||||
LDFLAGS_SL += $(filter -lm, $(LIBS))
|
LDFLAGS_SL += $(filter -lm, $(LIBS))
|
||||||
|
|
||||||
REGRESS_OPTS = --temp-config $(top_srcdir)/contrib/pg_stat_monitor/pg_stat_monitor.conf --inputdir=regression
|
REGRESS_OPTS = --temp-config $(top_srcdir)/contrib/pg_stat_monitor/pg_stat_monitor.conf --inputdir=regression
|
||||||
REGRESS = basic version guc user counters relations database top_query application_name cmd_type error rows
|
REGRESS = basic version guc counters relations database top_query application_name cmd_type error rows
|
||||||
|
|
||||||
# Disabled because these tests require "shared_preload_libraries=pg_stat_statements",
|
# Disabled because these tests require "shared_preload_libraries=pg_stat_statements",
|
||||||
# which typical installcheck users do not have (e.g. buildfarm clients).
|
# which typical installcheck users do not have (e.g. buildfarm clients).
|
||||||
|
|
64
hash_query.c
64
hash_query.c
|
@ -21,7 +21,6 @@
|
||||||
static pgssSharedState *pgss;
|
static pgssSharedState *pgss;
|
||||||
static HTAB *pgss_hash;
|
static HTAB *pgss_hash;
|
||||||
static HTAB *pgss_query_hash;
|
static HTAB *pgss_query_hash;
|
||||||
static HTAB *pgss_plan_hash;
|
|
||||||
|
|
||||||
static HTAB* hash_init(const char *hash_name, int key_size, int entry_size, int hash_size);
|
static HTAB* hash_init(const char *hash_name, int key_size, int entry_size, int hash_size);
|
||||||
|
|
||||||
|
@ -71,8 +70,7 @@ pgss_startup(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
pgss_hash = hash_init("pg_stat_monitor: bucket hashtable", sizeof(pgssHashKey), sizeof(pgssEntry), MAX_BUCKET_ENTRIES);
|
pgss_hash = hash_init("pg_stat_monitor: bucket hashtable", sizeof(pgssHashKey), sizeof(pgssEntry), MAX_BUCKET_ENTRIES);
|
||||||
pgss_query_hash = hash_init("pg_stat_monitor: query hashtable", sizeof(pgssQueryHashKey), sizeof(pgssQueryEntry),500000);
|
pgss_query_hash = hash_init("pg_stat_monitor: query hashtable", sizeof(pgssQueryHashKey), sizeof(pgssQueryEntry),MAX_BUCKET_ENTRIES);
|
||||||
pgss_plan_hash = hash_init("pg_stat_monitor: plan hashtable", sizeof(pgssPlanHashKey), sizeof(pgssPlanEntry), MAX_BUCKET_ENTRIES);
|
|
||||||
|
|
||||||
LWLockRelease(AddinShmemInitLock);
|
LWLockRelease(AddinShmemInitLock);
|
||||||
|
|
||||||
|
@ -83,12 +81,6 @@ pgss_startup(void)
|
||||||
on_shmem_exit(pgss_shmem_shutdown, (Datum) 0);
|
on_shmem_exit(pgss_shmem_shutdown, (Datum) 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
HTAB*
|
|
||||||
pgsm_get_plan_hash(void)
|
|
||||||
{
|
|
||||||
return pgss_plan_hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
pgssSharedState*
|
pgssSharedState*
|
||||||
pgsm_get_ss(void)
|
pgsm_get_ss(void)
|
||||||
{
|
{
|
||||||
|
@ -101,6 +93,12 @@ pgsm_get_hash(void)
|
||||||
return pgss_hash;
|
return pgss_hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HTAB*
|
||||||
|
pgsm_get_query_hash(void)
|
||||||
|
{
|
||||||
|
return pgss_query_hash;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* shmem_shutdown hook: Dump statistics into file.
|
* shmem_shutdown hook: Dump statistics into file.
|
||||||
*
|
*
|
||||||
|
@ -128,33 +126,11 @@ hash_memsize(void)
|
||||||
size = MAXALIGN(sizeof(pgssSharedState));
|
size = MAXALIGN(sizeof(pgssSharedState));
|
||||||
size += MAXALIGN(MAX_QUERY_BUF);
|
size += MAXALIGN(MAX_QUERY_BUF);
|
||||||
size = add_size(size, hash_estimate_size(MAX_BUCKET_ENTRIES, sizeof(pgssEntry)));
|
size = add_size(size, hash_estimate_size(MAX_BUCKET_ENTRIES, sizeof(pgssEntry)));
|
||||||
size = add_size(size, hash_estimate_size(MAX_BUCKET_ENTRIES, sizeof(pgssPlanEntry)));
|
size = add_size(size, hash_estimate_size(MAX_BUCKET_ENTRIES, sizeof(pgssQueryEntry)));
|
||||||
size = add_size(size, hash_estimate_size(500000, sizeof(pgssQueryEntry)));
|
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
pgssPlanEntry *
|
|
||||||
hash_plan_entry_alloc(pgssSharedState *pgss, pgssPlanHashKey *key)
|
|
||||||
{
|
|
||||||
pgssPlanEntry *entry = NULL;
|
|
||||||
bool found = false;
|
|
||||||
|
|
||||||
if (hash_get_num_entries(pgss_plan_hash) >= MAX_BUCKET_ENTRIES)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* Find or create an entry with desired hash code */
|
|
||||||
entry = (pgssPlanEntry *) hash_search(pgss_plan_hash, key, HASH_ENTER, &found);
|
|
||||||
if (!found)
|
|
||||||
{
|
|
||||||
memset(&entry->plan_info, 0, sizeof(PlanInfo));
|
|
||||||
SpinLockInit(&entry->mutex);
|
|
||||||
}
|
|
||||||
if (entry == NULL)
|
|
||||||
elog(FATAL, "%s", "pg_stat_monitor: out of memory");
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
pgssEntry *
|
pgssEntry *
|
||||||
hash_entry_alloc(pgssSharedState *pgss, pgssHashKey *key,int encoding)
|
hash_entry_alloc(pgssSharedState *pgss, pgssHashKey *key,int encoding)
|
||||||
{
|
{
|
||||||
|
@ -163,7 +139,7 @@ hash_entry_alloc(pgssSharedState *pgss, pgssHashKey *key,int encoding)
|
||||||
|
|
||||||
if (hash_get_num_entries(pgss_hash) >= MAX_BUCKET_ENTRIES)
|
if (hash_get_num_entries(pgss_hash) >= MAX_BUCKET_ENTRIES)
|
||||||
{
|
{
|
||||||
elog(DEBUG2, "%s", "pg_stat_monitor: out of memory");
|
elog(DEBUG1, "%s", "pg_stat_monitor: out of memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
/* Find or create an entry with desired hash code */
|
/* Find or create an entry with desired hash code */
|
||||||
|
@ -181,7 +157,7 @@ hash_entry_alloc(pgssSharedState *pgss, pgssHashKey *key,int encoding)
|
||||||
entry->encoding = encoding;
|
entry->encoding = encoding;
|
||||||
}
|
}
|
||||||
if (entry == NULL)
|
if (entry == NULL)
|
||||||
elog(FATAL, "%s", "pg_stat_monitor: out of memory");
|
elog(DEBUG1, "%s", "pg_stat_monitor: out of memory");
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,7 +175,7 @@ hash_query_entry_dealloc(int bucket)
|
||||||
hash_seq_init(&hash_seq, pgss_query_hash);
|
hash_seq_init(&hash_seq, pgss_query_hash);
|
||||||
while ((entry = hash_seq_search(&hash_seq)) != NULL)
|
while ((entry = hash_seq_search(&hash_seq)) != NULL)
|
||||||
{
|
{
|
||||||
if (entry->key.bucket_id == bucket)
|
if (entry->key.bucket_id == bucket || bucket < 0)
|
||||||
entry = hash_search(pgss_query_hash, &entry->key, HASH_REMOVE, NULL);
|
entry = hash_search(pgss_query_hash, &entry->key, HASH_REMOVE, NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -247,8 +223,8 @@ hash_entry_reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Caller must accuire lock */
|
/* Caller must accuire lock */
|
||||||
bool
|
pgssQueryEntry*
|
||||||
hash_create_query_entry(uint64 bucket_id, uint64 queryid)
|
hash_create_query_entry(uint64 bucket_id, uint64 queryid, uint64 dbid, uint64 userid, uint64 ip)
|
||||||
{
|
{
|
||||||
pgssQueryHashKey key;
|
pgssQueryHashKey key;
|
||||||
pgssQueryEntry *entry;
|
pgssQueryEntry *entry;
|
||||||
|
@ -256,14 +232,17 @@ hash_create_query_entry(uint64 bucket_id, uint64 queryid)
|
||||||
|
|
||||||
key.queryid = queryid;
|
key.queryid = queryid;
|
||||||
key.bucket_id = bucket_id;
|
key.bucket_id = bucket_id;
|
||||||
|
key.dbid = dbid;
|
||||||
|
key.userid = userid;
|
||||||
|
key.ip = ip;
|
||||||
|
|
||||||
entry = (pgssQueryEntry *) hash_search(pgss_query_hash, &key, HASH_ENTER, &found);
|
entry = (pgssQueryEntry *) hash_search(pgss_query_hash, &key, HASH_ENTER, &found);
|
||||||
return (entry != NULL);
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Caller must accuire lock */
|
/* Caller must accuire lock */
|
||||||
bool
|
pgssQueryEntry*
|
||||||
hash_find_query_entry(uint64 bucket_id, uint64 queryid)
|
hash_find_query_entry(uint64 bucket_id, uint64 queryid, uint64 dbid, uint64 userid, uint64 ip)
|
||||||
{
|
{
|
||||||
pgssQueryHashKey key;
|
pgssQueryHashKey key;
|
||||||
pgssQueryEntry *entry;
|
pgssQueryEntry *entry;
|
||||||
|
@ -271,10 +250,13 @@ hash_find_query_entry(uint64 bucket_id, uint64 queryid)
|
||||||
|
|
||||||
key.queryid = queryid;
|
key.queryid = queryid;
|
||||||
key.bucket_id = bucket_id;
|
key.bucket_id = bucket_id;
|
||||||
|
key.dbid = dbid;
|
||||||
|
key.userid = userid;
|
||||||
|
key.ip = ip;
|
||||||
|
|
||||||
/* Lookup the hash table entry with shared lock. */
|
/* Lookup the hash table entry with shared lock. */
|
||||||
entry = (pgssQueryEntry *) hash_search(pgss_query_hash, &key, HASH_FIND, &found);
|
entry = (pgssQueryEntry *) hash_search(pgss_query_hash, &key, HASH_FIND, &found);
|
||||||
return ((entry != NULL) && found);
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -25,19 +25,20 @@ SELECT string_to_array(get_histogram_timings(), ',');
|
||||||
$$ LANGUAGE SQL;
|
$$ LANGUAGE SQL;
|
||||||
|
|
||||||
CREATE FUNCTION pg_stat_monitor_internal(IN showtext boolean,
|
CREATE FUNCTION pg_stat_monitor_internal(IN showtext boolean,
|
||||||
OUT bucket int, -- 0
|
OUT bucket int8, -- 0
|
||||||
OUT userid oid,
|
OUT userid oid,
|
||||||
OUT dbid oid,
|
OUT dbid oid,
|
||||||
OUT client_ip int8,
|
OUT client_ip int8,
|
||||||
|
|
||||||
OUT queryid text, -- 4
|
OUT queryid text, -- 4
|
||||||
OUT planid text,
|
OUT planid text,
|
||||||
OUT top_queryid text,
|
|
||||||
OUT query text,
|
OUT query text,
|
||||||
OUT query_plan text,
|
OUT query_plan text,
|
||||||
|
OUT state int8,
|
||||||
|
OUT top_queryid text,
|
||||||
OUT application_name text,
|
OUT application_name text,
|
||||||
|
|
||||||
OUT relations text, -- 10
|
OUT relations text, -- 11
|
||||||
OUT cmd_type int,
|
OUT cmd_type int,
|
||||||
OUT elevel int,
|
OUT elevel int,
|
||||||
OUT sqlcode TEXT,
|
OUT sqlcode TEXT,
|
||||||
|
@ -57,8 +58,9 @@ CREATE FUNCTION pg_stat_monitor_internal(IN showtext boolean,
|
||||||
OUT plan_min_time float8,
|
OUT plan_min_time float8,
|
||||||
OUT plan_max_time float8,
|
OUT plan_max_time float8,
|
||||||
OUT plan_mean_time float8,
|
OUT plan_mean_time float8,
|
||||||
|
OUT plan_stddev_time float8,
|
||||||
|
|
||||||
OUT shared_blks_hit int8, -- 28
|
OUT shared_blks_hit int8, -- 29
|
||||||
OUT shared_blks_read int8,
|
OUT shared_blks_read int8,
|
||||||
OUT shared_blks_dirtied int8,
|
OUT shared_blks_dirtied int8,
|
||||||
OUT shared_blks_written int8,
|
OUT shared_blks_written int8,
|
||||||
|
@ -70,7 +72,7 @@ CREATE FUNCTION pg_stat_monitor_internal(IN showtext boolean,
|
||||||
OUT temp_blks_written int8,
|
OUT temp_blks_written int8,
|
||||||
OUT blk_read_time float8,
|
OUT blk_read_time float8,
|
||||||
OUT blk_write_time float8,
|
OUT blk_write_time float8,
|
||||||
OUT resp_calls text,
|
OUT resp_calls text, -- 41
|
||||||
OUT cpu_user_time float8,
|
OUT cpu_user_time float8,
|
||||||
OUT cpu_sys_time float8,
|
OUT cpu_sys_time float8,
|
||||||
OUT wal_records int8,
|
OUT wal_records int8,
|
||||||
|
@ -81,6 +83,19 @@ RETURNS SETOF record
|
||||||
AS 'MODULE_PATHNAME', 'pg_stat_monitor'
|
AS 'MODULE_PATHNAME', 'pg_stat_monitor'
|
||||||
LANGUAGE C STRICT VOLATILE PARALLEL SAFE;
|
LANGUAGE C STRICT VOLATILE PARALLEL SAFE;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION get_state(state int8) RETURNS TEXT AS
|
||||||
|
$$
|
||||||
|
SELECT
|
||||||
|
CASE
|
||||||
|
WHEN state = 0 THEN 'PARSED'
|
||||||
|
WHEN state = 1 THEN 'PLANNING'
|
||||||
|
WHEN state = 2 THEN 'EXECUTION FINISHED'
|
||||||
|
WHEN state = 3 THEN 'ERROR'
|
||||||
|
WHEN state = 4 THEN 'FINISHED'
|
||||||
|
END
|
||||||
|
$$
|
||||||
|
LANGUAGE SQL PARALLEL SAFE;
|
||||||
|
|
||||||
CREATE or REPLACE FUNCTION get_cmd_type (cmd_type INTEGER) RETURNS TEXT AS
|
CREATE or REPLACE FUNCTION get_cmd_type (cmd_type INTEGER) RETURNS TEXT AS
|
||||||
$$
|
$$
|
||||||
SELECT
|
SELECT
|
||||||
|
@ -169,7 +184,9 @@ CREATE VIEW pg_stat_monitor AS SELECT
|
||||||
round(cpu_sys_time::numeric, 4) as cpu_sys_time,
|
round(cpu_sys_time::numeric, 4) as cpu_sys_time,
|
||||||
wal_records,
|
wal_records,
|
||||||
wal_fpi,
|
wal_fpi,
|
||||||
wal_bytes
|
wal_bytes,
|
||||||
|
state,
|
||||||
|
get_state(state) as state_value
|
||||||
FROM pg_stat_monitor_internal(TRUE) p, pg_database d WHERE dbid = oid
|
FROM pg_stat_monitor_internal(TRUE) p, pg_database d WHERE dbid = oid
|
||||||
ORDER BY bucket_start_time;
|
ORDER BY bucket_start_time;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------
|
/*-------------------------------------------------------------------------
|
||||||
*
|
*
|
||||||
* pg_stat_monitor.c
|
* pg_stat_monitor.c
|
||||||
|
@ -22,7 +21,7 @@
|
||||||
PG_MODULE_MAGIC;
|
PG_MODULE_MAGIC;
|
||||||
|
|
||||||
#define BUILD_VERSION "devel"
|
#define BUILD_VERSION "devel"
|
||||||
#define PG_STAT_STATEMENTS_COLS 49 /* maximum of above */
|
#define PG_STAT_STATEMENTS_COLS 51 /* maximum of above */
|
||||||
#define PGSM_TEXT_FILE "/tmp/pg_stat_monitor_query"
|
#define PGSM_TEXT_FILE "/tmp/pg_stat_monitor_query"
|
||||||
|
|
||||||
#define PGUNSIXBIT(val) (((val) & 0x3F) + '0')
|
#define PGUNSIXBIT(val) (((val) & 0x3F) + '0')
|
||||||
|
@ -52,8 +51,6 @@ do \
|
||||||
void _PG_init(void);
|
void _PG_init(void);
|
||||||
void _PG_fini(void);
|
void _PG_fini(void);
|
||||||
|
|
||||||
int64 v = 5631;
|
|
||||||
|
|
||||||
/*---- Initicalization Function Declarations ----*/
|
/*---- Initicalization Function Declarations ----*/
|
||||||
void _PG_init(void);
|
void _PG_init(void);
|
||||||
void _PG_fini(void);
|
void _PG_fini(void);
|
||||||
|
@ -72,10 +69,7 @@ static bool system_init = false;
|
||||||
static struct rusage rusage_start;
|
static struct rusage rusage_start;
|
||||||
static struct rusage rusage_end;
|
static struct rusage rusage_end;
|
||||||
static unsigned char *pgss_qbuf[MAX_BUCKETS];
|
static unsigned char *pgss_qbuf[MAX_BUCKETS];
|
||||||
|
|
||||||
static char *pgss_explain(QueryDesc *queryDesc);
|
static char *pgss_explain(QueryDesc *queryDesc);
|
||||||
static bool pgss_get_plan(uint64 query_hash, PlanInfo *plan_info);
|
|
||||||
static bool pgss_store_plan(uint64 query_hash, PlanInfo *plan_info);
|
|
||||||
|
|
||||||
static int get_histogram_bucket(double q_time);
|
static int get_histogram_bucket(double q_time);
|
||||||
static bool IsSystemInitialized(void);
|
static bool IsSystemInitialized(void);
|
||||||
|
@ -141,7 +135,14 @@ static uint64 pgss_hash_string(const char *str, int len);
|
||||||
char *unpack_sql_state(int sql_state);
|
char *unpack_sql_state(int sql_state);
|
||||||
|
|
||||||
static void pgss_store_error(uint64 queryid, const char * query, ErrorData *edata);
|
static void pgss_store_error(uint64 queryid, const char * query, ErrorData *edata);
|
||||||
static void pgss_store_query(uint64 queryid, const char * query, CmdType cmd_type, int query_location, int query_len, pgssJumbleState *jstate);
|
static pgssQueryEntry *pgss_store_query_info(uint64 bucketid,
|
||||||
|
uint64 queryid,
|
||||||
|
uint64 dbid,
|
||||||
|
uint64 userid,
|
||||||
|
uint64 ip,
|
||||||
|
const char *query,
|
||||||
|
uint64 query_len,
|
||||||
|
pgssStoreKind kind);
|
||||||
|
|
||||||
static void pgss_store_utility(const char *query,
|
static void pgss_store_utility(const char *query,
|
||||||
double total_time,
|
double total_time,
|
||||||
|
@ -173,14 +174,20 @@ static void JumbleExpr(pgssJumbleState *jstate, Node *node);
|
||||||
static void RecordConstLocation(pgssJumbleState *jstate, int location);
|
static void RecordConstLocation(pgssJumbleState *jstate, int location);
|
||||||
static char *generate_normalized_query(pgssJumbleState *jstate, const char *query,
|
static char *generate_normalized_query(pgssJumbleState *jstate, const char *query,
|
||||||
int query_loc, int *query_len_p, int encoding);
|
int query_loc, int *query_len_p, int encoding);
|
||||||
static void fill_in_constant_lengths(pgssJumbleState *jstate, const char *query,
|
static void fill_in_constant_lengths(pgssJumbleState *jstate, const char *query, int query_loc);
|
||||||
int query_loc);
|
|
||||||
static int comp_location(const void *a, const void *b);
|
static int comp_location(const void *a, const void *b);
|
||||||
|
|
||||||
static uint64 get_next_wbucket(pgssSharedState *pgss);
|
static uint64 get_next_wbucket(pgssSharedState *pgss);
|
||||||
|
|
||||||
static void store_query(int bucket_id, uint64 queryid, const char *query, uint64 query_len);
|
static void
|
||||||
static uint64 read_query(unsigned char *buf, uint64 queryid, char * query);
|
pgss_store_query(uint64 queryid,
|
||||||
|
const char * query,
|
||||||
|
CmdType cmd_type,
|
||||||
|
int query_location,
|
||||||
|
int query_len,
|
||||||
|
pgssJumbleState *jstate,
|
||||||
|
pgssStoreKind kind);
|
||||||
|
static uint64 read_query(unsigned char *buf, uint64 bucketid, uint64 queryid, char * query);
|
||||||
int read_query_buffer(int bucket_id, uint64 queryid, char *query_txt);
|
int read_query_buffer(int bucket_id, uint64 queryid, char *query_txt);
|
||||||
|
|
||||||
static uint64 get_query_id(pgssJumbleState *jstate, Query *query);
|
static uint64 get_query_id(pgssJumbleState *jstate, Query *query);
|
||||||
|
@ -245,9 +252,9 @@ _PG_init(void)
|
||||||
ProcessUtility_hook = pgss_ProcessUtility;
|
ProcessUtility_hook = pgss_ProcessUtility;
|
||||||
planner_hook_next = planner_hook;
|
planner_hook_next = planner_hook;
|
||||||
planner_hook = pgss_planner_hook;
|
planner_hook = pgss_planner_hook;
|
||||||
emit_log_hook = pgsm_emit_log_hook;
|
emit_log_hook = pgsm_emit_log_hook;
|
||||||
prev_ExecutorCheckPerms_hook = ExecutorCheckPerms_hook;
|
prev_ExecutorCheckPerms_hook = ExecutorCheckPerms_hook;
|
||||||
ExecutorCheckPerms_hook = pgss_ExecutorCheckPerms;
|
ExecutorCheckPerms_hook = pgss_ExecutorCheckPerms;
|
||||||
|
|
||||||
nested_queryids = (uint64*) malloc(sizeof(uint64) * max_stack_depth);
|
nested_queryids = (uint64*) malloc(sizeof(uint64) * max_stack_depth);
|
||||||
|
|
||||||
|
@ -306,6 +313,7 @@ static void
|
||||||
pgss_post_parse_analyze(ParseState *pstate, Query *query)
|
pgss_post_parse_analyze(ParseState *pstate, Query *query)
|
||||||
{
|
{
|
||||||
pgssJumbleState jstate;
|
pgssJumbleState jstate;
|
||||||
|
pgssStoreKind kind = PGSS_PARSE;
|
||||||
|
|
||||||
if (prev_post_parse_analyze_hook)
|
if (prev_post_parse_analyze_hook)
|
||||||
prev_post_parse_analyze_hook(pstate, query);
|
prev_post_parse_analyze_hook(pstate, query);
|
||||||
|
@ -344,8 +352,9 @@ pgss_post_parse_analyze(ParseState *pstate, Query *query)
|
||||||
pstate->p_sourcetext, /* query */
|
pstate->p_sourcetext, /* query */
|
||||||
query->commandType, /* CmdType */
|
query->commandType, /* CmdType */
|
||||||
query->stmt_location, /* Query Location */
|
query->stmt_location, /* Query Location */
|
||||||
query->stmt_len, /* Quer Len */
|
query->stmt_len, /* Query Len */
|
||||||
&jstate); /* pgssJumbleState */
|
&jstate, /* pgssJumbleState */
|
||||||
|
kind); /*pgssStoreKind */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -355,7 +364,7 @@ static void
|
||||||
pgss_ExecutorStart(QueryDesc *queryDesc, int eflags)
|
pgss_ExecutorStart(QueryDesc *queryDesc, int eflags)
|
||||||
{
|
{
|
||||||
if(getrusage(RUSAGE_SELF, &rusage_start) != 0)
|
if(getrusage(RUSAGE_SELF, &rusage_start) != 0)
|
||||||
elog(WARNING, "pg_stat_monitor: failed to execute getrusage");
|
elog(DEBUG1, "pg_stat_monitor: failed to execute getrusage");
|
||||||
|
|
||||||
if (prev_ExecutorStart)
|
if (prev_ExecutorStart)
|
||||||
prev_ExecutorStart(queryDesc, eflags);
|
prev_ExecutorStart(queryDesc, eflags);
|
||||||
|
@ -438,55 +447,6 @@ pgss_ExecutorFinish(QueryDesc *queryDesc)
|
||||||
PG_END_TRY();
|
PG_END_TRY();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool
|
|
||||||
pgss_get_plan(uint64 query_hash, PlanInfo *plan_info)
|
|
||||||
{
|
|
||||||
pgssPlanHashKey key;
|
|
||||||
pgssPlanEntry *entry;
|
|
||||||
HTAB *pgss_plan_hash = pgsm_get_plan_hash();
|
|
||||||
|
|
||||||
key.query_hash = query_hash;
|
|
||||||
entry = (pgssPlanEntry *) hash_search(pgss_plan_hash, &key, HASH_FIND, NULL);
|
|
||||||
if(entry)
|
|
||||||
{
|
|
||||||
memcpy(plan_info, &entry->plan_info, sizeof(PlanInfo));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
pgss_store_plan(uint64 query_hash, PlanInfo *plan_info)
|
|
||||||
{
|
|
||||||
pgssPlanHashKey key;
|
|
||||||
pgssPlanEntry *entry;
|
|
||||||
HTAB *pgss_plan_hash = pgsm_get_plan_hash();
|
|
||||||
pgssSharedState *pgss = pgsm_get_ss();
|
|
||||||
bool found = true;
|
|
||||||
|
|
||||||
LWLockAcquire(pgss->lock, LW_SHARED);
|
|
||||||
|
|
||||||
/* Set up key for hashtable search */
|
|
||||||
key.query_hash = query_hash;
|
|
||||||
entry = (pgssPlanEntry *) hash_search(pgss_plan_hash, &key, HASH_FIND, NULL);
|
|
||||||
if (!entry)
|
|
||||||
{
|
|
||||||
entry = hash_plan_entry_alloc(pgss, &key);
|
|
||||||
if (entry == NULL)
|
|
||||||
{
|
|
||||||
LWLockRelease(pgss->lock);
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
found = false;
|
|
||||||
}
|
|
||||||
SpinLockAcquire(&entry->mutex);
|
|
||||||
memcpy(&entry->plan_info, plan_info, sizeof(PlanInfo));
|
|
||||||
SpinLockRelease(&entry->mutex);
|
|
||||||
LWLockRelease(pgss->lock);
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
pgss_explain(QueryDesc *queryDesc)
|
pgss_explain(QueryDesc *queryDesc)
|
||||||
{
|
{
|
||||||
|
@ -536,7 +496,7 @@ pgss_ExecutorEnd(QueryDesc *queryDesc)
|
||||||
*/
|
*/
|
||||||
InstrEndLoop(queryDesc->totaltime);
|
InstrEndLoop(queryDesc->totaltime);
|
||||||
if(getrusage(RUSAGE_SELF, &rusage_end) != 0)
|
if(getrusage(RUSAGE_SELF, &rusage_end) != 0)
|
||||||
elog(WARNING, "pg_stat_monitor: failed to execute getrusage");
|
elog(DEBUG1, "pg_stat_monitor: failed to execute getrusage");
|
||||||
|
|
||||||
sys_info.utime = time_diff(rusage_end.ru_utime, rusage_start.ru_utime);
|
sys_info.utime = time_diff(rusage_end.ru_utime, rusage_start.ru_utime);
|
||||||
sys_info.stime = time_diff(rusage_end.ru_stime, rusage_start.ru_stime);
|
sys_info.stime = time_diff(rusage_end.ru_stime, rusage_start.ru_stime);
|
||||||
|
@ -626,6 +586,7 @@ pgss_planner_hook(Query *parse, const char *query_string, int cursorOptions, Par
|
||||||
WalUsage walusage_start;
|
WalUsage walusage_start;
|
||||||
WalUsage walusage;
|
WalUsage walusage;
|
||||||
|
|
||||||
|
memset(&plan_info, 0, sizeof(PlanInfo));
|
||||||
/* We need to track buffer usage as the planner can access them. */
|
/* We need to track buffer usage as the planner can access them. */
|
||||||
bufusage_start = pgBufferUsage;
|
bufusage_start = pgBufferUsage;
|
||||||
|
|
||||||
|
@ -670,7 +631,7 @@ pgss_planner_hook(Query *parse, const char *query_string, int cursorOptions, Par
|
||||||
&bufusage, /* bufusage */
|
&bufusage, /* bufusage */
|
||||||
&walusage, /* walusage */
|
&walusage, /* walusage */
|
||||||
NULL, /* pgssJumbleState */
|
NULL, /* pgssJumbleState */
|
||||||
PGSS_PLAN); /* pgssStoreKind */
|
PGSS_PLAN); /* pgssStoreKind */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -916,7 +877,8 @@ pgss_update_entry(pgssEntry *entry,
|
||||||
uint64 rows,
|
uint64 rows,
|
||||||
BufferUsage *bufusage,
|
BufferUsage *bufusage,
|
||||||
WalUsage *walusage,
|
WalUsage *walusage,
|
||||||
bool reset)
|
bool reset,
|
||||||
|
pgssStoreKind kind)
|
||||||
{
|
{
|
||||||
int index;
|
int index;
|
||||||
char application_name[APPLICATIONNAME_LEN];
|
char application_name[APPLICATIONNAME_LEN];
|
||||||
|
@ -925,6 +887,8 @@ pgss_update_entry(pgssEntry *entry,
|
||||||
double old_mean;
|
double old_mean;
|
||||||
int message_len = error_info ? strlen (error_info->message) : 0;
|
int message_len = error_info ? strlen (error_info->message) : 0;
|
||||||
int sqlcode_len = error_info ? strlen (error_info->sqlcode) : 0;
|
int sqlcode_len = error_info ? strlen (error_info->sqlcode) : 0;
|
||||||
|
int plan_text_len = plan_info ? strlen (plan_info->plan_text) : 0;
|
||||||
|
|
||||||
|
|
||||||
/* volatile block */
|
/* volatile block */
|
||||||
{
|
{
|
||||||
|
@ -934,30 +898,58 @@ pgss_update_entry(pgssEntry *entry,
|
||||||
if (reset)
|
if (reset)
|
||||||
memset(&entry->counters, 0, sizeof(Counters));
|
memset(&entry->counters, 0, sizeof(Counters));
|
||||||
|
|
||||||
if (e->counters.calls.calls == 0)
|
if (kind == PGSS_PLAN)
|
||||||
e->counters.calls.usage = USAGE_INIT;
|
|
||||||
e->counters.calls.calls += 1;
|
|
||||||
e->counters.time.total_time += total_time;
|
|
||||||
|
|
||||||
if (e->counters.calls.calls == 1)
|
|
||||||
{
|
{
|
||||||
e->counters.time.min_time = total_time;
|
if (e->counters.plancalls.calls == 0)
|
||||||
e->counters.time.max_time = total_time;
|
e->counters.plancalls.usage = USAGE_INIT;
|
||||||
e->counters.time.mean_time = total_time;
|
e->counters.plancalls.calls += 1;
|
||||||
|
e->counters.plantime.total_time += total_time;
|
||||||
|
|
||||||
|
if (e->counters.plancalls.calls == 1)
|
||||||
|
{
|
||||||
|
e->counters.plantime.min_time = total_time;
|
||||||
|
e->counters.plantime.max_time = total_time;
|
||||||
|
e->counters.plantime.mean_time = total_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Increment the counts, except when jstate is not NULL */
|
||||||
|
old_mean = e->counters.plantime.mean_time;
|
||||||
|
e->counters.plantime.mean_time += (total_time - old_mean) / e->counters.plancalls.calls;
|
||||||
|
e->counters.plantime.sum_var_time +=(total_time - old_mean) * (total_time - e->counters.plantime.mean_time);
|
||||||
|
|
||||||
|
/* calculate min and max time */
|
||||||
|
if (e->counters.plantime.min_time > total_time) e->counters.plantime.min_time = total_time;
|
||||||
|
if (e->counters.plantime.max_time < total_time) e->counters.plantime.max_time = total_time;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
e->counters.state = kind;
|
||||||
|
if (e->counters.calls.calls == 0)
|
||||||
|
e->counters.calls.usage = USAGE_INIT;
|
||||||
|
e->counters.calls.calls += 1;
|
||||||
|
e->counters.time.total_time += total_time;
|
||||||
|
|
||||||
|
if (e->counters.calls.calls == 1)
|
||||||
|
{
|
||||||
|
e->counters.time.min_time = total_time;
|
||||||
|
e->counters.time.max_time = total_time;
|
||||||
|
e->counters.time.mean_time = total_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Increment the counts, except when jstate is not NULL */
|
||||||
|
old_mean = e->counters.time.mean_time;
|
||||||
|
e->counters.time.mean_time += (total_time - old_mean) / e->counters.calls.calls;
|
||||||
|
e->counters.time.sum_var_time +=(total_time - old_mean) * (total_time - e->counters.time.mean_time);
|
||||||
|
|
||||||
|
/* calculate min and max time */
|
||||||
|
if (e->counters.time.min_time > total_time) e->counters.time.min_time = total_time;
|
||||||
|
if (e->counters.time.max_time < total_time) e->counters.time.max_time = total_time;
|
||||||
|
|
||||||
|
index = get_histogram_bucket(total_time);
|
||||||
|
e->counters.resp_calls[index]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Increment the counts, except when jstate is not NULL */
|
_snprintf(e->counters.planinfo.plan_text, plan_info->plan_text, plan_text_len, PLAN_TEXT_LEN);
|
||||||
old_mean = e->counters.time.mean_time;
|
|
||||||
e->counters.time.mean_time += (total_time - old_mean) / e->counters.calls.calls;
|
|
||||||
e->counters.time.sum_var_time +=(total_time - old_mean) * (total_time - e->counters.time.mean_time);
|
|
||||||
|
|
||||||
/* calculate min and max time */
|
|
||||||
if (e->counters.time.min_time > total_time) e->counters.time.min_time = total_time;
|
|
||||||
if (e->counters.time.max_time < total_time) e->counters.time.max_time = total_time;
|
|
||||||
|
|
||||||
index = get_histogram_bucket(total_time);
|
|
||||||
e->counters.resp_calls[index]++;
|
|
||||||
|
|
||||||
_snprintf(e->counters.info.application_name, application_name, application_name_len, APPLICATIONNAME_LEN);
|
_snprintf(e->counters.info.application_name, application_name, application_name_len, APPLICATIONNAME_LEN);
|
||||||
|
|
||||||
e->counters.info.num_relations = pgss->num_relations;
|
e->counters.info.num_relations = pgss->num_relations;
|
||||||
|
@ -1020,7 +1012,7 @@ pgss_get_entry(uint64 bucket_id,
|
||||||
uint64 dbid,
|
uint64 dbid,
|
||||||
uint64 queryid,
|
uint64 queryid,
|
||||||
uint64 ip,
|
uint64 ip,
|
||||||
bool *found)
|
uint64 planid)
|
||||||
{
|
{
|
||||||
pgssEntry *entry;
|
pgssEntry *entry;
|
||||||
pgssHashKey key;
|
pgssHashKey key;
|
||||||
|
@ -1032,12 +1024,11 @@ pgss_get_entry(uint64 bucket_id,
|
||||||
key.dbid = MyDatabaseId;
|
key.dbid = MyDatabaseId;
|
||||||
key.queryid = queryid;
|
key.queryid = queryid;
|
||||||
key.ip = pg_get_client_addr();
|
key.ip = pg_get_client_addr();
|
||||||
|
key.planid = planid;
|
||||||
|
|
||||||
entry = (pgssEntry *) hash_search(pgss_hash, &key, HASH_FIND, NULL);
|
entry = (pgssEntry *) hash_search(pgss_hash, &key, HASH_FIND, NULL);
|
||||||
if(!entry)
|
if(!entry)
|
||||||
{
|
{
|
||||||
if (found)
|
|
||||||
*found = false;
|
|
||||||
/* OK to create a new hashtable entry */
|
/* OK to create a new hashtable entry */
|
||||||
entry = hash_entry_alloc(pgss, &key, GetDatabaseEncoding());
|
entry = hash_entry_alloc(pgss, &key, GetDatabaseEncoding());
|
||||||
if (entry == NULL)
|
if (entry == NULL)
|
||||||
|
@ -1053,7 +1044,8 @@ pgss_store_query(uint64 queryid,
|
||||||
CmdType cmd_type,
|
CmdType cmd_type,
|
||||||
int query_location,
|
int query_location,
|
||||||
int query_len,
|
int query_len,
|
||||||
pgssJumbleState *jstate)
|
pgssJumbleState *jstate,
|
||||||
|
pgssStoreKind kind)
|
||||||
{
|
{
|
||||||
char *norm_query = NULL;
|
char *norm_query = NULL;
|
||||||
|
|
||||||
|
@ -1105,7 +1097,7 @@ pgss_store_query(uint64 queryid,
|
||||||
NULL, /* bufusage */
|
NULL, /* bufusage */
|
||||||
NULL, /* walusage */
|
NULL, /* walusage */
|
||||||
jstate, /* pgssJumbleState */
|
jstate, /* pgssJumbleState */
|
||||||
PGSS_EXEC); /* pgssStoreKind */
|
kind); /* pgssStoreKind */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1117,7 +1109,7 @@ pgss_store_error(uint64 queryid,
|
||||||
|
|
||||||
error_info.elevel = edata->elevel;
|
error_info.elevel = edata->elevel;
|
||||||
snprintf(error_info.message, ERROR_MESSAGE_LEN, "%s", edata->message);
|
snprintf(error_info.message, ERROR_MESSAGE_LEN, "%s", edata->message);
|
||||||
snprintf(error_info.sqlcode, ERROR_MESSAGE_LEN, "%s", unpack_sql_state(edata->sqlerrcode));
|
snprintf(error_info.sqlcode, SQLCODE_LEN, "%s", unpack_sql_state(edata->sqlerrcode));
|
||||||
|
|
||||||
pgss_store(queryid, /* query id */
|
pgss_store(queryid, /* query id */
|
||||||
query, /* query text */
|
query, /* query text */
|
||||||
|
@ -1153,56 +1145,7 @@ pgss_store_utility(const char *query,
|
||||||
bufusage, /* bufusage */
|
bufusage, /* bufusage */
|
||||||
walusage, /* walusage */
|
walusage, /* walusage */
|
||||||
NULL, /* pgssJumbleState */
|
NULL, /* pgssJumbleState */
|
||||||
PGSS_EXEC); /* pgssStoreKind */
|
PGSS_EXEC); /* pgssStoreKind */
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
update_planinfo(PlanInfo *plan_info, pgssStoreKind kind, double total_time, uint64 userid, uint64 dbid, uint64 queryid, uint64 ip)
|
|
||||||
{
|
|
||||||
char str[64];
|
|
||||||
uint64 query_hash;
|
|
||||||
PlanInfo pi;
|
|
||||||
|
|
||||||
if (plan_info == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
snprintf(str, 64, "%08lx%08lX%08lX%08lX", userid, dbid, queryid, ip);
|
|
||||||
query_hash = DatumGetUInt64(hash_any_extended((const unsigned char*)str, strlen(str), 0));
|
|
||||||
|
|
||||||
if (pgss_get_plan(query_hash, &pi))
|
|
||||||
{
|
|
||||||
if (kind == PGSS_PLAN)
|
|
||||||
{
|
|
||||||
double old_mean = 0;
|
|
||||||
|
|
||||||
pi.plans += 1;
|
|
||||||
pi.time.total_time += total_time;
|
|
||||||
if (pi.plans == 0)
|
|
||||||
if (pi.plans == 1)
|
|
||||||
{
|
|
||||||
pi.time.min_time = total_time;
|
|
||||||
pi.time.max_time = total_time;
|
|
||||||
pi.time.mean_time = total_time;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Increment the counts, except when jstate is not NULL */
|
|
||||||
old_mean = pi.time.mean_time;
|
|
||||||
pi.time.mean_time += (total_time - old_mean) / pi.plans;
|
|
||||||
pi.time.sum_var_time +=(total_time - old_mean) * (total_time - pi.time.mean_time);
|
|
||||||
|
|
||||||
/* calculate min and max time */
|
|
||||||
if (pi.time.min_time > total_time) pi.time.min_time = total_time;
|
|
||||||
if (pi.time.max_time < total_time) pi.time.max_time = total_time;
|
|
||||||
pgss_store_plan(query_hash, &pi);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (kind == PGSS_EXEC)
|
|
||||||
{
|
|
||||||
pgss_store_plan(query_hash, plan_info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1229,11 +1172,14 @@ pgss_store(uint64 queryid,
|
||||||
pgssJumbleState *jstate,
|
pgssJumbleState *jstate,
|
||||||
pgssStoreKind kind)
|
pgssStoreKind kind)
|
||||||
{
|
{
|
||||||
int bucket_id;
|
|
||||||
pgssEntry *entry;
|
pgssEntry *entry;
|
||||||
pgssSharedState *pgss = pgsm_get_ss();
|
pgssSharedState *pgss = pgsm_get_ss();
|
||||||
bool reset = false;
|
bool reset = false;
|
||||||
bool found = true;
|
uint64 bucketid;
|
||||||
|
uint64 userid = GetUserId();
|
||||||
|
uint64 dbid = MyDatabaseId;
|
||||||
|
uint64 ip = pg_get_client_addr();
|
||||||
|
uint64 planid = plan_info ? plan_info->planid: 0;
|
||||||
|
|
||||||
/* Monitoring is disabled */
|
/* Monitoring is disabled */
|
||||||
if (!PGSM_ENABLED)
|
if (!PGSM_ENABLED)
|
||||||
|
@ -1245,41 +1191,67 @@ pgss_store(uint64 queryid,
|
||||||
if (!IsSystemInitialized() || !pgss_qbuf[pgss->current_wbucket])
|
if (!IsSystemInitialized() || !pgss_qbuf[pgss->current_wbucket])
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bucket_id = get_next_wbucket(pgss);
|
bucketid = get_next_wbucket(pgss);
|
||||||
if (bucket_id != pgss->current_wbucket)
|
if (bucketid != pgss->current_wbucket)
|
||||||
{
|
{
|
||||||
reset = true;
|
reset = true;
|
||||||
pgss->current_wbucket = bucket_id;
|
pgss->current_wbucket = bucketid;
|
||||||
}
|
}
|
||||||
|
|
||||||
update_planinfo(plan_info, kind, total_time, (uint64)GetUserId(), (uint64)MyDatabaseId, queryid, (uint64)pg_get_client_addr());
|
|
||||||
|
|
||||||
LWLockAcquire(pgss->lock, LW_EXCLUSIVE);
|
LWLockAcquire(pgss->lock, LW_EXCLUSIVE);
|
||||||
entry = pgss_get_entry(bucket_id, GetUserId(), MyDatabaseId, queryid, pg_get_client_addr(), &found);
|
|
||||||
if (entry == NULL)
|
switch (kind)
|
||||||
{
|
{
|
||||||
LWLockRelease(pgss->lock);
|
case PGSS_PARSE:
|
||||||
return;
|
case PGSS_PLAN:
|
||||||
|
{
|
||||||
|
pgssQueryEntry *query_entry;
|
||||||
|
query_entry = pgss_store_query_info(bucketid, queryid, dbid, userid, ip, query, strlen(query), kind);
|
||||||
|
if (query_entry == NULL)
|
||||||
|
elog(DEBUG1, "pg_stat_monitor: out of memory");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PGSS_EXEC:
|
||||||
|
{
|
||||||
|
pgssQueryEntry *query_entry;
|
||||||
|
query_entry = pgss_store_query_info(bucketid, queryid, dbid, userid, ip, query, strlen(query), kind);
|
||||||
|
if (query_entry == NULL)
|
||||||
|
{
|
||||||
|
elog(DEBUG1, "pg_stat_monitor: out of memory");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
entry = pgss_get_entry(bucketid, userid, dbid, queryid, ip, planid);
|
||||||
|
if (entry == NULL)
|
||||||
|
{
|
||||||
|
elog(DEBUG1, "pg_stat_monitor: out of memory");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jstate == NULL)
|
||||||
|
pgss_update_entry(entry, /* entry */
|
||||||
|
bucketid, /* bucketid */
|
||||||
|
queryid, /* queryid */
|
||||||
|
query, /* query */
|
||||||
|
plan_info, /* PlanInfo */
|
||||||
|
cmd_type, /* CmdType */
|
||||||
|
sys_info, /* SysInfo */
|
||||||
|
error_info, /* ErrorInfo */
|
||||||
|
total_time, /* total_time */
|
||||||
|
rows, /* rows */
|
||||||
|
bufusage, /* bufusage */
|
||||||
|
walusage, /* walusage */
|
||||||
|
reset, /* reset */
|
||||||
|
kind); /* kind */
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PGSS_FINISHED:
|
||||||
|
case PGSS_NUMKIND:
|
||||||
|
case PGSS_INVALID:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PGSS_ERROR:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* In case query is not found in the hash, add that into hash. */
|
|
||||||
if (!found)
|
|
||||||
store_query(bucket_id, queryid, query, strlen(query));
|
|
||||||
|
|
||||||
if (jstate == NULL && kind == PGSS_EXEC)
|
|
||||||
pgss_update_entry(entry, /* entry */
|
|
||||||
bucket_id, /* bucketid */
|
|
||||||
queryid, /* queryid */
|
|
||||||
query, /* query */
|
|
||||||
plan_info, /* PlanInfo */
|
|
||||||
cmd_type, /* CmdType */
|
|
||||||
sys_info, /* SysInfo */
|
|
||||||
error_info, /* ErrorInfo */
|
|
||||||
total_time, /* total_time */
|
|
||||||
rows, /* rows */
|
|
||||||
bufusage, /* bufusage */
|
|
||||||
walusage, /* walusage */
|
|
||||||
reset); /* reset */
|
|
||||||
LWLockRelease(pgss->lock);
|
LWLockRelease(pgss->lock);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
@ -1296,6 +1268,7 @@ pg_stat_monitor_reset(PG_FUNCTION_ARGS)
|
||||||
errmsg("pg_stat_monitor: must be loaded via shared_preload_libraries")));
|
errmsg("pg_stat_monitor: must be loaded via shared_preload_libraries")));
|
||||||
LWLockAcquire(pgss->lock, LW_EXCLUSIVE);
|
LWLockAcquire(pgss->lock, LW_EXCLUSIVE);
|
||||||
hash_entry_dealloc(-1);
|
hash_entry_dealloc(-1);
|
||||||
|
hash_query_entry_dealloc(-1);
|
||||||
LWLockRelease(pgss->lock);
|
LWLockRelease(pgss->lock);
|
||||||
PG_RETURN_VOID();
|
PG_RETURN_VOID();
|
||||||
}
|
}
|
||||||
|
@ -1307,6 +1280,25 @@ pg_stat_monitor(PG_FUNCTION_ARGS)
|
||||||
return (Datum) 0;
|
return (Datum) 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
IsBucketValid(uint64 bucketid)
|
||||||
|
{
|
||||||
|
struct tm tm;
|
||||||
|
time_t bucket_t,current_t;
|
||||||
|
double diff_t;
|
||||||
|
pgssSharedState *pgss = pgsm_get_ss();
|
||||||
|
|
||||||
|
memset(&tm, 0, sizeof(tm));
|
||||||
|
strptime(pgss->bucket_start_time[bucketid], "%Y-%m-%d %H:%M:%S", &tm);
|
||||||
|
bucket_t = mktime(&tm);
|
||||||
|
|
||||||
|
time(¤t_t);
|
||||||
|
diff_t = difftime(current_t, bucket_t);
|
||||||
|
if (diff_t > (PGSM_BUCKET_TIME * PGSM_MAX_BUCKETS))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/* Common code for all versions of pg_stat_statements() */
|
/* Common code for all versions of pg_stat_statements() */
|
||||||
static void
|
static void
|
||||||
pg_stat_monitor_internal(FunctionCallInfo fcinfo,
|
pg_stat_monitor_internal(FunctionCallInfo fcinfo,
|
||||||
|
@ -1317,21 +1309,12 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo,
|
||||||
Tuplestorestate *tupstore;
|
Tuplestorestate *tupstore;
|
||||||
MemoryContext per_query_ctx;
|
MemoryContext per_query_ctx;
|
||||||
MemoryContext oldcontext;
|
MemoryContext oldcontext;
|
||||||
Oid userid = GetUserId();
|
|
||||||
bool is_allowed_role;
|
|
||||||
HASH_SEQ_STATUS hash_seq;
|
HASH_SEQ_STATUS hash_seq;
|
||||||
pgssEntry *entry;
|
pgssEntry *entry;
|
||||||
char *query_txt;
|
|
||||||
char queryid_txt[64];
|
|
||||||
char planid_txt[64];
|
|
||||||
char parentid_txt[64];
|
char parentid_txt[64];
|
||||||
pgssSharedState *pgss = pgsm_get_ss();
|
pgssSharedState *pgss = pgsm_get_ss();
|
||||||
HTAB *pgss_hash = pgsm_get_hash();
|
HTAB *pgss_hash = pgsm_get_hash();
|
||||||
|
char *query_txt = (char*) malloc(PGSM_QUERY_MAX_LEN);
|
||||||
query_txt = (char*) malloc(PGSM_QUERY_MAX_LEN);
|
|
||||||
|
|
||||||
/* Superusers or members of pg_read_all_stats members are allowed */
|
|
||||||
is_allowed_role = is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_STATS);
|
|
||||||
|
|
||||||
/* Safety check... */
|
/* Safety check... */
|
||||||
if (!IsSystemInitialized())
|
if (!IsSystemInitialized())
|
||||||
|
@ -1358,7 +1341,7 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo,
|
||||||
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
|
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
|
||||||
elog(ERROR, "pg_stat_monitor: return type must be a row type");
|
elog(ERROR, "pg_stat_monitor: return type must be a row type");
|
||||||
|
|
||||||
if (tupdesc->natts != 46)
|
if (tupdesc->natts != 48)
|
||||||
elog(ERROR, "pg_stat_monitor: incorrect number of output arguments, required %d", tupdesc->natts);
|
elog(ERROR, "pg_stat_monitor: incorrect number of output arguments, required %d", tupdesc->natts);
|
||||||
|
|
||||||
tupstore = tuplestore_begin_heap(true, false, work_mem);
|
tupstore = tuplestore_begin_heap(true, false, work_mem);
|
||||||
|
@ -1373,83 +1356,37 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo,
|
||||||
hash_seq_init(&hash_seq, pgss_hash);
|
hash_seq_init(&hash_seq, pgss_hash);
|
||||||
while ((entry = hash_seq_search(&hash_seq)) != NULL)
|
while ((entry = hash_seq_search(&hash_seq)) != NULL)
|
||||||
{
|
{
|
||||||
Datum values[PG_STAT_STATEMENTS_COLS];
|
Datum values[PG_STAT_STATEMENTS_COLS] = {0};
|
||||||
bool nulls[PG_STAT_STATEMENTS_COLS];
|
bool nulls[PG_STAT_STATEMENTS_COLS] = {0};
|
||||||
int i = 0;
|
int i = 0;
|
||||||
Counters tmp;
|
Counters tmp;
|
||||||
double stddev;
|
double stddev;
|
||||||
uint64 queryid = entry->key.queryid;
|
char queryid_text[16] = {0};
|
||||||
struct tm tm;
|
char planid_text[16] = {0};
|
||||||
time_t bucket_t,current_t;
|
uint64 queryid = entry->key.queryid;
|
||||||
double diff_t;
|
uint64 bucketid = entry->key.bucket_id;
|
||||||
char str[64];
|
uint64 dbid = entry->key.dbid;
|
||||||
uint64 query_hash;
|
uint64 userid = entry->key.userid;
|
||||||
PlanInfo plan_info;
|
uint64 ip = entry->key.ip;
|
||||||
|
uint64 planid = entry->key.planid;
|
||||||
|
|
||||||
memset(&plan_info, 0, sizeof(plan_info));
|
unsigned char *buf = pgss_qbuf[bucketid];
|
||||||
snprintf(str, 64, "%08lx%08lX%08lX%08lX", (uint64)entry->key.userid, (uint64)entry->key.dbid, queryid, (uint64)entry->key.ip);
|
char *query_txt = (char*) malloc(PGSM_QUERY_MAX_LEN);
|
||||||
query_hash = DatumGetUInt64(hash_any_extended((const unsigned char*)str, strlen(str), 0));
|
bool is_allowed_role = is_member_of_role(GetUserId(), DEFAULT_ROLE_READ_ALL_STATS);
|
||||||
pgss_get_plan(query_hash, &plan_info);
|
|
||||||
|
|
||||||
memset(&tm, 0, sizeof(tm));
|
if (!IsBucketValid(bucketid))
|
||||||
strptime(pgss->bucket_start_time[entry->key.bucket_id], "%Y-%m-%d %H:%M:%S", &tm);
|
|
||||||
bucket_t = mktime(&tm);
|
|
||||||
|
|
||||||
time(¤t_t);
|
|
||||||
diff_t = difftime(current_t, bucket_t);
|
|
||||||
if (diff_t > (PGSM_BUCKET_TIME * PGSM_MAX_BUCKETS))
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
memset(values, 0, sizeof(values));
|
if (!hash_find_query_entry(bucketid, queryid, dbid, userid, ip))
|
||||||
memset(nulls, 0, sizeof(nulls));
|
continue;
|
||||||
|
|
||||||
if (!hash_find_query_entry(entry->key.bucket_id, queryid))
|
if (read_query(buf, bucketid, queryid, query_txt) == 0)
|
||||||
{
|
{
|
||||||
sprintf(query_txt, "%s", "pg_stat_monitor: queryid not found in hash and in temporay file");
|
int len;
|
||||||
|
len = read_query_buffer(bucketid, queryid, query_txt);
|
||||||
|
if (len != MAX_QUERY_BUFFER_BUCKET)
|
||||||
|
sprintf(query_txt, "%s", "<insufficient disk/shared space>");
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
int len = 0;
|
|
||||||
unsigned char *buf = pgss_qbuf[entry->key.bucket_id];
|
|
||||||
if(read_query(buf, queryid, query_txt) == 0)
|
|
||||||
{
|
|
||||||
switch(PGSM_OVERFLOW_TARGET)
|
|
||||||
{
|
|
||||||
case OVERFLOW_TARGET_NONE:
|
|
||||||
sprintf(query_txt, "%s", "query not found in query shared_buffer, no space left");
|
|
||||||
break;
|
|
||||||
case OVERFLOW_TARGET_DISK:
|
|
||||||
{
|
|
||||||
len = read_query_buffer(entry->key.bucket_id, queryid, query_txt);
|
|
||||||
if (len != MAX_QUERY_BUFFER_BUCKET)
|
|
||||||
sprintf(query_txt, "%s", "query not found either in hash nor in temporay file");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (query_txt)
|
|
||||||
sprintf(queryid_txt, "%08lX", queryid);
|
|
||||||
else
|
|
||||||
sprintf(queryid_txt, "%08lX", (long unsigned int)0);
|
|
||||||
|
|
||||||
sprintf(planid_txt, "%08lX", plan_info.planid);
|
|
||||||
|
|
||||||
/* bucketid at column number 0 */
|
|
||||||
values[i++] = ObjectIdGetDatum(entry->key.bucket_id);
|
|
||||||
|
|
||||||
/* userid at column number 1 */
|
|
||||||
values[i++] = ObjectIdGetDatum(entry->key.userid);
|
|
||||||
|
|
||||||
/* dbid at column number 2 */
|
|
||||||
values[i++] = ObjectIdGetDatum(entry->key.dbid);
|
|
||||||
|
|
||||||
/* ip address at column number 3 */
|
|
||||||
/* Superusers or members of pg_read_all_stats members are allowed */
|
|
||||||
if (is_allowed_role || entry->key.userid == userid)
|
|
||||||
values[i++] = Int64GetDatumFast(entry->key.ip);
|
|
||||||
else
|
|
||||||
values[i++] = Int64GetDatumFast(0);
|
|
||||||
|
|
||||||
/* copy counters to a local variable to keep locking time short */
|
/* copy counters to a local variable to keep locking time short */
|
||||||
{
|
{
|
||||||
|
@ -1458,17 +1395,76 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo,
|
||||||
tmp = e->counters;
|
tmp = e->counters;
|
||||||
SpinLockRelease(&e->mutex);
|
SpinLockRelease(&e->mutex);
|
||||||
}
|
}
|
||||||
|
/* bucketid at column number 0 */
|
||||||
|
values[i++] = Int64GetDatumFast(bucketid);
|
||||||
|
|
||||||
/* queryid at column number 4 */
|
/* userid at column number 1 */
|
||||||
values[i++] = CStringGetTextDatum(queryid_txt);
|
values[i++] = ObjectIdGetDatum(userid);
|
||||||
|
|
||||||
/* planid at column number 5 */
|
/* dbid at column number 2 */
|
||||||
if (plan_info.planid != 0)
|
values[i++] = ObjectIdGetDatum(dbid);
|
||||||
values[i++] = CStringGetTextDatum(planid_txt);
|
|
||||||
|
/*
|
||||||
|
* ip address at column number 3,
|
||||||
|
* Superusers or members of pg_read_all_stats members
|
||||||
|
* are allowed
|
||||||
|
*/
|
||||||
|
if (is_allowed_role || userid == GetUserId())
|
||||||
|
values[i++] = Int64GetDatumFast(ip);
|
||||||
else
|
else
|
||||||
nulls[i++] = true;
|
nulls[i++] = true;
|
||||||
|
|
||||||
/* parentid at column number 6 */
|
/* queryid at column number 4 */
|
||||||
|
sprintf(queryid_text, "%08lX", queryid);
|
||||||
|
values[i++] = CStringGetTextDatum(queryid_text);
|
||||||
|
|
||||||
|
/* planid at column number 5 */
|
||||||
|
if (planid)
|
||||||
|
{
|
||||||
|
sprintf(planid_text, "%08lX", planid);
|
||||||
|
values[i++] = CStringGetTextDatum(planid_text);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nulls[i++] = true;
|
||||||
|
}
|
||||||
|
if (is_allowed_role || userid == GetUserId())
|
||||||
|
{
|
||||||
|
if (showtext)
|
||||||
|
{
|
||||||
|
char *enc;
|
||||||
|
|
||||||
|
/* query at column number 6 */
|
||||||
|
enc = pg_any_to_server(query_txt, strlen(query_txt), GetDatabaseEncoding());
|
||||||
|
values[i++] = CStringGetTextDatum(enc);
|
||||||
|
if (enc != query_txt)
|
||||||
|
pfree(enc);
|
||||||
|
/* plan at column number 7 */
|
||||||
|
if (planid && tmp.planinfo.plan_text)
|
||||||
|
values[i++] = CStringGetTextDatum(tmp.planinfo.plan_text);
|
||||||
|
else
|
||||||
|
nulls[i++] = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* query at column number 6 */
|
||||||
|
nulls[i++] = true;
|
||||||
|
/* plan at column number 7 */
|
||||||
|
nulls[i++] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* query text at column number 6 */
|
||||||
|
values[i++] = CStringGetTextDatum("<insufficient privilege>");
|
||||||
|
values[i++] = CStringGetTextDatum("<insufficient privilege>");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* state at column number 8 */
|
||||||
|
values[i++] = Int64GetDatumFast(tmp.state);
|
||||||
|
|
||||||
|
/* parentid at column number 9 */
|
||||||
if (tmp.info.parentid != UINT64CONST(0))
|
if (tmp.info.parentid != UINT64CONST(0))
|
||||||
{
|
{
|
||||||
sprintf(parentid_txt,"%08lX",tmp.info.parentid);
|
sprintf(parentid_txt,"%08lX",tmp.info.parentid);
|
||||||
|
@ -1479,53 +1475,11 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo,
|
||||||
nulls[i++] = true;
|
nulls[i++] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_allowed_role || entry->key.userid == userid)
|
|
||||||
{
|
|
||||||
/* query at column number 7 */
|
|
||||||
/* plan at column number 8 */
|
|
||||||
if (showtext)
|
|
||||||
{
|
|
||||||
if (query_txt)
|
|
||||||
{
|
|
||||||
char *enc;
|
|
||||||
enc = pg_any_to_server(query_txt, strlen(query_txt), entry->encoding);
|
|
||||||
values[i++] = CStringGetTextDatum(enc);
|
|
||||||
values[i++] = CStringGetTextDatum(plan_info.plan_text);
|
|
||||||
if (enc != query_txt)
|
|
||||||
pfree(enc);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
nulls[i++] = true;
|
|
||||||
nulls[i++] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Query text not requested */
|
|
||||||
nulls[i++] = true;
|
|
||||||
nulls[i++] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Don't show query text, but hint as to the reason for not doing
|
|
||||||
* so if it was requested
|
|
||||||
*/
|
|
||||||
if (showtext)
|
|
||||||
values[i++] = CStringGetTextDatum("<insufficient privilege>");
|
|
||||||
else
|
|
||||||
nulls[i++] = true;
|
|
||||||
/* skip plan_text */
|
|
||||||
nulls[i++] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* application_name at column number 9 */
|
/* application_name at column number 9 */
|
||||||
if (strlen(tmp.info.application_name) == 0)
|
if (strlen(tmp.info.application_name) > 0)
|
||||||
nulls[i++] = true;
|
|
||||||
else
|
|
||||||
values[i++] = CStringGetTextDatum(tmp.info.application_name);
|
values[i++] = CStringGetTextDatum(tmp.info.application_name);
|
||||||
|
else
|
||||||
|
nulls[i++] = true;
|
||||||
|
|
||||||
/* relations at column number 10 */
|
/* relations at column number 10 */
|
||||||
if (tmp.info.num_relations > 0)
|
if (tmp.info.num_relations > 0)
|
||||||
|
@ -1608,22 +1562,36 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo,
|
||||||
/* calls at column number 22 */
|
/* calls at column number 22 */
|
||||||
values[i++] = Int64GetDatumFast(tmp.calls.rows);
|
values[i++] = Int64GetDatumFast(tmp.calls.rows);
|
||||||
|
|
||||||
/* plan_calls at column number 23 */
|
if (tmp.calls.calls == 0)
|
||||||
values[i++] = Int64GetDatumFast(plan_info.plans);
|
{
|
||||||
|
/* Query of pg_stat_monitor itslef started from zero count */
|
||||||
|
tmp.calls.calls++;
|
||||||
|
tmp.resp_calls[0]++;
|
||||||
|
}
|
||||||
|
|
||||||
/* plan_total_time at column number 24 */
|
/* calls at column number 23 */
|
||||||
values[i++] = Float8GetDatumFast(plan_info.time.total_time);
|
values[i++] = Int64GetDatumFast(tmp.plancalls.calls);
|
||||||
|
|
||||||
/* plan_min_time at column number 25 */
|
/* total_time at column number 24 */
|
||||||
values[i++] = Float8GetDatumFast(plan_info.time.min_time);
|
values[i++] = Float8GetDatumFast(tmp.plantime.total_time);
|
||||||
|
|
||||||
/* plan_max_time at column number 26 */
|
/* min_time at column number 25 */
|
||||||
values[i++] = Float8GetDatumFast(plan_info.time.max_time);
|
values[i++] = Float8GetDatumFast(tmp.plantime.min_time);
|
||||||
|
|
||||||
/* plan_mean_time at column number 27 */
|
/* max_time at column number 26 */
|
||||||
values[i++] = Float8GetDatumFast(plan_info.time.mean_time);
|
values[i++] = Float8GetDatumFast(tmp.plantime.max_time);
|
||||||
|
|
||||||
/* blocks are from column number 28 - 39 */
|
/* mean_time at column number 27 */
|
||||||
|
values[i++] = Float8GetDatumFast(tmp.plantime.mean_time);
|
||||||
|
if (tmp.plancalls.calls > 1)
|
||||||
|
stddev = sqrt(tmp.plantime.sum_var_time / tmp.plancalls.calls);
|
||||||
|
else
|
||||||
|
stddev = 0.0;
|
||||||
|
|
||||||
|
/* calls at column number 28 */
|
||||||
|
values[i++] = Float8GetDatumFast(stddev);
|
||||||
|
|
||||||
|
/* blocks are from column number 29 - 40 */
|
||||||
values[i++] = Int64GetDatumFast(tmp.blocks.shared_blks_hit);
|
values[i++] = Int64GetDatumFast(tmp.blocks.shared_blks_hit);
|
||||||
values[i++] = Int64GetDatumFast(tmp.blocks.shared_blks_read);
|
values[i++] = Int64GetDatumFast(tmp.blocks.shared_blks_read);
|
||||||
values[i++] = Int64GetDatumFast(tmp.blocks.shared_blks_dirtied);
|
values[i++] = Int64GetDatumFast(tmp.blocks.shared_blks_dirtied);
|
||||||
|
@ -1637,22 +1605,22 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo,
|
||||||
values[i++] = Float8GetDatumFast(tmp.blocks.blk_read_time);
|
values[i++] = Float8GetDatumFast(tmp.blocks.blk_read_time);
|
||||||
values[i++] = Float8GetDatumFast(tmp.blocks.blk_write_time);
|
values[i++] = Float8GetDatumFast(tmp.blocks.blk_write_time);
|
||||||
|
|
||||||
/* resp_calls at column number 40 */
|
/* resp_calls at column number 41 */
|
||||||
values[i++] = IntArrayGetTextDatum(tmp.resp_calls, MAX_RESPONSE_BUCKET);
|
values[i++] = IntArrayGetTextDatum(tmp.resp_calls, MAX_RESPONSE_BUCKET);
|
||||||
|
|
||||||
/* utime at column number 41 */
|
/* utime at column number 42 */
|
||||||
values[i++] = Float8GetDatumFast(tmp.sysinfo.utime);
|
values[i++] = Float8GetDatumFast(tmp.sysinfo.utime);
|
||||||
|
|
||||||
/* stime at column number 42 */
|
/* stime at column number 43 */
|
||||||
values[i++] = Float8GetDatumFast(tmp.sysinfo.stime);
|
values[i++] = Float8GetDatumFast(tmp.sysinfo.stime);
|
||||||
{
|
{
|
||||||
char buf[256];
|
char buf[256];
|
||||||
Datum wal_bytes;
|
Datum wal_bytes;
|
||||||
|
|
||||||
/* wal_records at column number 43 */
|
/* wal_records at column number 44 */
|
||||||
values[i++] = Int64GetDatumFast(tmp.walusage.wal_records);
|
values[i++] = Int64GetDatumFast(tmp.walusage.wal_records);
|
||||||
|
|
||||||
/* wal_fpi at column number 44 */
|
/* wal_fpi at column number 45 */
|
||||||
values[i++] = Int64GetDatumFast(tmp.walusage.wal_fpi);
|
values[i++] = Int64GetDatumFast(tmp.walusage.wal_fpi);
|
||||||
|
|
||||||
snprintf(buf, sizeof buf, UINT64_FORMAT, tmp.walusage.wal_bytes);
|
snprintf(buf, sizeof buf, UINT64_FORMAT, tmp.walusage.wal_bytes);
|
||||||
|
@ -1662,13 +1630,12 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo,
|
||||||
CStringGetDatum(buf),
|
CStringGetDatum(buf),
|
||||||
ObjectIdGetDatum(0),
|
ObjectIdGetDatum(0),
|
||||||
Int32GetDatum(-1));
|
Int32GetDatum(-1));
|
||||||
/* wal_bytes at column number 45 */
|
/* wal_bytes at column number 46 */
|
||||||
values[i++] = wal_bytes;
|
values[i++] = wal_bytes;
|
||||||
}
|
}
|
||||||
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
|
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
|
||||||
}
|
}
|
||||||
free(query_txt);
|
free(query_txt);
|
||||||
|
|
||||||
/* clean up and return the tuplestore */
|
/* clean up and return the tuplestore */
|
||||||
LWLockRelease(pgss->lock);
|
LWLockRelease(pgss->lock);
|
||||||
|
|
||||||
|
@ -2651,7 +2618,7 @@ intarray_get_datum(int32 arr[], int len)
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64
|
static uint64
|
||||||
read_query(unsigned char *buf, uint64 queryid, char * query)
|
read_query(unsigned char *buf, uint64 bucketid, uint64 queryid, char * query)
|
||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
uint64 query_id = 0;
|
uint64 query_id = 0;
|
||||||
|
@ -2661,13 +2628,13 @@ read_query(unsigned char *buf, uint64 queryid, char * query)
|
||||||
|
|
||||||
memcpy(&buf_len, buf, sizeof (uint64));
|
memcpy(&buf_len, buf, sizeof (uint64));
|
||||||
if (buf_len <= 0)
|
if (buf_len <= 0)
|
||||||
return 0;
|
goto exit;
|
||||||
|
|
||||||
rlen = sizeof (uint64); /* Move forwad to skip length bytes */
|
rlen = sizeof (uint64); /* Move forwad to skip length bytes */
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
if (rlen >= buf_len)
|
if (rlen >= buf_len)
|
||||||
return 0;
|
goto exit;
|
||||||
|
|
||||||
memcpy(&query_id, &buf[rlen], sizeof (uint64)); /* query id */
|
memcpy(&query_id, &buf[rlen], sizeof (uint64)); /* query id */
|
||||||
if (query_id == queryid)
|
if (query_id == queryid)
|
||||||
|
@ -2680,7 +2647,7 @@ read_query(unsigned char *buf, uint64 queryid, char * query)
|
||||||
memcpy(&query_len, &buf[rlen], sizeof (uint64)); /* query len */
|
memcpy(&query_len, &buf[rlen], sizeof (uint64)); /* query len */
|
||||||
rlen += sizeof (uint64);
|
rlen += sizeof (uint64);
|
||||||
if (buf_len < rlen + query_len)
|
if (buf_len < rlen + query_len)
|
||||||
return 0;
|
goto exit;
|
||||||
|
|
||||||
if (found)
|
if (found)
|
||||||
{
|
{
|
||||||
|
@ -2693,15 +2660,29 @@ read_query(unsigned char *buf, uint64 queryid, char * query)
|
||||||
}
|
}
|
||||||
rlen += query_len;
|
rlen += query_len;
|
||||||
}
|
}
|
||||||
|
exit:
|
||||||
|
if (PGSM_OVERFLOW_TARGET == OVERFLOW_TARGET_NONE)
|
||||||
|
{
|
||||||
|
sprintf(query, "%s", "<insufficient shared space>");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static pgssQueryEntry*
|
||||||
store_query(int bucket_id, uint64 queryid, const char *query, uint64 query_len)
|
pgss_store_query_info(uint64 bucketid,
|
||||||
|
uint64 queryid,
|
||||||
|
uint64 dbid,
|
||||||
|
uint64 userid,
|
||||||
|
uint64 ip,
|
||||||
|
const char *query,
|
||||||
|
uint64 query_len,
|
||||||
|
pgssStoreKind kind)
|
||||||
{
|
{
|
||||||
uint64 buf_len = 0;
|
uint64 buf_len = 0;
|
||||||
pgssSharedState *pgss = pgsm_get_ss();
|
pgssSharedState *pgss = pgsm_get_ss();
|
||||||
unsigned char *buf = pgss_qbuf[pgss->current_wbucket];
|
unsigned char *buf = pgss_qbuf[pgss->current_wbucket];
|
||||||
|
pgssQueryEntry *entry;
|
||||||
|
|
||||||
if (query_len > PGSM_QUERY_MAX_LEN)
|
if (query_len > PGSM_QUERY_MAX_LEN)
|
||||||
query_len = PGSM_QUERY_MAX_LEN;
|
query_len = PGSM_QUERY_MAX_LEN;
|
||||||
|
@ -2709,12 +2690,15 @@ store_query(int bucket_id, uint64 queryid, const char *query, uint64 query_len)
|
||||||
/* Already have query in the shared buffer, there
|
/* Already have query in the shared buffer, there
|
||||||
* is no need to add that again.
|
* is no need to add that again.
|
||||||
*/
|
*/
|
||||||
if (hash_find_query_entry(bucket_id, queryid))
|
entry = hash_find_query_entry(bucketid, queryid, dbid, userid, ip);
|
||||||
return;
|
if (entry)
|
||||||
|
return entry;
|
||||||
|
|
||||||
if (!hash_create_query_entry(bucket_id, queryid))
|
entry = hash_create_query_entry(bucketid, queryid, dbid, userid, ip);
|
||||||
return;
|
if (!entry)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
entry->state = kind;
|
||||||
memcpy(&buf_len, buf, sizeof (uint64));
|
memcpy(&buf_len, buf, sizeof (uint64));
|
||||||
if (buf_len == 0)
|
if (buf_len == 0)
|
||||||
buf_len += sizeof (uint64);
|
buf_len += sizeof (uint64);
|
||||||
|
@ -2724,10 +2708,10 @@ store_query(int bucket_id, uint64 queryid, const char *query, uint64 query_len)
|
||||||
switch(PGSM_OVERFLOW_TARGET)
|
switch(PGSM_OVERFLOW_TARGET)
|
||||||
{
|
{
|
||||||
case OVERFLOW_TARGET_NONE:
|
case OVERFLOW_TARGET_NONE:
|
||||||
return;
|
return NULL;
|
||||||
case OVERFLOW_TARGET_DISK:
|
case OVERFLOW_TARGET_DISK:
|
||||||
{
|
{
|
||||||
dump_queries_buffer(bucket_id, buf, MAX_QUERY_BUFFER_BUCKET);
|
dump_queries_buffer(bucketid, buf, MAX_QUERY_BUFFER_BUCKET);
|
||||||
buf_len = sizeof (uint64);
|
buf_len = sizeof (uint64);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -2745,6 +2729,7 @@ store_query(int bucket_id, uint64 queryid, const char *query, uint64 query_len)
|
||||||
memcpy(&buf[buf_len], query, query_len); /* query */
|
memcpy(&buf[buf_len], query, query_len); /* query */
|
||||||
buf_len += query_len;
|
buf_len += query_len;
|
||||||
memcpy(buf, &buf_len, sizeof (uint64));
|
memcpy(buf, &buf_len, sizeof (uint64));
|
||||||
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64
|
static uint64
|
||||||
|
@ -2915,7 +2900,7 @@ read_query_buffer(int bucket_id, uint64 queryid, char *query_txt)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
off += buf_len;
|
off += buf_len;
|
||||||
if (read_query(buf, queryid, query_txt))
|
if (read_query(buf, bucket_id, queryid, query_txt))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (fd > 0)
|
if (fd > 0)
|
||||||
|
|
|
@ -127,8 +127,11 @@ typedef enum pgssStoreKind
|
||||||
* reference the underlying values in the arrays in the Counters struct,
|
* reference the underlying values in the arrays in the Counters struct,
|
||||||
* and this order is required in pg_stat_statements_internal().
|
* and this order is required in pg_stat_statements_internal().
|
||||||
*/
|
*/
|
||||||
PGSS_PLAN = 0,
|
PGSS_PARSE = 0,
|
||||||
|
PGSS_PLAN,
|
||||||
PGSS_EXEC,
|
PGSS_EXEC,
|
||||||
|
PGSS_ERROR,
|
||||||
|
PGSS_FINISHED,
|
||||||
|
|
||||||
PGSS_NUMKIND /* Must be last value of this enum */
|
PGSS_NUMKIND /* Must be last value of this enum */
|
||||||
} pgssStoreKind;
|
} pgssStoreKind;
|
||||||
|
@ -160,37 +163,26 @@ typedef struct CallTime
|
||||||
|
|
||||||
typedef struct pgssQueryHashKey
|
typedef struct pgssQueryHashKey
|
||||||
{
|
{
|
||||||
uint64 queryid; /* query identifier */
|
|
||||||
uint64 bucket_id; /* bucket number */
|
uint64 bucket_id; /* bucket number */
|
||||||
|
uint64 queryid; /* query identifier */
|
||||||
|
uint64 userid; /* user OID */
|
||||||
|
uint64 dbid; /* database OID */
|
||||||
|
uint64 ip; /* client ip address */
|
||||||
} pgssQueryHashKey;
|
} pgssQueryHashKey;
|
||||||
|
|
||||||
typedef struct pgssQueryEntry
|
typedef struct pgssQueryEntry
|
||||||
{
|
{
|
||||||
pgssQueryHashKey key; /* hash key of entry - MUST BE FIRST */
|
pgssQueryHashKey key; /* hash key of entry - MUST BE FIRST */
|
||||||
uint64 pos; /* bucket number */
|
uint64 pos; /* bucket number */
|
||||||
|
uint64 state; /* query state */
|
||||||
} pgssQueryEntry;
|
} pgssQueryEntry;
|
||||||
|
|
||||||
typedef struct PlanInfo
|
typedef struct PlanInfo
|
||||||
{
|
{
|
||||||
uint64 planid; /* plan identifier */
|
uint64 planid; /* plan identifier */
|
||||||
uint64 plans; /* how many times plan */
|
|
||||||
CallTime time;
|
|
||||||
char plan_text[PLAN_TEXT_LEN]; /* plan text */
|
char plan_text[PLAN_TEXT_LEN]; /* plan text */
|
||||||
} PlanInfo;
|
} PlanInfo;
|
||||||
|
|
||||||
/* shared nenory storage for the query */
|
|
||||||
typedef struct pgssPlanHashKey
|
|
||||||
{
|
|
||||||
uint64 query_hash; /* query reference identifier */
|
|
||||||
} pgssPlanHashKey;
|
|
||||||
|
|
||||||
typedef struct pgssPlanEntry
|
|
||||||
{
|
|
||||||
pgssPlanHashKey key; /* hash key of entry - MUST BE FIRST */
|
|
||||||
PlanInfo plan_info; /* planning information */
|
|
||||||
slock_t mutex; /* protects the counters only */
|
|
||||||
} pgssPlanEntry;
|
|
||||||
|
|
||||||
typedef struct pgssHashKey
|
typedef struct pgssHashKey
|
||||||
{
|
{
|
||||||
uint64 bucket_id; /* bucket number */
|
uint64 bucket_id; /* bucket number */
|
||||||
|
@ -198,6 +190,7 @@ typedef struct pgssHashKey
|
||||||
uint64 userid; /* user OID */
|
uint64 userid; /* user OID */
|
||||||
uint64 dbid; /* database OID */
|
uint64 dbid; /* database OID */
|
||||||
uint64 ip; /* client ip address */
|
uint64 ip; /* client ip address */
|
||||||
|
uint64 planid; /* plan identifier */
|
||||||
} pgssHashKey;
|
} pgssHashKey;
|
||||||
|
|
||||||
typedef struct QueryInfo
|
typedef struct QueryInfo
|
||||||
|
@ -263,14 +256,18 @@ typedef struct Counters
|
||||||
uint64 bucket_id; /* bucket id */
|
uint64 bucket_id; /* bucket id */
|
||||||
Calls calls;
|
Calls calls;
|
||||||
QueryInfo info;
|
QueryInfo info;
|
||||||
PlanInfo plan_info;
|
|
||||||
CallTime time;
|
CallTime time;
|
||||||
|
|
||||||
|
Calls plancalls;
|
||||||
|
CallTime plantime;
|
||||||
|
PlanInfo planinfo;
|
||||||
|
|
||||||
Blocks blocks;
|
Blocks blocks;
|
||||||
SysInfo sysinfo;
|
SysInfo sysinfo;
|
||||||
ErrorInfo error;
|
ErrorInfo error;
|
||||||
Wal_Usage walusage;
|
Wal_Usage walusage;
|
||||||
int plans;
|
|
||||||
int resp_calls[MAX_RESPONSE_BUCKET]; /* execution time's in msec */
|
int resp_calls[MAX_RESPONSE_BUCKET]; /* execution time's in msec */
|
||||||
|
uint64 state; /* query state */
|
||||||
} Counters;
|
} Counters;
|
||||||
|
|
||||||
/* Some global structure to get the cpu usage, really don't like the idea of global variable */
|
/* Some global structure to get the cpu usage, really don't like the idea of global variable */
|
||||||
|
@ -362,18 +359,18 @@ void pgss_shmem_shutdown(int code, Datum arg);
|
||||||
int pgsm_get_bucket_size(void);
|
int pgsm_get_bucket_size(void);
|
||||||
pgssSharedState* pgsm_get_ss(void);
|
pgssSharedState* pgsm_get_ss(void);
|
||||||
HTAB *pgsm_get_plan_hash(void);
|
HTAB *pgsm_get_plan_hash(void);
|
||||||
|
HTAB *pgsm_get_query_hash(void);
|
||||||
HTAB *pgsm_get_hash(void);
|
HTAB *pgsm_get_hash(void);
|
||||||
HTAB *pgsm_get_plan_hash(void);
|
HTAB *pgsm_get_plan_hash(void);
|
||||||
HTAB* pgsm_get_query_hash(void);
|
HTAB* pgsm_get_query_hash(void);
|
||||||
void hash_entry_reset(void);
|
void hash_entry_reset(void);
|
||||||
void hash_query_entry_dealloc(int bucket);
|
void hash_query_entry_dealloc(int bucket);
|
||||||
void hash_entry_dealloc(int bucket);
|
void hash_entry_dealloc(int bucket);
|
||||||
pgssPlanEntry *hash_plan_entry_alloc(pgssSharedState *pgss, pgssPlanHashKey *key);
|
|
||||||
pgssEntry* hash_entry_alloc(pgssSharedState *pgss, pgssHashKey *key, int encoding);
|
pgssEntry* hash_entry_alloc(pgssSharedState *pgss, pgssHashKey *key, int encoding);
|
||||||
Size hash_memsize(void);
|
Size hash_memsize(void);
|
||||||
|
|
||||||
bool hash_find_query_entry(uint64 bucket_id, uint64 queryid);
|
pgssQueryEntry* hash_find_query_entry(uint64 bucket_id, uint64 queryid, uint64 dbid, uint64 userid, uint64 ip);
|
||||||
bool hash_create_query_entry(uint64 bucket_id, uint64 queryid);
|
pgssQueryEntry* hash_create_query_entry(uint64 bucket_id, uint64 queryid, uint64 dbid, uint64 userid, uint64 ip);
|
||||||
void pgss_startup(void);
|
void pgss_startup(void);
|
||||||
void set_qbuf(int i, unsigned char *);
|
void set_qbuf(int i, unsigned char *);
|
||||||
|
|
||||||
|
|
|
@ -12,12 +12,11 @@ SELECT 1 AS num;
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT query,application_name FROM pg_stat_monitor ORDER BY query COLLATE "C";
|
SELECT query,application_name FROM pg_stat_monitor ORDER BY query COLLATE "C";
|
||||||
query | application_name
|
query | application_name
|
||||||
--------------------------------------------------------------------------------+-----------------------------
|
---------------------------------+-----------------------------
|
||||||
SELECT $1 AS num | pg_regress/application_name
|
SELECT $1 AS num | pg_regress/application_name
|
||||||
SELECT pg_stat_monitor_reset(); | pg_regress/application_name
|
SELECT pg_stat_monitor_reset(); | pg_regress/application_name
|
||||||
SELECT query,application_name FROM pg_stat_monitor ORDER BY query COLLATE "C"; |
|
(2 rows)
|
||||||
(3 rows)
|
|
||||||
|
|
||||||
SELECT pg_stat_monitor_reset();
|
SELECT pg_stat_monitor_reset();
|
||||||
pg_stat_monitor_reset
|
pg_stat_monitor_reset
|
||||||
|
|
|
@ -5,12 +5,6 @@ SELECT pg_stat_monitor_reset();
|
||||||
|
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
select pg_sleep(.5);
|
|
||||||
pg_sleep
|
|
||||||
----------
|
|
||||||
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
SELECT 1 AS num;
|
SELECT 1 AS num;
|
||||||
num
|
num
|
||||||
-----
|
-----
|
||||||
|
@ -18,13 +12,11 @@ SELECT 1 AS num;
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT query FROM pg_stat_monitor ORDER BY query COLLATE "C";
|
SELECT query FROM pg_stat_monitor ORDER BY query COLLATE "C";
|
||||||
query
|
query
|
||||||
---------------------------------------------------------------
|
---------------------------------
|
||||||
SELECT $1 AS num
|
SELECT $1 AS num
|
||||||
SELECT pg_stat_monitor_reset();
|
SELECT pg_stat_monitor_reset();
|
||||||
SELECT query FROM pg_stat_monitor ORDER BY query COLLATE "C";
|
(2 rows)
|
||||||
select pg_sleep($1)
|
|
||||||
(4 rows)
|
|
||||||
|
|
||||||
SELECT pg_stat_monitor_reset();
|
SELECT pg_stat_monitor_reset();
|
||||||
pg_stat_monitor_reset
|
pg_stat_monitor_reset
|
||||||
|
|
|
@ -6,6 +6,7 @@ SELECT pg_stat_monitor_reset();
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
CREATE TABLE t1 (a INTEGER);
|
CREATE TABLE t1 (a INTEGER);
|
||||||
|
CREATE TABLE t2 (b INTEGER);
|
||||||
INSERT INTO t1 VALUES(1);
|
INSERT INTO t1 VALUES(1);
|
||||||
SELECT a FROM t1;
|
SELECT a FROM t1;
|
||||||
a
|
a
|
||||||
|
@ -15,26 +16,27 @@ SELECT a FROM t1;
|
||||||
|
|
||||||
UPDATE t1 SET a = 2;
|
UPDATE t1 SET a = 2;
|
||||||
DELETE FROM t1;
|
DELETE FROM t1;
|
||||||
SELECT a FROM t1 FOR UPDATE;
|
SELECT b FROM t2 FOR UPDATE;
|
||||||
a
|
b
|
||||||
---
|
---
|
||||||
(0 rows)
|
(0 rows)
|
||||||
|
|
||||||
TRUNCATE t1;
|
TRUNCATE t1;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
SELECT query, cmd_type, cmd_type_text FROM pg_stat_monitor ORDER BY query COLLATE "C";
|
SELECT query, cmd_type, cmd_type_text FROM pg_stat_monitor ORDER BY query COLLATE "C";
|
||||||
query | cmd_type | cmd_type_text
|
query | cmd_type | cmd_type_text
|
||||||
-----------------------------------------------------------------------------------------+----------+---------------
|
---------------------------------+----------+---------------
|
||||||
CREATE TABLE t1 (a INTEGER); | 0 |
|
CREATE TABLE t1 (a INTEGER); | 0 |
|
||||||
DELETE FROM t1; | 4 | DELETE
|
CREATE TABLE t2 (b INTEGER); | 0 |
|
||||||
DROP TABLE t1; | 0 |
|
DELETE FROM t1; | 4 | DELETE
|
||||||
INSERT INTO t1 VALUES($1) | 3 | INSERT
|
DROP TABLE t1; | 0 |
|
||||||
SELECT a FROM t1; | 1 | SELECT
|
INSERT INTO t1 VALUES($1) | 3 | INSERT
|
||||||
SELECT pg_stat_monitor_reset(); | 1 | SELECT
|
SELECT a FROM t1; | 1 | SELECT
|
||||||
SELECT query, cmd_type, cmd_type_text FROM pg_stat_monitor ORDER BY query COLLATE "C"; | 0 |
|
SELECT b FROM t2 FOR UPDATE; | 1 | SELECT
|
||||||
TRUNCATE t1; | 0 |
|
SELECT pg_stat_monitor_reset(); | 1 | SELECT
|
||||||
UPDATE t1 SET a = $1 | 2 | UPDATE
|
TRUNCATE t1; | 0 |
|
||||||
(9 rows)
|
UPDATE t1 SET a = $1 | 2 | UPDATE
|
||||||
|
(10 rows)
|
||||||
|
|
||||||
SELECT pg_stat_monitor_reset();
|
SELECT pg_stat_monitor_reset();
|
||||||
pg_stat_monitor_reset
|
pg_stat_monitor_reset
|
||||||
|
|
|
@ -1,4 +1,10 @@
|
||||||
CREATE EXTENSION pg_stat_monitor;
|
CREATE EXTENSION pg_stat_monitor;
|
||||||
|
SELECT pg_stat_monitor_reset();
|
||||||
|
pg_stat_monitor_reset
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
CREATE TABLE t1 (a INTEGER);
|
CREATE TABLE t1 (a INTEGER);
|
||||||
CREATE TABLE t2 (b INTEGER);
|
CREATE TABLE t2 (b INTEGER);
|
||||||
CREATE TABLE t3 (c INTEGER);
|
CREATE TABLE t3 (c INTEGER);
|
||||||
|
@ -34,8 +40,7 @@ SELECT query,calls FROM pg_stat_monitor ORDER BY query COLLATE "C";
|
||||||
----------------------------------------------------------------------------------+-------
|
----------------------------------------------------------------------------------+-------
|
||||||
SELECT a,b,c,d FROM t1, t2, t3, t4 WHERE t1.a = t2.b AND t3.c = t4.d ORDER BY a; | 4
|
SELECT a,b,c,d FROM t1, t2, t3, t4 WHERE t1.a = t2.b AND t3.c = t4.d ORDER BY a; | 4
|
||||||
SELECT pg_stat_monitor_reset(); | 1
|
SELECT pg_stat_monitor_reset(); | 1
|
||||||
SELECT query,calls FROM pg_stat_monitor ORDER BY query COLLATE "C"; | 1
|
(2 rows)
|
||||||
(3 rows)
|
|
||||||
|
|
||||||
SELECT pg_stat_monitor_reset();
|
SELECT pg_stat_monitor_reset();
|
||||||
pg_stat_monitor_reset
|
pg_stat_monitor_reset
|
||||||
|
@ -62,12 +67,8 @@ end $$;
|
||||||
SELECT query,calls FROM pg_stat_monitor ORDER BY query COLLATE "C";
|
SELECT query,calls FROM pg_stat_monitor ORDER BY query COLLATE "C";
|
||||||
query | calls
|
query | calls
|
||||||
---------------------------------------------------------------------------------------------------+-------
|
---------------------------------------------------------------------------------------------------+-------
|
||||||
SELECT $1 AS num | 1
|
|
||||||
SELECT a,b,c,d FROM t1, t2, t3, t4 WHERE t1.a = t2.b AND t3.c = t4.d ORDER BY a; | 1000
|
SELECT a,b,c,d FROM t1, t2, t3, t4 WHERE t1.a = t2.b AND t3.c = t4.d ORDER BY a; | 1000
|
||||||
SELECT n + $3 | 1
|
|
||||||
SELECT n = $3 | 1
|
|
||||||
SELECT pg_stat_monitor_reset(); | 1
|
SELECT pg_stat_monitor_reset(); | 1
|
||||||
SELECT query,calls FROM pg_stat_monitor ORDER BY query COLLATE "C"; | 1
|
|
||||||
do $$ +| 1
|
do $$ +| 1
|
||||||
declare +|
|
declare +|
|
||||||
n integer:= 1; +|
|
n integer:= 1; +|
|
||||||
|
@ -78,7 +79,7 @@ SELECT query,calls FROM pg_stat_monitor ORDER BY query COLLATE "C";
|
||||||
n := n + 1; +|
|
n := n + 1; +|
|
||||||
end loop; +|
|
end loop; +|
|
||||||
end $$; |
|
end $$; |
|
||||||
(7 rows)
|
(3 rows)
|
||||||
|
|
||||||
SELECT pg_stat_monitor_reset();
|
SELECT pg_stat_monitor_reset();
|
||||||
pg_stat_monitor_reset
|
pg_stat_monitor_reset
|
||||||
|
|
|
@ -28,13 +28,12 @@ SELECT * FROM t3,t4 WHERE t3.c = t4.d;
|
||||||
|
|
||||||
\c contrib_regression
|
\c contrib_regression
|
||||||
SELECT datname, query FROM pg_stat_monitor ORDER BY query COLLATE "C";
|
SELECT datname, query FROM pg_stat_monitor ORDER BY query COLLATE "C";
|
||||||
datname | query
|
datname | query
|
||||||
--------------------+------------------------------------------------------------------------
|
--------------------+----------------------------------------
|
||||||
db1 | SELECT * FROM t1,t2 WHERE t1.a = t2.b;
|
db1 | SELECT * FROM t1,t2 WHERE t1.a = t2.b;
|
||||||
db2 | SELECT * FROM t3,t4 WHERE t3.c = t4.d;
|
db2 | SELECT * FROM t3,t4 WHERE t3.c = t4.d;
|
||||||
contrib_regression | SELECT datname, query FROM pg_stat_monitor ORDER BY query COLLATE "C";
|
|
||||||
contrib_regression | SELECT pg_stat_monitor_reset();
|
contrib_regression | SELECT pg_stat_monitor_reset();
|
||||||
(4 rows)
|
(3 rows)
|
||||||
|
|
||||||
SELECT pg_stat_monitor_reset();
|
SELECT pg_stat_monitor_reset();
|
||||||
pg_stat_monitor_reset
|
pg_stat_monitor_reset
|
||||||
|
|
|
@ -21,19 +21,17 @@ RAISE WARNING 'warning message';
|
||||||
END $$;
|
END $$;
|
||||||
WARNING: warning message
|
WARNING: warning message
|
||||||
SELECT query, elevel,sqlcode, message FROM pg_stat_monitor ORDER BY query COLLATE "C";
|
SELECT query, elevel,sqlcode, message FROM pg_stat_monitor ORDER BY query COLLATE "C";
|
||||||
query | elevel | sqlcode | message
|
query | elevel | sqlcode | message
|
||||||
----------------------------------------------------------------------------------------+--------+---------+-----------------------------------
|
----------------------------------+--------+---------+-----------------------------------
|
||||||
ELECET * FROM unknown; | 20 | 42601 | syntax error at or near "ELECET"
|
ELECET * FROM unknown; | 20 | 42601 | syntax error at or near "ELECET"
|
||||||
SELECT $1/$2 | 0 | |
|
SELECT * FROM unknown; | 20 | 42P01 | relation "unknown" does not exist
|
||||||
SELECT * FROM unknown; | 20 | 42P01 | relation "unknown" does not exist
|
SELECT 1/0; | 20 | 22012 | division by zero
|
||||||
SELECT 1/0; | 20 | 22012 | division by zero
|
SELECT pg_stat_monitor_reset(); | 0 | |
|
||||||
SELECT pg_stat_monitor_reset(); | 0 | |
|
do $$ +| 19 | 01000 | warning message
|
||||||
SELECT query, elevel,sqlcode, message FROM pg_stat_monitor ORDER BY query COLLATE "C"; | 0 | |
|
BEGIN +| | |
|
||||||
do $$ +| 19 | 01000 | warning message
|
RAISE WARNING 'warning message';+| | |
|
||||||
BEGIN +| | |
|
END $$; | | |
|
||||||
RAISE WARNING 'warning message'; +| | |
|
(5 rows)
|
||||||
END $$; | | |
|
|
||||||
(7 rows)
|
|
||||||
|
|
||||||
SELECT pg_stat_monitor_reset();
|
SELECT pg_stat_monitor_reset();
|
||||||
pg_stat_monitor_reset
|
pg_stat_monitor_reset
|
||||||
|
|
|
@ -37,15 +37,14 @@ SELECT * FROM foo1, foo2, foo3, foo4;
|
||||||
(0 rows)
|
(0 rows)
|
||||||
|
|
||||||
SELECT query, relations from pg_stat_monitor ORDER BY query;
|
SELECT query, relations from pg_stat_monitor ORDER BY query;
|
||||||
query | relations
|
query | relations
|
||||||
--------------------------------------------------------------+---------------------------------------------------
|
---------------------------------------+---------------------------------------------------
|
||||||
SELECT * FROM foo1, foo2, foo3, foo4; | {public.foo1,public.foo2,public.foo3,public.foo4}
|
SELECT * FROM foo1, foo2, foo3, foo4; | {public.foo1,public.foo2,public.foo3,public.foo4}
|
||||||
SELECT * FROM foo1, foo2, foo3; | {public.foo1,public.foo2,public.foo3}
|
SELECT * FROM foo1, foo2, foo3; | {public.foo1,public.foo2,public.foo3}
|
||||||
SELECT * FROM foo1, foo2; | {public.foo1,public.foo2}
|
SELECT * FROM foo1, foo2; | {public.foo1,public.foo2}
|
||||||
SELECT * FROM foo1; | {public.foo1}
|
SELECT * FROM foo1; | {public.foo1}
|
||||||
SELECT pg_stat_monitor_reset(); |
|
SELECT pg_stat_monitor_reset(); |
|
||||||
SELECT query, relations from pg_stat_monitor ORDER BY query; |
|
(5 rows)
|
||||||
(6 rows)
|
|
||||||
|
|
||||||
SELECT pg_stat_monitor_reset();
|
SELECT pg_stat_monitor_reset();
|
||||||
pg_stat_monitor_reset
|
pg_stat_monitor_reset
|
||||||
|
@ -89,15 +88,14 @@ SELECT * FROM sch1.foo1, sch2.foo2, sch3.foo3, sch4.foo4;
|
||||||
(0 rows)
|
(0 rows)
|
||||||
|
|
||||||
SELECT query, relations from pg_stat_monitor ORDER BY query;
|
SELECT query, relations from pg_stat_monitor ORDER BY query;
|
||||||
query | relations
|
query | relations
|
||||||
--------------------------------------------------------------+-------------------------------------------
|
-----------------------------------------------------------+-------------------------------------------
|
||||||
SELECT * FROM sch1.foo1, sch2.foo2, sch3.foo3, sch4.foo4; | {sch1.foo1,sch2.foo2,sch3.foo3,sch4.foo4}
|
SELECT * FROM sch1.foo1, sch2.foo2, sch3.foo3, sch4.foo4; | {sch1.foo1,sch2.foo2,sch3.foo3,sch4.foo4}
|
||||||
SELECT * FROM sch1.foo1, sch2.foo2, sch3.foo3; | {sch1.foo1,sch2.foo2,sch3.foo3}
|
SELECT * FROM sch1.foo1, sch2.foo2, sch3.foo3; | {sch1.foo1,sch2.foo2,sch3.foo3}
|
||||||
SELECT * FROM sch1.foo1, sch2.foo2; | {sch1.foo1,sch2.foo2}
|
SELECT * FROM sch1.foo1, sch2.foo2; | {sch1.foo1,sch2.foo2}
|
||||||
SELECT * FROM sch1.foo1; | {sch1.foo1}
|
SELECT * FROM sch1.foo1; | {sch1.foo1}
|
||||||
SELECT pg_stat_monitor_reset(); |
|
SELECT pg_stat_monitor_reset(); |
|
||||||
SELECT query, relations from pg_stat_monitor ORDER BY query; |
|
(5 rows)
|
||||||
(6 rows)
|
|
||||||
|
|
||||||
SELECT pg_stat_monitor_reset();
|
SELECT pg_stat_monitor_reset();
|
||||||
pg_stat_monitor_reset
|
pg_stat_monitor_reset
|
||||||
|
@ -122,13 +120,12 @@ SELECT * FROM sch1.foo1, sch2.foo2, foo1, foo2;
|
||||||
(0 rows)
|
(0 rows)
|
||||||
|
|
||||||
SELECT query, relations from pg_stat_monitor ORDER BY query;
|
SELECT query, relations from pg_stat_monitor ORDER BY query;
|
||||||
query | relations
|
query | relations
|
||||||
--------------------------------------------------------------+-----------------------------------------------
|
-------------------------------------------------+-----------------------------------------------
|
||||||
SELECT * FROM sch1.foo1, foo1; | {sch1.foo1,public.foo1}
|
SELECT * FROM sch1.foo1, foo1; | {sch1.foo1,public.foo1}
|
||||||
SELECT * FROM sch1.foo1, sch2.foo2, foo1, foo2; | {sch1.foo1,sch2.foo2,public.foo1,public.foo2}
|
SELECT * FROM sch1.foo1, sch2.foo2, foo1, foo2; | {sch1.foo1,sch2.foo2,public.foo1,public.foo2}
|
||||||
SELECT pg_stat_monitor_reset(); |
|
SELECT pg_stat_monitor_reset(); |
|
||||||
SELECT query, relations from pg_stat_monitor ORDER BY query; |
|
(3 rows)
|
||||||
(4 rows)
|
|
||||||
|
|
||||||
SELECT pg_stat_monitor_reset();
|
SELECT pg_stat_monitor_reset();
|
||||||
pg_stat_monitor_reset
|
pg_stat_monitor_reset
|
||||||
|
@ -168,15 +165,14 @@ SELECT * FROM v1,v2,v3,v4;
|
||||||
(0 rows)
|
(0 rows)
|
||||||
|
|
||||||
SELECT query, relations from pg_stat_monitor ORDER BY query;
|
SELECT query, relations from pg_stat_monitor ORDER BY query;
|
||||||
query | relations
|
query | relations
|
||||||
--------------------------------------------------------------+-----------------------------------------------------------------------------------------------
|
---------------------------------+-----------------------------------------------------------------------------------------------
|
||||||
SELECT * FROM v1,v2,v3,v4; | {public.v1*,public.foo1,public.v2*,public.foo2,public.v3*,public.foo3,public.v4*,public.foo4}
|
SELECT * FROM v1,v2,v3,v4; | {public.v1*,public.foo1,public.v2*,public.foo2,public.v3*,public.foo3,public.v4*,public.foo4}
|
||||||
SELECT * FROM v1,v2,v3; | {public.v1*,public.foo1,public.v2*,public.foo2,public.v3*,public.foo3}
|
SELECT * FROM v1,v2,v3; | {public.v1*,public.foo1,public.v2*,public.foo2,public.v3*,public.foo3}
|
||||||
SELECT * FROM v1,v2; | {public.v1*,public.foo1,public.v2*,public.foo2}
|
SELECT * FROM v1,v2; | {public.v1*,public.foo1,public.v2*,public.foo2}
|
||||||
SELECT * FROM v1; | {public.v1*,public.foo1}
|
SELECT * FROM v1; | {public.v1*,public.foo1}
|
||||||
SELECT pg_stat_monitor_reset(); |
|
SELECT pg_stat_monitor_reset(); |
|
||||||
SELECT query, relations from pg_stat_monitor ORDER BY query; |
|
(5 rows)
|
||||||
(6 rows)
|
|
||||||
|
|
||||||
SELECT pg_stat_monitor_reset();
|
SELECT pg_stat_monitor_reset();
|
||||||
pg_stat_monitor_reset
|
pg_stat_monitor_reset
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
CREATE EXTENSION pg_stat_monitor;
|
CREATE EXTENSION pg_stat_monitor;
|
||||||
CREATE TABLE t1(a int);
|
CREATE TABLE t1(a int);
|
||||||
CREATE TABLE t2(b int);
|
CREATE TABLE t2(b int);
|
||||||
|
ERROR: relation "t2" already exists
|
||||||
INSERT INTO t1 VALUES(generate_series(1,1000));
|
INSERT INTO t1 VALUES(generate_series(1,1000));
|
||||||
INSERT INTO t2 VALUES(generate_series(1,5000));
|
INSERT INTO t2 VALUES(generate_series(1,5000));
|
||||||
SELECT pg_stat_monitor_reset();
|
SELECT pg_stat_monitor_reset();
|
||||||
|
@ -8540,15 +8541,14 @@ SELECt * FROM t2 WHERE b % 2 = 0;
|
||||||
(2500 rows)
|
(2500 rows)
|
||||||
|
|
||||||
SELECT query, rows FROM pg_stat_monitor ORDER BY query COLLATE "C";
|
SELECT query, rows FROM pg_stat_monitor ORDER BY query COLLATE "C";
|
||||||
query | rows
|
query | rows
|
||||||
---------------------------------------------------------------------+------
|
-------------------------------------+------
|
||||||
SELECT * FROM t1 LIMIT $1 | 10
|
SELECT * FROM t1 LIMIT $1 | 10
|
||||||
SELECT * FROM t1; | 1000
|
SELECT * FROM t1; | 1000
|
||||||
SELECT * FROM t2; | 5000
|
SELECT b FROM t2 FOR UPDATE; | 5000
|
||||||
SELECT pg_stat_monitor_reset(); | 1
|
SELECT pg_stat_monitor_reset(); | 1
|
||||||
SELECT query, rows FROM pg_stat_monitor ORDER BY query COLLATE "C"; | 0
|
SELECt * FROM t2 WHERE b % $1 = $2 | 2500
|
||||||
SELECt * FROM t2 WHERE b % $1 = $2 | 2500
|
(5 rows)
|
||||||
(6 rows)
|
|
||||||
|
|
||||||
SELECT pg_stat_monitor_reset();
|
SELECT pg_stat_monitor_reset();
|
||||||
pg_stat_monitor_reset
|
pg_stat_monitor_reset
|
||||||
|
|
|
@ -23,25 +23,23 @@ SELECT add2(1,2);
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT query, top_query FROM pg_stat_monitor ORDER BY query COLLATE "C";
|
SELECT query, top_query FROM pg_stat_monitor ORDER BY query COLLATE "C";
|
||||||
query | top_query
|
query | top_query
|
||||||
--------------------------------------------------------------------------+--------------------
|
-------------------------------------------------------------+--------------------
|
||||||
CREATE OR REPLACE FUNCTION add(int, int) RETURNS INTEGER AS +|
|
CREATE OR REPLACE FUNCTION add(int, int) RETURNS INTEGER AS+|
|
||||||
$$ +|
|
$$ +|
|
||||||
BEGIN +|
|
BEGIN +|
|
||||||
return (select $1 + $2); +|
|
return (select $1 + $2); +|
|
||||||
END; $$ language plpgsql; |
|
END; $$ language plpgsql; |
|
||||||
CREATE OR REPLACE function add2(int, int) RETURNS int as +|
|
CREATE OR REPLACE function add2(int, int) RETURNS int as +|
|
||||||
$$ +|
|
$$ +|
|
||||||
BEGIN +|
|
BEGIN +|
|
||||||
return add($1,$2); +|
|
return add($1,$2); +|
|
||||||
END; +|
|
END; +|
|
||||||
$$ language plpgsql; |
|
$$ language plpgsql; |
|
||||||
SELECT (select $1 + $2) | SELECT add2($1,$2)
|
SELECT (select $1 + $2) | SELECT add2($1,$2)
|
||||||
SELECT add($1,$2) |
|
SELECT add2($1,$2) |
|
||||||
SELECT add2($1,$2) |
|
SELECT pg_stat_monitor_reset(); |
|
||||||
SELECT pg_stat_monitor_reset(); |
|
(5 rows)
|
||||||
SELECT query, top_query FROM pg_stat_monitor ORDER BY query COLLATE "C"; |
|
|
||||||
(7 rows)
|
|
||||||
|
|
||||||
SELECT pg_stat_monitor_reset();
|
SELECT pg_stat_monitor_reset();
|
||||||
pg_stat_monitor_reset
|
pg_stat_monitor_reset
|
||||||
|
|
|
@ -27,18 +27,17 @@ SELECT * FROM t2;
|
||||||
|
|
||||||
SET ROLE su;
|
SET ROLE su;
|
||||||
SELECT userid, query FROM pg_stat_monitor ORDER BY query COLLATE "C";
|
SELECT userid, query FROM pg_stat_monitor ORDER BY query COLLATE "C";
|
||||||
userid | query
|
userid | query
|
||||||
--------+-----------------------------------------------------------------------
|
--------+---------------------------------
|
||||||
u1 | CREATE TABLE t1 (a int);
|
u1 | CREATE TABLE t1 (a int);
|
||||||
u2 | CREATE TABLE t2 (a int);
|
u2 | CREATE TABLE t2 (a int);
|
||||||
u1 | SELECT * FROM t1;
|
u1 | SELECT * FROM t1;
|
||||||
u2 | SELECT * FROM t2;
|
u2 | SELECT * FROM t2;
|
||||||
su | SELECT pg_stat_monitor_reset();
|
su | SELECT pg_stat_monitor_reset();
|
||||||
su | SELECT userid, query FROM pg_stat_monitor ORDER BY query COLLATE "C";
|
|
||||||
su | SET ROLE su;
|
su | SET ROLE su;
|
||||||
u1 | SET ROLE u1;
|
u1 | SET ROLE u1;
|
||||||
u2 | SET ROLE u2;
|
u2 | SET ROLE u2;
|
||||||
(9 rows)
|
(8 rows)
|
||||||
|
|
||||||
SELECT pg_stat_monitor_reset();
|
SELECT pg_stat_monitor_reset();
|
||||||
pg_stat_monitor_reset
|
pg_stat_monitor_reset
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
CREATE EXTENSION pg_stat_monitor;
|
CREATE EXTENSION pg_stat_monitor;
|
||||||
SELECT pg_stat_monitor_reset();
|
SELECT pg_stat_monitor_reset();
|
||||||
select pg_sleep(.5);
|
|
||||||
SELECT 1 AS num;
|
SELECT 1 AS num;
|
||||||
SELECT query FROM pg_stat_monitor ORDER BY query COLLATE "C";
|
SELECT query FROM pg_stat_monitor ORDER BY query COLLATE "C";
|
||||||
SELECT pg_stat_monitor_reset();
|
SELECT pg_stat_monitor_reset();
|
||||||
|
|
|
@ -2,11 +2,12 @@ CREATE EXTENSION pg_stat_monitor;
|
||||||
|
|
||||||
SELECT pg_stat_monitor_reset();
|
SELECT pg_stat_monitor_reset();
|
||||||
CREATE TABLE t1 (a INTEGER);
|
CREATE TABLE t1 (a INTEGER);
|
||||||
|
CREATE TABLE t2 (b INTEGER);
|
||||||
INSERT INTO t1 VALUES(1);
|
INSERT INTO t1 VALUES(1);
|
||||||
SELECT a FROM t1;
|
SELECT a FROM t1;
|
||||||
UPDATE t1 SET a = 2;
|
UPDATE t1 SET a = 2;
|
||||||
DELETE FROM t1;
|
DELETE FROM t1;
|
||||||
SELECT a FROM t1 FOR UPDATE;
|
SELECT b FROM t2 FOR UPDATE;
|
||||||
TRUNCATE t1;
|
TRUNCATE t1;
|
||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
SELECT query, cmd_type, cmd_type_text FROM pg_stat_monitor ORDER BY query COLLATE "C";
|
SELECT query, cmd_type, cmd_type_text FROM pg_stat_monitor ORDER BY query COLLATE "C";
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
CREATE EXTENSION pg_stat_monitor;
|
CREATE EXTENSION pg_stat_monitor;
|
||||||
|
SELECT pg_stat_monitor_reset();
|
||||||
|
|
||||||
CREATE TABLE t1 (a INTEGER);
|
CREATE TABLE t1 (a INTEGER);
|
||||||
CREATE TABLE t2 (b INTEGER);
|
CREATE TABLE t2 (b INTEGER);
|
||||||
|
|
Loading…
Reference in New Issue