mirror of
https://github.com/postgres/postgres.git
synced 2026-10-23 13:29:09 +03:00
Like VACUUM FULL, non-concurrent REPACK would try to rebuild such indexes, which can sometimes succeed. Concurrent REPACK would however fail. The inconsistency is not good, so make them both throw an error quickly to force the user to make a decision on those indexes (most likely, drop them). Author: Álvaro Herrera <alvherre@kurilemu.de> Reported-by: Zsolt Parragi <zsolt.parragi@percona.com> Suggested-by: Kyotaro Horiguchi <horikyota.ntt@gmail.com> Discussion: https://postgr.es/m/CAN4CZFO5A3YE0Dd-bn7eKrB20pECO3=U0wKg1z2rO=DxgWJJHQ@mail.gmail.com
152 lines
7.0 KiB
Plaintext
152 lines
7.0 KiB
Plaintext
-- Test REPACK (CONCURRENTLY).
|
|
-- This test isn't strictly about logical decoding per se, but
|
|
-- REPACK (CONCURRENTLY) involves logical decoding and therefore requires
|
|
-- to be run under higher than minimal wal_level, so we can't have them in
|
|
-- the main regression test suite.
|
|
-- Ownership of partitions is checked
|
|
CREATE TABLE ptnowner(i int unique not null) PARTITION BY LIST (i);
|
|
CREATE INDEX ptnowner_i_idx ON ptnowner(i);
|
|
CREATE TABLE ptnowner1 PARTITION OF ptnowner FOR VALUES IN (1);
|
|
CREATE ROLE regress_ptnowner;
|
|
CREATE TABLE ptnowner2 PARTITION OF ptnowner FOR VALUES IN (2);
|
|
ALTER TABLE ptnowner1 OWNER TO regress_ptnowner;
|
|
SET SESSION AUTHORIZATION regress_ptnowner;
|
|
ALTER TABLE ptnowner1 REPLICA IDENTITY USING INDEX ptnowner1_i_key;
|
|
REPACK (CONCURRENTLY) ptnowner1;
|
|
RESET SESSION AUTHORIZATION;
|
|
ALTER TABLE ptnowner OWNER TO regress_ptnowner;
|
|
CREATE TEMP TABLE ptnowner_oldnodes AS
|
|
SELECT oid, relname, relfilenode FROM pg_partition_tree('ptnowner') AS tree
|
|
JOIN pg_class AS c ON c.oid=tree.relid;
|
|
SELECT a.relname, a.relfilenode=b.relfilenode FROM pg_class a
|
|
JOIN ptnowner_oldnodes b USING (oid) ORDER BY a.relname COLLATE "C";
|
|
relname | ?column?
|
|
-----------+----------
|
|
ptnowner | t
|
|
ptnowner1 | t
|
|
ptnowner2 | t
|
|
(3 rows)
|
|
|
|
DROP TABLE ptnowner;
|
|
DROP ROLE regress_ptnowner;
|
|
-- Verify that REPACK (CONCURRENTLY) doesn't lose "attmissingval" columns
|
|
CREATE TABLE rpk_missing (id int PRIMARY KEY);
|
|
INSERT INTO rpk_missing SELECT generate_series(1, 3);
|
|
ALTER TABLE rpk_missing ADD COLUMN a int DEFAULT 42;
|
|
SELECT * FROM rpk_missing;
|
|
id | a
|
|
----+----
|
|
1 | 42
|
|
2 | 42
|
|
3 | 42
|
|
(3 rows)
|
|
|
|
REPACK (CONCURRENTLY) rpk_missing;
|
|
SELECT * FROM rpk_missing;
|
|
id | a
|
|
----+----
|
|
1 | 42
|
|
2 | 42
|
|
3 | 42
|
|
(3 rows)
|
|
|
|
DROP TABLE rpk_missing;
|
|
-- Verify handling of !indisready indexes
|
|
CREATE TABLE repack_conc_invidx (i int PRIMARY KEY, j int);
|
|
INSERT INTO repack_conc_invidx VALUES (1, 0), (2, 0);
|
|
CREATE UNIQUE INDEX CONCURRENTLY repack_conc_invidx_uq ON repack_conc_invidx (j);
|
|
ERROR: could not create unique index "repack_conc_invidx_uq"
|
|
DETAIL: Key (j)=(0) is duplicated.
|
|
CREATE INDEX CONCURRENTLY repack_conc_invalid_expr ON repack_conc_invidx ((1/j));
|
|
ERROR: division by zero
|
|
REPACK repack_conc_invidx;
|
|
ERROR: cannot execute REPACK on relation "repack_conc_invidx"
|
|
DETAIL: Some invalid indexes cannot be processed correctly: "repack_conc_invidx_uq", "repack_conc_invalid_expr".
|
|
HINT: Use DROP INDEX or REINDEX.
|
|
REPACK (CONCURRENTLY) repack_conc_invidx;
|
|
ERROR: cannot execute REPACK on relation "repack_conc_invidx"
|
|
DETAIL: Some invalid indexes cannot be processed correctly: "repack_conc_invidx_uq", "repack_conc_invalid_expr".
|
|
HINT: Use DROP INDEX or REINDEX.
|
|
-- Error cases for concurrent mode
|
|
-- Doesn't like partitioned tables
|
|
CREATE TABLE clstrpart (a int) PARTITION BY RANGE (a);
|
|
REPACK (CONCURRENTLY) clstrpart;
|
|
ERROR: REPACK (CONCURRENTLY) is not supported for partitioned tables
|
|
HINT: Consider running the command on individual partitions.
|
|
-- Disallowed in catalogs
|
|
REPACK (CONCURRENTLY) pg_class;
|
|
ERROR: cannot execute REPACK (CONCURRENTLY) on relation "pg_class"
|
|
DETAIL: This operation is not supported for system catalogs.
|
|
-- Doesn't support tables used as catalog tables
|
|
CREATE TABLE repack_conc_user_catalog (i int) WITH (user_catalog_table = true);
|
|
REPACK (CONCURRENTLY) repack_conc_user_catalog;
|
|
ERROR: cannot execute REPACK (CONCURRENTLY) on relation "repack_conc_user_catalog"
|
|
DETAIL: This operation is not supported for user catalog tables.
|
|
DROP TABLE repack_conc_user_catalog;
|
|
-- Doesn't support TOAST tables directly
|
|
CREATE TABLE repack_conc_toast (t text);
|
|
SELECT reltoastrelid::regclass AS toast_rel
|
|
FROM pg_class WHERE oid = 'repack_conc_toast'::regclass \gset
|
|
\set VERBOSITY sqlstate
|
|
REPACK (CONCURRENTLY) :toast_rel;
|
|
ERROR: 0A000
|
|
\set VERBOSITY default
|
|
DROP TABLE repack_conc_toast;
|
|
-- Only support permanent tables, temp and unlogged tables are not supported
|
|
CREATE TEMP TABLE repack_conc_temp (i int PRIMARY KEY);
|
|
REPACK (CONCURRENTLY) repack_conc_temp;
|
|
ERROR: cannot execute REPACK (CONCURRENTLY) on relation "repack_conc_temp"
|
|
DETAIL: This operation is only supported for permanent relations.
|
|
DROP TABLE repack_conc_temp;
|
|
CREATE UNLOGGED TABLE repack_conc_unlogged (i int PRIMARY KEY);
|
|
REPACK (CONCURRENTLY) repack_conc_unlogged;
|
|
ERROR: cannot execute REPACK (CONCURRENTLY) on relation "repack_conc_unlogged"
|
|
DETAIL: This operation is only supported for permanent relations.
|
|
DROP TABLE repack_conc_unlogged;
|
|
-- Doesn't support materialized views
|
|
CREATE MATERIALIZED VIEW repack_conc_matview AS SELECT 1 AS i;
|
|
REPACK (CONCURRENTLY) repack_conc_matview;
|
|
ERROR: cannot execute REPACK (CONCURRENTLY) on relation "repack_conc_matview"
|
|
DETAIL: This operation is not supported for materialized views.
|
|
DROP MATERIALIZED VIEW repack_conc_matview;
|
|
-- Doesn't support tables with REPLICA IDENTITY NOTHING, even if they have a primary key
|
|
CREATE TABLE repack_conc_replident (i int PRIMARY KEY);
|
|
ALTER TABLE repack_conc_replident REPLICA IDENTITY NOTHING;
|
|
REPACK (CONCURRENTLY) repack_conc_replident;
|
|
ERROR: cannot execute REPACK (CONCURRENTLY) on relation "repack_conc_replident"
|
|
DETAIL: This operation does not support tables with REPLICA IDENTITY NOTHING.
|
|
-- Doesn't support tables without a primary key or replica identity index
|
|
ALTER TABLE repack_conc_replident DROP CONSTRAINT repack_conc_replident_pkey;
|
|
ALTER TABLE repack_conc_replident REPLICA IDENTITY DEFAULT;
|
|
REPACK (CONCURRENTLY) repack_conc_replident;
|
|
ERROR: cannot execute REPACK (CONCURRENTLY) on relation "repack_conc_replident"
|
|
DETAIL: Relation "repack_conc_replident" has no identity index.
|
|
-- Doesn't support tables with deferrable primary keys
|
|
ALTER TABLE repack_conc_replident ADD PRIMARY KEY (i) DEFERRABLE;
|
|
REPACK (CONCURRENTLY) repack_conc_replident;
|
|
ERROR: cannot execute REPACK (CONCURRENTLY) on relation "repack_conc_replident"
|
|
DETAIL: This operation does not support deferrable primary keys.
|
|
HINT: Use ALTER TABLE ... REPLICA IDENTITY USING INDEX to designate another index as replica identity.
|
|
-- Doesn't support tables whose replica identity indexes were dropped, even
|
|
-- if a workable primary key is present.
|
|
ALTER TABLE repack_conc_replident DROP CONSTRAINT repack_conc_replident_pkey,
|
|
ADD PRIMARY KEY (i);
|
|
CREATE UNIQUE INDEX replidx ON repack_conc_replident (i);
|
|
ALTER TABLE repack_conc_replident REPLICA IDENTITY USING INDEX replidx;
|
|
DROP INDEX replidx;
|
|
REPACK (CONCURRENTLY) repack_conc_replident;
|
|
ERROR: cannot execute REPACK (CONCURRENTLY) on relation "repack_conc_replident"
|
|
DETAIL: Relation "repack_conc_replident" has no identity index.
|
|
-- clean up
|
|
DROP TABLE repack_conc_replident, clstrpart;
|
|
-- verify that the pgrepack plugin cannot be called directly
|
|
CREATE TABLE repack_plugin (a int);
|
|
SELECT * FROM pg_create_logical_replication_slot('s_repack', 'pgrepack');
|
|
ERROR: unsupported use of logical decoding plugin "pgrepack"
|
|
DETAIL: This plugin can only be used by REPACK (CONCURRENTLY).
|
|
INSERT INTO repack_plugin VALUES (1);
|
|
SELECT * FROM pg_logical_slot_get_binary_changes('s_repack', NULL, NULL);
|
|
ERROR: replication slot "s_repack" does not exist
|
|
SELECT pg_drop_replication_slot('s_repack');
|
|
ERROR: replication slot "s_repack" does not exist
|