doc PG 17 relnotes: Fixes from jian he
[pgsql.git] / contrib / seg / seg.c
blob7f9fc24eb4b60add583d6237e1dd575b17f58293
1 /*
2 * contrib/seg/seg.c
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 ******************************************************************************/
10 #include "postgres.h"
12 #include <float.h>
13 #include <math.h>
15 #include "access/gist.h"
16 #include "access/stratnum.h"
17 #include "fmgr.h"
19 #include "segdata.h"
22 #define DatumGetSegP(X) ((SEG *) DatumGetPointer(X))
23 #define PG_GETARG_SEG_P(n) DatumGetSegP(PG_GETARG_DATUM(n))
27 #define GIST_DEBUG
28 #define GIST_QUERY_DEBUG
31 PG_MODULE_MAGIC;
34 * Auxiliary data structure for picksplit method.
36 typedef struct
38 float center;
39 OffsetNumber index;
40 SEG *data;
41 } gseg_picksplit_item;
44 ** Input/Output routines
46 PG_FUNCTION_INFO_V1(seg_in);
47 PG_FUNCTION_INFO_V1(seg_out);
48 PG_FUNCTION_INFO_V1(seg_size);
49 PG_FUNCTION_INFO_V1(seg_lower);
50 PG_FUNCTION_INFO_V1(seg_upper);
51 PG_FUNCTION_INFO_V1(seg_center);
54 ** GiST support methods
56 PG_FUNCTION_INFO_V1(gseg_consistent);
57 PG_FUNCTION_INFO_V1(gseg_compress);
58 PG_FUNCTION_INFO_V1(gseg_decompress);
59 PG_FUNCTION_INFO_V1(gseg_picksplit);
60 PG_FUNCTION_INFO_V1(gseg_penalty);
61 PG_FUNCTION_INFO_V1(gseg_union);
62 PG_FUNCTION_INFO_V1(gseg_same);
63 static Datum gseg_leaf_consistent(Datum key, Datum query, StrategyNumber strategy);
64 static Datum gseg_internal_consistent(Datum key, Datum query, StrategyNumber strategy);
65 static Datum gseg_binary_union(Datum r1, Datum r2, int *sizep);
69 ** R-tree support functions
71 PG_FUNCTION_INFO_V1(seg_same);
72 PG_FUNCTION_INFO_V1(seg_contains);
73 PG_FUNCTION_INFO_V1(seg_contained);
74 PG_FUNCTION_INFO_V1(seg_overlap);
75 PG_FUNCTION_INFO_V1(seg_left);
76 PG_FUNCTION_INFO_V1(seg_over_left);
77 PG_FUNCTION_INFO_V1(seg_right);
78 PG_FUNCTION_INFO_V1(seg_over_right);
79 PG_FUNCTION_INFO_V1(seg_union);
80 PG_FUNCTION_INFO_V1(seg_inter);
81 static void rt_seg_size(SEG *a, float *size);
84 ** Various operators
86 PG_FUNCTION_INFO_V1(seg_cmp);
87 PG_FUNCTION_INFO_V1(seg_lt);
88 PG_FUNCTION_INFO_V1(seg_le);
89 PG_FUNCTION_INFO_V1(seg_gt);
90 PG_FUNCTION_INFO_V1(seg_ge);
91 PG_FUNCTION_INFO_V1(seg_different);
94 ** Auxiliary functions
96 static int restore(char *result, float val, int n);
99 /*****************************************************************************
100 * Input/Output functions
101 *****************************************************************************/
103 Datum
104 seg_in(PG_FUNCTION_ARGS)
106 char *str = PG_GETARG_CSTRING(0);
107 SEG *result = palloc(sizeof(SEG));
109 seg_scanner_init(str);
111 if (seg_yyparse(result, fcinfo->context) != 0)
112 seg_yyerror(result, fcinfo->context, "bogus input");
114 seg_scanner_finish();
116 PG_RETURN_POINTER(result);
119 Datum
120 seg_out(PG_FUNCTION_ARGS)
122 SEG *seg = PG_GETARG_SEG_P(0);
123 char *result;
124 char *p;
126 p = result = (char *) palloc(40);
128 if (seg->l_ext == '>' || seg->l_ext == '<' || seg->l_ext == '~')
129 p += sprintf(p, "%c", seg->l_ext);
131 if (seg->lower == seg->upper && seg->l_ext == seg->u_ext)
134 * indicates that this interval was built by seg_in off a single point
136 p += restore(p, seg->lower, seg->l_sigd);
138 else
140 if (seg->l_ext != '-')
142 /* print the lower boundary if exists */
143 p += restore(p, seg->lower, seg->l_sigd);
144 p += sprintf(p, " ");
146 p += sprintf(p, "..");
147 if (seg->u_ext != '-')
149 /* print the upper boundary if exists */
150 p += sprintf(p, " ");
151 if (seg->u_ext == '>' || seg->u_ext == '<' || seg->l_ext == '~')
152 p += sprintf(p, "%c", seg->u_ext);
153 p += restore(p, seg->upper, seg->u_sigd);
157 PG_RETURN_CSTRING(result);
160 Datum
161 seg_center(PG_FUNCTION_ARGS)
163 SEG *seg = PG_GETARG_SEG_P(0);
165 PG_RETURN_FLOAT4(((float) seg->lower + (float) seg->upper) / 2.0);
168 Datum
169 seg_lower(PG_FUNCTION_ARGS)
171 SEG *seg = PG_GETARG_SEG_P(0);
173 PG_RETURN_FLOAT4(seg->lower);
176 Datum
177 seg_upper(PG_FUNCTION_ARGS)
179 SEG *seg = PG_GETARG_SEG_P(0);
181 PG_RETURN_FLOAT4(seg->upper);
185 /*****************************************************************************
186 * GiST functions
187 *****************************************************************************/
190 ** The GiST Consistent method for segments
191 ** Should return false if for all data items x below entry,
192 ** the predicate x op query == false, where op is the oper
193 ** corresponding to strategy in the pg_amop table.
195 Datum
196 gseg_consistent(PG_FUNCTION_ARGS)
198 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
199 Datum query = PG_GETARG_DATUM(1);
200 StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
202 /* Oid subtype = PG_GETARG_OID(3); */
203 bool *recheck = (bool *) PG_GETARG_POINTER(4);
205 /* All cases served by this function are exact */
206 *recheck = false;
209 * if entry is not leaf, use gseg_internal_consistent, else use
210 * gseg_leaf_consistent
212 if (GIST_LEAF(entry))
213 return gseg_leaf_consistent(entry->key, query, strategy);
214 else
215 return gseg_internal_consistent(entry->key, query, strategy);
219 ** The GiST Union method for segments
220 ** returns the minimal bounding seg that encloses all the entries in entryvec
222 Datum
223 gseg_union(PG_FUNCTION_ARGS)
225 GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
226 int *sizep = (int *) PG_GETARG_POINTER(1);
227 int numranges,
229 Datum out = 0;
230 Datum tmp;
232 #ifdef GIST_DEBUG
233 fprintf(stderr, "union\n");
234 #endif
236 numranges = entryvec->n;
237 tmp = entryvec->vector[0].key;
238 *sizep = sizeof(SEG);
240 for (i = 1; i < numranges; i++)
242 out = gseg_binary_union(tmp, entryvec->vector[i].key, sizep);
243 tmp = out;
246 PG_RETURN_DATUM(out);
250 ** GiST Compress and Decompress methods for segments
251 ** do not do anything.
253 Datum
254 gseg_compress(PG_FUNCTION_ARGS)
256 PG_RETURN_POINTER(PG_GETARG_POINTER(0));
259 Datum
260 gseg_decompress(PG_FUNCTION_ARGS)
262 PG_RETURN_POINTER(PG_GETARG_POINTER(0));
266 ** The GiST Penalty method for segments
267 ** As in the R-tree paper, we use change in area as our penalty metric
269 Datum
270 gseg_penalty(PG_FUNCTION_ARGS)
272 GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
273 GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
274 float *result = (float *) PG_GETARG_POINTER(2);
275 SEG *ud;
276 float tmp1,
277 tmp2;
279 ud = DatumGetSegP(DirectFunctionCall2(seg_union,
280 origentry->key,
281 newentry->key));
282 rt_seg_size(ud, &tmp1);
283 rt_seg_size(DatumGetSegP(origentry->key), &tmp2);
284 *result = tmp1 - tmp2;
286 #ifdef GIST_DEBUG
287 fprintf(stderr, "penalty\n");
288 fprintf(stderr, "\t%g\n", *result);
289 #endif
291 PG_RETURN_POINTER(result);
295 * Compare function for gseg_picksplit_item: sort by center.
297 static int
298 gseg_picksplit_item_cmp(const void *a, const void *b)
300 const gseg_picksplit_item *i1 = (const gseg_picksplit_item *) a;
301 const gseg_picksplit_item *i2 = (const gseg_picksplit_item *) b;
303 if (i1->center < i2->center)
304 return -1;
305 else if (i1->center == i2->center)
306 return 0;
307 else
308 return 1;
312 * The GiST PickSplit method for segments
314 * We used to use Guttman's split algorithm here, but since the data is 1-D
315 * it's easier and more robust to just sort the segments by center-point and
316 * split at the middle.
318 Datum
319 gseg_picksplit(PG_FUNCTION_ARGS)
321 GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
322 GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
323 int i;
324 SEG *seg,
325 *seg_l,
326 *seg_r;
327 gseg_picksplit_item *sort_items;
328 OffsetNumber *left,
329 *right;
330 OffsetNumber maxoff;
331 OffsetNumber firstright;
333 #ifdef GIST_DEBUG
334 fprintf(stderr, "picksplit\n");
335 #endif
337 /* Valid items in entryvec->vector[] are indexed 1..maxoff */
338 maxoff = entryvec->n - 1;
341 * Prepare the auxiliary array and sort it.
343 sort_items = (gseg_picksplit_item *)
344 palloc(maxoff * sizeof(gseg_picksplit_item));
345 for (i = 1; i <= maxoff; i++)
347 seg = DatumGetSegP(entryvec->vector[i].key);
348 /* center calculation is done this way to avoid possible overflow */
349 sort_items[i - 1].center = seg->lower * 0.5f + seg->upper * 0.5f;
350 sort_items[i - 1].index = i;
351 sort_items[i - 1].data = seg;
353 qsort(sort_items, maxoff, sizeof(gseg_picksplit_item),
354 gseg_picksplit_item_cmp);
356 /* sort items below "firstright" will go into the left side */
357 firstright = maxoff / 2;
359 v->spl_left = (OffsetNumber *) palloc(maxoff * sizeof(OffsetNumber));
360 v->spl_right = (OffsetNumber *) palloc(maxoff * sizeof(OffsetNumber));
361 left = v->spl_left;
362 v->spl_nleft = 0;
363 right = v->spl_right;
364 v->spl_nright = 0;
367 * Emit segments to the left output page, and compute its bounding box.
369 seg_l = (SEG *) palloc(sizeof(SEG));
370 memcpy(seg_l, sort_items[0].data, sizeof(SEG));
371 *left++ = sort_items[0].index;
372 v->spl_nleft++;
373 for (i = 1; i < firstright; i++)
375 Datum sortitem = PointerGetDatum(sort_items[i].data);
377 seg_l = DatumGetSegP(DirectFunctionCall2(seg_union,
378 PointerGetDatum(seg_l),
379 sortitem));
380 *left++ = sort_items[i].index;
381 v->spl_nleft++;
385 * Likewise for the right page.
387 seg_r = (SEG *) palloc(sizeof(SEG));
388 memcpy(seg_r, sort_items[firstright].data, sizeof(SEG));
389 *right++ = sort_items[firstright].index;
390 v->spl_nright++;
391 for (i = firstright + 1; i < maxoff; i++)
393 Datum sortitem = PointerGetDatum(sort_items[i].data);
395 seg_r = DatumGetSegP(DirectFunctionCall2(seg_union,
396 PointerGetDatum(seg_r),
397 sortitem));
398 *right++ = sort_items[i].index;
399 v->spl_nright++;
402 v->spl_ldatum = PointerGetDatum(seg_l);
403 v->spl_rdatum = PointerGetDatum(seg_r);
405 PG_RETURN_POINTER(v);
409 ** Equality methods
411 Datum
412 gseg_same(PG_FUNCTION_ARGS)
414 bool *result = (bool *) PG_GETARG_POINTER(2);
416 if (DirectFunctionCall2(seg_same, PG_GETARG_DATUM(0), PG_GETARG_DATUM(1)))
417 *result = true;
418 else
419 *result = false;
421 #ifdef GIST_DEBUG
422 fprintf(stderr, "same: %s\n", (*result ? "TRUE" : "FALSE"));
423 #endif
425 PG_RETURN_POINTER(result);
429 ** SUPPORT ROUTINES
431 static Datum
432 gseg_leaf_consistent(Datum key, Datum query, StrategyNumber strategy)
434 Datum retval;
436 #ifdef GIST_QUERY_DEBUG
437 fprintf(stderr, "leaf_consistent, %d\n", strategy);
438 #endif
440 switch (strategy)
442 case RTLeftStrategyNumber:
443 retval = DirectFunctionCall2(seg_left, key, query);
444 break;
445 case RTOverLeftStrategyNumber:
446 retval = DirectFunctionCall2(seg_over_left, key, query);
447 break;
448 case RTOverlapStrategyNumber:
449 retval = DirectFunctionCall2(seg_overlap, key, query);
450 break;
451 case RTOverRightStrategyNumber:
452 retval = DirectFunctionCall2(seg_over_right, key, query);
453 break;
454 case RTRightStrategyNumber:
455 retval = DirectFunctionCall2(seg_right, key, query);
456 break;
457 case RTSameStrategyNumber:
458 retval = DirectFunctionCall2(seg_same, key, query);
459 break;
460 case RTContainsStrategyNumber:
461 case RTOldContainsStrategyNumber:
462 retval = DirectFunctionCall2(seg_contains, key, query);
463 break;
464 case RTContainedByStrategyNumber:
465 case RTOldContainedByStrategyNumber:
466 retval = DirectFunctionCall2(seg_contained, key, query);
467 break;
468 default:
469 retval = false;
472 PG_RETURN_DATUM(retval);
475 static Datum
476 gseg_internal_consistent(Datum key, Datum query, StrategyNumber strategy)
478 bool retval;
480 #ifdef GIST_QUERY_DEBUG
481 fprintf(stderr, "internal_consistent, %d\n", strategy);
482 #endif
484 switch (strategy)
486 case RTLeftStrategyNumber:
487 retval =
488 !DatumGetBool(DirectFunctionCall2(seg_over_right, key, query));
489 break;
490 case RTOverLeftStrategyNumber:
491 retval =
492 !DatumGetBool(DirectFunctionCall2(seg_right, key, query));
493 break;
494 case RTOverlapStrategyNumber:
495 retval =
496 DatumGetBool(DirectFunctionCall2(seg_overlap, key, query));
497 break;
498 case RTOverRightStrategyNumber:
499 retval =
500 !DatumGetBool(DirectFunctionCall2(seg_left, key, query));
501 break;
502 case RTRightStrategyNumber:
503 retval =
504 !DatumGetBool(DirectFunctionCall2(seg_over_left, key, query));
505 break;
506 case RTSameStrategyNumber:
507 case RTContainsStrategyNumber:
508 case RTOldContainsStrategyNumber:
509 retval =
510 DatumGetBool(DirectFunctionCall2(seg_contains, key, query));
511 break;
512 case RTContainedByStrategyNumber:
513 case RTOldContainedByStrategyNumber:
514 retval =
515 DatumGetBool(DirectFunctionCall2(seg_overlap, key, query));
516 break;
517 default:
518 retval = false;
521 PG_RETURN_BOOL(retval);
524 static Datum
525 gseg_binary_union(Datum r1, Datum r2, int *sizep)
527 Datum retval;
529 retval = DirectFunctionCall2(seg_union, r1, r2);
530 *sizep = sizeof(SEG);
532 return retval;
536 Datum
537 seg_contains(PG_FUNCTION_ARGS)
539 SEG *a = PG_GETARG_SEG_P(0);
540 SEG *b = PG_GETARG_SEG_P(1);
542 PG_RETURN_BOOL((a->lower <= b->lower) && (a->upper >= b->upper));
545 Datum
546 seg_contained(PG_FUNCTION_ARGS)
548 Datum a = PG_GETARG_DATUM(0);
549 Datum b = PG_GETARG_DATUM(1);
551 PG_RETURN_DATUM(DirectFunctionCall2(seg_contains, b, a));
554 /*****************************************************************************
555 * Operator class for R-tree indexing
556 *****************************************************************************/
558 Datum
559 seg_same(PG_FUNCTION_ARGS)
561 int cmp = DatumGetInt32(DirectFunctionCall2(seg_cmp,
562 PG_GETARG_DATUM(0),
563 PG_GETARG_DATUM(1)));
565 PG_RETURN_BOOL(cmp == 0);
568 /* seg_overlap -- does a overlap b?
570 Datum
571 seg_overlap(PG_FUNCTION_ARGS)
573 SEG *a = PG_GETARG_SEG_P(0);
574 SEG *b = PG_GETARG_SEG_P(1);
576 PG_RETURN_BOOL(((a->upper >= b->upper) && (a->lower <= b->upper)) ||
577 ((b->upper >= a->upper) && (b->lower <= a->upper)));
580 /* seg_over_left -- is the right edge of (a) located at or left of the right edge of (b)?
582 Datum
583 seg_over_left(PG_FUNCTION_ARGS)
585 SEG *a = PG_GETARG_SEG_P(0);
586 SEG *b = PG_GETARG_SEG_P(1);
588 PG_RETURN_BOOL(a->upper <= b->upper);
591 /* seg_left -- is (a) entirely on the left of (b)?
593 Datum
594 seg_left(PG_FUNCTION_ARGS)
596 SEG *a = PG_GETARG_SEG_P(0);
597 SEG *b = PG_GETARG_SEG_P(1);
599 PG_RETURN_BOOL(a->upper < b->lower);
602 /* seg_right -- is (a) entirely on the right of (b)?
604 Datum
605 seg_right(PG_FUNCTION_ARGS)
607 SEG *a = PG_GETARG_SEG_P(0);
608 SEG *b = PG_GETARG_SEG_P(1);
610 PG_RETURN_BOOL(a->lower > b->upper);
613 /* seg_over_right -- is the left edge of (a) located at or right of the left edge of (b)?
615 Datum
616 seg_over_right(PG_FUNCTION_ARGS)
618 SEG *a = PG_GETARG_SEG_P(0);
619 SEG *b = PG_GETARG_SEG_P(1);
621 PG_RETURN_BOOL(a->lower >= b->lower);
624 Datum
625 seg_union(PG_FUNCTION_ARGS)
627 SEG *a = PG_GETARG_SEG_P(0);
628 SEG *b = PG_GETARG_SEG_P(1);
629 SEG *n;
631 n = (SEG *) palloc(sizeof(*n));
633 /* take max of upper endpoints */
634 if (a->upper > b->upper)
636 n->upper = a->upper;
637 n->u_sigd = a->u_sigd;
638 n->u_ext = a->u_ext;
640 else
642 n->upper = b->upper;
643 n->u_sigd = b->u_sigd;
644 n->u_ext = b->u_ext;
647 /* take min of lower endpoints */
648 if (a->lower < b->lower)
650 n->lower = a->lower;
651 n->l_sigd = a->l_sigd;
652 n->l_ext = a->l_ext;
654 else
656 n->lower = b->lower;
657 n->l_sigd = b->l_sigd;
658 n->l_ext = b->l_ext;
661 PG_RETURN_POINTER(n);
664 Datum
665 seg_inter(PG_FUNCTION_ARGS)
667 SEG *a = PG_GETARG_SEG_P(0);
668 SEG *b = PG_GETARG_SEG_P(1);
669 SEG *n;
671 n = (SEG *) palloc(sizeof(*n));
673 /* take min of upper endpoints */
674 if (a->upper < b->upper)
676 n->upper = a->upper;
677 n->u_sigd = a->u_sigd;
678 n->u_ext = a->u_ext;
680 else
682 n->upper = b->upper;
683 n->u_sigd = b->u_sigd;
684 n->u_ext = b->u_ext;
687 /* take max of lower endpoints */
688 if (a->lower > b->lower)
690 n->lower = a->lower;
691 n->l_sigd = a->l_sigd;
692 n->l_ext = a->l_ext;
694 else
696 n->lower = b->lower;
697 n->l_sigd = b->l_sigd;
698 n->l_ext = b->l_ext;
701 PG_RETURN_POINTER(n);
704 static void
705 rt_seg_size(SEG *a, float *size)
707 if (a == (SEG *) NULL || a->upper <= a->lower)
708 *size = 0.0;
709 else
710 *size = fabsf(a->upper - a->lower);
713 Datum
714 seg_size(PG_FUNCTION_ARGS)
716 SEG *seg = PG_GETARG_SEG_P(0);
718 PG_RETURN_FLOAT4(fabsf(seg->upper - seg->lower));
722 /*****************************************************************************
723 * Miscellaneous operators
724 *****************************************************************************/
725 Datum
726 seg_cmp(PG_FUNCTION_ARGS)
728 SEG *a = PG_GETARG_SEG_P(0);
729 SEG *b = PG_GETARG_SEG_P(1);
732 * First compare on lower boundary position
734 if (a->lower < b->lower)
735 PG_RETURN_INT32(-1);
736 if (a->lower > b->lower)
737 PG_RETURN_INT32(1);
740 * a->lower == b->lower, so consider type of boundary.
742 * A '-' lower bound is < any other kind (this could only be relevant if
743 * -HUGE_VAL is used as a regular data value). A '<' lower bound is < any
744 * other kind except '-'. A '>' lower bound is > any other kind.
746 if (a->l_ext != b->l_ext)
748 if (a->l_ext == '-')
749 PG_RETURN_INT32(-1);
750 if (b->l_ext == '-')
751 PG_RETURN_INT32(1);
752 if (a->l_ext == '<')
753 PG_RETURN_INT32(-1);
754 if (b->l_ext == '<')
755 PG_RETURN_INT32(1);
756 if (a->l_ext == '>')
757 PG_RETURN_INT32(1);
758 if (b->l_ext == '>')
759 PG_RETURN_INT32(-1);
763 * For other boundary types, consider # of significant digits first.
765 if (a->l_sigd < b->l_sigd) /* (a) is blurred and is likely to include (b) */
766 PG_RETURN_INT32(-1);
767 if (a->l_sigd > b->l_sigd) /* (a) is less blurred and is likely to be
768 * included in (b) */
769 PG_RETURN_INT32(1);
772 * For same # of digits, an approximate boundary is more blurred than
773 * exact.
775 if (a->l_ext != b->l_ext)
777 if (a->l_ext == '~') /* (a) is approximate, while (b) is exact */
778 PG_RETURN_INT32(-1);
779 if (b->l_ext == '~')
780 PG_RETURN_INT32(1);
781 /* can't get here unless data is corrupt */
782 elog(ERROR, "bogus lower boundary types %d %d",
783 (int) a->l_ext, (int) b->l_ext);
786 /* at this point, the lower boundaries are identical */
789 * First compare on upper boundary position
791 if (a->upper < b->upper)
792 PG_RETURN_INT32(-1);
793 if (a->upper > b->upper)
794 PG_RETURN_INT32(1);
797 * a->upper == b->upper, so consider type of boundary.
799 * A '-' upper bound is > any other kind (this could only be relevant if
800 * HUGE_VAL is used as a regular data value). A '<' upper bound is < any
801 * other kind. A '>' upper bound is > any other kind except '-'.
803 if (a->u_ext != b->u_ext)
805 if (a->u_ext == '-')
806 PG_RETURN_INT32(1);
807 if (b->u_ext == '-')
808 PG_RETURN_INT32(-1);
809 if (a->u_ext == '<')
810 PG_RETURN_INT32(-1);
811 if (b->u_ext == '<')
812 PG_RETURN_INT32(1);
813 if (a->u_ext == '>')
814 PG_RETURN_INT32(1);
815 if (b->u_ext == '>')
816 PG_RETURN_INT32(-1);
820 * For other boundary types, consider # of significant digits first. Note
821 * result here is converse of the lower-boundary case.
823 if (a->u_sigd < b->u_sigd) /* (a) is blurred and is likely to include (b) */
824 PG_RETURN_INT32(1);
825 if (a->u_sigd > b->u_sigd) /* (a) is less blurred and is likely to be
826 * included in (b) */
827 PG_RETURN_INT32(-1);
830 * For same # of digits, an approximate boundary is more blurred than
831 * exact. Again, result is converse of lower-boundary case.
833 if (a->u_ext != b->u_ext)
835 if (a->u_ext == '~') /* (a) is approximate, while (b) is exact */
836 PG_RETURN_INT32(1);
837 if (b->u_ext == '~')
838 PG_RETURN_INT32(-1);
839 /* can't get here unless data is corrupt */
840 elog(ERROR, "bogus upper boundary types %d %d",
841 (int) a->u_ext, (int) b->u_ext);
844 PG_RETURN_INT32(0);
847 Datum
848 seg_lt(PG_FUNCTION_ARGS)
850 int cmp = DatumGetInt32(DirectFunctionCall2(seg_cmp,
851 PG_GETARG_DATUM(0),
852 PG_GETARG_DATUM(1)));
854 PG_RETURN_BOOL(cmp < 0);
857 Datum
858 seg_le(PG_FUNCTION_ARGS)
860 int cmp = DatumGetInt32(DirectFunctionCall2(seg_cmp,
861 PG_GETARG_DATUM(0),
862 PG_GETARG_DATUM(1)));
864 PG_RETURN_BOOL(cmp <= 0);
867 Datum
868 seg_gt(PG_FUNCTION_ARGS)
870 int cmp = DatumGetInt32(DirectFunctionCall2(seg_cmp,
871 PG_GETARG_DATUM(0),
872 PG_GETARG_DATUM(1)));
874 PG_RETURN_BOOL(cmp > 0);
877 Datum
878 seg_ge(PG_FUNCTION_ARGS)
880 int cmp = DatumGetInt32(DirectFunctionCall2(seg_cmp,
881 PG_GETARG_DATUM(0),
882 PG_GETARG_DATUM(1)));
884 PG_RETURN_BOOL(cmp >= 0);
888 Datum
889 seg_different(PG_FUNCTION_ARGS)
891 int cmp = DatumGetInt32(DirectFunctionCall2(seg_cmp,
892 PG_GETARG_DATUM(0),
893 PG_GETARG_DATUM(1)));
895 PG_RETURN_BOOL(cmp != 0);
900 /*****************************************************************************
901 * Auxiliary functions
902 *****************************************************************************/
905 * The purpose of this routine is to print the given floating point
906 * value with exactly n significant digits. Its behaviour
907 * is similar to %.ng except it prints 8.00 where %.ng would
908 * print 8. Returns the length of the string written at "result".
910 * Caller must provide a sufficiently large result buffer; 16 bytes
911 * should be enough for all known float implementations.
913 static int
914 restore(char *result, float val, int n)
916 char buf[25] = {
917 '0', '0', '0', '0', '0',
918 '0', '0', '0', '0', '0',
919 '0', '0', '0', '0', '0',
920 '0', '0', '0', '0', '0',
921 '0', '0', '0', '0', '\0'
923 char *p;
924 int exp;
925 int i,
927 sign;
930 * Put a cap on the number of significant digits to avoid garbage in the
931 * output and ensure we don't overrun the result buffer. (n should not be
932 * negative, but check to protect ourselves against corrupted data.)
934 if (n <= 0)
935 n = FLT_DIG;
936 else
937 n = Min(n, FLT_DIG);
939 /* remember the sign */
940 sign = (val < 0 ? 1 : 0);
942 /* print, in %e style to start with */
943 sprintf(result, "%.*e", n - 1, val);
945 /* find the exponent */
946 p = strchr(result, 'e');
948 /* punt if we have 'inf' or similar */
949 if (p == NULL)
950 return strlen(result);
952 exp = atoi(p + 1);
953 if (exp == 0)
955 /* just truncate off the 'e+00' */
956 *p = '\0';
958 else
960 if (abs(exp) <= 4)
963 * remove the decimal point from the mantissa and write the digits
964 * to the buf array
966 for (p = result + sign, i = 10, dp = 0; *p != 'e'; p++, i++)
968 buf[i] = *p;
969 if (*p == '.')
971 dp = i--; /* skip the decimal point */
974 if (dp == 0)
975 dp = i--; /* no decimal point was found in the above
976 * for() loop */
978 if (exp > 0)
980 if (dp - 10 + exp >= n)
983 * the decimal point is behind the last significant digit;
984 * the digits in between must be converted to the exponent
985 * and the decimal point placed after the first digit
987 exp = dp - 10 + exp - n;
988 buf[10 + n] = '\0';
990 /* insert the decimal point */
991 if (n > 1)
993 dp = 11;
994 for (i = 23; i > dp; i--)
995 buf[i] = buf[i - 1];
996 buf[dp] = '.';
1000 * adjust the exponent by the number of digits after the
1001 * decimal point
1003 if (n > 1)
1004 sprintf(&buf[11 + n], "e%d", exp + n - 1);
1005 else
1006 sprintf(&buf[11], "e%d", exp + n - 1);
1008 if (sign)
1010 buf[9] = '-';
1011 strcpy(result, &buf[9]);
1013 else
1014 strcpy(result, &buf[10]);
1016 else
1017 { /* insert the decimal point */
1018 dp += exp;
1019 for (i = 23; i > dp; i--)
1020 buf[i] = buf[i - 1];
1021 buf[11 + n] = '\0';
1022 buf[dp] = '.';
1023 if (sign)
1025 buf[9] = '-';
1026 strcpy(result, &buf[9]);
1028 else
1029 strcpy(result, &buf[10]);
1032 else
1033 { /* exp <= 0 */
1034 dp += exp - 1;
1035 buf[10 + n] = '\0';
1036 buf[dp] = '.';
1037 if (sign)
1039 buf[dp - 2] = '-';
1040 strcpy(result, &buf[dp - 2]);
1042 else
1043 strcpy(result, &buf[dp - 1]);
1047 /* do nothing for abs(exp) > 4; %e must be OK */
1048 /* just get rid of zeroes after [eE]- and +zeroes after [Ee]. */
1050 /* ... this is not done yet. */
1052 return strlen(result);
1057 ** Miscellany
1060 /* find out the number of significant digits in a string representing
1061 * a floating point number
1064 significant_digits(const char *s)
1066 const char *p = s;
1067 int n,
1069 zeroes;
1071 zeroes = 1;
1072 /* skip leading zeroes and sign */
1073 for (c = *p; (c == '0' || c == '+' || c == '-') && c != 0; c = *(++p));
1075 /* skip decimal point and following zeroes */
1076 for (c = *p; (c == '0' || c == '.') && c != 0; c = *(++p))
1078 if (c != '.')
1079 zeroes++;
1082 /* count significant digits (n) */
1083 for (c = *p, n = 0; c != 0; c = *(++p))
1085 if (!((c >= '0' && c <= '9') || (c == '.')))
1086 break;
1087 if (c != '.')
1088 n++;
1091 if (!n)
1092 return zeroes;
1094 return n;