From d60f725b4a7552ef07108e0fedcdcc9fafcfb6e7 Mon Sep 17 00:00:00 2001 From: Ibrar Ahmed Date: Thu, 11 Feb 2021 15:51:44 +0000 Subject: [PATCH] PG-176 : Extract fully qualified relations name. --- Makefile | 2 +- expected/guc.out | 35 +++++++++++++++++++ expected/relations.out | 34 ++++++++++++++++++ expected/relations_1.out | 34 ++++++++++++++++++ pg_stat_monitor--1.0.sql | 2 +- pg_stat_monitor.c | 74 ++++++++++++++++++++++++++++------------ pg_stat_monitor.h | 7 ++-- sql/guc.sql | 6 ++++ sql/relations.sql | 14 ++++++++ 9 files changed, 183 insertions(+), 25 deletions(-) create mode 100644 expected/guc.out create mode 100644 expected/relations.out create mode 100644 expected/relations_1.out create mode 100644 sql/guc.sql create mode 100644 sql/relations.sql diff --git a/Makefile b/Makefile index ab78ee1..8228920 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ PGFILEDESC = "pg_stat_monitor - execution statistics of SQL statements" LDFLAGS_SL += $(filter -lm, $(LIBS)) REGRESS_OPTS = --temp-config $(top_srcdir)/contrib/pg_stat_monitor/pg_stat_monitor.conf -REGRESS = guc basic pg_stat_monitor +REGRESS = guc relations basic pg_stat_monitor # 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/expected/guc.out b/expected/guc.out new file mode 100644 index 0000000..9c1b2bf --- /dev/null +++ b/expected/guc.out @@ -0,0 +1,35 @@ +CREATE EXTENSION pg_stat_monitor; +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + +select pg_sleep(.5); + pg_sleep +---------- + +(1 row) + +SELECT * FROM pg_stat_monitor_settings; + name | value | default_value | description | minimum | maximum | restart +----------------------------------------+--------+---------------+----------------------------------------------------------------------------------------------------------+---------+------------+--------- + pg_stat_monitor.pgsm_max | 100 | 100 | Sets the maximum size of shared memory in (MB) used for statement's metadata tracked by pg_stat_monitor. | 1 | 1000 | 1 + pg_stat_monitor.pgsm_query_max_len | 1024 | 1024 | Sets the maximum length of query. | 1024 | 2147483647 | 1 + pg_stat_monitor.pgsm_enable | 1 | 1 | Enable/Disable statistics collector. | 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_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_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_buckets | 10 | 10 | Sets the maximum number of histogram buckets | 2 | 2147483647 | 1 +(10 rows) + +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + +DROP EXTENSION pg_stat_monitor; diff --git a/expected/relations.out b/expected/relations.out new file mode 100644 index 0000000..a611c5b --- /dev/null +++ b/expected/relations.out @@ -0,0 +1,34 @@ +CREATE EXTENSION pg_stat_monitor; +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + +CREATE TABLE foo1(a int); +CREATE TABLE foo2(a int); +CREATE TABLE foo3(a int); +CREATE TABLE foo4(a int); +SELECT * FROM foo1, foo2, foo3, foo4; + a | a | a | a +---+---+---+--- +(0 rows) + +SELECT query, relations from pg_stat_monitor; + query | relations +--------------------------------------+--------------------------------------------------- + SELECT * FROM foo1, foo2, foo3, foo4 | {public.foo1,public.foo2,public.foo3,public.foo4} + SELECT pg_stat_monitor_reset() | +(2 rows) + +DROP TABLE foo1; +DROP TABLE foo2; +DROP TABLE foo3; +DROP TABLE foo4; +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + +DROP EXTENSION pg_stat_monitor; diff --git a/expected/relations_1.out b/expected/relations_1.out new file mode 100644 index 0000000..8176aea --- /dev/null +++ b/expected/relations_1.out @@ -0,0 +1,34 @@ +CREATE EXTENSION pg_stat_monitor; +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + +CREATE TABLE foo1(a int); +CREATE TABLE foo2(a int); +CREATE TABLE foo3(a int); +CREATE TABLE foo4(a int); +SELECT * FROM foo1, foo2, foo3, foo4; + a | a | a | a +---+---+---+--- +(0 rows) + +SELECT query, relations from pg_stat_monitor; + query | relations +--------------------------------------+--------------------------------------------------- + SELECT pg_stat_monitor_reset() | + SELECT * FROM foo1, foo2, foo3, foo4 | {public.foo1,public.foo2,public.foo3,public.foo4} +(2 rows) + +DROP TABLE foo1; +DROP TABLE foo2; +DROP TABLE foo3; +DROP TABLE foo4; +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + +DROP EXTENSION pg_stat_monitor; diff --git a/pg_stat_monitor--1.0.sql b/pg_stat_monitor--1.0.sql index 4f0ff39..e2d4556 100644 --- a/pg_stat_monitor--1.0.sql +++ b/pg_stat_monitor--1.0.sql @@ -127,7 +127,7 @@ CREATE VIEW pg_stat_monitor AS SELECT queryid, query, application_name, - (string_to_array(relations, ','))::oid[]::regclass[] AS relations, + string_to_array(relations, ',') AS relations, cmd_type, get_cmd_type(cmd_type) AS cmd_type_text, elevel, diff --git a/pg_stat_monitor.c b/pg_stat_monitor.c index 9a1bb7b..e0b3653 100644 --- a/pg_stat_monitor.c +++ b/pg_stat_monitor.c @@ -32,7 +32,20 @@ do \ { \ int i; \ for(i = 0; i < _len && i < _max_len; i++) \ + {\ _str_dst[i] = _str_src[i]; \ + }\ +}while(0) + +#define _snprintf2(_str_dst, _str_src, _len1, _len2)\ +do \ +{ \ + int i,j; \ + for(i = 0; i < _len1; i++) \ + for(j = 0; j < _len2; j++) \ + { \ + _str_dst[i][j] = _str_src[i][j]; \ + } \ }while(0) /*---- Initicalization Function Declarations ----*/ @@ -40,6 +53,11 @@ void _PG_init(void); void _PG_fini(void); int64 v = 5631; + +/*---- Initicalization Function Declarations ----*/ +void _PG_init(void); +void _PG_fini(void); + /*---- Local variables ----*/ /* Current nesting depth of ExecutorRun+ProcessUtility calls */ @@ -459,7 +477,7 @@ pgss_ExecutorEnd(QueryDesc *queryDesc) prev_ExecutorEnd(queryDesc); else standard_ExecutorEnd(queryDesc); - memset(pgss->relations, 0x0, sizeof(pgss->relations)); + pgss->num_relations = 0; } static bool @@ -469,9 +487,10 @@ pgss_ExecutorCheckPerms(List *rt, bool abort) pgssSharedState *pgss = pgsm_get_ss(); int i = 0; int j = 0; + Oid list_oid[20]; LWLockAcquire(pgss->lock, LW_EXCLUSIVE); - memset(pgss->relations, 0x0, sizeof(pgss->relations)); + pgss->num_relations = 0; foreach(lr, rt) { @@ -484,13 +503,22 @@ pgss_ExecutorCheckPerms(List *rt, bool abort) bool found = false; for(j = 0; j < i; j++) { - if (pgss->relations[j] == rte->relid) + if (list_oid[j] == rte->relid) found = true; } + if (!found) - pgss->relations[i++] = rte->relid; + { + char *namespace_name; + char *relation_name; + list_oid[j] = rte->relid; + namespace_name = get_namespace_name(get_rel_namespace(rte->relid)); + relation_name = get_rel_name(rte->relid); + snprintf(pgss->relations[i++], REL_LEN, "%s.%s", namespace_name, relation_name); + } } } + pgss->num_relations = i; LWLockRelease(pgss->lock); if (prev_ExecutorCheckPerms_hook) @@ -783,8 +811,6 @@ static void pgss_store(uint64 queryId, char *norm_query = NULL; int encoding = GetDatabaseEncoding(); bool reset = false; - bool found = false; - int i; pgssSharedState *pgss = pgsm_get_ss(); HTAB *pgss_hash = pgsm_get_hash(); int message_len = message ? strlen(message) : 0; @@ -951,13 +977,8 @@ static void pgss_store(uint64 queryId, } _snprintf(e->counters.info.application_name, application_name, application_name_len, APPLICATIONNAME_LEN); - found = false; - for (i = 0; i < REL_LST; i++) - if (e->counters.info.relations[i] != 0) - found = true; - - if (!found) - _snprintf(e->counters.info.relations, pgss->relations, REL_LST, REL_LST); + e->counters.info.num_relations = pgss->num_relations; + _snprintf2(e->counters.info.relations, pgss->relations, pgss->num_relations, REL_LEN); e->counters.info.cmd_type = cmd_type; e->counters.error.elevel = elevel; @@ -1103,7 +1124,6 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, Datum values[PG_STAT_STATEMENTS_COLS]; bool nulls[PG_STAT_STATEMENTS_COLS]; int i = 0; - int j = 0; int len = 0; int kind; Counters tmp; @@ -1200,15 +1220,27 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, else values[i++] = CStringGetTextDatum(tmp.info.application_name); - len = 0; - for (j = 0; j < REL_LST; j++) - if (tmp.info.relations[j] != 0) - len++; + if (tmp.info.num_relations > 0) + { + int j; + char *text_str = palloc0(1024); + bool first = true; - if (len == 0) - nulls[i++] = true; + /* Need to calculate the actual size, and avoid unnessary memory usage */ + for (j = 0; j < tmp.info.num_relations; j++) + { + if (first) + { + snprintf(text_str, 1024, "%s", tmp.info.relations[j]); + first = false; + continue; + } + snprintf(text_str, 1024, "%s,%s", text_str, tmp.info.relations[j]); + } + values[i++] = CStringGetTextDatum(text_str); + } else - values[i++] = IntArrayGetTextDatum(tmp.info.relations, len); + nulls[i++] = true; values[i++] = Int64GetDatumFast(tmp.info.cmd_type); values[i++] = Int64GetDatumFast(tmp.error.elevel); diff --git a/pg_stat_monitor.h b/pg_stat_monitor.h index 4b4e254..407b8a1 100644 --- a/pg_stat_monitor.h +++ b/pg_stat_monitor.h @@ -75,6 +75,7 @@ #define TEXT_LEN 255 #define ERROR_MESSAGE_LEN 100 #define REL_LST 10 +#define REL_LEN 1000 #define CMD_LST 10 #define CMD_LEN 20 #define APPLICATIONNAME_LEN 100 @@ -163,7 +164,8 @@ typedef struct QueryInfo uint host; /* client IP */ int64 type; /* type of query, options are query, info, warning, error, fatal */ char application_name[APPLICATIONNAME_LEN]; - int32 relations[REL_LST]; /* List of relation involved in the query */ + char relations[REL_LST][REL_LEN]; /* List of relation involved in the query */ + int num_relations; /* Number of relation in the query */ CmdType cmd_type; /* query command type SELECT/UPDATE/DELETE/INSERT */ } QueryInfo; @@ -262,7 +264,8 @@ typedef struct pgssSharedState uint64 prev_bucket_usec; uint64 bucket_entry[MAX_BUCKETS]; int64 query_buf_size_bucket; - int32 relations[REL_LST]; + char relations[REL_LST][REL_LEN]; + int num_relations; /* Number of relation in the query */ char bucket_start_time[MAX_BUCKETS][60]; /* start time of the bucket */ } pgssSharedState; diff --git a/sql/guc.sql b/sql/guc.sql new file mode 100644 index 0000000..09333f2 --- /dev/null +++ b/sql/guc.sql @@ -0,0 +1,6 @@ +CREATE EXTENSION pg_stat_monitor; +SELECT pg_stat_monitor_reset(); +select pg_sleep(.5); +SELECT * FROM pg_stat_monitor_settings; +SELECT pg_stat_monitor_reset(); +DROP EXTENSION pg_stat_monitor; diff --git a/sql/relations.sql b/sql/relations.sql new file mode 100644 index 0000000..50701c1 --- /dev/null +++ b/sql/relations.sql @@ -0,0 +1,14 @@ +CREATE EXTENSION pg_stat_monitor; +SELECT pg_stat_monitor_reset(); +CREATE TABLE foo1(a int); +CREATE TABLE foo2(a int); +CREATE TABLE foo3(a int); +CREATE TABLE foo4(a int); +SELECT * FROM foo1, foo2, foo3, foo4; +SELECT query, relations from pg_stat_monitor; +DROP TABLE foo1; +DROP TABLE foo2; +DROP TABLE foo3; +DROP TABLE foo4; +SELECT pg_stat_monitor_reset(); +DROP EXTENSION pg_stat_monitor;