Branch data Line data Source code
1 : : /*
2 : : * contrib/btree_gist/btree_bit.c
3 : : *
4 : : * Support for bit and varbit types (which act the same for our purposes).
5 : : *
6 : : * Leaf-page keys are bit/varbit values, but internal-page keys are just
7 : : * bytea values containing the first N bytes of the represented bitstring.
8 : : * (In particular, they lack the bit_len field of a bit/varbit Datum.)
9 : : */
10 : : #include "postgres.h"
11 : :
12 : : #include "btree_gist.h"
13 : : #include "btree_utils_var.h"
14 : : #include "utils/fmgrprotos.h"
15 : : #include "utils/sortsupport.h"
16 : : #include "utils/varbit.h"
17 : : #include "varatt.h"
18 : :
19 : : /* GiST support functions */
20 : 5 : PG_FUNCTION_INFO_V1(gbt_bit_compress);
21 : 5 : PG_FUNCTION_INFO_V1(gbt_bit_union);
22 : 5 : PG_FUNCTION_INFO_V1(gbt_bit_picksplit);
23 : 5 : PG_FUNCTION_INFO_V1(gbt_bit_consistent);
24 : 5 : PG_FUNCTION_INFO_V1(gbt_bit_penalty);
25 : 5 : PG_FUNCTION_INFO_V1(gbt_bit_same);
26 : 4 : PG_FUNCTION_INFO_V1(gbt_bit_sortsupport);
27 : 4 : PG_FUNCTION_INFO_V1(gbt_varbit_sortsupport);
28 : :
29 : :
30 : : /* define for comparison */
31 : :
32 : : static bool
33 : 600 : gbt_bitgt(const void *a, const void *b, Oid collation, FmgrInfo *flinfo)
34 : : {
35 : 600 : return DatumGetBool(DirectFunctionCall2(bitgt,
36 : : PointerGetDatum(a),
37 : : PointerGetDatum(b)));
38 : : }
39 : :
40 : : static bool
41 : 600 : gbt_bitge(const void *a, const void *b, Oid collation, FmgrInfo *flinfo)
42 : : {
43 : 600 : return DatumGetBool(DirectFunctionCall2(bitge,
44 : : PointerGetDatum(a),
45 : : PointerGetDatum(b)));
46 : : }
47 : :
48 : : static bool
49 : 300 : gbt_biteq(const void *a, const void *b, Oid collation, FmgrInfo *flinfo)
50 : : {
51 : 300 : return DatumGetBool(DirectFunctionCall2(biteq,
52 : : PointerGetDatum(a),
53 : : PointerGetDatum(b)));
54 : : }
55 : :
56 : : static bool
57 : 900 : gbt_bitle(const void *a, const void *b, Oid collation, FmgrInfo *flinfo)
58 : : {
59 : 900 : return DatumGetBool(DirectFunctionCall2(bitle,
60 : : PointerGetDatum(a),
61 : : PointerGetDatum(b)));
62 : : }
63 : :
64 : : static bool
65 : 900 : gbt_bitlt(const void *a, const void *b, Oid collation, FmgrInfo *flinfo)
66 : : {
67 : 900 : return DatumGetBool(DirectFunctionCall2(bitlt,
68 : : PointerGetDatum(a),
69 : : PointerGetDatum(b)));
70 : : }
71 : :
72 : : /*
73 : : * Notice we use byteacmp here, not bitcmp as you might expect.
74 : : * That's because internal-page keys are bytea.
75 : : */
76 : : static int32
77 : 9674 : gbt_bitcmp(const void *a, const void *b, Oid collation, FmgrInfo *flinfo)
78 : : {
79 : 9674 : return DatumGetInt32(DirectFunctionCall2(byteacmp,
80 : : PointerGetDatum(a),
81 : : PointerGetDatum(b)));
82 : : }
83 : :
84 : :
85 : : /*
86 : : * Convert a leaf-page bit/varbit value to internal-page form.
87 : : *
88 : : * The important change here is to remove the bit_len field so that
89 : : * what we have left looks like a bytea.
90 : : *
91 : : * The business with padding to INTALIGN length appears entirely historical,
92 : : * but we can't remove that without breaking on-disk compatibility.
93 : : * For example, if the lower bound of some leaf page is the 20-bit string
94 : : * of all ones, with data contents FFFFF0, this code pads it to bytea FFFFF000
95 : : * in the internal key representing that page. If, when we search the index
96 : : * for that value, we did not again pad to FFFFF000, then byteacmp would
97 : : * say that the query is strictly less than the lower bound so we would not
98 : : * descend to that leaf page.
99 : : */
100 : : static bytea *
101 : 3638 : gbt_bit_xfrm(VarBit *leaf)
102 : : {
103 : : bytea *out;
104 : 3638 : int sz = VARBITBYTES(leaf) + VARHDRSZ;
105 : 3638 : int padded_sz = INTALIGN(sz);
106 : :
107 : 3638 : out = (bytea *) palloc(padded_sz);
108 : : /* initialize the padding bytes to zero */
109 [ + + ]: 11799 : while (sz < padded_sz)
110 : 8161 : ((char *) out)[sz++] = 0;
111 : 3638 : SET_VARSIZE(out, padded_sz);
112 : 3638 : memcpy(VARDATA(out), VARBITS(leaf), VARBITBYTES(leaf));
113 : 3638 : return out;
114 : : }
115 : :
116 : : /*
117 : : * Convert a GBT_VARKEY representation of a leaf key to a palloc'd
118 : : * GBT_VARKEY representation of an internal key.
119 : : * We assume lower == upper since it's a leaf key.
120 : : */
121 : : static GBT_VARKEY *
122 : 3598 : gbt_bit_l2n(GBT_VARKEY *leaf, FmgrInfo *flinfo)
123 : : {
124 : : GBT_VARKEY *out;
125 : 3598 : GBT_VARKEY_R r = gbt_var_key_readable(leaf);
126 : : bytea *o;
127 : :
128 : 3598 : o = gbt_bit_xfrm((VarBit *) r.lower);
129 : 3598 : r.upper = r.lower = o;
130 : 3598 : out = gbt_var_key_copy(&r);
131 : 3598 : pfree(o);
132 : :
133 : 3598 : return out;
134 : : }
135 : :
136 : : static const gbtree_vinfo tinfo =
137 : : {
138 : : gbt_t_bit,
139 : : true, /* internal keys can be truncated */
140 : : gbt_bitgt,
141 : : gbt_bitge,
142 : : gbt_biteq,
143 : : gbt_bitle,
144 : : gbt_bitlt,
145 : : gbt_bitcmp,
146 : : gbt_bit_l2n /* leaf to internal transformation */
147 : : };
148 : :
149 : :
150 : : /**************************************************
151 : : * GiST support functions
152 : : **************************************************/
153 : :
154 : : Datum
155 : 1208 : gbt_bit_compress(PG_FUNCTION_ARGS)
156 : : {
157 : 1208 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
158 : :
159 : 1208 : PG_RETURN_POINTER(gbt_var_compress(entry, &tinfo));
160 : : }
161 : :
162 : : Datum
163 : 3340 : gbt_bit_consistent(PG_FUNCTION_ARGS)
164 : : {
165 : 3340 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
166 : 3340 : VarBit *query = PG_GETARG_VARBIT_P(1);
167 : 3340 : StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
168 : : #ifdef NOT_USED
169 : : Oid subtype = PG_GETARG_OID(3);
170 : : #endif
171 : 3340 : bool *recheck = (bool *) PG_GETARG_POINTER(4);
172 : : bool retval;
173 : 3340 : GBT_VARKEY *key = (GBT_VARKEY *) DatumGetPointer(entry->key);
174 : 3340 : GBT_VARKEY_R r = gbt_var_key_readable(key);
175 : :
176 : : /* All cases served by this function are exact */
177 : 3340 : *recheck = false;
178 : :
179 [ + + ]: 3340 : if (GIST_LEAF(entry))
180 : 3300 : retval = gbt_var_consistent(&r, query, strategy, PG_GET_COLLATION(),
181 : : true, &tinfo, fcinfo->flinfo);
182 : : else
183 : : {
184 : : /* Must convert to internal form to compare to internal-page entries */
185 : 40 : bytea *q = gbt_bit_xfrm(query);
186 : :
187 : 40 : retval = gbt_var_consistent(&r, q, strategy, PG_GET_COLLATION(),
188 : : false, &tinfo, fcinfo->flinfo);
189 : : }
190 : 3340 : PG_RETURN_BOOL(retval);
191 : : }
192 : :
193 : : Datum
194 : 2 : gbt_bit_union(PG_FUNCTION_ARGS)
195 : : {
196 : 2 : GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
197 : 2 : int32 *size = (int *) PG_GETARG_POINTER(1);
198 : :
199 : 2 : PG_RETURN_POINTER(gbt_var_union(entryvec, size, PG_GET_COLLATION(),
200 : : &tinfo, fcinfo->flinfo));
201 : : }
202 : :
203 : : Datum
204 : 6 : gbt_bit_picksplit(PG_FUNCTION_ARGS)
205 : : {
206 : 6 : GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
207 : 6 : GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
208 : :
209 : 6 : gbt_var_picksplit(entryvec, v, PG_GET_COLLATION(),
210 : : &tinfo, fcinfo->flinfo);
211 : 6 : PG_RETURN_POINTER(v);
212 : : }
213 : :
214 : : Datum
215 : 0 : gbt_bit_same(PG_FUNCTION_ARGS)
216 : : {
217 : 0 : Datum d1 = PG_GETARG_DATUM(0);
218 : 0 : Datum d2 = PG_GETARG_DATUM(1);
219 : 0 : bool *result = (bool *) PG_GETARG_POINTER(2);
220 : :
221 : 0 : *result = gbt_var_same(d1, d2, PG_GET_COLLATION(), &tinfo, fcinfo->flinfo);
222 : 0 : PG_RETURN_POINTER(result);
223 : : }
224 : :
225 : : Datum
226 : 0 : gbt_bit_penalty(PG_FUNCTION_ARGS)
227 : : {
228 : 0 : GISTENTRY *o = (GISTENTRY *) PG_GETARG_POINTER(0);
229 : 0 : GISTENTRY *n = (GISTENTRY *) PG_GETARG_POINTER(1);
230 : 0 : float *result = (float *) PG_GETARG_POINTER(2);
231 : :
232 : 0 : PG_RETURN_POINTER(gbt_var_penalty(result, o, n, PG_GET_COLLATION(),
233 : : &tinfo, fcinfo->flinfo));
234 : : }
235 : :
236 : : static int
237 : 11343 : gbt_bit_ssup_cmp(Datum x, Datum y, SortSupport ssup)
238 : : {
239 : 11343 : GBT_VARKEY *key1 = PG_DETOAST_DATUM(x);
240 : 11343 : GBT_VARKEY *key2 = PG_DETOAST_DATUM(y);
241 : :
242 : 11343 : GBT_VARKEY_R arg1 = gbt_var_key_readable(key1);
243 : 11343 : GBT_VARKEY_R arg2 = gbt_var_key_readable(key2);
244 : : Datum result;
245 : :
246 : : /* for leaf items we expect lower == upper, so only compare lower */
247 : 11343 : result = DirectFunctionCall2(bitcmp,
248 : : PointerGetDatum(arg1.lower),
249 : : PointerGetDatum(arg2.lower));
250 : :
251 [ + - ]: 11343 : GBT_FREE_IF_COPY(key1, x);
252 [ + - ]: 11343 : GBT_FREE_IF_COPY(key2, y);
253 : :
254 : 11343 : return DatumGetInt32(result);
255 : : }
256 : :
257 : : Datum
258 : 1 : gbt_bit_sortsupport(PG_FUNCTION_ARGS)
259 : : {
260 : 1 : SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
261 : :
262 : 1 : ssup->comparator = gbt_bit_ssup_cmp;
263 : 1 : ssup->ssup_extra = NULL;
264 : :
265 : 1 : PG_RETURN_VOID();
266 : : }
267 : :
268 : : Datum
269 : 1 : gbt_varbit_sortsupport(PG_FUNCTION_ARGS)
270 : : {
271 : 1 : SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
272 : :
273 : 1 : ssup->comparator = gbt_bit_ssup_cmp;
274 : 1 : ssup->ssup_extra = NULL;
275 : :
276 : 1 : PG_RETURN_VOID();
277 : : }
|