Merge tag '1.4.0' into debian

This commit is contained in:
Christoph Berg 2023-07-31 12:28:13 +02:00
commit 4d256101a3
31 changed files with 1107 additions and 77 deletions

View file

@ -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:
-------------------------

View file

@ -17,3 +17,6 @@ People who contributed to hypopg:
* nagaraju11
* ibrahim edib kokdemir
* github user nikhil-postgres
* Xiaozhe Yao
* Krzysztof Szularz
* NutVII

View file

@ -1,4 +1,4 @@
Portions Copyright (c) 2015-2021, PostgreSQL GLobal Development Group
Portions Copyright (c) 2015-2023, PostgreSQL GLobal Development Group
Portions Copyright (c) 1994, The Regents of the University of California

View file

@ -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

View file

@ -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,91 @@ 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.
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.

6
debian/changelog vendored
View file

@ -1,3 +1,9 @@
hypopg (1.4.0-1) unstable; urgency=medium
* New upstream version.
-- Julien Rouhaud <rjuju123@gmail.com> Mon, 31 Jul 2023 12:28:46 +0200
hypopg (1.3.1-2) unstable; urgency=medium
* Upload for PostgreSQL 15.

2
debian/copyright vendored
View file

@ -1,4 +1,4 @@
Portions Copyright (c) 2015-2021, PostgreSQL GLobal Development Group
Portions Copyright (c) 2015-2023, PostgreSQL GLobal Development Group
Portions Copyright (c) 1994, The Regents of the University of California

View file

@ -50,7 +50,7 @@ master_doc = 'index'
# General information about the project.
project = 'HypoPG'
copyright = '2015-2021, Julien Rouhaud'
copyright = '2015-2023, Julien Rouhaud'
author = 'Julien Rouhaud'
# The version info for the project you're documenting, acts as replacement for

View file

@ -1,4 +1,4 @@
.. title:: HypoPG: Hypothetical indexes for PostgreSQL
.. title:: HypoPG: Hypothetical indexes for PostgreSQL
HypoPG
======

View file

@ -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
<https://yum.postgresql.org>`_.
@ -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
<https://apt.postgresql.org>`_.
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

View file

@ -174,41 +174,219 @@ 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()**: function 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 | <NULL> | <NULL> | <NULL> | 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
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)

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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

50
hypopg--1.3.1--1.4.0.sql Normal file
View file

@ -0,0 +1,50 @@
-- This program is open source, licensed under the PostgreSQL License.
-- For license terms, see the LICENSE file.
--
-- 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
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;

View file

@ -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-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

105
hypopg--1.4.0.sql Normal file
View file

@ -0,0 +1,105 @@
-- This program is open source, licensed under the PostgreSQL License.
-- For license terms, see the LICENSE file.
--
-- 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
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, '<dropped>') 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';
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;

View file

@ -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-2023: Julien Rouhaud
*
*-------------------------------------------------------------------------
*/
@ -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);
@ -103,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)
@ -123,6 +122,7 @@ _PG_init(void)
isExplain = false;
hypoIndexes = NIL;
hypoHiddenIndexes = NIL;
HypoMemoryContext = AllocSetContextCreate(TopMemoryContext,
"HypoPG context",
@ -160,17 +160,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.
*
@ -315,14 +304,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(
@ -416,7 +404,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;
@ -426,6 +414,7 @@ hypo_query_walker(Node *parsetree)
if (parsetree == NULL)
return false;
#endif
switch (nodeTag(parsetree))
{
case T_ExplainStmt:
@ -540,6 +529,8 @@ hypo_get_relation_info_hook(PlannerInfo *root,
inhparent, rel, relation, entry);
}
}
hypo_hideIndexes(rel);
}
/* Close the relation release the lock now */

View file

@ -1,6 +1,6 @@
# hypopg extension
comment = 'Hypothetical indexes for PostgreSQL'
default_version = '1.3.1'
default_version = '1.4.0'
module_pathname = '$libdir/hypopg'
relocatable = true

View file

@ -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-2023: Julien Rouhaud
*
*-------------------------------------------------------------------------
*/
@ -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,
@ -350,7 +356,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.
*/
@ -395,12 +401,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 ... */
@ -921,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);
@ -932,6 +942,7 @@ hypo_index_remove(Oid indexid)
return true;
}
}
return false;
}
@ -1012,21 +1023,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
{
@ -1035,6 +1042,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];
@ -1045,9 +1056,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];
}
/*
@ -1063,7 +1074,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];
@ -1073,7 +1084,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];
@ -1290,7 +1301,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;
@ -1387,6 +1398,7 @@ hypopg_relation_size(PG_FUNCTION_ARGS)
double tuples;
Oid indexid = PG_GETARG_OID(0);
ListCell *lc;
bool found = false;
pages = 0;
tuples = 0;
@ -1397,9 +1409,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);
}
@ -1419,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)
{
@ -1491,8 +1507,6 @@ hypopg_get_indexdef(PG_FUNCTION_ARGS)
keycoltype = exprType(indexkey);
keycolcollation = exprCollation(indexkey);
cpt++;
}
/* Add collation, if not default for column */
@ -1585,6 +1599,189 @@ 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
#if PG_VERSION_NUM < 120000
, false
#endif
);
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

View file

@ -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-2023, PostgreSQL Global Development Group
*
*-------------------------------------------------------------------------
*/

View file

@ -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-2023, PostgreSQL Global Development Group
*
*-------------------------------------------------------------------------
*/

View file

@ -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-2023: Julien Rouhaud
*
*-------------------------------------------------------------------------
*/

View file

@ -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-2023, PostgreSQL Global Development Group
*
*-------------------------------------------------------------------------
*/

View file

@ -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-2023, PostgreSQL Global Development Group
*
*-------------------------------------------------------------------------
*/

View file

@ -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-2023: Julien Rouhaud
*
*-------------------------------------------------------------------------
*/
@ -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

View file

@ -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();

View file

@ -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);

View file

@ -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);

View file

@ -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;