From 066162c3f60c442698e4e303faaaf18959e34095 Mon Sep 17 00:00:00 2001 From: Ibrar Ahmed Date: Fri, 12 Mar 2021 18:55:12 +0000 Subject: [PATCH] PG-186: Add support to monitor query execution plan. This requires refactoring of code to add this functionality. Along with that this patch contains regression test cases. --- Makefile | 2 +- docs/USER_GUIDE.md | 50 + guc.c | 13 + hash_query.c | 35 +- pg_stat_monitor--1.0.sql | 51 +- pg_stat_monitor.c | 1146 ++- pg_stat_monitor.h | 65 +- regression/expected/application_name.out | 28 + regression/expected/basic.out | 19 +- regression/expected/cmd_type.out | 45 + regression/expected/counters.out | 93 + regression/expected/database.out | 54 + regression/expected/error.out | 44 + regression/expected/guc.out | 4 +- regression/expected/histogram.out | 0 regression/expected/pg_stat_monitor.out | 436 - regression/expected/relations.out | 181 +- regression/expected/rows.out | 8560 +++++++++++++++++ regression/expected/top_query.out | 52 + regression/expected/user.out | 53 + .../{test_version.out => version.out} | 2 +- regression/sql/application_name.sql | 6 + regression/sql/basic.sql | 2 +- regression/sql/cmd_type.sql | 15 + regression/sql/counters.sql | 35 + regression/sql/database.sql | 37 + regression/sql/error.sql | 14 + regression/sql/histogram.sql | 28 + regression/sql/pg_stat_monitor.sql | 198 - regression/sql/relations.sql | 70 +- regression/sql/rows.sql | 19 + regression/sql/top_query.sql | 19 + regression/sql/user.sql | 31 + .../sql/{test_version.sql => version.sql} | 0 34 files changed, 10234 insertions(+), 1173 deletions(-) create mode 100644 regression/expected/application_name.out create mode 100644 regression/expected/cmd_type.out create mode 100644 regression/expected/counters.out create mode 100644 regression/expected/database.out create mode 100644 regression/expected/error.out create mode 100644 regression/expected/histogram.out delete mode 100644 regression/expected/pg_stat_monitor.out create mode 100644 regression/expected/rows.out create mode 100644 regression/expected/top_query.out create mode 100644 regression/expected/user.out rename regression/expected/{test_version.out => version.out} (95%) create mode 100644 regression/sql/application_name.sql create mode 100644 regression/sql/cmd_type.sql create mode 100644 regression/sql/counters.sql create mode 100644 regression/sql/database.sql create mode 100644 regression/sql/error.sql create mode 100644 regression/sql/histogram.sql delete mode 100644 regression/sql/pg_stat_monitor.sql create mode 100644 regression/sql/rows.sql create mode 100644 regression/sql/top_query.sql create mode 100644 regression/sql/user.sql rename regression/sql/{test_version.sql => version.sql} (100%) diff --git a/Makefile b/Makefile index 68eaffe..c2b66a2 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ PGFILEDESC = "pg_stat_monitor - execution statistics of SQL statements" LDFLAGS_SL += $(filter -lm, $(LIBS)) REGRESS_OPTS = --temp-config $(top_srcdir)/contrib/pg_stat_monitor/pg_stat_monitor.conf --inputdir=regression -REGRESS = guc relations basic pg_stat_monitor test_version +REGRESS = basic version guc user counters relations database top_query application_name cmd_type error rows # 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/docs/USER_GUIDE.md b/docs/USER_GUIDE.md index 71255df..fcf5cd4 100644 --- a/docs/USER_GUIDE.md +++ b/docs/USER_GUIDE.md @@ -400,3 +400,53 @@ postgres=# SELECT queryid, top_queryid, query, top_query FROM pg_stat_monitor; 762B99349F6C7F31 | 3408CA84B2353094 | SELECT (select $1 + $2) | select add2($1,$2) (3 rows) ``` + +#### Monitor Query Execution Plan. + +```sql +postgres=# SELECT substr(query,0,50), query_plan from pg_stat_monitor limit 10; + substr | query_plan +---------------------------------------------------+--------------------------------------------------------------------------------------------------------------- + select o.n, p.partstrat, pg_catalog.count(i.inhpa | Limit + + | -> GroupAggregate + + | Group Key: (array_position(current_schemas(true), n.nspname)), p.partstrat + + | -> Sort + + | Sort Key: (array_position(current_schemas(true), n.nspname)), p.partstrat + + | -> Nested Loop Left Join + + | -> Nested Loop Left Join + + | -> Nested Loop + + | Join Filter: (c.relnamespace = n.oid) + + | -> Index Scan using pg_class_relname_nsp_index on pg_class c + + | Index Cond: (relname = 'pgbench_accounts'::name) + + | -> Seq Scan on pg_namespace n + + | Filter: (array_position(current_schemas(true), nspname) IS NOT NULL) + + | -> Index Scan using pg_partitioned_table_partrelid_index on pg_partitioned_table p+ + | Index Cond: (partrelid = c.oid) + + | -> Bitmap Heap Scan on pg_inherits i + + | R + SELECT abalance FROM pgbench_accounts WHERE aid = | Index Scan using pgbench_accounts_pkey on pgbench_accounts + + | Index Cond: (aid = 102232) + BEGIN; | + END; | + SELECT substr(query,$1,$2), query_plan from pg_st | + SELECT substr(query,$1,$2),calls, planid,query_pl | Limit + + | -> Subquery Scan on pg_stat_monitor + + | -> Result + + | -> Sort + + | Sort Key: p.bucket_start_time + + | -> Hash Join + + | Hash Cond: (p.dbid = d.oid) + + | -> Function Scan on pg_stat_monitor_internal p + + | -> Hash + + | -> Seq Scan on pg_database d + + | SubPlan 1 + + | -> Function Scan on pg_stat_monitor_internal s + + | Filter: (queryid = p.top_queryid) + select count(*) from pgbench_branches | Aggregate + + | -> Seq Scan on pgbench_branches + UPDATE pgbench_tellers SET tbalance = tbalance + | + vacuum pgbench_tellers | + UPDATE pgbench_accounts SET abalance = abalance + | +(10 rows) + +``` diff --git a/guc.c b/guc.c index 58b6e17..5d16b33 100644 --- a/guc.c +++ b/guc.c @@ -173,6 +173,19 @@ init_guc(void) }; DefineIntGUC(&conf[i++]); + conf[i] = (GucVariable) { + .guc_name = "pg_stat_monitor.pgsm_enable_query_plan", + .guc_desc = "Enable/Disable query plan monitoring", + .guc_default = 0, + .guc_min = 0, + .guc_max = 0, + .guc_restart = false, + .guc_unit = 0, + .guc_value = &PGSM_QUERY_PLAN + }; + DefineBoolGUC(&conf[i++]); + + #if PG_VERSION_NUM >= 130000 conf[i] = (GucVariable) { .guc_name = "pg_stat_monitor.pgsm_track_planning", diff --git a/hash_query.c b/hash_query.c index 3c36fa0..44a9dbb 100644 --- a/hash_query.c +++ b/hash_query.c @@ -21,8 +21,7 @@ static pgssSharedState *pgss; static HTAB *pgss_hash; static HTAB *pgss_query_hash; - - +static HTAB *pgss_plan_hash; static HTAB* hash_init(const char *hash_name, int key_size, int entry_size, int hash_size); @@ -73,6 +72,7 @@ pgss_startup(void) pgss_hash = hash_init("pg_stat_monitor: bucket hashtable", sizeof(pgssHashKey), sizeof(pgssEntry), MAX_BUCKET_ENTRIES); pgss_query_hash = hash_init("pg_stat_monitor: query hashtable", sizeof(pgssQueryHashKey), sizeof(pgssQueryEntry),500000); + pgss_plan_hash = hash_init("pg_stat_monitor: plan hashtable", sizeof(pgssPlanHashKey), sizeof(pgssPlanEntry), MAX_BUCKET_ENTRIES); LWLockRelease(AddinShmemInitLock); @@ -83,6 +83,12 @@ pgss_startup(void) on_shmem_exit(pgss_shmem_shutdown, (Datum) 0); } +HTAB* +pgsm_get_plan_hash(void) +{ + return pgss_plan_hash; +} + pgssSharedState* pgsm_get_ss(void) { @@ -122,11 +128,32 @@ hash_memsize(void) size = MAXALIGN(sizeof(pgssSharedState)); size += MAXALIGN(MAX_QUERY_BUF); size = add_size(size, hash_estimate_size(MAX_BUCKET_ENTRIES, sizeof(pgssEntry))); + size = add_size(size, hash_estimate_size(MAX_BUCKET_ENTRIES, sizeof(pgssPlanEntry))); size = add_size(size, hash_estimate_size(500000, sizeof(pgssQueryEntry))); return size; } +pgssPlanEntry * +hash_plan_entry_alloc(pgssSharedState *pgss, pgssPlanHashKey *key) +{ + pgssPlanEntry *entry = NULL; + bool found = false; + + if (hash_get_num_entries(pgss_plan_hash) >= MAX_BUCKET_ENTRIES) + return NULL; + + /* Find or create an entry with desired hash code */ + entry = (pgssPlanEntry *) hash_search(pgss_plan_hash, key, HASH_ENTER, &found); + if (!found) + { + memset(&entry->plan_info, 0, sizeof(PlanInfo)); + SpinLockInit(&entry->mutex); + } + if (entry == NULL) + elog(FATAL, "%s", "pg_stat_monitor: out of memory"); + return entry; +} pgssEntry * hash_entry_alloc(pgssSharedState *pgss, pgssHashKey *key,int encoding) @@ -135,8 +162,10 @@ hash_entry_alloc(pgssSharedState *pgss, pgssHashKey *key,int encoding) bool found = false; if (hash_get_num_entries(pgss_hash) >= MAX_BUCKET_ENTRIES) + { + elog(DEBUG2, "%s", "pg_stat_monitor: out of memory"); return NULL; - + } /* Find or create an entry with desired hash code */ entry = (pgssEntry *) hash_search(pgss_hash, key, HASH_ENTER, &found); if (!found) diff --git a/pg_stat_monitor--1.0.sql b/pg_stat_monitor--1.0.sql index 4ea6fc0..666639c 100644 --- a/pg_stat_monitor--1.0.sql +++ b/pg_stat_monitor--1.0.sql @@ -24,32 +24,27 @@ RETURNS text[] AS $$ SELECT string_to_array(get_histogram_timings(), ','); $$ LANGUAGE SQL; -CREATE FUNCTION pg_stat_monitor(IN showtext boolean, - OUT bucket int, +CREATE FUNCTION pg_stat_monitor_internal(IN showtext boolean, + OUT bucket int, -- 0 OUT userid oid, OUT dbid oid, OUT client_ip int8, - OUT queryid text, - OUT top_queryid text, + OUT queryid text, -- 4 + OUT planid text, + OUT top_queryid text, OUT query text, + OUT query_plan text, OUT application_name text, - OUT relations text, + + OUT relations text, -- 10 OUT cmd_type int, OUT elevel int, OUT sqlcode TEXT, OUT message text, OUT bucket_start_time text, - OUT plans int8, - OUT plan_total_time float8, - OUT plan_min_time float8, - OUT plan_max_time float8, - OUT plan_mean_time float8, - OUT plan_stddev_time float8, - OUT plan_rows int8, - - OUT calls int8, + OUT calls int8, -- 16 OUT total_time float8, OUT min_time float8, OUT max_time float8, @@ -57,7 +52,13 @@ CREATE FUNCTION pg_stat_monitor(IN showtext boolean, OUT stddev_time float8, OUT rows int8, - OUT shared_blks_hit int8, + OUT plans_calls int8, -- 23 + OUT plan_total_time float8, + OUT plan_min_time float8, + OUT plan_max_time float8, + OUT plan_mean_time float8, + + OUT shared_blks_hit int8, -- 28 OUT shared_blks_read int8, OUT shared_blks_dirtied int8, OUT shared_blks_written int8, @@ -128,7 +129,9 @@ CREATE VIEW pg_stat_monitor AS SELECT queryid, top_queryid, query, - (SELECT query from pg_stat_monitor(true) s where s.queryid = p.top_queryid) AS top_query, + planid, + query_plan, + (SELECT query from pg_stat_monitor_internal(true) s where s.queryid = p.top_queryid) AS top_query, application_name, string_to_array(relations, ',') AS relations, cmd_type, @@ -136,12 +139,6 @@ CREATE VIEW pg_stat_monitor AS SELECT elevel, sqlcode, message, - plans, - round( CAST(plan_total_time as numeric), 4)::float8 as plan_total_time, - round( CAST(plan_min_time as numeric), 4)::float8 as plan_min_time, - round( CAST(plan_max_time as numeric), 4)::float8 as plan_max_time, - round( CAST(plan_mean_time as numeric), 4)::float8 as plan_mean_time, - round( CAST(plan_stddev_time as numeric), 4)::float8 as plan_stddev_time, calls, round( CAST(total_time as numeric), 4)::float8 as total_time, round( CAST(min_time as numeric), 4)::float8 as min_time, @@ -149,7 +146,13 @@ CREATE VIEW pg_stat_monitor AS SELECT round( CAST(mean_time as numeric), 4)::float8 as mean_time, round( CAST(stddev_time as numeric), 4)::float8 as stddev_time, rows, - shared_blks_hit, + plans_calls, + round( CAST(plan_total_time as numeric), 4)::float8 as plan_total_time, + round( CAST(plan_min_time as numeric), 4)::float8 as plan_min_time, + round( CAST(plan_max_time as numeric), 4)::float8 as plan_max_time, + round( CAST(plan_mean_time as numeric), 4)::float8 as plan_mean_time, + + shared_blks_hit, shared_blks_read, shared_blks_dirtied, shared_blks_written, @@ -167,7 +170,7 @@ CREATE VIEW pg_stat_monitor AS SELECT wal_records, wal_fpi, wal_bytes -FROM pg_stat_monitor(TRUE) p, pg_database d WHERE dbid = oid +FROM pg_stat_monitor_internal(TRUE) p, pg_database d WHERE dbid = oid ORDER BY bucket_start_time; CREATE FUNCTION decode_error_level(elevel int) diff --git a/pg_stat_monitor.c b/pg_stat_monitor.c index f57581f..8fd5083 100644 --- a/pg_stat_monitor.c +++ b/pg_stat_monitor.c @@ -16,13 +16,13 @@ *------------------------------------------------------------------------- */ #include "postgres.h" - +#include "commands/explain.h" #include "pg_stat_monitor.h" PG_MODULE_MAGIC; -#define BUILD_VERSION "0.7.0" -#define PG_STAT_STATEMENTS_COLS 47 /* maximum of above */ +#define BUILD_VERSION "devel" +#define PG_STAT_STATEMENTS_COLS 49 /* maximum of above */ #define PGSM_TEXT_FILE "/tmp/pg_stat_monitor_query" #define PGUNSIXBIT(val) (((val) & 0x3F) + '0') @@ -62,26 +62,28 @@ void _PG_fini(void); /* Current nesting depth of ExecutorRun+ProcessUtility calls */ static int nested_level = 0; +static int plan_nested_level = 0; /* The array to store outer layer query id*/ uint64 *nested_queryids; -#if PG_VERSION_NUM >= 130000 -static int plan_nested_level = 0; -static int exec_nested_level = 0; -#endif - FILE *qfile; static bool system_init = false; static struct rusage rusage_start; static struct rusage rusage_end; static unsigned char *pgss_qbuf[MAX_BUCKETS]; +static char *pgss_explain(QueryDesc *queryDesc); +static bool pgss_get_plan(uint64 query_hash, PlanInfo *plan_info); +static bool pgss_store_plan(uint64 query_hash, PlanInfo *plan_info); + static int get_histogram_bucket(double q_time); static bool IsSystemInitialized(void); static void dump_queries_buffer(int bucket_id, unsigned char *buf, int buf_len); static double time_diff(struct timeval end, struct timeval start); +static PlannedStmt * pgss_planner_hook(Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams); + /* Saved hook values in case of unload */ static planner_hook_type planner_hook_next = NULL; static post_parse_analyze_hook_type prev_post_parse_analyze_hook = NULL; @@ -108,9 +110,7 @@ static int pg_get_application_name(char* application_name); static PgBackendStatus *pg_get_backend_status(void); static Datum intarray_get_datum(int32 arr[], int len); -#if PG_VERSION_NUM >= 130000 -static PlannedStmt * pgss_planner_hook(Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams); -#else +#if PG_VERSION_NUM < 130000 static void BufferUsageAccumDiff(BufferUsage* bufusage, BufferUsage* pgBufferUsage, BufferUsage* bufusage_start); static PlannedStmt *pgss_planner_hook(Query *parse, int opt, ParamListInfo param); #endif @@ -140,22 +140,27 @@ static void pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString, static uint64 pgss_hash_string(const char *str, int len); char *unpack_sql_state(int sql_state); -static void pgss_store(uint64 queryId, - const char *query, - CmdType cmd_type, - uint64 elevel, - char *sqlerrcode, - const char *message, - int query_location, - int query_len, - pgssStoreKind kind, - double total_time, uint64 rows, - const BufferUsage *bufusage, -#if PG_VERSION_NUM >= 130000 - const WalUsage *walusage, -#endif - pgssJumbleState *jstate, - float utime, float stime); +static void pgss_store_error(uint64 queryid, const char * query, ErrorData *edata); +static void pgss_store_query(uint64 queryid, const char * query, CmdType cmd_type, int query_location, int query_len, pgssJumbleState *jstate); + +static void pgss_store_utility(const char *query, + double total_time, + uint64 rows, + BufferUsage *bufusage, + WalUsage *walusage); + +static void pgss_store(uint64 queryid, + const char *query, + PlanInfo *plan_info, + CmdType cmd_type, + SysInfo *sys_info, + ErrorInfo *error_info, + double total_time, + uint64 rows, + BufferUsage *bufusage, + WalUsage *walusage, + pgssJumbleState *jstate, + pgssStoreKind kind); static void pg_stat_monitor_internal(FunctionCallInfo fcinfo, bool showtext); @@ -239,7 +244,7 @@ _PG_init(void) prev_ProcessUtility = ProcessUtility_hook; ProcessUtility_hook = pgss_ProcessUtility; planner_hook_next = planner_hook; - planner_hook = pgss_planner_hook; + planner_hook = pgss_planner_hook; emit_log_hook = pgsm_emit_log_hook; prev_ExecutorCheckPerms_hook = ExecutorCheckPerms_hook; ExecutorCheckPerms_hook = pgss_ExecutorCheckPerms; @@ -294,7 +299,6 @@ pg_stat_monitor_version(PG_FUNCTION_ARGS) PG_RETURN_TEXT_P(cstring_to_text(BUILD_VERSION)); } - /* * Post-parse-analysis hook: mark query with a queryId */ @@ -325,6 +329,7 @@ pgss_post_parse_analyze(ParseState *pstate, Query *query) } query->queryId = get_query_id(&jstate, query); + /* * If we are unlucky enough to get a hash of zero, use 1 instead, to * prevent confusion with the utility-statement case. @@ -335,24 +340,12 @@ pgss_post_parse_analyze(ParseState *pstate, Query *query) if (jstate.clocations_count <= 0) return; - pgss_store(query->queryId, - pstate->p_sourcetext, - query->commandType, - 0, /* error elevel */ - "", /* error sqlcode */ - NULL, /* error message */ - query->stmt_location, - query->stmt_len, - PGSS_INVALID, - 0, - 0, - NULL, -#if PG_VERSION_NUM >= 130000 - NULL, -#endif - &jstate, - 0.0, - 0.0); + pgss_store_query(query->queryId, /* queryid */ + pstate->p_sourcetext, /* query */ + query->commandType, /* CmdType */ + query->stmt_location, /* Query Location */ + query->stmt_len, /* Quer Len */ + &jstate); /* pgssJumbleState */ } /* @@ -445,19 +438,98 @@ pgss_ExecutorFinish(QueryDesc *queryDesc) PG_END_TRY(); } + +static bool +pgss_get_plan(uint64 query_hash, PlanInfo *plan_info) +{ + pgssPlanHashKey key; + pgssPlanEntry *entry; + HTAB *pgss_plan_hash = pgsm_get_plan_hash(); + + key.query_hash = query_hash; + entry = (pgssPlanEntry *) hash_search(pgss_plan_hash, &key, HASH_FIND, NULL); + if(entry) + { + memcpy(plan_info, &entry->plan_info, sizeof(PlanInfo)); + return true; + } + return false; +} + +static bool +pgss_store_plan(uint64 query_hash, PlanInfo *plan_info) +{ + pgssPlanHashKey key; + pgssPlanEntry *entry; + HTAB *pgss_plan_hash = pgsm_get_plan_hash(); + pgssSharedState *pgss = pgsm_get_ss(); + bool found = true; + + LWLockAcquire(pgss->lock, LW_SHARED); + + /* Set up key for hashtable search */ + key.query_hash = query_hash; + entry = (pgssPlanEntry *) hash_search(pgss_plan_hash, &key, HASH_FIND, NULL); + if (!entry) + { + entry = hash_plan_entry_alloc(pgss, &key); + if (entry == NULL) + { + LWLockRelease(pgss->lock); + return found; + } + found = false; + } + SpinLockAcquire(&entry->mutex); + memcpy(&entry->plan_info, plan_info, sizeof(PlanInfo)); + SpinLockRelease(&entry->mutex); + LWLockRelease(pgss->lock); + return found; +} + +static char * +pgss_explain(QueryDesc *queryDesc) +{ + ExplainState *es = NewExplainState(); + + es->buffers = false; + es->analyze = false; + es->verbose = false; + es->costs = false; + es->format = EXPLAIN_FORMAT_TEXT; + + ExplainBeginOutput(es); + ExplainPrintPlan(es, queryDesc); + ExplainEndOutput(es); + + if (es->str->len > 0 && es->str->data[es->str->len - 1] == '\n') + es->str->data[--es->str->len] = '\0'; + return es->str->data; +} + /* * ExecutorEnd hook: store results if needed */ static void pgss_ExecutorEnd(QueryDesc *queryDesc) { - uint64 queryId = queryDesc->plannedstmt->queryId; - pgssSharedState *pgss = pgsm_get_ss(); + uint64 queryId = queryDesc->plannedstmt->queryId; + pgssSharedState *pgss = pgsm_get_ss(); + SysInfo sys_info; + PlanInfo plan_info; + + /* Extract the plan information in case of SELECT statment */ + memset(&plan_info, 0, sizeof(PlanInfo)); + if (queryDesc->operation == CMD_SELECT && PGSM_QUERY_PLAN) + { + MemoryContext mct = MemoryContextSwitchTo(TopMemoryContext); + snprintf(plan_info.plan_text, PLAN_TEXT_LEN, "%s", pgss_explain(queryDesc)); + plan_info.planid = DatumGetUInt64(hash_any_extended((const unsigned char*)plan_info.plan_text, strlen(plan_info.plan_text), 0)); + MemoryContextSwitchTo(mct); + } if (queryId != UINT64CONST(0) && queryDesc->totaltime) { - float utime; - float stime; /* * Make sure stats accumulation is done. (Note: it's okay if several * levels of hook all do this.) @@ -465,29 +537,23 @@ pgss_ExecutorEnd(QueryDesc *queryDesc) InstrEndLoop(queryDesc->totaltime); if(getrusage(RUSAGE_SELF, &rusage_end) != 0) elog(WARNING, "pg_stat_monitor: failed to execute getrusage"); - utime = time_diff(rusage_end.ru_utime, rusage_start.ru_utime); - stime = time_diff(rusage_end.ru_stime, rusage_start.ru_stime); - pgss_store(queryId, - queryDesc->sourceText, - queryDesc->operation, - 0, /* error elevel */ - "", /* error sqlcode */ - NULL, /* error message */ - queryDesc->plannedstmt->stmt_location, - queryDesc->plannedstmt->stmt_len, - PGSS_EXEC, - queryDesc->totaltime->total * 1000.0, /* convert to msec */ - queryDesc->estate->es_processed, - &queryDesc->totaltime->bufusage, -#if PG_VERSION_NUM >= 130000 - &queryDesc->totaltime->walusage, -#endif + sys_info.utime = time_diff(rusage_end.ru_utime, rusage_start.ru_utime); + sys_info.stime = time_diff(rusage_end.ru_stime, rusage_start.ru_stime); + + pgss_store(queryId, /* query id */ + queryDesc->sourceText, /* query text */ + &plan_info, /* PlanInfo */ + queryDesc->operation, /* CmdType */ + &sys_info, /* SysInfo */ + NULL, /* ErrorInfo */ + queryDesc->totaltime->total * 1000.0, /* totaltime */ + queryDesc->estate->es_processed, /* rows */ + &queryDesc->totaltime->bufusage, /* bufusage */ + &queryDesc->totaltime->walusage, /* walusage */ NULL, - utime, - stime); + PGSS_EXEC); /* pgssStoreKind */ } - if (prev_ExecutorEnd) prev_ExecutorEnd(queryDesc); else @@ -529,7 +595,10 @@ pgss_ExecutorCheckPerms(List *rt, bool abort) list_oid[j] = rte->relid; namespace_name = get_namespace_name(get_rel_namespace(rte->relid)); relation_name = get_rel_name(rte->relid); - snprintf(pgss->relations[i++], REL_LEN, "%s.%s", namespace_name, relation_name); + if (rte->relkind == 'v') + snprintf(pgss->relations[i++], REL_LEN, "%s.%s*", namespace_name, relation_name); + else + snprintf(pgss->relations[i++], REL_LEN, "%s.%s", namespace_name, relation_name); } } } @@ -542,6 +611,76 @@ pgss_ExecutorCheckPerms(List *rt, bool abort) return true; } +static PlannedStmt * +pgss_planner_hook(Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams) +{ + PlannedStmt *result; + + if (PGSM_TRACK_PLANNING && query_string && parse->queryId != UINT64CONST(0)) + { + PlanInfo plan_info; + instr_time start; + instr_time duration; + BufferUsage bufusage_start; + BufferUsage bufusage; + WalUsage walusage_start; + WalUsage walusage; + + /* We need to track buffer usage as the planner can access them. */ + bufusage_start = pgBufferUsage; + + /* + * Similarly the planner could write some WAL records in some cases + * (e.g. setting a hint bit with those being WAL-logged) + */ + walusage_start = pgWalUsage; + INSTR_TIME_SET_CURRENT(start); + + plan_nested_level++; + PG_TRY(); + { + if (planner_hook_next) + result = planner_hook_next(parse, query_string, cursorOptions, boundParams); + result = standard_planner(parse, query_string, cursorOptions, boundParams); + } + PG_FINALLY(); + { + plan_nested_level--; + } + PG_END_TRY(); + + INSTR_TIME_SET_CURRENT(duration); + INSTR_TIME_SUBTRACT(duration, start); + + /* calc differences of buffer counters. */ + memset(&bufusage, 0, sizeof(BufferUsage)); + BufferUsageAccumDiff(&bufusage, &pgBufferUsage, &bufusage_start); + + /* calc differences of WAL counters. */ + memset(&walusage, 0, sizeof(WalUsage)); + WalUsageAccumDiff(&walusage, &pgWalUsage, &walusage_start); + pgss_store(parse->queryId, /* query id */ + query_string, /* query */ + &plan_info, /* PlanInfo */ + parse->commandType, /* CmdType */ + NULL, /* SysInfo */ + NULL, /* ErrorInfo */ + INSTR_TIME_GET_MILLISEC(duration), /* totaltime */ + 0, /* rows */ + &bufusage, /* bufusage */ + &walusage, /* walusage */ + NULL, /* pgssJumbleState */ + PGSS_PLAN); /* pgssStoreKind */ + } + else + { + if (planner_hook_next) + result = planner_hook_next(parse, query_string, cursorOptions, boundParams); + result = standard_planner(parse, query_string, cursorOptions, boundParams); + } + return result; +} + /* * ProcessUtility hook */ @@ -583,25 +722,19 @@ static void pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString, instr_time start; instr_time duration; uint64 rows; - BufferUsage bufusage_start, - bufusage; -#if PG_VERSION_NUM >= 130000 - WalUsage walusage_start, - walusage; - walusage_start = pgWalUsage; - exec_nested_level++; -#endif + BufferUsage bufusage_start; + BufferUsage bufusage; + WalUsage walusage_start; + WalUsage walusage; - bufusage_start = pgBufferUsage; -#if PG_VERSION_NUM >= 130000 - walusage_start = pgWalUsage; -#endif - INSTR_TIME_SET_CURRENT(start); - PG_TRY(); - { - if (prev_ProcessUtility) - prev_ProcessUtility(pstmt, queryString, - context, params, queryEnv, + bufusage_start = pgBufferUsage; + walusage_start = pgWalUsage; + INSTR_TIME_SET_CURRENT(start); + PG_TRY(); + { + if (prev_ProcessUtility) + prev_ProcessUtility(pstmt, queryString, + context, params, queryEnv, dest #if PG_VERSION_NUM >= 130000 ,qc @@ -620,19 +753,12 @@ static void pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString, #endif ); } -#if PG_VERSION_NUM >= 130000 - PG_FINALLY(); - { - exec_nested_level--; - } -#else PG_CATCH(); { nested_level--; PG_RE_THROW(); } -#endif PG_END_TRY(); INSTR_TIME_SET_CURRENT(duration); @@ -654,24 +780,11 @@ static void pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString, /* calc differences of buffer counters. */ memset(&bufusage, 0, sizeof(BufferUsage)); BufferUsageAccumDiff(&bufusage, &pgBufferUsage, &bufusage_start); - pgss_store(0, /* query id, passing 0 to signal that it's a utility stmt */ - queryString, /* query text */ - 0, - 0, /* error elevel */ - "", /* error sqlcode */ - NULL, /* error message */ - pstmt->stmt_location, - pstmt->stmt_len, - PGSS_EXEC, - INSTR_TIME_GET_MILLISEC(duration), - rows, - &bufusage, -#if PG_VERSION_NUM >= 130000 - &walusage, -#endif - NULL, - 0, - 0); + pgss_store_utility(queryString, /* query text */ + INSTR_TIME_GET_MILLISEC(duration), /* totaltime */ + rows, /* rows */ + &bufusage, /* bufusage */ + &walusage); /* walusage */ } else { @@ -790,66 +903,160 @@ pg_get_client_addr(void) return ntohl(inet_addr(remote_host)); } - -/* - * Store some statistics for a statement. - * - * If queryId is 0 then this is a utility statement and we should compute - * a suitable queryId internally. - * - * If jstate is not NULL then we're trying to create an entry for which - * we have no statistics as yet; we just want to record the normalized - * query string. total_time, rows, bufusage are ignored in this case. - */ -static void pgss_store(uint64 queryId, +static void +pgss_update_entry(pgssEntry *entry, + int bucketid, + uint64 queryid, const char *query, - CmdType cmd_type, - uint64 elevel, - char *sqlcode, - const char *message, - int query_location, - int query_len, - pgssStoreKind kind, + PlanInfo *plan_info, + CmdType cmd_type, + SysInfo *sys_info, + ErrorInfo *error_info, double total_time, uint64 rows, - const BufferUsage *bufusage, -#if PG_VERSION_NUM >= 130000 - const WalUsage *walusage, -#endif - pgssJumbleState *jstate, - float utime, - float stime) + BufferUsage *bufusage, + WalUsage *walusage, + bool reset) { + int index; + char application_name[APPLICATIONNAME_LEN]; + int application_name_len = pg_get_application_name(application_name); + pgssSharedState *pgss = pgsm_get_ss(); + double old_mean; + int message_len = error_info ? strlen (error_info->message) : 0; + int sqlcode_len = error_info ? strlen (error_info->sqlcode) : 0; + + /* volatile block */ + { + volatile pgssEntry *e = (volatile pgssEntry *) entry; + SpinLockAcquire(&e->mutex); + /* Start collecting data for next bucket and reset all counters */ + if (reset) + memset(&entry->counters, 0, sizeof(Counters)); + + if (e->counters.calls.calls == 0) + e->counters.calls.usage = USAGE_INIT; + e->counters.calls.calls += 1; + e->counters.time.total_time += total_time; + + if (e->counters.calls.calls == 1) + { + e->counters.time.min_time = total_time; + e->counters.time.max_time = total_time; + e->counters.time.mean_time = total_time; + } + + /* Increment the counts, except when jstate is not NULL */ + old_mean = e->counters.time.mean_time; + e->counters.time.mean_time += (total_time - old_mean) / e->counters.calls.calls; + e->counters.time.sum_var_time +=(total_time - old_mean) * (total_time - e->counters.time.mean_time); + + /* calculate min and max time */ + if (e->counters.time.min_time > total_time) e->counters.time.min_time = total_time; + if (e->counters.time.max_time < total_time) e->counters.time.max_time = total_time; + + index = get_histogram_bucket(total_time); + e->counters.resp_calls[index]++; + + _snprintf(e->counters.info.application_name, application_name, application_name_len, APPLICATIONNAME_LEN); + + e->counters.info.num_relations = pgss->num_relations; + _snprintf2(e->counters.info.relations, pgss->relations, pgss->num_relations, REL_LEN); + + e->counters.info.cmd_type = cmd_type; + + if(nested_level > 0) + { + if (nested_level >=0 && nested_level < max_stack_depth) + e->counters.info.parentid = nested_queryids[nested_level - 1]; + } + else + { + e->counters.info.parentid = UINT64CONST(0); + } + + if (error_info) + { + e->counters.error.elevel = error_info->elevel; + _snprintf(e->counters.error.sqlcode, error_info->sqlcode, sqlcode_len, SQLCODE_LEN); + _snprintf(e->counters.error.message, error_info->message, message_len, ERROR_MESSAGE_LEN); + } + e->counters.calls.rows += rows; + if (bufusage) + { + e->counters.blocks.shared_blks_hit += bufusage->shared_blks_hit; + e->counters.blocks.shared_blks_read += bufusage->shared_blks_read; + e->counters.blocks.shared_blks_dirtied += bufusage->shared_blks_dirtied; + e->counters.blocks.shared_blks_written += bufusage->shared_blks_written; + e->counters.blocks.local_blks_hit += bufusage->local_blks_hit; + e->counters.blocks.local_blks_read += bufusage->local_blks_read; + e->counters.blocks.local_blks_dirtied += bufusage->local_blks_dirtied; + e->counters.blocks.local_blks_written += bufusage->local_blks_written; + e->counters.blocks.temp_blks_read += bufusage->temp_blks_read; + 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); + } + e->counters.calls.usage += USAGE_EXEC(total_time); + e->counters.info.host = pg_get_client_addr(); + if (sys_info) + { + e->counters.sysinfo.utime = sys_info->utime; + e->counters.sysinfo.stime = sys_info->stime; + } + if (walusage) + { + e->counters.walusage.wal_records += walusage->wal_records; + e->counters.walusage.wal_fpi += walusage->wal_fpi; + e->counters.walusage.wal_bytes += walusage->wal_bytes; + } + SpinLockRelease(&e->mutex); + } +} + +static pgssEntry* +pgss_get_entry(uint64 bucket_id, + uint64 userid, + uint64 dbid, + uint64 queryid, + uint64 ip, + bool *found) +{ + pgssEntry *entry; pgssHashKey key; - int bucket_id; - pgssEntry *entry; - char *norm_query = NULL; - int encoding = GetDatabaseEncoding(); - bool reset = false; - pgssSharedState *pgss = pgsm_get_ss(); HTAB *pgss_hash = pgsm_get_hash(); - int message_len = message ? strlen(message) : 0; - char application_name[APPLICATIONNAME_LEN]; - int application_name_len; - int sqlcode_len = strlen(sqlcode); + pgssSharedState *pgss = pgsm_get_ss(); - /* Monitoring is disabled */ - if (!PGSM_ENABLED) - return; + key.bucket_id = bucket_id; + key.userid = userid; + key.dbid = MyDatabaseId; + key.queryid = queryid; + key.ip = pg_get_client_addr(); - Assert(query != NULL); - application_name_len = pg_get_application_name(application_name); + entry = (pgssEntry *) hash_search(pgss_hash, &key, HASH_FIND, NULL); + if(!entry) + { + if (found) + *found = false; + /* OK to create a new hashtable entry */ + entry = hash_entry_alloc(pgss, &key, GetDatabaseEncoding()); + if (entry == NULL) + return NULL; + } + Assert(entry); + return entry; +} - /* Safety check... */ - if (!IsSystemInitialized() || !pgss_qbuf[pgss->current_wbucket]) - return; +static void +pgss_store_query(uint64 queryid, + const char * query, + CmdType cmd_type, + int query_location, + int query_len, + pgssJumbleState *jstate) +{ + char *norm_query = NULL; - /* - * Confine our attention to the relevant part of the string, if the query - * is a portion of a multi-statement source string. - * - * First apply starting offset, unless it's -1 (unknown). - */ if (query_location >= 0) { Assert(query_location <= strlen(query)); @@ -876,189 +1083,205 @@ static void pgss_store(uint64 queryId, while (query_len > 0 && scanner_isspace(query[query_len - 1])) query_len--; + if (jstate) + norm_query = generate_normalized_query(jstate, query, + query_location, + &query_len, + GetDatabaseEncoding()); /* - * For utility statements, we just hash the query string to get an ID. - */ - if (queryId == UINT64CONST(0)) - queryId = pgss_hash_string(query, query_len); + * For utility statements, we just hash the query string to get an ID. + */ + if (queryid == UINT64CONST(0)) + queryid = pgss_hash_string(query, query_len); + + pgss_store(queryid, /* query id */ + PGSM_NORMALIZED_QUERY ? (norm_query ? norm_query : query) : query, /* query */ + NULL, /* PlanInfo */ + cmd_type, /* CmdType */ + NULL, /* SysInfo */ + NULL, /* ErrorInfo */ + 0, /* totaltime */ + 0, /* rows */ + NULL, /* bufusage */ + NULL, /* walusage */ + jstate, /* pgssJumbleState */ + PGSS_EXEC); /* pgssStoreKind */ +} + +static void +pgss_store_error(uint64 queryid, + const char * query, + ErrorData *edata) +{ + ErrorInfo error_info; + + error_info.elevel = edata->elevel; + snprintf(error_info.message, ERROR_MESSAGE_LEN, "%s", edata->message); + snprintf(error_info.sqlcode, ERROR_MESSAGE_LEN, "%s", unpack_sql_state(edata->sqlerrcode)); + + pgss_store(queryid, /* query id */ + query, /* query text */ + NULL, /* PlanInfo */ + 0, /* CmdType */ + NULL, /* SysInfo */ + &error_info, /* ErrorInfo */ + 0, /* total_time */ + 0, /* rows */ + NULL, /* bufusage */ + NULL, /* walusage */ + NULL, /* pgssJumbleState */ + PGSS_EXEC); /* pgssStoreKind */ +} + +static void +pgss_store_utility(const char *query, + double total_time, + uint64 rows, + BufferUsage *bufusage, + WalUsage *walusage) +{ + uint64 queryid = pgss_hash_string(query, strlen(query)); + + pgss_store(queryid, /* query id */ + query, /* query text */ + NULL, /* PlanInfo */ + 0, /* CmdType */ + NULL, /* SysInfo */ + NULL, /* ErrorInfo */ + total_time, /* total_time */ + rows, /* rows */ + bufusage, /* bufusage */ + walusage, /* walusage */ + NULL, /* pgssJumbleState */ + PGSS_EXEC); /* pgssStoreKind */ +} + +static void +update_planinfo(PlanInfo *plan_info, pgssStoreKind kind, double total_time, uint64 userid, uint64 dbid, uint64 queryid, uint64 ip) +{ + char str[64]; + uint64 query_hash; + PlanInfo pi; + + if (plan_info == NULL) + return; + + snprintf(str, 64, "%08lx%08lX%08lX%08lX", userid, dbid, queryid, ip); + query_hash = DatumGetUInt64(hash_any_extended((const unsigned char*)str, strlen(str), 0)); + + if (pgss_get_plan(query_hash, &pi)) + { + if (kind == PGSS_PLAN) + { + double old_mean = 0; + + pi.plans += 1; + pi.time.total_time += total_time; + if (pi.plans == 0) + if (pi.plans == 1) + { + pi.time.min_time = total_time; + pi.time.max_time = total_time; + pi.time.mean_time = total_time; + } + + /* Increment the counts, except when jstate is not NULL */ + old_mean = pi.time.mean_time; + pi.time.mean_time += (total_time - old_mean) / pi.plans; + pi.time.sum_var_time +=(total_time - old_mean) * (total_time - pi.time.mean_time); + + /* calculate min and max time */ + if (pi.time.min_time > total_time) pi.time.min_time = total_time; + if (pi.time.max_time < total_time) pi.time.max_time = total_time; + pgss_store_plan(query_hash, &pi); + } + } + else + { + if (kind == PGSS_EXEC) + { + pgss_store_plan(query_hash, plan_info); + } + } +} + +/* + * Store some statistics for a statement. + * + * If queryId is 0 then this is a utility statement and we should compute + * a suitable queryId internally. + * + * If jstate is not NULL then we're trying to create an entry for which + * we have no statistics as yet; we just want to record the normalized + * query string. total_time, rows, bufusage are ignored in this case. + */ +static void +pgss_store(uint64 queryid, + const char *query, + PlanInfo *plan_info, + CmdType cmd_type, + SysInfo *sys_info, + ErrorInfo *error_info, + double total_time, + uint64 rows, + BufferUsage *bufusage, + WalUsage *walusage, + pgssJumbleState *jstate, + pgssStoreKind kind) +{ + int bucket_id; + pgssEntry *entry; + pgssSharedState *pgss = pgsm_get_ss(); + bool reset = false; + bool found = true; + + /* Monitoring is disabled */ + if (!PGSM_ENABLED) + return; + + Assert(query != NULL); + + /* Safety check... */ + if (!IsSystemInitialized() || !pgss_qbuf[pgss->current_wbucket]) + return; bucket_id = get_next_wbucket(pgss); - if (bucket_id != pgss->current_wbucket) { reset = true; pgss->current_wbucket = bucket_id; } - /* Lookup the hash table entry with shared lock. */ - LWLockAcquire(pgss->lock, LW_SHARED); + update_planinfo(plan_info, kind, total_time, (uint64)GetUserId(), (uint64)MyDatabaseId, queryid, (uint64)pg_get_client_addr()); - /* Set up key for hashtable search */ - key.bucket_id = bucket_id; - key.userid = (elevel == 0) ? GetUserId() : 0; - key.dbid = MyDatabaseId; - key.queryid = queryId; - key.ip = pg_get_client_addr(); - - entry = (pgssEntry *) hash_search(pgss_hash, &key, HASH_FIND, NULL); - if(!entry) + LWLockAcquire(pgss->lock, LW_EXCLUSIVE); + entry = pgss_get_entry(bucket_id, GetUserId(), MyDatabaseId, queryid, pg_get_client_addr(), &found); + if (entry == NULL) { - /* - * Create a new, normalized query string if caller asked. We don't - * need to hold the lock while doing this work. (Note: in any case, - * it's possible that someone else creates a duplicate hashtable entry - * in the interval where we don't hold the lock below. That case is - * handled by entry_alloc.) - */ - if (jstate) - { - LWLockRelease(pgss->lock); - norm_query = generate_normalized_query(jstate, query, - query_location, - &query_len, - encoding); - LWLockAcquire(pgss->lock, LW_SHARED); - } - LWLockRelease(pgss->lock); - LWLockAcquire(pgss->lock, LW_EXCLUSIVE); - - /* OK to create a new hashtable entry */ - entry = hash_entry_alloc(pgss, &key, encoding); - if (entry == NULL) - { - goto exit; - } - if (PGSM_NORMALIZED_QUERY) - store_query(key.bucket_id, queryId, norm_query ? norm_query : query, query_len); - else - store_query(key.bucket_id, queryId, query, query_len); + return; } - /* - * Grab the spinlock while updating the counters (see comment about - * locking rules at the head of the file) - */ - { - volatile pgssEntry *e = (volatile pgssEntry *) entry; - /* Increment the counts, except when jstate is not NULL */ - if (!jstate) - { + /* In case query is not found in the hash, add that into hash. */ + if (!found) + store_query(bucket_id, queryid, query, strlen(query)); - SpinLockAcquire(&e->mutex); - - /* Start collecting data for next bucket and reset all counters */ - if (reset) - memset(&entry->counters, 0, sizeof(Counters)); - - /* "Unstick" entry if it was previously sticky */ - if (e->counters.calls[kind].calls == 0) - e->counters.calls[kind].usage = USAGE_INIT; - e->counters.calls[kind].calls += 1; - e->counters.time[kind].total_time += total_time; - - if (e->counters.calls[kind].calls == 1) - { - e->counters.time[kind].min_time = total_time; - e->counters.time[kind].max_time = total_time; - e->counters.time[kind].mean_time = total_time; - } - else - { - /* - * Welford's method for accurately computing variance. See - * - */ - double old_mean = e->counters.time[kind].mean_time; - - e->counters.time[kind].mean_time += - (total_time - old_mean) / e->counters.calls[kind].calls; - e->counters.time[kind].sum_var_time += - (total_time - old_mean) * (total_time - e->counters.time[kind].mean_time); - - /* calculate min and max time */ - if (e->counters.time[kind].min_time > total_time) - e->counters.time[kind].min_time = total_time; - if (e->counters.time[kind].max_time < total_time) - e->counters.time[kind].max_time = total_time; - } - - - /* increment only in case of PGSS_EXEC */ - if (kind == PGSS_EXEC) - { - int index = get_histogram_bucket(total_time); - e->counters.resp_calls[index]++; - } - _snprintf(e->counters.info.application_name, application_name, application_name_len, APPLICATIONNAME_LEN); - - e->counters.info.num_relations = pgss->num_relations; - _snprintf2(e->counters.info.relations, pgss->relations, pgss->num_relations, REL_LEN); - - e->counters.info.cmd_type = cmd_type; - e->counters.error.elevel = elevel; - - _snprintf(e->counters.error.sqlcode, sqlcode, sqlcode_len, SQLCODE_LEN); - _snprintf(e->counters.error.message, message, message_len, ERROR_MESSAGE_LEN); - - if(nested_level > 0) - { - if (nested_level >=0 && nested_level < max_stack_depth) - e->counters.info.parentid = nested_queryids[nested_level - 1]; - } - else - { - e->counters.info.parentid = UINT64CONST(0); - } - e->counters.calls[kind].rows += rows; - e->counters.blocks.shared_blks_hit += bufusage->shared_blks_hit; - e->counters.blocks.shared_blks_read += bufusage->shared_blks_read; - e->counters.blocks.shared_blks_dirtied += bufusage->shared_blks_dirtied; - e->counters.blocks.shared_blks_written += bufusage->shared_blks_written; - e->counters.blocks.local_blks_hit += bufusage->local_blks_hit; - e->counters.blocks.local_blks_read += bufusage->local_blks_read; - e->counters.blocks.local_blks_dirtied += bufusage->local_blks_dirtied; - e->counters.blocks.local_blks_written += bufusage->local_blks_written; - e->counters.blocks.temp_blks_read += bufusage->temp_blks_read; - 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); - e->counters.calls[kind].usage += USAGE_EXEC(total_time); - e->counters.info.host = pg_get_client_addr(); - e->counters.sysinfo.utime = utime; - e->counters.sysinfo.stime = stime; - if (sqlcode[0] != 0) - memset(&entry->counters.blocks, 0, sizeof(entry->counters.blocks)); -#if PG_VERSION_NUM >= 130000 - if (sqlcode[0] == 0) - { - e->counters.walusage.wal_records += walusage->wal_records; - e->counters.walusage.wal_fpi += walusage->wal_fpi; - e->counters.walusage.wal_bytes += walusage->wal_bytes; - } - else - { - e->counters.walusage.wal_records = 0; - e->counters.walusage.wal_fpi = 0; - e->counters.walusage.wal_bytes = 0; - } -#else - e->counters.walusage.wal_records = 0; - e->counters.walusage.wal_fpi = 0; - e->counters.walusage.wal_bytes = 0; -#endif - SpinLockRelease(&e->mutex); - } - } - -exit: + if (jstate == NULL && kind == PGSS_EXEC) + pgss_update_entry(entry, /* entry */ + bucket_id, /* bucketid */ + queryid, /* queryid */ + query, /* query */ + plan_info, /* PlanInfo */ + cmd_type, /* CmdType */ + sys_info, /* SysInfo */ + error_info, /* ErrorInfo */ + total_time, /* total_time */ + rows, /* rows */ + bufusage, /* bufusage */ + walusage, /* walusage */ + reset); /* reset */ LWLockRelease(pgss->lock); - - /* We postpone this clean-up until we're out of the lock */ - if (norm_query) - pfree(norm_query); } - /* * Reset all statement statistics. */ @@ -1100,6 +1323,7 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, pgssEntry *entry; char *query_txt; char queryid_txt[64]; + char planid_txt[64]; char parentid_txt[64]; pgssSharedState *pgss = pgsm_get_ss(); HTAB *pgss_hash = pgsm_get_hash(); @@ -1134,6 +1358,9 @@ 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 != 46) + elog(ERROR, "pg_stat_monitor: incorrect number of output arguments, required %d", tupdesc->natts); + tupstore = tuplestore_begin_heap(true, false, work_mem); rsinfo->returnMode = SFRM_Materialize; rsinfo->setResult = tupstore; @@ -1149,13 +1376,20 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, Datum values[PG_STAT_STATEMENTS_COLS]; bool nulls[PG_STAT_STATEMENTS_COLS]; int i = 0; - int kind; Counters tmp; double stddev; - int64 queryid = entry->key.queryid; + uint64 queryid = entry->key.queryid; struct tm tm; - time_t bucket_t,current_t; - double diff_t; + time_t bucket_t,current_t; + double diff_t; + char str[64]; + uint64 query_hash; + PlanInfo plan_info; + + memset(&plan_info, 0, sizeof(plan_info)); + snprintf(str, 64, "%08lx%08lX%08lX%08lX", (uint64)entry->key.userid, (uint64)entry->key.dbid, queryid, (uint64)entry->key.ip); + query_hash = DatumGetUInt64(hash_any_extended((const unsigned char*)str, strlen(str), 0)); + pgss_get_plan(query_hash, &plan_info); memset(&tm, 0, sizeof(tm)); strptime(pgss->bucket_start_time[entry->key.bucket_id], "%Y-%m-%d %H:%M:%S", &tm); @@ -1199,9 +1433,18 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, else sprintf(queryid_txt, "%08lX", (long unsigned int)0); + sprintf(planid_txt, "%08lX", plan_info.planid); + + /* bucketid at column number 0 */ values[i++] = ObjectIdGetDatum(entry->key.bucket_id); + + /* userid at column number 1 */ values[i++] = ObjectIdGetDatum(entry->key.userid); + + /* dbid at column number 2 */ values[i++] = ObjectIdGetDatum(entry->key.dbid); + + /* ip address at column number 3 */ /* Superusers or members of pg_read_all_stats members are allowed */ if (is_allowed_role || entry->key.userid == userid) values[i++] = Int64GetDatumFast(entry->key.ip); @@ -1216,8 +1459,16 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, SpinLockRelease(&e->mutex); } + /* queryid at column number 4 */ values[i++] = CStringGetTextDatum(queryid_txt); + /* planid at column number 5 */ + if (plan_info.planid != 0) + values[i++] = CStringGetTextDatum(planid_txt); + else + nulls[i++] = true; + + /* parentid at column number 6 */ if (tmp.info.parentid != UINT64CONST(0)) { sprintf(parentid_txt,"%08lX",tmp.info.parentid); @@ -1230,6 +1481,8 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, if (is_allowed_role || entry->key.userid == userid) { + /* query at column number 7 */ + /* plan at column number 8 */ if (showtext) { if (query_txt) @@ -1237,25 +1490,25 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, char *enc; enc = pg_any_to_server(query_txt, strlen(query_txt), entry->encoding); values[i++] = CStringGetTextDatum(enc); + values[i++] = CStringGetTextDatum(plan_info.plan_text); if (enc != query_txt) pfree(enc); } else { nulls[i++] = true; + nulls[i++] = true; } } else { /* Query text not requested */ nulls[i++] = true; + nulls[i++] = true; } } else { - /*skip the query id and parent id*/ - nulls[i++] = true; - nulls[i++] = true; /* * Don't show query text, but hint as to the reason for not doing * so if it was requested @@ -1264,12 +1517,17 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, values[i++] = CStringGetTextDatum(""); else nulls[i++] = true; + /* skip plan_text */ + nulls[i++] = true; } + + /* application_name at column number 9 */ if (strlen(tmp.info.application_name) == 0) nulls[i++] = true; else values[i++] = CStringGetTextDatum(tmp.info.application_name); + /* relations at column number 10 */ if (tmp.info.num_relations > 0) { int j; @@ -1295,39 +1553,77 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, else nulls[i++] = true; - values[i++] = Int64GetDatumFast(tmp.info.cmd_type); + /* cmd_type at column number 11 */ + if (tmp.info.cmd_type < 0) + nulls[i++] = true; + else + values[i++] = Int64GetDatumFast(tmp.info.cmd_type); + + /* elevel at column number 12 */ values[i++] = Int64GetDatumFast(tmp.error.elevel); + + /* sqlcode at column number 13 */ if (strlen(tmp.error.sqlcode) == 0) - values[i++] = CStringGetTextDatum("0"); + nulls[i++] = true; else values[i++] = CStringGetTextDatum(tmp.error.sqlcode); + /* message at column number 14 */ if (strlen(tmp.error.message) == 0) nulls[i++] = true; else values[i++] = CStringGetTextDatum(tmp.error.message); + + /* bucket_start_time at column number 15 */ values[i++] = CStringGetTextDatum(pgss->bucket_start_time[entry->key.bucket_id]); - for (kind = 0; kind < PGSS_NUMKIND; kind++) + if (tmp.calls.calls == 0) { - if (tmp.calls[kind].calls == 0) - { - /* Query of pg_stat_monitor itslef started from zero count */ - tmp.calls[kind].calls++; - if (kind == PGSS_EXEC) - tmp.resp_calls[0]++; - } - values[i++] = Int64GetDatumFast(tmp.calls[kind].calls); - values[i++] = Float8GetDatumFast(tmp.time[kind].total_time); - values[i++] = Float8GetDatumFast(tmp.time[kind].min_time); - values[i++] = Float8GetDatumFast(tmp.time[kind].max_time); - values[i++] = Float8GetDatumFast(tmp.time[kind].mean_time); - if (tmp.calls[kind].calls > 1) - stddev = sqrt(tmp.time[kind].sum_var_time / tmp.calls[kind].calls); - else - stddev = 0.0; - values[i++] = Float8GetDatumFast(stddev); - values[i++] = Int64GetDatumFast(tmp.calls[kind].rows); + /* Query of pg_stat_monitor itslef started from zero count */ + tmp.calls.calls++; + tmp.resp_calls[0]++; } + + /* calls at column number 16 */ + values[i++] = Int64GetDatumFast(tmp.calls.calls); + + /* total_time at column number 17 */ + values[i++] = Float8GetDatumFast(tmp.time.total_time); + + /* min_time at column number 18 */ + values[i++] = Float8GetDatumFast(tmp.time.min_time); + + /* max_time at column number 19 */ + values[i++] = Float8GetDatumFast(tmp.time.max_time); + + /* mean_time at column number 20 */ + values[i++] = Float8GetDatumFast(tmp.time.mean_time); + if (tmp.calls.calls > 1) + stddev = sqrt(tmp.time.sum_var_time / tmp.calls.calls); + else + stddev = 0.0; + + /* calls at column number 21 */ + values[i++] = Float8GetDatumFast(stddev); + + /* calls at column number 22 */ + values[i++] = Int64GetDatumFast(tmp.calls.rows); + + /* plan_calls at column number 23 */ + values[i++] = Int64GetDatumFast(plan_info.plans); + + /* plan_total_time at column number 24 */ + values[i++] = Float8GetDatumFast(plan_info.time.total_time); + + /* plan_min_time at column number 25 */ + values[i++] = Float8GetDatumFast(plan_info.time.min_time); + + /* plan_max_time at column number 26 */ + values[i++] = Float8GetDatumFast(plan_info.time.max_time); + + /* plan_mean_time at column number 27 */ + values[i++] = Float8GetDatumFast(plan_info.time.mean_time); + + /* blocks are from column number 28 - 39 */ values[i++] = Int64GetDatumFast(tmp.blocks.shared_blks_hit); values[i++] = Int64GetDatumFast(tmp.blocks.shared_blks_read); values[i++] = Int64GetDatumFast(tmp.blocks.shared_blks_dirtied); @@ -1340,23 +1636,33 @@ pg_stat_monitor_internal(FunctionCallInfo fcinfo, values[i++] = Int64GetDatumFast(tmp.blocks.temp_blks_written); values[i++] = Float8GetDatumFast(tmp.blocks.blk_read_time); values[i++] = Float8GetDatumFast(tmp.blocks.blk_write_time); + + /* resp_calls at column number 40 */ values[i++] = IntArrayGetTextDatum(tmp.resp_calls, MAX_RESPONSE_BUCKET); + + /* utime at column number 41 */ values[i++] = Float8GetDatumFast(tmp.sysinfo.utime); + + /* stime at column number 42 */ values[i++] = Float8GetDatumFast(tmp.sysinfo.stime); { char buf[256]; Datum wal_bytes; + /* wal_records at column number 43 */ values[i++] = Int64GetDatumFast(tmp.walusage.wal_records); + + /* wal_fpi at column number 44 */ values[i++] = Int64GetDatumFast(tmp.walusage.wal_fpi); snprintf(buf, sizeof buf, UINT64_FORMAT, tmp.walusage.wal_bytes); - /* Convert to numeric. */ + /* Convert to numeric */ wal_bytes = DirectFunctionCall3(numeric_in, CStringGetDatum(buf), ObjectIdGetDatum(0), Int32GetDatum(-1)); + /* wal_bytes at column number 45 */ values[i++] = wal_bytes; } tuplestore_putvalues(tupstore, tupdesc, values, nulls); @@ -2441,88 +2747,6 @@ store_query(int bucket_id, uint64 queryid, const char *query, uint64 query_len) memcpy(buf, &buf_len, sizeof (uint64)); } -#if PG_VERSION_NUM >= 130000 -static PlannedStmt * pgss_planner_hook(Query *parse, const char *query_string, int cursorOptions, ParamListInfo boundParams) -#else -static PlannedStmt *pgss_planner_hook(Query *parse, int opt, ParamListInfo param) -#endif -{ - PlannedStmt *result; -#if PG_VERSION_NUM >= 130000 - if (PGSM_TRACK_PLANNING && query_string - && parse->queryId != UINT64CONST(0)) - { - instr_time start; - instr_time duration; - BufferUsage bufusage_start, - bufusage; - WalUsage walusage_start, - walusage; - - /* We need to track buffer usage as the planner can access them. */ - bufusage_start = pgBufferUsage; - - /* - * Similarly the planner could write some WAL records in some cases - * (e.g. setting a hint bit with those being WAL-logged) - */ - walusage_start = pgWalUsage; - INSTR_TIME_SET_CURRENT(start); - - plan_nested_level++; - PG_TRY(); - { - if (planner_hook_next) - result = planner_hook_next(parse, query_string, cursorOptions, boundParams); - result = standard_planner(parse, query_string, cursorOptions, boundParams); - } - PG_FINALLY(); - { - plan_nested_level--; - } - PG_END_TRY(); - - INSTR_TIME_SET_CURRENT(duration); - INSTR_TIME_SUBTRACT(duration, start); - - /* calc differences of buffer counters. */ - memset(&bufusage, 0, sizeof(BufferUsage)); - BufferUsageAccumDiff(&bufusage, &pgBufferUsage, &bufusage_start); - - /* calc differences of WAL counters. */ - memset(&walusage, 0, sizeof(WalUsage)); - WalUsageAccumDiff(&walusage, &pgWalUsage, &walusage_start); - pgss_store(parse->queryId, /* query id */ - query_string, /* query text */ - parse->commandType, - 0, /* error elevel */ - "", /* error sqlcode */ - NULL, /* error message */ - parse->stmt_location, - parse->stmt_len, - PGSS_PLAN, - INSTR_TIME_GET_MILLISEC(duration), - 0, - &bufusage, - &walusage, - NULL, - 0, - 0); - } - else - { - if (planner_hook_next) - result = planner_hook_next(parse, query_string, cursorOptions, boundParams); - result = standard_planner(parse, query_string, cursorOptions, boundParams); - } -#else - if (planner_hook_next) - result = planner_hook_next(parse, opt, param); - result = standard_planner(parse, opt, param); -#endif - return result; -} - static uint64 get_query_id(pgssJumbleState *jstate, Query *query) { @@ -2552,6 +2776,13 @@ pg_stat_monitor_settings(PG_FUNCTION_ARGS) 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), @@ -2606,38 +2837,21 @@ set_qbuf(int i, unsigned char *buf) void pgsm_emit_log_hook(ErrorData *edata) { - BufferUsage bufusage; -#if PG_VERSION_NUM >= 130000 - WalUsage walusage; -#endif + if (!IsSystemInitialized()) + goto exit; - if (IsSystemInitialized() && - (edata->elevel == ERROR || edata->elevel == WARNING || edata->elevel == INFO || edata->elevel == DEBUG1) ) + if ((edata->elevel == ERROR || edata->elevel == WARNING || edata->elevel == INFO || edata->elevel == DEBUG1)) { uint64 queryid = 0; if (debug_query_string) queryid = DatumGetUInt64(hash_any_extended((const unsigned char *)debug_query_string, strlen(debug_query_string), 0)); - pgss_store(queryid, - debug_query_string ? debug_query_string : "", - 0, - edata->elevel, - unpack_sql_state(edata->sqlerrcode), - edata->message, - 0, - debug_query_string ? strlen(debug_query_string) : 0, - PGSS_EXEC, - 0, - 0, - &bufusage, -#if PG_VERSION_NUM >= 130000 - &walusage, -#endif - NULL, - 0, - 0); + pgss_store_error(queryid, + debug_query_string ? debug_query_string : "", + edata); } +exit: if (prev_emit_log_hook) prev_emit_log_hook(edata); } diff --git a/pg_stat_monitor.h b/pg_stat_monitor.h index 9b224ff..9f7f12b 100644 --- a/pg_stat_monitor.h +++ b/pg_stat_monitor.h @@ -79,7 +79,7 @@ #define CMD_LEN 20 #define APPLICATIONNAME_LEN 100 #define PGSM_OVER_FLOW_MAX 10 - +#define PLAN_TEXT_LEN 1024 /* the assumption of query max nested level */ #define DEFAULT_MAX_NESTED_LEVEL 10 @@ -94,9 +94,9 @@ #define SQLCODE_LEN 20 #if PG_VERSION_NUM >= 130000 -#define MAX_SETTINGS 13 +#define MAX_SETTINGS 14 #else -#define MAX_SETTINGS 12 +#define MAX_SETTINGS 13 #endif typedef struct GucVariables @@ -149,6 +149,15 @@ typedef enum AGG_KEY #define MAX_QUERY_LEN 1024 /* shared nenory storage for the query */ +typedef struct CallTime +{ + double total_time; /* total execution time, in msec */ + double min_time; /* minimum execution time in msec */ + double max_time; /* maximum execution time in msec */ + double mean_time; /* mean execution time in msec */ + double sum_var_time; /* sum of variances in execution time in msec */ +} CallTime; + typedef struct pgssQueryHashKey { uint64 queryid; /* query identifier */ @@ -161,6 +170,27 @@ typedef struct pgssQueryEntry uint64 pos; /* bucket number */ } pgssQueryEntry; +typedef struct PlanInfo +{ + uint64 planid; /* plan identifier */ + uint64 plans; /* how many times plan */ + CallTime time; + char plan_text[PLAN_TEXT_LEN]; /* plan text */ +} PlanInfo; + +/* shared nenory storage for the query */ +typedef struct pgssPlanHashKey +{ + uint64 query_hash; /* query reference identifier */ +} pgssPlanHashKey; + +typedef struct pgssPlanEntry +{ + pgssPlanHashKey key; /* hash key of entry - MUST BE FIRST */ + PlanInfo plan_info; /* planning information */ + slock_t mutex; /* protects the counters only */ +} pgssPlanEntry; + typedef struct pgssHashKey { uint64 bucket_id; /* bucket number */ @@ -187,7 +217,7 @@ typedef struct QueryInfo typedef struct ErrorInfo { int64 elevel; /* error elevel */ - char sqlcode[SQLCODE_LEN]; /* error sqlcode */ + char sqlcode[SQLCODE_LEN]; /* error sqlcode */ char message[ERROR_MESSAGE_LEN]; /* error message text */ } ErrorInfo; @@ -198,14 +228,6 @@ typedef struct Calls double usage; /* usage factor */ } Calls; -typedef struct CallTime -{ - double total_time; /* total execution time, in msec */ - double min_time; /* minimum execution time in msec */ - double max_time; /* maximum execution time in msec */ - double mean_time; /* mean execution time in msec */ - double sum_var_time; /* sum of variances in execution time in msec */ -} CallTime; typedef struct Blocks { @@ -235,15 +257,14 @@ typedef struct Wal_Usage int64 wal_fpi; /* # of WAL full page images generated */ uint64 wal_bytes; /* total amount of WAL bytes generated */ } Wal_Usage; -/* - * The actual stats counters kept within pgssEntry. - */ + typedef struct Counters { uint64 bucket_id; /* bucket id */ - Calls calls[PGSS_NUMKIND]; + Calls calls; QueryInfo info; - CallTime time[PGSS_NUMKIND]; + PlanInfo plan_info; + CallTime time; Blocks blocks; SysInfo sysinfo; ErrorInfo error; @@ -340,18 +361,19 @@ void pgss_shmem_startup(void); void pgss_shmem_shutdown(int code, Datum arg); int pgsm_get_bucket_size(void); pgssSharedState* pgsm_get_ss(void); -HTAB* pgsm_get_hash(void); +HTAB *pgsm_get_plan_hash(void); +HTAB *pgsm_get_hash(void); +HTAB *pgsm_get_plan_hash(void); HTAB* pgsm_get_query_hash(void); void hash_entry_reset(void); void hash_query_entry_dealloc(int bucket); void hash_entry_dealloc(int bucket); +pgssPlanEntry *hash_plan_entry_alloc(pgssSharedState *pgss, pgssPlanHashKey *key); pgssEntry* hash_entry_alloc(pgssSharedState *pgss, pgssHashKey *key, int encoding); Size hash_memsize(void); bool hash_find_query_entry(uint64 bucket_id, uint64 queryid); bool hash_create_query_entry(uint64 bucket_id, uint64 queryid); - -/* hash_query.c */ void pgss_startup(void); void set_qbuf(int i, unsigned char *); @@ -369,7 +391,8 @@ void pgss_startup(void); #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_TRACK_PLANNING get_conf(11)->guc_variable #define PGSM_OVERFLOW_TARGET get_conf(12)->guc_variable +#define PGSM_QUERY_PLAN get_conf(12)->guc_variable +#define PGSM_TRACK_PLANNING get_conf(13)->guc_variable #endif diff --git a/regression/expected/application_name.out b/regression/expected/application_name.out new file mode 100644 index 0000000..725af98 --- /dev/null +++ b/regression/expected/application_name.out @@ -0,0 +1,28 @@ +CREATE EXTENSION pg_stat_monitor; +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + +SELECT 1 AS num; + num +----- + 1 +(1 row) + +SELECT query,application_name FROM pg_stat_monitor ORDER BY query COLLATE "C"; + query | application_name +--------------------------------------------------------------------------------+----------------------------- + SELECT $1 AS num | pg_regress/application_name + SELECT pg_stat_monitor_reset(); | pg_regress/application_name + SELECT query,application_name FROM pg_stat_monitor ORDER BY query COLLATE "C"; | +(3 rows) + +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + +DROP EXTENSION pg_stat_monitor; diff --git a/regression/expected/basic.out b/regression/expected/basic.out index edf72fb..eb1e8ef 100644 --- a/regression/expected/basic.out +++ b/regression/expected/basic.out @@ -11,19 +11,20 @@ select pg_sleep(.5); (1 row) -SELECT 1; - ?column? ----------- - 1 +SELECT 1 AS num; + num +----- + 1 (1 row) SELECT query FROM pg_stat_monitor ORDER BY query COLLATE "C"; - query --------------------------------- - SELECT $1 - SELECT pg_stat_monitor_reset() + query +--------------------------------------------------------------- + SELECT $1 AS num + SELECT pg_stat_monitor_reset(); + SELECT query FROM pg_stat_monitor ORDER BY query COLLATE "C"; select pg_sleep($1) -(3 rows) +(4 rows) SELECT pg_stat_monitor_reset(); pg_stat_monitor_reset diff --git a/regression/expected/cmd_type.out b/regression/expected/cmd_type.out new file mode 100644 index 0000000..49716fe --- /dev/null +++ b/regression/expected/cmd_type.out @@ -0,0 +1,45 @@ +CREATE EXTENSION pg_stat_monitor; +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + +CREATE TABLE t1 (a INTEGER); +INSERT INTO t1 VALUES(1); +SELECT a FROM t1; + a +--- + 1 +(1 row) + +UPDATE t1 SET a = 2; +DELETE FROM t1; +SELECT a FROM t1 FOR UPDATE; + a +--- +(0 rows) + +TRUNCATE t1; +DROP TABLE t1; +SELECT query, cmd_type, cmd_type_text FROM pg_stat_monitor ORDER BY query COLLATE "C"; + query | cmd_type | cmd_type_text +-----------------------------------------------------------------------------------------+----------+--------------- + CREATE TABLE t1 (a INTEGER); | 0 | + DELETE FROM t1; | 4 | DELETE + DROP TABLE t1; | 0 | + INSERT INTO t1 VALUES($1) | 3 | INSERT + SELECT a FROM t1; | 1 | SELECT + SELECT pg_stat_monitor_reset(); | 1 | SELECT + SELECT query, cmd_type, cmd_type_text FROM pg_stat_monitor ORDER BY query COLLATE "C"; | 0 | + TRUNCATE t1; | 0 | + UPDATE t1 SET a = $1 | 2 | UPDATE +(9 rows) + +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + +DROP EXTENSION pg_stat_monitor; diff --git a/regression/expected/counters.out b/regression/expected/counters.out new file mode 100644 index 0000000..d365ba8 --- /dev/null +++ b/regression/expected/counters.out @@ -0,0 +1,93 @@ +CREATE EXTENSION pg_stat_monitor; +CREATE TABLE t1 (a INTEGER); +CREATE TABLE t2 (b INTEGER); +CREATE TABLE t3 (c INTEGER); +CREATE TABLE t4 (d INTEGER); +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + +SELECT a,b,c,d FROM t1, t2, t3, t4 WHERE t1.a = t2.b AND t3.c = t4.d ORDER BY a; + a | b | c | d +---+---+---+--- +(0 rows) + +SELECT a,b,c,d FROM t1, t2, t3, t4 WHERE t1.a = t2.b AND t3.c = t4.d ORDER BY a; + a | b | c | d +---+---+---+--- +(0 rows) + +SELECT a,b,c,d FROM t1, t2, t3, t4 WHERE t1.a = t2.b AND t3.c = t4.d ORDER BY a; + a | b | c | d +---+---+---+--- +(0 rows) + +SELECT a,b,c,d FROM t1, t2, t3, t4 WHERE t1.a = t2.b AND t3.c = t4.d ORDER BY a; + a | b | c | d +---+---+---+--- +(0 rows) + +SELECT query,calls FROM pg_stat_monitor ORDER BY query COLLATE "C"; + query | calls +----------------------------------------------------------------------------------+------- + SELECT a,b,c,d FROM t1, t2, t3, t4 WHERE t1.a = t2.b AND t3.c = t4.d ORDER BY a; | 4 + SELECT pg_stat_monitor_reset(); | 1 + SELECT query,calls FROM pg_stat_monitor ORDER BY query COLLATE "C"; | 1 +(3 rows) + +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + +do $$ +declare + n integer:= 1; +begin + loop + PERFORM a,b,c,d FROM t1, t2, t3, t4 WHERE t1.a = t2.b AND t3.c = t4.d ORDER BY a; + exit when n = 1000; + n := n + 1; + end loop; +end $$; +SELECT query,calls FROM pg_stat_monitor ORDER BY query COLLATE "C"; + query | calls +---------------------------------------------------------------------------------------------------+------- + SELECT $1 AS num | 1 + SELECT a,b,c,d FROM t1, t2, t3, t4 WHERE t1.a = t2.b AND t3.c = t4.d ORDER BY a; | 1000 + SELECT n + $3 | 1 + SELECT n = $3 | 1 + SELECT pg_stat_monitor_reset(); | 1 + SELECT query,calls FROM pg_stat_monitor ORDER BY query COLLATE "C"; | 1 + do $$ +| 1 + declare +| + n integer:= 1; +| + begin +| + loop +| + PERFORM a,b,c,d FROM t1, t2, t3, t4 WHERE t1.a = t2.b AND t3.c = t4.d ORDER BY a;+| + exit when n = 1000; +| + n := n + 1; +| + end loop; +| + end $$; | +(7 rows) + +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; +DROP TABLE t4; +DROP EXTENSION pg_stat_monitor; diff --git a/regression/expected/database.out b/regression/expected/database.out new file mode 100644 index 0000000..378cbea --- /dev/null +++ b/regression/expected/database.out @@ -0,0 +1,54 @@ +CREATE EXTENSION pg_stat_monitor; +CREATE DATABASE db1; +CREATE DATABASE db2; +\c db1 +CREATE TABLE t1 (a int); +CREATE TABLE t2 (b int); +\c db2 +CREATE TABLE t3 (c int); +CREATE TABLE t4 (d int); +\c contrib_regression +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + +\c db1 +SELECT * FROM t1,t2 WHERE t1.a = t2.b; + a | b +---+--- +(0 rows) + +\c db2 +SELECT * FROM t3,t4 WHERE t3.c = t4.d; + c | d +---+--- +(0 rows) + +\c contrib_regression +SELECT datname, query FROM pg_stat_monitor ORDER BY query COLLATE "C"; + datname | query +--------------------+------------------------------------------------------------------------ + db1 | SELECT * FROM t1,t2 WHERE t1.a = t2.b; + db2 | SELECT * FROM t3,t4 WHERE t3.c = t4.d; + contrib_regression | SELECT datname, query FROM pg_stat_monitor ORDER BY query COLLATE "C"; + contrib_regression | SELECT pg_stat_monitor_reset(); +(4 rows) + +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + +\c db1 +DROP TABLE t1; +DROP TABLE t2; +\c db2 +DROP TABLE t3; +DROP TABLE t4; +\c contrib_regression +DROP DATABASE db1; +DROP DATABASE db2; +DROP EXTENSION pg_stat_monitor; diff --git a/regression/expected/error.out b/regression/expected/error.out new file mode 100644 index 0000000..24228e1 --- /dev/null +++ b/regression/expected/error.out @@ -0,0 +1,44 @@ +CREATE EXTENSION pg_stat_monitor; +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + +SELECT 1/0; -- divide by zero +ERROR: division by zero +SELECT * FROM unknown; -- unknown table +ERROR: relation "unknown" does not exist +LINE 1: SELECT * FROM unknown; + ^ +ELECET * FROM unknown; -- syntax error +ERROR: syntax error at or near "ELECET" +LINE 1: ELECET * FROM unknown; + ^ +do $$ +BEGIN +RAISE WARNING 'warning message'; +END $$; +WARNING: warning message +SELECT query, elevel,sqlcode, message FROM pg_stat_monitor ORDER BY query COLLATE "C"; + query | elevel | sqlcode | message +----------------------------------------------------------------------------------------+--------+---------+----------------------------------- + ELECET * FROM unknown; | 20 | 42601 | syntax error at or near "ELECET" + SELECT $1/$2 | 0 | | + SELECT * FROM unknown; | 20 | 42P01 | relation "unknown" does not exist + SELECT 1/0; | 20 | 22012 | division by zero + SELECT pg_stat_monitor_reset(); | 0 | | + SELECT query, elevel,sqlcode, message FROM pg_stat_monitor ORDER BY query COLLATE "C"; | 0 | | + do $$ +| 19 | 01000 | warning message + BEGIN +| | | + RAISE WARNING 'warning message'; +| | | + END $$; | | | +(7 rows) + +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + +DROP EXTENSION pg_stat_monitor; diff --git a/regression/expected/guc.out b/regression/expected/guc.out index 11f90bb..9fa592c 100644 --- a/regression/expected/guc.out +++ b/regression/expected/guc.out @@ -16,6 +16,7 @@ SELECT * FROM pg_stat_monitor_settings ORDER BY name COLLATE "C"; ------------------------------------------+--------+---------------+----------------------------------------------------------------------------------------------------------+---------+------------+--------- pg_stat_monitor.pgsm_bucket_time | 300 | 300 | 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 @@ -25,8 +26,9 @@ SELECT * FROM pg_stat_monitor_settings ORDER BY name COLLATE "C"; pg_stat_monitor.pgsm_overflow_target | 0 | 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 -(12 rows) +(14 rows) SELECT pg_stat_monitor_reset(); pg_stat_monitor_reset diff --git a/regression/expected/histogram.out b/regression/expected/histogram.out new file mode 100644 index 0000000..e69de29 diff --git a/regression/expected/pg_stat_monitor.out b/regression/expected/pg_stat_monitor.out deleted file mode 100644 index 8d1de44..0000000 --- a/regression/expected/pg_stat_monitor.out +++ /dev/null @@ -1,436 +0,0 @@ -CREATE EXTENSION pg_stat_monitor; --- --- simple and compound statements --- -SET pg_stat_monitor.track_utility = FALSE; -SELECT pg_stat_monitor_reset(); - pg_stat_monitor_reset ------------------------ - -(1 row) - -SELECT 1 AS "int"; - int ------ - 1 -(1 row) - -SELECT 'hello' - -- multiline - AS "text"; - text -------- - hello -(1 row) - -SELECT 'world' AS "text"; - text -------- - world -(1 row) - --- transaction -BEGIN; -SELECT 1 AS "int"; - int ------ - 1 -(1 row) - -SELECT 'hello' AS "text"; - text -------- - hello -(1 row) - -COMMIT; --- compound transaction -BEGIN \; -SELECT 2.0 AS "float" \; -SELECT 'world' AS "text" \; -COMMIT; --- compound with empty statements and spurious leading spacing -\;\; SELECT 3 + 3 \;\;\; SELECT ' ' || ' !' \;\; SELECT 1 + 4 \;; - ?column? ----------- - 5 -(1 row) - --- non ;-terminated statements -SELECT 1 + 1 + 1 AS "add" \gset -SELECT :add + 1 + 1 AS "add" \; -SELECT :add + 1 + 1 AS "add" \gset --- set operator -SELECT 1 AS i UNION SELECT 2 ORDER BY i; - i ---- - 1 - 2 -(2 rows) - --- ? operator -select '{"a":1, "b":2}'::jsonb ? 'b'; - ?column? ----------- - t -(1 row) - --- cte -WITH t(f) AS ( - VALUES (1.0), (2.0) -) - SELECT f FROM t ORDER BY f; - f ------ - 1.0 - 2.0 -(2 rows) - --- prepared statement with parameter -PREPARE pgss_test (int) AS SELECT $1, 'test' LIMIT 1; -EXECUTE pgss_test(1); - ?column? | ?column? -----------+---------- - 1 | test -(1 row) - -DEALLOCATE pgss_test; -SELECT query, calls, rows FROM pg_stat_monitor ORDER BY query COLLATE "C"; - query | calls | rows ----------------------------------------------------+-------+------ - BEGIN | 2 | 0 - COMMIT | 2 | 0 - PREPARE pgss_test (int) AS SELECT $1, $2 LIMIT $3 | 1 | 1 - SELECT $1 | 2 | 2 - SELECT $1 +| 4 | 4 - +| | - AS "text" | | - SELECT $1 + $2 | 2 | 2 - SELECT $1 + $2 + $3 AS "add" | 3 | 3 - SELECT $1 AS "float" | 1 | 1 - SELECT $1 AS i UNION SELECT $2 ORDER BY i | 1 | 2 - SELECT $1 || $2 | 1 | 1 - SELECT pg_stat_monitor_reset() | 1 | 1 - WITH t(f) AS ( +| 1 | 2 - VALUES ($1), ($2) +| | - ) +| | - SELECT f FROM t ORDER BY f | | - select $1::jsonb ? $2 | 1 | 1 -(13 rows) - --- --- CRUD: INSERT SELECT UPDATE DELETE on test table --- -SELECT pg_stat_monitor_reset(); - pg_stat_monitor_reset ------------------------ - -(1 row) - --- utility "create table" should not be shown -CREATE TEMP TABLE test (a int, b char(20)); -INSERT INTO test VALUES(generate_series(1, 10), 'aaa'); -UPDATE test SET b = 'bbb' WHERE a > 7; -DELETE FROM test WHERE a > 9; --- explicit transaction -BEGIN; -UPDATE test SET b = '111' WHERE a = 1 ; -COMMIT; -BEGIN \; -UPDATE test SET b = '222' WHERE a = 2 \; -COMMIT ; -UPDATE test SET b = '333' WHERE a = 3 \; -UPDATE test SET b = '444' WHERE a = 4 ; -BEGIN \; -UPDATE test SET b = '555' WHERE a = 5 \; -UPDATE test SET b = '666' WHERE a = 6 \; -COMMIT ; --- many INSERT values -INSERT INTO test (a, b) VALUES (1, 'a'), (2, 'b'), (3, 'c'); --- SELECT with constants -SELECT * FROM test WHERE a > 5 ORDER BY a ; - a | b ----+---------------------- - 6 | 666 - 7 | aaa - 8 | bbb - 9 | bbb -(4 rows) - -SELECT * - FROM test - WHERE a > 9 - ORDER BY a ; - a | b ----+--- -(0 rows) - --- SELECT without constants -SELECT * FROM test ORDER BY a; - a | b ----+---------------------- - 1 | a - 1 | 111 - 2 | b - 2 | 222 - 3 | c - 3 | 333 - 4 | 444 - 5 | 555 - 6 | 666 - 7 | aaa - 8 | bbb - 9 | bbb -(12 rows) - --- SELECT with IN clause -SELECT * FROM test WHERE a IN (1, 2, 3, 4, 5); - a | b ----+---------------------- - 1 | 111 - 2 | 222 - 3 | 333 - 4 | 444 - 5 | 555 - 1 | a - 2 | b - 3 | c -(8 rows) - -SELECT query, calls, rows FROM pg_stat_monitor ORDER BY query COLLATE "C"; - query | calls | rows --------------------------------------------------------------+-------+------ - BEGIN | 3 | 0 - COMMIT | 3 | 0 - CREATE TEMP TABLE test (a int, b char(20)) | 1 | 0 - DELETE FROM test WHERE a > $1 | 1 | 1 - INSERT INTO test (a, b) VALUES ($1, $2), ($3, $4), ($5, $6) | 1 | 3 - INSERT INTO test VALUES(generate_series($1, $2), $3) | 1 | 10 - SELECT * FROM test ORDER BY a | 1 | 12 - SELECT * FROM test WHERE a > $1 ORDER BY a | 2 | 4 - SELECT * FROM test WHERE a IN ($1, $2, $3, $4, $5) | 1 | 8 - SELECT pg_stat_monitor_reset() | 1 | 1 - UPDATE test SET b = $1 WHERE a = $2 | 6 | 6 - UPDATE test SET b = $1 WHERE a > $2 | 1 | 3 -(12 rows) - --- --- pg_stat_monitor.track = none --- -SET pg_stat_monitor.track = 'none'; -SELECT pg_stat_monitor_reset(); - pg_stat_monitor_reset ------------------------ - -(1 row) - -SELECT 1 AS "one"; - one ------ - 1 -(1 row) - -SELECT 1 + 1 AS "two"; - two ------ - 2 -(1 row) - -SELECT query, calls, rows FROM pg_stat_monitor ORDER BY query COLLATE "C"; - query | calls | rows ---------------------------------+-------+------ - SELECT $1 | 1 | 1 - SELECT $1 + $2 | 1 | 1 - SELECT pg_stat_monitor_reset() | 1 | 1 -(3 rows) - --- --- pg_stat_monitor.track = top --- -SET pg_stat_monitor.track = 'top'; -SELECT pg_stat_monitor_reset(); - pg_stat_monitor_reset ------------------------ - -(1 row) - -DO LANGUAGE plpgsql $$ -BEGIN - -- this is a SELECT - PERFORM 'hello world'::TEXT; -END; -$$; --- PL/pgSQL function -CREATE FUNCTION PLUS_TWO(i INTEGER) RETURNS INTEGER AS $$ -DECLARE - r INTEGER; -BEGIN - SELECT (i + 1 + 1.0)::INTEGER INTO r; - RETURN r; -END; $$ LANGUAGE plpgsql; -SELECT PLUS_TWO(3); - plus_two ----------- - 5 -(1 row) - -SELECT PLUS_TWO(7); - plus_two ----------- - 9 -(1 row) - --- SQL function --- use LIMIT to keep it from being inlined -CREATE FUNCTION PLUS_ONE(i INTEGER) RETURNS INTEGER AS -$$ SELECT (i + 1.0)::INTEGER LIMIT 1 $$ LANGUAGE SQL; -SELECT PLUS_ONE(8); - plus_one ----------- - 9 -(1 row) - -SELECT PLUS_ONE(10); - plus_one ----------- - 11 -(1 row) - -SELECT query, calls, rows FROM pg_stat_monitor ORDER BY query COLLATE "C"; - query | calls | rows ------------------------------------------------------------+-------+------ - CREATE FUNCTION PLUS_ONE(i INTEGER) RETURNS INTEGER AS +| 1 | 0 - $$ SELECT (i + 1.0)::INTEGER LIMIT 1 $$ LANGUAGE SQL | | - CREATE FUNCTION PLUS_TWO(i INTEGER) RETURNS INTEGER AS $$+| 1 | 0 - DECLARE +| | - r INTEGER; +| | - BEGIN +| | - SELECT (i + 1 + 1.0)::INTEGER INTO r; +| | - RETURN r; +| | - END; $$ LANGUAGE plpgsql | | - DO LANGUAGE plpgsql $$ +| 1 | 0 - BEGIN +| | - -- this is a SELECT +| | - PERFORM 'hello world'::TEXT; +| | - END; +| | - $$ | | - SELECT $1 +| 1 | 1 - +| | - AS "text" | | - SELECT (i + $2 + $3)::INTEGER | 2 | 2 - SELECT (i + $2)::INTEGER LIMIT $3 | 2 | 2 - SELECT PLUS_ONE($1) | 2 | 2 - SELECT PLUS_TWO($1) | 2 | 2 - SELECT pg_stat_monitor_reset() | 1 | 1 -(9 rows) - --- --- pg_stat_monitor.track = all --- -SET pg_stat_monitor.track = 'all'; -SELECT pg_stat_monitor_reset(); - pg_stat_monitor_reset ------------------------ - -(1 row) - --- we drop and recreate the functions to avoid any caching funnies -DROP FUNCTION PLUS_ONE(INTEGER); -DROP FUNCTION PLUS_TWO(INTEGER); --- PL/pgSQL function -CREATE FUNCTION PLUS_TWO(i INTEGER) RETURNS INTEGER AS $$ -DECLARE - r INTEGER; -BEGIN - SELECT (i + 1 + 1.0)::INTEGER INTO r; - RETURN r; -END; $$ LANGUAGE plpgsql; -SELECT PLUS_TWO(-1); - plus_two ----------- - 1 -(1 row) - -SELECT PLUS_TWO(2); - plus_two ----------- - 4 -(1 row) - --- SQL function --- use LIMIT to keep it from being inlined -CREATE FUNCTION PLUS_ONE(i INTEGER) RETURNS INTEGER AS -$$ SELECT (i + 1.0)::INTEGER LIMIT 1 $$ LANGUAGE SQL; -SELECT PLUS_ONE(3); - plus_one ----------- - 4 -(1 row) - -SELECT PLUS_ONE(1); - plus_one ----------- - 2 -(1 row) - -SELECT query, calls, rows FROM pg_stat_monitor ORDER BY query COLLATE "C"; - query | calls | rows ------------------------------------------------------------+-------+------ - CREATE FUNCTION PLUS_ONE(i INTEGER) RETURNS INTEGER AS +| 1 | 0 - $$ SELECT (i + 1.0)::INTEGER LIMIT 1 $$ LANGUAGE SQL | | - CREATE FUNCTION PLUS_TWO(i INTEGER) RETURNS INTEGER AS $$+| 1 | 0 - DECLARE +| | - r INTEGER; +| | - BEGIN +| | - SELECT (i + 1 + 1.0)::INTEGER INTO r; +| | - RETURN r; +| | - END; $$ LANGUAGE plpgsql | | - DROP FUNCTION PLUS_ONE(INTEGER) | 1 | 0 - DROP FUNCTION PLUS_TWO(INTEGER) | 1 | 0 - SELECT (i + $2 + $3)::INTEGER | 2 | 2 - SELECT (i + $2)::INTEGER LIMIT $3 | 2 | 2 - SELECT PLUS_ONE($1) | 2 | 2 - SELECT PLUS_TWO($1) | 2 | 2 - SELECT pg_stat_monitor_reset() | 1 | 1 -(9 rows) - --- --- utility commands --- -SET pg_stat_monitor.track_utility = TRUE; -SELECT pg_stat_monitor_reset(); - pg_stat_monitor_reset ------------------------ - -(1 row) - -SELECT 1; - ?column? ----------- - 1 -(1 row) - -CREATE INDEX test_b ON test(b); -DROP TABLE test \; -DROP TABLE IF EXISTS test \; -DROP FUNCTION PLUS_ONE(INTEGER); -NOTICE: table "test" does not exist, skipping -DROP TABLE IF EXISTS test \; -DROP TABLE IF EXISTS test \; -DROP FUNCTION IF EXISTS PLUS_ONE(INTEGER); -NOTICE: table "test" does not exist, skipping -NOTICE: table "test" does not exist, skipping -NOTICE: function plus_one(pg_catalog.int4) does not exist, skipping -DROP FUNCTION PLUS_TWO(INTEGER); -SELECT query, calls, rows FROM pg_stat_monitor ORDER BY query COLLATE "C"; - query | calls | rows --------------------------------------------+-------+------ - CREATE INDEX test_b ON test(b) | 1 | 0 - DROP FUNCTION IF EXISTS PLUS_ONE(INTEGER) | 1 | 0 - DROP FUNCTION PLUS_ONE(INTEGER) | 1 | 0 - DROP FUNCTION PLUS_TWO(INTEGER) | 1 | 0 - DROP TABLE IF EXISTS test | 3 | 0 - DROP TABLE test | 1 | 0 - SELECT $1 | 1 | 1 - SELECT pg_stat_monitor_reset() | 1 | 1 -(8 rows) - -DROP EXTENSION pg_stat_monitor; diff --git a/regression/expected/relations.out b/regression/expected/relations.out index 182772f..ce760d1 100644 --- a/regression/expected/relations.out +++ b/regression/expected/relations.out @@ -6,26 +6,46 @@ SELECT pg_stat_monitor_reset(); (1 row) CREATE TABLE foo1(a int); -CREATE TABLE foo2(a int); -CREATE TABLE foo3(a int); -CREATE TABLE foo4(a int); +CREATE TABLE foo2(b int); +CREATE TABLE foo3(c int); +CREATE TABLE foo4(d int); +-- test the simple table names SELECT pg_stat_monitor_reset(); pg_stat_monitor_reset ----------------------- (1 row) +SELECT * FROM foo1; + a +--- +(0 rows) + +SELECT * FROM foo1, foo2; + a | b +---+--- +(0 rows) + +SELECT * FROM foo1, foo2, foo3; + a | b | c +---+---+--- +(0 rows) + SELECT * FROM foo1, foo2, foo3, foo4; - a | a | a | a + a | b | c | d ---+---+---+--- (0 rows) SELECT query, relations from pg_stat_monitor ORDER BY query; - query | relations ---------------------------------------+--------------------------------------------------- - SELECT * FROM foo1, foo2, foo3, foo4 | {public.foo1,public.foo2,public.foo3,public.foo4} - SELECT pg_stat_monitor_reset() | -(2 rows) + query | relations +--------------------------------------------------------------+--------------------------------------------------- + SELECT * FROM foo1, foo2, foo3, foo4; | {public.foo1,public.foo2,public.foo3,public.foo4} + SELECT * FROM foo1, foo2, foo3; | {public.foo1,public.foo2,public.foo3} + SELECT * FROM foo1, foo2; | {public.foo1,public.foo2} + SELECT * FROM foo1; | {public.foo1} + SELECT pg_stat_monitor_reset(); | + SELECT query, relations from pg_stat_monitor ORDER BY query; | +(6 rows) SELECT pg_stat_monitor_reset(); pg_stat_monitor_reset @@ -33,8 +53,151 @@ SELECT pg_stat_monitor_reset(); (1 row) +-- test the schema qualified table +CREATE schema sch1; +CREATE schema sch2; +CREATE schema sch3; +CREATE schema sch4; +CREATE TABLE sch1.foo1(a int); +CREATE TABLE sch2.foo2(b int); +CREATE TABLE sch3.foo3(c int); +CREATE TABLE sch4.foo4(d int); +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + +SELECT * FROM sch1.foo1; + a +--- +(0 rows) + +SELECT * FROM sch1.foo1, sch2.foo2; + a | b +---+--- +(0 rows) + +SELECT * FROM sch1.foo1, sch2.foo2, sch3.foo3; + a | b | c +---+---+--- +(0 rows) + +SELECT * FROM sch1.foo1, sch2.foo2, sch3.foo3, sch4.foo4; + a | b | c | d +---+---+---+--- +(0 rows) + +SELECT query, relations from pg_stat_monitor ORDER BY query; + query | relations +--------------------------------------------------------------+------------------------------------------- + SELECT * FROM sch1.foo1, sch2.foo2, sch3.foo3, sch4.foo4; | {sch1.foo1,sch2.foo2,sch3.foo3,sch4.foo4} + SELECT * FROM sch1.foo1, sch2.foo2, sch3.foo3; | {sch1.foo1,sch2.foo2,sch3.foo3} + SELECT * FROM sch1.foo1, sch2.foo2; | {sch1.foo1,sch2.foo2} + SELECT * FROM sch1.foo1; | {sch1.foo1} + SELECT pg_stat_monitor_reset(); | + SELECT query, relations from pg_stat_monitor ORDER BY query; | +(6 rows) + +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + +SELECT * FROM sch1.foo1, foo1; + a | a +---+--- +(0 rows) + +SELECT * FROM sch1.foo1, sch2.foo2, foo1, foo2; + a | b | a | b +---+---+---+--- +(0 rows) + +SELECT query, relations from pg_stat_monitor ORDER BY query; + query | relations +--------------------------------------------------------------+----------------------------------------------- + SELECT * FROM sch1.foo1, foo1; | {sch1.foo1,public.foo1} + SELECT * FROM sch1.foo1, sch2.foo2, foo1, foo2; | {sch1.foo1,sch2.foo2,public.foo1,public.foo2} + SELECT pg_stat_monitor_reset(); | + SELECT query, relations from pg_stat_monitor ORDER BY query; | +(4 rows) + +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + +-- test the view +CREATE VIEW v1 AS SELECT * from foo1; +CREATE VIEW v2 AS SELECT * from foo1,foo2; +CREATE VIEW v3 AS SELECT * from foo1,foo2,foo3; +CREATE VIEW v4 AS SELECT * from foo1,foo2,foo3,foo4; +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + +SELECT * FROM v1; + a +--- +(0 rows) + +SELECT * FROM v1,v2; + a | a | b +---+---+--- +(0 rows) + +SELECT * FROM v1,v2,v3; + a | a | b | a | b | c +---+---+---+---+---+--- +(0 rows) + +SELECT * FROM v1,v2,v3,v4; + a | a | b | a | b | c | a | b | c | d +---+---+---+---+---+---+---+---+---+--- +(0 rows) + +SELECT query, relations from pg_stat_monitor ORDER BY query; + query | relations +--------------------------------------------------------------+----------------------------------------------------------------------------------------------- + SELECT * FROM v1,v2,v3,v4; | {public.v1*,public.foo1,public.v2*,public.foo2,public.v3*,public.foo3,public.v4*,public.foo4} + SELECT * FROM v1,v2,v3; | {public.v1*,public.foo1,public.v2*,public.foo2,public.v3*,public.foo3} + SELECT * FROM v1,v2; | {public.v1*,public.foo1,public.v2*,public.foo2} + SELECT * FROM v1; | {public.v1*,public.foo1} + SELECT pg_stat_monitor_reset(); | + SELECT query, relations from pg_stat_monitor ORDER BY query; | +(6 rows) + +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + +DROP VIEW v1; +DROP VIEW v2; +DROP VIEW v3; +DROP VIEW v4; DROP TABLE foo1; DROP TABLE foo2; DROP TABLE foo3; DROP TABLE foo4; +DROP TABLE sch1.foo1; +DROP TABLE sch2.foo2; +DROP TABLE sch3.foo3; +DROP TABLE sch4.foo4; +DROP SCHEMA sch1; +DROP SCHEMA sch2; +DROP SCHEMA sch3; +DROP SCHEMA sch4; DROP EXTENSION pg_stat_monitor; diff --git a/regression/expected/rows.out b/regression/expected/rows.out new file mode 100644 index 0000000..ddd1ea5 --- /dev/null +++ b/regression/expected/rows.out @@ -0,0 +1,8560 @@ +CREATE EXTENSION pg_stat_monitor; +CREATE TABLE t1(a int); +CREATE TABLE t2(b int); +INSERT INTO t1 VALUES(generate_series(1,1000)); +INSERT INTO t2 VALUES(generate_series(1,5000)); +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + +SELECT * FROM t1; + a +------ + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 + 65 + 66 + 67 + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 86 + 87 + 88 + 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 + 100 + 101 + 102 + 103 + 104 + 105 + 106 + 107 + 108 + 109 + 110 + 111 + 112 + 113 + 114 + 115 + 116 + 117 + 118 + 119 + 120 + 121 + 122 + 123 + 124 + 125 + 126 + 127 + 128 + 129 + 130 + 131 + 132 + 133 + 134 + 135 + 136 + 137 + 138 + 139 + 140 + 141 + 142 + 143 + 144 + 145 + 146 + 147 + 148 + 149 + 150 + 151 + 152 + 153 + 154 + 155 + 156 + 157 + 158 + 159 + 160 + 161 + 162 + 163 + 164 + 165 + 166 + 167 + 168 + 169 + 170 + 171 + 172 + 173 + 174 + 175 + 176 + 177 + 178 + 179 + 180 + 181 + 182 + 183 + 184 + 185 + 186 + 187 + 188 + 189 + 190 + 191 + 192 + 193 + 194 + 195 + 196 + 197 + 198 + 199 + 200 + 201 + 202 + 203 + 204 + 205 + 206 + 207 + 208 + 209 + 210 + 211 + 212 + 213 + 214 + 215 + 216 + 217 + 218 + 219 + 220 + 221 + 222 + 223 + 224 + 225 + 226 + 227 + 228 + 229 + 230 + 231 + 232 + 233 + 234 + 235 + 236 + 237 + 238 + 239 + 240 + 241 + 242 + 243 + 244 + 245 + 246 + 247 + 248 + 249 + 250 + 251 + 252 + 253 + 254 + 255 + 256 + 257 + 258 + 259 + 260 + 261 + 262 + 263 + 264 + 265 + 266 + 267 + 268 + 269 + 270 + 271 + 272 + 273 + 274 + 275 + 276 + 277 + 278 + 279 + 280 + 281 + 282 + 283 + 284 + 285 + 286 + 287 + 288 + 289 + 290 + 291 + 292 + 293 + 294 + 295 + 296 + 297 + 298 + 299 + 300 + 301 + 302 + 303 + 304 + 305 + 306 + 307 + 308 + 309 + 310 + 311 + 312 + 313 + 314 + 315 + 316 + 317 + 318 + 319 + 320 + 321 + 322 + 323 + 324 + 325 + 326 + 327 + 328 + 329 + 330 + 331 + 332 + 333 + 334 + 335 + 336 + 337 + 338 + 339 + 340 + 341 + 342 + 343 + 344 + 345 + 346 + 347 + 348 + 349 + 350 + 351 + 352 + 353 + 354 + 355 + 356 + 357 + 358 + 359 + 360 + 361 + 362 + 363 + 364 + 365 + 366 + 367 + 368 + 369 + 370 + 371 + 372 + 373 + 374 + 375 + 376 + 377 + 378 + 379 + 380 + 381 + 382 + 383 + 384 + 385 + 386 + 387 + 388 + 389 + 390 + 391 + 392 + 393 + 394 + 395 + 396 + 397 + 398 + 399 + 400 + 401 + 402 + 403 + 404 + 405 + 406 + 407 + 408 + 409 + 410 + 411 + 412 + 413 + 414 + 415 + 416 + 417 + 418 + 419 + 420 + 421 + 422 + 423 + 424 + 425 + 426 + 427 + 428 + 429 + 430 + 431 + 432 + 433 + 434 + 435 + 436 + 437 + 438 + 439 + 440 + 441 + 442 + 443 + 444 + 445 + 446 + 447 + 448 + 449 + 450 + 451 + 452 + 453 + 454 + 455 + 456 + 457 + 458 + 459 + 460 + 461 + 462 + 463 + 464 + 465 + 466 + 467 + 468 + 469 + 470 + 471 + 472 + 473 + 474 + 475 + 476 + 477 + 478 + 479 + 480 + 481 + 482 + 483 + 484 + 485 + 486 + 487 + 488 + 489 + 490 + 491 + 492 + 493 + 494 + 495 + 496 + 497 + 498 + 499 + 500 + 501 + 502 + 503 + 504 + 505 + 506 + 507 + 508 + 509 + 510 + 511 + 512 + 513 + 514 + 515 + 516 + 517 + 518 + 519 + 520 + 521 + 522 + 523 + 524 + 525 + 526 + 527 + 528 + 529 + 530 + 531 + 532 + 533 + 534 + 535 + 536 + 537 + 538 + 539 + 540 + 541 + 542 + 543 + 544 + 545 + 546 + 547 + 548 + 549 + 550 + 551 + 552 + 553 + 554 + 555 + 556 + 557 + 558 + 559 + 560 + 561 + 562 + 563 + 564 + 565 + 566 + 567 + 568 + 569 + 570 + 571 + 572 + 573 + 574 + 575 + 576 + 577 + 578 + 579 + 580 + 581 + 582 + 583 + 584 + 585 + 586 + 587 + 588 + 589 + 590 + 591 + 592 + 593 + 594 + 595 + 596 + 597 + 598 + 599 + 600 + 601 + 602 + 603 + 604 + 605 + 606 + 607 + 608 + 609 + 610 + 611 + 612 + 613 + 614 + 615 + 616 + 617 + 618 + 619 + 620 + 621 + 622 + 623 + 624 + 625 + 626 + 627 + 628 + 629 + 630 + 631 + 632 + 633 + 634 + 635 + 636 + 637 + 638 + 639 + 640 + 641 + 642 + 643 + 644 + 645 + 646 + 647 + 648 + 649 + 650 + 651 + 652 + 653 + 654 + 655 + 656 + 657 + 658 + 659 + 660 + 661 + 662 + 663 + 664 + 665 + 666 + 667 + 668 + 669 + 670 + 671 + 672 + 673 + 674 + 675 + 676 + 677 + 678 + 679 + 680 + 681 + 682 + 683 + 684 + 685 + 686 + 687 + 688 + 689 + 690 + 691 + 692 + 693 + 694 + 695 + 696 + 697 + 698 + 699 + 700 + 701 + 702 + 703 + 704 + 705 + 706 + 707 + 708 + 709 + 710 + 711 + 712 + 713 + 714 + 715 + 716 + 717 + 718 + 719 + 720 + 721 + 722 + 723 + 724 + 725 + 726 + 727 + 728 + 729 + 730 + 731 + 732 + 733 + 734 + 735 + 736 + 737 + 738 + 739 + 740 + 741 + 742 + 743 + 744 + 745 + 746 + 747 + 748 + 749 + 750 + 751 + 752 + 753 + 754 + 755 + 756 + 757 + 758 + 759 + 760 + 761 + 762 + 763 + 764 + 765 + 766 + 767 + 768 + 769 + 770 + 771 + 772 + 773 + 774 + 775 + 776 + 777 + 778 + 779 + 780 + 781 + 782 + 783 + 784 + 785 + 786 + 787 + 788 + 789 + 790 + 791 + 792 + 793 + 794 + 795 + 796 + 797 + 798 + 799 + 800 + 801 + 802 + 803 + 804 + 805 + 806 + 807 + 808 + 809 + 810 + 811 + 812 + 813 + 814 + 815 + 816 + 817 + 818 + 819 + 820 + 821 + 822 + 823 + 824 + 825 + 826 + 827 + 828 + 829 + 830 + 831 + 832 + 833 + 834 + 835 + 836 + 837 + 838 + 839 + 840 + 841 + 842 + 843 + 844 + 845 + 846 + 847 + 848 + 849 + 850 + 851 + 852 + 853 + 854 + 855 + 856 + 857 + 858 + 859 + 860 + 861 + 862 + 863 + 864 + 865 + 866 + 867 + 868 + 869 + 870 + 871 + 872 + 873 + 874 + 875 + 876 + 877 + 878 + 879 + 880 + 881 + 882 + 883 + 884 + 885 + 886 + 887 + 888 + 889 + 890 + 891 + 892 + 893 + 894 + 895 + 896 + 897 + 898 + 899 + 900 + 901 + 902 + 903 + 904 + 905 + 906 + 907 + 908 + 909 + 910 + 911 + 912 + 913 + 914 + 915 + 916 + 917 + 918 + 919 + 920 + 921 + 922 + 923 + 924 + 925 + 926 + 927 + 928 + 929 + 930 + 931 + 932 + 933 + 934 + 935 + 936 + 937 + 938 + 939 + 940 + 941 + 942 + 943 + 944 + 945 + 946 + 947 + 948 + 949 + 950 + 951 + 952 + 953 + 954 + 955 + 956 + 957 + 958 + 959 + 960 + 961 + 962 + 963 + 964 + 965 + 966 + 967 + 968 + 969 + 970 + 971 + 972 + 973 + 974 + 975 + 976 + 977 + 978 + 979 + 980 + 981 + 982 + 983 + 984 + 985 + 986 + 987 + 988 + 989 + 990 + 991 + 992 + 993 + 994 + 995 + 996 + 997 + 998 + 999 + 1000 +(1000 rows) + +SELECT * FROM t2; + b +------ + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21 + 22 + 23 + 24 + 25 + 26 + 27 + 28 + 29 + 30 + 31 + 32 + 33 + 34 + 35 + 36 + 37 + 38 + 39 + 40 + 41 + 42 + 43 + 44 + 45 + 46 + 47 + 48 + 49 + 50 + 51 + 52 + 53 + 54 + 55 + 56 + 57 + 58 + 59 + 60 + 61 + 62 + 63 + 64 + 65 + 66 + 67 + 68 + 69 + 70 + 71 + 72 + 73 + 74 + 75 + 76 + 77 + 78 + 79 + 80 + 81 + 82 + 83 + 84 + 85 + 86 + 87 + 88 + 89 + 90 + 91 + 92 + 93 + 94 + 95 + 96 + 97 + 98 + 99 + 100 + 101 + 102 + 103 + 104 + 105 + 106 + 107 + 108 + 109 + 110 + 111 + 112 + 113 + 114 + 115 + 116 + 117 + 118 + 119 + 120 + 121 + 122 + 123 + 124 + 125 + 126 + 127 + 128 + 129 + 130 + 131 + 132 + 133 + 134 + 135 + 136 + 137 + 138 + 139 + 140 + 141 + 142 + 143 + 144 + 145 + 146 + 147 + 148 + 149 + 150 + 151 + 152 + 153 + 154 + 155 + 156 + 157 + 158 + 159 + 160 + 161 + 162 + 163 + 164 + 165 + 166 + 167 + 168 + 169 + 170 + 171 + 172 + 173 + 174 + 175 + 176 + 177 + 178 + 179 + 180 + 181 + 182 + 183 + 184 + 185 + 186 + 187 + 188 + 189 + 190 + 191 + 192 + 193 + 194 + 195 + 196 + 197 + 198 + 199 + 200 + 201 + 202 + 203 + 204 + 205 + 206 + 207 + 208 + 209 + 210 + 211 + 212 + 213 + 214 + 215 + 216 + 217 + 218 + 219 + 220 + 221 + 222 + 223 + 224 + 225 + 226 + 227 + 228 + 229 + 230 + 231 + 232 + 233 + 234 + 235 + 236 + 237 + 238 + 239 + 240 + 241 + 242 + 243 + 244 + 245 + 246 + 247 + 248 + 249 + 250 + 251 + 252 + 253 + 254 + 255 + 256 + 257 + 258 + 259 + 260 + 261 + 262 + 263 + 264 + 265 + 266 + 267 + 268 + 269 + 270 + 271 + 272 + 273 + 274 + 275 + 276 + 277 + 278 + 279 + 280 + 281 + 282 + 283 + 284 + 285 + 286 + 287 + 288 + 289 + 290 + 291 + 292 + 293 + 294 + 295 + 296 + 297 + 298 + 299 + 300 + 301 + 302 + 303 + 304 + 305 + 306 + 307 + 308 + 309 + 310 + 311 + 312 + 313 + 314 + 315 + 316 + 317 + 318 + 319 + 320 + 321 + 322 + 323 + 324 + 325 + 326 + 327 + 328 + 329 + 330 + 331 + 332 + 333 + 334 + 335 + 336 + 337 + 338 + 339 + 340 + 341 + 342 + 343 + 344 + 345 + 346 + 347 + 348 + 349 + 350 + 351 + 352 + 353 + 354 + 355 + 356 + 357 + 358 + 359 + 360 + 361 + 362 + 363 + 364 + 365 + 366 + 367 + 368 + 369 + 370 + 371 + 372 + 373 + 374 + 375 + 376 + 377 + 378 + 379 + 380 + 381 + 382 + 383 + 384 + 385 + 386 + 387 + 388 + 389 + 390 + 391 + 392 + 393 + 394 + 395 + 396 + 397 + 398 + 399 + 400 + 401 + 402 + 403 + 404 + 405 + 406 + 407 + 408 + 409 + 410 + 411 + 412 + 413 + 414 + 415 + 416 + 417 + 418 + 419 + 420 + 421 + 422 + 423 + 424 + 425 + 426 + 427 + 428 + 429 + 430 + 431 + 432 + 433 + 434 + 435 + 436 + 437 + 438 + 439 + 440 + 441 + 442 + 443 + 444 + 445 + 446 + 447 + 448 + 449 + 450 + 451 + 452 + 453 + 454 + 455 + 456 + 457 + 458 + 459 + 460 + 461 + 462 + 463 + 464 + 465 + 466 + 467 + 468 + 469 + 470 + 471 + 472 + 473 + 474 + 475 + 476 + 477 + 478 + 479 + 480 + 481 + 482 + 483 + 484 + 485 + 486 + 487 + 488 + 489 + 490 + 491 + 492 + 493 + 494 + 495 + 496 + 497 + 498 + 499 + 500 + 501 + 502 + 503 + 504 + 505 + 506 + 507 + 508 + 509 + 510 + 511 + 512 + 513 + 514 + 515 + 516 + 517 + 518 + 519 + 520 + 521 + 522 + 523 + 524 + 525 + 526 + 527 + 528 + 529 + 530 + 531 + 532 + 533 + 534 + 535 + 536 + 537 + 538 + 539 + 540 + 541 + 542 + 543 + 544 + 545 + 546 + 547 + 548 + 549 + 550 + 551 + 552 + 553 + 554 + 555 + 556 + 557 + 558 + 559 + 560 + 561 + 562 + 563 + 564 + 565 + 566 + 567 + 568 + 569 + 570 + 571 + 572 + 573 + 574 + 575 + 576 + 577 + 578 + 579 + 580 + 581 + 582 + 583 + 584 + 585 + 586 + 587 + 588 + 589 + 590 + 591 + 592 + 593 + 594 + 595 + 596 + 597 + 598 + 599 + 600 + 601 + 602 + 603 + 604 + 605 + 606 + 607 + 608 + 609 + 610 + 611 + 612 + 613 + 614 + 615 + 616 + 617 + 618 + 619 + 620 + 621 + 622 + 623 + 624 + 625 + 626 + 627 + 628 + 629 + 630 + 631 + 632 + 633 + 634 + 635 + 636 + 637 + 638 + 639 + 640 + 641 + 642 + 643 + 644 + 645 + 646 + 647 + 648 + 649 + 650 + 651 + 652 + 653 + 654 + 655 + 656 + 657 + 658 + 659 + 660 + 661 + 662 + 663 + 664 + 665 + 666 + 667 + 668 + 669 + 670 + 671 + 672 + 673 + 674 + 675 + 676 + 677 + 678 + 679 + 680 + 681 + 682 + 683 + 684 + 685 + 686 + 687 + 688 + 689 + 690 + 691 + 692 + 693 + 694 + 695 + 696 + 697 + 698 + 699 + 700 + 701 + 702 + 703 + 704 + 705 + 706 + 707 + 708 + 709 + 710 + 711 + 712 + 713 + 714 + 715 + 716 + 717 + 718 + 719 + 720 + 721 + 722 + 723 + 724 + 725 + 726 + 727 + 728 + 729 + 730 + 731 + 732 + 733 + 734 + 735 + 736 + 737 + 738 + 739 + 740 + 741 + 742 + 743 + 744 + 745 + 746 + 747 + 748 + 749 + 750 + 751 + 752 + 753 + 754 + 755 + 756 + 757 + 758 + 759 + 760 + 761 + 762 + 763 + 764 + 765 + 766 + 767 + 768 + 769 + 770 + 771 + 772 + 773 + 774 + 775 + 776 + 777 + 778 + 779 + 780 + 781 + 782 + 783 + 784 + 785 + 786 + 787 + 788 + 789 + 790 + 791 + 792 + 793 + 794 + 795 + 796 + 797 + 798 + 799 + 800 + 801 + 802 + 803 + 804 + 805 + 806 + 807 + 808 + 809 + 810 + 811 + 812 + 813 + 814 + 815 + 816 + 817 + 818 + 819 + 820 + 821 + 822 + 823 + 824 + 825 + 826 + 827 + 828 + 829 + 830 + 831 + 832 + 833 + 834 + 835 + 836 + 837 + 838 + 839 + 840 + 841 + 842 + 843 + 844 + 845 + 846 + 847 + 848 + 849 + 850 + 851 + 852 + 853 + 854 + 855 + 856 + 857 + 858 + 859 + 860 + 861 + 862 + 863 + 864 + 865 + 866 + 867 + 868 + 869 + 870 + 871 + 872 + 873 + 874 + 875 + 876 + 877 + 878 + 879 + 880 + 881 + 882 + 883 + 884 + 885 + 886 + 887 + 888 + 889 + 890 + 891 + 892 + 893 + 894 + 895 + 896 + 897 + 898 + 899 + 900 + 901 + 902 + 903 + 904 + 905 + 906 + 907 + 908 + 909 + 910 + 911 + 912 + 913 + 914 + 915 + 916 + 917 + 918 + 919 + 920 + 921 + 922 + 923 + 924 + 925 + 926 + 927 + 928 + 929 + 930 + 931 + 932 + 933 + 934 + 935 + 936 + 937 + 938 + 939 + 940 + 941 + 942 + 943 + 944 + 945 + 946 + 947 + 948 + 949 + 950 + 951 + 952 + 953 + 954 + 955 + 956 + 957 + 958 + 959 + 960 + 961 + 962 + 963 + 964 + 965 + 966 + 967 + 968 + 969 + 970 + 971 + 972 + 973 + 974 + 975 + 976 + 977 + 978 + 979 + 980 + 981 + 982 + 983 + 984 + 985 + 986 + 987 + 988 + 989 + 990 + 991 + 992 + 993 + 994 + 995 + 996 + 997 + 998 + 999 + 1000 + 1001 + 1002 + 1003 + 1004 + 1005 + 1006 + 1007 + 1008 + 1009 + 1010 + 1011 + 1012 + 1013 + 1014 + 1015 + 1016 + 1017 + 1018 + 1019 + 1020 + 1021 + 1022 + 1023 + 1024 + 1025 + 1026 + 1027 + 1028 + 1029 + 1030 + 1031 + 1032 + 1033 + 1034 + 1035 + 1036 + 1037 + 1038 + 1039 + 1040 + 1041 + 1042 + 1043 + 1044 + 1045 + 1046 + 1047 + 1048 + 1049 + 1050 + 1051 + 1052 + 1053 + 1054 + 1055 + 1056 + 1057 + 1058 + 1059 + 1060 + 1061 + 1062 + 1063 + 1064 + 1065 + 1066 + 1067 + 1068 + 1069 + 1070 + 1071 + 1072 + 1073 + 1074 + 1075 + 1076 + 1077 + 1078 + 1079 + 1080 + 1081 + 1082 + 1083 + 1084 + 1085 + 1086 + 1087 + 1088 + 1089 + 1090 + 1091 + 1092 + 1093 + 1094 + 1095 + 1096 + 1097 + 1098 + 1099 + 1100 + 1101 + 1102 + 1103 + 1104 + 1105 + 1106 + 1107 + 1108 + 1109 + 1110 + 1111 + 1112 + 1113 + 1114 + 1115 + 1116 + 1117 + 1118 + 1119 + 1120 + 1121 + 1122 + 1123 + 1124 + 1125 + 1126 + 1127 + 1128 + 1129 + 1130 + 1131 + 1132 + 1133 + 1134 + 1135 + 1136 + 1137 + 1138 + 1139 + 1140 + 1141 + 1142 + 1143 + 1144 + 1145 + 1146 + 1147 + 1148 + 1149 + 1150 + 1151 + 1152 + 1153 + 1154 + 1155 + 1156 + 1157 + 1158 + 1159 + 1160 + 1161 + 1162 + 1163 + 1164 + 1165 + 1166 + 1167 + 1168 + 1169 + 1170 + 1171 + 1172 + 1173 + 1174 + 1175 + 1176 + 1177 + 1178 + 1179 + 1180 + 1181 + 1182 + 1183 + 1184 + 1185 + 1186 + 1187 + 1188 + 1189 + 1190 + 1191 + 1192 + 1193 + 1194 + 1195 + 1196 + 1197 + 1198 + 1199 + 1200 + 1201 + 1202 + 1203 + 1204 + 1205 + 1206 + 1207 + 1208 + 1209 + 1210 + 1211 + 1212 + 1213 + 1214 + 1215 + 1216 + 1217 + 1218 + 1219 + 1220 + 1221 + 1222 + 1223 + 1224 + 1225 + 1226 + 1227 + 1228 + 1229 + 1230 + 1231 + 1232 + 1233 + 1234 + 1235 + 1236 + 1237 + 1238 + 1239 + 1240 + 1241 + 1242 + 1243 + 1244 + 1245 + 1246 + 1247 + 1248 + 1249 + 1250 + 1251 + 1252 + 1253 + 1254 + 1255 + 1256 + 1257 + 1258 + 1259 + 1260 + 1261 + 1262 + 1263 + 1264 + 1265 + 1266 + 1267 + 1268 + 1269 + 1270 + 1271 + 1272 + 1273 + 1274 + 1275 + 1276 + 1277 + 1278 + 1279 + 1280 + 1281 + 1282 + 1283 + 1284 + 1285 + 1286 + 1287 + 1288 + 1289 + 1290 + 1291 + 1292 + 1293 + 1294 + 1295 + 1296 + 1297 + 1298 + 1299 + 1300 + 1301 + 1302 + 1303 + 1304 + 1305 + 1306 + 1307 + 1308 + 1309 + 1310 + 1311 + 1312 + 1313 + 1314 + 1315 + 1316 + 1317 + 1318 + 1319 + 1320 + 1321 + 1322 + 1323 + 1324 + 1325 + 1326 + 1327 + 1328 + 1329 + 1330 + 1331 + 1332 + 1333 + 1334 + 1335 + 1336 + 1337 + 1338 + 1339 + 1340 + 1341 + 1342 + 1343 + 1344 + 1345 + 1346 + 1347 + 1348 + 1349 + 1350 + 1351 + 1352 + 1353 + 1354 + 1355 + 1356 + 1357 + 1358 + 1359 + 1360 + 1361 + 1362 + 1363 + 1364 + 1365 + 1366 + 1367 + 1368 + 1369 + 1370 + 1371 + 1372 + 1373 + 1374 + 1375 + 1376 + 1377 + 1378 + 1379 + 1380 + 1381 + 1382 + 1383 + 1384 + 1385 + 1386 + 1387 + 1388 + 1389 + 1390 + 1391 + 1392 + 1393 + 1394 + 1395 + 1396 + 1397 + 1398 + 1399 + 1400 + 1401 + 1402 + 1403 + 1404 + 1405 + 1406 + 1407 + 1408 + 1409 + 1410 + 1411 + 1412 + 1413 + 1414 + 1415 + 1416 + 1417 + 1418 + 1419 + 1420 + 1421 + 1422 + 1423 + 1424 + 1425 + 1426 + 1427 + 1428 + 1429 + 1430 + 1431 + 1432 + 1433 + 1434 + 1435 + 1436 + 1437 + 1438 + 1439 + 1440 + 1441 + 1442 + 1443 + 1444 + 1445 + 1446 + 1447 + 1448 + 1449 + 1450 + 1451 + 1452 + 1453 + 1454 + 1455 + 1456 + 1457 + 1458 + 1459 + 1460 + 1461 + 1462 + 1463 + 1464 + 1465 + 1466 + 1467 + 1468 + 1469 + 1470 + 1471 + 1472 + 1473 + 1474 + 1475 + 1476 + 1477 + 1478 + 1479 + 1480 + 1481 + 1482 + 1483 + 1484 + 1485 + 1486 + 1487 + 1488 + 1489 + 1490 + 1491 + 1492 + 1493 + 1494 + 1495 + 1496 + 1497 + 1498 + 1499 + 1500 + 1501 + 1502 + 1503 + 1504 + 1505 + 1506 + 1507 + 1508 + 1509 + 1510 + 1511 + 1512 + 1513 + 1514 + 1515 + 1516 + 1517 + 1518 + 1519 + 1520 + 1521 + 1522 + 1523 + 1524 + 1525 + 1526 + 1527 + 1528 + 1529 + 1530 + 1531 + 1532 + 1533 + 1534 + 1535 + 1536 + 1537 + 1538 + 1539 + 1540 + 1541 + 1542 + 1543 + 1544 + 1545 + 1546 + 1547 + 1548 + 1549 + 1550 + 1551 + 1552 + 1553 + 1554 + 1555 + 1556 + 1557 + 1558 + 1559 + 1560 + 1561 + 1562 + 1563 + 1564 + 1565 + 1566 + 1567 + 1568 + 1569 + 1570 + 1571 + 1572 + 1573 + 1574 + 1575 + 1576 + 1577 + 1578 + 1579 + 1580 + 1581 + 1582 + 1583 + 1584 + 1585 + 1586 + 1587 + 1588 + 1589 + 1590 + 1591 + 1592 + 1593 + 1594 + 1595 + 1596 + 1597 + 1598 + 1599 + 1600 + 1601 + 1602 + 1603 + 1604 + 1605 + 1606 + 1607 + 1608 + 1609 + 1610 + 1611 + 1612 + 1613 + 1614 + 1615 + 1616 + 1617 + 1618 + 1619 + 1620 + 1621 + 1622 + 1623 + 1624 + 1625 + 1626 + 1627 + 1628 + 1629 + 1630 + 1631 + 1632 + 1633 + 1634 + 1635 + 1636 + 1637 + 1638 + 1639 + 1640 + 1641 + 1642 + 1643 + 1644 + 1645 + 1646 + 1647 + 1648 + 1649 + 1650 + 1651 + 1652 + 1653 + 1654 + 1655 + 1656 + 1657 + 1658 + 1659 + 1660 + 1661 + 1662 + 1663 + 1664 + 1665 + 1666 + 1667 + 1668 + 1669 + 1670 + 1671 + 1672 + 1673 + 1674 + 1675 + 1676 + 1677 + 1678 + 1679 + 1680 + 1681 + 1682 + 1683 + 1684 + 1685 + 1686 + 1687 + 1688 + 1689 + 1690 + 1691 + 1692 + 1693 + 1694 + 1695 + 1696 + 1697 + 1698 + 1699 + 1700 + 1701 + 1702 + 1703 + 1704 + 1705 + 1706 + 1707 + 1708 + 1709 + 1710 + 1711 + 1712 + 1713 + 1714 + 1715 + 1716 + 1717 + 1718 + 1719 + 1720 + 1721 + 1722 + 1723 + 1724 + 1725 + 1726 + 1727 + 1728 + 1729 + 1730 + 1731 + 1732 + 1733 + 1734 + 1735 + 1736 + 1737 + 1738 + 1739 + 1740 + 1741 + 1742 + 1743 + 1744 + 1745 + 1746 + 1747 + 1748 + 1749 + 1750 + 1751 + 1752 + 1753 + 1754 + 1755 + 1756 + 1757 + 1758 + 1759 + 1760 + 1761 + 1762 + 1763 + 1764 + 1765 + 1766 + 1767 + 1768 + 1769 + 1770 + 1771 + 1772 + 1773 + 1774 + 1775 + 1776 + 1777 + 1778 + 1779 + 1780 + 1781 + 1782 + 1783 + 1784 + 1785 + 1786 + 1787 + 1788 + 1789 + 1790 + 1791 + 1792 + 1793 + 1794 + 1795 + 1796 + 1797 + 1798 + 1799 + 1800 + 1801 + 1802 + 1803 + 1804 + 1805 + 1806 + 1807 + 1808 + 1809 + 1810 + 1811 + 1812 + 1813 + 1814 + 1815 + 1816 + 1817 + 1818 + 1819 + 1820 + 1821 + 1822 + 1823 + 1824 + 1825 + 1826 + 1827 + 1828 + 1829 + 1830 + 1831 + 1832 + 1833 + 1834 + 1835 + 1836 + 1837 + 1838 + 1839 + 1840 + 1841 + 1842 + 1843 + 1844 + 1845 + 1846 + 1847 + 1848 + 1849 + 1850 + 1851 + 1852 + 1853 + 1854 + 1855 + 1856 + 1857 + 1858 + 1859 + 1860 + 1861 + 1862 + 1863 + 1864 + 1865 + 1866 + 1867 + 1868 + 1869 + 1870 + 1871 + 1872 + 1873 + 1874 + 1875 + 1876 + 1877 + 1878 + 1879 + 1880 + 1881 + 1882 + 1883 + 1884 + 1885 + 1886 + 1887 + 1888 + 1889 + 1890 + 1891 + 1892 + 1893 + 1894 + 1895 + 1896 + 1897 + 1898 + 1899 + 1900 + 1901 + 1902 + 1903 + 1904 + 1905 + 1906 + 1907 + 1908 + 1909 + 1910 + 1911 + 1912 + 1913 + 1914 + 1915 + 1916 + 1917 + 1918 + 1919 + 1920 + 1921 + 1922 + 1923 + 1924 + 1925 + 1926 + 1927 + 1928 + 1929 + 1930 + 1931 + 1932 + 1933 + 1934 + 1935 + 1936 + 1937 + 1938 + 1939 + 1940 + 1941 + 1942 + 1943 + 1944 + 1945 + 1946 + 1947 + 1948 + 1949 + 1950 + 1951 + 1952 + 1953 + 1954 + 1955 + 1956 + 1957 + 1958 + 1959 + 1960 + 1961 + 1962 + 1963 + 1964 + 1965 + 1966 + 1967 + 1968 + 1969 + 1970 + 1971 + 1972 + 1973 + 1974 + 1975 + 1976 + 1977 + 1978 + 1979 + 1980 + 1981 + 1982 + 1983 + 1984 + 1985 + 1986 + 1987 + 1988 + 1989 + 1990 + 1991 + 1992 + 1993 + 1994 + 1995 + 1996 + 1997 + 1998 + 1999 + 2000 + 2001 + 2002 + 2003 + 2004 + 2005 + 2006 + 2007 + 2008 + 2009 + 2010 + 2011 + 2012 + 2013 + 2014 + 2015 + 2016 + 2017 + 2018 + 2019 + 2020 + 2021 + 2022 + 2023 + 2024 + 2025 + 2026 + 2027 + 2028 + 2029 + 2030 + 2031 + 2032 + 2033 + 2034 + 2035 + 2036 + 2037 + 2038 + 2039 + 2040 + 2041 + 2042 + 2043 + 2044 + 2045 + 2046 + 2047 + 2048 + 2049 + 2050 + 2051 + 2052 + 2053 + 2054 + 2055 + 2056 + 2057 + 2058 + 2059 + 2060 + 2061 + 2062 + 2063 + 2064 + 2065 + 2066 + 2067 + 2068 + 2069 + 2070 + 2071 + 2072 + 2073 + 2074 + 2075 + 2076 + 2077 + 2078 + 2079 + 2080 + 2081 + 2082 + 2083 + 2084 + 2085 + 2086 + 2087 + 2088 + 2089 + 2090 + 2091 + 2092 + 2093 + 2094 + 2095 + 2096 + 2097 + 2098 + 2099 + 2100 + 2101 + 2102 + 2103 + 2104 + 2105 + 2106 + 2107 + 2108 + 2109 + 2110 + 2111 + 2112 + 2113 + 2114 + 2115 + 2116 + 2117 + 2118 + 2119 + 2120 + 2121 + 2122 + 2123 + 2124 + 2125 + 2126 + 2127 + 2128 + 2129 + 2130 + 2131 + 2132 + 2133 + 2134 + 2135 + 2136 + 2137 + 2138 + 2139 + 2140 + 2141 + 2142 + 2143 + 2144 + 2145 + 2146 + 2147 + 2148 + 2149 + 2150 + 2151 + 2152 + 2153 + 2154 + 2155 + 2156 + 2157 + 2158 + 2159 + 2160 + 2161 + 2162 + 2163 + 2164 + 2165 + 2166 + 2167 + 2168 + 2169 + 2170 + 2171 + 2172 + 2173 + 2174 + 2175 + 2176 + 2177 + 2178 + 2179 + 2180 + 2181 + 2182 + 2183 + 2184 + 2185 + 2186 + 2187 + 2188 + 2189 + 2190 + 2191 + 2192 + 2193 + 2194 + 2195 + 2196 + 2197 + 2198 + 2199 + 2200 + 2201 + 2202 + 2203 + 2204 + 2205 + 2206 + 2207 + 2208 + 2209 + 2210 + 2211 + 2212 + 2213 + 2214 + 2215 + 2216 + 2217 + 2218 + 2219 + 2220 + 2221 + 2222 + 2223 + 2224 + 2225 + 2226 + 2227 + 2228 + 2229 + 2230 + 2231 + 2232 + 2233 + 2234 + 2235 + 2236 + 2237 + 2238 + 2239 + 2240 + 2241 + 2242 + 2243 + 2244 + 2245 + 2246 + 2247 + 2248 + 2249 + 2250 + 2251 + 2252 + 2253 + 2254 + 2255 + 2256 + 2257 + 2258 + 2259 + 2260 + 2261 + 2262 + 2263 + 2264 + 2265 + 2266 + 2267 + 2268 + 2269 + 2270 + 2271 + 2272 + 2273 + 2274 + 2275 + 2276 + 2277 + 2278 + 2279 + 2280 + 2281 + 2282 + 2283 + 2284 + 2285 + 2286 + 2287 + 2288 + 2289 + 2290 + 2291 + 2292 + 2293 + 2294 + 2295 + 2296 + 2297 + 2298 + 2299 + 2300 + 2301 + 2302 + 2303 + 2304 + 2305 + 2306 + 2307 + 2308 + 2309 + 2310 + 2311 + 2312 + 2313 + 2314 + 2315 + 2316 + 2317 + 2318 + 2319 + 2320 + 2321 + 2322 + 2323 + 2324 + 2325 + 2326 + 2327 + 2328 + 2329 + 2330 + 2331 + 2332 + 2333 + 2334 + 2335 + 2336 + 2337 + 2338 + 2339 + 2340 + 2341 + 2342 + 2343 + 2344 + 2345 + 2346 + 2347 + 2348 + 2349 + 2350 + 2351 + 2352 + 2353 + 2354 + 2355 + 2356 + 2357 + 2358 + 2359 + 2360 + 2361 + 2362 + 2363 + 2364 + 2365 + 2366 + 2367 + 2368 + 2369 + 2370 + 2371 + 2372 + 2373 + 2374 + 2375 + 2376 + 2377 + 2378 + 2379 + 2380 + 2381 + 2382 + 2383 + 2384 + 2385 + 2386 + 2387 + 2388 + 2389 + 2390 + 2391 + 2392 + 2393 + 2394 + 2395 + 2396 + 2397 + 2398 + 2399 + 2400 + 2401 + 2402 + 2403 + 2404 + 2405 + 2406 + 2407 + 2408 + 2409 + 2410 + 2411 + 2412 + 2413 + 2414 + 2415 + 2416 + 2417 + 2418 + 2419 + 2420 + 2421 + 2422 + 2423 + 2424 + 2425 + 2426 + 2427 + 2428 + 2429 + 2430 + 2431 + 2432 + 2433 + 2434 + 2435 + 2436 + 2437 + 2438 + 2439 + 2440 + 2441 + 2442 + 2443 + 2444 + 2445 + 2446 + 2447 + 2448 + 2449 + 2450 + 2451 + 2452 + 2453 + 2454 + 2455 + 2456 + 2457 + 2458 + 2459 + 2460 + 2461 + 2462 + 2463 + 2464 + 2465 + 2466 + 2467 + 2468 + 2469 + 2470 + 2471 + 2472 + 2473 + 2474 + 2475 + 2476 + 2477 + 2478 + 2479 + 2480 + 2481 + 2482 + 2483 + 2484 + 2485 + 2486 + 2487 + 2488 + 2489 + 2490 + 2491 + 2492 + 2493 + 2494 + 2495 + 2496 + 2497 + 2498 + 2499 + 2500 + 2501 + 2502 + 2503 + 2504 + 2505 + 2506 + 2507 + 2508 + 2509 + 2510 + 2511 + 2512 + 2513 + 2514 + 2515 + 2516 + 2517 + 2518 + 2519 + 2520 + 2521 + 2522 + 2523 + 2524 + 2525 + 2526 + 2527 + 2528 + 2529 + 2530 + 2531 + 2532 + 2533 + 2534 + 2535 + 2536 + 2537 + 2538 + 2539 + 2540 + 2541 + 2542 + 2543 + 2544 + 2545 + 2546 + 2547 + 2548 + 2549 + 2550 + 2551 + 2552 + 2553 + 2554 + 2555 + 2556 + 2557 + 2558 + 2559 + 2560 + 2561 + 2562 + 2563 + 2564 + 2565 + 2566 + 2567 + 2568 + 2569 + 2570 + 2571 + 2572 + 2573 + 2574 + 2575 + 2576 + 2577 + 2578 + 2579 + 2580 + 2581 + 2582 + 2583 + 2584 + 2585 + 2586 + 2587 + 2588 + 2589 + 2590 + 2591 + 2592 + 2593 + 2594 + 2595 + 2596 + 2597 + 2598 + 2599 + 2600 + 2601 + 2602 + 2603 + 2604 + 2605 + 2606 + 2607 + 2608 + 2609 + 2610 + 2611 + 2612 + 2613 + 2614 + 2615 + 2616 + 2617 + 2618 + 2619 + 2620 + 2621 + 2622 + 2623 + 2624 + 2625 + 2626 + 2627 + 2628 + 2629 + 2630 + 2631 + 2632 + 2633 + 2634 + 2635 + 2636 + 2637 + 2638 + 2639 + 2640 + 2641 + 2642 + 2643 + 2644 + 2645 + 2646 + 2647 + 2648 + 2649 + 2650 + 2651 + 2652 + 2653 + 2654 + 2655 + 2656 + 2657 + 2658 + 2659 + 2660 + 2661 + 2662 + 2663 + 2664 + 2665 + 2666 + 2667 + 2668 + 2669 + 2670 + 2671 + 2672 + 2673 + 2674 + 2675 + 2676 + 2677 + 2678 + 2679 + 2680 + 2681 + 2682 + 2683 + 2684 + 2685 + 2686 + 2687 + 2688 + 2689 + 2690 + 2691 + 2692 + 2693 + 2694 + 2695 + 2696 + 2697 + 2698 + 2699 + 2700 + 2701 + 2702 + 2703 + 2704 + 2705 + 2706 + 2707 + 2708 + 2709 + 2710 + 2711 + 2712 + 2713 + 2714 + 2715 + 2716 + 2717 + 2718 + 2719 + 2720 + 2721 + 2722 + 2723 + 2724 + 2725 + 2726 + 2727 + 2728 + 2729 + 2730 + 2731 + 2732 + 2733 + 2734 + 2735 + 2736 + 2737 + 2738 + 2739 + 2740 + 2741 + 2742 + 2743 + 2744 + 2745 + 2746 + 2747 + 2748 + 2749 + 2750 + 2751 + 2752 + 2753 + 2754 + 2755 + 2756 + 2757 + 2758 + 2759 + 2760 + 2761 + 2762 + 2763 + 2764 + 2765 + 2766 + 2767 + 2768 + 2769 + 2770 + 2771 + 2772 + 2773 + 2774 + 2775 + 2776 + 2777 + 2778 + 2779 + 2780 + 2781 + 2782 + 2783 + 2784 + 2785 + 2786 + 2787 + 2788 + 2789 + 2790 + 2791 + 2792 + 2793 + 2794 + 2795 + 2796 + 2797 + 2798 + 2799 + 2800 + 2801 + 2802 + 2803 + 2804 + 2805 + 2806 + 2807 + 2808 + 2809 + 2810 + 2811 + 2812 + 2813 + 2814 + 2815 + 2816 + 2817 + 2818 + 2819 + 2820 + 2821 + 2822 + 2823 + 2824 + 2825 + 2826 + 2827 + 2828 + 2829 + 2830 + 2831 + 2832 + 2833 + 2834 + 2835 + 2836 + 2837 + 2838 + 2839 + 2840 + 2841 + 2842 + 2843 + 2844 + 2845 + 2846 + 2847 + 2848 + 2849 + 2850 + 2851 + 2852 + 2853 + 2854 + 2855 + 2856 + 2857 + 2858 + 2859 + 2860 + 2861 + 2862 + 2863 + 2864 + 2865 + 2866 + 2867 + 2868 + 2869 + 2870 + 2871 + 2872 + 2873 + 2874 + 2875 + 2876 + 2877 + 2878 + 2879 + 2880 + 2881 + 2882 + 2883 + 2884 + 2885 + 2886 + 2887 + 2888 + 2889 + 2890 + 2891 + 2892 + 2893 + 2894 + 2895 + 2896 + 2897 + 2898 + 2899 + 2900 + 2901 + 2902 + 2903 + 2904 + 2905 + 2906 + 2907 + 2908 + 2909 + 2910 + 2911 + 2912 + 2913 + 2914 + 2915 + 2916 + 2917 + 2918 + 2919 + 2920 + 2921 + 2922 + 2923 + 2924 + 2925 + 2926 + 2927 + 2928 + 2929 + 2930 + 2931 + 2932 + 2933 + 2934 + 2935 + 2936 + 2937 + 2938 + 2939 + 2940 + 2941 + 2942 + 2943 + 2944 + 2945 + 2946 + 2947 + 2948 + 2949 + 2950 + 2951 + 2952 + 2953 + 2954 + 2955 + 2956 + 2957 + 2958 + 2959 + 2960 + 2961 + 2962 + 2963 + 2964 + 2965 + 2966 + 2967 + 2968 + 2969 + 2970 + 2971 + 2972 + 2973 + 2974 + 2975 + 2976 + 2977 + 2978 + 2979 + 2980 + 2981 + 2982 + 2983 + 2984 + 2985 + 2986 + 2987 + 2988 + 2989 + 2990 + 2991 + 2992 + 2993 + 2994 + 2995 + 2996 + 2997 + 2998 + 2999 + 3000 + 3001 + 3002 + 3003 + 3004 + 3005 + 3006 + 3007 + 3008 + 3009 + 3010 + 3011 + 3012 + 3013 + 3014 + 3015 + 3016 + 3017 + 3018 + 3019 + 3020 + 3021 + 3022 + 3023 + 3024 + 3025 + 3026 + 3027 + 3028 + 3029 + 3030 + 3031 + 3032 + 3033 + 3034 + 3035 + 3036 + 3037 + 3038 + 3039 + 3040 + 3041 + 3042 + 3043 + 3044 + 3045 + 3046 + 3047 + 3048 + 3049 + 3050 + 3051 + 3052 + 3053 + 3054 + 3055 + 3056 + 3057 + 3058 + 3059 + 3060 + 3061 + 3062 + 3063 + 3064 + 3065 + 3066 + 3067 + 3068 + 3069 + 3070 + 3071 + 3072 + 3073 + 3074 + 3075 + 3076 + 3077 + 3078 + 3079 + 3080 + 3081 + 3082 + 3083 + 3084 + 3085 + 3086 + 3087 + 3088 + 3089 + 3090 + 3091 + 3092 + 3093 + 3094 + 3095 + 3096 + 3097 + 3098 + 3099 + 3100 + 3101 + 3102 + 3103 + 3104 + 3105 + 3106 + 3107 + 3108 + 3109 + 3110 + 3111 + 3112 + 3113 + 3114 + 3115 + 3116 + 3117 + 3118 + 3119 + 3120 + 3121 + 3122 + 3123 + 3124 + 3125 + 3126 + 3127 + 3128 + 3129 + 3130 + 3131 + 3132 + 3133 + 3134 + 3135 + 3136 + 3137 + 3138 + 3139 + 3140 + 3141 + 3142 + 3143 + 3144 + 3145 + 3146 + 3147 + 3148 + 3149 + 3150 + 3151 + 3152 + 3153 + 3154 + 3155 + 3156 + 3157 + 3158 + 3159 + 3160 + 3161 + 3162 + 3163 + 3164 + 3165 + 3166 + 3167 + 3168 + 3169 + 3170 + 3171 + 3172 + 3173 + 3174 + 3175 + 3176 + 3177 + 3178 + 3179 + 3180 + 3181 + 3182 + 3183 + 3184 + 3185 + 3186 + 3187 + 3188 + 3189 + 3190 + 3191 + 3192 + 3193 + 3194 + 3195 + 3196 + 3197 + 3198 + 3199 + 3200 + 3201 + 3202 + 3203 + 3204 + 3205 + 3206 + 3207 + 3208 + 3209 + 3210 + 3211 + 3212 + 3213 + 3214 + 3215 + 3216 + 3217 + 3218 + 3219 + 3220 + 3221 + 3222 + 3223 + 3224 + 3225 + 3226 + 3227 + 3228 + 3229 + 3230 + 3231 + 3232 + 3233 + 3234 + 3235 + 3236 + 3237 + 3238 + 3239 + 3240 + 3241 + 3242 + 3243 + 3244 + 3245 + 3246 + 3247 + 3248 + 3249 + 3250 + 3251 + 3252 + 3253 + 3254 + 3255 + 3256 + 3257 + 3258 + 3259 + 3260 + 3261 + 3262 + 3263 + 3264 + 3265 + 3266 + 3267 + 3268 + 3269 + 3270 + 3271 + 3272 + 3273 + 3274 + 3275 + 3276 + 3277 + 3278 + 3279 + 3280 + 3281 + 3282 + 3283 + 3284 + 3285 + 3286 + 3287 + 3288 + 3289 + 3290 + 3291 + 3292 + 3293 + 3294 + 3295 + 3296 + 3297 + 3298 + 3299 + 3300 + 3301 + 3302 + 3303 + 3304 + 3305 + 3306 + 3307 + 3308 + 3309 + 3310 + 3311 + 3312 + 3313 + 3314 + 3315 + 3316 + 3317 + 3318 + 3319 + 3320 + 3321 + 3322 + 3323 + 3324 + 3325 + 3326 + 3327 + 3328 + 3329 + 3330 + 3331 + 3332 + 3333 + 3334 + 3335 + 3336 + 3337 + 3338 + 3339 + 3340 + 3341 + 3342 + 3343 + 3344 + 3345 + 3346 + 3347 + 3348 + 3349 + 3350 + 3351 + 3352 + 3353 + 3354 + 3355 + 3356 + 3357 + 3358 + 3359 + 3360 + 3361 + 3362 + 3363 + 3364 + 3365 + 3366 + 3367 + 3368 + 3369 + 3370 + 3371 + 3372 + 3373 + 3374 + 3375 + 3376 + 3377 + 3378 + 3379 + 3380 + 3381 + 3382 + 3383 + 3384 + 3385 + 3386 + 3387 + 3388 + 3389 + 3390 + 3391 + 3392 + 3393 + 3394 + 3395 + 3396 + 3397 + 3398 + 3399 + 3400 + 3401 + 3402 + 3403 + 3404 + 3405 + 3406 + 3407 + 3408 + 3409 + 3410 + 3411 + 3412 + 3413 + 3414 + 3415 + 3416 + 3417 + 3418 + 3419 + 3420 + 3421 + 3422 + 3423 + 3424 + 3425 + 3426 + 3427 + 3428 + 3429 + 3430 + 3431 + 3432 + 3433 + 3434 + 3435 + 3436 + 3437 + 3438 + 3439 + 3440 + 3441 + 3442 + 3443 + 3444 + 3445 + 3446 + 3447 + 3448 + 3449 + 3450 + 3451 + 3452 + 3453 + 3454 + 3455 + 3456 + 3457 + 3458 + 3459 + 3460 + 3461 + 3462 + 3463 + 3464 + 3465 + 3466 + 3467 + 3468 + 3469 + 3470 + 3471 + 3472 + 3473 + 3474 + 3475 + 3476 + 3477 + 3478 + 3479 + 3480 + 3481 + 3482 + 3483 + 3484 + 3485 + 3486 + 3487 + 3488 + 3489 + 3490 + 3491 + 3492 + 3493 + 3494 + 3495 + 3496 + 3497 + 3498 + 3499 + 3500 + 3501 + 3502 + 3503 + 3504 + 3505 + 3506 + 3507 + 3508 + 3509 + 3510 + 3511 + 3512 + 3513 + 3514 + 3515 + 3516 + 3517 + 3518 + 3519 + 3520 + 3521 + 3522 + 3523 + 3524 + 3525 + 3526 + 3527 + 3528 + 3529 + 3530 + 3531 + 3532 + 3533 + 3534 + 3535 + 3536 + 3537 + 3538 + 3539 + 3540 + 3541 + 3542 + 3543 + 3544 + 3545 + 3546 + 3547 + 3548 + 3549 + 3550 + 3551 + 3552 + 3553 + 3554 + 3555 + 3556 + 3557 + 3558 + 3559 + 3560 + 3561 + 3562 + 3563 + 3564 + 3565 + 3566 + 3567 + 3568 + 3569 + 3570 + 3571 + 3572 + 3573 + 3574 + 3575 + 3576 + 3577 + 3578 + 3579 + 3580 + 3581 + 3582 + 3583 + 3584 + 3585 + 3586 + 3587 + 3588 + 3589 + 3590 + 3591 + 3592 + 3593 + 3594 + 3595 + 3596 + 3597 + 3598 + 3599 + 3600 + 3601 + 3602 + 3603 + 3604 + 3605 + 3606 + 3607 + 3608 + 3609 + 3610 + 3611 + 3612 + 3613 + 3614 + 3615 + 3616 + 3617 + 3618 + 3619 + 3620 + 3621 + 3622 + 3623 + 3624 + 3625 + 3626 + 3627 + 3628 + 3629 + 3630 + 3631 + 3632 + 3633 + 3634 + 3635 + 3636 + 3637 + 3638 + 3639 + 3640 + 3641 + 3642 + 3643 + 3644 + 3645 + 3646 + 3647 + 3648 + 3649 + 3650 + 3651 + 3652 + 3653 + 3654 + 3655 + 3656 + 3657 + 3658 + 3659 + 3660 + 3661 + 3662 + 3663 + 3664 + 3665 + 3666 + 3667 + 3668 + 3669 + 3670 + 3671 + 3672 + 3673 + 3674 + 3675 + 3676 + 3677 + 3678 + 3679 + 3680 + 3681 + 3682 + 3683 + 3684 + 3685 + 3686 + 3687 + 3688 + 3689 + 3690 + 3691 + 3692 + 3693 + 3694 + 3695 + 3696 + 3697 + 3698 + 3699 + 3700 + 3701 + 3702 + 3703 + 3704 + 3705 + 3706 + 3707 + 3708 + 3709 + 3710 + 3711 + 3712 + 3713 + 3714 + 3715 + 3716 + 3717 + 3718 + 3719 + 3720 + 3721 + 3722 + 3723 + 3724 + 3725 + 3726 + 3727 + 3728 + 3729 + 3730 + 3731 + 3732 + 3733 + 3734 + 3735 + 3736 + 3737 + 3738 + 3739 + 3740 + 3741 + 3742 + 3743 + 3744 + 3745 + 3746 + 3747 + 3748 + 3749 + 3750 + 3751 + 3752 + 3753 + 3754 + 3755 + 3756 + 3757 + 3758 + 3759 + 3760 + 3761 + 3762 + 3763 + 3764 + 3765 + 3766 + 3767 + 3768 + 3769 + 3770 + 3771 + 3772 + 3773 + 3774 + 3775 + 3776 + 3777 + 3778 + 3779 + 3780 + 3781 + 3782 + 3783 + 3784 + 3785 + 3786 + 3787 + 3788 + 3789 + 3790 + 3791 + 3792 + 3793 + 3794 + 3795 + 3796 + 3797 + 3798 + 3799 + 3800 + 3801 + 3802 + 3803 + 3804 + 3805 + 3806 + 3807 + 3808 + 3809 + 3810 + 3811 + 3812 + 3813 + 3814 + 3815 + 3816 + 3817 + 3818 + 3819 + 3820 + 3821 + 3822 + 3823 + 3824 + 3825 + 3826 + 3827 + 3828 + 3829 + 3830 + 3831 + 3832 + 3833 + 3834 + 3835 + 3836 + 3837 + 3838 + 3839 + 3840 + 3841 + 3842 + 3843 + 3844 + 3845 + 3846 + 3847 + 3848 + 3849 + 3850 + 3851 + 3852 + 3853 + 3854 + 3855 + 3856 + 3857 + 3858 + 3859 + 3860 + 3861 + 3862 + 3863 + 3864 + 3865 + 3866 + 3867 + 3868 + 3869 + 3870 + 3871 + 3872 + 3873 + 3874 + 3875 + 3876 + 3877 + 3878 + 3879 + 3880 + 3881 + 3882 + 3883 + 3884 + 3885 + 3886 + 3887 + 3888 + 3889 + 3890 + 3891 + 3892 + 3893 + 3894 + 3895 + 3896 + 3897 + 3898 + 3899 + 3900 + 3901 + 3902 + 3903 + 3904 + 3905 + 3906 + 3907 + 3908 + 3909 + 3910 + 3911 + 3912 + 3913 + 3914 + 3915 + 3916 + 3917 + 3918 + 3919 + 3920 + 3921 + 3922 + 3923 + 3924 + 3925 + 3926 + 3927 + 3928 + 3929 + 3930 + 3931 + 3932 + 3933 + 3934 + 3935 + 3936 + 3937 + 3938 + 3939 + 3940 + 3941 + 3942 + 3943 + 3944 + 3945 + 3946 + 3947 + 3948 + 3949 + 3950 + 3951 + 3952 + 3953 + 3954 + 3955 + 3956 + 3957 + 3958 + 3959 + 3960 + 3961 + 3962 + 3963 + 3964 + 3965 + 3966 + 3967 + 3968 + 3969 + 3970 + 3971 + 3972 + 3973 + 3974 + 3975 + 3976 + 3977 + 3978 + 3979 + 3980 + 3981 + 3982 + 3983 + 3984 + 3985 + 3986 + 3987 + 3988 + 3989 + 3990 + 3991 + 3992 + 3993 + 3994 + 3995 + 3996 + 3997 + 3998 + 3999 + 4000 + 4001 + 4002 + 4003 + 4004 + 4005 + 4006 + 4007 + 4008 + 4009 + 4010 + 4011 + 4012 + 4013 + 4014 + 4015 + 4016 + 4017 + 4018 + 4019 + 4020 + 4021 + 4022 + 4023 + 4024 + 4025 + 4026 + 4027 + 4028 + 4029 + 4030 + 4031 + 4032 + 4033 + 4034 + 4035 + 4036 + 4037 + 4038 + 4039 + 4040 + 4041 + 4042 + 4043 + 4044 + 4045 + 4046 + 4047 + 4048 + 4049 + 4050 + 4051 + 4052 + 4053 + 4054 + 4055 + 4056 + 4057 + 4058 + 4059 + 4060 + 4061 + 4062 + 4063 + 4064 + 4065 + 4066 + 4067 + 4068 + 4069 + 4070 + 4071 + 4072 + 4073 + 4074 + 4075 + 4076 + 4077 + 4078 + 4079 + 4080 + 4081 + 4082 + 4083 + 4084 + 4085 + 4086 + 4087 + 4088 + 4089 + 4090 + 4091 + 4092 + 4093 + 4094 + 4095 + 4096 + 4097 + 4098 + 4099 + 4100 + 4101 + 4102 + 4103 + 4104 + 4105 + 4106 + 4107 + 4108 + 4109 + 4110 + 4111 + 4112 + 4113 + 4114 + 4115 + 4116 + 4117 + 4118 + 4119 + 4120 + 4121 + 4122 + 4123 + 4124 + 4125 + 4126 + 4127 + 4128 + 4129 + 4130 + 4131 + 4132 + 4133 + 4134 + 4135 + 4136 + 4137 + 4138 + 4139 + 4140 + 4141 + 4142 + 4143 + 4144 + 4145 + 4146 + 4147 + 4148 + 4149 + 4150 + 4151 + 4152 + 4153 + 4154 + 4155 + 4156 + 4157 + 4158 + 4159 + 4160 + 4161 + 4162 + 4163 + 4164 + 4165 + 4166 + 4167 + 4168 + 4169 + 4170 + 4171 + 4172 + 4173 + 4174 + 4175 + 4176 + 4177 + 4178 + 4179 + 4180 + 4181 + 4182 + 4183 + 4184 + 4185 + 4186 + 4187 + 4188 + 4189 + 4190 + 4191 + 4192 + 4193 + 4194 + 4195 + 4196 + 4197 + 4198 + 4199 + 4200 + 4201 + 4202 + 4203 + 4204 + 4205 + 4206 + 4207 + 4208 + 4209 + 4210 + 4211 + 4212 + 4213 + 4214 + 4215 + 4216 + 4217 + 4218 + 4219 + 4220 + 4221 + 4222 + 4223 + 4224 + 4225 + 4226 + 4227 + 4228 + 4229 + 4230 + 4231 + 4232 + 4233 + 4234 + 4235 + 4236 + 4237 + 4238 + 4239 + 4240 + 4241 + 4242 + 4243 + 4244 + 4245 + 4246 + 4247 + 4248 + 4249 + 4250 + 4251 + 4252 + 4253 + 4254 + 4255 + 4256 + 4257 + 4258 + 4259 + 4260 + 4261 + 4262 + 4263 + 4264 + 4265 + 4266 + 4267 + 4268 + 4269 + 4270 + 4271 + 4272 + 4273 + 4274 + 4275 + 4276 + 4277 + 4278 + 4279 + 4280 + 4281 + 4282 + 4283 + 4284 + 4285 + 4286 + 4287 + 4288 + 4289 + 4290 + 4291 + 4292 + 4293 + 4294 + 4295 + 4296 + 4297 + 4298 + 4299 + 4300 + 4301 + 4302 + 4303 + 4304 + 4305 + 4306 + 4307 + 4308 + 4309 + 4310 + 4311 + 4312 + 4313 + 4314 + 4315 + 4316 + 4317 + 4318 + 4319 + 4320 + 4321 + 4322 + 4323 + 4324 + 4325 + 4326 + 4327 + 4328 + 4329 + 4330 + 4331 + 4332 + 4333 + 4334 + 4335 + 4336 + 4337 + 4338 + 4339 + 4340 + 4341 + 4342 + 4343 + 4344 + 4345 + 4346 + 4347 + 4348 + 4349 + 4350 + 4351 + 4352 + 4353 + 4354 + 4355 + 4356 + 4357 + 4358 + 4359 + 4360 + 4361 + 4362 + 4363 + 4364 + 4365 + 4366 + 4367 + 4368 + 4369 + 4370 + 4371 + 4372 + 4373 + 4374 + 4375 + 4376 + 4377 + 4378 + 4379 + 4380 + 4381 + 4382 + 4383 + 4384 + 4385 + 4386 + 4387 + 4388 + 4389 + 4390 + 4391 + 4392 + 4393 + 4394 + 4395 + 4396 + 4397 + 4398 + 4399 + 4400 + 4401 + 4402 + 4403 + 4404 + 4405 + 4406 + 4407 + 4408 + 4409 + 4410 + 4411 + 4412 + 4413 + 4414 + 4415 + 4416 + 4417 + 4418 + 4419 + 4420 + 4421 + 4422 + 4423 + 4424 + 4425 + 4426 + 4427 + 4428 + 4429 + 4430 + 4431 + 4432 + 4433 + 4434 + 4435 + 4436 + 4437 + 4438 + 4439 + 4440 + 4441 + 4442 + 4443 + 4444 + 4445 + 4446 + 4447 + 4448 + 4449 + 4450 + 4451 + 4452 + 4453 + 4454 + 4455 + 4456 + 4457 + 4458 + 4459 + 4460 + 4461 + 4462 + 4463 + 4464 + 4465 + 4466 + 4467 + 4468 + 4469 + 4470 + 4471 + 4472 + 4473 + 4474 + 4475 + 4476 + 4477 + 4478 + 4479 + 4480 + 4481 + 4482 + 4483 + 4484 + 4485 + 4486 + 4487 + 4488 + 4489 + 4490 + 4491 + 4492 + 4493 + 4494 + 4495 + 4496 + 4497 + 4498 + 4499 + 4500 + 4501 + 4502 + 4503 + 4504 + 4505 + 4506 + 4507 + 4508 + 4509 + 4510 + 4511 + 4512 + 4513 + 4514 + 4515 + 4516 + 4517 + 4518 + 4519 + 4520 + 4521 + 4522 + 4523 + 4524 + 4525 + 4526 + 4527 + 4528 + 4529 + 4530 + 4531 + 4532 + 4533 + 4534 + 4535 + 4536 + 4537 + 4538 + 4539 + 4540 + 4541 + 4542 + 4543 + 4544 + 4545 + 4546 + 4547 + 4548 + 4549 + 4550 + 4551 + 4552 + 4553 + 4554 + 4555 + 4556 + 4557 + 4558 + 4559 + 4560 + 4561 + 4562 + 4563 + 4564 + 4565 + 4566 + 4567 + 4568 + 4569 + 4570 + 4571 + 4572 + 4573 + 4574 + 4575 + 4576 + 4577 + 4578 + 4579 + 4580 + 4581 + 4582 + 4583 + 4584 + 4585 + 4586 + 4587 + 4588 + 4589 + 4590 + 4591 + 4592 + 4593 + 4594 + 4595 + 4596 + 4597 + 4598 + 4599 + 4600 + 4601 + 4602 + 4603 + 4604 + 4605 + 4606 + 4607 + 4608 + 4609 + 4610 + 4611 + 4612 + 4613 + 4614 + 4615 + 4616 + 4617 + 4618 + 4619 + 4620 + 4621 + 4622 + 4623 + 4624 + 4625 + 4626 + 4627 + 4628 + 4629 + 4630 + 4631 + 4632 + 4633 + 4634 + 4635 + 4636 + 4637 + 4638 + 4639 + 4640 + 4641 + 4642 + 4643 + 4644 + 4645 + 4646 + 4647 + 4648 + 4649 + 4650 + 4651 + 4652 + 4653 + 4654 + 4655 + 4656 + 4657 + 4658 + 4659 + 4660 + 4661 + 4662 + 4663 + 4664 + 4665 + 4666 + 4667 + 4668 + 4669 + 4670 + 4671 + 4672 + 4673 + 4674 + 4675 + 4676 + 4677 + 4678 + 4679 + 4680 + 4681 + 4682 + 4683 + 4684 + 4685 + 4686 + 4687 + 4688 + 4689 + 4690 + 4691 + 4692 + 4693 + 4694 + 4695 + 4696 + 4697 + 4698 + 4699 + 4700 + 4701 + 4702 + 4703 + 4704 + 4705 + 4706 + 4707 + 4708 + 4709 + 4710 + 4711 + 4712 + 4713 + 4714 + 4715 + 4716 + 4717 + 4718 + 4719 + 4720 + 4721 + 4722 + 4723 + 4724 + 4725 + 4726 + 4727 + 4728 + 4729 + 4730 + 4731 + 4732 + 4733 + 4734 + 4735 + 4736 + 4737 + 4738 + 4739 + 4740 + 4741 + 4742 + 4743 + 4744 + 4745 + 4746 + 4747 + 4748 + 4749 + 4750 + 4751 + 4752 + 4753 + 4754 + 4755 + 4756 + 4757 + 4758 + 4759 + 4760 + 4761 + 4762 + 4763 + 4764 + 4765 + 4766 + 4767 + 4768 + 4769 + 4770 + 4771 + 4772 + 4773 + 4774 + 4775 + 4776 + 4777 + 4778 + 4779 + 4780 + 4781 + 4782 + 4783 + 4784 + 4785 + 4786 + 4787 + 4788 + 4789 + 4790 + 4791 + 4792 + 4793 + 4794 + 4795 + 4796 + 4797 + 4798 + 4799 + 4800 + 4801 + 4802 + 4803 + 4804 + 4805 + 4806 + 4807 + 4808 + 4809 + 4810 + 4811 + 4812 + 4813 + 4814 + 4815 + 4816 + 4817 + 4818 + 4819 + 4820 + 4821 + 4822 + 4823 + 4824 + 4825 + 4826 + 4827 + 4828 + 4829 + 4830 + 4831 + 4832 + 4833 + 4834 + 4835 + 4836 + 4837 + 4838 + 4839 + 4840 + 4841 + 4842 + 4843 + 4844 + 4845 + 4846 + 4847 + 4848 + 4849 + 4850 + 4851 + 4852 + 4853 + 4854 + 4855 + 4856 + 4857 + 4858 + 4859 + 4860 + 4861 + 4862 + 4863 + 4864 + 4865 + 4866 + 4867 + 4868 + 4869 + 4870 + 4871 + 4872 + 4873 + 4874 + 4875 + 4876 + 4877 + 4878 + 4879 + 4880 + 4881 + 4882 + 4883 + 4884 + 4885 + 4886 + 4887 + 4888 + 4889 + 4890 + 4891 + 4892 + 4893 + 4894 + 4895 + 4896 + 4897 + 4898 + 4899 + 4900 + 4901 + 4902 + 4903 + 4904 + 4905 + 4906 + 4907 + 4908 + 4909 + 4910 + 4911 + 4912 + 4913 + 4914 + 4915 + 4916 + 4917 + 4918 + 4919 + 4920 + 4921 + 4922 + 4923 + 4924 + 4925 + 4926 + 4927 + 4928 + 4929 + 4930 + 4931 + 4932 + 4933 + 4934 + 4935 + 4936 + 4937 + 4938 + 4939 + 4940 + 4941 + 4942 + 4943 + 4944 + 4945 + 4946 + 4947 + 4948 + 4949 + 4950 + 4951 + 4952 + 4953 + 4954 + 4955 + 4956 + 4957 + 4958 + 4959 + 4960 + 4961 + 4962 + 4963 + 4964 + 4965 + 4966 + 4967 + 4968 + 4969 + 4970 + 4971 + 4972 + 4973 + 4974 + 4975 + 4976 + 4977 + 4978 + 4979 + 4980 + 4981 + 4982 + 4983 + 4984 + 4985 + 4986 + 4987 + 4988 + 4989 + 4990 + 4991 + 4992 + 4993 + 4994 + 4995 + 4996 + 4997 + 4998 + 4999 + 5000 +(5000 rows) + +SELECT * FROM t1 LIMIT 10; + a +---- + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 +(10 rows) + +SELECt * FROM t2 WHERE b % 2 = 0; + b +------ + 2 + 4 + 6 + 8 + 10 + 12 + 14 + 16 + 18 + 20 + 22 + 24 + 26 + 28 + 30 + 32 + 34 + 36 + 38 + 40 + 42 + 44 + 46 + 48 + 50 + 52 + 54 + 56 + 58 + 60 + 62 + 64 + 66 + 68 + 70 + 72 + 74 + 76 + 78 + 80 + 82 + 84 + 86 + 88 + 90 + 92 + 94 + 96 + 98 + 100 + 102 + 104 + 106 + 108 + 110 + 112 + 114 + 116 + 118 + 120 + 122 + 124 + 126 + 128 + 130 + 132 + 134 + 136 + 138 + 140 + 142 + 144 + 146 + 148 + 150 + 152 + 154 + 156 + 158 + 160 + 162 + 164 + 166 + 168 + 170 + 172 + 174 + 176 + 178 + 180 + 182 + 184 + 186 + 188 + 190 + 192 + 194 + 196 + 198 + 200 + 202 + 204 + 206 + 208 + 210 + 212 + 214 + 216 + 218 + 220 + 222 + 224 + 226 + 228 + 230 + 232 + 234 + 236 + 238 + 240 + 242 + 244 + 246 + 248 + 250 + 252 + 254 + 256 + 258 + 260 + 262 + 264 + 266 + 268 + 270 + 272 + 274 + 276 + 278 + 280 + 282 + 284 + 286 + 288 + 290 + 292 + 294 + 296 + 298 + 300 + 302 + 304 + 306 + 308 + 310 + 312 + 314 + 316 + 318 + 320 + 322 + 324 + 326 + 328 + 330 + 332 + 334 + 336 + 338 + 340 + 342 + 344 + 346 + 348 + 350 + 352 + 354 + 356 + 358 + 360 + 362 + 364 + 366 + 368 + 370 + 372 + 374 + 376 + 378 + 380 + 382 + 384 + 386 + 388 + 390 + 392 + 394 + 396 + 398 + 400 + 402 + 404 + 406 + 408 + 410 + 412 + 414 + 416 + 418 + 420 + 422 + 424 + 426 + 428 + 430 + 432 + 434 + 436 + 438 + 440 + 442 + 444 + 446 + 448 + 450 + 452 + 454 + 456 + 458 + 460 + 462 + 464 + 466 + 468 + 470 + 472 + 474 + 476 + 478 + 480 + 482 + 484 + 486 + 488 + 490 + 492 + 494 + 496 + 498 + 500 + 502 + 504 + 506 + 508 + 510 + 512 + 514 + 516 + 518 + 520 + 522 + 524 + 526 + 528 + 530 + 532 + 534 + 536 + 538 + 540 + 542 + 544 + 546 + 548 + 550 + 552 + 554 + 556 + 558 + 560 + 562 + 564 + 566 + 568 + 570 + 572 + 574 + 576 + 578 + 580 + 582 + 584 + 586 + 588 + 590 + 592 + 594 + 596 + 598 + 600 + 602 + 604 + 606 + 608 + 610 + 612 + 614 + 616 + 618 + 620 + 622 + 624 + 626 + 628 + 630 + 632 + 634 + 636 + 638 + 640 + 642 + 644 + 646 + 648 + 650 + 652 + 654 + 656 + 658 + 660 + 662 + 664 + 666 + 668 + 670 + 672 + 674 + 676 + 678 + 680 + 682 + 684 + 686 + 688 + 690 + 692 + 694 + 696 + 698 + 700 + 702 + 704 + 706 + 708 + 710 + 712 + 714 + 716 + 718 + 720 + 722 + 724 + 726 + 728 + 730 + 732 + 734 + 736 + 738 + 740 + 742 + 744 + 746 + 748 + 750 + 752 + 754 + 756 + 758 + 760 + 762 + 764 + 766 + 768 + 770 + 772 + 774 + 776 + 778 + 780 + 782 + 784 + 786 + 788 + 790 + 792 + 794 + 796 + 798 + 800 + 802 + 804 + 806 + 808 + 810 + 812 + 814 + 816 + 818 + 820 + 822 + 824 + 826 + 828 + 830 + 832 + 834 + 836 + 838 + 840 + 842 + 844 + 846 + 848 + 850 + 852 + 854 + 856 + 858 + 860 + 862 + 864 + 866 + 868 + 870 + 872 + 874 + 876 + 878 + 880 + 882 + 884 + 886 + 888 + 890 + 892 + 894 + 896 + 898 + 900 + 902 + 904 + 906 + 908 + 910 + 912 + 914 + 916 + 918 + 920 + 922 + 924 + 926 + 928 + 930 + 932 + 934 + 936 + 938 + 940 + 942 + 944 + 946 + 948 + 950 + 952 + 954 + 956 + 958 + 960 + 962 + 964 + 966 + 968 + 970 + 972 + 974 + 976 + 978 + 980 + 982 + 984 + 986 + 988 + 990 + 992 + 994 + 996 + 998 + 1000 + 1002 + 1004 + 1006 + 1008 + 1010 + 1012 + 1014 + 1016 + 1018 + 1020 + 1022 + 1024 + 1026 + 1028 + 1030 + 1032 + 1034 + 1036 + 1038 + 1040 + 1042 + 1044 + 1046 + 1048 + 1050 + 1052 + 1054 + 1056 + 1058 + 1060 + 1062 + 1064 + 1066 + 1068 + 1070 + 1072 + 1074 + 1076 + 1078 + 1080 + 1082 + 1084 + 1086 + 1088 + 1090 + 1092 + 1094 + 1096 + 1098 + 1100 + 1102 + 1104 + 1106 + 1108 + 1110 + 1112 + 1114 + 1116 + 1118 + 1120 + 1122 + 1124 + 1126 + 1128 + 1130 + 1132 + 1134 + 1136 + 1138 + 1140 + 1142 + 1144 + 1146 + 1148 + 1150 + 1152 + 1154 + 1156 + 1158 + 1160 + 1162 + 1164 + 1166 + 1168 + 1170 + 1172 + 1174 + 1176 + 1178 + 1180 + 1182 + 1184 + 1186 + 1188 + 1190 + 1192 + 1194 + 1196 + 1198 + 1200 + 1202 + 1204 + 1206 + 1208 + 1210 + 1212 + 1214 + 1216 + 1218 + 1220 + 1222 + 1224 + 1226 + 1228 + 1230 + 1232 + 1234 + 1236 + 1238 + 1240 + 1242 + 1244 + 1246 + 1248 + 1250 + 1252 + 1254 + 1256 + 1258 + 1260 + 1262 + 1264 + 1266 + 1268 + 1270 + 1272 + 1274 + 1276 + 1278 + 1280 + 1282 + 1284 + 1286 + 1288 + 1290 + 1292 + 1294 + 1296 + 1298 + 1300 + 1302 + 1304 + 1306 + 1308 + 1310 + 1312 + 1314 + 1316 + 1318 + 1320 + 1322 + 1324 + 1326 + 1328 + 1330 + 1332 + 1334 + 1336 + 1338 + 1340 + 1342 + 1344 + 1346 + 1348 + 1350 + 1352 + 1354 + 1356 + 1358 + 1360 + 1362 + 1364 + 1366 + 1368 + 1370 + 1372 + 1374 + 1376 + 1378 + 1380 + 1382 + 1384 + 1386 + 1388 + 1390 + 1392 + 1394 + 1396 + 1398 + 1400 + 1402 + 1404 + 1406 + 1408 + 1410 + 1412 + 1414 + 1416 + 1418 + 1420 + 1422 + 1424 + 1426 + 1428 + 1430 + 1432 + 1434 + 1436 + 1438 + 1440 + 1442 + 1444 + 1446 + 1448 + 1450 + 1452 + 1454 + 1456 + 1458 + 1460 + 1462 + 1464 + 1466 + 1468 + 1470 + 1472 + 1474 + 1476 + 1478 + 1480 + 1482 + 1484 + 1486 + 1488 + 1490 + 1492 + 1494 + 1496 + 1498 + 1500 + 1502 + 1504 + 1506 + 1508 + 1510 + 1512 + 1514 + 1516 + 1518 + 1520 + 1522 + 1524 + 1526 + 1528 + 1530 + 1532 + 1534 + 1536 + 1538 + 1540 + 1542 + 1544 + 1546 + 1548 + 1550 + 1552 + 1554 + 1556 + 1558 + 1560 + 1562 + 1564 + 1566 + 1568 + 1570 + 1572 + 1574 + 1576 + 1578 + 1580 + 1582 + 1584 + 1586 + 1588 + 1590 + 1592 + 1594 + 1596 + 1598 + 1600 + 1602 + 1604 + 1606 + 1608 + 1610 + 1612 + 1614 + 1616 + 1618 + 1620 + 1622 + 1624 + 1626 + 1628 + 1630 + 1632 + 1634 + 1636 + 1638 + 1640 + 1642 + 1644 + 1646 + 1648 + 1650 + 1652 + 1654 + 1656 + 1658 + 1660 + 1662 + 1664 + 1666 + 1668 + 1670 + 1672 + 1674 + 1676 + 1678 + 1680 + 1682 + 1684 + 1686 + 1688 + 1690 + 1692 + 1694 + 1696 + 1698 + 1700 + 1702 + 1704 + 1706 + 1708 + 1710 + 1712 + 1714 + 1716 + 1718 + 1720 + 1722 + 1724 + 1726 + 1728 + 1730 + 1732 + 1734 + 1736 + 1738 + 1740 + 1742 + 1744 + 1746 + 1748 + 1750 + 1752 + 1754 + 1756 + 1758 + 1760 + 1762 + 1764 + 1766 + 1768 + 1770 + 1772 + 1774 + 1776 + 1778 + 1780 + 1782 + 1784 + 1786 + 1788 + 1790 + 1792 + 1794 + 1796 + 1798 + 1800 + 1802 + 1804 + 1806 + 1808 + 1810 + 1812 + 1814 + 1816 + 1818 + 1820 + 1822 + 1824 + 1826 + 1828 + 1830 + 1832 + 1834 + 1836 + 1838 + 1840 + 1842 + 1844 + 1846 + 1848 + 1850 + 1852 + 1854 + 1856 + 1858 + 1860 + 1862 + 1864 + 1866 + 1868 + 1870 + 1872 + 1874 + 1876 + 1878 + 1880 + 1882 + 1884 + 1886 + 1888 + 1890 + 1892 + 1894 + 1896 + 1898 + 1900 + 1902 + 1904 + 1906 + 1908 + 1910 + 1912 + 1914 + 1916 + 1918 + 1920 + 1922 + 1924 + 1926 + 1928 + 1930 + 1932 + 1934 + 1936 + 1938 + 1940 + 1942 + 1944 + 1946 + 1948 + 1950 + 1952 + 1954 + 1956 + 1958 + 1960 + 1962 + 1964 + 1966 + 1968 + 1970 + 1972 + 1974 + 1976 + 1978 + 1980 + 1982 + 1984 + 1986 + 1988 + 1990 + 1992 + 1994 + 1996 + 1998 + 2000 + 2002 + 2004 + 2006 + 2008 + 2010 + 2012 + 2014 + 2016 + 2018 + 2020 + 2022 + 2024 + 2026 + 2028 + 2030 + 2032 + 2034 + 2036 + 2038 + 2040 + 2042 + 2044 + 2046 + 2048 + 2050 + 2052 + 2054 + 2056 + 2058 + 2060 + 2062 + 2064 + 2066 + 2068 + 2070 + 2072 + 2074 + 2076 + 2078 + 2080 + 2082 + 2084 + 2086 + 2088 + 2090 + 2092 + 2094 + 2096 + 2098 + 2100 + 2102 + 2104 + 2106 + 2108 + 2110 + 2112 + 2114 + 2116 + 2118 + 2120 + 2122 + 2124 + 2126 + 2128 + 2130 + 2132 + 2134 + 2136 + 2138 + 2140 + 2142 + 2144 + 2146 + 2148 + 2150 + 2152 + 2154 + 2156 + 2158 + 2160 + 2162 + 2164 + 2166 + 2168 + 2170 + 2172 + 2174 + 2176 + 2178 + 2180 + 2182 + 2184 + 2186 + 2188 + 2190 + 2192 + 2194 + 2196 + 2198 + 2200 + 2202 + 2204 + 2206 + 2208 + 2210 + 2212 + 2214 + 2216 + 2218 + 2220 + 2222 + 2224 + 2226 + 2228 + 2230 + 2232 + 2234 + 2236 + 2238 + 2240 + 2242 + 2244 + 2246 + 2248 + 2250 + 2252 + 2254 + 2256 + 2258 + 2260 + 2262 + 2264 + 2266 + 2268 + 2270 + 2272 + 2274 + 2276 + 2278 + 2280 + 2282 + 2284 + 2286 + 2288 + 2290 + 2292 + 2294 + 2296 + 2298 + 2300 + 2302 + 2304 + 2306 + 2308 + 2310 + 2312 + 2314 + 2316 + 2318 + 2320 + 2322 + 2324 + 2326 + 2328 + 2330 + 2332 + 2334 + 2336 + 2338 + 2340 + 2342 + 2344 + 2346 + 2348 + 2350 + 2352 + 2354 + 2356 + 2358 + 2360 + 2362 + 2364 + 2366 + 2368 + 2370 + 2372 + 2374 + 2376 + 2378 + 2380 + 2382 + 2384 + 2386 + 2388 + 2390 + 2392 + 2394 + 2396 + 2398 + 2400 + 2402 + 2404 + 2406 + 2408 + 2410 + 2412 + 2414 + 2416 + 2418 + 2420 + 2422 + 2424 + 2426 + 2428 + 2430 + 2432 + 2434 + 2436 + 2438 + 2440 + 2442 + 2444 + 2446 + 2448 + 2450 + 2452 + 2454 + 2456 + 2458 + 2460 + 2462 + 2464 + 2466 + 2468 + 2470 + 2472 + 2474 + 2476 + 2478 + 2480 + 2482 + 2484 + 2486 + 2488 + 2490 + 2492 + 2494 + 2496 + 2498 + 2500 + 2502 + 2504 + 2506 + 2508 + 2510 + 2512 + 2514 + 2516 + 2518 + 2520 + 2522 + 2524 + 2526 + 2528 + 2530 + 2532 + 2534 + 2536 + 2538 + 2540 + 2542 + 2544 + 2546 + 2548 + 2550 + 2552 + 2554 + 2556 + 2558 + 2560 + 2562 + 2564 + 2566 + 2568 + 2570 + 2572 + 2574 + 2576 + 2578 + 2580 + 2582 + 2584 + 2586 + 2588 + 2590 + 2592 + 2594 + 2596 + 2598 + 2600 + 2602 + 2604 + 2606 + 2608 + 2610 + 2612 + 2614 + 2616 + 2618 + 2620 + 2622 + 2624 + 2626 + 2628 + 2630 + 2632 + 2634 + 2636 + 2638 + 2640 + 2642 + 2644 + 2646 + 2648 + 2650 + 2652 + 2654 + 2656 + 2658 + 2660 + 2662 + 2664 + 2666 + 2668 + 2670 + 2672 + 2674 + 2676 + 2678 + 2680 + 2682 + 2684 + 2686 + 2688 + 2690 + 2692 + 2694 + 2696 + 2698 + 2700 + 2702 + 2704 + 2706 + 2708 + 2710 + 2712 + 2714 + 2716 + 2718 + 2720 + 2722 + 2724 + 2726 + 2728 + 2730 + 2732 + 2734 + 2736 + 2738 + 2740 + 2742 + 2744 + 2746 + 2748 + 2750 + 2752 + 2754 + 2756 + 2758 + 2760 + 2762 + 2764 + 2766 + 2768 + 2770 + 2772 + 2774 + 2776 + 2778 + 2780 + 2782 + 2784 + 2786 + 2788 + 2790 + 2792 + 2794 + 2796 + 2798 + 2800 + 2802 + 2804 + 2806 + 2808 + 2810 + 2812 + 2814 + 2816 + 2818 + 2820 + 2822 + 2824 + 2826 + 2828 + 2830 + 2832 + 2834 + 2836 + 2838 + 2840 + 2842 + 2844 + 2846 + 2848 + 2850 + 2852 + 2854 + 2856 + 2858 + 2860 + 2862 + 2864 + 2866 + 2868 + 2870 + 2872 + 2874 + 2876 + 2878 + 2880 + 2882 + 2884 + 2886 + 2888 + 2890 + 2892 + 2894 + 2896 + 2898 + 2900 + 2902 + 2904 + 2906 + 2908 + 2910 + 2912 + 2914 + 2916 + 2918 + 2920 + 2922 + 2924 + 2926 + 2928 + 2930 + 2932 + 2934 + 2936 + 2938 + 2940 + 2942 + 2944 + 2946 + 2948 + 2950 + 2952 + 2954 + 2956 + 2958 + 2960 + 2962 + 2964 + 2966 + 2968 + 2970 + 2972 + 2974 + 2976 + 2978 + 2980 + 2982 + 2984 + 2986 + 2988 + 2990 + 2992 + 2994 + 2996 + 2998 + 3000 + 3002 + 3004 + 3006 + 3008 + 3010 + 3012 + 3014 + 3016 + 3018 + 3020 + 3022 + 3024 + 3026 + 3028 + 3030 + 3032 + 3034 + 3036 + 3038 + 3040 + 3042 + 3044 + 3046 + 3048 + 3050 + 3052 + 3054 + 3056 + 3058 + 3060 + 3062 + 3064 + 3066 + 3068 + 3070 + 3072 + 3074 + 3076 + 3078 + 3080 + 3082 + 3084 + 3086 + 3088 + 3090 + 3092 + 3094 + 3096 + 3098 + 3100 + 3102 + 3104 + 3106 + 3108 + 3110 + 3112 + 3114 + 3116 + 3118 + 3120 + 3122 + 3124 + 3126 + 3128 + 3130 + 3132 + 3134 + 3136 + 3138 + 3140 + 3142 + 3144 + 3146 + 3148 + 3150 + 3152 + 3154 + 3156 + 3158 + 3160 + 3162 + 3164 + 3166 + 3168 + 3170 + 3172 + 3174 + 3176 + 3178 + 3180 + 3182 + 3184 + 3186 + 3188 + 3190 + 3192 + 3194 + 3196 + 3198 + 3200 + 3202 + 3204 + 3206 + 3208 + 3210 + 3212 + 3214 + 3216 + 3218 + 3220 + 3222 + 3224 + 3226 + 3228 + 3230 + 3232 + 3234 + 3236 + 3238 + 3240 + 3242 + 3244 + 3246 + 3248 + 3250 + 3252 + 3254 + 3256 + 3258 + 3260 + 3262 + 3264 + 3266 + 3268 + 3270 + 3272 + 3274 + 3276 + 3278 + 3280 + 3282 + 3284 + 3286 + 3288 + 3290 + 3292 + 3294 + 3296 + 3298 + 3300 + 3302 + 3304 + 3306 + 3308 + 3310 + 3312 + 3314 + 3316 + 3318 + 3320 + 3322 + 3324 + 3326 + 3328 + 3330 + 3332 + 3334 + 3336 + 3338 + 3340 + 3342 + 3344 + 3346 + 3348 + 3350 + 3352 + 3354 + 3356 + 3358 + 3360 + 3362 + 3364 + 3366 + 3368 + 3370 + 3372 + 3374 + 3376 + 3378 + 3380 + 3382 + 3384 + 3386 + 3388 + 3390 + 3392 + 3394 + 3396 + 3398 + 3400 + 3402 + 3404 + 3406 + 3408 + 3410 + 3412 + 3414 + 3416 + 3418 + 3420 + 3422 + 3424 + 3426 + 3428 + 3430 + 3432 + 3434 + 3436 + 3438 + 3440 + 3442 + 3444 + 3446 + 3448 + 3450 + 3452 + 3454 + 3456 + 3458 + 3460 + 3462 + 3464 + 3466 + 3468 + 3470 + 3472 + 3474 + 3476 + 3478 + 3480 + 3482 + 3484 + 3486 + 3488 + 3490 + 3492 + 3494 + 3496 + 3498 + 3500 + 3502 + 3504 + 3506 + 3508 + 3510 + 3512 + 3514 + 3516 + 3518 + 3520 + 3522 + 3524 + 3526 + 3528 + 3530 + 3532 + 3534 + 3536 + 3538 + 3540 + 3542 + 3544 + 3546 + 3548 + 3550 + 3552 + 3554 + 3556 + 3558 + 3560 + 3562 + 3564 + 3566 + 3568 + 3570 + 3572 + 3574 + 3576 + 3578 + 3580 + 3582 + 3584 + 3586 + 3588 + 3590 + 3592 + 3594 + 3596 + 3598 + 3600 + 3602 + 3604 + 3606 + 3608 + 3610 + 3612 + 3614 + 3616 + 3618 + 3620 + 3622 + 3624 + 3626 + 3628 + 3630 + 3632 + 3634 + 3636 + 3638 + 3640 + 3642 + 3644 + 3646 + 3648 + 3650 + 3652 + 3654 + 3656 + 3658 + 3660 + 3662 + 3664 + 3666 + 3668 + 3670 + 3672 + 3674 + 3676 + 3678 + 3680 + 3682 + 3684 + 3686 + 3688 + 3690 + 3692 + 3694 + 3696 + 3698 + 3700 + 3702 + 3704 + 3706 + 3708 + 3710 + 3712 + 3714 + 3716 + 3718 + 3720 + 3722 + 3724 + 3726 + 3728 + 3730 + 3732 + 3734 + 3736 + 3738 + 3740 + 3742 + 3744 + 3746 + 3748 + 3750 + 3752 + 3754 + 3756 + 3758 + 3760 + 3762 + 3764 + 3766 + 3768 + 3770 + 3772 + 3774 + 3776 + 3778 + 3780 + 3782 + 3784 + 3786 + 3788 + 3790 + 3792 + 3794 + 3796 + 3798 + 3800 + 3802 + 3804 + 3806 + 3808 + 3810 + 3812 + 3814 + 3816 + 3818 + 3820 + 3822 + 3824 + 3826 + 3828 + 3830 + 3832 + 3834 + 3836 + 3838 + 3840 + 3842 + 3844 + 3846 + 3848 + 3850 + 3852 + 3854 + 3856 + 3858 + 3860 + 3862 + 3864 + 3866 + 3868 + 3870 + 3872 + 3874 + 3876 + 3878 + 3880 + 3882 + 3884 + 3886 + 3888 + 3890 + 3892 + 3894 + 3896 + 3898 + 3900 + 3902 + 3904 + 3906 + 3908 + 3910 + 3912 + 3914 + 3916 + 3918 + 3920 + 3922 + 3924 + 3926 + 3928 + 3930 + 3932 + 3934 + 3936 + 3938 + 3940 + 3942 + 3944 + 3946 + 3948 + 3950 + 3952 + 3954 + 3956 + 3958 + 3960 + 3962 + 3964 + 3966 + 3968 + 3970 + 3972 + 3974 + 3976 + 3978 + 3980 + 3982 + 3984 + 3986 + 3988 + 3990 + 3992 + 3994 + 3996 + 3998 + 4000 + 4002 + 4004 + 4006 + 4008 + 4010 + 4012 + 4014 + 4016 + 4018 + 4020 + 4022 + 4024 + 4026 + 4028 + 4030 + 4032 + 4034 + 4036 + 4038 + 4040 + 4042 + 4044 + 4046 + 4048 + 4050 + 4052 + 4054 + 4056 + 4058 + 4060 + 4062 + 4064 + 4066 + 4068 + 4070 + 4072 + 4074 + 4076 + 4078 + 4080 + 4082 + 4084 + 4086 + 4088 + 4090 + 4092 + 4094 + 4096 + 4098 + 4100 + 4102 + 4104 + 4106 + 4108 + 4110 + 4112 + 4114 + 4116 + 4118 + 4120 + 4122 + 4124 + 4126 + 4128 + 4130 + 4132 + 4134 + 4136 + 4138 + 4140 + 4142 + 4144 + 4146 + 4148 + 4150 + 4152 + 4154 + 4156 + 4158 + 4160 + 4162 + 4164 + 4166 + 4168 + 4170 + 4172 + 4174 + 4176 + 4178 + 4180 + 4182 + 4184 + 4186 + 4188 + 4190 + 4192 + 4194 + 4196 + 4198 + 4200 + 4202 + 4204 + 4206 + 4208 + 4210 + 4212 + 4214 + 4216 + 4218 + 4220 + 4222 + 4224 + 4226 + 4228 + 4230 + 4232 + 4234 + 4236 + 4238 + 4240 + 4242 + 4244 + 4246 + 4248 + 4250 + 4252 + 4254 + 4256 + 4258 + 4260 + 4262 + 4264 + 4266 + 4268 + 4270 + 4272 + 4274 + 4276 + 4278 + 4280 + 4282 + 4284 + 4286 + 4288 + 4290 + 4292 + 4294 + 4296 + 4298 + 4300 + 4302 + 4304 + 4306 + 4308 + 4310 + 4312 + 4314 + 4316 + 4318 + 4320 + 4322 + 4324 + 4326 + 4328 + 4330 + 4332 + 4334 + 4336 + 4338 + 4340 + 4342 + 4344 + 4346 + 4348 + 4350 + 4352 + 4354 + 4356 + 4358 + 4360 + 4362 + 4364 + 4366 + 4368 + 4370 + 4372 + 4374 + 4376 + 4378 + 4380 + 4382 + 4384 + 4386 + 4388 + 4390 + 4392 + 4394 + 4396 + 4398 + 4400 + 4402 + 4404 + 4406 + 4408 + 4410 + 4412 + 4414 + 4416 + 4418 + 4420 + 4422 + 4424 + 4426 + 4428 + 4430 + 4432 + 4434 + 4436 + 4438 + 4440 + 4442 + 4444 + 4446 + 4448 + 4450 + 4452 + 4454 + 4456 + 4458 + 4460 + 4462 + 4464 + 4466 + 4468 + 4470 + 4472 + 4474 + 4476 + 4478 + 4480 + 4482 + 4484 + 4486 + 4488 + 4490 + 4492 + 4494 + 4496 + 4498 + 4500 + 4502 + 4504 + 4506 + 4508 + 4510 + 4512 + 4514 + 4516 + 4518 + 4520 + 4522 + 4524 + 4526 + 4528 + 4530 + 4532 + 4534 + 4536 + 4538 + 4540 + 4542 + 4544 + 4546 + 4548 + 4550 + 4552 + 4554 + 4556 + 4558 + 4560 + 4562 + 4564 + 4566 + 4568 + 4570 + 4572 + 4574 + 4576 + 4578 + 4580 + 4582 + 4584 + 4586 + 4588 + 4590 + 4592 + 4594 + 4596 + 4598 + 4600 + 4602 + 4604 + 4606 + 4608 + 4610 + 4612 + 4614 + 4616 + 4618 + 4620 + 4622 + 4624 + 4626 + 4628 + 4630 + 4632 + 4634 + 4636 + 4638 + 4640 + 4642 + 4644 + 4646 + 4648 + 4650 + 4652 + 4654 + 4656 + 4658 + 4660 + 4662 + 4664 + 4666 + 4668 + 4670 + 4672 + 4674 + 4676 + 4678 + 4680 + 4682 + 4684 + 4686 + 4688 + 4690 + 4692 + 4694 + 4696 + 4698 + 4700 + 4702 + 4704 + 4706 + 4708 + 4710 + 4712 + 4714 + 4716 + 4718 + 4720 + 4722 + 4724 + 4726 + 4728 + 4730 + 4732 + 4734 + 4736 + 4738 + 4740 + 4742 + 4744 + 4746 + 4748 + 4750 + 4752 + 4754 + 4756 + 4758 + 4760 + 4762 + 4764 + 4766 + 4768 + 4770 + 4772 + 4774 + 4776 + 4778 + 4780 + 4782 + 4784 + 4786 + 4788 + 4790 + 4792 + 4794 + 4796 + 4798 + 4800 + 4802 + 4804 + 4806 + 4808 + 4810 + 4812 + 4814 + 4816 + 4818 + 4820 + 4822 + 4824 + 4826 + 4828 + 4830 + 4832 + 4834 + 4836 + 4838 + 4840 + 4842 + 4844 + 4846 + 4848 + 4850 + 4852 + 4854 + 4856 + 4858 + 4860 + 4862 + 4864 + 4866 + 4868 + 4870 + 4872 + 4874 + 4876 + 4878 + 4880 + 4882 + 4884 + 4886 + 4888 + 4890 + 4892 + 4894 + 4896 + 4898 + 4900 + 4902 + 4904 + 4906 + 4908 + 4910 + 4912 + 4914 + 4916 + 4918 + 4920 + 4922 + 4924 + 4926 + 4928 + 4930 + 4932 + 4934 + 4936 + 4938 + 4940 + 4942 + 4944 + 4946 + 4948 + 4950 + 4952 + 4954 + 4956 + 4958 + 4960 + 4962 + 4964 + 4966 + 4968 + 4970 + 4972 + 4974 + 4976 + 4978 + 4980 + 4982 + 4984 + 4986 + 4988 + 4990 + 4992 + 4994 + 4996 + 4998 + 5000 +(2500 rows) + +SELECT query, rows FROM pg_stat_monitor ORDER BY query COLLATE "C"; + query | rows +---------------------------------------------------------------------+------ + SELECT * FROM t1 LIMIT $1 | 10 + SELECT * FROM t1; | 1000 + SELECT * FROM t2; | 5000 + SELECT pg_stat_monitor_reset(); | 1 + SELECT query, rows FROM pg_stat_monitor ORDER BY query COLLATE "C"; | 0 + SELECt * FROM t2 WHERE b % $1 = $2 | 2500 +(6 rows) + +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + +DROP TABLE t1; +DROP EXTENSION pg_stat_monitor; diff --git a/regression/expected/top_query.out b/regression/expected/top_query.out new file mode 100644 index 0000000..5ef50ab --- /dev/null +++ b/regression/expected/top_query.out @@ -0,0 +1,52 @@ +CREATE EXTENSION pg_stat_monitor; +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + +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); + add2 +------ + 3 +(1 row) + +SELECT query, top_query FROM pg_stat_monitor ORDER BY query COLLATE "C"; + query | top_query +--------------------------------------------------------------------------+-------------------- + 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 (select $1 + $2) | SELECT add2($1,$2) + SELECT add($1,$2) | + SELECT add2($1,$2) | + SELECT pg_stat_monitor_reset(); | + SELECT query, top_query FROM pg_stat_monitor ORDER BY query COLLATE "C"; | +(7 rows) + +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + +DROP EXTENSION pg_stat_monitor; diff --git a/regression/expected/user.out b/regression/expected/user.out new file mode 100644 index 0000000..3ec3dec --- /dev/null +++ b/regression/expected/user.out @@ -0,0 +1,53 @@ +DROP USER IF EXISTS su; +CREATE USER su WITH SUPERUSER; +SET ROLE su; +CREATE EXTENSION pg_stat_monitor; +CREATE USER u1; +CREATE USER u2; +SET ROLE su; +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + +SET ROLE u1; +CREATE TABLE t1 (a int); +SELECT * FROM t1; + a +--- +(0 rows) + +SET ROLE u2; +CREATE TABLE t2 (a int); +SELECT * FROM t2; + a +--- +(0 rows) + +SET ROLE su; +SELECT userid, query FROM pg_stat_monitor ORDER BY query COLLATE "C"; + userid | query +--------+----------------------------------------------------------------------- + u1 | CREATE TABLE t1 (a int); + u2 | CREATE TABLE t2 (a int); + u1 | SELECT * FROM t1; + u2 | SELECT * FROM t2; + su | SELECT pg_stat_monitor_reset(); + su | SELECT userid, query FROM pg_stat_monitor ORDER BY query COLLATE "C"; + su | SET ROLE su; + u1 | SET ROLE u1; + u2 | SET ROLE u2; +(9 rows) + +SELECT pg_stat_monitor_reset(); + pg_stat_monitor_reset +----------------------- + +(1 row) + +DROP TABLE t1; +DROP TABLE t2; +DROP USER u1; +DROP USER u2; +DROP EXTENSION pg_stat_monitor; diff --git a/regression/expected/test_version.out b/regression/expected/version.out similarity index 95% rename from regression/expected/test_version.out rename to regression/expected/version.out index 2438821..b9920ea 100644 --- a/regression/expected/test_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 ------------------------- - 0.7.0 + devel (1 row) DROP EXTENSION pg_stat_monitor; diff --git a/regression/sql/application_name.sql b/regression/sql/application_name.sql new file mode 100644 index 0000000..c566eaf --- /dev/null +++ b/regression/sql/application_name.sql @@ -0,0 +1,6 @@ +CREATE EXTENSION pg_stat_monitor; +SELECT pg_stat_monitor_reset(); +SELECT 1 AS num; +SELECT query,application_name FROM pg_stat_monitor ORDER BY query COLLATE "C"; +SELECT pg_stat_monitor_reset(); +DROP EXTENSION pg_stat_monitor; diff --git a/regression/sql/basic.sql b/regression/sql/basic.sql index e40fb8a..9dce16f 100644 --- a/regression/sql/basic.sql +++ b/regression/sql/basic.sql @@ -1,7 +1,7 @@ CREATE EXTENSION pg_stat_monitor; SELECT pg_stat_monitor_reset(); select pg_sleep(.5); -SELECT 1; +SELECT 1 AS num; SELECT query FROM pg_stat_monitor ORDER BY query COLLATE "C"; SELECT pg_stat_monitor_reset(); DROP EXTENSION pg_stat_monitor; diff --git a/regression/sql/cmd_type.sql b/regression/sql/cmd_type.sql new file mode 100644 index 0000000..68892bb --- /dev/null +++ b/regression/sql/cmd_type.sql @@ -0,0 +1,15 @@ +CREATE EXTENSION pg_stat_monitor; + +SELECT pg_stat_monitor_reset(); +CREATE TABLE t1 (a INTEGER); +INSERT INTO t1 VALUES(1); +SELECT a FROM t1; +UPDATE t1 SET a = 2; +DELETE FROM t1; +SELECT a FROM t1 FOR UPDATE; +TRUNCATE t1; +DROP TABLE t1; +SELECT query, cmd_type, cmd_type_text FROM pg_stat_monitor ORDER BY query COLLATE "C"; +SELECT pg_stat_monitor_reset(); + +DROP EXTENSION pg_stat_monitor; diff --git a/regression/sql/counters.sql b/regression/sql/counters.sql new file mode 100644 index 0000000..f03a3b3 --- /dev/null +++ b/regression/sql/counters.sql @@ -0,0 +1,35 @@ +CREATE EXTENSION pg_stat_monitor; + +CREATE TABLE t1 (a INTEGER); +CREATE TABLE t2 (b INTEGER); +CREATE TABLE t3 (c INTEGER); +CREATE TABLE t4 (d INTEGER); + +SELECT pg_stat_monitor_reset(); +SELECT a,b,c,d FROM t1, t2, t3, t4 WHERE t1.a = t2.b AND t3.c = t4.d ORDER BY a; +SELECT a,b,c,d FROM t1, t2, t3, t4 WHERE t1.a = t2.b AND t3.c = t4.d ORDER BY a; +SELECT a,b,c,d FROM t1, t2, t3, t4 WHERE t1.a = t2.b AND t3.c = t4.d ORDER BY a; +SELECT a,b,c,d FROM t1, t2, t3, t4 WHERE t1.a = t2.b AND t3.c = t4.d ORDER BY a; +SELECT query,calls FROM pg_stat_monitor ORDER BY query COLLATE "C"; +SELECT pg_stat_monitor_reset(); + +SELECT pg_stat_monitor_reset(); +do $$ +declare + n integer:= 1; +begin + loop + PERFORM a,b,c,d FROM t1, t2, t3, t4 WHERE t1.a = t2.b AND t3.c = t4.d ORDER BY a; + exit when n = 1000; + n := n + 1; + end loop; +end $$; +SELECT query,calls FROM pg_stat_monitor ORDER BY query COLLATE "C"; +SELECT pg_stat_monitor_reset(); + +DROP TABLE t1; +DROP TABLE t2; +DROP TABLE t3; +DROP TABLE t4; + +DROP EXTENSION pg_stat_monitor; diff --git a/regression/sql/database.sql b/regression/sql/database.sql new file mode 100644 index 0000000..0431004 --- /dev/null +++ b/regression/sql/database.sql @@ -0,0 +1,37 @@ +CREATE EXTENSION pg_stat_monitor; + +CREATE DATABASE db1; +CREATE DATABASE db2; + +\c db1 +CREATE TABLE t1 (a int); +CREATE TABLE t2 (b int); + +\c db2 +CREATE TABLE t3 (c int); +CREATE TABLE t4 (d int); + +\c contrib_regression +SELECT pg_stat_monitor_reset(); +\c db1 +SELECT * FROM t1,t2 WHERE t1.a = t2.b; + +\c db2 +SELECT * FROM t3,t4 WHERE t3.c = t4.d; + +\c contrib_regression +SELECT datname, query FROM pg_stat_monitor ORDER BY query COLLATE "C"; +SELECT pg_stat_monitor_reset(); + +\c db1 +DROP TABLE t1; +DROP TABLE t2; + +\c db2 +DROP TABLE t3; +DROP TABLE t4; + +\c contrib_regression +DROP DATABASE db1; +DROP DATABASE db2; +DROP EXTENSION pg_stat_monitor; diff --git a/regression/sql/error.sql b/regression/sql/error.sql new file mode 100644 index 0000000..3f98f75 --- /dev/null +++ b/regression/sql/error.sql @@ -0,0 +1,14 @@ +CREATE EXTENSION pg_stat_monitor; +SELECT pg_stat_monitor_reset(); +SELECT 1/0; -- divide by zero +SELECT * FROM unknown; -- unknown table +ELECET * FROM unknown; -- syntax error + +do $$ +BEGIN +RAISE WARNING 'warning message'; +END $$; + +SELECT query, elevel,sqlcode, message FROM pg_stat_monitor ORDER BY query COLLATE "C"; +SELECT pg_stat_monitor_reset(); +DROP EXTENSION pg_stat_monitor; diff --git a/regression/sql/histogram.sql b/regression/sql/histogram.sql new file mode 100644 index 0000000..50aa897 --- /dev/null +++ b/regression/sql/histogram.sql @@ -0,0 +1,28 @@ +CREATE EXTENSION pg_stat_monitor; + +CREATE TABLE t1(a int); + +SELECT pg_stat_monitor_reset(); + +INSERT INTO t1 VALUES(generate_series(1,10)); +ANALYZE t1; +SELECT count(*) FROM t1; + +INSERT INTO t1 VALUES(generate_series(1,10000)); +ANALYZE t1; +SELECT count(*) FROM t1;; + +INSERT INTO t1 VALUES(generate_series(1,1000000)); +ANALYZE t1; +SELECT count(*) FROM t1; + +INSERT INTO t1 VALUES(generate_series(1,10000000)); +ANALYZE t1; +SELECT count(*) FROM t1; + +SELECT query, calls, min_time, max_time, resp_calls FROM pg_stat_monitor ORDER BY query COLLATE "C"; +SELECT * FROM histogram(0, 'F44CD1B4B33A47AF') AS a(range TEXT, freq INT, bar TEXT); + +DROP TABLE t1; +SELECT pg_stat_monitor_reset(); +DROP EXTENSION pg_stat_monitor; diff --git a/regression/sql/pg_stat_monitor.sql b/regression/sql/pg_stat_monitor.sql deleted file mode 100644 index a46e25b..0000000 --- a/regression/sql/pg_stat_monitor.sql +++ /dev/null @@ -1,198 +0,0 @@ -CREATE EXTENSION pg_stat_monitor; - --- --- simple and compound statements --- -SET pg_stat_monitor.track_utility = FALSE; -SELECT pg_stat_monitor_reset(); - -SELECT 1 AS "int"; - -SELECT 'hello' - -- multiline - AS "text"; - -SELECT 'world' AS "text"; - --- transaction -BEGIN; -SELECT 1 AS "int"; -SELECT 'hello' AS "text"; -COMMIT; - --- compound transaction -BEGIN \; -SELECT 2.0 AS "float" \; -SELECT 'world' AS "text" \; -COMMIT; - --- compound with empty statements and spurious leading spacing -\;\; SELECT 3 + 3 \;\;\; SELECT ' ' || ' !' \;\; SELECT 1 + 4 \;; - --- non ;-terminated statements -SELECT 1 + 1 + 1 AS "add" \gset -SELECT :add + 1 + 1 AS "add" \; -SELECT :add + 1 + 1 AS "add" \gset - --- set operator -SELECT 1 AS i UNION SELECT 2 ORDER BY i; - --- ? operator -select '{"a":1, "b":2}'::jsonb ? 'b'; - --- cte -WITH t(f) AS ( - VALUES (1.0), (2.0) -) - SELECT f FROM t ORDER BY f; - --- prepared statement with parameter -PREPARE pgss_test (int) AS SELECT $1, 'test' LIMIT 1; -EXECUTE pgss_test(1); -DEALLOCATE pgss_test; - -SELECT query, calls, rows FROM pg_stat_monitor ORDER BY query COLLATE "C"; - --- --- CRUD: INSERT SELECT UPDATE DELETE on test table --- -SELECT pg_stat_monitor_reset(); - --- utility "create table" should not be shown -CREATE TEMP TABLE test (a int, b char(20)); - -INSERT INTO test VALUES(generate_series(1, 10), 'aaa'); -UPDATE test SET b = 'bbb' WHERE a > 7; -DELETE FROM test WHERE a > 9; - --- explicit transaction -BEGIN; -UPDATE test SET b = '111' WHERE a = 1 ; -COMMIT; - -BEGIN \; -UPDATE test SET b = '222' WHERE a = 2 \; -COMMIT ; - -UPDATE test SET b = '333' WHERE a = 3 \; -UPDATE test SET b = '444' WHERE a = 4 ; - -BEGIN \; -UPDATE test SET b = '555' WHERE a = 5 \; -UPDATE test SET b = '666' WHERE a = 6 \; -COMMIT ; - --- many INSERT values -INSERT INTO test (a, b) VALUES (1, 'a'), (2, 'b'), (3, 'c'); - --- SELECT with constants -SELECT * FROM test WHERE a > 5 ORDER BY a ; - -SELECT * - FROM test - WHERE a > 9 - ORDER BY a ; - --- SELECT without constants -SELECT * FROM test ORDER BY a; - --- SELECT with IN clause -SELECT * FROM test WHERE a IN (1, 2, 3, 4, 5); - -SELECT query, calls, rows FROM pg_stat_monitor ORDER BY query COLLATE "C"; - --- --- pg_stat_monitor.track = none --- -SET pg_stat_monitor.track = 'none'; -SELECT pg_stat_monitor_reset(); - -SELECT 1 AS "one"; -SELECT 1 + 1 AS "two"; - -SELECT query, calls, rows FROM pg_stat_monitor ORDER BY query COLLATE "C"; - --- --- pg_stat_monitor.track = top --- -SET pg_stat_monitor.track = 'top'; -SELECT pg_stat_monitor_reset(); - -DO LANGUAGE plpgsql $$ -BEGIN - -- this is a SELECT - PERFORM 'hello world'::TEXT; -END; -$$; - --- PL/pgSQL function -CREATE FUNCTION PLUS_TWO(i INTEGER) RETURNS INTEGER AS $$ -DECLARE - r INTEGER; -BEGIN - SELECT (i + 1 + 1.0)::INTEGER INTO r; - RETURN r; -END; $$ LANGUAGE plpgsql; - -SELECT PLUS_TWO(3); -SELECT PLUS_TWO(7); - --- SQL function --- use LIMIT to keep it from being inlined -CREATE FUNCTION PLUS_ONE(i INTEGER) RETURNS INTEGER AS -$$ SELECT (i + 1.0)::INTEGER LIMIT 1 $$ LANGUAGE SQL; - -SELECT PLUS_ONE(8); -SELECT PLUS_ONE(10); - -SELECT query, calls, rows FROM pg_stat_monitor ORDER BY query COLLATE "C"; - --- --- pg_stat_monitor.track = all --- -SET pg_stat_monitor.track = 'all'; -SELECT pg_stat_monitor_reset(); - --- we drop and recreate the functions to avoid any caching funnies -DROP FUNCTION PLUS_ONE(INTEGER); -DROP FUNCTION PLUS_TWO(INTEGER); - --- PL/pgSQL function -CREATE FUNCTION PLUS_TWO(i INTEGER) RETURNS INTEGER AS $$ -DECLARE - r INTEGER; -BEGIN - SELECT (i + 1 + 1.0)::INTEGER INTO r; - RETURN r; -END; $$ LANGUAGE plpgsql; - -SELECT PLUS_TWO(-1); -SELECT PLUS_TWO(2); - --- SQL function --- use LIMIT to keep it from being inlined -CREATE FUNCTION PLUS_ONE(i INTEGER) RETURNS INTEGER AS -$$ SELECT (i + 1.0)::INTEGER LIMIT 1 $$ LANGUAGE SQL; - -SELECT PLUS_ONE(3); -SELECT PLUS_ONE(1); - -SELECT query, calls, rows FROM pg_stat_monitor ORDER BY query COLLATE "C"; - --- --- utility commands --- -SET pg_stat_monitor.track_utility = TRUE; -SELECT pg_stat_monitor_reset(); - -SELECT 1; -CREATE INDEX test_b ON test(b); -DROP TABLE test \; -DROP TABLE IF EXISTS test \; -DROP FUNCTION PLUS_ONE(INTEGER); -DROP TABLE IF EXISTS test \; -DROP TABLE IF EXISTS test \; -DROP FUNCTION IF EXISTS PLUS_ONE(INTEGER); -DROP FUNCTION PLUS_TWO(INTEGER); - -SELECT query, calls, rows FROM pg_stat_monitor ORDER BY query COLLATE "C"; - -DROP EXTENSION pg_stat_monitor; diff --git a/regression/sql/relations.sql b/regression/sql/relations.sql index 7eaef72..97ce312 100644 --- a/regression/sql/relations.sql +++ b/regression/sql/relations.sql @@ -1,15 +1,79 @@ CREATE EXTENSION pg_stat_monitor; SELECT pg_stat_monitor_reset(); CREATE TABLE foo1(a int); -CREATE TABLE foo2(a int); -CREATE TABLE foo3(a int); -CREATE TABLE foo4(a int); +CREATE TABLE foo2(b int); +CREATE TABLE foo3(c int); +CREATE TABLE foo4(d int); + +-- test the simple table names SELECT pg_stat_monitor_reset(); +SELECT * FROM foo1; +SELECT * FROM foo1, foo2; +SELECT * FROM foo1, foo2, foo3; SELECT * FROM foo1, foo2, foo3, foo4; SELECT query, relations from pg_stat_monitor ORDER BY query; SELECT pg_stat_monitor_reset(); + + +-- test the schema qualified table +CREATE schema sch1; +CREATE schema sch2; +CREATE schema sch3; +CREATE schema sch4; + +CREATE TABLE sch1.foo1(a int); +CREATE TABLE sch2.foo2(b int); +CREATE TABLE sch3.foo3(c int); +CREATE TABLE sch4.foo4(d int); + +SELECT pg_stat_monitor_reset(); +SELECT * FROM sch1.foo1; +SELECT * FROM sch1.foo1, sch2.foo2; +SELECT * FROM sch1.foo1, sch2.foo2, sch3.foo3; +SELECT * FROM sch1.foo1, sch2.foo2, sch3.foo3, sch4.foo4; +SELECT query, relations from pg_stat_monitor ORDER BY query; +SELECT pg_stat_monitor_reset(); + +SELECT pg_stat_monitor_reset(); +SELECT * FROM sch1.foo1, foo1; +SELECT * FROM sch1.foo1, sch2.foo2, foo1, foo2; +SELECT query, relations from pg_stat_monitor ORDER BY query; +SELECT pg_stat_monitor_reset(); + +-- test the view +CREATE VIEW v1 AS SELECT * from foo1; +CREATE VIEW v2 AS SELECT * from foo1,foo2; +CREATE VIEW v3 AS SELECT * from foo1,foo2,foo3; +CREATE VIEW v4 AS SELECT * from foo1,foo2,foo3,foo4; + +SELECT pg_stat_monitor_reset(); +SELECT * FROM v1; +SELECT * FROM v1,v2; +SELECT * FROM v1,v2,v3; +SELECT * FROM v1,v2,v3,v4; +SELECT query, relations from pg_stat_monitor ORDER BY query; +SELECT pg_stat_monitor_reset(); + + +DROP VIEW v1; +DROP VIEW v2; +DROP VIEW v3; +DROP VIEW v4; + DROP TABLE foo1; DROP TABLE foo2; DROP TABLE foo3; DROP TABLE foo4; + +DROP TABLE sch1.foo1; +DROP TABLE sch2.foo2; +DROP TABLE sch3.foo3; +DROP TABLE sch4.foo4; + +DROP SCHEMA sch1; +DROP SCHEMA sch2; +DROP SCHEMA sch3; +DROP SCHEMA sch4; + + DROP EXTENSION pg_stat_monitor; diff --git a/regression/sql/rows.sql b/regression/sql/rows.sql new file mode 100644 index 0000000..02f0f70 --- /dev/null +++ b/regression/sql/rows.sql @@ -0,0 +1,19 @@ +CREATE EXTENSION pg_stat_monitor; + +CREATE TABLE t1(a int); +CREATE TABLE t2(b int); +INSERT INTO t1 VALUES(generate_series(1,1000)); +INSERT INTO t2 VALUES(generate_series(1,5000)); + +SELECT pg_stat_monitor_reset(); +SELECT * FROM t1; +SELECT * FROM t2; + +SELECT * FROM t1 LIMIT 10; +SELECt * FROM t2 WHERE b % 2 = 0; + +SELECT query, rows FROM pg_stat_monitor ORDER BY query COLLATE "C"; +SELECT pg_stat_monitor_reset(); + +DROP TABLE t1; +DROP EXTENSION pg_stat_monitor; diff --git a/regression/sql/top_query.sql b/regression/sql/top_query.sql new file mode 100644 index 0000000..3642f99 --- /dev/null +++ b/regression/sql/top_query.sql @@ -0,0 +1,19 @@ +CREATE EXTENSION pg_stat_monitor; +SELECT pg_stat_monitor_reset(); +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 query, top_query FROM pg_stat_monitor ORDER BY query COLLATE "C"; +SELECT pg_stat_monitor_reset(); +DROP EXTENSION pg_stat_monitor; diff --git a/regression/sql/user.sql b/regression/sql/user.sql new file mode 100644 index 0000000..8addf12 --- /dev/null +++ b/regression/sql/user.sql @@ -0,0 +1,31 @@ +DROP USER IF EXISTS su; +CREATE USER su WITH SUPERUSER; + +SET ROLE su; +CREATE EXTENSION pg_stat_monitor; + +CREATE USER u1; +CREATE USER u2; + +SET ROLE su; + +SELECT pg_stat_monitor_reset(); +SET ROLE u1; +CREATE TABLE t1 (a int); +SELECT * FROM t1; + +SET ROLE u2; +CREATE TABLE t2 (a int); +SELECT * FROM t2; + +SET ROLE su; +SELECT userid, query FROM pg_stat_monitor ORDER BY query COLLATE "C"; +SELECT pg_stat_monitor_reset(); + +DROP TABLE t1; +DROP TABLE t2; + +DROP USER u1; +DROP USER u2; + +DROP EXTENSION pg_stat_monitor; diff --git a/regression/sql/test_version.sql b/regression/sql/version.sql similarity index 100% rename from regression/sql/test_version.sql rename to regression/sql/version.sql