1 /*-------------------------------------------------------------------------
4 * GIN support functions for tsvector_ops
6 * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
10 * src/backend/utils/adt/tsginidx.c
12 *-------------------------------------------------------------------------
16 #include "access/gin.h"
17 #include "access/skey.h"
18 #include "tsearch/ts_type.h"
19 #include "tsearch/ts_utils.h"
20 #include "utils/builtins.h"
24 gin_cmp_tslexeme(PG_FUNCTION_ARGS)
26 text *a = PG_GETARG_TEXT_PP(0);
27 text *b = PG_GETARG_TEXT_PP(1);
30 cmp = tsCompareString(VARDATA_ANY(a), VARSIZE_ANY_EXHDR(a),
31 VARDATA_ANY(b), VARSIZE_ANY_EXHDR(b),
34 PG_FREE_IF_COPY(a, 0);
35 PG_FREE_IF_COPY(b, 1);
40 gin_cmp_prefix(PG_FUNCTION_ARGS)
42 text *a = PG_GETARG_TEXT_PP(0);
43 text *b = PG_GETARG_TEXT_PP(1);
46 StrategyNumber strategy = PG_GETARG_UINT16(2);
47 Pointer extra_data = PG_GETARG_POINTER(3);
51 cmp = tsCompareString(VARDATA_ANY(a), VARSIZE_ANY_EXHDR(a),
52 VARDATA_ANY(b), VARSIZE_ANY_EXHDR(b),
56 cmp = 1; /* prevent continue scan */
58 PG_FREE_IF_COPY(a, 0);
59 PG_FREE_IF_COPY(b, 1);
64 gin_extract_tsvector(PG_FUNCTION_ARGS)
66 TSVector vector = PG_GETARG_TSVECTOR(0);
67 int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
68 Datum *entries = NULL;
70 *nentries = vector->size;
74 WordEntry *we = ARRPTR(vector);
76 entries = (Datum *) palloc(sizeof(Datum) * vector->size);
78 for (i = 0; i < vector->size; i++)
82 txt = cstring_to_text_with_len(STRPTR(vector) + we->pos, we->len);
83 entries[i] = PointerGetDatum(txt);
89 PG_FREE_IF_COPY(vector, 0);
90 PG_RETURN_POINTER(entries);
94 gin_extract_tsquery(PG_FUNCTION_ARGS)
96 TSQuery query = PG_GETARG_TSQUERY(0);
97 int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
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);
103 /* bool **nullFlags = (bool **) PG_GETARG_POINTER(5); */
104 int32 *searchMode = (int32 *) PG_GETARG_POINTER(6);
105 Datum *entries = NULL;
111 QueryItem *item = GETQUERY(query);
115 int *map_item_operand;
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
122 if (tsquery_requires_match(item))
123 *searchMode = GIN_SEARCH_MODE_DEFAULT;
125 *searchMode = GIN_SEARCH_MODE_ALL;
127 /* count number of VAL items */
129 for (i = 0; i < query->size; i++)
131 if (item[i].type == QI_VAL)
136 entries = (Datum *) palloc(sizeof(Datum) * j);
137 partialmatch = *ptr_partialmatch = (bool *) palloc(sizeof(bool) * j);
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.
144 *extra_data = (Pointer *) palloc(sizeof(Pointer) * j);
145 map_item_operand = (int *) palloc0(sizeof(int) * query->size);
147 /* Now rescan the VAL items and fill in the arrays */
149 for (i = 0; i < query->size; i++)
151 if (item[i].type == QI_VAL)
153 QueryOperand *val = &item[i].qoperand;
156 txt = cstring_to_text_with_len(GETOPERAND(query) + val->distance,
158 entries[j] = PointerGetDatum(txt);
159 partialmatch[j] = val->prefix;
160 (*extra_data)[j] = (Pointer) map_item_operand;
161 map_item_operand[i] = j;
167 PG_FREE_IF_COPY(query, 0);
169 PG_RETURN_POINTER(entries);
174 QueryItem *first_item;
176 int *map_item_operand;
181 checkcondition_gin(void *checkval, QueryOperand *val)
183 GinChkVal *gcv = (GinChkVal *) checkval;
186 /* if any val requiring a weight is used, set recheck flag */
187 if (val->weight != 0)
188 *(gcv->need_recheck) = true;
190 /* convert item's number to corresponding entry's (operand's) number */
191 j = gcv->map_item_operand[((QueryItem *) val) - gcv->first_item];
193 /* return presence of current entry in indexed value */
194 return gcv->check[j];
198 gin_tsquery_consistent(PG_FUNCTION_ARGS)
200 bool *check = (bool *) PG_GETARG_POINTER(0);
202 /* StrategyNumber strategy = PG_GETARG_UINT16(1); */
203 TSQuery query = PG_GETARG_TSQUERY(2);
205 /* int32 nkeys = PG_GETARG_INT32(3); */
206 Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4);
207 bool *recheck = (bool *) PG_GETARG_POINTER(5);
210 /* The query requires recheck only if it involves weights */
219 * check-parameter array has one entry for each value (operand) in the
222 gcv.first_item = item = GETQUERY(query);
224 gcv.map_item_operand = (int *) (extra_data[0]);
225 gcv.need_recheck = recheck;
227 res = TS_execute(GETQUERY(query),
237 * Formerly, gin_extract_tsvector had only two arguments. Now it has three,
238 * but we still need a pg_proc entry with two args to support reloading
239 * pre-9.1 contrib/tsearch2 opclass declarations. This compatibility
240 * function should go away eventually. (Note: you might say "hey, but the
241 * code above is only *using* two args, so let's just declare it that way".
242 * If you try that you'll find the opr_sanity regression test complains.)
245 gin_extract_tsvector_2args(PG_FUNCTION_ARGS)
247 if (PG_NARGS() < 3) /* should not happen */
248 elog(ERROR, "gin_extract_tsvector requires three arguments");
249 return gin_extract_tsvector(fcinfo);
253 * Likewise, we need a stub version of gin_extract_tsquery declared with
254 * only five arguments.
257 gin_extract_tsquery_5args(PG_FUNCTION_ARGS)
259 if (PG_NARGS() < 7) /* should not happen */
260 elog(ERROR, "gin_extract_tsquery requires seven arguments");
261 return gin_extract_tsquery(fcinfo);
265 * Likewise, we need a stub version of gin_tsquery_consistent declared with
266 * only six arguments.
269 gin_tsquery_consistent_6args(PG_FUNCTION_ARGS)
271 if (PG_NARGS() < 8) /* should not happen */
272 elog(ERROR, "gin_tsquery_consistent requires eight arguments");
273 return gin_tsquery_consistent(fcinfo);