Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * tsquery_gist.c
4 : * GiST index support for tsquery
5 : *
6 : * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7 : *
8 : *
9 : * IDENTIFICATION
10 : * src/backend/utils/adt/tsquery_gist.c
11 : *
12 : *-------------------------------------------------------------------------
13 : */
14 :
15 : #include "postgres.h"
16 :
17 : #include "access/stratnum.h"
18 : #include "access/gist.h"
19 : #include "tsearch/ts_utils.h"
20 : #include "utils/builtins.h"
21 :
22 : #define GETENTRY(vec,pos) DatumGetTSQuerySign((vec)->vector[pos].key)
23 :
24 :
25 : Datum
26 6 : gtsquery_compress(PG_FUNCTION_ARGS)
27 : {
28 6 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
29 6 : GISTENTRY *retval = entry;
30 :
31 6 : if (entry->leafkey)
32 : {
33 : TSQuerySign sign;
34 :
35 6 : retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
36 6 : sign = makeTSQuerySign(DatumGetTSQuery(entry->key));
37 :
38 6 : gistentryinit(*retval, TSQuerySignGetDatum(sign),
39 : entry->rel, entry->page,
40 : entry->offset, FALSE);
41 : }
42 :
43 6 : PG_RETURN_POINTER(retval);
44 : }
45 :
46 : Datum
47 0 : gtsquery_decompress(PG_FUNCTION_ARGS)
48 : {
49 0 : PG_RETURN_DATUM(PG_GETARG_DATUM(0));
50 : }
51 :
52 : Datum
53 0 : gtsquery_consistent(PG_FUNCTION_ARGS)
54 : {
55 0 : GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
56 0 : TSQuery query = PG_GETARG_TSQUERY(1);
57 0 : StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
58 :
59 : /* Oid subtype = PG_GETARG_OID(3); */
60 0 : bool *recheck = (bool *) PG_GETARG_POINTER(4);
61 0 : TSQuerySign key = DatumGetTSQuerySign(entry->key);
62 0 : TSQuerySign sq = makeTSQuerySign(query);
63 : bool retval;
64 :
65 : /* All cases served by this function are inexact */
66 0 : *recheck = true;
67 :
68 0 : switch (strategy)
69 : {
70 : case RTContainsStrategyNumber:
71 0 : if (GIST_LEAF(entry))
72 0 : retval = (key & sq) == sq;
73 : else
74 0 : retval = (key & sq) != 0;
75 0 : break;
76 : case RTContainedByStrategyNumber:
77 0 : if (GIST_LEAF(entry))
78 0 : retval = (key & sq) == key;
79 : else
80 0 : retval = (key & sq) != 0;
81 0 : break;
82 : default:
83 0 : retval = FALSE;
84 : }
85 0 : PG_RETURN_BOOL(retval);
86 : }
87 :
88 : Datum
89 0 : gtsquery_union(PG_FUNCTION_ARGS)
90 : {
91 0 : GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
92 0 : int *size = (int *) PG_GETARG_POINTER(1);
93 : TSQuerySign sign;
94 : int i;
95 :
96 0 : sign = 0;
97 :
98 0 : for (i = 0; i < entryvec->n; i++)
99 0 : sign |= GETENTRY(entryvec, i);
100 :
101 0 : *size = sizeof(TSQuerySign);
102 :
103 0 : PG_RETURN_TSQUERYSIGN(sign);
104 : }
105 :
106 : Datum
107 0 : gtsquery_same(PG_FUNCTION_ARGS)
108 : {
109 0 : TSQuerySign a = PG_GETARG_TSQUERYSIGN(0);
110 0 : TSQuerySign b = PG_GETARG_TSQUERYSIGN(1);
111 0 : bool *result = (bool *) PG_GETARG_POINTER(2);
112 :
113 0 : *result = (a == b) ? true : false;
114 :
115 0 : PG_RETURN_POINTER(result);
116 : }
117 :
118 : static int
119 0 : sizebitvec(TSQuerySign sign)
120 : {
121 0 : int size = 0,
122 : i;
123 :
124 0 : for (i = 0; i < TSQS_SIGLEN; i++)
125 0 : size += 0x01 & (sign >> i);
126 :
127 0 : return size;
128 : }
129 :
130 : static int
131 0 : hemdist(TSQuerySign a, TSQuerySign b)
132 : {
133 0 : TSQuerySign res = a ^ b;
134 :
135 0 : return sizebitvec(res);
136 : }
137 :
138 : Datum
139 0 : gtsquery_penalty(PG_FUNCTION_ARGS)
140 : {
141 0 : TSQuerySign origval = DatumGetTSQuerySign(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
142 0 : TSQuerySign newval = DatumGetTSQuerySign(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
143 0 : float *penalty = (float *) PG_GETARG_POINTER(2);
144 :
145 0 : *penalty = hemdist(origval, newval);
146 :
147 0 : PG_RETURN_POINTER(penalty);
148 : }
149 :
150 :
151 : typedef struct
152 : {
153 : OffsetNumber pos;
154 : int32 cost;
155 : } SPLITCOST;
156 :
157 : static int
158 0 : comparecost(const void *a, const void *b)
159 : {
160 0 : if (((const SPLITCOST *) a)->cost == ((const SPLITCOST *) b)->cost)
161 0 : return 0;
162 : else
163 0 : return (((const SPLITCOST *) a)->cost > ((const SPLITCOST *) b)->cost) ? 1 : -1;
164 : }
165 :
166 : #define WISH_F(a,b,c) (double)( -(double)(((a)-(b))*((a)-(b))*((a)-(b)))*(c) )
167 :
168 : Datum
169 0 : gtsquery_picksplit(PG_FUNCTION_ARGS)
170 : {
171 0 : GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
172 0 : GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
173 0 : OffsetNumber maxoff = entryvec->n - 2;
174 : OffsetNumber k,
175 : j;
176 : TSQuerySign datum_l,
177 : datum_r;
178 : int32 size_alpha,
179 : size_beta;
180 : int32 size_waste,
181 0 : waste = -1;
182 : int32 nbytes;
183 0 : OffsetNumber seed_1 = 0,
184 0 : seed_2 = 0;
185 : OffsetNumber *left,
186 : *right;
187 :
188 : SPLITCOST *costvector;
189 :
190 0 : nbytes = (maxoff + 2) * sizeof(OffsetNumber);
191 0 : left = v->spl_left = (OffsetNumber *) palloc(nbytes);
192 0 : right = v->spl_right = (OffsetNumber *) palloc(nbytes);
193 0 : v->spl_nleft = v->spl_nright = 0;
194 :
195 0 : for (k = FirstOffsetNumber; k < maxoff; k = OffsetNumberNext(k))
196 0 : for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j))
197 : {
198 0 : size_waste = hemdist(GETENTRY(entryvec, j), GETENTRY(entryvec, k));
199 0 : if (size_waste > waste)
200 : {
201 0 : waste = size_waste;
202 0 : seed_1 = k;
203 0 : seed_2 = j;
204 : }
205 : }
206 :
207 :
208 0 : if (seed_1 == 0 || seed_2 == 0)
209 : {
210 0 : seed_1 = 1;
211 0 : seed_2 = 2;
212 : }
213 :
214 0 : datum_l = GETENTRY(entryvec, seed_1);
215 0 : datum_r = GETENTRY(entryvec, seed_2);
216 :
217 0 : maxoff = OffsetNumberNext(maxoff);
218 0 : costvector = (SPLITCOST *) palloc(sizeof(SPLITCOST) * maxoff);
219 0 : for (j = FirstOffsetNumber; j <= maxoff; j = OffsetNumberNext(j))
220 : {
221 0 : costvector[j - 1].pos = j;
222 0 : size_alpha = hemdist(GETENTRY(entryvec, seed_1), GETENTRY(entryvec, j));
223 0 : size_beta = hemdist(GETENTRY(entryvec, seed_2), GETENTRY(entryvec, j));
224 0 : costvector[j - 1].cost = abs(size_alpha - size_beta);
225 : }
226 0 : qsort((void *) costvector, maxoff, sizeof(SPLITCOST), comparecost);
227 :
228 0 : for (k = 0; k < maxoff; k++)
229 : {
230 0 : j = costvector[k].pos;
231 0 : if (j == seed_1)
232 : {
233 0 : *left++ = j;
234 0 : v->spl_nleft++;
235 0 : continue;
236 : }
237 0 : else if (j == seed_2)
238 : {
239 0 : *right++ = j;
240 0 : v->spl_nright++;
241 0 : continue;
242 : }
243 0 : size_alpha = hemdist(datum_l, GETENTRY(entryvec, j));
244 0 : size_beta = hemdist(datum_r, GETENTRY(entryvec, j));
245 :
246 0 : if (size_alpha < size_beta + WISH_F(v->spl_nleft, v->spl_nright, 0.05))
247 : {
248 0 : datum_l |= GETENTRY(entryvec, j);
249 0 : *left++ = j;
250 0 : v->spl_nleft++;
251 : }
252 : else
253 : {
254 0 : datum_r |= GETENTRY(entryvec, j);
255 0 : *right++ = j;
256 0 : v->spl_nright++;
257 : }
258 : }
259 :
260 0 : *right = *left = FirstOffsetNumber;
261 0 : v->spl_ldatum = TSQuerySignGetDatum(datum_l);
262 0 : v->spl_rdatum = TSQuerySignGetDatum(datum_r);
263 :
264 0 : PG_RETURN_POINTER(v);
265 : }
266 :
267 : /*
268 : * Formerly, gtsquery_consistent was declared in pg_proc.h with arguments
269 : * that did not match the documented conventions for GiST support functions.
270 : * We fixed that, but we still need a pg_proc entry with the old signature
271 : * to support reloading pre-9.6 contrib/tsearch2 opclass declarations.
272 : * This compatibility function should go away eventually.
273 : */
274 : Datum
275 0 : gtsquery_consistent_oldsig(PG_FUNCTION_ARGS)
276 : {
277 0 : return gtsquery_consistent(fcinfo);
278 : }
|