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 3b2e64b..eb19a9c 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, @@ -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; + } } @@ -1234,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; @@ -1612,6 +1630,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: @@ -1691,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); } @@ -1723,6 +1761,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 */