4 #include "btree_gist.h"
10 #include "btree_utils_var.h"
11 #include "utils/pg_locale.h"
12 #include "utils/builtins.h"
13 #include "utils/rel.h"
15 PG_FUNCTION_INFO_V1(gbt_var_decompress
);
16 Datum
gbt_var_decompress(PG_FUNCTION_ARGS
);
20 gbt_var_decompress(PG_FUNCTION_ARGS
)
22 GISTENTRY
*entry
= (GISTENTRY
*) PG_GETARG_POINTER(0);
23 GBT_VARKEY
*key
= (GBT_VARKEY
*) DatumGetPointer(PG_DETOAST_DATUM(entry
->key
));
25 if (key
!= (GBT_VARKEY
*) DatumGetPointer(entry
->key
))
27 GISTENTRY
*retval
= (GISTENTRY
*) palloc(sizeof(GISTENTRY
));
29 gistentryinit(*retval
, PointerGetDatum(key
),
30 entry
->rel
, entry
->page
,
31 entry
->offset
, FALSE
);
33 PG_RETURN_POINTER(retval
);
36 PG_RETURN_POINTER(entry
);
39 /* Returns a better readable representaion of variable key ( sets pointer ) */
41 gbt_var_key_readable(const GBT_VARKEY
*k
)
46 r
.lower
= (bytea
*) &(((char *) k
)[VARHDRSZ
]);
47 if (VARSIZE(k
) > (VARHDRSZ
+ (VARSIZE(r
.lower
))))
48 r
.upper
= (bytea
*) &(((char *) k
)[VARHDRSZ
+ INTALIGN(VARSIZE(r
.lower
))]);
56 gbt_var_key_copy(const GBT_VARKEY_R
*u
, bool force_node
)
60 if (u
->lower
== u
->upper
&& !force_node
)
62 r
= (GBT_VARKEY
*) palloc(VARSIZE(u
->lower
) + VARHDRSZ
);
63 memcpy(VARDATA(r
), u
->lower
, VARSIZE(u
->lower
));
64 SET_VARSIZE(r
, VARSIZE(u
->lower
) + VARHDRSZ
);
68 r
= (GBT_VARKEY
*) palloc(INTALIGN(VARSIZE(u
->lower
)) + VARSIZE(u
->upper
) + VARHDRSZ
);
69 memcpy(VARDATA(r
), u
->lower
, VARSIZE(u
->lower
));
70 memcpy(VARDATA(r
) + INTALIGN(VARSIZE(u
->lower
)), u
->upper
, VARSIZE(u
->upper
));
71 SET_VARSIZE(r
, INTALIGN(VARSIZE(u
->lower
)) + VARSIZE(u
->upper
) + VARHDRSZ
);
78 gbt_var_leaf2node(GBT_VARKEY
*leaf
, const gbtree_vinfo
*tinfo
)
80 GBT_VARKEY
*out
= leaf
;
83 out
= (*tinfo
->f_l2n
) (leaf
);
90 * returns the common prefix length of a node key
93 gbt_var_node_cp_len(const GBT_VARKEY
*node
, const gbtree_vinfo
*tinfo
)
96 GBT_VARKEY_R r
= gbt_var_key_readable(node
);
99 int32 t1len
= VARSIZE(r
.lower
) - VARHDRSZ
;
100 int32 t2len
= VARSIZE(r
.upper
) - VARHDRSZ
;
101 int32 ml
= Min(t1len
, t2len
);
103 char *p1
= VARDATA(r
.lower
);
104 char *p2
= VARDATA(r
.upper
);
111 if (tinfo
->eml
> 1 && l
== 0)
114 if ((l
= pg_mblen(p1
)) != pg_mblen(p2
))
136 return (ml
); /* lower == upper */
141 * returns true, if query matches prefix ( common prefix )
144 gbt_bytea_pf_match(const bytea
*pf
, const bytea
*query
, const gbtree_vinfo
*tinfo
)
149 int32 qlen
= VARSIZE(query
) - VARHDRSZ
;
150 int32 nlen
= VARSIZE(pf
) - VARHDRSZ
;
154 char *q
= VARDATA(query
);
155 char *n
= VARDATA(pf
);
159 out
= (varstr_cmp(q
, nlen
, n
, nlen
) == 0);
164 for (k
= 0; k
< nlen
; k
++)
185 * returns true, if query matches node using common prefix
189 gbt_var_node_pf_match(const GBT_VARKEY_R
*node
, const bytea
*query
, const gbtree_vinfo
*tinfo
)
192 return (tinfo
->trnc
&& (
193 gbt_bytea_pf_match(node
->lower
, query
, tinfo
) ||
194 gbt_bytea_pf_match(node
->upper
, query
, tinfo
)
201 * truncates / compresses the node key
202 * cpf_length .. common prefix length
205 gbt_var_node_truncate(const GBT_VARKEY
*node
, int32 cpf_length
, const gbtree_vinfo
*tinfo
)
207 GBT_VARKEY
*out
= NULL
;
208 GBT_VARKEY_R r
= gbt_var_key_readable(node
);
209 int32 len1
= VARSIZE(r
.lower
) - VARHDRSZ
;
210 int32 len2
= VARSIZE(r
.upper
) - VARHDRSZ
;
214 len1
= Min(len1
, (cpf_length
+ 1));
215 len2
= Min(len2
, (cpf_length
+ 1));
217 si
= 2 * VARHDRSZ
+ INTALIGN(len1
+ VARHDRSZ
) + len2
;
218 out
= (GBT_VARKEY
*) palloc(si
);
219 SET_VARSIZE(out
, si
);
221 memcpy(VARDATA(out
), r
.lower
, len1
+ VARHDRSZ
);
222 SET_VARSIZE(VARDATA(out
), len1
+ VARHDRSZ
);
224 out2
= VARDATA(out
) + INTALIGN(len1
+ VARHDRSZ
);
225 memcpy(out2
, r
.upper
, len2
+ VARHDRSZ
);
226 SET_VARSIZE(out2
, len2
+ VARHDRSZ
);
234 gbt_var_bin_union(Datum
*u
, GBT_VARKEY
*e
, const gbtree_vinfo
*tinfo
)
237 GBT_VARKEY
*nk
= NULL
;
238 GBT_VARKEY
*tmp
= NULL
;
240 GBT_VARKEY_R eo
= gbt_var_key_readable(e
);
242 if (eo
.lower
== eo
.upper
) /* leaf */
244 tmp
= gbt_var_leaf2node(e
, tinfo
);
246 eo
= gbt_var_key_readable(tmp
);
249 if (DatumGetPointer(*u
))
252 GBT_VARKEY_R ro
= gbt_var_key_readable((GBT_VARKEY
*) DatumGetPointer(*u
));
254 if ((*tinfo
->f_cmp
) ((bytea
*) ro
.lower
, (bytea
*) eo
.lower
) > 0)
258 nk
= gbt_var_key_copy(&nr
, TRUE
);
261 if ((*tinfo
->f_cmp
) ((bytea
*) ro
.upper
, (bytea
*) eo
.upper
) < 0)
265 nk
= gbt_var_key_copy(&nr
, TRUE
);
269 *u
= PointerGetDatum(nk
);
275 *u
= PointerGetDatum(gbt_var_key_copy(&nr
, TRUE
));
282 gbt_var_compress(GISTENTRY
*entry
, const gbtree_vinfo
*tinfo
)
289 GBT_VARKEY
*r
= NULL
;
290 bytea
*leaf
= (bytea
*) DatumGetPointer(PG_DETOAST_DATUM(entry
->key
));
293 u
.lower
= u
.upper
= leaf
;
294 r
= gbt_var_key_copy(&u
, FALSE
);
296 retval
= palloc(sizeof(GISTENTRY
));
297 gistentryinit(*retval
, PointerGetDatum(r
),
298 entry
->rel
, entry
->page
,
299 entry
->offset
, TRUE
);
310 gbt_var_union(const GistEntryVector
*entryvec
, int32
*size
, const gbtree_vinfo
*tinfo
)
314 numranges
= entryvec
->n
;
319 *size
= sizeof(GBT_VARKEY
);
321 cur
= (GBT_VARKEY
*) DatumGetPointer(entryvec
->vector
[0].key
);
322 rk
= gbt_var_key_readable(cur
);
323 out
= PointerGetDatum(gbt_var_key_copy(&rk
, TRUE
));
325 for (i
= 1; i
< numranges
; i
++)
327 cur
= (GBT_VARKEY
*) DatumGetPointer(entryvec
->vector
[i
].key
);
328 gbt_var_bin_union(&out
, cur
, tinfo
);
332 /* Truncate (=compress) key */
336 GBT_VARKEY
*trc
= NULL
;
338 plen
= gbt_var_node_cp_len((GBT_VARKEY
*) DatumGetPointer(out
), tinfo
);
339 trc
= gbt_var_node_truncate((GBT_VARKEY
*) DatumGetPointer(out
), plen
+ 1, tinfo
);
341 out
= PointerGetDatum(trc
);
344 return ((GBT_VARKEY
*) DatumGetPointer(out
));
349 gbt_var_same(bool *result
, const Datum d1
, const Datum d2
, const gbtree_vinfo
*tinfo
)
352 GBT_VARKEY
*t1
= (GBT_VARKEY
*) DatumGetPointer(d1
);
353 GBT_VARKEY
*t2
= (GBT_VARKEY
*) DatumGetPointer(d2
);
357 r1
= gbt_var_key_readable(t1
);
358 r2
= gbt_var_key_readable(t2
);
362 *result
= (((*tinfo
->f_cmp
) ((bytea
*) r1
.lower
, (bytea
*) r2
.lower
) == 0
363 && (*tinfo
->f_cmp
) ((bytea
*) r1
.upper
, (bytea
*) r2
.upper
) == 0) ? TRUE
: FALSE
);
366 *result
= (t1
== NULL
&& t2
== NULL
) ? TRUE
: FALSE
;
368 PG_RETURN_POINTER(result
);
374 gbt_var_penalty(float *res
, const GISTENTRY
*o
, const GISTENTRY
*n
, const gbtree_vinfo
*tinfo
)
377 GBT_VARKEY
*orge
= (GBT_VARKEY
*) DatumGetPointer(o
->key
);
378 GBT_VARKEY
*newe
= (GBT_VARKEY
*) DatumGetPointer(n
->key
);
381 GBT_VARKEY
*tmp
= NULL
;
385 nk
= gbt_var_key_readable(newe
);
386 if (nk
.lower
== nk
.upper
) /* leaf */
388 tmp
= gbt_var_leaf2node(newe
, tinfo
);
390 nk
= gbt_var_key_readable(tmp
);
392 ok
= gbt_var_key_readable(orge
);
394 if ((VARSIZE(ok
.lower
) - VARHDRSZ
) == 0 && (VARSIZE(ok
.upper
) - VARHDRSZ
) == 0)
398 ((*tinfo
->f_cmp
) (nk
.lower
, ok
.lower
) >= 0 || gbt_bytea_pf_match(ok
.lower
, nk
.lower
, tinfo
)) &&
399 ((*tinfo
->f_cmp
) (nk
.upper
, ok
.upper
) <= 0 || gbt_bytea_pf_match(ok
.upper
, nk
.upper
, tinfo
))
403 Datum d
= PointerGetDatum(0);
408 gbt_var_bin_union(&d
, orge
, tinfo
);
409 ol
= gbt_var_node_cp_len((GBT_VARKEY
*) DatumGetPointer(d
), tinfo
);
410 gbt_var_bin_union(&d
, newe
, tinfo
);
411 ul
= gbt_var_node_cp_len((GBT_VARKEY
*) DatumGetPointer(d
), tinfo
);
415 dres
= (ol
- ul
); /* lost of common prefix len */
419 GBT_VARKEY_R uk
= gbt_var_key_readable((GBT_VARKEY
*) DatumGetPointer(d
));
423 tmp
[0] = ((VARSIZE(ok
.lower
) - VARHDRSZ
) == ul
) ? (CHAR_MIN
) : (VARDATA(ok
.lower
)[ul
]);
424 tmp
[1] = ((VARSIZE(uk
.lower
) - VARHDRSZ
) == ul
) ? (CHAR_MIN
) : (VARDATA(uk
.lower
)[ul
]);
425 tmp
[2] = ((VARSIZE(ok
.upper
) - VARHDRSZ
) == ul
) ? (CHAR_MIN
) : (VARDATA(ok
.upper
)[ul
]);
426 tmp
[3] = ((VARSIZE(uk
.upper
) - VARHDRSZ
) == ul
) ? (CHAR_MIN
) : (VARDATA(uk
.upper
)[ul
]);
427 dres
= (tmp
[0] - tmp
[1]) +
433 *res
+= (float) (dres
/ ((double) (ol
+ 1)));
434 *res
*= (FLT_MAX
/ (o
->rel
->rd_att
->natts
+ 1));
442 gbt_vsrt_cmp(const void *a
, const void *b
, void *arg
)
444 GBT_VARKEY_R ar
= gbt_var_key_readable(((const Vsrt
*) a
)->t
);
445 GBT_VARKEY_R br
= gbt_var_key_readable(((const Vsrt
*) b
)->t
);
446 const gbtree_vinfo
*tinfo
= (const gbtree_vinfo
*) arg
;
448 return (*tinfo
->f_cmp
) (ar
.lower
, br
.lower
);
452 gbt_var_picksplit(const GistEntryVector
*entryvec
, GIST_SPLITVEC
*v
, const gbtree_vinfo
*tinfo
)
455 maxoff
= entryvec
->n
- 1;
460 GBT_VARKEY
**sv
= NULL
;
462 arr
= (Vsrt
*) palloc((maxoff
+ 1) * sizeof(Vsrt
));
463 nbytes
= (maxoff
+ 2) * sizeof(OffsetNumber
);
464 v
->spl_left
= (OffsetNumber
*) palloc(nbytes
);
465 v
->spl_right
= (OffsetNumber
*) palloc(nbytes
);
466 v
->spl_ldatum
= PointerGetDatum(0);
467 v
->spl_rdatum
= PointerGetDatum(0);
471 sv
= palloc(sizeof(bytea
*) * (maxoff
+ 1));
475 for (i
= FirstOffsetNumber
; i
<= maxoff
; i
= OffsetNumberNext(i
))
479 cur
= (char *) DatumGetPointer(entryvec
->vector
[i
].key
);
480 ro
= gbt_var_key_readable((GBT_VARKEY
*) cur
);
481 if (ro
.lower
== ro
.upper
) /* leaf */
483 sv
[svcntr
] = gbt_var_leaf2node((GBT_VARKEY
*) cur
, tinfo
);
484 arr
[i
].t
= sv
[svcntr
];
485 if (sv
[svcntr
] != (GBT_VARKEY
*) cur
)
489 arr
[i
].t
= (GBT_VARKEY
*) cur
;
494 qsort_arg((void *) &arr
[FirstOffsetNumber
],
495 maxoff
- FirstOffsetNumber
+ 1,
500 /* We do simply create two parts */
502 for (i
= FirstOffsetNumber
; i
<= maxoff
; i
= OffsetNumberNext(i
))
504 if (i
<= (maxoff
- FirstOffsetNumber
+ 1) / 2)
506 gbt_var_bin_union(&v
->spl_ldatum
, arr
[i
].t
, tinfo
);
507 v
->spl_left
[v
->spl_nleft
] = arr
[i
].i
;
512 gbt_var_bin_union(&v
->spl_rdatum
, arr
[i
].t
, tinfo
);
513 v
->spl_right
[v
->spl_nright
] = arr
[i
].i
;
518 /* Truncate (=compress) key */
521 int32 ll
= gbt_var_node_cp_len((GBT_VARKEY
*) DatumGetPointer(v
->spl_ldatum
), tinfo
);
522 int32 lr
= gbt_var_node_cp_len((GBT_VARKEY
*) DatumGetPointer(v
->spl_rdatum
), tinfo
);
529 dl
= gbt_var_node_truncate((GBT_VARKEY
*) DatumGetPointer(v
->spl_ldatum
), ll
, tinfo
);
530 dr
= gbt_var_node_truncate((GBT_VARKEY
*) DatumGetPointer(v
->spl_rdatum
), ll
, tinfo
);
531 v
->spl_ldatum
= PointerGetDatum(dl
);
532 v
->spl_rdatum
= PointerGetDatum(dr
);
540 * The GiST consistent method
546 const StrategyNumber
*strategy
,
548 const gbtree_vinfo
*tinfo
555 case BTLessEqualStrategyNumber
:
557 retval
= (*tinfo
->f_ge
) (query
, (void *) key
->lower
);
559 retval
= (*tinfo
->f_cmp
) ((bytea
*) query
, key
->lower
) >= 0
560 || gbt_var_node_pf_match(key
, query
, tinfo
);
562 case BTLessStrategyNumber
:
564 retval
= (*tinfo
->f_gt
) (query
, (void *) key
->lower
);
566 retval
= (*tinfo
->f_cmp
) ((bytea
*) query
, key
->lower
) >= 0
567 || gbt_var_node_pf_match(key
, query
, tinfo
);
569 case BTEqualStrategyNumber
:
571 retval
= (*tinfo
->f_eq
) (query
, (void *) key
->lower
);
575 (*tinfo
->f_cmp
) (key
->lower
, (bytea
*) query
) <= 0 &&
576 (*tinfo
->f_cmp
) ((bytea
*) query
, (void *) key
->upper
) <= 0
577 ) || gbt_var_node_pf_match(key
, query
, tinfo
)
580 case BTGreaterStrategyNumber
:
582 retval
= (*tinfo
->f_lt
) (query
, (void *) key
->upper
);
584 retval
= (*tinfo
->f_cmp
) ((bytea
*) query
, key
->upper
) <= 0
585 || gbt_var_node_pf_match(key
, query
, tinfo
);
587 case BTGreaterEqualStrategyNumber
:
589 retval
= (*tinfo
->f_le
) (query
, (void *) key
->upper
);
591 retval
= (*tinfo
->f_cmp
) ((bytea
*) query
, key
->upper
) <= 0
592 || gbt_var_node_pf_match(key
, query
, tinfo
);