Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * ginarrayproc.c
4 : * support functions for GIN's indexing of any array
5 : *
6 : *
7 : * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
8 : * Portions Copyright (c) 1994, Regents of the University of California
9 : *
10 : * IDENTIFICATION
11 : * src/backend/access/gin/ginarrayproc.c
12 : *-------------------------------------------------------------------------
13 : */
14 : #include "postgres.h"
15 :
16 : #include "access/gin.h"
17 : #include "access/stratnum.h"
18 : #include "utils/array.h"
19 : #include "utils/builtins.h"
20 : #include "utils/lsyscache.h"
21 :
22 :
23 : #define GinOverlapStrategy 1
24 : #define GinContainsStrategy 2
25 : #define GinContainedStrategy 3
26 : #define GinEqualStrategy 4
27 :
28 :
29 : /*
30 : * extractValue support function
31 : */
32 : Datum
33 34510 : ginarrayextract(PG_FUNCTION_ARGS)
34 : {
35 : /* Make copy of array input to ensure it doesn't disappear while in use */
36 34510 : ArrayType *array = PG_GETARG_ARRAYTYPE_P_COPY(0);
37 34510 : int32 *nkeys = (int32 *) PG_GETARG_POINTER(1);
38 34510 : bool **nullFlags = (bool **) PG_GETARG_POINTER(2);
39 : int16 elmlen;
40 : bool elmbyval;
41 : char elmalign;
42 : Datum *elems;
43 : bool *nulls;
44 : int nelems;
45 :
46 34510 : get_typlenbyvalalign(ARR_ELEMTYPE(array),
47 : &elmlen, &elmbyval, &elmalign);
48 :
49 34510 : deconstruct_array(array,
50 : ARR_ELEMTYPE(array),
51 : elmlen, elmbyval, elmalign,
52 : &elems, &nulls, &nelems);
53 :
54 34510 : *nkeys = nelems;
55 34510 : *nullFlags = nulls;
56 :
57 : /* we should not free array, elems[i] points into it */
58 34510 : PG_RETURN_POINTER(elems);
59 : }
60 :
61 : /*
62 : * Formerly, ginarrayextract had only two arguments. Now it has three,
63 : * but we still need a pg_proc entry with two args to support reloading
64 : * pre-9.1 contrib/intarray opclass declarations. This compatibility
65 : * function should go away eventually.
66 : */
67 : Datum
68 0 : ginarrayextract_2args(PG_FUNCTION_ARGS)
69 : {
70 0 : if (PG_NARGS() < 3) /* should not happen */
71 0 : elog(ERROR, "ginarrayextract requires three arguments");
72 0 : return ginarrayextract(fcinfo);
73 : }
74 :
75 : /*
76 : * extractQuery support function
77 : */
78 : Datum
79 74 : ginqueryarrayextract(PG_FUNCTION_ARGS)
80 : {
81 : /* Make copy of array input to ensure it doesn't disappear while in use */
82 74 : ArrayType *array = PG_GETARG_ARRAYTYPE_P_COPY(0);
83 74 : int32 *nkeys = (int32 *) PG_GETARG_POINTER(1);
84 74 : StrategyNumber strategy = PG_GETARG_UINT16(2);
85 :
86 : /* bool **pmatch = (bool **) PG_GETARG_POINTER(3); */
87 : /* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
88 74 : bool **nullFlags = (bool **) PG_GETARG_POINTER(5);
89 74 : int32 *searchMode = (int32 *) PG_GETARG_POINTER(6);
90 : int16 elmlen;
91 : bool elmbyval;
92 : char elmalign;
93 : Datum *elems;
94 : bool *nulls;
95 : int nelems;
96 :
97 74 : get_typlenbyvalalign(ARR_ELEMTYPE(array),
98 : &elmlen, &elmbyval, &elmalign);
99 :
100 74 : deconstruct_array(array,
101 : ARR_ELEMTYPE(array),
102 : elmlen, elmbyval, elmalign,
103 : &elems, &nulls, &nelems);
104 :
105 74 : *nkeys = nelems;
106 74 : *nullFlags = nulls;
107 :
108 74 : switch (strategy)
109 : {
110 : case GinOverlapStrategy:
111 24 : *searchMode = GIN_SEARCH_MODE_DEFAULT;
112 24 : break;
113 : case GinContainsStrategy:
114 32 : if (nelems > 0)
115 28 : *searchMode = GIN_SEARCH_MODE_DEFAULT;
116 : else /* everything contains the empty set */
117 4 : *searchMode = GIN_SEARCH_MODE_ALL;
118 32 : break;
119 : case GinContainedStrategy:
120 : /* empty set is contained in everything */
121 8 : *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY;
122 8 : break;
123 : case GinEqualStrategy:
124 10 : if (nelems > 0)
125 4 : *searchMode = GIN_SEARCH_MODE_DEFAULT;
126 : else
127 6 : *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY;
128 10 : break;
129 : default:
130 0 : elog(ERROR, "ginqueryarrayextract: unknown strategy number: %d",
131 : strategy);
132 : }
133 :
134 : /* we should not free array, elems[i] points into it */
135 74 : PG_RETURN_POINTER(elems);
136 : }
137 :
138 : /*
139 : * consistent support function
140 : */
141 : Datum
142 0 : ginarrayconsistent(PG_FUNCTION_ARGS)
143 : {
144 0 : bool *check = (bool *) PG_GETARG_POINTER(0);
145 0 : StrategyNumber strategy = PG_GETARG_UINT16(1);
146 :
147 : /* ArrayType *query = PG_GETARG_ARRAYTYPE_P(2); */
148 0 : int32 nkeys = PG_GETARG_INT32(3);
149 :
150 : /* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
151 0 : bool *recheck = (bool *) PG_GETARG_POINTER(5);
152 :
153 : /* Datum *queryKeys = (Datum *) PG_GETARG_POINTER(6); */
154 0 : bool *nullFlags = (bool *) PG_GETARG_POINTER(7);
155 : bool res;
156 : int32 i;
157 :
158 0 : switch (strategy)
159 : {
160 : case GinOverlapStrategy:
161 : /* result is not lossy */
162 0 : *recheck = false;
163 : /* must have a match for at least one non-null element */
164 0 : res = false;
165 0 : for (i = 0; i < nkeys; i++)
166 : {
167 0 : if (check[i] && !nullFlags[i])
168 : {
169 0 : res = true;
170 0 : break;
171 : }
172 : }
173 0 : break;
174 : case GinContainsStrategy:
175 : /* result is not lossy */
176 0 : *recheck = false;
177 : /* must have all elements in check[] true, and no nulls */
178 0 : res = true;
179 0 : for (i = 0; i < nkeys; i++)
180 : {
181 0 : if (!check[i] || nullFlags[i])
182 : {
183 0 : res = false;
184 0 : break;
185 : }
186 : }
187 0 : break;
188 : case GinContainedStrategy:
189 : /* we will need recheck */
190 0 : *recheck = true;
191 : /* can't do anything else useful here */
192 0 : res = true;
193 0 : break;
194 : case GinEqualStrategy:
195 : /* we will need recheck */
196 0 : *recheck = true;
197 :
198 : /*
199 : * Must have all elements in check[] true; no discrimination
200 : * against nulls here. This is because array_contain_compare and
201 : * array_eq handle nulls differently ...
202 : */
203 0 : res = true;
204 0 : for (i = 0; i < nkeys; i++)
205 : {
206 0 : if (!check[i])
207 : {
208 0 : res = false;
209 0 : break;
210 : }
211 : }
212 0 : break;
213 : default:
214 0 : elog(ERROR, "ginarrayconsistent: unknown strategy number: %d",
215 : strategy);
216 : res = false;
217 : }
218 :
219 0 : PG_RETURN_BOOL(res);
220 : }
221 :
222 : /*
223 : * triconsistent support function
224 : */
225 : Datum
226 43393 : ginarraytriconsistent(PG_FUNCTION_ARGS)
227 : {
228 43393 : GinTernaryValue *check = (GinTernaryValue *) PG_GETARG_POINTER(0);
229 43393 : StrategyNumber strategy = PG_GETARG_UINT16(1);
230 :
231 : /* ArrayType *query = PG_GETARG_ARRAYTYPE_P(2); */
232 43393 : int32 nkeys = PG_GETARG_INT32(3);
233 :
234 : /* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
235 : /* Datum *queryKeys = (Datum *) PG_GETARG_POINTER(5); */
236 43393 : bool *nullFlags = (bool *) PG_GETARG_POINTER(6);
237 : GinTernaryValue res;
238 : int32 i;
239 :
240 43393 : switch (strategy)
241 : {
242 : case GinOverlapStrategy:
243 : /* must have a match for at least one non-null element */
244 62 : res = GIN_FALSE;
245 73 : for (i = 0; i < nkeys; i++)
246 : {
247 71 : if (!nullFlags[i])
248 : {
249 71 : if (check[i] == GIN_TRUE)
250 : {
251 60 : res = GIN_TRUE;
252 60 : break;
253 : }
254 11 : else if (check[i] == GIN_MAYBE && res == GIN_FALSE)
255 : {
256 2 : res = GIN_MAYBE;
257 : }
258 : }
259 : }
260 62 : break;
261 : case GinContainsStrategy:
262 : /* must have all elements in check[] true, and no nulls */
263 43263 : res = GIN_TRUE;
264 86323 : for (i = 0; i < nkeys; i++)
265 : {
266 43067 : if (check[i] == GIN_FALSE || nullFlags[i])
267 : {
268 7 : res = GIN_FALSE;
269 7 : break;
270 : }
271 43060 : if (check[i] == GIN_MAYBE)
272 : {
273 1 : res = GIN_MAYBE;
274 : }
275 : }
276 43263 : break;
277 : case GinContainedStrategy:
278 : /* can't do anything else useful here */
279 56 : res = GIN_MAYBE;
280 56 : break;
281 : case GinEqualStrategy:
282 :
283 : /*
284 : * Must have all elements in check[] true; no discrimination
285 : * against nulls here. This is because array_contain_compare and
286 : * array_eq handle nulls differently ...
287 : */
288 12 : res = GIN_MAYBE;
289 22 : for (i = 0; i < nkeys; i++)
290 : {
291 17 : if (check[i] == GIN_FALSE)
292 : {
293 7 : res = GIN_FALSE;
294 7 : break;
295 : }
296 : }
297 12 : break;
298 : default:
299 0 : elog(ERROR, "ginarrayconsistent: unknown strategy number: %d",
300 : strategy);
301 : res = false;
302 : }
303 :
304 43393 : PG_RETURN_GIN_TERNARY_VALUE(res);
305 : }
|