Age Owner Branch data TLA Line data Source code
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 : :
6529 tgl@sss.pgh.pa.us 31 :CBC 2 : PG_MODULE_MAGIC;
32 : :
33 : : /*
34 : : * Auxiliary data structure for picksplit method.
35 : : */
36 : : typedef struct
37 : : {
38 : : float center;
39 : : OffsetNumber index;
40 : : SEG *data;
41 : : } gseg_picksplit_item;
42 : :
43 : : /*
44 : : ** Input/Output routines
45 : : */
5840 alvherre@alvh.no-ip. 46 : 3 : PG_FUNCTION_INFO_V1(seg_in);
47 : 3 : PG_FUNCTION_INFO_V1(seg_out);
5839 tgl@sss.pgh.pa.us 48 : 2 : PG_FUNCTION_INFO_V1(seg_size);
5840 alvherre@alvh.no-ip. 49 : 3 : PG_FUNCTION_INFO_V1(seg_lower);
50 : 3 : PG_FUNCTION_INFO_V1(seg_upper);
51 : 3 : PG_FUNCTION_INFO_V1(seg_center);
52 : :
53 : : /*
54 : : ** GiST support methods
55 : : */
2573 andres@anarazel.de 56 : 3 : PG_FUNCTION_INFO_V1(gseg_consistent);
57 : 2 : PG_FUNCTION_INFO_V1(gseg_compress);
58 : 2 : PG_FUNCTION_INFO_V1(gseg_decompress);
59 : 3 : PG_FUNCTION_INFO_V1(gseg_picksplit);
60 : 3 : PG_FUNCTION_INFO_V1(gseg_penalty);
61 : 3 : PG_FUNCTION_INFO_V1(gseg_union);
62 : 3 : PG_FUNCTION_INFO_V1(gseg_same);
63 : : static Datum gseg_leaf_consistent(Datum key, Datum query, StrategyNumber strategy);
64 : : static Datum gseg_internal_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 : : */
71 : 3 : PG_FUNCTION_INFO_V1(seg_same);
72 : 3 : PG_FUNCTION_INFO_V1(seg_contains);
73 : 3 : PG_FUNCTION_INFO_V1(seg_contained);
74 : 3 : PG_FUNCTION_INFO_V1(seg_overlap);
75 : 3 : PG_FUNCTION_INFO_V1(seg_left);
76 : 3 : PG_FUNCTION_INFO_V1(seg_over_left);
77 : 3 : PG_FUNCTION_INFO_V1(seg_right);
78 : 3 : PG_FUNCTION_INFO_V1(seg_over_right);
79 : 2 : PG_FUNCTION_INFO_V1(seg_union);
80 : 2 : PG_FUNCTION_INFO_V1(seg_inter);
81 : : static void rt_seg_size(SEG *a, float *size);
82 : :
83 : : /*
84 : : ** Various operators
85 : : */
86 : 3 : PG_FUNCTION_INFO_V1(seg_cmp);
87 : 2 : PG_FUNCTION_INFO_V1(seg_lt);
88 : 2 : PG_FUNCTION_INFO_V1(seg_le);
89 : 2 : PG_FUNCTION_INFO_V1(seg_gt);
90 : 2 : PG_FUNCTION_INFO_V1(seg_ge);
91 : 3 : PG_FUNCTION_INFO_V1(seg_different);
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
5840 alvherre@alvh.no-ip. 104 : 2823 : seg_in(PG_FUNCTION_ARGS)
105 : : {
106 : 2823 : char *str = PG_GETARG_CSTRING(0);
8424 bruce@momjian.us 107 : 2823 : SEG *result = palloc(sizeof(SEG));
108 : :
7518 tgl@sss.pgh.pa.us 109 : 2823 : seg_scanner_init(str);
110 : :
478 andrew@dunslane.net 111 [ + + ]: 2823 : if (seg_yyparse(result, fcinfo->context) != 0)
112 : 8 : seg_yyerror(result, fcinfo->context, "bogus input");
113 : :
7518 tgl@sss.pgh.pa.us 114 : 2814 : seg_scanner_finish();
115 : :
5840 alvherre@alvh.no-ip. 116 : 2814 : PG_RETURN_POINTER(result);
117 : : }
118 : :
119 : : Datum
120 : 209 : seg_out(PG_FUNCTION_ARGS)
121 : : {
2573 andres@anarazel.de 122 : 209 : SEG *seg = PG_GETARG_SEG_P(0);
123 : : char *result;
124 : : char *p;
125 : :
8424 bruce@momjian.us 126 : 209 : p = result = (char *) palloc(40);
127 : :
128 [ + + + + : 209 : if (seg->l_ext == '>' || seg->l_ext == '<' || seg->l_ext == '~')
+ + ]
129 : 22 : p += sprintf(p, "%c", seg->l_ext);
130 : :
131 [ + + + - ]: 209 : 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 : 47 : p += restore(p, seg->lower, seg->l_sigd);
137 : : }
138 : : else
139 : : {
140 [ + + ]: 162 : if (seg->l_ext != '-')
141 : : {
142 : : /* print the lower boundary if exists */
143 : 155 : p += restore(p, seg->lower, seg->l_sigd);
144 : 155 : p += sprintf(p, " ");
145 : : }
146 : 162 : p += sprintf(p, "..");
147 [ + + ]: 162 : if (seg->u_ext != '-')
148 : : {
149 : : /* print the upper boundary if exists */
150 : 123 : p += sprintf(p, " ");
151 [ + + + + : 123 : if (seg->u_ext == '>' || seg->u_ext == '<' || seg->l_ext == '~')
- + ]
152 : 32 : p += sprintf(p, "%c", seg->u_ext);
153 : 123 : p += restore(p, seg->upper, seg->u_sigd);
154 : : }
155 : : }
156 : :
5840 alvherre@alvh.no-ip. 157 : 209 : PG_RETURN_CSTRING(result);
158 : : }
159 : :
160 : : Datum
161 : 143 : seg_center(PG_FUNCTION_ARGS)
162 : : {
2573 andres@anarazel.de 163 : 143 : SEG *seg = PG_GETARG_SEG_P(0);
164 : :
5840 alvherre@alvh.no-ip. 165 : 143 : PG_RETURN_FLOAT4(((float) seg->lower + (float) seg->upper) / 2.0);
166 : : }
167 : :
168 : : Datum
169 : 143 : seg_lower(PG_FUNCTION_ARGS)
170 : : {
2573 andres@anarazel.de 171 : 143 : SEG *seg = PG_GETARG_SEG_P(0);
172 : :
5840 alvherre@alvh.no-ip. 173 : 143 : PG_RETURN_FLOAT4(seg->lower);
174 : : }
175 : :
176 : : Datum
177 : 143 : seg_upper(PG_FUNCTION_ARGS)
178 : : {
2573 andres@anarazel.de 179 : 143 : SEG *seg = PG_GETARG_SEG_P(0);
180 : :
5840 alvherre@alvh.no-ip. 181 : 143 : 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
2573 andres@anarazel.de 196 : 5800 : gseg_consistent(PG_FUNCTION_ARGS)
197 : : {
198 : 5800 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
199 : 5800 : Datum query = PG_GETARG_DATUM(1);
200 : 5800 : StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
201 : :
202 : : /* Oid subtype = PG_GETARG_OID(3); */
203 : 5800 : bool *recheck = (bool *) PG_GETARG_POINTER(4);
204 : :
205 : : /* All cases served by this function are exact */
5844 tgl@sss.pgh.pa.us 206 : 5800 : *recheck = false;
207 : :
208 : : /*
209 : : * if entry is not leaf, use gseg_internal_consistent, else use
210 : : * gseg_leaf_consistent
211 : : */
8424 bruce@momjian.us 212 [ + + ]: 5800 : if (GIST_LEAF(entry))
2573 andres@anarazel.de 213 : 5728 : return gseg_leaf_consistent(entry->key, query, strategy);
214 : : else
215 : 72 : 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
223 : 2316 : gseg_union(PG_FUNCTION_ARGS)
224 : : {
225 : 2316 : GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
226 : 2316 : int *sizep = (int *) PG_GETARG_POINTER(1);
227 : : int numranges,
228 : : i;
229 : 2316 : Datum out = 0;
230 : : Datum tmp;
231 : :
232 : : #ifdef GIST_DEBUG
233 : : fprintf(stderr, "union\n");
234 : : #endif
235 : :
7320 teodor@sigaev.ru 236 : 2316 : numranges = entryvec->n;
2573 andres@anarazel.de 237 : 2316 : tmp = entryvec->vector[0].key;
8424 bruce@momjian.us 238 : 2316 : *sizep = sizeof(SEG);
239 : :
240 [ + + ]: 4632 : for (i = 1; i < numranges; i++)
241 : : {
2573 andres@anarazel.de 242 : 2316 : out = gseg_binary_union(tmp, entryvec->vector[i].key, sizep);
8424 bruce@momjian.us 243 : 2316 : tmp = out;
244 : : }
245 : :
2573 andres@anarazel.de 246 : 2316 : PG_RETURN_DATUM(out);
247 : : }
248 : :
249 : : /*
250 : : ** GiST Compress and Decompress methods for segments
251 : : ** do not do anything.
252 : : */
253 : : Datum
2573 andres@anarazel.de 254 :UBC 0 : gseg_compress(PG_FUNCTION_ARGS)
255 : : {
256 : 0 : PG_RETURN_POINTER(PG_GETARG_POINTER(0));
257 : : }
258 : :
259 : : Datum
260 : 0 : gseg_decompress(PG_FUNCTION_ARGS)
261 : : {
262 : 0 : PG_RETURN_POINTER(PG_GETARG_POINTER(0));
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
2573 andres@anarazel.de 270 :CBC 4821 : gseg_penalty(PG_FUNCTION_ARGS)
271 : : {
272 : 4821 : GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
273 : 4821 : GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
274 : 4821 : float *result = (float *) PG_GETARG_POINTER(2);
275 : : SEG *ud;
276 : : float tmp1,
277 : : tmp2;
278 : :
279 : 4821 : ud = DatumGetSegP(DirectFunctionCall2(seg_union,
280 : : origentry->key,
281 : : newentry->key));
8354 tgl@sss.pgh.pa.us 282 : 4821 : rt_seg_size(ud, &tmp1);
2573 andres@anarazel.de 283 : 4821 : rt_seg_size(DatumGetSegP(origentry->key), &tmp2);
8424 bruce@momjian.us 284 : 4821 : *result = tmp1 - tmp2;
285 : :
286 : : #ifdef GIST_DEBUG
287 : : fprintf(stderr, "penalty\n");
288 : : fprintf(stderr, "\t%g\n", *result);
289 : : #endif
290 : :
2573 andres@anarazel.de 291 : 4821 : PG_RETURN_POINTER(result);
292 : : }
293 : :
294 : : /*
295 : : * Compare function for gseg_picksplit_item: sort by center.
296 : : */
297 : : static int
4869 tgl@sss.pgh.pa.us 298 : 28640 : gseg_picksplit_item_cmp(const void *a, const void *b)
299 : : {
300 : 28640 : const gseg_picksplit_item *i1 = (const gseg_picksplit_item *) a;
301 : 28640 : const gseg_picksplit_item *i2 = (const gseg_picksplit_item *) b;
302 : :
303 [ + + ]: 28640 : if (i1->center < i2->center)
304 : 12256 : return -1;
305 [ + + ]: 16384 : else if (i1->center == i2->center)
306 : 4933 : return 0;
307 : : else
308 : 11451 : 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
2573 andres@anarazel.de 319 : 17 : gseg_picksplit(PG_FUNCTION_ARGS)
320 : : {
321 : 17 : GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
322 : 17 : GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
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 */
4869 tgl@sss.pgh.pa.us 338 : 17 : maxoff = entryvec->n - 1;
339 : :
340 : : /*
341 : : * Prepare the auxiliary array and sort it.
342 : : */
343 : : sort_items = (gseg_picksplit_item *)
344 : 17 : palloc(maxoff * sizeof(gseg_picksplit_item));
345 [ + + ]: 4471 : for (i = 1; i <= maxoff; i++)
346 : : {
2573 andres@anarazel.de 347 : 4454 : seg = DatumGetSegP(entryvec->vector[i].key);
348 : : /* center calculation is done this way to avoid possible overflow */
4753 bruce@momjian.us 349 : 4454 : sort_items[i - 1].center = seg->lower * 0.5f + seg->upper * 0.5f;
4869 tgl@sss.pgh.pa.us 350 : 4454 : sort_items[i - 1].index = i;
351 : 4454 : sort_items[i - 1].data = seg;
352 : : }
353 : 17 : qsort(sort_items, maxoff, sizeof(gseg_picksplit_item),
354 : : gseg_picksplit_item_cmp);
355 : :
356 : : /* sort items below "firstright" will go into the left side */
357 : 17 : firstright = maxoff / 2;
358 : :
359 : 17 : v->spl_left = (OffsetNumber *) palloc(maxoff * sizeof(OffsetNumber));
360 : 17 : v->spl_right = (OffsetNumber *) palloc(maxoff * sizeof(OffsetNumber));
8424 bruce@momjian.us 361 : 17 : left = v->spl_left;
362 : 17 : v->spl_nleft = 0;
363 : 17 : right = v->spl_right;
364 : 17 : v->spl_nright = 0;
365 : :
366 : : /*
367 : : * Emit segments to the left output page, and compute its bounding box.
368 : : */
2573 andres@anarazel.de 369 : 17 : seg_l = (SEG *) palloc(sizeof(SEG));
370 : 17 : memcpy(seg_l, sort_items[0].data, sizeof(SEG));
4869 tgl@sss.pgh.pa.us 371 : 17 : *left++ = sort_items[0].index;
372 : 17 : v->spl_nleft++;
373 [ + + ]: 2227 : for (i = 1; i < firstright; i++)
374 : : {
2573 andres@anarazel.de 375 : 2210 : Datum sortitem = PointerGetDatum(sort_items[i].data);
376 : :
377 : 2210 : seg_l = DatumGetSegP(DirectFunctionCall2(seg_union,
378 : : PointerGetDatum(seg_l),
379 : : sortitem));
4869 tgl@sss.pgh.pa.us 380 : 2210 : *left++ = sort_items[i].index;
381 : 2210 : v->spl_nleft++;
382 : : }
383 : :
384 : : /*
385 : : * Likewise for the right page.
386 : : */
2573 andres@anarazel.de 387 : 17 : seg_r = (SEG *) palloc(sizeof(SEG));
388 : 17 : memcpy(seg_r, sort_items[firstright].data, sizeof(SEG));
4869 tgl@sss.pgh.pa.us 389 : 17 : *right++ = sort_items[firstright].index;
390 : 17 : v->spl_nright++;
391 [ + + ]: 2227 : for (i = firstright + 1; i < maxoff; i++)
392 : : {
2573 andres@anarazel.de 393 : 2210 : Datum sortitem = PointerGetDatum(sort_items[i].data);
394 : :
395 : 2210 : seg_r = DatumGetSegP(DirectFunctionCall2(seg_union,
396 : : PointerGetDatum(seg_r),
397 : : sortitem));
4869 tgl@sss.pgh.pa.us 398 : 2210 : *right++ = sort_items[i].index;
399 : 2210 : v->spl_nright++;
400 : : }
401 : :
2573 andres@anarazel.de 402 : 17 : v->spl_ldatum = PointerGetDatum(seg_l);
403 : 17 : v->spl_rdatum = PointerGetDatum(seg_r);
404 : :
405 : 17 : PG_RETURN_POINTER(v);
406 : : }
407 : :
408 : : /*
409 : : ** Equality methods
410 : : */
411 : : Datum
412 : 2315 : gseg_same(PG_FUNCTION_ARGS)
413 : : {
414 : 2315 : bool *result = (bool *) PG_GETARG_POINTER(2);
415 : :
416 [ + + ]: 2315 : if (DirectFunctionCall2(seg_same, PG_GETARG_DATUM(0), PG_GETARG_DATUM(1)))
2433 peter_e@gmx.net 417 : 2284 : *result = true;
418 : : else
419 : 31 : *result = false;
420 : :
421 : : #ifdef GIST_DEBUG
422 : : fprintf(stderr, "same: %s\n", (*result ? "TRUE" : "FALSE"));
423 : : #endif
424 : :
2573 andres@anarazel.de 425 : 2315 : PG_RETURN_POINTER(result);
426 : : }
427 : :
428 : : /*
429 : : ** SUPPORT ROUTINES
430 : : */
431 : : static Datum
432 : 5728 : gseg_leaf_consistent(Datum key, Datum query, StrategyNumber strategy)
433 : : {
434 : : Datum retval;
435 : :
436 : : #ifdef GIST_QUERY_DEBUG
437 : : fprintf(stderr, "leaf_consistent, %d\n", strategy);
438 : : #endif
439 : :
8424 bruce@momjian.us 440 [ - - - - : 5728 : switch (strategy)
- - + -
- ]
441 : : {
8424 bruce@momjian.us 442 :UBC 0 : case RTLeftStrategyNumber:
2573 andres@anarazel.de 443 : 0 : retval = DirectFunctionCall2(seg_left, key, query);
8424 bruce@momjian.us 444 : 0 : break;
445 : 0 : case RTOverLeftStrategyNumber:
2573 andres@anarazel.de 446 : 0 : retval = DirectFunctionCall2(seg_over_left, key, query);
8424 bruce@momjian.us 447 : 0 : break;
448 : 0 : case RTOverlapStrategyNumber:
2573 andres@anarazel.de 449 : 0 : retval = DirectFunctionCall2(seg_overlap, key, query);
8424 bruce@momjian.us 450 : 0 : break;
451 : 0 : case RTOverRightStrategyNumber:
2573 andres@anarazel.de 452 : 0 : retval = DirectFunctionCall2(seg_over_right, key, query);
8424 bruce@momjian.us 453 : 0 : break;
454 : 0 : case RTRightStrategyNumber:
2573 andres@anarazel.de 455 : 0 : retval = DirectFunctionCall2(seg_right, key, query);
8424 bruce@momjian.us 456 : 0 : break;
457 : 0 : case RTSameStrategyNumber:
2573 andres@anarazel.de 458 : 0 : retval = DirectFunctionCall2(seg_same, key, query);
8424 bruce@momjian.us 459 : 0 : break;
8424 bruce@momjian.us 460 :CBC 5728 : case RTContainsStrategyNumber:
461 : : case RTOldContainsStrategyNumber:
2573 andres@anarazel.de 462 : 5728 : retval = DirectFunctionCall2(seg_contains, key, query);
8424 bruce@momjian.us 463 : 5728 : break;
8424 bruce@momjian.us 464 :UBC 0 : case RTContainedByStrategyNumber:
465 : : case RTOldContainedByStrategyNumber:
2573 andres@anarazel.de 466 : 0 : retval = DirectFunctionCall2(seg_contained, key, query);
8424 bruce@momjian.us 467 : 0 : break;
468 : 0 : default:
2433 peter_e@gmx.net 469 : 0 : retval = false;
470 : : }
471 : :
2573 andres@anarazel.de 472 :CBC 5728 : PG_RETURN_DATUM(retval);
473 : : }
474 : :
475 : : static Datum
476 : 72 : gseg_internal_consistent(Datum key, Datum query, StrategyNumber strategy)
477 : : {
478 : : bool retval;
479 : :
480 : : #ifdef GIST_QUERY_DEBUG
481 : : fprintf(stderr, "internal_consistent, %d\n", strategy);
482 : : #endif
483 : :
8424 bruce@momjian.us 484 [ - - - - : 72 : switch (strategy)
- + - - ]
485 : : {
8424 bruce@momjian.us 486 :UBC 0 : case RTLeftStrategyNumber:
2573 andres@anarazel.de 487 : 0 : retval =
488 : 0 : !DatumGetBool(DirectFunctionCall2(seg_over_right, key, query));
6866 tgl@sss.pgh.pa.us 489 : 0 : break;
8424 bruce@momjian.us 490 : 0 : case RTOverLeftStrategyNumber:
2573 andres@anarazel.de 491 : 0 : retval =
492 : 0 : !DatumGetBool(DirectFunctionCall2(seg_right, key, query));
8424 bruce@momjian.us 493 : 0 : break;
494 : 0 : case RTOverlapStrategyNumber:
495 : : retval =
2573 andres@anarazel.de 496 : 0 : DatumGetBool(DirectFunctionCall2(seg_overlap, key, query));
8424 bruce@momjian.us 497 : 0 : break;
498 : 0 : case RTOverRightStrategyNumber:
2573 andres@anarazel.de 499 : 0 : retval =
500 : 0 : !DatumGetBool(DirectFunctionCall2(seg_left, key, query));
6866 tgl@sss.pgh.pa.us 501 : 0 : break;
8424 bruce@momjian.us 502 : 0 : case RTRightStrategyNumber:
2573 andres@anarazel.de 503 : 0 : retval =
504 : 0 : !DatumGetBool(DirectFunctionCall2(seg_over_left, key, query));
8424 bruce@momjian.us 505 : 0 : break;
8424 bruce@momjian.us 506 :CBC 72 : case RTSameStrategyNumber:
507 : : case RTContainsStrategyNumber:
508 : : case RTOldContainsStrategyNumber:
509 : : retval =
2573 andres@anarazel.de 510 : 72 : DatumGetBool(DirectFunctionCall2(seg_contains, key, query));
8424 bruce@momjian.us 511 : 72 : break;
8424 bruce@momjian.us 512 :UBC 0 : case RTContainedByStrategyNumber:
513 : : case RTOldContainedByStrategyNumber:
514 : : retval =
2573 andres@anarazel.de 515 : 0 : DatumGetBool(DirectFunctionCall2(seg_overlap, key, query));
8424 bruce@momjian.us 516 : 0 : break;
517 : 0 : default:
2433 peter_e@gmx.net 518 : 0 : retval = false;
519 : : }
520 : :
2573 andres@anarazel.de 521 :CBC 72 : PG_RETURN_BOOL(retval);
522 : : }
523 : :
524 : : static Datum
525 : 2316 : gseg_binary_union(Datum r1, Datum r2, int *sizep)
526 : : {
527 : : Datum retval;
528 : :
529 : 2316 : retval = DirectFunctionCall2(seg_union, r1, r2);
8424 bruce@momjian.us 530 : 2316 : *sizep = sizeof(SEG);
531 : :
2432 peter_e@gmx.net 532 : 2316 : return retval;
533 : : }
534 : :
535 : :
536 : : Datum
2573 andres@anarazel.de 537 : 5815 : seg_contains(PG_FUNCTION_ARGS)
538 : : {
539 : 5815 : SEG *a = PG_GETARG_SEG_P(0);
540 : 5815 : SEG *b = PG_GETARG_SEG_P(1);
541 : :
542 [ + + + + ]: 5815 : PG_RETURN_BOOL((a->lower <= b->lower) && (a->upper >= b->upper));
543 : : }
544 : :
545 : : Datum
546 : 14 : seg_contained(PG_FUNCTION_ARGS)
547 : : {
548 : 14 : Datum a = PG_GETARG_DATUM(0);
549 : 14 : Datum b = PG_GETARG_DATUM(1);
550 : :
551 : 14 : PG_RETURN_DATUM(DirectFunctionCall2(seg_contains, b, a));
552 : : }
553 : :
554 : : /*****************************************************************************
555 : : * Operator class for R-tree indexing
556 : : *****************************************************************************/
557 : :
558 : : Datum
559 : 2459 : seg_same(PG_FUNCTION_ARGS)
560 : : {
1536 alvherre@alvh.no-ip. 561 : 2459 : int cmp = DatumGetInt32(DirectFunctionCall2(seg_cmp,
562 : : PG_GETARG_DATUM(0),
563 : : PG_GETARG_DATUM(1)));
564 : :
2573 andres@anarazel.de 565 : 2459 : PG_RETURN_BOOL(cmp == 0);
566 : : }
567 : :
568 : : /* seg_overlap -- does a overlap b?
569 : : */
570 : : Datum
571 : 15 : seg_overlap(PG_FUNCTION_ARGS)
572 : : {
573 : 15 : SEG *a = PG_GETARG_SEG_P(0);
574 : 15 : SEG *b = PG_GETARG_SEG_P(1);
575 : :
576 [ + + + + : 15 : 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
583 : 11 : seg_over_left(PG_FUNCTION_ARGS)
584 : : {
585 : 11 : SEG *a = PG_GETARG_SEG_P(0);
586 : 11 : SEG *b = PG_GETARG_SEG_P(1);
587 : :
588 : 11 : PG_RETURN_BOOL(a->upper <= b->upper);
589 : : }
590 : :
591 : : /* seg_left -- is (a) entirely on the left of (b)?
592 : : */
593 : : Datum
594 : 11 : seg_left(PG_FUNCTION_ARGS)
595 : : {
596 : 11 : SEG *a = PG_GETARG_SEG_P(0);
597 : 11 : SEG *b = PG_GETARG_SEG_P(1);
598 : :
599 : 11 : PG_RETURN_BOOL(a->upper < b->lower);
600 : : }
601 : :
602 : : /* seg_right -- is (a) entirely on the right of (b)?
603 : : */
604 : : Datum
605 : 11 : seg_right(PG_FUNCTION_ARGS)
606 : : {
607 : 11 : SEG *a = PG_GETARG_SEG_P(0);
608 : 11 : SEG *b = PG_GETARG_SEG_P(1);
609 : :
610 : 11 : 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
616 : 11 : seg_over_right(PG_FUNCTION_ARGS)
617 : : {
618 : 11 : SEG *a = PG_GETARG_SEG_P(0);
619 : 11 : SEG *b = PG_GETARG_SEG_P(1);
620 : :
621 : 11 : PG_RETURN_BOOL(a->lower >= b->lower);
622 : : }
623 : :
624 : : Datum
625 : 11557 : seg_union(PG_FUNCTION_ARGS)
626 : : {
627 : 11557 : SEG *a = PG_GETARG_SEG_P(0);
628 : 11557 : SEG *b = PG_GETARG_SEG_P(1);
629 : : SEG *n;
630 : :
8424 bruce@momjian.us 631 : 11557 : n = (SEG *) palloc(sizeof(*n));
632 : :
633 : : /* take max of upper endpoints */
634 [ + + ]: 11557 : if (a->upper > b->upper)
635 : : {
636 : 10526 : n->upper = a->upper;
637 : 10526 : n->u_sigd = a->u_sigd;
638 : 10526 : n->u_ext = a->u_ext;
639 : : }
640 : : else
641 : : {
642 : 1031 : n->upper = b->upper;
643 : 1031 : n->u_sigd = b->u_sigd;
644 : 1031 : n->u_ext = b->u_ext;
645 : : }
646 : :
647 : : /* take min of lower endpoints */
648 [ + + ]: 11557 : if (a->lower < b->lower)
649 : : {
650 : 11231 : n->lower = a->lower;
651 : 11231 : n->l_sigd = a->l_sigd;
652 : 11231 : n->l_ext = a->l_ext;
653 : : }
654 : : else
655 : : {
656 : 326 : n->lower = b->lower;
657 : 326 : n->l_sigd = b->l_sigd;
658 : 326 : n->l_ext = b->l_ext;
659 : : }
660 : :
2573 andres@anarazel.de 661 : 11557 : PG_RETURN_POINTER(n);
662 : : }
663 : :
664 : : Datum
2573 andres@anarazel.de 665 :UBC 0 : seg_inter(PG_FUNCTION_ARGS)
666 : : {
667 : 0 : SEG *a = PG_GETARG_SEG_P(0);
668 : 0 : SEG *b = PG_GETARG_SEG_P(1);
669 : : SEG *n;
670 : :
8424 bruce@momjian.us 671 : 0 : n = (SEG *) palloc(sizeof(*n));
672 : :
673 : : /* take min of upper endpoints */
674 [ # # ]: 0 : if (a->upper < b->upper)
675 : : {
676 : 0 : n->upper = a->upper;
677 : 0 : n->u_sigd = a->u_sigd;
678 : 0 : n->u_ext = a->u_ext;
679 : : }
680 : : else
681 : : {
682 : 0 : n->upper = b->upper;
683 : 0 : n->u_sigd = b->u_sigd;
684 : 0 : n->u_ext = b->u_ext;
685 : : }
686 : :
687 : : /* take max of lower endpoints */
688 [ # # ]: 0 : if (a->lower > b->lower)
689 : : {
690 : 0 : n->lower = a->lower;
691 : 0 : n->l_sigd = a->l_sigd;
692 : 0 : n->l_ext = a->l_ext;
693 : : }
694 : : else
695 : : {
696 : 0 : n->lower = b->lower;
697 : 0 : n->l_sigd = b->l_sigd;
698 : 0 : n->l_ext = b->l_ext;
699 : : }
700 : :
2573 andres@anarazel.de 701 : 0 : PG_RETURN_POINTER(n);
702 : : }
703 : :
704 : : static void
5421 bruce@momjian.us 705 :CBC 9642 : rt_seg_size(SEG *a, float *size)
706 : : {
8424 707 [ + - - + ]: 9642 : if (a == (SEG *) NULL || a->upper <= a->lower)
8424 bruce@momjian.us 708 :UBC 0 : *size = 0.0;
709 : : else
554 peter@eisentraut.org 710 :CBC 9642 : *size = fabsf(a->upper - a->lower);
8525 tgl@sss.pgh.pa.us 711 : 9642 : }
712 : :
713 : : Datum
5839 tgl@sss.pgh.pa.us 714 :UBC 0 : seg_size(PG_FUNCTION_ARGS)
715 : : {
2573 andres@anarazel.de 716 : 0 : SEG *seg = PG_GETARG_SEG_P(0);
717 : :
554 peter@eisentraut.org 718 : 0 : PG_RETURN_FLOAT4(fabsf(seg->upper - seg->lower));
719 : : }
720 : :
721 : :
722 : : /*****************************************************************************
723 : : * Miscellaneous operators
724 : : *****************************************************************************/
725 : : Datum
2573 andres@anarazel.de 726 :CBC 4433 : seg_cmp(PG_FUNCTION_ARGS)
727 : : {
728 : 4433 : SEG *a = PG_GETARG_SEG_P(0);
729 : 4433 : SEG *b = PG_GETARG_SEG_P(1);
730 : :
731 : : /*
732 : : * First compare on lower boundary position
733 : : */
8424 bruce@momjian.us 734 [ + + ]: 4433 : if (a->lower < b->lower)
2573 andres@anarazel.de 735 : 904 : PG_RETURN_INT32(-1);
8424 bruce@momjian.us 736 [ + + ]: 3529 : if (a->lower > b->lower)
2573 andres@anarazel.de 737 : 801 : 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 : : */
8424 bruce@momjian.us 746 [ + + ]: 2728 : if (a->l_ext != b->l_ext)
747 : : {
748 [ - + ]: 66 : if (a->l_ext == '-')
2573 andres@anarazel.de 749 :UBC 0 : PG_RETURN_INT32(-1);
8424 bruce@momjian.us 750 [ - + ]:CBC 66 : if (b->l_ext == '-')
2573 andres@anarazel.de 751 :UBC 0 : PG_RETURN_INT32(1);
8424 bruce@momjian.us 752 [ + + ]:CBC 66 : if (a->l_ext == '<')
2573 andres@anarazel.de 753 : 26 : PG_RETURN_INT32(-1);
8424 bruce@momjian.us 754 [ + + ]: 40 : if (b->l_ext == '<')
2573 andres@anarazel.de 755 : 21 : PG_RETURN_INT32(1);
8424 bruce@momjian.us 756 [ + + ]: 19 : if (a->l_ext == '>')
2573 andres@anarazel.de 757 : 13 : PG_RETURN_INT32(1);
8424 bruce@momjian.us 758 [ + - ]: 6 : if (b->l_ext == '>')
2573 andres@anarazel.de 759 : 6 : PG_RETURN_INT32(-1);
760 : : }
761 : :
762 : : /*
763 : : * For other boundary types, consider # of significant digits first.
764 : : */
6756 bruce@momjian.us 765 [ + + ]: 2662 : if (a->l_sigd < b->l_sigd) /* (a) is blurred and is likely to include (b) */
2573 andres@anarazel.de 766 : 18 : PG_RETURN_INT32(-1);
8424 bruce@momjian.us 767 [ + + ]: 2644 : if (a->l_sigd > b->l_sigd) /* (a) is less blurred and is likely to be
768 : : * included in (b) */
2573 andres@anarazel.de 769 : 18 : PG_RETURN_INT32(1);
770 : :
771 : : /*
772 : : * For same # of digits, an approximate boundary is more blurred than
773 : : * exact.
774 : : */
8424 bruce@momjian.us 775 [ - + ]: 2626 : if (a->l_ext != b->l_ext)
776 : : {
8424 bruce@momjian.us 777 [ # # ]:UBC 0 : if (a->l_ext == '~') /* (a) is approximate, while (b) is exact */
2573 andres@anarazel.de 778 : 0 : PG_RETURN_INT32(-1);
8424 bruce@momjian.us 779 [ # # ]: 0 : if (b->l_ext == '~')
2573 andres@anarazel.de 780 : 0 : PG_RETURN_INT32(1);
781 : : /* can't get here unless data is corrupt */
7570 tgl@sss.pgh.pa.us 782 [ # # ]: 0 : 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 : : */
8424 bruce@momjian.us 791 [ + + ]:CBC 2626 : if (a->upper < b->upper)
2573 andres@anarazel.de 792 : 163 : PG_RETURN_INT32(-1);
8424 bruce@momjian.us 793 [ + + ]: 2463 : if (a->upper > b->upper)
2573 andres@anarazel.de 794 : 126 : 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 : : */
8424 bruce@momjian.us 803 [ + + ]: 2337 : if (a->u_ext != b->u_ext)
804 : : {
805 [ - + ]: 41 : if (a->u_ext == '-')
2573 andres@anarazel.de 806 :UBC 0 : PG_RETURN_INT32(1);
8424 bruce@momjian.us 807 [ - + ]:CBC 41 : if (b->u_ext == '-')
2573 andres@anarazel.de 808 :UBC 0 : PG_RETURN_INT32(-1);
8424 bruce@momjian.us 809 [ + + ]:CBC 41 : if (a->u_ext == '<')
2573 andres@anarazel.de 810 : 3 : PG_RETURN_INT32(-1);
8424 bruce@momjian.us 811 [ + + ]: 38 : if (b->u_ext == '<')
2573 andres@anarazel.de 812 : 1 : PG_RETURN_INT32(1);
8424 bruce@momjian.us 813 [ + + ]: 37 : if (a->u_ext == '>')
2573 andres@anarazel.de 814 : 20 : PG_RETURN_INT32(1);
8424 bruce@momjian.us 815 [ + - ]: 17 : if (b->u_ext == '>')
2573 andres@anarazel.de 816 : 17 : 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 : : */
6756 bruce@momjian.us 823 [ + + ]: 2296 : if (a->u_sigd < b->u_sigd) /* (a) is blurred and is likely to include (b) */
2573 andres@anarazel.de 824 : 6 : PG_RETURN_INT32(1);
8424 bruce@momjian.us 825 [ + + ]: 2290 : if (a->u_sigd > b->u_sigd) /* (a) is less blurred and is likely to be
826 : : * included in (b) */
2573 andres@anarazel.de 827 : 4 : 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 : : */
8424 bruce@momjian.us 833 [ - + ]: 2286 : if (a->u_ext != b->u_ext)
834 : : {
8424 bruce@momjian.us 835 [ # # ]:UBC 0 : if (a->u_ext == '~') /* (a) is approximate, while (b) is exact */
2573 andres@anarazel.de 836 : 0 : PG_RETURN_INT32(1);
8424 bruce@momjian.us 837 [ # # ]: 0 : if (b->u_ext == '~')
2573 andres@anarazel.de 838 : 0 : PG_RETURN_INT32(-1);
839 : : /* can't get here unless data is corrupt */
7570 tgl@sss.pgh.pa.us 840 [ # # ]: 0 : elog(ERROR, "bogus upper boundary types %d %d",
841 : : (int) a->u_ext, (int) b->u_ext);
842 : : }
843 : :
2573 andres@anarazel.de 844 :CBC 2286 : PG_RETURN_INT32(0);
845 : : }
846 : :
847 : : Datum
2573 andres@anarazel.de 848 :UBC 0 : seg_lt(PG_FUNCTION_ARGS)
849 : : {
1536 alvherre@alvh.no-ip. 850 : 0 : int cmp = DatumGetInt32(DirectFunctionCall2(seg_cmp,
851 : : PG_GETARG_DATUM(0),
852 : : PG_GETARG_DATUM(1)));
853 : :
2573 andres@anarazel.de 854 : 0 : PG_RETURN_BOOL(cmp < 0);
855 : : }
856 : :
857 : : Datum
858 : 0 : seg_le(PG_FUNCTION_ARGS)
859 : : {
1536 alvherre@alvh.no-ip. 860 : 0 : int cmp = DatumGetInt32(DirectFunctionCall2(seg_cmp,
861 : : PG_GETARG_DATUM(0),
862 : : PG_GETARG_DATUM(1)));
863 : :
2573 andres@anarazel.de 864 : 0 : PG_RETURN_BOOL(cmp <= 0);
865 : : }
866 : :
867 : : Datum
868 : 0 : seg_gt(PG_FUNCTION_ARGS)
869 : : {
1536 alvherre@alvh.no-ip. 870 : 0 : int cmp = DatumGetInt32(DirectFunctionCall2(seg_cmp,
871 : : PG_GETARG_DATUM(0),
872 : : PG_GETARG_DATUM(1)));
873 : :
2573 andres@anarazel.de 874 : 0 : PG_RETURN_BOOL(cmp > 0);
875 : : }
876 : :
877 : : Datum
878 : 0 : seg_ge(PG_FUNCTION_ARGS)
879 : : {
1536 alvherre@alvh.no-ip. 880 : 0 : int cmp = DatumGetInt32(DirectFunctionCall2(seg_cmp,
881 : : PG_GETARG_DATUM(0),
882 : : PG_GETARG_DATUM(1)));
883 : :
2573 andres@anarazel.de 884 : 0 : PG_RETURN_BOOL(cmp >= 0);
885 : : }
886 : :
887 : :
888 : : Datum
2573 andres@anarazel.de 889 :CBC 2 : seg_different(PG_FUNCTION_ARGS)
890 : : {
1536 alvherre@alvh.no-ip. 891 : 2 : int cmp = DatumGetInt32(DirectFunctionCall2(seg_cmp,
892 : : PG_GETARG_DATUM(0),
893 : : PG_GETARG_DATUM(1)));
894 : :
2573 andres@anarazel.de 895 : 2 : 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
8424 bruce@momjian.us 914 : 325 : restore(char *result, float val, int n)
915 : : {
916 : 325 : 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 : : */
480 tgl@sss.pgh.pa.us 934 [ - + ]: 325 : if (n <= 0)
480 tgl@sss.pgh.pa.us 935 :UBC 0 : n = FLT_DIG;
936 : : else
480 tgl@sss.pgh.pa.us 937 :CBC 325 : n = Min(n, FLT_DIG);
938 : :
939 : : /* remember the sign */
8424 bruce@momjian.us 940 : 325 : sign = (val < 0 ? 1 : 0);
941 : :
942 : : /* print, in %e style to start with */
2933 tgl@sss.pgh.pa.us 943 : 325 : sprintf(result, "%.*e", n - 1, val);
944 : :
945 : : /* find the exponent */
946 : 325 : p = strchr(result, 'e');
947 : :
948 : : /* punt if we have 'inf' or similar */
949 [ - + ]: 325 : if (p == NULL)
2933 tgl@sss.pgh.pa.us 950 :UBC 0 : return strlen(result);
951 : :
2933 tgl@sss.pgh.pa.us 952 :CBC 325 : exp = atoi(p + 1);
8424 bruce@momjian.us 953 [ + + ]: 325 : if (exp == 0)
954 : : {
955 : : /* just truncate off the 'e+00' */
2933 tgl@sss.pgh.pa.us 956 : 169 : *p = '\0';
957 : : }
958 : : else
959 : : {
555 peter@eisentraut.org 960 [ + + + + ]: 156 : if (abs(exp) <= 4)
961 : : {
962 : : /*
963 : : * remove the decimal point from the mantissa and write the digits
964 : : * to the buf array
965 : : */
8424 bruce@momjian.us 966 [ + + ]: 637 : for (p = result + sign, i = 10, dp = 0; *p != 'e'; p++, i++)
967 : : {
968 : 499 : buf[i] = *p;
969 [ + + ]: 499 : if (*p == '.')
970 : : {
971 : 130 : dp = i--; /* skip the decimal point */
972 : : }
973 : : }
974 [ + + ]: 138 : if (dp == 0)
975 : 8 : dp = i--; /* no decimal point was found in the above
976 : : * for() loop */
977 : :
978 [ + + ]: 138 : if (exp > 0)
979 : : {
980 [ + + ]: 133 : 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 : 43 : exp = dp - 10 + exp - n;
988 : 43 : buf[10 + n] = '\0';
989 : :
990 : : /* insert the decimal point */
991 [ + + ]: 43 : if (n > 1)
992 : : {
993 : 39 : dp = 11;
994 [ + + ]: 507 : for (i = 23; i > dp; i--)
995 : 468 : buf[i] = buf[i - 1];
996 : 39 : buf[dp] = '.';
997 : : }
998 : :
999 : : /*
1000 : : * adjust the exponent by the number of digits after the
1001 : : * decimal point
1002 : : */
1003 [ + + ]: 43 : if (n > 1)
1004 : 39 : sprintf(&buf[11 + n], "e%d", exp + n - 1);
1005 : : else
1006 : 4 : sprintf(&buf[11], "e%d", exp + n - 1);
1007 : :
1008 [ - + ]: 43 : if (sign)
1009 : : {
8424 bruce@momjian.us 1010 :UBC 0 : buf[9] = '-';
1011 : 0 : strcpy(result, &buf[9]);
1012 : : }
1013 : : else
8424 bruce@momjian.us 1014 :CBC 43 : strcpy(result, &buf[10]);
1015 : : }
1016 : : else
1017 : : { /* insert the decimal point */
1018 : 90 : dp += exp;
1019 [ + + ]: 1080 : for (i = 23; i > dp; i--)
1020 : 990 : buf[i] = buf[i - 1];
1021 : 90 : buf[11 + n] = '\0';
1022 : 90 : buf[dp] = '.';
1023 [ - + ]: 90 : if (sign)
1024 : : {
8424 bruce@momjian.us 1025 :UBC 0 : buf[9] = '-';
1026 : 0 : strcpy(result, &buf[9]);
1027 : : }
1028 : : else
8424 bruce@momjian.us 1029 :CBC 90 : strcpy(result, &buf[10]);
1030 : : }
1031 : : }
1032 : : else
1033 : : { /* exp <= 0 */
1034 : 5 : dp += exp - 1;
1035 : 5 : buf[10 + n] = '\0';
1036 : 5 : buf[dp] = '.';
1037 [ - + ]: 5 : if (sign)
1038 : : {
8424 bruce@momjian.us 1039 :UBC 0 : buf[dp - 2] = '-';
1040 : 0 : strcpy(result, &buf[dp - 2]);
1041 : : }
1042 : : else
8424 bruce@momjian.us 1043 :CBC 5 : 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 : : }
2432 peter_e@gmx.net 1052 : 325 : 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
2357 1064 : 5187 : significant_digits(const char *s)
1065 : : {
1066 : 5187 : const char *p = s;
1067 : : int n,
1068 : : c,
1069 : : zeroes;
1070 : :
8424 bruce@momjian.us 1071 : 5187 : zeroes = 1;
1072 : : /* skip leading zeroes and sign */
1073 [ + + + - : 5324 : for (c = *p; (c == '0' || c == '+' || c == '-') && c != 0; c = *(++p));
+ + + - ]
1074 : :
1075 : : /* skip decimal point and following zeroes */
1076 [ + + + + : 5208 : for (c = *p; (c == '0' || c == '.') && c != 0; c = *(++p))
+ - ]
1077 : : {
1078 [ + + ]: 21 : if (c != '.')
1079 : 11 : zeroes++;
1080 : : }
1081 : :
1082 : : /* count significant digits (n) */
1083 [ + + ]: 20346 : for (c = *p, n = 0; c != 0; c = *(++p))
1084 : : {
1085 [ + + + + : 15186 : if (!((c >= '0' && c <= '9') || (c == '.')))
+ + ]
1086 : 27 : break;
1087 [ + + ]: 15159 : if (c != '.')
1088 : 10614 : n++;
1089 : : }
1090 : :
1091 [ + + ]: 5187 : if (!n)
2432 peter_e@gmx.net 1092 : 97 : return zeroes;
1093 : :
1094 : 5090 : return n;
1095 : : }
|