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 {
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 
711 Datum
713 {
714  SEG *seg = PG_GETARG_SEG_P(0);
715 
716  PG_RETURN_FLOAT4((float) Abs(seg->upper - seg->lower));
717 }
718 
719 
720 /*****************************************************************************
721  * Miscellaneous operators
722  *****************************************************************************/
723 Datum
725 {
726  SEG *a = PG_GETARG_SEG_P(0);
727  SEG *b = PG_GETARG_SEG_P(1);
728 
729  /*
730  * First compare on lower boundary position
731  */
732  if (a->lower < b->lower)
733  PG_RETURN_INT32(-1);
734  if (a->lower > b->lower)
735  PG_RETURN_INT32(1);
736 
737  /*
738  * a->lower == b->lower, so consider type of boundary.
739  *
740  * A '-' lower bound is < any other kind (this could only be relevant if
741  * -HUGE_VAL is used as a regular data value). A '<' lower bound is < any
742  * other kind except '-'. A '>' lower bound is > any other kind.
743  */
744  if (a->l_ext != b->l_ext)
745  {
746  if (a->l_ext == '-')
747  PG_RETURN_INT32(-1);
748  if (b->l_ext == '-')
749  PG_RETURN_INT32(1);
750  if (a->l_ext == '<')
751  PG_RETURN_INT32(-1);
752  if (b->l_ext == '<')
753  PG_RETURN_INT32(1);
754  if (a->l_ext == '>')
755  PG_RETURN_INT32(1);
756  if (b->l_ext == '>')
757  PG_RETURN_INT32(-1);
758  }
759 
760  /*
761  * For other boundary types, consider # of significant digits first.
762  */
763  if (a->l_sigd < b->l_sigd) /* (a) is blurred and is likely to include (b) */
764  PG_RETURN_INT32(-1);
765  if (a->l_sigd > b->l_sigd) /* (a) is less blurred and is likely to be
766  * included in (b) */
767  PG_RETURN_INT32(1);
768 
769  /*
770  * For same # of digits, an approximate boundary is more blurred than
771  * exact.
772  */
773  if (a->l_ext != b->l_ext)
774  {
775  if (a->l_ext == '~') /* (a) is approximate, while (b) is exact */
776  PG_RETURN_INT32(-1);
777  if (b->l_ext == '~')
778  PG_RETURN_INT32(1);
779  /* can't get here unless data is corrupt */
780  elog(ERROR, "bogus lower boundary types %d %d",
781  (int) a->l_ext, (int) b->l_ext);
782  }
783 
784  /* at this point, the lower boundaries are identical */
785 
786  /*
787  * First compare on upper boundary position
788  */
789  if (a->upper < b->upper)
790  PG_RETURN_INT32(-1);
791  if (a->upper > b->upper)
792  PG_RETURN_INT32(1);
793 
794  /*
795  * a->upper == b->upper, so consider type of boundary.
796  *
797  * A '-' upper bound is > any other kind (this could only be relevant if
798  * HUGE_VAL is used as a regular data value). A '<' upper bound is < any
799  * other kind. A '>' upper bound is > any other kind except '-'.
800  */
801  if (a->u_ext != b->u_ext)
802  {
803  if (a->u_ext == '-')
804  PG_RETURN_INT32(1);
805  if (b->u_ext == '-')
806  PG_RETURN_INT32(-1);
807  if (a->u_ext == '<')
808  PG_RETURN_INT32(-1);
809  if (b->u_ext == '<')
810  PG_RETURN_INT32(1);
811  if (a->u_ext == '>')
812  PG_RETURN_INT32(1);
813  if (b->u_ext == '>')
814  PG_RETURN_INT32(-1);
815  }
816 
817  /*
818  * For other boundary types, consider # of significant digits first. Note
819  * result here is converse of the lower-boundary case.
820  */
821  if (a->u_sigd < b->u_sigd) /* (a) is blurred and is likely to include (b) */
822  PG_RETURN_INT32(1);
823  if (a->u_sigd > b->u_sigd) /* (a) is less blurred and is likely to be
824  * included in (b) */
825  PG_RETURN_INT32(-1);
826 
827  /*
828  * For same # of digits, an approximate boundary is more blurred than
829  * exact. Again, result is converse of lower-boundary case.
830  */
831  if (a->u_ext != b->u_ext)
832  {
833  if (a->u_ext == '~') /* (a) is approximate, while (b) is exact */
834  PG_RETURN_INT32(1);
835  if (b->u_ext == '~')
836  PG_RETURN_INT32(-1);
837  /* can't get here unless data is corrupt */
838  elog(ERROR, "bogus upper boundary types %d %d",
839  (int) a->u_ext, (int) b->u_ext);
840  }
841 
842  PG_RETURN_INT32(0);
843 }
844 
845 Datum
847 {
848  int cmp = DatumGetInt32(
850 
851  PG_RETURN_BOOL(cmp < 0);
852 }
853 
854 Datum
856 {
857  int cmp = DatumGetInt32(
859 
860  PG_RETURN_BOOL(cmp <= 0);
861 }
862 
863 Datum
865 {
866  int cmp = DatumGetInt32(
868 
869  PG_RETURN_BOOL(cmp > 0);
870 }
871 
872 Datum
874 {
875  int cmp = DatumGetInt32(
877 
878  PG_RETURN_BOOL(cmp >= 0);
879 }
880 
881 
882 Datum
884 {
885  int cmp = DatumGetInt32(
887 
888  PG_RETURN_BOOL(cmp != 0);
889 }
890 
891 
892 
893 /*****************************************************************************
894  * Auxiliary functions
895  *****************************************************************************/
896 
897 /*
898  * The purpose of this routine is to print the given floating point
899  * value with exactly n significant digits. Its behaviour
900  * is similar to %.ng except it prints 8.00 where %.ng would
901  * print 8. Returns the length of the string written at "result".
902  *
903  * Caller must provide a sufficiently large result buffer; 16 bytes
904  * should be enough for all known float implementations.
905  */
906 static int
907 restore(char *result, float val, int n)
908 {
909  char buf[25] = {
910  '0', '0', '0', '0', '0',
911  '0', '0', '0', '0', '0',
912  '0', '0', '0', '0', '0',
913  '0', '0', '0', '0', '0',
914  '0', '0', '0', '0', '\0'
915  };
916  char *p;
917  int exp;
918  int i,
919  dp,
920  sign;
921 
922  /*
923  * Put a cap on the number of significant digits to avoid garbage in the
924  * output and ensure we don't overrun the result buffer.
925  */
926  n = Min(n, FLT_DIG);
927 
928  /* remember the sign */
929  sign = (val < 0 ? 1 : 0);
930 
931  /* print, in %e style to start with */
932  sprintf(result, "%.*e", n - 1, val);
933 
934  /* find the exponent */
935  p = strchr(result, 'e');
936 
937  /* punt if we have 'inf' or similar */
938  if (p == NULL)
939  return strlen(result);
940 
941  exp = atoi(p + 1);
942  if (exp == 0)
943  {
944  /* just truncate off the 'e+00' */
945  *p = '\0';
946  }
947  else
948  {
949  if (Abs(exp) <= 4)
950  {
951  /*
952  * remove the decimal point from the mantissa and write the digits
953  * to the buf array
954  */
955  for (p = result + sign, i = 10, dp = 0; *p != 'e'; p++, i++)
956  {
957  buf[i] = *p;
958  if (*p == '.')
959  {
960  dp = i--; /* skip the decimal point */
961  }
962  }
963  if (dp == 0)
964  dp = i--; /* no decimal point was found in the above
965  * for() loop */
966 
967  if (exp > 0)
968  {
969  if (dp - 10 + exp >= n)
970  {
971  /*
972  * the decimal point is behind the last significant digit;
973  * the digits in between must be converted to the exponent
974  * and the decimal point placed after the first digit
975  */
976  exp = dp - 10 + exp - n;
977  buf[10 + n] = '\0';
978 
979  /* insert the decimal point */
980  if (n > 1)
981  {
982  dp = 11;
983  for (i = 23; i > dp; i--)
984  buf[i] = buf[i - 1];
985  buf[dp] = '.';
986  }
987 
988  /*
989  * adjust the exponent by the number of digits after the
990  * decimal point
991  */
992  if (n > 1)
993  sprintf(&buf[11 + n], "e%d", exp + n - 1);
994  else
995  sprintf(&buf[11], "e%d", exp + n - 1);
996 
997  if (sign)
998  {
999  buf[9] = '-';
1000  strcpy(result, &buf[9]);
1001  }
1002  else
1003  strcpy(result, &buf[10]);
1004  }
1005  else
1006  { /* insert the decimal point */
1007  dp += exp;
1008  for (i = 23; i > dp; i--)
1009  buf[i] = buf[i - 1];
1010  buf[11 + n] = '\0';
1011  buf[dp] = '.';
1012  if (sign)
1013  {
1014  buf[9] = '-';
1015  strcpy(result, &buf[9]);
1016  }
1017  else
1018  strcpy(result, &buf[10]);
1019  }
1020  }
1021  else
1022  { /* exp <= 0 */
1023  dp += exp - 1;
1024  buf[10 + n] = '\0';
1025  buf[dp] = '.';
1026  if (sign)
1027  {
1028  buf[dp - 2] = '-';
1029  strcpy(result, &buf[dp - 2]);
1030  }
1031  else
1032  strcpy(result, &buf[dp - 1]);
1033  }
1034  }
1035 
1036  /* do nothing for Abs(exp) > 4; %e must be OK */
1037  /* just get rid of zeroes after [eE]- and +zeroes after [Ee]. */
1038 
1039  /* ... this is not done yet. */
1040  }
1041  return strlen(result);
1042 }
1043 
1044 
1045 /*
1046 ** Miscellany
1047 */
1048 
1049 /* find out the number of significant digits in a string representing
1050  * a floating point number
1051  */
1052 int
1053 significant_digits(const char *s)
1054 {
1055  const char *p = s;
1056  int n,
1057  c,
1058  zeroes;
1059 
1060  zeroes = 1;
1061  /* skip leading zeroes and sign */
1062  for (c = *p; (c == '0' || c == '+' || c == '-') && c != 0; c = *(++p));
1063 
1064  /* skip decimal point and following zeroes */
1065  for (c = *p; (c == '0' || c == '.') && c != 0; c = *(++p))
1066  {
1067  if (c != '.')
1068  zeroes++;
1069  }
1070 
1071  /* count significant digits (n) */
1072  for (c = *p, n = 0; c != 0; c = *(++p))
1073  {
1074  if (!((c >= '0' && c <= '9') || (c == '.')))
1075  break;
1076  if (c != '.')
1077  n++;
1078  }
1079 
1080  if (!n)
1081  return zeroes;
1082 
1083  return n;
1084 }
#define GIST_LEAF(entry)
Definition: gist.h:141
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:351
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:355
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: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:263
float center
Definition: seg.c:37
Datum seg_out(PG_FUNCTION_ARGS)
Definition: seg.c:119
#define Min(x, y)
Definition: c.h:911
OffsetNumber * spl_left
Definition: gist.h:113
Datum spl_rdatum
Definition: gist.h:120
#define PG_RETURN_INT32(x)
Definition: fmgr.h:344
int32 n
Definition: gist.h:206
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:271
void seg_scanner_finish(void)
int spl_nleft
Definition: gist.h:114
#define fprintf
Definition: port.h:196
Datum seg_left(PG_FUNCTION_ARGS)
Definition: seg.c:592
uint16 OffsetNumber
Definition: off.h:24
#define Abs(x)
Definition: c.h:917
GISTENTRY vector[FLEXIBLE_ARRAY_MEMBER]
Definition: gist.h:207
#define sprintf
Definition: port.h:194
#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:712
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:119
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:668
Datum key
Definition: gist.h:131
char * c
PG_MODULE_MAGIC
Definition: seg.c:30
int significant_digits(const char *s)
Definition: seg.c:1053
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:569
Datum seg_ge(PG_FUNCTION_ARGS)
Definition: seg.c:873
#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:349
uintptr_t Datum
Definition: postgres.h:367
char l_ext
Definition: segdata.h:10
Datum seg_gt(PG_FUNCTION_ARGS)
Definition: seg.c:864
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:343
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:846
Datum spl_ldatum
Definition: gist.h:115
char l_sigd
Definition: segdata.h:8
#define RTRightStrategyNumber
Definition: stratnum.h:55
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:352
OffsetNumber * spl_right
Definition: gist.h:118
#define RTContainsStrategyNumber
Definition: stratnum.h:57
static int restore(char *s, float val, int n)
Definition: seg.c:907
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:267
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:724
void * palloc(Size size)
Definition: mcxt.c:949
float4 upper
Definition: segdata.h:7
Datum seg_over_right(PG_FUNCTION_ARGS)
Definition: seg.c:614
#define elog(elevel,...)
Definition: elog.h:228
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:272
#define RTOverlapStrategyNumber
Definition: stratnum.h:53
#define PG_FUNCTION_ARGS
Definition: fmgr.h:188
#define qsort(a, b, c, d)
Definition: port.h:488
Datum seg_different(PG_FUNCTION_ARGS)
Definition: seg.c:883
Datum seg_le(PG_FUNCTION_ARGS)
Definition: seg.c:855
long val
Definition: informix.c:664
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:617
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