diff --git a/.github/workflows/postgresql-11-pmm.yaml b/.github/workflows/postgresql-11-pmm.yaml index d33e5c1..1791955 100644 --- a/.github/workflows/postgresql-11-pmm.yaml +++ b/.github/workflows/postgresql-11-pmm.yaml @@ -8,7 +8,7 @@ jobs: timeout-minutes: 30 steps: - name: Clone QA Integration repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: repository: 'Percona-Lab/qa-integration' ref: 'main' @@ -16,9 +16,17 @@ jobs: # print branch and Repo name - name: Get branch and Repo Name run: echo 'The branch and Repo Name is' ${{ github.head_ref }} ${{ github.actor }}/pg_stat_monitor + + - name: "Set TARGET_BRANCH variable for a PR run" + if: github.event_name == 'pull_request' + run: echo "TARGET_BRANCH=${{ github.event.pull_request.base.ref }}" >> $GITHUB_ENV + + - name: "Set TARGET_BRANCH variable for a PUSH run" + if: github.event_name == 'push' + run: echo "TARGET_BRANCH=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV - name: Run PMM & PGSM Setup, E2E Tests - run: bash -xe ./pmm_pgsm_setup/pmm_pgsm_setup.sh --pgsql-version=11 --pgstat-monitor-branch=REL_1_1_1 + run: bash -xe ./pmm_pgsm_setup/pmm_pgsm_setup.sh --pgsql-version=11 --pgstat-monitor-branch=${{ env.TARGET_BRANCH }} - name: Get PMM-Agent Logs from the Container if: success() || failure() # run this step even if previous step failed diff --git a/.github/workflows/postgresql-12-pmm.yaml b/.github/workflows/postgresql-12-pmm.yaml index 60cb6e4..96bf832 100644 --- a/.github/workflows/postgresql-12-pmm.yaml +++ b/.github/workflows/postgresql-12-pmm.yaml @@ -8,7 +8,7 @@ jobs: timeout-minutes: 30 steps: - name: Clone QA Integration repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: repository: 'Percona-Lab/qa-integration' ref: 'main' @@ -16,9 +16,17 @@ jobs: # print branch and Repo name - name: Get branch and Repo Name run: echo 'The branch and Repo Name is' ${{ github.head_ref }} ${{ github.actor }}/pg_stat_monitor + + - name: "Set TARGET_BRANCH variable for a PR run" + if: github.event_name == 'pull_request' + run: echo "TARGET_BRANCH=${{ github.event.pull_request.base.ref }}" >> $GITHUB_ENV + + - name: "Set TARGET_BRANCH variable for a PUSH run" + if: github.event_name == 'push' + run: echo "TARGET_BRANCH=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV - name: Run PMM & PGSM Setup, E2E Tests - run: bash -xe ./pmm_pgsm_setup/pmm_pgsm_setup.sh --pgsql-version=12 --pgstat-monitor-branch=REL_1_1_1 + run: bash -xe ./pmm_pgsm_setup/pmm_pgsm_setup.sh --pgsql-version=12 --pgstat-monitor-branch=${{ env.TARGET_BRANCH }} - name: Get PMM-Agent Logs from the Container if: success() || failure() # run this step even if previous step failed diff --git a/.github/workflows/postgresql-13-pmm.yaml b/.github/workflows/postgresql-13-pmm.yaml index 93c5cd0..5d6f108 100644 --- a/.github/workflows/postgresql-13-pmm.yaml +++ b/.github/workflows/postgresql-13-pmm.yaml @@ -8,7 +8,7 @@ jobs: timeout-minutes: 30 steps: - name: Clone QA Integration repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: repository: 'Percona-Lab/qa-integration' ref: 'main' @@ -17,8 +17,16 @@ jobs: - name: Get branch and Repo Name run: echo 'The branch and Repo Name is' ${{ github.head_ref }} ${{ github.actor }}/pg_stat_monitor + - name: "Set TARGET_BRANCH variable for a PR run" + if: github.event_name == 'pull_request' + run: echo "TARGET_BRANCH=${{ github.event.pull_request.base.ref }}" >> $GITHUB_ENV + + - name: "Set TARGET_BRANCH variable for a PUSH run" + if: github.event_name == 'push' + run: echo "TARGET_BRANCH=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV + - name: Run PMM & PGSM Setup, E2E Tests - run: bash -xe ./pmm_pgsm_setup/pmm_pgsm_setup.sh --pgsql-version=13 --pgstat-monitor-branch=REL_1_1_1 + run: bash -xe ./pmm_pgsm_setup/pmm_pgsm_setup.sh --pgsql-version=13 --pgstat-monitor-branch=${{ env.TARGET_BRANCH }} - name: Get PMM-Agent Logs from the Container if: success() || failure() # run this step even if previous step failed diff --git a/.github/workflows/postgresql-14-pmm.yaml b/.github/workflows/postgresql-14-pmm.yaml index 20d0d11..1f83111 100644 --- a/.github/workflows/postgresql-14-pmm.yaml +++ b/.github/workflows/postgresql-14-pmm.yaml @@ -8,7 +8,7 @@ jobs: timeout-minutes: 30 steps: - name: Clone QA Integration repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: repository: 'Percona-Lab/qa-integration' ref: 'main' @@ -17,8 +17,16 @@ jobs: - name: Get branch and Repo Name run: echo 'The branch and Repo Name is' ${{ github.head_ref }} ${{ github.actor }}/pg_stat_monitor + - name: "Set TARGET_BRANCH variable for a PR run" + if: github.event_name == 'pull_request' + run: echo "TARGET_BRANCH=${{ github.event.pull_request.base.ref }}" >> $GITHUB_ENV + + - name: "Set TARGET_BRANCH variable for a PUSH run" + if: github.event_name == 'push' + run: echo "TARGET_BRANCH=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV + - name: Run PMM & PGSM Setup, E2E Tests - run: bash -xe ./pmm_pgsm_setup/pmm_pgsm_setup.sh --pgsql-version=14 --pgstat-monitor-branch=REL_1_1_1 + run: bash -xe ./pmm_pgsm_setup/pmm_pgsm_setup.sh --pgsql-version=14 --pgstat-monitor-branch=${{ env.TARGET_BRANCH }} - name: Get PMM-Agent Logs from the Container if: success() || failure() # run this step even if previous step failed diff --git a/.github/workflows/postgresql-15-pmm.yaml b/.github/workflows/postgresql-15-pmm.yaml index 073fa1b..40e4930 100644 --- a/.github/workflows/postgresql-15-pmm.yaml +++ b/.github/workflows/postgresql-15-pmm.yaml @@ -8,7 +8,7 @@ jobs: timeout-minutes: 30 steps: - name: Clone QA Integration repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: repository: 'Percona-Lab/qa-integration' ref: 'main' @@ -17,8 +17,16 @@ jobs: - name: Get branch and Repo Name run: echo 'The branch and Repo Name is' ${{ github.head_ref }} ${{ github.actor }}/pg_stat_monitor + - name: "Set TARGET_BRANCH variable for a PR run" + if: github.event_name == 'pull_request' + run: echo "TARGET_BRANCH=${{ github.event.pull_request.base.ref }}" >> $GITHUB_ENV + + - name: "Set TARGET_BRANCH variable for a PUSH run" + if: github.event_name == 'push' + run: echo "TARGET_BRANCH=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV + - name: Run PMM & PGSM Setup, E2E Tests - run: bash -xe ./pmm_pgsm_setup/pmm_pgsm_setup.sh --pgsql-version=15 --pgstat-monitor-branch=REL_1_1_1 + run: bash -xe ./pmm_pgsm_setup/pmm_pgsm_setup.sh --pgsql-version=15 --pgstat-monitor-branch=${{ env.TARGET_BRANCH }} - name: Get PMM-Agent Logs from the Container if: success() || failure() # run this step even if previous step failed diff --git a/Makefile b/Makefile index 2a1e11a..471988c 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 counters relations database error_insert application_name application_name_unique top_query cmd_type error rows tags +REGRESS = basic version guc functions counters relations database error_insert application_name application_name_unique top_query cmd_type error rows tags # 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--1.0--2.0.sql b/pg_stat_monitor--1.0--2.0.sql index c3302a7..6199ab3 100644 --- a/pg_stat_monitor--1.0--2.0.sql +++ b/pg_stat_monitor--1.0--2.0.sql @@ -8,6 +8,7 @@ DROP FUNCTION pgsm_create_11_view CASCADE; DROP FUNCTION pgsm_create_13_view CASCADE; DROP FUNCTION pgsm_create_14_view CASCADE; DROP FUNCTION pgsm_create_view CASCADE; +DROP FUNCTION pg_stat_monitor_settings CASCADE; -- pg_stat_monitor internal function, must not call outside from this file. CREATE FUNCTION pg_stat_monitor_internal( @@ -62,17 +63,31 @@ CREATE FUNCTION pg_stat_monitor_internal( OUT temp_blks_written int8, OUT blk_read_time float8, OUT blk_write_time float8, + OUT temp_blk_read_time float8, + OUT temp_blk_write_time float8, + OUT resp_calls text, -- 41 OUT cpu_user_time float8, OUT cpu_sys_time float8, - OUT wal_records int8, - OUT wal_fpi int8, - OUT wal_bytes numeric, - OUT comments TEXT, - OUT toplevel BOOLEAN + OUT wal_records int8, + OUT wal_fpi int8, + OUT wal_bytes numeric, + OUT comments TEXT, + + OUT jit_functions int8, + OUT jit_generation_time float8, + OUT jit_inlining_count int8, + OUT jit_inlining_time float8, + OUT jit_optimization_count int8, + OUT jit_optimization_time float8, + OUT jit_emission_count int8, + OUT jit_emission_time float8, + + OUT toplevel BOOLEAN, + OUT bucket_done BOOLEAN ) RETURNS SETOF record -AS 'MODULE_PATHNAME', 'pg_stat_monitor' +AS 'MODULE_PATHNAME', 'pg_stat_monitor_2_0' LANGUAGE C STRICT VOLATILE PARALLEL SAFE; -- Register a view on the function for ease of use. @@ -122,9 +137,7 @@ CREATE VIEW pg_stat_monitor AS SELECT (string_to_array(resp_calls, ',')) resp_calls, cpu_user_time, cpu_sys_time, - wal_records, - wal_fpi, - wal_bytes + bucket_done FROM pg_stat_monitor_internal(TRUE) p, pg_database d WHERE dbid = oid ORDER BY bucket_start_time; RETURN 0; @@ -242,6 +255,7 @@ CREATE VIEW pg_stat_monitor AS SELECT wal_records, wal_fpi, wal_bytes, + bucket_done, plans_calls, total_plan_time, @@ -255,18 +269,97 @@ RETURN 0; END; $$ LANGUAGE plpgsql; +CREATE FUNCTION pgsm_create_15_view() RETURNS INT AS +$$ +BEGIN +CREATE VIEW pg_stat_monitor AS SELECT + bucket, + bucket_start_time AS bucket_start_time, + userid::regrole, + datname, + '0.0.0.0'::inet + client_ip AS client_ip, + queryid, + toplevel, + top_queryid, + query, + comments, + planid, + query_plan, + top_query, + application_name, + string_to_array(relations, ',') AS relations, + cmd_type, + get_cmd_type(cmd_type) AS cmd_type_text, + elevel, + sqlcode, + message, + calls, + total_exec_time, + min_exec_time, + max_exec_time, + mean_exec_time, + stddev_exec_time, + rows_retrieved, + shared_blks_hit, + shared_blks_read, + shared_blks_dirtied, + shared_blks_written, + local_blks_hit, + local_blks_read, + local_blks_dirtied, + local_blks_written, + temp_blks_read, + temp_blks_written, + blk_read_time, + blk_write_time, + temp_blk_read_time, + temp_blk_write_time, + + (string_to_array(resp_calls, ',')) resp_calls, + cpu_user_time, + cpu_sys_time, + wal_records, + wal_fpi, + wal_bytes, + bucket_done, + + plans_calls, + total_plan_time, + min_plan_time, + max_plan_time, + mean_plan_time, + stddev_plan_time, + + jit_functions, + jit_generation_time, + jit_inlining_count, + jit_inlining_time, + jit_optimization_count, + jit_optimization_time, + jit_emission_count, + jit_emission_time + +FROM pg_stat_monitor_internal(TRUE) p, pg_database d WHERE dbid = oid +ORDER BY bucket_start_time; +RETURN 0; +END; +$$ LANGUAGE plpgsql; + CREATE FUNCTION pgsm_create_view() RETURNS INT AS $$ DECLARE ver integer; BEGIN SELECT current_setting('server_version_num') INTO ver; - IF (ver >= 14000) THEN + IF (ver >= 150000) THEN + return pgsm_create_15_view(); + END IF; + IF (ver >= 140000) THEN return pgsm_create_14_view(); END IF; - IF (ver >= 13000) THEN + IF (ver >= 130000) THEN return pgsm_create_13_view(); END IF; - IF (ver >= 11000) THEN + IF (ver >= 110000) THEN return pgsm_create_11_view(); END IF; RETURN 0; @@ -274,11 +367,17 @@ $$ $$ LANGUAGE plpgsql; SELECT pgsm_create_view(); + REVOKE ALL ON FUNCTION range FROM PUBLIC; REVOKE ALL ON FUNCTION get_cmd_type FROM PUBLIC; -REVOKE ALL ON FUNCTION pg_stat_monitor_settings FROM PUBLIC; REVOKE ALL ON FUNCTION decode_error_level FROM PUBLIC; REVOKE ALL ON FUNCTION pg_stat_monitor_internal FROM PUBLIC; +REVOKE ALL ON FUNCTION get_histogram_timings FROM PUBLIC; +REVOKE ALL ON FUNCTION pgsm_create_view FROM PUBLIC; +REVOKE ALL ON FUNCTION pgsm_create_11_view FROM PUBLIC; +REVOKE ALL ON FUNCTION pgsm_create_13_view FROM PUBLIC; +REVOKE ALL ON FUNCTION pgsm_create_14_view FROM PUBLIC; +REVOKE ALL ON FUNCTION pgsm_create_15_view FROM PUBLIC; GRANT SELECT ON pg_stat_monitor TO PUBLIC; diff --git a/pg_stat_monitor--1.0.sql b/pg_stat_monitor--1.0.sql index 467d6b5..3242e16 100644 --- a/pg_stat_monitor--1.0.sql +++ b/pg_stat_monitor--1.0.sql @@ -178,7 +178,8 @@ CREATE FUNCTION pg_stat_monitor_internal( OUT wal_fpi int8, OUT wal_bytes numeric, OUT comments TEXT, - OUT toplevel BOOLEAN + OUT toplevel BOOLEAN, + OUT bucket_done BOOLEAN ) RETURNS SETOF record AS 'MODULE_PATHNAME', 'pg_stat_monitor' @@ -396,6 +397,12 @@ REVOKE ALL ON FUNCTION get_cmd_type FROM PUBLIC; REVOKE ALL ON FUNCTION pg_stat_monitor_settings FROM PUBLIC; REVOKE ALL ON FUNCTION decode_error_level FROM PUBLIC; REVOKE ALL ON FUNCTION pg_stat_monitor_internal FROM PUBLIC; +REVOKE ALL ON FUNCTION get_histogram_timings FROM PUBLIC; +REVOKE ALL ON FUNCTION pgsm_create_view FROM PUBLIC; +REVOKE ALL ON FUNCTION pgsm_create_11_view FROM PUBLIC; +REVOKE ALL ON FUNCTION pgsm_create_13_view FROM PUBLIC; +REVOKE ALL ON FUNCTION pgsm_create_14_view FROM PUBLIC; +REVOKE ALL ON FUNCTION pgsm_create_15_view FROM PUBLIC; GRANT SELECT ON pg_stat_monitor TO PUBLIC; diff --git a/pg_stat_monitor--2.0.sql b/pg_stat_monitor--2.0.sql index bc0a0f9..ff16d71 100644 --- a/pg_stat_monitor--2.0.sql +++ b/pg_stat_monitor--2.0.sql @@ -41,31 +41,6 @@ SELECT $$ LANGUAGE SQL PARALLEL SAFE; -CREATE FUNCTION pg_stat_monitor_settings( - OUT name text, - OUT value text, - OUT default_value text, - OUT description text, - OUT minimum INTEGER, - OUT maximum INTEGER, - OUT options text, - OUT restart text -) -RETURNS SETOF record -AS 'MODULE_PATHNAME', 'pg_stat_monitor_settings' -LANGUAGE C STRICT VOLATILE PARALLEL SAFE; - -CREATE VIEW pg_stat_monitor_settings AS SELECT - name, - value, - default_value, - description, - minimum, - maximum, - options, - restart -FROM pg_stat_monitor_settings(); - CREATE FUNCTION decode_error_level(elevel int) RETURNS text AS @@ -116,7 +91,6 @@ CREATE FUNCTION pg_stat_monitor_internal( OUT planid text, OUT query text, OUT query_plan text, - OUT state_code int8, OUT top_queryid text, OUT top_query text, OUT application_name text, @@ -126,7 +100,7 @@ CREATE FUNCTION pg_stat_monitor_internal( OUT elevel int, OUT sqlcode TEXT, OUT message text, - OUT bucket_start_time timestamp, + OUT bucket_start_time timestamptz, OUT calls int8, -- 16 @@ -158,17 +132,32 @@ CREATE FUNCTION pg_stat_monitor_internal( OUT temp_blks_written int8, OUT blk_read_time float8, OUT blk_write_time float8, + + OUT temp_blk_read_time float8, + OUT temp_blk_write_time float8, + OUT resp_calls text, -- 41 OUT cpu_user_time float8, OUT cpu_sys_time float8, - OUT wal_records int8, - OUT wal_fpi int8, - OUT wal_bytes numeric, - OUT comments TEXT, - OUT toplevel BOOLEAN + OUT wal_records int8, + OUT wal_fpi int8, + OUT wal_bytes numeric, + OUT comments TEXT, + + OUT jit_functions int8, + OUT jit_generation_time float8, + OUT jit_inlining_count int8, + OUT jit_inlining_time float8, + OUT jit_optimization_count int8, + OUT jit_optimization_time float8, + OUT jit_emission_count int8, + OUT jit_emission_time float8, + + OUT toplevel BOOLEAN, + OUT bucket_done BOOLEAN ) RETURNS SETOF record -AS 'MODULE_PATHNAME', 'pg_stat_monitor' +AS 'MODULE_PATHNAME', 'pg_stat_monitor_2_0' LANGUAGE C STRICT VOLATILE PARALLEL SAFE; -- Register a view on the function for ease of use. @@ -217,9 +206,7 @@ CREATE VIEW pg_stat_monitor AS SELECT (string_to_array(resp_calls, ',')) resp_calls, cpu_user_time, cpu_sys_time, - wal_records, - wal_fpi, - wal_bytes + bucket_done FROM pg_stat_monitor_internal(TRUE) p, pg_database d WHERE dbid = oid ORDER BY bucket_start_time; RETURN 0; @@ -276,6 +263,7 @@ CREATE VIEW pg_stat_monitor AS SELECT wal_records, wal_fpi, wal_bytes, + bucket_done, -- PostgreSQL-13 Specific Coulumns plans_calls, total_plan_time, @@ -338,6 +326,7 @@ CREATE VIEW pg_stat_monitor AS SELECT wal_records, wal_fpi, wal_bytes, + bucket_done, plans_calls, total_plan_time, @@ -351,11 +340,90 @@ RETURN 0; END; $$ LANGUAGE plpgsql; +CREATE FUNCTION pgsm_create_15_view() RETURNS INT AS +$$ +BEGIN +CREATE VIEW pg_stat_monitor AS SELECT + bucket, + bucket_start_time AS bucket_start_time, + userid::regrole, + datname, + '0.0.0.0'::inet + client_ip AS client_ip, + queryid, + toplevel, + top_queryid, + query, + comments, + planid, + query_plan, + top_query, + application_name, + string_to_array(relations, ',') AS relations, + cmd_type, + get_cmd_type(cmd_type) AS cmd_type_text, + elevel, + sqlcode, + message, + calls, + total_exec_time, + min_exec_time, + max_exec_time, + mean_exec_time, + stddev_exec_time, + rows_retrieved, + shared_blks_hit, + shared_blks_read, + shared_blks_dirtied, + shared_blks_written, + local_blks_hit, + local_blks_read, + local_blks_dirtied, + local_blks_written, + temp_blks_read, + temp_blks_written, + blk_read_time, + blk_write_time, + temp_blk_read_time, + temp_blk_write_time, + + (string_to_array(resp_calls, ',')) resp_calls, + cpu_user_time, + cpu_sys_time, + wal_records, + wal_fpi, + wal_bytes, + bucket_done, + + plans_calls, + total_plan_time, + min_plan_time, + max_plan_time, + mean_plan_time, + stddev_plan_time, + + jit_functions, + jit_generation_time, + jit_inlining_count, + jit_inlining_time, + jit_optimization_count, + jit_optimization_time, + jit_emission_count, + jit_emission_time + +FROM pg_stat_monitor_internal(TRUE) p, pg_database d WHERE dbid = oid +ORDER BY bucket_start_time; +RETURN 0; +END; +$$ LANGUAGE plpgsql; + CREATE FUNCTION pgsm_create_view() RETURNS INT AS $$ DECLARE ver integer; BEGIN SELECT current_setting('server_version_num') INTO ver; + IF (ver >= 150000) THEN + return pgsm_create_15_view(); + END IF; IF (ver >= 140000) THEN return pgsm_create_14_view(); END IF; @@ -372,9 +440,14 @@ $$ LANGUAGE plpgsql; SELECT pgsm_create_view(); REVOKE ALL ON FUNCTION range FROM PUBLIC; REVOKE ALL ON FUNCTION get_cmd_type FROM PUBLIC; -REVOKE ALL ON FUNCTION pg_stat_monitor_settings FROM PUBLIC; REVOKE ALL ON FUNCTION decode_error_level FROM PUBLIC; REVOKE ALL ON FUNCTION pg_stat_monitor_internal FROM PUBLIC; +REVOKE ALL ON FUNCTION get_histogram_timings FROM PUBLIC; +REVOKE ALL ON FUNCTION pgsm_create_view FROM PUBLIC; +REVOKE ALL ON FUNCTION pgsm_create_11_view FROM PUBLIC; +REVOKE ALL ON FUNCTION pgsm_create_13_view FROM PUBLIC; +REVOKE ALL ON FUNCTION pgsm_create_14_view FROM PUBLIC; +REVOKE ALL ON FUNCTION pgsm_create_15_view FROM PUBLIC; GRANT SELECT ON pg_stat_monitor TO PUBLIC; diff --git a/pg_stat_monitor.c b/pg_stat_monitor.c index 41bcb4f..88ccada 100644 --- a/pg_stat_monitor.c +++ b/pg_stat_monitor.c @@ -23,10 +23,25 @@ #include "commands/explain.h" #include "pg_stat_monitor.h" + /* + * Extension version number, for supporting older extension versions' objects + */ + typedef enum pgsmVersion + { + PGSM_V1_0 = 0, + PGSM_V2_0 + } pgsmVersion; + + PG_MODULE_MAGIC; -#define BUILD_VERSION "1.1.1" -#define PG_STAT_STATEMENTS_COLS 52 /* maximum of above */ +#define BUILD_VERSION "2.0.0-dev" + +/* Number of output arguments (columns) for various API versions */ +#define PG_STAT_MONITOR_COLS_V1_0 52 +#define PG_STAT_MONITOR_COLS_V2_0 61 +#define PG_STAT_MONITOR_COLS 61 /* maximum of above */ + #define PGSM_TEXT_FILE PGSTAT_STAT_PERMANENT_DIRECTORY "pg_stat_monitor_query" #define roundf(x,d) ((floor(((x)*pow(10,d))+.5))/pow(10,d)) @@ -107,8 +122,9 @@ static ExecutorCheckPerms_hook_type prev_ExecutorCheckPerms_hook = NULL; PG_FUNCTION_INFO_V1(pg_stat_monitor_version); PG_FUNCTION_INFO_V1(pg_stat_monitor_reset); +PG_FUNCTION_INFO_V1(pg_stat_monitor_1_0); +PG_FUNCTION_INFO_V1(pg_stat_monitor_2_0); PG_FUNCTION_INFO_V1(pg_stat_monitor); -PG_FUNCTION_INFO_V1(pg_stat_monitor_settings); PG_FUNCTION_INFO_V1(get_histogram_timings); PG_FUNCTION_INFO_V1(pg_stat_monitor_hook_stats); @@ -174,10 +190,12 @@ static void pgss_store(uint64 queryid, uint64 rows, BufferUsage *bufusage, WalUsage *walusage, + const struct JitInstrumentation *jitusage, JumbleState *jstate, pgssStoreKind kind); static void pg_stat_monitor_internal(FunctionCallInfo fcinfo, + pgsmVersion api_version, bool showtext); #if PG_VERSION_NUM < 140000 @@ -228,7 +246,7 @@ _PG_init(void) * In order to create our shared memory area, we have to be loaded via * shared_preload_libraries. If not, fall out without hooking into any of * the main system. (We don't throw error here because it seems useful to - * allow the pg_stat_statements functions to be created even when the + * allow the pg_stat_monitor functions to be created even when the * module isn't active. The functions must protect themselves against * being called then, however.) */ @@ -419,6 +437,7 @@ pgss_post_parse_analyze(ParseState *pstate, Query *query, JumbleState *jstate) 0, /* rows */ NULL, /* bufusage */ NULL, /* walusage */ + NULL, /* jitusage */ jstate, /* JumbleState */ PGSS_PARSE); /* pgssStoreKind */ } @@ -477,6 +496,7 @@ pgss_post_parse_analyze(ParseState *pstate, Query *query) 0, /* rows */ NULL, /* bufusage */ NULL, /* walusage */ + NULL, /* jitusage */ &jstate, /* JumbleState */ PGSS_PARSE); /* pgssStoreKind */ } @@ -648,6 +668,11 @@ pgss_ExecutorEnd(QueryDesc *queryDesc) &queryDesc->totaltime->walusage, /* walusage */ #else NULL, +#endif +#if PG_VERSION_NUM >= 150000 + queryDesc->estate->es_jit ? &queryDesc->estate->es_jit->instr : NULL, +#else + NULL, #endif NULL, PGSS_FINISHED); /* pgssStoreKind */ @@ -791,6 +816,7 @@ pgss_planner_hook(Query *parse, const char *query_string, int cursorOptions, Par &bufusage, /* bufusage */ &walusage, /* walusage */ NULL, /* JumbleState */ + NULL, PGSS_PLAN); /* pgssStoreKind */ } else @@ -980,6 +1006,7 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString, #else NULL, /* walusage, NULL for PG <= 12 */ #endif + NULL, NULL, /* JumbleState */ PGSS_FINISHED); /* pgssStoreKind */ } @@ -1126,7 +1153,7 @@ pg_get_client_addr(bool *ok) static void pgss_update_entry(pgssEntry *entry, - int bucketid, + uint64 bucketid, uint64 queryid, const char *query, const char *comments, @@ -1138,6 +1165,7 @@ pgss_update_entry(pgssEntry *entry, uint64 rows, BufferUsage *bufusage, WalUsage *walusage, + const struct JitInstrumentation *jitusage, bool reset, pgssStoreKind kind, const char *app_name, @@ -1259,6 +1287,10 @@ pgss_update_entry(pgssEntry *entry, e->counters.blocks.temp_blks_written += bufusage->temp_blks_written; e->counters.blocks.blk_read_time += INSTR_TIME_GET_MILLISEC(bufusage->blk_read_time); e->counters.blocks.blk_write_time += INSTR_TIME_GET_MILLISEC(bufusage->blk_write_time); + #if PG_VERSION_NUM >= 150000 + e->counters.blocks.temp_blk_read_time += INSTR_TIME_GET_MILLISEC(bufusage->temp_blk_read_time); + e->counters.blocks.temp_blk_write_time += INSTR_TIME_GET_MILLISEC(bufusage->temp_blk_write_time); + #endif } e->counters.calls.usage += USAGE_EXEC(total_time); if (sys_info) @@ -1272,6 +1304,23 @@ pgss_update_entry(pgssEntry *entry, e->counters.walusage.wal_fpi += walusage->wal_fpi; e->counters.walusage.wal_bytes += walusage->wal_bytes; } + if (jitusage) + { + e->counters.jitinfo.jit_functions += jitusage->created_functions; + e->counters.jitinfo.jit_generation_time += INSTR_TIME_GET_MILLISEC(jitusage->generation_counter); + + if (INSTR_TIME_GET_MILLISEC(jitusage->inlining_counter)) + e->counters.jitinfo.jit_inlining_count++; + e->counters.jitinfo.jit_inlining_time += INSTR_TIME_GET_MILLISEC(jitusage->inlining_counter); + + if (INSTR_TIME_GET_MILLISEC(jitusage->optimization_counter)) + e->counters.jitinfo.jit_optimization_count++; + e->counters.jitinfo.jit_optimization_time += INSTR_TIME_GET_MILLISEC(jitusage->optimization_counter); + + if (INSTR_TIME_GET_MILLISEC(jitusage->emission_counter)) + e->counters.jitinfo.jit_emission_count++; + e->counters.jitinfo.jit_emission_time += INSTR_TIME_GET_MILLISEC(jitusage->emission_counter); + } SpinLockRelease(&e->mutex); } } @@ -1300,6 +1349,7 @@ pgss_store_error(uint64 queryid, NULL, /* bufusage */ NULL, /* walusage */ NULL, /* JumbleState */ + NULL, PGSS_ERROR); /* pgssStoreKind */ } @@ -1326,6 +1376,7 @@ pgss_store(uint64 queryid, uint64 rows, BufferUsage *bufusage, WalUsage *walusage, + const struct JitInstrumentation *jitusage, JumbleState *jstate, pgssStoreKind kind) { @@ -1540,6 +1591,7 @@ pgss_store(uint64 queryid, rows, /* rows */ bufusage, /* bufusage */ walusage, /* walusage */ + jitusage, reset, /* reset */ kind, /* kind */ app_name_ptr, @@ -1573,25 +1625,39 @@ pg_stat_monitor_reset(PG_FUNCTION_ARGS) PG_RETURN_VOID(); } +Datum +pg_stat_monitor_1_0(PG_FUNCTION_ARGS) +{ + pg_stat_monitor_internal(fcinfo, PGSM_V1_0, true); + return (Datum) 0; +} + +Datum +pg_stat_monitor_2_0(PG_FUNCTION_ARGS) +{ + pg_stat_monitor_internal(fcinfo, PGSM_V2_0, true); + return (Datum) 0; +} + +/* + * Legacy entry point for pg_stat_monitor() API versions 1.0 + */ Datum pg_stat_monitor(PG_FUNCTION_ARGS) { - pg_stat_monitor_internal(fcinfo, true); + pg_stat_monitor_internal(fcinfo, PGSM_V1_0, true); 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); + bucket_t = mktime(&pgss->bucket_start_time[bucketid]); time(¤t_t); diff_t = difftime(current_t, bucket_t); @@ -1600,9 +1666,10 @@ IsBucketValid(uint64 bucketid) return true; } -/* Common code for all versions of pg_stat_statements() */ +/* Common code for all versions of pg_stat_monitor() */ static void pg_stat_monitor_internal(FunctionCallInfo fcinfo, + pgsmVersion api_version, bool showtext) { ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; @@ -1617,6 +1684,7 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, HTAB *pgss_hash = pgsm_get_hash(); char *query_txt = (char *) palloc0(PGSM_QUERY_MAX_LEN + 1); char *parent_query_txt = (char *) palloc0(PGSM_QUERY_MAX_LEN + 1); + int expected_columns = (api_version >= PGSM_V2_0)?PG_STAT_MONITOR_COLS_V2_0:PG_STAT_MONITOR_COLS_V1_0; /* Safety check... */ if (!IsSystemInitialized()) @@ -1643,7 +1711,7 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "pg_stat_monitor: return type must be a row type"); - if (tupdesc->natts != 51) + if (tupdesc->natts != expected_columns) elog(ERROR, "pg_stat_monitor: incorrect number of output arguments, required %d", tupdesc->natts); tupstore = tuplestore_begin_heap(true, false, work_mem); @@ -1658,18 +1726,18 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, hash_seq_init(&hash_seq, pgss_hash); while ((entry = hash_seq_search(&hash_seq)) != NULL) { - Datum values[PG_STAT_STATEMENTS_COLS] = {0}; - bool nulls[PG_STAT_STATEMENTS_COLS] = {0}; + Datum values[PG_STAT_MONITOR_COLS] = {0}; + bool nulls[PG_STAT_MONITOR_COLS] = {0}; int i = 0; Counters tmp; double stddev; char queryid_text[32] = {0}; char planid_text[32] = {0}; uint64 queryid = entry->key.queryid; - uint64 bucketid = entry->key.bucket_id; + int64 bucketid = entry->key.bucket_id; uint64 dbid = entry->key.dbid; uint64 userid = entry->key.userid; - uint64 ip = entry->key.ip; + int64 ip = entry->key.ip; uint64 planid = entry->key.planid; #if PG_VERSION_NUM < 140000 bool toplevel = 1; @@ -1718,7 +1786,7 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, { if (read_query(pgss_qbuf, tmp.info.parentid, parent_query_txt, 0) == 0) { - int rc = read_query_buffer(bucketid, tmp.info.parentid, parent_query_txt, 0); + int rc = read_query_buffer(bucketid, tmp.info.parentid, parent_query_txt, 0); if (rc != 1) snprintf(parent_query_txt, 32, "%s", ""); @@ -1788,8 +1856,9 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, values[i++] = CStringGetTextDatum(""); } - /* state at column number 8 */ - values[i++] = Int64GetDatumFast(tmp.state); + /* state at column number 8 for V1.0 API*/ + if (api_version <= PGSM_V1_0) + values[i++] = Int64GetDatumFast(tmp.state); /* parentid at column number 9 */ if (tmp.info.parentid != UINT64CONST(0)) @@ -1843,7 +1912,7 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, if (tmp.info.cmd_type == CMD_NOTHING) nulls[i++] = true; else - values[i++] = Int64GetDatumFast(tmp.info.cmd_type); + values[i++] = Int64GetDatumFast((int64)tmp.info.cmd_type); /* elevel at column number 12 */ values[i++] = Int64GetDatumFast(tmp.error.elevel); @@ -1861,7 +1930,11 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, values[i++] = CStringGetTextDatum(tmp.error.message); /* bucket_start_time at column number 15 */ - values[i++] = CStringGetDatum(pgss->bucket_start_time[entry->key.bucket_id]); + { + TimestampTz tm; + tm2timestamp((struct pg_tm*) &pgss->bucket_start_time[entry->key.bucket_id], 0, NULL, &tm); + values[i++] = TimestampGetDatum(tm); + } if (tmp.calls.calls == 0) { /* Query of pg_stat_monitor itslef started from zero count */ @@ -1937,6 +2010,12 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, values[i++] = Float8GetDatumFast(tmp.blocks.blk_read_time); values[i++] = Float8GetDatumFast(tmp.blocks.blk_write_time); + if (api_version >= PGSM_V2_0) + { + values[i++] = Float8GetDatumFast(tmp.blocks.temp_blk_read_time); + values[i++] = Float8GetDatumFast(tmp.blocks.temp_blk_write_time); + } + /* resp_calls at column number 41 */ values[i++] = IntArrayGetTextDatum(tmp.resp_calls, PGSM_HISTOGRAM_BUCKETS); @@ -1970,8 +2049,24 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, values[i++] = CStringGetTextDatum(tmp.info.comments); else nulls[i++] = true; + + if (api_version >= PGSM_V2_0) + { + values[i++] = Int64GetDatumFast(tmp.jitinfo.jit_functions); + values[i++] = Float8GetDatumFast(tmp.jitinfo.jit_generation_time); + values[i++] = Int64GetDatumFast(tmp.jitinfo.jit_inlining_count); + values[i++] = Float8GetDatumFast(tmp.jitinfo.jit_inlining_time); + values[i++] = Int64GetDatumFast(tmp.jitinfo.jit_optimization_count); + values[i++] = Float8GetDatumFast(tmp.jitinfo.jit_optimization_time); + values[i++] = Int64GetDatumFast(tmp.jitinfo.jit_emission_count); + values[i++] = Float8GetDatumFast(tmp.jitinfo.jit_emission_time); + } + } values[i++] = BoolGetDatum(toplevel); + values[i++] = BoolGetDatum(pg_atomic_read_u64(&pgss->current_wbucket) != bucketid); + + /* clean up and return the tuplestore */ tuplestore_putvalues(tupstore, tupdesc, values, nulls); } /* clean up and return the tuplestore */ @@ -2055,13 +2150,16 @@ get_next_wbucket(pgssSharedState *pgss) tv.tv_sec = (tv.tv_sec) - (tv.tv_sec % PGSM_BUCKET_TIME); lt = localtime(&tv.tv_sec); + /* + * Year is 1900 behind and month is 0 based, therefore we need to + * adjust that. + */ + lt->tm_year += 1900; + lt->tm_mon += 1; /* Allign the value in prev_bucket_sec to the bucket start time */ pg_atomic_exchange_u64(&pgss->prev_bucket_sec, (uint64)tv.tv_sec); - - snprintf(pgss->bucket_start_time[new_bucket_id], sizeof(pgss->bucket_start_time[new_bucket_id]), - "%04d-%02d-%02d %02d:%02d:%02d", lt->tm_year + 1900, lt->tm_mon + 1, lt->tm_mday, lt->tm_hour, lt->tm_min, lt->tm_sec); - + memcpy(&pgss->bucket_start_time[new_bucket_id], lt, sizeof(struct tm)); return new_bucket_id; } @@ -3205,136 +3303,6 @@ SaveQueryText(uint64 bucketid, return true; } -Datum -pg_stat_monitor_settings(PG_FUNCTION_ARGS) -{ - ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - TupleDesc tupdesc; - Tuplestorestate *tupstore; - MemoryContext per_query_ctx; - MemoryContext oldcontext; - int i; - - /* Safety check... */ - if (!IsSystemInitialized()) - ereport(ERROR, - (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), - errmsg("pg_stat_monitor: must be loaded via shared_preload_libraries"))); - - /* check to see if caller supports us returning a tuplestore */ - if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("pg_stat_monitor: set-valued function called in context that cannot accept a set"))); - - /* Switch into long-lived context to construct returned data structures */ - per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; - oldcontext = MemoryContextSwitchTo(per_query_ctx); - - /* Build a tuple descriptor for our result type */ - if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) - { - elog(ERROR, "pg_stat_monitor_settings: return type must be a row type"); - return (Datum) 0; - } - - if (tupdesc->natts != 8) - { - elog(ERROR, "pg_stat_monitor_settings: incorrect number of output arguments, required: 7, found %d", tupdesc->natts); - return (Datum) 0; - } - - tupstore = tuplestore_begin_heap(true, false, work_mem); - rsinfo->returnMode = SFRM_Materialize; - rsinfo->setResult = tupstore; - rsinfo->setDesc = tupdesc; - - MemoryContextSwitchTo(oldcontext); - - for (i = 0; i < MAX_SETTINGS; i++) - { - Datum values[8]; - bool nulls[8]; - int j = 0; - char options[1024] = ""; - GucVariable *conf; - - memset(values, 0, sizeof(values)); - memset(nulls, 0, sizeof(nulls)); - - conf = get_conf(i); - - values[j++] = CStringGetTextDatum(conf->guc_name); - - /* Handle current and default values. */ - switch (conf->type) - { - case PGC_ENUM: - values[j++] = CStringGetTextDatum(conf->guc_options[conf->guc_variable]); - values[j++] = CStringGetTextDatum(conf->guc_options[conf->guc_default]); - break; - - case PGC_INT: - { - char value[32]; - - sprintf(value, "%d", conf->guc_variable); - values[j++] = CStringGetTextDatum(value); - - sprintf(value, "%d", conf->guc_default); - values[j++] = CStringGetTextDatum(value); - break; - } - - case PGC_BOOL: - values[j++] = CStringGetTextDatum(conf->guc_variable ? "yes" : "no"); - values[j++] = CStringGetTextDatum(conf->guc_default ? "yes" : "no"); - break; - - default: - Assert(false); - } - - values[j++] = CStringGetTextDatum(get_conf(i)->guc_desc); - - /* Minimum and maximum displayed only for integers or real numbers. */ - if (conf->type != PGC_INT) - { - nulls[j++] = true; - nulls[j++] = true; - } - else - { - values[j++] = Int64GetDatumFast(get_conf(i)->guc_min); - values[j++] = Int64GetDatumFast(get_conf(i)->guc_max); - } - - if (conf->type == PGC_ENUM) - { - size_t i; - - strcat(options, conf->guc_options[0]); - for (i = 1; i < conf->n_options; ++i) - { - strcat(options, ", "); - strcat(options, conf->guc_options[i]); - } - } - else if (conf->type == PGC_BOOL) - { - strcat(options, "yes, no"); - } - - values[j++] = CStringGetTextDatum(options); - values[j++] = CStringGetTextDatum(get_conf(i)->guc_restart ? "yes" : "no"); - tuplestore_putvalues(tupstore, tupdesc, values, nulls); - } - /* clean up and return the tuplestore */ - tuplestore_donestoring(tupstore); - return (Datum) 0; -} - - Datum pg_stat_monitor_hook_stats(PG_FUNCTION_ARGS) { diff --git a/pg_stat_monitor.h b/pg_stat_monitor.h index fd6c3cd..dd66c9d 100644 --- a/pg_stat_monitor.h +++ b/pg_stat_monitor.h @@ -31,6 +31,7 @@ #include "catalog/pg_authid.h" #include "executor/instrument.h" #include "common/ip.h" +#include "jit/jit.h" #include "funcapi.h" #include "access/twophase.h" #include "mb/pg_wchar.h" @@ -255,8 +256,27 @@ typedef struct Blocks int64 temp_blks_written; /* # of temp blocks written */ double blk_read_time; /* time spent reading, in msec */ double blk_write_time; /* time spent writing, in msec */ + + double temp_blk_read_time; /* time spent reading temp blocks, in msec */ + double temp_blk_write_time; /* time spent writing temp blocks, in + * msec */ } Blocks; +typedef struct JitInfo +{ + int64 jit_functions; /* total number of JIT functions emitted */ + double jit_generation_time; /* total time to generate jit code */ + int64 jit_inlining_count; /* number of times inlining time has been + * > 0 */ + double jit_inlining_time; /* total time to inline jit code */ + int64 jit_optimization_count; /* number of times optimization time + * has been > 0 */ + double jit_optimization_time; /* total time to optimize jit code */ + int64 jit_emission_count; /* number of times emission time has been + * > 0 */ + double jit_emission_time; /* total time to emit jit code */ +} JitInfo; + typedef struct SysInfo { float utime; /* user cpu time */ @@ -283,11 +303,12 @@ typedef struct Counters Blocks blocks; SysInfo sysinfo; + JitInfo jitinfo; ErrorInfo error; Wal_Usage walusage; int resp_calls[MAX_RESPONSE_BUCKET]; /* execution time's in * msec */ - uint64 state; /* query state */ + int64 state; /* query state */ } Counters; /* Some global structure to get the cpu usage, really don't like the idea of global variable */ @@ -317,11 +338,9 @@ typedef struct pgssSharedState pg_atomic_uint64 current_wbucket; pg_atomic_uint64 prev_bucket_sec; uint64 bucket_entry[MAX_BUCKETS]; - char bucket_start_time[MAX_BUCKETS][60]; /* start time of the - * bucket */ + struct tm bucket_start_time[MAX_BUCKETS]; /* start time of the bucket */ LWLock *errors_lock; /* protects errors hashtable * search/modification */ - /* * These variables are used when pgsm_overflow_target is ON. * diff --git a/regression/expected/error_1.out b/regression/expected/error_1.out index 389f7b6..3d74fd0 100644 --- a/regression/expected/error_1.out +++ b/regression/expected/error_1.out @@ -27,11 +27,15 @@ SELECT query, elevel, sqlcode, message FROM pg_stat_monitor ORDER BY query COLLA SELECT * FROM unknown; | 21 | 42P01 | relation "unknown" does not exist SELECT 1/0; | 21 | 22012 | division by zero SELECT pg_stat_monitor_reset() | 0 | | + do $$ +| 0 | | + BEGIN +| | | + RAISE WARNING 'warning message';+| | | + END $$ | | | do $$ +| 19 | 01000 | warning message BEGIN +| | | RAISE WARNING 'warning message';+| | | END $$; | | | -(5 rows) +(6 rows) SELECT pg_stat_monitor_reset(); pg_stat_monitor_reset diff --git a/regression/expected/error_insert_1.out b/regression/expected/error_insert_1.out index fc8cba7..e201a36 100644 --- a/regression/expected/error_insert_1.out +++ b/regression/expected/error_insert_1.out @@ -19,10 +19,11 @@ Drop Table if exists Company; SELECT query, elevel, sqlcode, message FROM pg_stat_monitor ORDER BY query COLLATE "C",elevel; query | elevel | sqlcode | message -------------------------------------------------------+--------+---------+--------------------------------------------------------------- + Drop Table if exists Company | 0 | | INSERT INTO Company(ID, Name) VALUES (1, 'Percona') | 0 | | INSERT INTO Company(ID, Name) VALUES (1, 'Percona'); | 21 | 23505 | duplicate key value violates unique constraint "company_pkey" SELECT pg_stat_monitor_reset() | 0 | | -(3 rows) +(4 rows) SELECT pg_stat_monitor_reset(); pg_stat_monitor_reset diff --git a/regression/expected/functions.out b/regression/expected/functions.out new file mode 100644 index 0000000..2a9c5c0 --- /dev/null +++ b/regression/expected/functions.out @@ -0,0 +1,40 @@ +CREATE USER su WITH SUPERUSER; +SET ROLE su; +CREATE EXTENSION pg_stat_monitor; +CREATE USER u1; +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + +SELECT routine_schema, routine_name, routine_type, data_type FROM information_schema.routines WHERE routine_schema = 'public' ORDER BY routine_name COLLATE "C"; + routine_schema | routine_name | routine_type | data_type +----------------+--------------------------+--------------+----------- + public | decode_error_level | FUNCTION | text + public | get_cmd_type | FUNCTION | text + public | get_histogram_timings | FUNCTION | text + public | histogram | FUNCTION | record + public | pg_stat_monitor_internal | FUNCTION | record + public | pg_stat_monitor_reset | FUNCTION | void + public | pg_stat_monitor_version | FUNCTION | text + public | pgsm_create_11_view | FUNCTION | integer + public | pgsm_create_13_view | FUNCTION | integer + public | pgsm_create_14_view | FUNCTION | integer + public | pgsm_create_15_view | FUNCTION | integer + public | pgsm_create_view | FUNCTION | integer + public | range | FUNCTION | ARRAY +(13 rows) + +SET ROLE u1; +SELECT routine_schema, routine_name, routine_type, data_type FROM information_schema.routines WHERE routine_schema = 'public' ORDER BY routine_name COLLATE "C"; + routine_schema | routine_name | routine_type | data_type +----------------+-------------------------+--------------+----------- + public | histogram | FUNCTION | record + public | pg_stat_monitor_reset | FUNCTION | void + public | pg_stat_monitor_version | FUNCTION | text +(3 rows) + +set role su; +DROP USER u1; +DROP EXTENSION pg_stat_monitor; diff --git a/regression/expected/guc.out b/regression/expected/guc.out index 3b07ada..c666b3e 100644 --- a/regression/expected/guc.out +++ b/regression/expected/guc.out @@ -36,4 +36,4 @@ SELECT pg_stat_monitor_reset(); (1 row) -DROP EXTENSION pg_stat_monitor; +DROP EXTENSION pg_stat_monitor; \ No newline at end of file diff --git a/regression/expected/top_query_1.out b/regression/expected/top_query_1.out index eb09470..9109771 100644 --- a/regression/expected/top_query_1.out +++ b/regression/expected/top_query_1.out @@ -24,12 +24,23 @@ SELECT add2(1,2); (1 row) SELECT query, top_query FROM pg_stat_monitor ORDER BY query COLLATE "C"; - query | top_query ---------------------------------+------------------ - (select $1 + $2) | SELECT add2(1,2) - SELECT add2(1,2) | - SELECT pg_stat_monitor_reset() | -(3 rows) + query | top_query +-------------------------------------------------------------+------------------ + (select $1 + $2) | SELECT add2(1,2) + CREATE OR REPLACE FUNCTION add(int, int) RETURNS INTEGER AS+| + $$ +| + BEGIN +| + return (select $1 + $2); +| + END; $$ language plpgsql | + CREATE OR REPLACE function add2(int, int) RETURNS int as +| + $$ +| + BEGIN +| + return add($1,$2); +| + END; +| + $$ language plpgsql | + SELECT add2(1,2) | + SELECT pg_stat_monitor_reset() | +(5 rows) SELECT pg_stat_monitor_reset(); pg_stat_monitor_reset diff --git a/regression/expected/version.out b/regression/expected/version.out index 1a494bf..4a3511b 100644 --- a/regression/expected/version.out +++ b/regression/expected/version.out @@ -2,7 +2,7 @@ CREATE EXTENSION pg_stat_monitor; SELECT pg_stat_monitor_version(); pg_stat_monitor_version ------------------------- - 1.1.1 + 2.0.0-dev (1 row) DROP EXTENSION pg_stat_monitor; diff --git a/regression/sql/functions.sql b/regression/sql/functions.sql new file mode 100644 index 0000000..27db119 --- /dev/null +++ b/regression/sql/functions.sql @@ -0,0 +1,15 @@ +CREATE USER su WITH SUPERUSER; +SET ROLE su; + +CREATE EXTENSION pg_stat_monitor; +CREATE USER u1; + +SELECT pg_stat_monitor_reset(); +SELECT routine_schema, routine_name, routine_type, data_type FROM information_schema.routines WHERE routine_schema = 'public' ORDER BY routine_name COLLATE "C"; + +SET ROLE u1; +SELECT routine_schema, routine_name, routine_type, data_type FROM information_schema.routines WHERE routine_schema = 'public' ORDER BY routine_name COLLATE "C"; + +set role su; +DROP USER u1; +DROP EXTENSION pg_stat_monitor; diff --git a/regression/sql/guc.sql b/regression/sql/guc.sql index ee22e5e..9743b34 100644 --- a/regression/sql/guc.sql +++ b/regression/sql/guc.sql @@ -1,6 +1,31 @@ CREATE EXTENSION pg_stat_monitor; -SELECT pg_stat_monitor_reset(); -select pg_sleep(.5); -SELECT * FROM pg_stat_monitor_settings WHERE name NOT LIKE 'pg_stat_monitor.pgsm_track_planning' ORDER BY name COLLATE "C"; -SELECT pg_stat_monitor_reset(); + +\x + +SELECT name + , setting + , unit + , category + , short_desc + , extra_desc + , context + , vartype + , source + , min_val + , max_val + , enumvals + , boot_val + , reset_val + , sourcefile + , sourceline + , pending_restart +FROM pg_settings +WHERE name LIKE 'pg_stat_monitor.%' + AND name NOT LIKE 'pg_stat_monitor.pgsm_track_planning' +ORDER +BY name +COLLATE "C"; + +\x + DROP EXTENSION pg_stat_monitor; diff --git a/t/018_column_names.pl b/t/018_column_names.pl new file mode 100644 index 0000000..8cb03a3 --- /dev/null +++ b/t/018_column_names.pl @@ -0,0 +1,104 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use File::Basename; +use File::Compare; +use File::Copy; +use String::Util qw(trim); +use Test::More; +use lib 't'; +use pgsm; + +# Get filename and create out file name and dirs where requried +PGSM::setup_files_dir(basename($0)); + +# Create new PostgreSQL node and do initdb +my $node = PGSM->pgsm_init_pg(); +my $pgdata = $node->data_dir; + +# Update postgresql.conf to include/load pg_stat_monitor library +open my $conf, '>>', "$pgdata/postgresql.conf"; +print $conf "shared_preload_libraries = 'pg_stat_monitor'\n"; +close $conf; + +# Dictionary for expected PGSM columns names on different PG server versions +my %pg_versions_pgsm_columns = ( 15 => "application_name,blk_read_time," . + "blk_write_time,bucket,bucket_done,bucket_start_time,calls," . + "client_ip,cmd_type,cmd_type_text,comments,cpu_sys_time,cpu_user_time," . + "datname,elevel,jit_emission_count,jit_emission_time,jit_functions," . + "jit_generation_time,jit_inlining_count,jit_inlining_time," . + "jit_optimization_count,jit_optimization_time," . + "local_blks_dirtied,local_blks_hit,local_blks_read," . + "local_blks_written,max_exec_time,max_plan_time,mean_exec_time," . + "mean_plan_time,message,min_exec_time,min_plan_time,planid," . + "plans_calls,query,query_plan,queryid,relations,resp_calls," . + "rows_retrieved,shared_blks_dirtied,shared_blks_hit,shared_blks_read," . + "shared_blks_written,sqlcode,stddev_exec_time,stddev_plan_time," . + "temp_blk_read_time,temp_blk_write_time,temp_blks_read,temp_blks_written," . + "top_query,top_queryid,toplevel,total_exec_time,total_plan_time," . + "userid,wal_bytes,wal_fpi,wal_records", + 14 => "application_name,blk_read_time," . + "blk_write_time,bucket,bucket_done,bucket_start_time,calls," . + "client_ip,cmd_type,cmd_type_text,comments,cpu_sys_time,cpu_user_time," . + "datname,elevel,local_blks_dirtied,local_blks_hit,local_blks_read," . + "local_blks_written,max_exec_time,max_plan_time,mean_exec_time," . + "mean_plan_time,message,min_exec_time,min_plan_time,planid," . + "plans_calls,query,query_plan,queryid,relations,resp_calls," . + "rows_retrieved,shared_blks_dirtied,shared_blks_hit,shared_blks_read," . + "shared_blks_written,sqlcode,stddev_exec_time,stddev_plan_time," . + "temp_blks_read,temp_blks_written,top_query,top_queryid,toplevel," . + "total_exec_time,total_plan_time,userid,wal_bytes,wal_fpi,wal_records", + 13 => "application_name,blk_read_time," . + "blk_write_time,bucket,bucket_done,bucket_start_time,calls," . + "client_ip,cmd_type,cmd_type_text,comments,cpu_sys_time,cpu_user_time," . + "datname,elevel,local_blks_dirtied,local_blks_hit,local_blks_read," . + "local_blks_written,max_exec_time,max_plan_time,mean_exec_time," . + "mean_plan_time,message,min_exec_time,min_plan_time,planid," . + "plans_calls,query,query_plan,queryid,relations,resp_calls," . + "rows_retrieved,shared_blks_dirtied,shared_blks_hit,shared_blks_read," . + "shared_blks_written,sqlcode,stddev_exec_time,stddev_plan_time," . + "temp_blks_read,temp_blks_written,top_query,top_queryid,toplevel," . + "total_exec_time,total_plan_time,userid,wal_bytes,wal_fpi,wal_records", + 12 => "application_name,blk_read_time,blk_write_time,bucket,bucket_done," . + "bucket_start_time,calls,client_ip,cmd_type,cmd_type_text,comments," . + "cpu_sys_time,cpu_user_time,datname,elevel,local_blks_dirtied," . + "local_blks_hit,local_blks_read,local_blks_written,max_time,mean_time," . + "message,min_time,planid,query,query_plan,queryid,relations,resp_calls," . + "rows_retrieved,shared_blks_dirtied,shared_blks_hit,shared_blks_read," . + "shared_blks_written,sqlcode,stddev_time,temp_blks_read,temp_blks_written," . + "top_query,top_queryid,total_time,userid" + ); + +# Start server +my $rt_value = $node->start; +ok($rt_value == 1, "Start Server"); + +# Create extension and change out file permissions +my ($cmdret, $stdout, $stderr) = $node->psql('postgres', 'CREATE EXTENSION pg_stat_monitor;', extra_params => ['-a']); +ok($cmdret == 0, "Create PGSM Extension"); +PGSM::append_to_file($stdout . "\n"); + +# Get PGSM columns names from PGSM installation in server +($cmdret, $stdout, $stderr) = $node->psql('postgres', "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = 'pg_stat_monitor' order by column_name;", extra_params => ['-A', '-R,', '-Ptuples_only=on']); +ok($cmdret == 0, "Get columns names in PGSM installation for PG version $PGSM::PG_MAJOR_VERSION"); +PGSM::append_to_file($stdout . "\n"); + +# Compare PGSM column names in installation to expected column names +ok($stdout eq $pg_versions_pgsm_columns{$PGSM::PG_MAJOR_VERSION}, "Compare supported columns names for PG version $PGSM::PG_MAJOR_VERSION against expected"); + +# Run Select statement against expected column names +($cmdret, $stdout, $stderr) = $node->psql('postgres', "Select $pg_versions_pgsm_columns{$PGSM::PG_MAJOR_VERSION} from pg_stat_monitor;", extra_params => ['-a', '-Pformat=aligned','-Ptuples_only=off']); +ok($cmdret == 0, "Select statement against expected column names"); +PGSM::append_to_file($stdout); + +# Drop extension +$stdout = $node->safe_psql('postgres', 'Drop extension pg_stat_monitor;', extra_params => ['-a']); +ok($cmdret == 0, "Drop PGSM Extension"); +PGSM::append_to_file($stdout); + +# Stop the server +$node->stop; + +# Done testing for this testcase file. +done_testing();