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