1 /*-------------------------------------------------------------------------
4 * GiST index support for tsquery
6 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
10 * src/backend/utils/adt/tsquery_gist.c
12 *-------------------------------------------------------------------------
17 #include "access/gist.h"
18 #include "access/stratnum.h"
19 #include "tsearch/ts_utils.h"
20 #include "utils/builtins.h"
22 #define GETENTRY(vec,pos) DatumGetTSQuerySign((vec)->vector[pos].key)
26 gtsquery_compress(PG_FUNCTION_ARGS
)
28 GISTENTRY
*entry
= (GISTENTRY
*) PG_GETARG_POINTER(0);
29 GISTENTRY
*retval
= entry
;
35 retval
= (GISTENTRY
*) palloc(sizeof(GISTENTRY
));
36 sign
= makeTSQuerySign(DatumGetTSQuery(entry
->key
));
38 gistentryinit(*retval
, TSQuerySignGetDatum(sign
),
39 entry
->rel
, entry
->page
,
40 entry
->offset
, false);
43 PG_RETURN_POINTER(retval
);
47 * We do not need a decompress function, because the other gtsquery
48 * support functions work with the compressed representation.
52 gtsquery_consistent(PG_FUNCTION_ARGS
)
54 GISTENTRY
*entry
= (GISTENTRY
*) PG_GETARG_POINTER(0);
55 TSQuery query
= PG_GETARG_TSQUERY(1);
56 StrategyNumber strategy
= (StrategyNumber
) PG_GETARG_UINT16(2);
58 /* Oid subtype = PG_GETARG_OID(3); */
59 bool *recheck
= (bool *) PG_GETARG_POINTER(4);
60 TSQuerySign key
= DatumGetTSQuerySign(entry
->key
);
61 TSQuerySign sq
= makeTSQuerySign(query
);
64 /* All cases served by this function are inexact */
69 case RTContainsStrategyNumber
:
71 retval
= (key
& sq
) == sq
;
73 retval
= (key
& sq
) != 0;
75 case RTContainedByStrategyNumber
:
77 retval
= (key
& sq
) == key
;
79 retval
= (key
& sq
) != 0;
84 PG_RETURN_BOOL(retval
);
88 gtsquery_union(PG_FUNCTION_ARGS
)
90 GistEntryVector
*entryvec
= (GistEntryVector
*) PG_GETARG_POINTER(0);
91 int *size
= (int *) PG_GETARG_POINTER(1);
97 for (i
= 0; i
< entryvec
->n
; i
++)
98 sign
|= GETENTRY(entryvec
, i
);
100 *size
= sizeof(TSQuerySign
);
102 PG_RETURN_TSQUERYSIGN(sign
);
106 gtsquery_same(PG_FUNCTION_ARGS
)
108 TSQuerySign a
= PG_GETARG_TSQUERYSIGN(0);
109 TSQuerySign b
= PG_GETARG_TSQUERYSIGN(1);
110 bool *result
= (bool *) PG_GETARG_POINTER(2);
114 PG_RETURN_POINTER(result
);
118 sizebitvec(TSQuerySign sign
)
123 for (i
= 0; i
< TSQS_SIGLEN
; i
++)
124 size
+= 0x01 & (sign
>> i
);
130 hemdist(TSQuerySign a
, TSQuerySign b
)
132 TSQuerySign res
= a
^ b
;
134 return sizebitvec(res
);
138 gtsquery_penalty(PG_FUNCTION_ARGS
)
140 TSQuerySign origval
= DatumGetTSQuerySign(((GISTENTRY
*) PG_GETARG_POINTER(0))->key
);
141 TSQuerySign newval
= DatumGetTSQuerySign(((GISTENTRY
*) PG_GETARG_POINTER(1))->key
);
142 float *penalty
= (float *) PG_GETARG_POINTER(2);
144 *penalty
= hemdist(origval
, newval
);
146 PG_RETURN_POINTER(penalty
);
157 comparecost(const void *a
, const void *b
)
159 if (((const SPLITCOST
*) a
)->cost
== ((const SPLITCOST
*) b
)->cost
)
162 return (((const SPLITCOST
*) a
)->cost
> ((const SPLITCOST
*) b
)->cost
) ? 1 : -1;
165 #define WISH_F(a,b,c) (double)( -(double)(((a)-(b))*((a)-(b))*((a)-(b)))*(c) )
168 gtsquery_picksplit(PG_FUNCTION_ARGS
)
170 GistEntryVector
*entryvec
= (GistEntryVector
*) PG_GETARG_POINTER(0);
171 GIST_SPLITVEC
*v
= (GIST_SPLITVEC
*) PG_GETARG_POINTER(1);
172 OffsetNumber maxoff
= entryvec
->n
- 2;
182 OffsetNumber seed_1
= 0,
187 SPLITCOST
*costvector
;
189 nbytes
= (maxoff
+ 2) * sizeof(OffsetNumber
);
190 left
= v
->spl_left
= (OffsetNumber
*) palloc(nbytes
);
191 right
= v
->spl_right
= (OffsetNumber
*) palloc(nbytes
);
192 v
->spl_nleft
= v
->spl_nright
= 0;
194 for (k
= FirstOffsetNumber
; k
< maxoff
; k
= OffsetNumberNext(k
))
195 for (j
= OffsetNumberNext(k
); j
<= maxoff
; j
= OffsetNumberNext(j
))
197 size_waste
= hemdist(GETENTRY(entryvec
, j
), GETENTRY(entryvec
, k
));
198 if (size_waste
> waste
)
207 if (seed_1
== 0 || seed_2
== 0)
213 datum_l
= GETENTRY(entryvec
, seed_1
);
214 datum_r
= GETENTRY(entryvec
, seed_2
);
216 maxoff
= OffsetNumberNext(maxoff
);
217 costvector
= (SPLITCOST
*) palloc(sizeof(SPLITCOST
) * maxoff
);
218 for (j
= FirstOffsetNumber
; j
<= maxoff
; j
= OffsetNumberNext(j
))
220 costvector
[j
- 1].pos
= j
;
221 size_alpha
= hemdist(GETENTRY(entryvec
, seed_1
), GETENTRY(entryvec
, j
));
222 size_beta
= hemdist(GETENTRY(entryvec
, seed_2
), GETENTRY(entryvec
, j
));
223 costvector
[j
- 1].cost
= abs(size_alpha
- size_beta
);
225 qsort((void *) costvector
, maxoff
, sizeof(SPLITCOST
), comparecost
);
227 for (k
= 0; k
< maxoff
; k
++)
229 j
= costvector
[k
].pos
;
236 else if (j
== seed_2
)
242 size_alpha
= hemdist(datum_l
, GETENTRY(entryvec
, j
));
243 size_beta
= hemdist(datum_r
, GETENTRY(entryvec
, j
));
245 if (size_alpha
< size_beta
+ WISH_F(v
->spl_nleft
, v
->spl_nright
, 0.05))
247 datum_l
|= GETENTRY(entryvec
, j
);
253 datum_r
|= GETENTRY(entryvec
, j
);
259 *right
= *left
= FirstOffsetNumber
;
260 v
->spl_ldatum
= TSQuerySignGetDatum(datum_l
);
261 v
->spl_rdatum
= TSQuerySignGetDatum(datum_r
);
263 PG_RETURN_POINTER(v
);
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.
274 gtsquery_consistent_oldsig(PG_FUNCTION_ARGS
)
276 return gtsquery_consistent(fcinfo
);