--
--  CLUSTER
--
CREATE TABLE clstr_tst_s (rf_a SERIAL PRIMARY KEY,
	b INT);
NOTICE:  CREATE TABLE will create implicit sequence "clstr_tst_s_rf_a_seq" for serial column "clstr_tst_s.rf_a"
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "clstr_tst_s_pkey" for table "clstr_tst_s"
CREATE TABLE clstr_tst (a SERIAL PRIMARY KEY,
	b INT,
	c TEXT,
	d TEXT,
	CONSTRAINT clstr_tst_con FOREIGN KEY (b) REFERENCES clstr_tst_s);
NOTICE:  CREATE TABLE will create implicit sequence "clstr_tst_a_seq" for serial column "clstr_tst.a"
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "clstr_tst_pkey" for table "clstr_tst"
CREATE INDEX clstr_tst_b ON clstr_tst (b);
CREATE INDEX clstr_tst_c ON clstr_tst (c);
CREATE INDEX clstr_tst_c_b ON clstr_tst (c,b);
CREATE INDEX clstr_tst_b_c ON clstr_tst (b,c);
INSERT INTO clstr_tst_s (b) VALUES (0);
INSERT INTO clstr_tst_s (b) SELECT b FROM clstr_tst_s;
INSERT INTO clstr_tst_s (b) SELECT b FROM clstr_tst_s;
INSERT INTO clstr_tst_s (b) SELECT b FROM clstr_tst_s;
INSERT INTO clstr_tst_s (b) SELECT b FROM clstr_tst_s;
INSERT INTO clstr_tst_s (b) SELECT b FROM clstr_tst_s;
CREATE TABLE clstr_tst_inh () INHERITS (clstr_tst);
INSERT INTO clstr_tst (b, c) VALUES (11, 'once');
INSERT INTO clstr_tst (b, c) VALUES (10, 'diez');
INSERT INTO clstr_tst (b, c) VALUES (31, 'treinta y uno');
INSERT INTO clstr_tst (b, c) VALUES (22, 'veintidos');
INSERT INTO clstr_tst (b, c) VALUES (3, 'tres');
INSERT INTO clstr_tst (b, c) VALUES (20, 'veinte');
INSERT INTO clstr_tst (b, c) VALUES (23, 'veintitres');
INSERT INTO clstr_tst (b, c) VALUES (21, 'veintiuno');
INSERT INTO clstr_tst (b, c) VALUES (4, 'cuatro');
INSERT INTO clstr_tst (b, c) VALUES (14, 'catorce');
INSERT INTO clstr_tst (b, c) VALUES (2, 'dos');
INSERT INTO clstr_tst (b, c) VALUES (18, 'dieciocho');
INSERT INTO clstr_tst (b, c) VALUES (27, 'veintisiete');
INSERT INTO clstr_tst (b, c) VALUES (25, 'veinticinco');
INSERT INTO clstr_tst (b, c) VALUES (13, 'trece');
INSERT INTO clstr_tst (b, c) VALUES (28, 'veintiocho');
INSERT INTO clstr_tst (b, c) VALUES (32, 'treinta y dos');
INSERT INTO clstr_tst (b, c) VALUES (5, 'cinco');
INSERT INTO clstr_tst (b, c) VALUES (29, 'veintinueve');
INSERT INTO clstr_tst (b, c) VALUES (1, 'uno');
INSERT INTO clstr_tst (b, c) VALUES (24, 'veinticuatro');
INSERT INTO clstr_tst (b, c) VALUES (30, 'treinta');
INSERT INTO clstr_tst (b, c) VALUES (12, 'doce');
INSERT INTO clstr_tst (b, c) VALUES (17, 'diecisiete');
INSERT INTO clstr_tst (b, c) VALUES (9, 'nueve');
INSERT INTO clstr_tst (b, c) VALUES (19, 'diecinueve');
INSERT INTO clstr_tst (b, c) VALUES (26, 'veintiseis');
INSERT INTO clstr_tst (b, c) VALUES (15, 'quince');
INSERT INTO clstr_tst (b, c) VALUES (7, 'siete');
INSERT INTO clstr_tst (b, c) VALUES (16, 'dieciseis');
INSERT INTO clstr_tst (b, c) VALUES (8, 'ocho');
-- This entry is needed to test that TOASTED values are copied correctly.
INSERT INTO clstr_tst (b, c, d) VALUES (6, 'seis', repeat('xyzzy', 100000));
CLUSTER clstr_tst_c ON clstr_tst;
SELECT a,b,c,substring(d for 30), length(d) from clstr_tst;
 a  | b  |       c       |           substring            | length 
----+----+---------------+--------------------------------+--------
 10 | 14 | catorce       |                                |       
 18 |  5 | cinco         |                                |       
  9 |  4 | cuatro        |                                |       
 26 | 19 | diecinueve    |                                |       
 12 | 18 | dieciocho     |                                |       
 30 | 16 | dieciseis     |                                |       
 24 | 17 | diecisiete    |                                |       
  2 | 10 | diez          |                                |       
 23 | 12 | doce          |                                |       
 11 |  2 | dos           |                                |       
 25 |  9 | nueve         |                                |       
 31 |  8 | ocho          |                                |       
  1 | 11 | once          |                                |       
 28 | 15 | quince        |                                |       
 32 |  6 | seis          | xyzzyxyzzyxyzzyxyzzyxyzzyxyzzy | 500000
 29 |  7 | siete         |                                |       
 15 | 13 | trece         |                                |       
 22 | 30 | treinta       |                                |       
 17 | 32 | treinta y dos |                                |       
  3 | 31 | treinta y uno |                                |       
  5 |  3 | tres          |                                |       
 20 |  1 | uno           |                                |       
  6 | 20 | veinte        |                                |       
 14 | 25 | veinticinco   |                                |       
 21 | 24 | veinticuatro  |                                |       
  4 | 22 | veintidos     |                                |       
 19 | 29 | veintinueve   |                                |       
 16 | 28 | veintiocho    |                                |       
 27 | 26 | veintiseis    |                                |       
 13 | 27 | veintisiete   |                                |       
  7 | 23 | veintitres    |                                |       
  8 | 21 | veintiuno     |                                |       
(32 rows)

SELECT a,b,c,substring(d for 30), length(d) from clstr_tst ORDER BY a;
 a  | b  |       c       |           substring            | length 
----+----+---------------+--------------------------------+--------
  1 | 11 | once          |                                |       
  2 | 10 | diez          |                                |       
  3 | 31 | treinta y uno |                                |       
  4 | 22 | veintidos     |                                |       
  5 |  3 | tres          |                                |       
  6 | 20 | veinte        |                                |       
  7 | 23 | veintitres    |                                |       
  8 | 21 | veintiuno     |                                |       
  9 |  4 | cuatro        |                                |       
 10 | 14 | catorce       |                                |       
 11 |  2 | dos           |                                |       
 12 | 18 | dieciocho     |                                |       
 13 | 27 | veintisiete   |                                |       
 14 | 25 | veinticinco   |                                |       
 15 | 13 | trece         |                                |       
 16 | 28 | veintiocho    |                                |       
 17 | 32 | treinta y dos |                                |       
 18 |  5 | cinco         |                                |       
 19 | 29 | veintinueve   |                                |       
 20 |  1 | uno           |                                |       
 21 | 24 | veinticuatro  |                                |       
 22 | 30 | treinta       |                                |       
 23 | 12 | doce          |                                |       
 24 | 17 | diecisiete    |                                |       
 25 |  9 | nueve         |                                |       
 26 | 19 | diecinueve    |                                |       
 27 | 26 | veintiseis    |                                |       
 28 | 15 | quince        |                                |       
 29 |  7 | siete         |                                |       
 30 | 16 | dieciseis     |                                |       
 31 |  8 | ocho          |                                |       
 32 |  6 | seis          | xyzzyxyzzyxyzzyxyzzyxyzzyxyzzy | 500000
(32 rows)

SELECT a,b,c,substring(d for 30), length(d) from clstr_tst ORDER BY b;
 a  | b  |       c       |           substring            | length 
----+----+---------------+--------------------------------+--------
 20 |  1 | uno           |                                |       
 11 |  2 | dos           |                                |       
  5 |  3 | tres          |                                |       
  9 |  4 | cuatro        |                                |       
 18 |  5 | cinco         |                                |       
 32 |  6 | seis          | xyzzyxyzzyxyzzyxyzzyxyzzyxyzzy | 500000
 29 |  7 | siete         |                                |       
 31 |  8 | ocho          |                                |       
 25 |  9 | nueve         |                                |       
  2 | 10 | diez          |                                |       
  1 | 11 | once          |                                |       
 23 | 12 | doce          |                                |       
 15 | 13 | trece         |                                |       
 10 | 14 | catorce       |                                |       
 28 | 15 | quince        |                                |       
 30 | 16 | dieciseis     |                                |       
 24 | 17 | diecisiete    |                                |       
 12 | 18 | dieciocho     |                                |       
 26 | 19 | diecinueve    |                                |       
  6 | 20 | veinte        |                                |       
  8 | 21 | veintiuno     |                                |       
  4 | 22 | veintidos     |                                |       
  7 | 23 | veintitres    |                                |       
 21 | 24 | veinticuatro  |                                |       
 14 | 25 | veinticinco   |                                |       
 27 | 26 | veintiseis    |                                |       
 13 | 27 | veintisiete   |                                |       
 16 | 28 | veintiocho    |                                |       
 19 | 29 | veintinueve   |                                |       
 22 | 30 | treinta       |                                |       
  3 | 31 | treinta y uno |                                |       
 17 | 32 | treinta y dos |                                |       
(32 rows)

SELECT a,b,c,substring(d for 30), length(d) from clstr_tst ORDER BY c;
 a  | b  |       c       |           substring            | length 
----+----+---------------+--------------------------------+--------
 10 | 14 | catorce       |                                |       
 18 |  5 | cinco         |                                |       
  9 |  4 | cuatro        |                                |       
 26 | 19 | diecinueve    |                                |       
 12 | 18 | dieciocho     |                                |       
 30 | 16 | dieciseis     |                                |       
 24 | 17 | diecisiete    |                                |       
  2 | 10 | diez          |                                |       
 23 | 12 | doce          |                                |       
 11 |  2 | dos           |                                |       
 25 |  9 | nueve         |                                |       
 31 |  8 | ocho          |                                |       
  1 | 11 | once          |                                |       
 28 | 15 | quince        |                                |       
 32 |  6 | seis          | xyzzyxyzzyxyzzyxyzzyxyzzyxyzzy | 500000
 29 |  7 | siete         |                                |       
 15 | 13 | trece         |                                |       
 22 | 30 | treinta       |                                |       
 17 | 32 | treinta y dos |                                |       
  3 | 31 | treinta y uno |                                |       
  5 |  3 | tres          |                                |       
 20 |  1 | uno           |                                |       
  6 | 20 | veinte        |                                |       
 14 | 25 | veinticinco   |                                |       
 21 | 24 | veinticuatro  |                                |       
  4 | 22 | veintidos     |                                |       
 19 | 29 | veintinueve   |                                |       
 16 | 28 | veintiocho    |                                |       
 27 | 26 | veintiseis    |                                |       
 13 | 27 | veintisiete   |                                |       
  7 | 23 | veintitres    |                                |       
  8 | 21 | veintiuno     |                                |       
(32 rows)

-- Verify that inheritance link still works
INSERT INTO clstr_tst_inh VALUES (0, 100, 'in child table');
SELECT a,b,c,substring(d for 30), length(d) from clstr_tst;
 a  |  b  |       c        |           substring            | length 
----+-----+----------------+--------------------------------+--------
 10 |  14 | catorce        |                                |       
 18 |   5 | cinco          |                                |       
  9 |   4 | cuatro         |                                |       
 26 |  19 | diecinueve     |                                |       
 12 |  18 | dieciocho      |                                |       
 30 |  16 | dieciseis      |                                |       
 24 |  17 | diecisiete     |                                |       
  2 |  10 | diez           |                                |       
 23 |  12 | doce           |                                |       
 11 |   2 | dos            |                                |       
 25 |   9 | nueve          |                                |       
 31 |   8 | ocho           |                                |       
  1 |  11 | once           |                                |       
 28 |  15 | quince         |                                |       
 32 |   6 | seis           | xyzzyxyzzyxyzzyxyzzyxyzzyxyzzy | 500000
 29 |   7 | siete          |                                |       
 15 |  13 | trece          |                                |       
 22 |  30 | treinta        |                                |       
 17 |  32 | treinta y dos  |                                |       
  3 |  31 | treinta y uno  |                                |       
  5 |   3 | tres           |                                |       
 20 |   1 | uno            |                                |       
  6 |  20 | veinte         |                                |       
 14 |  25 | veinticinco    |                                |       
 21 |  24 | veinticuatro   |                                |       
  4 |  22 | veintidos      |                                |       
 19 |  29 | veintinueve    |                                |       
 16 |  28 | veintiocho     |                                |       
 27 |  26 | veintiseis     |                                |       
 13 |  27 | veintisiete    |                                |       
  7 |  23 | veintitres     |                                |       
  8 |  21 | veintiuno      |                                |       
  0 | 100 | in child table |                                |       
(33 rows)

-- Verify that foreign key link still works
INSERT INTO clstr_tst (b, c) VALUES (1111, 'this should fail');
ERROR:  insert or update on table "clstr_tst" violates foreign key constraint "clstr_tst_con"
DETAIL:  Key (b)=(1111) is not present in table "clstr_tst_s".
SELECT conname FROM pg_constraint WHERE conrelid = 'clstr_tst'::regclass
ORDER BY 1;
    conname     
----------------
 clstr_tst_con
 clstr_tst_pkey
(2 rows)

SELECT relname, relkind,
    EXISTS(SELECT 1 FROM pg_class WHERE oid = c.reltoastrelid) AS hastoast
FROM pg_class c WHERE relname LIKE 'clstr_tst%' ORDER BY relname;
       relname        | relkind | hastoast 
----------------------+---------+----------
 clstr_tst            | r       | t
 clstr_tst_a_seq      | S       | f
 clstr_tst_b          | i       | f
 clstr_tst_b_c        | i       | f
 clstr_tst_c          | i       | f
 clstr_tst_c_b        | i       | f
 clstr_tst_inh        | r       | t
 clstr_tst_pkey       | i       | f
 clstr_tst_s          | r       | f
 clstr_tst_s_pkey     | i       | f
 clstr_tst_s_rf_a_seq | S       | f
(11 rows)

-- Verify that indisclustered is correctly set
SELECT pg_class.relname FROM pg_index, pg_class, pg_class AS pg_class_2
WHERE pg_class.oid=indexrelid
	AND indrelid=pg_class_2.oid
	AND pg_class_2.relname = 'clstr_tst'
	AND indisclustered;
   relname   
-------------
 clstr_tst_c
(1 row)

-- Try changing indisclustered
ALTER TABLE clstr_tst CLUSTER ON clstr_tst_b_c;
SELECT pg_class.relname FROM pg_index, pg_class, pg_class AS pg_class_2
WHERE pg_class.oid=indexrelid
	AND indrelid=pg_class_2.oid
	AND pg_class_2.relname = 'clstr_tst'
	AND indisclustered;
    relname    
---------------
 clstr_tst_b_c
(1 row)

-- Try turning off all clustering
ALTER TABLE clstr_tst SET WITHOUT CLUSTER;
SELECT pg_class.relname FROM pg_index, pg_class, pg_class AS pg_class_2
WHERE pg_class.oid=indexrelid
	AND indrelid=pg_class_2.oid
	AND pg_class_2.relname = 'clstr_tst'
	AND indisclustered;
 relname 
---------
(0 rows)

-- Verify that clustering all tables does in fact cluster the right ones
CREATE USER clstr_user;
CREATE TABLE clstr_1 (a INT PRIMARY KEY);
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "clstr_1_pkey" for table "clstr_1"
CREATE TABLE clstr_2 (a INT PRIMARY KEY);
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "clstr_2_pkey" for table "clstr_2"
CREATE TABLE clstr_3 (a INT PRIMARY KEY);
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "clstr_3_pkey" for table "clstr_3"
ALTER TABLE clstr_1 OWNER TO clstr_user;
ALTER TABLE clstr_3 OWNER TO clstr_user;
GRANT SELECT ON clstr_2 TO clstr_user;
INSERT INTO clstr_1 VALUES (2);
INSERT INTO clstr_1 VALUES (1);
INSERT INTO clstr_2 VALUES (2);
INSERT INTO clstr_2 VALUES (1);
INSERT INTO clstr_3 VALUES (2);
INSERT INTO clstr_3 VALUES (1);
-- "CLUSTER <tablename>" on a table that hasn't been clustered
CLUSTER clstr_2;
ERROR:  there is no previously clustered index for table "clstr_2"
CLUSTER clstr_1_pkey ON clstr_1;
CLUSTER clstr_2 USING clstr_2_pkey;
SELECT * FROM clstr_1 UNION ALL
  SELECT * FROM clstr_2 UNION ALL
  SELECT * FROM clstr_3;
 a 
---
 1
 2
 1
 2
 2
 1
(6 rows)

-- revert to the original state
DELETE FROM clstr_1;
DELETE FROM clstr_2;
DELETE FROM clstr_3;
INSERT INTO clstr_1 VALUES (2);
INSERT INTO clstr_1 VALUES (1);
INSERT INTO clstr_2 VALUES (2);
INSERT INTO clstr_2 VALUES (1);
INSERT INTO clstr_3 VALUES (2);
INSERT INTO clstr_3 VALUES (1);
-- this user can only cluster clstr_1 and clstr_3, but the latter
-- has not been clustered
SET SESSION AUTHORIZATION clstr_user;
CLUSTER;
SELECT * FROM clstr_1 UNION ALL
  SELECT * FROM clstr_2 UNION ALL
  SELECT * FROM clstr_3;
 a 
---
 1
 2
 2
 1
 2
 1
(6 rows)

-- cluster a single table using the indisclustered bit previously set
DELETE FROM clstr_1;
INSERT INTO clstr_1 VALUES (2);
INSERT INTO clstr_1 VALUES (1);
CLUSTER clstr_1;
SELECT * FROM clstr_1;
 a 
---
 1
 2
(2 rows)

-- Test MVCC-safety of cluster. There isn't much we can do to verify the
-- results with a single backend...
CREATE TABLE clustertest (key int PRIMARY KEY);
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "clustertest_pkey" for table "clustertest"
INSERT INTO clustertest VALUES (10);
INSERT INTO clustertest VALUES (20);
INSERT INTO clustertest VALUES (30);
INSERT INTO clustertest VALUES (40);
INSERT INTO clustertest VALUES (50);
-- Use a transaction so that updates are not committed when CLUSTER sees 'em
BEGIN;
-- Test update where the old row version is found first in the scan
UPDATE clustertest SET key = 100 WHERE key = 10;
-- Test update where the new row version is found first in the scan
UPDATE clustertest SET key = 35 WHERE key = 40;
-- Test longer update chain 
UPDATE clustertest SET key = 60 WHERE key = 50;
UPDATE clustertest SET key = 70 WHERE key = 60;
UPDATE clustertest SET key = 80 WHERE key = 70;
SELECT * FROM clustertest;
 key 
-----
  20
  30
 100
  35
  80
(5 rows)

CLUSTER clustertest_pkey ON clustertest;
SELECT * FROM clustertest;
 key 
-----
  20
  30
  35
  80
 100
(5 rows)

COMMIT;
SELECT * FROM clustertest;
 key 
-----
  20
  30
  35
  80
 100
(5 rows)

-- check that temp tables can be clustered
create temp table clstr_temp (col1 int primary key, col2 text);
NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "clstr_temp_pkey" for table "clstr_temp"
insert into clstr_temp values (2, 'two'), (1, 'one');
cluster clstr_temp using clstr_temp_pkey;
select * from clstr_temp;
 col1 | col2 
------+------
    1 | one
    2 | two
(2 rows)

drop table clstr_temp;
-- clean up
\c -
DROP TABLE clustertest;
DROP TABLE clstr_1;
DROP TABLE clstr_2;
DROP TABLE clstr_3;
DROP USER clstr_user;
