1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-27 12:41:57 +03:00

Adjust INCLUDE index truncation comments and code.

Add several assertions that ensure that we're dealing with a pivot tuple
without non-key attributes where that's expected.  Also, remove the
assertion within _bt_isequal(), restoring the v10 function signature.  A
similar check will be performed for the page highkey within
_bt_moveright() in most cases.  Also avoid dropping all objects within
regression tests, to increase pg_dump test coverage for INCLUDE indexes.

Rather than using infrastructure that's generally intended to be used
with reference counted heap tuple descriptors during truncation, use the
same function that was introduced to store flat TupleDescs in shared
memory (we use a temp palloc'd buffer).  This isn't strictly necessary,
but seems more future-proof than the old approach.  It also lets us
avoid including rel.h within indextuple.c, which was arguably a
modularity violation.  Also, we now call index_deform_tuple() with the
truncated TupleDesc, not the source TupleDesc, since that's more robust,
and saves a few cycles.

In passing, fix a memory leak by pfree'ing truncated pivot tuple memory
during CREATE INDEX.  Also pfree during a page split, just to be
consistent.

Refactor _bt_check_natts() to be more readable.

Author: Peter Geoghegan with some editorization by me
Reviewed by: Alexander Korotkov, Teodor Sigaev
Discussion: https://www.postgresql.org/message-id/CAH2-Wz%3DkCWuXeMrBCopC-tFs3FbiVxQNjjgNKdG2sHxZ5k2y3w%40mail.gmail.com
This commit is contained in:
Teodor Sigaev
2018-04-19 08:45:58 +03:00
parent 5372c2c841
commit 075aade436
13 changed files with 428 additions and 329 deletions

View File

@ -1,81 +1,78 @@
/*
* 1.test CREATE INDEX
*
* Deliberately avoid dropping objects in this section, to get some pg_dump
* coverage.
*/
-- Regular index with included columns
CREATE TABLE tbl (c1 int, c2 int, c3 int, c4 box);
INSERT INTO tbl SELECT x, 2*x, 3*x, box('4,4,4,4') FROM generate_series(1,10) AS x;
CREATE INDEX tbl_idx ON tbl using btree (c1, c2) INCLUDE (c3,c4);
CREATE TABLE tbl_include_reg (c1 int, c2 int, c3 int, c4 box);
INSERT INTO tbl_include_reg SELECT x, 2*x, 3*x, box('4,4,4,4') FROM generate_series(1,10) AS x;
CREATE INDEX tbl_include_reg_idx ON tbl_include_reg using btree (c1, c2) INCLUDE (c3,c4);
-- must fail because of intersection of key and included columns
CREATE INDEX tbl_idx ON tbl using btree (c1, c2) INCLUDE (c1,c3);
CREATE INDEX tbl_include_reg_idx ON tbl_include_reg using btree (c1, c2) INCLUDE (c1,c3);
ERROR: included columns must not intersect with key columns
SELECT pg_get_indexdef(i.indexrelid)
FROM pg_index i JOIN pg_class c ON i.indexrelid = c.oid
WHERE i.indrelid = 'tbl'::regclass ORDER BY c.relname;
pg_get_indexdef
--------------------------------------------------------------------------
CREATE INDEX tbl_idx ON public.tbl USING btree (c1, c2) INCLUDE (c3, c4)
WHERE i.indrelid = 'tbl_include_reg'::regclass ORDER BY c.relname;
pg_get_indexdef
--------------------------------------------------------------------------------------------------
CREATE INDEX tbl_include_reg_idx ON public.tbl_include_reg USING btree (c1, c2) INCLUDE (c3, c4)
(1 row)
DROP TABLE tbl;
-- Unique index and unique constraint
CREATE TABLE tbl (c1 int, c2 int, c3 int, c4 box);
INSERT INTO tbl SELECT x, 2*x, 3*x, box('4,4,4,4') FROM generate_series(1,10) AS x;
CREATE UNIQUE INDEX tbl_idx_unique ON tbl using btree (c1, c2) INCLUDE (c3, c4);
ALTER TABLE tbl add UNIQUE USING INDEX tbl_idx_unique;
ALTER TABLE tbl add UNIQUE (c1, c2) INCLUDE (c3, c4);
CREATE TABLE tbl_include_unique1 (c1 int, c2 int, c3 int, c4 box);
INSERT INTO tbl_include_unique1 SELECT x, 2*x, 3*x, box('4,4,4,4') FROM generate_series(1,10) AS x;
CREATE UNIQUE INDEX tbl_include_unique1_idx_unique ON tbl_include_unique1 using btree (c1, c2) INCLUDE (c3, c4);
ALTER TABLE tbl_include_unique1 add UNIQUE USING INDEX tbl_include_unique1_idx_unique;
ALTER TABLE tbl_include_unique1 add UNIQUE (c1, c2) INCLUDE (c3, c4);
SELECT pg_get_indexdef(i.indexrelid)
FROM pg_index i JOIN pg_class c ON i.indexrelid = c.oid
WHERE i.indrelid = 'tbl'::regclass ORDER BY c.relname;
pg_get_indexdef
---------------------------------------------------------------------------------------------
CREATE UNIQUE INDEX tbl_c1_c2_c3_c4_key ON public.tbl USING btree (c1, c2) INCLUDE (c3, c4)
CREATE UNIQUE INDEX tbl_idx_unique ON public.tbl USING btree (c1, c2) INCLUDE (c3, c4)
WHERE i.indrelid = 'tbl_include_unique1'::regclass ORDER BY c.relname;
pg_get_indexdef
-----------------------------------------------------------------------------------------------------------------------------
CREATE UNIQUE INDEX tbl_include_unique1_c1_c2_c3_c4_key ON public.tbl_include_unique1 USING btree (c1, c2) INCLUDE (c3, c4)
CREATE UNIQUE INDEX tbl_include_unique1_idx_unique ON public.tbl_include_unique1 USING btree (c1, c2) INCLUDE (c3, c4)
(2 rows)
DROP TABLE tbl;
-- Unique index and unique constraint. Both must fail.
CREATE TABLE tbl (c1 int, c2 int, c3 int, c4 box);
INSERT INTO tbl SELECT 1, 2, 3*x, box('4,4,4,4') FROM generate_series(1,10) AS x;
CREATE UNIQUE INDEX tbl_idx_unique ON tbl using btree (c1, c2) INCLUDE (c3, c4);
ERROR: could not create unique index "tbl_idx_unique"
CREATE TABLE tbl_include_unique2 (c1 int, c2 int, c3 int, c4 box);
INSERT INTO tbl_include_unique2 SELECT 1, 2, 3*x, box('4,4,4,4') FROM generate_series(1,10) AS x;
CREATE UNIQUE INDEX tbl_include_unique2_idx_unique ON tbl_include_unique2 using btree (c1, c2) INCLUDE (c3, c4);
ERROR: could not create unique index "tbl_include_unique2_idx_unique"
DETAIL: Key (c1, c2)=(1, 2) is duplicated.
ALTER TABLE tbl add UNIQUE (c1, c2) INCLUDE (c3, c4);
ERROR: could not create unique index "tbl_c1_c2_c3_c4_key"
ALTER TABLE tbl_include_unique2 add UNIQUE (c1, c2) INCLUDE (c3, c4);
ERROR: could not create unique index "tbl_include_unique2_c1_c2_c3_c4_key"
DETAIL: Key (c1, c2)=(1, 2) is duplicated.
DROP TABLE tbl;
-- PK constraint
CREATE TABLE tbl (c1 int, c2 int, c3 int, c4 box);
INSERT INTO tbl SELECT 1, 2*x, 3*x, box('4,4,4,4') FROM generate_series(1,10) AS x;
ALTER TABLE tbl add PRIMARY KEY (c1, c2) INCLUDE (c3, c4);
CREATE TABLE tbl_include_pk (c1 int, c2 int, c3 int, c4 box);
INSERT INTO tbl_include_pk SELECT 1, 2*x, 3*x, box('4,4,4,4') FROM generate_series(1,10) AS x;
ALTER TABLE tbl_include_pk add PRIMARY KEY (c1, c2) INCLUDE (c3, c4);
SELECT pg_get_indexdef(i.indexrelid)
FROM pg_index i JOIN pg_class c ON i.indexrelid = c.oid
WHERE i.indrelid = 'tbl'::regclass ORDER BY c.relname;
pg_get_indexdef
----------------------------------------------------------------------------------
CREATE UNIQUE INDEX tbl_pkey ON public.tbl USING btree (c1, c2) INCLUDE (c3, c4)
WHERE i.indrelid = 'tbl_include_pk'::regclass ORDER BY c.relname;
pg_get_indexdef
--------------------------------------------------------------------------------------------------------
CREATE UNIQUE INDEX tbl_include_pk_pkey ON public.tbl_include_pk USING btree (c1, c2) INCLUDE (c3, c4)
(1 row)
DROP TABLE tbl;
CREATE TABLE tbl (c1 int, c2 int, c3 int, c4 box);
INSERT INTO tbl SELECT 1, 2*x, 3*x, box('4,4,4,4') FROM generate_series(1,10) AS x;
CREATE UNIQUE INDEX tbl_idx_unique ON tbl using btree (c1, c2) INCLUDE (c3, c4);
ALTER TABLE tbl add PRIMARY KEY USING INDEX tbl_idx_unique;
CREATE TABLE tbl_include_box (c1 int, c2 int, c3 int, c4 box);
INSERT INTO tbl_include_box SELECT 1, 2*x, 3*x, box('4,4,4,4') FROM generate_series(1,10) AS x;
CREATE UNIQUE INDEX tbl_include_box_idx_unique ON tbl_include_box using btree (c1, c2) INCLUDE (c3, c4);
ALTER TABLE tbl_include_box add PRIMARY KEY USING INDEX tbl_include_box_idx_unique;
SELECT pg_get_indexdef(i.indexrelid)
FROM pg_index i JOIN pg_class c ON i.indexrelid = c.oid
WHERE i.indrelid = 'tbl'::regclass ORDER BY c.relname;
pg_get_indexdef
----------------------------------------------------------------------------------------
CREATE UNIQUE INDEX tbl_idx_unique ON public.tbl USING btree (c1, c2) INCLUDE (c3, c4)
WHERE i.indrelid = 'tbl_include_box'::regclass ORDER BY c.relname;
pg_get_indexdef
----------------------------------------------------------------------------------------------------------------
CREATE UNIQUE INDEX tbl_include_box_idx_unique ON public.tbl_include_box USING btree (c1, c2) INCLUDE (c3, c4)
(1 row)
DROP TABLE tbl;
-- PK constraint. Must fail.
CREATE TABLE tbl (c1 int, c2 int, c3 int, c4 box);
INSERT INTO tbl SELECT 1, 2, 3*x, box('4,4,4,4') FROM generate_series(1,10) AS x;
ALTER TABLE tbl add PRIMARY KEY (c1, c2) INCLUDE (c3, c4);
ERROR: could not create unique index "tbl_pkey"
CREATE TABLE tbl_include_box_pk (c1 int, c2 int, c3 int, c4 box);
INSERT INTO tbl_include_box_pk SELECT 1, 2, 3*x, box('4,4,4,4') FROM generate_series(1,10) AS x;
ALTER TABLE tbl_include_box_pk add PRIMARY KEY (c1, c2) INCLUDE (c3, c4);
ERROR: could not create unique index "tbl_include_box_pk_pkey"
DETAIL: Key (c1, c2)=(1, 2) is duplicated.
DROP TABLE tbl;
/*
* 2. Test CREATE TABLE with constraint
*/

View File

@ -185,6 +185,12 @@ sql_sizing|f
sql_sizing_profiles|f
stud_emp|f
student|f
tbl_include_box|t
tbl_include_box_pk|f
tbl_include_pk|t
tbl_include_reg|t
tbl_include_unique1|t
tbl_include_unique2|f
tenk1|t
tenk2|t
test_range_excl|t

View File

@ -1,59 +1,56 @@
/*
* 1.test CREATE INDEX
*
* Deliberately avoid dropping objects in this section, to get some pg_dump
* coverage.
*/
-- Regular index with included columns
CREATE TABLE tbl (c1 int, c2 int, c3 int, c4 box);
INSERT INTO tbl SELECT x, 2*x, 3*x, box('4,4,4,4') FROM generate_series(1,10) AS x;
CREATE INDEX tbl_idx ON tbl using btree (c1, c2) INCLUDE (c3,c4);
CREATE TABLE tbl_include_reg (c1 int, c2 int, c3 int, c4 box);
INSERT INTO tbl_include_reg SELECT x, 2*x, 3*x, box('4,4,4,4') FROM generate_series(1,10) AS x;
CREATE INDEX tbl_include_reg_idx ON tbl_include_reg using btree (c1, c2) INCLUDE (c3,c4);
-- must fail because of intersection of key and included columns
CREATE INDEX tbl_idx ON tbl using btree (c1, c2) INCLUDE (c1,c3);
CREATE INDEX tbl_include_reg_idx ON tbl_include_reg using btree (c1, c2) INCLUDE (c1,c3);
SELECT pg_get_indexdef(i.indexrelid)
FROM pg_index i JOIN pg_class c ON i.indexrelid = c.oid
WHERE i.indrelid = 'tbl'::regclass ORDER BY c.relname;
DROP TABLE tbl;
WHERE i.indrelid = 'tbl_include_reg'::regclass ORDER BY c.relname;
-- Unique index and unique constraint
CREATE TABLE tbl (c1 int, c2 int, c3 int, c4 box);
INSERT INTO tbl SELECT x, 2*x, 3*x, box('4,4,4,4') FROM generate_series(1,10) AS x;
CREATE UNIQUE INDEX tbl_idx_unique ON tbl using btree (c1, c2) INCLUDE (c3, c4);
ALTER TABLE tbl add UNIQUE USING INDEX tbl_idx_unique;
ALTER TABLE tbl add UNIQUE (c1, c2) INCLUDE (c3, c4);
CREATE TABLE tbl_include_unique1 (c1 int, c2 int, c3 int, c4 box);
INSERT INTO tbl_include_unique1 SELECT x, 2*x, 3*x, box('4,4,4,4') FROM generate_series(1,10) AS x;
CREATE UNIQUE INDEX tbl_include_unique1_idx_unique ON tbl_include_unique1 using btree (c1, c2) INCLUDE (c3, c4);
ALTER TABLE tbl_include_unique1 add UNIQUE USING INDEX tbl_include_unique1_idx_unique;
ALTER TABLE tbl_include_unique1 add UNIQUE (c1, c2) INCLUDE (c3, c4);
SELECT pg_get_indexdef(i.indexrelid)
FROM pg_index i JOIN pg_class c ON i.indexrelid = c.oid
WHERE i.indrelid = 'tbl'::regclass ORDER BY c.relname;
DROP TABLE tbl;
WHERE i.indrelid = 'tbl_include_unique1'::regclass ORDER BY c.relname;
-- Unique index and unique constraint. Both must fail.
CREATE TABLE tbl (c1 int, c2 int, c3 int, c4 box);
INSERT INTO tbl SELECT 1, 2, 3*x, box('4,4,4,4') FROM generate_series(1,10) AS x;
CREATE UNIQUE INDEX tbl_idx_unique ON tbl using btree (c1, c2) INCLUDE (c3, c4);
ALTER TABLE tbl add UNIQUE (c1, c2) INCLUDE (c3, c4);
DROP TABLE tbl;
CREATE TABLE tbl_include_unique2 (c1 int, c2 int, c3 int, c4 box);
INSERT INTO tbl_include_unique2 SELECT 1, 2, 3*x, box('4,4,4,4') FROM generate_series(1,10) AS x;
CREATE UNIQUE INDEX tbl_include_unique2_idx_unique ON tbl_include_unique2 using btree (c1, c2) INCLUDE (c3, c4);
ALTER TABLE tbl_include_unique2 add UNIQUE (c1, c2) INCLUDE (c3, c4);
-- PK constraint
CREATE TABLE tbl (c1 int, c2 int, c3 int, c4 box);
INSERT INTO tbl SELECT 1, 2*x, 3*x, box('4,4,4,4') FROM generate_series(1,10) AS x;
ALTER TABLE tbl add PRIMARY KEY (c1, c2) INCLUDE (c3, c4);
CREATE TABLE tbl_include_pk (c1 int, c2 int, c3 int, c4 box);
INSERT INTO tbl_include_pk SELECT 1, 2*x, 3*x, box('4,4,4,4') FROM generate_series(1,10) AS x;
ALTER TABLE tbl_include_pk add PRIMARY KEY (c1, c2) INCLUDE (c3, c4);
SELECT pg_get_indexdef(i.indexrelid)
FROM pg_index i JOIN pg_class c ON i.indexrelid = c.oid
WHERE i.indrelid = 'tbl'::regclass ORDER BY c.relname;
DROP TABLE tbl;
WHERE i.indrelid = 'tbl_include_pk'::regclass ORDER BY c.relname;
CREATE TABLE tbl (c1 int, c2 int, c3 int, c4 box);
INSERT INTO tbl SELECT 1, 2*x, 3*x, box('4,4,4,4') FROM generate_series(1,10) AS x;
CREATE UNIQUE INDEX tbl_idx_unique ON tbl using btree (c1, c2) INCLUDE (c3, c4);
ALTER TABLE tbl add PRIMARY KEY USING INDEX tbl_idx_unique;
CREATE TABLE tbl_include_box (c1 int, c2 int, c3 int, c4 box);
INSERT INTO tbl_include_box SELECT 1, 2*x, 3*x, box('4,4,4,4') FROM generate_series(1,10) AS x;
CREATE UNIQUE INDEX tbl_include_box_idx_unique ON tbl_include_box using btree (c1, c2) INCLUDE (c3, c4);
ALTER TABLE tbl_include_box add PRIMARY KEY USING INDEX tbl_include_box_idx_unique;
SELECT pg_get_indexdef(i.indexrelid)
FROM pg_index i JOIN pg_class c ON i.indexrelid = c.oid
WHERE i.indrelid = 'tbl'::regclass ORDER BY c.relname;
DROP TABLE tbl;
WHERE i.indrelid = 'tbl_include_box'::regclass ORDER BY c.relname;
-- PK constraint. Must fail.
CREATE TABLE tbl (c1 int, c2 int, c3 int, c4 box);
INSERT INTO tbl SELECT 1, 2, 3*x, box('4,4,4,4') FROM generate_series(1,10) AS x;
ALTER TABLE tbl add PRIMARY KEY (c1, c2) INCLUDE (c3, c4);
DROP TABLE tbl;
CREATE TABLE tbl_include_box_pk (c1 int, c2 int, c3 int, c4 box);
INSERT INTO tbl_include_box_pk SELECT 1, 2, 3*x, box('4,4,4,4') FROM generate_series(1,10) AS x;
ALTER TABLE tbl_include_box_pk add PRIMARY KEY (c1, c2) INCLUDE (c3, c4);
/*