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

Generated by: LCOV version 1.14