1-- Tests for range data types.
2CREATE TYPE textrange AS RANGE (
3    subtype = text,
4    COLLATION = "C"
5);
6
7--
8-- test input parser
9--
10-- negative tests; should fail
11SELECT
12    ''::textrange;
13
14SELECT
15    '-[a,z)'::textrange;
16
17SELECT
18    '[a,z) - '::textrange;
19
20SELECT
21    '(",a)'::textrange;
22
23SELECT
24    '(,,a)'::textrange;
25
26SELECT
27    '(),a)'::textrange;
28
29SELECT
30    '(a,))'::textrange;
31
32SELECT
33    '(],a)'::textrange;
34
35SELECT
36    '(a,])'::textrange;
37
38SELECT
39    '[z,a]'::textrange;
40
41-- should succeed
42SELECT
43    '  empty  '::textrange;
44
45SELECT
46    ' ( empty, empty )  '::textrange;
47
48SELECT
49    ' ( " a " " a ", " z " " z " )  '::textrange;
50
51SELECT
52    '(,z)'::textrange;
53
54SELECT
55    '(a,)'::textrange;
56
57SELECT
58    '[,z]'::textrange;
59
60SELECT
61    '[a,]'::textrange;
62
63SELECT
64    '(,)'::textrange;
65
66SELECT
67    '[ , ]'::textrange;
68
69SELECT
70    '["",""]'::textrange;
71
72SELECT
73    '[",",","]'::textrange;
74
75SELECT
76    '["\\","\\"]'::textrange;
77
78SELECT
79    '(\\,a)'::textrange;
80
81SELECT
82    '((,z)'::textrange;
83
84SELECT
85    '([,z)'::textrange;
86
87SELECT
88    '(!,()'::textrange;
89
90SELECT
91    '(!,[)'::textrange;
92
93SELECT
94    '[a,a]'::textrange;
95
96-- these are allowed but normalize to empty:
97SELECT
98    '[a,a)'::textrange;
99
100SELECT
101    '(a,a]'::textrange;
102
103SELECT
104    '(a,a)'::textrange;
105
106--
107-- create some test data and test the operators
108--
109CREATE TABLE numrange_test (
110    nr numrange
111);
112
113CREATE INDEX numrange_test_btree ON numrange_test (nr);
114
115INSERT INTO numrange_test
116    VALUES ('[,)');
117
118INSERT INTO numrange_test
119    VALUES ('[3,]');
120
121INSERT INTO numrange_test
122    VALUES ('[, 5)');
123
124INSERT INTO numrange_test
125    VALUES (numrange(1.1, 2.2));
126
127INSERT INTO numrange_test
128    VALUES ('empty');
129
130INSERT INTO numrange_test
131    VALUES (numrange(1.7, 1.7, '[]'));
132
133SELECT
134    nr,
135    isempty(nr),
136    lower(nr),
137    upper(nr)
138FROM
139    numrange_test;
140
141SELECT
142    nr,
143    lower_inc(nr),
144    lower_inf(nr),
145    upper_inc(nr),
146    upper_inf(nr)
147FROM
148    numrange_test;
149
150SELECT
151    *
152FROM
153    numrange_test
154WHERE
155    range_contains(nr, numrange(1.9, 1.91));
156
157SELECT
158    *
159FROM
160    numrange_test
161WHERE
162    nr @> numrange(1.0, 10000.1);
163
164SELECT
165    *
166FROM
167    numrange_test
168WHERE
169    range_contained_by(numrange(- 1e7, -10000.1), nr);
170
171SELECT
172    *
173FROM
174    numrange_test
175WHERE
176    1.9 <@ nr;
177
178SELECT
179    *
180FROM
181    numrange_test
182WHERE
183    nr = 'empty';
184
185SELECT
186    *
187FROM
188    numrange_test
189WHERE
190    nr = '(1.1, 2.2)';
191
192SELECT
193    *
194FROM
195    numrange_test
196WHERE
197    nr = '[1.1, 2.2)';
198
199SELECT
200    *
201FROM
202    numrange_test
203WHERE
204    nr < 'empty';
205
206SELECT
207    *
208FROM
209    numrange_test
210WHERE
211    nr < numrange(-1000.0, -1000.0, '[]');
212
213SELECT
214    *
215FROM
216    numrange_test
217WHERE
218    nr < numrange(0.0, 1.0, '[]');
219
220SELECT
221    *
222FROM
223    numrange_test
224WHERE
225    nr < numrange(1000.0, 1001.0, '[]');
226
227SELECT
228    *
229FROM
230    numrange_test
231WHERE
232    nr <= 'empty';
233
234SELECT
235    *
236FROM
237    numrange_test
238WHERE
239    nr >= 'empty';
240
241SELECT
242    *
243FROM
244    numrange_test
245WHERE
246    nr > 'empty';
247
248SELECT
249    *
250FROM
251    numrange_test
252WHERE
253    nr > numrange(-1001.0, -1000.0, '[]');
254
255SELECT
256    *
257FROM
258    numrange_test
259WHERE
260    nr > numrange(0.0, 1.0, '[]');
261
262SELECT
263    *
264FROM
265    numrange_test
266WHERE
267    nr > numrange(1000.0, 1000.0, '[]');
268
269SELECT
270    numrange(2.0, 1.0);
271
272SELECT
273    numrange(2.0, 3.0) -|- numrange(3.0, 4.0);
274
275SELECT
276    range_adjacent(numrange(2.0, 3.0), numrange(3.1, 4.0));
277
278SELECT
279    range_adjacent(numrange(2.0, 3.0), numrange(3.1, NULL));
280
281SELECT
282    numrange(2.0, 3.0, '[]') -|- numrange(3.0, 4.0, '()');
283
284SELECT
285    numrange(1.0, 2.0) -|- numrange(2.0, 3.0, '[]');
286
287SELECT
288    range_adjacent(numrange(2.0, 3.0, '(]'), numrange(1.0, 2.0, '(]'));
289
290SELECT
291    numrange(1.1, 3.3) <@ numrange(0.1, 10.1);
292
293SELECT
294    numrange(0.1, 10.1) <@ numrange(1.1, 3.3);
295
296SELECT
297    numrange(1.1, 2.2) - numrange(2.0, 3.0);
298
299SELECT
300    numrange(1.1, 2.2) - numrange(2.2, 3.0);
301
302SELECT
303    numrange(1.1, 2.2, '[]') - numrange(2.0, 3.0);
304
305SELECT
306    range_minus(numrange(10.1, 12.2, '[]'), numrange(110.0, 120.2, '(]'));
307
308SELECT
309    range_minus(numrange(10.1, 12.2, '[]'), numrange(0.0, 120.2, '(]'));
310
311SELECT
312    numrange(4.5, 5.5, '[]') && numrange(5.5, 6.5);
313
314SELECT
315    numrange(1.0, 2.0) << numrange(3.0, 4.0);
316
317SELECT
318    numrange(1.0, 3.0, '[]') << numrange(3.0, 4.0, '[]');
319
320SELECT
321    numrange(1.0, 3.0, '()') << numrange(3.0, 4.0, '()');
322
323SELECT
324    numrange(1.0, 2.0) >> numrange(3.0, 4.0);
325
326SELECT
327    numrange(3.0, 70.0) &< numrange(6.6, 100.0);
328
329SELECT
330    numrange(1.1, 2.2) < numrange(1.0, 200.2);
331
332SELECT
333    numrange(1.1, 2.2) < numrange(1.1, 1.2);
334
335SELECT
336    numrange(1.0, 2.0) + numrange(2.0, 3.0);
337
338SELECT
339    numrange(1.0, 2.0) + numrange(1.5, 3.0);
340
341SELECT
342    numrange(1.0, 2.0) + numrange(2.5, 3.0);
343
344-- should fail
345SELECT
346    range_merge(numrange(1.0, 2.0), numrange(2.0, 3.0));
347
348SELECT
349    range_merge(numrange(1.0, 2.0), numrange(1.5, 3.0));
350
351SELECT
352    range_merge(numrange(1.0, 2.0), numrange(2.5, 3.0));
353
354-- shouldn't fail
355SELECT
356    numrange(1.0, 2.0) * numrange(2.0, 3.0);
357
358SELECT
359    numrange(1.0, 2.0) * numrange(1.5, 3.0);
360
361SELECT
362    numrange(1.0, 2.0) * numrange(2.5, 3.0);
363
364CREATE TABLE numrange_test2 (
365    nr numrange
366);
367
368CREATE INDEX numrange_test2_hash_idx ON numrange_test2 (nr);
369
370INSERT INTO numrange_test2
371    VALUES ('[, 5)');
372
373INSERT INTO numrange_test2
374    VALUES (numrange(1.1, 2.2));
375
376INSERT INTO numrange_test2
377    VALUES (numrange(1.1, 2.2));
378
379INSERT INTO numrange_test2
380    VALUES (numrange(1.1, 2.2, '()'));
381
382INSERT INTO numrange_test2
383    VALUES ('empty');
384
385SELECT
386    *
387FROM
388    numrange_test2
389WHERE
390    nr = 'empty'::numrange;
391
392SELECT
393    *
394FROM
395    numrange_test2
396WHERE
397    nr = numrange(1.1, 2.2);
398
399SELECT
400    *
401FROM
402    numrange_test2
403WHERE
404    nr = numrange(1.1, 2.3);
405
406SET enable_nestloop = t;
407
408SET enable_hashjoin = f;
409
410SET enable_mergejoin = f;
411
412SELECT
413    *
414FROM
415    numrange_test
416    NATURAL JOIN numrange_test2
417ORDER BY
418    nr;
419
420SET enable_nestloop = f;
421
422SET enable_hashjoin = t;
423
424SET enable_mergejoin = f;
425
426SELECT
427    *
428FROM
429    numrange_test
430    NATURAL JOIN numrange_test2
431ORDER BY
432    nr;
433
434SET enable_nestloop = f;
435
436SET enable_hashjoin = f;
437
438SET enable_mergejoin = t;
439
440SELECT
441    *
442FROM
443    numrange_test
444    NATURAL JOIN numrange_test2
445ORDER BY
446    nr;
447
448SET enable_nestloop TO DEFAULT;
449
450SET enable_hashjoin TO DEFAULT;
451
452SET enable_mergejoin TO DEFAULT;
453
454DROP TABLE numrange_test;
455
456DROP TABLE numrange_test2;
457
458-- test canonical form for int4range
459SELECT
460    int4range(1, 10, '[]');
461
462SELECT
463    int4range(1, 10, '[)');
464
465SELECT
466    int4range(1, 10, '(]');
467
468SELECT
469    int4range(1, 10, '()');
470
471SELECT
472    int4range(1, 2, '()');
473
474-- test canonical form for daterange
475SELECT
476    daterange('2000-01-10'::date, '2000-01-20'::date, '[]');
477
478SELECT
479    daterange('2000-01-10'::date, '2000-01-20'::date, '[)');
480
481SELECT
482    daterange('2000-01-10'::date, '2000-01-20'::date, '(]');
483
484SELECT
485    daterange('2000-01-10'::date, '2000-01-20'::date, '()');
486
487SELECT
488    daterange('2000-01-10'::date, '2000-01-11'::date, '()');
489
490SELECT
491    daterange('2000-01-10'::date, '2000-01-11'::date, '(]');
492
493-- test GiST index that's been built incrementally
494CREATE TABLE test_range_gist (
495    ir int4range
496);
497
498CREATE INDEX test_range_gist_idx ON test_range_gist USING gist (ir);
499
500INSERT INTO test_range_gist
501SELECT
502    int4range(g, g + 10)
503FROM
504    generate_series(1, 2000) g;
505
506INSERT INTO test_range_gist
507SELECT
508    'empty'::int4range
509FROM
510    generate_series(1, 500) g;
511
512INSERT INTO test_range_gist
513SELECT
514    int4range(g, g + 10000)
515FROM
516    generate_series(1, 1000) g;
517
518INSERT INTO test_range_gist
519SELECT
520    'empty'::int4range
521FROM
522    generate_series(1, 500) g;
523
524INSERT INTO test_range_gist
525SELECT
526    int4range(NULL, g * 10, '(]')
527FROM
528    generate_series(1, 100) g;
529
530INSERT INTO test_range_gist
531SELECT
532    int4range(g * 10, NULL, '(]')
533FROM
534    generate_series(1, 100) g;
535
536INSERT INTO test_range_gist
537SELECT
538    int4range(g, g + 10)
539FROM
540    generate_series(1, 2000) g;
541
542-- first, verify non-indexed results
543SET enable_seqscan = t;
544
545SET enable_indexscan = f;
546
547SET enable_bitmapscan = f;
548
549SELECT
550    count(*)
551FROM
552    test_range_gist
553WHERE
554    ir @> 'empty'::int4range;
555
556SELECT
557    count(*)
558FROM
559    test_range_gist
560WHERE
561    ir = int4range(10, 20);
562
563SELECT
564    count(*)
565FROM
566    test_range_gist
567WHERE
568    ir @> 10;
569
570SELECT
571    count(*)
572FROM
573    test_range_gist
574WHERE
575    ir @> int4range(10, 20);
576
577SELECT
578    count(*)
579FROM
580    test_range_gist
581WHERE
582    ir && int4range(10, 20);
583
584SELECT
585    count(*)
586FROM
587    test_range_gist
588WHERE
589    ir <@ int4range(10, 50);
590
591SELECT
592    count(*)
593FROM
594    test_range_gist
595WHERE
596    ir << int4range(100, 500);
597
598SELECT
599    count(*)
600FROM
601    test_range_gist
602WHERE
603    ir >> int4range(100, 500);
604
605SELECT
606    count(*)
607FROM
608    test_range_gist
609WHERE
610    ir &< int4range(100, 500);
611
612SELECT
613    count(*)
614FROM
615    test_range_gist
616WHERE
617    ir &> int4range(100, 500);
618
619SELECT
620    count(*)
621FROM
622    test_range_gist
623WHERE
624    ir -|- int4range(100, 500);
625
626-- now check same queries using index
627SET enable_seqscan = f;
628
629SET enable_indexscan = t;
630
631SET enable_bitmapscan = f;
632
633SELECT
634    count(*)
635FROM
636    test_range_gist
637WHERE
638    ir @> 'empty'::int4range;
639
640SELECT
641    count(*)
642FROM
643    test_range_gist
644WHERE
645    ir = int4range(10, 20);
646
647SELECT
648    count(*)
649FROM
650    test_range_gist
651WHERE
652    ir @> 10;
653
654SELECT
655    count(*)
656FROM
657    test_range_gist
658WHERE
659    ir @> int4range(10, 20);
660
661SELECT
662    count(*)
663FROM
664    test_range_gist
665WHERE
666    ir && int4range(10, 20);
667
668SELECT
669    count(*)
670FROM
671    test_range_gist
672WHERE
673    ir <@ int4range(10, 50);
674
675SELECT
676    count(*)
677FROM
678    test_range_gist
679WHERE
680    ir << int4range(100, 500);
681
682SELECT
683    count(*)
684FROM
685    test_range_gist
686WHERE
687    ir >> int4range(100, 500);
688
689SELECT
690    count(*)
691FROM
692    test_range_gist
693WHERE
694    ir &< int4range(100, 500);
695
696SELECT
697    count(*)
698FROM
699    test_range_gist
700WHERE
701    ir &> int4range(100, 500);
702
703SELECT
704    count(*)
705FROM
706    test_range_gist
707WHERE
708    ir -|- int4range(100, 500);
709
710-- now check same queries using a bulk-loaded index
711DROP INDEX test_range_gist_idx;
712
713CREATE INDEX test_range_gist_idx ON test_range_gist USING gist (ir);
714
715SELECT
716    count(*)
717FROM
718    test_range_gist
719WHERE
720    ir @> 'empty'::int4range;
721
722SELECT
723    count(*)
724FROM
725    test_range_gist
726WHERE
727    ir = int4range(10, 20);
728
729SELECT
730    count(*)
731FROM
732    test_range_gist
733WHERE
734    ir @> 10;
735
736SELECT
737    count(*)
738FROM
739    test_range_gist
740WHERE
741    ir @> int4range(10, 20);
742
743SELECT
744    count(*)
745FROM
746    test_range_gist
747WHERE
748    ir && int4range(10, 20);
749
750SELECT
751    count(*)
752FROM
753    test_range_gist
754WHERE
755    ir <@ int4range(10, 50);
756
757SELECT
758    count(*)
759FROM
760    test_range_gist
761WHERE
762    ir << int4range(100, 500);
763
764SELECT
765    count(*)
766FROM
767    test_range_gist
768WHERE
769    ir >> int4range(100, 500);
770
771SELECT
772    count(*)
773FROM
774    test_range_gist
775WHERE
776    ir &< int4range(100, 500);
777
778SELECT
779    count(*)
780FROM
781    test_range_gist
782WHERE
783    ir &> int4range(100, 500);
784
785SELECT
786    count(*)
787FROM
788    test_range_gist
789WHERE
790    ir -|- int4range(100, 500);
791
792-- test SP-GiST index that's been built incrementally
793CREATE TABLE test_range_spgist (
794    ir int4range
795);
796
797CREATE INDEX test_range_spgist_idx ON test_range_spgist USING spgist (ir);
798
799INSERT INTO test_range_spgist
800SELECT
801    int4range(g, g + 10)
802FROM
803    generate_series(1, 2000) g;
804
805INSERT INTO test_range_spgist
806SELECT
807    'empty'::int4range
808FROM
809    generate_series(1, 500) g;
810
811INSERT INTO test_range_spgist
812SELECT
813    int4range(g, g + 10000)
814FROM
815    generate_series(1, 1000) g;
816
817INSERT INTO test_range_spgist
818SELECT
819    'empty'::int4range
820FROM
821    generate_series(1, 500) g;
822
823INSERT INTO test_range_spgist
824SELECT
825    int4range(NULL, g * 10, '(]')
826FROM
827    generate_series(1, 100) g;
828
829INSERT INTO test_range_spgist
830SELECT
831    int4range(g * 10, NULL, '(]')
832FROM
833    generate_series(1, 100) g;
834
835INSERT INTO test_range_spgist
836SELECT
837    int4range(g, g + 10)
838FROM
839    generate_series(1, 2000) g;
840
841-- first, verify non-indexed results
842SET enable_seqscan = t;
843
844SET enable_indexscan = f;
845
846SET enable_bitmapscan = f;
847
848SELECT
849    count(*)
850FROM
851    test_range_spgist
852WHERE
853    ir @> 'empty'::int4range;
854
855SELECT
856    count(*)
857FROM
858    test_range_spgist
859WHERE
860    ir = int4range(10, 20);
861
862SELECT
863    count(*)
864FROM
865    test_range_spgist
866WHERE
867    ir @> 10;
868
869SELECT
870    count(*)
871FROM
872    test_range_spgist
873WHERE
874    ir @> int4range(10, 20);
875
876SELECT
877    count(*)
878FROM
879    test_range_spgist
880WHERE
881    ir && int4range(10, 20);
882
883SELECT
884    count(*)
885FROM
886    test_range_spgist
887WHERE
888    ir <@ int4range(10, 50);
889
890SELECT
891    count(*)
892FROM
893    test_range_spgist
894WHERE
895    ir << int4range(100, 500);
896
897SELECT
898    count(*)
899FROM
900    test_range_spgist
901WHERE
902    ir >> int4range(100, 500);
903
904SELECT
905    count(*)
906FROM
907    test_range_spgist
908WHERE
909    ir &< int4range(100, 500);
910
911SELECT
912    count(*)
913FROM
914    test_range_spgist
915WHERE
916    ir &> int4range(100, 500);
917
918SELECT
919    count(*)
920FROM
921    test_range_spgist
922WHERE
923    ir -|- int4range(100, 500);
924
925-- now check same queries using index
926SET enable_seqscan = f;
927
928SET enable_indexscan = t;
929
930SET enable_bitmapscan = f;
931
932SELECT
933    count(*)
934FROM
935    test_range_spgist
936WHERE
937    ir @> 'empty'::int4range;
938
939SELECT
940    count(*)
941FROM
942    test_range_spgist
943WHERE
944    ir = int4range(10, 20);
945
946SELECT
947    count(*)
948FROM
949    test_range_spgist
950WHERE
951    ir @> 10;
952
953SELECT
954    count(*)
955FROM
956    test_range_spgist
957WHERE
958    ir @> int4range(10, 20);
959
960SELECT
961    count(*)
962FROM
963    test_range_spgist
964WHERE
965    ir && int4range(10, 20);
966
967SELECT
968    count(*)
969FROM
970    test_range_spgist
971WHERE
972    ir <@ int4range(10, 50);
973
974SELECT
975    count(*)
976FROM
977    test_range_spgist
978WHERE
979    ir << int4range(100, 500);
980
981SELECT
982    count(*)
983FROM
984    test_range_spgist
985WHERE
986    ir >> int4range(100, 500);
987
988SELECT
989    count(*)
990FROM
991    test_range_spgist
992WHERE
993    ir &< int4range(100, 500);
994
995SELECT
996    count(*)
997FROM
998    test_range_spgist
999WHERE
1000    ir &> int4range(100, 500);
1001
1002SELECT
1003    count(*)
1004FROM
1005    test_range_spgist
1006WHERE
1007    ir -|- int4range(100, 500);
1008
1009-- now check same queries using a bulk-loaded index
1010DROP INDEX test_range_spgist_idx;
1011
1012CREATE INDEX test_range_spgist_idx ON test_range_spgist USING spgist (ir);
1013
1014SELECT
1015    count(*)
1016FROM
1017    test_range_spgist
1018WHERE
1019    ir @> 'empty'::int4range;
1020
1021SELECT
1022    count(*)
1023FROM
1024    test_range_spgist
1025WHERE
1026    ir = int4range(10, 20);
1027
1028SELECT
1029    count(*)
1030FROM
1031    test_range_spgist
1032WHERE
1033    ir @> 10;
1034
1035SELECT
1036    count(*)
1037FROM
1038    test_range_spgist
1039WHERE
1040    ir @> int4range(10, 20);
1041
1042SELECT
1043    count(*)
1044FROM
1045    test_range_spgist
1046WHERE
1047    ir && int4range(10, 20);
1048
1049SELECT
1050    count(*)
1051FROM
1052    test_range_spgist
1053WHERE
1054    ir <@ int4range(10, 50);
1055
1056SELECT
1057    count(*)
1058FROM
1059    test_range_spgist
1060WHERE
1061    ir << int4range(100, 500);
1062
1063SELECT
1064    count(*)
1065FROM
1066    test_range_spgist
1067WHERE
1068    ir >> int4range(100, 500);
1069
1070SELECT
1071    count(*)
1072FROM
1073    test_range_spgist
1074WHERE
1075    ir &< int4range(100, 500);
1076
1077SELECT
1078    count(*)
1079FROM
1080    test_range_spgist
1081WHERE
1082    ir &> int4range(100, 500);
1083
1084SELECT
1085    count(*)
1086FROM
1087    test_range_spgist
1088WHERE
1089    ir -|- int4range(100, 500);
1090
1091-- test index-only scans
1092EXPLAIN (
1093    COSTS OFF
1094)
1095SELECT
1096    ir
1097FROM
1098    test_range_spgist
1099WHERE
1100    ir -|- int4range(10, 20)
1101ORDER BY
1102    ir;
1103
1104SELECT
1105    ir
1106FROM
1107    test_range_spgist
1108WHERE
1109    ir -|- int4range(10, 20)
1110ORDER BY
1111    ir;
1112
1113RESET enable_seqscan;
1114
1115RESET enable_indexscan;
1116
1117RESET enable_bitmapscan;
1118
1119-- test elem <@ range operator
1120CREATE TABLE test_range_elem (
1121    i int4
1122);
1123
1124CREATE INDEX test_range_elem_idx ON test_range_elem (i);
1125
1126INSERT INTO test_range_elem
1127SELECT
1128    i
1129FROM
1130    generate_series(1, 100) i;
1131
1132SELECT
1133    count(*)
1134FROM
1135    test_range_elem
1136WHERE
1137    i <@ int4range(10, 50);
1138
1139DROP TABLE test_range_elem;
1140
1141--
1142-- Btree_gist is not included by default, so to test exclusion
1143-- constraints with range types, use singleton int ranges for the "="
1144-- portion of the constraint.
1145--
1146CREATE TABLE test_range_excl (
1147    room int4range,
1148    speaker int4range,
1149    during tsrange,
1150    EXCLUDE USING gist (room WITH =, during WITH &&),
1151    EXCLUDE USING gist (speaker WITH =, during WITH &&)
1152);
1153
1154INSERT INTO test_range_excl
1155    VALUES (int4range(123, 123, '[]'), int4range(1, 1, '[]'), '[2010-01-02 10:00, 2010-01-02 11:00)');
1156
1157INSERT INTO test_range_excl
1158    VALUES (int4range(123, 123, '[]'), int4range(2, 2, '[]'), '[2010-01-02 11:00, 2010-01-02 12:00)');
1159
1160INSERT INTO test_range_excl
1161    VALUES (int4range(123, 123, '[]'), int4range(3, 3, '[]'), '[2010-01-02 10:10, 2010-01-02 11:00)');
1162
1163INSERT INTO test_range_excl
1164    VALUES (int4range(124, 124, '[]'), int4range(3, 3, '[]'), '[2010-01-02 10:10, 2010-01-02 11:10)');
1165
1166INSERT INTO test_range_excl
1167    VALUES (int4range(125, 125, '[]'), int4range(1, 1, '[]'), '[2010-01-02 10:10, 2010-01-02 11:00)');
1168
1169-- test bigint ranges
1170SELECT
1171    int8range(10000000000::int8, 20000000000::int8, '(]');
1172
1173-- test tstz ranges
1174SET timezone TO '-08';
1175
1176SELECT
1177    '[2010-01-01 01:00:00 -05, 2010-01-01 02:00:00 -08)'::tstzrange;
1178
1179-- should fail
1180SELECT
1181    '[2010-01-01 01:00:00 -08, 2010-01-01 02:00:00 -05)'::tstzrange;
1182
1183SET timezone TO DEFAULT;
1184
1185--
1186-- Test user-defined range of floats
1187--
1188--should fail
1189CREATE TYPE float8range AS RANGE (
1190    subtype = float8,
1191    subtype_diff = float4mi
1192);
1193
1194--should succeed
1195CREATE TYPE float8range AS RANGE (
1196    subtype = float8,
1197    subtype_diff = float8mi
1198);
1199
1200SELECT
1201    '[123.001, 5.e9)'::float8range @> 888.882::float8;
1202
1203CREATE TABLE float8range_test (
1204    f8r float8range,
1205    i int
1206);
1207
1208INSERT INTO float8range_test
1209    VALUES (float8range (-100.00007, '1.111113e9'), 42);
1210
1211SELECT
1212    *
1213FROM
1214    float8range_test;
1215
1216DROP TABLE float8range_test;
1217
1218--
1219-- Test range types over domains
1220--
1221CREATE DOMAIN mydomain AS int4;
1222
1223CREATE TYPE mydomainrange AS RANGE (
1224    subtype = mydomain
1225);
1226
1227SELECT
1228    '[4,50)'::mydomainrange @> 7::mydomain;
1229
1230DROP DOMAIN mydomain;
1231
1232-- fail
1233DROP DOMAIN mydomain CASCADE;
1234
1235--
1236-- Test domains over range types
1237--
1238CREATE DOMAIN restrictedrange AS int4range CHECK (upper(value) < 10);
1239
1240SELECT
1241    '[4,5)'::restrictedrange @> 7;
1242
1243SELECT
1244    '[4,50)'::restrictedrange @> 7;
1245
1246-- should fail
1247DROP DOMAIN restrictedrange;
1248
1249--
1250-- Test multiple range types over the same subtype
1251--
1252CREATE TYPE textrange1 AS RANGE (
1253    subtype = text,
1254    COLLATION = "C"
1255);
1256
1257CREATE TYPE textrange2 AS RANGE (
1258    subtype = text,
1259    COLLATION = "C"
1260);
1261
1262SELECT
1263    textrange1 ('a', 'Z') @> 'b'::text;
1264
1265SELECT
1266    textrange2 ('a', 'z') @> 'b'::text;
1267
1268DROP TYPE textrange1;
1269
1270DROP TYPE textrange2;
1271
1272--
1273-- Test polymorphic type system
1274--
1275CREATE FUNCTION anyarray_anyrange_func (a anyarray, r anyrange)
1276    RETURNS anyelement
1277    AS 'select $1[1] + lower($2);'
1278    LANGUAGE sql;
1279
1280SELECT
1281    anyarray_anyrange_func (ARRAY[1, 2], int4range(10, 20));
1282
1283-- should fail
1284SELECT
1285    anyarray_anyrange_func (ARRAY[1, 2], numrange(10, 20));
1286
1287DROP FUNCTION anyarray_anyrange_func (anyarray, anyrange);
1288
1289-- should fail
1290CREATE FUNCTION bogus_func (anyelement)
1291    RETURNS anyrange
1292    AS 'select int4range(1,10)'
1293    LANGUAGE sql;
1294
1295-- should fail
1296CREATE FUNCTION bogus_func (int)
1297    RETURNS anyrange
1298    AS 'select int4range(1,10)'
1299    LANGUAGE sql;
1300
1301CREATE FUNCTION range_add_bounds (anyrange)
1302    RETURNS anyelement
1303    AS 'select lower($1) + upper($1)'
1304    LANGUAGE sql;
1305
1306SELECT
1307    range_add_bounds (int4range(1, 17));
1308
1309SELECT
1310    range_add_bounds (numrange(1.0001, 123.123));
1311
1312CREATE FUNCTION rangetypes_sql (q anyrange, b anyarray, out c anyelement)
1313AS $$
1314    SELECT
1315        upper($1) + $2[1]
1316$$
1317LANGUAGE sql;
1318
1319SELECT
1320    rangetypes_sql (int4range(1, 10), ARRAY[2, 20]);
1321
1322SELECT
1323    rangetypes_sql (numrange(1, 10), ARRAY[2, 20]);
1324
1325-- match failure
1326--
1327-- Arrays of ranges
1328--
1329SELECT
1330    ARRAY[numrange(1.1, 1.2), numrange(12.3, 155.5)];
1331
1332CREATE TABLE i8r_array (
1333    f1 int,
1334    f2 int8range[]
1335);
1336
1337INSERT INTO i8r_array
1338    VALUES (42, ARRAY[int8range(1, 10), int8range(2, 20)]);
1339
1340SELECT
1341    *
1342FROM
1343    i8r_array;
1344
1345DROP TABLE i8r_array;
1346
1347--
1348-- Ranges of arrays
1349--
1350CREATE TYPE arrayrange AS RANGE (
1351    subtype = int4[]
1352);
1353
1354SELECT
1355    arrayrange (ARRAY[1, 2], ARRAY[2, 1]);
1356
1357SELECT
1358    arrayrange (ARRAY[2, 1], ARRAY[1, 2]);
1359
1360-- fail
1361SELECT
1362    ARRAY[1, 1] <@ arrayrange (ARRAY[1, 2], ARRAY[2, 1]);
1363
1364SELECT
1365    ARRAY[1, 3] <@ arrayrange (ARRAY[1, 2], ARRAY[2, 1]);
1366
1367--
1368-- Ranges of composites
1369--
1370CREATE TYPE two_ints AS (
1371    a int,
1372    b int
1373);
1374
1375CREATE TYPE two_ints_range AS RANGE (
1376    subtype = two_ints
1377);
1378
1379-- with force_parallel_mode on, this exercises tqueue.c's range remapping
1380SELECT
1381    *,
1382    row_to_json(upper(t)) AS u
1383FROM (
1384    VALUES (two_ints_range (ROW (1, 2), ROW (3, 4))),
1385        (two_ints_range (ROW (5, 6), ROW (7, 8)))) v (t);
1386
1387DROP TYPE two_ints CASCADE;
1388
1389--
1390-- Check behavior when subtype lacks a hash function
1391--
1392CREATE TYPE cashrange AS RANGE (
1393    subtype = money
1394);
1395
1396SET enable_sort = OFF;
1397
1398-- try to make it pick a hash setop implementation
1399SELECT
1400    '(2,5)'::cashrange
1401EXCEPT
1402SELECT
1403    '(5,6)'::cashrange;
1404
1405RESET enable_sort;
1406
1407--
1408-- OUT/INOUT/TABLE functions
1409--
1410CREATE FUNCTION outparam_succeed (i anyrange, out r anyrange, out t text)
1411AS $$
1412    SELECT
1413        $1,
1414        'foo'::text
1415$$
1416LANGUAGE sql;
1417
1418SELECT
1419    *
1420FROM
1421    outparam_succeed (int4range(1, 2));
1422
1423CREATE FUNCTION inoutparam_succeed (out i anyelement, INOUT r anyrange)
1424AS $$
1425    SELECT
1426        upper($1),
1427        $1
1428$$
1429LANGUAGE sql;
1430
1431SELECT
1432    *
1433FROM
1434    inoutparam_succeed (int4range(1, 2));
1435
1436CREATE FUNCTION table_succeed (i anyelement, r anyrange)
1437    RETURNS TABLE (
1438        i anyelement,
1439        r anyrange
1440    )
1441    AS $$
1442    SELECT
1443        $1,
1444        $2
1445$$
1446LANGUAGE sql;
1447
1448SELECT
1449    *
1450FROM
1451    table_succeed (123, int4range(1, 11));
1452
1453-- should fail
1454CREATE FUNCTION outparam_fail (i anyelement, out r anyrange, out t text)
1455AS $$
1456    SELECT
1457        '[1,10]',
1458        'foo'
1459$$
1460LANGUAGE sql;
1461
1462--should fail
1463CREATE FUNCTION inoutparam_fail (INOUT i anyelement, out r anyrange)
1464AS $$
1465    SELECT
1466        $1,
1467        '[1,10]'
1468$$
1469LANGUAGE sql;
1470
1471--should fail
1472CREATE FUNCTION table_fail (i anyelement)
1473    RETURNS TABLE (
1474        i anyelement,
1475        r anyrange
1476    )
1477    AS $$
1478    SELECT
1479        $1,
1480        '[1,10]'
1481$$
1482LANGUAGE sql;
1483
1484