Header And Logo

PostgreSQL
| The world's most advanced open source database.

seg.c

Go to the documentation of this file.
00001 /*
00002  * contrib/seg/seg.c
00003  *
00004  ******************************************************************************
00005   This file contains routines that can be bound to a Postgres backend and
00006   called by the backend in the process of processing queries.  The calling
00007   format for these routines is dictated by Postgres architecture.
00008 ******************************************************************************/
00009 
00010 #include "postgres.h"
00011 
00012 #include <float.h>
00013 
00014 #include "access/gist.h"
00015 #include "access/skey.h"
00016 
00017 #include "segdata.h"
00018 
00019 /*
00020 #define GIST_DEBUG
00021 #define GIST_QUERY_DEBUG
00022 */
00023 
00024 PG_MODULE_MAGIC;
00025 
00026 extern int  seg_yyparse();
00027 extern void seg_yyerror(const char *message);
00028 extern void seg_scanner_init(const char *str);
00029 extern void seg_scanner_finish(void);
00030 
00031 /*
00032 extern int   seg_yydebug;
00033 */
00034 
00035 /*
00036  * Auxiliary data structure for picksplit method.
00037  */
00038 typedef struct
00039 {
00040     float       center;
00041     OffsetNumber index;
00042     SEG        *data;
00043 } gseg_picksplit_item;
00044 
00045 /*
00046 ** Input/Output routines
00047 */
00048 PG_FUNCTION_INFO_V1(seg_in);
00049 PG_FUNCTION_INFO_V1(seg_out);
00050 PG_FUNCTION_INFO_V1(seg_size);
00051 PG_FUNCTION_INFO_V1(seg_lower);
00052 PG_FUNCTION_INFO_V1(seg_upper);
00053 PG_FUNCTION_INFO_V1(seg_center);
00054 
00055 Datum       seg_in(PG_FUNCTION_ARGS);
00056 Datum       seg_out(PG_FUNCTION_ARGS);
00057 Datum       seg_size(PG_FUNCTION_ARGS);
00058 Datum       seg_lower(PG_FUNCTION_ARGS);
00059 Datum       seg_upper(PG_FUNCTION_ARGS);
00060 Datum       seg_center(PG_FUNCTION_ARGS);
00061 
00062 /*
00063 ** GiST support methods
00064 */
00065 bool gseg_consistent(GISTENTRY *entry,
00066                 SEG *query,
00067                 StrategyNumber strategy,
00068                 Oid subtype,
00069                 bool *recheck);
00070 GISTENTRY  *gseg_compress(GISTENTRY *entry);
00071 GISTENTRY  *gseg_decompress(GISTENTRY *entry);
00072 float      *gseg_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result);
00073 GIST_SPLITVEC *gseg_picksplit(GistEntryVector *entryvec, GIST_SPLITVEC *v);
00074 bool        gseg_leaf_consistent(SEG *key, SEG *query, StrategyNumber strategy);
00075 bool        gseg_internal_consistent(SEG *key, SEG *query, StrategyNumber strategy);
00076 SEG        *gseg_union(GistEntryVector *entryvec, int *sizep);
00077 SEG        *gseg_binary_union(SEG *r1, SEG *r2, int *sizep);
00078 bool       *gseg_same(SEG *b1, SEG *b2, bool *result);
00079 
00080 
00081 /*
00082 ** R-tree support functions
00083 */
00084 bool        seg_same(SEG *a, SEG *b);
00085 bool        seg_contains_int(SEG *a, int *b);
00086 bool        seg_contains_float4(SEG *a, float4 *b);
00087 bool        seg_contains_float8(SEG *a, float8 *b);
00088 bool        seg_contains(SEG *a, SEG *b);
00089 bool        seg_contained(SEG *a, SEG *b);
00090 bool        seg_overlap(SEG *a, SEG *b);
00091 bool        seg_left(SEG *a, SEG *b);
00092 bool        seg_over_left(SEG *a, SEG *b);
00093 bool        seg_right(SEG *a, SEG *b);
00094 bool        seg_over_right(SEG *a, SEG *b);
00095 SEG        *seg_union(SEG *a, SEG *b);
00096 SEG        *seg_inter(SEG *a, SEG *b);
00097 void        rt_seg_size(SEG *a, float *sz);
00098 
00099 /*
00100 ** Various operators
00101 */
00102 int32       seg_cmp(SEG *a, SEG *b);
00103 bool        seg_lt(SEG *a, SEG *b);
00104 bool        seg_le(SEG *a, SEG *b);
00105 bool        seg_gt(SEG *a, SEG *b);
00106 bool        seg_ge(SEG *a, SEG *b);
00107 bool        seg_different(SEG *a, SEG *b);
00108 
00109 /*
00110 ** Auxiliary funxtions
00111 */
00112 static int  restore(char *s, float val, int n);
00113 int         significant_digits(char *s);
00114 
00115 
00116 /*****************************************************************************
00117  * Input/Output functions
00118  *****************************************************************************/
00119 
00120 Datum
00121 seg_in(PG_FUNCTION_ARGS)
00122 {
00123     char       *str = PG_GETARG_CSTRING(0);
00124     SEG        *result = palloc(sizeof(SEG));
00125 
00126     seg_scanner_init(str);
00127 
00128     if (seg_yyparse(result) != 0)
00129         seg_yyerror("bogus input");
00130 
00131     seg_scanner_finish();
00132 
00133     PG_RETURN_POINTER(result);
00134 }
00135 
00136 Datum
00137 seg_out(PG_FUNCTION_ARGS)
00138 {
00139     SEG        *seg = (SEG *) PG_GETARG_POINTER(0);
00140     char       *result;
00141     char       *p;
00142 
00143     p = result = (char *) palloc(40);
00144 
00145     if (seg->l_ext == '>' || seg->l_ext == '<' || seg->l_ext == '~')
00146         p += sprintf(p, "%c", seg->l_ext);
00147 
00148     if (seg->lower == seg->upper && seg->l_ext == seg->u_ext)
00149     {
00150         /*
00151          * indicates that this interval was built by seg_in off a single point
00152          */
00153         p += restore(p, seg->lower, seg->l_sigd);
00154     }
00155     else
00156     {
00157         if (seg->l_ext != '-')
00158         {
00159             /* print the lower boundary if exists */
00160             p += restore(p, seg->lower, seg->l_sigd);
00161             p += sprintf(p, " ");
00162         }
00163         p += sprintf(p, "..");
00164         if (seg->u_ext != '-')
00165         {
00166             /* print the upper boundary if exists */
00167             p += sprintf(p, " ");
00168             if (seg->u_ext == '>' || seg->u_ext == '<' || seg->l_ext == '~')
00169                 p += sprintf(p, "%c", seg->u_ext);
00170             p += restore(p, seg->upper, seg->u_sigd);
00171         }
00172     }
00173 
00174     PG_RETURN_CSTRING(result);
00175 }
00176 
00177 Datum
00178 seg_center(PG_FUNCTION_ARGS)
00179 {
00180     SEG        *seg = (SEG *) PG_GETARG_POINTER(0);
00181 
00182     PG_RETURN_FLOAT4(((float) seg->lower + (float) seg->upper) / 2.0);
00183 }
00184 
00185 Datum
00186 seg_lower(PG_FUNCTION_ARGS)
00187 {
00188     SEG        *seg = (SEG *) PG_GETARG_POINTER(0);
00189 
00190     PG_RETURN_FLOAT4(seg->lower);
00191 }
00192 
00193 Datum
00194 seg_upper(PG_FUNCTION_ARGS)
00195 {
00196     SEG        *seg = (SEG *) PG_GETARG_POINTER(0);
00197 
00198     PG_RETURN_FLOAT4(seg->upper);
00199 }
00200 
00201 
00202 /*****************************************************************************
00203  *                         GiST functions
00204  *****************************************************************************/
00205 
00206 /*
00207 ** The GiST Consistent method for segments
00208 ** Should return false if for all data items x below entry,
00209 ** the predicate x op query == FALSE, where op is the oper
00210 ** corresponding to strategy in the pg_amop table.
00211 */
00212 bool
00213 gseg_consistent(GISTENTRY *entry,
00214                 SEG *query,
00215                 StrategyNumber strategy,
00216                 Oid subtype,
00217                 bool *recheck)
00218 {
00219     /* All cases served by this function are exact */
00220     *recheck = false;
00221 
00222     /*
00223      * if entry is not leaf, use gseg_internal_consistent, else use
00224      * gseg_leaf_consistent
00225      */
00226     if (GIST_LEAF(entry))
00227         return (gseg_leaf_consistent((SEG *) DatumGetPointer(entry->key), query, strategy));
00228     else
00229         return (gseg_internal_consistent((SEG *) DatumGetPointer(entry->key), query, strategy));
00230 }
00231 
00232 /*
00233 ** The GiST Union method for segments
00234 ** returns the minimal bounding seg that encloses all the entries in entryvec
00235 */
00236 SEG *
00237 gseg_union(GistEntryVector *entryvec, int *sizep)
00238 {
00239     int         numranges,
00240                 i;
00241     SEG        *out = (SEG *) NULL;
00242     SEG        *tmp;
00243 
00244 #ifdef GIST_DEBUG
00245     fprintf(stderr, "union\n");
00246 #endif
00247 
00248     numranges = entryvec->n;
00249     tmp = (SEG *) DatumGetPointer(entryvec->vector[0].key);
00250     *sizep = sizeof(SEG);
00251 
00252     for (i = 1; i < numranges; i++)
00253     {
00254         out = gseg_binary_union(tmp, (SEG *)
00255                                 DatumGetPointer(entryvec->vector[i].key),
00256                                 sizep);
00257         tmp = out;
00258     }
00259 
00260     return (out);
00261 }
00262 
00263 /*
00264 ** GiST Compress and Decompress methods for segments
00265 ** do not do anything.
00266 */
00267 GISTENTRY *
00268 gseg_compress(GISTENTRY *entry)
00269 {
00270     return (entry);
00271 }
00272 
00273 GISTENTRY *
00274 gseg_decompress(GISTENTRY *entry)
00275 {
00276     return (entry);
00277 }
00278 
00279 /*
00280 ** The GiST Penalty method for segments
00281 ** As in the R-tree paper, we use change in area as our penalty metric
00282 */
00283 float *
00284 gseg_penalty(GISTENTRY *origentry, GISTENTRY *newentry, float *result)
00285 {
00286     SEG        *ud;
00287     float       tmp1,
00288                 tmp2;
00289 
00290     ud = seg_union((SEG *) DatumGetPointer(origentry->key),
00291                    (SEG *) DatumGetPointer(newentry->key));
00292     rt_seg_size(ud, &tmp1);
00293     rt_seg_size((SEG *) DatumGetPointer(origentry->key), &tmp2);
00294     *result = tmp1 - tmp2;
00295 
00296 #ifdef GIST_DEBUG
00297     fprintf(stderr, "penalty\n");
00298     fprintf(stderr, "\t%g\n", *result);
00299 #endif
00300 
00301     return (result);
00302 }
00303 
00304 /*
00305  * Compare function for gseg_picksplit_item: sort by center.
00306  */
00307 static int
00308 gseg_picksplit_item_cmp(const void *a, const void *b)
00309 {
00310     const gseg_picksplit_item *i1 = (const gseg_picksplit_item *) a;
00311     const gseg_picksplit_item *i2 = (const gseg_picksplit_item *) b;
00312 
00313     if (i1->center < i2->center)
00314         return -1;
00315     else if (i1->center == i2->center)
00316         return 0;
00317     else
00318         return 1;
00319 }
00320 
00321 /*
00322  * The GiST PickSplit method for segments
00323  *
00324  * We used to use Guttman's split algorithm here, but since the data is 1-D
00325  * it's easier and more robust to just sort the segments by center-point and
00326  * split at the middle.
00327  */
00328 GIST_SPLITVEC *
00329 gseg_picksplit(GistEntryVector *entryvec,
00330                GIST_SPLITVEC *v)
00331 {
00332     int         i;
00333     SEG        *datum_l,
00334                *datum_r,
00335                *seg;
00336     gseg_picksplit_item *sort_items;
00337     OffsetNumber *left,
00338                *right;
00339     OffsetNumber maxoff;
00340     OffsetNumber firstright;
00341 
00342 #ifdef GIST_DEBUG
00343     fprintf(stderr, "picksplit\n");
00344 #endif
00345 
00346     /* Valid items in entryvec->vector[] are indexed 1..maxoff */
00347     maxoff = entryvec->n - 1;
00348 
00349     /*
00350      * Prepare the auxiliary array and sort it.
00351      */
00352     sort_items = (gseg_picksplit_item *)
00353         palloc(maxoff * sizeof(gseg_picksplit_item));
00354     for (i = 1; i <= maxoff; i++)
00355     {
00356         seg = (SEG *) DatumGetPointer(entryvec->vector[i].key);
00357         /* center calculation is done this way to avoid possible overflow */
00358         sort_items[i - 1].center = seg->lower * 0.5f + seg->upper * 0.5f;
00359         sort_items[i - 1].index = i;
00360         sort_items[i - 1].data = seg;
00361     }
00362     qsort(sort_items, maxoff, sizeof(gseg_picksplit_item),
00363           gseg_picksplit_item_cmp);
00364 
00365     /* sort items below "firstright" will go into the left side */
00366     firstright = maxoff / 2;
00367 
00368     v->spl_left = (OffsetNumber *) palloc(maxoff * sizeof(OffsetNumber));
00369     v->spl_right = (OffsetNumber *) palloc(maxoff * sizeof(OffsetNumber));
00370     left = v->spl_left;
00371     v->spl_nleft = 0;
00372     right = v->spl_right;
00373     v->spl_nright = 0;
00374 
00375     /*
00376      * Emit segments to the left output page, and compute its bounding box.
00377      */
00378     datum_l = (SEG *) palloc(sizeof(SEG));
00379     memcpy(datum_l, sort_items[0].data, sizeof(SEG));
00380     *left++ = sort_items[0].index;
00381     v->spl_nleft++;
00382     for (i = 1; i < firstright; i++)
00383     {
00384         datum_l = seg_union(datum_l, sort_items[i].data);
00385         *left++ = sort_items[i].index;
00386         v->spl_nleft++;
00387     }
00388 
00389     /*
00390      * Likewise for the right page.
00391      */
00392     datum_r = (SEG *) palloc(sizeof(SEG));
00393     memcpy(datum_r, sort_items[firstright].data, sizeof(SEG));
00394     *right++ = sort_items[firstright].index;
00395     v->spl_nright++;
00396     for (i = firstright + 1; i < maxoff; i++)
00397     {
00398         datum_r = seg_union(datum_r, sort_items[i].data);
00399         *right++ = sort_items[i].index;
00400         v->spl_nright++;
00401     }
00402 
00403     v->spl_ldatum = PointerGetDatum(datum_l);
00404     v->spl_rdatum = PointerGetDatum(datum_r);
00405 
00406     return v;
00407 }
00408 
00409 /*
00410 ** Equality methods
00411 */
00412 bool *
00413 gseg_same(SEG *b1, SEG *b2, bool *result)
00414 {
00415     if (seg_same(b1, b2))
00416         *result = TRUE;
00417     else
00418         *result = FALSE;
00419 
00420 #ifdef GIST_DEBUG
00421     fprintf(stderr, "same: %s\n", (*result ? "TRUE" : "FALSE"));
00422 #endif
00423 
00424     return (result);
00425 }
00426 
00427 /*
00428 ** SUPPORT ROUTINES
00429 */
00430 bool
00431 gseg_leaf_consistent(SEG *key,
00432                      SEG *query,
00433                      StrategyNumber strategy)
00434 {
00435     bool        retval;
00436 
00437 #ifdef GIST_QUERY_DEBUG
00438     fprintf(stderr, "leaf_consistent, %d\n", strategy);
00439 #endif
00440 
00441     switch (strategy)
00442     {
00443         case RTLeftStrategyNumber:
00444             retval = (bool) seg_left(key, query);
00445             break;
00446         case RTOverLeftStrategyNumber:
00447             retval = (bool) seg_over_left(key, query);
00448             break;
00449         case RTOverlapStrategyNumber:
00450             retval = (bool) seg_overlap(key, query);
00451             break;
00452         case RTOverRightStrategyNumber:
00453             retval = (bool) seg_over_right(key, query);
00454             break;
00455         case RTRightStrategyNumber:
00456             retval = (bool) seg_right(key, query);
00457             break;
00458         case RTSameStrategyNumber:
00459             retval = (bool) seg_same(key, query);
00460             break;
00461         case RTContainsStrategyNumber:
00462         case RTOldContainsStrategyNumber:
00463             retval = (bool) seg_contains(key, query);
00464             break;
00465         case RTContainedByStrategyNumber:
00466         case RTOldContainedByStrategyNumber:
00467             retval = (bool) seg_contained(key, query);
00468             break;
00469         default:
00470             retval = FALSE;
00471     }
00472     return (retval);
00473 }
00474 
00475 bool
00476 gseg_internal_consistent(SEG *key,
00477                          SEG *query,
00478                          StrategyNumber strategy)
00479 {
00480     bool        retval;
00481 
00482 #ifdef GIST_QUERY_DEBUG
00483     fprintf(stderr, "internal_consistent, %d\n", strategy);
00484 #endif
00485 
00486     switch (strategy)
00487     {
00488         case RTLeftStrategyNumber:
00489             retval = (bool) !seg_over_right(key, query);
00490             break;
00491         case RTOverLeftStrategyNumber:
00492             retval = (bool) !seg_right(key, query);
00493             break;
00494         case RTOverlapStrategyNumber:
00495             retval = (bool) seg_overlap(key, query);
00496             break;
00497         case RTOverRightStrategyNumber:
00498             retval = (bool) !seg_left(key, query);
00499             break;
00500         case RTRightStrategyNumber:
00501             retval = (bool) !seg_over_left(key, query);
00502             break;
00503         case RTSameStrategyNumber:
00504         case RTContainsStrategyNumber:
00505         case RTOldContainsStrategyNumber:
00506             retval = (bool) seg_contains(key, query);
00507             break;
00508         case RTContainedByStrategyNumber:
00509         case RTOldContainedByStrategyNumber:
00510             retval = (bool) seg_overlap(key, query);
00511             break;
00512         default:
00513             retval = FALSE;
00514     }
00515     return (retval);
00516 }
00517 
00518 SEG *
00519 gseg_binary_union(SEG *r1, SEG *r2, int *sizep)
00520 {
00521     SEG        *retval;
00522 
00523     retval = seg_union(r1, r2);
00524     *sizep = sizeof(SEG);
00525 
00526     return (retval);
00527 }
00528 
00529 
00530 bool
00531 seg_contains(SEG *a, SEG *b)
00532 {
00533     return ((a->lower <= b->lower) && (a->upper >= b->upper));
00534 }
00535 
00536 bool
00537 seg_contained(SEG *a, SEG *b)
00538 {
00539     return (seg_contains(b, a));
00540 }
00541 
00542 /*****************************************************************************
00543  * Operator class for R-tree indexing
00544  *****************************************************************************/
00545 
00546 bool
00547 seg_same(SEG *a, SEG *b)
00548 {
00549     return seg_cmp(a, b) == 0;
00550 }
00551 
00552 /*  seg_overlap -- does a overlap b?
00553  */
00554 bool
00555 seg_overlap(SEG *a, SEG *b)
00556 {
00557     return (
00558             ((a->upper >= b->upper) && (a->lower <= b->upper))
00559             ||
00560             ((b->upper >= a->upper) && (b->lower <= a->upper))
00561         );
00562 }
00563 
00564 /*  seg_overleft -- is the right edge of (a) located at or left of the right edge of (b)?
00565  */
00566 bool
00567 seg_over_left(SEG *a, SEG *b)
00568 {
00569     return (a->upper <= b->upper);
00570 }
00571 
00572 /*  seg_left -- is (a) entirely on the left of (b)?
00573  */
00574 bool
00575 seg_left(SEG *a, SEG *b)
00576 {
00577     return (a->upper < b->lower);
00578 }
00579 
00580 /*  seg_right -- is (a) entirely on the right of (b)?
00581  */
00582 bool
00583 seg_right(SEG *a, SEG *b)
00584 {
00585     return (a->lower > b->upper);
00586 }
00587 
00588 /*  seg_overright -- is the left edge of (a) located at or right of the left edge of (b)?
00589  */
00590 bool
00591 seg_over_right(SEG *a, SEG *b)
00592 {
00593     return (a->lower >= b->lower);
00594 }
00595 
00596 
00597 SEG *
00598 seg_union(SEG *a, SEG *b)
00599 {
00600     SEG        *n;
00601 
00602     n = (SEG *) palloc(sizeof(*n));
00603 
00604     /* take max of upper endpoints */
00605     if (a->upper > b->upper)
00606     {
00607         n->upper = a->upper;
00608         n->u_sigd = a->u_sigd;
00609         n->u_ext = a->u_ext;
00610     }
00611     else
00612     {
00613         n->upper = b->upper;
00614         n->u_sigd = b->u_sigd;
00615         n->u_ext = b->u_ext;
00616     }
00617 
00618     /* take min of lower endpoints */
00619     if (a->lower < b->lower)
00620     {
00621         n->lower = a->lower;
00622         n->l_sigd = a->l_sigd;
00623         n->l_ext = a->l_ext;
00624     }
00625     else
00626     {
00627         n->lower = b->lower;
00628         n->l_sigd = b->l_sigd;
00629         n->l_ext = b->l_ext;
00630     }
00631 
00632     return (n);
00633 }
00634 
00635 
00636 SEG *
00637 seg_inter(SEG *a, SEG *b)
00638 {
00639     SEG        *n;
00640 
00641     n = (SEG *) palloc(sizeof(*n));
00642 
00643     /* take min of upper endpoints */
00644     if (a->upper < b->upper)
00645     {
00646         n->upper = a->upper;
00647         n->u_sigd = a->u_sigd;
00648         n->u_ext = a->u_ext;
00649     }
00650     else
00651     {
00652         n->upper = b->upper;
00653         n->u_sigd = b->u_sigd;
00654         n->u_ext = b->u_ext;
00655     }
00656 
00657     /* take max of lower endpoints */
00658     if (a->lower > b->lower)
00659     {
00660         n->lower = a->lower;
00661         n->l_sigd = a->l_sigd;
00662         n->l_ext = a->l_ext;
00663     }
00664     else
00665     {
00666         n->lower = b->lower;
00667         n->l_sigd = b->l_sigd;
00668         n->l_ext = b->l_ext;
00669     }
00670 
00671     return (n);
00672 }
00673 
00674 void
00675 rt_seg_size(SEG *a, float *size)
00676 {
00677     if (a == (SEG *) NULL || a->upper <= a->lower)
00678         *size = 0.0;
00679     else
00680         *size = (float) Abs(a->upper - a->lower);
00681 
00682     return;
00683 }
00684 
00685 Datum
00686 seg_size(PG_FUNCTION_ARGS)
00687 {
00688     SEG        *seg = (SEG *) PG_GETARG_POINTER(0);
00689 
00690     PG_RETURN_FLOAT4((float) Abs(seg->upper - seg->lower));
00691 }
00692 
00693 
00694 /*****************************************************************************
00695  *                 Miscellaneous operators
00696  *****************************************************************************/
00697 int32
00698 seg_cmp(SEG *a, SEG *b)
00699 {
00700     /*
00701      * First compare on lower boundary position
00702      */
00703     if (a->lower < b->lower)
00704         return -1;
00705     if (a->lower > b->lower)
00706         return 1;
00707 
00708     /*
00709      * a->lower == b->lower, so consider type of boundary.
00710      *
00711      * A '-' lower bound is < any other kind (this could only be relevant if
00712      * -HUGE_VAL is used as a regular data value). A '<' lower bound is < any
00713      * other kind except '-'. A '>' lower bound is > any other kind.
00714      */
00715     if (a->l_ext != b->l_ext)
00716     {
00717         if (a->l_ext == '-')
00718             return -1;
00719         if (b->l_ext == '-')
00720             return 1;
00721         if (a->l_ext == '<')
00722             return -1;
00723         if (b->l_ext == '<')
00724             return 1;
00725         if (a->l_ext == '>')
00726             return 1;
00727         if (b->l_ext == '>')
00728             return -1;
00729     }
00730 
00731     /*
00732      * For other boundary types, consider # of significant digits first.
00733      */
00734     if (a->l_sigd < b->l_sigd)  /* (a) is blurred and is likely to include (b) */
00735         return -1;
00736     if (a->l_sigd > b->l_sigd)  /* (a) is less blurred and is likely to be
00737                                  * included in (b) */
00738         return 1;
00739 
00740     /*
00741      * For same # of digits, an approximate boundary is more blurred than
00742      * exact.
00743      */
00744     if (a->l_ext != b->l_ext)
00745     {
00746         if (a->l_ext == '~')    /* (a) is approximate, while (b) is exact */
00747             return -1;
00748         if (b->l_ext == '~')
00749             return 1;
00750         /* can't get here unless data is corrupt */
00751         elog(ERROR, "bogus lower boundary types %d %d",
00752              (int) a->l_ext, (int) b->l_ext);
00753     }
00754 
00755     /* at this point, the lower boundaries are identical */
00756 
00757     /*
00758      * First compare on upper boundary position
00759      */
00760     if (a->upper < b->upper)
00761         return -1;
00762     if (a->upper > b->upper)
00763         return 1;
00764 
00765     /*
00766      * a->upper == b->upper, so consider type of boundary.
00767      *
00768      * A '-' upper bound is > any other kind (this could only be relevant if
00769      * HUGE_VAL is used as a regular data value). A '<' upper bound is < any
00770      * other kind. A '>' upper bound is > any other kind except '-'.
00771      */
00772     if (a->u_ext != b->u_ext)
00773     {
00774         if (a->u_ext == '-')
00775             return 1;
00776         if (b->u_ext == '-')
00777             return -1;
00778         if (a->u_ext == '<')
00779             return -1;
00780         if (b->u_ext == '<')
00781             return 1;
00782         if (a->u_ext == '>')
00783             return 1;
00784         if (b->u_ext == '>')
00785             return -1;
00786     }
00787 
00788     /*
00789      * For other boundary types, consider # of significant digits first. Note
00790      * result here is converse of the lower-boundary case.
00791      */
00792     if (a->u_sigd < b->u_sigd)  /* (a) is blurred and is likely to include (b) */
00793         return 1;
00794     if (a->u_sigd > b->u_sigd)  /* (a) is less blurred and is likely to be
00795                                  * included in (b) */
00796         return -1;
00797 
00798     /*
00799      * For same # of digits, an approximate boundary is more blurred than
00800      * exact.  Again, result is converse of lower-boundary case.
00801      */
00802     if (a->u_ext != b->u_ext)
00803     {
00804         if (a->u_ext == '~')    /* (a) is approximate, while (b) is exact */
00805             return 1;
00806         if (b->u_ext == '~')
00807             return -1;
00808         /* can't get here unless data is corrupt */
00809         elog(ERROR, "bogus upper boundary types %d %d",
00810              (int) a->u_ext, (int) b->u_ext);
00811     }
00812 
00813     return 0;
00814 }
00815 
00816 bool
00817 seg_lt(SEG *a, SEG *b)
00818 {
00819     return seg_cmp(a, b) < 0;
00820 }
00821 
00822 bool
00823 seg_le(SEG *a, SEG *b)
00824 {
00825     return seg_cmp(a, b) <= 0;
00826 }
00827 
00828 bool
00829 seg_gt(SEG *a, SEG *b)
00830 {
00831     return seg_cmp(a, b) > 0;
00832 }
00833 
00834 bool
00835 seg_ge(SEG *a, SEG *b)
00836 {
00837     return seg_cmp(a, b) >= 0;
00838 }
00839 
00840 bool
00841 seg_different(SEG *a, SEG *b)
00842 {
00843     return seg_cmp(a, b) != 0;
00844 }
00845 
00846 
00847 
00848 /*****************************************************************************
00849  *                 Auxiliary functions
00850  *****************************************************************************/
00851 
00852 /* The purpose of this routine is to print the floating point
00853  * value with exact number of significant digits. Its behaviour
00854  * is similar to %.ng except it prints 8.00 where %.ng would
00855  * print 8
00856  */
00857 static int
00858 restore(char *result, float val, int n)
00859 {
00860     static char efmt[8] = {'%', '-', '1', '5', '.', '#', 'e', 0};
00861     char        buf[25] = {
00862         '0', '0', '0', '0', '0',
00863         '0', '0', '0', '0', '0',
00864         '0', '0', '0', '0', '0',
00865         '0', '0', '0', '0', '0',
00866         '0', '0', '0', '0', '\0'
00867     };
00868     char       *p;
00869     int         exp;
00870     int         i,
00871                 dp,
00872                 sign;
00873 
00874     /*
00875      * put a cap on the number of siugnificant digits to avoid nonsense in the
00876      * output
00877      */
00878     n = Min(n, FLT_DIG);
00879 
00880     /* remember the sign */
00881     sign = (val < 0 ? 1 : 0);
00882 
00883     efmt[5] = '0' + (n - 1) % 10;       /* makes %-15.(n-1)e -- this format
00884                                          * guarantees that the exponent is
00885                                          * always present */
00886 
00887     sprintf(result, efmt, val);
00888 
00889     /* trim the spaces left by the %e */
00890     for (p = result; *p != ' '; p++);
00891     *p = '\0';
00892 
00893     /* get the exponent */
00894     strtok(pstrdup(result), "e");
00895     exp = atoi(strtok(NULL, "e"));
00896 
00897     if (exp == 0)
00898     {
00899         /* use the supplied mantyssa with sign */
00900         strcpy((char *) strchr(result, 'e'), "");
00901     }
00902     else
00903     {
00904         if (Abs(exp) <= 4)
00905         {
00906             /*
00907              * remove the decimal point from the mantyssa and write the digits
00908              * to the buf array
00909              */
00910             for (p = result + sign, i = 10, dp = 0; *p != 'e'; p++, i++)
00911             {
00912                 buf[i] = *p;
00913                 if (*p == '.')
00914                 {
00915                     dp = i--;   /* skip the decimal point */
00916                 }
00917             }
00918             if (dp == 0)
00919                 dp = i--;       /* no decimal point was found in the above
00920                                  * for() loop */
00921 
00922             if (exp > 0)
00923             {
00924                 if (dp - 10 + exp >= n)
00925                 {
00926                     /*
00927                      * the decimal point is behind the last significant digit;
00928                      * the digits in between must be converted to the exponent
00929                      * and the decimal point placed after the first digit
00930                      */
00931                     exp = dp - 10 + exp - n;
00932                     buf[10 + n] = '\0';
00933 
00934                     /* insert the decimal point */
00935                     if (n > 1)
00936                     {
00937                         dp = 11;
00938                         for (i = 23; i > dp; i--)
00939                             buf[i] = buf[i - 1];
00940                         buf[dp] = '.';
00941                     }
00942 
00943                     /*
00944                      * adjust the exponent by the number of digits after the
00945                      * decimal point
00946                      */
00947                     if (n > 1)
00948                         sprintf(&buf[11 + n], "e%d", exp + n - 1);
00949                     else
00950                         sprintf(&buf[11], "e%d", exp + n - 1);
00951 
00952                     if (sign)
00953                     {
00954                         buf[9] = '-';
00955                         strcpy(result, &buf[9]);
00956                     }
00957                     else
00958                         strcpy(result, &buf[10]);
00959                 }
00960                 else
00961                 {               /* insert the decimal point */
00962                     dp += exp;
00963                     for (i = 23; i > dp; i--)
00964                         buf[i] = buf[i - 1];
00965                     buf[11 + n] = '\0';
00966                     buf[dp] = '.';
00967                     if (sign)
00968                     {
00969                         buf[9] = '-';
00970                         strcpy(result, &buf[9]);
00971                     }
00972                     else
00973                         strcpy(result, &buf[10]);
00974                 }
00975             }
00976             else
00977             {                   /* exp <= 0 */
00978                 dp += exp - 1;
00979                 buf[10 + n] = '\0';
00980                 buf[dp] = '.';
00981                 if (sign)
00982                 {
00983                     buf[dp - 2] = '-';
00984                     strcpy(result, &buf[dp - 2]);
00985                 }
00986                 else
00987                     strcpy(result, &buf[dp - 1]);
00988             }
00989         }
00990 
00991         /* do nothing for Abs(exp) > 4; %e must be OK */
00992         /* just get rid of zeroes after [eE]- and +zeroes after [Ee]. */
00993 
00994         /* ... this is not done yet. */
00995     }
00996     return (strlen(result));
00997 }
00998 
00999 
01000 /*
01001 ** Miscellany
01002 */
01003 
01004 bool
01005 seg_contains_int(SEG *a, int *b)
01006 {
01007     return ((a->lower <= *b) && (a->upper >= *b));
01008 }
01009 
01010 bool
01011 seg_contains_float4(SEG *a, float4 *b)
01012 {
01013     return ((a->lower <= *b) && (a->upper >= *b));
01014 }
01015 
01016 bool
01017 seg_contains_float8(SEG *a, float8 *b)
01018 {
01019     return ((a->lower <= *b) && (a->upper >= *b));
01020 }
01021 
01022 /* find out the number of significant digits in a string representing
01023  * a floating point number
01024  */
01025 int
01026 significant_digits(char *s)
01027 {
01028     char       *p = s;
01029     int         n,
01030                 c,
01031                 zeroes;
01032 
01033     zeroes = 1;
01034     /* skip leading zeroes and sign */
01035     for (c = *p; (c == '0' || c == '+' || c == '-') && c != 0; c = *(++p));
01036 
01037     /* skip decimal point and following zeroes */
01038     for (c = *p; (c == '0' || c == '.') && c != 0; c = *(++p))
01039     {
01040         if (c != '.')
01041             zeroes++;
01042     }
01043 
01044     /* count significant digits (n) */
01045     for (c = *p, n = 0; c != 0; c = *(++p))
01046     {
01047         if (!((c >= '0' && c <= '9') || (c == '.')))
01048             break;
01049         if (c != '.')
01050             n++;
01051     }
01052 
01053     if (!n)
01054         return (zeroes);
01055 
01056     return (n);
01057 }