PG-147 Stored Procedure Support add parentid to track caller.

Patch By: Martin Sun
Reviewed By: Hamid Akhtar
pull/73/head
Ibrar Ahmed 2021-02-12 11:42:36 +00:00
parent cba6bbfbd4
commit ed6fe2d8dc
8 changed files with 95 additions and 8 deletions

View File

@ -376,3 +376,44 @@ postgres=# SELECT bucket, substr(query,0, 50) AS query, cmd_type FROM pg_stat_mo
4 | UPDATE pgbench_branches SET bbalance = bbalance + | UPDATE 4 | UPDATE pgbench_branches SET bbalance = bbalance + | UPDATE
(14 rows) (14 rows)
``` ```
#### Function Execution Tracking
**`parentid`**: Outer layer caller's query id.
```sql
postgres=# select prosrc from pg_proc where proname = 'getnum';
prosrc
--------------------------------
select * from t1 where a >= $1
(1 row)
postgresr=# select pg_stat_monitor_reset();
pg_stat_monitor_reset
-----------------------
(1 row)
postgres=# select prosrc from pg_proc where proname = 'getnum';
prosrc
--------------------------------
select * from t1 where a >= $1
(1 row)
postgres=# select * from getnum(2);
a
---
2
3
4
(3 rows)
postgres=# select queryid,parentid,query,calls from pg_stat_monitor;
queryid | parentid | query | calls
------------------+------------------+-----------------------------------------------+-------
3FEC80684AFE7FC7 | DD2A4843140299C2 | select * from t1 where a >= $1 | 1
6ED05FFB78DD52FA | | select pg_stat_monitor_reset() | 1
DD2A4843140299C2 | | select * from getnum($1) | 1
42517D48FB98ACF7 | | select prosrc from pg_proc where proname = $1 | 1
(4 rows)
```

View File

@ -17,7 +17,7 @@ SELECT 1;
1 1
(1 row) (1 row)
SELECT query FROM pg_stat_monitor ORDER BY query; SELECT query FROM pg_stat_monitor ORDER BY query COLLATE "C";
query query
-------------------------------- --------------------------------
SELECT $1 SELECT $1

View File

@ -20,9 +20,9 @@ SELECT * FROM pg_stat_monitor_settings;
pg_stat_monitor.pgsm_track_utility | 0 | 0 | Selects whether utility commands are tracked. | 0 | 0 | 0 pg_stat_monitor.pgsm_track_utility | 0 | 0 | Selects whether utility commands are tracked. | 0 | 0 | 0
pg_stat_monitor.pgsm_normalized_query | 1 | 1 | Selects whether save query in normalized format. | 0 | 0 | 0 pg_stat_monitor.pgsm_normalized_query | 1 | 1 | Selects whether save query in normalized format. | 0 | 0 | 0
pg_stat_monitor.pgsm_max_buckets | 10 | 10 | Sets the maximum number of buckets. | 1 | 10 | 1 pg_stat_monitor.pgsm_max_buckets | 10 | 10 | Sets the maximum number of buckets. | 1 | 10 | 1
pg_stat_monitor.pgsm_bucket_time | 300 | 60 | Sets the time in seconds per bucket. | 1 | 2147483647 | 1 pg_stat_monitor.pgsm_bucket_time | 300 | 300 | Sets the time in seconds per bucket. | 1 | 2147483647 | 1
pg_stat_monitor.pgsm_histogram_min | 0 | 0 | Sets the time in millisecond. | 0 | 2147483647 | 1 pg_stat_monitor.pgsm_histogram_min | 0 | 0 | Sets the time in millisecond. | 0 | 2147483647 | 1
pg_stat_monitor.pgsm_histogram_max | 100000 | 10 | Sets the time in millisecond. | 10 | 2147483647 | 1 pg_stat_monitor.pgsm_histogram_max | 100000 | 100000 | Sets the time in millisecond. | 10 | 2147483647 | 1
pg_stat_monitor.pgsm_histogram_buckets | 10 | 10 | Sets the maximum number of histogram buckets | 2 | 2147483647 | 1 pg_stat_monitor.pgsm_histogram_buckets | 10 | 10 | Sets the maximum number of histogram buckets | 2 | 2147483647 | 1
(10 rows) (10 rows)

4
guc.c
View File

@ -104,7 +104,7 @@ init_guc(void)
conf[i] = (GucVariable) { conf[i] = (GucVariable) {
.guc_name = "pg_stat_monitor.pgsm_bucket_time", .guc_name = "pg_stat_monitor.pgsm_bucket_time",
.guc_desc = "Sets the time in seconds per bucket.", .guc_desc = "Sets the time in seconds per bucket.",
.guc_default = 60, .guc_default = 300,
.guc_min = 1, .guc_min = 1,
.guc_max = INT_MAX, .guc_max = INT_MAX,
.guc_restart = true, .guc_restart = true,
@ -128,7 +128,7 @@ init_guc(void)
conf[i] = (GucVariable) { conf[i] = (GucVariable) {
.guc_name = "pg_stat_monitor.pgsm_histogram_max", .guc_name = "pg_stat_monitor.pgsm_histogram_max",
.guc_desc = "Sets the time in millisecond.", .guc_desc = "Sets the time in millisecond.",
.guc_default = 10, .guc_default = 100000,
.guc_min = 10, .guc_min = 10,
.guc_max = INT_MAX, .guc_max = INT_MAX,
.guc_restart = true, .guc_restart = true,

View File

@ -31,6 +31,7 @@ CREATE FUNCTION pg_stat_monitor(IN showtext boolean,
OUT client_ip int8, OUT client_ip int8,
OUT queryid text, OUT queryid text,
OUT parentid text,
OUT query text, OUT query text,
OUT application_name text, OUT application_name text,
OUT relations text, OUT relations text,
@ -125,10 +126,12 @@ CREATE VIEW pg_stat_monitor AS SELECT
datname, datname,
'0.0.0.0'::inet + client_ip AS client_ip, '0.0.0.0'::inet + client_ip AS client_ip,
queryid, queryid,
parentid,
query, query,
(SELECT query from pg_stat_monitor(true) s where s.queryid = p.parentid) AS parent_query,
application_name, application_name,
string_to_array(relations, ',') AS relations, string_to_array(relations, ',') AS relations,
cmd_type, cmd_type,
get_cmd_type(cmd_type) AS cmd_type_text, get_cmd_type(cmd_type) AS cmd_type_text,
elevel, elevel,
sqlcode, sqlcode,

View File

@ -22,7 +22,7 @@
PG_MODULE_MAGIC; PG_MODULE_MAGIC;
#define BUILD_VERSION "0.7.0" #define BUILD_VERSION "0.7.0"
#define PG_STAT_STATEMENTS_COLS 46 /* maximum of above */ #define PG_STAT_STATEMENTS_COLS 47 /* 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')
@ -63,6 +63,11 @@ void _PG_fini(void);
/* Current nesting depth of ExecutorRun+ProcessUtility calls */ /* Current nesting depth of ExecutorRun+ProcessUtility calls */
static int nested_level = 0; static int nested_level = 0;
/* the current max level a query can nested */
int cur_max_nested_level;
/* The array to store outer layer query id*/
uint64 *nested_queryids;
#if PG_VERSION_NUM >= 130000 #if PG_VERSION_NUM >= 130000
static int plan_nested_level = 0; static int plan_nested_level = 0;
static int exec_nested_level = 0; static int exec_nested_level = 0;
@ -240,6 +245,9 @@ _PG_init(void)
prev_ExecutorCheckPerms_hook = ExecutorCheckPerms_hook; prev_ExecutorCheckPerms_hook = ExecutorCheckPerms_hook;
ExecutorCheckPerms_hook = pgss_ExecutorCheckPerms; ExecutorCheckPerms_hook = pgss_ExecutorCheckPerms;
cur_max_nested_level = max_stack_depth;
nested_queryids = (uint64*)malloc(sizeof(uint64)*cur_max_nested_level);
system_init = true; system_init = true;
} }
@ -257,6 +265,9 @@ _PG_fini(void)
ExecutorFinish_hook = prev_ExecutorFinish; ExecutorFinish_hook = prev_ExecutorFinish;
ExecutorEnd_hook = prev_ExecutorEnd; ExecutorEnd_hook = prev_ExecutorEnd;
ProcessUtility_hook = prev_ProcessUtility; ProcessUtility_hook = prev_ProcessUtility;
free(nested_queryids);
hash_entry_reset(); hash_entry_reset();
} }
@ -389,6 +400,12 @@ static void
pgss_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, pgss_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count,
bool execute_once) bool execute_once)
{ {
nested_queryids[nested_level] = queryDesc->plannedstmt->queryId;
if(nested_level + 1 >= cur_max_nested_level)
{
cur_max_nested_level *= 2;
nested_queryids = realloc(nested_queryids, cur_max_nested_level);
}
nested_level++; nested_level++;
PG_TRY(); PG_TRY();
{ {
@ -397,10 +414,12 @@ pgss_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count,
else else
standard_ExecutorRun(queryDesc, direction, count, execute_once); standard_ExecutorRun(queryDesc, direction, count, execute_once);
nested_level--; nested_level--;
nested_queryids[nested_level] = UINT64CONST(0);
} }
PG_CATCH(); PG_CATCH();
{ {
nested_level--; nested_level--;
nested_queryids[nested_level] = UINT64CONST(0);
PG_RE_THROW(); PG_RE_THROW();
} }
PG_END_TRY(); PG_END_TRY();
@ -985,6 +1004,11 @@ static void pgss_store(uint64 queryId,
_snprintf(e->counters.error.sqlcode, sqlcode, sqlcode_len, SQLCODE_LEN); _snprintf(e->counters.error.sqlcode, sqlcode, sqlcode_len, SQLCODE_LEN);
_snprintf(e->counters.error.message, message, message_len, ERROR_MESSAGE_LEN); _snprintf(e->counters.error.message, message, message_len, ERROR_MESSAGE_LEN);
if(nested_level > 0)
e->counters.info.parentid = nested_queryids[nested_level - 1];
else
e->counters.info.parentid = UINT64CONST(0);
e->counters.calls[kind].rows += rows; e->counters.calls[kind].rows += rows;
e->counters.blocks.shared_blks_hit += bufusage->shared_blks_hit; e->counters.blocks.shared_blks_hit += bufusage->shared_blks_hit;
e->counters.blocks.shared_blks_read += bufusage->shared_blks_read; e->counters.blocks.shared_blks_read += bufusage->shared_blks_read;
@ -1075,6 +1099,7 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo,
pgssEntry *entry; pgssEntry *entry;
char *query_txt; char *query_txt;
char queryid_txt[64]; char queryid_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();
@ -1179,7 +1204,19 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo,
tmp = e->counters; tmp = e->counters;
SpinLockRelease(&e->mutex); SpinLockRelease(&e->mutex);
} }
values[i++] = CStringGetTextDatum(queryid_txt); values[i++] = CStringGetTextDatum(queryid_txt);
if (tmp.info.parentid != UINT64CONST(0))
{
sprintf(parentid_txt,"%08lX",tmp.info.parentid);
values[i++] = CStringGetTextDatum(parentid_txt);
}
else
{
nulls[i++] = true;
}
if (is_allowed_role || entry->key.userid == userid) if (is_allowed_role || entry->key.userid == userid)
{ {
if (showtext) if (showtext)
@ -1205,6 +1242,9 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo,
} }
else else
{ {
/*skip the query id and parent id*/
nulls[i++] = true;
nulls[i++] = true;
/* /*
* Don't show query text, but hint as to the reason for not doing * Don't show query text, but hint as to the reason for not doing
* so if it was requested * so if it was requested

View File

@ -120,6 +120,8 @@ typedef enum pgssStoreKind
PGSS_NUMKIND /* Must be last value of this enum */ PGSS_NUMKIND /* Must be last value of this enum */
} pgssStoreKind; } pgssStoreKind;
/* the assumption of query max nested level */
#define DEFAULT_MAX_NESTED_LEVEL 10
/* /*
* Type of aggregate keys * Type of aggregate keys
@ -161,6 +163,7 @@ typedef struct QueryInfo
Oid userid; /* user OID */ Oid userid; /* user OID */
Oid dbid; /* database OID */ Oid dbid; /* database OID */
uint host; /* client IP */ uint host; /* client IP */
uint64 parentid; /* parent queryid of current query*/
int64 type; /* type of query, options are query, info, warning, error, fatal */ int64 type; /* type of query, options are query, info, warning, error, fatal */
char application_name[APPLICATIONNAME_LEN]; char application_name[APPLICATIONNAME_LEN];
char relations[REL_LST][REL_LEN]; /* List of relation involved in the query */ char relations[REL_LST][REL_LEN]; /* List of relation involved in the query */

View File

@ -2,6 +2,6 @@ CREATE EXTENSION pg_stat_monitor;
SELECT pg_stat_monitor_reset(); SELECT pg_stat_monitor_reset();
select pg_sleep(.5); select pg_sleep(.5);
SELECT 1; SELECT 1;
SELECT query FROM pg_stat_monitor ORDER BY query; SELECT query FROM pg_stat_monitor ORDER BY query COLLATE "C";
SELECT pg_stat_monitor_reset(); SELECT pg_stat_monitor_reset();
DROP EXTENSION pg_stat_monitor; DROP EXTENSION pg_stat_monitor;