LCOV - code coverage report
Current view: top level - contrib/intarray - _int_gist.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 255 273 93.4 %
Date: 2020-06-05 18:07:03 Functions: 17 17 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * contrib/intarray/_int_gist.c
       3             :  */
       4             : #include "postgres.h"
       5             : 
       6             : #include <limits.h>
       7             : 
       8             : #include "_int.h"
       9             : #include "access/gist.h"
      10             : #include "access/reloptions.h"
      11             : #include "access/stratnum.h"
      12             : 
      13             : #define GETENTRY(vec,pos) ((ArrayType *) DatumGetPointer((vec)->vector[(pos)].key))
      14             : 
      15             : /*
      16             :  * Control the maximum sparseness of compressed keys.
      17             :  *
      18             :  * The upper safe bound for this limit is half the maximum allocatable array
      19             :  * size. A lower bound would give more guarantees that pathological data
      20             :  * wouldn't eat excessive CPU and memory, but at the expense of breaking
      21             :  * possibly working (after a fashion) indexes.
      22             :  */
      23             : #define MAXNUMELTS (Min((MaxAllocSize / sizeof(Datum)),((MaxAllocSize - ARR_OVERHEAD_NONULLS(1)) / sizeof(int)))/2)
      24             : /* or: #define MAXNUMELTS 1000000 */
      25             : 
      26             : /*
      27             : ** GiST support methods
      28             : */
      29           4 : PG_FUNCTION_INFO_V1(g_int_consistent);
      30           4 : PG_FUNCTION_INFO_V1(g_int_compress);
      31           4 : PG_FUNCTION_INFO_V1(g_int_decompress);
      32           4 : PG_FUNCTION_INFO_V1(g_int_penalty);
      33           4 : PG_FUNCTION_INFO_V1(g_int_picksplit);
      34           4 : PG_FUNCTION_INFO_V1(g_int_union);
      35           4 : PG_FUNCTION_INFO_V1(g_int_same);
      36           4 : PG_FUNCTION_INFO_V1(g_int_options);
      37             : 
      38             : 
      39             : /*
      40             : ** The GiST Consistent method for _intments
      41             : ** Should return false if for all data items x below entry,
      42             : ** the predicate x op query == false, where op is the oper
      43             : ** corresponding to strategy in the pg_amop table.
      44             : */
      45             : Datum
      46      209098 : g_int_consistent(PG_FUNCTION_ARGS)
      47             : {
      48      209098 :     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
      49      209098 :     ArrayType  *query = PG_GETARG_ARRAYTYPE_P_COPY(1);
      50      209098 :     StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
      51             : 
      52             :     /* Oid      subtype = PG_GETARG_OID(3); */
      53      209098 :     bool       *recheck = (bool *) PG_GETARG_POINTER(4);
      54             :     bool        retval;
      55             : 
      56             :     /* this is exact except for RTSameStrategyNumber */
      57      209098 :     *recheck = (strategy == RTSameStrategyNumber);
      58             : 
      59      209098 :     if (strategy == BooleanSearchStrategy)
      60             :     {
      61      338460 :         retval = execconsistent((QUERYTYPE *) query,
      62      112820 :                                 (ArrayType *) DatumGetPointer(entry->key),
      63      112820 :                                 GIST_LEAF(entry));
      64             : 
      65      112820 :         pfree(query);
      66      112820 :         PG_RETURN_BOOL(retval);
      67             :     }
      68             : 
      69             :     /* sort query for fast search, key is already sorted */
      70       96278 :     CHECKARRVALID(query);
      71       96278 :     PREPAREARR(query);
      72             : 
      73       96278 :     switch (strategy)
      74             :     {
      75       22628 :         case RTOverlapStrategyNumber:
      76       22628 :             retval = inner_int_overlap((ArrayType *) DatumGetPointer(entry->key),
      77             :                                        query);
      78       22628 :             break;
      79        6194 :         case RTSameStrategyNumber:
      80        6194 :             if (GIST_LEAF(entry))
      81        5874 :                 DirectFunctionCall3(g_int_same,
      82             :                                     entry->key,
      83             :                                     PointerGetDatum(query),
      84             :                                     PointerGetDatum(&retval));
      85             :             else
      86         320 :                 retval = inner_int_contains((ArrayType *) DatumGetPointer(entry->key),
      87             :                                             query);
      88        6194 :             break;
      89       40082 :         case RTContainsStrategyNumber:
      90             :         case RTOldContainsStrategyNumber:
      91       40082 :             retval = inner_int_contains((ArrayType *) DatumGetPointer(entry->key),
      92             :                                         query);
      93       40082 :             break;
      94       27374 :         case RTContainedByStrategyNumber:
      95             :         case RTOldContainedByStrategyNumber:
      96       27374 :             if (GIST_LEAF(entry))
      97       27024 :                 retval = inner_int_contains(query,
      98       27024 :                                             (ArrayType *) DatumGetPointer(entry->key));
      99             :             else
     100             :             {
     101             :                 /*
     102             :                  * Unfortunately, because empty arrays could be anywhere in
     103             :                  * the index, we must search the whole tree.
     104             :                  */
     105         350 :                 retval = true;
     106             :             }
     107       27374 :             break;
     108           0 :         default:
     109           0 :             retval = false;
     110             :     }
     111       96278 :     pfree(query);
     112       96278 :     PG_RETURN_BOOL(retval);
     113             : }
     114             : 
     115             : Datum
     116       45684 : g_int_union(PG_FUNCTION_ARGS)
     117             : {
     118       45684 :     GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
     119       45684 :     int        *size = (int *) PG_GETARG_POINTER(1);
     120             :     int32       i,
     121             :                *ptr;
     122             :     ArrayType  *res;
     123       45684 :     int         totlen = 0;
     124             : 
     125      137708 :     for (i = 0; i < entryvec->n; i++)
     126             :     {
     127       92024 :         ArrayType  *ent = GETENTRY(entryvec, i);
     128             : 
     129       92024 :         CHECKARRVALID(ent);
     130       92024 :         totlen += ARRNELEMS(ent);
     131             :     }
     132             : 
     133       45684 :     res = new_intArrayType(totlen);
     134       45684 :     ptr = ARRPTR(res);
     135             : 
     136      137708 :     for (i = 0; i < entryvec->n; i++)
     137             :     {
     138       92024 :         ArrayType  *ent = GETENTRY(entryvec, i);
     139             :         int         nel;
     140             : 
     141       92024 :         nel = ARRNELEMS(ent);
     142       92024 :         memcpy(ptr, ARRPTR(ent), nel * sizeof(int32));
     143       92024 :         ptr += nel;
     144             :     }
     145             : 
     146       45684 :     QSORT(res, 1);
     147       45684 :     res = _int_unique(res);
     148       45684 :     *size = VARSIZE(res);
     149       45684 :     PG_RETURN_POINTER(res);
     150             : }
     151             : 
     152             : /*
     153             : ** GiST Compress and Decompress methods
     154             : */
     155             : Datum
     156       36172 : g_int_compress(PG_FUNCTION_ARGS)
     157             : {
     158       36172 :     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
     159             :     GISTENTRY  *retval;
     160             :     ArrayType  *r;
     161       36172 :     int         num_ranges = G_INT_GET_NUMRANGES();
     162             :     int         len,
     163             :                 lenr;
     164             :     int        *dr;
     165             :     int         i,
     166             :                 j,
     167             :                 cand;
     168             :     int64       min;
     169             : 
     170       36172 :     if (entry->leafkey)
     171             :     {
     172       27024 :         r = DatumGetArrayTypePCopy(entry->key);
     173       27024 :         CHECKARRVALID(r);
     174       27024 :         PREPAREARR(r);
     175             : 
     176       27024 :         if (ARRNELEMS(r) >= 2 * num_ranges)
     177           0 :             elog(NOTICE, "input array is too big (%d maximum allowed, %d current), use gist__intbig_ops opclass instead",
     178             :                  2 * num_ranges - 1, ARRNELEMS(r));
     179             : 
     180       27024 :         retval = palloc(sizeof(GISTENTRY));
     181       27024 :         gistentryinit(*retval, PointerGetDatum(r),
     182             :                       entry->rel, entry->page, entry->offset, false);
     183             : 
     184       27024 :         PG_RETURN_POINTER(retval);
     185             :     }
     186             : 
     187             :     /*
     188             :      * leaf entries never compress one more time, only when entry->leafkey
     189             :      * ==true, so now we work only with internal keys
     190             :      */
     191             : 
     192        9148 :     r = DatumGetArrayTypeP(entry->key);
     193        9148 :     CHECKARRVALID(r);
     194        9148 :     if (ARRISEMPTY(r))
     195             :     {
     196           0 :         if (r != (ArrayType *) DatumGetPointer(entry->key))
     197           0 :             pfree(r);
     198           0 :         PG_RETURN_POINTER(entry);
     199             :     }
     200             : 
     201        9148 :     if ((len = ARRNELEMS(r)) >= 2 * num_ranges)
     202             :     {                           /* compress */
     203         274 :         if (r == (ArrayType *) DatumGetPointer(entry->key))
     204         274 :             r = DatumGetArrayTypePCopy(entry->key);
     205         274 :         r = resize_intArrayType(r, 2 * (len));
     206             : 
     207         274 :         dr = ARRPTR(r);
     208             : 
     209             :         /*
     210             :          * "len" at this point is the number of ranges we will construct.
     211             :          * "lenr" is the number of ranges we must eventually remove by
     212             :          * merging, we must be careful to remove no more than this number.
     213             :          */
     214         274 :         lenr = len - num_ranges;
     215             : 
     216             :         /*
     217             :          * Initially assume we can merge consecutive ints into a range. but we
     218             :          * must count every value removed and stop when lenr runs out
     219             :          */
     220        8132 :         for (j = i = len - 1; i > 0 && lenr > 0; i--, j--)
     221             :         {
     222        7858 :             int         r_end = dr[i];
     223        7858 :             int         r_start = r_end;
     224             : 
     225       47086 :             while (i > 0 && lenr > 0 && dr[i - 1] == r_start - 1)
     226       39228 :                 --r_start, --i, --lenr;
     227        7858 :             dr[2 * j] = r_start;
     228        7858 :             dr[2 * j + 1] = r_end;
     229             :         }
     230             :         /* just copy the rest, if any, as trivial ranges */
     231       19816 :         for (; i >= 0; i--, j--)
     232       19542 :             dr[2 * j] = dr[2 * j + 1] = dr[i];
     233             : 
     234         274 :         if (++j)
     235             :         {
     236             :             /*
     237             :              * shunt everything down to start at the right place
     238             :              */
     239         274 :             memmove((void *) &dr[0], (void *) &dr[2 * j], 2 * (len - j) * sizeof(int32));
     240             :         }
     241             : 
     242             :         /*
     243             :          * make "len" be number of array elements, not ranges
     244             :          */
     245         274 :         len = 2 * (len - j);
     246         274 :         cand = 1;
     247         274 :         while (len > num_ranges * 2)
     248             :         {
     249           0 :             min = PG_INT64_MAX;
     250           0 :             for (i = 2; i < len; i += 2)
     251           0 :                 if (min > ((int64) dr[i] - (int64) dr[i - 1]))
     252             :                 {
     253           0 :                     min = ((int64) dr[i] - (int64) dr[i - 1]);
     254           0 :                     cand = i;
     255             :                 }
     256           0 :             memmove((void *) &dr[cand - 1], (void *) &dr[cand + 1], (len - cand - 1) * sizeof(int32));
     257           0 :             len -= 2;
     258             :         }
     259             : 
     260             :         /*
     261             :          * check sparseness of result
     262             :          */
     263         274 :         lenr = internal_size(dr, len);
     264         274 :         if (lenr < 0 || lenr > MAXNUMELTS)
     265           0 :             ereport(ERROR,
     266             :                     (errmsg("data is too sparse, recreate index using gist__intbig_ops opclass instead")));
     267             : 
     268         274 :         r = resize_intArrayType(r, len);
     269         274 :         retval = palloc(sizeof(GISTENTRY));
     270         274 :         gistentryinit(*retval, PointerGetDatum(r),
     271             :                       entry->rel, entry->page, entry->offset, false);
     272         274 :         PG_RETURN_POINTER(retval);
     273             :     }
     274             :     else
     275        8874 :         PG_RETURN_POINTER(entry);
     276             : }
     277             : 
     278             : Datum
     279      689252 : g_int_decompress(PG_FUNCTION_ARGS)
     280             : {
     281      689252 :     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
     282             :     GISTENTRY  *retval;
     283             :     ArrayType  *r;
     284      689252 :     int         num_ranges = G_INT_GET_NUMRANGES();
     285             :     int        *dr,
     286             :                 lenr;
     287             :     ArrayType  *in;
     288             :     int         lenin;
     289             :     int        *din;
     290             :     int         i,
     291             :                 j;
     292             : 
     293      689252 :     in = DatumGetArrayTypeP(entry->key);
     294             : 
     295      689252 :     CHECKARRVALID(in);
     296      689252 :     if (ARRISEMPTY(in))
     297             :     {
     298         548 :         if (in != (ArrayType *) DatumGetPointer(entry->key))
     299             :         {
     300         548 :             retval = palloc(sizeof(GISTENTRY));
     301         548 :             gistentryinit(*retval, PointerGetDatum(in),
     302             :                           entry->rel, entry->page, entry->offset, false);
     303         548 :             PG_RETURN_POINTER(retval);
     304             :         }
     305             : 
     306           0 :         PG_RETURN_POINTER(entry);
     307             :     }
     308             : 
     309      688704 :     lenin = ARRNELEMS(in);
     310             : 
     311      688704 :     if (lenin < 2 * num_ranges)
     312             :     {                           /* not compressed value */
     313      684322 :         if (in != (ArrayType *) DatumGetPointer(entry->key))
     314             :         {
     315      336886 :             retval = palloc(sizeof(GISTENTRY));
     316      336886 :             gistentryinit(*retval, PointerGetDatum(in),
     317             :                           entry->rel, entry->page, entry->offset, false);
     318             : 
     319      336886 :             PG_RETURN_POINTER(retval);
     320             :         }
     321      347436 :         PG_RETURN_POINTER(entry);
     322             :     }
     323             : 
     324        4382 :     din = ARRPTR(in);
     325        4382 :     lenr = internal_size(din, lenin);
     326        4382 :     if (lenr < 0 || lenr > MAXNUMELTS)
     327           0 :         ereport(ERROR,
     328             :                 (errmsg("compressed array is too big, recreate index using gist__intbig_ops opclass instead")));
     329             : 
     330        4382 :     r = new_intArrayType(lenr);
     331        4382 :     dr = ARRPTR(r);
     332             : 
     333      442582 :     for (i = 0; i < lenin; i += 2)
     334     1512210 :         for (j = din[i]; j <= din[i + 1]; j++)
     335     1074010 :             if ((!i) || *(dr - 1) != j)
     336     1074010 :                 *dr++ = j;
     337             : 
     338        4382 :     if (in != (ArrayType *) DatumGetPointer(entry->key))
     339        4382 :         pfree(in);
     340        4382 :     retval = palloc(sizeof(GISTENTRY));
     341        4382 :     gistentryinit(*retval, PointerGetDatum(r),
     342             :                   entry->rel, entry->page, entry->offset, false);
     343             : 
     344        4382 :     PG_RETURN_POINTER(retval);
     345             : }
     346             : 
     347             : /*
     348             : ** The GiST Penalty method for _intments
     349             : */
     350             : Datum
     351      297420 : g_int_penalty(PG_FUNCTION_ARGS)
     352             : {
     353      297420 :     GISTENTRY  *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
     354      297420 :     GISTENTRY  *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
     355      297420 :     float      *result = (float *) PG_GETARG_POINTER(2);
     356             :     ArrayType  *ud;
     357             :     float       tmp1,
     358             :                 tmp2;
     359             : 
     360      297420 :     ud = inner_int_union((ArrayType *) DatumGetPointer(origentry->key),
     361      297420 :                          (ArrayType *) DatumGetPointer(newentry->key));
     362      297420 :     rt__int_size(ud, &tmp1);
     363      297420 :     rt__int_size((ArrayType *) DatumGetPointer(origentry->key), &tmp2);
     364      297420 :     *result = tmp1 - tmp2;
     365      297420 :     pfree(ud);
     366             : 
     367      297420 :     PG_RETURN_POINTER(result);
     368             : }
     369             : 
     370             : 
     371             : 
     372             : Datum
     373       51548 : g_int_same(PG_FUNCTION_ARGS)
     374             : {
     375       51548 :     ArrayType  *a = PG_GETARG_ARRAYTYPE_P(0);
     376       51548 :     ArrayType  *b = PG_GETARG_ARRAYTYPE_P(1);
     377       51548 :     bool       *result = (bool *) PG_GETARG_POINTER(2);
     378       51548 :     int32       n = ARRNELEMS(a);
     379             :     int32      *da,
     380             :                *db;
     381             : 
     382       51548 :     CHECKARRVALID(a);
     383       51548 :     CHECKARRVALID(b);
     384             : 
     385       51548 :     if (n != ARRNELEMS(b))
     386             :     {
     387       13024 :         *result = false;
     388       13024 :         PG_RETURN_POINTER(result);
     389             :     }
     390       38524 :     *result = true;
     391       38524 :     da = ARRPTR(a);
     392       38524 :     db = ARRPTR(b);
     393     4119958 :     while (n--)
     394             :     {
     395     4082738 :         if (*da++ != *db++)
     396             :         {
     397        1304 :             *result = false;
     398        1304 :             break;
     399             :         }
     400             :     }
     401             : 
     402       38524 :     PG_RETURN_POINTER(result);
     403             : }
     404             : 
     405             : /*****************************************************************
     406             : ** Common GiST Method
     407             : *****************************************************************/
     408             : 
     409             : typedef struct
     410             : {
     411             :     OffsetNumber pos;
     412             :     float       cost;
     413             : } SPLITCOST;
     414             : 
     415             : static int
     416       74494 : comparecost(const void *a, const void *b)
     417             : {
     418       74494 :     if (((const SPLITCOST *) a)->cost == ((const SPLITCOST *) b)->cost)
     419       44180 :         return 0;
     420             :     else
     421       30314 :         return (((const SPLITCOST *) a)->cost > ((const SPLITCOST *) b)->cost) ? 1 : -1;
     422             : }
     423             : 
     424             : /*
     425             : ** The GiST PickSplit method for _intments
     426             : ** We use Guttman's poly time split algorithm
     427             : */
     428             : Datum
     429         340 : g_int_picksplit(PG_FUNCTION_ARGS)
     430             : {
     431         340 :     GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
     432         340 :     GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
     433             :     OffsetNumber i,
     434             :                 j;
     435             :     ArrayType  *datum_alpha,
     436             :                *datum_beta;
     437             :     ArrayType  *datum_l,
     438             :                *datum_r;
     439             :     ArrayType  *union_d,
     440             :                *union_dl,
     441             :                *union_dr;
     442             :     ArrayType  *inter_d;
     443             :     bool        firsttime;
     444             :     float       size_alpha,
     445             :                 size_beta,
     446             :                 size_union,
     447             :                 size_inter;
     448             :     float       size_waste,
     449             :                 waste;
     450             :     float       size_l,
     451             :                 size_r;
     452             :     int         nbytes;
     453         340 :     OffsetNumber seed_1 = 0,
     454         340 :                 seed_2 = 0;
     455             :     OffsetNumber *left,
     456             :                *right;
     457             :     OffsetNumber maxoff;
     458             :     SPLITCOST  *costvector;
     459             : 
     460             : #ifdef GIST_DEBUG
     461             :     elog(DEBUG3, "--------picksplit %d", entryvec->n);
     462             : #endif
     463             : 
     464         340 :     maxoff = entryvec->n - 2;
     465         340 :     nbytes = (maxoff + 2) * sizeof(OffsetNumber);
     466         340 :     v->spl_left = (OffsetNumber *) palloc(nbytes);
     467         340 :     v->spl_right = (OffsetNumber *) palloc(nbytes);
     468             : 
     469         340 :     firsttime = true;
     470         340 :     waste = 0.0;
     471       40724 :     for (i = FirstOffsetNumber; i < maxoff; i = OffsetNumberNext(i))
     472             :     {
     473       40384 :         datum_alpha = GETENTRY(entryvec, i);
     474     2752486 :         for (j = OffsetNumberNext(i); j <= maxoff; j = OffsetNumberNext(j))
     475             :         {
     476     2712102 :             datum_beta = GETENTRY(entryvec, j);
     477             : 
     478             :             /* compute the wasted space by unioning these guys */
     479             :             /* size_waste = size_union - size_inter; */
     480     2712102 :             union_d = inner_int_union(datum_alpha, datum_beta);
     481     2712102 :             rt__int_size(union_d, &size_union);
     482     2712102 :             inter_d = inner_int_inter(datum_alpha, datum_beta);
     483     2712102 :             rt__int_size(inter_d, &size_inter);
     484     2712102 :             size_waste = size_union - size_inter;
     485             : 
     486     2712102 :             pfree(union_d);
     487     2712102 :             pfree(inter_d);
     488             : 
     489             :             /*
     490             :              * are these a more promising split that what we've already seen?
     491             :              */
     492             : 
     493     2712102 :             if (size_waste > waste || firsttime)
     494             :             {
     495        1910 :                 waste = size_waste;
     496        1910 :                 seed_1 = i;
     497        1910 :                 seed_2 = j;
     498        1910 :                 firsttime = false;
     499             :             }
     500             :         }
     501             :     }
     502             : 
     503         340 :     left = v->spl_left;
     504         340 :     v->spl_nleft = 0;
     505         340 :     right = v->spl_right;
     506         340 :     v->spl_nright = 0;
     507         340 :     if (seed_1 == 0 || seed_2 == 0)
     508             :     {
     509           0 :         seed_1 = 1;
     510           0 :         seed_2 = 2;
     511             :     }
     512             : 
     513         340 :     datum_alpha = GETENTRY(entryvec, seed_1);
     514         340 :     datum_l = copy_intArrayType(datum_alpha);
     515         340 :     rt__int_size(datum_l, &size_l);
     516         340 :     datum_beta = GETENTRY(entryvec, seed_2);
     517         340 :     datum_r = copy_intArrayType(datum_beta);
     518         340 :     rt__int_size(datum_r, &size_r);
     519             : 
     520         340 :     maxoff = OffsetNumberNext(maxoff);
     521             : 
     522             :     /*
     523             :      * sort entries
     524             :      */
     525         340 :     costvector = (SPLITCOST *) palloc(sizeof(SPLITCOST) * maxoff);
     526       41404 :     for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
     527             :     {
     528       41064 :         costvector[i - 1].pos = i;
     529       41064 :         datum_alpha = GETENTRY(entryvec, i);
     530       41064 :         union_d = inner_int_union(datum_l, datum_alpha);
     531       41064 :         rt__int_size(union_d, &size_alpha);
     532       41064 :         pfree(union_d);
     533       41064 :         union_d = inner_int_union(datum_r, datum_alpha);
     534       41064 :         rt__int_size(union_d, &size_beta);
     535       41064 :         pfree(union_d);
     536       41064 :         costvector[i - 1].cost = Abs((size_alpha - size_l) - (size_beta - size_r));
     537             :     }
     538         340 :     qsort((void *) costvector, maxoff, sizeof(SPLITCOST), comparecost);
     539             : 
     540             :     /*
     541             :      * Now split up the regions between the two seeds.  An important property
     542             :      * of this split algorithm is that the split vector v has the indices of
     543             :      * items to be split in order in its left and right vectors.  We exploit
     544             :      * this property by doing a merge in the code that actually splits the
     545             :      * page.
     546             :      *
     547             :      * For efficiency, we also place the new index tuple in this loop. This is
     548             :      * handled at the very end, when we have placed all the existing tuples
     549             :      * and i == maxoff + 1.
     550             :      */
     551             : 
     552             : 
     553       41404 :     for (j = 0; j < maxoff; j++)
     554             :     {
     555       41064 :         i = costvector[j].pos;
     556             : 
     557             :         /*
     558             :          * If we've already decided where to place this item, just put it on
     559             :          * the right list.  Otherwise, we need to figure out which page needs
     560             :          * the least enlargement in order to store the item.
     561             :          */
     562             : 
     563       41064 :         if (i == seed_1)
     564             :         {
     565         340 :             *left++ = i;
     566         340 :             v->spl_nleft++;
     567         340 :             continue;
     568             :         }
     569       40724 :         else if (i == seed_2)
     570             :         {
     571         340 :             *right++ = i;
     572         340 :             v->spl_nright++;
     573         340 :             continue;
     574             :         }
     575             : 
     576             :         /* okay, which page needs least enlargement? */
     577       40384 :         datum_alpha = GETENTRY(entryvec, i);
     578       40384 :         union_dl = inner_int_union(datum_l, datum_alpha);
     579       40384 :         union_dr = inner_int_union(datum_r, datum_alpha);
     580       40384 :         rt__int_size(union_dl, &size_alpha);
     581       40384 :         rt__int_size(union_dr, &size_beta);
     582             : 
     583             :         /* pick which page to add it to */
     584       40384 :         if (size_alpha - size_l < size_beta - size_r + WISH_F(v->spl_nleft, v->spl_nright, 0.01))
     585             :         {
     586       20030 :             pfree(datum_l);
     587       20030 :             pfree(union_dr);
     588       20030 :             datum_l = union_dl;
     589       20030 :             size_l = size_alpha;
     590       20030 :             *left++ = i;
     591       20030 :             v->spl_nleft++;
     592             :         }
     593             :         else
     594             :         {
     595       20354 :             pfree(datum_r);
     596       20354 :             pfree(union_dl);
     597       20354 :             datum_r = union_dr;
     598       20354 :             size_r = size_beta;
     599       20354 :             *right++ = i;
     600       20354 :             v->spl_nright++;
     601             :         }
     602             :     }
     603         340 :     pfree(costvector);
     604         340 :     *right = *left = FirstOffsetNumber;
     605             : 
     606         340 :     v->spl_ldatum = PointerGetDatum(datum_l);
     607         340 :     v->spl_rdatum = PointerGetDatum(datum_r);
     608             : 
     609         340 :     PG_RETURN_POINTER(v);
     610             : }
     611             : 
     612             : Datum
     613          18 : g_int_options(PG_FUNCTION_ARGS)
     614             : {
     615          18 :     local_relopts *relopts = (local_relopts *) PG_GETARG_POINTER(0);
     616             : 
     617          18 :     init_local_reloptions(relopts, sizeof(GISTIntArrayOptions));
     618          18 :     add_local_int_reloption(relopts, "numranges",
     619             :                             "number of ranges for compression",
     620             :                             G_INT_NUMRANGES_DEFAULT, 1, G_INT_NUMRANGES_MAX,
     621             :                             offsetof(GISTIntArrayOptions, num_ranges));
     622             : 
     623          18 :     PG_RETURN_VOID();
     624             : }

Generated by: LCOV version 1.13