diff --git a/.gitignore b/.gitignore index 3ba025a8..299caa8d 100644 --- a/.gitignore +++ b/.gitignore @@ -45,6 +45,7 @@ *.mod* *.cmd .tmp_versions/ +.deps/ modules.order Module.symvers Mkfile.old diff --git a/Makefile b/Makefile index 117c4871..ba11b1ec 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ LDFLAGS_SL += $(filter -lm, $(LIBS)) TAP_TESTS = 1 REGRESS_OPTS = --temp-config $(top_srcdir)/contrib/pg_stat_monitor/pg_stat_monitor.conf --inputdir=regression -REGRESS = basic version guc pgsm_query_id functions counters relations database error_insert application_name application_name_unique top_query cmd_type error rows tags user level_tracking +REGRESS = basic version guc pgsm_query_id functions counters relations database error_insert application_name application_name_unique top_query different_parent_queries cmd_type error rows tags user level_tracking # Disabled because these tests require "shared_preload_libraries=pg_stat_statements", # which typical installcheck users do not have (e.g. buildfarm clients). diff --git a/pg_stat_monitor.c b/pg_stat_monitor.c index 91f1a2b4..b6642e91 100644 --- a/pg_stat_monitor.c +++ b/pg_stat_monitor.c @@ -1542,15 +1542,13 @@ pgsm_update_entry(pgsmEntry * entry, e->counters.info.num_relations = num_relations; _snprintf2(e->counters.info.relations, relations, num_relations, REL_LEN); - if (nesting_level > 0 && e->counters.info.parentid == 0 && pgsm_track == PGSM_TRACK_ALL) + if (nesting_level > 0 && nesting_level < max_stack_depth && e->key.parentid != 0 && pgsm_track == PGSM_TRACK_ALL) { - if (nesting_level >= 0 && nesting_level < max_stack_depth) + if (!DsaPointerIsValid(e->counters.info.parent_query)) { int parent_query_len = nested_query_txts[nesting_level - 1] ? strlen(nested_query_txts[nesting_level - 1]) : 0; - e->counters.info.parentid = nested_queryids[nesting_level - 1]; - e->counters.info.parent_query = InvalidDsaPointer; /* If we have a parent query, store it in the raw dsa area */ if (parent_query_len > 0) { @@ -1577,8 +1575,7 @@ pgsm_update_entry(pgsmEntry * entry, } else { - e->counters.info.parentid = UINT64CONST(0); - e->counters.info.parent_query = InvalidDsaPointer; + Assert(!DsaPointerIsValid(e->counters.info.parent_query)); } } @@ -1826,6 +1823,7 @@ pgsm_create_hash_entry(uint64 bucket_id, uint64 queryid, PlanInfo * plan_info) entry->key.dbid = MyDatabaseId; entry->key.queryid = queryid; entry->key.bucket_id = bucket_id; + entry->key.parentid = 0; #if PG_VERSION_NUM < 140000 entry->key.toplevel = 1; @@ -1947,13 +1945,24 @@ pgsm_store(pgsmEntry * entry) memcpy(&jitusage.optimization_counter, &entry->counters.jitinfo.instr_optimization_counter, sizeof(instr_time)); memcpy(&jitusage.emission_counter, &entry->counters.jitinfo.instr_emission_counter, sizeof(instr_time)); + + // Update parent id if needed + if(pgsm_track == PGSM_TRACK_ALL && nesting_level > 0 && nesting_level < max_stack_depth) + { + entry->key.parentid = nested_queryids[nesting_level - 1]; + } + else + { + entry->key.parentid = UINT64CONST(0); + } + #if PG_VERSION_NUM >= 170000 memcpy(&jitusage.deform_counter, &entry->counters.jitinfo.instr_deform_counter, sizeof(instr_time)); #endif /* * Acquire a share lock to start with. We'd have to acquire exclusive if - * we need ot create the entry. + * we need to create the entry. */ LWLockAcquire(pgsm->lock, LW_SHARED); shared_hash_entry = (pgsmEntry *) pgsm_hash_find(get_pgsmHash(), &entry->key, &found); @@ -2047,6 +2056,7 @@ pgsm_store(pgsmEntry * entry) shared_hash_entry->pgsm_query_id = entry->pgsm_query_id; shared_hash_entry->encoding = entry->encoding; shared_hash_entry->counters.info.cmd_type = entry->counters.info.cmd_type; + shared_hash_entry->counters.info.parent_query = InvalidDsaPointer; snprintf(shared_hash_entry->datname, sizeof(shared_hash_entry->datname), "%s", entry->datname); snprintf(shared_hash_entry->username, sizeof(shared_hash_entry->username), "%s", entry->username); @@ -2233,6 +2243,7 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, bool nulls[PG_STAT_MONITOR_COLS] = {0}; int i = 0; Counters tmp; + pgsmHashKey tmpkey; double stddev; uint64 queryid = entry->key.queryid; int64 bucketid = entry->key.bucket_id; @@ -2269,6 +2280,7 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, SpinLockAcquire(&e->mutex); tmp = e->counters; + tmpkey = e->key; SpinLockRelease(&e->mutex); } @@ -2285,7 +2297,7 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, } /* read the parent query text if any */ - if (tmp.info.parentid != UINT64CONST(0)) + if (tmpkey.parentid != UINT64CONST(0)) { if (DsaPointerIsValid(tmp.info.parent_query)) { @@ -2370,10 +2382,10 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, else nulls[i++] = true; - /* parentid at column number 11 */ - if (tmp.info.parentid != UINT64CONST(0)) + /* parentid at column number 9 */ + if (tmpkey.parentid != UINT64CONST(0)) { - values[i++] = UInt64GetDatum(tmp.info.parentid); + values[i++] = UInt64GetDatum(tmpkey.parentid); values[i++] = CStringGetTextDatum(parent_query_txt); } else diff --git a/pg_stat_monitor.h b/pg_stat_monitor.h index c4a23d5d..32339da9 100644 --- a/pg_stat_monitor.h +++ b/pg_stat_monitor.h @@ -240,11 +240,11 @@ typedef struct pgsmHashKey Oid dbid; /* database OID */ uint32 ip; /* client ip address */ bool toplevel; /* query executed at top level */ + uint64 parentid; /* parent queryid of current query */ } pgsmHashKey; typedef struct QueryInfo { - uint64 parentid; /* parent queryid of current query */ dsa_pointer parent_query; int64 type; /* type of query, options are query, info, * warning, error, fatal */ diff --git a/regression/expected/different_parent_queries.out b/regression/expected/different_parent_queries.out new file mode 100644 index 00000000..ff0a674b --- /dev/null +++ b/regression/expected/different_parent_queries.out @@ -0,0 +1,54 @@ +CREATE EXTENSION pg_stat_monitor; +SET pg_stat_monitor.pgsm_track='all'; +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + +CREATE OR REPLACE FUNCTION test() RETURNS VOID AS +$$ +BEGIN + PERFORM 1 + 2; +END; $$ language plpgsql; +CREATE OR REPLACE FUNCTION test2() RETURNS VOID AS +$$ +BEGIN + PERFORM 1 + 2; +END; $$ language plpgsql; +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + +SELECT test(); + test +------ + +(1 row) + +SELECT test2(); + test2 +------- + +(1 row) + +SELECT 1 + 2; + ?column? +---------- + 3 +(1 row) + +SELECT left(query, 15) as query, calls, top_query, pgsm_query_id FROM pg_stat_monitor ORDER BY query, top_query COLLATE "C"; + query | calls | top_query | pgsm_query_id +-----------------+-------+-----------------+---------------------- + SELECT 1 + 2 | 1 | SELECT test(); | 5193804135051352284 + SELECT 1 + 2 | 1 | SELECT test2(); | 5193804135051352284 + SELECT 1 + 2 | 1 | | 5193804135051352284 + SELECT pg_stat_ | 1 | | 689150021118383254 + SELECT test() | 1 | | -6801876889834540522 + SELECT test2() | 1 | | 369102705908374543 +(6 rows) + +DROP EXTENSION pg_stat_monitor; diff --git a/regression/sql/different_parent_queries.sql b/regression/sql/different_parent_queries.sql new file mode 100644 index 00000000..c3e1d180 --- /dev/null +++ b/regression/sql/different_parent_queries.sql @@ -0,0 +1,24 @@ +CREATE EXTENSION pg_stat_monitor; +SET pg_stat_monitor.pgsm_track='all'; +SELECT pg_stat_monitor_reset(); + +CREATE OR REPLACE FUNCTION test() RETURNS VOID AS +$$ +BEGIN + PERFORM 1 + 2; +END; $$ language plpgsql; + +CREATE OR REPLACE FUNCTION test2() RETURNS VOID AS +$$ +BEGIN + PERFORM 1 + 2; +END; $$ language plpgsql; + +SELECT pg_stat_monitor_reset(); +SELECT test(); +SELECT test2(); + +SELECT 1 + 2; +SELECT left(query, 15) as query, calls, top_query, pgsm_query_id FROM pg_stat_monitor ORDER BY query, top_query COLLATE "C"; + +DROP EXTENSION pg_stat_monitor; \ No newline at end of file