2 * contrib/btree_gist/btree_utils_var.c
10 #include "btree_gist.h"
11 #include "btree_utils_var.h"
12 #include "utils/builtins.h"
13 #include "utils/pg_locale.h"
14 #include "utils/rel.h"
16 /* used for key sorting */
25 const gbtree_vinfo
*tinfo
;
31 PG_FUNCTION_INFO_V1(gbt_var_decompress
);
32 PG_FUNCTION_INFO_V1(gbt_var_fetch
);
36 gbt_var_decompress(PG_FUNCTION_ARGS
)
38 GISTENTRY
*entry
= (GISTENTRY
*) PG_GETARG_POINTER(0);
39 GBT_VARKEY
*key
= (GBT_VARKEY
*) PG_DETOAST_DATUM(entry
->key
);
41 if (key
!= (GBT_VARKEY
*) DatumGetPointer(entry
->key
))
43 GISTENTRY
*retval
= (GISTENTRY
*) palloc(sizeof(GISTENTRY
));
45 gistentryinit(*retval
, PointerGetDatum(key
),
46 entry
->rel
, entry
->page
,
47 entry
->offset
, false);
49 PG_RETURN_POINTER(retval
);
52 PG_RETURN_POINTER(entry
);
55 /* Returns a better readable representation of variable key ( sets pointer ) */
57 gbt_var_key_readable(const GBT_VARKEY
*k
)
61 r
.lower
= (bytea
*) &(((char *) k
)[VARHDRSZ
]);
62 if (VARSIZE(k
) > (VARHDRSZ
+ (VARSIZE(r
.lower
))))
63 r
.upper
= (bytea
*) &(((char *) k
)[VARHDRSZ
+ INTALIGN(VARSIZE(r
.lower
))]);
71 * Create a leaf-entry to store in the index, from a single Datum.
74 gbt_var_key_from_datum(const struct varlena
*u
)
76 int32 lowersize
= VARSIZE(u
);
79 r
= (GBT_VARKEY
*) palloc(lowersize
+ VARHDRSZ
);
80 memcpy(VARDATA(r
), u
, lowersize
);
81 SET_VARSIZE(r
, lowersize
+ VARHDRSZ
);
87 * Create an entry to store in the index, from lower and upper bound.
90 gbt_var_key_copy(const GBT_VARKEY_R
*u
)
92 int32 lowersize
= VARSIZE(u
->lower
);
93 int32 uppersize
= VARSIZE(u
->upper
);
96 r
= (GBT_VARKEY
*) palloc0(INTALIGN(lowersize
) + uppersize
+ VARHDRSZ
);
97 memcpy(VARDATA(r
), u
->lower
, lowersize
);
98 memcpy(VARDATA(r
) + INTALIGN(lowersize
), u
->upper
, uppersize
);
99 SET_VARSIZE(r
, INTALIGN(lowersize
) + uppersize
+ VARHDRSZ
);
106 gbt_var_leaf2node(GBT_VARKEY
*leaf
, const gbtree_vinfo
*tinfo
, FmgrInfo
*flinfo
)
108 GBT_VARKEY
*out
= leaf
;
111 out
= tinfo
->f_l2n(leaf
, flinfo
);
118 * returns the common prefix length of a node key
121 gbt_var_node_cp_len(const GBT_VARKEY
*node
, const gbtree_vinfo
*tinfo
)
123 GBT_VARKEY_R r
= gbt_var_key_readable(node
);
126 int32 t1len
= VARSIZE(r
.lower
) - VARHDRSZ
;
127 int32 t2len
= VARSIZE(r
.upper
) - VARHDRSZ
;
128 int32 ml
= Min(t1len
, t2len
);
129 char *p1
= VARDATA(r
.lower
);
130 char *p2
= VARDATA(r
.upper
);
137 if (tinfo
->eml
> 1 && l
== 0)
139 if ((l
= pg_mblen(p1
)) != pg_mblen(p2
))
161 return ml
; /* lower == upper */
166 * returns true, if query matches prefix ( common prefix )
169 gbt_bytea_pf_match(const bytea
*pf
, const bytea
*query
, const gbtree_vinfo
*tinfo
)
172 int32 qlen
= VARSIZE(query
) - VARHDRSZ
;
173 int32 nlen
= VARSIZE(pf
) - VARHDRSZ
;
177 char *q
= VARDATA(query
);
178 char *n
= VARDATA(pf
);
180 out
= (memcmp(q
, n
, nlen
) == 0);
188 * returns true, if query matches node using common prefix
191 gbt_var_node_pf_match(const GBT_VARKEY_R
*node
, const bytea
*query
, const gbtree_vinfo
*tinfo
)
193 return (tinfo
->trnc
&&
194 (gbt_bytea_pf_match(node
->lower
, query
, tinfo
) ||
195 gbt_bytea_pf_match(node
->upper
, query
, tinfo
)));
200 * truncates / compresses the node key
201 * cpf_length .. common prefix length
204 gbt_var_node_truncate(const GBT_VARKEY
*node
, int32 cpf_length
, const gbtree_vinfo
*tinfo
)
206 GBT_VARKEY
*out
= NULL
;
207 GBT_VARKEY_R r
= gbt_var_key_readable(node
);
208 int32 len1
= VARSIZE(r
.lower
) - VARHDRSZ
;
209 int32 len2
= VARSIZE(r
.upper
) - VARHDRSZ
;
213 len1
= Min(len1
, (cpf_length
+ 1));
214 len2
= Min(len2
, (cpf_length
+ 1));
216 si
= 2 * VARHDRSZ
+ INTALIGN(len1
+ VARHDRSZ
) + len2
;
217 out
= (GBT_VARKEY
*) palloc0(si
);
218 SET_VARSIZE(out
, si
);
220 memcpy(VARDATA(out
), r
.lower
, len1
+ VARHDRSZ
);
221 SET_VARSIZE(VARDATA(out
), len1
+ VARHDRSZ
);
223 out2
= VARDATA(out
) + INTALIGN(len1
+ VARHDRSZ
);
224 memcpy(out2
, r
.upper
, len2
+ VARHDRSZ
);
225 SET_VARSIZE(out2
, len2
+ VARHDRSZ
);
233 gbt_var_bin_union(Datum
*u
, GBT_VARKEY
*e
, Oid collation
,
234 const gbtree_vinfo
*tinfo
, FmgrInfo
*flinfo
)
236 GBT_VARKEY_R eo
= gbt_var_key_readable(e
);
239 if (eo
.lower
== eo
.upper
) /* leaf */
243 tmp
= gbt_var_leaf2node(e
, tinfo
, flinfo
);
245 eo
= gbt_var_key_readable(tmp
);
248 if (DatumGetPointer(*u
))
250 GBT_VARKEY_R ro
= gbt_var_key_readable((GBT_VARKEY
*) DatumGetPointer(*u
));
256 if (tinfo
->f_cmp(ro
.lower
, eo
.lower
, collation
, flinfo
) > 0)
262 if (tinfo
->f_cmp(ro
.upper
, eo
.upper
, collation
, flinfo
) < 0)
269 *u
= PointerGetDatum(gbt_var_key_copy(&nr
));
275 *u
= PointerGetDatum(gbt_var_key_copy(&nr
));
281 gbt_var_compress(GISTENTRY
*entry
, const gbtree_vinfo
*tinfo
)
287 struct varlena
*leaf
= PG_DETOAST_DATUM(entry
->key
);
290 r
= gbt_var_key_from_datum(leaf
);
292 retval
= palloc(sizeof(GISTENTRY
));
293 gistentryinit(*retval
, PointerGetDatum(r
),
294 entry
->rel
, entry
->page
,
295 entry
->offset
, true);
305 gbt_var_fetch(PG_FUNCTION_ARGS
)
307 GISTENTRY
*entry
= (GISTENTRY
*) PG_GETARG_POINTER(0);
308 GBT_VARKEY
*key
= (GBT_VARKEY
*) PG_DETOAST_DATUM(entry
->key
);
309 GBT_VARKEY_R r
= gbt_var_key_readable(key
);
312 retval
= palloc(sizeof(GISTENTRY
));
313 gistentryinit(*retval
, PointerGetDatum(r
.lower
),
314 entry
->rel
, entry
->page
,
315 entry
->offset
, true);
317 PG_RETURN_POINTER(retval
);
322 gbt_var_union(const GistEntryVector
*entryvec
, int32
*size
, Oid collation
,
323 const gbtree_vinfo
*tinfo
, FmgrInfo
*flinfo
)
326 numranges
= entryvec
->n
;
331 *size
= sizeof(GBT_VARKEY
);
333 cur
= (GBT_VARKEY
*) DatumGetPointer(entryvec
->vector
[0].key
);
334 rk
= gbt_var_key_readable(cur
);
335 out
= PointerGetDatum(gbt_var_key_copy(&rk
));
337 for (i
= 1; i
< numranges
; i
++)
339 cur
= (GBT_VARKEY
*) DatumGetPointer(entryvec
->vector
[i
].key
);
340 gbt_var_bin_union(&out
, cur
, collation
, tinfo
, flinfo
);
344 /* Truncate (=compress) key */
348 GBT_VARKEY
*trc
= NULL
;
350 plen
= gbt_var_node_cp_len((GBT_VARKEY
*) DatumGetPointer(out
), tinfo
);
351 trc
= gbt_var_node_truncate((GBT_VARKEY
*) DatumGetPointer(out
), plen
+ 1, tinfo
);
353 out
= PointerGetDatum(trc
);
356 return ((GBT_VARKEY
*) DatumGetPointer(out
));
361 gbt_var_same(Datum d1
, Datum d2
, Oid collation
,
362 const gbtree_vinfo
*tinfo
, FmgrInfo
*flinfo
)
364 GBT_VARKEY
*t1
= (GBT_VARKEY
*) DatumGetPointer(d1
);
365 GBT_VARKEY
*t2
= (GBT_VARKEY
*) DatumGetPointer(d2
);
369 r1
= gbt_var_key_readable(t1
);
370 r2
= gbt_var_key_readable(t2
);
372 return (tinfo
->f_cmp(r1
.lower
, r2
.lower
, collation
, flinfo
) == 0 &&
373 tinfo
->f_cmp(r1
.upper
, r2
.upper
, collation
, flinfo
) == 0);
378 gbt_var_penalty(float *res
, const GISTENTRY
*o
, const GISTENTRY
*n
,
379 Oid collation
, const gbtree_vinfo
*tinfo
, FmgrInfo
*flinfo
)
381 GBT_VARKEY
*orge
= (GBT_VARKEY
*) DatumGetPointer(o
->key
);
382 GBT_VARKEY
*newe
= (GBT_VARKEY
*) DatumGetPointer(n
->key
);
388 nk
= gbt_var_key_readable(newe
);
389 if (nk
.lower
== nk
.upper
) /* leaf */
393 tmp
= gbt_var_leaf2node(newe
, tinfo
, flinfo
);
395 nk
= gbt_var_key_readable(tmp
);
397 ok
= gbt_var_key_readable(orge
);
399 if ((VARSIZE(ok
.lower
) - VARHDRSZ
) == 0 && (VARSIZE(ok
.upper
) - VARHDRSZ
) == 0)
401 else if (!((tinfo
->f_cmp(nk
.lower
, ok
.lower
, collation
, flinfo
) >= 0 ||
402 gbt_bytea_pf_match(ok
.lower
, nk
.lower
, tinfo
)) &&
403 (tinfo
->f_cmp(nk
.upper
, ok
.upper
, collation
, flinfo
) <= 0 ||
404 gbt_bytea_pf_match(ok
.upper
, nk
.upper
, tinfo
))))
406 Datum d
= PointerGetDatum(0);
411 gbt_var_bin_union(&d
, orge
, collation
, tinfo
, flinfo
);
412 ol
= gbt_var_node_cp_len((GBT_VARKEY
*) DatumGetPointer(d
), tinfo
);
413 gbt_var_bin_union(&d
, newe
, collation
, tinfo
, flinfo
);
414 ul
= gbt_var_node_cp_len((GBT_VARKEY
*) DatumGetPointer(d
), tinfo
);
418 dres
= (ol
- ul
); /* reduction of common prefix len */
422 GBT_VARKEY_R uk
= gbt_var_key_readable((GBT_VARKEY
*) DatumGetPointer(d
));
423 unsigned char tmp
[4];
425 tmp
[0] = (unsigned char) (((VARSIZE(ok
.lower
) - VARHDRSZ
) <= ul
) ? 0 : (VARDATA(ok
.lower
)[ul
]));
426 tmp
[1] = (unsigned char) (((VARSIZE(uk
.lower
) - VARHDRSZ
) <= ul
) ? 0 : (VARDATA(uk
.lower
)[ul
]));
427 tmp
[2] = (unsigned char) (((VARSIZE(ok
.upper
) - VARHDRSZ
) <= ul
) ? 0 : (VARDATA(ok
.upper
)[ul
]));
428 tmp
[3] = (unsigned char) (((VARSIZE(uk
.upper
) - VARHDRSZ
) <= ul
) ? 0 : (VARDATA(uk
.upper
)[ul
]));
429 dres
= Abs(tmp
[0] - tmp
[1]) + Abs(tmp
[3] - tmp
[2]);
434 *res
+= (float) (dres
/ ((double) (ol
+ 1)));
435 *res
*= (FLT_MAX
/ (o
->rel
->rd_att
->natts
+ 1));
443 gbt_vsrt_cmp(const void *a
, const void *b
, void *arg
)
445 GBT_VARKEY_R ar
= gbt_var_key_readable(((const Vsrt
*) a
)->t
);
446 GBT_VARKEY_R br
= gbt_var_key_readable(((const Vsrt
*) b
)->t
);
447 const gbt_vsrt_arg
*varg
= (const gbt_vsrt_arg
*) arg
;
450 res
= varg
->tinfo
->f_cmp(ar
.lower
, br
.lower
, varg
->collation
, varg
->flinfo
);
452 return varg
->tinfo
->f_cmp(ar
.upper
, br
.upper
, varg
->collation
, varg
->flinfo
);
458 gbt_var_picksplit(const GistEntryVector
*entryvec
, GIST_SPLITVEC
*v
,
459 Oid collation
, const gbtree_vinfo
*tinfo
, FmgrInfo
*flinfo
)
462 maxoff
= entryvec
->n
- 1;
467 GBT_VARKEY
**sv
= NULL
;
470 arr
= (Vsrt
*) palloc((maxoff
+ 1) * sizeof(Vsrt
));
471 nbytes
= (maxoff
+ 2) * sizeof(OffsetNumber
);
472 v
->spl_left
= (OffsetNumber
*) palloc(nbytes
);
473 v
->spl_right
= (OffsetNumber
*) palloc(nbytes
);
474 v
->spl_ldatum
= PointerGetDatum(0);
475 v
->spl_rdatum
= PointerGetDatum(0);
479 sv
= palloc(sizeof(bytea
*) * (maxoff
+ 1));
483 for (i
= FirstOffsetNumber
; i
<= maxoff
; i
= OffsetNumberNext(i
))
487 cur
= (char *) DatumGetPointer(entryvec
->vector
[i
].key
);
488 ro
= gbt_var_key_readable((GBT_VARKEY
*) cur
);
489 if (ro
.lower
== ro
.upper
) /* leaf */
491 sv
[svcntr
] = gbt_var_leaf2node((GBT_VARKEY
*) cur
, tinfo
, flinfo
);
492 arr
[i
].t
= sv
[svcntr
];
493 if (sv
[svcntr
] != (GBT_VARKEY
*) cur
)
497 arr
[i
].t
= (GBT_VARKEY
*) cur
;
503 varg
.collation
= collation
;
504 varg
.flinfo
= flinfo
;
505 qsort_arg((void *) &arr
[FirstOffsetNumber
],
506 maxoff
- FirstOffsetNumber
+ 1,
511 /* We do simply create two parts */
513 for (i
= FirstOffsetNumber
; i
<= maxoff
; i
= OffsetNumberNext(i
))
515 if (i
<= (maxoff
- FirstOffsetNumber
+ 1) / 2)
517 gbt_var_bin_union(&v
->spl_ldatum
, arr
[i
].t
, collation
, tinfo
, flinfo
);
518 v
->spl_left
[v
->spl_nleft
] = arr
[i
].i
;
523 gbt_var_bin_union(&v
->spl_rdatum
, arr
[i
].t
, collation
, tinfo
, flinfo
);
524 v
->spl_right
[v
->spl_nright
] = arr
[i
].i
;
529 /* Truncate (=compress) key */
532 int32 ll
= gbt_var_node_cp_len((GBT_VARKEY
*) DatumGetPointer(v
->spl_ldatum
), tinfo
);
533 int32 lr
= gbt_var_node_cp_len((GBT_VARKEY
*) DatumGetPointer(v
->spl_rdatum
), tinfo
);
540 dl
= gbt_var_node_truncate((GBT_VARKEY
*) DatumGetPointer(v
->spl_ldatum
), ll
, tinfo
);
541 dr
= gbt_var_node_truncate((GBT_VARKEY
*) DatumGetPointer(v
->spl_rdatum
), ll
, tinfo
);
542 v
->spl_ldatum
= PointerGetDatum(dl
);
543 v
->spl_rdatum
= PointerGetDatum(dr
);
551 * The GiST consistent method
554 gbt_var_consistent(GBT_VARKEY_R
*key
,
556 StrategyNumber strategy
,
559 const gbtree_vinfo
*tinfo
,
566 case BTLessEqualStrategyNumber
:
568 retval
= tinfo
->f_ge(query
, key
->lower
, collation
, flinfo
);
570 retval
= tinfo
->f_cmp(query
, key
->lower
, collation
, flinfo
) >= 0
571 || gbt_var_node_pf_match(key
, query
, tinfo
);
573 case BTLessStrategyNumber
:
575 retval
= tinfo
->f_gt(query
, key
->lower
, collation
, flinfo
);
577 retval
= tinfo
->f_cmp(query
, key
->lower
, collation
, flinfo
) >= 0
578 || gbt_var_node_pf_match(key
, query
, tinfo
);
580 case BTEqualStrategyNumber
:
582 retval
= tinfo
->f_eq(query
, key
->lower
, collation
, flinfo
);
585 (tinfo
->f_cmp(key
->lower
, query
, collation
, flinfo
) <= 0 &&
586 tinfo
->f_cmp(query
, key
->upper
, collation
, flinfo
) <= 0) ||
587 gbt_var_node_pf_match(key
, query
, tinfo
);
589 case BTGreaterStrategyNumber
:
591 retval
= tinfo
->f_lt(query
, key
->upper
, collation
, flinfo
);
593 retval
= tinfo
->f_cmp(query
, key
->upper
, collation
, flinfo
) <= 0
594 || gbt_var_node_pf_match(key
, query
, tinfo
);
596 case BTGreaterEqualStrategyNumber
:
598 retval
= tinfo
->f_le(query
, key
->upper
, collation
, flinfo
);
600 retval
= tinfo
->f_cmp(query
, key
->upper
, collation
, flinfo
) <= 0
601 || gbt_var_node_pf_match(key
, query
, tinfo
);
603 case BtreeGistNotEqualStrategyNumber
:
604 retval
= !(tinfo
->f_eq(query
, key
->lower
, collation
, flinfo
) &&
605 tinfo
->f_eq(query
, key
->upper
, collation
, flinfo
));