Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitd6a90aa

Browse files
committed
Improve handling of NULLs in KNN-GiST and KNN-SP-GiST
This commit improves subject in two ways: * It removes ugliness of02f9087, which stores distance values and null flags in two separate arrays after GISTSearchItem struct. Instead we pack both distance value and null flag in IndexOrderByDistance struct. Alignment overhead should be negligible, because we typically deal with at most few "col op const" expressions in ORDER BY clause. * It fixes handling of "col op NULL" expression in KNN-SP-GiST. Now, these expression are not passed to support functions, which can't deal with them. Instead, NULL result is implicitly assumed. It future we may decide to teach support functions to deal with NULL arguments, but current solution is bugfix suitable for backpatch.Reported-by: Nikita GlukhovDiscussion:https://postgr.es/m/826f57ee-afc7-8977-c44c-6111d18b02ec%40postgrespro.ruAuthor: Nikita GlukhovReviewed-by: Alexander KorotkovBackpatch-through: 9.4
1 parent3153328 commitd6a90aa

File tree

5 files changed

+47
-79
lines changed

5 files changed

+47
-79
lines changed

‎src/backend/access/gist/gistget.c

Lines changed: 27 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,8 @@ gistkillitems(IndexScanDesc scan)
112112
* Similarly, *recheck_distances_p is set to indicate whether the distances
113113
* need to be rechecked, and it is also ignored for non-leaf entries.
114114
*
115-
* If we are doing an ordered scan, so->distancesValues[] and
116-
* so->distancesNulls[] is filled with distance data from the distance()
117-
* functions before returning success.
115+
* If we are doing an ordered scan, so->distances[] is filled with distance
116+
* data from the distance() functions before returning success.
118117
*
119118
* We must decompress the key in the IndexTuple before passing it to the
120119
* sk_funcs (which actually are the opclass Consistent or Distance methods).
@@ -135,8 +134,7 @@ gistindex_keytest(IndexScanDesc scan,
135134
GISTSTATE*giststate=so->giststate;
136135
ScanKeykey=scan->keyData;
137136
intkeySize=scan->numberOfKeys;
138-
double*distance_value_p;
139-
bool*distance_null_p;
137+
IndexOrderByDistance*distance_p;
140138
Relationr=scan->indexRelation;
141139

142140
*recheck_p= false;
@@ -155,8 +153,8 @@ gistindex_keytest(IndexScanDesc scan,
155153
elog(ERROR,"invalid GiST tuple found on leaf page");
156154
for (i=0;i<scan->numberOfOrderBys;i++)
157155
{
158-
so->distanceValues[i]=-get_float8_infinity();
159-
so->distanceNulls[i]= false;
156+
so->distances[i].value=-get_float8_infinity();
157+
so->distances[i].isnull= false;
160158
}
161159
return true;
162160
}
@@ -240,8 +238,7 @@ gistindex_keytest(IndexScanDesc scan,
240238

241239
/* OK, it passes --- now let's compute the distances */
242240
key=scan->orderByData;
243-
distance_value_p=so->distanceValues;
244-
distance_null_p=so->distanceNulls;
241+
distance_p=so->distances;
245242
keySize=scan->numberOfOrderBys;
246243
while (keySize>0)
247244
{
@@ -256,8 +253,8 @@ gistindex_keytest(IndexScanDesc scan,
256253
if ((key->sk_flags&SK_ISNULL)||isNull)
257254
{
258255
/* Assume distance computes as null */
259-
*distance_value_p=0.0;
260-
*distance_null_p= true;
256+
distance_p->value=0.0;
257+
distance_p->isnull= true;
261258
}
262259
else
263260
{
@@ -294,13 +291,12 @@ gistindex_keytest(IndexScanDesc scan,
294291
ObjectIdGetDatum(key->sk_subtype),
295292
PointerGetDatum(&recheck));
296293
*recheck_distances_p |=recheck;
297-
*distance_value_p=DatumGetFloat8(dist);
298-
*distance_null_p= false;
294+
distance_p->value=DatumGetFloat8(dist);
295+
distance_p->isnull= false;
299296
}
300297

301298
key++;
302-
distance_value_p++;
303-
distance_null_p++;
299+
distance_p++;
304300
keySize--;
305301
}
306302

@@ -313,8 +309,7 @@ gistindex_keytest(IndexScanDesc scan,
313309
*
314310
* scan: index scan we are executing
315311
* pageItem: search queue item identifying an index page to scan
316-
* myDistanceValues: distances array associated with pageItem, or NULL at the root
317-
* myDistanceNulls: null flags for myDistanceValues array, or NULL at the root
312+
* myDistances: distances array associated with pageItem, or NULL at the root
318313
* tbm: if not NULL, gistgetbitmap's output bitmap
319314
* ntids: if not NULL, gistgetbitmap's output tuple counter
320315
*
@@ -332,8 +327,7 @@ gistindex_keytest(IndexScanDesc scan,
332327
*/
333328
staticvoid
334329
gistScanPage(IndexScanDescscan,GISTSearchItem*pageItem,
335-
double*myDistanceValues,bool*myDistanceNulls,
336-
TIDBitmap*tbm,int64*ntids)
330+
IndexOrderByDistance*myDistances,TIDBitmap*tbm,int64*ntids)
337331
{
338332
GISTScanOpaqueso= (GISTScanOpaque)scan->opaque;
339333
GISTSTATE*giststate=so->giststate;
@@ -370,7 +364,7 @@ gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem,
370364
GISTSearchItem*item;
371365

372366
/* This can't happen when starting at the root */
373-
Assert(myDistanceValues!=NULL&&myDistanceNulls!=NULL);
367+
Assert(myDistances!=NULL);
374368

375369
oldcxt=MemoryContextSwitchTo(so->queueCxt);
376370

@@ -380,10 +374,8 @@ gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem,
380374
item->data.parentlsn=pageItem->data.parentlsn;
381375

382376
/* Insert it into the queue using same distances as for this page */
383-
memcpy(GISTSearchItemDistanceValues(item,scan->numberOfOrderBys),
384-
myDistanceValues,sizeof(double)*scan->numberOfOrderBys);
385-
memcpy(GISTSearchItemDistanceNulls(item,scan->numberOfOrderBys),
386-
myDistanceNulls,sizeof(bool)*scan->numberOfOrderBys);
377+
memcpy(item->distances,myDistances,
378+
sizeof(item->distances[0])*scan->numberOfOrderBys);
387379

388380
pairingheap_add(so->queue,&item->phNode);
389381

@@ -513,10 +505,8 @@ gistScanPage(IndexScanDesc scan, GISTSearchItem *pageItem,
513505
}
514506

515507
/* Insert it into the queue using new distance data */
516-
memcpy(GISTSearchItemDistanceValues(item,nOrderBys),
517-
so->distanceValues,sizeof(double)*nOrderBys);
518-
memcpy(GISTSearchItemDistanceNulls(item,nOrderBys),
519-
so->distanceNulls,sizeof(bool)*nOrderBys);
508+
memcpy(item->distances,so->distances,
509+
sizeof(item->distances[0])*nOrderBys);
520510

521511
pairingheap_add(so->queue,&item->phNode);
522512

@@ -571,8 +561,6 @@ getNextNearest(IndexScanDesc scan)
571561
do
572562
{
573563
GISTSearchItem*item=getNextGISTSearchItem(so);
574-
float8*distanceValues=GISTSearchItemDistanceValues(item,scan->numberOfOrderBys);
575-
bool*distanceNulls=GISTSearchItemDistanceNulls(item,scan->numberOfOrderBys);
576564

577565
if (!item)
578566
break;
@@ -592,8 +580,8 @@ getNextNearest(IndexScanDesc scan)
592580
if (!scan->xs_orderbynulls[i])
593581
pfree(DatumGetPointer(scan->xs_orderbyvals[i]));
594582
#endif
595-
scan->xs_orderbyvals[i]=Float8GetDatum(distanceValues[i]);
596-
scan->xs_orderbynulls[i]=distanceNulls[i];
583+
scan->xs_orderbyvals[i]=item->distances[i].value;
584+
scan->xs_orderbynulls[i]=item->distances[i].isnull;
597585
}
598586
elseif (so->orderByTypes[i]==FLOAT4OID)
599587
{
@@ -603,8 +591,8 @@ getNextNearest(IndexScanDesc scan)
603591
if (!scan->xs_orderbynulls[i])
604592
pfree(DatumGetPointer(scan->xs_orderbyvals[i]));
605593
#endif
606-
scan->xs_orderbyvals[i]=Float4GetDatum(distanceValues[i]);
607-
scan->xs_orderbynulls[i]=distanceNulls[i];
594+
scan->xs_orderbyvals[i]=Float4GetDatum(item->distances[i].value);
595+
scan->xs_orderbynulls[i]=item->distances[i].isnull;
608596
}
609597
else
610598
{
@@ -632,10 +620,7 @@ getNextNearest(IndexScanDesc scan)
632620
/* visit an index page, extract its items into queue */
633621
CHECK_FOR_INTERRUPTS();
634622

635-
gistScanPage(scan,item,
636-
GISTSearchItemDistanceValues(item,scan->numberOfOrderBys),
637-
GISTSearchItemDistanceNulls(item,scan->numberOfOrderBys),
638-
NULL,NULL);
623+
gistScanPage(scan,item,item->distances,NULL,NULL);
639624
}
640625

641626
pfree(item);
@@ -673,7 +658,7 @@ gistgettuple(IndexScanDesc scan, ScanDirection dir)
673658

674659
fakeItem.blkno=GIST_ROOT_BLKNO;
675660
memset(&fakeItem.data.parentlsn,0,sizeof(GistNSN));
676-
gistScanPage(scan,&fakeItem,NULL,NULL,NULL,NULL);
661+
gistScanPage(scan,&fakeItem,NULL,NULL,NULL);
677662
}
678663

679664
if (scan->numberOfOrderBys>0)
@@ -767,10 +752,7 @@ gistgettuple(IndexScanDesc scan, ScanDirection dir)
767752
* this page, we fall out of the inner "do" and loop around to
768753
* return them.
769754
*/
770-
gistScanPage(scan,item,
771-
GISTSearchItemDistanceValues(item,scan->numberOfOrderBys),
772-
GISTSearchItemDistanceNulls(item,scan->numberOfOrderBys),
773-
NULL,NULL);
755+
gistScanPage(scan,item,item->distances,NULL,NULL);
774756

775757
pfree(item);
776758
}while (so->nPageData==0);
@@ -801,7 +783,7 @@ gistgetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
801783

802784
fakeItem.blkno=GIST_ROOT_BLKNO;
803785
memset(&fakeItem.data.parentlsn,0,sizeof(GistNSN));
804-
gistScanPage(scan,&fakeItem,NULL,NULL,tbm,&ntids);
786+
gistScanPage(scan,&fakeItem,NULL,tbm,&ntids);
805787

806788
/*
807789
* While scanning a leaf page, ItemPointers of matching heap tuples will
@@ -816,10 +798,7 @@ gistgetbitmap(IndexScanDesc scan, TIDBitmap *tbm)
816798

817799
CHECK_FOR_INTERRUPTS();
818800

819-
gistScanPage(scan,item,
820-
GISTSearchItemDistanceValues(item,scan->numberOfOrderBys),
821-
GISTSearchItemDistanceNulls(item,scan->numberOfOrderBys),
822-
tbm,&ntids);
801+
gistScanPage(scan,item,item->distances,tbm,&ntids);
823802

824803
pfree(item);
825804
}

‎src/backend/access/gist/gistscan.c

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,26 +33,23 @@ pairingheap_GISTSearchItem_cmp(const pairingheap_node *a, const pairingheap_node
3333
constGISTSearchItem*sb= (constGISTSearchItem*)b;
3434
IndexScanDescscan= (IndexScanDesc)arg;
3535
inti;
36-
double*da=GISTSearchItemDistanceValues(sa,scan->numberOfOrderBys),
37-
*db=GISTSearchItemDistanceValues(sb,scan->numberOfOrderBys);
38-
bool*na=GISTSearchItemDistanceNulls(sa,scan->numberOfOrderBys),
39-
*nb=GISTSearchItemDistanceNulls(sb,scan->numberOfOrderBys);
4036

4137
/* Order according to distance comparison */
4238
for (i=0;i<scan->numberOfOrderBys;i++)
4339
{
44-
if (na[i])
40+
if (sa->distances[i].isnull)
4541
{
46-
if (!nb[i])
42+
if (!sb->distances[i].isnull)
4743
return-1;
4844
}
49-
elseif (nb[i])
45+
elseif (sb->distances[i].isnull)
5046
{
5147
return1;
5248
}
5349
else
5450
{
55-
intcmp=-float8_cmp_internal(da[i],db[i]);
51+
intcmp=-float8_cmp_internal(sa->distances[i].value,
52+
sb->distances[i].value);
5653

5754
if (cmp!=0)
5855
returncmp;
@@ -100,8 +97,7 @@ gistbeginscan(Relation r, int nkeys, int norderbys)
10097
so->queueCxt=giststate->scanCxt;/* see gistrescan */
10198

10299
/* workspaces with size dependent on numberOfOrderBys: */
103-
so->distanceValues=palloc(sizeof(double)*scan->numberOfOrderBys);
104-
so->distanceNulls=palloc(sizeof(bool)*scan->numberOfOrderBys);
100+
so->distances=palloc(sizeof(so->distances[0])*scan->numberOfOrderBys);
105101
so->qual_ok= true;/* in case there are zero keys */
106102
if (scan->numberOfOrderBys>0)
107103
{

‎src/include/access/genam.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,13 @@ typedef enum IndexUniqueCheck
117117
}IndexUniqueCheck;
118118

119119

120+
/* Nullable "ORDER BY col op const" distance */
121+
typedefstructIndexOrderByDistance
122+
{
123+
doublevalue;
124+
boolisnull;
125+
}IndexOrderByDistance;
126+
120127
/*
121128
* generalized index_ interface routines (in indexam.c)
122129
*/

‎src/include/access/gist_private.h

Lines changed: 6 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -137,29 +137,15 @@ typedef struct GISTSearchItem
137137
GISTSearchHeapItemheap;/* heap info, if heap tuple */
138138
}data;
139139

140-
/*
141-
* This data structure is followed by arrays of distance values and
142-
* distance null flags. Size of both arrays is
143-
* IndexScanDesc->numberOfOrderBys. See macros below for accessing those
144-
* arrays.
145-
*/
140+
/* numberOfOrderBys entries */
141+
IndexOrderByDistancedistances[FLEXIBLE_ARRAY_MEMBER];
146142
}GISTSearchItem;
147143

148144
#defineGISTSearchItemIsHeap(item)((item).blkno == InvalidBlockNumber)
149145

150-
#defineSizeOfGISTSearchItem(n_distances) (DOUBLEALIGN(sizeof(GISTSearchItem)) + \
151-
(sizeof(double) + sizeof(bool)) * (n_distances))
152-
153-
/*
154-
* We actually don't need n_distances compute pointer to distance values.
155-
* Nevertheless take n_distances as argument to have same arguments list for
156-
* GISTSearchItemDistanceValues() and GISTSearchItemDistanceNulls().
157-
*/
158-
#defineGISTSearchItemDistanceValues(item,n_distances) \
159-
((double *) ((Pointer) (item) + DOUBLEALIGN(sizeof(GISTSearchItem))))
160-
161-
#defineGISTSearchItemDistanceNulls(item,n_distances) \
162-
((bool *) ((Pointer) (item) + DOUBLEALIGN(sizeof(GISTSearchItem)) + sizeof(double) * (n_distances)))
146+
#defineSizeOfGISTSearchItem(n_distances) \
147+
(offsetof(GISTSearchItem, distances) + \
148+
sizeof(IndexOrderByDistance) * (n_distances))
163149

164150
/*
165151
* GISTScanOpaqueData: private state for a scan of a GiST index
@@ -175,8 +161,7 @@ typedef struct GISTScanOpaqueData
175161
boolfirstCall;/* true until first gistgettuple call */
176162

177163
/* pre-allocated workspace arrays */
178-
double*distanceValues;/* output area for gistindex_keytest */
179-
bool*distanceNulls;
164+
IndexOrderByDistance*distances;/* output area for gistindex_keytest */
180165

181166
/* info about killed items if any (killedItems is NULL if never used) */
182167
OffsetNumber*killedItems;/* offset numbers of killed items */

‎src/tools/pgindent/typedefs.list

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,6 +1022,7 @@ IndexList
10221022
IndexOnlyScan
10231023
IndexOnlyScanState
10241024
IndexOptInfo
1025+
IndexOrderByDistance
10251026
IndexPath
10261027
IndexQualInfo
10271028
IndexRuntimeKeyInfo

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp