LCOV - code coverage report
Current view: top level - contrib/seg - seg.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 0.0 % 502 0
Test Date: 2026-01-26 10:56:24 Functions: 0.0 % 66 0
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            0 : 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            0 : PG_FUNCTION_INFO_V1(seg_in);
      50            0 : PG_FUNCTION_INFO_V1(seg_out);
      51            0 : PG_FUNCTION_INFO_V1(seg_size);
      52            0 : PG_FUNCTION_INFO_V1(seg_lower);
      53            0 : PG_FUNCTION_INFO_V1(seg_upper);
      54            0 : PG_FUNCTION_INFO_V1(seg_center);
      55              : 
      56              : /*
      57              : ** GiST support methods
      58              : */
      59            0 : PG_FUNCTION_INFO_V1(gseg_consistent);
      60            0 : PG_FUNCTION_INFO_V1(gseg_compress);
      61            0 : PG_FUNCTION_INFO_V1(gseg_decompress);
      62            0 : PG_FUNCTION_INFO_V1(gseg_picksplit);
      63            0 : PG_FUNCTION_INFO_V1(gseg_penalty);
      64            0 : PG_FUNCTION_INFO_V1(gseg_union);
      65            0 : 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            0 : PG_FUNCTION_INFO_V1(seg_same);
      75            0 : PG_FUNCTION_INFO_V1(seg_contains);
      76            0 : PG_FUNCTION_INFO_V1(seg_contained);
      77            0 : PG_FUNCTION_INFO_V1(seg_overlap);
      78            0 : PG_FUNCTION_INFO_V1(seg_left);
      79            0 : PG_FUNCTION_INFO_V1(seg_over_left);
      80            0 : PG_FUNCTION_INFO_V1(seg_right);
      81            0 : PG_FUNCTION_INFO_V1(seg_over_right);
      82            0 : PG_FUNCTION_INFO_V1(seg_union);
      83            0 : PG_FUNCTION_INFO_V1(seg_inter);
      84              : static void rt_seg_size(SEG *a, float *size);
      85              : 
      86              : /*
      87              : ** Various operators
      88              : */
      89            0 : PG_FUNCTION_INFO_V1(seg_cmp);
      90            0 : PG_FUNCTION_INFO_V1(seg_lt);
      91            0 : PG_FUNCTION_INFO_V1(seg_le);
      92            0 : PG_FUNCTION_INFO_V1(seg_gt);
      93            0 : PG_FUNCTION_INFO_V1(seg_ge);
      94            0 : 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            0 : seg_in(PG_FUNCTION_ARGS)
     108              : {
     109            0 :         char       *str = PG_GETARG_CSTRING(0);
     110            0 :         SEG                *result = palloc_object(SEG);
     111            0 :         yyscan_t        scanner;
     112              : 
     113            0 :         seg_scanner_init(str, &scanner);
     114              : 
     115            0 :         if (seg_yyparse(result, fcinfo->context, scanner) != 0)
     116            0 :                 seg_yyerror(result, fcinfo->context, scanner, "bogus input");
     117              : 
     118            0 :         seg_scanner_finish(scanner);
     119              : 
     120            0 :         PG_RETURN_POINTER(result);
     121            0 : }
     122              : 
     123              : Datum
     124            0 : seg_out(PG_FUNCTION_ARGS)
     125              : {
     126            0 :         SEG                *seg = PG_GETARG_SEG_P(0);
     127            0 :         char       *result;
     128            0 :         char       *p;
     129              : 
     130            0 :         p = result = (char *) palloc(40);
     131              : 
     132            0 :         if (seg->l_ext == '>' || seg->l_ext == '<' || seg->l_ext == '~')
     133            0 :                 p += sprintf(p, "%c", seg->l_ext);
     134              : 
     135            0 :         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            0 :                 p += restore(p, seg->lower, seg->l_sigd);
     141            0 :         }
     142              :         else
     143              :         {
     144            0 :                 if (seg->l_ext != '-')
     145              :                 {
     146              :                         /* print the lower boundary if exists */
     147            0 :                         p += restore(p, seg->lower, seg->l_sigd);
     148            0 :                         p += sprintf(p, " ");
     149            0 :                 }
     150            0 :                 p += sprintf(p, "..");
     151            0 :                 if (seg->u_ext != '-')
     152              :                 {
     153              :                         /* print the upper boundary if exists */
     154            0 :                         p += sprintf(p, " ");
     155            0 :                         if (seg->u_ext == '>' || seg->u_ext == '<' || seg->l_ext == '~')
     156            0 :                                 p += sprintf(p, "%c", seg->u_ext);
     157            0 :                         p += restore(p, seg->upper, seg->u_sigd);
     158            0 :                 }
     159              :         }
     160              : 
     161            0 :         PG_RETURN_CSTRING(result);
     162            0 : }
     163              : 
     164              : Datum
     165            0 : seg_center(PG_FUNCTION_ARGS)
     166              : {
     167            0 :         SEG                *seg = PG_GETARG_SEG_P(0);
     168              : 
     169            0 :         PG_RETURN_FLOAT4(((float) seg->lower + (float) seg->upper) / 2.0);
     170            0 : }
     171              : 
     172              : Datum
     173            0 : seg_lower(PG_FUNCTION_ARGS)
     174              : {
     175            0 :         SEG                *seg = PG_GETARG_SEG_P(0);
     176              : 
     177            0 :         PG_RETURN_FLOAT4(seg->lower);
     178            0 : }
     179              : 
     180              : Datum
     181            0 : seg_upper(PG_FUNCTION_ARGS)
     182              : {
     183            0 :         SEG                *seg = PG_GETARG_SEG_P(0);
     184              : 
     185            0 :         PG_RETURN_FLOAT4(seg->upper);
     186            0 : }
     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            0 : gseg_consistent(PG_FUNCTION_ARGS)
     201              : {
     202            0 :         GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
     203            0 :         Datum           query = PG_GETARG_DATUM(1);
     204            0 :         StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
     205              : #ifdef NOT_USED
     206              :         Oid                     subtype = PG_GETARG_OID(3);
     207              : #endif
     208            0 :         bool       *recheck = (bool *) PG_GETARG_POINTER(4);
     209              : 
     210              :         /* All cases served by this function are exact */
     211            0 :         *recheck = false;
     212              : 
     213              :         /*
     214              :          * if entry is not leaf, use gseg_internal_consistent, else use
     215              :          * gseg_leaf_consistent
     216              :          */
     217            0 :         if (GIST_LEAF(entry))
     218            0 :                 return gseg_leaf_consistent(entry->key, query, strategy);
     219              :         else
     220            0 :                 return gseg_internal_consistent(entry->key, query, strategy);
     221            0 : }
     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            0 : gseg_union(PG_FUNCTION_ARGS)
     229              : {
     230            0 :         GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
     231            0 :         int                *sizep = (int *) PG_GETARG_POINTER(1);
     232            0 :         int                     numranges,
     233              :                                 i;
     234            0 :         Datum           out = 0;
     235            0 :         Datum           tmp;
     236              : 
     237              : #ifdef GIST_DEBUG
     238              :         fprintf(stderr, "union\n");
     239              : #endif
     240              : 
     241            0 :         numranges = entryvec->n;
     242            0 :         tmp = entryvec->vector[0].key;
     243            0 :         *sizep = sizeof(SEG);
     244              : 
     245            0 :         for (i = 1; i < numranges; i++)
     246              :         {
     247            0 :                 out = gseg_binary_union(tmp, entryvec->vector[i].key, sizep);
     248            0 :                 tmp = out;
     249            0 :         }
     250              : 
     251            0 :         PG_RETURN_DATUM(out);
     252            0 : }
     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            0 : gseg_penalty(PG_FUNCTION_ARGS)
     276              : {
     277            0 :         GISTENTRY  *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
     278            0 :         GISTENTRY  *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
     279            0 :         float      *result = (float *) PG_GETARG_POINTER(2);
     280            0 :         SEG                *ud;
     281            0 :         float           tmp1,
     282              :                                 tmp2;
     283              : 
     284            0 :         ud = DatumGetSegP(DirectFunctionCall2(seg_union,
     285              :                                                                                   origentry->key,
     286              :                                                                                   newentry->key));
     287            0 :         rt_seg_size(ud, &tmp1);
     288            0 :         rt_seg_size(DatumGetSegP(origentry->key), &tmp2);
     289            0 :         *result = tmp1 - tmp2;
     290              : 
     291              : #ifdef GIST_DEBUG
     292              :         fprintf(stderr, "penalty\n");
     293              :         fprintf(stderr, "\t%g\n", *result);
     294              : #endif
     295              : 
     296            0 :         PG_RETURN_POINTER(result);
     297            0 : }
     298              : 
     299              : /*
     300              :  * Compare function for gseg_picksplit_item: sort by center.
     301              :  */
     302              : static int
     303            0 : gseg_picksplit_item_cmp(const void *a, const void *b)
     304              : {
     305            0 :         const gseg_picksplit_item *i1 = (const gseg_picksplit_item *) a;
     306            0 :         const gseg_picksplit_item *i2 = (const gseg_picksplit_item *) b;
     307              : 
     308            0 :         if (i1->center < i2->center)
     309            0 :                 return -1;
     310            0 :         else if (i1->center == i2->center)
     311            0 :                 return 0;
     312              :         else
     313            0 :                 return 1;
     314            0 : }
     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            0 : gseg_picksplit(PG_FUNCTION_ARGS)
     325              : {
     326            0 :         GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
     327            0 :         GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
     328            0 :         int                     i;
     329            0 :         SEG                *seg,
     330              :                            *seg_l,
     331              :                            *seg_r;
     332            0 :         gseg_picksplit_item *sort_items;
     333            0 :         OffsetNumber *left,
     334              :                            *right;
     335            0 :         OffsetNumber maxoff;
     336            0 :         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            0 :         maxoff = entryvec->n - 1;
     344              : 
     345              :         /*
     346              :          * Prepare the auxiliary array and sort it.
     347              :          */
     348            0 :         sort_items = (gseg_picksplit_item *)
     349            0 :                 palloc(maxoff * sizeof(gseg_picksplit_item));
     350            0 :         for (i = 1; i <= maxoff; i++)
     351              :         {
     352            0 :                 seg = DatumGetSegP(entryvec->vector[i].key);
     353              :                 /* center calculation is done this way to avoid possible overflow */
     354            0 :                 sort_items[i - 1].center = seg->lower * 0.5f + seg->upper * 0.5f;
     355            0 :                 sort_items[i - 1].index = i;
     356            0 :                 sort_items[i - 1].data = seg;
     357            0 :         }
     358            0 :         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            0 :         firstright = maxoff / 2;
     363              : 
     364            0 :         v->spl_left = (OffsetNumber *) palloc(maxoff * sizeof(OffsetNumber));
     365            0 :         v->spl_right = (OffsetNumber *) palloc(maxoff * sizeof(OffsetNumber));
     366            0 :         left = v->spl_left;
     367            0 :         v->spl_nleft = 0;
     368            0 :         right = v->spl_right;
     369            0 :         v->spl_nright = 0;
     370              : 
     371              :         /*
     372              :          * Emit segments to the left output page, and compute its bounding box.
     373              :          */
     374            0 :         seg_l = palloc_object(SEG);
     375            0 :         memcpy(seg_l, sort_items[0].data, sizeof(SEG));
     376            0 :         *left++ = sort_items[0].index;
     377            0 :         v->spl_nleft++;
     378            0 :         for (i = 1; i < firstright; i++)
     379              :         {
     380            0 :                 Datum           sortitem = PointerGetDatum(sort_items[i].data);
     381              : 
     382            0 :                 seg_l = DatumGetSegP(DirectFunctionCall2(seg_union,
     383              :                                                                                                  PointerGetDatum(seg_l),
     384              :                                                                                                  sortitem));
     385            0 :                 *left++ = sort_items[i].index;
     386            0 :                 v->spl_nleft++;
     387            0 :         }
     388              : 
     389              :         /*
     390              :          * Likewise for the right page.
     391              :          */
     392            0 :         seg_r = palloc_object(SEG);
     393            0 :         memcpy(seg_r, sort_items[firstright].data, sizeof(SEG));
     394            0 :         *right++ = sort_items[firstright].index;
     395            0 :         v->spl_nright++;
     396            0 :         for (i = firstright + 1; i < maxoff; i++)
     397              :         {
     398            0 :                 Datum           sortitem = PointerGetDatum(sort_items[i].data);
     399              : 
     400            0 :                 seg_r = DatumGetSegP(DirectFunctionCall2(seg_union,
     401              :                                                                                                  PointerGetDatum(seg_r),
     402              :                                                                                                  sortitem));
     403            0 :                 *right++ = sort_items[i].index;
     404            0 :                 v->spl_nright++;
     405            0 :         }
     406              : 
     407            0 :         v->spl_ldatum = PointerGetDatum(seg_l);
     408            0 :         v->spl_rdatum = PointerGetDatum(seg_r);
     409              : 
     410            0 :         PG_RETURN_POINTER(v);
     411            0 : }
     412              : 
     413              : /*
     414              : ** Equality methods
     415              : */
     416              : Datum
     417            0 : gseg_same(PG_FUNCTION_ARGS)
     418              : {
     419            0 :         bool       *result = (bool *) PG_GETARG_POINTER(2);
     420              : 
     421            0 :         if (DatumGetBool(DirectFunctionCall2(seg_same, PG_GETARG_DATUM(0), PG_GETARG_DATUM(1))))
     422            0 :                 *result = true;
     423              :         else
     424            0 :                 *result = false;
     425              : 
     426              : #ifdef GIST_DEBUG
     427              :         fprintf(stderr, "same: %s\n", (*result ? "TRUE" : "FALSE"));
     428              : #endif
     429              : 
     430            0 :         PG_RETURN_POINTER(result);
     431            0 : }
     432              : 
     433              : /*
     434              : ** SUPPORT ROUTINES
     435              : */
     436              : static Datum
     437            0 : gseg_leaf_consistent(Datum key, Datum query, StrategyNumber strategy)
     438              : {
     439            0 :         Datum           retval;
     440              : 
     441              : #ifdef GIST_QUERY_DEBUG
     442              :         fprintf(stderr, "leaf_consistent, %d\n", strategy);
     443              : #endif
     444              : 
     445            0 :         switch (strategy)
     446              :         {
     447              :                 case RTLeftStrategyNumber:
     448            0 :                         retval = DirectFunctionCall2(seg_left, key, query);
     449            0 :                         break;
     450              :                 case RTOverLeftStrategyNumber:
     451            0 :                         retval = DirectFunctionCall2(seg_over_left, key, query);
     452            0 :                         break;
     453              :                 case RTOverlapStrategyNumber:
     454            0 :                         retval = DirectFunctionCall2(seg_overlap, key, query);
     455            0 :                         break;
     456              :                 case RTOverRightStrategyNumber:
     457            0 :                         retval = DirectFunctionCall2(seg_over_right, key, query);
     458            0 :                         break;
     459              :                 case RTRightStrategyNumber:
     460            0 :                         retval = DirectFunctionCall2(seg_right, key, query);
     461            0 :                         break;
     462              :                 case RTSameStrategyNumber:
     463            0 :                         retval = DirectFunctionCall2(seg_same, key, query);
     464            0 :                         break;
     465              :                 case RTContainsStrategyNumber:
     466              :                 case RTOldContainsStrategyNumber:
     467            0 :                         retval = DirectFunctionCall2(seg_contains, key, query);
     468            0 :                         break;
     469              :                 case RTContainedByStrategyNumber:
     470              :                 case RTOldContainedByStrategyNumber:
     471            0 :                         retval = DirectFunctionCall2(seg_contained, key, query);
     472            0 :                         break;
     473              :                 default:
     474            0 :                         retval = BoolGetDatum(false);
     475            0 :         }
     476              : 
     477            0 :         PG_RETURN_DATUM(retval);
     478            0 : }
     479              : 
     480              : static Datum
     481            0 : gseg_internal_consistent(Datum key, Datum query, StrategyNumber strategy)
     482              : {
     483            0 :         bool            retval;
     484              : 
     485              : #ifdef GIST_QUERY_DEBUG
     486              :         fprintf(stderr, "internal_consistent, %d\n", strategy);
     487              : #endif
     488              : 
     489            0 :         switch (strategy)
     490              :         {
     491              :                 case RTLeftStrategyNumber:
     492            0 :                         retval =
     493            0 :                                 !DatumGetBool(DirectFunctionCall2(seg_over_right, key, query));
     494            0 :                         break;
     495              :                 case RTOverLeftStrategyNumber:
     496            0 :                         retval =
     497            0 :                                 !DatumGetBool(DirectFunctionCall2(seg_right, key, query));
     498            0 :                         break;
     499              :                 case RTOverlapStrategyNumber:
     500            0 :                         retval =
     501            0 :                                 DatumGetBool(DirectFunctionCall2(seg_overlap, key, query));
     502            0 :                         break;
     503              :                 case RTOverRightStrategyNumber:
     504            0 :                         retval =
     505            0 :                                 !DatumGetBool(DirectFunctionCall2(seg_left, key, query));
     506            0 :                         break;
     507              :                 case RTRightStrategyNumber:
     508            0 :                         retval =
     509            0 :                                 !DatumGetBool(DirectFunctionCall2(seg_over_left, key, query));
     510            0 :                         break;
     511              :                 case RTSameStrategyNumber:
     512              :                 case RTContainsStrategyNumber:
     513              :                 case RTOldContainsStrategyNumber:
     514            0 :                         retval =
     515            0 :                                 DatumGetBool(DirectFunctionCall2(seg_contains, key, query));
     516            0 :                         break;
     517              :                 case RTContainedByStrategyNumber:
     518              :                 case RTOldContainedByStrategyNumber:
     519            0 :                         retval =
     520            0 :                                 DatumGetBool(DirectFunctionCall2(seg_overlap, key, query));
     521            0 :                         break;
     522              :                 default:
     523            0 :                         retval = false;
     524            0 :         }
     525              : 
     526            0 :         PG_RETURN_BOOL(retval);
     527            0 : }
     528              : 
     529              : static Datum
     530            0 : gseg_binary_union(Datum r1, Datum r2, int *sizep)
     531              : {
     532            0 :         Datum           retval;
     533              : 
     534            0 :         retval = DirectFunctionCall2(seg_union, r1, r2);
     535            0 :         *sizep = sizeof(SEG);
     536              : 
     537            0 :         return retval;
     538            0 : }
     539              : 
     540              : 
     541              : Datum
     542            0 : seg_contains(PG_FUNCTION_ARGS)
     543              : {
     544            0 :         SEG                *a = PG_GETARG_SEG_P(0);
     545            0 :         SEG                *b = PG_GETARG_SEG_P(1);
     546              : 
     547            0 :         PG_RETURN_BOOL((a->lower <= b->lower) && (a->upper >= b->upper));
     548            0 : }
     549              : 
     550              : Datum
     551            0 : seg_contained(PG_FUNCTION_ARGS)
     552              : {
     553            0 :         Datum           a = PG_GETARG_DATUM(0);
     554            0 :         Datum           b = PG_GETARG_DATUM(1);
     555              : 
     556            0 :         PG_RETURN_DATUM(DirectFunctionCall2(seg_contains, b, a));
     557            0 : }
     558              : 
     559              : /*****************************************************************************
     560              :  * Operator class for R-tree indexing
     561              :  *****************************************************************************/
     562              : 
     563              : Datum
     564            0 : seg_same(PG_FUNCTION_ARGS)
     565              : {
     566            0 :         int                     cmp = DatumGetInt32(DirectFunctionCall2(seg_cmp,
     567              :                                                                                                                 PG_GETARG_DATUM(0),
     568              :                                                                                                                 PG_GETARG_DATUM(1)));
     569              : 
     570            0 :         PG_RETURN_BOOL(cmp == 0);
     571            0 : }
     572              : 
     573              : /*      seg_overlap -- does a overlap b?
     574              :  */
     575              : Datum
     576            0 : seg_overlap(PG_FUNCTION_ARGS)
     577              : {
     578            0 :         SEG                *a = PG_GETARG_SEG_P(0);
     579            0 :         SEG                *b = PG_GETARG_SEG_P(1);
     580              : 
     581            0 :         PG_RETURN_BOOL(((a->upper >= b->upper) && (a->lower <= b->upper)) ||
     582              :                                    ((b->upper >= a->upper) && (b->lower <= a->upper)));
     583            0 : }
     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            0 : seg_over_left(PG_FUNCTION_ARGS)
     589              : {
     590            0 :         SEG                *a = PG_GETARG_SEG_P(0);
     591            0 :         SEG                *b = PG_GETARG_SEG_P(1);
     592              : 
     593            0 :         PG_RETURN_BOOL(a->upper <= b->upper);
     594            0 : }
     595              : 
     596              : /*      seg_left -- is (a) entirely on the left of (b)?
     597              :  */
     598              : Datum
     599            0 : seg_left(PG_FUNCTION_ARGS)
     600              : {
     601            0 :         SEG                *a = PG_GETARG_SEG_P(0);
     602            0 :         SEG                *b = PG_GETARG_SEG_P(1);
     603              : 
     604            0 :         PG_RETURN_BOOL(a->upper < b->lower);
     605            0 : }
     606              : 
     607              : /*      seg_right -- is (a) entirely on the right of (b)?
     608              :  */
     609              : Datum
     610            0 : seg_right(PG_FUNCTION_ARGS)
     611              : {
     612            0 :         SEG                *a = PG_GETARG_SEG_P(0);
     613            0 :         SEG                *b = PG_GETARG_SEG_P(1);
     614              : 
     615            0 :         PG_RETURN_BOOL(a->lower > b->upper);
     616            0 : }
     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            0 : seg_over_right(PG_FUNCTION_ARGS)
     622              : {
     623            0 :         SEG                *a = PG_GETARG_SEG_P(0);
     624            0 :         SEG                *b = PG_GETARG_SEG_P(1);
     625              : 
     626            0 :         PG_RETURN_BOOL(a->lower >= b->lower);
     627            0 : }
     628              : 
     629              : Datum
     630            0 : seg_union(PG_FUNCTION_ARGS)
     631              : {
     632            0 :         SEG                *a = PG_GETARG_SEG_P(0);
     633            0 :         SEG                *b = PG_GETARG_SEG_P(1);
     634            0 :         SEG                *n;
     635              : 
     636            0 :         n = palloc_object(SEG);
     637              : 
     638              :         /* take max of upper endpoints */
     639            0 :         if (a->upper > b->upper)
     640              :         {
     641            0 :                 n->upper = a->upper;
     642            0 :                 n->u_sigd = a->u_sigd;
     643            0 :                 n->u_ext = a->u_ext;
     644            0 :         }
     645              :         else
     646              :         {
     647            0 :                 n->upper = b->upper;
     648            0 :                 n->u_sigd = b->u_sigd;
     649            0 :                 n->u_ext = b->u_ext;
     650              :         }
     651              : 
     652              :         /* take min of lower endpoints */
     653            0 :         if (a->lower < b->lower)
     654              :         {
     655            0 :                 n->lower = a->lower;
     656            0 :                 n->l_sigd = a->l_sigd;
     657            0 :                 n->l_ext = a->l_ext;
     658            0 :         }
     659              :         else
     660              :         {
     661            0 :                 n->lower = b->lower;
     662            0 :                 n->l_sigd = b->l_sigd;
     663            0 :                 n->l_ext = b->l_ext;
     664              :         }
     665              : 
     666            0 :         PG_RETURN_POINTER(n);
     667            0 : }
     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            0 :         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            0 :         }
     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            0 :         }
     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            0 : }
     708              : 
     709              : static void
     710            0 : rt_seg_size(SEG *a, float *size)
     711              : {
     712            0 :         if (a == (SEG *) NULL || a->upper <= a->lower)
     713            0 :                 *size = 0.0;
     714              :         else
     715            0 :                 *size = fabsf(a->upper - a->lower);
     716            0 : }
     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            0 : }
     725              : 
     726              : 
     727              : /*****************************************************************************
     728              :  *                                 Miscellaneous operators
     729              :  *****************************************************************************/
     730              : Datum
     731            0 : seg_cmp(PG_FUNCTION_ARGS)
     732              : {
     733            0 :         SEG                *a = PG_GETARG_SEG_P(0);
     734            0 :         SEG                *b = PG_GETARG_SEG_P(1);
     735              : 
     736              :         /*
     737              :          * First compare on lower boundary position
     738              :          */
     739            0 :         if (a->lower < b->lower)
     740            0 :                 PG_RETURN_INT32(-1);
     741            0 :         if (a->lower > b->lower)
     742            0 :                 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            0 :         if (a->l_ext != b->l_ext)
     752              :         {
     753            0 :                 if (a->l_ext == '-')
     754            0 :                         PG_RETURN_INT32(-1);
     755            0 :                 if (b->l_ext == '-')
     756            0 :                         PG_RETURN_INT32(1);
     757            0 :                 if (a->l_ext == '<')
     758            0 :                         PG_RETURN_INT32(-1);
     759            0 :                 if (b->l_ext == '<')
     760            0 :                         PG_RETURN_INT32(1);
     761            0 :                 if (a->l_ext == '>')
     762            0 :                         PG_RETURN_INT32(1);
     763            0 :                 if (b->l_ext == '>')
     764            0 :                         PG_RETURN_INT32(-1);
     765            0 :         }
     766              : 
     767              :         /*
     768              :          * For other boundary types, consider # of significant digits first.
     769              :          */
     770            0 :         if (a->l_sigd < b->l_sigd)     /* (a) is blurred and is likely to include (b) */
     771            0 :                 PG_RETURN_INT32(-1);
     772            0 :         if (a->l_sigd > b->l_sigd)     /* (a) is less blurred and is likely to be
     773              :                                                                  * included in (b) */
     774            0 :                 PG_RETURN_INT32(1);
     775              : 
     776              :         /*
     777              :          * For same # of digits, an approximate boundary is more blurred than
     778              :          * exact.
     779              :          */
     780            0 :         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            0 :         }
     790              : 
     791              :         /* at this point, the lower boundaries are identical */
     792              : 
     793              :         /*
     794              :          * First compare on upper boundary position
     795              :          */
     796            0 :         if (a->upper < b->upper)
     797            0 :                 PG_RETURN_INT32(-1);
     798            0 :         if (a->upper > b->upper)
     799            0 :                 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            0 :         if (a->u_ext != b->u_ext)
     809              :         {
     810            0 :                 if (a->u_ext == '-')
     811            0 :                         PG_RETURN_INT32(1);
     812            0 :                 if (b->u_ext == '-')
     813            0 :                         PG_RETURN_INT32(-1);
     814            0 :                 if (a->u_ext == '<')
     815            0 :                         PG_RETURN_INT32(-1);
     816            0 :                 if (b->u_ext == '<')
     817            0 :                         PG_RETURN_INT32(1);
     818            0 :                 if (a->u_ext == '>')
     819            0 :                         PG_RETURN_INT32(1);
     820            0 :                 if (b->u_ext == '>')
     821            0 :                         PG_RETURN_INT32(-1);
     822            0 :         }
     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            0 :         if (a->u_sigd < b->u_sigd)     /* (a) is blurred and is likely to include (b) */
     829            0 :                 PG_RETURN_INT32(1);
     830            0 :         if (a->u_sigd > b->u_sigd)     /* (a) is less blurred and is likely to be
     831              :                                                                  * included in (b) */
     832            0 :                 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            0 :         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            0 :         }
     848              : 
     849            0 :         PG_RETURN_INT32(0);
     850            0 : }
     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            0 : }
     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            0 : }
     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            0 : }
     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            0 : }
     891              : 
     892              : 
     893              : Datum
     894            0 : seg_different(PG_FUNCTION_ARGS)
     895              : {
     896            0 :         int                     cmp = DatumGetInt32(DirectFunctionCall2(seg_cmp,
     897              :                                                                                                                 PG_GETARG_DATUM(0),
     898              :                                                                                                                 PG_GETARG_DATUM(1)));
     899              : 
     900            0 :         PG_RETURN_BOOL(cmp != 0);
     901            0 : }
     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            0 : restore(char *result, float val, int n)
     920              : {
     921            0 :         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            0 :         char       *p;
     929            0 :         int                     exp;
     930            0 :         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            0 :         if (n <= 0)
     940            0 :                 n = FLT_DIG;
     941              :         else
     942            0 :                 n = Min(n, FLT_DIG);
     943              : 
     944              :         /* remember the sign */
     945            0 :         sign = (val < 0 ? 1 : 0);
     946              : 
     947              :         /* print, in %e style to start with */
     948            0 :         sprintf(result, "%.*e", n - 1, val);
     949              : 
     950              :         /* find the exponent */
     951            0 :         p = strchr(result, 'e');
     952              : 
     953              :         /* punt if we have 'inf' or similar */
     954            0 :         if (p == NULL)
     955            0 :                 return strlen(result);
     956              : 
     957            0 :         exp = atoi(p + 1);
     958            0 :         if (exp == 0)
     959              :         {
     960              :                 /* just truncate off the 'e+00' */
     961            0 :                 *p = '\0';
     962            0 :         }
     963              :         else
     964              :         {
     965            0 :                 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            0 :                         for (p = result + sign, i = 10, dp = 0; *p != 'e'; p++, i++)
     972              :                         {
     973            0 :                                 buf[i] = *p;
     974            0 :                                 if (*p == '.')
     975              :                                 {
     976            0 :                                         dp = i--;       /* skip the decimal point */
     977            0 :                                 }
     978            0 :                         }
     979            0 :                         if (dp == 0)
     980            0 :                                 dp = i--;               /* no decimal point was found in the above
     981              :                                                                  * for() loop */
     982              : 
     983            0 :                         if (exp > 0)
     984              :                         {
     985            0 :                                 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            0 :                                         exp = dp - 10 + exp - n;
     993            0 :                                         buf[10 + n] = '\0';
     994              : 
     995              :                                         /* insert the decimal point */
     996            0 :                                         if (n > 1)
     997              :                                         {
     998            0 :                                                 dp = 11;
     999            0 :                                                 for (i = 23; i > dp; i--)
    1000            0 :                                                         buf[i] = buf[i - 1];
    1001            0 :                                                 buf[dp] = '.';
    1002            0 :                                         }
    1003              : 
    1004              :                                         /*
    1005              :                                          * adjust the exponent by the number of digits after the
    1006              :                                          * decimal point
    1007              :                                          */
    1008            0 :                                         if (n > 1)
    1009            0 :                                                 sprintf(&buf[11 + n], "e%d", exp + n - 1);
    1010              :                                         else
    1011            0 :                                                 sprintf(&buf[11], "e%d", exp + n - 1);
    1012              : 
    1013            0 :                                         if (sign)
    1014              :                                         {
    1015            0 :                                                 buf[9] = '-';
    1016            0 :                                                 strcpy(result, &buf[9]);
    1017            0 :                                         }
    1018              :                                         else
    1019            0 :                                                 strcpy(result, &buf[10]);
    1020            0 :                                 }
    1021              :                                 else
    1022              :                                 {                               /* insert the decimal point */
    1023            0 :                                         dp += exp;
    1024            0 :                                         for (i = 23; i > dp; i--)
    1025            0 :                                                 buf[i] = buf[i - 1];
    1026            0 :                                         buf[11 + n] = '\0';
    1027            0 :                                         buf[dp] = '.';
    1028            0 :                                         if (sign)
    1029              :                                         {
    1030            0 :                                                 buf[9] = '-';
    1031            0 :                                                 strcpy(result, &buf[9]);
    1032            0 :                                         }
    1033              :                                         else
    1034            0 :                                                 strcpy(result, &buf[10]);
    1035              :                                 }
    1036            0 :                         }
    1037              :                         else
    1038              :                         {                                       /* exp <= 0 */
    1039            0 :                                 dp += exp - 1;
    1040            0 :                                 buf[10 + n] = '\0';
    1041            0 :                                 buf[dp] = '.';
    1042            0 :                                 if (sign)
    1043              :                                 {
    1044            0 :                                         buf[dp - 2] = '-';
    1045            0 :                                         strcpy(result, &buf[dp - 2]);
    1046            0 :                                 }
    1047              :                                 else
    1048            0 :                                         strcpy(result, &buf[dp - 1]);
    1049              :                         }
    1050            0 :                 }
    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            0 :         return strlen(result);
    1058            0 : }
    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            0 : significant_digits(const char *s)
    1070              : {
    1071            0 :         const char *p = s;
    1072            0 :         int                     n,
    1073              :                                 c,
    1074              :                                 zeroes;
    1075              : 
    1076            0 :         zeroes = 1;
    1077              :         /* skip leading zeroes and sign */
    1078            0 :         for (c = *p; (c == '0' || c == '+' || c == '-') && c != 0; c = *(++p));
    1079              : 
    1080              :         /* skip decimal point and following zeroes */
    1081            0 :         for (c = *p; (c == '0' || c == '.') && c != 0; c = *(++p))
    1082              :         {
    1083            0 :                 if (c != '.')
    1084            0 :                         zeroes++;
    1085            0 :         }
    1086              : 
    1087              :         /* count significant digits (n) */
    1088            0 :         for (c = *p, n = 0; c != 0; c = *(++p))
    1089              :         {
    1090            0 :                 if (!((c >= '0' && c <= '9') || (c == '.')))
    1091            0 :                         break;
    1092            0 :                 if (c != '.')
    1093            0 :                         n++;
    1094            0 :         }
    1095              : 
    1096            0 :         if (!n)
    1097            0 :                 return zeroes;
    1098              : 
    1099            0 :         return n;
    1100            0 : }
        

Generated by: LCOV version 2.3.2-1