1--
2-- CREATE_INDEX
3-- Create ancillary data structures (i.e. indices)
4--
5
6--
7-- BTREE
8--
9CREATE INDEX onek_unique1 ON onek USING btree(unique1 int4_ops);
10
11CREATE INDEX IF NOT EXISTS onek_unique1 ON onek USING btree(unique1 int4_ops);
12
13CREATE INDEX IF NOT EXISTS ON onek USING btree(unique1 int4_ops);
14
15CREATE INDEX onek_unique2 ON onek USING btree(unique2 int4_ops);
16
17CREATE INDEX onek_hundred ON onek USING btree(hundred int4_ops);
18
19CREATE INDEX onek_stringu1 ON onek USING btree(stringu1 name_ops);
20
21CREATE INDEX tenk1_unique1 ON tenk1 USING btree(unique1 int4_ops);
22
23CREATE INDEX tenk1_unique2 ON tenk1 USING btree(unique2 int4_ops);
24
25CREATE INDEX tenk1_hundred ON tenk1 USING btree(hundred int4_ops);
26
27CREATE INDEX tenk1_thous_tenthous ON tenk1 (thousand, tenthous);
28
29CREATE INDEX tenk2_unique1 ON tenk2 USING btree(unique1 int4_ops);
30
31CREATE INDEX tenk2_unique2 ON tenk2 USING btree(unique2 int4_ops);
32
33CREATE INDEX tenk2_hundred ON tenk2 USING btree(hundred int4_ops);
34
35CREATE INDEX rix ON road USING btree (name text_ops);
36
37CREATE INDEX iix ON ihighway USING btree (name text_ops);
38
39CREATE INDEX six ON shighway USING btree (name text_ops);
40
41-- test comments
42COMMENT ON INDEX six_wrong IS 'bad index';
43COMMENT ON INDEX six IS 'good index';
44COMMENT ON INDEX six IS NULL;
45
46--
47-- BTREE ascending/descending cases
48--
49-- we load int4/text from pure descending data (each key is a new
50-- low key) and name/f8 from pure ascending data (each key is a new
51-- high key).  we had a bug where new low keys would sometimes be
52-- "lost".
53--
54CREATE INDEX bt_i4_index ON bt_i4_heap USING btree (seqno int4_ops);
55
56CREATE INDEX bt_name_index ON bt_name_heap USING btree (seqno name_ops);
57
58CREATE INDEX bt_txt_index ON bt_txt_heap USING btree (seqno text_ops);
59
60CREATE INDEX bt_f8_index ON bt_f8_heap USING btree (seqno float8_ops);
61
62--
63-- BTREE partial indices
64--
65CREATE INDEX onek2_u1_prtl ON onek2 USING btree(unique1 int4_ops)
66	where unique1 < 20 or unique1 > 980;
67
68CREATE INDEX onek2_u2_prtl ON onek2 USING btree(unique2 int4_ops)
69	where stringu1 < 'B';
70
71CREATE INDEX onek2_stu1_prtl ON onek2 USING btree(stringu1 name_ops)
72	where onek2.stringu1 >= 'J' and onek2.stringu1 < 'K';
73
74--
75-- GiST (rtree-equivalent opclasses only)
76--
77CREATE INDEX grect2ind ON fast_emp4000 USING gist (home_base);
78
79CREATE INDEX gpolygonind ON polygon_tbl USING gist (f1);
80
81CREATE INDEX gcircleind ON circle_tbl USING gist (f1);
82
83INSERT INTO POINT_TBL(f1) VALUES (NULL);
84
85CREATE INDEX gpointind ON point_tbl USING gist (f1);
86
87CREATE TEMP TABLE gpolygon_tbl AS
88    SELECT polygon(home_base) AS f1 FROM slow_emp4000;
89INSERT INTO gpolygon_tbl VALUES ( '(1000,0,0,1000)' );
90INSERT INTO gpolygon_tbl VALUES ( '(0,1000,1000,1000)' );
91
92CREATE TEMP TABLE gcircle_tbl AS
93    SELECT circle(home_base) AS f1 FROM slow_emp4000;
94
95CREATE INDEX ggpolygonind ON gpolygon_tbl USING gist (f1);
96
97CREATE INDEX ggcircleind ON gcircle_tbl USING gist (f1);
98
99--
100-- Test GiST indexes
101--
102
103-- get non-indexed results for comparison purposes
104
105SET enable_seqscan = ON;
106SET enable_indexscan = OFF;
107SET enable_bitmapscan = OFF;
108
109SELECT * FROM fast_emp4000
110    WHERE home_base @ '(200,200),(2000,1000)'::box
111    ORDER BY (home_base[0])[0];
112
113SELECT count(*) FROM fast_emp4000 WHERE home_base && '(1000,1000,0,0)'::box;
114
115SELECT count(*) FROM fast_emp4000 WHERE home_base IS NULL;
116
117SELECT * FROM polygon_tbl WHERE f1 ~ '((1,1),(2,2),(2,1))'::polygon
118    ORDER BY (poly_center(f1))[0];
119
120SELECT * FROM circle_tbl WHERE f1 && circle(point(1,-2), 1)
121    ORDER BY area(f1);
122
123SELECT count(*) FROM gpolygon_tbl WHERE f1 && '(1000,1000,0,0)'::polygon;
124
125SELECT count(*) FROM gcircle_tbl WHERE f1 && '<(500,500),500>'::circle;
126
127SELECT count(*) FROM point_tbl WHERE f1 <@ box '(0,0,100,100)';
128
129SELECT count(*) FROM point_tbl WHERE box '(0,0,100,100)' @> f1;
130
131SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50,50),(100,0),(0,0)';
132
133SELECT count(*) FROM point_tbl WHERE f1 <@ circle '<(50,50),50>';
134
135SELECT count(*) FROM point_tbl p WHERE p.f1 << '(0.0, 0.0)';
136
137SELECT count(*) FROM point_tbl p WHERE p.f1 >> '(0.0, 0.0)';
138
139SELECT count(*) FROM point_tbl p WHERE p.f1 <^ '(0.0, 0.0)';
140
141SELECT count(*) FROM point_tbl p WHERE p.f1 >^ '(0.0, 0.0)';
142
143SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
144
145SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
146
147SELECT * FROM point_tbl WHERE f1 IS NULL;
148
149SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
150
151SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
152
153SELECT * FROM gpolygon_tbl ORDER BY f1 <-> '(0,0)'::point LIMIT 10;
154
155SELECT circle_center(f1), round(radius(f1)) as radius FROM gcircle_tbl ORDER BY f1 <-> '(200,300)'::point LIMIT 10;
156
157-- Now check the results from plain indexscan
158SET enable_seqscan = OFF;
159SET enable_indexscan = ON;
160SET enable_bitmapscan = OFF;
161
162EXPLAIN (COSTS OFF)
163SELECT * FROM fast_emp4000
164    WHERE home_base @ '(200,200),(2000,1000)'::box
165    ORDER BY (home_base[0])[0];
166SELECT * FROM fast_emp4000
167    WHERE home_base @ '(200,200),(2000,1000)'::box
168    ORDER BY (home_base[0])[0];
169
170EXPLAIN (COSTS OFF)
171SELECT count(*) FROM fast_emp4000 WHERE home_base && '(1000,1000,0,0)'::box;
172SELECT count(*) FROM fast_emp4000 WHERE home_base && '(1000,1000,0,0)'::box;
173
174EXPLAIN (COSTS OFF)
175SELECT count(*) FROM fast_emp4000 WHERE home_base IS NULL;
176SELECT count(*) FROM fast_emp4000 WHERE home_base IS NULL;
177
178EXPLAIN (COSTS OFF)
179SELECT * FROM polygon_tbl WHERE f1 ~ '((1,1),(2,2),(2,1))'::polygon
180    ORDER BY (poly_center(f1))[0];
181SELECT * FROM polygon_tbl WHERE f1 ~ '((1,1),(2,2),(2,1))'::polygon
182    ORDER BY (poly_center(f1))[0];
183
184EXPLAIN (COSTS OFF)
185SELECT * FROM circle_tbl WHERE f1 && circle(point(1,-2), 1)
186    ORDER BY area(f1);
187SELECT * FROM circle_tbl WHERE f1 && circle(point(1,-2), 1)
188    ORDER BY area(f1);
189
190EXPLAIN (COSTS OFF)
191SELECT count(*) FROM gpolygon_tbl WHERE f1 && '(1000,1000,0,0)'::polygon;
192SELECT count(*) FROM gpolygon_tbl WHERE f1 && '(1000,1000,0,0)'::polygon;
193
194EXPLAIN (COSTS OFF)
195SELECT count(*) FROM gcircle_tbl WHERE f1 && '<(500,500),500>'::circle;
196SELECT count(*) FROM gcircle_tbl WHERE f1 && '<(500,500),500>'::circle;
197
198EXPLAIN (COSTS OFF)
199SELECT count(*) FROM point_tbl WHERE f1 <@ box '(0,0,100,100)';
200SELECT count(*) FROM point_tbl WHERE f1 <@ box '(0,0,100,100)';
201
202EXPLAIN (COSTS OFF)
203SELECT count(*) FROM point_tbl WHERE box '(0,0,100,100)' @> f1;
204SELECT count(*) FROM point_tbl WHERE box '(0,0,100,100)' @> f1;
205
206EXPLAIN (COSTS OFF)
207SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50,50),(100,0),(0,0)';
208SELECT count(*) FROM point_tbl WHERE f1 <@ polygon '(0,0),(0,100),(100,100),(50,50),(100,0),(0,0)';
209
210EXPLAIN (COSTS OFF)
211SELECT count(*) FROM point_tbl WHERE f1 <@ circle '<(50,50),50>';
212SELECT count(*) FROM point_tbl WHERE f1 <@ circle '<(50,50),50>';
213
214EXPLAIN (COSTS OFF)
215SELECT count(*) FROM point_tbl p WHERE p.f1 << '(0.0, 0.0)';
216SELECT count(*) FROM point_tbl p WHERE p.f1 << '(0.0, 0.0)';
217
218EXPLAIN (COSTS OFF)
219SELECT count(*) FROM point_tbl p WHERE p.f1 >> '(0.0, 0.0)';
220SELECT count(*) FROM point_tbl p WHERE p.f1 >> '(0.0, 0.0)';
221
222EXPLAIN (COSTS OFF)
223SELECT count(*) FROM point_tbl p WHERE p.f1 <^ '(0.0, 0.0)';
224SELECT count(*) FROM point_tbl p WHERE p.f1 <^ '(0.0, 0.0)';
225
226EXPLAIN (COSTS OFF)
227SELECT count(*) FROM point_tbl p WHERE p.f1 >^ '(0.0, 0.0)';
228SELECT count(*) FROM point_tbl p WHERE p.f1 >^ '(0.0, 0.0)';
229
230EXPLAIN (COSTS OFF)
231SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
232SELECT count(*) FROM point_tbl p WHERE p.f1 ~= '(-5, -12)';
233
234EXPLAIN (COSTS OFF)
235SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
236SELECT * FROM point_tbl ORDER BY f1 <-> '0,1';
237
238EXPLAIN (COSTS OFF)
239SELECT * FROM point_tbl WHERE f1 IS NULL;
240SELECT * FROM point_tbl WHERE f1 IS NULL;
241
242EXPLAIN (COSTS OFF)
243SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
244SELECT * FROM point_tbl WHERE f1 IS NOT NULL ORDER BY f1 <-> '0,1';
245
246EXPLAIN (COSTS OFF)
247SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
248SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
249
250EXPLAIN (COSTS OFF)
251SELECT * FROM gpolygon_tbl ORDER BY f1 <-> '(0,0)'::point LIMIT 10;
252SELECT * FROM gpolygon_tbl ORDER BY f1 <-> '(0,0)'::point LIMIT 10;
253
254EXPLAIN (COSTS OFF)
255SELECT circle_center(f1), round(radius(f1)) as radius FROM gcircle_tbl ORDER BY f1 <-> '(200,300)'::point LIMIT 10;
256SELECT circle_center(f1), round(radius(f1)) as radius FROM gcircle_tbl ORDER BY f1 <-> '(200,300)'::point LIMIT 10;
257
258-- Now check the results from bitmap indexscan
259SET enable_seqscan = OFF;
260SET enable_indexscan = OFF;
261SET enable_bitmapscan = ON;
262
263EXPLAIN (COSTS OFF)
264SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
265SELECT * FROM point_tbl WHERE f1 <@ '(-10,-10),(10,10)':: box ORDER BY f1 <-> '0,1';
266
267RESET enable_seqscan;
268RESET enable_indexscan;
269RESET enable_bitmapscan;
270
271--
272-- GIN over int[] and text[]
273--
274-- Note: GIN currently supports only bitmap scans, not plain indexscans
275--
276
277SET enable_seqscan = OFF;
278SET enable_indexscan = OFF;
279SET enable_bitmapscan = ON;
280
281CREATE INDEX intarrayidx ON array_index_op_test USING gin (i);
282
283explain (costs off)
284SELECT * FROM array_index_op_test WHERE i @> '{32}' ORDER BY seqno;
285
286SELECT * FROM array_index_op_test WHERE i @> '{32}' ORDER BY seqno;
287SELECT * FROM array_index_op_test WHERE i && '{32}' ORDER BY seqno;
288SELECT * FROM array_index_op_test WHERE i @> '{17}' ORDER BY seqno;
289SELECT * FROM array_index_op_test WHERE i && '{17}' ORDER BY seqno;
290SELECT * FROM array_index_op_test WHERE i @> '{32,17}' ORDER BY seqno;
291SELECT * FROM array_index_op_test WHERE i && '{32,17}' ORDER BY seqno;
292SELECT * FROM array_index_op_test WHERE i <@ '{38,34,32,89}' ORDER BY seqno;
293SELECT * FROM array_index_op_test WHERE i = '{47,77}' ORDER BY seqno;
294SELECT * FROM array_index_op_test WHERE i = '{}' ORDER BY seqno;
295SELECT * FROM array_index_op_test WHERE i @> '{}' ORDER BY seqno;
296SELECT * FROM array_index_op_test WHERE i && '{}' ORDER BY seqno;
297SELECT * FROM array_index_op_test WHERE i <@ '{}' ORDER BY seqno;
298SELECT * FROM array_op_test WHERE i = '{NULL}' ORDER BY seqno;
299SELECT * FROM array_op_test WHERE i @> '{NULL}' ORDER BY seqno;
300SELECT * FROM array_op_test WHERE i && '{NULL}' ORDER BY seqno;
301SELECT * FROM array_op_test WHERE i <@ '{NULL}' ORDER BY seqno;
302
303CREATE INDEX textarrayidx ON array_index_op_test USING gin (t);
304
305explain (costs off)
306SELECT * FROM array_index_op_test WHERE t @> '{AAAAAAAA72908}' ORDER BY seqno;
307
308SELECT * FROM array_index_op_test WHERE t @> '{AAAAAAAA72908}' ORDER BY seqno;
309SELECT * FROM array_index_op_test WHERE t && '{AAAAAAAA72908}' ORDER BY seqno;
310SELECT * FROM array_index_op_test WHERE t @> '{AAAAAAAAAA646}' ORDER BY seqno;
311SELECT * FROM array_index_op_test WHERE t && '{AAAAAAAAAA646}' ORDER BY seqno;
312SELECT * FROM array_index_op_test WHERE t @> '{AAAAAAAA72908,AAAAAAAAAA646}' ORDER BY seqno;
313SELECT * FROM array_index_op_test WHERE t && '{AAAAAAAA72908,AAAAAAAAAA646}' ORDER BY seqno;
314SELECT * FROM array_index_op_test WHERE t <@ '{AAAAAAAA72908,AAAAAAAAAAAAAAAAAAA17075,AA88409,AAAAAAAAAAAAAAAAAA36842,AAAAAAA48038,AAAAAAAAAAAAAA10611}' ORDER BY seqno;
315SELECT * FROM array_index_op_test WHERE t = '{AAAAAAAAAA646,A87088}' ORDER BY seqno;
316SELECT * FROM array_index_op_test WHERE t = '{}' ORDER BY seqno;
317SELECT * FROM array_index_op_test WHERE t @> '{}' ORDER BY seqno;
318SELECT * FROM array_index_op_test WHERE t && '{}' ORDER BY seqno;
319SELECT * FROM array_index_op_test WHERE t <@ '{}' ORDER BY seqno;
320
321-- And try it with a multicolumn GIN index
322
323DROP INDEX intarrayidx, textarrayidx;
324
325CREATE INDEX botharrayidx ON array_index_op_test USING gin (i, t);
326
327SELECT * FROM array_index_op_test WHERE i @> '{32}' ORDER BY seqno;
328SELECT * FROM array_index_op_test WHERE i && '{32}' ORDER BY seqno;
329SELECT * FROM array_index_op_test WHERE t @> '{AAAAAAA80240}' ORDER BY seqno;
330SELECT * FROM array_index_op_test WHERE t && '{AAAAAAA80240}' ORDER BY seqno;
331SELECT * FROM array_index_op_test WHERE i @> '{32}' AND t && '{AAAAAAA80240}' ORDER BY seqno;
332SELECT * FROM array_index_op_test WHERE i && '{32}' AND t @> '{AAAAAAA80240}' ORDER BY seqno;
333SELECT * FROM array_index_op_test WHERE t = '{}' ORDER BY seqno;
334SELECT * FROM array_op_test WHERE i = '{NULL}' ORDER BY seqno;
335SELECT * FROM array_op_test WHERE i <@ '{NULL}' ORDER BY seqno;
336
337RESET enable_seqscan;
338RESET enable_indexscan;
339RESET enable_bitmapscan;
340
341--
342-- Try a GIN index with a lot of items with same key. (GIN creates a posting
343-- tree when there are enough duplicates)
344--
345CREATE TABLE array_gin_test (a int[]);
346
347INSERT INTO array_gin_test SELECT ARRAY[1, g%5, g] FROM generate_series(1, 10000) g;
348
349CREATE INDEX array_gin_test_idx ON array_gin_test USING gin (a);
350
351SELECT COUNT(*) FROM array_gin_test WHERE a @> '{2}';
352
353DROP TABLE array_gin_test;
354
355--
356-- Test GIN index's reloptions
357--
358CREATE INDEX gin_relopts_test ON array_index_op_test USING gin (i)
359  WITH (FASTUPDATE=on, GIN_PENDING_LIST_LIMIT=128);
360\d+ gin_relopts_test
361
362--
363-- HASH
364--
365CREATE INDEX hash_i4_index ON hash_i4_heap USING hash (random int4_ops);
366
367CREATE INDEX hash_name_index ON hash_name_heap USING hash (random name_ops);
368
369CREATE INDEX hash_txt_index ON hash_txt_heap USING hash (random text_ops);
370
371CREATE INDEX hash_f8_index ON hash_f8_heap USING hash (random float8_ops) WITH (fillfactor=60);
372
373CREATE UNLOGGED TABLE unlogged_hash_table (id int4);
374CREATE INDEX unlogged_hash_index ON unlogged_hash_table USING hash (id int4_ops);
375DROP TABLE unlogged_hash_table;
376
377-- CREATE INDEX hash_ovfl_index ON hash_ovfl_heap USING hash (x int4_ops);
378
379-- Test hash index build tuplesorting.  Force hash tuplesort using low
380-- maintenance_work_mem setting and fillfactor:
381SET maintenance_work_mem = '1MB';
382CREATE INDEX hash_tuplesort_idx ON tenk1 USING hash (stringu1 name_ops) WITH (fillfactor = 10);
383EXPLAIN (COSTS OFF)
384SELECT count(*) FROM tenk1 WHERE stringu1 = 'TVAAAA';
385SELECT count(*) FROM tenk1 WHERE stringu1 = 'TVAAAA';
386DROP INDEX hash_tuplesort_idx;
387RESET maintenance_work_mem;
388
389
390--
391-- Test functional index
392--
393CREATE TABLE func_index_heap (f1 text, f2 text);
394CREATE UNIQUE INDEX func_index_index on func_index_heap (textcat(f1,f2));
395
396INSERT INTO func_index_heap VALUES('ABC','DEF');
397INSERT INTO func_index_heap VALUES('AB','CDEFG');
398INSERT INTO func_index_heap VALUES('QWE','RTY');
399-- this should fail because of unique index:
400INSERT INTO func_index_heap VALUES('ABCD', 'EF');
401-- but this shouldn't:
402INSERT INTO func_index_heap VALUES('QWERTY');
403
404
405--
406-- Same test, expressional index
407--
408DROP TABLE func_index_heap;
409CREATE TABLE func_index_heap (f1 text, f2 text);
410CREATE UNIQUE INDEX func_index_index on func_index_heap ((f1 || f2) text_ops);
411
412INSERT INTO func_index_heap VALUES('ABC','DEF');
413INSERT INTO func_index_heap VALUES('AB','CDEFG');
414INSERT INTO func_index_heap VALUES('QWE','RTY');
415-- this should fail because of unique index:
416INSERT INTO func_index_heap VALUES('ABCD', 'EF');
417-- but this shouldn't:
418INSERT INTO func_index_heap VALUES('QWERTY');
419
420--
421-- Test unique index with included columns
422--
423CREATE TABLE covering_index_heap (f1 int, f2 int, f3 text);
424CREATE UNIQUE INDEX covering_index_index on covering_index_heap (f1,f2) INCLUDE(f3);
425
426INSERT INTO covering_index_heap VALUES(1,1,'AAA');
427INSERT INTO covering_index_heap VALUES(1,2,'AAA');
428-- this should fail because of unique index on f1,f2:
429INSERT INTO covering_index_heap VALUES(1,2,'BBB');
430-- and this shouldn't:
431INSERT INTO covering_index_heap VALUES(1,4,'AAA');
432-- Try to build index on table that already contains data
433CREATE UNIQUE INDEX covering_pkey on covering_index_heap (f1,f2) INCLUDE(f3);
434-- Try to use existing covering index as primary key
435ALTER TABLE covering_index_heap ADD CONSTRAINT covering_pkey PRIMARY KEY USING INDEX
436covering_pkey;
437DROP TABLE covering_index_heap;
438
439
440--
441-- Also try building functional, expressional, and partial indexes on
442-- tables that already contain data.
443--
444create unique index hash_f8_index_1 on hash_f8_heap(abs(random));
445create unique index hash_f8_index_2 on hash_f8_heap((seqno + 1), random);
446create unique index hash_f8_index_3 on hash_f8_heap(random) where seqno > 1000;
447
448--
449-- Try some concurrent index builds
450--
451-- Unfortunately this only tests about half the code paths because there are
452-- no concurrent updates happening to the table at the same time.
453
454CREATE TABLE concur_heap (f1 text, f2 text);
455-- empty table
456CREATE INDEX CONCURRENTLY concur_index1 ON concur_heap(f2,f1);
457CREATE INDEX CONCURRENTLY IF NOT EXISTS concur_index1 ON concur_heap(f2,f1);
458INSERT INTO concur_heap VALUES  ('a','b');
459INSERT INTO concur_heap VALUES  ('b','b');
460-- unique index
461CREATE UNIQUE INDEX CONCURRENTLY concur_index2 ON concur_heap(f1);
462CREATE UNIQUE INDEX CONCURRENTLY IF NOT EXISTS concur_index2 ON concur_heap(f1);
463-- check if constraint is set up properly to be enforced
464INSERT INTO concur_heap VALUES ('b','x');
465-- check if constraint is enforced properly at build time
466CREATE UNIQUE INDEX CONCURRENTLY concur_index3 ON concur_heap(f2);
467-- test that expression indexes and partial indexes work concurrently
468CREATE INDEX CONCURRENTLY concur_index4 on concur_heap(f2) WHERE f1='a';
469CREATE INDEX CONCURRENTLY concur_index5 on concur_heap(f2) WHERE f1='x';
470-- here we also check that you can default the index name
471CREATE INDEX CONCURRENTLY on concur_heap((f2||f1));
472
473-- You can't do a concurrent index build in a transaction
474BEGIN;
475CREATE INDEX CONCURRENTLY concur_index7 ON concur_heap(f1);
476COMMIT;
477
478-- But you can do a regular index build in a transaction
479BEGIN;
480CREATE INDEX std_index on concur_heap(f2);
481COMMIT;
482
483-- Failed builds are left invalid by VACUUM FULL, fixed by REINDEX
484VACUUM FULL concur_heap;
485REINDEX TABLE concur_heap;
486DELETE FROM concur_heap WHERE f1 = 'b';
487VACUUM FULL concur_heap;
488\d concur_heap
489REINDEX TABLE concur_heap;
490\d concur_heap
491
492--
493-- Try some concurrent index drops
494--
495DROP INDEX CONCURRENTLY "concur_index2";				-- works
496DROP INDEX CONCURRENTLY IF EXISTS "concur_index2";		-- notice
497
498-- failures
499DROP INDEX CONCURRENTLY "concur_index2", "concur_index3";
500BEGIN;
501DROP INDEX CONCURRENTLY "concur_index5";
502ROLLBACK;
503
504-- successes
505DROP INDEX CONCURRENTLY IF EXISTS "concur_index3";
506DROP INDEX CONCURRENTLY "concur_index4";
507DROP INDEX CONCURRENTLY "concur_index5";
508DROP INDEX CONCURRENTLY "concur_index1";
509DROP INDEX CONCURRENTLY "concur_heap_expr_idx";
510
511\d concur_heap
512
513DROP TABLE concur_heap;
514
515--
516-- Test ADD CONSTRAINT USING INDEX
517--
518
519CREATE TABLE cwi_test( a int , b varchar(10), c char);
520
521-- add some data so that all tests have something to work with.
522
523INSERT INTO cwi_test VALUES(1, 2), (3, 4), (5, 6);
524
525CREATE UNIQUE INDEX cwi_uniq_idx ON cwi_test(a , b);
526ALTER TABLE cwi_test ADD primary key USING INDEX cwi_uniq_idx;
527
528\d cwi_test
529\d cwi_uniq_idx
530
531CREATE UNIQUE INDEX cwi_uniq2_idx ON cwi_test(b , a);
532ALTER TABLE cwi_test DROP CONSTRAINT cwi_uniq_idx,
533	ADD CONSTRAINT cwi_replaced_pkey PRIMARY KEY
534		USING INDEX cwi_uniq2_idx;
535
536\d cwi_test
537\d cwi_replaced_pkey
538
539DROP INDEX cwi_replaced_pkey;	-- Should fail; a constraint depends on it
540
541DROP TABLE cwi_test;
542
543-- ADD CONSTRAINT USING INDEX is forbidden on partitioned tables
544CREATE TABLE cwi_test(a int) PARTITION BY hash (a);
545create unique index on cwi_test (a);
546alter table cwi_test add primary key using index cwi_test_a_idx ;
547DROP TABLE cwi_test;
548
549--
550-- Check handling of indexes on system columns
551--
552CREATE TABLE syscol_table (a INT);
553
554-- System columns cannot be indexed
555CREATE INDEX ON syscolcol_table (ctid);
556
557-- nor used in expressions
558CREATE INDEX ON syscol_table ((ctid >= '(1000,0)'));
559
560-- nor used in predicates
561CREATE INDEX ON syscol_table (a) WHERE ctid >= '(1000,0)';
562
563DROP TABLE syscol_table;
564
565--
566-- Tests for IS NULL/IS NOT NULL with b-tree indexes
567--
568
569SELECT unique1, unique2 INTO onek_with_null FROM onek;
570INSERT INTO onek_with_null (unique1,unique2) VALUES (NULL, -1), (NULL, NULL);
571CREATE UNIQUE INDEX onek_nulltest ON onek_with_null (unique2,unique1);
572
573SET enable_seqscan = OFF;
574SET enable_indexscan = ON;
575SET enable_bitmapscan = ON;
576
577SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL;
578SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique2 IS NULL;
579SELECT count(*) FROM onek_with_null WHERE unique1 IS NOT NULL;
580SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique2 IS NOT NULL;
581SELECT count(*) FROM onek_with_null WHERE unique1 IS NOT NULL AND unique1 > 500;
582SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique1 > 500;
583
584DROP INDEX onek_nulltest;
585
586CREATE UNIQUE INDEX onek_nulltest ON onek_with_null (unique2 desc,unique1);
587
588SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL;
589SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique2 IS NULL;
590SELECT count(*) FROM onek_with_null WHERE unique1 IS NOT NULL;
591SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique2 IS NOT NULL;
592SELECT count(*) FROM onek_with_null WHERE unique1 IS NOT NULL AND unique1 > 500;
593SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique1 > 500;
594
595DROP INDEX onek_nulltest;
596
597CREATE UNIQUE INDEX onek_nulltest ON onek_with_null (unique2 desc nulls last,unique1);
598
599SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL;
600SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique2 IS NULL;
601SELECT count(*) FROM onek_with_null WHERE unique1 IS NOT NULL;
602SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique2 IS NOT NULL;
603SELECT count(*) FROM onek_with_null WHERE unique1 IS NOT NULL AND unique1 > 500;
604SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique1 > 500;
605
606DROP INDEX onek_nulltest;
607
608CREATE UNIQUE INDEX onek_nulltest ON onek_with_null (unique2  nulls first,unique1);
609
610SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL;
611SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique2 IS NULL;
612SELECT count(*) FROM onek_with_null WHERE unique1 IS NOT NULL;
613SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique2 IS NOT NULL;
614SELECT count(*) FROM onek_with_null WHERE unique1 IS NOT NULL AND unique1 > 500;
615SELECT count(*) FROM onek_with_null WHERE unique1 IS NULL AND unique1 > 500;
616
617DROP INDEX onek_nulltest;
618
619-- Check initial-positioning logic too
620
621CREATE UNIQUE INDEX onek_nulltest ON onek_with_null (unique2);
622
623SET enable_seqscan = OFF;
624SET enable_indexscan = ON;
625SET enable_bitmapscan = OFF;
626
627SELECT unique1, unique2 FROM onek_with_null
628  ORDER BY unique2 LIMIT 2;
629SELECT unique1, unique2 FROM onek_with_null WHERE unique2 >= -1
630  ORDER BY unique2 LIMIT 2;
631SELECT unique1, unique2 FROM onek_with_null WHERE unique2 >= 0
632  ORDER BY unique2 LIMIT 2;
633
634SELECT unique1, unique2 FROM onek_with_null
635  ORDER BY unique2 DESC LIMIT 2;
636SELECT unique1, unique2 FROM onek_with_null WHERE unique2 >= -1
637  ORDER BY unique2 DESC LIMIT 2;
638SELECT unique1, unique2 FROM onek_with_null WHERE unique2 < 999
639  ORDER BY unique2 DESC LIMIT 2;
640
641RESET enable_seqscan;
642RESET enable_indexscan;
643RESET enable_bitmapscan;
644
645DROP TABLE onek_with_null;
646
647--
648-- Check bitmap index path planning
649--
650
651EXPLAIN (COSTS OFF)
652SELECT * FROM tenk1
653  WHERE thousand = 42 AND (tenthous = 1 OR tenthous = 3 OR tenthous = 42);
654SELECT * FROM tenk1
655  WHERE thousand = 42 AND (tenthous = 1 OR tenthous = 3 OR tenthous = 42);
656
657EXPLAIN (COSTS OFF)
658SELECT count(*) FROM tenk1
659  WHERE hundred = 42 AND (thousand = 42 OR thousand = 99);
660SELECT count(*) FROM tenk1
661  WHERE hundred = 42 AND (thousand = 42 OR thousand = 99);
662
663--
664-- Check behavior with duplicate index column contents
665--
666
667CREATE TABLE dupindexcols AS
668  SELECT unique1 as id, stringu2::text as f1 FROM tenk1;
669CREATE INDEX dupindexcols_i ON dupindexcols (f1, id, f1 text_pattern_ops);
670ANALYZE dupindexcols;
671
672EXPLAIN (COSTS OFF)
673  SELECT count(*) FROM dupindexcols
674    WHERE f1 BETWEEN 'WA' AND 'ZZZ' and id < 1000 and f1 ~<~ 'YX';
675SELECT count(*) FROM dupindexcols
676  WHERE f1 BETWEEN 'WA' AND 'ZZZ' and id < 1000 and f1 ~<~ 'YX';
677
678--
679-- Check ordering of =ANY indexqual results (bug in 9.2.0)
680--
681
682vacuum tenk1;		-- ensure we get consistent plans here
683
684explain (costs off)
685SELECT unique1 FROM tenk1
686WHERE unique1 IN (1,42,7)
687ORDER BY unique1;
688
689SELECT unique1 FROM tenk1
690WHERE unique1 IN (1,42,7)
691ORDER BY unique1;
692
693explain (costs off)
694SELECT thousand, tenthous FROM tenk1
695WHERE thousand < 2 AND tenthous IN (1001,3000)
696ORDER BY thousand;
697
698SELECT thousand, tenthous FROM tenk1
699WHERE thousand < 2 AND tenthous IN (1001,3000)
700ORDER BY thousand;
701
702SET enable_indexonlyscan = OFF;
703
704explain (costs off)
705SELECT thousand, tenthous FROM tenk1
706WHERE thousand < 2 AND tenthous IN (1001,3000)
707ORDER BY thousand;
708
709SELECT thousand, tenthous FROM tenk1
710WHERE thousand < 2 AND tenthous IN (1001,3000)
711ORDER BY thousand;
712
713RESET enable_indexonlyscan;
714
715--
716-- Check elimination of constant-NULL subexpressions
717--
718
719explain (costs off)
720  select * from tenk1 where (thousand, tenthous) in ((1,1001), (null,null));
721
722--
723-- Check matching of boolean index columns to WHERE conditions and sort keys
724--
725
726create temp table boolindex (b bool, i int, unique(b, i), junk float);
727
728explain (costs off)
729  select * from boolindex order by b, i limit 10;
730explain (costs off)
731  select * from boolindex where b order by i limit 10;
732explain (costs off)
733  select * from boolindex where b = true order by i desc limit 10;
734explain (costs off)
735  select * from boolindex where not b order by i limit 10;
736explain (costs off)
737  select * from boolindex where b is true order by i desc limit 10;
738explain (costs off)
739  select * from boolindex where b is false order by i desc limit 10;
740
741--
742-- REINDEX (VERBOSE)
743--
744CREATE TABLE reindex_verbose(id integer primary key);
745\set VERBOSITY terse \\ -- suppress machine-dependent details
746REINDEX (VERBOSE) TABLE reindex_verbose;
747\set VERBOSITY default
748DROP TABLE reindex_verbose;
749
750--
751-- REINDEX CONCURRENTLY
752--
753CREATE TABLE concur_reindex_tab (c1 int);
754-- REINDEX
755REINDEX TABLE concur_reindex_tab; -- notice
756REINDEX TABLE CONCURRENTLY concur_reindex_tab; -- notice
757ALTER TABLE concur_reindex_tab ADD COLUMN c2 text; -- add toast index
758-- Normal index with integer column
759CREATE UNIQUE INDEX concur_reindex_ind1 ON concur_reindex_tab(c1);
760-- Normal index with text column
761CREATE INDEX concur_reindex_ind2 ON concur_reindex_tab(c2);
762-- UNIQUE index with expression
763CREATE UNIQUE INDEX concur_reindex_ind3 ON concur_reindex_tab(abs(c1));
764-- Duplicate column names
765CREATE INDEX concur_reindex_ind4 ON concur_reindex_tab(c1, c1, c2);
766-- Create table for check on foreign key dependence switch with indexes swapped
767ALTER TABLE concur_reindex_tab ADD PRIMARY KEY USING INDEX concur_reindex_ind1;
768CREATE TABLE concur_reindex_tab2 (c1 int REFERENCES concur_reindex_tab);
769INSERT INTO concur_reindex_tab VALUES  (1, 'a');
770INSERT INTO concur_reindex_tab VALUES  (2, 'a');
771-- Reindex concurrently of exclusion constraint currently not supported
772CREATE TABLE concur_reindex_tab3 (c1 int, c2 int4range, EXCLUDE USING gist (c2 WITH &&));
773INSERT INTO concur_reindex_tab3 VALUES  (3, '[1,2]');
774REINDEX INDEX CONCURRENTLY  concur_reindex_tab3_c2_excl;  -- error
775REINDEX TABLE CONCURRENTLY concur_reindex_tab3;  -- succeeds with warning
776INSERT INTO concur_reindex_tab3 VALUES  (4, '[2,4]');
777-- Check materialized views
778CREATE MATERIALIZED VIEW concur_reindex_matview AS SELECT * FROM concur_reindex_tab;
779REINDEX INDEX CONCURRENTLY concur_reindex_ind1;
780REINDEX TABLE CONCURRENTLY concur_reindex_tab;
781REINDEX TABLE CONCURRENTLY concur_reindex_matview;
782-- Check that comments are preserved
783CREATE TABLE testcomment (i int);
784CREATE INDEX testcomment_idx1 ON testcomment (i);
785COMMENT ON INDEX testcomment_idx1 IS 'test comment';
786SELECT obj_description('testcomment_idx1'::regclass, 'pg_class');
787REINDEX TABLE testcomment;
788SELECT obj_description('testcomment_idx1'::regclass, 'pg_class');
789REINDEX TABLE CONCURRENTLY testcomment ;
790SELECT obj_description('testcomment_idx1'::regclass, 'pg_class');
791DROP TABLE testcomment;
792-- Partitions
793-- Create some partitioned tables
794CREATE TABLE concur_reindex_part (c1 int, c2 int) PARTITION BY RANGE (c1);
795CREATE TABLE concur_reindex_part_0 PARTITION OF concur_reindex_part
796  FOR VALUES FROM (0) TO (10) PARTITION BY list (c2);
797CREATE TABLE concur_reindex_part_0_1 PARTITION OF concur_reindex_part_0
798  FOR VALUES IN (1);
799CREATE TABLE concur_reindex_part_0_2 PARTITION OF concur_reindex_part_0
800  FOR VALUES IN (2);
801-- This partitioned table will have no partitions.
802CREATE TABLE concur_reindex_part_10 PARTITION OF concur_reindex_part
803  FOR VALUES FROM (10) TO (20) PARTITION BY list (c2);
804-- Create some partitioned indexes
805CREATE INDEX concur_reindex_part_index ON ONLY concur_reindex_part (c1);
806CREATE INDEX concur_reindex_part_index_0 ON ONLY concur_reindex_part_0 (c1);
807ALTER INDEX concur_reindex_part_index ATTACH PARTITION concur_reindex_part_index_0;
808-- This partitioned index will have no partitions.
809CREATE INDEX concur_reindex_part_index_10 ON ONLY concur_reindex_part_10 (c1);
810ALTER INDEX concur_reindex_part_index ATTACH PARTITION concur_reindex_part_index_10;
811CREATE INDEX concur_reindex_part_index_0_1 ON ONLY concur_reindex_part_0_1 (c1);
812ALTER INDEX concur_reindex_part_index_0 ATTACH PARTITION concur_reindex_part_index_0_1;
813CREATE INDEX concur_reindex_part_index_0_2 ON ONLY concur_reindex_part_0_2 (c1);
814ALTER INDEX concur_reindex_part_index_0 ATTACH PARTITION concur_reindex_part_index_0_2;
815SELECT relid, parentrelid, level FROM pg_partition_tree('concur_reindex_part_index')
816  ORDER BY relid, level;
817-- REINDEX fails for partitioned indexes
818REINDEX INDEX concur_reindex_part_index_10;
819REINDEX INDEX CONCURRENTLY concur_reindex_part_index_10;
820-- REINDEX is a no-op for partitioned tables
821REINDEX TABLE concur_reindex_part_10;
822REINDEX TABLE CONCURRENTLY concur_reindex_part_10;
823SELECT relid, parentrelid, level FROM pg_partition_tree('concur_reindex_part_index')
824  ORDER BY relid, level;
825-- REINDEX should preserve dependencies of partition tree.
826REINDEX INDEX CONCURRENTLY concur_reindex_part_index_0_1;
827REINDEX INDEX CONCURRENTLY concur_reindex_part_index_0_2;
828SELECT relid, parentrelid, level FROM pg_partition_tree('concur_reindex_part_index')
829  ORDER BY relid, level;
830REINDEX TABLE CONCURRENTLY concur_reindex_part_0_1;
831REINDEX TABLE CONCURRENTLY concur_reindex_part_0_2;
832SELECT relid, parentrelid, level FROM pg_partition_tree('concur_reindex_part_index')
833  ORDER BY relid, level;
834DROP TABLE concur_reindex_part;
835
836-- Check errors
837-- Cannot run inside a transaction block
838BEGIN;
839REINDEX TABLE CONCURRENTLY concur_reindex_tab;
840COMMIT;
841REINDEX TABLE CONCURRENTLY pg_database; -- no shared relation
842REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relations
843REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
844-- Warns about catalog relations
845REINDEX SCHEMA CONCURRENTLY pg_catalog;
846
847-- Check the relation status, there should not be invalid indexes
848\d concur_reindex_tab
849DROP MATERIALIZED VIEW concur_reindex_matview;
850DROP TABLE concur_reindex_tab, concur_reindex_tab2, concur_reindex_tab3;
851
852-- Check handling of invalid indexes
853CREATE TABLE concur_reindex_tab4 (c1 int);
854INSERT INTO concur_reindex_tab4 VALUES (1), (1), (2);
855-- This trick creates an invalid index.
856CREATE UNIQUE INDEX CONCURRENTLY concur_reindex_ind5 ON concur_reindex_tab4 (c1);
857-- Reindexing concurrently this index fails with the same failure.
858-- The extra index created is itself invalid, and can be dropped.
859REINDEX INDEX CONCURRENTLY concur_reindex_ind5;
860\d concur_reindex_tab4
861DROP INDEX concur_reindex_ind5_ccnew;
862-- This makes the previous failure go away, so the index can become valid.
863DELETE FROM concur_reindex_tab4 WHERE c1 = 1;
864-- The invalid index is not processed when running REINDEX TABLE.
865REINDEX TABLE CONCURRENTLY concur_reindex_tab4;
866\d concur_reindex_tab4
867-- But it is fixed with REINDEX INDEX.
868REINDEX INDEX CONCURRENTLY concur_reindex_ind5;
869\d concur_reindex_tab4
870DROP TABLE concur_reindex_tab4;
871
872--
873-- REINDEX SCHEMA
874--
875REINDEX SCHEMA schema_to_reindex; -- failure, schema does not exist
876CREATE SCHEMA schema_to_reindex;
877SET search_path = 'schema_to_reindex';
878CREATE TABLE table1(col1 SERIAL PRIMARY KEY);
879INSERT INTO table1 SELECT generate_series(1,400);
880CREATE TABLE table2(col1 SERIAL PRIMARY KEY, col2 TEXT NOT NULL);
881INSERT INTO table2 SELECT generate_series(1,400), 'abc';
882CREATE INDEX ON table2(col2);
883CREATE MATERIALIZED VIEW matview AS SELECT col1 FROM table2;
884CREATE INDEX ON matview(col1);
885CREATE VIEW view AS SELECT col2 FROM table2;
886CREATE TABLE reindex_before AS
887SELECT oid, relname, relfilenode, relkind, reltoastrelid
888	FROM pg_class
889	where relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'schema_to_reindex');
890INSERT INTO reindex_before
891SELECT oid, 'pg_toast_TABLE', relfilenode, relkind, reltoastrelid
892FROM pg_class WHERE oid IN
893	(SELECT reltoastrelid FROM reindex_before WHERE reltoastrelid > 0);
894INSERT INTO reindex_before
895SELECT oid, 'pg_toast_TABLE_index', relfilenode, relkind, reltoastrelid
896FROM pg_class where oid in
897	(select indexrelid from pg_index where indrelid in
898		(select reltoastrelid from reindex_before where reltoastrelid > 0));
899REINDEX SCHEMA schema_to_reindex;
900CREATE TABLE reindex_after AS SELECT oid, relname, relfilenode, relkind
901	FROM pg_class
902	where relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = 'schema_to_reindex');
903SELECT  b.relname,
904        b.relkind,
905        CASE WHEN a.relfilenode = b.relfilenode THEN 'relfilenode is unchanged'
906        ELSE 'relfilenode has changed' END
907  FROM reindex_before b JOIN pg_class a ON b.oid = a.oid
908  ORDER BY 1;
909REINDEX SCHEMA schema_to_reindex;
910BEGIN;
911REINDEX SCHEMA schema_to_reindex; -- failure, cannot run in a transaction
912END;
913
914-- concurrently
915REINDEX SCHEMA CONCURRENTLY schema_to_reindex;
916
917-- Failure for unauthorized user
918CREATE ROLE regress_reindexuser NOLOGIN;
919SET SESSION ROLE regress_reindexuser;
920REINDEX SCHEMA schema_to_reindex;
921
922-- Clean up
923RESET ROLE;
924DROP ROLE regress_reindexuser;
925DROP SCHEMA schema_to_reindex CASCADE;
926