1/*-------------------------------------------------------------------------
4 * routines to manage scans on GiST index relations
7 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/access/gist/gistscan.c
13 *-------------------------------------------------------------------------
27 * Pairing heap comparison function for the GISTSearchItem queue
37 /* Order according to distance comparison */
40 if (
sa->distances[
i].isnull)
59 /* Heap items go before inner pages, to ensure a depth-first search */
70 * Index AM API functions for scanning GiST indexes
83 /* First, set up a GISTSTATE with a scan-lifespan memory context */
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.
92 /* initialize opaque data */
99 /* workspaces with size dependent on numberOfOrderBys: */
101 so->
qual_ok =
true;
/* in case there are zero keys */
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.
128 ScanKey orderbys,
int norderbys)
130 /* nkeys and norderbys arguments are ignored */
136 /* rescan an existing indexscan --- reset state */
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.
150 /* first time through */
156 /* second time through */
158 "GiST queue context",
164 /* third or later time through */
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.
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
189 for (attno = 1; attno <= nkeyatts; attno++)
196 for (; attno <= natts; attno++)
198 /* taking opcintype from giststate->tupdesc */
201 attno - 1)->atttypid,
206 /* Also create a memory context that will hold the returned tuples */
208 "GiST page data context",
212 /* create new, empty pairing heap for search queue */
219 /* Update scan key, if a new one is given */
222 void **fn_extras = NULL;
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.
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
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).
256 * Copy consistent support function to ScanKey structure instead
257 * of function implementing filtering operator.
263 /* Restore prior fn_extra pointers, if not first time */
278 /* Update order-by key, if a new one is given */
281 void **fn_extras = NULL;
283 /* As above, preserve fn_extra if not first time through */
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
307 /* Check we actually have a distance function ... */
309 elog(
ERROR,
"missing support function %d for attribute %d of index \"%s\"",
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.
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
328 * Copy distance support function to ScanKey structure instead of
329 * function implementing ordering operator.
333 /* Restore prior fn_extra pointers, if not first time */
342 /* any previous xs_hitup will have been pfree'd in context resets above */
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.
#define InvalidBlockNumber
#define OidIsValid(objectId)
int float8_cmp_internal(float8 a, float8 b)
void fmgr_info_copy(FmgrInfo *dstinfo, FmgrInfo *srcinfo, MemoryContext destcxt)
IndexScanDesc RelationGetIndexScan(Relation indexRelation, int nkeys, int norderbys)
struct IndexScanDescData * IndexScanDesc
GISTSTATE * initGISTstate(Relation index)
MemoryContext createTempGistContext(void)
void freeGISTstate(GISTSTATE *giststate)
#define GIST_DISTANCE_PROC
GISTScanOpaqueData * GISTScanOpaque
#define GISTSearchItemIsHeap(item)
IndexScanDesc gistbeginscan(Relation r, int nkeys, int norderbys)
void gistendscan(IndexScanDesc scan)
void gistrescan(IndexScanDesc scan, ScanKey key, int nkeys, ScanKey orderbys, int norderbys)
static int pairingheap_GISTSearchItem_cmp(const pairingheap_node *a, const pairingheap_node *b, void *arg)
Assert(PointerIsAligned(start, uint64))
if(TABLE==NULL||TABLE_index==NULL)
Oid get_func_rettype(Oid funcid)
void MemoryContextReset(MemoryContext context)
void pfree(void *pointer)
void * palloc0(Size size)
#define AllocSetContextCreate
#define ALLOCSET_DEFAULT_SIZES
pairingheap * pairingheap_allocate(pairingheap_comparator compare, void *arg)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
static int cmp(const chr *x, const chr *y, size_t len)
#define RelationGetNumberOfAttributes(relation)
#define RelationGetRelationName(relation)
#define IndexRelationGetNumberOfKeyAttributes(relation)
FmgrInfo distanceFn[INDEX_MAX_KEYS]
FmgrInfo consistentFn[INDEX_MAX_KEYS]
OffsetNumber * killedItems
IndexOrderByDistance * distances
MemoryContext pageDataCxt
IndexOrderByDistance distances[FLEXIBLE_ARRAY_MEMBER]
struct ScanKeyData * keyData
struct ScanKeyData * orderByData
struct TupleDescData * xs_hitupdesc
TupleDesc CreateTemplateTupleDesc(int natts)
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
#define InvalidXLogRecPtr