]> granicus.if.org Git - postgresql/blob - src/backend/utils/adt/tsginidx.c
Run pgindent on 9.2 source tree in preparation for first 9.3
[postgresql] / src / backend / utils / adt / tsginidx.c
1 /*-------------------------------------------------------------------------
2  *
3  * tsginidx.c
4  *       GIN support functions for tsvector_ops
5  *
6  * Portions Copyright (c) 1996-2012, 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/skey.h"
18 #include "tsearch/ts_type.h"
19 #include "tsearch/ts_utils.h"
20 #include "utils/builtins.h"
21
22
23 Datum
24 gin_cmp_tslexeme(PG_FUNCTION_ARGS)
25 {
26         text       *a = PG_GETARG_TEXT_PP(0);
27         text       *b = PG_GETARG_TEXT_PP(1);
28         int                     cmp;
29
30         cmp = tsCompareString(VARDATA_ANY(a), VARSIZE_ANY_EXHDR(a),
31                                                   VARDATA_ANY(b), VARSIZE_ANY_EXHDR(b),
32                                                   false);
33
34         PG_FREE_IF_COPY(a, 0);
35         PG_FREE_IF_COPY(b, 1);
36         PG_RETURN_INT32(cmp);
37 }
38
39 Datum
40 gin_cmp_prefix(PG_FUNCTION_ARGS)
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
51         cmp = tsCompareString(VARDATA_ANY(a), VARSIZE_ANY_EXHDR(a),
52                                                   VARDATA_ANY(b), VARSIZE_ANY_EXHDR(b),
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);
60         PG_RETURN_INT32(cmp);
61 }
62
63 Datum
64 gin_extract_tsvector(PG_FUNCTION_ARGS)
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
94 gin_extract_tsquery(PG_FUNCTION_ARGS)
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                 int4            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 {
174         QueryItem  *first_item;
175         bool       *check;
176         int                *map_item_operand;
177         bool       *need_recheck;
178 } GinChkVal;
179
180 static bool
181 checkcondition_gin(void *checkval, QueryOperand *val)
182 {
183         GinChkVal  *gcv = (GinChkVal *) checkval;
184         int                     j;
185
186         /* if any val requiring a weight is used, set recheck flag */
187         if (val->weight != 0)
188                 *(gcv->need_recheck) = true;
189
190         /* convert item's number to corresponding entry's (operand's) number */
191         j = gcv->map_item_operand[((QueryItem *) val) - gcv->first_item];
192
193         /* return presence of current entry in indexed value */
194         return gcv->check[j];
195 }
196
197 Datum
198 gin_tsquery_consistent(PG_FUNCTION_ARGS)
199 {
200         bool       *check = (bool *) PG_GETARG_POINTER(0);
201
202         /* StrategyNumber strategy = PG_GETARG_UINT16(1); */
203         TSQuery         query = PG_GETARG_TSQUERY(2);
204
205         /* int32        nkeys = PG_GETARG_INT32(3); */
206         Pointer    *extra_data = (Pointer *) PG_GETARG_POINTER(4);
207         bool       *recheck = (bool *) PG_GETARG_POINTER(5);
208         bool            res = FALSE;
209
210         /* The query requires recheck only if it involves weights */
211         *recheck = false;
212
213         if (query->size > 0)
214         {
215                 QueryItem  *item;
216                 GinChkVal       gcv;
217
218                 /*
219                  * check-parameter array has one entry for each value (operand) in the
220                  * query.
221                  */
222                 gcv.first_item = item = GETQUERY(query);
223                 gcv.check = check;
224                 gcv.map_item_operand = (int *) (extra_data[0]);
225                 gcv.need_recheck = recheck;
226
227                 res = TS_execute(GETQUERY(query),
228                                                  &gcv,
229                                                  true,
230                                                  checkcondition_gin);
231         }
232
233         PG_RETURN_BOOL(res);
234 }
235
236 /*
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.)
243  */
244 Datum
245 gin_extract_tsvector_2args(PG_FUNCTION_ARGS)
246 {
247         if (PG_NARGS() < 3)                     /* should not happen */
248                 elog(ERROR, "gin_extract_tsvector requires three arguments");
249         return gin_extract_tsvector(fcinfo);
250 }
251
252 /*
253  * Likewise, we need a stub version of gin_extract_tsquery declared with
254  * only five arguments.
255  */
256 Datum
257 gin_extract_tsquery_5args(PG_FUNCTION_ARGS)
258 {
259         if (PG_NARGS() < 7)                     /* should not happen */
260                 elog(ERROR, "gin_extract_tsquery requires seven arguments");
261         return gin_extract_tsquery(fcinfo);
262 }
263
264 /*
265  * Likewise, we need a stub version of gin_tsquery_consistent declared with
266  * only six arguments.
267  */
268 Datum
269 gin_tsquery_consistent_6args(PG_FUNCTION_ARGS)
270 {
271         if (PG_NARGS() < 8)                     /* should not happen */
272                 elog(ERROR, "gin_tsquery_consistent requires eight arguments");
273         return gin_tsquery_consistent(fcinfo);
274 }