diff --git a/guc.c b/guc.c index 9b1cbcb..66120a9 100644 --- a/guc.c +++ b/guc.c @@ -22,6 +22,7 @@ GucVariable conf[MAX_SETTINGS]; static void DefineIntGUC(GucVariable *conf); static void DefineIntGUCWithCheck(GucVariable *conf, GucIntCheckHook check); static void DefineBoolGUC(GucVariable *conf); +static void DefineEnumGUC(GucVariable *conf, const struct config_enum_entry *options); /* Check hooks to ensure histogram_min < histogram_max */ static bool check_histogram_min(int *newval, void **extra, GucSource source); @@ -34,6 +35,7 @@ void init_guc(void) { int i = 0; + conf[i] = (GucVariable) { .guc_name = "pg_stat_monitor.pgsm_max", .guc_desc = "Sets the maximum size of shared memory in (MB) used for statement's metadata tracked by pg_stat_monitor.", @@ -58,18 +60,6 @@ init_guc(void) }; DefineIntGUC(&conf[i++]); - conf[i] = (GucVariable) { - .guc_name = "pg_stat_monitor.pgsm_enable", - .guc_desc = "Enable/Disable statistics collector.", - .guc_default = 1, - .guc_min = 0, - .guc_max = 0, - .guc_restart = false, - .guc_unit = 0, - .guc_value = &PGSM_ENABLED - }; - DefineBoolGUC(&conf[i++]); - conf[i] = (GucVariable) { .guc_name = "pg_stat_monitor.pgsm_track_utility", .guc_desc = "Selects whether utility commands are tracked.", @@ -190,12 +180,39 @@ init_guc(void) }; DefineBoolGUC(&conf[i++]); + conf[i] = (GucVariable) { + .guc_name = "pg_stat_monitor.pgsm_track", + .guc_desc = "Selects which statements are tracked by pg_stat_monitor.", + .n_options = 3, + .guc_default = PGSM_TRACK_ALL, + .guc_min = PSGM_TRACK_NONE, + .guc_max = PGSM_TRACK_ALL, + .guc_restart = false, + .guc_unit = 0, + .guc_value = &PGSM_TRACK + }; + for (int j = 0; j < conf[i].n_options; ++j) { + strlcpy(conf[i].guc_options[j], track_options[j].name, sizeof(conf[i].guc_options[j])); + } + DefineEnumGUC(&conf[i++], track_options); + + conf[i] = (GucVariable) { + .guc_name = "pg_stat_monitor.pgsm_extract_comments", + .guc_desc = "Enable/Disable extracting comments from queries.", + .guc_default = 0, + .guc_min = 0, + .guc_max = 0, + .guc_restart = false, + .guc_unit = 0, + .guc_value = &PGSM_EXTRACT_COMMENTS + }; + DefineBoolGUC(&conf[i++]); #if PG_VERSION_NUM >= 130000 conf[i] = (GucVariable) { .guc_name = "pg_stat_monitor.pgsm_track_planning", .guc_desc = "Selects whether planning statistics are tracked.", - .guc_default = 1, + .guc_default = 0, .guc_min = 0, .guc_max = 0, .guc_restart = false, @@ -208,6 +225,7 @@ init_guc(void) static void DefineIntGUCWithCheck(GucVariable *conf, GucIntCheckHook check) { + conf->type = PGC_INT; DefineCustomIntVariable(conf->guc_name, conf->guc_desc, NULL, @@ -231,6 +249,7 @@ DefineIntGUC(GucVariable *conf) static void DefineBoolGUC(GucVariable *conf) { + conf->type = PGC_BOOL; DefineCustomBoolVariable(conf->guc_name, conf->guc_desc, NULL, @@ -243,10 +262,27 @@ DefineBoolGUC(GucVariable *conf) NULL); } +static void +DefineEnumGUC(GucVariable *conf, const struct config_enum_entry *options) +{ + conf->type = PGC_ENUM; + DefineCustomEnumVariable(conf->guc_name, + conf->guc_desc, + NULL, + conf->guc_value, + conf->guc_default, + options, + conf->guc_restart ? PGC_POSTMASTER : PGC_USERSET, + 0, + NULL, + NULL, + NULL); +} + GucVariable* get_conf(int i) { - return &conf[i]; + return &conf[i]; } static bool check_histogram_min(int *newval, void **extra, GucSource source) diff --git a/pg_stat_monitor--1.0.13.sql.in b/pg_stat_monitor--1.0.13.sql.in index 4147536..5de6083 100644 --- a/pg_stat_monitor--1.0.13.sql.in +++ b/pg_stat_monitor--1.0.13.sql.in @@ -119,12 +119,13 @@ LANGUAGE SQL PARALLEL SAFE; CREATE FUNCTION pg_stat_monitor_settings( OUT name text, - OUT value INTEGER, - OUT default_value INTEGER, + OUT value text, + OUT default_value text, OUT description text, OUT minimum INTEGER, OUT maximum INTEGER, - OUT restart INTEGER + OUT options text, + OUT restart text ) RETURNS SETOF record AS 'MODULE_PATHNAME', 'pg_stat_monitor_settings' @@ -137,6 +138,7 @@ CREATE VIEW pg_stat_monitor_settings AS SELECT description, minimum, maximum, + options, restart FROM pg_stat_monitor_settings(); @@ -261,4 +263,4 @@ GRANT SELECT ON pg_stat_monitor TO PUBLIC; GRANT SELECT ON pg_stat_monitor_settings TO PUBLIC; -- Don't want this to be available to non-superusers. -REVOKE ALL ON FUNCTION pg_stat_monitor_reset() FROM PUBLIC; \ No newline at end of file +REVOKE ALL ON FUNCTION pg_stat_monitor_reset() FROM PUBLIC; diff --git a/pg_stat_monitor--1.0.14.sql.in b/pg_stat_monitor--1.0.14.sql.in index f2bd4c8..0bbb0ce 100644 --- a/pg_stat_monitor--1.0.14.sql.in +++ b/pg_stat_monitor--1.0.14.sql.in @@ -119,12 +119,13 @@ LANGUAGE SQL PARALLEL SAFE; CREATE FUNCTION pg_stat_monitor_settings( OUT name text, - OUT value INTEGER, - OUT default_value INTEGER, + OUT value text, + OUT default_value text, OUT description text, OUT minimum INTEGER, OUT maximum INTEGER, - OUT restart INTEGER + OUT options text, + OUT restart text ) RETURNS SETOF record AS 'MODULE_PATHNAME', 'pg_stat_monitor_settings' @@ -137,6 +138,7 @@ CREATE VIEW pg_stat_monitor_settings AS SELECT description, minimum, maximum, + options, restart FROM pg_stat_monitor_settings(); @@ -262,4 +264,4 @@ GRANT SELECT ON pg_stat_monitor TO PUBLIC; GRANT SELECT ON pg_stat_monitor_settings TO PUBLIC; -- Don't want this to be available to non-superusers. -REVOKE ALL ON FUNCTION pg_stat_monitor_reset() FROM PUBLIC; \ No newline at end of file +REVOKE ALL ON FUNCTION pg_stat_monitor_reset() FROM PUBLIC; diff --git a/pg_stat_monitor--1.0.sql.in b/pg_stat_monitor--1.0.sql.in index fd2495d..fda49f7 100644 --- a/pg_stat_monitor--1.0.sql.in +++ b/pg_stat_monitor--1.0.sql.in @@ -116,12 +116,13 @@ LANGUAGE SQL PARALLEL SAFE; CREATE FUNCTION pg_stat_monitor_settings( OUT name text, - OUT value INTEGER, - OUT default_value INTEGER, + OUT value text, + OUT default_value text, OUT description text, OUT minimum INTEGER, OUT maximum INTEGER, - OUT restart INTEGER + OUT options text, + OUT restart text ) RETURNS SETOF record AS 'MODULE_PATHNAME', 'pg_stat_monitor_settings' @@ -134,6 +135,7 @@ CREATE VIEW pg_stat_monitor_settings AS SELECT description, minimum, maximum, + options, restart FROM pg_stat_monitor_settings(); diff --git a/pg_stat_monitor.c b/pg_stat_monitor.c index 9b204b8..9a14a46 100644 --- a/pg_stat_monitor.c +++ b/pg_stat_monitor.c @@ -38,6 +38,11 @@ PG_MODULE_MAGIC; #define _snprintf(_str_dst, _str_src, _len, _max_len)\ memcpy((void *)_str_dst, _str_src, _len < _max_len ? _len : _max_len) +#define pgsm_enabled(level) \ + (!IsParallelWorker() && \ + (PGSM_TRACK == PGSM_TRACK_ALL || \ + (PGSM_TRACK == PGSM_TRACK_TOP && (level) == 0))) + #define _snprintf2(_str_dst, _str_src, _len1, _len2)\ do \ { \ @@ -53,7 +58,7 @@ void _PG_fini(void); /*---- Local variables ----*/ /* Current nesting depth of ExecutorRun+ProcessUtility calls */ -static int nested_level = 0; +static int exec_nested_level = 0; #if PG_VERSION_NUM >= 130000 static int plan_nested_level = 0; #endif @@ -359,7 +364,7 @@ pgss_post_parse_analyze(ParseState *pstate, Query *query, JumbleState *jstate) if (!IsSystemInitialized()) return; - if (IsParallelWorker()) + if (!pgsm_enabled(exec_nested_level)) return; /* @@ -423,8 +428,7 @@ pgss_post_parse_analyze(ParseState *pstate, Query *query) /* Safety check... */ if (!IsSystemInitialized()) return; - - if (IsParallelWorker()) + if (!pgsm_enabled(exec_nested_level)) return; /* @@ -492,15 +496,13 @@ pgss_ExecutorStart(QueryDesc *queryDesc, int eflags) else standard_ExecutorStart(queryDesc, eflags); - if (IsParallelWorker()) - return; - /* * If query has queryId zero, don't track it. This prevents double * counting of optimizable statements that are directly contained in * utility statements. */ - if (PGSM_ENABLED && queryDesc->plannedstmt->queryId != UINT64CONST(0)) + if (pgsm_enabled(exec_nested_level) && + queryDesc->plannedstmt->queryId != UINT64CONST(0)) { /* * Set up to track total elapsed time in ExecutorRun. Make sure the @@ -555,24 +557,24 @@ static void pgss_ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count, bool execute_once) { - if (nested_level >=0 && nested_level < max_stack_depth) - nested_queryids[nested_level] = queryDesc->plannedstmt->queryId; - nested_level++; + if (exec_nested_level >=0 && exec_nested_level < max_stack_depth) + nested_queryids[exec_nested_level] = queryDesc->plannedstmt->queryId; + exec_nested_level++; PG_TRY(); { if (prev_ExecutorRun) prev_ExecutorRun(queryDesc, direction, count, execute_once); else standard_ExecutorRun(queryDesc, direction, count, execute_once); - nested_level--; - if (nested_level >=0 && nested_level < max_stack_depth) - nested_queryids[nested_level] = UINT64CONST(0); + exec_nested_level--; + if (exec_nested_level >=0 && exec_nested_level < max_stack_depth) + nested_queryids[exec_nested_level] = UINT64CONST(0); } PG_CATCH(); { - nested_level--; - if (nested_level >=0 && nested_level < max_stack_depth) - nested_queryids[nested_level] = UINT64CONST(0); + exec_nested_level--; + if (exec_nested_level >=0 && exec_nested_level < max_stack_depth) + nested_queryids[exec_nested_level] = UINT64CONST(0); PG_RE_THROW(); } PG_END_TRY(); @@ -595,18 +597,18 @@ pgss_ExecutorFinish_benchmark(QueryDesc *queryDesc) static void pgss_ExecutorFinish(QueryDesc *queryDesc) { - nested_level++; + exec_nested_level++; PG_TRY(); { if (prev_ExecutorFinish) prev_ExecutorFinish(queryDesc); else standard_ExecutorFinish(queryDesc); - nested_level--; + exec_nested_level--; } PG_CATCH(); { - nested_level--; + exec_nested_level--; PG_RE_THROW(); } PG_END_TRY(); @@ -664,7 +666,7 @@ pgss_ExecutorEnd(QueryDesc *queryDesc) MemoryContextSwitchTo(mct); } - if (queryId != UINT64CONST(0) && queryDesc->totaltime && !IsParallelWorker()) + if (queryId != UINT64CONST(0) && queryDesc->totaltime && pgsm_enabled(exec_nested_level)) { /* * Make sure stats accumulation is done. (Note: it's okay if several @@ -781,7 +783,20 @@ pgss_planner_hook(Query *parse, const char *query_string, int cursorOptions, Par { PlannedStmt *result; - if (PGSM_TRACK_PLANNING && query_string && parse->queryId != UINT64CONST(0) && !IsParallelWorker()) + /* + * We can't process the query if no query_string is provided, as + * pgss_store needs it. We also ignore query without queryid, as it would + * be treated as a utility statement, which may not be the case. + * + * Note that planner_hook can be called from the planner itself, so we + * have a specific nesting level for the planner. However, utility + * commands containing optimizable statements can also call the planner, + * same for regular DML (for instance for underlying foreign key queries). + * So testing the planner nesting level only is not enough to detect real + * top level planner call. + */ + if (pgsm_enabled(plan_nested_level + exec_nested_level) && + PGSM_TRACK_PLANNING && query_string && parse->queryId != UINT64CONST(0)) { instr_time start; instr_time duration; @@ -949,7 +964,7 @@ static void pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString, * since we are already measuring the statement's costs at the utility * level. */ - if (PGSM_TRACK_UTILITY && !IsParallelWorker()) + if (PGSM_TRACK_UTILITY && pgsm_enabled(exec_nested_level)) pstmt->queryId = UINT64CONST(0); #endif @@ -967,8 +982,8 @@ static void pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString, * * Likewise, we don't track execution of DEALLOCATE. */ - if (PGSM_TRACK_UTILITY && PGSM_HANDLED_UTILITY(parsetree) && - !IsParallelWorker()) + if (PGSM_TRACK_UTILITY && pgsm_enabled(exec_nested_level) && + PGSM_HANDLED_UTILITY(parsetree)) { instr_time start; instr_time duration; @@ -980,7 +995,7 @@ static void pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString, WalUsage walusage_start = pgWalUsage; #endif INSTR_TIME_SET_CURRENT(start); - nested_level++; + exec_nested_level++; PG_TRY(); { #if PG_VERSION_NUM >= 140000 @@ -1019,11 +1034,11 @@ static void pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString, dest, completionTag); #endif - nested_level--; + exec_nested_level--; } PG_CATCH(); { - nested_level--; + exec_nested_level--; PG_RE_THROW(); } @@ -1312,10 +1327,10 @@ pgss_update_entry(pgssEntry *entry, e->counters.info.cmd_type = cmd_type; - if(nested_level > 0) + if(exec_nested_level > 0) { - if (nested_level >=0 && nested_level < max_stack_depth) - e->counters.info.parentid = nested_queryids[nested_level - 1]; + if (exec_nested_level >=0 && exec_nested_level < max_stack_depth) + e->counters.info.parentid = nested_queryids[exec_nested_level - 1]; } else { @@ -1432,10 +1447,6 @@ pgss_store(uint64 queryid, bool found_client_addr = false; uint client_addr = 0; - /* Monitoring is disabled */ - if (!PGSM_ENABLED) - return; - /* Safety check... */ if (!IsSystemInitialized()) return; @@ -1514,7 +1525,7 @@ pgss_store(uint64 queryid, #if PG_VERSION_NUM < 140000 key.toplevel = 1; #else - key.toplevel = ((nested_level + plan_nested_level) == 0); + key.toplevel = ((exec_nested_level + plan_nested_level) == 0); #endif pgss_hash = pgsm_get_hash(); @@ -3274,69 +3285,133 @@ 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; + 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"))); + /* 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"))); + /* 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); + /* 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: return type must be a row type"); + /* 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 != 7) - elog(ERROR, "pg_stat_monitor: incorrect number of output arguments, required %d", tupdesc->natts); + 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; + tupstore = tuplestore_begin_heap(true, false, work_mem); + rsinfo->returnMode = SFRM_Materialize; + rsinfo->setResult = tupstore; + rsinfo->setDesc = tupdesc; - MemoryContextSwitchTo(oldcontext); + MemoryContextSwitchTo(oldcontext); - for(i = 0; i < MAX_SETTINGS; i++) - { - Datum values[7]; - bool nulls[7]; - int j = 0; - memset(values, 0, sizeof(values)); - memset(nulls, 0, sizeof(nulls)); + for(i = 0; i < MAX_SETTINGS; i++) + { + Datum values[8]; + bool nulls[8]; + int j = 0; + char options[1024] = ""; + GucVariable *conf; - values[j++] = CStringGetTextDatum(get_conf(i)->guc_name); - values[j++] = Int64GetDatumFast(get_conf(i)->guc_variable); - values[j++] = Int64GetDatumFast(get_conf(i)->guc_default); - values[j++] = CStringGetTextDatum(get_conf(i)->guc_desc); - values[j++] = Int64GetDatumFast(get_conf(i)->guc_min); - values[j++] = Int64GetDatumFast(get_conf(i)->guc_max); - values[j++] = Int64GetDatumFast(get_conf(i)->guc_restart); - tuplestore_putvalues(tupstore, tupdesc, values, nulls); - } - /* clean up and return the tuplestore */ - tuplestore_donestoring(tupstore); - return (Datum)0; + 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) + { + strcat(options, conf->guc_options[0]); + for (size_t 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 0d96fe7..eeb9210 100644 --- a/pg_stat_monitor.h +++ b/pg_stat_monitor.h @@ -52,6 +52,7 @@ #include "utils/timestamp.h" #include "utils/lsyscache.h" #include "utils/guc.h" +#include "utils/guc_tables.h" #define MAX_BACKEND_PROCESES (MaxBackends + NUM_AUXILIARY_PROCS + max_prepared_xacts) #define IntArrayGetTextDatum(x,y) intarray_get_datum(x,y) @@ -94,24 +95,30 @@ #define SQLCODE_LEN 20 #if PG_VERSION_NUM >= 130000 -#define MAX_SETTINGS 14 +#define MAX_SETTINGS 15 #else -#define MAX_SETTINGS 13 +#define MAX_SETTINGS 14 #endif +/* Update this if need a enum GUC with more options. */ +#define MAX_ENUM_OPTIONS 6 typedef struct GucVariables { - int guc_variable; - char guc_name[TEXT_LEN]; - char guc_desc[TEXT_LEN]; - int guc_default; - int guc_min; - int guc_max; - int guc_unit; - int *guc_value; - bool guc_restart; + enum config_type type; /* PGC_BOOL, PGC_INT, PGC_REAL, PGC_STRING, PGC_ENUM */ + int guc_variable; + char guc_name[TEXT_LEN]; + char guc_desc[TEXT_LEN]; + int guc_default; + int guc_min; + int guc_max; + int guc_unit; + int *guc_value; + bool guc_restart; + int n_options; + char guc_options[MAX_ENUM_OPTIONS][32]; } GucVariable; + #if PG_VERSION_NUM < 130000 typedef struct WalUsage { @@ -408,20 +415,35 @@ void set_qbuf(unsigned char *); /* hash_query.c */ void pgss_startup(void); /*---- GUC variables ----*/ +typedef enum { + PSGM_TRACK_NONE = 0, /* track no statements */ + PGSM_TRACK_TOP, /* only top level statements */ + PGSM_TRACK_ALL /* all statements, including nested ones */ +} PGSMTrackLevel; +static const struct config_enum_entry track_options[] = +{ + {"none", PSGM_TRACK_NONE, false}, + {"top", PGSM_TRACK_TOP, false}, + {"all", PGSM_TRACK_ALL, false}, + {NULL, 0, false} +}; + #define PGSM_MAX get_conf(0)->guc_variable #define PGSM_QUERY_MAX_LEN get_conf(1)->guc_variable -#define PGSM_ENABLED get_conf(2)->guc_variable -#define PGSM_TRACK_UTILITY get_conf(3)->guc_variable -#define PGSM_NORMALIZED_QUERY get_conf(4)->guc_variable -#define PGSM_MAX_BUCKETS get_conf(5)->guc_variable -#define PGSM_BUCKET_TIME get_conf(6)->guc_variable -#define PGSM_HISTOGRAM_MIN get_conf(7)->guc_variable -#define PGSM_HISTOGRAM_MAX get_conf(8)->guc_variable -#define PGSM_HISTOGRAM_BUCKETS get_conf(9)->guc_variable -#define PGSM_QUERY_SHARED_BUFFER get_conf(10)->guc_variable -#define PGSM_OVERFLOW_TARGET get_conf(11)->guc_variable -#define PGSM_QUERY_PLAN get_conf(12)->guc_variable -#define PGSM_TRACK_PLANNING get_conf(13)->guc_variable +#define PGSM_TRACK_UTILITY get_conf(2)->guc_variable +#define PGSM_NORMALIZED_QUERY get_conf(3)->guc_variable +#define PGSM_MAX_BUCKETS get_conf(4)->guc_variable +#define PGSM_BUCKET_TIME get_conf(5)->guc_variable +#define PGSM_HISTOGRAM_MIN get_conf(6)->guc_variable +#define PGSM_HISTOGRAM_MAX get_conf(7)->guc_variable +#define PGSM_HISTOGRAM_BUCKETS get_conf(8)->guc_variable +#define PGSM_QUERY_SHARED_BUFFER get_conf(9)->guc_variable +#define PGSM_OVERFLOW_TARGET get_conf(10)->guc_variable +#define PGSM_QUERY_PLAN get_conf(11)->guc_variable +#define PGSM_TRACK get_conf(12)->guc_variable +#define PGSM_EXTRACT_COMMENTS get_conf(13)->guc_variable +#define PGSM_TRACK_PLANNING get_conf(14)->guc_variable + /*---- Benchmarking ----*/ #ifdef BENCHMARK diff --git a/regression/expected/guc.out b/regression/expected/guc.out index 0da2986..12b65a5 100644 --- a/regression/expected/guc.out +++ b/regression/expected/guc.out @@ -12,22 +12,22 @@ select pg_sleep(.5); (1 row) SELECT * FROM pg_stat_monitor_settings ORDER BY name COLLATE "C"; - name | value | default_value | description | minimum | maximum | restart -------------------------------------------+--------+---------------+----------------------------------------------------------------------------------------------------------+---------+------------+--------- - pg_stat_monitor.pgsm_bucket_time | 60 | 60 | Sets the time in seconds per bucket. | 1 | 2147483647 | 1 - pg_stat_monitor.pgsm_enable | 1 | 1 | Enable/Disable statistics collector. | 0 | 0 | 0 - pg_stat_monitor.pgsm_enable_query_plan | 0 | 0 | Enable/Disable query plan monitoring | 0 | 0 | 0 - pg_stat_monitor.pgsm_histogram_buckets | 10 | 10 | Sets the maximum number of histogram buckets | 2 | 2147483647 | 1 - pg_stat_monitor.pgsm_histogram_max | 100000 | 100000 | Sets the time in millisecond. | 10 | 2147483647 | 1 - pg_stat_monitor.pgsm_histogram_min | 0 | 0 | Sets the time in millisecond. | 0 | 2147483647 | 1 - 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_max_buckets | 10 | 10 | Sets the maximum number of buckets. | 1 | 10 | 1 - pg_stat_monitor.pgsm_normalized_query | 1 | 1 | Selects whether save query in normalized format. | 0 | 0 | 0 - pg_stat_monitor.pgsm_overflow_target | 1 | 1 | Sets the overflow target for pg_stat_monitor | 0 | 1 | 1 - pg_stat_monitor.pgsm_query_max_len | 1024 | 1024 | Sets the maximum length of query. | 1024 | 2147483647 | 1 - pg_stat_monitor.pgsm_query_shared_buffer | 20 | 20 | Sets the maximum size of shared memory in (MB) used for query tracked by pg_stat_monitor. | 1 | 10000 | 1 - pg_stat_monitor.pgsm_track_planning | 1 | 1 | Selects whether planning statistics are tracked. | 0 | 0 | 0 - pg_stat_monitor.pgsm_track_utility | 1 | 1 | Selects whether utility commands are tracked. | 0 | 0 | 0 + name | value | default_value | description | minimum | maximum | options | restart +------------------------------------------+--------+---------------+----------------------------------------------------------------------------------------------------------+---------+------------+----------------+--------- + pg_stat_monitor.pgsm_bucket_time | 60 | 60 | Sets the time in seconds per bucket. | 1 | 2147483647 | | yes + pg_stat_monitor.pgsm_enable_query_plan | no | no | Enable/Disable query plan monitoring | | | yes, no | no + pg_stat_monitor.pgsm_extract_comments | no | no | Enable/Disable extracting comments from queries. | | | yes, no | no + pg_stat_monitor.pgsm_histogram_buckets | 10 | 10 | Sets the maximum number of histogram buckets | 2 | 2147483647 | | yes + pg_stat_monitor.pgsm_histogram_max | 100000 | 100000 | Sets the time in millisecond. | 10 | 2147483647 | | yes + pg_stat_monitor.pgsm_histogram_min | 0 | 0 | Sets the time in millisecond. | 0 | 2147483647 | | yes + 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 | | yes + pg_stat_monitor.pgsm_max_buckets | 10 | 10 | Sets the maximum number of buckets. | 1 | 10 | | yes + pg_stat_monitor.pgsm_normalized_query | yes | yes | Selects whether save query in normalized format. | | | yes, no | no + pg_stat_monitor.pgsm_overflow_target | 1 | 1 | Sets the overflow target for pg_stat_monitor | 0 | 1 | | yes + pg_stat_monitor.pgsm_query_max_len | 1024 | 1024 | Sets the maximum length of query. | 1024 | 2147483647 | | yes + pg_stat_monitor.pgsm_query_shared_buffer | 20 | 20 | Sets the maximum size of shared memory in (MB) used for query tracked by pg_stat_monitor. | 1 | 10000 | | yes + pg_stat_monitor.pgsm_track | all | all | Selects which statements are tracked by pg_stat_monitor. | | | none, top, all | no + pg_stat_monitor.pgsm_track_utility | yes | yes | Selects whether utility commands are tracked. | | | yes, no | no (14 rows) SELECT pg_stat_monitor_reset(); diff --git a/regression/expected/guc_1.out b/regression/expected/guc_1.out index ef3da0b..0628c7e 100644 --- a/regression/expected/guc_1.out +++ b/regression/expected/guc_1.out @@ -12,22 +12,24 @@ select pg_sleep(.5); (1 row) SELECT * FROM pg_stat_monitor_settings ORDER BY name COLLATE "C"; - name | value | default_value | description | minimum | maximum | restart -------------------------------------------+--------+---------------+----------------------------------------------------------------------------------------------------------+---------+------------+--------- - pg_stat_monitor.pgsm_bucket_time | 60 | 60 | Sets the time in seconds per bucket. | 1 | 2147483647 | 1 - pg_stat_monitor.pgsm_enable | 1 | 1 | Enable/Disable statistics collector. | 0 | 0 | 0 - pg_stat_monitor.pgsm_enable_query_plan | 0 | 0 | Enable/Disable query plan monitoring | 0 | 0 | 0 - pg_stat_monitor.pgsm_histogram_buckets | 10 | 10 | Sets the maximum number of histogram buckets | 2 | 2147483647 | 1 - pg_stat_monitor.pgsm_histogram_max | 100000 | 100000 | Sets the time in millisecond. | 10 | 2147483647 | 1 - pg_stat_monitor.pgsm_histogram_min | 0 | 0 | Sets the time in millisecond. | 0 | 2147483647 | 1 - 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_max_buckets | 10 | 10 | Sets the maximum number of buckets. | 1 | 10 | 1 - pg_stat_monitor.pgsm_normalized_query | 1 | 1 | Selects whether save query in normalized format. | 0 | 0 | 0 - pg_stat_monitor.pgsm_overflow_target | 1 | 1 | Sets the overflow target for pg_stat_monitor | 0 | 1 | 1 - pg_stat_monitor.pgsm_query_max_len | 1024 | 1024 | Sets the maximum length of query. | 1024 | 2147483647 | 1 - pg_stat_monitor.pgsm_query_shared_buffer | 20 | 20 | Sets the maximum size of shared memory in (MB) used for query tracked by pg_stat_monitor. | 1 | 10000 | 1 - pg_stat_monitor.pgsm_track_utility | 1 | 1 | Selects whether utility commands are tracked. | 0 | 0 | 0 -(13 rows) + name | value | default_value | description | minimum | maximum | options | restart +------------------------------------------+--------+---------------+----------------------------------------------------------------------------------------------------------+---------+------------+----------------+--------- + pg_stat_monitor.pgsm_bucket_time | 60 | 60 | Sets the time in seconds per bucket. | 1 | 2147483647 | | yes + pg_stat_monitor.pgsm_enable_query_plan | no | no | Enable/Disable query plan monitoring | | | yes, no | no + pg_stat_monitor.pgsm_extract_comments | no | no | Enable/Disable extracting comments from queries. | | | yes, no | no + pg_stat_monitor.pgsm_histogram_buckets | 10 | 10 | Sets the maximum number of histogram buckets | 2 | 2147483647 | | yes + pg_stat_monitor.pgsm_histogram_max | 100000 | 100000 | Sets the time in millisecond. | 10 | 2147483647 | | yes + pg_stat_monitor.pgsm_histogram_min | 0 | 0 | Sets the time in millisecond. | 0 | 2147483647 | | yes + 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 | | yes + pg_stat_monitor.pgsm_max_buckets | 10 | 10 | Sets the maximum number of buckets. | 1 | 10 | | yes + pg_stat_monitor.pgsm_normalized_query | yes | yes | Selects whether save query in normalized format. | | | yes, no | no + pg_stat_monitor.pgsm_overflow_target | 1 | 1 | Sets the overflow target for pg_stat_monitor | 0 | 1 | | yes + pg_stat_monitor.pgsm_query_max_len | 1024 | 1024 | Sets the maximum length of query. | 1024 | 2147483647 | | yes + pg_stat_monitor.pgsm_query_shared_buffer | 20 | 20 | Sets the maximum size of shared memory in (MB) used for query tracked by pg_stat_monitor. | 1 | 10000 | | yes + pg_stat_monitor.pgsm_track | all | all | Selects which statements are tracked by pg_stat_monitor. | | | none, top, all | no + pg_stat_monitor.pgsm_track_planning | no | no | Selects whether planning statistics are tracked. | | | yes, no | no + pg_stat_monitor.pgsm_track_utility | yes | yes | Selects whether utility commands are tracked. | | | yes, no | no +(15 rows) SELECT pg_stat_monitor_reset(); pg_stat_monitor_reset diff --git a/regression/expected/histogram.out b/regression/expected/histogram.out index b469b72..ad1450d 100644 --- a/regression/expected/histogram.out +++ b/regression/expected/histogram.out @@ -55,8 +55,8 @@ SELECT substr(query, 0,50) as query, calls, resp_calls FROM pg_stat_monitor ORDE (5 rows) select * from generate_histogram(); - range | freq | bar ---------------------+------+-------------------------------------------------------------------------------------------- + range | freq | bar +--------------------+------+-------------------------------- (0 - 3)} | 0 | (3 - 10)} | 0 | (10 - 31)} | 0 | diff --git a/regression/expected/histogram_1.out b/regression/expected/histogram_1.out index f926990..e458a6c 100644 --- a/regression/expected/histogram_1.out +++ b/regression/expected/histogram_1.out @@ -45,13 +45,14 @@ INFO: Sleep 5 seconds (1 row) SELECT substr(query, 0,50) as query, calls, resp_calls FROM pg_stat_monitor ORDER BY query COLLATE "C"; - query | calls | resp_calls ----------------------------------+-------+----------------------- - SELECT pg_sleep(i) | 5 | {0,0,0,0,0,0,3,2,0,0} - SELECT pg_stat_monitor_reset() | 1 | {1,0,0,0,0,0,0,0,0,0} - Set pg_stat_monitor.track='all' | 1 | {1,0,0,0,0,0,0,0,0,0} - select run_pg_sleep($1) | 1 | {0,0,0,0,0,0,0,0,1,0} -(4 rows) + query | calls | resp_calls +---------------------------------------------------+-------+----------------------- + SELECT pg_sleep(i) | 5 | {0,0,0,0,0,0,2,3,0,0} + SELECT pg_stat_monitor_reset() | 1 | {1,0,0,0,0,0,0,0,0,0} + SELECT substr(query, $1,$2) as query, calls, resp | 1 | {1,0,0,0,0,0,0,0,0,0} + Set pg_stat_monitor.track='all' | 1 | {1,0,0,0,0,0,0,0,0,0} + select run_pg_sleep($1) | 1 | {0,0,0,0,0,0,0,0,1,0} +(5 rows) select * from generate_histogram(); range | freq | bar @@ -62,8 +63,8 @@ select * from generate_histogram(); (31 - 100)} | 0 | (100 - 316)} | 0 | (316 - 1000)} | 0 | - (1000 - 3162)} | 3 | ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ - (3162 - 10000)} | 2 | ■■■■■■■■■■■■■■■■■■■■ + (1000 - 3162)} | 2 | ■■■■■■■■■■■■■■■■■■■■ + (3162 - 10000)} | 3 | ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ (10000 - 31622)} | 0 | (31622 - 100000)} | 0 | (10 rows)