PostgreSQL Source Code  git master
seg.c
Go to the documentation of this file.
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_DATUM(n))
23 
24 
25 /*
26 #define GIST_DEBUG
27 #define GIST_QUERY_DEBUG
28 */
29 
31 
32 /*
33  * Auxiliary data structure for picksplit method.
34  */
35 typedef struct
36 {
37  float center;
41 
42 /*
43 ** Input/Output routines
44 */
51 
52 /*
53 ** GiST support methods
54 */
62 static Datum gseg_leaf_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 */
80 static void rt_seg_size(SEG *a, float *size);
81 
82 /*
83 ** Various operators
84 */
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
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 
114 
115  PG_RETURN_POINTER(result);
116 }
117 
118 Datum
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 */
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 
159 Datum
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
169 {
170  SEG *seg = PG_GETARG_SEG_P(0);
171 
172  PG_RETURN_FLOAT4(seg->lower);
173 }
174 
175 Datum
177 {
178  SEG *seg = PG_GETARG_SEG_P(0);
179 
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
196 {
197  GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
198  Datum query = PG_GETARG_DATUM(1);
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
223 {
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
254 {
256 }
257 
258 Datum
260 {
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
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 
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 /*
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 /*
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
319 {
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),
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 
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 
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 
405 }
406 
407 /*
408 ** Equality methods
409 */
410 Datum
412 {
413  bool *result = (bool *) PG_GETARG_POINTER(2);
414 
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 }
426 
427 /*
428 ** SUPPORT ROUTINES
429 */
430 static Datum
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  {
442  retval = DirectFunctionCall2(seg_left, key, query);
443  break;
445  retval = DirectFunctionCall2(seg_over_left, key, query);
446  break;
448  retval = DirectFunctionCall2(seg_overlap, key, query);
449  break;
451  retval = DirectFunctionCall2(seg_over_right, key, query);
452  break;
454  retval = DirectFunctionCall2(seg_right, key, query);
455  break;
457  retval = DirectFunctionCall2(seg_same, key, query);
458  break;
461  retval = DirectFunctionCall2(seg_contains, key, query);
462  break;
465  retval = DirectFunctionCall2(seg_contained, key, query);
466  break;
467  default:
468  retval = false;
469  }
470 
471  PG_RETURN_DATUM(retval);
472 }
473 
474 static Datum
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  {
486  retval =
488  break;
490  retval =
492  break;
494  retval =
496  break;
498  retval =
500  break;
502  retval =
504  break;
508  retval =
510  break;
513  retval =
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);
529  *sizep = sizeof(SEG);
530 
531  return retval;
532 }
533 
534 
535 Datum
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
546 {
547  Datum a = PG_GETARG_DATUM(0);
548  Datum b = PG_GETARG_DATUM(1);
549 
551 }
552 
553 /*****************************************************************************
554  * Operator class for R-tree indexing
555  *****************************************************************************/
556 
557 Datum
559 {
561  PG_GETARG_DATUM(0),
562  PG_GETARG_DATUM(1)));
563 
564  PG_RETURN_BOOL(cmp == 0);
565 }
566 
567 /* seg_overlap -- does a overlap b?
568  */
569 Datum
571 {
572  SEG *a = PG_GETARG_SEG_P(0);
573  SEG *b = PG_GETARG_SEG_P(1);
574 
575  PG_RETURN_BOOL(((a->upper >= b->upper) && (a->lower <= b->upper)) ||
576  ((b->upper >= a->upper) && (b->lower <= a->upper)));
577 }
578 
579 /* seg_over_left -- is the right edge of (a) located at or left of the right edge of (b)?
580  */
581 Datum
583 {
584  SEG *a = PG_GETARG_SEG_P(0);
585  SEG *b = PG_GETARG_SEG_P(1);
586 
587  PG_RETURN_BOOL(a->upper <= b->upper);
588 }
589 
590 /* seg_left -- is (a) entirely on the left of (b)?
591  */
592 Datum
594 {
595  SEG *a = PG_GETARG_SEG_P(0);
596  SEG *b = PG_GETARG_SEG_P(1);
597 
598  PG_RETURN_BOOL(a->upper < b->lower);
599 }
600 
601 /* seg_right -- is (a) entirely on the right of (b)?
602  */
603 Datum
605 {
606  SEG *a = PG_GETARG_SEG_P(0);
607  SEG *b = PG_GETARG_SEG_P(1);
608 
609  PG_RETURN_BOOL(a->lower > b->upper);
610 }
611 
612 /* seg_over_right -- is the left edge of (a) located at or right of the left edge of (b)?
613  */
614 Datum
616 {
617  SEG *a = PG_GETARG_SEG_P(0);
618  SEG *b = PG_GETARG_SEG_P(1);
619 
620  PG_RETURN_BOOL(a->lower >= b->lower);
621 }
622 
623 Datum
625 {
626  SEG *a = PG_GETARG_SEG_P(0);
627  SEG *b = PG_GETARG_SEG_P(1);
628  SEG *n;
629 
630  n = (SEG *) palloc(sizeof(*n));
631 
632  /* take max of upper endpoints */
633  if (a->upper > b->upper)
634  {
635  n->upper = a->upper;
636  n->u_sigd = a->u_sigd;
637  n->u_ext = a->u_ext;
638  }
639  else
640  {
641  n->upper = b->upper;
642  n->u_sigd = b->u_sigd;
643  n->u_ext = b->u_ext;
644  }
645 
646  /* take min of lower endpoints */
647  if (a->lower < b->lower)
648  {
649  n->lower = a->lower;
650  n->l_sigd = a->l_sigd;
651  n->l_ext = a->l_ext;
652  }
653  else
654  {
655  n->lower = b->lower;
656  n->l_sigd = b->l_sigd;
657  n->l_ext = b->l_ext;
658  }
659 
661 }
662 
663 Datum
665 {
666  SEG *a = PG_GETARG_SEG_P(0);
667  SEG *b = PG_GETARG_SEG_P(1);
668  SEG *n;
669 
670  n = (SEG *) palloc(sizeof(*n));
671 
672  /* take min of upper endpoints */
673  if (a->upper < b->upper)
674  {
675  n->upper = a->upper;
676  n->u_sigd = a->u_sigd;
677  n->u_ext = a->u_ext;
678  }
679  else
680  {
681  n->upper = b->upper;
682  n->u_sigd = b->u_sigd;
683  n->u_ext = b->u_ext;
684  }
685 
686  /* take max of lower endpoints */
687  if (a->lower > b->lower)
688  {
689  n->lower = a->lower;
690  n->l_sigd = a->l_sigd;
691  n->l_ext = a->l_ext;
692  }
693  else
694  {
695  n->lower = b->lower;
696  n->l_sigd = b->l_sigd;
697  n->l_ext = b->l_ext;
698  }
699 
701 }
702 
703 static void
704 rt_seg_size(SEG *a, float *size)
705 {
706  if (a == (SEG *) NULL || a->upper <= a->lower)
707  *size = 0.0;
708  else
709  *size = (float) Abs(a->upper - a->lower);
710 }
711 
712 Datum
714 {
715  SEG *seg = PG_GETARG_SEG_P(0);
716 
717  PG_RETURN_FLOAT4((float) Abs(seg->upper - seg->lower));
718 }
719 
720 
721 /*****************************************************************************
722  * Miscellaneous operators
723  *****************************************************************************/
724 Datum
726 {
727  SEG *a = PG_GETARG_SEG_P(0);
728  SEG *b = PG_GETARG_SEG_P(1);
729 
730  /*
731  * First compare on lower boundary position
732  */
733  if (a->lower < b->lower)
734  PG_RETURN_INT32(-1);
735  if (a->lower > b->lower)
736  PG_RETURN_INT32(1);
737 
738  /*
739  * a->lower == b->lower, so consider type of boundary.
740  *
741  * A '-' lower bound is < any other kind (this could only be relevant if
742  * -HUGE_VAL is used as a regular data value). A '<' lower bound is < any
743  * other kind except '-'. A '>' lower bound is > any other kind.
744  */
745  if (a->l_ext != b->l_ext)
746  {
747  if (a->l_ext == '-')
748  PG_RETURN_INT32(-1);
749  if (b->l_ext == '-')
750  PG_RETURN_INT32(1);
751  if (a->l_ext == '<')
752  PG_RETURN_INT32(-1);
753  if (b->l_ext == '<')
754  PG_RETURN_INT32(1);
755  if (a->l_ext == '>')
756  PG_RETURN_INT32(1);
757  if (b->l_ext == '>')
758  PG_RETURN_INT32(-1);
759  }
760 
761  /*
762  * For other boundary types, consider # of significant digits first.
763  */
764  if (a->l_sigd < b->l_sigd) /* (a) is blurred and is likely to include (b) */
765  PG_RETURN_INT32(-1);
766  if (a->l_sigd > b->l_sigd) /* (a) is less blurred and is likely to be
767  * included in (b) */
768  PG_RETURN_INT32(1);
769 
770  /*
771  * For same # of digits, an approximate boundary is more blurred than
772  * exact.
773  */
774  if (a->l_ext != b->l_ext)
775  {
776  if (a->l_ext == '~') /* (a) is approximate, while (b) is exact */
777  PG_RETURN_INT32(-1);
778  if (b->l_ext == '~')
779  PG_RETURN_INT32(1);
780  /* can't get here unless data is corrupt */
781  elog(ERROR, "bogus lower boundary types %d %d",
782  (int) a->l_ext, (int) b->l_ext);
783  }
784 
785  /* at this point, the lower boundaries are identical */
786 
787  /*
788  * First compare on upper boundary position
789  */
790  if (a->upper < b->upper)
791  PG_RETURN_INT32(-1);
792  if (a->upper > b->upper)
793  PG_RETURN_INT32(1);
794 
795  /*
796  * a->upper == b->upper, so consider type of boundary.
797  *
798  * A '-' upper bound is > any other kind (this could only be relevant if
799  * HUGE_VAL is used as a regular data value). A '<' upper bound is < any
800  * other kind. A '>' upper bound is > any other kind except '-'.
801  */
802  if (a->u_ext != b->u_ext)
803  {
804  if (a->u_ext == '-')
805  PG_RETURN_INT32(1);
806  if (b->u_ext == '-')
807  PG_RETURN_INT32(-1);
808  if (a->u_ext == '<')
809  PG_RETURN_INT32(-1);
810  if (b->u_ext == '<')
811  PG_RETURN_INT32(1);
812  if (a->u_ext == '>')
813  PG_RETURN_INT32(1);
814  if (b->u_ext == '>')
815  PG_RETURN_INT32(-1);
816  }
817 
818  /*
819  * For other boundary types, consider # of significant digits first. Note
820  * result here is converse of the lower-boundary case.
821  */
822  if (a->u_sigd < b->u_sigd) /* (a) is blurred and is likely to include (b) */
823  PG_RETURN_INT32(1);
824  if (a->u_sigd > b->u_sigd) /* (a) is less blurred and is likely to be
825  * included in (b) */
826  PG_RETURN_INT32(-1);
827 
828  /*
829  * For same # of digits, an approximate boundary is more blurred than
830  * exact. Again, result is converse of lower-boundary case.
831  */
832  if (a->u_ext != b->u_ext)
833  {
834  if (a->u_ext == '~') /* (a) is approximate, while (b) is exact */
835  PG_RETURN_INT32(1);
836  if (b->u_ext == '~')
837  PG_RETURN_INT32(-1);
838  /* can't get here unless data is corrupt */
839  elog(ERROR, "bogus upper boundary types %d %d",
840  (int) a->u_ext, (int) b->u_ext);
841  }
842 
843  PG_RETURN_INT32(0);
844 }
845 
846 Datum
848 {
850  PG_GETARG_DATUM(0),
851  PG_GETARG_DATUM(1)));
852 
853  PG_RETURN_BOOL(cmp < 0);
854 }
855 
856 Datum
858 {
860  PG_GETARG_DATUM(0),
861  PG_GETARG_DATUM(1)));
862 
863  PG_RETURN_BOOL(cmp <= 0);
864 }
865 
866 Datum
868 {
870  PG_GETARG_DATUM(0),
871  PG_GETARG_DATUM(1)));
872 
873  PG_RETURN_BOOL(cmp > 0);
874 }
875 
876 Datum
878 {
880  PG_GETARG_DATUM(0),
881  PG_GETARG_DATUM(1)));
882 
883  PG_RETURN_BOOL(cmp >= 0);
884 }
885 
886 
887 Datum
889 {
891  PG_GETARG_DATUM(0),
892  PG_GETARG_DATUM(1)));
893 
894  PG_RETURN_BOOL(cmp != 0);
895 }
896 
897 
898 
899 /*****************************************************************************
900  * Auxiliary functions
901  *****************************************************************************/
902 
903 /*
904  * The purpose of this routine is to print the given floating point
905  * value with exactly n significant digits. Its behaviour
906  * is similar to %.ng except it prints 8.00 where %.ng would
907  * print 8. Returns the length of the string written at "result".
908  *
909  * Caller must provide a sufficiently large result buffer; 16 bytes
910  * should be enough for all known float implementations.
911  */
912 static int
913 restore(char *result, float val, int n)
914 {
915  char buf[25] = {
916  '0', '0', '0', '0', '0',
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  };
922  char *p;
923  int exp;
924  int i,
925  dp,
926  sign;
927 
928  /*
929  * Put a cap on the number of significant digits to avoid garbage in the
930  * output and ensure we don't overrun the result buffer.
931  */
932  n = Min(n, FLT_DIG);
933 
934  /* remember the sign */
935  sign = (val < 0 ? 1 : 0);
936 
937  /* print, in %e style to start with */
938  sprintf(result, "%.*e", n - 1, val);
939 
940  /* find the exponent */
941  p = strchr(result, 'e');
942 
943  /* punt if we have 'inf' or similar */
944  if (p == NULL)
945  return strlen(result);
946 
947  exp = atoi(p + 1);
948  if (exp == 0)
949  {
950  /* just truncate off the 'e+00' */
951  *p = '\0';
952  }
953  else
954  {
955  if (Abs(exp) <= 4)
956  {
957  /*
958  * remove the decimal point from the mantissa and write the digits
959  * to the buf array
960  */
961  for (p = result + sign, i = 10, dp = 0; *p != 'e'; p++, i++)
962  {
963  buf[i] = *p;
964  if (*p == '.')
965  {
966  dp = i--; /* skip the decimal point */
967  }
968  }
969  if (dp == 0)
970  dp = i--; /* no decimal point was found in the above
971  * for() loop */
972 
973  if (exp > 0)
974  {
975  if (dp - 10 + exp >= n)
976  {
977  /*
978  * the decimal point is behind the last significant digit;
979  * the digits in between must be converted to the exponent
980  * and the decimal point placed after the first digit
981  */
982  exp = dp - 10 + exp - n;
983  buf[10 + n] = '\0';
984 
985  /* insert the decimal point */
986  if (n > 1)
987  {
988  dp = 11;
989  for (i = 23; i > dp; i--)
990  buf[i] = buf[i - 1];
991  buf[dp] = '.';
992  }
993 
994  /*
995  * adjust the exponent by the number of digits after the
996  * decimal point
997  */
998  if (n > 1)
999  sprintf(&buf[11 + n], "e%d", exp + n - 1);
1000  else
1001  sprintf(&buf[11], "e%d", exp + n - 1);
1002 
1003  if (sign)
1004  {
1005  buf[9] = '-';
1006  strcpy(result, &buf[9]);
1007  }
1008  else
1009  strcpy(result, &buf[10]);
1010  }
1011  else
1012  { /* insert the decimal point */
1013  dp += exp;
1014  for (i = 23; i > dp; i--)
1015  buf[i] = buf[i - 1];
1016  buf[11 + n] = '\0';
1017  buf[dp] = '.';
1018  if (sign)
1019  {
1020  buf[9] = '-';
1021  strcpy(result, &buf[9]);
1022  }
1023  else
1024  strcpy(result, &buf[10]);
1025  }
1026  }
1027  else
1028  { /* exp <= 0 */
1029  dp += exp - 1;
1030  buf[10 + n] = '\0';
1031  buf[dp] = '.';
1032  if (sign)
1033  {
1034  buf[dp - 2] = '-';
1035  strcpy(result, &buf[dp - 2]);
1036  }
1037  else
1038  strcpy(result, &buf[dp - 1]);
1039  }
1040  }
1041 
1042  /* do nothing for Abs(exp) > 4; %e must be OK */
1043  /* just get rid of zeroes after [eE]- and +zeroes after [Ee]. */
1044 
1045  /* ... this is not done yet. */
1046  }
1047  return strlen(result);
1048 }
1049 
1050 
1051 /*
1052 ** Miscellany
1053 */
1054 
1055 /* find out the number of significant digits in a string representing
1056  * a floating point number
1057  */
1058 int
1059 significant_digits(const char *s)
1060 {
1061  const char *p = s;
1062  int n,
1063  c,
1064  zeroes;
1065 
1066  zeroes = 1;
1067  /* skip leading zeroes and sign */
1068  for (c = *p; (c == '0' || c == '+' || c == '-') && c != 0; c = *(++p));
1069 
1070  /* skip decimal point and following zeroes */
1071  for (c = *p; (c == '0' || c == '.') && c != 0; c = *(++p))
1072  {
1073  if (c != '.')
1074  zeroes++;
1075  }
1076 
1077  /* count significant digits (n) */
1078  for (c = *p, n = 0; c != 0; c = *(++p))
1079  {
1080  if (!((c >= '0' && c <= '9') || (c == '.')))
1081  break;
1082  if (c != '.')
1083  n++;
1084  }
1085 
1086  if (!n)
1087  return zeroes;
1088 
1089  return n;
1090 }
#define GIST_LEAF(entry)
Definition: gist.h:161
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:360
static Datum gseg_leaf_consistent(Datum key, Datum query, StrategyNumber strategy)
Definition: seg.c:431
Datum gseg_same(PG_FUNCTION_ARGS)
Definition: seg.c:411
char u_sigd
Definition: segdata.h:9
OffsetNumber index
Definition: seg.c:38
#define PG_RETURN_FLOAT4(x)
Definition: fmgr.h:364
Datum seg_same(PG_FUNCTION_ARGS)
Definition: seg.c:558
float4 lower
Definition: segdata.h:6
static int gseg_picksplit_item_cmp(const void *a, const void *b)
Definition: seg.c:297
static void rt_seg_size(SEG *a, float *size)
Definition: seg.c:704
#define RTOldContainsStrategyNumber
Definition: stratnum.h:63
#define DatumGetInt32(X)
Definition: postgres.h:472
#define RTOldContainedByStrategyNumber
Definition: stratnum.h:64
#define RTLeftStrategyNumber
Definition: stratnum.h:51
Datum seg_lower(PG_FUNCTION_ARGS)
Definition: seg.c:168
Datum seg_contains(PG_FUNCTION_ARGS)
Definition: seg.c:536
#define PointerGetDatum(X)
Definition: postgres.h:556
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
float center
Definition: seg.c:37
Datum seg_out(PG_FUNCTION_ARGS)
Definition: seg.c:119
#define Min(x, y)
Definition: c.h:927
OffsetNumber * spl_left
Definition: gist.h:133
Datum spl_rdatum
Definition: gist.h:140
#define PG_RETURN_INT32(x)
Definition: fmgr.h:353
int32 n
Definition: gist.h:226
uint16 StrategyNumber
Definition: stratnum.h:22
Datum gseg_union(PG_FUNCTION_ARGS)
Definition: seg.c:222
#define RTContainedByStrategyNumber
Definition: stratnum.h:58
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
void seg_scanner_finish(void)
int spl_nleft
Definition: gist.h:134
#define fprintf
Definition: port.h:197
Datum seg_left(PG_FUNCTION_ARGS)
Definition: seg.c:593
uint16 OffsetNumber
Definition: off.h:24
#define Abs(x)
Definition: c.h:933
GISTENTRY vector[FLEXIBLE_ARRAY_MEMBER]
Definition: gist.h:227
#define sprintf
Definition: port.h:195
#define ERROR
Definition: elog.h:43
Datum seg_right(PG_FUNCTION_ARGS)
Definition: seg.c:604
Datum seg_size(PG_FUNCTION_ARGS)
Definition: seg.c:713
int seg_yyparse(SEG *result)
static Datum gseg_binary_union(Datum r1, Datum r2, int *sizep)
Definition: seg.c:524
int spl_nright
Definition: gist.h:139
Datum seg_in(PG_FUNCTION_ARGS)
Definition: seg.c:103
Datum seg_contained(PG_FUNCTION_ARGS)
Definition: seg.c:545
Datum seg_over_left(PG_FUNCTION_ARGS)
Definition: seg.c:582
char sign
Definition: informix.c:668
Datum key
Definition: gist.h:151
char * c
PG_MODULE_MAGIC
Definition: seg.c:30
int significant_digits(const char *s)
Definition: seg.c:1059
static char * buf
Definition: pg_test_fsync.c:67
Datum seg_center(PG_FUNCTION_ARGS)
Definition: seg.c:160
Datum gseg_compress(PG_FUNCTION_ARGS)
Definition: seg.c:253
#define DatumGetBool(X)
Definition: postgres.h:393
#define RTSameStrategyNumber
Definition: stratnum.h:56
#define PG_GETARG_SEG_P(n)
Definition: seg.c:22
Datum gseg_penalty(PG_FUNCTION_ARGS)
Definition: seg.c:269
#define RTOverRightStrategyNumber
Definition: stratnum.h:54
Datum seg_overlap(PG_FUNCTION_ARGS)
Definition: seg.c:570
Datum seg_ge(PG_FUNCTION_ARGS)
Definition: seg.c:877
#define DatumGetSegP(X)
Definition: seg.c:21
PG_FUNCTION_INFO_V1(seg_in)
void seg_scanner_init(const char *str)
#define RTOverLeftStrategyNumber
Definition: stratnum.h:52
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:358
uintptr_t Datum
Definition: postgres.h:367
char l_ext
Definition: segdata.h:10
Datum seg_gt(PG_FUNCTION_ARGS)
Definition: seg.c:867
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:352
struct SEG SEG
Definition: segdata.h:4
Datum seg_union(PG_FUNCTION_ARGS)
Definition: seg.c:624
Datum seg_lt(PG_FUNCTION_ARGS)
Definition: seg.c:847
Datum spl_ldatum
Definition: gist.h:135
char l_sigd
Definition: segdata.h:8
#define RTRightStrategyNumber
Definition: stratnum.h:55
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:361
OffsetNumber * spl_right
Definition: gist.h:138
#define RTContainsStrategyNumber
Definition: stratnum.h:57
static int restore(char *s, float val, int n)
Definition: seg.c:913
Datum seg_upper(PG_FUNCTION_ARGS)
Definition: seg.c:176
Datum gseg_decompress(PG_FUNCTION_ARGS)
Definition: seg.c:259
static Datum gseg_internal_consistent(Datum key, Datum query, StrategyNumber strategy)
Definition: seg.c:475
#define PG_GETARG_UINT16(n)
Definition: fmgr.h:272
void seg_yyerror(SEG *result, const char *message) pg_attribute_noreturn()
SEG * data
Definition: seg.c:39
Datum seg_inter(PG_FUNCTION_ARGS)
Definition: seg.c:664
Datum seg_cmp(PG_FUNCTION_ARGS)
Definition: seg.c:725
void * palloc(Size size)
Definition: mcxt.c:949
float4 upper
Definition: segdata.h:7
Datum seg_over_right(PG_FUNCTION_ARGS)
Definition: seg.c:615
#define elog(elevel,...)
Definition: elog.h:214
int i
char u_ext
Definition: segdata.h:11
Datum gseg_consistent(PG_FUNCTION_ARGS)
Definition: seg.c:195
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:277
#define RTOverlapStrategyNumber
Definition: stratnum.h:53
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define qsort(a, b, c, d)
Definition: port.h:479
Datum seg_different(PG_FUNCTION_ARGS)
Definition: seg.c:888
Datum seg_le(PG_FUNCTION_ARGS)
Definition: seg.c:857
long val
Definition: informix.c:664
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:626
static int cmp(const chr *x, const chr *y, size_t len)
Definition: regc_locale.c:742
Datum gseg_picksplit(PG_FUNCTION_ARGS)
Definition: seg.c:318