Age Owner Branch data TLA 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-2024, 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/fmgrprotos.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
6402 bruce@momjian.us 33 :CBC 529001 : ginarrayextract(PG_FUNCTION_ARGS)
34 : : {
35 : : /* Make copy of array input to ensure it doesn't disappear while in use */
4846 tgl@sss.pgh.pa.us 36 : 529001 : ArrayType *array = PG_GETARG_ARRAYTYPE_P_COPY(0);
37 : 529001 : int32 *nkeys = (int32 *) PG_GETARG_POINTER(1);
38 : 529001 : 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 : :
6557 teodor@sigaev.ru 46 : 529001 : get_typlenbyvalalign(ARR_ELEMTYPE(array),
47 : : &elmlen, &elmbyval, &elmalign);
48 : :
49 : 529001 : deconstruct_array(array,
50 : : ARR_ELEMTYPE(array),
51 : : elmlen, elmbyval, elmalign,
52 : : &elems, &nulls, &nelems);
53 : :
4846 tgl@sss.pgh.pa.us 54 : 529001 : *nkeys = nelems;
55 : 529001 : *nullFlags = nulls;
56 : :
57 : : /* we should not free array, elems[i] points into it */
58 : 529001 : 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
4806 tgl@sss.pgh.pa.us 68 :UBC 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
6081 tgl@sss.pgh.pa.us 79 :CBC 666 : ginqueryarrayextract(PG_FUNCTION_ARGS)
80 : : {
81 : : /* Make copy of array input to ensure it doesn't disappear while in use */
4846 82 : 666 : ArrayType *array = PG_GETARG_ARRAYTYPE_P_COPY(0);
83 : 666 : int32 *nkeys = (int32 *) PG_GETARG_POINTER(1);
84 : 666 : 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 : 666 : bool **nullFlags = (bool **) PG_GETARG_POINTER(5);
89 : 666 : 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 : 666 : get_typlenbyvalalign(ARR_ELEMTYPE(array),
98 : : &elmlen, &elmbyval, &elmalign);
99 : :
100 : 666 : deconstruct_array(array,
101 : : ARR_ELEMTYPE(array),
102 : : elmlen, elmbyval, elmalign,
103 : : &elems, &nulls, &nelems);
104 : :
105 : 666 : *nkeys = nelems;
106 : 666 : *nullFlags = nulls;
107 : :
108 [ + + + + : 666 : switch (strategy)
- ]
109 : : {
110 : 82 : case GinOverlapStrategy:
111 : 82 : *searchMode = GIN_SEARCH_MODE_DEFAULT;
112 : 82 : break;
113 : 530 : case GinContainsStrategy:
114 [ + + ]: 530 : if (nelems > 0)
115 : 338 : *searchMode = GIN_SEARCH_MODE_DEFAULT;
116 : : else /* everything contains the empty set */
117 : 192 : *searchMode = GIN_SEARCH_MODE_ALL;
118 : 530 : break;
119 : 24 : case GinContainedStrategy:
120 : : /* empty set is contained in everything */
121 : 24 : *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY;
122 : 24 : break;
123 : 30 : case GinEqualStrategy:
124 [ + + ]: 30 : if (nelems > 0)
125 : 12 : *searchMode = GIN_SEARCH_MODE_DEFAULT;
126 : : else
127 : 18 : *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY;
128 : 30 : break;
4846 tgl@sss.pgh.pa.us 129 :UBC 0 : 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 */
4846 tgl@sss.pgh.pa.us 135 :CBC 666 : PG_RETURN_POINTER(elems);
136 : : }
137 : :
138 : : /*
139 : : * consistent support function
140 : : */
141 : : Datum
6402 bruce@momjian.us 142 : 405 : ginarrayconsistent(PG_FUNCTION_ARGS)
143 : : {
144 : 405 : bool *check = (bool *) PG_GETARG_POINTER(0);
145 : 405 : StrategyNumber strategy = PG_GETARG_UINT16(1);
146 : :
147 : : /* ArrayType *query = PG_GETARG_ARRAYTYPE_P(2); */
4846 tgl@sss.pgh.pa.us 148 : 405 : int32 nkeys = PG_GETARG_INT32(3);
149 : :
150 : : /* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
5499 151 : 405 : bool *recheck = (bool *) PG_GETARG_POINTER(5);
152 : :
153 : : /* Datum *queryKeys = (Datum *) PG_GETARG_POINTER(6); */
4846 154 : 405 : bool *nullFlags = (bool *) PG_GETARG_POINTER(7);
155 : : bool res;
156 : : int32 i;
157 : :
6402 bruce@momjian.us 158 [ - + - - : 405 : switch (strategy)
- ]
159 : : {
6557 teodor@sigaev.ru 160 :UBC 0 : case GinOverlapStrategy:
161 : : /* result is not lossy */
5844 tgl@sss.pgh.pa.us 162 : 0 : *recheck = false;
163 : : /* must have a match for at least one non-null element */
4846 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 : : }
6557 teodor@sigaev.ru 173 : 0 : break;
6557 teodor@sigaev.ru 174 :CBC 405 : case GinContainsStrategy:
175 : : /* result is not lossy */
5844 tgl@sss.pgh.pa.us 176 : 405 : *recheck = false;
177 : : /* must have all elements in check[] true, and no nulls */
178 : 405 : res = true;
4846 179 [ + + ]: 555 : for (i = 0; i < nkeys; i++)
180 : : {
181 [ + - - + ]: 150 : if (!check[i] || nullFlags[i])
182 : : {
5844 tgl@sss.pgh.pa.us 183 :UBC 0 : res = false;
184 : 0 : break;
185 : : }
186 : : }
5844 tgl@sss.pgh.pa.us 187 :CBC 405 : break;
4846 tgl@sss.pgh.pa.us 188 :UBC 0 : 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;
6487 teodor@sigaev.ru 194 : 0 : case GinEqualStrategy:
195 : : /* we will need recheck */
5844 tgl@sss.pgh.pa.us 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;
4846 204 [ # # ]: 0 : for (i = 0; i < nkeys; i++)
205 : : {
6402 bruce@momjian.us 206 [ # # ]: 0 : if (!check[i])
207 : : {
5844 tgl@sss.pgh.pa.us 208 : 0 : res = false;
6557 teodor@sigaev.ru 209 : 0 : break;
210 : : }
211 : : }
212 : 0 : break;
213 : 0 : default:
6426 tgl@sss.pgh.pa.us 214 [ # # ]: 0 : elog(ERROR, "ginarrayconsistent: unknown strategy number: %d",
215 : : strategy);
216 : : res = false;
217 : : }
218 : :
6557 teodor@sigaev.ru 219 :CBC 405 : PG_RETURN_BOOL(res);
220 : : }
221 : :
222 : : /*
223 : : * triconsistent support function
224 : : */
225 : : Datum
3686 heikki.linnakangas@i 226 : 404269 : ginarraytriconsistent(PG_FUNCTION_ARGS)
227 : : {
3667 228 : 404269 : GinTernaryValue *check = (GinTernaryValue *) PG_GETARG_POINTER(0);
3686 229 : 404269 : StrategyNumber strategy = PG_GETARG_UINT16(1);
230 : :
231 : : /* ArrayType *query = PG_GETARG_ARRAYTYPE_P(2); */
232 : 404269 : 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 : 404269 : bool *nullFlags = (bool *) PG_GETARG_POINTER(6);
237 : : GinTernaryValue res;
238 : : int32 i;
239 : :
240 [ + + + + : 404269 : switch (strategy)
- ]
241 : : {
242 : 1746 : case GinOverlapStrategy:
243 : : /* must have a match for at least one non-null element */
244 : 1746 : res = GIN_FALSE;
245 [ + + ]: 461067 : for (i = 0; i < nkeys; i++)
246 : : {
247 [ + - ]: 459566 : if (!nullFlags[i])
248 : : {
249 [ + + ]: 459566 : if (check[i] == GIN_TRUE)
250 : : {
251 : 245 : res = GIN_TRUE;
252 : 245 : break;
253 : : }
254 [ + + + + ]: 459321 : else if (check[i] == GIN_MAYBE && res == GIN_FALSE)
255 : : {
256 : 1501 : res = GIN_MAYBE;
257 : : }
258 : : }
259 : : }
260 : 1746 : break;
261 : 402319 : case GinContainsStrategy:
262 : : /* must have all elements in check[] true, and no nulls */
263 : 402319 : res = GIN_TRUE;
264 [ + + ]: 744008 : for (i = 0; i < nkeys; i++)
265 : : {
266 [ + + - + ]: 341713 : if (check[i] == GIN_FALSE || nullFlags[i])
267 : : {
268 : 24 : res = GIN_FALSE;
269 : 24 : break;
270 : : }
271 [ + + ]: 341689 : if (check[i] == GIN_MAYBE)
272 : : {
273 : 6 : res = GIN_MAYBE;
274 : : }
275 : : }
276 : 402319 : break;
277 : 168 : case GinContainedStrategy:
278 : : /* can't do anything else useful here */
279 : 168 : res = GIN_MAYBE;
280 : 168 : break;
281 : 36 : 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 : 36 : res = GIN_MAYBE;
289 [ + + ]: 66 : for (i = 0; i < nkeys; i++)
290 : : {
291 [ + + ]: 51 : if (check[i] == GIN_FALSE)
292 : : {
293 : 21 : res = GIN_FALSE;
294 : 21 : break;
295 : : }
296 : : }
297 : 36 : break;
3686 heikki.linnakangas@i 298 :UBC 0 : default:
299 [ # # ]: 0 : elog(ERROR, "ginarrayconsistent: unknown strategy number: %d",
300 : : strategy);
301 : : res = false;
302 : : }
303 : :
3667 heikki.linnakangas@i 304 :CBC 404269 : PG_RETURN_GIN_TERNARY_VALUE(res);
305 : : }
|