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-2024, 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 
23 Datum
25 {
26  text *a = PG_GETARG_TEXT_PP(0);
27  text *b = PG_GETARG_TEXT_PP(1);
28  int cmp;
29 
32  false);
33 
34  PG_FREE_IF_COPY(a, 0);
35  PG_FREE_IF_COPY(b, 1);
37 }
38 
39 Datum
41 {
42  text *a = PG_GETARG_TEXT_PP(0);
43  text *b = PG_GETARG_TEXT_PP(1);
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 
58  PG_FREE_IF_COPY(a, 0);
59  PG_FREE_IF_COPY(b, 1);
61 }
62 
63 Datum
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 
93 Datum
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 
172 typedef struct
173 {
177 } GinChkVal;
178 
179 /*
180  * TS_execute callback for matching a tsquery operand to GIN index data
181  */
182 static 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 
213 Datum
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 
262 Datum
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  */
303 Datum
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  */
315 Datum
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  */
327 Datum
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  */
339 Datum
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  */
349 Datum
351 {
352  return gin_tsquery_consistent(fcinfo);
353 }
#define GETQUERY(x)
Definition: _int.h:157
signed int int32
Definition: c.h:481
char * Pointer
Definition: c.h:470
#define ARRPTR(x)
Definition: cube.c:25
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#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:664
int b
Definition: isn.c:70
int a
Definition: isn.c:69
int j
Definition: isn.c:74
int i
Definition: isn.c:73
#define GETOPERAND(x)
Definition: ltree.h:165
void * palloc0(Size size)
Definition: mcxt.c:1334
void * palloc(Size size)
Definition: mcxt.c:1304
const void * data
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
uintptr_t Datum
Definition: postgres.h:64
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:674
#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