PostgreSQL Source Code  git master
ginlogic.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * ginlogic.c
4  * routines for performing binary- and ternary-logic consistent checks.
5  *
6  * A GIN operator class can provide a boolean or ternary consistent
7  * function, or both. This file provides both boolean and ternary
8  * interfaces to the rest of the GIN code, even if only one of them is
9  * implemented by the opclass.
10  *
11  * Providing a boolean interface when the opclass implements only the
12  * ternary function is straightforward - just call the ternary function
13  * with the check-array as is, and map the GIN_TRUE, GIN_FALSE, GIN_MAYBE
14  * return codes to TRUE, FALSE and TRUE+recheck, respectively. Providing
15  * a ternary interface when the opclass only implements a boolean function
16  * is implemented by calling the boolean function many times, with all the
17  * MAYBE arguments set to all combinations of TRUE and FALSE (up to a
18  * certain number of MAYBE arguments).
19  *
20  * (A boolean function is enough to determine if an item matches, but a
21  * GIN scan can apply various optimizations if it can determine that an
22  * item matches or doesn't match, even if it doesn't know if some of the
23  * keys are present or not. That's what the ternary consistent function
24  * is used for.)
25  *
26  *
27  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
28  * Portions Copyright (c) 1994, Regents of the University of California
29  *
30  * IDENTIFICATION
31  * src/backend/access/gin/ginlogic.c
32  *-------------------------------------------------------------------------
33  */
34 
35 #include "postgres.h"
36 
37 #include "access/gin_private.h"
38 
39 
40 /*
41  * Maximum number of MAYBE inputs that shimTriConsistentFn will try to
42  * resolve by calling all combinations.
43  */
44 #define MAX_MAYBE_ENTRIES 4
45 
46 /*
47  * Dummy consistent functions for an EVERYTHING key. Just claim it matches.
48  */
49 static bool
51 {
52  key->recheckCurItem = false;
53  return true;
54 }
55 static GinTernaryValue
57 {
58  return GIN_TRUE;
59 }
60 
61 /*
62  * A helper function for calling a regular, binary logic, consistent function.
63  */
64 static bool
66 {
67  /*
68  * Initialize recheckCurItem in case the consistentFn doesn't know it
69  * should set it. The safe assumption in that case is to force recheck.
70  */
71  key->recheckCurItem = true;
72 
73  return DatumGetBool(FunctionCall8Coll(key->consistentFmgrInfo,
74  key->collation,
75  PointerGetDatum(key->entryRes),
76  UInt16GetDatum(key->strategy),
77  key->query,
78  UInt32GetDatum(key->nuserentries),
79  PointerGetDatum(key->extra_data),
80  PointerGetDatum(&key->recheckCurItem),
81  PointerGetDatum(key->queryValues),
82  PointerGetDatum(key->queryCategories)));
83 }
84 
85 /*
86  * A helper function for calling a native ternary logic consistent function.
87  */
88 static GinTernaryValue
90 {
91  return DatumGetGinTernaryValue(FunctionCall7Coll(key->triConsistentFmgrInfo,
92  key->collation,
93  PointerGetDatum(key->entryRes),
94  UInt16GetDatum(key->strategy),
95  key->query,
96  UInt32GetDatum(key->nuserentries),
97  PointerGetDatum(key->extra_data),
98  PointerGetDatum(key->queryValues),
99  PointerGetDatum(key->queryCategories)));
100 }
101 
102 /*
103  * This function implements a binary logic consistency check, using a ternary
104  * logic consistent function provided by the opclass. GIN_MAYBE return value
105  * is interpreted as true with recheck flag.
106  */
107 static bool
109 {
110  GinTernaryValue result;
111 
112  result = DatumGetGinTernaryValue(FunctionCall7Coll(key->triConsistentFmgrInfo,
113  key->collation,
114  PointerGetDatum(key->entryRes),
115  UInt16GetDatum(key->strategy),
116  key->query,
117  UInt32GetDatum(key->nuserentries),
118  PointerGetDatum(key->extra_data),
119  PointerGetDatum(key->queryValues),
120  PointerGetDatum(key->queryCategories)));
121  if (result == GIN_MAYBE)
122  {
123  key->recheckCurItem = true;
124  return true;
125  }
126  else
127  {
128  key->recheckCurItem = false;
129  return result;
130  }
131 }
132 
133 /*
134  * This function implements a tri-state consistency check, using a boolean
135  * consistent function provided by the opclass.
136  *
137  * Our strategy is to call consistentFn with MAYBE inputs replaced with every
138  * combination of TRUE/FALSE. If consistentFn returns the same value for every
139  * combination, that's the overall result. Otherwise, return MAYBE. Testing
140  * every combination is O(n^2), so this is only feasible for a small number of
141  * MAYBE inputs.
142  *
143  * NB: This function modifies the key->entryRes array!
144  */
145 static GinTernaryValue
147 {
148  int nmaybe;
149  int maybeEntries[MAX_MAYBE_ENTRIES];
150  int i;
151  bool boolResult;
152  bool recheck = false;
153  GinTernaryValue curResult;
154 
155  /*
156  * Count how many MAYBE inputs there are, and store their indexes in
157  * maybeEntries. If there are too many MAYBE inputs, it's not feasible to
158  * test all combinations, so give up and return MAYBE.
159  */
160  nmaybe = 0;
161  for (i = 0; i < key->nentries; i++)
162  {
163  if (key->entryRes[i] == GIN_MAYBE)
164  {
165  if (nmaybe >= MAX_MAYBE_ENTRIES)
166  return GIN_MAYBE;
167  maybeEntries[nmaybe++] = i;
168  }
169  }
170 
171  /*
172  * If none of the inputs were MAYBE, so we can just call consistent
173  * function as is.
174  */
175  if (nmaybe == 0)
176  return directBoolConsistentFn(key);
177 
178  /* First call consistent function with all the maybe-inputs set FALSE */
179  for (i = 0; i < nmaybe; i++)
180  key->entryRes[maybeEntries[i]] = GIN_FALSE;
181  curResult = directBoolConsistentFn(key);
182 
183  for (;;)
184  {
185  /* Twiddle the entries for next combination. */
186  for (i = 0; i < nmaybe; i++)
187  {
188  if (key->entryRes[maybeEntries[i]] == GIN_FALSE)
189  {
190  key->entryRes[maybeEntries[i]] = GIN_TRUE;
191  break;
192  }
193  else
194  key->entryRes[maybeEntries[i]] = GIN_FALSE;
195  }
196  if (i == nmaybe)
197  break;
198 
199  boolResult = directBoolConsistentFn(key);
200  recheck |= key->recheckCurItem;
201 
202  if (curResult != boolResult)
203  return GIN_MAYBE;
204  }
205 
206  /* TRUE with recheck is taken to mean MAYBE */
207  if (curResult == GIN_TRUE && recheck)
208  curResult = GIN_MAYBE;
209 
210  return curResult;
211 }
212 
213 /*
214  * Set up the implementation of the consistent functions for a scan key.
215  */
216 void
218 {
219  if (key->searchMode == GIN_SEARCH_MODE_EVERYTHING)
220  {
221  key->boolConsistentFn = trueConsistentFn;
222  key->triConsistentFn = trueTriConsistentFn;
223  }
224  else
225  {
226  key->consistentFmgrInfo = &ginstate->consistentFn[key->attnum - 1];
227  key->triConsistentFmgrInfo = &ginstate->triConsistentFn[key->attnum - 1];
228  key->collation = ginstate->supportCollation[key->attnum - 1];
229 
230  if (OidIsValid(ginstate->consistentFn[key->attnum - 1].fn_oid))
231  key->boolConsistentFn = directBoolConsistentFn;
232  else
233  key->boolConsistentFn = shimBoolConsistentFn;
234 
235  if (OidIsValid(ginstate->triConsistentFn[key->attnum - 1].fn_oid))
236  key->triConsistentFn = directTriConsistentFn;
237  else
238  key->triConsistentFn = shimTriConsistentFn;
239  }
240 }
#define OidIsValid(objectId)
Definition: c.h:775
Datum FunctionCall8Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6, Datum arg7, Datum arg8)
Definition: fmgr.c:1318
Datum FunctionCall7Coll(FmgrInfo *flinfo, Oid collation, Datum arg1, Datum arg2, Datum arg3, Datum arg4, Datum arg5, Datum arg6, Datum arg7)
Definition: fmgr.c:1284
#define GIN_SEARCH_MODE_EVERYTHING
Definition: gin.h:37
#define GIN_FALSE
Definition: gin.h:63
static GinTernaryValue DatumGetGinTernaryValue(Datum X)
Definition: gin.h:68
char GinTernaryValue
Definition: gin.h:58
#define GIN_MAYBE
Definition: gin.h:65
#define GIN_TRUE
Definition: gin.h:64
static GinTernaryValue trueTriConsistentFn(GinScanKey key)
Definition: ginlogic.c:56
static GinTernaryValue shimTriConsistentFn(GinScanKey key)
Definition: ginlogic.c:146
static GinTernaryValue directTriConsistentFn(GinScanKey key)
Definition: ginlogic.c:89
static bool trueConsistentFn(GinScanKey key)
Definition: ginlogic.c:50
static bool directBoolConsistentFn(GinScanKey key)
Definition: ginlogic.c:65
void ginInitConsistentFunction(GinState *ginstate, GinScanKey key)
Definition: ginlogic.c:217
#define MAX_MAYBE_ENTRIES
Definition: ginlogic.c:44
static bool shimBoolConsistentFn(GinScanKey key)
Definition: ginlogic.c:108
int i
Definition: isn.c:73
static bool DatumGetBool(Datum X)
Definition: postgres.h:90
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
static Datum UInt16GetDatum(uint16 X)
Definition: postgres.h:192
static Datum UInt32GetDatum(uint32 X)
Definition: postgres.h:232
Oid fn_oid
Definition: fmgr.h:59
FmgrInfo triConsistentFn[INDEX_MAX_KEYS]
Definition: gin_private.h:83
FmgrInfo consistentFn[INDEX_MAX_KEYS]
Definition: gin_private.h:82
Oid supportCollation[INDEX_MAX_KEYS]
Definition: gin_private.h:88