LCOV - code coverage report
Current view: top level - contrib/seg - seg.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 74.9 % 431 323
Test Date: 2026-02-17 17:20:33 Functions: 87.9 % 66 58
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*
       2              :  * contrib/seg/seg.c
       3              :  *
       4              :  ******************************************************************************
       5              :   This file contains routines that can be bound to a Postgres backend and
       6              :   called by the backend in the process of processing queries.  The calling
       7              :   format for these routines is dictated by Postgres architecture.
       8              : ******************************************************************************/
       9              : 
      10              : #include "postgres.h"
      11              : 
      12              : #include <float.h>
      13              : #include <math.h>
      14              : 
      15              : #include "access/gist.h"
      16              : #include "access/stratnum.h"
      17              : #include "fmgr.h"
      18              : 
      19              : #include "segdata.h"
      20              : 
      21              : 
      22              : #define DatumGetSegP(X) ((SEG *) DatumGetPointer(X))
      23              : #define PG_GETARG_SEG_P(n) DatumGetSegP(PG_GETARG_DATUM(n))
      24              : 
      25              : 
      26              : /*
      27              : #define GIST_DEBUG
      28              : #define GIST_QUERY_DEBUG
      29              : */
      30              : 
      31            3 : PG_MODULE_MAGIC_EXT(
      32              :                     .name = "seg",
      33              :                     .version = PG_VERSION
      34              : );
      35              : 
      36              : /*
      37              :  * Auxiliary data structure for picksplit method.
      38              :  */
      39              : typedef struct
      40              : {
      41              :     float       center;
      42              :     OffsetNumber index;
      43              :     SEG        *data;
      44              : } gseg_picksplit_item;
      45              : 
      46              : /*
      47              : ** Input/Output routines
      48              : */
      49            4 : PG_FUNCTION_INFO_V1(seg_in);
      50            3 : PG_FUNCTION_INFO_V1(seg_out);
      51            2 : PG_FUNCTION_INFO_V1(seg_size);
      52            3 : PG_FUNCTION_INFO_V1(seg_lower);
      53            3 : PG_FUNCTION_INFO_V1(seg_upper);
      54            3 : PG_FUNCTION_INFO_V1(seg_center);
      55              : 
      56              : /*
      57              : ** GiST support methods
      58              : */
      59            3 : PG_FUNCTION_INFO_V1(gseg_consistent);
      60            2 : PG_FUNCTION_INFO_V1(gseg_compress);
      61            2 : PG_FUNCTION_INFO_V1(gseg_decompress);
      62            3 : PG_FUNCTION_INFO_V1(gseg_picksplit);
      63            3 : PG_FUNCTION_INFO_V1(gseg_penalty);
      64            3 : PG_FUNCTION_INFO_V1(gseg_union);
      65            3 : PG_FUNCTION_INFO_V1(gseg_same);
      66              : static Datum gseg_leaf_consistent(Datum key, Datum query, StrategyNumber strategy);
      67              : static Datum gseg_internal_consistent(Datum key, Datum query, StrategyNumber strategy);
      68              : static Datum gseg_binary_union(Datum r1, Datum r2, int *sizep);
      69              : 
      70              : 
      71              : /*
      72              : ** R-tree support functions
      73              : */
      74            3 : PG_FUNCTION_INFO_V1(seg_same);
      75            3 : PG_FUNCTION_INFO_V1(seg_contains);
      76            3 : PG_FUNCTION_INFO_V1(seg_contained);
      77            3 : PG_FUNCTION_INFO_V1(seg_overlap);
      78            3 : PG_FUNCTION_INFO_V1(seg_left);
      79            3 : PG_FUNCTION_INFO_V1(seg_over_left);
      80            3 : PG_FUNCTION_INFO_V1(seg_right);
      81            3 : PG_FUNCTION_INFO_V1(seg_over_right);
      82            2 : PG_FUNCTION_INFO_V1(seg_union);
      83            2 : PG_FUNCTION_INFO_V1(seg_inter);
      84              : static void rt_seg_size(SEG *a, float *size);
      85              : 
      86              : /*
      87              : ** Various operators
      88              : */
      89            4 : PG_FUNCTION_INFO_V1(seg_cmp);
      90            2 : PG_FUNCTION_INFO_V1(seg_lt);
      91            2 : PG_FUNCTION_INFO_V1(seg_le);
      92            2 : PG_FUNCTION_INFO_V1(seg_gt);
      93            2 : PG_FUNCTION_INFO_V1(seg_ge);
      94            3 : PG_FUNCTION_INFO_V1(seg_different);
      95              : 
      96              : /*
      97              : ** Auxiliary functions
      98              : */
      99              : static int  restore(char *result, float val, int n);
     100              : 
     101              : 
     102              : /*****************************************************************************
     103              :  * Input/Output functions
     104              :  *****************************************************************************/
     105              : 
     106              : Datum
     107         2825 : seg_in(PG_FUNCTION_ARGS)
     108              : {
     109         2825 :     char       *str = PG_GETARG_CSTRING(0);
     110         2825 :     SEG        *result = palloc_object(SEG);
     111              :     yyscan_t    scanner;
     112              : 
     113         2825 :     seg_scanner_init(str, &scanner);
     114              : 
     115         2825 :     if (seg_yyparse(result, fcinfo->context, scanner) != 0)
     116            8 :         seg_yyerror(result, fcinfo->context, scanner, "bogus input");
     117              : 
     118         2816 :     seg_scanner_finish(scanner);
     119              : 
     120         2816 :     PG_RETURN_POINTER(result);
     121              : }
     122              : 
     123              : Datum
     124          209 : seg_out(PG_FUNCTION_ARGS)
     125              : {
     126          209 :     SEG        *seg = PG_GETARG_SEG_P(0);
     127              :     char       *result;
     128              :     char       *p;
     129              : 
     130          209 :     p = result = (char *) palloc(40);
     131              : 
     132          209 :     if (seg->l_ext == '>' || seg->l_ext == '<' || seg->l_ext == '~')
     133           22 :         p += sprintf(p, "%c", seg->l_ext);
     134              : 
     135          209 :     if (seg->lower == seg->upper && seg->l_ext == seg->u_ext)
     136              :     {
     137              :         /*
     138              :          * indicates that this interval was built by seg_in off a single point
     139              :          */
     140           47 :         p += restore(p, seg->lower, seg->l_sigd);
     141              :     }
     142              :     else
     143              :     {
     144          162 :         if (seg->l_ext != '-')
     145              :         {
     146              :             /* print the lower boundary if exists */
     147          155 :             p += restore(p, seg->lower, seg->l_sigd);
     148          155 :             p += sprintf(p, " ");
     149              :         }
     150          162 :         p += sprintf(p, "..");
     151          162 :         if (seg->u_ext != '-')
     152              :         {
     153              :             /* print the upper boundary if exists */
     154          123 :             p += sprintf(p, " ");
     155          123 :             if (seg->u_ext == '>' || seg->u_ext == '<' || seg->l_ext == '~')
     156           32 :                 p += sprintf(p, "%c", seg->u_ext);
     157          123 :             p += restore(p, seg->upper, seg->u_sigd);
     158              :         }
     159              :     }
     160              : 
     161          209 :     PG_RETURN_CSTRING(result);
     162              : }
     163              : 
     164              : Datum
     165          143 : seg_center(PG_FUNCTION_ARGS)
     166              : {
     167          143 :     SEG        *seg = PG_GETARG_SEG_P(0);
     168              : 
     169          143 :     PG_RETURN_FLOAT4(((float) seg->lower + (float) seg->upper) / 2.0);
     170              : }
     171              : 
     172              : Datum
     173          143 : seg_lower(PG_FUNCTION_ARGS)
     174              : {
     175          143 :     SEG        *seg = PG_GETARG_SEG_P(0);
     176              : 
     177          143 :     PG_RETURN_FLOAT4(seg->lower);
     178              : }
     179              : 
     180              : Datum
     181          143 : seg_upper(PG_FUNCTION_ARGS)
     182              : {
     183          143 :     SEG        *seg = PG_GETARG_SEG_P(0);
     184              : 
     185          143 :     PG_RETURN_FLOAT4(seg->upper);
     186              : }
     187              : 
     188              : 
     189              : /*****************************************************************************
     190              :  *                         GiST functions
     191              :  *****************************************************************************/
     192              : 
     193              : /*
     194              : ** The GiST Consistent method for segments
     195              : ** Should return false if for all data items x below entry,
     196              : ** the predicate x op query == false, where op is the oper
     197              : ** corresponding to strategy in the pg_amop table.
     198              : */
     199              : Datum
     200         5816 : gseg_consistent(PG_FUNCTION_ARGS)
     201              : {
     202         5816 :     GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
     203         5816 :     Datum       query = PG_GETARG_DATUM(1);
     204         5816 :     StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
     205              : #ifdef NOT_USED
     206              :     Oid         subtype = PG_GETARG_OID(3);
     207              : #endif
     208         5816 :     bool       *recheck = (bool *) PG_GETARG_POINTER(4);
     209              : 
     210              :     /* All cases served by this function are exact */
     211         5816 :     *recheck = false;
     212              : 
     213              :     /*
     214              :      * if entry is not leaf, use gseg_internal_consistent, else use
     215              :      * gseg_leaf_consistent
     216              :      */
     217         5816 :     if (GIST_LEAF(entry))
     218         5744 :         return gseg_leaf_consistent(entry->key, query, strategy);
     219              :     else
     220           72 :         return gseg_internal_consistent(entry->key, query, strategy);
     221              : }
     222              : 
     223              : /*
     224              : ** The GiST Union method for segments
     225              : ** returns the minimal bounding seg that encloses all the entries in entryvec
     226              : */
     227              : Datum
     228         2316 : gseg_union(PG_FUNCTION_ARGS)
     229              : {
     230         2316 :     GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
     231         2316 :     int        *sizep = (int *) PG_GETARG_POINTER(1);
     232              :     int         numranges,
     233              :                 i;
     234         2316 :     Datum       out = 0;
     235              :     Datum       tmp;
     236              : 
     237              : #ifdef GIST_DEBUG
     238              :     fprintf(stderr, "union\n");
     239              : #endif
     240              : 
     241         2316 :     numranges = entryvec->n;
     242         2316 :     tmp = entryvec->vector[0].key;
     243         2316 :     *sizep = sizeof(SEG);
     244              : 
     245         4632 :     for (i = 1; i < numranges; i++)
     246              :     {
     247         2316 :         out = gseg_binary_union(tmp, entryvec->vector[i].key, sizep);
     248         2316 :         tmp = out;
     249              :     }
     250              : 
     251         2316 :     PG_RETURN_DATUM(out);
     252              : }
     253              : 
     254              : /*
     255              : ** GiST Compress and Decompress methods for segments
     256              : ** do not do anything.
     257              : */
     258              : Datum
     259            0 : gseg_compress(PG_FUNCTION_ARGS)
     260              : {
     261            0 :     PG_RETURN_POINTER(PG_GETARG_POINTER(0));
     262              : }
     263              : 
     264              : Datum
     265            0 : gseg_decompress(PG_FUNCTION_ARGS)
     266              : {
     267            0 :     PG_RETURN_POINTER(PG_GETARG_POINTER(0));
     268              : }
     269              : 
     270              : /*
     271              : ** The GiST Penalty method for segments
     272              : ** As in the R-tree paper, we use change in area as our penalty metric
     273              : */
     274              : Datum
     275         4911 : gseg_penalty(PG_FUNCTION_ARGS)
     276              : {
     277         4911 :     GISTENTRY  *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
     278         4911 :     GISTENTRY  *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
     279         4911 :     float      *result = (float *) PG_GETARG_POINTER(2);
     280              :     SEG        *ud;
     281              :     float       tmp1,
     282              :                 tmp2;
     283              : 
     284         4911 :     ud = DatumGetSegP(DirectFunctionCall2(seg_union,
     285              :                                           origentry->key,
     286              :                                           newentry->key));
     287         4911 :     rt_seg_size(ud, &tmp1);
     288         4911 :     rt_seg_size(DatumGetSegP(origentry->key), &tmp2);
     289         4911 :     *result = tmp1 - tmp2;
     290              : 
     291              : #ifdef GIST_DEBUG
     292              :     fprintf(stderr, "penalty\n");
     293              :     fprintf(stderr, "\t%g\n", *result);
     294              : #endif
     295              : 
     296         4911 :     PG_RETURN_POINTER(result);
     297              : }
     298              : 
     299              : /*
     300              :  * Compare function for gseg_picksplit_item: sort by center.
     301              :  */
     302              : static int
     303        28962 : gseg_picksplit_item_cmp(const void *a, const void *b)
     304              : {
     305        28962 :     const gseg_picksplit_item *i1 = (const gseg_picksplit_item *) a;
     306        28962 :     const gseg_picksplit_item *i2 = (const gseg_picksplit_item *) b;
     307              : 
     308        28962 :     if (i1->center < i2->center)
     309        12059 :         return -1;
     310        16903 :     else if (i1->center == i2->center)
     311         5106 :         return 0;
     312              :     else
     313        11797 :         return 1;
     314              : }
     315              : 
     316              : /*
     317              :  * The GiST PickSplit method for segments
     318              :  *
     319              :  * We used to use Guttman's split algorithm here, but since the data is 1-D
     320              :  * it's easier and more robust to just sort the segments by center-point and
     321              :  * split at the middle.
     322              :  */
     323              : Datum
     324           17 : gseg_picksplit(PG_FUNCTION_ARGS)
     325              : {
     326           17 :     GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
     327           17 :     GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
     328              :     int         i;
     329              :     SEG        *seg,
     330              :                *seg_l,
     331              :                *seg_r;
     332              :     gseg_picksplit_item *sort_items;
     333              :     OffsetNumber *left,
     334              :                *right;
     335              :     OffsetNumber maxoff;
     336              :     OffsetNumber firstright;
     337              : 
     338              : #ifdef GIST_DEBUG
     339              :     fprintf(stderr, "picksplit\n");
     340              : #endif
     341              : 
     342              :     /* Valid items in entryvec->vector[] are indexed 1..maxoff */
     343           17 :     maxoff = entryvec->n - 1;
     344              : 
     345              :     /*
     346              :      * Prepare the auxiliary array and sort it.
     347              :      */
     348              :     sort_items = (gseg_picksplit_item *)
     349           17 :         palloc(maxoff * sizeof(gseg_picksplit_item));
     350         4471 :     for (i = 1; i <= maxoff; i++)
     351              :     {
     352         4454 :         seg = DatumGetSegP(entryvec->vector[i].key);
     353              :         /* center calculation is done this way to avoid possible overflow */
     354         4454 :         sort_items[i - 1].center = seg->lower * 0.5f + seg->upper * 0.5f;
     355         4454 :         sort_items[i - 1].index = i;
     356         4454 :         sort_items[i - 1].data = seg;
     357              :     }
     358           17 :     qsort(sort_items, maxoff, sizeof(gseg_picksplit_item),
     359              :           gseg_picksplit_item_cmp);
     360              : 
     361              :     /* sort items below "firstright" will go into the left side */
     362           17 :     firstright = maxoff / 2;
     363              : 
     364           17 :     v->spl_left = (OffsetNumber *) palloc(maxoff * sizeof(OffsetNumber));
     365           17 :     v->spl_right = (OffsetNumber *) palloc(maxoff * sizeof(OffsetNumber));
     366           17 :     left = v->spl_left;
     367           17 :     v->spl_nleft = 0;
     368           17 :     right = v->spl_right;
     369           17 :     v->spl_nright = 0;
     370              : 
     371              :     /*
     372              :      * Emit segments to the left output page, and compute its bounding box.
     373              :      */
     374           17 :     seg_l = palloc_object(SEG);
     375           17 :     memcpy(seg_l, sort_items[0].data, sizeof(SEG));
     376           17 :     *left++ = sort_items[0].index;
     377           17 :     v->spl_nleft++;
     378         2227 :     for (i = 1; i < firstright; i++)
     379              :     {
     380         2210 :         Datum       sortitem = PointerGetDatum(sort_items[i].data);
     381              : 
     382         2210 :         seg_l = DatumGetSegP(DirectFunctionCall2(seg_union,
     383              :                                                  PointerGetDatum(seg_l),
     384              :                                                  sortitem));
     385         2210 :         *left++ = sort_items[i].index;
     386         2210 :         v->spl_nleft++;
     387              :     }
     388              : 
     389              :     /*
     390              :      * Likewise for the right page.
     391              :      */
     392           17 :     seg_r = palloc_object(SEG);
     393           17 :     memcpy(seg_r, sort_items[firstright].data, sizeof(SEG));
     394           17 :     *right++ = sort_items[firstright].index;
     395           17 :     v->spl_nright++;
     396         2227 :     for (i = firstright + 1; i < maxoff; i++)
     397              :     {
     398         2210 :         Datum       sortitem = PointerGetDatum(sort_items[i].data);
     399              : 
     400         2210 :         seg_r = DatumGetSegP(DirectFunctionCall2(seg_union,
     401              :                                                  PointerGetDatum(seg_r),
     402              :                                                  sortitem));
     403         2210 :         *right++ = sort_items[i].index;
     404         2210 :         v->spl_nright++;
     405              :     }
     406              : 
     407           17 :     v->spl_ldatum = PointerGetDatum(seg_l);
     408           17 :     v->spl_rdatum = PointerGetDatum(seg_r);
     409              : 
     410           17 :     PG_RETURN_POINTER(v);
     411              : }
     412              : 
     413              : /*
     414              : ** Equality methods
     415              : */
     416              : Datum
     417         2315 : gseg_same(PG_FUNCTION_ARGS)
     418              : {
     419         2315 :     bool       *result = (bool *) PG_GETARG_POINTER(2);
     420              : 
     421         2315 :     if (DatumGetBool(DirectFunctionCall2(seg_same, PG_GETARG_DATUM(0), PG_GETARG_DATUM(1))))
     422         2277 :         *result = true;
     423              :     else
     424           38 :         *result = false;
     425              : 
     426              : #ifdef GIST_DEBUG
     427              :     fprintf(stderr, "same: %s\n", (*result ? "TRUE" : "FALSE"));
     428              : #endif
     429              : 
     430         2315 :     PG_RETURN_POINTER(result);
     431              : }
     432              : 
     433              : /*
     434              : ** SUPPORT ROUTINES
     435              : */
     436              : static Datum
     437         5744 : gseg_leaf_consistent(Datum key, Datum query, StrategyNumber strategy)
     438              : {
     439              :     Datum       retval;
     440              : 
     441              : #ifdef GIST_QUERY_DEBUG
     442              :     fprintf(stderr, "leaf_consistent, %d\n", strategy);
     443              : #endif
     444              : 
     445         5744 :     switch (strategy)
     446              :     {
     447            0 :         case RTLeftStrategyNumber:
     448            0 :             retval = DirectFunctionCall2(seg_left, key, query);
     449            0 :             break;
     450            0 :         case RTOverLeftStrategyNumber:
     451            0 :             retval = DirectFunctionCall2(seg_over_left, key, query);
     452            0 :             break;
     453            0 :         case RTOverlapStrategyNumber:
     454            0 :             retval = DirectFunctionCall2(seg_overlap, key, query);
     455            0 :             break;
     456            0 :         case RTOverRightStrategyNumber:
     457            0 :             retval = DirectFunctionCall2(seg_over_right, key, query);
     458            0 :             break;
     459            0 :         case RTRightStrategyNumber:
     460            0 :             retval = DirectFunctionCall2(seg_right, key, query);
     461            0 :             break;
     462            0 :         case RTSameStrategyNumber:
     463            0 :             retval = DirectFunctionCall2(seg_same, key, query);
     464            0 :             break;
     465         5744 :         case RTContainsStrategyNumber:
     466              :         case RTOldContainsStrategyNumber:
     467         5744 :             retval = DirectFunctionCall2(seg_contains, key, query);
     468         5744 :             break;
     469            0 :         case RTContainedByStrategyNumber:
     470              :         case RTOldContainedByStrategyNumber:
     471            0 :             retval = DirectFunctionCall2(seg_contained, key, query);
     472            0 :             break;
     473            0 :         default:
     474            0 :             retval = BoolGetDatum(false);
     475              :     }
     476              : 
     477         5744 :     PG_RETURN_DATUM(retval);
     478              : }
     479              : 
     480              : static Datum
     481           72 : gseg_internal_consistent(Datum key, Datum query, StrategyNumber strategy)
     482              : {
     483              :     bool        retval;
     484              : 
     485              : #ifdef GIST_QUERY_DEBUG
     486              :     fprintf(stderr, "internal_consistent, %d\n", strategy);
     487              : #endif
     488              : 
     489           72 :     switch (strategy)
     490              :     {
     491            0 :         case RTLeftStrategyNumber:
     492            0 :             retval =
     493            0 :                 !DatumGetBool(DirectFunctionCall2(seg_over_right, key, query));
     494            0 :             break;
     495            0 :         case RTOverLeftStrategyNumber:
     496            0 :             retval =
     497            0 :                 !DatumGetBool(DirectFunctionCall2(seg_right, key, query));
     498            0 :             break;
     499            0 :         case RTOverlapStrategyNumber:
     500              :             retval =
     501            0 :                 DatumGetBool(DirectFunctionCall2(seg_overlap, key, query));
     502            0 :             break;
     503            0 :         case RTOverRightStrategyNumber:
     504            0 :             retval =
     505            0 :                 !DatumGetBool(DirectFunctionCall2(seg_left, key, query));
     506            0 :             break;
     507            0 :         case RTRightStrategyNumber:
     508            0 :             retval =
     509            0 :                 !DatumGetBool(DirectFunctionCall2(seg_over_left, key, query));
     510            0 :             break;
     511           72 :         case RTSameStrategyNumber:
     512              :         case RTContainsStrategyNumber:
     513              :         case RTOldContainsStrategyNumber:
     514              :             retval =
     515           72 :                 DatumGetBool(DirectFunctionCall2(seg_contains, key, query));
     516           72 :             break;
     517            0 :         case RTContainedByStrategyNumber:
     518              :         case RTOldContainedByStrategyNumber:
     519              :             retval =
     520            0 :                 DatumGetBool(DirectFunctionCall2(seg_overlap, key, query));
     521            0 :             break;
     522            0 :         default:
     523            0 :             retval = false;
     524              :     }
     525              : 
     526           72 :     PG_RETURN_BOOL(retval);
     527              : }
     528              : 
     529              : static Datum
     530         2316 : gseg_binary_union(Datum r1, Datum r2, int *sizep)
     531              : {
     532              :     Datum       retval;
     533              : 
     534         2316 :     retval = DirectFunctionCall2(seg_union, r1, r2);
     535         2316 :     *sizep = sizeof(SEG);
     536              : 
     537         2316 :     return retval;
     538              : }
     539              : 
     540              : 
     541              : Datum
     542         5831 : seg_contains(PG_FUNCTION_ARGS)
     543              : {
     544         5831 :     SEG        *a = PG_GETARG_SEG_P(0);
     545         5831 :     SEG        *b = PG_GETARG_SEG_P(1);
     546              : 
     547         5831 :     PG_RETURN_BOOL((a->lower <= b->lower) && (a->upper >= b->upper));
     548              : }
     549              : 
     550              : Datum
     551           14 : seg_contained(PG_FUNCTION_ARGS)
     552              : {
     553           14 :     Datum       a = PG_GETARG_DATUM(0);
     554           14 :     Datum       b = PG_GETARG_DATUM(1);
     555              : 
     556           14 :     PG_RETURN_DATUM(DirectFunctionCall2(seg_contains, b, a));
     557              : }
     558              : 
     559              : /*****************************************************************************
     560              :  * Operator class for R-tree indexing
     561              :  *****************************************************************************/
     562              : 
     563              : Datum
     564         2459 : seg_same(PG_FUNCTION_ARGS)
     565              : {
     566         2459 :     int         cmp = DatumGetInt32(DirectFunctionCall2(seg_cmp,
     567              :                                                         PG_GETARG_DATUM(0),
     568              :                                                         PG_GETARG_DATUM(1)));
     569              : 
     570         2459 :     PG_RETURN_BOOL(cmp == 0);
     571              : }
     572              : 
     573              : /*  seg_overlap -- does a overlap b?
     574              :  */
     575              : Datum
     576           15 : seg_overlap(PG_FUNCTION_ARGS)
     577              : {
     578           15 :     SEG        *a = PG_GETARG_SEG_P(0);
     579           15 :     SEG        *b = PG_GETARG_SEG_P(1);
     580              : 
     581           15 :     PG_RETURN_BOOL(((a->upper >= b->upper) && (a->lower <= b->upper)) ||
     582              :                    ((b->upper >= a->upper) && (b->lower <= a->upper)));
     583              : }
     584              : 
     585              : /*  seg_over_left -- is the right edge of (a) located at or left of the right edge of (b)?
     586              :  */
     587              : Datum
     588           11 : seg_over_left(PG_FUNCTION_ARGS)
     589              : {
     590           11 :     SEG        *a = PG_GETARG_SEG_P(0);
     591           11 :     SEG        *b = PG_GETARG_SEG_P(1);
     592              : 
     593           11 :     PG_RETURN_BOOL(a->upper <= b->upper);
     594              : }
     595              : 
     596              : /*  seg_left -- is (a) entirely on the left of (b)?
     597              :  */
     598              : Datum
     599           11 : seg_left(PG_FUNCTION_ARGS)
     600              : {
     601           11 :     SEG        *a = PG_GETARG_SEG_P(0);
     602           11 :     SEG        *b = PG_GETARG_SEG_P(1);
     603              : 
     604           11 :     PG_RETURN_BOOL(a->upper < b->lower);
     605              : }
     606              : 
     607              : /*  seg_right -- is (a) entirely on the right of (b)?
     608              :  */
     609              : Datum
     610           11 : seg_right(PG_FUNCTION_ARGS)
     611              : {
     612           11 :     SEG        *a = PG_GETARG_SEG_P(0);
     613           11 :     SEG        *b = PG_GETARG_SEG_P(1);
     614              : 
     615           11 :     PG_RETURN_BOOL(a->lower > b->upper);
     616              : }
     617              : 
     618              : /*  seg_over_right -- is the left edge of (a) located at or right of the left edge of (b)?
     619              :  */
     620              : Datum
     621           11 : seg_over_right(PG_FUNCTION_ARGS)
     622              : {
     623           11 :     SEG        *a = PG_GETARG_SEG_P(0);
     624           11 :     SEG        *b = PG_GETARG_SEG_P(1);
     625              : 
     626           11 :     PG_RETURN_BOOL(a->lower >= b->lower);
     627              : }
     628              : 
     629              : Datum
     630        11647 : seg_union(PG_FUNCTION_ARGS)
     631              : {
     632        11647 :     SEG        *a = PG_GETARG_SEG_P(0);
     633        11647 :     SEG        *b = PG_GETARG_SEG_P(1);
     634              :     SEG        *n;
     635              : 
     636        11647 :     n = palloc_object(SEG);
     637              : 
     638              :     /* take max of upper endpoints */
     639        11647 :     if (a->upper > b->upper)
     640              :     {
     641        10516 :         n->upper = a->upper;
     642        10516 :         n->u_sigd = a->u_sigd;
     643        10516 :         n->u_ext = a->u_ext;
     644              :     }
     645              :     else
     646              :     {
     647         1131 :         n->upper = b->upper;
     648         1131 :         n->u_sigd = b->u_sigd;
     649         1131 :         n->u_ext = b->u_ext;
     650              :     }
     651              : 
     652              :     /* take min of lower endpoints */
     653        11647 :     if (a->lower < b->lower)
     654              :     {
     655        11259 :         n->lower = a->lower;
     656        11259 :         n->l_sigd = a->l_sigd;
     657        11259 :         n->l_ext = a->l_ext;
     658              :     }
     659              :     else
     660              :     {
     661          388 :         n->lower = b->lower;
     662          388 :         n->l_sigd = b->l_sigd;
     663          388 :         n->l_ext = b->l_ext;
     664              :     }
     665              : 
     666        11647 :     PG_RETURN_POINTER(n);
     667              : }
     668              : 
     669              : Datum
     670            0 : seg_inter(PG_FUNCTION_ARGS)
     671              : {
     672            0 :     SEG        *a = PG_GETARG_SEG_P(0);
     673            0 :     SEG        *b = PG_GETARG_SEG_P(1);
     674              :     SEG        *n;
     675              : 
     676            0 :     n = palloc_object(SEG);
     677              : 
     678              :     /* take min of upper endpoints */
     679            0 :     if (a->upper < b->upper)
     680              :     {
     681            0 :         n->upper = a->upper;
     682            0 :         n->u_sigd = a->u_sigd;
     683            0 :         n->u_ext = a->u_ext;
     684              :     }
     685              :     else
     686              :     {
     687            0 :         n->upper = b->upper;
     688            0 :         n->u_sigd = b->u_sigd;
     689            0 :         n->u_ext = b->u_ext;
     690              :     }
     691              : 
     692              :     /* take max of lower endpoints */
     693            0 :     if (a->lower > b->lower)
     694              :     {
     695            0 :         n->lower = a->lower;
     696            0 :         n->l_sigd = a->l_sigd;
     697            0 :         n->l_ext = a->l_ext;
     698              :     }
     699              :     else
     700              :     {
     701            0 :         n->lower = b->lower;
     702            0 :         n->l_sigd = b->l_sigd;
     703            0 :         n->l_ext = b->l_ext;
     704              :     }
     705              : 
     706            0 :     PG_RETURN_POINTER(n);
     707              : }
     708              : 
     709              : static void
     710         9822 : rt_seg_size(SEG *a, float *size)
     711              : {
     712         9822 :     if (a == (SEG *) NULL || a->upper <= a->lower)
     713            0 :         *size = 0.0;
     714              :     else
     715         9822 :         *size = fabsf(a->upper - a->lower);
     716         9822 : }
     717              : 
     718              : Datum
     719            0 : seg_size(PG_FUNCTION_ARGS)
     720              : {
     721            0 :     SEG        *seg = PG_GETARG_SEG_P(0);
     722              : 
     723            0 :     PG_RETURN_FLOAT4(fabsf(seg->upper - seg->lower));
     724              : }
     725              : 
     726              : 
     727              : /*****************************************************************************
     728              :  *                 Miscellaneous operators
     729              :  *****************************************************************************/
     730              : Datum
     731         4433 : seg_cmp(PG_FUNCTION_ARGS)
     732              : {
     733         4433 :     SEG        *a = PG_GETARG_SEG_P(0);
     734         4433 :     SEG        *b = PG_GETARG_SEG_P(1);
     735              : 
     736              :     /*
     737              :      * First compare on lower boundary position
     738              :      */
     739         4433 :     if (a->lower < b->lower)
     740          904 :         PG_RETURN_INT32(-1);
     741         3529 :     if (a->lower > b->lower)
     742          800 :         PG_RETURN_INT32(1);
     743              : 
     744              :     /*
     745              :      * a->lower == b->lower, so consider type of boundary.
     746              :      *
     747              :      * A '-' lower bound is < any other kind (this could only be relevant if
     748              :      * -HUGE_VAL is used as a regular data value). A '<' lower bound is < any
     749              :      * other kind except '-'. A '>' lower bound is > any other kind.
     750              :      */
     751         2729 :     if (a->l_ext != b->l_ext)
     752              :     {
     753           67 :         if (a->l_ext == '-')
     754            0 :             PG_RETURN_INT32(-1);
     755           67 :         if (b->l_ext == '-')
     756            0 :             PG_RETURN_INT32(1);
     757           67 :         if (a->l_ext == '<')
     758           27 :             PG_RETURN_INT32(-1);
     759           40 :         if (b->l_ext == '<')
     760           21 :             PG_RETURN_INT32(1);
     761           19 :         if (a->l_ext == '>')
     762           13 :             PG_RETURN_INT32(1);
     763            6 :         if (b->l_ext == '>')
     764            6 :             PG_RETURN_INT32(-1);
     765              :     }
     766              : 
     767              :     /*
     768              :      * For other boundary types, consider # of significant digits first.
     769              :      */
     770         2662 :     if (a->l_sigd < b->l_sigd) /* (a) is blurred and is likely to include (b) */
     771           19 :         PG_RETURN_INT32(-1);
     772         2643 :     if (a->l_sigd > b->l_sigd) /* (a) is less blurred and is likely to be
     773              :                                  * included in (b) */
     774           18 :         PG_RETURN_INT32(1);
     775              : 
     776              :     /*
     777              :      * For same # of digits, an approximate boundary is more blurred than
     778              :      * exact.
     779              :      */
     780         2625 :     if (a->l_ext != b->l_ext)
     781              :     {
     782            0 :         if (a->l_ext == '~') /* (a) is approximate, while (b) is exact */
     783            0 :             PG_RETURN_INT32(-1);
     784            0 :         if (b->l_ext == '~')
     785            0 :             PG_RETURN_INT32(1);
     786              :         /* can't get here unless data is corrupt */
     787            0 :         elog(ERROR, "bogus lower boundary types %d %d",
     788              :              (int) a->l_ext, (int) b->l_ext);
     789              :     }
     790              : 
     791              :     /* at this point, the lower boundaries are identical */
     792              : 
     793              :     /*
     794              :      * First compare on upper boundary position
     795              :      */
     796         2625 :     if (a->upper < b->upper)
     797          163 :         PG_RETURN_INT32(-1);
     798         2462 :     if (a->upper > b->upper)
     799          126 :         PG_RETURN_INT32(1);
     800              : 
     801              :     /*
     802              :      * a->upper == b->upper, so consider type of boundary.
     803              :      *
     804              :      * A '-' upper bound is > any other kind (this could only be relevant if
     805              :      * HUGE_VAL is used as a regular data value). A '<' upper bound is < any
     806              :      * other kind. A '>' upper bound is > any other kind except '-'.
     807              :      */
     808         2336 :     if (a->u_ext != b->u_ext)
     809              :     {
     810           48 :         if (a->u_ext == '-')
     811            0 :             PG_RETURN_INT32(1);
     812           48 :         if (b->u_ext == '-')
     813            0 :             PG_RETURN_INT32(-1);
     814           48 :         if (a->u_ext == '<')
     815            3 :             PG_RETURN_INT32(-1);
     816           45 :         if (b->u_ext == '<')
     817            1 :             PG_RETURN_INT32(1);
     818           44 :         if (a->u_ext == '>')
     819           24 :             PG_RETURN_INT32(1);
     820           20 :         if (b->u_ext == '>')
     821           20 :             PG_RETURN_INT32(-1);
     822              :     }
     823              : 
     824              :     /*
     825              :      * For other boundary types, consider # of significant digits first. Note
     826              :      * result here is converse of the lower-boundary case.
     827              :      */
     828         2288 :     if (a->u_sigd < b->u_sigd) /* (a) is blurred and is likely to include (b) */
     829            2 :         PG_RETURN_INT32(1);
     830         2286 :     if (a->u_sigd > b->u_sigd) /* (a) is less blurred and is likely to be
     831              :                                  * included in (b) */
     832            7 :         PG_RETURN_INT32(-1);
     833              : 
     834              :     /*
     835              :      * For same # of digits, an approximate boundary is more blurred than
     836              :      * exact.  Again, result is converse of lower-boundary case.
     837              :      */
     838         2279 :     if (a->u_ext != b->u_ext)
     839              :     {
     840            0 :         if (a->u_ext == '~') /* (a) is approximate, while (b) is exact */
     841            0 :             PG_RETURN_INT32(1);
     842            0 :         if (b->u_ext == '~')
     843            0 :             PG_RETURN_INT32(-1);
     844              :         /* can't get here unless data is corrupt */
     845            0 :         elog(ERROR, "bogus upper boundary types %d %d",
     846              :              (int) a->u_ext, (int) b->u_ext);
     847              :     }
     848              : 
     849         2279 :     PG_RETURN_INT32(0);
     850              : }
     851              : 
     852              : Datum
     853            0 : seg_lt(PG_FUNCTION_ARGS)
     854              : {
     855            0 :     int         cmp = DatumGetInt32(DirectFunctionCall2(seg_cmp,
     856              :                                                         PG_GETARG_DATUM(0),
     857              :                                                         PG_GETARG_DATUM(1)));
     858              : 
     859            0 :     PG_RETURN_BOOL(cmp < 0);
     860              : }
     861              : 
     862              : Datum
     863            0 : seg_le(PG_FUNCTION_ARGS)
     864              : {
     865            0 :     int         cmp = DatumGetInt32(DirectFunctionCall2(seg_cmp,
     866              :                                                         PG_GETARG_DATUM(0),
     867              :                                                         PG_GETARG_DATUM(1)));
     868              : 
     869            0 :     PG_RETURN_BOOL(cmp <= 0);
     870              : }
     871              : 
     872              : Datum
     873            0 : seg_gt(PG_FUNCTION_ARGS)
     874              : {
     875            0 :     int         cmp = DatumGetInt32(DirectFunctionCall2(seg_cmp,
     876              :                                                         PG_GETARG_DATUM(0),
     877              :                                                         PG_GETARG_DATUM(1)));
     878              : 
     879            0 :     PG_RETURN_BOOL(cmp > 0);
     880              : }
     881              : 
     882              : Datum
     883            0 : seg_ge(PG_FUNCTION_ARGS)
     884              : {
     885            0 :     int         cmp = DatumGetInt32(DirectFunctionCall2(seg_cmp,
     886              :                                                         PG_GETARG_DATUM(0),
     887              :                                                         PG_GETARG_DATUM(1)));
     888              : 
     889            0 :     PG_RETURN_BOOL(cmp >= 0);
     890              : }
     891              : 
     892              : 
     893              : Datum
     894            2 : seg_different(PG_FUNCTION_ARGS)
     895              : {
     896            2 :     int         cmp = DatumGetInt32(DirectFunctionCall2(seg_cmp,
     897              :                                                         PG_GETARG_DATUM(0),
     898              :                                                         PG_GETARG_DATUM(1)));
     899              : 
     900            2 :     PG_RETURN_BOOL(cmp != 0);
     901              : }
     902              : 
     903              : 
     904              : 
     905              : /*****************************************************************************
     906              :  *                 Auxiliary functions
     907              :  *****************************************************************************/
     908              : 
     909              : /*
     910              :  * The purpose of this routine is to print the given floating point
     911              :  * value with exactly n significant digits.  Its behaviour
     912              :  * is similar to %.ng except it prints 8.00 where %.ng would
     913              :  * print 8.  Returns the length of the string written at "result".
     914              :  *
     915              :  * Caller must provide a sufficiently large result buffer; 16 bytes
     916              :  * should be enough for all known float implementations.
     917              :  */
     918              : static int
     919          325 : restore(char *result, float val, int n)
     920              : {
     921          325 :     char        buf[25] = {
     922              :         '0', '0', '0', '0', '0',
     923              :         '0', '0', '0', '0', '0',
     924              :         '0', '0', '0', '0', '0',
     925              :         '0', '0', '0', '0', '0',
     926              :         '0', '0', '0', '0', '\0'
     927              :     };
     928              :     char       *p;
     929              :     int         exp;
     930              :     int         i,
     931              :                 dp,
     932              :                 sign;
     933              : 
     934              :     /*
     935              :      * Put a cap on the number of significant digits to avoid garbage in the
     936              :      * output and ensure we don't overrun the result buffer.  (n should not be
     937              :      * negative, but check to protect ourselves against corrupted data.)
     938              :      */
     939          325 :     if (n <= 0)
     940            0 :         n = FLT_DIG;
     941              :     else
     942          325 :         n = Min(n, FLT_DIG);
     943              : 
     944              :     /* remember the sign */
     945          325 :     sign = (val < 0 ? 1 : 0);
     946              : 
     947              :     /* print, in %e style to start with */
     948          325 :     sprintf(result, "%.*e", n - 1, val);
     949              : 
     950              :     /* find the exponent */
     951          325 :     p = strchr(result, 'e');
     952              : 
     953              :     /* punt if we have 'inf' or similar */
     954          325 :     if (p == NULL)
     955            0 :         return strlen(result);
     956              : 
     957          325 :     exp = atoi(p + 1);
     958          325 :     if (exp == 0)
     959              :     {
     960              :         /* just truncate off the 'e+00' */
     961          169 :         *p = '\0';
     962              :     }
     963              :     else
     964              :     {
     965          156 :         if (abs(exp) <= 4)
     966              :         {
     967              :             /*
     968              :              * remove the decimal point from the mantissa and write the digits
     969              :              * to the buf array
     970              :              */
     971          637 :             for (p = result + sign, i = 10, dp = 0; *p != 'e'; p++, i++)
     972              :             {
     973          499 :                 buf[i] = *p;
     974          499 :                 if (*p == '.')
     975              :                 {
     976          130 :                     dp = i--;   /* skip the decimal point */
     977              :                 }
     978              :             }
     979          138 :             if (dp == 0)
     980            8 :                 dp = i--;       /* no decimal point was found in the above
     981              :                                  * for() loop */
     982              : 
     983          138 :             if (exp > 0)
     984              :             {
     985          133 :                 if (dp - 10 + exp >= n)
     986              :                 {
     987              :                     /*
     988              :                      * the decimal point is behind the last significant digit;
     989              :                      * the digits in between must be converted to the exponent
     990              :                      * and the decimal point placed after the first digit
     991              :                      */
     992           43 :                     exp = dp - 10 + exp - n;
     993           43 :                     buf[10 + n] = '\0';
     994              : 
     995              :                     /* insert the decimal point */
     996           43 :                     if (n > 1)
     997              :                     {
     998           39 :                         dp = 11;
     999          507 :                         for (i = 23; i > dp; i--)
    1000          468 :                             buf[i] = buf[i - 1];
    1001           39 :                         buf[dp] = '.';
    1002              :                     }
    1003              : 
    1004              :                     /*
    1005              :                      * adjust the exponent by the number of digits after the
    1006              :                      * decimal point
    1007              :                      */
    1008           43 :                     if (n > 1)
    1009           39 :                         sprintf(&buf[11 + n], "e%d", exp + n - 1);
    1010              :                     else
    1011            4 :                         sprintf(&buf[11], "e%d", exp + n - 1);
    1012              : 
    1013           43 :                     if (sign)
    1014              :                     {
    1015            0 :                         buf[9] = '-';
    1016            0 :                         strcpy(result, &buf[9]);
    1017              :                     }
    1018              :                     else
    1019           43 :                         strcpy(result, &buf[10]);
    1020              :                 }
    1021              :                 else
    1022              :                 {               /* insert the decimal point */
    1023           90 :                     dp += exp;
    1024         1080 :                     for (i = 23; i > dp; i--)
    1025          990 :                         buf[i] = buf[i - 1];
    1026           90 :                     buf[11 + n] = '\0';
    1027           90 :                     buf[dp] = '.';
    1028           90 :                     if (sign)
    1029              :                     {
    1030            0 :                         buf[9] = '-';
    1031            0 :                         strcpy(result, &buf[9]);
    1032              :                     }
    1033              :                     else
    1034           90 :                         strcpy(result, &buf[10]);
    1035              :                 }
    1036              :             }
    1037              :             else
    1038              :             {                   /* exp <= 0 */
    1039            5 :                 dp += exp - 1;
    1040            5 :                 buf[10 + n] = '\0';
    1041            5 :                 buf[dp] = '.';
    1042            5 :                 if (sign)
    1043              :                 {
    1044            0 :                     buf[dp - 2] = '-';
    1045            0 :                     strcpy(result, &buf[dp - 2]);
    1046              :                 }
    1047              :                 else
    1048            5 :                     strcpy(result, &buf[dp - 1]);
    1049              :             }
    1050              :         }
    1051              : 
    1052              :         /* do nothing for abs(exp) > 4; %e must be OK */
    1053              :         /* just get rid of zeroes after [eE]- and +zeroes after [Ee]. */
    1054              : 
    1055              :         /* ... this is not done yet. */
    1056              :     }
    1057          325 :     return strlen(result);
    1058              : }
    1059              : 
    1060              : 
    1061              : /*
    1062              : ** Miscellany
    1063              : */
    1064              : 
    1065              : /* find out the number of significant digits in a string representing
    1066              :  * a floating point number
    1067              :  */
    1068              : int
    1069         5191 : significant_digits(const char *s)
    1070              : {
    1071         5191 :     const char *p = s;
    1072              :     int         n,
    1073              :                 c,
    1074              :                 zeroes;
    1075              : 
    1076         5191 :     zeroes = 1;
    1077              :     /* skip leading zeroes and sign */
    1078         5330 :     for (c = *p; (c == '0' || c == '+' || c == '-') && c != 0; c = *(++p));
    1079              : 
    1080              :     /* skip decimal point and following zeroes */
    1081         5212 :     for (c = *p; (c == '0' || c == '.') && c != 0; c = *(++p))
    1082              :     {
    1083           21 :         if (c != '.')
    1084           11 :             zeroes++;
    1085              :     }
    1086              : 
    1087              :     /* count significant digits (n) */
    1088        20353 :     for (c = *p, n = 0; c != 0; c = *(++p))
    1089              :     {
    1090        15189 :         if (!((c >= '0' && c <= '9') || (c == '.')))
    1091           27 :             break;
    1092        15162 :         if (c != '.')
    1093        10617 :             n++;
    1094              :     }
    1095              : 
    1096         5191 :     if (!n)
    1097           98 :         return zeroes;
    1098              : 
    1099         5093 :     return n;
    1100              : }
        

Generated by: LCOV version 2.0-1