]> granicus.if.org Git - postgresql/blob - contrib/pg_trgm/trgm_gin.c
Fix contrib/pg_trgm to have smoother updates from 9.0.
[postgresql] / contrib / pg_trgm / trgm_gin.c
1 /*
2  * contrib/pg_trgm/trgm_gin.c
3  */
4 #include "postgres.h"
5
6 #include "trgm.h"
7
8 #include "access/gin.h"
9 #include "access/itup.h"
10 #include "access/skey.h"
11 #include "access/tuptoaster.h"
12 #include "storage/bufpage.h"
13 #include "utils/array.h"
14 #include "utils/builtins.h"
15
16
17 PG_FUNCTION_INFO_V1(gin_extract_trgm);
18 Datum           gin_extract_trgm(PG_FUNCTION_ARGS);
19
20 PG_FUNCTION_INFO_V1(gin_extract_value_trgm);
21 Datum           gin_extract_value_trgm(PG_FUNCTION_ARGS);
22
23 PG_FUNCTION_INFO_V1(gin_extract_query_trgm);
24 Datum           gin_extract_query_trgm(PG_FUNCTION_ARGS);
25
26 PG_FUNCTION_INFO_V1(gin_trgm_consistent);
27 Datum           gin_trgm_consistent(PG_FUNCTION_ARGS);
28
29 /*
30  * This function can only be called if a pre-9.1 version of the GIN operator
31  * class definition is present in the catalogs (probably as a consequence
32  * of upgrade-in-place).  Cope.
33  */
34 Datum
35 gin_extract_trgm(PG_FUNCTION_ARGS)
36 {
37         if (PG_NARGS() == 3)
38                 return gin_extract_value_trgm(fcinfo);
39         if (PG_NARGS() == 7)
40                 return gin_extract_query_trgm(fcinfo);
41         elog(ERROR, "unexpected number of arguments to gin_extract_trgm");
42         PG_RETURN_NULL();
43 }
44
45 Datum
46 gin_extract_value_trgm(PG_FUNCTION_ARGS)
47 {
48         text       *val = (text *) PG_GETARG_TEXT_P(0);
49         int32      *nentries = (int32 *) PG_GETARG_POINTER(1);
50         Datum      *entries = NULL;
51         TRGM       *trg;
52         int32           trglen;
53
54         *nentries = 0;
55
56         trg = generate_trgm(VARDATA(val), VARSIZE(val) - VARHDRSZ);
57         trglen = ARRNELEM(trg);
58
59         if (trglen > 0)
60         {
61                 trgm       *ptr;
62                 int32           i;
63
64                 *nentries = trglen;
65                 entries = (Datum *) palloc(sizeof(Datum) * trglen);
66
67                 ptr = GETARR(trg);
68                 for (i = 0; i < trglen; i++)
69                 {
70                         int32   item = trgm2int(ptr);
71
72                         entries[i] = Int32GetDatum(item);
73                         ptr++;
74                 }
75         }
76
77         PG_RETURN_POINTER(entries);
78 }
79
80 Datum
81 gin_extract_query_trgm(PG_FUNCTION_ARGS)
82 {
83         text       *val = (text *) PG_GETARG_TEXT_P(0);
84         int32      *nentries = (int32 *) PG_GETARG_POINTER(1);
85         StrategyNumber strategy = PG_GETARG_UINT16(2);
86         /* bool   **pmatch = (bool **) PG_GETARG_POINTER(3); */
87         /* Pointer    *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
88         /* bool   **nullFlags = (bool **) PG_GETARG_POINTER(5); */
89         int32      *searchMode = (int32 *) PG_GETARG_POINTER(6);
90         Datum      *entries = NULL;
91         TRGM       *trg;
92         int32           trglen;
93         trgm       *ptr;
94         int32           i;
95
96         switch (strategy)
97         {
98                 case SimilarityStrategyNumber:
99                         trg = generate_trgm(VARDATA(val), VARSIZE(val) - VARHDRSZ);
100                         break;
101                 case ILikeStrategyNumber:
102 #ifndef IGNORECASE
103                         elog(ERROR, "cannot handle ~~* with case-sensitive trigrams");
104 #endif
105                         /* FALL THRU */
106                 case LikeStrategyNumber:
107                         /*
108                          * For wildcard search we extract all the trigrams that every
109                          * potentially-matching string must include.
110                          */
111                         trg = generate_wildcard_trgm(VARDATA(val), VARSIZE(val) - VARHDRSZ);
112                         break;
113                 default:
114                         elog(ERROR, "unrecognized strategy number: %d", strategy);
115                         trg = NULL;             /* keep compiler quiet */
116                         break;
117         }
118
119         trglen = ARRNELEM(trg);
120         *nentries = trglen;
121
122         if (trglen > 0)
123         {
124                 entries = (Datum *) palloc(sizeof(Datum) * trglen);
125                 ptr = GETARR(trg);
126                 for (i = 0; i < trglen; i++)
127                 {
128                         int32   item = trgm2int(ptr);
129
130                         entries[i] = Int32GetDatum(item);
131                         ptr++;
132                 }
133         }
134
135         /*
136          * If no trigram was extracted then we have to scan all the index.
137          */
138         if (trglen == 0)
139                 *searchMode = GIN_SEARCH_MODE_ALL;
140
141         PG_RETURN_POINTER(entries);
142 }
143
144 Datum
145 gin_trgm_consistent(PG_FUNCTION_ARGS)
146 {
147         bool       *check = (bool *) PG_GETARG_POINTER(0);
148         StrategyNumber strategy = PG_GETARG_UINT16(1);
149         /* text    *query = PG_GETARG_TEXT_P(2); */
150         int32           nkeys = PG_GETARG_INT32(3);
151         /* Pointer    *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
152         bool       *recheck = (bool *) PG_GETARG_POINTER(5);
153         bool            res;
154         int32           i,
155                                 ntrue;
156
157         /* All cases served by this function are inexact */
158         *recheck = true;
159
160         switch (strategy)
161         {
162                 case SimilarityStrategyNumber:
163                         /* Count the matches */
164                         ntrue = 0;
165                         for (i = 0; i < nkeys; i++)
166                         {
167                                 if (check[i])
168                                         ntrue++;
169                         }
170 #ifdef DIVUNION
171                         res = (nkeys == ntrue) ? true : ((((((float4) ntrue) / ((float4) (nkeys - ntrue)))) >= trgm_limit) ? true : false);
172 #else
173                         res = (nkeys == 0) ? false : ((((((float4) ntrue) / ((float4) nkeys))) >= trgm_limit) ? true : false);
174 #endif
175                         break;
176                 case ILikeStrategyNumber:
177 #ifndef IGNORECASE
178                         elog(ERROR, "cannot handle ~~* with case-sensitive trigrams");
179 #endif
180                         /* FALL THRU */
181                 case LikeStrategyNumber:
182                         /* Check if all extracted trigrams are presented. */
183                         res = true;
184                         for (i = 0; i < nkeys; i++)
185                         {
186                                 if (!check[i])
187                                 {
188                                         res = false;
189                                         break;
190                                 }
191                         }
192                         break;
193                 default:
194                         elog(ERROR, "unrecognized strategy number: %d", strategy);
195                         res = false;            /* keep compiler quiet */
196                         break;
197         }
198
199         PG_RETURN_BOOL(res);
200 }