PostgreSQL Source Code  git master
ginscan.c File Reference
#include "postgres.h"
#include "access/gin_private.h"
#include "access/relscan.h"
#include "pgstat.h"
#include "utils/memutils.h"
#include "utils/rel.h"
Include dependency graph for ginscan.c:

Go to the source code of this file.

Functions

IndexScanDesc ginbeginscan (Relation rel, int nkeys, int norderbys)
 
static GinScanEntry ginFillScanEntry (GinScanOpaque so, OffsetNumber attnum, StrategyNumber strategy, int32 searchMode, Datum queryKey, GinNullCategory queryCategory, bool isPartialMatch, Pointer extra_data)
 
static void ginScanKeyAddHiddenEntry (GinScanOpaque so, GinScanKey key, GinNullCategory queryCategory)
 
static void ginFillScanKey (GinScanOpaque so, OffsetNumber attnum, StrategyNumber strategy, int32 searchMode, Datum query, uint32 nQueryValues, Datum *queryValues, GinNullCategory *queryCategories, bool *partial_matches, Pointer *extra_data)
 
void ginFreeScanKeys (GinScanOpaque so)
 
void ginNewScanKey (IndexScanDesc scan)
 
void ginrescan (IndexScanDesc scan, ScanKey scankey, int nscankeys, ScanKey orderbys, int norderbys)
 
void ginendscan (IndexScanDesc scan)
 

Function Documentation

◆ ginbeginscan()

IndexScanDesc ginbeginscan ( Relation  rel,
int  nkeys,
int  norderbys 
)

Definition at line 25 of file ginscan.c.

26 {
27  IndexScanDesc scan;
28  GinScanOpaque so;
29 
30  /* no order by operators allowed */
31  Assert(norderbys == 0);
32 
33  scan = RelationGetIndexScan(rel, nkeys, norderbys);
34 
35  /* allocate private workspace */
36  so = (GinScanOpaque) palloc(sizeof(GinScanOpaqueData));
37  so->keys = NULL;
38  so->nkeys = 0;
40  "Gin scan temporary context",
43  "Gin scan key context",
45  initGinState(&so->ginstate, scan->indexRelation);
46 
47  scan->opaque = so;
48 
49  return scan;
50 }
IndexScanDesc RelationGetIndexScan(Relation indexRelation, int nkeys, int norderbys)
Definition: genam.c:78
GinScanOpaqueData * GinScanOpaque
Definition: gin_private.h:386
void initGinState(GinState *state, Relation index)
Definition: ginutil.c:97
Assert(fmt[strlen(fmt) - 1] !='\n')
MemoryContext CurrentMemoryContext
Definition: mcxt.c:131
void * palloc(Size size)
Definition: mcxt.c:1304
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:153
GinScanKey keys
Definition: gin_private.h:374
MemoryContext keyCtx
Definition: gin_private.h:381
MemoryContext tempCtx
Definition: gin_private.h:371
Relation indexRelation
Definition: relscan.h:118

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert(), CurrentMemoryContext, GinScanOpaqueData::ginstate, IndexScanDescData::indexRelation, initGinState(), GinScanOpaqueData::keyCtx, GinScanOpaqueData::keys, GinScanOpaqueData::nkeys, IndexScanDescData::opaque, palloc(), RelationGetIndexScan(), and GinScanOpaqueData::tempCtx.

Referenced by ginhandler().

◆ ginendscan()

void ginendscan ( IndexScanDesc  scan)

Definition at line 458 of file ginscan.c.

459 {
460  GinScanOpaque so = (GinScanOpaque) scan->opaque;
461 
462  ginFreeScanKeys(so);
463 
466 
467  pfree(so);
468 }
void ginFreeScanKeys(GinScanOpaque so)
Definition: ginscan.c:233
void pfree(void *pointer)
Definition: mcxt.c:1508
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:442

References ginFreeScanKeys(), GinScanOpaqueData::keyCtx, MemoryContextDelete(), IndexScanDescData::opaque, pfree(), and GinScanOpaqueData::tempCtx.

Referenced by ginhandler().

◆ ginFillScanEntry()

static GinScanEntry ginFillScanEntry ( GinScanOpaque  so,
OffsetNumber  attnum,
StrategyNumber  strategy,
int32  searchMode,
Datum  queryKey,
GinNullCategory  queryCategory,
bool  isPartialMatch,
Pointer  extra_data 
)
static

Definition at line 57 of file ginscan.c.

61 {
62  GinState *ginstate = &so->ginstate;
63  GinScanEntry scanEntry;
64  uint32 i;
65 
66  /*
67  * Look for an existing equivalent entry.
68  *
69  * Entries with non-null extra_data are never considered identical, since
70  * we can't know exactly what the opclass might be doing with that.
71  */
72  if (extra_data == NULL)
73  {
74  for (i = 0; i < so->totalentries; i++)
75  {
76  GinScanEntry prevEntry = so->entries[i];
77 
78  if (prevEntry->extra_data == NULL &&
79  prevEntry->isPartialMatch == isPartialMatch &&
80  prevEntry->strategy == strategy &&
81  prevEntry->searchMode == searchMode &&
82  prevEntry->attnum == attnum &&
83  ginCompareEntries(ginstate, attnum,
84  prevEntry->queryKey,
85  prevEntry->queryCategory,
86  queryKey,
87  queryCategory) == 0)
88  {
89  /* Successful match */
90  return prevEntry;
91  }
92  }
93  }
94 
95  /* Nope, create a new entry */
96  scanEntry = (GinScanEntry) palloc(sizeof(GinScanEntryData));
97  scanEntry->queryKey = queryKey;
98  scanEntry->queryCategory = queryCategory;
99  scanEntry->isPartialMatch = isPartialMatch;
100  scanEntry->extra_data = extra_data;
101  scanEntry->strategy = strategy;
102  scanEntry->searchMode = searchMode;
103  scanEntry->attnum = attnum;
104 
105  scanEntry->buffer = InvalidBuffer;
106  ItemPointerSetMin(&scanEntry->curItem);
107  scanEntry->matchBitmap = NULL;
108  scanEntry->matchIterator = NULL;
109  scanEntry->matchResult = NULL;
110  scanEntry->list = NULL;
111  scanEntry->nlist = 0;
112  scanEntry->offset = InvalidOffsetNumber;
113  scanEntry->isFinished = false;
114  scanEntry->reduceResult = false;
115 
116  /* Add it to so's array */
117  if (so->totalentries >= so->allocentries)
118  {
119  so->allocentries *= 2;
120  so->entries = (GinScanEntry *)
121  repalloc(so->entries, so->allocentries * sizeof(GinScanEntry));
122  }
123  so->entries[so->totalentries++] = scanEntry;
124 
125  return scanEntry;
126 }
#define InvalidBuffer
Definition: buf.h:25
unsigned int uint32
Definition: c.h:493
struct GinScanEntryData * GinScanEntry
Definition: gin_private.h:266
#define ItemPointerSetMin(p)
Definition: ginblock.h:166
int ginCompareEntries(GinState *ginstate, OffsetNumber attnum, Datum a, GinNullCategory categorya, Datum b, GinNullCategory categoryb)
Definition: ginutil.c:388
int i
Definition: isn.c:73
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1528
#define InvalidOffsetNumber
Definition: off.h:26
int16 attnum
Definition: pg_attribute.h:74
ItemPointerData curItem
Definition: gin_private.h:351
TBMIterateResult * matchResult
Definition: gin_private.h:356
TIDBitmap * matchBitmap
Definition: gin_private.h:354
ItemPointerData * list
Definition: gin_private.h:359
GinNullCategory queryCategory
Definition: gin_private.h:340
TBMIterator * matchIterator
Definition: gin_private.h:355
StrategyNumber strategy
Definition: gin_private.h:343
Pointer extra_data
Definition: gin_private.h:342
OffsetNumber offset
Definition: gin_private.h:361
OffsetNumber attnum
Definition: gin_private.h:345
GinScanEntry * entries
Definition: gin_private.h:377

References GinScanOpaqueData::allocentries, GinScanEntryData::attnum, attnum, GinScanEntryData::buffer, GinScanEntryData::curItem, GinScanOpaqueData::entries, GinScanEntryData::extra_data, ginCompareEntries(), GinScanOpaqueData::ginstate, i, InvalidBuffer, InvalidOffsetNumber, GinScanEntryData::isFinished, GinScanEntryData::isPartialMatch, ItemPointerSetMin, GinScanEntryData::list, GinScanEntryData::matchBitmap, GinScanEntryData::matchIterator, GinScanEntryData::matchResult, GinScanEntryData::nlist, GinScanEntryData::offset, palloc(), GinScanEntryData::queryCategory, GinScanEntryData::queryKey, GinScanEntryData::reduceResult, repalloc(), GinScanEntryData::searchMode, GinScanEntryData::strategy, and GinScanOpaqueData::totalentries.

Referenced by ginFillScanKey(), and ginScanKeyAddHiddenEntry().

◆ ginFillScanKey()

static void ginFillScanKey ( GinScanOpaque  so,
OffsetNumber  attnum,
StrategyNumber  strategy,
int32  searchMode,
Datum  query,
uint32  nQueryValues,
Datum queryValues,
GinNullCategory queryCategories,
bool partial_matches,
Pointer extra_data 
)
static

Definition at line 153 of file ginscan.c.

158 {
159  GinScanKey key = &(so->keys[so->nkeys++]);
160  GinState *ginstate = &so->ginstate;
161  uint32 i;
162 
163  key->nentries = nQueryValues;
164  key->nuserentries = nQueryValues;
165 
166  /* Allocate one extra array slot for possible "hidden" entry */
167  key->scanEntry = (GinScanEntry *) palloc(sizeof(GinScanEntry) *
168  (nQueryValues + 1));
169  key->entryRes = (GinTernaryValue *) palloc0(sizeof(GinTernaryValue) *
170  (nQueryValues + 1));
171 
172  key->query = query;
173  key->queryValues = queryValues;
174  key->queryCategories = queryCategories;
175  key->extra_data = extra_data;
176  key->strategy = strategy;
177  key->searchMode = searchMode;
178  key->attnum = attnum;
179 
180  /*
181  * Initially, scan keys of GIN_SEARCH_MODE_ALL mode are marked
182  * excludeOnly. This might get changed later.
183  */
184  key->excludeOnly = (searchMode == GIN_SEARCH_MODE_ALL);
185 
186  ItemPointerSetMin(&key->curItem);
187  key->curItemMatches = false;
188  key->recheckCurItem = false;
189  key->isFinished = false;
190  key->nrequired = 0;
191  key->nadditional = 0;
192  key->requiredEntries = NULL;
193  key->additionalEntries = NULL;
194 
195  ginInitConsistentFunction(ginstate, key);
196 
197  /* Set up normal scan entries using extractQueryFn's outputs */
198  for (i = 0; i < nQueryValues; i++)
199  {
200  Datum queryKey;
201  GinNullCategory queryCategory;
202  bool isPartialMatch;
203  Pointer this_extra;
204 
205  queryKey = queryValues[i];
206  queryCategory = queryCategories[i];
207  isPartialMatch =
208  (ginstate->canPartialMatch[attnum - 1] && partial_matches)
209  ? partial_matches[i] : false;
210  this_extra = (extra_data) ? extra_data[i] : NULL;
211 
212  key->scanEntry[i] = ginFillScanEntry(so, attnum,
213  strategy, searchMode,
214  queryKey, queryCategory,
215  isPartialMatch, this_extra);
216  }
217 
218  /*
219  * For GIN_SEARCH_MODE_INCLUDE_EMPTY and GIN_SEARCH_MODE_EVERYTHING search
220  * modes, we add the "hidden" entry immediately. GIN_SEARCH_MODE_ALL is
221  * handled later, since we might be able to omit the hidden entry for it.
222  */
223  if (searchMode == GIN_SEARCH_MODE_INCLUDE_EMPTY)
225  else if (searchMode == GIN_SEARCH_MODE_EVERYTHING)
227 }
char * Pointer
Definition: c.h:470
#define GIN_SEARCH_MODE_ALL
Definition: gin.h:36
#define GIN_SEARCH_MODE_EVERYTHING
Definition: gin.h:37
char GinTernaryValue
Definition: gin.h:58
#define GIN_SEARCH_MODE_INCLUDE_EMPTY
Definition: gin.h:35
#define GIN_CAT_EMPTY_ITEM
Definition: ginblock.h:210
signed char GinNullCategory
Definition: ginblock.h:206
#define GIN_CAT_EMPTY_QUERY
Definition: ginblock.h:212
void ginInitConsistentFunction(GinState *ginstate, GinScanKey key)
Definition: ginlogic.c:217
static void ginScanKeyAddHiddenEntry(GinScanOpaque so, GinScanKey key, GinNullCategory queryCategory)
Definition: ginscan.c:137
static GinScanEntry ginFillScanEntry(GinScanOpaque so, OffsetNumber attnum, StrategyNumber strategy, int32 searchMode, Datum queryKey, GinNullCategory queryCategory, bool isPartialMatch, Pointer extra_data)
Definition: ginscan.c:57
void * palloc0(Size size)
Definition: mcxt.c:1334
uintptr_t Datum
Definition: postgres.h:64
bool canPartialMatch[INDEX_MAX_KEYS]
Definition: gin_private.h:86

References attnum, GinState::canPartialMatch, GIN_CAT_EMPTY_ITEM, GIN_CAT_EMPTY_QUERY, GIN_SEARCH_MODE_ALL, GIN_SEARCH_MODE_EVERYTHING, GIN_SEARCH_MODE_INCLUDE_EMPTY, ginFillScanEntry(), ginInitConsistentFunction(), ginScanKeyAddHiddenEntry(), GinScanOpaqueData::ginstate, i, ItemPointerSetMin, sort-test::key, GinScanOpaqueData::keys, GinScanOpaqueData::nkeys, palloc(), and palloc0().

◆ ginFreeScanKeys()

void ginFreeScanKeys ( GinScanOpaque  so)

Definition at line 233 of file ginscan.c.

234 {
235  uint32 i;
236 
237  if (so->keys == NULL)
238  return;
239 
240  for (i = 0; i < so->totalentries; i++)
241  {
242  GinScanEntry entry = so->entries[i];
243 
244  if (entry->buffer != InvalidBuffer)
245  ReleaseBuffer(entry->buffer);
246  if (entry->list)
247  pfree(entry->list);
248  if (entry->matchIterator)
250  if (entry->matchBitmap)
251  tbm_free(entry->matchBitmap);
252  }
253 
255 
256  so->keys = NULL;
257  so->nkeys = 0;
258  so->entries = NULL;
259  so->totalentries = 0;
260 }
void ReleaseBuffer(Buffer buffer)
Definition: bufmgr.c:4560
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:371
void tbm_free(TIDBitmap *tbm)
Definition: tidbitmap.c:322
void tbm_end_iterate(TBMIterator *iterator)
Definition: tidbitmap.c:1146

References GinScanEntryData::buffer, GinScanOpaqueData::entries, i, InvalidBuffer, GinScanOpaqueData::keyCtx, GinScanOpaqueData::keys, GinScanEntryData::list, GinScanEntryData::matchBitmap, GinScanEntryData::matchIterator, MemoryContextReset(), GinScanOpaqueData::nkeys, pfree(), ReleaseBuffer(), tbm_end_iterate(), tbm_free(), and GinScanOpaqueData::totalentries.

Referenced by ginendscan(), gingetbitmap(), and ginrescan().

◆ ginNewScanKey()

void ginNewScanKey ( IndexScanDesc  scan)

Definition at line 263 of file ginscan.c.

264 {
265  ScanKey scankey = scan->keyData;
266  GinScanOpaque so = (GinScanOpaque) scan->opaque;
267  int i;
268  bool hasNullQuery = false;
269  bool attrHasNormalScan[INDEX_MAX_KEYS] = {false};
270  MemoryContext oldCtx;
271 
272  /*
273  * Allocate all the scan key information in the key context. (If
274  * extractQuery leaks anything there, it won't be reset until the end of
275  * scan or rescan, but that's OK.)
276  */
277  oldCtx = MemoryContextSwitchTo(so->keyCtx);
278 
279  /* if no scan keys provided, allocate extra EVERYTHING GinScanKey */
280  so->keys = (GinScanKey)
281  palloc(Max(scan->numberOfKeys, 1) * sizeof(GinScanKeyData));
282  so->nkeys = 0;
283 
284  /* initialize expansible array of GinScanEntry pointers */
285  so->totalentries = 0;
286  so->allocentries = 32;
287  so->entries = (GinScanEntry *)
288  palloc(so->allocentries * sizeof(GinScanEntry));
289 
290  so->isVoidRes = false;
291 
292  for (i = 0; i < scan->numberOfKeys; i++)
293  {
294  ScanKey skey = &scankey[i];
295  Datum *queryValues;
296  int32 nQueryValues = 0;
297  bool *partial_matches = NULL;
298  Pointer *extra_data = NULL;
299  bool *nullFlags = NULL;
300  GinNullCategory *categories;
301  int32 searchMode = GIN_SEARCH_MODE_DEFAULT;
302 
303  /*
304  * We assume that GIN-indexable operators are strict, so a null query
305  * argument means an unsatisfiable query.
306  */
307  if (skey->sk_flags & SK_ISNULL)
308  {
309  so->isVoidRes = true;
310  break;
311  }
312 
313  /* OK to call the extractQueryFn */
314  queryValues = (Datum *)
315  DatumGetPointer(FunctionCall7Coll(&so->ginstate.extractQueryFn[skey->sk_attno - 1],
316  so->ginstate.supportCollation[skey->sk_attno - 1],
317  skey->sk_argument,
318  PointerGetDatum(&nQueryValues),
320  PointerGetDatum(&partial_matches),
321  PointerGetDatum(&extra_data),
322  PointerGetDatum(&nullFlags),
323  PointerGetDatum(&searchMode)));
324 
325  /*
326  * If bogus searchMode is returned, treat as GIN_SEARCH_MODE_ALL; note
327  * in particular we don't allow extractQueryFn to select
328  * GIN_SEARCH_MODE_EVERYTHING.
329  */
330  if (searchMode < GIN_SEARCH_MODE_DEFAULT ||
331  searchMode > GIN_SEARCH_MODE_ALL)
332  searchMode = GIN_SEARCH_MODE_ALL;
333 
334  /* Non-default modes require the index to have placeholders */
335  if (searchMode != GIN_SEARCH_MODE_DEFAULT)
336  hasNullQuery = true;
337 
338  /*
339  * In default mode, no keys means an unsatisfiable query.
340  */
341  if (queryValues == NULL || nQueryValues <= 0)
342  {
343  if (searchMode == GIN_SEARCH_MODE_DEFAULT)
344  {
345  so->isVoidRes = true;
346  break;
347  }
348  nQueryValues = 0; /* ensure sane value */
349  }
350 
351  /*
352  * Create GinNullCategory representation. If the extractQueryFn
353  * didn't create a nullFlags array, we assume everything is non-null.
354  * While at it, detect whether any null keys are present.
355  */
356  categories = (GinNullCategory *) palloc0(nQueryValues * sizeof(GinNullCategory));
357  if (nullFlags)
358  {
359  int32 j;
360 
361  for (j = 0; j < nQueryValues; j++)
362  {
363  if (nullFlags[j])
364  {
365  categories[j] = GIN_CAT_NULL_KEY;
366  hasNullQuery = true;
367  }
368  }
369  }
370 
371  ginFillScanKey(so, skey->sk_attno,
372  skey->sk_strategy, searchMode,
373  skey->sk_argument, nQueryValues,
374  queryValues, categories,
375  partial_matches, extra_data);
376 
377  /* Remember if we had any non-excludeOnly keys */
378  if (searchMode != GIN_SEARCH_MODE_ALL)
379  attrHasNormalScan[skey->sk_attno - 1] = true;
380  }
381 
382  /*
383  * Processing GIN_SEARCH_MODE_ALL scan keys requires us to make a second
384  * pass over the scan keys. Above we marked each such scan key as
385  * excludeOnly. If the involved column has any normal (not excludeOnly)
386  * scan key as well, then we can leave it like that. Otherwise, one
387  * excludeOnly scan key must receive a GIN_CAT_EMPTY_QUERY hidden entry
388  * and be set to normal (excludeOnly = false).
389  */
390  for (i = 0; i < so->nkeys; i++)
391  {
392  GinScanKey key = &so->keys[i];
393 
394  if (key->searchMode != GIN_SEARCH_MODE_ALL)
395  continue;
396 
397  if (!attrHasNormalScan[key->attnum - 1])
398  {
399  key->excludeOnly = false;
401  attrHasNormalScan[key->attnum - 1] = true;
402  }
403  }
404 
405  /*
406  * If there are no regular scan keys, generate an EVERYTHING scankey to
407  * drive a full-index scan.
408  */
409  if (so->nkeys == 0 && !so->isVoidRes)
410  {
411  hasNullQuery = true;
414  (Datum) 0, 0,
415  NULL, NULL, NULL, NULL);
416  }
417 
418  /*
419  * If the index is version 0, it may be missing null and placeholder
420  * entries, which would render searches for nulls and full-index scans
421  * unreliable. Throw an error if so.
422  */
423  if (hasNullQuery && !so->isVoidRes)
424  {
425  GinStatsData ginStats;
426 
427  ginGetStats(scan->indexRelation, &ginStats);
428  if (ginStats.ginVersion < 1)
429  ereport(ERROR,
430  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
431  errmsg("old GIN indexes do not support whole-index scans nor searches for nulls"),
432  errhint("To fix this, do REINDEX INDEX \"%s\".",
434  }
435 
436  MemoryContextSwitchTo(oldCtx);
437 
439 }
signed int int32
Definition: c.h:481
#define Max(x, y)
Definition: c.h:985
int errhint(const char *fmt,...)
Definition: elog.c:1319
int errcode(int sqlerrcode)
Definition: elog.c:859
int errmsg(const char *fmt,...)
Definition: elog.c:1072
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
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_DEFAULT
Definition: gin.h:34
struct GinScanKeyData GinScanKeyData
struct GinScanKeyData * GinScanKey
Definition: gin_private.h:264
#define GIN_CAT_NULL_KEY
Definition: ginblock.h:209
static void ginFillScanKey(GinScanOpaque so, OffsetNumber attnum, StrategyNumber strategy, int32 searchMode, Datum query, uint32 nQueryValues, Datum *queryValues, GinNullCategory *queryCategories, bool *partial_matches, Pointer *extra_data)
Definition: ginscan.c:153
void ginGetStats(Relation index, GinStatsData *stats)
Definition: ginutil.c:623
int j
Definition: isn.c:74
#define FirstOffsetNumber
Definition: off.h:27
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
#define INDEX_MAX_KEYS
#define pgstat_count_index_scan(rel)
Definition: pgstat.h:625
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
static Datum UInt16GetDatum(uint16 X)
Definition: postgres.h:192
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
#define RelationGetRelationName(relation)
Definition: rel.h:539
#define SK_ISNULL
Definition: skey.h:115
#define InvalidStrategy
Definition: stratnum.h:24
int32 ginVersion
Definition: gin.h:49
struct ScanKeyData * keyData
Definition: relscan.h:122
int sk_flags
Definition: skey.h:66
Datum sk_argument
Definition: skey.h:72
StrategyNumber sk_strategy
Definition: skey.h:68
AttrNumber sk_attno
Definition: skey.h:67

References i, INDEX_MAX_KEYS, IndexScanDescData::keyData, and IndexScanDescData::opaque.

Referenced by gingetbitmap().

◆ ginrescan()

void ginrescan ( IndexScanDesc  scan,
ScanKey  scankey,
int  nscankeys,
ScanKey  orderbys,
int  norderbys 
)

Definition at line 442 of file ginscan.c.

444 {
445  GinScanOpaque so = (GinScanOpaque) scan->opaque;
446 
447  ginFreeScanKeys(so);
448 
449  if (scankey && scan->numberOfKeys > 0)
450  {
451  memmove(scan->keyData, scankey,
452  scan->numberOfKeys * sizeof(ScanKeyData));
453  }
454 }

References ginFreeScanKeys(), IndexScanDescData::keyData, IndexScanDescData::numberOfKeys, and IndexScanDescData::opaque.

Referenced by ginhandler().

◆ ginScanKeyAddHiddenEntry()

static void ginScanKeyAddHiddenEntry ( GinScanOpaque  so,
GinScanKey  key,
GinNullCategory  queryCategory 
)
static

Definition at line 137 of file ginscan.c.

139 {
140  int i = key->nentries++;
141 
142  /* strategy is of no interest because this is not a partial-match item */
143  key->scanEntry[i] = ginFillScanEntry(so, key->attnum,
144  InvalidStrategy, key->searchMode,
145  (Datum) 0, queryCategory,
146  false, NULL);
147 }

References ginFillScanEntry(), i, InvalidStrategy, and sort-test::key.

Referenced by ginFillScanKey().