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 #include <math.h>
14 
15 #include "access/gist.h"
16 #include "access/stratnum.h"
17 #include "fmgr.h"
18 
19 #include "segdata.h"
20 
21 
22 #define DatumGetSegP(X) ((SEG *) DatumGetPointer(X))
23 #define PG_GETARG_SEG_P(n) DatumGetSegP(PG_GETARG_DATUM(n))
24 
25 
26 /*
27 #define GIST_DEBUG
28 #define GIST_QUERY_DEBUG
29 */
30 
32 
33 /*
34  * Auxiliary data structure for picksplit method.
35  */
36 typedef struct
37 {
38  float center;
42 
43 /*
44 ** Input/Output routines
45 */
52 
53 /*
54 ** GiST support methods
55 */
63 static Datum gseg_leaf_consistent(Datum key, Datum query, StrategyNumber strategy);
65 static Datum gseg_binary_union(Datum r1, Datum r2, int *sizep);
66 
67 
68 /*
69 ** R-tree support functions
70 */
81 static void rt_seg_size(SEG *a, float *size);
82 
83 /*
84 ** Various operators
85 */
92 
93 /*
94 ** Auxiliary functions
95 */
96 static int restore(char *result, float val, int n);
97 
98 
99 /*****************************************************************************
100  * Input/Output functions
101  *****************************************************************************/
102 
103 Datum
105 {
106  char *str = PG_GETARG_CSTRING(0);
107  SEG *result = palloc(sizeof(SEG));
108 
110 
111  if (seg_yyparse(result, fcinfo->context) != 0)
112  seg_yyerror(result, fcinfo->context, "bogus input");
113 
115 
116  PG_RETURN_POINTER(result);
117 }
118 
119 Datum
121 {
122  SEG *seg = PG_GETARG_SEG_P(0);
123  char *result;
124  char *p;
125 
126  p = result = (char *) palloc(40);
127 
128  if (seg->l_ext == '>' || seg->l_ext == '<' || seg->l_ext == '~')
129  p += sprintf(p, "%c", seg->l_ext);
130 
131  if (seg->lower == seg->upper && seg->l_ext == seg->u_ext)
132  {
133  /*
134  * indicates that this interval was built by seg_in off a single point
135  */
136  p += restore(p, seg->lower, seg->l_sigd);
137  }
138  else
139  {
140  if (seg->l_ext != '-')
141  {
142  /* print the lower boundary if exists */
143  p += restore(p, seg->lower, seg->l_sigd);
144  p += sprintf(p, " ");
145  }
146  p += sprintf(p, "..");
147  if (seg->u_ext != '-')
148  {
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);
154  }
155  }
156 
157  PG_RETURN_CSTRING(result);
158 }
159 
160 Datum
162 {
163  SEG *seg = PG_GETARG_SEG_P(0);
164 
165  PG_RETURN_FLOAT4(((float) seg->lower + (float) seg->upper) / 2.0);
166 }
167 
168 Datum
170 {
171  SEG *seg = PG_GETARG_SEG_P(0);
172 
173  PG_RETURN_FLOAT4(seg->lower);
174 }
175 
176 Datum
178 {
179  SEG *seg = PG_GETARG_SEG_P(0);
180 
181  PG_RETURN_FLOAT4(seg->upper);
182 }
183 
184 
185 /*****************************************************************************
186  * GiST functions
187  *****************************************************************************/
188 
189 /*
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.
194 */
195 Datum
197 {
198  GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
199  Datum query = PG_GETARG_DATUM(1);
201 
202  /* Oid subtype = PG_GETARG_OID(3); */
203  bool *recheck = (bool *) PG_GETARG_POINTER(4);
204 
205  /* All cases served by this function are exact */
206  *recheck = false;
207 
208  /*
209  * if entry is not leaf, use gseg_internal_consistent, else use
210  * gseg_leaf_consistent
211  */
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);
216 }
217 
218 /*
219 ** The GiST Union method for segments
220 ** returns the minimal bounding seg that encloses all the entries in entryvec
221 */
222 Datum
224 {
226  int *sizep = (int *) PG_GETARG_POINTER(1);
227  int numranges,
228  i;
229  Datum out = 0;
230  Datum tmp;
231 
232 #ifdef GIST_DEBUG
233  fprintf(stderr, "union\n");
234 #endif
235 
236  numranges = entryvec->n;
237  tmp = entryvec->vector[0].key;
238  *sizep = sizeof(SEG);
239 
240  for (i = 1; i < numranges; i++)
241  {
242  out = gseg_binary_union(tmp, entryvec->vector[i].key, sizep);
243  tmp = out;
244  }
245 
246  PG_RETURN_DATUM(out);
247 }
248 
249 /*
250 ** GiST Compress and Decompress methods for segments
251 ** do not do anything.
252 */
253 Datum
255 {
257 }
258 
259 Datum
261 {
263 }
264 
265 /*
266 ** The GiST Penalty method for segments
267 ** As in the R-tree paper, we use change in area as our penalty metric
268 */
269 Datum
271 {
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;
278 
280  origentry->key,
281  newentry->key));
282  rt_seg_size(ud, &tmp1);
283  rt_seg_size(DatumGetSegP(origentry->key), &tmp2);
284  *result = tmp1 - tmp2;
285 
286 #ifdef GIST_DEBUG
287  fprintf(stderr, "penalty\n");
288  fprintf(stderr, "\t%g\n", *result);
289 #endif
290 
291  PG_RETURN_POINTER(result);
292 }
293 
294 /*
295  * Compare function for gseg_picksplit_item: sort by center.
296  */
297 static int
298 gseg_picksplit_item_cmp(const void *a, const void *b)
299 {
300  const gseg_picksplit_item *i1 = (const gseg_picksplit_item *) a;
301  const gseg_picksplit_item *i2 = (const gseg_picksplit_item *) b;
302 
303  if (i1->center < i2->center)
304  return -1;
305  else if (i1->center == i2->center)
306  return 0;
307  else
308  return 1;
309 }
310 
311 /*
312  * The GiST PickSplit method for segments
313  *
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.
317  */
318 Datum
320 {
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;
332 
333 #ifdef GIST_DEBUG
334  fprintf(stderr, "picksplit\n");
335 #endif
336 
337  /* Valid items in entryvec->vector[] are indexed 1..maxoff */
338  maxoff = entryvec->n - 1;
339 
340  /*
341  * Prepare the auxiliary array and sort it.
342  */
343  sort_items = (gseg_picksplit_item *)
344  palloc(maxoff * sizeof(gseg_picksplit_item));
345  for (i = 1; i <= maxoff; i++)
346  {
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;
352  }
353  qsort(sort_items, maxoff, sizeof(gseg_picksplit_item),
355 
356  /* sort items below "firstright" will go into the left side */
357  firstright = maxoff / 2;
358 
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;
365 
366  /*
367  * Emit segments to the left output page, and compute its bounding box.
368  */
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++)
374  {
375  Datum sortitem = PointerGetDatum(sort_items[i].data);
376 
378  PointerGetDatum(seg_l),
379  sortitem));
380  *left++ = sort_items[i].index;
381  v->spl_nleft++;
382  }
383 
384  /*
385  * Likewise for the right page.
386  */
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++)
392  {
393  Datum sortitem = PointerGetDatum(sort_items[i].data);
394 
396  PointerGetDatum(seg_r),
397  sortitem));
398  *right++ = sort_items[i].index;
399  v->spl_nright++;
400  }
401 
402  v->spl_ldatum = PointerGetDatum(seg_l);
403  v->spl_rdatum = PointerGetDatum(seg_r);
404 
406 }
407 
408 /*
409 ** Equality methods
410 */
411 Datum
413 {
414  bool *result = (bool *) PG_GETARG_POINTER(2);
415 
417  *result = true;
418  else
419  *result = false;
420 
421 #ifdef GIST_DEBUG
422  fprintf(stderr, "same: %s\n", (*result ? "TRUE" : "FALSE"));
423 #endif
424 
425  PG_RETURN_POINTER(result);
426 }
427 
428 /*
429 ** SUPPORT ROUTINES
430 */
431 static Datum
433 {
434  Datum retval;
435 
436 #ifdef GIST_QUERY_DEBUG
437  fprintf(stderr, "leaf_consistent, %d\n", strategy);
438 #endif
439 
440  switch (strategy)
441  {
443  retval = DirectFunctionCall2(seg_left, key, query);
444  break;
446  retval = DirectFunctionCall2(seg_over_left, key, query);
447  break;
449  retval = DirectFunctionCall2(seg_overlap, key, query);
450  break;
452  retval = DirectFunctionCall2(seg_over_right, key, query);
453  break;
455  retval = DirectFunctionCall2(seg_right, key, query);
456  break;
458  retval = DirectFunctionCall2(seg_same, key, query);
459  break;
462  retval = DirectFunctionCall2(seg_contains, key, query);
463  break;
466  retval = DirectFunctionCall2(seg_contained, key, query);
467  break;
468  default:
469  retval = false;
470  }
471 
472  PG_RETURN_DATUM(retval);
473 }
474 
475 static Datum
477 {
478  bool retval;
479 
480 #ifdef GIST_QUERY_DEBUG
481  fprintf(stderr, "internal_consistent, %d\n", strategy);
482 #endif
483 
484  switch (strategy)
485  {
487  retval =
489  break;
491  retval =
493  break;
495  retval =
497  break;
499  retval =
501  break;
503  retval =
505  break;
509  retval =
511  break;
514  retval =
516  break;
517  default:
518  retval = false;
519  }
520 
521  PG_RETURN_BOOL(retval);
522 }
523 
524 static Datum
525 gseg_binary_union(Datum r1, Datum r2, int *sizep)
526 {
527  Datum retval;
528 
529  retval = DirectFunctionCall2(seg_union, r1, r2);
530  *sizep = sizeof(SEG);
531 
532  return retval;
533 }
534 
535 
536 Datum
538 {
539  SEG *a = PG_GETARG_SEG_P(0);
540  SEG *b = PG_GETARG_SEG_P(1);
541 
542  PG_RETURN_BOOL((a->lower <= b->lower) && (a->upper >= b->upper));
543 }
544 
545 Datum
547 {
548  Datum a = PG_GETARG_DATUM(0);
549  Datum b = PG_GETARG_DATUM(1);
550 
552 }
553 
554 /*****************************************************************************
555  * Operator class for R-tree indexing
556  *****************************************************************************/
557 
558 Datum
560 {
562  PG_GETARG_DATUM(0),
563  PG_GETARG_DATUM(1)));
564 
565  PG_RETURN_BOOL(cmp == 0);
566 }
567 
568 /* seg_overlap -- does a overlap b?
569  */
570 Datum
572 {
573  SEG *a = PG_GETARG_SEG_P(0);
574  SEG *b = PG_GETARG_SEG_P(1);
575 
576  PG_RETURN_BOOL(((a->upper >= b->upper) && (a->lower <= b->upper)) ||
577  ((b->upper >= a->upper) && (b->lower <= a->upper)));
578 }
579 
580 /* seg_over_left -- is the right edge of (a) located at or left of the right edge of (b)?
581  */
582 Datum
584 {
585  SEG *a = PG_GETARG_SEG_P(0);
586  SEG *b = PG_GETARG_SEG_P(1);
587 
588  PG_RETURN_BOOL(a->upper <= b->upper);
589 }
590 
591 /* seg_left -- is (a) entirely on the left of (b)?
592  */
593 Datum
595 {
596  SEG *a = PG_GETARG_SEG_P(0);
597  SEG *b = PG_GETARG_SEG_P(1);
598 
599  PG_RETURN_BOOL(a->upper < b->lower);
600 }
601 
602 /* seg_right -- is (a) entirely on the right of (b)?
603  */
604 Datum
606 {
607  SEG *a = PG_GETARG_SEG_P(0);
608  SEG *b = PG_GETARG_SEG_P(1);
609 
610  PG_RETURN_BOOL(a->lower > b->upper);
611 }
612 
613 /* seg_over_right -- is the left edge of (a) located at or right of the left edge of (b)?
614  */
615 Datum
617 {
618  SEG *a = PG_GETARG_SEG_P(0);
619  SEG *b = PG_GETARG_SEG_P(1);
620 
621  PG_RETURN_BOOL(a->lower >= b->lower);
622 }
623 
624 Datum
626 {
627  SEG *a = PG_GETARG_SEG_P(0);
628  SEG *b = PG_GETARG_SEG_P(1);
629  SEG *n;
630 
631  n = (SEG *) palloc(sizeof(*n));
632 
633  /* take max of upper endpoints */
634  if (a->upper > b->upper)
635  {
636  n->upper = a->upper;
637  n->u_sigd = a->u_sigd;
638  n->u_ext = a->u_ext;
639  }
640  else
641  {
642  n->upper = b->upper;
643  n->u_sigd = b->u_sigd;
644  n->u_ext = b->u_ext;
645  }
646 
647  /* take min of lower endpoints */
648  if (a->lower < b->lower)
649  {
650  n->lower = a->lower;
651  n->l_sigd = a->l_sigd;
652  n->l_ext = a->l_ext;
653  }
654  else
655  {
656  n->lower = b->lower;
657  n->l_sigd = b->l_sigd;
658  n->l_ext = b->l_ext;
659  }
660 
662 }
663 
664 Datum
666 {
667  SEG *a = PG_GETARG_SEG_P(0);
668  SEG *b = PG_GETARG_SEG_P(1);
669  SEG *n;
670 
671  n = (SEG *) palloc(sizeof(*n));
672 
673  /* take min of upper endpoints */
674  if (a->upper < b->upper)
675  {
676  n->upper = a->upper;
677  n->u_sigd = a->u_sigd;
678  n->u_ext = a->u_ext;
679  }
680  else
681  {
682  n->upper = b->upper;
683  n->u_sigd = b->u_sigd;
684  n->u_ext = b->u_ext;
685  }
686 
687  /* take max of lower endpoints */
688  if (a->lower > b->lower)
689  {
690  n->lower = a->lower;
691  n->l_sigd = a->l_sigd;
692  n->l_ext = a->l_ext;
693  }
694  else
695  {
696  n->lower = b->lower;
697  n->l_sigd = b->l_sigd;
698  n->l_ext = b->l_ext;
699  }
700 
702 }
703 
704 static void
706 {
707  if (a == (SEG *) NULL || a->upper <= a->lower)
708  *size = 0.0;
709  else
710  *size = fabsf(a->upper - a->lower);
711 }
712 
713 Datum
715 {
716  SEG *seg = PG_GETARG_SEG_P(0);
717 
718  PG_RETURN_FLOAT4(fabsf(seg->upper - seg->lower));
719 }
720 
721 
722 /*****************************************************************************
723  * Miscellaneous operators
724  *****************************************************************************/
725 Datum
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
849 {
851  PG_GETARG_DATUM(0),
852  PG_GETARG_DATUM(1)));
853 
854  PG_RETURN_BOOL(cmp < 0);
855 }
856 
857 Datum
859 {
861  PG_GETARG_DATUM(0),
862  PG_GETARG_DATUM(1)));
863 
864  PG_RETURN_BOOL(cmp <= 0);
865 }
866 
867 Datum
869 {
871  PG_GETARG_DATUM(0),
872  PG_GETARG_DATUM(1)));
873 
874  PG_RETURN_BOOL(cmp > 0);
875 }
876 
877 Datum
879 {
881  PG_GETARG_DATUM(0),
882  PG_GETARG_DATUM(1)));
883 
884  PG_RETURN_BOOL(cmp >= 0);
885 }
886 
887 
888 Datum
890 {
892  PG_GETARG_DATUM(0),
893  PG_GETARG_DATUM(1)));
894 
895  PG_RETURN_BOOL(cmp != 0);
896 }
897 
898 
899 
900 /*****************************************************************************
901  * Auxiliary functions
902  *****************************************************************************/
903 
904 /*
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".
909  *
910  * Caller must provide a sufficiently large result buffer; 16 bytes
911  * should be enough for all known float implementations.
912  */
913 static int
914 restore(char *result, float val, int n)
915 {
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'
922  };
923  char *p;
924  int exp;
925  int i,
926  dp,
927  sign;
928 
929  /*
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.)
933  */
934  if (n <= 0)
935  n = FLT_DIG;
936  else
937  n = Min(n, FLT_DIG);
938 
939  /* remember the sign */
940  sign = (val < 0 ? 1 : 0);
941 
942  /* print, in %e style to start with */
943  sprintf(result, "%.*e", n - 1, val);
944 
945  /* find the exponent */
946  p = strchr(result, 'e');
947 
948  /* punt if we have 'inf' or similar */
949  if (p == NULL)
950  return strlen(result);
951 
952  exp = atoi(p + 1);
953  if (exp == 0)
954  {
955  /* just truncate off the 'e+00' */
956  *p = '\0';
957  }
958  else
959  {
960  if (abs(exp) <= 4)
961  {
962  /*
963  * remove the decimal point from the mantissa and write the digits
964  * to the buf array
965  */
966  for (p = result + sign, i = 10, dp = 0; *p != 'e'; p++, i++)
967  {
968  buf[i] = *p;
969  if (*p == '.')
970  {
971  dp = i--; /* skip the decimal point */
972  }
973  }
974  if (dp == 0)
975  dp = i--; /* no decimal point was found in the above
976  * for() loop */
977 
978  if (exp > 0)
979  {
980  if (dp - 10 + exp >= n)
981  {
982  /*
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
986  */
987  exp = dp - 10 + exp - n;
988  buf[10 + n] = '\0';
989 
990  /* insert the decimal point */
991  if (n > 1)
992  {
993  dp = 11;
994  for (i = 23; i > dp; i--)
995  buf[i] = buf[i - 1];
996  buf[dp] = '.';
997  }
998 
999  /*
1000  * adjust the exponent by the number of digits after the
1001  * decimal point
1002  */
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);
1007 
1008  if (sign)
1009  {
1010  buf[9] = '-';
1011  strcpy(result, &buf[9]);
1012  }
1013  else
1014  strcpy(result, &buf[10]);
1015  }
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)
1024  {
1025  buf[9] = '-';
1026  strcpy(result, &buf[9]);
1027  }
1028  else
1029  strcpy(result, &buf[10]);
1030  }
1031  }
1032  else
1033  { /* exp <= 0 */
1034  dp += exp - 1;
1035  buf[10 + n] = '\0';
1036  buf[dp] = '.';
1037  if (sign)
1038  {
1039  buf[dp - 2] = '-';
1040  strcpy(result, &buf[dp - 2]);
1041  }
1042  else
1043  strcpy(result, &buf[dp - 1]);
1044  }
1045  }
1046 
1047  /* do nothing for abs(exp) > 4; %e must be OK */
1048  /* just get rid of zeroes after [eE]- and +zeroes after [Ee]. */
1049 
1050  /* ... this is not done yet. */
1051  }
1052  return strlen(result);
1053 }
1054 
1055 
1056 /*
1057 ** Miscellany
1058 */
1059 
1060 /* find out the number of significant digits in a string representing
1061  * a floating point number
1062  */
1063 int
1064 significant_digits(const char *s)
1065 {
1066  const char *p = s;
1067  int n,
1068  c,
1069  zeroes;
1070 
1071  zeroes = 1;
1072  /* skip leading zeroes and sign */
1073  for (c = *p; (c == '0' || c == '+' || c == '-') && c != 0; c = *(++p));
1074 
1075  /* skip decimal point and following zeroes */
1076  for (c = *p; (c == '0' || c == '.') && c != 0; c = *(++p))
1077  {
1078  if (c != '.')
1079  zeroes++;
1080  }
1081 
1082  /* count significant digits (n) */
1083  for (c = *p, n = 0; c != 0; c = *(++p))
1084  {
1085  if (!((c >= '0' && c <= '9') || (c == '.')))
1086  break;
1087  if (c != '.')
1088  n++;
1089  }
1090 
1091  if (!n)
1092  return zeroes;
1093 
1094  return n;
1095 }
#define Min(x, y)
Definition: c.h:991
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:644
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:362
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:277
#define PG_GETARG_UINT16(n)
Definition: fmgr.h:272
#define PG_RETURN_INT32(x)
Definition: fmgr.h:354
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
#define PG_RETURN_FLOAT4(x)
Definition: fmgr.h:366
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
#define GIST_LEAF(entry)
Definition: gist.h:170
long val
Definition: informix.c:664
char sign
Definition: informix.c:668
int b
Definition: isn.c:70
int a
Definition: isn.c:69
int i
Definition: isn.c:73
void * palloc(Size size)
Definition: mcxt.c:1304
uint16 OffsetNumber
Definition: off.h:24
const void * data
static char * buf
Definition: pg_test_fsync.c:73
#define sprintf
Definition: port.h:240
#define fprintf
Definition: port.h:242
#define qsort(a, b, c, d)
Definition: port.h:449
static bool DatumGetBool(Datum X)
Definition: postgres.h:90
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
static int32 DatumGetInt32(Datum X)
Definition: postgres.h:202
char * c
static int cmp(const chr *x, const chr *y, size_t len)
Definition: regc_locale.c:743
Datum seg_le(PG_FUNCTION_ARGS)
Definition: seg.c:858
Datum gseg_decompress(PG_FUNCTION_ARGS)
Definition: seg.c:260
Datum seg_gt(PG_FUNCTION_ARGS)
Definition: seg.c:868
static Datum gseg_leaf_consistent(Datum key, Datum query, StrategyNumber strategy)
Definition: seg.c:432
Datum gseg_penalty(PG_FUNCTION_ARGS)
Definition: seg.c:270
Datum gseg_union(PG_FUNCTION_ARGS)
Definition: seg.c:223
Datum gseg_consistent(PG_FUNCTION_ARGS)
Definition: seg.c:196
Datum seg_center(PG_FUNCTION_ARGS)
Definition: seg.c:161
Datum seg_over_right(PG_FUNCTION_ARGS)
Definition: seg.c:616
Datum seg_contained(PG_FUNCTION_ARGS)
Definition: seg.c:546
Datum seg_overlap(PG_FUNCTION_ARGS)
Definition: seg.c:571
Datum seg_right(PG_FUNCTION_ARGS)
Definition: seg.c:605
#define PG_GETARG_SEG_P(n)
Definition: seg.c:23
Datum gseg_same(PG_FUNCTION_ARGS)
Definition: seg.c:412
static int gseg_picksplit_item_cmp(const void *a, const void *b)
Definition: seg.c:298
PG_MODULE_MAGIC
Definition: seg.c:31
Datum seg_lt(PG_FUNCTION_ARGS)
Definition: seg.c:848
#define DatumGetSegP(X)
Definition: seg.c:22
Datum seg_size(PG_FUNCTION_ARGS)
Definition: seg.c:714
Datum seg_union(PG_FUNCTION_ARGS)
Definition: seg.c:625
int significant_digits(const char *s)
Definition: seg.c:1064
Datum seg_upper(PG_FUNCTION_ARGS)
Definition: seg.c:177
static Datum gseg_internal_consistent(Datum key, Datum query, StrategyNumber strategy)
Definition: seg.c:476
Datum seg_ge(PG_FUNCTION_ARGS)
Definition: seg.c:878
Datum seg_lower(PG_FUNCTION_ARGS)
Definition: seg.c:169
Datum gseg_picksplit(PG_FUNCTION_ARGS)
Definition: seg.c:319
Datum seg_in(PG_FUNCTION_ARGS)
Definition: seg.c:104
Datum seg_cmp(PG_FUNCTION_ARGS)
Definition: seg.c:726
static int restore(char *result, float val, int n)
Definition: seg.c:914
Datum seg_inter(PG_FUNCTION_ARGS)
Definition: seg.c:665
Datum seg_left(PG_FUNCTION_ARGS)
Definition: seg.c:594
static void rt_seg_size(SEG *a, float *size)
Definition: seg.c:705
Datum seg_out(PG_FUNCTION_ARGS)
Definition: seg.c:120
PG_FUNCTION_INFO_V1(seg_in)
static Datum gseg_binary_union(Datum r1, Datum r2, int *sizep)
Definition: seg.c:525
Datum seg_over_left(PG_FUNCTION_ARGS)
Definition: seg.c:583
Datum gseg_compress(PG_FUNCTION_ARGS)
Definition: seg.c:254
Datum seg_contains(PG_FUNCTION_ARGS)
Definition: seg.c:537
Datum seg_same(PG_FUNCTION_ARGS)
Definition: seg.c:559
Datum seg_different(PG_FUNCTION_ARGS)
Definition: seg.c:889
int seg_yyparse(SEG *result, struct Node *escontext)
void seg_yyerror(SEG *result, struct Node *escontext, const char *message)
void seg_scanner_init(const char *str)
void seg_scanner_finish(void)
struct SEG SEG
static pg_noinline void Size size
Definition: slab.c:607
#define RTOldContainsStrategyNumber
Definition: stratnum.h:63
uint16 StrategyNumber
Definition: stratnum.h:22
#define RTOverlapStrategyNumber
Definition: stratnum.h:53
#define RTLeftStrategyNumber
Definition: stratnum.h:51
#define RTOverRightStrategyNumber
Definition: stratnum.h:54
#define RTRightStrategyNumber
Definition: stratnum.h:55
#define RTSameStrategyNumber
Definition: stratnum.h:56
#define RTContainsStrategyNumber
Definition: stratnum.h:57
#define RTOverLeftStrategyNumber
Definition: stratnum.h:52
#define RTOldContainedByStrategyNumber
Definition: stratnum.h:64
#define RTContainedByStrategyNumber
Definition: stratnum.h:58
Datum key
Definition: gist.h:160
int spl_nleft
Definition: gist.h:143
OffsetNumber * spl_right
Definition: gist.h:147
Datum spl_ldatum
Definition: gist.h:144
Datum spl_rdatum
Definition: gist.h:149
int spl_nright
Definition: gist.h:148
OffsetNumber * spl_left
Definition: gist.h:142
GISTENTRY vector[FLEXIBLE_ARRAY_MEMBER]
Definition: gist.h:236
int32 n
Definition: gist.h:235
Definition: segdata.h:5
char l_ext
Definition: segdata.h:10
char l_sigd
Definition: segdata.h:8
char u_sigd
Definition: segdata.h:9
float4 upper
Definition: segdata.h:7
char u_ext
Definition: segdata.h:11
float4 lower
Definition: segdata.h:6
OffsetNumber index
Definition: seg.c:39
float center
Definition: seg.c:38
SEG * data
Definition: seg.c:40