2 * contrib/btree_gist/btree_utils_var.c
10 #include "btree_gist.h"
11 #include "btree_utils_var.h"
12 #include "mb/pg_wchar.h"
13 #include "utils/rel.h"
15 /* used for key sorting */
24 const gbtree_vinfo
*tinfo
;
30 PG_FUNCTION_INFO_V1(gbt_var_decompress
);
31 PG_FUNCTION_INFO_V1(gbt_var_fetch
);
35 gbt_var_decompress(PG_FUNCTION_ARGS
)
37 GISTENTRY
*entry
= (GISTENTRY
*) PG_GETARG_POINTER(0);
38 GBT_VARKEY
*key
= (GBT_VARKEY
*) PG_DETOAST_DATUM(entry
->key
);
40 if (key
!= (GBT_VARKEY
*) DatumGetPointer(entry
->key
))
42 GISTENTRY
*retval
= (GISTENTRY
*) palloc(sizeof(GISTENTRY
));
44 gistentryinit(*retval
, PointerGetDatum(key
),
45 entry
->rel
, entry
->page
,
46 entry
->offset
, false);
48 PG_RETURN_POINTER(retval
);
51 PG_RETURN_POINTER(entry
);
54 /* Returns a better readable representation of variable key ( sets pointer ) */
56 gbt_var_key_readable(const GBT_VARKEY
*k
)
60 r
.lower
= (bytea
*) &(((char *) k
)[VARHDRSZ
]);
61 if (VARSIZE(k
) > (VARHDRSZ
+ (VARSIZE(r
.lower
))))
62 r
.upper
= (bytea
*) &(((char *) k
)[VARHDRSZ
+ INTALIGN(VARSIZE(r
.lower
))]);
70 * Create a leaf-entry to store in the index, from a single Datum.
73 gbt_var_key_from_datum(const struct varlena
*u
)
75 int32 lowersize
= VARSIZE(u
);
78 r
= (GBT_VARKEY
*) palloc(lowersize
+ VARHDRSZ
);
79 memcpy(VARDATA(r
), u
, lowersize
);
80 SET_VARSIZE(r
, lowersize
+ VARHDRSZ
);
86 * Create an entry to store in the index, from lower and upper bound.
89 gbt_var_key_copy(const GBT_VARKEY_R
*u
)
91 int32 lowersize
= VARSIZE(u
->lower
);
92 int32 uppersize
= VARSIZE(u
->upper
);
95 r
= (GBT_VARKEY
*) palloc0(INTALIGN(lowersize
) + uppersize
+ VARHDRSZ
);
96 memcpy(VARDATA(r
), u
->lower
, lowersize
);
97 memcpy(VARDATA(r
) + INTALIGN(lowersize
), u
->upper
, uppersize
);
98 SET_VARSIZE(r
, INTALIGN(lowersize
) + uppersize
+ VARHDRSZ
);
105 gbt_var_leaf2node(GBT_VARKEY
*leaf
, const gbtree_vinfo
*tinfo
, FmgrInfo
*flinfo
)
107 GBT_VARKEY
*out
= leaf
;
110 out
= tinfo
->f_l2n(leaf
, flinfo
);
117 * returns the common prefix length of a node key
120 gbt_var_node_cp_len(const GBT_VARKEY
*node
, const gbtree_vinfo
*tinfo
)
122 GBT_VARKEY_R r
= gbt_var_key_readable(node
);
125 int32 t1len
= VARSIZE(r
.lower
) - VARHDRSZ
;
126 int32 t2len
= VARSIZE(r
.upper
) - VARHDRSZ
;
127 int32 ml
= Min(t1len
, t2len
);
128 char *p1
= VARDATA(r
.lower
);
129 char *p2
= VARDATA(r
.upper
);
136 if (tinfo
->eml
> 1 && l
== 0)
138 if ((l
= pg_mblen(p1
)) != pg_mblen(p2
))
160 return ml
; /* lower == upper */
165 * returns true, if query matches prefix ( common prefix )
168 gbt_bytea_pf_match(const bytea
*pf
, const bytea
*query
, const gbtree_vinfo
*tinfo
)
171 int32 qlen
= VARSIZE(query
) - VARHDRSZ
;
172 int32 nlen
= VARSIZE(pf
) - VARHDRSZ
;
176 char *q
= VARDATA(query
);
177 char *n
= VARDATA(pf
);
179 out
= (memcmp(q
, n
, nlen
) == 0);
187 * returns true, if query matches node using common prefix
190 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
)));
199 * truncates / compresses the node key
200 * cpf_length .. common prefix length
203 gbt_var_node_truncate(const GBT_VARKEY
*node
, int32 cpf_length
, const gbtree_vinfo
*tinfo
)
205 GBT_VARKEY
*out
= NULL
;
206 GBT_VARKEY_R r
= gbt_var_key_readable(node
);
207 int32 len1
= VARSIZE(r
.lower
) - VARHDRSZ
;
208 int32 len2
= VARSIZE(r
.upper
) - VARHDRSZ
;
212 len1
= Min(len1
, (cpf_length
+ 1));
213 len2
= Min(len2
, (cpf_length
+ 1));
215 si
= 2 * VARHDRSZ
+ INTALIGN(len1
+ VARHDRSZ
) + len2
;
216 out
= (GBT_VARKEY
*) palloc0(si
);
217 SET_VARSIZE(out
, si
);
219 memcpy(VARDATA(out
), r
.lower
, len1
+ VARHDRSZ
);
220 SET_VARSIZE(VARDATA(out
), len1
+ VARHDRSZ
);
222 out2
= VARDATA(out
) + INTALIGN(len1
+ VARHDRSZ
);
223 memcpy(out2
, r
.upper
, len2
+ VARHDRSZ
);
224 SET_VARSIZE(out2
, len2
+ VARHDRSZ
);
232 gbt_var_bin_union(Datum
*u
, GBT_VARKEY
*e
, Oid collation
,
233 const gbtree_vinfo
*tinfo
, FmgrInfo
*flinfo
)
235 GBT_VARKEY_R eo
= gbt_var_key_readable(e
);
238 if (eo
.lower
== eo
.upper
) /* leaf */
242 tmp
= gbt_var_leaf2node(e
, tinfo
, flinfo
);
244 eo
= gbt_var_key_readable(tmp
);
247 if (DatumGetPointer(*u
))
249 GBT_VARKEY_R ro
= gbt_var_key_readable((GBT_VARKEY
*) DatumGetPointer(*u
));
255 if (tinfo
->f_cmp(ro
.lower
, eo
.lower
, collation
, flinfo
) > 0)
261 if (tinfo
->f_cmp(ro
.upper
, eo
.upper
, collation
, flinfo
) < 0)
268 *u
= PointerGetDatum(gbt_var_key_copy(&nr
));
274 *u
= PointerGetDatum(gbt_var_key_copy(&nr
));
280 gbt_var_compress(GISTENTRY
*entry
, const gbtree_vinfo
*tinfo
)
286 struct varlena
*leaf
= PG_DETOAST_DATUM(entry
->key
);
289 r
= gbt_var_key_from_datum(leaf
);
291 retval
= palloc(sizeof(GISTENTRY
));
292 gistentryinit(*retval
, PointerGetDatum(r
),
293 entry
->rel
, entry
->page
,
294 entry
->offset
, true);
304 gbt_var_fetch(PG_FUNCTION_ARGS
)
306 GISTENTRY
*entry
= (GISTENTRY
*) PG_GETARG_POINTER(0);
307 GBT_VARKEY
*key
= (GBT_VARKEY
*) PG_DETOAST_DATUM(entry
->key
);
308 GBT_VARKEY_R r
= gbt_var_key_readable(key
);
311 retval
= palloc(sizeof(GISTENTRY
));
312 gistentryinit(*retval
, PointerGetDatum(r
.lower
),
313 entry
->rel
, entry
->page
,
314 entry
->offset
, true);
316 PG_RETURN_POINTER(retval
);
321 gbt_var_union(const GistEntryVector
*entryvec
, int32
*size
, Oid collation
,
322 const gbtree_vinfo
*tinfo
, FmgrInfo
*flinfo
)
325 numranges
= entryvec
->n
;
330 *size
= sizeof(GBT_VARKEY
);
332 cur
= (GBT_VARKEY
*) DatumGetPointer(entryvec
->vector
[0].key
);
333 rk
= gbt_var_key_readable(cur
);
334 out
= PointerGetDatum(gbt_var_key_copy(&rk
));
336 for (i
= 1; i
< numranges
; i
++)
338 cur
= (GBT_VARKEY
*) DatumGetPointer(entryvec
->vector
[i
].key
);
339 gbt_var_bin_union(&out
, cur
, collation
, tinfo
, flinfo
);
343 /* Truncate (=compress) key */
347 GBT_VARKEY
*trc
= NULL
;
349 plen
= gbt_var_node_cp_len((GBT_VARKEY
*) DatumGetPointer(out
), tinfo
);
350 trc
= gbt_var_node_truncate((GBT_VARKEY
*) DatumGetPointer(out
), plen
+ 1, tinfo
);
352 out
= PointerGetDatum(trc
);
355 return ((GBT_VARKEY
*) DatumGetPointer(out
));
360 gbt_var_same(Datum d1
, Datum d2
, Oid collation
,
361 const gbtree_vinfo
*tinfo
, FmgrInfo
*flinfo
)
363 GBT_VARKEY
*t1
= (GBT_VARKEY
*) DatumGetPointer(d1
);
364 GBT_VARKEY
*t2
= (GBT_VARKEY
*) DatumGetPointer(d2
);
368 r1
= gbt_var_key_readable(t1
);
369 r2
= gbt_var_key_readable(t2
);
371 return (tinfo
->f_cmp(r1
.lower
, r2
.lower
, collation
, flinfo
) == 0 &&
372 tinfo
->f_cmp(r1
.upper
, r2
.upper
, collation
, flinfo
) == 0);
377 gbt_var_penalty(float *res
, const GISTENTRY
*o
, const GISTENTRY
*n
,
378 Oid collation
, const gbtree_vinfo
*tinfo
, FmgrInfo
*flinfo
)
380 GBT_VARKEY
*orge
= (GBT_VARKEY
*) DatumGetPointer(o
->key
);
381 GBT_VARKEY
*newe
= (GBT_VARKEY
*) DatumGetPointer(n
->key
);
387 nk
= gbt_var_key_readable(newe
);
388 if (nk
.lower
== nk
.upper
) /* leaf */
392 tmp
= gbt_var_leaf2node(newe
, tinfo
, flinfo
);
394 nk
= gbt_var_key_readable(tmp
);
396 ok
= gbt_var_key_readable(orge
);
398 if ((VARSIZE(ok
.lower
) - VARHDRSZ
) == 0 && (VARSIZE(ok
.upper
) - VARHDRSZ
) == 0)
400 else if (!((tinfo
->f_cmp(nk
.lower
, ok
.lower
, collation
, flinfo
) >= 0 ||
401 gbt_bytea_pf_match(ok
.lower
, nk
.lower
, tinfo
)) &&
402 (tinfo
->f_cmp(nk
.upper
, ok
.upper
, collation
, flinfo
) <= 0 ||
403 gbt_bytea_pf_match(ok
.upper
, nk
.upper
, tinfo
))))
405 Datum d
= PointerGetDatum(0);
410 gbt_var_bin_union(&d
, orge
, collation
, tinfo
, flinfo
);
411 ol
= gbt_var_node_cp_len((GBT_VARKEY
*) DatumGetPointer(d
), tinfo
);
412 gbt_var_bin_union(&d
, newe
, collation
, tinfo
, flinfo
);
413 ul
= gbt_var_node_cp_len((GBT_VARKEY
*) DatumGetPointer(d
), tinfo
);
417 dres
= (ol
- ul
); /* reduction of common prefix len */
421 GBT_VARKEY_R uk
= gbt_var_key_readable((GBT_VARKEY
*) DatumGetPointer(d
));
422 unsigned char tmp
[4];
424 tmp
[0] = (unsigned char) (((VARSIZE(ok
.lower
) - VARHDRSZ
) <= ul
) ? 0 : (VARDATA(ok
.lower
)[ul
]));
425 tmp
[1] = (unsigned char) (((VARSIZE(uk
.lower
) - VARHDRSZ
) <= ul
) ? 0 : (VARDATA(uk
.lower
)[ul
]));
426 tmp
[2] = (unsigned char) (((VARSIZE(ok
.upper
) - VARHDRSZ
) <= ul
) ? 0 : (VARDATA(ok
.upper
)[ul
]));
427 tmp
[3] = (unsigned char) (((VARSIZE(uk
.upper
) - VARHDRSZ
) <= ul
) ? 0 : (VARDATA(uk
.upper
)[ul
]));
428 dres
= abs(tmp
[0] - tmp
[1]) + abs(tmp
[3] - tmp
[2]);
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 gbt_vsrt_arg
*varg
= (const gbt_vsrt_arg
*) arg
;
449 res
= varg
->tinfo
->f_cmp(ar
.lower
, br
.lower
, varg
->collation
, varg
->flinfo
);
451 return varg
->tinfo
->f_cmp(ar
.upper
, br
.upper
, varg
->collation
, varg
->flinfo
);
457 gbt_var_picksplit(const GistEntryVector
*entryvec
, GIST_SPLITVEC
*v
,
458 Oid collation
, const gbtree_vinfo
*tinfo
, FmgrInfo
*flinfo
)
461 maxoff
= entryvec
->n
- 1;
466 GBT_VARKEY
**sv
= NULL
;
469 arr
= (Vsrt
*) palloc((maxoff
+ 1) * sizeof(Vsrt
));
470 nbytes
= (maxoff
+ 2) * sizeof(OffsetNumber
);
471 v
->spl_left
= (OffsetNumber
*) palloc(nbytes
);
472 v
->spl_right
= (OffsetNumber
*) palloc(nbytes
);
473 v
->spl_ldatum
= PointerGetDatum(0);
474 v
->spl_rdatum
= PointerGetDatum(0);
478 sv
= palloc(sizeof(bytea
*) * (maxoff
+ 1));
482 for (i
= FirstOffsetNumber
; i
<= maxoff
; i
= OffsetNumberNext(i
))
486 cur
= (char *) DatumGetPointer(entryvec
->vector
[i
].key
);
487 ro
= gbt_var_key_readable((GBT_VARKEY
*) cur
);
488 if (ro
.lower
== ro
.upper
) /* leaf */
490 sv
[svcntr
] = gbt_var_leaf2node((GBT_VARKEY
*) cur
, tinfo
, flinfo
);
491 arr
[i
].t
= sv
[svcntr
];
492 if (sv
[svcntr
] != (GBT_VARKEY
*) cur
)
496 arr
[i
].t
= (GBT_VARKEY
*) cur
;
502 varg
.collation
= collation
;
503 varg
.flinfo
= flinfo
;
504 qsort_arg(&arr
[FirstOffsetNumber
],
505 maxoff
- FirstOffsetNumber
+ 1,
510 /* We do simply create two parts */
512 for (i
= FirstOffsetNumber
; i
<= maxoff
; i
= OffsetNumberNext(i
))
514 if (i
<= (maxoff
- FirstOffsetNumber
+ 1) / 2)
516 gbt_var_bin_union(&v
->spl_ldatum
, arr
[i
].t
, collation
, tinfo
, flinfo
);
517 v
->spl_left
[v
->spl_nleft
] = arr
[i
].i
;
522 gbt_var_bin_union(&v
->spl_rdatum
, arr
[i
].t
, collation
, tinfo
, flinfo
);
523 v
->spl_right
[v
->spl_nright
] = arr
[i
].i
;
528 /* Truncate (=compress) key */
531 int32 ll
= gbt_var_node_cp_len((GBT_VARKEY
*) DatumGetPointer(v
->spl_ldatum
), tinfo
);
532 int32 lr
= gbt_var_node_cp_len((GBT_VARKEY
*) DatumGetPointer(v
->spl_rdatum
), tinfo
);
539 dl
= gbt_var_node_truncate((GBT_VARKEY
*) DatumGetPointer(v
->spl_ldatum
), ll
, tinfo
);
540 dr
= gbt_var_node_truncate((GBT_VARKEY
*) DatumGetPointer(v
->spl_rdatum
), ll
, tinfo
);
541 v
->spl_ldatum
= PointerGetDatum(dl
);
542 v
->spl_rdatum
= PointerGetDatum(dr
);
550 * The GiST consistent method
553 gbt_var_consistent(GBT_VARKEY_R
*key
,
555 StrategyNumber strategy
,
558 const gbtree_vinfo
*tinfo
,
565 case BTLessEqualStrategyNumber
:
567 retval
= tinfo
->f_ge(query
, key
->lower
, collation
, flinfo
);
569 retval
= tinfo
->f_cmp(query
, key
->lower
, collation
, flinfo
) >= 0
570 || gbt_var_node_pf_match(key
, query
, tinfo
);
572 case BTLessStrategyNumber
:
574 retval
= tinfo
->f_gt(query
, key
->lower
, collation
, flinfo
);
576 retval
= tinfo
->f_cmp(query
, key
->lower
, collation
, flinfo
) >= 0
577 || gbt_var_node_pf_match(key
, query
, tinfo
);
579 case BTEqualStrategyNumber
:
581 retval
= tinfo
->f_eq(query
, key
->lower
, collation
, flinfo
);
584 (tinfo
->f_cmp(key
->lower
, query
, collation
, flinfo
) <= 0 &&
585 tinfo
->f_cmp(query
, key
->upper
, collation
, flinfo
) <= 0) ||
586 gbt_var_node_pf_match(key
, query
, tinfo
);
588 case BTGreaterStrategyNumber
:
590 retval
= tinfo
->f_lt(query
, key
->upper
, collation
, flinfo
);
592 retval
= tinfo
->f_cmp(query
, key
->upper
, collation
, flinfo
) <= 0
593 || gbt_var_node_pf_match(key
, query
, tinfo
);
595 case BTGreaterEqualStrategyNumber
:
597 retval
= tinfo
->f_le(query
, key
->upper
, collation
, flinfo
);
599 retval
= tinfo
->f_cmp(query
, key
->upper
, collation
, flinfo
) <= 0
600 || gbt_var_node_pf_match(key
, query
, tinfo
);
602 case BtreeGistNotEqualStrategyNumber
:
603 retval
= !(tinfo
->f_eq(query
, key
->lower
, collation
, flinfo
) &&
604 tinfo
->f_eq(query
, key
->upper
, collation
, flinfo
));