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