PostgreSQL Source Code  git master
ginarrayproc.c
Go to the documentation of this file.
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
34 {
35  /* Make copy of array input to ensure it doesn't disappear while in use */
37  int32 *nkeys = (int32 *) PG_GETARG_POINTER(1);
38  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 
47  &elmlen, &elmbyval, &elmalign);
48 
49  deconstruct_array(array,
50  ARR_ELEMTYPE(array),
51  elmlen, elmbyval, elmalign,
52  &elems, &nulls, &nelems);
53 
54  *nkeys = nelems;
55  *nullFlags = nulls;
56 
57  /* we should not free array, elems[i] points into it */
58  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
69 {
70  if (PG_NARGS() < 3) /* should not happen */
71  elog(ERROR, "ginarrayextract requires three arguments");
72  return ginarrayextract(fcinfo);
73 }
74 
75 /*
76  * extractQuery support function
77  */
78 Datum
80 {
81  /* Make copy of array input to ensure it doesn't disappear while in use */
83  int32 *nkeys = (int32 *) PG_GETARG_POINTER(1);
84  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  bool **nullFlags = (bool **) PG_GETARG_POINTER(5);
89  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 
98  &elmlen, &elmbyval, &elmalign);
99 
100  deconstruct_array(array,
101  ARR_ELEMTYPE(array),
102  elmlen, elmbyval, elmalign,
103  &elems, &nulls, &nelems);
104 
105  *nkeys = nelems;
106  *nullFlags = nulls;
107 
108  switch (strategy)
109  {
110  case GinOverlapStrategy:
111  *searchMode = GIN_SEARCH_MODE_DEFAULT;
112  break;
113  case GinContainsStrategy:
114  if (nelems > 0)
115  *searchMode = GIN_SEARCH_MODE_DEFAULT;
116  else /* everything contains the empty set */
117  *searchMode = GIN_SEARCH_MODE_ALL;
118  break;
120  /* empty set is contained in everything */
121  *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY;
122  break;
123  case GinEqualStrategy:
124  if (nelems > 0)
125  *searchMode = GIN_SEARCH_MODE_DEFAULT;
126  else
127  *searchMode = GIN_SEARCH_MODE_INCLUDE_EMPTY;
128  break;
129  default:
130  elog(ERROR, "ginqueryarrayextract: unknown strategy number: %d",
131  strategy);
132  }
133 
134  /* we should not free array, elems[i] points into it */
135  PG_RETURN_POINTER(elems);
136 }
137 
138 /*
139  * consistent support function
140  */
141 Datum
143 {
144  bool *check = (bool *) PG_GETARG_POINTER(0);
145  StrategyNumber strategy = PG_GETARG_UINT16(1);
146 
147  /* ArrayType *query = PG_GETARG_ARRAYTYPE_P(2); */
148  int32 nkeys = PG_GETARG_INT32(3);
149 
150  /* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
151  bool *recheck = (bool *) PG_GETARG_POINTER(5);
152 
153  /* Datum *queryKeys = (Datum *) PG_GETARG_POINTER(6); */
154  bool *nullFlags = (bool *) PG_GETARG_POINTER(7);
155  bool res;
156  int32 i;
157 
158  switch (strategy)
159  {
160  case GinOverlapStrategy:
161  /* result is not lossy */
162  *recheck = false;
163  /* must have a match for at least one non-null element */
164  res = false;
165  for (i = 0; i < nkeys; i++)
166  {
167  if (check[i] && !nullFlags[i])
168  {
169  res = true;
170  break;
171  }
172  }
173  break;
174  case GinContainsStrategy:
175  /* result is not lossy */
176  *recheck = false;
177  /* must have all elements in check[] true, and no nulls */
178  res = true;
179  for (i = 0; i < nkeys; i++)
180  {
181  if (!check[i] || nullFlags[i])
182  {
183  res = false;
184  break;
185  }
186  }
187  break;
189  /* we will need recheck */
190  *recheck = true;
191  /* can't do anything else useful here */
192  res = true;
193  break;
194  case GinEqualStrategy:
195  /* we will need recheck */
196  *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  res = true;
204  for (i = 0; i < nkeys; i++)
205  {
206  if (!check[i])
207  {
208  res = false;
209  break;
210  }
211  }
212  break;
213  default:
214  elog(ERROR, "ginarrayconsistent: unknown strategy number: %d",
215  strategy);
216  res = false;
217  }
218 
220 }
221 
222 /*
223  * triconsistent support function
224  */
225 Datum
227 {
229  StrategyNumber strategy = PG_GETARG_UINT16(1);
230 
231  /* ArrayType *query = PG_GETARG_ARRAYTYPE_P(2); */
232  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  bool *nullFlags = (bool *) PG_GETARG_POINTER(6);
238  int32 i;
239 
240  switch (strategy)
241  {
242  case GinOverlapStrategy:
243  /* must have a match for at least one non-null element */
244  res = GIN_FALSE;
245  for (i = 0; i < nkeys; i++)
246  {
247  if (!nullFlags[i])
248  {
249  if (check[i] == GIN_TRUE)
250  {
251  res = GIN_TRUE;
252  break;
253  }
254  else if (check[i] == GIN_MAYBE && res == GIN_FALSE)
255  {
256  res = GIN_MAYBE;
257  }
258  }
259  }
260  break;
261  case GinContainsStrategy:
262  /* must have all elements in check[] true, and no nulls */
263  res = GIN_TRUE;
264  for (i = 0; i < nkeys; i++)
265  {
266  if (check[i] == GIN_FALSE || nullFlags[i])
267  {
268  res = GIN_FALSE;
269  break;
270  }
271  if (check[i] == GIN_MAYBE)
272  {
273  res = GIN_MAYBE;
274  }
275  }
276  break;
278  /* can't do anything else useful here */
279  res = GIN_MAYBE;
280  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  res = GIN_MAYBE;
289  for (i = 0; i < nkeys; i++)
290  {
291  if (check[i] == GIN_FALSE)
292  {
293  res = GIN_FALSE;
294  break;
295  }
296  }
297  break;
298  default:
299  elog(ERROR, "ginarrayconsistent: unknown strategy number: %d",
300  strategy);
301  res = false;
302  }
303 
305 }
#define PG_GETARG_ARRAYTYPE_P_COPY(n)
Definition: array.h:264
#define ARR_ELEMTYPE(a)
Definition: array.h:292
void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3612
signed short int16
Definition: c.h:493
signed int int32
Definition: c.h:494
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
#define PG_NARGS()
Definition: fmgr.h:203
#define PG_GETARG_UINT16(n)
Definition: fmgr.h:272
#define PG_GETARG_INT32(n)
Definition: fmgr.h:269
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
#define PG_RETURN_GIN_TERNARY_VALUE(x)
Definition: gin.h:79
#define GIN_SEARCH_MODE_ALL
Definition: gin.h:36
#define GIN_FALSE
Definition: gin.h:63
#define GIN_SEARCH_MODE_DEFAULT
Definition: gin.h:34
char GinTernaryValue
Definition: gin.h:58
#define GIN_SEARCH_MODE_INCLUDE_EMPTY
Definition: gin.h:35
#define GIN_MAYBE
Definition: gin.h:65
#define GIN_TRUE
Definition: gin.h:64
Datum ginarraytriconsistent(PG_FUNCTION_ARGS)
Definition: ginarrayproc.c:226
Datum ginarrayextract_2args(PG_FUNCTION_ARGS)
Definition: ginarrayproc.c:68
#define GinEqualStrategy
Definition: ginarrayproc.c:26
Datum ginarrayextract(PG_FUNCTION_ARGS)
Definition: ginarrayproc.c:33
Datum ginarrayconsistent(PG_FUNCTION_ARGS)
Definition: ginarrayproc.c:142
#define GinOverlapStrategy
Definition: ginarrayproc.c:23
#define GinContainedStrategy
Definition: ginarrayproc.c:25
#define GinContainsStrategy
Definition: ginarrayproc.c:24
Datum ginqueryarrayextract(PG_FUNCTION_ARGS)
Definition: ginarrayproc.c:79
int i
Definition: isn.c:73
void get_typlenbyvalalign(Oid typid, int16 *typlen, bool *typbyval, char *typalign)
Definition: lsyscache.c:2271
uintptr_t Datum
Definition: postgres.h:64
uint16 StrategyNumber
Definition: stratnum.h:22