LCOV - code coverage report
Current view: top level - src/backend/utils/adt - rangetypes_spgist.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 85.0 % 327 278
Test Date: 2026-07-22 12:15:41 Functions: 100.0 % 9 9
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 74.2 % 163 121

             Branch data     Line data    Source code
       1                 :             : /*-------------------------------------------------------------------------
       2                 :             :  *
       3                 :             :  * rangetypes_spgist.c
       4                 :             :  *    implementation of quad tree over ranges mapped to 2d-points for SP-GiST.
       5                 :             :  *
       6                 :             :  * Quad tree is a data structure similar to a binary tree, but is adapted to
       7                 :             :  * 2d data. Each inner node of a quad tree contains a point (centroid) which
       8                 :             :  * divides the 2d-space into 4 quadrants. Each quadrant is associated with a
       9                 :             :  * child node.
      10                 :             :  *
      11                 :             :  * Ranges are mapped to 2d-points so that the lower bound is one dimension,
      12                 :             :  * and the upper bound is another. By convention, we visualize the lower bound
      13                 :             :  * to be the horizontal axis, and upper bound the vertical axis.
      14                 :             :  *
      15                 :             :  * One quirk with this mapping is the handling of empty ranges. An empty range
      16                 :             :  * doesn't have lower and upper bounds, so it cannot be mapped to 2d space in
      17                 :             :  * a straightforward way. To cope with that, the root node can have a 5th
      18                 :             :  * quadrant, which is reserved for empty ranges. Furthermore, there can be
      19                 :             :  * inner nodes in the tree with no centroid. They contain only two child nodes,
      20                 :             :  * one for empty ranges and another for non-empty ones. Such a node can appear
      21                 :             :  * as the root node, or in the tree under the 5th child of the root node (in
      22                 :             :  * which case it will only contain empty nodes).
      23                 :             :  *
      24                 :             :  * The SP-GiST picksplit function uses medians along both axes as the centroid.
      25                 :             :  * This implementation only uses the comparison function of the range element
      26                 :             :  * datatype, therefore it works for any range type.
      27                 :             :  *
      28                 :             :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
      29                 :             :  * Portions Copyright (c) 1994, Regents of the University of California
      30                 :             :  *
      31                 :             :  * IDENTIFICATION
      32                 :             :  *          src/backend/utils/adt/rangetypes_spgist.c
      33                 :             :  *
      34                 :             :  *-------------------------------------------------------------------------
      35                 :             :  */
      36                 :             : 
      37                 :             : #include "postgres.h"
      38                 :             : 
      39                 :             : #include "access/spgist.h"
      40                 :             : #include "access/stratnum.h"
      41                 :             : #include "catalog/pg_type.h"
      42                 :             : #include "utils/datum.h"
      43                 :             : #include "utils/fmgrprotos.h"
      44                 :             : #include "utils/rangetypes.h"
      45                 :             : 
      46                 :             : static int16 getQuadrant(TypeCacheEntry *typcache, const RangeType *centroid,
      47                 :             :                          const RangeType *tst);
      48                 :             : static int  bound_cmp(const void *a, const void *b, void *arg);
      49                 :             : 
      50                 :             : static int  adjacent_inner_consistent(TypeCacheEntry *typcache,
      51                 :             :                                       const RangeBound *arg, const RangeBound *centroid,
      52                 :             :                                       const RangeBound *prev);
      53                 :             : static int  adjacent_cmp_bounds(TypeCacheEntry *typcache, const RangeBound *arg,
      54                 :             :                                 const RangeBound *centroid);
      55                 :             : 
      56                 :             : /*
      57                 :             :  * SP-GiST 'config' interface function.
      58                 :             :  */
      59                 :             : Datum
      60                 :          63 : spg_range_quad_config(PG_FUNCTION_ARGS)
      61                 :             : {
      62                 :             : #ifdef NOT_USED
      63                 :             :     spgConfigIn *cfgin = (spgConfigIn *) PG_GETARG_POINTER(0);
      64                 :             : #endif
      65                 :          63 :     spgConfigOut *cfg = (spgConfigOut *) PG_GETARG_POINTER(1);
      66                 :             : 
      67                 :          63 :     cfg->prefixType = ANYRANGEOID;
      68                 :          63 :     cfg->labelType = VOIDOID;    /* we don't need node labels */
      69                 :          63 :     cfg->canReturnData = true;
      70                 :          63 :     cfg->longValuesOK = false;
      71                 :          63 :     PG_RETURN_VOID();
      72                 :             : }
      73                 :             : 
      74                 :             : /*----------
      75                 :             :  * Determine which quadrant a 2d-mapped range falls into, relative to the
      76                 :             :  * centroid.
      77                 :             :  *
      78                 :             :  * Quadrants are numbered like this:
      79                 :             :  *
      80                 :             :  *   4  |  1
      81                 :             :  *  ----+----
      82                 :             :  *   3  |  2
      83                 :             :  *
      84                 :             :  * Where the lower bound of range is the horizontal axis and upper bound the
      85                 :             :  * vertical axis.
      86                 :             :  *
      87                 :             :  * Ranges on one of the axes are taken to lie in the quadrant with higher value
      88                 :             :  * along perpendicular axis. That is, a value on the horizontal axis is taken
      89                 :             :  * to belong to quadrant 1 or 4, and a value on the vertical axis is taken to
      90                 :             :  * belong to quadrant 1 or 2. A range equal to centroid is taken to lie in
      91                 :             :  * quadrant 1.
      92                 :             :  *
      93                 :             :  * Empty ranges are taken to lie in the special quadrant 5.
      94                 :             :  *----------
      95                 :             :  */
      96                 :             : static int16
      97                 :      505981 : getQuadrant(TypeCacheEntry *typcache, const RangeType *centroid, const RangeType *tst)
      98                 :             : {
      99                 :             :     RangeBound  centroidLower,
     100                 :             :                 centroidUpper;
     101                 :             :     bool        centroidEmpty;
     102                 :             :     RangeBound  lower,
     103                 :             :                 upper;
     104                 :             :     bool        empty;
     105                 :             : 
     106                 :      505981 :     range_deserialize(typcache, centroid, &centroidLower, &centroidUpper,
     107                 :             :                       &centroidEmpty);
     108                 :      505981 :     range_deserialize(typcache, tst, &lower, &upper, &empty);
     109                 :             : 
     110         [ +  + ]:      505981 :     if (empty)
     111                 :        8000 :         return 5;
     112                 :             : 
     113         [ +  + ]:      497981 :     if (range_cmp_bounds(typcache, &lower, &centroidLower) >= 0)
     114                 :             :     {
     115         [ +  + ]:      453548 :         if (range_cmp_bounds(typcache, &upper, &centroidUpper) >= 0)
     116                 :      453126 :             return 1;
     117                 :             :         else
     118                 :         422 :             return 2;
     119                 :             :     }
     120                 :             :     else
     121                 :             :     {
     122         [ +  + ]:       44433 :         if (range_cmp_bounds(typcache, &upper, &centroidUpper) >= 0)
     123                 :        9741 :             return 4;
     124                 :             :         else
     125                 :       34692 :             return 3;
     126                 :             :     }
     127                 :             : }
     128                 :             : 
     129                 :             : /*
     130                 :             :  * Choose SP-GiST function: choose path for addition of new range.
     131                 :             :  */
     132                 :             : Datum
     133                 :      476549 : spg_range_quad_choose(PG_FUNCTION_ARGS)
     134                 :             : {
     135                 :      476549 :     spgChooseIn *in = (spgChooseIn *) PG_GETARG_POINTER(0);
     136                 :      476549 :     spgChooseOut *out = (spgChooseOut *) PG_GETARG_POINTER(1);
     137                 :      476549 :     RangeType  *inRange = DatumGetRangeTypeP(in->datum),
     138                 :             :                *centroid;
     139                 :             :     int16       quadrant;
     140                 :             :     TypeCacheEntry *typcache;
     141                 :             : 
     142         [ +  + ]:      476549 :     if (in->allTheSame)
     143                 :             :     {
     144                 :        8784 :         out->resultType = spgMatchNode;
     145                 :             :         /* nodeN will be set by core */
     146                 :        8784 :         out->result.matchNode.levelAdd = 0;
     147                 :        8784 :         out->result.matchNode.restDatum = RangeTypePGetDatum(inRange);
     148                 :        8784 :         PG_RETURN_VOID();
     149                 :             :     }
     150                 :             : 
     151                 :      467765 :     typcache = range_get_typcache(fcinfo, RangeTypeGetOid(inRange));
     152                 :             : 
     153                 :             :     /*
     154                 :             :      * A node with no centroid divides ranges purely on whether they're empty
     155                 :             :      * or not. All empty ranges go to child node 0, all non-empty ranges go to
     156                 :             :      * node 1.
     157                 :             :      */
     158         [ -  + ]:      467765 :     if (!in->hasPrefix)
     159                 :             :     {
     160                 :           0 :         out->resultType = spgMatchNode;
     161         [ #  # ]:           0 :         if (RangeIsEmpty(inRange))
     162                 :           0 :             out->result.matchNode.nodeN = 0;
     163                 :             :         else
     164                 :           0 :             out->result.matchNode.nodeN = 1;
     165                 :           0 :         out->result.matchNode.levelAdd = 1;
     166                 :           0 :         out->result.matchNode.restDatum = RangeTypePGetDatum(inRange);
     167                 :           0 :         PG_RETURN_VOID();
     168                 :             :     }
     169                 :             : 
     170                 :      467765 :     centroid = DatumGetRangeTypeP(in->prefixDatum);
     171                 :      467765 :     quadrant = getQuadrant(typcache, centroid, inRange);
     172                 :             : 
     173                 :             :     Assert(quadrant <= in->nNodes);
     174                 :             : 
     175                 :             :     /* Select node matching to quadrant number */
     176                 :      467765 :     out->resultType = spgMatchNode;
     177                 :      467765 :     out->result.matchNode.nodeN = quadrant - 1;
     178                 :      467765 :     out->result.matchNode.levelAdd = 1;
     179                 :      467765 :     out->result.matchNode.restDatum = RangeTypePGetDatum(inRange);
     180                 :             : 
     181                 :      467765 :     PG_RETURN_VOID();
     182                 :             : }
     183                 :             : 
     184                 :             : /*
     185                 :             :  * Bound comparison for sorting.
     186                 :             :  */
     187                 :             : static int
     188                 :      471789 : bound_cmp(const void *a, const void *b, void *arg)
     189                 :             : {
     190                 :      471789 :     const RangeBound *ba = a;
     191                 :      471789 :     const RangeBound *bb = b;
     192                 :      471789 :     TypeCacheEntry *typcache = arg;
     193                 :             : 
     194                 :      471789 :     return range_cmp_bounds(typcache, ba, bb);
     195                 :             : }
     196                 :             : 
     197                 :             : /*
     198                 :             :  * Picksplit SP-GiST function: split ranges into nodes. Select "centroid"
     199                 :             :  * range and distribute ranges according to quadrants.
     200                 :             :  */
     201                 :             : Datum
     202                 :         326 : spg_range_quad_picksplit(PG_FUNCTION_ARGS)
     203                 :             : {
     204                 :         326 :     spgPickSplitIn *in = (spgPickSplitIn *) PG_GETARG_POINTER(0);
     205                 :         326 :     spgPickSplitOut *out = (spgPickSplitOut *) PG_GETARG_POINTER(1);
     206                 :             :     int         i;
     207                 :             :     int         j;
     208                 :             :     int         nonEmptyCount;
     209                 :             :     RangeType  *centroid;
     210                 :             :     bool        empty;
     211                 :             :     TypeCacheEntry *typcache;
     212                 :             : 
     213                 :             :     /* Use the median values of lower and upper bounds as the centroid range */
     214                 :             :     RangeBound *lowerBounds,
     215                 :             :                *upperBounds;
     216                 :             : 
     217                 :         326 :     typcache = range_get_typcache(fcinfo,
     218                 :         326 :                                   RangeTypeGetOid(DatumGetRangeTypeP(in->datums[0])));
     219                 :             : 
     220                 :             :     /* Allocate memory for bounds */
     221                 :         326 :     lowerBounds = palloc_array(RangeBound, in->nTuples);
     222                 :         326 :     upperBounds = palloc_array(RangeBound, in->nTuples);
     223                 :         326 :     j = 0;
     224                 :             : 
     225                 :             :     /* Deserialize bounds of ranges, count non-empty ranges */
     226         [ +  + ]:       43155 :     for (i = 0; i < in->nTuples; i++)
     227                 :             :     {
     228                 :       42829 :         range_deserialize(typcache, DatumGetRangeTypeP(in->datums[i]),
     229                 :       42829 :                           &lowerBounds[j], &upperBounds[j], &empty);
     230         [ +  + ]:       42829 :         if (!empty)
     231                 :       38200 :             j++;
     232                 :             :     }
     233                 :         326 :     nonEmptyCount = j;
     234                 :             : 
     235                 :             :     /*
     236                 :             :      * All the ranges are empty. The best we can do is to construct an inner
     237                 :             :      * node with no centroid, and put all ranges into node 0. If non-empty
     238                 :             :      * ranges are added later, they will be routed to node 1.
     239                 :             :      */
     240         [ +  + ]:         326 :     if (nonEmptyCount == 0)
     241                 :             :     {
     242                 :          51 :         out->nNodes = 2;
     243                 :          51 :         out->hasPrefix = false;
     244                 :             :         /* Prefix is empty */
     245                 :          51 :         out->prefixDatum = PointerGetDatum(NULL);
     246                 :          51 :         out->nodeLabels = NULL;
     247                 :             : 
     248                 :          51 :         out->mapTuplesToNodes = palloc_array(int, in->nTuples);
     249                 :          51 :         out->leafTupleDatums = palloc_array(Datum, in->nTuples);
     250                 :             : 
     251                 :             :         /* Place all ranges into node 0 */
     252         [ +  + ]:        4680 :         for (i = 0; i < in->nTuples; i++)
     253                 :             :         {
     254                 :        4629 :             RangeType  *range = DatumGetRangeTypeP(in->datums[i]);
     255                 :             : 
     256                 :        4629 :             out->leafTupleDatums[i] = RangeTypePGetDatum(range);
     257                 :        4629 :             out->mapTuplesToNodes[i] = 0;
     258                 :             :         }
     259                 :          51 :         PG_RETURN_VOID();
     260                 :             :     }
     261                 :             : 
     262                 :             :     /* Sort range bounds in order to find medians */
     263                 :         275 :     qsort_arg(lowerBounds, nonEmptyCount, sizeof(RangeBound),
     264                 :             :               bound_cmp, typcache);
     265                 :         275 :     qsort_arg(upperBounds, nonEmptyCount, sizeof(RangeBound),
     266                 :             :               bound_cmp, typcache);
     267                 :             : 
     268                 :             :     /* Construct "centroid" range from medians of lower and upper bounds */
     269                 :         275 :     centroid = range_serialize(typcache, &lowerBounds[nonEmptyCount / 2],
     270                 :         275 :                                &upperBounds[nonEmptyCount / 2], false, NULL);
     271                 :         275 :     out->hasPrefix = true;
     272                 :         275 :     out->prefixDatum = RangeTypePGetDatum(centroid);
     273                 :             : 
     274                 :             :     /* Create node for empty ranges only if it is a root node */
     275         [ +  + ]:         275 :     out->nNodes = (in->level == 0) ? 5 : 4;
     276                 :         275 :     out->nodeLabels = NULL;      /* we don't need node labels */
     277                 :             : 
     278                 :         275 :     out->mapTuplesToNodes = palloc_array(int, in->nTuples);
     279                 :         275 :     out->leafTupleDatums = palloc_array(Datum, in->nTuples);
     280                 :             : 
     281                 :             :     /*
     282                 :             :      * Assign ranges to corresponding nodes according to quadrants relative to
     283                 :             :      * "centroid" range.
     284                 :             :      */
     285         [ +  + ]:       38475 :     for (i = 0; i < in->nTuples; i++)
     286                 :             :     {
     287                 :       38200 :         RangeType  *range = DatumGetRangeTypeP(in->datums[i]);
     288                 :       38200 :         int16       quadrant = getQuadrant(typcache, centroid, range);
     289                 :             : 
     290                 :       38200 :         out->leafTupleDatums[i] = RangeTypePGetDatum(range);
     291                 :       38200 :         out->mapTuplesToNodes[i] = quadrant - 1;
     292                 :             :     }
     293                 :             : 
     294                 :         275 :     PG_RETURN_VOID();
     295                 :             : }
     296                 :             : 
     297                 :             : /*
     298                 :             :  * SP-GiST consistent function for inner nodes: check which nodes are
     299                 :             :  * consistent with given set of queries.
     300                 :             :  */
     301                 :             : Datum
     302                 :        1204 : spg_range_quad_inner_consistent(PG_FUNCTION_ARGS)
     303                 :             : {
     304                 :        1204 :     spgInnerConsistentIn *in = (spgInnerConsistentIn *) PG_GETARG_POINTER(0);
     305                 :        1204 :     spgInnerConsistentOut *out = (spgInnerConsistentOut *) PG_GETARG_POINTER(1);
     306                 :             :     int         which;
     307                 :             :     int         i;
     308                 :             :     MemoryContext oldCtx;
     309                 :             : 
     310                 :             :     /*
     311                 :             :      * For adjacent search we need also previous centroid (if any) to improve
     312                 :             :      * the precision of the consistent check. In this case needPrevious flag
     313                 :             :      * is set and centroid is passed into traversalValue.
     314                 :             :      */
     315                 :        1204 :     bool        needPrevious = false;
     316                 :             : 
     317         [ +  + ]:        1204 :     if (in->allTheSame)
     318                 :             :     {
     319                 :             :         /* Report that all nodes should be visited */
     320                 :         102 :         out->nNodes = in->nNodes;
     321                 :         102 :         out->nodeNumbers = palloc_array(int, in->nNodes);
     322         [ +  + ]:         918 :         for (i = 0; i < in->nNodes; i++)
     323                 :         816 :             out->nodeNumbers[i] = i;
     324                 :         102 :         PG_RETURN_VOID();
     325                 :             :     }
     326                 :             : 
     327         [ -  + ]:        1102 :     if (!in->hasPrefix)
     328                 :             :     {
     329                 :             :         /*
     330                 :             :          * No centroid on this inner node. Such a node has two child nodes,
     331                 :             :          * the first for empty ranges, and the second for non-empty ones.
     332                 :             :          */
     333                 :             :         Assert(in->nNodes == 2);
     334                 :             : 
     335                 :             :         /*
     336                 :             :          * Nth bit of which variable means that (N - 1)th node should be
     337                 :             :          * visited. Initially all bits are set. Bits of nodes which should be
     338                 :             :          * skipped will be unset.
     339                 :             :          */
     340                 :           0 :         which = (1 << 1) | (1 << 2);
     341         [ #  # ]:           0 :         for (i = 0; i < in->nkeys; i++)
     342                 :             :         {
     343                 :           0 :             StrategyNumber strategy = in->scankeys[i].sk_strategy;
     344                 :             :             bool        empty;
     345                 :             : 
     346                 :             :             /*
     347                 :             :              * The only strategy when second argument of operator is not range
     348                 :             :              * is RANGESTRAT_CONTAINS_ELEM.
     349                 :             :              */
     350         [ #  # ]:           0 :             if (strategy != RANGESTRAT_CONTAINS_ELEM)
     351                 :           0 :                 empty = RangeIsEmpty(DatumGetRangeTypeP(in->scankeys[i].sk_argument));
     352                 :             :             else
     353                 :           0 :                 empty = false;
     354                 :             : 
     355   [ #  #  #  #  :           0 :             switch (strategy)
                   #  # ]
     356                 :             :             {
     357                 :           0 :                 case RANGESTRAT_BEFORE:
     358                 :             :                 case RANGESTRAT_OVERLEFT:
     359                 :             :                 case RANGESTRAT_OVERLAPS:
     360                 :             :                 case RANGESTRAT_OVERRIGHT:
     361                 :             :                 case RANGESTRAT_AFTER:
     362                 :             :                 case RANGESTRAT_ADJACENT:
     363                 :             :                     /* These strategies return false if any argument is empty */
     364         [ #  # ]:           0 :                     if (empty)
     365                 :           0 :                         which = 0;
     366                 :             :                     else
     367                 :           0 :                         which &= (1 << 2);
     368                 :           0 :                     break;
     369                 :             : 
     370                 :           0 :                 case RANGESTRAT_CONTAINS:
     371                 :             : 
     372                 :             :                     /*
     373                 :             :                      * All ranges contain an empty range. Only non-empty
     374                 :             :                      * ranges can contain a non-empty range.
     375                 :             :                      */
     376         [ #  # ]:           0 :                     if (!empty)
     377                 :           0 :                         which &= (1 << 2);
     378                 :           0 :                     break;
     379                 :             : 
     380                 :           0 :                 case RANGESTRAT_CONTAINED_BY:
     381                 :             : 
     382                 :             :                     /*
     383                 :             :                      * Only an empty range is contained by an empty range.
     384                 :             :                      * Both empty and non-empty ranges can be contained by a
     385                 :             :                      * non-empty range.
     386                 :             :                      */
     387         [ #  # ]:           0 :                     if (empty)
     388                 :           0 :                         which &= (1 << 1);
     389                 :           0 :                     break;
     390                 :             : 
     391                 :           0 :                 case RANGESTRAT_CONTAINS_ELEM:
     392                 :           0 :                     which &= (1 << 2);
     393                 :           0 :                     break;
     394                 :             : 
     395                 :           0 :                 case RANGESTRAT_EQ:
     396         [ #  # ]:           0 :                     if (empty)
     397                 :           0 :                         which &= (1 << 1);
     398                 :             :                     else
     399                 :           0 :                         which &= (1 << 2);
     400                 :           0 :                     break;
     401                 :             : 
     402                 :           0 :                 default:
     403         [ #  # ]:           0 :                     elog(ERROR, "unrecognized range strategy: %d", strategy);
     404                 :             :                     break;
     405                 :             :             }
     406         [ #  # ]:           0 :             if (which == 0)
     407                 :           0 :                 break;          /* no need to consider remaining conditions */
     408                 :             :         }
     409                 :             :     }
     410                 :             :     else
     411                 :             :     {
     412                 :             :         RangeBound  centroidLower,
     413                 :             :                     centroidUpper;
     414                 :             :         bool        centroidEmpty;
     415                 :             :         TypeCacheEntry *typcache;
     416                 :             :         RangeType  *centroid;
     417                 :             : 
     418                 :             :         /* This node has a centroid. Fetch it. */
     419                 :        1102 :         centroid = DatumGetRangeTypeP(in->prefixDatum);
     420                 :        1102 :         typcache = range_get_typcache(fcinfo,
     421                 :             :                                       RangeTypeGetOid(centroid));
     422                 :        1102 :         range_deserialize(typcache, centroid, &centroidLower, &centroidUpper,
     423                 :             :                           &centroidEmpty);
     424                 :             : 
     425                 :             :         Assert(in->nNodes == 4 || in->nNodes == 5);
     426                 :             : 
     427                 :             :         /*
     428                 :             :          * Nth bit of which variable means that (N - 1)th node (Nth quadrant)
     429                 :             :          * should be visited. Initially all bits are set. Bits of nodes which
     430                 :             :          * can be skipped will be unset.
     431                 :             :          */
     432                 :        1102 :         which = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5);
     433                 :             : 
     434         [ +  + ]:        2204 :         for (i = 0; i < in->nkeys; i++)
     435                 :             :         {
     436                 :             :             StrategyNumber strategy;
     437                 :             :             RangeBound  lower,
     438                 :             :                         upper;
     439                 :             :             bool        empty;
     440                 :        1102 :             RangeType  *range = NULL;
     441                 :             : 
     442                 :        1102 :             RangeType  *prevCentroid = NULL;
     443                 :             :             RangeBound  prevLower,
     444                 :             :                         prevUpper;
     445                 :             :             bool        prevEmpty;
     446                 :             : 
     447                 :             :             /* Restrictions on range bounds according to scan strategy */
     448                 :        1102 :             RangeBound *minLower = NULL,
     449                 :        1102 :                        *maxLower = NULL,
     450                 :        1102 :                        *minUpper = NULL,
     451                 :        1102 :                        *maxUpper = NULL;
     452                 :             : 
     453                 :             :             /* Are the restrictions on range bounds inclusive? */
     454                 :        1102 :             bool        inclusive = true;
     455                 :        1102 :             bool        strictEmpty = true;
     456                 :             :             int         cmp,
     457                 :             :                         which1,
     458                 :             :                         which2;
     459                 :             : 
     460                 :        1102 :             strategy = in->scankeys[i].sk_strategy;
     461                 :             : 
     462                 :             :             /*
     463                 :             :              * RANGESTRAT_CONTAINS_ELEM is just like RANGESTRAT_CONTAINS, but
     464                 :             :              * the argument is a single element. Expand the single element to
     465                 :             :              * a range containing only the element, and treat it like
     466                 :             :              * RANGESTRAT_CONTAINS.
     467                 :             :              */
     468         [ +  + ]:        1102 :             if (strategy == RANGESTRAT_CONTAINS_ELEM)
     469                 :             :             {
     470                 :          31 :                 lower.inclusive = true;
     471                 :          31 :                 lower.infinite = false;
     472                 :          31 :                 lower.lower = true;
     473                 :          31 :                 lower.val = in->scankeys[i].sk_argument;
     474                 :             : 
     475                 :          31 :                 upper.inclusive = true;
     476                 :          31 :                 upper.infinite = false;
     477                 :          31 :                 upper.lower = false;
     478                 :          31 :                 upper.val = in->scankeys[i].sk_argument;
     479                 :             : 
     480                 :          31 :                 empty = false;
     481                 :             : 
     482                 :          31 :                 strategy = RANGESTRAT_CONTAINS;
     483                 :             :             }
     484                 :             :             else
     485                 :             :             {
     486                 :        1071 :                 range = DatumGetRangeTypeP(in->scankeys[i].sk_argument);
     487                 :        1071 :                 range_deserialize(typcache, range, &lower, &upper, &empty);
     488                 :             :             }
     489                 :             : 
     490                 :             :             /*
     491                 :             :              * Most strategies are handled by forming a bounding box from the
     492                 :             :              * search key, defined by a minLower, maxLower, minUpper,
     493                 :             :              * maxUpper. Some modify 'which' directly, to specify exactly
     494                 :             :              * which quadrants need to be visited.
     495                 :             :              *
     496                 :             :              * For most strategies, nothing matches an empty search key, and
     497                 :             :              * an empty range never matches a non-empty key. If a strategy
     498                 :             :              * does not behave like that wrt. empty ranges, set strictEmpty to
     499                 :             :              * false.
     500                 :             :              */
     501   [ +  +  +  +  :        1102 :             switch (strategy)
          +  +  +  +  +  
                      - ]
     502                 :             :             {
     503                 :          16 :                 case RANGESTRAT_BEFORE:
     504                 :             : 
     505                 :             :                     /*
     506                 :             :                      * Range A is before range B if upper bound of A is lower
     507                 :             :                      * than lower bound of B.
     508                 :             :                      */
     509                 :          16 :                     maxUpper = &lower;
     510                 :          16 :                     inclusive = false;
     511                 :          16 :                     break;
     512                 :             : 
     513                 :          87 :                 case RANGESTRAT_OVERLEFT:
     514                 :             : 
     515                 :             :                     /*
     516                 :             :                      * Range A is overleft to range B if upper bound of A is
     517                 :             :                      * less than or equal to upper bound of B.
     518                 :             :                      */
     519                 :          87 :                     maxUpper = &upper;
     520                 :          87 :                     break;
     521                 :             : 
     522                 :          31 :                 case RANGESTRAT_OVERLAPS:
     523                 :             : 
     524                 :             :                     /*
     525                 :             :                      * Non-empty ranges overlap, if lower bound of each range
     526                 :             :                      * is lower or equal to upper bound of the other range.
     527                 :             :                      */
     528                 :          31 :                     maxLower = &upper;
     529                 :          31 :                     minUpper = &lower;
     530                 :          31 :                     break;
     531                 :             : 
     532                 :         268 :                 case RANGESTRAT_OVERRIGHT:
     533                 :             : 
     534                 :             :                     /*
     535                 :             :                      * Range A is overright to range B if lower bound of A is
     536                 :             :                      * greater than or equal to lower bound of B.
     537                 :             :                      */
     538                 :         268 :                     minLower = &lower;
     539                 :         268 :                     break;
     540                 :             : 
     541                 :         244 :                 case RANGESTRAT_AFTER:
     542                 :             : 
     543                 :             :                     /*
     544                 :             :                      * Range A is after range B if lower bound of A is greater
     545                 :             :                      * than upper bound of B.
     546                 :             :                      */
     547                 :         244 :                     minLower = &upper;
     548                 :         244 :                     inclusive = false;
     549                 :         244 :                     break;
     550                 :             : 
     551                 :          87 :                 case RANGESTRAT_ADJACENT:
     552         [ -  + ]:          87 :                     if (empty)
     553                 :           0 :                         break;  /* Skip to strictEmpty check. */
     554                 :             : 
     555                 :             :                     /*
     556                 :             :                      * Previously selected quadrant could exclude possibility
     557                 :             :                      * for lower or upper bounds to be adjacent. Deserialize
     558                 :             :                      * previous centroid range if present for checking this.
     559                 :             :                      */
     560         [ +  + ]:          87 :                     if (in->traversalValue)
     561                 :             :                     {
     562                 :          75 :                         prevCentroid = in->traversalValue;
     563                 :          75 :                         range_deserialize(typcache, prevCentroid,
     564                 :             :                                           &prevLower, &prevUpper, &prevEmpty);
     565                 :             :                     }
     566                 :             : 
     567                 :             :                     /*
     568                 :             :                      * For a range's upper bound to be adjacent to the
     569                 :             :                      * argument's lower bound, it will be found along the line
     570                 :             :                      * adjacent to (and just below) Y=lower. Therefore, if the
     571                 :             :                      * argument's lower bound is less than the centroid's
     572                 :             :                      * upper bound, the line falls in quadrants 2 and 3; if
     573                 :             :                      * greater, the line falls in quadrants 1 and 4. (see
     574                 :             :                      * adjacent_cmp_bounds for description of edge cases).
     575                 :             :                      */
     576         [ +  + ]:          87 :                     cmp = adjacent_inner_consistent(typcache, &lower,
     577                 :             :                                                     &centroidUpper,
     578                 :             :                                                     prevCentroid ? &prevUpper : NULL);
     579         [ +  + ]:          87 :                     if (cmp > 0)
     580                 :           8 :                         which1 = (1 << 1) | (1 << 4);
     581         [ +  + ]:          79 :                     else if (cmp < 0)
     582                 :          19 :                         which1 = (1 << 2) | (1 << 3);
     583                 :             :                     else
     584                 :          60 :                         which1 = 0;
     585                 :             : 
     586                 :             :                     /*
     587                 :             :                      * Also search for ranges's adjacent to argument's upper
     588                 :             :                      * bound. They will be found along the line adjacent to
     589                 :             :                      * (and just right of) X=upper, which falls in quadrants 3
     590                 :             :                      * and 4, or 1 and 2.
     591                 :             :                      */
     592         [ +  + ]:          87 :                     cmp = adjacent_inner_consistent(typcache, &upper,
     593                 :             :                                                     &centroidLower,
     594                 :             :                                                     prevCentroid ? &prevLower : NULL);
     595         [ +  + ]:          87 :                     if (cmp > 0)
     596                 :          51 :                         which2 = (1 << 1) | (1 << 2);
     597         [ +  + ]:          36 :                     else if (cmp < 0)
     598                 :          28 :                         which2 = (1 << 3) | (1 << 4);
     599                 :             :                     else
     600                 :           8 :                         which2 = 0;
     601                 :             : 
     602                 :             :                     /* We must chase down ranges adjacent to either bound. */
     603                 :          87 :                     which &= which1 | which2;
     604                 :             : 
     605                 :          87 :                     needPrevious = true;
     606                 :          87 :                     break;
     607                 :             : 
     608                 :         337 :                 case RANGESTRAT_CONTAINS:
     609                 :             : 
     610                 :             :                     /*
     611                 :             :                      * Non-empty range A contains non-empty range B if lower
     612                 :             :                      * bound of A is lower or equal to lower bound of range B
     613                 :             :                      * and upper bound of range A is greater than or equal to
     614                 :             :                      * upper bound of range A.
     615                 :             :                      *
     616                 :             :                      * All non-empty ranges contain an empty range.
     617                 :             :                      */
     618                 :         337 :                     strictEmpty = false;
     619         [ +  + ]:         337 :                     if (!empty)
     620                 :             :                     {
     621                 :          62 :                         which &= (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4);
     622                 :          62 :                         maxLower = &lower;
     623                 :          62 :                         minUpper = &upper;
     624                 :             :                     }
     625                 :         337 :                     break;
     626                 :             : 
     627                 :          16 :                 case RANGESTRAT_CONTAINED_BY:
     628                 :             :                     /* The opposite of contains. */
     629                 :          16 :                     strictEmpty = false;
     630         [ -  + ]:          16 :                     if (empty)
     631                 :             :                     {
     632                 :             :                         /* An empty range is only contained by an empty range */
     633                 :           0 :                         which &= (1 << 5);
     634                 :             :                     }
     635                 :             :                     else
     636                 :             :                     {
     637                 :          16 :                         minLower = &lower;
     638                 :          16 :                         maxUpper = &upper;
     639                 :             :                     }
     640                 :          16 :                     break;
     641                 :             : 
     642                 :          16 :                 case RANGESTRAT_EQ:
     643                 :             : 
     644                 :             :                     /*
     645                 :             :                      * Equal range can be only in the same quadrant where
     646                 :             :                      * argument would be placed to.
     647                 :             :                      */
     648                 :          16 :                     strictEmpty = false;
     649                 :          16 :                     which &= (1 << getQuadrant(typcache, centroid, range));
     650                 :          16 :                     break;
     651                 :             : 
     652                 :           0 :                 default:
     653         [ #  # ]:           0 :                     elog(ERROR, "unrecognized range strategy: %d", strategy);
     654                 :             :                     break;
     655                 :             :             }
     656                 :             : 
     657         [ +  + ]:        1102 :             if (strictEmpty)
     658                 :             :             {
     659         [ -  + ]:         733 :                 if (empty)
     660                 :             :                 {
     661                 :             :                     /* Scan key is empty, no branches are satisfying */
     662                 :           0 :                     which = 0;
     663                 :           0 :                     break;
     664                 :             :                 }
     665                 :             :                 else
     666                 :             :                 {
     667                 :             :                     /* Shouldn't visit tree branch with empty ranges */
     668                 :         733 :                     which &= (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4);
     669                 :             :                 }
     670                 :             :             }
     671                 :             : 
     672                 :             :             /*
     673                 :             :              * Using the bounding box, see which quadrants we have to descend
     674                 :             :              * into.
     675                 :             :              */
     676         [ +  + ]:        1102 :             if (minLower)
     677                 :             :             {
     678                 :             :                 /*
     679                 :             :                  * If the centroid's lower bound is less than or equal to the
     680                 :             :                  * minimum lower bound, anything in the 3rd and 4th quadrants
     681                 :             :                  * will have an even smaller lower bound, and thus can't
     682                 :             :                  * match.
     683                 :             :                  */
     684         [ +  + ]:         528 :                 if (range_cmp_bounds(typcache, &centroidLower, minLower) <= 0)
     685                 :          64 :                     which &= (1 << 1) | (1 << 2) | (1 << 5);
     686                 :             :             }
     687         [ +  + ]:        1102 :             if (maxLower)
     688                 :             :             {
     689                 :             :                 /*
     690                 :             :                  * If the centroid's lower bound is greater than the maximum
     691                 :             :                  * lower bound, anything in the 1st and 2nd quadrants will
     692                 :             :                  * also have a greater than or equal lower bound, and thus
     693                 :             :                  * can't match. If the centroid's lower bound is equal to the
     694                 :             :                  * maximum lower bound, we can still exclude the 1st and 2nd
     695                 :             :                  * quadrants if we're looking for a value strictly greater
     696                 :             :                  * than the maximum.
     697                 :             :                  */
     698                 :             : 
     699                 :          93 :                 cmp = range_cmp_bounds(typcache, &centroidLower, maxLower);
     700   [ +  +  -  +  :          93 :                 if (cmp > 0 || (!inclusive && cmp == 0))
                   -  - ]
     701                 :          72 :                     which &= (1 << 3) | (1 << 4) | (1 << 5);
     702                 :             :             }
     703         [ +  + ]:        1102 :             if (minUpper)
     704                 :             :             {
     705                 :             :                 /*
     706                 :             :                  * If the centroid's upper bound is less than or equal to the
     707                 :             :                  * minimum upper bound, anything in the 2nd and 3rd quadrants
     708                 :             :                  * will have an even smaller upper bound, and thus can't
     709                 :             :                  * match.
     710                 :             :                  */
     711         [ -  + ]:          93 :                 if (range_cmp_bounds(typcache, &centroidUpper, minUpper) <= 0)
     712                 :           0 :                     which &= (1 << 1) | (1 << 4) | (1 << 5);
     713                 :             :             }
     714         [ +  + ]:        1102 :             if (maxUpper)
     715                 :             :             {
     716                 :             :                 /*
     717                 :             :                  * If the centroid's upper bound is greater than the maximum
     718                 :             :                  * upper bound, anything in the 1st and 4th quadrants will
     719                 :             :                  * also have a greater than or equal upper bound, and thus
     720                 :             :                  * can't match. If the centroid's upper bound is equal to the
     721                 :             :                  * maximum upper bound, we can still exclude the 1st and 4th
     722                 :             :                  * quadrants if we're looking for a value strictly greater
     723                 :             :                  * than the maximum.
     724                 :             :                  */
     725                 :             : 
     726                 :         119 :                 cmp = range_cmp_bounds(typcache, &centroidUpper, maxUpper);
     727   [ +  +  +  +  :         119 :                 if (cmp > 0 || (!inclusive && cmp == 0))
                   -  + ]
     728                 :          55 :                     which &= (1 << 2) | (1 << 3) | (1 << 5);
     729                 :             :             }
     730                 :             : 
     731         [ -  + ]:        1102 :             if (which == 0)
     732                 :           0 :                 break;          /* no need to consider remaining conditions */
     733                 :             :         }
     734                 :             :     }
     735                 :             : 
     736                 :             :     /* We must descend into the quadrant(s) identified by 'which' */
     737                 :        1102 :     out->nodeNumbers = palloc_array(int, in->nNodes);
     738         [ +  + ]:        1102 :     if (needPrevious)
     739                 :          87 :         out->traversalValues = palloc_array(void *, in->nNodes);
     740                 :        1102 :     out->nNodes = 0;
     741                 :             : 
     742                 :             :     /*
     743                 :             :      * Elements of traversalValues should be allocated in
     744                 :             :      * traversalMemoryContext
     745                 :             :      */
     746                 :        1102 :     oldCtx = MemoryContextSwitchTo(in->traversalMemoryContext);
     747                 :             : 
     748         [ +  + ]:        5602 :     for (i = 1; i <= in->nNodes; i++)
     749                 :             :     {
     750         [ +  + ]:        4500 :         if (which & (1 << i))
     751                 :             :         {
     752                 :             :             /* Save previous prefix if needed */
     753         [ +  + ]:        3839 :             if (needPrevious)
     754                 :             :             {
     755                 :             :                 Datum       previousCentroid;
     756                 :             : 
     757                 :             :                 /*
     758                 :             :                  * We know, that in->prefixDatum in this place is varlena,
     759                 :             :                  * because it's range
     760                 :             :                  */
     761                 :         193 :                 previousCentroid = datumCopy(in->prefixDatum, false, -1);
     762                 :         193 :                 out->traversalValues[out->nNodes] = DatumGetPointer(previousCentroid);
     763                 :             :             }
     764                 :        3839 :             out->nodeNumbers[out->nNodes] = i - 1;
     765                 :        3839 :             out->nNodes++;
     766                 :             :         }
     767                 :             :     }
     768                 :             : 
     769                 :        1102 :     MemoryContextSwitchTo(oldCtx);
     770                 :             : 
     771                 :        1102 :     PG_RETURN_VOID();
     772                 :             : }
     773                 :             : 
     774                 :             : /*
     775                 :             :  * adjacent_cmp_bounds
     776                 :             :  *
     777                 :             :  * Given an argument and centroid bound, this function determines if any
     778                 :             :  * bounds that are adjacent to the argument are smaller than, or greater than
     779                 :             :  * or equal to centroid. For brevity, we call the arg < centroid "left", and
     780                 :             :  * arg >= centroid case "right". This corresponds to how the quadrants are
     781                 :             :  * arranged, if you imagine that "left" is equivalent to "down" and "right"
     782                 :             :  * is equivalent to "up".
     783                 :             :  *
     784                 :             :  * For the "left" case, returns -1, and for the "right" case, returns 1.
     785                 :             :  */
     786                 :             : static int
     787                 :         256 : adjacent_cmp_bounds(TypeCacheEntry *typcache, const RangeBound *arg,
     788                 :             :                     const RangeBound *centroid)
     789                 :             : {
     790                 :             :     int         cmp;
     791                 :             : 
     792                 :             :     Assert(arg->lower != centroid->lower);
     793                 :             : 
     794                 :         256 :     cmp = range_cmp_bounds(typcache, arg, centroid);
     795                 :             : 
     796         [ +  + ]:         256 :     if (centroid->lower)
     797                 :             :     {
     798                 :             :         /*------
     799                 :             :          * The argument is an upper bound, we are searching for adjacent lower
     800                 :             :          * bounds. A matching adjacent lower bound must be *larger* than the
     801                 :             :          * argument, but only just.
     802                 :             :          *
     803                 :             :          * The following table illustrates the desired result with a fixed
     804                 :             :          * argument bound, and different centroids. The CMP column shows
     805                 :             :          * the value of 'cmp' variable, and ADJ shows whether the argument
     806                 :             :          * and centroid are adjacent, per bounds_adjacent(). (N) means we
     807                 :             :          * don't need to check for that case, because it's implied by CMP.
     808                 :             :          * With the argument range [..., 500), the adjacent range we're
     809                 :             :          * searching for is [500, ...):
     810                 :             :          *
     811                 :             :          *  ARGUMENT   CENTROID     CMP   ADJ
     812                 :             :          *  [..., 500) [498, ...)    >     (N)   [500, ...) is to the right
     813                 :             :          *  [..., 500) [499, ...)    =    (N)   [500, ...) is to the right
     814                 :             :          *  [..., 500) [500, ...)    <      Y    [500, ...) is to the right
     815                 :             :          *  [..., 500) [501, ...)    <      N    [500, ...) is to the left
     816                 :             :          *
     817                 :             :          * So, we must search left when the argument is smaller than, and not
     818                 :             :          * adjacent, to the centroid. Otherwise search right.
     819                 :             :          *------
     820                 :             :          */
     821   [ +  +  +  - ]:         154 :         if (cmp < 0 && !bounds_adjacent(typcache, *arg, *centroid))
     822                 :          47 :             return -1;
     823                 :             :         else
     824                 :         107 :             return 1;
     825                 :             :     }
     826                 :             :     else
     827                 :             :     {
     828                 :             :         /*------
     829                 :             :          * The argument is a lower bound, we are searching for adjacent upper
     830                 :             :          * bounds. A matching adjacent upper bound must be *smaller* than the
     831                 :             :          * argument, but only just.
     832                 :             :          *
     833                 :             :          *  ARGUMENT   CENTROID     CMP   ADJ
     834                 :             :          *  [500, ...) [..., 499)    >     (N)   [..., 500) is to the right
     835                 :             :          *  [500, ...) [..., 500)    >     (Y)   [..., 500) is to the right
     836                 :             :          *  [500, ...) [..., 501)    =    (N)   [..., 500) is to the left
     837                 :             :          *  [500, ...) [..., 502)    <     (N)   [..., 500) is to the left
     838                 :             :          *
     839                 :             :          * We must search left when the argument is smaller than or equal to
     840                 :             :          * the centroid. Otherwise search right. We don't need to check
     841                 :             :          * whether the argument is adjacent with the centroid, because it
     842                 :             :          * doesn't matter.
     843                 :             :          *------
     844                 :             :          */
     845         [ +  + ]:         102 :         if (cmp <= 0)
     846                 :          94 :             return -1;
     847                 :             :         else
     848                 :           8 :             return 1;
     849                 :             :     }
     850                 :             : }
     851                 :             : 
     852                 :             : /*----------
     853                 :             :  * adjacent_inner_consistent
     854                 :             :  *
     855                 :             :  * Like adjacent_cmp_bounds, but also takes into account the previous
     856                 :             :  * level's centroid. We might've traversed left (or right) at the previous
     857                 :             :  * node, in search for ranges adjacent to the other bound, even though we
     858                 :             :  * already ruled out the possibility for any matches in that direction for
     859                 :             :  * this bound. By comparing the argument with the previous centroid, and
     860                 :             :  * the previous centroid with the current centroid, we can determine which
     861                 :             :  * direction we should've moved in at previous level, and which direction we
     862                 :             :  * actually moved.
     863                 :             :  *
     864                 :             :  * If there can be any matches to the left, returns -1. If to the right,
     865                 :             :  * returns 1. If there can be no matches below this centroid, because we
     866                 :             :  * already ruled them out at the previous level, returns 0.
     867                 :             :  *
     868                 :             :  * XXX: Comparing just the previous and current level isn't foolproof; we
     869                 :             :  * might still search some branches unnecessarily. For example, imagine that
     870                 :             :  * we are searching for value 15, and we traverse the following centroids
     871                 :             :  * (only considering one bound for the moment):
     872                 :             :  *
     873                 :             :  * Level 1: 20
     874                 :             :  * Level 2: 50
     875                 :             :  * Level 3: 25
     876                 :             :  *
     877                 :             :  * At this point, previous centroid is 50, current centroid is 25, and the
     878                 :             :  * target value is to the left. But because we already moved right from
     879                 :             :  * centroid 20 to 50 in the first level, there cannot be any values < 20 in
     880                 :             :  * the current branch. But we don't know that just by looking at the previous
     881                 :             :  * and current centroid, so we traverse left, unnecessarily. The reason we are
     882                 :             :  * down this branch is that we're searching for matches with the *other*
     883                 :             :  * bound. If we kept track of which bound we are searching for explicitly,
     884                 :             :  * instead of deducing that from the previous and current centroid, we could
     885                 :             :  * avoid some unnecessary work.
     886                 :             :  *----------
     887                 :             :  */
     888                 :             : static int
     889                 :         174 : adjacent_inner_consistent(TypeCacheEntry *typcache, const RangeBound *arg,
     890                 :             :                           const RangeBound *centroid, const RangeBound *prev)
     891                 :             : {
     892         [ +  + ]:         174 :     if (prev)
     893                 :             :     {
     894                 :             :         int         prevcmp;
     895                 :             :         int         cmp;
     896                 :             : 
     897                 :             :         /*
     898                 :             :          * Which direction were we supposed to traverse at previous level,
     899                 :             :          * left or right?
     900                 :             :          */
     901                 :         150 :         prevcmp = adjacent_cmp_bounds(typcache, arg, prev);
     902                 :             : 
     903                 :             :         /* and which direction did we actually go? */
     904                 :         150 :         cmp = range_cmp_bounds(typcache, centroid, prev);
     905                 :             : 
     906                 :             :         /* if the two don't agree, there's nothing to see here */
     907   [ +  +  +  +  :         150 :         if ((prevcmp < 0 && cmp >= 0) || (prevcmp > 0 && cmp < 0))
             +  +  +  + ]
     908                 :          68 :             return 0;
     909                 :             :     }
     910                 :             : 
     911                 :         106 :     return adjacent_cmp_bounds(typcache, arg, centroid);
     912                 :             : }
     913                 :             : 
     914                 :             : /*
     915                 :             :  * SP-GiST consistent function for leaf nodes: check leaf value against query
     916                 :             :  * using corresponding function.
     917                 :             :  */
     918                 :             : Datum
     919                 :      151908 : spg_range_quad_leaf_consistent(PG_FUNCTION_ARGS)
     920                 :             : {
     921                 :      151908 :     spgLeafConsistentIn *in = (spgLeafConsistentIn *) PG_GETARG_POINTER(0);
     922                 :      151908 :     spgLeafConsistentOut *out = (spgLeafConsistentOut *) PG_GETARG_POINTER(1);
     923                 :      151908 :     RangeType  *leafRange = DatumGetRangeTypeP(in->leafDatum);
     924                 :             :     TypeCacheEntry *typcache;
     925                 :             :     bool        res;
     926                 :             :     int         i;
     927                 :             : 
     928                 :             :     /* all tests are exact */
     929                 :      151908 :     out->recheck = false;
     930                 :             : 
     931                 :             :     /* leafDatum is what it is... */
     932                 :      151908 :     out->leafValue = in->leafDatum;
     933                 :             : 
     934                 :      151908 :     typcache = range_get_typcache(fcinfo, RangeTypeGetOid(leafRange));
     935                 :             : 
     936                 :             :     /* Perform the required comparison(s) */
     937                 :      151908 :     res = true;
     938         [ +  + ]:      289836 :     for (i = 0; i < in->nkeys; i++)
     939                 :             :     {
     940                 :      151908 :         Datum       keyDatum = in->scankeys[i].sk_argument;
     941                 :             : 
     942                 :             :         /* Call the function corresponding to the scan strategy */
     943   [ +  +  +  +  :      151908 :         switch (in->scankeys[i].sk_strategy)
          +  +  +  +  +  
                   +  - ]
     944                 :             :         {
     945                 :        1904 :             case RANGESTRAT_BEFORE:
     946                 :        1904 :                 res = range_before_internal(typcache, leafRange,
     947                 :        1904 :                                             DatumGetRangeTypeP(keyDatum));
     948                 :        1904 :                 break;
     949                 :       12233 :             case RANGESTRAT_OVERLEFT:
     950                 :       12233 :                 res = range_overleft_internal(typcache, leafRange,
     951                 :       12233 :                                               DatumGetRangeTypeP(keyDatum));
     952                 :       12233 :                 break;
     953                 :        1959 :             case RANGESTRAT_OVERLAPS:
     954                 :        1959 :                 res = range_overlaps_internal(typcache, leafRange,
     955                 :        1959 :                                               DatumGetRangeTypeP(keyDatum));
     956                 :        1959 :                 break;
     957                 :       39641 :             case RANGESTRAT_OVERRIGHT:
     958                 :       39641 :                 res = range_overright_internal(typcache, leafRange,
     959                 :       39641 :                                                DatumGetRangeTypeP(keyDatum));
     960                 :       39641 :                 break;
     961                 :       28952 :             case RANGESTRAT_AFTER:
     962                 :       28952 :                 res = range_after_internal(typcache, leafRange,
     963                 :       28952 :                                            DatumGetRangeTypeP(keyDatum));
     964                 :       28952 :                 break;
     965                 :        3557 :             case RANGESTRAT_ADJACENT:
     966                 :        3557 :                 res = range_adjacent_internal(typcache, leafRange,
     967                 :        3557 :                                               DatumGetRangeTypeP(keyDatum));
     968                 :        3557 :                 break;
     969                 :       51559 :             case RANGESTRAT_CONTAINS:
     970                 :       51559 :                 res = range_contains_internal(typcache, leafRange,
     971                 :       51559 :                                               DatumGetRangeTypeP(keyDatum));
     972                 :       51559 :                 break;
     973                 :        9296 :             case RANGESTRAT_CONTAINED_BY:
     974                 :        9296 :                 res = range_contained_by_internal(typcache, leafRange,
     975                 :        9296 :                                                   DatumGetRangeTypeP(keyDatum));
     976                 :        9296 :                 break;
     977                 :        1959 :             case RANGESTRAT_CONTAINS_ELEM:
     978                 :        1959 :                 res = range_contains_elem_internal(typcache, leafRange,
     979                 :             :                                                    keyDatum);
     980                 :        1959 :                 break;
     981                 :         848 :             case RANGESTRAT_EQ:
     982                 :         848 :                 res = range_eq_internal(typcache, leafRange,
     983                 :         848 :                                         DatumGetRangeTypeP(keyDatum));
     984                 :         848 :                 break;
     985                 :           0 :             default:
     986         [ #  # ]:           0 :                 elog(ERROR, "unrecognized range strategy: %d",
     987                 :             :                      in->scankeys[i].sk_strategy);
     988                 :             :                 break;
     989                 :             :         }
     990                 :             : 
     991                 :             :         /*
     992                 :             :          * If leaf datum doesn't match to a query key, no need to check
     993                 :             :          * subsequent keys.
     994                 :             :          */
     995         [ +  + ]:      151908 :         if (!res)
     996                 :       13980 :             break;
     997                 :             :     }
     998                 :             : 
     999                 :      151908 :     PG_RETURN_BOOL(res);
    1000                 :             : }
        

Generated by: LCOV version 2.0-1