PostgreSQL Source Code  git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
gistscan.c File Reference
#include "postgres.h"
#include "access/gist_private.h"
#include "access/gistscan.h"
#include "access/relscan.h"
#include "utils/float.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/rel.h"
Include dependency graph for gistscan.c:

Go to the source code of this file.

Functions

static int pairingheap_GISTSearchItem_cmp (const pairingheap_node *a, const pairingheap_node *b, void *arg)
 
IndexScanDesc gistbeginscan (Relation r, int nkeys, int norderbys)
 
void gistrescan (IndexScanDesc scan, ScanKey key, int nkeys, ScanKey orderbys, int norderbys)
 
void gistendscan (IndexScanDesc scan)
 

Function Documentation

◆ gistbeginscan()

IndexScanDesc gistbeginscan ( Relation  r,
int  nkeys,
int  norderbys 
)

Definition at line 74 of file gistscan.c.

75 {
76  IndexScanDesc scan;
77  GISTSTATE *giststate;
78  GISTScanOpaque so;
79  MemoryContext oldCxt;
80 
81  scan = RelationGetIndexScan(r, nkeys, norderbys);
82 
83  /* First, set up a GISTSTATE with a scan-lifespan memory context */
84  giststate = initGISTstate(scan->indexRelation);
85 
86  /*
87  * Everything made below is in the scanCxt, or is a child of the scanCxt,
88  * so it'll all go away automatically in gistendscan.
89  */
90  oldCxt = MemoryContextSwitchTo(giststate->scanCxt);
91 
92  /* initialize opaque data */
94  so->giststate = giststate;
95  giststate->tempCxt = createTempGistContext();
96  so->queue = NULL;
97  so->queueCxt = giststate->scanCxt; /* see gistrescan */
98 
99  /* workspaces with size dependent on numberOfOrderBys: */
100  so->distances = palloc(sizeof(so->distances[0]) * scan->numberOfOrderBys);
101  so->qual_ok = true; /* in case there are zero keys */
102  if (scan->numberOfOrderBys > 0)
103  {
104  scan->xs_orderbyvals = palloc0(sizeof(Datum) * scan->numberOfOrderBys);
105  scan->xs_orderbynulls = palloc(sizeof(bool) * scan->numberOfOrderBys);
106  memset(scan->xs_orderbynulls, true, sizeof(bool) * scan->numberOfOrderBys);
107  }
108 
109  so->killedItems = NULL; /* until needed */
110  so->numKilled = 0;
113 
114  scan->opaque = so;
115 
116  /*
117  * All fields required for index-only scans are initialized in gistrescan,
118  * as we don't know yet if we're doing an index-only scan or not.
119  */
120 
121  MemoryContextSwitchTo(oldCxt);
122 
123  return scan;
124 }
#define InvalidBlockNumber
Definition: block.h:33
IndexScanDesc RelationGetIndexScan(Relation indexRelation, int nkeys, int norderbys)
Definition: genam.c:80
GISTSTATE * initGISTstate(Relation index)
Definition: gist.c:1525
MemoryContext createTempGistContext(void)
Definition: gist.c:123
GISTScanOpaqueData * GISTScanOpaque
Definition: gist_private.h:181
void * palloc0(Size size)
Definition: mcxt.c:1347
void * palloc(Size size)
Definition: mcxt.c:1317
uintptr_t Datum
Definition: postgres.h:64
MemoryContextSwitchTo(old_ctx)
MemoryContext tempCxt
Definition: gist_private.h:78
MemoryContext scanCxt
Definition: gist_private.h:77
OffsetNumber * killedItems
Definition: gist_private.h:168
pairingheap * queue
Definition: gist_private.h:159
GISTSTATE * giststate
Definition: gist_private.h:156
MemoryContext queueCxt
Definition: gist_private.h:160
IndexOrderByDistance * distances
Definition: gist_private.h:165
BlockNumber curBlkno
Definition: gist_private.h:170
bool * xs_orderbynulls
Definition: relscan.h:185
int numberOfOrderBys
Definition: relscan.h:144
Relation indexRelation
Definition: relscan.h:141
Datum * xs_orderbyvals
Definition: relscan.h:184
#define InvalidXLogRecPtr
Definition: xlogdefs.h:28

References createTempGistContext(), GISTScanOpaqueData::curBlkno, GISTScanOpaqueData::curPageLSN, GISTScanOpaqueData::distances, GISTScanOpaqueData::giststate, IndexScanDescData::indexRelation, initGISTstate(), InvalidBlockNumber, InvalidXLogRecPtr, GISTScanOpaqueData::killedItems, MemoryContextSwitchTo(), IndexScanDescData::numberOfOrderBys, GISTScanOpaqueData::numKilled, IndexScanDescData::opaque, palloc(), palloc0(), GISTScanOpaqueData::qual_ok, GISTScanOpaqueData::queue, GISTScanOpaqueData::queueCxt, RelationGetIndexScan(), GISTSTATE::scanCxt, GISTSTATE::tempCxt, IndexScanDescData::xs_orderbynulls, and IndexScanDescData::xs_orderbyvals.

Referenced by gisthandler().

◆ gistendscan()

void gistendscan ( IndexScanDesc  scan)

Definition at line 347 of file gistscan.c.

348 {
349  GISTScanOpaque so = (GISTScanOpaque) scan->opaque;
350 
351  /*
352  * freeGISTstate is enough to clean up everything made by gistbeginscan,
353  * as well as the queueCxt if there is a separate context for it.
354  */
356 }
void freeGISTstate(GISTSTATE *giststate)
Definition: gist.c:1653

References freeGISTstate(), GISTScanOpaqueData::giststate, and IndexScanDescData::opaque.

Referenced by gisthandler().

◆ gistrescan()

void gistrescan ( IndexScanDesc  scan,
ScanKey  key,
int  nkeys,
ScanKey  orderbys,
int  norderbys 
)

Definition at line 127 of file gistscan.c.

129 {
130  /* nkeys and norderbys arguments are ignored */
131  GISTScanOpaque so = (GISTScanOpaque) scan->opaque;
132  bool first_time;
133  int i;
134  MemoryContext oldCxt;
135 
136  /* rescan an existing indexscan --- reset state */
137 
138  /*
139  * The first time through, we create the search queue in the scanCxt.
140  * Subsequent times through, we create the queue in a separate queueCxt,
141  * which is created on the second call and reset on later calls. Thus, in
142  * the common case where a scan is only rescan'd once, we just put the
143  * queue in scanCxt and don't pay the overhead of making a second memory
144  * context. If we do rescan more than once, the first queue is just left
145  * for dead until end of scan; this small wastage seems worth the savings
146  * in the common case.
147  */
148  if (so->queue == NULL)
149  {
150  /* first time through */
151  Assert(so->queueCxt == so->giststate->scanCxt);
152  first_time = true;
153  }
154  else if (so->queueCxt == so->giststate->scanCxt)
155  {
156  /* second time through */
158  "GiST queue context",
160  first_time = false;
161  }
162  else
163  {
164  /* third or later time through */
166  first_time = false;
167  }
168 
169  /*
170  * If we're doing an index-only scan, on the first call, also initialize a
171  * tuple descriptor to represent the returned index tuples and create a
172  * memory context to hold them during the scan.
173  */
174  if (scan->xs_want_itup && !scan->xs_hitupdesc)
175  {
176  int natts;
177  int nkeyatts;
178  int attno;
179 
180  /*
181  * The storage type of the index can be different from the original
182  * datatype being indexed, so we cannot just grab the index's tuple
183  * descriptor. Instead, construct a descriptor with the original data
184  * types.
185  */
189  for (attno = 1; attno <= nkeyatts; attno++)
190  {
191  TupleDescInitEntry(so->giststate->fetchTupdesc, attno, NULL,
192  scan->indexRelation->rd_opcintype[attno - 1],
193  -1, 0);
194  }
195 
196  for (; attno <= natts; attno++)
197  {
198  /* taking opcintype from giststate->tupdesc */
199  TupleDescInitEntry(so->giststate->fetchTupdesc, attno, NULL,
201  attno - 1)->atttypid,
202  -1, 0);
203  }
204  scan->xs_hitupdesc = so->giststate->fetchTupdesc;
205 
206  /* Also create a memory context that will hold the returned tuples */
208  "GiST page data context",
210  }
211 
212  /* create new, empty pairing heap for search queue */
213  oldCxt = MemoryContextSwitchTo(so->queueCxt);
215  MemoryContextSwitchTo(oldCxt);
216 
217  so->firstCall = true;
218 
219  /* Update scan key, if a new one is given */
220  if (key && scan->numberOfKeys > 0)
221  {
222  void **fn_extras = NULL;
223 
224  /*
225  * If this isn't the first time through, preserve the fn_extra
226  * pointers, so that if the consistentFns are using them to cache
227  * data, that data is not leaked across a rescan.
228  */
229  if (!first_time)
230  {
231  fn_extras = (void **) palloc(scan->numberOfKeys * sizeof(void *));
232  for (i = 0; i < scan->numberOfKeys; i++)
233  fn_extras[i] = scan->keyData[i].sk_func.fn_extra;
234  }
235 
236  memcpy(scan->keyData, key, scan->numberOfKeys * sizeof(ScanKeyData));
237 
238  /*
239  * Modify the scan key so that the Consistent method is called for all
240  * comparisons. The original operator is passed to the Consistent
241  * function in the form of its strategy number, which is available
242  * from the sk_strategy field, and its subtype from the sk_subtype
243  * field.
244  *
245  * Next, if any of keys is a NULL and that key is not marked with
246  * SK_SEARCHNULL/SK_SEARCHNOTNULL then nothing can be found (ie, we
247  * assume all indexable operators are strict).
248  */
249  so->qual_ok = true;
250 
251  for (i = 0; i < scan->numberOfKeys; i++)
252  {
253  ScanKey skey = scan->keyData + i;
254 
255  /*
256  * Copy consistent support function to ScanKey structure instead
257  * of function implementing filtering operator.
258  */
259  fmgr_info_copy(&(skey->sk_func),
260  &(so->giststate->consistentFn[skey->sk_attno - 1]),
261  so->giststate->scanCxt);
262 
263  /* Restore prior fn_extra pointers, if not first time */
264  if (!first_time)
265  skey->sk_func.fn_extra = fn_extras[i];
266 
267  if (skey->sk_flags & SK_ISNULL)
268  {
269  if (!(skey->sk_flags & (SK_SEARCHNULL | SK_SEARCHNOTNULL)))
270  so->qual_ok = false;
271  }
272  }
273 
274  if (!first_time)
275  pfree(fn_extras);
276  }
277 
278  /* Update order-by key, if a new one is given */
279  if (orderbys && scan->numberOfOrderBys > 0)
280  {
281  void **fn_extras = NULL;
282 
283  /* As above, preserve fn_extra if not first time through */
284  if (!first_time)
285  {
286  fn_extras = (void **) palloc(scan->numberOfOrderBys * sizeof(void *));
287  for (i = 0; i < scan->numberOfOrderBys; i++)
288  fn_extras[i] = scan->orderByData[i].sk_func.fn_extra;
289  }
290 
291  memcpy(scan->orderByData, orderbys, scan->numberOfOrderBys * sizeof(ScanKeyData));
292 
293  so->orderByTypes = (Oid *) palloc(scan->numberOfOrderBys * sizeof(Oid));
294 
295  /*
296  * Modify the order-by key so that the Distance method is called for
297  * all comparisons. The original operator is passed to the Distance
298  * function in the form of its strategy number, which is available
299  * from the sk_strategy field, and its subtype from the sk_subtype
300  * field.
301  */
302  for (i = 0; i < scan->numberOfOrderBys; i++)
303  {
304  ScanKey skey = scan->orderByData + i;
305  FmgrInfo *finfo = &(so->giststate->distanceFn[skey->sk_attno - 1]);
306 
307  /* Check we actually have a distance function ... */
308  if (!OidIsValid(finfo->fn_oid))
309  elog(ERROR, "missing support function %d for attribute %d of index \"%s\"",
312 
313  /*
314  * Look up the datatype returned by the original ordering
315  * operator. GiST always uses a float8 for the distance function,
316  * but the ordering operator could be anything else.
317  *
318  * XXX: The distance function is only allowed to be lossy if the
319  * ordering operator's result type is float4 or float8. Otherwise
320  * we don't know how to return the distance to the executor. But
321  * we cannot check that here, as we won't know if the distance
322  * function is lossy until it returns *recheck = true for the
323  * first time.
324  */
326 
327  /*
328  * Copy distance support function to ScanKey structure instead of
329  * function implementing ordering operator.
330  */
331  fmgr_info_copy(&(skey->sk_func), finfo, so->giststate->scanCxt);
332 
333  /* Restore prior fn_extra pointers, if not first time */
334  if (!first_time)
335  skey->sk_func.fn_extra = fn_extras[i];
336  }
337 
338  if (!first_time)
339  pfree(fn_extras);
340  }
341 
342  /* any previous xs_hitup will have been pfree'd in context resets above */
343  scan->xs_hitup = NULL;
344 }
#define Assert(condition)
Definition: c.h:837
#define OidIsValid(objectId)
Definition: c.h:754
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
void fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo, MemoryContext destcxt)
Definition: fmgr.c:580
#define GIST_DISTANCE_PROC
Definition: gist.h:38
static int pairingheap_GISTSearchItem_cmp(const pairingheap_node *a, const pairingheap_node *b, void *arg)
Definition: gistscan.c:30
int i
Definition: isn.c:72
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:76
Oid get_func_rettype(Oid funcid)
Definition: lsyscache.c:1655
void MemoryContextReset(MemoryContext context)
Definition: mcxt.c:383
void pfree(void *pointer)
Definition: mcxt.c:1521
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:160
pairingheap * pairingheap_allocate(pairingheap_comparator compare, void *arg)
Definition: pairingheap.c:42
unsigned int Oid
Definition: postgres_ext.h:31
#define RelationGetNumberOfAttributes(relation)
Definition: rel.h:511
#define RelationGetRelationName(relation)
Definition: rel.h:539
#define IndexRelationGetNumberOfKeyAttributes(relation)
Definition: rel.h:524
#define SK_SEARCHNOTNULL
Definition: skey.h:122
#define SK_SEARCHNULL
Definition: skey.h:121
#define SK_ISNULL
Definition: skey.h:115
Definition: fmgr.h:57
void * fn_extra
Definition: fmgr.h:64
Oid fn_oid
Definition: fmgr.h:59
TupleDesc leafTupdesc
Definition: gist_private.h:80
TupleDesc fetchTupdesc
Definition: gist_private.h:83
FmgrInfo distanceFn[INDEX_MAX_KEYS]
Definition: gist_private.h:93
FmgrInfo consistentFn[INDEX_MAX_KEYS]
Definition: gist_private.h:86
MemoryContext pageDataCxt
Definition: gist_private.h:177
struct ScanKeyData * keyData
Definition: relscan.h:145
struct ScanKeyData * orderByData
Definition: relscan.h:146
HeapTuple xs_hitup
Definition: relscan.h:167
struct TupleDescData * xs_hitupdesc
Definition: relscan.h:168
Oid * rd_opcintype
Definition: rel.h:208
int sk_flags
Definition: skey.h:66
FmgrInfo sk_func
Definition: skey.h:71
AttrNumber sk_attno
Definition: skey.h:67
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:67
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:651
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92

References ALLOCSET_DEFAULT_SIZES, AllocSetContextCreate, Assert, GISTSTATE::consistentFn, CreateTemplateTupleDesc(), GISTSTATE::distanceFn, elog, ERROR, GISTSTATE::fetchTupdesc, GISTScanOpaqueData::firstCall, fmgr_info_copy(), FmgrInfo::fn_extra, FmgrInfo::fn_oid, get_func_rettype(), GIST_DISTANCE_PROC, GISTScanOpaqueData::giststate, i, if(), IndexScanDescData::indexRelation, IndexRelationGetNumberOfKeyAttributes, sort-test::key, IndexScanDescData::keyData, GISTSTATE::leafTupdesc, MemoryContextReset(), MemoryContextSwitchTo(), IndexScanDescData::numberOfKeys, IndexScanDescData::numberOfOrderBys, OidIsValid, IndexScanDescData::opaque, IndexScanDescData::orderByData, GISTScanOpaqueData::orderByTypes, GISTScanOpaqueData::pageDataCxt, pairingheap_allocate(), pairingheap_GISTSearchItem_cmp(), palloc(), pfree(), GISTScanOpaqueData::qual_ok, GISTScanOpaqueData::queue, GISTScanOpaqueData::queueCxt, RelationData::rd_opcintype, RelationGetNumberOfAttributes, RelationGetRelationName, GISTSTATE::scanCxt, ScanKeyData::sk_attno, ScanKeyData::sk_flags, ScanKeyData::sk_func, SK_ISNULL, SK_SEARCHNOTNULL, SK_SEARCHNULL, TupleDescAttr, TupleDescInitEntry(), IndexScanDescData::xs_hitup, IndexScanDescData::xs_hitupdesc, and IndexScanDescData::xs_want_itup.

Referenced by gisthandler().

◆ pairingheap_GISTSearchItem_cmp()

static int pairingheap_GISTSearchItem_cmp ( const pairingheap_node a,
const pairingheap_node b,
void *  arg 
)
static

Definition at line 30 of file gistscan.c.

31 {
32  const GISTSearchItem *sa = (const GISTSearchItem *) a;
33  const GISTSearchItem *sb = (const GISTSearchItem *) b;
35  int i;
36 
37  /* Order according to distance comparison */
38  for (i = 0; i < scan->numberOfOrderBys; i++)
39  {
40  if (sa->distances[i].isnull)
41  {
42  if (!sb->distances[i].isnull)
43  return -1;
44  }
45  else if (sb->distances[i].isnull)
46  {
47  return 1;
48  }
49  else
50  {
51  int cmp = -float8_cmp_internal(sa->distances[i].value,
52  sb->distances[i].value);
53 
54  if (cmp != 0)
55  return cmp;
56  }
57  }
58 
59  /* Heap items go before inner pages, to ensure a depth-first search */
61  return 1;
63  return -1;
64 
65  return 0;
66 }
int float8_cmp_internal(float8 a, float8 b)
Definition: float.c:910
struct IndexScanDescData * IndexScanDesc
Definition: genam.h:90
#define GISTSearchItemIsHeap(item)
Definition: gist_private.h:145
int b
Definition: isn.c:69
int a
Definition: isn.c:68
void * arg
static int cmp(const chr *x, const chr *y, size_t len)
Definition: regc_locale.c:743
IndexOrderByDistance distances[FLEXIBLE_ARRAY_MEMBER]
Definition: gist_private.h:142

References a, arg, b, cmp(), GISTSearchItem::distances, float8_cmp_internal(), GISTSearchItemIsHeap, i, IndexOrderByDistance::isnull, IndexScanDescData::numberOfOrderBys, and IndexOrderByDistance::value.

Referenced by gistrescan().