ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/bioseg/trunk/bioseg.c
Revision: 49
Committed: Wed Aug 12 11:30:55 2009 UTC (13 years, 1 month ago) by kmr
File size: 23861 byte(s)
Log Message:
Change by Matthew Wakeling: changed procedures to the new calling conventions
which improves performance.

Line File contents
1 /*
2 This file contains the implementation of the BIOSEG PostgreSQL type. The
3 implementation is a copy of the SEG type from the contrib directory in the
4 PostgreSQL source, which has been changed to represent ranges of integers.
5 The anticipated use of this type is to represent contiguous intervals of a
6 biological sequence.
7
8 SEG code written Gene Selkov, Jr.
9
10 Changes for BIOSEG written by Kim Rutherford <kmr@xenu.org.uk>.
11 */
12
13 #include "postgres.h"
14
15 #include <stdlib.h>
16 #include <errno.h>
17 #include <limits.h>
18
19 #include "access/gist.h"
20 #include "access/skey.h"
21 #include "utils/builtins.h"
22
23 #include "biosegdata.h"
24
25 #ifdef INTERBASE_COORDS
26 #define BIOSEG bioseg0
27 #define BIOSEG_PREFIX(x) bioseg0 ## x
28 #else
29 #define BIOSEG bioseg
30 #define BIOSEG_PREFIX(x) bioseg ## x
31 #endif
32
33 PG_MODULE_MAGIC;
34
35 extern int BIOSEG_PREFIX(_yyparse)();
36 extern void BIOSEG_PREFIX(_yyerror)(const char *message);
37 extern void BIOSEG_PREFIX(_scanner_init)(const char *str);
38 extern void BIOSEG_PREFIX(_scanner_finish)(void);
39
40 /*
41 ** Input/Output routines
42 */
43 SEG *BIOSEG_PREFIX(_in)(char *str);
44 char *BIOSEG_PREFIX(_out)(SEG * seg);
45 Datum BIOSEG_PREFIX(_create)(PG_FUNCTION_ARGS);
46 int32 BIOSEG_PREFIX(_lower)(SEG * seg);
47 int32 BIOSEG_PREFIX(_upper)(SEG * seg);
48 int32 BIOSEG_PREFIX(_center)(SEG * seg);
49
50 /*
51 ** GiST support methods
52 */
53 Datum BIOSEG_PREFIX(_gist_consistent)(PG_FUNCTION_ARGS);
54 Datum BIOSEG_PREFIX(_gist_compress)(PG_FUNCTION_ARGS);
55 Datum BIOSEG_PREFIX(_gist_decompress)(PG_FUNCTION_ARGS);
56 Datum BIOSEG_PREFIX(_gist_penalty)(PG_FUNCTION_ARGS);
57 Datum BIOSEG_PREFIX(_gist_picksplit)(PG_FUNCTION_ARGS);
58 Datum BIOSEG_PREFIX(_gist_union)(PG_FUNCTION_ARGS);
59 Datum BIOSEG_PREFIX(_gist_same)(PG_FUNCTION_ARGS);
60
61
62 /*
63 ** R-tree support functions
64 */
65 Datum BIOSEG_PREFIX(_same)(PG_FUNCTION_ARGS);
66 Datum BIOSEG_PREFIX(_contains_int)(PG_FUNCTION_ARGS);
67 Datum BIOSEG_PREFIX(_contains)(PG_FUNCTION_ARGS);
68 Datum BIOSEG_PREFIX(_contained)(PG_FUNCTION_ARGS);
69 Datum BIOSEG_PREFIX(_overlap)(PG_FUNCTION_ARGS);
70 Datum BIOSEG_PREFIX(_left)(PG_FUNCTION_ARGS);
71 Datum BIOSEG_PREFIX(_over_left)(PG_FUNCTION_ARGS);
72 Datum BIOSEG_PREFIX(_right)(PG_FUNCTION_ARGS);
73 Datum BIOSEG_PREFIX(_over_right)(PG_FUNCTION_ARGS);
74 Datum BIOSEG_PREFIX(_rt_size)(PG_FUNCTION_ARGS);
75 Datum BIOSEG_PREFIX(_size)(PG_FUNCTION_ARGS);
76
77 static SEG *BIOSEG_PREFIX(_union)(SEG * a, SEG * b);
78
79 /*
80 ** Various operators
81 */
82 Datum BIOSEG_PREFIX(_cmp)(PG_FUNCTION_ARGS);
83 Datum BIOSEG_PREFIX(_lt)(PG_FUNCTION_ARGS);
84 Datum BIOSEG_PREFIX(_le)(PG_FUNCTION_ARGS);
85 Datum BIOSEG_PREFIX(_gt)(PG_FUNCTION_ARGS);
86 Datum BIOSEG_PREFIX(_ge)(PG_FUNCTION_ARGS);
87 Datum BIOSEG_PREFIX(_different)(PG_FUNCTION_ARGS);
88 Datum BIOSEG_PREFIX(_joinsel)(PG_FUNCTION_ARGS);
89 Datum BIOSEG_PREFIX(_sel)(PG_FUNCTION_ARGS);
90 Datum BIOSEG_PREFIX(_contsel)(PG_FUNCTION_ARGS);
91 Datum BIOSEG_PREFIX(_contjoinsel)(PG_FUNCTION_ARGS);
92
93
94 static int get_dots(char **str);
95 static int get_int(char **str, int32 *result);
96
97
98 /*****************************************************************************
99 * Input/Output functions
100 *****************************************************************************/
101
102 SEG *
103 BIOSEG_PREFIX(_in)(char *str)
104 {
105 int32 lower;
106 int32 upper;
107
108 if (!get_int(&str, &lower)) {
109 return NULL;
110 }
111
112 if (str[0] == 0) {
113 upper = lower;
114 } else {
115 if (!get_dots(&str)) {
116 ereport(ERROR,
117 (errcode(ERRCODE_SYNTAX_ERROR),
118 errmsg("bad bioseg representation"),
119 errdetail("number followed by something other than ..: %s", str)));
120 return NULL;
121 }
122
123 if (!get_int(&str, &upper)) {
124 ereport(ERROR,
125 (errcode(ERRCODE_SYNTAX_ERROR),
126 errmsg("bad bioseg representation"),
127 errdetail("number\"..\" followed by something other than a number: %s", str)));
128 return NULL;
129 }
130
131 if (lower > upper) {
132 ereport(ERROR,
133 (errcode(ERRCODE_SYNTAX_ERROR),
134 errmsg("bad bioseg representation"),
135 errdetail("lower limit of range greater than upper")));
136 return NULL;
137 }
138
139 if (str[0] != 0) {
140 ereport(ERROR,
141 (errcode(ERRCODE_SYNTAX_ERROR),
142 errmsg("bad bioseg representation"),
143 errdetail("garbage at end of string: %s", str)));
144 return NULL;
145 }
146 }
147
148 {
149 SEG *result = palloc(sizeof(SEG));
150
151 result->lower = lower;
152 result->upper = upper;
153 return result;
154 }
155 }
156
157 #ifdef INTERBASE_COORDS
158 #define MIN_LOWER INT_MIN
159 #else
160 #define MIN_LOWER 1l
161 #endif
162
163 int get_int(char **strp, int32 *result) {
164 char *return_pos;
165 long int long_result = -1;
166
167 if (!(*strp)[0]) {
168 ereport(ERROR,
169 (errcode(ERRCODE_SYNTAX_ERROR),
170 errmsg("bad bioseg representation"),
171 errdetail("end of string found when expecting an integer")));
172 return 0;
173 }
174
175 errno = 0;
176
177 long_result = strtol(*strp, &return_pos, 0);
178
179 if (errno == ERANGE && (long_result == LONG_MAX || long_result == LONG_MIN)) {
180 ereport(ERROR,
181 (errcode(ERRCODE_SYNTAX_ERROR),
182 errmsg("bad bioseg representation"),
183 errdetail("integer at: %s is out of range", *strp)));
184 return 0;
185 }
186
187 if (errno != 0 && long_result == 0) {
188 ereport(ERROR,
189 (errcode(ERRCODE_SYNTAX_ERROR),
190 errmsg("bad bioseg representation"),
191 errdetail("unable to read an integer: %s", strerror(errno))));
192 return 0;
193 }
194
195 if (*strp == return_pos) {
196 ereport(ERROR,
197 (errcode(ERRCODE_SYNTAX_ERROR),
198 errmsg("bad bioseg representation"),
199 errdetail("no integer found at: %s", *strp)));
200 return 0;
201 }
202
203 if (long_result < MIN_LOWER) {
204 // when INTERBASE_COORDS is set, on machines where
205 // sizeof(long int) == sizeof(int32) this block won't be executed because
206 // strtol() will return ERANGE
207 ereport(ERROR,
208 (errcode(ERRCODE_SYNTAX_ERROR),
209 errmsg("bad bioseg representation"),
210 errdetail("integer %ld at: %s is out of range - must be >= %ld",
211 long_result, *strp, MIN_LOWER)));
212 return 0;
213 }
214
215 if (long_result > INT_MAX) {
216 // on machines where sizeof(long int) == sizeof(int32) this won't happen
217 // because strtol() will return ERANGE
218 ereport(ERROR,
219 (errcode(ERRCODE_SYNTAX_ERROR),
220 errmsg("bad bioseg representation"),
221 errdetail("integer %ld at: %s is out of range - must be <= %d",
222 long_result, *strp, INT_MAX)));
223 return 0;
224 }
225
226 *strp = return_pos;
227 *result = long_result;
228
229 return 1;
230 }
231
232 int
233 get_dots(char **strp)
234 {
235 if ((*strp)[0] == '.') {
236 (*strp)++;
237 if ((*strp)[0] == '.') {
238 (*strp)++;
239 if ((*strp)[0] == '.') {
240 // allow for "10...20"
241 (*strp)++;
242 }
243 return 1;
244 } else {
245 return 0;
246 }
247 } else {
248 return 0;
249 }
250 }
251
252 char *
253 BIOSEG_PREFIX(_out)(SEG * bioseg)
254 {
255 char *result;
256 char *p;
257
258 if (bioseg == NULL)
259 return (NULL);
260
261 p = result = (char *) palloc(40);
262
263 if (bioseg->lower == bioseg->upper)
264 {
265 /*
266 * indicates that this interval was built by bioseg_in off a single point
267 */
268 sprintf(p, "%d", bioseg->lower);
269 }
270 else
271 {
272 sprintf(p, "%d..%d", bioseg->lower, bioseg->upper);
273 }
274
275 return (result);
276 }
277
278 PG_FUNCTION_INFO_V1(BIOSEG_PREFIX(_create));
279 Datum BIOSEG_PREFIX(_create)(PG_FUNCTION_ARGS)
280 {
281 SEG *result = palloc(sizeof(SEG));
282 int32 lower = PG_GETARG_INT32(0);
283 int32 upper = PG_GETARG_INT32(1);
284
285 if (lower > upper) {
286 ereport(ERROR,
287 (errcode(ERRCODE_SYNTAX_ERROR),
288 errmsg("bad bioseg representation"),
289 errdetail("lower limit of range greater than upper")));
290 PG_RETURN_POINTER(0);
291 }
292
293 if (lower < MIN_LOWER) {
294 ereport(ERROR,
295 (errcode(ERRCODE_SYNTAX_ERROR),
296 errmsg("bad bioseg representation"),
297 errdetail("lower bound (%ld) must be >= %ld",
298 (long int) lower, MIN_LOWER)));
299 PG_RETURN_POINTER(0);
300 }
301
302 result->lower = lower;
303 result->upper = upper;
304
305 PG_RETURN_POINTER(result);
306 }
307
308
309
310 int32
311 BIOSEG_PREFIX(_center)(SEG * bioseg)
312 {
313 return ((int32) bioseg->lower + (int32) bioseg->upper) / 2;
314 }
315
316 int32
317 BIOSEG_PREFIX(_lower)(SEG * bioseg)
318 {
319 return bioseg->lower;
320 }
321
322 int32
323 BIOSEG_PREFIX(_upper)(SEG * bioseg)
324 {
325 return bioseg->upper;
326 }
327
328
329 /*****************************************************************************
330 * GiST functions
331 *****************************************************************************/
332
333 /*
334 ** The GiST Consistent method for biosegments
335 ** Should return false if for all data items x below entry,
336 ** the predicate x op query == FALSE, where op is the oper
337 ** corresponding to strategy in the pg_amop table.
338 */
339 PG_FUNCTION_INFO_V1(BIOSEG_PREFIX(_gist_consistent));
340 Datum BIOSEG_PREFIX(_gist_consistent)(PG_FUNCTION_ARGS)
341 {
342 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
343 SEG *query = (SEG *) PG_GETARG_POINTER(1);
344 StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
345 SEG *key = (SEG *) DatumGetPointer(entry->key);
346
347 if (GIST_LEAF(entry)) {
348 switch (strategy)
349 {
350 case RTLeftStrategyNumber:
351 PG_RETURN_BOOL(key->upper < query->lower);
352 break;
353 case RTOverLeftStrategyNumber:
354 PG_RETURN_BOOL(key->upper <= query->upper);
355 break;
356 case RTOverlapStrategyNumber:
357 #ifdef INTERBASE_COORDS
358 PG_RETURN_BOOL((key->upper > query->lower) && (key->lower < query->upper));
359 #else
360 PG_RETURN_BOOL((key->upper >= query->lower) && (key->lower <= query->upper));
361 #endif
362 break;
363 case RTOverRightStrategyNumber:
364 PG_RETURN_BOOL(key->lower >= query->lower);
365 break;
366 case RTRightStrategyNumber:
367 PG_RETURN_BOOL(key->lower > query->upper);
368 break;
369 case RTSameStrategyNumber:
370 PG_RETURN_BOOL((key->lower == query->lower) && (key->upper == query->upper));
371 break;
372 case RTContainsStrategyNumber:
373 case RTOldContainsStrategyNumber:
374 PG_RETURN_BOOL((key->lower <= query->lower) && (key->upper >= query->upper));
375 break;
376 case RTContainedByStrategyNumber:
377 case RTOldContainedByStrategyNumber:
378 PG_RETURN_BOOL((key->lower >= query->lower) && (key->upper <= query->upper));
379 break;
380 }
381 } else {
382 switch (strategy)
383 {
384 case RTLeftStrategyNumber:
385 PG_RETURN_BOOL(key->lower < query->lower);
386 break;
387 case RTOverLeftStrategyNumber:
388 PG_RETURN_BOOL(key->lower <= query->upper);
389 break;
390 case RTOverlapStrategyNumber:
391 #ifdef INTERBASE_COORDS
392 PG_RETURN_BOOL((key->upper > query->lower) && (key->lower < query->upper));
393 #else
394 PG_RETURN_BOOL((key->upper >= query->lower) && (key->lower <= query->upper));
395 #endif
396 break;
397 case RTOverRightStrategyNumber:
398 PG_RETURN_BOOL(key->upper >= query->lower);
399 break;
400 case RTRightStrategyNumber:
401 PG_RETURN_BOOL(key->upper > query->upper);
402 break;
403 case RTSameStrategyNumber:
404 case RTContainsStrategyNumber:
405 case RTOldContainsStrategyNumber:
406 PG_RETURN_BOOL((key->lower <= query->lower) && (key->upper >= query->upper));
407 break;
408 case RTContainedByStrategyNumber:
409 case RTOldContainedByStrategyNumber:
410 #ifdef INTERBASE_COORDS
411 PG_RETURN_BOOL((key->upper > query->lower) && (key->lower < query->upper));
412 #else
413 PG_RETURN_BOOL((key->upper >= query->lower) && (key->lower <= query->upper));
414 #endif
415 break;
416 }
417 }
418 PG_RETURN_BOOL(FALSE);
419 }
420
421 /*
422 ** The GiST Union method for biosegments
423 ** returns the minimal bounding bioseg that encloses all the entries in entryvec
424 */
425 PG_FUNCTION_INFO_V1(BIOSEG_PREFIX(_gist_union));
426 Datum BIOSEG_PREFIX(_gist_union)(PG_FUNCTION_ARGS)
427 {
428 GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
429 int numranges;
430 int i;
431 SEG *out = (SEG *) NULL;
432 SEG *tmp;
433
434 #ifdef GIST_DEBUG
435 fprintf(stderr, "union\n");
436 #endif
437
438 out = (SEG *) palloc(sizeof(*out));
439 tmp = (SEG *) entryvec->vector[0].key;
440 out->lower = tmp->lower;
441 out->upper = tmp->upper;
442 numranges = entryvec->n;
443
444 for (i = 1; i < numranges; i++) {
445 tmp = (SEG *) entryvec->vector[i].key;
446 if (tmp->lower < out->lower) {
447 out->lower = tmp->lower;
448 }
449 if (tmp->upper > out->upper) {
450 out->upper = tmp->upper;
451 }
452 }
453
454 PG_RETURN_POINTER(out);
455 }
456
457 /*
458 ** GiST Compress and Decompress methods for biosegments
459 ** do not do anything.
460 */
461 PG_FUNCTION_INFO_V1(BIOSEG_PREFIX(_gist_compress));
462 Datum BIOSEG_PREFIX(_gist_compress)(PG_FUNCTION_ARGS)
463 {
464 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
465 PG_RETURN_POINTER(entry);
466 }
467
468 PG_FUNCTION_INFO_V1(BIOSEG_PREFIX(_gist_decompress));
469 Datum BIOSEG_PREFIX(_gist_decompress)(PG_FUNCTION_ARGS)
470 {
471 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
472 PG_RETURN_POINTER(entry);
473 }
474
475 /*
476 ** The GiST Penalty method for biosegments
477 ** As in the R-tree paper, we use change in area as our penalty metric
478 */
479 PG_FUNCTION_INFO_V1(BIOSEG_PREFIX(_gist_penalty));
480 Datum BIOSEG_PREFIX(_gist_penalty)(PG_FUNCTION_ARGS)
481 {
482 GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
483 GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
484 float *result = (float *) PG_GETARG_POINTER(2);
485 SEG *ud;
486 SEG *origrange;
487 SEG *newrange;
488 int32 tmp1;
489 int32 tmp2;
490
491 origrange = (SEG *) DatumGetPointer(origentry->key);
492 newrange = (SEG *) DatumGetPointer(newentry->key);
493 ud = BIOSEG_PREFIX(_union)(origrange, newrange);
494 tmp1 = ud->upper - ud->lower;
495 tmp2 = origrange->upper - origrange->lower;
496 if (tmp1 == tmp2)
497 {
498 tmp1 = newrange->upper - newrange->lower;
499 *result = ((tmp2 - tmp1) * 100000.0) / tmp2;
500 }
501 else
502 {
503 *result = tmp1 - tmp2 + 100000.0;
504 }
505
506 #ifdef GIST_DEBUG
507 fprintf(stderr, "Penalty of putting %d..%d into %d..%d is %g\n", newrange->lower, newrange->upper, origrange->lower, origrange->upper, *result);
508 #endif
509
510 PG_RETURN_POINTER(result);
511 }
512
513
514 /*
515 ** The GiST PickSplit method for segments
516 */
517 PG_FUNCTION_INFO_V1(BIOSEG_PREFIX(_gist_picksplit));
518 Datum BIOSEG_PREFIX(_gist_picksplit)(PG_FUNCTION_ARGS)
519 {
520 GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
521 GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
522 OffsetNumber i;
523 SEG *datum_alpha;
524 SEG *datum_l;
525 SEG *datum_r;
526 int32 lowest;
527 int32 highest;
528 int32 midpoint;
529 int32 split;
530 int nbytes;
531 int firsttime;
532 long long int midpointsum;
533 int sumcount;
534 OffsetNumber *left;
535 OffsetNumber *right;
536 OffsetNumber maxoff;
537
538 maxoff = entryvec->n - 1;
539 nbytes = (maxoff + 2) * sizeof(OffsetNumber);
540 v->spl_left = (OffsetNumber *) palloc(nbytes);
541 v->spl_right = (OffsetNumber *) palloc(nbytes);
542
543 midpointsum = 0;
544 sumcount = 0;
545 firsttime = true;
546 lowest = 0;
547 highest = 0;
548
549 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
550 {
551 datum_alpha = (SEG *) DatumGetPointer(entryvec->vector[i].key);
552 midpoint = datum_alpha->lower + ((datum_alpha->upper - datum_alpha->lower) / 2);
553 midpointsum += midpoint;
554 sumcount++;
555 if (firsttime || (midpoint < lowest))
556 {
557 lowest = midpoint;
558 }
559 if (firsttime || (midpoint > highest))
560 {
561 highest = midpoint;
562 }
563 firsttime = false;
564 }
565
566 split = midpointsum / sumcount;
567 left = v->spl_left;
568 v->spl_nleft = 0;
569 right = v->spl_right;
570 v->spl_nright = 0;
571
572 datum_l = (SEG *) palloc(sizeof(*datum_l));
573 datum_l->lower = lowest;
574 datum_l->upper = lowest;
575 datum_r = (SEG *) palloc(sizeof(*datum_r));
576 datum_r->lower = highest;
577 datum_r->upper = highest;
578
579 /*
580 * Now split up the regions between the two seeds.
581 */
582
583 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
584 {
585 datum_alpha = (SEG *) DatumGetPointer(entryvec->vector[i].key);
586 midpoint = datum_alpha->lower + ((datum_alpha->upper - datum_alpha->lower) / 2);
587
588 /* pick which page to add it to */
589 if (midpoint <= split)
590 {
591 datum_l = BIOSEG_PREFIX(_union)(datum_l, datum_alpha);
592 *left++ = i;
593 v->spl_nleft++;
594 }
595 else
596 {
597 datum_r = BIOSEG_PREFIX(_union)(datum_r, datum_alpha);
598 *right++ = i;
599 v->spl_nright++;
600 }
601 }
602 *left = *right = FirstOffsetNumber; /* sentinel value, see dosplit() */
603
604 v->spl_ldatum = PointerGetDatum(datum_l);
605 v->spl_rdatum = PointerGetDatum(datum_r);
606
607 #ifdef GIST_DEBUG
608 fprintf(stderr, "Picksplit summary to %d..%d (%d locations) and %d..%d (%d locations), with pivot %d\n", datum_l->lower, datum_l->upper, v->spl_nleft,
609 datum_r->lower, datum_r->upper, v->spl_nright, split);
610 #endif
611
612 PG_RETURN_POINTER(v);
613 }
614
615 /*
616 ** Equality methods
617 */
618 PG_FUNCTION_INFO_V1(BIOSEG_PREFIX(_gist_same));
619 Datum BIOSEG_PREFIX(_gist_same)(PG_FUNCTION_ARGS)
620 {
621 SEG *b1 = (SEG *) PG_GETARG_POINTER(0);
622 SEG *b2 = (SEG *) PG_GETARG_POINTER(1);
623 bool *result = (bool *) PG_GETARG_POINTER(2);
624
625 *result = ((b1->lower == b2->lower) && (b1->upper == b2->upper));
626
627 #ifdef GIST_DEBUG
628 fprintf(stderr, "same: %s\n", (*result ? "TRUE" : "FALSE"));
629 #endif
630
631 PG_RETURN_POINTER(result);
632 }
633
634 PG_FUNCTION_INFO_V1(BIOSEG_PREFIX(_contains));
635 Datum BIOSEG_PREFIX(_contains)(PG_FUNCTION_ARGS)
636 {
637 SEG *a = (SEG *) PG_GETARG_POINTER(0);
638 SEG *b = (SEG *) PG_GETARG_POINTER(1);
639
640 PG_RETURN_BOOL((a->lower <= b->lower) && (a->upper >= b->upper));
641 }
642
643 PG_FUNCTION_INFO_V1(BIOSEG_PREFIX(_contained));
644 Datum BIOSEG_PREFIX(_contained)(PG_FUNCTION_ARGS)
645 {
646 SEG *a = (SEG *) PG_GETARG_POINTER(0);
647 SEG *b = (SEG *) PG_GETARG_POINTER(1);
648
649 PG_RETURN_BOOL((a->lower >= b->lower) && (a->upper <= b->upper));
650 }
651
652 /*****************************************************************************
653 * Operator class for R-tree indexing
654 *****************************************************************************/
655
656 PG_FUNCTION_INFO_V1(BIOSEG_PREFIX(_same));
657 Datum BIOSEG_PREFIX(_same)(PG_FUNCTION_ARGS)
658 {
659 SEG *a = (SEG *) PG_GETARG_POINTER(0);
660 SEG *b = (SEG *) PG_GETARG_POINTER(1);
661
662 PG_RETURN_BOOL((a->lower == b->lower) && (a->upper == b->upper));
663 }
664
665 /* bioseg_overlap -- does a overlap b?
666 */
667 PG_FUNCTION_INFO_V1(BIOSEG_PREFIX(_overlap));
668 Datum BIOSEG_PREFIX(_overlap)(PG_FUNCTION_ARGS)
669 {
670 SEG *a = (SEG *) PG_GETARG_POINTER(0);
671 SEG *b = (SEG *) PG_GETARG_POINTER(1);
672 #ifdef INTERBASE_COORDS
673 PG_RETURN_BOOL((a->upper > b->lower) && (a->lower < b->upper));
674 #else
675 PG_RETURN_BOOL((a->upper >= b->lower) && (a->lower <= b->upper));
676 #endif
677 }
678
679 /* bioseg_overleft -- is the right edge of (a) located at or left of the right edge of (b)?
680 */
681 PG_FUNCTION_INFO_V1(BIOSEG_PREFIX(_over_left));
682 Datum BIOSEG_PREFIX(_over_left)(PG_FUNCTION_ARGS)
683 {
684 SEG *a = (SEG *) PG_GETARG_POINTER(0);
685 SEG *b = (SEG *) PG_GETARG_POINTER(1);
686 PG_RETURN_BOOL(a->upper <= b->upper);
687 }
688
689 /* bioseg_left -- is (a) entirely on the left of (b)?
690 */
691 PG_FUNCTION_INFO_V1(BIOSEG_PREFIX(_left));
692 Datum BIOSEG_PREFIX(_left)(PG_FUNCTION_ARGS)
693 {
694 SEG *a = (SEG *) PG_GETARG_POINTER(0);
695 SEG *b = (SEG *) PG_GETARG_POINTER(1);
696 PG_RETURN_BOOL(a->upper < b->lower);
697 }
698
699 /* bioseg_right -- is (a) entirely on the right of (b)?
700 */
701 PG_FUNCTION_INFO_V1(BIOSEG_PREFIX(_right));
702 Datum BIOSEG_PREFIX(_right)(PG_FUNCTION_ARGS)
703 {
704 SEG *a = (SEG *) PG_GETARG_POINTER(0);
705 SEG *b = (SEG *) PG_GETARG_POINTER(1);
706 PG_RETURN_BOOL(a->lower > b->upper);
707 }
708
709 /* bioseg_overright -- is the left edge of (a) located at or right of the left edge of (b)?
710 */
711 PG_FUNCTION_INFO_V1(BIOSEG_PREFIX(_over_right));
712 Datum BIOSEG_PREFIX(_over_right)(PG_FUNCTION_ARGS)
713 {
714 SEG *a = (SEG *) PG_GETARG_POINTER(0);
715 SEG *b = (SEG *) PG_GETARG_POINTER(1);
716 PG_RETURN_BOOL(a->lower >= b->lower);
717 }
718
719
720 static SEG *
721 BIOSEG_PREFIX(_union)(SEG * a, SEG * b)
722 {
723 SEG *n;
724
725 n = (SEG *) palloc(sizeof(*n));
726
727 /* take max of upper endpoints */
728 if (a->upper > b->upper)
729 {
730 n->upper = a->upper;
731 }
732 else
733 {
734 n->upper = b->upper;
735 }
736
737 /* take min of lower endpoints */
738 if (a->lower < b->lower)
739 {
740 n->lower = a->lower;
741 }
742 else
743 {
744 n->lower = b->lower;
745 }
746
747 return (n);
748 }
749
750 PG_FUNCTION_INFO_V1(BIOSEG_PREFIX(_rt_size));
751 Datum BIOSEG_PREFIX(_rt_size)(PG_FUNCTION_ARGS)
752 {
753 SEG *a = (SEG *) PG_GETARG_POINTER(0);
754 int32 *size = (int32 *) PG_GETARG_POINTER(1);
755 if (a == (SEG *) NULL)
756 *size = 0;
757 else
758 #ifdef INTERBASE_COORDS
759 *size = (int32) (a->upper - a->lower);
760 #else
761 *size = (int32) (a->upper - a->lower + 1);
762 #endif
763 PG_RETURN_NULL();
764 }
765
766 PG_FUNCTION_INFO_V1(BIOSEG_PREFIX(_size));
767 Datum BIOSEG_PREFIX(_size)(PG_FUNCTION_ARGS)
768 {
769 SEG *a = (SEG *) PG_GETARG_POINTER(0);
770 #ifdef INTERBASE_COORDS
771 PG_RETURN_INT32(a->upper - a->lower);
772 #else
773 PG_RETURN_INT32(a->upper - a->lower + 1);
774 #endif
775 }
776
777
778 /*****************************************************************************
779 * Miscellaneous operators
780 *****************************************************************************/
781 PG_FUNCTION_INFO_V1(BIOSEG_PREFIX(_cmp));
782 Datum BIOSEG_PREFIX(_cmp)(PG_FUNCTION_ARGS)
783 {
784 SEG *a = (SEG *) PG_GETARG_POINTER(0);
785 SEG *b = (SEG *) PG_GETARG_POINTER(1);
786 if (a->lower < b->lower)
787 PG_RETURN_INT32(-1);
788 if (a->lower > b->lower)
789 PG_RETURN_INT32(1);
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 PG_RETURN_INT32(0);
797 }
798
799 PG_FUNCTION_INFO_V1(BIOSEG_PREFIX(_lt));
800 Datum BIOSEG_PREFIX(_lt)(PG_FUNCTION_ARGS)
801 {
802 SEG *a = (SEG *) PG_GETARG_POINTER(0);
803 SEG *b = (SEG *) PG_GETARG_POINTER(1);
804 PG_RETURN_BOOL((a->lower < b->lower) || ((a->lower == b->lower) && (a->upper < b->upper)));
805 }
806
807 PG_FUNCTION_INFO_V1(BIOSEG_PREFIX(_le));
808 Datum BIOSEG_PREFIX(_le)(PG_FUNCTION_ARGS)
809 {
810 SEG *a = (SEG *) PG_GETARG_POINTER(0);
811 SEG *b = (SEG *) PG_GETARG_POINTER(1);
812 PG_RETURN_BOOL((a->lower < b->lower) || ((a->lower == b->lower) && (a->upper <= b->upper)));
813 }
814
815 PG_FUNCTION_INFO_V1(BIOSEG_PREFIX(_gt));
816 Datum BIOSEG_PREFIX(_gt)(PG_FUNCTION_ARGS)
817 {
818 SEG *a = (SEG *) PG_GETARG_POINTER(0);
819 SEG *b = (SEG *) PG_GETARG_POINTER(1);
820 PG_RETURN_BOOL((a->lower > b->lower) || ((a->lower == b->lower) && (a->upper > b->upper)));
821 }
822
823 PG_FUNCTION_INFO_V1(BIOSEG_PREFIX(_ge));
824 Datum BIOSEG_PREFIX(_ge)(PG_FUNCTION_ARGS)
825 {
826 SEG *a = (SEG *) PG_GETARG_POINTER(0);
827 SEG *b = (SEG *) PG_GETARG_POINTER(1);
828 PG_RETURN_BOOL((a->lower > b->lower) || ((a->lower == b->lower) && (a->upper >= b->upper)));
829 }
830
831 PG_FUNCTION_INFO_V1(BIOSEG_PREFIX(_different));
832 Datum BIOSEG_PREFIX(_different)(PG_FUNCTION_ARGS)
833 {
834 SEG *a = (SEG *) PG_GETARG_POINTER(0);
835 SEG *b = (SEG *) PG_GETARG_POINTER(1);
836 PG_RETURN_BOOL((a->lower != b->lower) || (a->upper != b->upper));
837 }
838
839 PG_FUNCTION_INFO_V1(BIOSEG_PREFIX(_contains_int));
840 Datum BIOSEG_PREFIX(_contains_int)(PG_FUNCTION_ARGS)
841 {
842 SEG *a = (SEG *) PG_GETARG_POINTER(0);
843 int *b = (int *) PG_GETARG_POINTER(1);
844 #ifdef INTERBASE_COORDS
845 PG_RETURN_BOOL((a->lower <= *b) && (a->upper > *b));
846 #else
847 PG_RETURN_BOOL((a->lower <= *b) && (a->upper >= *b));
848 #endif
849 }
850
851 /*
852 ** These are lower than those in geo_selfuncs.c - found by trail and error.
853 */
854 PG_FUNCTION_INFO_V1(BIOSEG_PREFIX(_sel));
855 Datum
856 BIOSEG_PREFIX(_sel)(PG_FUNCTION_ARGS)
857 {
858 PG_RETURN_FLOAT8(2.0e-4);
859 }
860
861 PG_FUNCTION_INFO_V1(BIOSEG_PREFIX(_joinsel));
862 Datum
863 BIOSEG_PREFIX(_joinsel)(PG_FUNCTION_ARGS)
864 {
865 PG_RETURN_FLOAT8(1.0e-5);
866 }
867
868 PG_FUNCTION_INFO_V1(BIOSEG_PREFIX(_contsel));
869 Datum
870 BIOSEG_PREFIX(_contsel)(PG_FUNCTION_ARGS)
871 {
872 PG_RETURN_FLOAT8(1.0e-4);
873 }
874
875 PG_FUNCTION_INFO_V1(BIOSEG_PREFIX(_contjoinsel));
876 Datum
877 BIOSEG_PREFIX(_contjoinsel)(PG_FUNCTION_ARGS)
878 {
879 PG_RETURN_FLOAT8(5e-6);
880 }