PostgreSQL Source Code git master
tsginidx.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * tsginidx.c
4 * GIN support functions for tsvector_ops
5 *
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 *
8 *
9 * IDENTIFICATION
10 * src/backend/utils/adt/tsginidx.c
11 *
12 *-------------------------------------------------------------------------
13 */
14#include "postgres.h"
15
16#include "access/gin.h"
17#include "tsearch/ts_type.h"
18#include "tsearch/ts_utils.h"
19#include "utils/builtins.h"
20#include "varatt.h"
21
22
25{
28 int cmp;
29
32 false);
33
37}
38
41{
44
45#ifdef NOT_USED
46 StrategyNumber strategy = PG_GETARG_UINT16(2);
47 Pointer extra_data = PG_GETARG_POINTER(3);
48#endif
49 int cmp;
50
53 true);
54
55 if (cmp < 0)
56 cmp = 1; /* prevent continue scan */
57
61}
62
65{
66 TSVector vector = PG_GETARG_TSVECTOR(0);
67 int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
68 Datum *entries = NULL;
69
70 *nentries = vector->size;
71 if (vector->size > 0)
72 {
73 int i;
74 WordEntry *we = ARRPTR(vector);
75
76 entries = (Datum *) palloc(sizeof(Datum) * vector->size);
77
78 for (i = 0; i < vector->size; i++)
79 {
80 text *txt;
81
82 txt = cstring_to_text_with_len(STRPTR(vector) + we->pos, we->len);
83 entries[i] = PointerGetDatum(txt);
84
85 we++;
86 }
87 }
88
89 PG_FREE_IF_COPY(vector, 0);
90 PG_RETURN_POINTER(entries);
91}
92
95{
96 TSQuery query = PG_GETARG_TSQUERY(0);
97 int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
98
99 /* StrategyNumber strategy = PG_GETARG_UINT16(2); */
100 bool **ptr_partialmatch = (bool **) PG_GETARG_POINTER(3);
101 Pointer **extra_data = (Pointer **) PG_GETARG_POINTER(4);
102
103 /* bool **nullFlags = (bool **) PG_GETARG_POINTER(5); */
104 int32 *searchMode = (int32 *) PG_GETARG_POINTER(6);
105 Datum *entries = NULL;
106
107 *nentries = 0;
108
109 if (query->size > 0)
110 {
111 QueryItem *item = GETQUERY(query);
112 int32 i,
113 j;
114 bool *partialmatch;
115 int *map_item_operand;
116
117 /*
118 * If the query doesn't have any required positive matches (for
119 * instance, it's something like '! foo'), we have to do a full index
120 * scan.
121 */
122 if (tsquery_requires_match(item))
123 *searchMode = GIN_SEARCH_MODE_DEFAULT;
124 else
125 *searchMode = GIN_SEARCH_MODE_ALL;
126
127 /* count number of VAL items */
128 j = 0;
129 for (i = 0; i < query->size; i++)
130 {
131 if (item[i].type == QI_VAL)
132 j++;
133 }
134 *nentries = j;
135
136 entries = (Datum *) palloc(sizeof(Datum) * j);
137 partialmatch = *ptr_partialmatch = (bool *) palloc(sizeof(bool) * j);
138
139 /*
140 * Make map to convert item's number to corresponding operand's (the
141 * same, entry's) number. Entry's number is used in check array in
142 * consistent method. We use the same map for each entry.
143 */
144 *extra_data = (Pointer *) palloc(sizeof(Pointer) * j);
145 map_item_operand = (int *) palloc0(sizeof(int) * query->size);
146
147 /* Now rescan the VAL items and fill in the arrays */
148 j = 0;
149 for (i = 0; i < query->size; i++)
150 {
151 if (item[i].type == QI_VAL)
152 {
153 QueryOperand *val = &item[i].qoperand;
154 text *txt;
155
156 txt = cstring_to_text_with_len(GETOPERAND(query) + val->distance,
157 val->length);
158 entries[j] = PointerGetDatum(txt);
159 partialmatch[j] = val->prefix;
160 (*extra_data)[j] = (Pointer) map_item_operand;
161 map_item_operand[i] = j;
162 j++;
163 }
164 }
165 }
166
167 PG_FREE_IF_COPY(query, 0);
168
169 PG_RETURN_POINTER(entries);
170}
171
172typedef struct
173{
177} GinChkVal;
178
179/*
180 * TS_execute callback for matching a tsquery operand to GIN index data
181 */
182static TSTernaryValue
184{
185 GinChkVal *gcv = (GinChkVal *) checkval;
186 int j;
187 GinTernaryValue result;
188
189 /* convert item's number to corresponding entry's (operand's) number */
190 j = gcv->map_item_operand[((QueryItem *) val) - gcv->first_item];
191
192 /* determine presence of current entry in indexed value */
193 result = gcv->check[j];
194
195 /*
196 * If any val requiring a weight is used or caller needs position
197 * information then we must recheck, so replace TRUE with MAYBE.
198 */
199 if (result == GIN_TRUE)
200 {
201 if (val->weight != 0 || data != NULL)
202 result = GIN_MAYBE;
203 }
204
205 /*
206 * We rely on GinTernaryValue and TSTernaryValue using equivalent value
207 * assignments. We could use a switch statement to map the values if that
208 * ever stops being true, but it seems unlikely to happen.
209 */
210 return (TSTernaryValue) result;
211}
212
213Datum
215{
216 bool *check = (bool *) PG_GETARG_POINTER(0);
217
218 /* StrategyNumber strategy = PG_GETARG_UINT16(1); */
219 TSQuery query = PG_GETARG_TSQUERY(2);
220
221 /* int32 nkeys = PG_GETARG_INT32(3); */
222 Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4);
223 bool *recheck = (bool *) PG_GETARG_POINTER(5);
224 bool res = false;
225
226 /* Initially assume query doesn't require recheck */
227 *recheck = false;
228
229 if (query->size > 0)
230 {
231 GinChkVal gcv;
232
233 /*
234 * check-parameter array has one entry for each value (operand) in the
235 * query.
236 */
237 gcv.first_item = GETQUERY(query);
238 gcv.check = (GinTernaryValue *) check;
239 gcv.map_item_operand = (int *) (extra_data[0]);
240
241 switch (TS_execute_ternary(GETQUERY(query),
242 &gcv,
245 {
246 case TS_NO:
247 res = false;
248 break;
249 case TS_YES:
250 res = true;
251 break;
252 case TS_MAYBE:
253 res = true;
254 *recheck = true;
255 break;
256 }
257 }
258
260}
261
262Datum
264{
266
267 /* StrategyNumber strategy = PG_GETARG_UINT16(1); */
268 TSQuery query = PG_GETARG_TSQUERY(2);
269
270 /* int32 nkeys = PG_GETARG_INT32(3); */
271 Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4);
273
274 if (query->size > 0)
275 {
276 GinChkVal gcv;
277
278 /*
279 * check-parameter array has one entry for each value (operand) in the
280 * query.
281 */
282 gcv.first_item = GETQUERY(query);
283 gcv.check = check;
284 gcv.map_item_operand = (int *) (extra_data[0]);
285
287 &gcv,
290 }
291
293}
294
295/*
296 * Formerly, gin_extract_tsvector had only two arguments. Now it has three,
297 * but we still need a pg_proc entry with two args to support reloading
298 * pre-9.1 contrib/tsearch2 opclass declarations. This compatibility
299 * function should go away eventually. (Note: you might say "hey, but the
300 * code above is only *using* two args, so let's just declare it that way".
301 * If you try that you'll find the opr_sanity regression test complains.)
302 */
303Datum
305{
306 if (PG_NARGS() < 3) /* should not happen */
307 elog(ERROR, "gin_extract_tsvector requires three arguments");
308 return gin_extract_tsvector(fcinfo);
309}
310
311/*
312 * Likewise, we need a stub version of gin_extract_tsquery declared with
313 * only five arguments.
314 */
315Datum
317{
318 if (PG_NARGS() < 7) /* should not happen */
319 elog(ERROR, "gin_extract_tsquery requires seven arguments");
320 return gin_extract_tsquery(fcinfo);
321}
322
323/*
324 * Likewise, we need a stub version of gin_tsquery_consistent declared with
325 * only six arguments.
326 */
327Datum
329{
330 if (PG_NARGS() < 8) /* should not happen */
331 elog(ERROR, "gin_tsquery_consistent requires eight arguments");
332 return gin_tsquery_consistent(fcinfo);
333}
334
335/*
336 * Likewise, a stub version of gin_extract_tsquery declared with argument
337 * types that are no longer considered appropriate.
338 */
339Datum
341{
342 return gin_extract_tsquery(fcinfo);
343}
344
345/*
346 * Likewise, a stub version of gin_tsquery_consistent declared with argument
347 * types that are no longer considered appropriate.
348 */
349Datum
351{
352 return gin_tsquery_consistent(fcinfo);
353}
#define GETQUERY(x)
Definition: _int.h:157
char * Pointer
Definition: c.h:479
int32_t int32
Definition: c.h:484
#define ARRPTR(x)
Definition: cube.c:25
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:260
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
#define PG_NARGS()
Definition: fmgr.h:203
#define PG_GETARG_UINT16(n)
Definition: fmgr.h:272
#define PG_RETURN_INT32(x)
Definition: fmgr.h:354
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
#define PG_RETURN_GIN_TERNARY_VALUE(x)
Definition: gin.h:79
#define GIN_SEARCH_MODE_ALL
Definition: gin.h:36
#define GIN_FALSE
Definition: gin.h:63
#define GIN_SEARCH_MODE_DEFAULT
Definition: gin.h:34
char GinTernaryValue
Definition: gin.h:58
#define GIN_MAYBE
Definition: gin.h:65
#define GIN_TRUE
Definition: gin.h:64
#define STRPTR(x)
Definition: hstore.h:76
long val
Definition: informix.c:689
int b
Definition: isn.c:69
int a
Definition: isn.c:68
int j
Definition: isn.c:73
int i
Definition: isn.c:72
#define GETOPERAND(x)
Definition: ltree.h:165
void * palloc0(Size size)
Definition: mcxt.c:1347
void * palloc(Size size)
Definition: mcxt.c:1317
const void * data
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
uintptr_t Datum
Definition: postgres.h:69
static int cmp(const chr *x, const chr *y, size_t len)
Definition: regc_locale.c:743
uint16 StrategyNumber
Definition: stratnum.h:22
QueryItem * first_item
Definition: tsginidx.c:174
GinTernaryValue * check
Definition: tsginidx.c:175
int * map_item_operand
Definition: tsginidx.c:176
int32 size
Definition: ts_type.h:221
int32 size
Definition: ts_type.h:93
uint32 pos
Definition: ts_type.h:46
uint32 len
Definition: ts_type.h:45
Definition: c.h:644
#define PG_GETARG_TSVECTOR(n)
Definition: ts_type.h:135
#define PG_GETARG_TSQUERY(n)
Definition: ts_type.h:266
#define QI_VAL
Definition: ts_type.h:149
#define TS_EXEC_PHRASE_NO_POS
Definition: ts_utils.h:202
TSTernaryValue
Definition: ts_utils.h:133
@ TS_MAYBE
Definition: ts_utils.h:136
@ TS_NO
Definition: ts_utils.h:134
@ TS_YES
Definition: ts_utils.h:135
Datum gin_cmp_prefix(PG_FUNCTION_ARGS)
Definition: tsginidx.c:40
Datum gin_tsquery_consistent_oldsig(PG_FUNCTION_ARGS)
Definition: tsginidx.c:350
Datum gin_tsquery_triconsistent(PG_FUNCTION_ARGS)
Definition: tsginidx.c:263
Datum gin_extract_tsquery_5args(PG_FUNCTION_ARGS)
Definition: tsginidx.c:316
Datum gin_cmp_tslexeme(PG_FUNCTION_ARGS)
Definition: tsginidx.c:24
Datum gin_extract_tsquery(PG_FUNCTION_ARGS)
Definition: tsginidx.c:94
Datum gin_tsquery_consistent_6args(PG_FUNCTION_ARGS)
Definition: tsginidx.c:328
Datum gin_extract_tsquery_oldsig(PG_FUNCTION_ARGS)
Definition: tsginidx.c:340
Datum gin_extract_tsvector_2args(PG_FUNCTION_ARGS)
Definition: tsginidx.c:304
Datum gin_extract_tsvector(PG_FUNCTION_ARGS)
Definition: tsginidx.c:64
Datum gin_tsquery_consistent(PG_FUNCTION_ARGS)
Definition: tsginidx.c:214
static TSTernaryValue checkcondition_gin(void *checkval, QueryOperand *val, ExecPhraseData *data)
Definition: tsginidx.c:183
int32 tsCompareString(char *a, int lena, char *b, int lenb, bool prefix)
Definition: tsvector_op.c:1152
bool tsquery_requires_match(QueryItem *curitem)
Definition: tsvector_op.c:2156
TSTernaryValue TS_execute_ternary(QueryItem *curitem, void *arg, uint32 flags, TSExecuteCallback chkcond)
Definition: tsvector_op.c:1871
QueryOperand qoperand
Definition: ts_type.h:210
#define VARDATA_ANY(PTR)
Definition: varatt.h:324
#define VARSIZE_ANY_EXHDR(PTR)
Definition: varatt.h:317
text * cstring_to_text_with_len(const char *s, int len)
Definition: varlena.c:196
const char * type