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