From 30c4f2a52c74da44f8ce1b28b764260c91cdb7ab Mon Sep 17 00:00:00 2001 From: Julien Rouhaud Date: Mon, 2 Aug 2021 23:50:15 +0800 Subject: [PATCH 01/22] Start working on version 1.3.2 --- hypopg--1.3.1--1.3.2.sql | 7 +++++ hypopg--1.3.2.sql | 62 ++++++++++++++++++++++++++++++++++++++++ hypopg.control | 2 +- 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 hypopg--1.3.1--1.3.2.sql create mode 100644 hypopg--1.3.2.sql diff --git a/hypopg--1.3.1--1.3.2.sql b/hypopg--1.3.1--1.3.2.sql new file mode 100644 index 0000000..35387ac --- /dev/null +++ b/hypopg--1.3.1--1.3.2.sql @@ -0,0 +1,7 @@ +-- This program is open source, licensed under the PostgreSQL License. +-- For license terms, see the LICENSE file. +-- +-- Copyright (C) 2015-2021: Julien Rouhaud + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "ALTER EXTENSION hypopg" to load this file. \quit diff --git a/hypopg--1.3.2.sql b/hypopg--1.3.2.sql new file mode 100644 index 0000000..8462df6 --- /dev/null +++ b/hypopg--1.3.2.sql @@ -0,0 +1,62 @@ +-- This program is open source, licensed under the PostgreSQL License. +-- For license terms, see the LICENSE file. +-- +-- Copyright (C) 2015-2021: Julien Rouhaud + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION hypopg" to load this file. \quit + +SET LOCAL client_encoding = 'UTF8'; + +CREATE FUNCTION hypopg_reset_index() + RETURNS void + LANGUAGE C VOLATILE COST 100 +AS '$libdir/hypopg', 'hypopg_reset_index'; + +CREATE FUNCTION hypopg_reset() + RETURNS void + LANGUAGE C VOLATILE COST 100 +AS '$libdir/hypopg', 'hypopg_reset'; + +CREATE FUNCTION +hypopg_create_index(IN sql_order text, OUT indexrelid oid, OUT indexname text) + RETURNS SETOF record + LANGUAGE C STRICT VOLATILE COST 100 +AS '$libdir/hypopg', 'hypopg_create_index'; + +CREATE FUNCTION +hypopg_drop_index(IN indexid oid) + RETURNS bool + LANGUAGE C STRICT VOLATILE COST 100 +AS '$libdir/hypopg', 'hypopg_drop_index'; + +CREATE FUNCTION hypopg(OUT indexname text, OUT indexrelid oid, + OUT indrelid oid, OUT innatts integer, + OUT indisunique boolean, OUT indkey int2vector, + OUT indcollation oidvector, OUT indclass oidvector, + OUT indoption oidvector, OUT indexprs pg_node_tree, + OUT indpred pg_node_tree, OUT amid oid) + RETURNS SETOF record + LANGUAGE c COST 100 +AS '$libdir/hypopg', 'hypopg'; + +CREATE VIEW hypopg_list_indexes +AS + SELECT h.indexrelid, h.indexname AS index_name, n.nspname AS schema_name, + coalesce(c.relname, '') AS table_name, am.amname AS am_name + FROM hypopg() h + LEFT JOIN pg_catalog.pg_class c ON c.oid = h.indrelid + LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace + LEFT JOIN pg_catalog.pg_am am ON am.oid = h.amid; + +CREATE FUNCTION +hypopg_relation_size(IN indexid oid) + RETURNS bigint +LANGUAGE C STRICT VOLATILE COST 100 +AS '$libdir/hypopg', 'hypopg_relation_size'; + +CREATE FUNCTION +hypopg_get_indexdef(IN indexid oid) + RETURNS text +LANGUAGE C STRICT VOLATILE COST 100 +AS '$libdir/hypopg', 'hypopg_get_indexdef'; diff --git a/hypopg.control b/hypopg.control index 7de312a..daca457 100644 --- a/hypopg.control +++ b/hypopg.control @@ -1,6 +1,6 @@ # hypopg extension comment = 'Hypothetical indexes for PostgreSQL' -default_version = '1.3.1' +default_version = '1.3.2' module_pathname = '$libdir/hypopg' relocatable = true From 15751f65be4ffaed5d87ccb762eff5d6c07136ce Mon Sep 17 00:00:00 2001 From: Xiaozhe Yao Date: Mon, 2 Aug 2021 17:46:21 +0200 Subject: [PATCH 02/22] Fix a typo (#59) "which should should be" --> "which should be" --- hypopg_index.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hypopg_index.c b/hypopg_index.c index dbf445d..a2304bd 100644 --- a/hypopg_index.c +++ b/hypopg_index.c @@ -350,7 +350,7 @@ hypo_index_store_parsetree(IndexStmt *node, const char *queryString) /* * Support for hypothetical BRIN indexes is broken in some minor versions * of pg10, pg11 and pg12. For simplicity, check PG_VERSION_NUM rather - * than the real instance version, which should should be right most of the + * than the real instance version, which should be right most of the * time. When it's not, the only effect is to have a less user-friendly * error message. */ From ccd02b593b50e9875948753f603c8924ec68d5c5 Mon Sep 17 00:00:00 2001 From: Julien Rouhaud Date: Mon, 2 Aug 2021 23:48:05 +0800 Subject: [PATCH 03/22] Update contributors. --- CONTRIBUTORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 7c96ed9..8f17b49 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -17,3 +17,4 @@ People who contributed to hypopg: * nagaraju11 * ibrahim edib kokdemir * github user nikhil-postgres + * Xiaozhe Yao From 20f570ac860356be8b1bc3b25f79b0e52811c078 Mon Sep 17 00:00:00 2001 From: Julien Rouhaud Date: Sun, 15 Aug 2021 20:00:12 +0800 Subject: [PATCH 04/22] Simplify an error message construction. Duplicate the full elog() call rather than constructing the message using --- hypopg_index.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/hypopg_index.c b/hypopg_index.c index a2304bd..3b8a4c3 100644 --- a/hypopg_index.c +++ b/hypopg_index.c @@ -395,12 +395,13 @@ hypo_index_store_parsetree(IndexStmt *node, const char *queryString) break; #endif default: - elog(ERROR, "hypopg: \"%s\" is not a table" #if PG_VERSION_NUM >= 90300 - " or materialized view" -#endif - , + elog(ERROR, "hypopg: \"%s\" is not a table or materialized view", node->relation->relname); +#else + elog(ERROR, "hypopg: \"%s\" is not a table", + node->relation->relname); +#endif } /* Run parse analysis ... */ From 6e2d7bfca12e1aeb58bd77d96b9c222b759df33d Mon Sep 17 00:00:00 2001 From: Julien Rouhaud Date: Thu, 25 Nov 2021 13:41:42 +0800 Subject: [PATCH 05/22] Fix documentation to reflect that hypopg_list_indexes is now a view. Thanks to Duc Hoang for the report. --- README.md | 6 +++--- docs/usage.rst | 38 +++++++++++++++++++++++++------------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index d4f153a..9f28f94 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ a future release. You can check the available hypothetical indexes in your own backend: - rjuju=# SELECT * FROM hypopg_list_indexes(); + rjuju=# SELECT * FROM hypopg_list_indexes ; indexrelid | indexname | nspname | relname | amname -----------+-------------------------------------------+---------+---------+-------- 205101 | <41072>btree_hypo_id | public | hypo | btree @@ -96,6 +96,6 @@ Of course, only `EXPLAIN` without `ANALYZE` will use hypothetical indexes: (5 rows) To remove your backend's hypothetical indexes, you can use the function -`hypopg_drop_index(indexrelid)` with the OID that the `hypopg_list_indexes()` -function returns and call `hypopg_reset()` to remove all at once, or just close +`hypopg_drop_index(indexrelid)` with the OID that the `hypopg_list_indexes` +view returns and call `hypopg_reset()` to remove all at once, or just close your current connection. diff --git a/docs/usage.rst b/docs/usage.rst index d3fcbef..b879a79 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -174,41 +174,53 @@ use such indexes. Manipulate hypothetical indexes ------------------------------- -Some other convenience functions are available: +Some other convenience functions and views are available: -- **hypopg_list_indexes()**: list all hypothetical indexes that have been - created +- **hypopg_list_indexes**: view that lists all hypothetical indexes that have + been created .. code-block:: psql - SELECT * FROM hypopg_list_indexes() + SELECT * FROM hypopg_list_indexes ; indexrelid | indexname | nspname | relname | amname ------------+----------------------+---------+---------+-------- 18284 | <18284>btree_hypo_id | public | hypo | btree (1 row) -- **hypopg_get_indexdef(oid)**: get the CREATE INDEX statement that would - recreate a stored hypothetical index +- **hypopg()**: fuctions that lists all hypothetical indexes that have + been created with the same format as **pg_index** .. code-block:: psql - SELECT indexname, hypopg_get_indexdef(indexrelid) FROM hypopg_list_indexes() ; - indexname | hypopg_get_indexdef + SELECT * FROM hypopg() ; + indexname | indexrelid | indrelid | innatts | indisunique | indkey | indcollation | indclass | indoption | indexprs | indpred | amid +----------------------+------------+----------+---------+-------------+--------+--------------+----------+-----------+----------+---------+------ + <18284>btree_hypo_id | 13543 | 18122 | 1 | f | 1 | 0 | 1978 | | | | 403 +(1 row) + +- **hypopg_get_indexdef(oid)**: function that lists the CREATE INDEX statement + that would recreate a stored hypothetical index + +.. code-block:: psql + + SELECT indexname, hypopg_get_indexdef(indexrelid) FROM hypopg_list_indexes ; + indexname | hypopg_get_indexdef ----------------------+---------------------------------------------- <18284>btree_hypo_id | CREATE INDEX ON public.hypo USING btree (id) (1 row) -- **hypopg_relation_size(oid)**: estimate how big a hypothetical index would - be: +- **hypopg_relation_size(oid)**: function that estimates how big a hypothetical + index would be: .. code-block:: psql SELECT indexname, pg_size_pretty(hypopg_relation_size(indexrelid)) - FROM hypopg_list_indexes() ; + FROM hypopg_list_indexes ; indexname | pg_size_pretty ----------------------+---------------- <18284>btree_hypo_id | 2544 kB (1 row) -- **hypopg_drop_index(oid)**: remove the given hypothetical index -- **hypopg_reset()**: remove all hypothetical indexes +- **hypopg_drop_index(oid)**: function that removes the given hypothetical + index +- **hypopg_reset()**: function that removes all hypothetical indexes From 99a0d0c4bf9d9c94c57d59e33225d6e79c68ec6a Mon Sep 17 00:00:00 2001 From: Julien Rouhaud Date: Thu, 25 Nov 2021 13:47:25 +0800 Subject: [PATCH 06/22] Document that debian/ubuntu have official hypopg packages. Also fix the install documentation to mention Rocky Linux, as the community is not supporting centos anymore. --- docs/installation.rst | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/docs/installation.rst b/docs/installation.rst index 026fd27..df2fe8d 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -13,7 +13,7 @@ Packages Hypopg is available as a package on some GNU/Linux distributions: -- RHEL/Centos +- RHEL/Rocky Linux HypoPG is available as a package using `the PGDG packages `_. @@ -25,6 +25,20 @@ Hypopg is available as a package on some GNU/Linux distributions: yum install hypopg +- Debian / Ubuntu + + HypoPG is available as a package using `the PGDG packages + `_. + + Once the PGDG repository is setup, you just need to install the package. As + root: + + .. code-block:: bash + + apt install postgresql-XY-hypopg + + where XY is the major version for which you want to install hypopg. + - Archlinux Hypopg is available on the `AUR repository From b97cb0ce458e01b8138158fa165a935e486978f5 Mon Sep 17 00:00:00 2001 From: Julien Rouhaud Date: Thu, 25 Nov 2021 13:49:17 +0800 Subject: [PATCH 07/22] Fix typo in the documentation. --- docs/usage.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/usage.rst b/docs/usage.rst index b879a79..c6e5c28 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -187,7 +187,7 @@ Some other convenience functions and views are available: 18284 | <18284>btree_hypo_id | public | hypo | btree (1 row) -- **hypopg()**: fuctions that lists all hypothetical indexes that have +- **hypopg()**: function that lists all hypothetical indexes that have been created with the same format as **pg_index** .. code-block:: psql From 8005133cd4ccf50474bfc8f185e91593965d6bd1 Mon Sep 17 00:00:00 2001 From: Julien Rouhaud Date: Sun, 16 Jan 2022 12:57:30 +0800 Subject: [PATCH 08/22] Update copyright year. --- LICENSE | 2 +- debian/copyright | 2 +- docs/conf.py | 2 +- hypopg--1.3.1--1.3.2.sql | 2 +- hypopg--1.3.1.sql | 2 +- hypopg--1.3.2.sql | 2 +- hypopg.c | 2 +- hypopg_index.c | 2 +- import/hypopg_import.c | 2 +- import/hypopg_import_index.c | 2 +- include/hypopg.h | 2 +- include/hypopg_import.h | 2 +- include/hypopg_import_index.h | 2 +- include/hypopg_index.h | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/LICENSE b/LICENSE index 1ed145e..d2632be 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Portions Copyright (c) 2015-2021, PostgreSQL GLobal Development Group +Portions Copyright (c) 2015-2022, PostgreSQL GLobal Development Group Portions Copyright (c) 1994, The Regents of the University of California diff --git a/debian/copyright b/debian/copyright index a978fb4..20aab17 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,4 +1,4 @@ -Portions Copyright (c) 2015-2021, PostgreSQL GLobal Development Group +Portions Copyright (c) 2015-2022, PostgreSQL GLobal Development Group Portions Copyright (c) 1994, The Regents of the University of California diff --git a/docs/conf.py b/docs/conf.py index 689ac91..5118637 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -50,7 +50,7 @@ master_doc = 'index' # General information about the project. project = 'HypoPG' -copyright = '2015-2021, Julien Rouhaud' +copyright = '2015-2022, Julien Rouhaud' author = 'Julien Rouhaud' # The version info for the project you're documenting, acts as replacement for diff --git a/hypopg--1.3.1--1.3.2.sql b/hypopg--1.3.1--1.3.2.sql index 35387ac..41b1f4d 100644 --- a/hypopg--1.3.1--1.3.2.sql +++ b/hypopg--1.3.1--1.3.2.sql @@ -1,7 +1,7 @@ -- This program is open source, licensed under the PostgreSQL License. -- For license terms, see the LICENSE file. -- --- Copyright (C) 2015-2021: Julien Rouhaud +-- Copyright (C) 2015-2022: Julien Rouhaud -- complain if script is sourced in psql, rather than via CREATE EXTENSION \echo Use "ALTER EXTENSION hypopg" to load this file. \quit diff --git a/hypopg--1.3.1.sql b/hypopg--1.3.1.sql index 8462df6..978cf40 100644 --- a/hypopg--1.3.1.sql +++ b/hypopg--1.3.1.sql @@ -1,7 +1,7 @@ -- This program is open source, licensed under the PostgreSQL License. -- For license terms, see the LICENSE file. -- --- Copyright (C) 2015-2021: Julien Rouhaud +-- Copyright (C) 2015-2022: Julien Rouhaud -- complain if script is sourced in psql, rather than via CREATE EXTENSION \echo Use "CREATE EXTENSION hypopg" to load this file. \quit diff --git a/hypopg--1.3.2.sql b/hypopg--1.3.2.sql index 8462df6..978cf40 100644 --- a/hypopg--1.3.2.sql +++ b/hypopg--1.3.2.sql @@ -1,7 +1,7 @@ -- This program is open source, licensed under the PostgreSQL License. -- For license terms, see the LICENSE file. -- --- Copyright (C) 2015-2021: Julien Rouhaud +-- Copyright (C) 2015-2022: Julien Rouhaud -- complain if script is sourced in psql, rather than via CREATE EXTENSION \echo Use "CREATE EXTENSION hypopg" to load this file. \quit diff --git a/hypopg.c b/hypopg.c index 872d24c..cc81102 100644 --- a/hypopg.c +++ b/hypopg.c @@ -8,7 +8,7 @@ * This program is open source, licensed under the PostgreSQL license. * For license terms, see the LICENSE file. * - * Copyright (C) 2015-2021: Julien Rouhaud + * Copyright (C) 2015-2022: Julien Rouhaud * *------------------------------------------------------------------------- */ diff --git a/hypopg_index.c b/hypopg_index.c index 3b8a4c3..bf7ca38 100644 --- a/hypopg_index.c +++ b/hypopg_index.c @@ -8,7 +8,7 @@ * This program is open source, licensed under the PostgreSQL license. * For license terms, see the LICENSE file. * - * Copyright (C) 2015-2021: Julien Rouhaud + * Copyright (C) 2015-2022: Julien Rouhaud * *------------------------------------------------------------------------- */ diff --git a/import/hypopg_import.c b/import/hypopg_import.c index d21dfa0..5c11263 100644 --- a/import/hypopg_import.c +++ b/import/hypopg_import.c @@ -5,7 +5,7 @@ * This program is open source, licensed under the PostgreSQL license. * For license terms, see the LICENSE file. * - * Copyright (c) 2008-2021, PostgreSQL Global Development Group + * Copyright (c) 2008-2022, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/import/hypopg_import_index.c b/import/hypopg_import_index.c index 22e2902..2b5f4a7 100644 --- a/import/hypopg_import_index.c +++ b/import/hypopg_import_index.c @@ -6,7 +6,7 @@ * This program is open source, licensed under the PostgreSQL license. * For license terms, see the LICENSE file. * - * Copyright (c) 2008-2021, PostgreSQL Global Development Group + * Copyright (c) 2008-2022, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/include/hypopg.h b/include/hypopg.h index 0d47093..662acd6 100644 --- a/include/hypopg.h +++ b/include/hypopg.h @@ -5,7 +5,7 @@ * This program is open source, licensed under the PostgreSQL license. * For license terms, see the LICENSE file. * - * Copyright (C) 2015-2021: Julien Rouhaud + * Copyright (C) 2015-2022: Julien Rouhaud * *------------------------------------------------------------------------- */ diff --git a/include/hypopg_import.h b/include/hypopg_import.h index 0569190..98aedf3 100644 --- a/include/hypopg_import.h +++ b/include/hypopg_import.h @@ -5,7 +5,7 @@ * This program is open source, licensed under the PostgreSQL license. * For license terms, see the LICENSE file. * - * Copyright (c) 2008-2021, PostgreSQL Global Development Group + * Copyright (c) 2008-2022, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/include/hypopg_import_index.h b/include/hypopg_import_index.h index 9af3d2f..915f795 100644 --- a/include/hypopg_import_index.h +++ b/include/hypopg_import_index.h @@ -6,7 +6,7 @@ * This program is open source, licensed under the PostgreSQL license. * For license terms, see the LICENSE file. * - * Copyright (c) 2008-2021, PostgreSQL Global Development Group + * Copyright (c) 2008-2022, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/include/hypopg_index.h b/include/hypopg_index.h index a07b03e..06d2f9a 100644 --- a/include/hypopg_index.h +++ b/include/hypopg_index.h @@ -8,7 +8,7 @@ * This program is open source, licensed under the PostgreSQL license. * For license terms, see the LICENSE file. * - * Copyright (C) 2015-2021: Julien Rouhaud + * Copyright (C) 2015-2022: Julien Rouhaud * *------------------------------------------------------------------------- */ From edd5211d39846549de43417bed3a7c01670fb9ef Mon Sep 17 00:00:00 2001 From: Julien Rouhaud Date: Sat, 14 May 2022 00:02:36 +0800 Subject: [PATCH 09/22] Remove _PG_fini(). Postgres hasn't called this function for more than a decade (even before extensions were introduced), and version 15 officially removes it so let's get rid of it too. --- hypopg.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/hypopg.c b/hypopg.c index cc81102..d419857 100644 --- a/hypopg.c +++ b/hypopg.c @@ -55,7 +55,6 @@ static bool oid_wraparound = false; /*--- Functions --- */ PGDLLEXPORT void _PG_init(void); -PGDLLEXPORT void _PG_fini(void); PGDLLEXPORT Datum hypopg_reset(PG_FUNCTION_ARGS); @@ -160,17 +159,6 @@ _PG_init(void) EmitWarningsOnPlaceholders("hypopg"); } -void -_PG_fini(void) -{ - /* uninstall hooks */ - ProcessUtility_hook = prev_utility_hook; - ExecutorEnd_hook = prev_ExecutorEnd_hook; - get_relation_info_hook = prev_get_relation_info_hook; - explain_get_index_name_hook = prev_explain_get_index_name_hook; - -} - /*--------------------------------- * Return a new OID for an hypothetical index. * From 4fc6a7eadf972c452a96e66c4ba7e9cab62ae1b9 Mon Sep 17 00:00:00 2001 From: Krzysztof Szularz Date: Fri, 26 Aug 2022 14:49:33 +0200 Subject: [PATCH 10/22] Amend formatting in usage documentation One output in `Manipulate hypothetical indexes` section was not indented properly. --- docs/usage.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/usage.rst b/docs/usage.rst index c6e5c28..231c6d6 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -193,10 +193,10 @@ Some other convenience functions and views are available: .. code-block:: psql SELECT * FROM hypopg() ; - indexname | indexrelid | indrelid | innatts | indisunique | indkey | indcollation | indclass | indoption | indexprs | indpred | amid -----------------------+------------+----------+---------+-------------+--------+--------------+----------+-----------+----------+---------+------ - <18284>btree_hypo_id | 13543 | 18122 | 1 | f | 1 | 0 | 1978 | | | | 403 -(1 row) + indexname | indexrelid | indrelid | innatts | indisunique | indkey | indcollation | indclass | indoption | indexprs | indpred | amid + ----------------------+------------+----------+---------+-------------+--------+--------------+----------+-----------+----------+---------+------ + <18284>btree_hypo_id | 13543 | 18122 | 1 | f | 1 | 0 | 1978 | | | | 403 + (1 row) - **hypopg_get_indexdef(oid)**: function that lists the CREATE INDEX statement that would recreate a stored hypothetical index From 0316eb991194475116229c3bef2a6097030e650f Mon Sep 17 00:00:00 2001 From: Julien Rouhaud Date: Fri, 26 Aug 2022 21:24:20 +0800 Subject: [PATCH 11/22] Update contributors. --- CONTRIBUTORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 8f17b49..b61991b 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -18,3 +18,4 @@ People who contributed to hypopg: * ibrahim edib kokdemir * github user nikhil-postgres * Xiaozhe Yao + * Krzysztof Szularz From 512bcd30de328419b7551528cfd31d60f1f07e37 Mon Sep 17 00:00:00 2001 From: Julien Rouhaud Date: Thu, 1 Sep 2022 11:06:25 +0800 Subject: [PATCH 12/22] Fix typo in regression test comments. Per report from Zhihong Yu. --- expected/hypo_index_part.out | 2 +- expected/hypo_index_part_10.out | 2 +- test/sql/hypo_index_part.sql | 2 +- test/sql/hypo_index_part_10.sql | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/expected/hypo_index_part.out b/expected/hypo_index_part.out index fbd1fc9..d87ed72 100644 --- a/expected/hypo_index_part.out +++ b/expected/hypo_index_part.out @@ -1,4 +1,4 @@ --- Hypothetical on partitioned tabled +-- Hypothetical on partitioned tables CREATE TABLE hypo_part(id1 integer, id2 integer, id3 integer) PARTITION BY LIST (id1); CREATE TABLE hypo_part_1 diff --git a/expected/hypo_index_part_10.out b/expected/hypo_index_part_10.out index a0d4040..f55e785 100644 --- a/expected/hypo_index_part_10.out +++ b/expected/hypo_index_part_10.out @@ -1,4 +1,4 @@ --- Hypothetical on partitioned tabled +-- Hypothetical on partitioned tables CREATE TABLE hypo_part(id1 integer, id2 integer, id3 integer) PARTITION BY LIST (id1); CREATE TABLE hypo_part_1 diff --git a/test/sql/hypo_index_part.sql b/test/sql/hypo_index_part.sql index 36d5c9a..d1c6cce 100644 --- a/test/sql/hypo_index_part.sql +++ b/test/sql/hypo_index_part.sql @@ -1,4 +1,4 @@ --- Hypothetical on partitioned tabled +-- Hypothetical on partitioned tables CREATE TABLE hypo_part(id1 integer, id2 integer, id3 integer) PARTITION BY LIST (id1); diff --git a/test/sql/hypo_index_part_10.sql b/test/sql/hypo_index_part_10.sql index ddc38cd..274896b 100644 --- a/test/sql/hypo_index_part_10.sql +++ b/test/sql/hypo_index_part_10.sql @@ -1,4 +1,4 @@ --- Hypothetical on partitioned tabled +-- Hypothetical on partitioned tables CREATE TABLE hypo_part(id1 integer, id2 integer, id3 integer) PARTITION BY LIST (id1); From 0a80ba3090f3d291973f13b16fbb948d0b4d0ca1 Mon Sep 17 00:00:00 2001 From: Julien Rouhaud Date: Sat, 17 Sep 2022 22:05:24 +0800 Subject: [PATCH 13/22] Fix a few allocation size and array assignation mistakes. Some part of the code was allocating array entries to account for included columns while it's only needed for key columns, and some other parts were trying to store data for included columns on info that's only relevant for key columns (and thus allocated in consequence). While at it, reorder a few lines to keep the order consistent between and hypo_newIndex() and hypo_injectHypotheticalIndex(). Per initial report from Zhihong Yu. --- hypopg_index.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/hypopg_index.c b/hypopg_index.c index bf7ca38..d03d554 100644 --- a/hypopg_index.c +++ b/hypopg_index.c @@ -1013,21 +1013,17 @@ hypo_injectHypotheticalIndex(PlannerInfo *root, #endif index->indexkeys = (int *) palloc(sizeof(int) * ncolumns); - index->indexcollations = (Oid *) palloc(sizeof(int) * ncolumns); - index->opfamily = (Oid *) palloc(sizeof(int) * ncolumns); - index->opcintype = (Oid *) palloc(sizeof(int) * ncolumns); - -#if PG_VERSION_NUM >= 90500 - index->canreturn = (bool *) palloc(sizeof(bool) * ncolumns); -#endif + index->indexcollations = (Oid *) palloc(sizeof(int) * nkeycolumns); + index->opfamily = (Oid *) palloc(sizeof(int) * nkeycolumns); + index->opcintype = (Oid *) palloc(sizeof(int) * nkeycolumns); if ((index->relam == BTREE_AM_OID) || entry->amcanorder) { if (index->relam != BTREE_AM_OID) - index->sortopfamily = palloc0(sizeof(Oid) * ncolumns); + index->sortopfamily = palloc0(sizeof(Oid) * nkeycolumns); - index->reverse_sort = (bool *) palloc(sizeof(bool) * ncolumns); - index->nulls_first = (bool *) palloc(sizeof(bool) * ncolumns); + index->reverse_sort = (bool *) palloc(sizeof(bool) * nkeycolumns); + index->nulls_first = (bool *) palloc(sizeof(bool) * nkeycolumns); } else { @@ -1036,6 +1032,10 @@ hypo_injectHypotheticalIndex(PlannerInfo *root, index->nulls_first = NULL; } +#if PG_VERSION_NUM >= 90500 + index->canreturn = (bool *) palloc(sizeof(bool) * ncolumns); +#endif + for (i = 0; i < ncolumns; i++) { index->indexkeys[i] = entry->indexkeys[i]; @@ -1046,9 +1046,9 @@ hypo_injectHypotheticalIndex(PlannerInfo *root, for (i = 0; i < nkeycolumns; i++) { + index->indexcollations[i] = entry->indexcollations[i]; index->opfamily[i] = entry->opfamily[i]; index->opcintype[i] = entry->opcintype[i]; - index->indexcollations[i] = entry->indexcollations[i]; } /* @@ -1064,7 +1064,7 @@ hypo_injectHypotheticalIndex(PlannerInfo *root, */ index->sortopfamily = index->opfamily; - for (i = 0; i < ncolumns; i++) + for (i = 0; i < nkeycolumns; i++) { index->reverse_sort[i] = entry->reverse_sort[i]; index->nulls_first[i] = entry->nulls_first[i]; @@ -1074,7 +1074,7 @@ hypo_injectHypotheticalIndex(PlannerInfo *root, { if (entry->sortopfamily) { - for (i = 0; i < ncolumns; i++) + for (i = 0; i < nkeycolumns; i++) { index->sortopfamily[i] = entry->sortopfamily[i]; index->reverse_sort[i] = entry->reverse_sort[i]; From 9605ba45804cb75f816818f1ef1e83851a68116a Mon Sep 17 00:00:00 2001 From: Julien Rouhaud Date: Sun, 8 Jan 2023 22:59:49 +0800 Subject: [PATCH 14/22] Update copyright year. --- LICENSE | 2 +- debian/copyright | 2 +- docs/conf.py | 2 +- hypopg--1.3.1--1.3.2.sql | 2 +- hypopg--1.3.1.sql | 2 +- hypopg--1.3.2.sql | 2 +- hypopg.c | 2 +- hypopg_index.c | 2 +- import/hypopg_import.c | 2 +- import/hypopg_import_index.c | 2 +- include/hypopg.h | 2 +- include/hypopg_import.h | 2 +- include/hypopg_import_index.h | 2 +- include/hypopg_index.h | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/LICENSE b/LICENSE index d2632be..1267c02 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Portions Copyright (c) 2015-2022, PostgreSQL GLobal Development Group +Portions Copyright (c) 2015-2023, PostgreSQL GLobal Development Group Portions Copyright (c) 1994, The Regents of the University of California diff --git a/debian/copyright b/debian/copyright index 20aab17..96f6f37 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,4 +1,4 @@ -Portions Copyright (c) 2015-2022, PostgreSQL GLobal Development Group +Portions Copyright (c) 2015-2023, PostgreSQL GLobal Development Group Portions Copyright (c) 1994, The Regents of the University of California diff --git a/docs/conf.py b/docs/conf.py index 5118637..259e28d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -50,7 +50,7 @@ master_doc = 'index' # General information about the project. project = 'HypoPG' -copyright = '2015-2022, Julien Rouhaud' +copyright = '2015-2023, Julien Rouhaud' author = 'Julien Rouhaud' # The version info for the project you're documenting, acts as replacement for diff --git a/hypopg--1.3.1--1.3.2.sql b/hypopg--1.3.1--1.3.2.sql index 41b1f4d..aafba06 100644 --- a/hypopg--1.3.1--1.3.2.sql +++ b/hypopg--1.3.1--1.3.2.sql @@ -1,7 +1,7 @@ -- This program is open source, licensed under the PostgreSQL License. -- For license terms, see the LICENSE file. -- --- Copyright (C) 2015-2022: Julien Rouhaud +-- Copyright (C) 2015-2023: Julien Rouhaud -- complain if script is sourced in psql, rather than via CREATE EXTENSION \echo Use "ALTER EXTENSION hypopg" to load this file. \quit diff --git a/hypopg--1.3.1.sql b/hypopg--1.3.1.sql index 978cf40..8492966 100644 --- a/hypopg--1.3.1.sql +++ b/hypopg--1.3.1.sql @@ -1,7 +1,7 @@ -- This program is open source, licensed under the PostgreSQL License. -- For license terms, see the LICENSE file. -- --- Copyright (C) 2015-2022: Julien Rouhaud +-- Copyright (C) 2015-2023: Julien Rouhaud -- complain if script is sourced in psql, rather than via CREATE EXTENSION \echo Use "CREATE EXTENSION hypopg" to load this file. \quit diff --git a/hypopg--1.3.2.sql b/hypopg--1.3.2.sql index 978cf40..8492966 100644 --- a/hypopg--1.3.2.sql +++ b/hypopg--1.3.2.sql @@ -1,7 +1,7 @@ -- This program is open source, licensed under the PostgreSQL License. -- For license terms, see the LICENSE file. -- --- Copyright (C) 2015-2022: Julien Rouhaud +-- Copyright (C) 2015-2023: Julien Rouhaud -- complain if script is sourced in psql, rather than via CREATE EXTENSION \echo Use "CREATE EXTENSION hypopg" to load this file. \quit diff --git a/hypopg.c b/hypopg.c index d419857..a4210f9 100644 --- a/hypopg.c +++ b/hypopg.c @@ -8,7 +8,7 @@ * This program is open source, licensed under the PostgreSQL license. * For license terms, see the LICENSE file. * - * Copyright (C) 2015-2022: Julien Rouhaud + * Copyright (C) 2015-2023: Julien Rouhaud * *------------------------------------------------------------------------- */ diff --git a/hypopg_index.c b/hypopg_index.c index d03d554..4d925c0 100644 --- a/hypopg_index.c +++ b/hypopg_index.c @@ -8,7 +8,7 @@ * This program is open source, licensed under the PostgreSQL license. * For license terms, see the LICENSE file. * - * Copyright (C) 2015-2022: Julien Rouhaud + * Copyright (C) 2015-2023: Julien Rouhaud * *------------------------------------------------------------------------- */ diff --git a/import/hypopg_import.c b/import/hypopg_import.c index 5c11263..f698d5d 100644 --- a/import/hypopg_import.c +++ b/import/hypopg_import.c @@ -5,7 +5,7 @@ * This program is open source, licensed under the PostgreSQL license. * For license terms, see the LICENSE file. * - * Copyright (c) 2008-2022, PostgreSQL Global Development Group + * Copyright (c) 2008-2023, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/import/hypopg_import_index.c b/import/hypopg_import_index.c index 2b5f4a7..9afcaa5 100644 --- a/import/hypopg_import_index.c +++ b/import/hypopg_import_index.c @@ -6,7 +6,7 @@ * This program is open source, licensed under the PostgreSQL license. * For license terms, see the LICENSE file. * - * Copyright (c) 2008-2022, PostgreSQL Global Development Group + * Copyright (c) 2008-2023, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/include/hypopg.h b/include/hypopg.h index 662acd6..24a0090 100644 --- a/include/hypopg.h +++ b/include/hypopg.h @@ -5,7 +5,7 @@ * This program is open source, licensed under the PostgreSQL license. * For license terms, see the LICENSE file. * - * Copyright (C) 2015-2022: Julien Rouhaud + * Copyright (C) 2015-2023: Julien Rouhaud * *------------------------------------------------------------------------- */ diff --git a/include/hypopg_import.h b/include/hypopg_import.h index 98aedf3..46f88cd 100644 --- a/include/hypopg_import.h +++ b/include/hypopg_import.h @@ -5,7 +5,7 @@ * This program is open source, licensed under the PostgreSQL license. * For license terms, see the LICENSE file. * - * Copyright (c) 2008-2022, PostgreSQL Global Development Group + * Copyright (c) 2008-2023, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/include/hypopg_import_index.h b/include/hypopg_import_index.h index 915f795..b965731 100644 --- a/include/hypopg_import_index.h +++ b/include/hypopg_import_index.h @@ -6,7 +6,7 @@ * This program is open source, licensed under the PostgreSQL license. * For license terms, see the LICENSE file. * - * Copyright (c) 2008-2022, PostgreSQL Global Development Group + * Copyright (c) 2008-2023, PostgreSQL Global Development Group * *------------------------------------------------------------------------- */ diff --git a/include/hypopg_index.h b/include/hypopg_index.h index 06d2f9a..75cb178 100644 --- a/include/hypopg_index.h +++ b/include/hypopg_index.h @@ -8,7 +8,7 @@ * This program is open source, licensed under the PostgreSQL license. * For license terms, see the LICENSE file. * - * Copyright (C) 2015-2022: Julien Rouhaud + * Copyright (C) 2015-2023: Julien Rouhaud * *------------------------------------------------------------------------- */ From 12396d6db6c83727b3b220f2eabafad9e408b47f Mon Sep 17 00:00:00 2001 From: Julien Rouhaud Date: Sat, 25 Feb 2023 14:39:35 +0800 Subject: [PATCH 15/22] Simplify isExplain retrieval. Previous version was using query_or_expression_tree_walker, which isn't really necessary. Since the signature of that function changed as of 1c27d16e6e5c1f463bbe1e9ece88dda811235165, don't rely on it anymore and simply get the info from the top level node. --- hypopg.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/hypopg.c b/hypopg.c index a4210f9..5c042f2 100644 --- a/hypopg.c +++ b/hypopg.c @@ -102,7 +102,7 @@ static void hypo_get_relation_info_hook(PlannerInfo *root, static get_relation_info_hook_type prev_get_relation_info_hook = NULL; static bool hypo_index_match_table(hypoIndex *entry, Oid relid); -static bool hypo_query_walker(Node *node); +static bool hypo_is_simple_explain(Node *node); void _PG_init(void) @@ -303,14 +303,13 @@ hypo_utility_hook( #endif ) { - isExplain = query_or_expression_tree_walker( + isExplain = hypo_is_simple_explain( #if PG_VERSION_NUM >= 100000 - (Node *) pstmt, + (Node *) pstmt #else - parsetree, + parsetree #endif - hypo_query_walker, - NULL, 0); + ); if (prev_utility_hook) prev_utility_hook( @@ -404,7 +403,7 @@ hypo_index_match_table(hypoIndex *entry, Oid relid) * i.e. an EXPLAIN, no ANALYZE */ static bool -hypo_query_walker(Node *parsetree) +hypo_is_simple_explain(Node *parsetree) { if (parsetree == NULL) return false; @@ -414,6 +413,7 @@ hypo_query_walker(Node *parsetree) if (parsetree == NULL) return false; #endif + switch (nodeTag(parsetree)) { case T_ExplainStmt: From e7d1fea516626e752e2143bab6ebe665bc812378 Mon Sep 17 00:00:00 2001 From: Julien Rouhaud Date: Sat, 25 Feb 2023 14:47:20 +0800 Subject: [PATCH 16/22] Fix hypopg_create_index argument retrieval. --- hypopg_index.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hypopg_index.c b/hypopg_index.c index 4d925c0..204fc3e 100644 --- a/hypopg_index.c +++ b/hypopg_index.c @@ -1291,7 +1291,7 @@ hypopg(PG_FUNCTION_ARGS) Datum hypopg_create_index(PG_FUNCTION_ARGS) { - char *sql = TextDatumGetCString(PG_GETARG_TEXT_PP(0)); + char *sql = TextDatumGetCString(PG_GETARG_DATUM(0)); List *parsetree_list; ListCell *parsetree_item; ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; From 1a5766274d40525ea8d4a994cd739b1f5ecfb5a2 Mon Sep 17 00:00:00 2001 From: Julien Rouhaud Date: Thu, 16 Mar 2023 11:55:44 +0800 Subject: [PATCH 17/22] Check that hypopg_relation_size was given a hypothetical index oid. And error out instead of returning 0 if that's not the case. While at it, some iterating over the list of hypothetical indexes once we found the wanted one. --- expected/hypopg.out | 3 +++ hypopg_index.c | 6 ++++++ test/sql/hypopg.sql | 3 +++ 3 files changed, 12 insertions(+) diff --git a/expected/hypopg.out b/expected/hypopg.out index 990cb46..a00648f 100644 --- a/expected/hypopg.out +++ b/expected/hypopg.out @@ -105,6 +105,9 @@ ORDER BY indexrelid; f (3 rows) +-- Should detect invalid argument +SELECT hypopg_relation_size(1); +ERROR: oid 1 is not a hypothetical index -- locally disable hypoopg SET hypopg.enabled to false; -- no hypothetical index should be used diff --git a/hypopg_index.c b/hypopg_index.c index 204fc3e..e7a0b7a 100644 --- a/hypopg_index.c +++ b/hypopg_index.c @@ -1388,6 +1388,7 @@ hypopg_relation_size(PG_FUNCTION_ARGS) double tuples; Oid indexid = PG_GETARG_OID(0); ListCell *lc; + bool found = false; pages = 0; tuples = 0; @@ -1398,9 +1399,14 @@ hypopg_relation_size(PG_FUNCTION_ARGS) if (entry->oid == indexid) { hypo_estimate_index_simple(entry, &pages, &tuples); + found = true; + break; } } + if (!found) + elog(ERROR, "oid %u is not a hypothetical index", indexid); + PG_RETURN_INT64(pages * 1.0L * BLCKSZ); } diff --git a/test/sql/hypopg.sql b/test/sql/hypopg.sql index 28e3fcb..64cfcd5 100644 --- a/test/sql/hypopg.sql +++ b/test/sql/hypopg.sql @@ -70,6 +70,9 @@ SELECT hypopg_relation_size(indexrelid) = current_setting('block_size')::bigint FROM hypopg() ORDER BY indexrelid; +-- Should detect invalid argument +SELECT hypopg_relation_size(1); + -- locally disable hypoopg SET hypopg.enabled to false; From 93f15d0a3a3b8c6ecad1826cb5453dd8cf270a03 Mon Sep 17 00:00:00 2001 From: nutvii <1972404126@qq.com> Date: Tue, 21 Mar 2023 00:12:38 +0800 Subject: [PATCH 18/22] Start working on version 1.4.0 --- hypopg--1.3.1--1.3.2.sql => hypopg--1.3.1--1.4.0.sql | 0 hypopg--1.3.2.sql => hypopg--1.4.0.sql | 0 hypopg.control | 2 +- 3 files changed, 1 insertion(+), 1 deletion(-) rename hypopg--1.3.1--1.3.2.sql => hypopg--1.3.1--1.4.0.sql (100%) rename hypopg--1.3.2.sql => hypopg--1.4.0.sql (100%) diff --git a/hypopg--1.3.1--1.3.2.sql b/hypopg--1.3.1--1.4.0.sql similarity index 100% rename from hypopg--1.3.1--1.3.2.sql rename to hypopg--1.3.1--1.4.0.sql diff --git a/hypopg--1.3.2.sql b/hypopg--1.4.0.sql similarity index 100% rename from hypopg--1.3.2.sql rename to hypopg--1.4.0.sql diff --git a/hypopg.control b/hypopg.control index daca457..4e08300 100644 --- a/hypopg.control +++ b/hypopg.control @@ -1,6 +1,6 @@ # hypopg extension comment = 'Hypothetical indexes for PostgreSQL' -default_version = '1.3.2' +default_version = '1.4.0' module_pathname = '$libdir/hypopg' relocatable = true From 351f14a79daae8ab57339d2367d7f2fc639041f7 Mon Sep 17 00:00:00 2001 From: nutvii <1972404126@qq.com> Date: Tue, 21 Mar 2023 13:14:36 +0800 Subject: [PATCH 19/22] Add support for hypothetically hide existing index on explain. Add new list hideIndexes and develop new function by hypo_get_relation_info_hook. User can hide or unhide existing index and hypothetical indexes. When user set hide existing index and execute EXPLAIN, it will scan the same oid in hideIndexes and remove it to make query-plan can't use it. Add regression tests for hiding existing indexes. Update to version hypopg--1.4.0. Provide simple examples of using the hide series functions in README.md. Update doc about hypothetically hide existing indexes. --- CONTRIBUTORS.md | 1 + Makefile | 2 + README.md | 85 +++++++++++ docs/usage.rst | 166 ++++++++++++++++++++++ expected/hypo_hide_index.out | 268 +++++++++++++++++++++++++++++++++++ hypopg--1.3.1--1.4.0.sql | 43 ++++++ hypopg--1.4.0.sql | 43 ++++++ hypopg.c | 3 + hypopg_index.c | 189 ++++++++++++++++++++++++ include/hypopg_index.h | 10 ++ test/sql/hypo_hide_index.sql | 100 +++++++++++++ 11 files changed, 910 insertions(+) create mode 100644 expected/hypo_hide_index.out create mode 100644 test/sql/hypo_hide_index.sql diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index b61991b..5fae84b 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -19,3 +19,4 @@ People who contributed to hypopg: * github user nikhil-postgres * Xiaozhe Yao * Krzysztof Szularz + * NutVII \ No newline at end of file diff --git a/Makefile b/Makefile index e245936..2ac6b7d 100644 --- a/Makefile +++ b/Makefile @@ -51,6 +51,8 @@ ifneq ($(MAJORVERSION),$(filter $(MAJORVERSION), 9.2 9.3 9.4 9.5 9.6)) REGRESS += hypo_hash endif +REGRESS += hypo_hide_index + DEBUILD_ROOT = /tmp/$(EXTENSION) deb: release-zip diff --git a/README.md b/README.md index 9f28f94..f83549d 100644 --- a/README.md +++ b/README.md @@ -99,3 +99,88 @@ To remove your backend's hypothetical indexes, you can use the function `hypopg_drop_index(indexrelid)` with the OID that the `hypopg_list_indexes` view returns and call `hypopg_reset()` to remove all at once, or just close your current connection. + +Continuing with the above case, you can `hide existing indexes`, +but should be use `hypopg_reset()` to clear the previous effects of other indexes at first. + +Create two real indexes and run `EXPLAIN`: + + rjuju=# SELECT hypopg_reset(); + rjuju=# CREATE INDEX ON hypo(id); + rjuju=# CREATE INDEX ON hypo(id, val); + rjuju=# EXPLAIN SELECT * FROM hypo WHERE id = 1; + QUERY PLAN + ---------------------------------------------------------------------------------- + Index Only Scan using hypo_id_val_idx on hypo (cost=0.29..8.30 rows=1 width=13) + Index Cond: (id = 1) + (2 rows) + +The query plan is using the `hypo_id_val_idx` index. Use `hypopg_hide_index(oid)` to hide one of the indexes: + + rjuju=# SELECT hypopg_hide_index('hypo_id_val_idx'::REGCLASS); + rjuju=# EXPLAIN SELECT * FROM hypo WHERE id = 1; + QUERY PLAN + ------------------------------------------------------------------------- + Index Scan using hypo_id_idx on hypo (cost=0.29..8.30 rows=1 width=13) + Index Cond: (id = 1) + (2 rows) + +The query plan is using the other index `hypo_id_idx` now. Use `hypopg_hide_index(oid)` to hide it: + + rjuju=# SELECT hypopg_hide_index('hypo_id_idx'::REGCLASS); + rjuju=# EXPLAIN SELECT * FROM hypo WHERE id = 1; + QUERY PLAN + ------------------------------------------------------- + Seq Scan on hypo (cost=0.00..180.00 rows=1 width=13) + Filter: (id = 1) + (2 rows) + +And now the query plan changes back to `Seq Scan`. Use `hypopg_unhide_index(oid)` to restore index: + + rjuju=# SELECT hypopg_unhide_index('hypo_id_idx'::regclass); + rjuju=# EXPLAIN SELECT * FROM hypo WHERE id = 1; + QUERY PLAN + ------------------------------------------------------------------------- + Index Scan using hypo_id_idx on hypo (cost=0.29..8.30 rows=1 width=13) + Index Cond: (id = 1) + (2 rows) + +Of course, you can also hide hypothetical indexes: + + rjuju=# SELECT hypopg_create_index('CREATE INDEX ON hypo(id)'); + rjuju=# EXPLAIN SELECT * FROM hypo WHERE id = 1; + QUERY PLAN + ------------------------------------------------------------------------------------ + Index Scan using "<12659>btree_hypo_id" on hypo (cost=0.04..8.05 rows=1 width=13) + Index Cond: (id = 1) + (2 rows) + + rjuju=# SELECT hypopg_hide_index(12659); + rjuju=# EXPLAIN SELECT * FROM hypo WHERE id = 1; + QUERY PLAN + ------------------------------------------------------- + Seq Scan on hypo (cost=0.00..180.00 rows=1 width=13) + Filter: (id = 1) + (2 rows) + +You can check which indexes are hidden using `hypopg_hidden_indexes()` or the `hypopg_hidden_indexes` view: + + rjuju=# SELECT * FROM hypopg_hidden_indexes(); + indexid + --------- + 526604 + 526603 + 12659 + (3 rows) + + rjuju=# SELECT * FROM hypopg_hidden_indexes; + indexrelid | index_name | schema_name | table_name | am_name | is_hypo + ------------+----------------------+-------------+------------+---------+--------- + 12659 | <12659>btree_hypo_id | public | hypo | btree | t + 526603 | hypo_id_idx | public | hypo | btree | f + 526604 | hypo_id_val_idx | public | hypo | btree | f + (3 rows) + +To restore all existing indexes, you can use the function `hypopg_unhide_all_indexes()`. +Note that the functionality to hide existing indexes only applies to the EXPLAIN command in the current session +and will not affect other sessions. \ No newline at end of file diff --git a/docs/usage.rst b/docs/usage.rst index 231c6d6..6d2cf27 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -224,3 +224,169 @@ Some other convenience functions and views are available: - **hypopg_drop_index(oid)**: function that removes the given hypothetical index - **hypopg_reset()**: function that removes all hypothetical indexes + +Hypothetically hide existing indexes +------------------------------------ + +You can hide both existing and hypothetical indexes hypothetically. +If you want to test it as described in the documentation, +you should first use **hypopg_reset()** to clear the effects of any other hypothetical indexes. + +As a simple case, let's consider two indexes: + +.. code-block:: psql + + SELECT hypopg_reset(); + CREATE INDEX ON hypo(id); + CREATE INDEX ON hypo(id, val); + +.. code-block:: psql + :emphasize-lines: 4 + + EXPLAIN SELECT * FROM hypo WHERE id = 1; + QUERY PLAN + ---------------------------------------------------------------------------------- + Index Only Scan using hypo_id_val_idx on hypo (cost=0.29..8.30 rows=1 width=13) + Index Cond: (id = 1) + (2 rows) + +The query plan is using the **hypo_id_val_idx** index now. + +- **hypopg_hide_index(oid)**: function that allows you to hide an index in the EXPLAIN output by using its OID. + It returns `true` if the index was successfully hidden, and `false` otherwise. + +.. code-block:: psql + :emphasize-lines: 10 + + SELECT hypopg_hide_index('hypo_id_val_idx'::REGCLASS); + hypopg_hide_index + ------------------- + t + (1 row) + + EXPLAIN SELECT * FROM hypo WHERE id = 1; + QUERY PLAN + ------------------------------------------------------------------------- + Index Scan using hypo_id_idx on hypo (cost=0.29..8.30 rows=1 width=13) + Index Cond: (id = 1) + (2 rows) + +As an example, let's assume that the query plan is currently using the **hypo_id_val_idx** index. +To continue testing, use the **hypopg_hide_index(oid)** function to hide another index. + +.. code-block:: psql + :emphasize-lines: 10 + + SELECT hypopg_hide_index('hypo_id_idx'::REGCLASS); + hypopg_hide_index + ------------------- + t + (1 row) + + EXPLAIN SELECT * FROM hypo WHERE id = 1; + QUERY PLAN + ------------------------------------------------------- + Seq Scan on hypo (cost=0.00..180.00 rows=1 width=13) + Filter: (id = 1) + (2 rows) + +- **hypopg_unhide_index(oid)**: function that restore a previously hidden index in the EXPLAIN output by using its OID. + It returns `true` if the index was successfully restored, and `false` otherwise. + +.. code-block:: psql + :emphasize-lines: 10 + + SELECT hypopg_unhide_index('hypo_id_idx'::regclass); + hypopg_unhide_index + ------------------- + t + (1 row) + + EXPLAIN SELECT * FROM hypo WHERE id = 1; + QUERY PLAN + ------------------------------------------------------------------------- + Index Scan using hypo_id_idx on hypo (cost=0.29..8.30 rows=1 width=13) + Index Cond: (id = 1) + (2 rows) + +- **hypopg_unhide_all_index()**: function that restore all hidden indexes and returns void. + +- **hypopg_hidden_indexes()**: function that returns a list of OIDs for all hidden indexes. + +.. code-block:: psql + + SELECT * FROM hypopg_hidden_indexes(); + indexid + --------- + 526604 + (1 rows) + +- **hypopg_hidden_indexes**: view that returns a formatted list of all hidden indexes. + +.. code-block:: psql + + SELECT * FROM hypopg_hidden_indexes; + indexrelid | index_name | schema_name | table_name | am_name | is_hypo + -------------+----------------------+-------------+------------+---------+--------- + 526604 | hypo_id_val_idx | public | hypo | btree | f + (1 rows) + +.. note:: + + Hypothetical indexes can be hidden as well. + +.. code-block:: psql + :emphasize-lines: 10 + + SELECT hypopg_create_index('CREATE INDEX ON hypo(id)'); + hypopg_create_index + ------------------------------ + (12659,<12659>btree_hypo_id) + (1 row) + + EXPLAIN SELECT * FROM hypo WHERE id = 1; + QUERY PLAN + ------------------------------------------------------------------------------------ + Index Scan using "<12659>btree_hypo_id" on hypo (cost=0.04..8.05 rows=1 width=13) + Index Cond: (id = 1) + (2 rows) + +Now that the hypothetical index is being used, we can try hiding it to see the change: + +.. code-block:: psql + :emphasize-lines: 10 + + SELECT hypopg_hide_index(12659); + hypopg_hide_index + ------------------- + t + (1 row) + + EXPLAIN SELECT * FROM hypo WHERE id = 1; + QUERY PLAN + ------------------------------------------------------------------------- + Index Scan using hypo_id_idx on hypo (cost=0.29..8.30 rows=1 width=13) + Index Cond: (id = 1) + (2 rows) + + SELECT * FROM hypopg_hidden_indexes; + indexrelid | index_name | schema_name | table_name | am_name | is_hypo + -------------+----------------------+-------------+------------+---------+--------- + 12659 | <12659>btree_hypo_id | public | hypo | btree | t + 526604 | hypo_id_val_idx | public | hypo | btree | f + (2 rows) + +.. note:: + + If a hypothetical index has been hidden, it will be automatically unhidden + when it is deleted using **hypopg_drop_index(oid)** or **hypopg_reset()**. + +.. code-block:: psql + + SELECT hypopg_drop_index(12659); + + SELECT * FROM hypopg_hidden_indexes; + indexrelid | index_name | schema_name | table_name | am_name | is_hypo + -------------+----------------------+-------------+------------+---------+--------- + 526604 | hypo_id_val_idx | public | hypo | btree | f + (2 rows) \ No newline at end of file diff --git a/expected/hypo_hide_index.out b/expected/hypo_hide_index.out new file mode 100644 index 0000000..c63d47b --- /dev/null +++ b/expected/hypo_hide_index.out @@ -0,0 +1,268 @@ +-- Hypothetically hiding existing indexes tests +-- Remove all the hypothetical indexes if any +SELECT hypopg_reset(); + hypopg_reset +-------------- + +(1 row) + +-- The EXPLAIN initial state +SELECT COUNT(*) FROM do_explain('SELECT * FROM hypo WHERE id = 1') e +WHERE e ~ 'hypo_id_idx'; + count +------- + 0 +(1 row) + +-- Create real index in hypo and use this index +CREATE INDEX hypo_id_idx ON hypo(id); +SELECT COUNT(*) FROM do_explain('SELECT * FROM hypo WHERE id = 1') e +WHERE e ~ 'hypo_id_idx'; + count +------- + 1 +(1 row) + +-- Should be zero +SELECT COUNT(*) FROM hypopg_hidden_indexes(); + count +------- + 0 +(1 row) + +-- The hypo_id_idx index should not be used +SELECT hypopg_hide_index('hypo_id_idx'::regclass); + hypopg_hide_index +------------------- + t +(1 row) + +SELECT COUNT(*) FROM do_explain('SELECT * FROM hypo WHERE id = 1') e +WHERE e ~ 'hypo_id_idx'; + count +------- + 0 +(1 row) + +-- Should be only one record +SELECT COUNT(*) FROM hypopg_hidden_indexes(); + count +------- + 1 +(1 row) + +SELECT table_name,index_name FROM hypopg_hidden_indexes; + table_name | index_name +------------+------------- + hypo | hypo_id_idx +(1 row) + +-- Create the real index again and +-- EXPLAIN should use this index instead of the previous one +CREATE index hypo_id_val_idx ON hypo(id, val); +SELECT COUNT(*) FROM do_explain('SELECT * FROM hypo WHERE id = 1') e +WHERE e ~ 'hypo_id_val_idx'; + count +------- + 1 +(1 row) + +-- Shouldn't use any index +SELECT hypopg_hide_index('hypo_id_val_idx'::regclass); + hypopg_hide_index +------------------- + t +(1 row) + +SELECT COUNT(*) FROM do_explain('SELECT * FROM hypo WHERE id = 1') e +WHERE e ~ 'hypo_id_val_idx'; + count +------- + 0 +(1 row) + +-- Should be two records +SELECT table_name,index_name FROM hypopg_hidden_indexes; + table_name | index_name +------------+----------------- + hypo | hypo_id_idx + hypo | hypo_id_val_idx +(2 rows) + +-- Try to add one repeatedly or add another wrong index oid +SELECT hypopg_hide_index('hypo_id_idx'::regclass); + hypopg_hide_index +------------------- + f +(1 row) + +SELECT hypopg_hide_index('hypo'::regclass); + hypopg_hide_index +------------------- + f +(1 row) + +SELECT hypopg_hide_index(0); + hypopg_hide_index +------------------- + f +(1 row) + +-- Also of course can be used to hide hypothetical indexes +SELECT COUNT(*) FROM hypopg_create_index('create index on hypo(id,val);'); + count +------- + 1 +(1 row) + +SELECT COUNT(*) FROM do_explain('SELECT * FROM hypo WHERE id = 1') e +WHERE e ~ 'Index.*<\d+>btree_hypo.*'; + count +------- + 1 +(1 row) + +SELECT hypopg_hide_index((SELECT indexrelid FROM hypopg_list_indexes LIMIT 1)); + hypopg_hide_index +------------------- + t +(1 row) + +SELECT COUNT(*) FROM do_explain('SELECT * FROM hypo WHERE id = 1') e +WHERE e ~ 'Index.*<\d+>btree_hypo.*'; + count +------- + 0 +(1 row) + +-- Should be only three records +SELECT COUNT(*) FROM hypopg_hidden_indexes; + count +------- + 3 +(1 row) + +-- Hypothetical indexes should be unhidden when deleting +SELECT hypopg_drop_index((SELECT indexrelid FROM hypopg_list_indexes LIMIT 1)); + hypopg_drop_index +------------------- + t +(1 row) + +-- Should become two records +SELECT COUNT(*) FROM hypopg_hidden_indexes; + count +------- + 2 +(1 row) + +-- Hypopg_reset can also unhidden the hidden indexes +-- due to the deletion of hypothetical indexes. +SELECT COUNT(*) FROM hypopg_create_index('create index on hypo(id,val);'); + count +------- + 1 +(1 row) + +SELECT COUNT(*) FROM do_explain('SELECT * FROM hypo WHERE id = 1') e +WHERE e ~ 'Index.*<\d+>btree_hypo.*'; + count +------- + 1 +(1 row) + +SELECT hypopg_hide_index((SELECT indexrelid FROM hypopg_list_indexes LIMIT 1)); + hypopg_hide_index +------------------- + t +(1 row) + +-- Changed from three records to two records. +SELECT COUNT(*) FROM hypopg_hidden_indexes; + count +------- + 3 +(1 row) + +SELECT hypopg_reset(); + hypopg_reset +-------------- + +(1 row) + +SELECT COUNT(*) FROM hypopg_hidden_indexes; + count +------- + 2 +(1 row) + +-- Unhide an index +SELECT hypopg_unhide_index('hypo_id_idx'::regclass); + hypopg_unhide_index +--------------------- + t +(1 row) + +SELECT COUNT(*) FROM do_explain('SELECT * FROM hypo WHERE id = 1') e +WHERE e ~ 'hypo_id_idx'; + count +------- + 1 +(1 row) + +-- Should become one record +SELECT table_name,index_name FROM hypopg_hidden_indexes; + table_name | index_name +------------+----------------- + hypo | hypo_id_val_idx +(1 row) + +-- Try to delete one repeatedly or delete another wrong index oid +SELECT hypopg_unhide_index('hypo_id_idx'::regclass); + hypopg_unhide_index +--------------------- + f +(1 row) + +SELECT hypopg_unhide_index('hypo'::regclass); + hypopg_unhide_index +--------------------- + f +(1 row) + +SELECT hypopg_unhide_index(0); + hypopg_unhide_index +--------------------- + f +(1 row) + +-- Should still have one record +SELECT table_name,index_name FROM hypopg_hidden_indexes; + table_name | index_name +------------+----------------- + hypo | hypo_id_val_idx +(1 row) + +-- Unhide all indexes +SELECT hypopg_unhide_all_indexes(); + hypopg_unhide_all_indexes +--------------------------- + +(1 row) + +-- Should change back to the original zero +SELECT COUNT(*) FROM hypopg_hidden_indexes(); + count +------- + 0 +(1 row) + +-- Clean real indexes and hypothetical indexes +DROP INDEX hypo_id_idx; +DROP INDEX hypo_id_val_idx; +SELECT hypopg_reset(); + hypopg_reset +-------------- + +(1 row) + diff --git a/hypopg--1.3.1--1.4.0.sql b/hypopg--1.3.1--1.4.0.sql index aafba06..ce0a3a1 100644 --- a/hypopg--1.3.1--1.4.0.sql +++ b/hypopg--1.3.1--1.4.0.sql @@ -5,3 +5,46 @@ -- complain if script is sourced in psql, rather than via CREATE EXTENSION \echo Use "ALTER EXTENSION hypopg" to load this file. \quit + +CREATE FUNCTION +hypopg_hide_index(IN indexid oid) + RETURNS bool + LANGUAGE C STRICT VOLATILE COST 100 +AS '$libdir/hypopg', 'hypopg_hide_index'; + +CREATE FUNCTION +hypopg_unhide_index(IN indexid oid) + RETURNS bool + LANGUAGE C STRICT VOLATILE COST 100 +AS '$libdir/hypopg', 'hypopg_unhide_index'; + +CREATE FUNCTION +hypopg_unhide_all_indexes() + RETURNS void + LANGUAGE C VOLATILE COST 100 +AS '$libdir/hypopg', 'hypopg_unhide_all_indexes'; + +CREATE FUNCTION hypopg_hidden_indexes() + RETURNS TABLE (indexid oid) + LANGUAGE C STRICT VOLATILE +AS '$libdir/hypopg', 'hypopg_hidden_indexes'; + +CREATE VIEW hypopg_hidden_indexes +AS + SELECT h.indexid AS indexrelid, + i.relname AS index_name, + n.nspname AS schema_name, + t.relname AS table_name, + m.amname AS am_name, + false AS is_hypo + FROM hypopg_hidden_indexes() h + JOIN pg_index x ON x.indexrelid = h.indexid + JOIN pg_class i ON i.oid = h.indexid + JOIN pg_namespace n ON n.oid = i.relnamespace + JOIN pg_class t ON t.oid = x.indrelid + JOIN pg_am m ON m.oid = i.relam + UNION ALL + SELECT hl.*, true AS is_hypo + FROM hypopg_hidden_indexes() hi + JOIN hypopg_list_indexes hl on hl.indexrelid = hi.indexid + ORDER BY index_name; \ No newline at end of file diff --git a/hypopg--1.4.0.sql b/hypopg--1.4.0.sql index 8492966..f9d580c 100644 --- a/hypopg--1.4.0.sql +++ b/hypopg--1.4.0.sql @@ -60,3 +60,46 @@ hypopg_get_indexdef(IN indexid oid) RETURNS text LANGUAGE C STRICT VOLATILE COST 100 AS '$libdir/hypopg', 'hypopg_get_indexdef'; + +CREATE FUNCTION +hypopg_hide_index(IN indexid oid) + RETURNS bool + LANGUAGE C STRICT VOLATILE COST 100 +AS '$libdir/hypopg', 'hypopg_hide_index'; + +CREATE FUNCTION +hypopg_unhide_index(IN indexid oid) + RETURNS bool + LANGUAGE C STRICT VOLATILE COST 100 +AS '$libdir/hypopg', 'hypopg_unhide_index'; + +CREATE FUNCTION +hypopg_unhide_all_indexes() + RETURNS void + LANGUAGE C VOLATILE COST 100 +AS '$libdir/hypopg', 'hypopg_unhide_all_indexes'; + +CREATE FUNCTION hypopg_hidden_indexes() + RETURNS TABLE (indexid oid) + LANGUAGE C STRICT VOLATILE +AS '$libdir/hypopg', 'hypopg_hidden_indexes'; + +CREATE VIEW hypopg_hidden_indexes +AS + SELECT h.indexid AS indexrelid, + i.relname AS index_name, + n.nspname AS schema_name, + t.relname AS table_name, + m.amname AS am_name, + false AS is_hypo + FROM hypopg_hidden_indexes() h + JOIN pg_index x ON x.indexrelid = h.indexid + JOIN pg_class i ON i.oid = h.indexid + JOIN pg_namespace n ON n.oid = i.relnamespace + JOIN pg_class t ON t.oid = x.indrelid + JOIN pg_am m ON m.oid = i.relam + UNION ALL + SELECT hl.*, true AS is_hypo + FROM hypopg_hidden_indexes() hi + JOIN hypopg_list_indexes hl on hl.indexrelid = hi.indexid + ORDER BY index_name; \ No newline at end of file diff --git a/hypopg.c b/hypopg.c index 5c042f2..dbcfb56 100644 --- a/hypopg.c +++ b/hypopg.c @@ -122,6 +122,7 @@ _PG_init(void) isExplain = false; hypoIndexes = NIL; + hypoHiddenIndexes = NIL; HypoMemoryContext = AllocSetContextCreate(TopMemoryContext, "HypoPG context", @@ -528,6 +529,8 @@ hypo_get_relation_info_hook(PlannerInfo *root, inhparent, rel, relation, entry); } } + + hypo_hideIndexes(rel); } /* Close the relation release the lock now */ diff --git a/hypopg_index.c b/hypopg_index.c index e7a0b7a..d77f584 100644 --- a/hypopg_index.c +++ b/hypopg_index.c @@ -81,6 +81,7 @@ static Oid BLOOM_AM_OID = InvalidOid; explain_get_index_name_hook_type prev_explain_get_index_name_hook; List *hypoIndexes; +List *hypoHiddenIndexes; /*--- Functions --- */ @@ -90,6 +91,10 @@ PG_FUNCTION_INFO_V1(hypopg_drop_index); PG_FUNCTION_INFO_V1(hypopg_relation_size); PG_FUNCTION_INFO_V1(hypopg_get_indexdef); PG_FUNCTION_INFO_V1(hypopg_reset_index); +PG_FUNCTION_INFO_V1(hypopg_hide_index); +PG_FUNCTION_INFO_V1(hypopg_unhide_index); +PG_FUNCTION_INFO_V1(hypopg_unhide_all_indexes); +PG_FUNCTION_INFO_V1(hypopg_hidden_indexes); static void hypo_addIndex(hypoIndex * entry); @@ -101,6 +106,7 @@ static void hypo_estimate_index(hypoIndex * entry, RelOptInfo *rel); static int hypo_estimate_index_colsize(hypoIndex * entry, int col); static void hypo_index_pfree(hypoIndex * entry); static bool hypo_index_remove(Oid indexid); +static bool hypo_index_unhide(Oid indexid); static const hypoIndex *hypo_index_store_parsetree(IndexStmt *node, const char *queryString); static hypoIndex * hypo_newIndex(Oid relid, char *accessMethod, int nkeycolumns, @@ -922,6 +928,9 @@ hypo_index_remove(Oid indexid) { ListCell *lc; + /* remove this index from the list of hidden indexes if present */ + hypo_index_unhide(indexid); + foreach(lc, hypoIndexes) { hypoIndex *entry = (hypoIndex *) lfirst(lc); @@ -933,6 +942,7 @@ hypo_index_remove(Oid indexid) return true; } } + return false; } @@ -1592,6 +1602,185 @@ hypopg_reset_index(PG_FUNCTION_ARGS) PG_RETURN_VOID(); } +/* + * Add the given oid for the list of hidden indexes + * if it's a valid index (hypothetical or real), and if not hidden already. + * Return true if the oid is added to the list, false otherwise. + */ +Datum +hypopg_hide_index(PG_FUNCTION_ARGS) +{ + Oid indexid = PG_GETARG_OID(0); + MemoryContext old_context; + bool is_hypo = false; + ListCell *lc; + + /* first check if it is in hypoIndexes */ + foreach(lc, hypoIndexes) + { + hypoIndex *entry = (hypoIndex *) lfirst(lc); + + if (entry->oid == indexid) + { + is_hypo = true; + break; + } + } + + if (!is_hypo) + { + HeapTuple index_tup = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(indexid)); + + if (!HeapTupleIsValid(index_tup)) + return false; + + ReleaseSysCache(index_tup); + } + + if (list_member_oid(hypoHiddenIndexes, indexid)) + return false; + + old_context = MemoryContextSwitchTo(HypoMemoryContext); + hypoHiddenIndexes = lappend_oid(hypoHiddenIndexes, indexid); + MemoryContextSwitchTo(old_context); + + return true; +} + +/* + * Unhide the given index oid (hypothetical or not) to make it visible to + * the planner again. + */ +Datum +hypopg_unhide_index(PG_FUNCTION_ARGS) +{ + Oid indexid = PG_GETARG_OID(0); + + PG_RETURN_BOOL(hypo_index_unhide(indexid)); +} + +/* + * Restore all hidden index. + */ +Datum +hypopg_unhide_all_indexes(PG_FUNCTION_ARGS) +{ + list_free(hypoHiddenIndexes); + hypoHiddenIndexes = NIL; + PG_RETURN_VOID(); +} + +/* + * Get all hidden index oid. + */ +Datum +hypopg_hidden_indexes(PG_FUNCTION_ARGS) +{ + ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; + MemoryContext oldcontext; + TupleDesc tupdesc; + Tuplestorestate *tupstore; + ListCell *lc; + + /* check to see if caller supports us returning a tuplestore */ + if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("set-valued function called in context that cannot accept a set"))); + if (!(rsinfo->allowedModes & SFRM_Materialize)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("materialize mode required, but it is not " \ + "allowed in this context"))); + + oldcontext = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory); + + tupdesc = CreateTemplateTupleDesc(1); + TupleDescInitEntry(tupdesc, (AttrNumber) 1, "indexid", OIDOID, -1, 0); + + tupstore = tuplestore_begin_heap(true, false, work_mem); + rsinfo->returnMode = SFRM_Materialize; + rsinfo->setResult = tupstore; + rsinfo->setDesc = tupdesc; + + MemoryContextSwitchTo(oldcontext); + + foreach(lc, hypoHiddenIndexes) + { + Oid indexid = lfirst_oid(lc); + Datum values[HYPO_HIDDEN_INDEX_COLS]; + bool nulls[HYPO_HIDDEN_INDEX_COLS]; + + memset(values, 0, sizeof(values)); + memset(nulls, 0, sizeof(nulls)); + + values[0] = ObjectIdGetDatum(indexid); + tuplestore_putvalues(tupstore, tupdesc, values, nulls); + } + + /* clean up and return the tuplestore */ + tuplestore_donestoring(tupstore); + + return (Datum) 0; +} + +/* + * Remove the oid to restore this index on EXPLAIN. + */ +bool +hypo_index_unhide(Oid indexid) +{ + int prev_length = list_length(hypoHiddenIndexes); + + hypoHiddenIndexes = list_delete_oid(hypoHiddenIndexes, indexid); + return prev_length > list_length(hypoHiddenIndexes); +} + +/* + * Check rel and delete the same oid index as hypoHiddenIndexes + * in rel->indexlist. + */ +void +hypo_hideIndexes(RelOptInfo *rel) +{ + ListCell *cell = NULL; + + if (rel == NULL) + return; + + if (list_length(rel->indexlist) == 0 || list_length(hypoHiddenIndexes) == 0) + return; + + foreach(cell, hypoHiddenIndexes) + { + Oid oid = lfirst_oid(cell); + ListCell *lc = NULL; + +#if PG_VERSION_NUM >= 130000 + foreach(lc, rel->indexlist) + { + IndexOptInfo *index = (IndexOptInfo *) lfirst(lc); + + if (index->indexoid == oid) + rel->indexlist = foreach_delete_current(rel->indexlist, lc); + } +#else + ListCell *next; + ListCell *prev = NULL; + + for (lc = list_head(rel->indexlist); lc != NULL; lc = next) + { + IndexOptInfo *index = (IndexOptInfo *) lfirst(lc); + + next = lnext(lc); + if (index->indexoid == oid) + rel->indexlist = list_delete_cell(rel->indexlist, lc, prev); + else + prev = lc; + } +#endif + } +} /* Simple function to set the indexname, dealing with max name length, and the * ending \0 diff --git a/include/hypopg_index.h b/include/hypopg_index.h index 75cb178..02c7abd 100644 --- a/include/hypopg_index.h +++ b/include/hypopg_index.h @@ -24,6 +24,8 @@ #define HYPO_INDEX_NB_COLS 12 /* # of column hypopg() returns */ #define HYPO_INDEX_CREATE_COLS 2 /* # of column hypopg_create_index() * returns */ +#define HYPO_HIDDEN_INDEX_COLS 1 /* # of column hypopg_hidden_indexes() + * returns */ #if PG_VERSION_NUM >= 90600 /* hardcode some bloom values, bloom.h is not exported */ @@ -110,6 +112,9 @@ typedef struct hypoIndex /* List of hypothetic indexes for current backend */ extern List *hypoIndexes; +/* List of hypothetical hidden existing indexes for current backend */ +extern List *hypoHiddenIndexes; + /*--- Functions --- */ void hypo_index_reset(void); @@ -120,6 +125,10 @@ PGDLLEXPORT Datum hypopg_drop_index(PG_FUNCTION_ARGS); PGDLLEXPORT Datum hypopg_relation_size(PG_FUNCTION_ARGS); PGDLLEXPORT Datum hypopg_get_indexdef(PG_FUNCTION_ARGS); PGDLLEXPORT Datum hypopg_reset_index(PG_FUNCTION_ARGS); +PGDLLEXPORT Datum hypopg_hide_index(PG_FUNCTION_ARGS); +PGDLLEXPORT Datum hypopg_unhide_index(PG_FUNCTION_ARGS); +PGDLLEXPORT Datum hypopg_unhide_all_indexes(PG_FUNCTION_ARGS); +PGDLLEXPORT Datum hypopg_hidden_indexes(PG_FUNCTION_ARGS); extern explain_get_index_name_hook_type prev_explain_get_index_name_hook; hypoIndex *hypo_get_index(Oid indexId); @@ -131,5 +140,6 @@ void hypo_injectHypotheticalIndex(PlannerInfo *root, RelOptInfo *rel, Relation relation, hypoIndex * entry); +void hypo_hideIndexes(RelOptInfo *rel); #endif diff --git a/test/sql/hypo_hide_index.sql b/test/sql/hypo_hide_index.sql new file mode 100644 index 0000000..fa5875c --- /dev/null +++ b/test/sql/hypo_hide_index.sql @@ -0,0 +1,100 @@ +-- Hypothetically hiding existing indexes tests + +-- Remove all the hypothetical indexes if any +SELECT hypopg_reset(); + +-- The EXPLAIN initial state +SELECT COUNT(*) FROM do_explain('SELECT * FROM hypo WHERE id = 1') e +WHERE e ~ 'hypo_id_idx'; + +-- Create real index in hypo and use this index +CREATE INDEX hypo_id_idx ON hypo(id); +SELECT COUNT(*) FROM do_explain('SELECT * FROM hypo WHERE id = 1') e +WHERE e ~ 'hypo_id_idx'; + +-- Should be zero +SELECT COUNT(*) FROM hypopg_hidden_indexes(); + +-- The hypo_id_idx index should not be used +SELECT hypopg_hide_index('hypo_id_idx'::regclass); +SELECT COUNT(*) FROM do_explain('SELECT * FROM hypo WHERE id = 1') e +WHERE e ~ 'hypo_id_idx'; + +-- Should be only one record +SELECT COUNT(*) FROM hypopg_hidden_indexes(); +SELECT table_name,index_name FROM hypopg_hidden_indexes; + +-- Create the real index again and +-- EXPLAIN should use this index instead of the previous one +CREATE index hypo_id_val_idx ON hypo(id, val); +SELECT COUNT(*) FROM do_explain('SELECT * FROM hypo WHERE id = 1') e +WHERE e ~ 'hypo_id_val_idx'; + +-- Shouldn't use any index +SELECT hypopg_hide_index('hypo_id_val_idx'::regclass); +SELECT COUNT(*) FROM do_explain('SELECT * FROM hypo WHERE id = 1') e +WHERE e ~ 'hypo_id_val_idx'; + +-- Should be two records +SELECT table_name,index_name FROM hypopg_hidden_indexes; + +-- Try to add one repeatedly or add another wrong index oid +SELECT hypopg_hide_index('hypo_id_idx'::regclass); +SELECT hypopg_hide_index('hypo'::regclass); +SELECT hypopg_hide_index(0); + +-- Also of course can be used to hide hypothetical indexes +SELECT COUNT(*) FROM hypopg_create_index('create index on hypo(id,val);'); +SELECT COUNT(*) FROM do_explain('SELECT * FROM hypo WHERE id = 1') e +WHERE e ~ 'Index.*<\d+>btree_hypo.*'; +SELECT hypopg_hide_index((SELECT indexrelid FROM hypopg_list_indexes LIMIT 1)); +SELECT COUNT(*) FROM do_explain('SELECT * FROM hypo WHERE id = 1') e +WHERE e ~ 'Index.*<\d+>btree_hypo.*'; + +-- Should be only three records +SELECT COUNT(*) FROM hypopg_hidden_indexes; + +-- Hypothetical indexes should be unhidden when deleting +SELECT hypopg_drop_index((SELECT indexrelid FROM hypopg_list_indexes LIMIT 1)); + +-- Should become two records +SELECT COUNT(*) FROM hypopg_hidden_indexes; + +-- Hypopg_reset can also unhidden the hidden indexes +-- due to the deletion of hypothetical indexes. +SELECT COUNT(*) FROM hypopg_create_index('create index on hypo(id,val);'); +SELECT COUNT(*) FROM do_explain('SELECT * FROM hypo WHERE id = 1') e +WHERE e ~ 'Index.*<\d+>btree_hypo.*'; +SELECT hypopg_hide_index((SELECT indexrelid FROM hypopg_list_indexes LIMIT 1)); + +-- Changed from three records to two records. +SELECT COUNT(*) FROM hypopg_hidden_indexes; +SELECT hypopg_reset(); +SELECT COUNT(*) FROM hypopg_hidden_indexes; + +-- Unhide an index +SELECT hypopg_unhide_index('hypo_id_idx'::regclass); +SELECT COUNT(*) FROM do_explain('SELECT * FROM hypo WHERE id = 1') e +WHERE e ~ 'hypo_id_idx'; + +-- Should become one record +SELECT table_name,index_name FROM hypopg_hidden_indexes; + +-- Try to delete one repeatedly or delete another wrong index oid +SELECT hypopg_unhide_index('hypo_id_idx'::regclass); +SELECT hypopg_unhide_index('hypo'::regclass); +SELECT hypopg_unhide_index(0); + +-- Should still have one record +SELECT table_name,index_name FROM hypopg_hidden_indexes; + +-- Unhide all indexes +SELECT hypopg_unhide_all_indexes(); + +-- Should change back to the original zero +SELECT COUNT(*) FROM hypopg_hidden_indexes(); + +-- Clean real indexes and hypothetical indexes +DROP INDEX hypo_id_idx; +DROP INDEX hypo_id_val_idx; +SELECT hypopg_reset(); From 9385d5e25e951dc9acf8e6bebca33dffc14e33f7 Mon Sep 17 00:00:00 2001 From: Julien Rouhaud Date: Thu, 23 Mar 2023 17:09:35 +0800 Subject: [PATCH 20/22] Fixup for index hiding patch. Fix compatibility for pg12- servers, and while at it remove some uncessary trailing whitespaces. --- README.md | 16 ++++++++-------- docs/index.rst | 2 +- docs/usage.rst | 24 ++++++++++++------------ hypopg_index.c | 6 +++++- 4 files changed, 26 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index f83549d..32fd3c9 100644 --- a/README.md +++ b/README.md @@ -109,7 +109,7 @@ Create two real indexes and run `EXPLAIN`: rjuju=# CREATE INDEX ON hypo(id); rjuju=# CREATE INDEX ON hypo(id, val); rjuju=# EXPLAIN SELECT * FROM hypo WHERE id = 1; - QUERY PLAN + QUERY PLAN ---------------------------------------------------------------------------------- Index Only Scan using hypo_id_val_idx on hypo (cost=0.29..8.30 rows=1 width=13) Index Cond: (id = 1) @@ -119,7 +119,7 @@ The query plan is using the `hypo_id_val_idx` index. Use `hypopg_hide_index(oid) rjuju=# SELECT hypopg_hide_index('hypo_id_val_idx'::REGCLASS); rjuju=# EXPLAIN SELECT * FROM hypo WHERE id = 1; - QUERY PLAN + QUERY PLAN ------------------------------------------------------------------------- Index Scan using hypo_id_idx on hypo (cost=0.29..8.30 rows=1 width=13) Index Cond: (id = 1) @@ -129,7 +129,7 @@ The query plan is using the other index `hypo_id_idx` now. Use `hypopg_hide_inde rjuju=# SELECT hypopg_hide_index('hypo_id_idx'::REGCLASS); rjuju=# EXPLAIN SELECT * FROM hypo WHERE id = 1; - QUERY PLAN + QUERY PLAN ------------------------------------------------------- Seq Scan on hypo (cost=0.00..180.00 rows=1 width=13) Filter: (id = 1) @@ -139,7 +139,7 @@ And now the query plan changes back to `Seq Scan`. Use `hypopg_unhide_index(oid) rjuju=# SELECT hypopg_unhide_index('hypo_id_idx'::regclass); rjuju=# EXPLAIN SELECT * FROM hypo WHERE id = 1; - QUERY PLAN + QUERY PLAN ------------------------------------------------------------------------- Index Scan using hypo_id_idx on hypo (cost=0.29..8.30 rows=1 width=13) Index Cond: (id = 1) @@ -149,7 +149,7 @@ Of course, you can also hide hypothetical indexes: rjuju=# SELECT hypopg_create_index('CREATE INDEX ON hypo(id)'); rjuju=# EXPLAIN SELECT * FROM hypo WHERE id = 1; - QUERY PLAN + QUERY PLAN ------------------------------------------------------------------------------------ Index Scan using "<12659>btree_hypo_id" on hypo (cost=0.04..8.05 rows=1 width=13) Index Cond: (id = 1) @@ -157,7 +157,7 @@ Of course, you can also hide hypothetical indexes: rjuju=# SELECT hypopg_hide_index(12659); rjuju=# EXPLAIN SELECT * FROM hypo WHERE id = 1; - QUERY PLAN + QUERY PLAN ------------------------------------------------------- Seq Scan on hypo (cost=0.00..180.00 rows=1 width=13) Filter: (id = 1) @@ -166,7 +166,7 @@ Of course, you can also hide hypothetical indexes: You can check which indexes are hidden using `hypopg_hidden_indexes()` or the `hypopg_hidden_indexes` view: rjuju=# SELECT * FROM hypopg_hidden_indexes(); - indexid + indexid --------- 526604 526603 @@ -183,4 +183,4 @@ You can check which indexes are hidden using `hypopg_hidden_indexes()` or the `h To restore all existing indexes, you can use the function `hypopg_unhide_all_indexes()`. Note that the functionality to hide existing indexes only applies to the EXPLAIN command in the current session -and will not affect other sessions. \ No newline at end of file +and will not affect other sessions. diff --git a/docs/index.rst b/docs/index.rst index 2f64e82..62ec24c 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,4 +1,4 @@ -.. title:: HypoPG: Hypothetical indexes for PostgreSQL +.. title:: HypoPG: Hypothetical indexes for PostgreSQL HypoPG ====== diff --git a/docs/usage.rst b/docs/usage.rst index 6d2cf27..7dae9cb 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -244,7 +244,7 @@ As a simple case, let's consider two indexes: :emphasize-lines: 4 EXPLAIN SELECT * FROM hypo WHERE id = 1; - QUERY PLAN + QUERY PLAN ---------------------------------------------------------------------------------- Index Only Scan using hypo_id_val_idx on hypo (cost=0.29..8.30 rows=1 width=13) Index Cond: (id = 1) @@ -259,13 +259,13 @@ The query plan is using the **hypo_id_val_idx** index now. :emphasize-lines: 10 SELECT hypopg_hide_index('hypo_id_val_idx'::REGCLASS); - hypopg_hide_index + hypopg_hide_index ------------------- t (1 row) - + EXPLAIN SELECT * FROM hypo WHERE id = 1; - QUERY PLAN + QUERY PLAN ------------------------------------------------------------------------- Index Scan using hypo_id_idx on hypo (cost=0.29..8.30 rows=1 width=13) Index Cond: (id = 1) @@ -278,13 +278,13 @@ To continue testing, use the **hypopg_hide_index(oid)** function to hide another :emphasize-lines: 10 SELECT hypopg_hide_index('hypo_id_idx'::REGCLASS); - hypopg_hide_index + hypopg_hide_index ------------------- t (1 row) EXPLAIN SELECT * FROM hypo WHERE id = 1; - QUERY PLAN + QUERY PLAN ------------------------------------------------------- Seq Scan on hypo (cost=0.00..180.00 rows=1 width=13) Filter: (id = 1) @@ -303,7 +303,7 @@ To continue testing, use the **hypopg_hide_index(oid)** function to hide another (1 row) EXPLAIN SELECT * FROM hypo WHERE id = 1; - QUERY PLAN + QUERY PLAN ------------------------------------------------------------------------- Index Scan using hypo_id_idx on hypo (cost=0.29..8.30 rows=1 width=13) Index Cond: (id = 1) @@ -316,7 +316,7 @@ To continue testing, use the **hypopg_hide_index(oid)** function to hide another .. code-block:: psql SELECT * FROM hypopg_hidden_indexes(); - indexid + indexid --------- 526604 (1 rows) @@ -339,13 +339,13 @@ To continue testing, use the **hypopg_hide_index(oid)** function to hide another :emphasize-lines: 10 SELECT hypopg_create_index('CREATE INDEX ON hypo(id)'); - hypopg_create_index + hypopg_create_index ------------------------------ (12659,<12659>btree_hypo_id) (1 row) EXPLAIN SELECT * FROM hypo WHERE id = 1; - QUERY PLAN + QUERY PLAN ------------------------------------------------------------------------------------ Index Scan using "<12659>btree_hypo_id" on hypo (cost=0.04..8.05 rows=1 width=13) Index Cond: (id = 1) @@ -363,7 +363,7 @@ Now that the hypothetical index is being used, we can try hiding it to see the c (1 row) EXPLAIN SELECT * FROM hypo WHERE id = 1; - QUERY PLAN + QUERY PLAN ------------------------------------------------------------------------- Index Scan using hypo_id_idx on hypo (cost=0.29..8.30 rows=1 width=13) Index Cond: (id = 1) @@ -389,4 +389,4 @@ Now that the hypothetical index is being used, we can try hiding it to see the c indexrelid | index_name | schema_name | table_name | am_name | is_hypo -------------+----------------------+-------------+------------+---------+--------- 526604 | hypo_id_val_idx | public | hypo | btree | f - (2 rows) \ No newline at end of file + (2 rows) diff --git a/hypopg_index.c b/hypopg_index.c index d77f584..a861a8b 100644 --- a/hypopg_index.c +++ b/hypopg_index.c @@ -1695,7 +1695,11 @@ hypopg_hidden_indexes(PG_FUNCTION_ARGS) oldcontext = MemoryContextSwitchTo(rsinfo->econtext->ecxt_per_query_memory); - tupdesc = CreateTemplateTupleDesc(1); + tupdesc = CreateTemplateTupleDesc(1 +#if PG_VERSION_NUM < 120000 + , false +#endif + ); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "indexid", OIDOID, -1, 0); tupstore = tuplestore_begin_heap(true, false, work_mem); From 759306b32f4a54aa67f524b0f2c341cb3d8f2900 Mon Sep 17 00:00:00 2001 From: Julien Rouhaud Date: Thu, 11 May 2023 13:56:31 +0800 Subject: [PATCH 21/22] Remove unused variable. --- hypopg_index.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/hypopg_index.c b/hypopg_index.c index a861a8b..2b800da 100644 --- a/hypopg_index.c +++ b/hypopg_index.c @@ -1436,8 +1436,7 @@ hypopg_get_indexdef(PG_FUNCTION_ARGS) hypoIndex *entry = NULL; ListCell *lc; List *context; - int keyno, - cpt = 0; + int keyno; foreach(lc, hypoIndexes) { @@ -1508,8 +1507,6 @@ hypopg_get_indexdef(PG_FUNCTION_ARGS) keycoltype = exprType(indexkey); keycolcollation = exprCollation(indexkey); - - cpt++; } /* Add collation, if not default for column */ From d90375b6696fe052a18faa1702711b346819fbef Mon Sep 17 00:00:00 2001 From: Julien Rouhaud Date: Sat, 27 May 2023 15:28:18 +0800 Subject: [PATCH 22/22] Release 1.4.0 --- CHANGELOG.md | 15 +++++++++++++++ debian/changelog | 6 ++++++ 2 files changed, 21 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 34b7fd3..9259444 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,21 @@ Changelog ========= +2023-05-27 version 1.4.0: +------------------------- + + **New features**: + + - Support hypothetically hiding existing indexes, hypothetical or not (github + user nutvii and Julien Rouhaud) + + **Miscellaneous**: + + - Have hypopg_relation_size() error out rather than returning 0 if called for + an oid that isn't a hypothetical index oid + - Slighthly reduce memory usage for hypothetical btree indexes without + INCLUDE keys + 2021-06-21 version 1.3.1: ------------------------- diff --git a/debian/changelog b/debian/changelog index 11e097b..1209a26 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +hypopg (1.4.0-1) unstable; urgency=medium + + * New upstream version. + + -- Julien Rouhaud Sat, 27 May 2021 15:26:37 +0800 + hypopg (1.3.1-1) unstable; urgency=medium * New upstream version.