Fixes for multirange selectivity estimation
authorAlexander Korotkov <akorotkov@postgresql.org>
Tue, 29 Jun 2021 20:18:09 +0000 (23:18 +0300)
committerAlexander Korotkov <akorotkov@postgresql.org>
Tue, 29 Jun 2021 20:18:22 +0000 (23:18 +0300)
 * Fix enumeration of the multirange operators in calc_multirangesel() and
   calc_multirangesel() switches.
 * Add more regression tests for matching to empty ranges/multiranges.

Reported-by: Alexander Lakhin
Discussion: https://postgr.es/m/c5269c65-f967-77c5-ff7c-15e621c47f6a%40gmail.com
Author: Alexander Korotkov
Backpatch-through: 14, where multiranges were introduced

src/backend/utils/adt/multirangetypes_selfuncs.c
src/test/regress/expected/multirangetypes.out
src/test/regress/sql/multirangetypes.sql

index 551176bc21377731d5cc8a3bc52c0a6b9f608be2..191cc1f002f106d43c3897c7a9645b0be391b138 100644 (file)
@@ -347,16 +347,15 @@ calc_multirangesel(TypeCacheEntry *typcache, VariableStatData *vardata,
        switch (operator)
        {
                /* these return false if either argument is empty */
-           case OID_RANGE_OVERLAPS_MULTIRANGE_OP:
            case OID_MULTIRANGE_OVERLAPS_RANGE_OP:
            case OID_MULTIRANGE_OVERLAPS_MULTIRANGE_OP:
-           case OID_RANGE_OVERLAPS_LEFT_MULTIRANGE_OP:
            case OID_MULTIRANGE_OVERLAPS_LEFT_RANGE_OP:
            case OID_MULTIRANGE_OVERLAPS_LEFT_MULTIRANGE_OP:
-           case OID_RANGE_OVERLAPS_RIGHT_MULTIRANGE_OP:
            case OID_MULTIRANGE_OVERLAPS_RIGHT_RANGE_OP:
            case OID_MULTIRANGE_OVERLAPS_RIGHT_MULTIRANGE_OP:
+           case OID_MULTIRANGE_LEFT_RANGE_OP:
            case OID_MULTIRANGE_LEFT_MULTIRANGE_OP:
+           case OID_MULTIRANGE_RIGHT_RANGE_OP:
            case OID_MULTIRANGE_RIGHT_MULTIRANGE_OP:
                /* nothing is less than an empty multirange */
            case OID_MULTIRANGE_LESS_OP:
@@ -367,7 +366,7 @@ calc_multirangesel(TypeCacheEntry *typcache, VariableStatData *vardata,
                 * only empty multiranges can be contained by an empty
                 * multirange
                 */
-           case OID_MULTIRANGE_RANGE_CONTAINED_OP:
+           case OID_RANGE_MULTIRANGE_CONTAINED_OP:
            case OID_MULTIRANGE_MULTIRANGE_CONTAINED_OP:
                /* only empty ranges are <= an empty multirange */
            case OID_MULTIRANGE_LESS_EQUAL_OP:
@@ -388,8 +387,18 @@ calc_multirangesel(TypeCacheEntry *typcache, VariableStatData *vardata,
                break;
 
                /* an element cannot be empty */
-           case OID_MULTIRANGE_ELEM_CONTAINED_OP:
            case OID_MULTIRANGE_CONTAINS_ELEM_OP:
+
+               /* filtered out by multirangesel() */
+           case OID_RANGE_OVERLAPS_MULTIRANGE_OP:
+           case OID_RANGE_OVERLAPS_LEFT_MULTIRANGE_OP:
+           case OID_RANGE_OVERLAPS_RIGHT_MULTIRANGE_OP:
+           case OID_RANGE_LEFT_MULTIRANGE_OP:
+           case OID_RANGE_RIGHT_MULTIRANGE_OP:
+           case OID_RANGE_CONTAINS_MULTIRANGE_OP:
+           case OID_MULTIRANGE_ELEM_CONTAINED_OP:
+           case OID_MULTIRANGE_RANGE_CONTAINED_OP:
+
            default:
                elog(ERROR, "unexpected operator %u", operator);
                selec = 0.0;    /* keep compiler quiet */
@@ -416,8 +425,7 @@ calc_multirangesel(TypeCacheEntry *typcache, VariableStatData *vardata,
         * calculations, realizing that the histogram covers only the
         * non-null, non-empty values.
         */
-       if (operator == OID_MULTIRANGE_ELEM_CONTAINED_OP ||
-           operator == OID_MULTIRANGE_RANGE_CONTAINED_OP ||
+       if (operator == OID_RANGE_MULTIRANGE_CONTAINED_OP ||
            operator == OID_MULTIRANGE_MULTIRANGE_CONTAINED_OP)
        {
            /* empty is contained by anything non-empty */
@@ -575,7 +583,6 @@ calc_hist_selectivity(TypeCacheEntry *typcache, VariableStatData *vardata,
                                                 hist_lower, nhist, true);
            break;
 
-       case OID_RANGE_LEFT_MULTIRANGE_OP:
        case OID_MULTIRANGE_LEFT_RANGE_OP:
        case OID_MULTIRANGE_LEFT_MULTIRANGE_OP:
            /* var << const when upper(var) < lower(const) */
@@ -584,7 +591,6 @@ calc_hist_selectivity(TypeCacheEntry *typcache, VariableStatData *vardata,
                                             hist_upper, nhist, false);
            break;
 
-       case OID_RANGE_RIGHT_MULTIRANGE_OP:
        case OID_MULTIRANGE_RIGHT_RANGE_OP:
        case OID_MULTIRANGE_RIGHT_MULTIRANGE_OP:
            /* var >> const when lower(var) > upper(const) */
@@ -593,7 +599,6 @@ calc_hist_selectivity(TypeCacheEntry *typcache, VariableStatData *vardata,
                                                 hist_lower, nhist, true);
            break;
 
-       case OID_RANGE_OVERLAPS_RIGHT_MULTIRANGE_OP:
        case OID_MULTIRANGE_OVERLAPS_RIGHT_RANGE_OP:
        case OID_MULTIRANGE_OVERLAPS_RIGHT_MULTIRANGE_OP:
            /* compare lower bounds */
@@ -602,7 +607,6 @@ calc_hist_selectivity(TypeCacheEntry *typcache, VariableStatData *vardata,
                                                 hist_lower, nhist, false);
            break;
 
-       case OID_RANGE_OVERLAPS_LEFT_MULTIRANGE_OP:
        case OID_MULTIRANGE_OVERLAPS_LEFT_RANGE_OP:
        case OID_MULTIRANGE_OVERLAPS_LEFT_MULTIRANGE_OP:
            /* compare upper bounds */
@@ -611,7 +615,6 @@ calc_hist_selectivity(TypeCacheEntry *typcache, VariableStatData *vardata,
                                             hist_upper, nhist, true);
            break;
 
-       case OID_RANGE_OVERLAPS_MULTIRANGE_OP:
        case OID_MULTIRANGE_OVERLAPS_RANGE_OP:
        case OID_MULTIRANGE_OVERLAPS_MULTIRANGE_OP:
        case OID_MULTIRANGE_CONTAINS_ELEM_OP:
@@ -647,7 +650,6 @@ calc_hist_selectivity(TypeCacheEntry *typcache, VariableStatData *vardata,
                                               lslot.values, lslot.nvalues);
            break;
 
-       case OID_MULTIRANGE_RANGE_CONTAINED_OP:
        case OID_MULTIRANGE_MULTIRANGE_CONTAINED_OP:
        case OID_RANGE_MULTIRANGE_CONTAINED_OP:
            if (const_lower.infinite)
@@ -675,6 +677,16 @@ calc_hist_selectivity(TypeCacheEntry *typcache, VariableStatData *vardata,
            }
            break;
 
+           /* filtered out by multirangesel() */
+       case OID_RANGE_OVERLAPS_MULTIRANGE_OP:
+       case OID_RANGE_OVERLAPS_LEFT_MULTIRANGE_OP:
+       case OID_RANGE_OVERLAPS_RIGHT_MULTIRANGE_OP:
+       case OID_RANGE_LEFT_MULTIRANGE_OP:
+       case OID_RANGE_RIGHT_MULTIRANGE_OP:
+       case OID_RANGE_CONTAINS_MULTIRANGE_OP:
+       case OID_MULTIRANGE_ELEM_CONTAINED_OP:
+       case OID_MULTIRANGE_RANGE_CONTAINED_OP:
+
        default:
            elog(ERROR, "unknown multirange operator %u", operator);
            hist_selec = -1.0;  /* keep compiler quiet */
index 3e941aec68c46289e430e6337c842d193b4eba1b..af3ef4a258cd731b32ae6630379da0cc557b4bb7 100644 (file)
@@ -2241,12 +2241,114 @@ analyze test_multirange_gist;
 SET enable_seqscan    = t;
 SET enable_indexscan  = f;
 SET enable_bitmapscan = f;
+select count(*) from test_multirange_gist where mr = '{}'::int4multirange;
+ count 
+-------
+   500
+(1 row)
+
 select count(*) from test_multirange_gist where mr @> 'empty'::int4range;
  count 
 -------
   3700
 (1 row)
 
+select count(*) from test_multirange_gist where mr && 'empty'::int4range;
+ count 
+-------
+     0
+(1 row)
+
+select count(*) from test_multirange_gist where mr <@ 'empty'::int4range;
+ count 
+-------
+   500
+(1 row)
+
+select count(*) from test_multirange_gist where mr << 'empty'::int4range;
+ count 
+-------
+     0
+(1 row)
+
+select count(*) from test_multirange_gist where mr >> 'empty'::int4range;
+ count 
+-------
+     0
+(1 row)
+
+select count(*) from test_multirange_gist where mr &< 'empty'::int4range;
+ count 
+-------
+     0
+(1 row)
+
+select count(*) from test_multirange_gist where mr &> 'empty'::int4range;
+ count 
+-------
+     0
+(1 row)
+
+select count(*) from test_multirange_gist where mr -|- 'empty'::int4range;
+ count 
+-------
+     0
+(1 row)
+
+select count(*) from test_multirange_gist where mr @> '{}'::int4multirange;
+ count 
+-------
+  3700
+(1 row)
+
+select count(*) from test_multirange_gist where mr @> '{}'::int4multirange;
+ count 
+-------
+  3700
+(1 row)
+
+select count(*) from test_multirange_gist where mr && '{}'::int4multirange;
+ count 
+-------
+     0
+(1 row)
+
+select count(*) from test_multirange_gist where mr <@ '{}'::int4multirange;
+ count 
+-------
+   500
+(1 row)
+
+select count(*) from test_multirange_gist where mr << '{}'::int4multirange;
+ count 
+-------
+     0
+(1 row)
+
+select count(*) from test_multirange_gist where mr >> '{}'::int4multirange;
+ count 
+-------
+     0
+(1 row)
+
+select count(*) from test_multirange_gist where mr &< '{}'::int4multirange;
+ count 
+-------
+     0
+(1 row)
+
+select count(*) from test_multirange_gist where mr &> '{}'::int4multirange;
+ count 
+-------
+     0
+(1 row)
+
+select count(*) from test_multirange_gist where mr -|- '{}'::int4multirange;
+ count 
+-------
+     0
+(1 row)
+
 select count(*) from test_multirange_gist where mr = int4multirange(int4range(10,20), int4range(30,40), int4range(50,60));
  count 
 -------
@@ -2365,6 +2467,114 @@ select count(*) from test_multirange_gist where mr -|- int4multirange(int4range(
 SET enable_seqscan    = f;
 SET enable_indexscan  = t;
 SET enable_bitmapscan = f;
+select count(*) from test_multirange_gist where mr = '{}'::int4multirange;
+ count 
+-------
+   500
+(1 row)
+
+select count(*) from test_multirange_gist where mr @> 'empty'::int4range;
+ count 
+-------
+  3700
+(1 row)
+
+select count(*) from test_multirange_gist where mr && 'empty'::int4range;
+ count 
+-------
+     0
+(1 row)
+
+select count(*) from test_multirange_gist where mr <@ 'empty'::int4range;
+ count 
+-------
+   500
+(1 row)
+
+select count(*) from test_multirange_gist where mr << 'empty'::int4range;
+ count 
+-------
+     0
+(1 row)
+
+select count(*) from test_multirange_gist where mr >> 'empty'::int4range;
+ count 
+-------
+     0
+(1 row)
+
+select count(*) from test_multirange_gist where mr &< 'empty'::int4range;
+ count 
+-------
+     0
+(1 row)
+
+select count(*) from test_multirange_gist where mr &> 'empty'::int4range;
+ count 
+-------
+     0
+(1 row)
+
+select count(*) from test_multirange_gist where mr -|- 'empty'::int4range;
+ count 
+-------
+     0
+(1 row)
+
+select count(*) from test_multirange_gist where mr @> '{}'::int4multirange;
+ count 
+-------
+  3700
+(1 row)
+
+select count(*) from test_multirange_gist where mr @> '{}'::int4multirange;
+ count 
+-------
+  3700
+(1 row)
+
+select count(*) from test_multirange_gist where mr && '{}'::int4multirange;
+ count 
+-------
+     0
+(1 row)
+
+select count(*) from test_multirange_gist where mr <@ '{}'::int4multirange;
+ count 
+-------
+   500
+(1 row)
+
+select count(*) from test_multirange_gist where mr << '{}'::int4multirange;
+ count 
+-------
+     0
+(1 row)
+
+select count(*) from test_multirange_gist where mr >> '{}'::int4multirange;
+ count 
+-------
+     0
+(1 row)
+
+select count(*) from test_multirange_gist where mr &< '{}'::int4multirange;
+ count 
+-------
+     0
+(1 row)
+
+select count(*) from test_multirange_gist where mr &> '{}'::int4multirange;
+ count 
+-------
+     0
+(1 row)
+
+select count(*) from test_multirange_gist where mr -|- '{}'::int4multirange;
+ count 
+-------
+     0
+(1 row)
+
 select count(*) from test_multirange_gist where mr @> 'empty'::int4range;
  count 
 -------
index 3cbebedcd4a11732cd51079433ec6a6f24bfc9b7..b91a23e0d5aa7e903e501411fb1d8cb2c8ef9a7f 100644 (file)
@@ -435,7 +435,25 @@ SET enable_seqscan    = t;
 SET enable_indexscan  = f;
 SET enable_bitmapscan = f;
 
+select count(*) from test_multirange_gist where mr = '{}'::int4multirange;
 select count(*) from test_multirange_gist where mr @> 'empty'::int4range;
+select count(*) from test_multirange_gist where mr && 'empty'::int4range;
+select count(*) from test_multirange_gist where mr <@ 'empty'::int4range;
+select count(*) from test_multirange_gist where mr << 'empty'::int4range;
+select count(*) from test_multirange_gist where mr >> 'empty'::int4range;
+select count(*) from test_multirange_gist where mr &< 'empty'::int4range;
+select count(*) from test_multirange_gist where mr &> 'empty'::int4range;
+select count(*) from test_multirange_gist where mr -|- 'empty'::int4range;
+select count(*) from test_multirange_gist where mr @> '{}'::int4multirange;
+select count(*) from test_multirange_gist where mr @> '{}'::int4multirange;
+select count(*) from test_multirange_gist where mr && '{}'::int4multirange;
+select count(*) from test_multirange_gist where mr <@ '{}'::int4multirange;
+select count(*) from test_multirange_gist where mr << '{}'::int4multirange;
+select count(*) from test_multirange_gist where mr >> '{}'::int4multirange;
+select count(*) from test_multirange_gist where mr &< '{}'::int4multirange;
+select count(*) from test_multirange_gist where mr &> '{}'::int4multirange;
+select count(*) from test_multirange_gist where mr -|- '{}'::int4multirange;
+
 select count(*) from test_multirange_gist where mr = int4multirange(int4range(10,20), int4range(30,40), int4range(50,60));
 select count(*) from test_multirange_gist where mr @> 10;
 select count(*) from test_multirange_gist where mr @> int4range(10,20);
@@ -461,6 +479,25 @@ SET enable_seqscan    = f;
 SET enable_indexscan  = t;
 SET enable_bitmapscan = f;
 
+select count(*) from test_multirange_gist where mr = '{}'::int4multirange;
+select count(*) from test_multirange_gist where mr @> 'empty'::int4range;
+select count(*) from test_multirange_gist where mr && 'empty'::int4range;
+select count(*) from test_multirange_gist where mr <@ 'empty'::int4range;
+select count(*) from test_multirange_gist where mr << 'empty'::int4range;
+select count(*) from test_multirange_gist where mr >> 'empty'::int4range;
+select count(*) from test_multirange_gist where mr &< 'empty'::int4range;
+select count(*) from test_multirange_gist where mr &> 'empty'::int4range;
+select count(*) from test_multirange_gist where mr -|- 'empty'::int4range;
+select count(*) from test_multirange_gist where mr @> '{}'::int4multirange;
+select count(*) from test_multirange_gist where mr @> '{}'::int4multirange;
+select count(*) from test_multirange_gist where mr && '{}'::int4multirange;
+select count(*) from test_multirange_gist where mr <@ '{}'::int4multirange;
+select count(*) from test_multirange_gist where mr << '{}'::int4multirange;
+select count(*) from test_multirange_gist where mr >> '{}'::int4multirange;
+select count(*) from test_multirange_gist where mr &< '{}'::int4multirange;
+select count(*) from test_multirange_gist where mr &> '{}'::int4multirange;
+select count(*) from test_multirange_gist where mr -|- '{}'::int4multirange;
+
 select count(*) from test_multirange_gist where mr @> 'empty'::int4range;
 select count(*) from test_multirange_gist where mr = int4multirange(int4range(10,20), int4range(30,40), int4range(50,60));
 select count(*) from test_multirange_gist where mr @> 10;