Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 2030 lines (1753 sloc) 53.429 kb
0fc1320 Importing prefix operator and opclass files
dim authored
1 /**
2 * Prefix opclass allows to efficiently index a prefix table with
3 * GiST.
4 *
5 * More common use case is telephony prefix searching for cost or
6 * routing.
7 *
8 * Many thanks to AndrewSN, who provided great amount of help in the
9 * writting of this opclass, on the PostgreSQL internals, GiST inner
10 * working and prefix search analyses.
11 *
4adc1f1 refine __pr_penalty() DEBUG, some more docs
dim authored
12 * $Id: prefix.c,v 1.34 2008/04/10 07:38:27 dim Exp $
0fc1320 Importing prefix operator and opclass files
dim authored
13 */
14
15 #include <stdio.h>
16 #include "postgres.h"
17
18 #include "access/gist.h"
19 #include "access/skey.h"
20 #include "utils/elog.h"
21 #include "utils/palloc.h"
22 #include "utils/builtins.h"
23 #include <math.h>
24
25 #define DEBUG
cf4a835 Begin main presort() loop at OffsetNumberNext(FirstOffsetNumber); and…
dim authored
26 /**
27 * We use those DEBUG defines in the code, uncomment them to get very
28 * verbose output.
29 *
30 #define DEBUG_UNION
31 #define DEBUG_PENALTY
32 #define DEBUG_PRESORT_GP
33 #define DEBUG_PRESORT_MAX
34 #define DEBUG_PRESORT_UNIONS
35 #define DEBUG_PRESORT_RESULT
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
36
37 #define DEBUG_PR_IN
5dcaf22 Implementation of operators & (intersection) and && (overlaps)
dim authored
38 #define DEBUG_PR_NORMALIZE
099f76d Operator <(prefix_range, prefix_range) and <=, > and >= to follow
dim authored
39 #define DEBUG_MAKE_VARLENA
cf4a835 Begin main presort() loop at OffsetNumberNext(FirstOffsetNumber); and…
dim authored
40 */
0fc1320 Importing prefix operator and opclass files
dim authored
41
42 PG_MODULE_MAGIC;
43
44 /**
7d2ac3d firsts attempts towards 8.3 compliance, using VARSIZE_ANY_EXHDR()
dim authored
45 * This code has only been tested with PostgreSQL 8.2 and 8.3
46 */
9ececbd Now using PG_VERSION_NUM
dim authored
47 #if PG_VERSION_NUM / 100 != 802 && PG_VERSION_NUM / 100 != 803
7d2ac3d firsts attempts towards 8.3 compliance, using VARSIZE_ANY_EXHDR()
dim authored
48 #error "Unknown or unsupported postgresql version"
49 #endif
50
51 /**
52 * Define our own varlena size macro depending on PGVER
53 */
9ececbd Now using PG_VERSION_NUM
dim authored
54 #if PG_VERSION_NUM / 100 == 802
fef1590 8.3 compat now ok, using VARDATA_ANY() and PG_GETARG_TEXT_PP()
dim authored
55 #define PREFIX_VARSIZE(x) (VARSIZE(x) - VARHDRSZ)
56 #define PREFIX_VARDATA(x) (VARDATA(x))
57 #define PREFIX_PG_GETARG_TEXT(x) (PG_GETARG_TEXT_P(x))
bc2f8f1 Attempts to debug the invalid memory alloc request size ERROR, which …
dim authored
58 #define PREFIX_SET_VARSIZE(p, s) (VARATT_SIZEP(p) = s)
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
59
7d2ac3d firsts attempts towards 8.3 compliance, using VARSIZE_ANY_EXHDR()
dim authored
60 #else
fef1590 8.3 compat now ok, using VARDATA_ANY() and PG_GETARG_TEXT_PP()
dim authored
61 #define PREFIX_VARSIZE(x) (VARSIZE_ANY_EXHDR(x))
62 #define PREFIX_VARDATA(x) (VARDATA_ANY(x))
63 #define PREFIX_PG_GETARG_TEXT(x) (PG_GETARG_TEXT_PP(x))
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
64 #define PREFIX_SET_VARSIZE(p, s) (SET_VARSIZE(p, s))
65 #endif
66
67 /**
68 * prefix_range datatype, varlena structure
69 */
70 typedef struct {
71 char first;
099f76d Operator <(prefix_range, prefix_range) and <=, > and >= to follow
dim authored
72 char last;
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
73 char prefix[1]; /* this is a varlena structure, data follows */
74 } prefix_range;
75
76 enum pr_delimiters_t {
77 PR_OPEN = '[',
78 PR_CLOSE = ']',
79 PR_SEP = '-'
80 } pr_delimiters;
81
82 /**
e2307bd prefix_range @> prefix(text) operator and its commutator
dim authored
83 * prefix_range input/output functions and operators
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
84 */
85 Datum prefix_range_in(PG_FUNCTION_ARGS);
86 Datum prefix_range_out(PG_FUNCTION_ARGS);
5dcaf22 Implementation of operators & (intersection) and && (overlaps)
dim authored
87 /*
88 Datum prefix_range_recv(PG_FUNCTION_ARGS);
89 Datum prefix_range_send(PG_FUNCTION_ARGS);
90 */
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
91 Datum prefix_range_cast_to_text(PG_FUNCTION_ARGS);
92 Datum prefix_range_cast_from_text(PG_FUNCTION_ARGS);
fb5a44a prefix_range_cmp() implementation
dim authored
93
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
94 Datum prefix_range_eq(PG_FUNCTION_ARGS);
95 Datum prefix_range_neq(PG_FUNCTION_ARGS);
099f76d Operator <(prefix_range, prefix_range) and <=, > and >= to follow
dim authored
96 Datum prefix_range_lt(PG_FUNCTION_ARGS);
97 Datum prefix_range_le(PG_FUNCTION_ARGS);
e7f1655 Operator >(prefix_range, prefix_range) and >=
dim authored
98 Datum prefix_range_gt(PG_FUNCTION_ARGS);
99 Datum prefix_range_ge(PG_FUNCTION_ARGS);
fb5a44a prefix_range_cmp() implementation
dim authored
100 Datum prefix_range_cmp(PG_FUNCTION_ARGS);
101
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
102 Datum prefix_range_overlaps(PG_FUNCTION_ARGS);
103 Datum prefix_range_contains(PG_FUNCTION_ARGS);
104 Datum prefix_range_contains_strict(PG_FUNCTION_ARGS);
105 Datum prefix_range_contained_by(PG_FUNCTION_ARGS);
106 Datum prefix_range_contained_by_strict(PG_FUNCTION_ARGS);
e2307bd prefix_range @> prefix(text) operator and its commutator
dim authored
107 Datum prefix_range_contains_prefix(PG_FUNCTION_ARGS);
108 Datum prefix_range_contained_by_prefix(PG_FUNCTION_ARGS);
9060f42 prefix_range unions, operator |
dim authored
109 Datum prefix_range_union(PG_FUNCTION_ARGS);
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
110 Datum prefix_range_inter(PG_FUNCTION_ARGS);
111
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
112 #define DatumGetPrefixRange(X) ((prefix_range *) PREFIX_VARDATA(DatumGetPointer(X)) )
113 #define PrefixRangeGetDatum(X) PointerGetDatum(make_varlena(X))
114 #define PG_GETARG_PREFIX_RANGE_P(n) DatumGetPrefixRange(PG_DETOAST_DATUM(PG_GETARG_DATUM(n)))
115 #define PG_RETURN_PREFIX_RANGE_P(x) return PrefixRangeGetDatum(x)
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
116
117 /**
e2307bd prefix_range @> prefix(text) operator and its commutator
dim authored
118 * Used by prefix_contains_internal and pr_contains_prefix.
119 *
120 * plen is the length of string p, qlen the length of string q, the
121 * caller are dealing with either text * or char * and its their
122 * responsabolity to use either strlen() or PREFIX_VARSIZE()
123 */
124 static inline
125 bool __prefix_contains(char *p, char *q, int plen, int qlen) {
126 if(qlen < plen )
127 return false;
128
129 return memcmp(p, q, plen) == 0;
130 }
131
9060f42 prefix_range unions, operator |
dim authored
132 static inline
133 char *__greater_prefix(char *a, char *b, int alen, int blen)
134 {
135 int i = 0;
136 char *result = NULL;
137
138 for(i=0; i<alen && i<blen && a[i] == b[i]; i++);
139
140 /* i is the last common char position in a, or 0 */
141 if( i == 0 ) {
142 /**
143 * return ""
144 */
145 result = (char *)palloc(sizeof(char));
146 }
147 else {
148 result = (char *)palloc((i+1) * sizeof(char));
149 memcpy(result, a, i);
150 }
151 result[i] = 0;
152
153 return result;
154 }
155
e2307bd prefix_range @> prefix(text) operator and its commutator
dim authored
156 /**
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
157 * First, the input reader. A prefix range will have to respect the
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
158 * following regular expression: .*([[].-.[]])?
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
159 *
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
160 * examples : 123[4-6], [1-3], 234, 01[] --- last one not covered by
161 * regexp.
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
162 */
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
163
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
164 static inline
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
165 prefix_range *build_pr(char *prefix) {
166 int s = strlen(prefix) + 1;
167 prefix_range *pr = palloc(sizeof(prefix_range) + s);
168 memcpy(pr->prefix, prefix, s);
169 pr->first = 0;
170 pr->last = 0;
171
172 #ifdef DEBUG_PR_IN
173 elog(NOTICE,
174 "build_pr: pr->prefix = '%s', pr->first = %d, pr->last = %d",
175 pr->prefix, pr->first, pr->last);
176 #endif
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
177
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
178 return pr;
179 }
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
180
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
181 static inline
5dcaf22 Implementation of operators & (intersection) and && (overlaps)
dim authored
182 prefix_range *pr_normalize(prefix_range *a) {
183 char tmpswap;
184 char *prefix;
185
186 prefix_range *pr = build_pr(a->prefix);
187 pr->first = a->first;
188 pr->last = a->last;
189
190 if( pr->first == pr->last ) {
191 int s = strlen(pr->prefix)+2;
192 prefix = (char *)palloc(s);
193 memcpy(prefix, pr->prefix, s-2);
194 prefix[s-2] = pr->first;
195 prefix[s-1] = 0;
196
197 #ifdef DEBUG_PR_NORMALIZE
198 elog(NOTICE, "prefix_range %s %s %s", str, pr->prefix, prefix);
199 #endif
200
201 pfree(pr);
202 pr = build_pr(prefix);
203 }
204 else if( pr->first > pr->last ) {
205 tmpswap = pr->first;
206 pr->first = pr->last;
207 pr->last = tmpswap;
208 }
209 return pr;
210 }
211
212 static inline
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
213 prefix_range *pr_from_str(char *str) {
214 prefix_range *pr = NULL;
215 char *prefix = (char *)palloc(strlen(str)+1);
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
216 char current = 0, previous = 0;
217 bool opened = false;
218 bool closed = false;
219 bool sawsep = false;
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
220 char *ptr, *prefix_ptr = prefix;
221
222 bzero(prefix, strlen(str)+1);
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
223
224 for(ptr=str; *ptr != 0; ptr++) {
225 previous = current;
226 current = *ptr;
227
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
228 if( !opened && current != PR_OPEN )
229 *prefix_ptr++ = current;
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
230
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
231 #ifdef DEBUG_PR_IN
232 elog(NOTICE, "prefix_range previous='%c' current='%c' prefix='%s'",
233 (previous?previous:' '), current, prefix);
234 #endif
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
235
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
236 switch( current ) {
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
237
238 case PR_OPEN:
239 if( opened ) {
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
240 #ifdef DEBUG_PR_IN
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
241 elog(ERROR,
242 "prefix_range %s contains several %c", str, PR_OPEN);
243 #endif
244 return NULL;
245 }
246 opened = true;
247
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
248 pr = build_pr(prefix);
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
249 break;
250
251 case PR_SEP:
252 if( opened ) {
253 if( closed ) {
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
254 #ifdef DEBUG_PR_IN
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
255 elog(ERROR,
256 "prefix_range %s contains trailing character", str);
7d2ac3d firsts attempts towards 8.3 compliance, using VARSIZE_ANY_EXHDR()
dim authored
257 #endif
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
258 return NULL;
259 }
260 sawsep = true;
261
262 if( previous == PR_OPEN ) {
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
263 #ifdef DEBUG_PR_IN
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
264 elog(ERROR,
265 "prefix_range %s has separator following range opening, without data", str);
266 #endif
267 return NULL;
268 }
269
270 pr->first = previous;
271 }
272 break;
273
274 case PR_CLOSE:
275 if( !opened ) {
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
276 #ifdef DEBUG_PR_IN
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
277 elog(ERROR,
278 "prefix_range %s closes a range which is not opened ", str);
279 #endif
280 return NULL;
281 }
282
283 if( closed ) {
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
284 #ifdef DEBUG_PR_IN
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
285 elog(ERROR,
286 "prefix_range %s contains several %c", str, PR_CLOSE);
287 #endif
288 return NULL;
289 }
290 closed = true;
291
292 if( sawsep ) {
293 if( previous == PR_SEP ) {
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
294 #ifdef DEBUG_PR_IN
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
295 elog(ERROR,
296 "prefix_range %s has a closed range without last bound", str);
297 #endif
298 return NULL;
299 }
300 pr->last = previous;
301 }
302 else {
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
303 if( previous != PR_OPEN ) {
304 #ifdef DEBUG_PR_IN
305 elog(ERROR,
306 "prefix_range %s has a closing range without separator", str);
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
307 #endif
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
308 return NULL;
309 }
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
310 }
311 break;
312
313 default:
314 if( closed ) {
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
315 #ifdef DEBUG_PR_IN
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
316 elog(ERROR,
317 "prefix_range %s contains trailing characters", str);
318 #endif
319 return NULL;
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
320 }
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
321 break;
322 }
323 }
324
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
325 if( ! opened ) {
326 pr = build_pr(prefix);
327 }
328
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
329 if( opened && !closed ) {
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
330 #ifdef DEBUG_PR_IN
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
331 elog(ERROR, "prefix_range %s opens a range but does not close it", str);
332 #endif
333 return NULL;
334 }
335
5dcaf22 Implementation of operators & (intersection) and && (overlaps)
dim authored
336 pr = pr_normalize(pr);
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
337
338 #ifdef DEBUG_PR_IN
339 if( pr != NULL ) {
340 if( pr->first && pr->last )
341 elog(NOTICE,
342 "prefix_range %s: prefix = '%s', first = '%c', last = '%c'",
343 str, pr->prefix, pr->first, pr->last);
344 else
345 elog(NOTICE,
346 "prefix_range %s: prefix = '%s', no first nor last",
347 str, pr->prefix);
348 }
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
349 #endif
350
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
351 return pr;
352 }
353
354 static inline
355 struct varlena *make_varlena(prefix_range *pr) {
356 struct varlena *vdat;
357 int size;
358
359 if (pr != NULL) {
bc2f8f1 Attempts to debug the invalid memory alloc request size ERROR, which …
dim authored
360 size = sizeof(prefix_range) + ((strlen(pr->prefix)+1)*sizeof(char)) + VARHDRSZ;
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
361 vdat = palloc(size);
362 PREFIX_SET_VARSIZE(vdat, size);
bc2f8f1 Attempts to debug the invalid memory alloc request size ERROR, which …
dim authored
363 memcpy(VARDATA(vdat), pr, (size - VARHDRSZ));
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
364
099f76d Operator <(prefix_range, prefix_range) and <=, > and >= to follow
dim authored
365 #ifdef DEBUG_MAKE_VARLENA
bc2f8f1 Attempts to debug the invalid memory alloc request size ERROR, which …
dim authored
366 elog(NOTICE, "make varlena: size=%d varsize=%d compressed=%c external=%c %s[%c-%c] %s[%c-%c]",
367 size,
368 PREFIX_VARSIZE(vdat),
369 (VARATT_IS_COMPRESSED(vdat) ? 't' : 'f'),
370 (VARATT_IS_EXTERNAL(vdat) ? 't' : 'f'),
f98ae67 Use union instead of greater_prefix in gpr_picksplit()
dim authored
371 pr->prefix,
372 (pr->first != 0 ? pr->first : ' '),
373 (pr->last != 0 ? pr->last : ' '),
099f76d Operator <(prefix_range, prefix_range) and <=, > and >= to follow
dim authored
374 ((prefix_range *)VARDATA(vdat))->prefix,
f98ae67 Use union instead of greater_prefix in gpr_picksplit()
dim authored
375 (((prefix_range *)VARDATA(vdat))->first ? ((prefix_range *)VARDATA(vdat))->first : ' '),
376 (((prefix_range *)VARDATA(vdat))->last ? ((prefix_range *)VARDATA(vdat))->last : ' '));
099f76d Operator <(prefix_range, prefix_range) and <=, > and >= to follow
dim authored
377 #endif
378
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
379 return vdat;
380 }
381 return NULL;
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
382 }
383
2425c39 Implementation of some more operators for prefix_range: =, <>, <<, <<…
dim authored
384 static inline
385 bool pr_eq(prefix_range *a, prefix_range *b) {
386 int sa = strlen(a->prefix);
387 int sb = strlen(b->prefix);
388
389 return sa == sb
390 && memcmp(a->prefix, b->prefix, sa) == 0
391 && a->first == b->first
392 && a->last == b->last;
393 }
394
099f76d Operator <(prefix_range, prefix_range) and <=, > and >= to follow
dim authored
395 static inline
396 bool pr_lt(prefix_range *a, prefix_range *b, bool eqval) {
397 int cmp = 0;
398 int alen = strlen(a->prefix);
399 int blen = strlen(b->prefix);
400 int mlen = alen;
401 char *p = a->prefix;
402 char *q = b->prefix;
403
404 if( alen == blen ) {
405 cmp = memcmp(p, q, alen);
406
407 if( cmp < 0 )
408 return true;
409
410 else if( cmp == 0 ) {
411 if( a->first == 0 ) {
412 if( b->first == 0 )
413 return eqval;
414 return true;
415 }
416 else
417 return (eqval ? a->first <= b->first : a->first < b->first);
418 }
419 else
420 return false;
421 }
422 if( mlen > blen )
423 mlen = blen;
424
425 if( alen == 0 && a->first != 0 ) {
426 return (eqval ? (a->first <= q[0]) : (a->first < q[0]));
427 }
428 else if( blen == 0 && b->first != 0 ) {
429 return (eqval ? (p[0] <= b->first) : (p[0] < b->first));
430 }
431 else
432 return (eqval ? memcmp(p, q, mlen) <= 0 : memcmp(p, q, mlen) < 0);
433 }
434
e7f1655 Operator >(prefix_range, prefix_range) and >=
dim authored
435 static inline
436 bool pr_gt(prefix_range *a, prefix_range *b, bool eqval) {
437 int cmp = 0;
438 int alen = strlen(a->prefix);
439 int blen = strlen(b->prefix);
440 int mlen = alen;
441 char *p = a->prefix;
442 char *q = b->prefix;
443
444 if( alen == blen ) {
445 cmp = memcmp(p, q, alen);
446
447 if( cmp > 0 )
448 return true;
449
450 else if( cmp == 0 ) {
451 if( a->last == 0 ) {
452 if( b->last == 0 )
453 return eqval;
454 return false;
455 }
456 else
457 return (eqval ? a->last >= b->last : a->last > b->last);
458 }
459 else
460 return false;
461 }
462 if( mlen > blen )
463 mlen = blen;
464
465 if( alen == 0 && a->last != 0 ) {
466 return (eqval ? (a->last >= q[0]) : (a->last > q[0]));
467 }
468 else if( blen == 0 && b->first != 0 ) {
469 return (eqval ? (p[0] >= b->last) : (p[0] > b->last));
470 }
471 else
472 return (eqval ? memcmp(p, q, mlen) >= 0 : memcmp(p, q, mlen) > 0);
473 }
474
2425c39 Implementation of some more operators for prefix_range: =, <>, <<, <<…
dim authored
475 static inline
476 bool pr_contains(prefix_range *left, prefix_range *right, bool eqval) {
477 int sl;
478 int sr;
479 bool left_prefixes_right;
480
481 if( pr_eq(left, right) )
482 return eqval;
483
484 sl = strlen(left->prefix);
485 sr = strlen(right->prefix);
486
487 if( sr < sl )
488 return false;
489
490 left_prefixes_right = memcmp(left->prefix, right->prefix, sl) == 0;
491
492 if( left_prefixes_right ) {
493 if( sl == sr )
494 return left->first == 0 ||
495 (left->first <= right->first && left->last >= right->last);
496
497 return left->first == 0 ||
498 (left->first <= right->prefix[sl] && right->prefix[sl] <= left->last);
499 }
500 return false;
501 }
502
503 /**
e2307bd prefix_range @> prefix(text) operator and its commutator
dim authored
504 * does a given prefix_range includes a given prefix?
505 */
506 static inline
507 bool pr_contains_prefix(prefix_range *pr, text *query, bool eqval) {
508 int plen = strlen(pr->prefix);
509 int qlen = PREFIX_VARSIZE(query);
510 char *p = pr->prefix;
511 char *q = (char *)PREFIX_VARDATA(query);
512
513 if( __prefix_contains(p, q, plen, qlen) ) {
514 if( pr->first == 0 || qlen == plen ) {
515 return eqval;
516 }
517
518 /**
519 * __prefix_contains() is true means qlen >= plen, and previous
520 * test ensures qlen != plen, we hence assume qlen > plen.
521 */
522 Assert(qlen > plen);
523 return pr-> first <= q[plen] && q[plen] <= pr->last;
524 }
525 return false;
526 }
527
9060f42 prefix_range unions, operator |
dim authored
528 static inline
529 prefix_range *pr_union(prefix_range *a, prefix_range *b) {
530 prefix_range *res = NULL;
531 int alen = strlen(a->prefix);
532 int blen = strlen(b->prefix);
533 char *gp = NULL;
534 int gplen;
535 char min, max;
536
e728818 fixes for prefix_range unions when prefixes are empty
dim authored
537 if( 0 == alen && 0 == blen ) {
9060f42 prefix_range unions, operator |
dim authored
538 res = build_pr("");
e728818 fixes for prefix_range unions when prefixes are empty
dim authored
539 res->first = a->first <= b->first ? a->first : b->first;
540 res->last = a->last >= b->last ? a->last : b->last;
5dcaf22 Implementation of operators & (intersection) and && (overlaps)
dim authored
541 return pr_normalize(res);
9060f42 prefix_range unions, operator |
dim authored
542 }
543
544 gp = __greater_prefix(a->prefix, b->prefix, alen, blen);
545 gplen = strlen(gp);
546
547 if( gplen == 0 ) {
548 res = build_pr("");
e728818 fixes for prefix_range unions when prefixes are empty
dim authored
549 if( alen > 0 && blen > 0 ) {
550 res->first = a->prefix[0];
551 res->last = b->prefix[0];
552 }
553 else if( alen == 0 ) {
554 res->first = a->first <= b->prefix[0] ? a->first : b->prefix[0];
555 res->last = a->last >= b->prefix[0] ? a->last : b->prefix[0];
556 }
557 else if( blen == 0 ) {
558 res->first = b->first <= a->prefix[0] ? b->first : a->prefix[0];
559 res->last = b->last >= a->prefix[0] ? b->last : a->prefix[0];
560 }
9060f42 prefix_range unions, operator |
dim authored
561 }
562 else {
563 res = build_pr(gp);
564
565 if( gplen == alen && alen == blen ) {
566 res->first = a->first <= b->first ? a->first : b->first;
567 res->last = a->last >= b->last ? a->last : b->last;
568 }
569 else if( gplen == alen ) {
570 Assert(alen < blen);
571 res->first = a->first <= b->prefix[alen] ? a->first : b->prefix[alen];
572 res->last = a->last >= b->prefix[alen] ? a->last : b->prefix[alen];
573 }
574 else if( gplen == blen ) {
575 Assert(blen < alen);
576 res->first = b->first <= a->prefix[blen] ? b->first : a->prefix[blen];
577 res->last = b->last >= a->prefix[blen] ? b->last : a->prefix[blen];
578 }
579 else {
580 Assert(gplen < alen && gplen < blen);
581 min = a->prefix[gplen];
582 max = b->prefix[gplen];
583
584 if( min > max ) {
585 min = b->prefix[gplen];
586 max = a->prefix[gplen];
587 }
588 res->first = min;
589 res->last = max;
590 }
591 }
5dcaf22 Implementation of operators & (intersection) and && (overlaps)
dim authored
592 return pr_normalize(res);
9060f42 prefix_range unions, operator |
dim authored
593 }
594
595 static inline
596 prefix_range *pr_inter(prefix_range *a, prefix_range *b) {
597 prefix_range *res = NULL;
598 int alen = strlen(a->prefix);
599 int blen = strlen(b->prefix);
5dcaf22 Implementation of operators & (intersection) and && (overlaps)
dim authored
600 char *gp = NULL;
601 int gplen;
9060f42 prefix_range unions, operator |
dim authored
602
e728818 fixes for prefix_range unions when prefixes are empty
dim authored
603 if( 0 == alen && 0 == blen ) {
5dcaf22 Implementation of operators & (intersection) and && (overlaps)
dim authored
604 res = build_pr("");
605 res->first = a->first > b->first ? a->first : b->first;
606 res->last = a->last < b->last ? a->last : b->last;
607 return pr_normalize(res);
e728818 fixes for prefix_range unions when prefixes are empty
dim authored
608 }
609
5dcaf22 Implementation of operators & (intersection) and && (overlaps)
dim authored
610 gp = __greater_prefix(a->prefix, b->prefix, alen, blen);
611 gplen = strlen(gp);
612
613 if( gplen != alen && gplen != blen ) {
614 return build_pr("");
e728818 fixes for prefix_range unions when prefixes are empty
dim authored
615 }
5dcaf22 Implementation of operators & (intersection) and && (overlaps)
dim authored
616
617 if( gplen == alen && 0 == alen ) {
618 if( a->first <= b->prefix[0] && b->prefix[0] <= a->last ) {
619 res = build_pr(b->prefix);
620 res->first = b->first;
621 res->last = b->last;
622 }
623 else
624 res = build_pr("");
625 }
626 else if( gplen == blen && 0 == blen ) {
627 if( b->first <= a->prefix[0] && a->prefix[0] <= b->last ) {
628 res = build_pr(a->prefix);
629 res->first = a->first;
630 res->last = a->last;
631 }
632 else
633 res = build_pr("");
634 }
635 else if( gplen == alen && alen == blen ) {
636 res = build_pr(gp);
637 res->first = a->first > b->first ? a->first : b->first;
638 res->last = a->last < b->last ? a->last : b->last;
639 }
640 else if( gplen == alen ) {
641 Assert(gplen < blen);
642 res = build_pr(b->prefix);
643 res->first = b->first;
644 res->last = b->last;
645 }
646 else if( gplen == blen ) {
647 Assert(gplen < alen);
648 res = build_pr(a->prefix);
649 res->first = a->first;
650 res->last = a->last;
651 }
652
653 return pr_normalize(res);
9060f42 prefix_range unions, operator |
dim authored
654 }
655
656 /**
657 * true if ranges have at least one common element
658 */
659 static inline
5dcaf22 Implementation of operators & (intersection) and && (overlaps)
dim authored
660 bool pr_overlaps(prefix_range *a, prefix_range *b) {
661 prefix_range *inter = pr_inter(a, b);
9060f42 prefix_range unions, operator |
dim authored
662
5dcaf22 Implementation of operators & (intersection) and && (overlaps)
dim authored
663 return strlen(inter->prefix) > 0 || (inter->first != 0 && inter->last != 0);
664 }
9060f42 prefix_range unions, operator |
dim authored
665
e2307bd prefix_range @> prefix(text) operator and its commutator
dim authored
666
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
667 PG_FUNCTION_INFO_V1(prefix_range_in);
668 Datum
669 prefix_range_in(PG_FUNCTION_ARGS)
670 {
671 char *str = PG_GETARG_CSTRING(0);
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
672 prefix_range *pr = pr_from_str(str);
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
673
674 if (pr != NULL) {
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
675 PG_RETURN_PREFIX_RANGE_P(pr);
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
676 }
677
678 ereport(ERROR,
679 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
680 errmsg("invalid prefix_range value: \"%s\"", str)));
681 PG_RETURN_NULL();
682 }
683
684
685 PG_FUNCTION_INFO_V1(prefix_range_out);
686 Datum
687 prefix_range_out(PG_FUNCTION_ARGS)
688 {
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
689 prefix_range *pr = PG_GETARG_PREFIX_RANGE_P(0);
690 char *out = NULL;
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
691
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
692 if( pr->first ) {
693 out = (char *)palloc((strlen(pr->prefix)+6) * sizeof(char));
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
694 sprintf(out, "%s[%c-%c]", pr->prefix, pr->first, pr->last);
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
695 }
696 else {
697 out = (char *)palloc((strlen(pr->prefix)+3) * sizeof(char));
698 sprintf(out, "%s[]", pr->prefix);
699 }
700 PG_RETURN_CSTRING(out);
701 }
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
702
a4da0ee prefix_range datatype now has working in/out functions and text casts
dim authored
703 PG_FUNCTION_INFO_V1(prefix_range_cast_from_text);
704 Datum
705 prefix_range_cast_from_text(PG_FUNCTION_ARGS)
706 {
707 text *txt = PG_GETARG_TEXT_P(0);
708 Datum cstring = DirectFunctionCall1(textout, PointerGetDatum(txt));
709 return DirectFunctionCall1(prefix_range_in, cstring);
710 }
711
712 PG_FUNCTION_INFO_V1(prefix_range_cast_to_text);
713 Datum
714 prefix_range_cast_to_text(PG_FUNCTION_ARGS)
715 {
716 prefix_range *pr = PG_GETARG_PREFIX_RANGE_P(0);
717 Datum cstring;
718 text *out;
719
720 if (pr != NULL) {
721 cstring = DirectFunctionCall1(prefix_range_out, PrefixRangeGetDatum(pr));
722 out = (text *)DirectFunctionCall1(textin, cstring);
723
724 PG_RETURN_TEXT_P(out);
725 }
726 PG_RETURN_NULL();
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
727 }
7d2ac3d firsts attempts towards 8.3 compliance, using VARSIZE_ANY_EXHDR()
dim authored
728
2425c39 Implementation of some more operators for prefix_range: =, <>, <<, <<…
dim authored
729 PG_FUNCTION_INFO_V1(prefix_range_eq);
730 Datum
731 prefix_range_eq(PG_FUNCTION_ARGS)
732 {
733 PG_RETURN_BOOL( pr_eq(PG_GETARG_PREFIX_RANGE_P(0),
734 PG_GETARG_PREFIX_RANGE_P(1)) );
735 }
736
737 PG_FUNCTION_INFO_V1(prefix_range_neq);
738 Datum
739 prefix_range_neq(PG_FUNCTION_ARGS)
740 {
741 PG_RETURN_BOOL( ! pr_eq(PG_GETARG_PREFIX_RANGE_P(0),
742 PG_GETARG_PREFIX_RANGE_P(1)) );
743 }
744
099f76d Operator <(prefix_range, prefix_range) and <=, > and >= to follow
dim authored
745 PG_FUNCTION_INFO_V1(prefix_range_lt);
746 Datum
747 prefix_range_lt(PG_FUNCTION_ARGS)
748 {
e7f1655 Operator >(prefix_range, prefix_range) and >=
dim authored
749 PG_RETURN_BOOL( pr_lt(PG_GETARG_PREFIX_RANGE_P(0),
099f76d Operator <(prefix_range, prefix_range) and <=, > and >= to follow
dim authored
750 PG_GETARG_PREFIX_RANGE_P(1),
751 FALSE) );
752 }
753
754 PG_FUNCTION_INFO_V1(prefix_range_le);
755 Datum
756 prefix_range_le(PG_FUNCTION_ARGS)
757 {
e7f1655 Operator >(prefix_range, prefix_range) and >=
dim authored
758 PG_RETURN_BOOL( pr_lt(PG_GETARG_PREFIX_RANGE_P(0),
099f76d Operator <(prefix_range, prefix_range) and <=, > and >= to follow
dim authored
759 PG_GETARG_PREFIX_RANGE_P(1),
760 TRUE) );
761 }
762
e7f1655 Operator >(prefix_range, prefix_range) and >=
dim authored
763 PG_FUNCTION_INFO_V1(prefix_range_gt);
764 Datum
765 prefix_range_gt(PG_FUNCTION_ARGS)
766 {
767 PG_RETURN_BOOL( pr_gt(PG_GETARG_PREFIX_RANGE_P(0),
768 PG_GETARG_PREFIX_RANGE_P(1),
769 FALSE) );
770 }
771
772 PG_FUNCTION_INFO_V1(prefix_range_ge);
773 Datum
774 prefix_range_ge(PG_FUNCTION_ARGS)
775 {
776 PG_RETURN_BOOL( pr_gt(PG_GETARG_PREFIX_RANGE_P(0),
777 PG_GETARG_PREFIX_RANGE_P(1),
778 TRUE) );
779 }
099f76d Operator <(prefix_range, prefix_range) and <=, > and >= to follow
dim authored
780
fb5a44a prefix_range_cmp() implementation
dim authored
781 PG_FUNCTION_INFO_V1(prefix_range_cmp);
782 Datum
783 prefix_range_cmp(PG_FUNCTION_ARGS)
784 {
785 prefix_range *a = PG_GETARG_PREFIX_RANGE_P(0);
786 prefix_range *b = PG_GETARG_PREFIX_RANGE_P(1);
787
788 if( pr_eq(a, b) )
789 PG_RETURN_INT32(0);
790
791 if( pr_lt(a, b, false) )
792 PG_RETURN_INT32(-1);
793
794 PG_RETURN_INT32(1);
795 }
796
2425c39 Implementation of some more operators for prefix_range: =, <>, <<, <<…
dim authored
797 PG_FUNCTION_INFO_V1(prefix_range_overlaps);
798 Datum
799 prefix_range_overlaps(PG_FUNCTION_ARGS)
800 {
801 PG_RETURN_BOOL( pr_overlaps(PG_GETARG_PREFIX_RANGE_P(0),
802 PG_GETARG_PREFIX_RANGE_P(1)) );
803 }
804
805 PG_FUNCTION_INFO_V1(prefix_range_contains);
806 Datum
807 prefix_range_contains(PG_FUNCTION_ARGS)
808 {
809 PG_RETURN_BOOL( pr_contains(PG_GETARG_PREFIX_RANGE_P(0),
810 PG_GETARG_PREFIX_RANGE_P(1),
811 TRUE ));
812 }
813
814 PG_FUNCTION_INFO_V1(prefix_range_contains_strict);
815 Datum
816 prefix_range_contains_strict(PG_FUNCTION_ARGS)
817 {
818 PG_RETURN_BOOL( pr_contains(PG_GETARG_PREFIX_RANGE_P(0),
819 PG_GETARG_PREFIX_RANGE_P(1),
820 FALSE ));
821 }
822
823 PG_FUNCTION_INFO_V1(prefix_range_contained_by);
824 Datum
825 prefix_range_contained_by(PG_FUNCTION_ARGS)
826 {
827 PG_RETURN_BOOL( pr_contains(PG_GETARG_PREFIX_RANGE_P(1),
828 PG_GETARG_PREFIX_RANGE_P(0),
829 TRUE ));
830 }
831
832 PG_FUNCTION_INFO_V1(prefix_range_contained_by_strict);
833 Datum
834 prefix_range_contained_by_strict(PG_FUNCTION_ARGS)
835 {
836 PG_RETURN_BOOL( pr_contains(PG_GETARG_PREFIX_RANGE_P(1),
837 PG_GETARG_PREFIX_RANGE_P(0),
838 FALSE ));
839 }
840
e2307bd prefix_range @> prefix(text) operator and its commutator
dim authored
841 PG_FUNCTION_INFO_V1(prefix_range_contains_prefix);
842 Datum
843 prefix_range_contains_prefix(PG_FUNCTION_ARGS)
844 {
845 PG_RETURN_BOOL( pr_contains_prefix(PG_GETARG_PREFIX_RANGE_P(0),
846 PG_GETARG_TEXT_P(1),
847 TRUE ));
848 }
849
850 PG_FUNCTION_INFO_V1(prefix_range_contained_by_prefix);
851 Datum
852 prefix_range_contained_by_prefix(PG_FUNCTION_ARGS)
853 {
854 PG_RETURN_BOOL( pr_contains_prefix(PG_GETARG_PREFIX_RANGE_P(1),
855 PG_GETARG_TEXT_P(0),
856 TRUE ));
857 }
858
9060f42 prefix_range unions, operator |
dim authored
859 PG_FUNCTION_INFO_V1(prefix_range_union);
860 Datum
861 prefix_range_union(PG_FUNCTION_ARGS)
862 {
863 PG_RETURN_PREFIX_RANGE_P( pr_union(PG_GETARG_PREFIX_RANGE_P(0),
864 PG_GETARG_PREFIX_RANGE_P(1)) );
865 }
866
5dcaf22 Implementation of operators & (intersection) and && (overlaps)
dim authored
867 PG_FUNCTION_INFO_V1(prefix_range_inter);
868 Datum
869 prefix_range_inter(PG_FUNCTION_ARGS)
870 {
871 PG_RETURN_PREFIX_RANGE_P( pr_inter(PG_GETARG_PREFIX_RANGE_P(0),
872 PG_GETARG_PREFIX_RANGE_P(1)) );
873 }
874
528746c copy/paste-o broken implementation of gist_prefix_range_ops, operator…
dim authored
875 /**
876 * GiST support methods
98953de Respect GiST calling conventions for gpr_penalty()
dim authored
877 *
878 * pr_penalty allows SQL level penalty code testing.
528746c copy/paste-o broken implementation of gist_prefix_range_ops, operator…
dim authored
879 */
880 Datum gpr_consistent(PG_FUNCTION_ARGS);
881 Datum gpr_compress(PG_FUNCTION_ARGS);
882 Datum gpr_decompress(PG_FUNCTION_ARGS);
883 Datum gpr_penalty(PG_FUNCTION_ARGS);
884 Datum gpr_picksplit(PG_FUNCTION_ARGS);
885 Datum gpr_union(PG_FUNCTION_ARGS);
886 Datum gpr_same(PG_FUNCTION_ARGS);
98953de Respect GiST calling conventions for gpr_penalty()
dim authored
887 Datum pr_penalty(PG_FUNCTION_ARGS);
528746c copy/paste-o broken implementation of gist_prefix_range_ops, operator…
dim authored
888
889 PG_FUNCTION_INFO_V1(gpr_consistent);
890 Datum
891 gpr_consistent(PG_FUNCTION_ARGS)
892 {
893 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
894 prefix_range *query = PG_GETARG_PREFIX_RANGE_P(1);
895 StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
896 prefix_range *key = (prefix_range *) DatumGetPrefixRange(entry->key);
897 bool retval;
898
899 /**
900 * We only have 1 Strategy (operator @>)
901 * and we want to avoid compiler complaints that we do not use it.
902 */
903 Assert(strategy == 1);
904 (void) strategy;
905 retval = pr_contains(key, query, true);
906
907 PG_RETURN_BOOL(retval);
908 }
909
910 /*
911 * GiST Compress and Decompress methods for prefix_range
912 * do not do anything.
913 */
914 PG_FUNCTION_INFO_V1(gpr_compress);
915 Datum
916 gpr_compress(PG_FUNCTION_ARGS)
917 {
918 PG_RETURN_POINTER(PG_GETARG_POINTER(0));
919 }
920
921 PG_FUNCTION_INFO_V1(gpr_decompress);
922 Datum
923 gpr_decompress(PG_FUNCTION_ARGS)
924 {
925 PG_RETURN_POINTER(PG_GETARG_POINTER(0));
926 }
927
928 static inline
929 float __pr_penalty(prefix_range *orig, prefix_range *new)
930 {
931 float penalty;
932 char *gp;
933 int nlen, olen, gplen, dist = 0;
1b22c3e fix gpr_penalty implementation, having it consider '[a-b]' kind of pr…
dim authored
934 char tmp;
528746c copy/paste-o broken implementation of gist_prefix_range_ops, operator…
dim authored
935
98f1e68 penalty fix, some more debug Assert() tied to test data which is nume…
dim authored
936 if( orig->prefix[0] != 0 ) {
4adc1f1 refine __pr_penalty() DEBUG, some more docs
dim authored
937 /**
938 * The prefix main test case deals with phone number data, hence
939 * containing only numbers...
940 */
941 if( orig->prefix[0] < '0' || orig->prefix[0] > '9' )
98f1e68 penalty fix, some more debug Assert() tied to test data which is nume…
dim authored
942 #ifdef DEBUG
4adc1f1 refine __pr_penalty() DEBUG, some more docs
dim authored
943 elog(NOTICE, "__pr_penalty(%s, %s) orig->first=%d orig->last=%d ",
944 DatumGetCString(DirectFunctionCall1(prefix_range_out,PrefixRangeGetDatum(orig))),
945 DatumGetCString(DirectFunctionCall1(prefix_range_out,PrefixRangeGetDatum(new))),
946 orig->first, orig->last);
98f1e68 penalty fix, some more debug Assert() tied to test data which is nume…
dim authored
947 #endif
948 Assert(orig->prefix[0] >= '0' && orig->prefix[0] <= '9');
949 }
950
528746c copy/paste-o broken implementation of gist_prefix_range_ops, operator…
dim authored
951 olen = strlen(orig->prefix);
952 nlen = strlen(new->prefix);
953 gp = __greater_prefix(orig->prefix, new->prefix, olen, nlen);
954 gplen = strlen(gp);
955
1b22c3e fix gpr_penalty implementation, having it consider '[a-b]' kind of pr…
dim authored
956 dist = 1;
957
958 if( 0 == olen && 0 == nlen ) {
959 if( orig->last >= new->first )
960 dist = 0;
961 else
962 dist = new->first - orig->last;
963 }
964 else if( 0 == olen ) {
965 /**
966 * penalty('[a-b]', 'xyz');
967 */
968 if( orig->first != 0 ) {
969 tmp = new->prefix[0];
528746c copy/paste-o broken implementation of gist_prefix_range_ops, operator…
dim authored
970
9f1a210 Better version of gpr_penalty()
dim authored
971 if( orig->first <= tmp && tmp <= orig->last ) {
972 gplen = 1;
973
974 dist = 1 + (int)tmp - (int)orig->first;
975 if( (1 + (int)orig->last - (int)tmp) < dist )
976 dist = 1 + (int)orig->last - (int)tmp;
977 }
1b22c3e fix gpr_penalty implementation, having it consider '[a-b]' kind of pr…
dim authored
978 else
979 dist = (orig->first > tmp ? orig->first - tmp : tmp - orig->last );
980 }
981 }
982 else if( 0 == nlen ) {
983 /**
984 * penalty('abc', '[x-y]');
985 */
986 if( new->first != 0 ) {
987 tmp = orig->prefix[0];
988
9f1a210 Better version of gpr_penalty()
dim authored
989 if( new->first <= tmp && tmp <= new->last ) {
990 gplen = 1;
991
992 dist = 1 + (int)tmp - (int)new->first;
993 if( (1 + (int)new->last - (int)tmp) < dist )
994 dist = 1 + (int)new->last - (int)tmp;
995 }
1b22c3e fix gpr_penalty implementation, having it consider '[a-b]' kind of pr…
dim authored
996 else
997 dist = (new->first > tmp ? new->first - tmp : tmp - new->last );
998 }
999 }
1000 else {
9f1a210 Better version of gpr_penalty()
dim authored
1001 /**
1002 * General case
1003 */
1004
1005 if( gplen > 0 ) {
1006 if( olen > gplen && nlen == gplen && new->first != 0 ) {
1007 /**
1008 * gpr_penalty('abc[f-l]', 'ab[x-y]')
1009 */
1010 if( new->first <= orig->prefix[gplen]
1011 && orig->prefix[gplen] <= new->last ) {
1012
98f1e68 penalty fix, some more debug Assert() tied to test data which is nume…
dim authored
1013 dist = 1 + (int)orig->prefix[gplen] - (int)new->first;
9f1a210 Better version of gpr_penalty()
dim authored
1014 if( (1 + (int)new->last - (int)orig->prefix[gplen]) < dist )
1015 dist = 1 + (int)new->last - (int)orig->prefix[gplen];
98f1e68 penalty fix, some more debug Assert() tied to test data which is nume…
dim authored
1016
1017 gplen += 1;
9f1a210 Better version of gpr_penalty()
dim authored
1018 }
1019 else {
1020 dist += 1;
1021 }
1022 }
1023 else if( nlen > gplen && olen == gplen && orig->first != 0 ) {
1024 /**
1025 * gpr_penalty('ab[f-l]', 'abc[x-y]')
1026 */
1027 if( orig->first <= new->prefix[gplen]
1028 && new->prefix[gplen] <= orig->last ) {
1029
1030 dist = 1 + (int)new->prefix[gplen] - (int)orig->first;
1031 if( (1 + (int)orig->last - (int)new->prefix[gplen]) < dist )
1032 dist = 1 + (int)orig->last - (int)new->prefix[gplen];
98f1e68 penalty fix, some more debug Assert() tied to test data which is nume…
dim authored
1033
1034 gplen += 1;
9f1a210 Better version of gpr_penalty()
dim authored
1035 }
1036 else {
1037 dist += 1;
1038 }
1039 }
1b22c3e fix gpr_penalty implementation, having it consider '[a-b]' kind of pr…
dim authored
1040 }
9f1a210 Better version of gpr_penalty()
dim authored
1041 /**
1042 * penalty('abc[f-l]', 'xyz[g-m]'), nothing common
1043 * dist = 1, gplen = 0, penalty = 1
1044 */
528746c copy/paste-o broken implementation of gist_prefix_range_ops, operator…
dim authored
1045 }
1046 penalty = (((float)dist) / powf(256, gplen));
1047
1048 #ifdef DEBUG_PENALTY
1049 elog(NOTICE, "__pr_penalty(%s, %s) == %d/(256^%d) == %g",
1050 DatumGetCString(DirectFunctionCall1(prefix_range_out,PrefixRangeGetDatum(orig))),
1051 DatumGetCString(DirectFunctionCall1(prefix_range_out,PrefixRangeGetDatum(new))),
1052 dist, gplen, penalty);
1053 #endif
1054
1055 return penalty;
1056 }
1057
1058 PG_FUNCTION_INFO_V1(gpr_penalty);
1059 Datum
1060 gpr_penalty(PG_FUNCTION_ARGS)
1061 {
98953de Respect GiST calling conventions for gpr_penalty()
dim authored
1062 GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
1063 GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
1064 float *penalty = (float *) PG_GETARG_POINTER(2);
1065
1066 prefix_range *orig = DatumGetPrefixRange(origentry->key);
1067 prefix_range *new = DatumGetPrefixRange(newentry->key);
1068
1069 *penalty = __pr_penalty(orig, new);
1070 PG_RETURN_POINTER(penalty);
1071 }
1072
1073 PG_FUNCTION_INFO_V1(pr_penalty);
1074 Datum
1075 pr_penalty(PG_FUNCTION_ARGS)
1076 {
528746c copy/paste-o broken implementation of gist_prefix_range_ops, operator…
dim authored
1077 float penalty = __pr_penalty(PG_GETARG_PREFIX_RANGE_P(0),
1078 PG_GETARG_PREFIX_RANGE_P(1));
1079 PG_RETURN_FLOAT4(penalty);
1080 }
1081
1082 PG_FUNCTION_INFO_V1(gpr_picksplit);
1083 Datum
1084 gpr_picksplit(PG_FUNCTION_ARGS)
1085 {
1086 GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
1087 OffsetNumber maxoff = entryvec->n - 1;
1088 GISTENTRY *ent = entryvec->vector;
1089 GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
1090
1091 int nbytes;
1092 OffsetNumber offl, offr;
1093 OffsetNumber *listL;
1094 OffsetNumber *listR;
f98ae67 Use union instead of greater_prefix in gpr_picksplit()
dim authored
1095 prefix_range *curl, *curr, *tmp_union;
528746c copy/paste-o broken implementation of gist_prefix_range_ops, operator…
dim authored
1096 prefix_range *unionL;
1097 prefix_range *unionR;
1098
1099 /**
1100 * Keeping track of penalties to insert into ListL or ListR, for
1101 * both the leftmost and the rightmost element of the remaining
1102 * list.
1103 */
1104 float pll, plr, prl, prr;
1105
1106 nbytes = (maxoff + 1) * sizeof(OffsetNumber);
1107 listL = (OffsetNumber *) palloc(nbytes);
1108 listR = (OffsetNumber *) palloc(nbytes);
1109 v->spl_left = listL;
1110 v->spl_right = listR;
1111 v->spl_nleft = v->spl_nright = 0;
1112
1113 offl = FirstOffsetNumber;
1114 offr = maxoff;
1115
1116 unionL = DatumGetPrefixRange(ent[offl].key);
1117 unionR = DatumGetPrefixRange(ent[offr].key);
1118
1119 v->spl_left[v->spl_nleft++] = offl;
1120 v->spl_right[v->spl_nright++] = offr;
1121 v->spl_left = listL;
1122 v->spl_right = listR;
1123
1124 offl = OffsetNumberNext(offl);
1125 offr = OffsetNumberPrev(offr);
1126
1127 for(; offl < offr; offl = OffsetNumberNext(offl), offr = OffsetNumberPrev(offr)) {
1128 curl = DatumGetPrefixRange(ent[offl].key);
1129 curr = DatumGetPrefixRange(ent[offr].key);
1130
1131 Assert(curl != NULL && curr != NULL);
bde55c9 more Asserts to try to find where garbage comes from
dim authored
1132
98f1e68 penalty fix, some more debug Assert() tied to test data which is nume…
dim authored
1133 if( curl->prefix[0] != 0 )
1134 Assert(curl->prefix[0] >= '0' && curl->prefix[0] <= '9');
bde55c9 more Asserts to try to find where garbage comes from
dim authored
1135
98f1e68 penalty fix, some more debug Assert() tied to test data which is nume…
dim authored
1136 if( curr->prefix[0] != 0 )
1137 Assert(curr->prefix[0] >= '0' && curr->prefix[0] <= '9');
528746c copy/paste-o broken implementation of gist_prefix_range_ops, operator…
dim authored
1138
bde55c9 more Asserts to try to find where garbage comes from
dim authored
1139 if( unionL->prefix[0] != 0 )
1140 Assert(unionL->prefix[0] >= '0' && unionL->prefix[0] <= '9');
1141
1142 if( unionR->prefix[0] != 0 )
1143 Assert(unionR->prefix[0] >= '0' && unionR->prefix[0] <= '9');
1144
528746c copy/paste-o broken implementation of gist_prefix_range_ops, operator…
dim authored
1145 pll = __pr_penalty(unionL, curl);
1146 plr = __pr_penalty(unionR, curl);
1147 prl = __pr_penalty(unionL, curr);
1148 prr = __pr_penalty(unionR, curr);
1149
1150 if( pll <= plr && prl >= prr ) {
1151 /**
1152 * curl should go to left and curr to right, unless they share
1153 * a non-empty common prefix, in which case we place both curr
1154 * and curl on the same side. Arbitrarily the left one.
1155 */
1156 if( pll == plr && prl == prr ) {
f98ae67 Use union instead of greater_prefix in gpr_picksplit()
dim authored
1157 tmp_union = pr_union(curl, curr);
528746c copy/paste-o broken implementation of gist_prefix_range_ops, operator…
dim authored
1158
f98ae67 Use union instead of greater_prefix in gpr_picksplit()
dim authored
1159 if( strlen(tmp_union->prefix) > 0 ) {
1160 unionL = pr_union(unionL, tmp_union);
528746c copy/paste-o broken implementation of gist_prefix_range_ops, operator…
dim authored
1161 v->spl_left[v->spl_nleft++] = offl;
1162 v->spl_left[v->spl_nleft++] = offr;
1163 continue;
1164 }
1165 }
1166 /**
1167 * here pll <= plr and prl >= prr and (pll != plr || prl != prr)
1168 */
f98ae67 Use union instead of greater_prefix in gpr_picksplit()
dim authored
1169 unionL = pr_union(unionL, curl);
1170 unionR = pr_union(unionR, curr);
528746c copy/paste-o broken implementation of gist_prefix_range_ops, operator…
dim authored
1171
1172 v->spl_left[v->spl_nleft++] = offl;
1173 v->spl_right[v->spl_nright++] = offr;
1174 }
1175 else if( pll > plr && prl >= prr ) {
f98ae67 Use union instead of greater_prefix in gpr_picksplit()
dim authored
1176 unionR = pr_union(unionR, curr);
528746c copy/paste-o broken implementation of gist_prefix_range_ops, operator…
dim authored
1177 v->spl_right[v->spl_nright++] = offr;
1178 }
1179 else if( pll <= plr && prl < prr ) {
1180 /**
1181 * Current leftmost entry is added to listL
1182 */
f98ae67 Use union instead of greater_prefix in gpr_picksplit()
dim authored
1183 unionL = pr_union(unionL, curl);
528746c copy/paste-o broken implementation of gist_prefix_range_ops, operator…
dim authored
1184 v->spl_left[v->spl_nleft++] = offl;
1185 }
1186 else if( (pll - plr) < (prr - prl) ) {
1187 /**
1188 * All entries still in the list go into listL
1189 */
1190 for(; offl <= maxoff; offl = OffsetNumberNext(offl)) {
99979f7 fix DatumGetPrefixRange usage
dim authored
1191 curl = DatumGetPrefixRange(ent[offl].key);
f98ae67 Use union instead of greater_prefix in gpr_picksplit()
dim authored
1192 unionL = pr_union(unionL, curl);
528746c copy/paste-o broken implementation of gist_prefix_range_ops, operator…
dim authored
1193 v->spl_left[v->spl_nleft++] = offl;
1194 }
1195 }
1196 else {
1197 /**
1198 * All entries still in the list go into listR
1199 */
1200 for(; offl <= maxoff; offl = OffsetNumberNext(offl)) {
99979f7 fix DatumGetPrefixRange usage
dim authored
1201 curl = DatumGetPrefixRange(ent[offl].key);
f98ae67 Use union instead of greater_prefix in gpr_picksplit()
dim authored
1202 unionR = pr_union(unionR, curl);
528746c copy/paste-o broken implementation of gist_prefix_range_ops, operator…
dim authored
1203 v->spl_right[v->spl_nright++] = offl;
1204 }
1205 }
1206 }
1207
1208 /**
1209 * The for loop continues while offl < offr. If maxoff is odd, it
1210 * could be that there's a last value to process. Here we choose
1211 * where to add it.
1212 */
1213 if( offl == offr ) {
99979f7 fix DatumGetPrefixRange usage
dim authored
1214 curl = DatumGetPrefixRange(ent[offl].key);
bde55c9 more Asserts to try to find where garbage comes from
dim authored
1215
1216 if( curl->prefix[0] != 0 )
1217 Assert(curl->prefix[0] >= '0' && curl->prefix[0] <= '9');
1218
1219 if( unionL->prefix[0] != 0 )
1220 Assert(unionL->prefix[0] >= '0' && unionL->prefix[0] <= '9');
1221
1222 if( unionR->prefix[0] != 0 )
1223 Assert(unionR->prefix[0] >= '0' && unionR->prefix[0] <= '9');
1224
528746c copy/paste-o broken implementation of gist_prefix_range_ops, operator…
dim authored
1225 pll = __pr_penalty(unionL, curl);
1226 plr = __pr_penalty(unionR, curl);
1227
1228 if( pll < plr || (pll == plr && v->spl_nleft < v->spl_nright) ) {
99979f7 fix DatumGetPrefixRange usage
dim authored
1229 curl = DatumGetPrefixRange(ent[offl].key);
f98ae67 Use union instead of greater_prefix in gpr_picksplit()
dim authored
1230 unionL = pr_union(unionL, curl);
528746c copy/paste-o broken implementation of gist_prefix_range_ops, operator…
dim authored
1231 v->spl_left[v->spl_nleft++] = offl;
1232 }
1233 else {
99979f7 fix DatumGetPrefixRange usage
dim authored
1234 curl = DatumGetPrefixRange(ent[offl].key);
f98ae67 Use union instead of greater_prefix in gpr_picksplit()
dim authored
1235 unionR = pr_union(unionR, curl);
528746c copy/paste-o broken implementation of gist_prefix_range_ops, operator…
dim authored
1236 v->spl_right[v->spl_nright++] = offl;
1237 }
1238 }
1239
bde55c9 more Asserts to try to find where garbage comes from
dim authored
1240 if( unionL->prefix[0] != 0 )
1241 Assert(unionL->prefix[0] >= '0' && unionL->prefix[0] <= '9');
1242
1243 if( unionR->prefix[0] != 0 )
1244 Assert(unionR->prefix[0] >= '0' && unionR->prefix[0] <= '9');
1245
f98ae67 Use union instead of greater_prefix in gpr_picksplit()
dim authored
1246 v->spl_ldatum = PrefixRangeGetDatum(unionL);
1247 v->spl_rdatum = PrefixRangeGetDatum(unionR);
528746c copy/paste-o broken implementation of gist_prefix_range_ops, operator…
dim authored
1248
1249 /**
1250 * All read entries (maxoff) should have make it to the
1251 * GIST_SPLITVEC return value.
1252 */
1253 Assert(maxoff = v->spl_nleft+v->spl_nright);
1254
1255 #ifdef DEBUG
f98ae67 Use union instead of greater_prefix in gpr_picksplit()
dim authored
1256 elog(NOTICE, "gpr_picksplit(): entryvec->n=%4d maxoff=%4d l=%4d r=%4d l+r=%4d unionL='%s' unionR='%s'",
528746c copy/paste-o broken implementation of gist_prefix_range_ops, operator…
dim authored
1257 entryvec->n, maxoff, v->spl_nleft, v->spl_nright, v->spl_nleft+v->spl_nright,
f98ae67 Use union instead of greater_prefix in gpr_picksplit()
dim authored
1258 DatumGetCString(DirectFunctionCall1(prefix_range_out, v->spl_ldatum)),
1259 DatumGetCString(DirectFunctionCall1(prefix_range_out, v->spl_rdatum)));
528746c copy/paste-o broken implementation of gist_prefix_range_ops, operator…
dim authored
1260 #endif
1261
1262 PG_RETURN_POINTER(v);
1263 }
1264
1265 PG_FUNCTION_INFO_V1(gpr_union);
1266 Datum
1267 gpr_union(PG_FUNCTION_ARGS)
1268 {
1269 GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
1270 GISTENTRY *ent = entryvec->vector;
1271
1b22c3e fix gpr_penalty implementation, having it consider '[a-b]' kind of pr…
dim authored
1272 prefix_range *out, *tmp, *old;
528746c copy/paste-o broken implementation of gist_prefix_range_ops, operator…
dim authored
1273 int numranges, i = 0;
1274
1275 numranges = entryvec->n;
1276 tmp = DatumGetPrefixRange(ent[0].key);
1277 out = tmp;
1278
1279 if( numranges == 1 ) {
1280 out = build_pr(tmp->prefix);
1281 out->first = tmp->first;
1282 out->last = tmp->last;
1283
1284 PG_RETURN_PREFIX_RANGE_P(out);
1285 }
1286
1287 for (i = 1; i < numranges; i++) {
1288 tmp = DatumGetPrefixRange(ent[i].key);
1b22c3e fix gpr_penalty implementation, having it consider '[a-b]' kind of pr…
dim authored
1289 old = out;
528746c copy/paste-o broken implementation of gist_prefix_range_ops, operator…
dim authored
1290 out = pr_union(out, tmp);
1b22c3e fix gpr_penalty implementation, having it consider '[a-b]' kind of pr…
dim authored
1291
1292 #ifdef DEBUG_UNION
1293 elog(NOTICE, "gpr_union: %s | %s = %s",
1294 DatumGetCString(DirectFunctionCall1(prefix_range_out, PrefixRangeGetDatum(old))),
1295 DatumGetCString(DirectFunctionCall1(prefix_range_out, PrefixRangeGetDatum(tmp))),
1296 DatumGetCString(DirectFunctionCall1(prefix_range_out, PrefixRangeGetDatum(out))));
1297 #endif
528746c copy/paste-o broken implementation of gist_prefix_range_ops, operator…
dim authored
1298 }
1299
1b22c3e fix gpr_penalty implementation, having it consider '[a-b]' kind of pr…
dim authored
1300 /*
528746c copy/paste-o broken implementation of gist_prefix_range_ops, operator…
dim authored
1301 #ifdef DEBUG_UNION
1b22c3e fix gpr_penalty implementation, having it consider '[a-b]' kind of pr…
dim authored
1302 elog(NOTICE, "gpr_union: %s",
528746c copy/paste-o broken implementation of gist_prefix_range_ops, operator…
dim authored
1303 DatumGetCString(DirectFunctionCall1(prefix_range_out,
1304 PrefixRangeGetDatum(out))));
1305 #endif
1b22c3e fix gpr_penalty implementation, having it consider '[a-b]' kind of pr…
dim authored
1306 */
f98ae67 Use union instead of greater_prefix in gpr_picksplit()
dim authored
1307 PG_RETURN_PREFIX_RANGE_P(out);
528746c copy/paste-o broken implementation of gist_prefix_range_ops, operator…
dim authored
1308 }
1309
1310 PG_FUNCTION_INFO_V1(gpr_same);
1311 Datum
1312 gpr_same(PG_FUNCTION_ARGS)
1313 {
1314 prefix_range *v1 = PG_GETARG_PREFIX_RANGE_P(0);
1315 prefix_range *v2 = PG_GETARG_PREFIX_RANGE_P(1);
1316 bool *result = (bool *) PG_GETARG_POINTER(2);
1317
1318 *result = pr_eq(v1, v2);
1319 PG_RETURN_POINTER( result );
1320 }
1321
1322
1323
9060f42 prefix_range unions, operator |
dim authored
1324
7d2ac3d firsts attempts towards 8.3 compliance, using VARSIZE_ANY_EXHDR()
dim authored
1325 /**
f61609e First picksplit() implementation of AndrewSN ideas, missing the preli…
dim authored
1326 * - Operator prefix @> query and query <@ prefix
1327 * - greater_prefix, exposed as a func and an aggregate
1328 * - prefix_penalty, exposed for testing purpose
0fc1320 Importing prefix operator and opclass files
dim authored
1329 */
1330 Datum prefix_contains(PG_FUNCTION_ARGS);
1331 Datum prefix_contained_by(PG_FUNCTION_ARGS);
1332 Datum greater_prefix(PG_FUNCTION_ARGS);
f61609e First picksplit() implementation of AndrewSN ideas, missing the preli…
dim authored
1333 Datum prefix_penalty(PG_FUNCTION_ARGS);
0fc1320 Importing prefix operator and opclass files
dim authored
1334
1335 /**
1336 * GiST support methods
1337 */
1338 Datum gprefix_consistent(PG_FUNCTION_ARGS);
1339 Datum gprefix_compress(PG_FUNCTION_ARGS);
1340 Datum gprefix_decompress(PG_FUNCTION_ARGS);
1341 Datum gprefix_penalty(PG_FUNCTION_ARGS);
1342 Datum gprefix_picksplit(PG_FUNCTION_ARGS);
1343 Datum gprefix_union(PG_FUNCTION_ARGS);
1344 Datum gprefix_same(PG_FUNCTION_ARGS);
1345
1346 /**
1347 * prefix opclass only provides 1 operator, @>
1348 */
1349 static inline
1350 bool prefix_contains_internal(text *prefix, text *query, bool eqval)
1351 {
e2307bd prefix_range @> prefix(text) operator and its commutator
dim authored
1352 int plen = PREFIX_VARSIZE(prefix);
1353 int qlen = PREFIX_VARSIZE(query);
1354 char *p = PREFIX_VARDATA(prefix);
1355 char *q = PREFIX_VARDATA(query);
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
1356
e2307bd prefix_range @> prefix(text) operator and its commutator
dim authored
1357 if( __prefix_contains(p, q, plen, qlen) )
0fc1320 Importing prefix operator and opclass files
dim authored
1358 return eqval;
1359
e2307bd prefix_range @> prefix(text) operator and its commutator
dim authored
1360 return false;
0fc1320 Importing prefix operator and opclass files
dim authored
1361 }
1362
1363 /**
1364 * The operator @> code
1365 */
1366 PG_FUNCTION_INFO_V1(prefix_contains);
1367 Datum
1368 prefix_contains(PG_FUNCTION_ARGS)
1369 {
fef1590 8.3 compat now ok, using VARDATA_ANY() and PG_GETARG_TEXT_PP()
dim authored
1370 PG_RETURN_BOOL( prefix_contains_internal(PREFIX_PG_GETARG_TEXT(0),
1371 PREFIX_PG_GETARG_TEXT(1),
1372 true) );
0fc1320 Importing prefix operator and opclass files
dim authored
1373 }
1374
1375 /**
1376 * The commutator, <@, using the same internal code
1377 */
1378 PG_FUNCTION_INFO_V1(prefix_contained_by);
1379 Datum
1380 prefix_contained_by(PG_FUNCTION_ARGS)
1381 {
fef1590 8.3 compat now ok, using VARDATA_ANY() and PG_GETARG_TEXT_PP()
dim authored
1382 PG_RETURN_BOOL( prefix_contains_internal(PREFIX_PG_GETARG_TEXT(1),
1383 PREFIX_PG_GETARG_TEXT(0),
7a4fd5a First steps at implementing a prefix_range datatype
dim authored
1384 true) );
0fc1320 Importing prefix operator and opclass files
dim authored
1385 }
1386
1387 /**
1388 * greater_prefix returns the greater prefix of any 2 given texts
1389 */
1390 static inline
1391 text *greater_prefix_internal(text *a, text *b)
1392 {
1393 int i = 0;
7d2ac3d firsts attempts towards 8.3 compliance, using VARSIZE_ANY_EXHDR()
dim authored
1394 int la = PREFIX_VARSIZE(a);
1395 int lb = PREFIX_VARSIZE(b);
fef1590 8.3 compat now ok, using VARDATA_ANY() and PG_GETARG_TEXT_PP()
dim authored
1396 char *ca = PREFIX_VARDATA(a);
1397 char *cb = PREFIX_VARDATA(b);
0fc1320 Importing prefix operator and opclass files
dim authored
1398
1399 for(i=0; i<la && i<lb && ca[i] == cb[i]; i++);
1400
1401 /* i is the last common char position in a, or 0 */
1402 if( i == 0 )
1403 return DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum("")));
1404 else
1405 return DatumGetTextPSlice(PointerGetDatum(a), 0, i);
1406 }
1407
1408 PG_FUNCTION_INFO_V1(greater_prefix);
1409 Datum
1410 greater_prefix(PG_FUNCTION_ARGS)
1411 {
1412
fef1590 8.3 compat now ok, using VARDATA_ANY() and PG_GETARG_TEXT_PP()
dim authored
1413 PG_RETURN_POINTER( greater_prefix_internal(PREFIX_PG_GETARG_TEXT(0),
1414 PREFIX_PG_GETARG_TEXT(1)) );
0fc1320 Importing prefix operator and opclass files
dim authored
1415 }
1416
f61609e First picksplit() implementation of AndrewSN ideas, missing the preli…
dim authored
1417 /**
1418 * penalty internal function, which is called in more places than just
1419 * gist penalty() function, namely picksplit() uses it too.
1420 *
1421 * Consider greater common prefix length, the greater the better, then
1422 * for a distance of 1 (only last prefix char is different), consider
1423 * char code distance.
1424 *
1425 * With gplen the size of the greatest common prefix and dist the char
1426 * code distance, the following maths should do (per AndrewSN):
1427 *
1428 * penalty() = dist / (256 ^ gplen)
1429 *
1430 * penalty(01, 03) == 2 / (256^1)
1431 * penalty(123, 125) == 2 / (256^2)
1432 * penalty(12, 56) == 4 / (256^0)
1433 * penalty(0, 17532) == 1 / (256^0)
1434 *
1435 * 256 is then number of codes any text position (char) can admit.
1436 */
1437 static inline
1438 float prefix_penalty_internal(text *orig, text *new)
1439 {
1440 float penalty;
1441 text *gp;
1442 int nlen, olen, gplen, dist = 0;
1443
7d2ac3d firsts attempts towards 8.3 compliance, using VARSIZE_ANY_EXHDR()
dim authored
1444 olen = PREFIX_VARSIZE(orig);
1445 nlen = PREFIX_VARSIZE(new);
f61609e First picksplit() implementation of AndrewSN ideas, missing the preli…
dim authored
1446 gp = greater_prefix_internal(orig, new);
7d2ac3d firsts attempts towards 8.3 compliance, using VARSIZE_ANY_EXHDR()
dim authored
1447 gplen = PREFIX_VARSIZE(gp);
f61609e First picksplit() implementation of AndrewSN ideas, missing the preli…
dim authored
1448
1449 /**
1450 * greater_prefix length is orig length only if orig == gp
1451 */
1452 if( gplen == olen )
1453 penalty = 0;
1454
1455 dist = 1;
1456 if( nlen == olen ) {
fef1590 8.3 compat now ok, using VARDATA_ANY() and PG_GETARG_TEXT_PP()
dim authored
1457 char *o = PREFIX_VARDATA(orig);
1458 char *n = PREFIX_VARDATA(new);
f61609e First picksplit() implementation of AndrewSN ideas, missing the preli…
dim authored
1459 dist = abs((int)o[olen-1] - (int)n[nlen-1]);
1460 }
1461 penalty = (((float)dist) / powf(256, gplen));
1462
67b9a2f picksplit() first pass is about some kind of sorting. This commit sti…
dim authored
1463 #ifdef DEBUG_PENALTY
f61609e First picksplit() implementation of AndrewSN ideas, missing the preli…
dim authored
1464 elog(NOTICE, "gprefix_penalty_internal(%s, %s) == %d/(256^%d) == %g",
1465 DatumGetCString(DirectFunctionCall1(textout,PointerGetDatum(orig))),
1466 DatumGetCString(DirectFunctionCall1(textout,PointerGetDatum(new))),
1467 dist, gplen, penalty);
1468 #endif
1469
1470 return penalty;
1471 }
1472
1473 /**
1474 * For testing purposes we export our penalty function to SQL
1475 */
1476 PG_FUNCTION_INFO_V1(prefix_penalty);
1477 Datum
1478 prefix_penalty(PG_FUNCTION_ARGS)
1479 {
fef1590 8.3 compat now ok, using VARDATA_ANY() and PG_GETARG_TEXT_PP()
dim authored
1480 float penalty = prefix_penalty_internal(PREFIX_PG_GETARG_TEXT(0),
1481 PREFIX_PG_GETARG_TEXT(1));
f61609e First picksplit() implementation of AndrewSN ideas, missing the preli…
dim authored
1482
1483 PG_RETURN_FLOAT4(penalty);
1484 }
0fc1320 Importing prefix operator and opclass files
dim authored
1485
1486 /**
1487 * GiST opclass methods
1488 */
1489
1490 PG_FUNCTION_INFO_V1(gprefix_consistent);
1491 Datum
1492 gprefix_consistent(PG_FUNCTION_ARGS)
1493 {
1494 GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
1495 text *query = (text *) PG_GETARG_POINTER(1);
1496 StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
1497 text *key = (text *) DatumGetPointer(entry->key);
1498 bool retval;
1499
1500 /**
1501 * We only have 1 Strategy (operator @>)
3f678f4 First version working, some more doc, avoiding gcc complaints, better…
dim authored
1502 * and we want to avoid compiler complaints that we do not use it.
0fc1320 Importing prefix operator and opclass files
dim authored
1503 */
1504 Assert(strategy == 1);
3f678f4 First version working, some more doc, avoiding gcc complaints, better…
dim authored
1505 (void) strategy;
1506 retval = prefix_contains_internal(key, query, true);
0fc1320 Importing prefix operator and opclass files
dim authored
1507
1508 PG_RETURN_BOOL(retval);
1509 }
1510
1511 /**
1512 * Prefix penalty: we want the penalty to be lower for closer
1513 * prefixes, taking into account length difference and content
1514 * distance.
1515 *
1516 * For examples we want new prefix 125 to be inserted by preference in
1517 * the 124 branch, not in a 128 or a 256 branch.
1518 *
1519 */
1520 PG_FUNCTION_INFO_V1(gprefix_penalty);
1521 Datum
1522 gprefix_penalty(PG_FUNCTION_ARGS)
1523 {
1524 GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
1525 GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
1526 float *penalty = (float *) PG_GETARG_POINTER(2);
1527
1528 text *orig = (text *) DatumGetPointer(origentry->key);
1529 text *new = (text *) DatumGetPointer(newentry->key);
1530
f61609e First picksplit() implementation of AndrewSN ideas, missing the preli…
dim authored
1531 *penalty = prefix_penalty_internal(orig, new);
0fc1320 Importing prefix operator and opclass files
dim authored
1532 PG_RETURN_POINTER(penalty);
1533 }
1534
1535 /**
67b9a2f picksplit() first pass is about some kind of sorting. This commit sti…
dim authored
1536 * prefix picksplit first pass step: presort the SPLITVEC vector by
1537 * positionning the elements sharing the non-empty prefix which is the
1538 * more frequent in the distribution at the beginning of the vector.
1539 *
1540 * This will have the effect that the picksplit() implementation will
1541 * do a better job, per preliminary tests on not-so random data.
1542 */
1543 struct gprefix_unions
1544 {
1545 text *prefix; /* a shared prefix */
1546 int n; /* how many entries begins with this prefix */
1547 };
1548
1549
1550 static inline
1551 text **prefix_presort(GistEntryVector *list)
1552 {
2be7f8e picksplit() presort() SYGSEGV fixed
dim authored
1553 GISTENTRY *ent = list->vector;
1554 OffsetNumber maxoff = list->n - 1;
67b9a2f picksplit() first pass is about some kind of sorting. This commit sti…
dim authored
1555 text *init = (text *) DatumGetPointer(ent[FirstOffsetNumber].key);
1556 text *cur, *gp;
cf4a835 Begin main presort() loop at OffsetNumberNext(FirstOffsetNumber); and…
dim authored
1557 int gplen;
67b9a2f picksplit() first pass is about some kind of sorting. This commit sti…
dim authored
1558 bool found;
1559
1560 struct gprefix_unions max;
1561 struct gprefix_unions *unions = (struct gprefix_unions *)
cf4a835 Begin main presort() loop at OffsetNumberNext(FirstOffsetNumber); and…
dim authored
1562 palloc((maxoff+1) * sizeof(struct gprefix_unions));
67b9a2f picksplit() first pass is about some kind of sorting. This commit sti…
dim authored
1563
cf4a835 Begin main presort() loop at OffsetNumberNext(FirstOffsetNumber); and…
dim authored
1564 OffsetNumber unions_it = FirstOffsetNumber; /* unions iterator */
40f9a17 presort: reuse current union entry instead of zeroing its .n
dim authored
1565 OffsetNumber i, u;
67b9a2f picksplit() first pass is about some kind of sorting. This commit sti…
dim authored
1566
1567 int result_it, result_it_maxes = FirstOffsetNumber;
cf4a835 Begin main presort() loop at OffsetNumberNext(FirstOffsetNumber); and…
dim authored
1568 text **result = (text **)palloc((maxoff+1) * sizeof(text *));
1569
1570 #ifdef DEBUG_PRESORT_MAX
1571 int debug_count;
1572 #endif
1573 #ifdef DEBUG_PRESORT_UNIONS
1574 int debug_count;
1575 #endif
67b9a2f picksplit() first pass is about some kind of sorting. This commit sti…
dim authored
1576
1577 unions[unions_it].prefix = init;
1578 unions[unions_it].n = 1;
1579 unions_it = OffsetNumberNext(unions_it);
1580
1581 max.prefix = init;
1582 max.n = 1;
1583
cf4a835 Begin main presort() loop at OffsetNumberNext(FirstOffsetNumber); and…
dim authored
1584 #ifdef DEBUG_PRESORT_MAX
1585 elog(NOTICE, " prefix_presort(): init=%s max.prefix=%s max.n=%d",
1586 DatumGetCString(DirectFunctionCall1(textout,PointerGetDatum(init))),
1587 DatumGetCString(DirectFunctionCall1(textout,PointerGetDatum(max.prefix))),
1588 max.n);
1589 #endif
1590
67b9a2f picksplit() first pass is about some kind of sorting. This commit sti…
dim authored
1591 /**
1592 * Prepare a list of prefixes and how many time they are found.
1593 */
cf4a835 Begin main presort() loop at OffsetNumberNext(FirstOffsetNumber); and…
dim authored
1594 for(i = OffsetNumberNext(FirstOffsetNumber); i <= maxoff; i = OffsetNumberNext(i)) {
67b9a2f picksplit() first pass is about some kind of sorting. This commit sti…
dim authored
1595 found = false;
1596 cur = (text *) DatumGetPointer(ent[i].key);
2be7f8e picksplit() presort() SYGSEGV fixed
dim authored
1597
67b9a2f picksplit() first pass is about some kind of sorting. This commit sti…
dim authored
1598 for(u = FirstOffsetNumber; u < unions_it; u = OffsetNumberNext(u)) {
1599 if( unions[u].n < 1 )
1600 continue;
1601
1602 /**
1603 * We'll need the prefix itself, so it's better to call
1604 * greater_prefix_internal each time rather than
1605 * prefix_contains_internal then when true
1606 * greater_prefix_internal.
1607 */
1608 gp = greater_prefix_internal(cur, unions[u].prefix);
7d2ac3d firsts attempts towards 8.3 compliance, using VARSIZE_ANY_EXHDR()
dim authored
1609 gplen = PREFIX_VARSIZE(gp);
67b9a2f picksplit() first pass is about some kind of sorting. This commit sti…
dim authored
1610
cf4a835 Begin main presort() loop at OffsetNumberNext(FirstOffsetNumber); and…
dim authored
1611 #ifdef DEBUG_PRESORT_GP
7d2ac3d firsts attempts towards 8.3 compliance, using VARSIZE_ANY_EXHDR()
dim authored
1612 if( gplen > 0 ) {
cf4a835 Begin main presort() loop at OffsetNumberNext(FirstOffsetNumber); and…
dim authored
1613 elog(NOTICE, " prefix_presort(): gplen=%2d, %s @> %s = %s",
1614 gplen,
1615 DatumGetCString(DirectFunctionCall1(textout,PointerGetDatum(gp))),
1616 DatumGetCString(DirectFunctionCall1(textout,PointerGetDatum(cur))),
1617 (prefix_contains_internal(gp, cur, true) ? "t" : "f"));
1618 }
1619 #endif
1620
7d2ac3d firsts attempts towards 8.3 compliance, using VARSIZE_ANY_EXHDR()
dim authored
1621 if( gplen > 0 ) {
5593c9d DEBUG_PRESORT_GP code has to be reached before the Assert() call
dim authored
1622 Assert(prefix_contains_internal(gp, cur, true));
1623 }
1624
cf4a835 Begin main presort() loop at OffsetNumberNext(FirstOffsetNumber); and…
dim authored
1625 if( gplen > 0 ) {
67b9a2f picksplit() first pass is about some kind of sorting. This commit sti…
dim authored
1626 /**
1627 * Current list entry share a common prefix with some previous
1628 * analyzed list entry, update the prefix and number.
1629 */
40f9a17 presort: reuse current union entry instead of zeroing its .n
dim authored
1630 found = true;
1631 unions[u].n += 1;
1632 unions[u].prefix = gp;
67b9a2f picksplit() first pass is about some kind of sorting. This commit sti…
dim authored
1633
1634 /**
1635 * We just updated unions, we may have to update max too.
1636 */
40f9a17 presort: reuse current union entry instead of zeroing its .n
dim authored
1637 if( unions[u].n > max.n ) {
1638 max.prefix = unions[u].prefix;
1639 max.n = unions[u].n;
cf4a835 Begin main presort() loop at OffsetNumberNext(FirstOffsetNumber); and…
dim authored
1640 #ifdef DEBUG_PRESORT_MAX
1641 elog(NOTICE, " prefix_presort(): max.prefix=%s max.n=%d",
1642 DatumGetCString(DirectFunctionCall1(textout,PointerGetDatum(max.prefix))),
1643 max.n);
1644 #endif
67b9a2f picksplit() first pass is about some kind of sorting. This commit sti…
dim authored
1645 }
1646
1647 /**
1648 * break from the unions loop, we're done with it for this
1649 * element.
1650 */
1651 break;
1652 }
1653 }
1654 /**
1655 * We're done with the unions loop, if we didn't find a common
1656 * prefix we have to add the current list element to unions
1657 */
1658 if( !found ) {
1659 unions[unions_it].prefix = cur;
1660 unions[unions_it].n = 1;
1661 unions_it = OffsetNumberNext(unions_it);
1662 }
1663 }
cf4a835 Begin main presort() loop at OffsetNumberNext(FirstOffsetNumber); and…
dim authored
1664 #ifdef DEBUG_PRESORT_UNIONS
388a8a1 prefix opclass works again: picksplit() now has counts and offset rigths
dim authored
1665 debug_count = 0;
67b9a2f picksplit() first pass is about some kind of sorting. This commit sti…
dim authored
1666 for(u = FirstOffsetNumber; u < unions_it; u = OffsetNumberNext(u)) {
388a8a1 prefix opclass works again: picksplit() now has counts and offset rigths
dim authored
1667 debug_count += unions[u].n;
1668 elog(NOTICE, " prefix_presort(): unions[%s] = %d",
1669 DatumGetCString(DirectFunctionCall1(textout,PointerGetDatum(unions[u].prefix))),
1670 unions[u].n);
67b9a2f picksplit() first pass is about some kind of sorting. This commit sti…
dim authored
1671 }
388a8a1 prefix opclass works again: picksplit() now has counts and offset rigths
dim authored
1672 elog(NOTICE, " prefix_presort(): total: %d", debug_count);
cf4a835 Begin main presort() loop at OffsetNumberNext(FirstOffsetNumber); and…
dim authored
1673 #endif
1674
1675 #ifdef DEBUG_PRESORT_MAX
1676 debug_count = 0;
1677 for(i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) {
1678 cur = (text *) DatumGetPointer(ent[i].key);
1679
1680 if( prefix_contains_internal(max.prefix, cur, true) )
1681 debug_count++;
1682 }
1683 elog(NOTICE, " prefix_presort(): max.prefix %s @> %d entries",
1684 DatumGetCString(DirectFunctionCall1(textout,PointerGetDatum(max.prefix))),
1685 debug_count);
67b9a2f picksplit() first pass is about some kind of sorting. This commit sti…
dim authored
1686 #endif
1687
1688 /**
1689 * We now have a list of common non-empty prefixes found on the list
1690 * (unions) and kept the max entry while computing this weighted
1691 * unions list.
1692 *
cf4a835 Begin main presort() loop at OffsetNumberNext(FirstOffsetNumber); and…
dim authored
1693 * Simple case : a common non-empty prefix is shared by all list
1694 * entries.
67b9a2f picksplit() first pass is about some kind of sorting. This commit sti…
dim authored
1695 */
1696 if( max.n == list->n ) {
1697 /**
1698 * A common non-empty prefix is shared by all list entries.
1699 */
1700 for(i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) {
1701 cur = (text *) DatumGetPointer(ent[i].key);
1702 result[i] = cur;
1703 }
1704 return result;
1705 }
1706
cf4a835 Begin main presort() loop at OffsetNumberNext(FirstOffsetNumber); and…
dim authored
1707 /**
1708 * If we arrive here, we now have to make up the result by copying
1709 * max matching elements first, then the others list entries in
1710 * their original order. To do this, we reserve the first result
1711 * max.n places to the max.prefix matching elements (see result_it
1712 * and result_it_maxes).
1713 *
1714 * result_it_maxes will go from FirstOffsetNumber to max.n included,
1715 * and result_it will iterate through the end of the list, that is
1716 * from max.n - FirstOffsetNumber + 1 to maxoff.
1717 *
1718 * [a, b] contains b - a + 1 elements, hence
1719 * [FirstOffsetNumber, max.n] contains max.n - FirstOffsetNumber + 1
1720 * elements, whatever FirstOffsetNumber value.
1721 */
1722 result_it_maxes = FirstOffsetNumber;
1723 result_it = OffsetNumberNext(max.n - FirstOffsetNumber + 1);
1724
1725 #ifdef DEBUG_PRESORT_MAX
1726 elog(NOTICE, " prefix_presort(): max.prefix=%s max.n=%d result_it=%d",
1727 DatumGetCString(DirectFunctionCall1(textout,PointerGetDatum(max.prefix))),
1728 max.n, result_it);
1729 #endif
67b9a2f picksplit() first pass is about some kind of sorting. This commit sti…
dim authored
1730
1731 for(i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i)) {
1732 cur = (text *) DatumGetPointer(ent[i].key);
1733
cf4a835 Begin main presort() loop at OffsetNumberNext(FirstOffsetNumber); and…
dim authored
1734 #ifdef DEBUG_PRESORT_RESULT
1735 elog(NOTICE, " prefix_presort(): ent[%4d] = %s <@ %s = %s => result[%4d]",
1736 i,
1737 DatumGetCString(DirectFunctionCall1(textout,PointerGetDatum(cur))),
1738 DatumGetCString(DirectFunctionCall1(textout,PointerGetDatum(max.prefix))),
1739 (prefix_contains_internal(max.prefix, cur, true) ? "t" : "f"),
1740 (prefix_contains_internal(max.prefix, cur, true) ? result_it_maxes : result_it));
1741 #endif
1742
67b9a2f picksplit() first pass is about some kind of sorting. This commit sti…
dim authored
1743 if( prefix_contains_internal(max.prefix, cur, true) ) {
1744 /**
1745 * cur has to go in first part of the list, as max.prefix is a
1746 * prefix of it.
1747 */
cf4a835 Begin main presort() loop at OffsetNumberNext(FirstOffsetNumber); and…
dim authored
1748 Assert(result_it_maxes <= max.n);
67b9a2f picksplit() first pass is about some kind of sorting. This commit sti…
dim authored
1749 result[result_it_maxes] = cur;
1750 result_it_maxes = OffsetNumberNext(result_it_maxes);
1751 }
1752 else {
1753 /**
1754 * cur has to go at next second part position.
1755 */
cf4a835 Begin main presort() loop at OffsetNumberNext(FirstOffsetNumber); and…
dim authored
1756 Assert(result_it <= maxoff);
67b9a2f picksplit() first pass is about some kind of sorting. This commit sti…
dim authored
1757 result[result_it] = cur;
1758 result_it = OffsetNumberNext(result_it);
1759 }
1760 }
cf4a835 Begin main presort() loop at OffsetNumberNext(FirstOffsetNumber); and…
dim authored
1761 #ifdef DEBUG_PRESORT_RESULT
1762 elog(NOTICE, " prefix_presort(): result_it_maxes=%4d result_it=%4d list->n=%d maxoff=%d",
1763 result_it_maxes, result_it, list->n, maxoff);
1764 #endif
67b9a2f picksplit() first pass is about some kind of sorting. This commit sti…
dim authored
1765 return result;
1766 }
1767
1768
1769
1770 /**
0fc1320 Importing prefix operator and opclass files
dim authored
1771 * prefix picksplit implementation
1772 *
f61609e First picksplit() implementation of AndrewSN ideas, missing the preli…
dim authored
1773 * The idea is to consume the SPLITVEC vector by both its start and
1774 * end, inserting one or two items at a time depending on relative
388a8a1 prefix opclass works again: picksplit() now has counts and offset rigths
dim authored
1775 * penalty() with current ends of new vectors, or even all remaining
1776 * items at once.
0fc1320 Importing prefix operator and opclass files
dim authored
1777 *
f61609e First picksplit() implementation of AndrewSN ideas, missing the preli…
dim authored
1778 * Idea and perl test script per AndreSN with some modifications by me
1779 * (Dimitri Fontaine).
1780 *
1781 * TODO: check whether qsort() is the right first pass. Another idea
1782 * (by dim, this time) being to care first about items which non-empty
1783 * union appears the most in the SPLITVEC vector. Perl test
1784 * implementation show good results on random test data.
0fc1320 Importing prefix operator and opclass files
dim authored
1785 */
67b9a2f picksplit() first pass is about some kind of sorting. This commit sti…
dim authored
1786
0fc1320 Importing prefix operator and opclass files
dim authored
1787 PG_FUNCTION_INFO_V1(gprefix_picksplit);
1788 Datum
1789 gprefix_picksplit(PG_FUNCTION_ARGS)
1790 {
1791 GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
388a8a1 prefix opclass works again: picksplit() now has counts and offset rigths
dim authored
1792 OffsetNumber maxoff = entryvec->n - 1;
0fc1320 Importing prefix operator and opclass files
dim authored
1793 GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
1794
1795 int nbytes;
f61609e First picksplit() implementation of AndrewSN ideas, missing the preli…
dim authored
1796 OffsetNumber offl, offr;
0fc1320 Importing prefix operator and opclass files
dim authored
1797 OffsetNumber *listL;
1798 OffsetNumber *listR;
f61609e First picksplit() implementation of AndrewSN ideas, missing the preli…
dim authored
1799 text *curl, *curr, *gp;
0fc1320 Importing prefix operator and opclass files
dim authored
1800 text *unionL;
1801 text *unionR;
f61609e First picksplit() implementation of AndrewSN ideas, missing the preli…
dim authored
1802
1803 /**
1804 * Keeping track of penalties to insert into ListL or ListR, for
1805 * both the leftmost and the rightmost element of the remaining
1806 * list.
1807 */
1808 float pll, plr, prl, prr;
1809
67b9a2f picksplit() first pass is about some kind of sorting. This commit sti…
dim authored
1810 /**
1811 * First pass: sort out the entryvec.
1812 */
1813 text **sorted = prefix_presort(entryvec);
0fc1320 Importing prefix operator and opclass files
dim authored
1814
388a8a1 prefix opclass works again: picksplit() now has counts and offset rigths
dim authored
1815 nbytes = (maxoff + 1) * sizeof(OffsetNumber);
0fc1320 Importing prefix operator and opclass files
dim authored
1816 listL = (OffsetNumber *) palloc(nbytes);
1817 listR = (OffsetNumber *) palloc(nbytes);
f61609e First picksplit() implementation of AndrewSN ideas, missing the preli…
dim authored
1818 v->spl_left = listL;
1819 v->spl_right = listR;
0fc1320 Importing prefix operator and opclass files
dim authored
1820 v->spl_nleft = v->spl_nright = 0;
1821
f61609e First picksplit() implementation of AndrewSN ideas, missing the preli…
dim authored
1822 offl = FirstOffsetNumber;
1823 offr = maxoff;
1824
67b9a2f picksplit() first pass is about some kind of sorting. This commit sti…
dim authored
1825 unionL = sorted[offl];
1826 unionR = sorted[offr];
f61609e First picksplit() implementation of AndrewSN ideas, missing the preli…
dim authored
1827
1828 v->spl_left[v->spl_nleft++] = offl;
1829 v->spl_right[v->spl_nright++] = offr;
1830 v->spl_left = listL;
0fc1320 Importing prefix operator and opclass files
dim authored
1831 v->spl_right = listR;
1832
388a8a1 prefix opclass works again: picksplit() now has counts and offset rigths
dim authored
1833 offl = OffsetNumberNext(offl);
1834 offr = OffsetNumberPrev(offr);
1835
f61609e First picksplit() implementation of AndrewSN ideas, missing the preli…
dim authored
1836 for(; offl < offr; offl = OffsetNumberNext(offl), offr = OffsetNumberPrev(offr)) {
67b9a2f picksplit() first pass is about some kind of sorting. This commit sti…
dim authored
1837 curl = sorted[offl];
1838 curr = sorted[offr];
1839
1840 Assert(curl != NULL && curr != NULL);
f61609e First picksplit() implementation of AndrewSN ideas, missing the preli…
dim authored
1841
1842 pll = prefix_penalty_internal(unionL, curl);
1843 plr = prefix_penalty_internal(unionR, curl);
1844 prl = prefix_penalty_internal(unionL, curr);
1845 prr = prefix_penalty_internal(unionR, curr);
1846
1847 if( pll <= plr && prl >= prr ) {
1848 /**
1849 * curl should go to left and curr to right, unless they share
1850 * a non-empty common prefix, in which case we place both curr
1851 * and curl on the same side. Arbitrarily the left one.
1852 */
1853 if( pll == plr && prl == prr ) {
1854 gp = greater_prefix_internal(curl, curr);
7d2ac3d firsts attempts towards 8.3 compliance, using VARSIZE_ANY_EXHDR()
dim authored
1855 if( PREFIX_VARSIZE(gp) > 0 ) {
f61609e First picksplit() implementation of AndrewSN ideas, missing the preli…
dim authored
1856 unionL = greater_prefix_internal(unionL, gp);
1857 v->spl_left[v->spl_nleft++] = offl;
1858 v->spl_left[v->spl_nleft++] = offr;
1859 continue;
1860 }
1861 }
1862 /**
388a8a1 prefix opclass works again: picksplit() now has counts and offset rigths
dim authored
1863 * here pll <= plr and prl >= prr and (pll != plr || prl != prr)
f61609e First picksplit() implementation of AndrewSN ideas, missing the preli…
dim authored
1864 */
1865 unionL = greater_prefix_internal(unionL, curl);
1866 unionR = greater_prefix_internal(unionR, curr);
1867 v->spl_left[v->spl_nleft++] = offl;
1868 v->spl_right[v->spl_nright++] = offr;
1869 }
1870 else if( pll > plr && prl >= prr ) {
1871 unionR = greater_prefix_internal(unionR, curr);
1872 v->spl_right[v->spl_nright++] = offr;
1873 }
1874 else if( pll <= plr && prl < prr ) {
1875 /**
1876 * Current leftmost entry is added to listL
1877 */
1878 unionL = greater_prefix_internal(unionL, curl);
1879 v->spl_left[v->spl_nleft++] = offl;
1880 }
1881 else if( (pll - plr) < (prr - prl) ) {
1882 /**
1883 * All entries still in the list go into listL
1884 */
388a8a1 prefix opclass works again: picksplit() now has counts and offset rigths
dim authored
1885 for(; offl <= maxoff; offl = OffsetNumberNext(offl)) {
67b9a2f picksplit() first pass is about some kind of sorting. This commit sti…
dim authored
1886 curl = sorted[offl];
f61609e First picksplit() implementation of AndrewSN ideas, missing the preli…
dim authored
1887 unionL = greater_prefix_internal(unionL, curl);
1888 v->spl_left[v->spl_nleft++] = offl;
1889 }
1890 }
1891 else {
1892 /**
1893 * All entries still in the list go into listR
1894 */
388a8a1 prefix opclass works again: picksplit() now has counts and offset rigths
dim authored
1895 for(; offl <= maxoff; offl = OffsetNumberNext(offl)) {
67b9a2f picksplit() first pass is about some kind of sorting. This commit sti…
dim authored
1896 curl = sorted[offl];
f61609e First picksplit() implementation of AndrewSN ideas, missing the preli…
dim authored
1897 unionR = greater_prefix_internal(unionR, curl);
1898 v->spl_right[v->spl_nright++] = offl;
1899 }
1900 }
0fc1320 Importing prefix operator and opclass files
dim authored
1901 }
388a8a1 prefix opclass works again: picksplit() now has counts and offset rigths
dim authored
1902
1903 /**
1904 * The for loop continues while offl < offr. If maxoff is odd, it
1905 * could be that there's a last value to process. Here we choose
1906 * where to add it.
1907 */
f61609e First picksplit() implementation of AndrewSN ideas, missing the preli…
dim authored
1908 if( offl == offr ) {
67b9a2f picksplit() first pass is about some kind of sorting. This commit sti…
dim authored
1909 curl = sorted[offl];
f61609e First picksplit() implementation of AndrewSN ideas, missing the preli…
dim authored
1910 pll = prefix_penalty_internal(unionL, curl);
1911 plr = prefix_penalty_internal(unionR, curl);
1912
1913 if( pll < plr || (pll == plr && v->spl_nleft < v->spl_nright) ) {
388a8a1 prefix opclass works again: picksplit() now has counts and offset rigths
dim authored
1914 curl = sorted[offl];
1915 unionL = greater_prefix_internal(unionL, curl);
1916 v->spl_left[v->spl_nleft++] = offl;
f61609e First picksplit() implementation of AndrewSN ideas, missing the preli…
dim authored
1917 }
1918 else {
388a8a1 prefix opclass works again: picksplit() now has counts and offset rigths
dim authored
1919 curl = sorted[offl];
1920 unionR = greater_prefix_internal(unionR, curl);
1921 v->spl_right[v->spl_nright++] = offl;
f61609e First picksplit() implementation of AndrewSN ideas, missing the preli…
dim authored
1922 }
0fc1320 Importing prefix operator and opclass files
dim authored
1923 }
1924
1925 v->spl_ldatum = PointerGetDatum(unionL);
1926 v->spl_rdatum = PointerGetDatum(unionR);
3f678f4 First version working, some more doc, avoiding gcc complaints, better…
dim authored
1927
388a8a1 prefix opclass works again: picksplit() now has counts and offset rigths
dim authored
1928 /**
1929 * All read entries (maxoff) should have make it to the
1930 * GIST_SPLITVEC return value.
1931 */
1932 Assert(maxoff = v->spl_nleft+v->spl_nright);
1933
3f678f4 First version working, some more doc, avoiding gcc complaints, better…
dim authored
1934 #ifdef DEBUG
40f9a17 presort: reuse current union entry instead of zeroing its .n
dim authored
1935 elog(NOTICE, "gprefix_picksplit(): entryvec->n=%4d maxoff=%4d l=%4d r=%4d l+r=%4d unionL=%s unionR=%s",
2be7f8e picksplit() presort() SYGSEGV fixed
dim authored
1936 entryvec->n, maxoff, v->spl_nleft, v->spl_nright, v->spl_nleft+v->spl_nright,
67b9a2f picksplit() first pass is about some kind of sorting. This commit sti…
dim authored
1937 DatumGetCString(DirectFunctionCall1(textout,PointerGetDatum(unionL))),
2be7f8e picksplit() presort() SYGSEGV fixed
dim authored
1938 DatumGetCString(DirectFunctionCall1(textout,PointerGetDatum(unionR))));
3f678f4 First version working, some more doc, avoiding gcc complaints, better…
dim authored
1939 #endif
0fc1320 Importing prefix operator and opclass files
dim authored
1940
1941 PG_RETURN_POINTER(v);
1942 }
1943
1944 /**
1945 * Prefix union should return the greatest common prefix.
1946 */
1947 PG_FUNCTION_INFO_V1(gprefix_union);
1948 Datum
1949 gprefix_union(PG_FUNCTION_ARGS)
1950 {
1951 GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
1952 GISTENTRY *ent = entryvec->vector;
1953
1954 text *out, *tmp, *gp;
1955 int numranges, i = 0;
1956
1957 numranges = entryvec->n;
1958 tmp = (text *) DatumGetPointer(ent[0].key);
1959 out = tmp;
1960
1961 if( numranges == 1 ) {
1962 /**
1963 * We need to return a palloc()ed copy of ent[0].key (==tmp)
1964 */
1965 out = DatumGetTextPCopy(PointerGetDatum(tmp));
2be7f8e picksplit() presort() SYGSEGV fixed
dim authored
1966 #ifdef DEBUG_UNION
0fc1320 Importing prefix operator and opclass files
dim authored
1967 elog(NOTICE, "gprefix_union(%s) == %s",
1968 DatumGetCString(DirectFunctionCall1(textout,PointerGetDatum(tmp))),
1969 DatumGetCString(DirectFunctionCall1(textout,PointerGetDatum(out))));
1970 #endif
1971 PG_RETURN_POINTER(out);
1972 }
1973
1974 for (i = 1; i < numranges; i++) {
1975 tmp = (text *) DatumGetPointer(ent[i].key);
1976 gp = greater_prefix_internal(out, tmp);
2be7f8e picksplit() presort() SYGSEGV fixed
dim authored
1977 #ifdef DEBUG_UNION
0fc1320 Importing prefix operator and opclass files
dim authored
1978 elog(NOTICE, "gprefix_union: gp(%s, %s) == %s",
1979 DatumGetCString(DirectFunctionCall1(textout,PointerGetDatum(out))),
1980 DatumGetCString(DirectFunctionCall1(textout,PointerGetDatum(tmp))),
1981 DatumGetCString(DirectFunctionCall1(textout,PointerGetDatum(gp))));
1982 #endif
1983 out = gp;
1984 }
1985
2be7f8e picksplit() presort() SYGSEGV fixed
dim authored
1986 #ifdef DEBUG_UNION
0fc1320 Importing prefix operator and opclass files
dim authored
1987 elog(NOTICE, "gprefix_union: %s",
1988 DatumGetCString(DirectFunctionCall1(textout,PointerGetDatum(out))));
1989 #endif
1990
1991 PG_RETURN_POINTER(out);
1992 }
1993
1994 /**
1995 * GiST Compress and Decompress methods for prefix
1996 * do not do anything.
1997 */
1998 PG_FUNCTION_INFO_V1(gprefix_compress);
1999 Datum
2000 gprefix_compress(PG_FUNCTION_ARGS)
2001 {
2002 PG_RETURN_POINTER(PG_GETARG_POINTER(0));
2003 }
2004
2005 PG_FUNCTION_INFO_V1(gprefix_decompress);
2006 Datum
2007 gprefix_decompress(PG_FUNCTION_ARGS)
2008 {
2009 PG_RETURN_POINTER(PG_GETARG_POINTER(0));
2010 }
2011
2012 /**
2013 * Equality methods
2014 */
2015 PG_FUNCTION_INFO_V1(gprefix_same);
2016 Datum
2017 gprefix_same(PG_FUNCTION_ARGS)
2018 {
2019 text *v1 = (text *) PG_GETARG_POINTER(0);
2020 text *v2 = (text *) PG_GETARG_POINTER(1);
2021 bool *result = (bool *) PG_GETARG_POINTER(2);
2022
2023 *result = DirectFunctionCall2(texteq,
2024 PointerGetDatum(v1),
2025 PointerGetDatum(v2));
2026