From e1d567b4198f7de2ea455308e3fe56399d00e804 Mon Sep 17 00:00:00 2001 From: kayform Date: Fri, 26 Apr 2024 10:52:10 +0900 Subject: [PATCH 1/5] Prevent abnormal termination due to plan text read failure when `pg_store_plans.plan_storage=file` and `pgsp_plan_texts.stat` is deleted. --- pg_store_plans.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pg_store_plans.c b/pg_store_plans.c index 3b2e64b..6d58e13 100644 --- a/pg_store_plans.c +++ b/pg_store_plans.c @@ -1612,6 +1612,9 @@ pg_store_plans_internal(FunctionCallInfo fcinfo, else pstr = SHMEM_PLAN_PTR(entry); + if (pstr == NULL) + continue; /* Ignore any entries with bogus texts */ + switch (plan_format) { case PLAN_FORMAT_TEXT: From 6b5d565ed0e4a86652de46c9ca2e2e6132b451fc Mon Sep 17 00:00:00 2001 From: experdb Date: Wed, 15 Jan 2025 13:06:12 +0900 Subject: [PATCH 2/5] modified default values log_timing from on to off, max: 1000 to 5000, min_duration 0 to 10 --- pg_store_plans.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pg_store_plans.c b/pg_store_plans.c index 6d58e13..5ff5bca 100644 --- a/pg_store_plans.c +++ b/pg_store_plans.c @@ -423,7 +423,7 @@ _PG_init(void) "Sets the maximum number of plans tracked by pg_store_plans.", NULL, &store_size, - 1000, + 5000, 100, INT_MAX, PGC_POSTMASTER, @@ -485,7 +485,7 @@ _PG_init(void) "Minimum duration to record plan in milliseconds.", NULL, &min_duration, - 0, + 10, 0, INT_MAX, PGC_SUSET, @@ -531,7 +531,7 @@ _PG_init(void) "Log timings.", NULL, &log_timing, - true, + false, PGC_SUSET, 0, NULL, From 1681c110ce72e45dc80ee55e842509c9ae980def Mon Sep 17 00:00:00 2001 From: "kayform@" Date: Fri, 14 Feb 2025 14:50:27 +0900 Subject: [PATCH 3/5] Fix suspected memory leak using by Coverity --- pg_store_plans.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/pg_store_plans.c b/pg_store_plans.c index 5ff5bca..4a416c1 100644 --- a/pg_store_plans.c +++ b/pg_store_plans.c @@ -752,6 +752,15 @@ pgsp_shmem_startup(void) pgver != PGSP_PG_MAJOR_VERSION) goto data_error; + /* check if num is out of range */ + if (num < 0 || num > store_size) + { + ereport(LOG, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("Invalid number of entries in file: %d", num))); + goto data_error; + } + for (i = 0; i < num; i++) { pgspEntry temp; @@ -944,6 +953,10 @@ pgsp_shmem_shutdown(int code, Datum arg) /* Unlink query-texts file; it's not needed while shutdown */ unlink(PGSP_TEXT_FILE); + if (pbuffer){ + free(pbuffer); // or free(pbuffer) + pbuffer = NULL; + } return; error: @@ -954,6 +967,10 @@ pgsp_shmem_shutdown(int code, Datum arg) if (file) FreeFile(file); unlink(PGSP_DUMP_FILE ".tmp"); + if (pbuffer){ + free(pbuffer); // or free(pbuffer) + pbuffer = NULL; + } } @@ -1726,6 +1743,11 @@ pg_store_plans_internal(FunctionCallInfo fcinfo, } LWLockRelease(shared_state->lock); + + if (pbuffer){ + free(pbuffer); // or free(pbuffer) + pbuffer = NULL; + } } /* Number of output arguments (columns) for pg_stat_statements_info */ From d3d1a6bae71d4b87b0b670a2834fa3cc00a704c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=ED=98=84=EC=88=98?= Date: Wed, 25 Jun 2025 11:29:31 +0900 Subject: [PATCH 4/5] Fix uninitialized memory usage --- pg_store_plans.c | 1 + 1 file changed, 1 insertion(+) diff --git a/pg_store_plans.c b/pg_store_plans.c index 4a416c1..d7e4065 100644 --- a/pg_store_plans.c +++ b/pg_store_plans.c @@ -1251,6 +1251,7 @@ pgsp_store(char *plan, queryid_t queryId, return; /* Set up key for hashtable search */ + memset(&key, 0, sizeof(key)); key.userid = GetUserId(); key.dbid = MyDatabaseId; key.queryid = queryId; From 3bc3ed9d0cf514fce982feac72c3ecb23a7d0d72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=B5=9C=ED=98=84=EC=88=98?= Date: Thu, 26 Jun 2025 11:23:24 +0900 Subject: [PATCH 5/5] =?UTF-8?q?PG=2017=20=EC=9D=B4=EC=A0=84=20=EB=B2=84?= =?UTF-8?q?=EC=A0=84=20=ED=98=B8=ED=99=98=EC=84=B1=20=ED=99=95=EB=B3=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 3 +- pg_store_plans--1.8--1.9.sql | 105 ++++++++++++++++++++++++++ pg_store_plans--1.9.sql | 139 ++++++++++++++++++++++++----------- pg_store_plans.c | 21 +++++- 4 files changed, 223 insertions(+), 45 deletions(-) create mode 100644 pg_store_plans--1.8--1.9.sql diff --git a/Makefile b/Makefile index dcdf17c..2efdb7c 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,8 @@ EXTENSION = pg_store_plans PG_VERSION := $(shell pg_config --version | sed "s/^PostgreSQL //" | sed "s/\.[0-9]*$$//") -DATA = pg_store_plans--1.9.sql +DATA = pg_store_plans--1.9.sql \ + pg_store_plans--1.8--1.9.sql REGRESS = convert store REGRESS_OPTS = --temp-config=regress.conf diff --git a/pg_store_plans--1.8--1.9.sql b/pg_store_plans--1.8--1.9.sql new file mode 100644 index 0000000..4ac802b --- /dev/null +++ b/pg_store_plans--1.8--1.9.sql @@ -0,0 +1,105 @@ +/* + * pg_store_plans/pg_store_plans--1.8--1.9.sql + * + * 업그레이드 스크립트: pg_store_plans 1.8 -> 1.9 + * + * - 기존 함수 및 뷰 삭제 + * - PostgreSQL 17 이상/미만 버전별 함수(분기 처리) 재생성 + * - 뷰 생성 및 권한 부여 + */ + +-- psql에서 직접 실행되는 것을 방지 (CREATE EXTENSION을 통해서만 실행) +\echo Use "CREATE EXTENSION pg_store_plans" to load this file. \quit + +-- 기존 뷰 및 함수 삭제 (업그레이드 전 정리) +DROP VIEW pg_store_plans; +DROP FUNCTION pg_store_plans(); + +-- PostgreSQL 버전에 따라 메인 함수 생성 (17 이상/미만 분기) +DO +$$ +BEGIN + IF (SELECT split_part(setting,'.',1) FROM pg_settings WHERE name = 'server_version')::int >= 17 THEN + -- PostgreSQL 17 이상: shared/local 블록 시간 컬럼 분리 + CREATE FUNCTION pg_store_plans( + OUT userid oid, + OUT dbid oid, + OUT queryid int8, + OUT planid int8, + OUT plan text, + OUT calls int8, + OUT total_time float8, + OUT min_time float8, + OUT max_time float8, + OUT mean_time float8, + OUT stddev_time float8, + OUT rows int8, + OUT shared_blks_hit int8, + OUT shared_blks_read int8, + OUT shared_blks_dirtied int8, + OUT shared_blks_written int8, + OUT local_blks_hit int8, + OUT local_blks_read int8, + OUT local_blks_dirtied int8, + OUT local_blks_written int8, + OUT temp_blks_read int8, + OUT temp_blks_written int8, + OUT shared_blk_read_time float8, + OUT shared_blk_write_time float8, + OUT local_blk_read_time float8, + OUT local_blk_write_time float8, + OUT temp_blk_read_time float8, + OUT temp_blk_write_time float8, + OUT first_call timestamptz, + OUT last_call timestamptz + ) + RETURNS SETOF record + AS 'MODULE_PATHNAME', 'pg_store_plans_1_9' + LANGUAGE C + VOLATILE PARALLEL SAFE; + ELSE + -- PostgreSQL 17 미만: blk_read_time, blk_write_time 사용 + CREATE FUNCTION pg_store_plans( + OUT userid oid, + OUT dbid oid, + OUT queryid int8, + OUT planid int8, + OUT plan text, + OUT calls int8, + OUT total_time float8, + OUT min_time float8, + OUT max_time float8, + OUT mean_time float8, + OUT stddev_time float8, + OUT rows int8, + OUT shared_blks_hit int8, + OUT shared_blks_read int8, + OUT shared_blks_dirtied int8, + OUT shared_blks_written int8, + OUT local_blks_hit int8, + OUT local_blks_read int8, + OUT local_blks_dirtied int8, + OUT local_blks_written int8, + OUT temp_blks_read int8, + 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 first_call timestamptz, + OUT last_call timestamptz + ) + RETURNS SETOF record + AS 'MODULE_PATHNAME', 'pg_store_plans_1_7' + LANGUAGE C + VOLATILE PARALLEL SAFE; + END IF; +END +$$ LANGUAGE plpgsql; + +-- 메인 함수에 대한 뷰 생성 (사용 편의성 제공) +CREATE VIEW pg_store_plans AS + SELECT * FROM pg_store_plans(); + +-- 모든 사용자에게 SELECT 권한 부여 +GRANT SELECT ON pg_store_plans TO PUBLIC; diff --git a/pg_store_plans--1.9.sql b/pg_store_plans--1.9.sql index 9f2bec3..77971dd 100644 --- a/pg_store_plans--1.9.sql +++ b/pg_store_plans--1.9.sql @@ -1,9 +1,17 @@ -/* pg_store_plans/pg_store_plans--1.9.sql */ +/* + * pg_store_plans/pg_store_plans--1.9.sql + * + * 확장 설치용 SQL 스크립트 (버전 1.9) + * + * - 주요 함수 및 뷰 생성 + * - PostgreSQL 17 이상/미만 버전별 함수(분기 처리) 생성 + * - 권한 부여 + */ --- complain if script is sourced in psql, rather than via CREATE EXTENSION +-- psql에서 직접 실행되는 것을 방지 (CREATE EXTENSION을 통해서만 실행) \echo Use "CREATE EXTENSION pg_store_plans" to load this file. \quit ---- Define pg_store_plans_info +--- pg_store_plans_info 함수 및 뷰 정의 (통계 정보 제공) CREATE FUNCTION pg_store_plans_info( OUT dealloc bigint, OUT stats_reset timestamp with time zone @@ -17,7 +25,7 @@ CREATE VIEW pg_store_plans_info AS GRANT SELECT ON pg_store_plans_info TO PUBLIC; --- Register functions. +-- 주요 기능 함수 등록 (플랜 리셋, 쿼리 축약, 정규화, 다양한 포맷 변환 등) CREATE FUNCTION pg_store_plans_reset() RETURNS void AS 'MODULE_PATHNAME' @@ -57,48 +65,95 @@ RETURNS oid AS 'MODULE_PATHNAME' LANGUAGE C RETURNS NULL ON NULL INPUT PARALLEL SAFE; -CREATE FUNCTION pg_store_plans( - OUT userid oid, - OUT dbid oid, - OUT queryid int8, - OUT planid int8, - OUT plan text, - OUT calls int8, - OUT total_time float8, - OUT min_time float8, - OUT max_time float8, - OUT mean_time float8, - OUT stddev_time float8, - OUT rows int8, - OUT shared_blks_hit int8, - OUT shared_blks_read int8, - OUT shared_blks_dirtied int8, - OUT shared_blks_written int8, - OUT local_blks_hit int8, - OUT local_blks_read int8, - OUT local_blks_dirtied int8, - OUT local_blks_written int8, - OUT temp_blks_read int8, - OUT temp_blks_written int8, - OUT shared_blk_read_time float8, - OUT shared_blk_write_time float8, - OUT local_blk_read_time float8, - OUT local_blk_write_time float8, - OUT temp_blk_read_time float8, - OUT temp_blk_write_time float8, - OUT first_call timestamptz, - OUT last_call timestamptz -) -RETURNS SETOF record -AS 'MODULE_PATHNAME', 'pg_store_plans_1_9' -LANGUAGE C -VOLATILE PARALLEL SAFE; --- Register a view on the function for ease of use. +-- PostgreSQL 버전에 따라 메인 함수 생성 (17 이상/미만 분기) +DO +$$ +BEGIN + IF (SELECT split_part(setting,'.',1) FROM pg_settings WHERE name = 'server_version')::int >= 17 THEN + -- PostgreSQL 17 이상: shared/local 블록 시간 컬럼 분리 + CREATE FUNCTION pg_store_plans( + OUT userid oid, + OUT dbid oid, + OUT queryid int8, + OUT planid int8, + OUT plan text, + OUT calls int8, + OUT total_time float8, + OUT min_time float8, + OUT max_time float8, + OUT mean_time float8, + OUT stddev_time float8, + OUT rows int8, + OUT shared_blks_hit int8, + OUT shared_blks_read int8, + OUT shared_blks_dirtied int8, + OUT shared_blks_written int8, + OUT local_blks_hit int8, + OUT local_blks_read int8, + OUT local_blks_dirtied int8, + OUT local_blks_written int8, + OUT temp_blks_read int8, + OUT temp_blks_written int8, + OUT shared_blk_read_time float8, + OUT shared_blk_write_time float8, + OUT local_blk_read_time float8, + OUT local_blk_write_time float8, + OUT temp_blk_read_time float8, + OUT temp_blk_write_time float8, + OUT first_call timestamptz, + OUT last_call timestamptz + ) + RETURNS SETOF record + AS 'MODULE_PATHNAME', 'pg_store_plans_1_9' + LANGUAGE C + VOLATILE PARALLEL SAFE; + ELSE + -- PostgreSQL 17 미만: blk_read_time, blk_write_time 사용 + CREATE FUNCTION pg_store_plans( + OUT userid oid, + OUT dbid oid, + OUT queryid int8, + OUT planid int8, + OUT plan text, + OUT calls int8, + OUT total_time float8, + OUT min_time float8, + OUT max_time float8, + OUT mean_time float8, + OUT stddev_time float8, + OUT rows int8, + OUT shared_blks_hit int8, + OUT shared_blks_read int8, + OUT shared_blks_dirtied int8, + OUT shared_blks_written int8, + OUT local_blks_hit int8, + OUT local_blks_read int8, + OUT local_blks_dirtied int8, + OUT local_blks_written int8, + OUT temp_blks_read int8, + 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 first_call timestamptz, + OUT last_call timestamptz + ) + RETURNS SETOF record + AS 'MODULE_PATHNAME', 'pg_store_plans_1_7' + LANGUAGE C + VOLATILE PARALLEL SAFE; + END IF; +END +$$ LANGUAGE plpgsql; + +-- 메인 함수에 대한 뷰 생성 (사용 편의성 제공) CREATE VIEW pg_store_plans AS SELECT * FROM pg_store_plans(); +-- 모든 사용자에게 SELECT 권한 부여 GRANT SELECT ON pg_store_plans TO PUBLIC; --- Don't want this to be available to non-superusers. +-- superuser가 아닌 사용자에게는 리셋 함수 권한 제한 REVOKE ALL ON FUNCTION pg_store_plans_reset() FROM PUBLIC; diff --git a/pg_store_plans.c b/pg_store_plans.c index d7e4065..eb19a9c 100644 --- a/pg_store_plans.c +++ b/pg_store_plans.c @@ -1712,21 +1712,38 @@ pg_store_plans_internal(FunctionCallInfo fcinfo, values[i++] = Int64GetDatumFast(tmp.local_blks_written); values[i++] = Int64GetDatumFast(tmp.temp_blks_read); values[i++] = Int64GetDatumFast(tmp.temp_blks_written); - values[i++] = Float8GetDatumFast(tmp.shared_blk_read_time); - values[i++] = Float8GetDatumFast(tmp.shared_blk_write_time); if (api_version >= PGSP_V1_9) { #if PG_VERSION_NUM >= 170000 + values[i++] = Float8GetDatumFast(tmp.shared_blk_read_time); + values[i++] = Float8GetDatumFast(tmp.shared_blk_write_time); values[i++] = Float8GetDatumFast(tmp.local_blk_read_time); values[i++] = Float8GetDatumFast(tmp.local_blk_write_time); #else values[i++] = Float8GetDatumFast(0.0); values[i++] = Float8GetDatumFast(0.0); + values[i++] = Float8GetDatumFast(0.0); + values[i++] = Float8GetDatumFast(0.0); #endif } if (api_version >= PGSP_V1_7) { +#if PG_VERSION_NUM >= 170000 + if (api_version < PGSP_V1_9) + { + values[i++] = Float8GetDatumFast(tmp.shared_blk_read_time+ + tmp.local_blk_read_time); + values[i++] = Float8GetDatumFast(tmp.shared_blk_write_time+ + tmp.local_blk_write_time); + } +#else + if (api_version < PGSP_V1_9) + { + values[i++] = Float8GetDatumFast(tmp.blk_read_time); + values[i++] = Float8GetDatumFast(tmp.blk_write_time); + } +#endif values[i++] = Float8GetDatumFast(tmp.temp_blk_read_time); values[i++] = Float8GetDatumFast(tmp.temp_blk_write_time); }