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_POINTER(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);
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 */
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 {
560  int cmp = DatumGetInt32(
562 
563  PG_RETURN_BOOL(cmp == 0);
564 }
565 
566 /* seg_overlap -- does a overlap b?
567  */
568 Datum
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
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  */
591 Datum
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 }
599 
600 /* seg_right -- is (a) entirely on the right of (b)?
601  */
602 Datum
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
615 {
616  SEG *a = PG_GETARG_SEG_P(0);
617  SEG *b = PG_GETARG_SEG_P(1);
618 
619  PG_RETURN_BOOL(a->lower >= b->lower);
620 }
621 
622 Datum
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 
660 }
661 
662 Datum
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 
700 }
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 }
712 
713 Datum
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
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 {
850  int cmp = DatumGetInt32(
852 
853  PG_RETURN_BOOL(cmp < 0);
854 }
855 
856 Datum
858 {
859  int cmp = DatumGetInt32(
861 
862  PG_RETURN_BOOL(cmp <= 0);
863 }
864 
865 Datum
867 {
868  int cmp = DatumGetInt32(
870 
871  PG_RETURN_BOOL(cmp > 0);
872 }
873 
874 Datum
876 {
877  int cmp = DatumGetInt32(
879 
880  PG_RETURN_BOOL(cmp >= 0);
881 }
882 
883 
884 Datum
886 {
887  int cmp = DatumGetInt32(
889 
890  PG_RETURN_BOOL(cmp != 0);
891 }
892 
893 
894 
895 /*****************************************************************************
896  * Auxiliary functions
897  *****************************************************************************/
898 
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 }
#define GIST_LEAF(entry)
Definition: gist.h:133
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:321
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:325
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:703
#define RTOldContainsStrategyNumber
Definition: stratnum.h:56
#define DatumGetInt32(X)
Definition: postgres.h:478
#define RTOldContainedByStrategyNumber
Definition: stratnum.h:57
#define RTLeftStrategyNumber
Definition: stratnum.h:44
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:562
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:233
float center
Definition: seg.c:37
Datum seg_out(PG_FUNCTION_ARGS)
Definition: seg.c:119
#define Min(x, y)
Definition: c.h:802
OffsetNumber * spl_left
Definition: gist.h:105
Datum spl_rdatum
Definition: gist.h:112
#define PG_RETURN_INT32(x)
Definition: fmgr.h:314
int32 n
Definition: gist.h:160
uint16 StrategyNumber
Definition: stratnum.h:22
Datum gseg_union(PG_FUNCTION_ARGS)
Definition: seg.c:222
#define RTContainedByStrategyNumber
Definition: stratnum.h:51
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:241
void seg_scanner_finish(void)
int spl_nleft
Definition: gist.h:106
Datum seg_left(PG_FUNCTION_ARGS)
Definition: seg.c:592
uint16 OffsetNumber
Definition: off.h:24
#define Abs(x)
Definition: c.h:808
GISTENTRY vector[FLEXIBLE_ARRAY_MEMBER]
Definition: gist.h:161
#define ERROR
Definition: elog.h:43
Datum seg_right(PG_FUNCTION_ARGS)
Definition: seg.c:603
Datum seg_size(PG_FUNCTION_ARGS)
Definition: seg.c:714
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:111
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:581
char sign
Definition: informix.c:693
Datum key
Definition: gist.h:123
char * c
PG_MODULE_MAGIC
Definition: seg.c:30
int significant_digits(const char *s)
Definition: seg.c:1055
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:399
#define RTSameStrategyNumber
Definition: stratnum.h:49
#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:47
Datum seg_overlap(PG_FUNCTION_ARGS)
Definition: seg.c:569
Datum seg_ge(PG_FUNCTION_ARGS)
Definition: seg.c:875
#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:45
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:319
uintptr_t Datum
Definition: postgres.h:372
char l_ext
Definition: segdata.h:10
Datum seg_gt(PG_FUNCTION_ARGS)
Definition: seg.c:866
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:313
struct SEG SEG
Definition: segdata.h:4
Datum seg_union(PG_FUNCTION_ARGS)
Definition: seg.c:623
Datum seg_lt(PG_FUNCTION_ARGS)
Definition: seg.c:848
Datum spl_ldatum
Definition: gist.h:107
char l_sigd
Definition: segdata.h:8
#define RTRightStrategyNumber
Definition: stratnum.h:48
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:322
OffsetNumber * spl_right
Definition: gist.h:110
#define RTContainsStrategyNumber
Definition: stratnum.h:50
static int restore(char *s, float val, int n)
Definition: seg.c:909
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:237
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:663
Datum seg_cmp(PG_FUNCTION_ARGS)
Definition: seg.c:726
void * palloc(Size size)
Definition: mcxt.c:848
float4 upper
Definition: segdata.h:7
Datum seg_over_right(PG_FUNCTION_ARGS)
Definition: seg.c:614
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:242
#define RTOverlapStrategyNumber
Definition: stratnum.h:46
#define PG_FUNCTION_ARGS
Definition: fmgr.h:158
#define elog
Definition: elog.h:219
#define qsort(a, b, c, d)
Definition: port.h:408
Datum seg_different(PG_FUNCTION_ARGS)
Definition: seg.c:885
Datum seg_le(PG_FUNCTION_ARGS)
Definition: seg.c:857
long val
Definition: informix.c:689
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:587
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