8
8
* Portions Copyright (c) 1994, Regents of the University of California
9
9
*
10
10
* IDENTIFICATION
11
- * $PostgreSQL: pgsql/src/backend/access/gin/ginget.c,v 1.24 2009/03/25 22:19 :01 tgl Exp $
11
+ * $PostgreSQL: pgsql/src/backend/access/gin/ginget.c,v 1.25 2009/04/05 11:32 :01 teodor Exp $
12
12
*-------------------------------------------------------------------------
13
13
*/
14
14
@@ -618,6 +618,7 @@ entryGetItem(Relation index, GinScanEntry entry)
618
618
* Sets key->curItem to new found heap item pointer for one scan key
619
619
* Returns isFinished, ie TRUE means we did NOT get a new item pointer!
620
620
* Also, *keyrecheck is set true if recheck is needed for this scan key.
621
+ * Note: lossy page could be returned after items from the same page.
621
622
*/
622
623
static bool
623
624
keyGetItem (Relation index , GinState * ginstate , MemoryContext tempCtx ,
@@ -635,7 +636,10 @@ keyGetItem(Relation index, GinState *ginstate, MemoryContext tempCtx,
635
636
{
636
637
/*
637
638
* move forward from previously value and set new curItem, which is
638
- * minimal from entries->curItems
639
+ * minimal from entries->curItems. Lossy page is encoded by ItemPointer
640
+ * with max value for offset (0xffff), so if there is an non-lossy entries
641
+ * on lossy page they will returned too and after that the whole page.
642
+ * That's not a problem for resulting tidbitmap.
639
643
*/
640
644
ItemPointerSetMax (& key -> curItem );
641
645
for (i = 0 ; i < key -> nentries ; i ++ )
@@ -646,7 +650,8 @@ keyGetItem(Relation index, GinState *ginstate, MemoryContext tempCtx,
646
650
{
647
651
/*
648
652
* Move forward only entries which was the least
649
- * on previous call
653
+ * on previous call, key->entryRes[i] points that
654
+ * current entry was a result of loop/call.
650
655
*/
651
656
if (entry -> isFinished == FALSE && entryGetItem (index , entry ) == FALSE)
652
657
{
@@ -671,11 +676,21 @@ keyGetItem(Relation index, GinState *ginstate, MemoryContext tempCtx,
671
676
}
672
677
673
678
/*
679
+ * Now key->curItem contains closest ItemPointer to previous result.
680
+ *
674
681
* if key->nentries == 1 then the consistentFn should always succeed,
675
682
* but we must call it anyway to find out the recheck status.
676
683
*/
677
684
678
- /* setting up array for consistentFn */
685
+ /*----------
686
+ * entryRes array is used for:
687
+ * - as an argument for consistentFn
688
+ * - entry->curItem with corresponding key->entryRes[i] == false are
689
+ * greater than key->curItem, so next loop/call they should be
690
+ * renewed by entryGetItem(). So, we need to set up an array before
691
+ * checking of lossy page.
692
+ *----------
693
+ */
679
694
for (i = 0 ; i < key -> nentries ; i ++ )
680
695
{
681
696
entry = key -> scanEntry + i ;
@@ -719,7 +734,10 @@ keyGetItem(Relation index, GinState *ginstate, MemoryContext tempCtx,
719
734
720
735
/*
721
736
* Get ItemPointer of next heap row to be checked from pending list.
722
- * Returns false if there are no more.
737
+ * Returns false if there are no more. On pages with several rows
738
+ * it returns each row separately, on page with part of heap row returns
739
+ * per page data. pos->firstOffset and pos->lastOffset points
740
+ * fraction of tuples for current heap row.
723
741
*
724
742
* The pendingBuffer is presumed pinned and share-locked on entry, and is
725
743
* pinned and share-locked on success exit. On failure exit it's released.
@@ -787,13 +805,26 @@ scanGetCandidate(IndexScanDesc scan, pendingPosition *pos)
787
805
*/
788
806
pos -> lastOffset = maxoff + 1 ;
789
807
}
808
+
809
+ /*
810
+ * Now pos->firstOffset points to the first tuple of current heap row,
811
+ * pos->lastOffset points to the first tuple of second heap row (or
812
+ * to the end of page)
813
+ */
814
+
790
815
break ;
791
816
}
792
817
}
793
818
794
819
return true;
795
820
}
796
821
822
+ /*
823
+ * Scan page from current tuple (off) up to the first event:
824
+ * - tuple's attribute number is not equal to entry's attrnum
825
+ * - reach of last tuple
826
+ * - match is found (then returns true)
827
+ */
797
828
static bool
798
829
matchPartialInPendingList (GinState * ginstate , Page page ,
799
830
OffsetNumber off , OffsetNumber maxoff ,
@@ -817,6 +848,13 @@ matchPartialInPendingList(GinState *ginstate, Page page,
817
848
datumExtracted [ off - 1 ] = true;
818
849
}
819
850
851
+ /*----------
852
+ * Check of partial match.
853
+ * case cmp == 0 => match
854
+ * case cmp > 0 => not match and finish scan
855
+ * case cmp < 0 => not match and continue scan
856
+ *----------
857
+ */
820
858
cmp = DatumGetInt32 (FunctionCall4 (& ginstate -> comparePartialFn [attrnum ],
821
859
value ,
822
860
datum [off - 1 ],
@@ -826,14 +864,16 @@ matchPartialInPendingList(GinState *ginstate, Page page,
826
864
return true;
827
865
else if (cmp > 0 )
828
866
return false;
867
+
868
+ off ++ ;
829
869
}
830
870
831
871
return false;
832
872
}
833
873
834
874
/*
835
875
* Sets entryRes array for each key by looking at
836
- * every entry per indexed value (row) in pending list.
876
+ * every entry per indexed value (heap's row) in pending list.
837
877
* returns true if at least one of datum was matched by key's entry
838
878
*
839
879
* The pendingBuffer is presumed pinned and share-locked on entry.
@@ -878,9 +918,15 @@ collectDatumForItem(IndexScanDesc scan, pendingPosition *pos)
878
918
StopMiddle ;
879
919
GinScanEntry entry = key -> scanEntry + j ;
880
920
921
+ /* already true - do not extra work */
881
922
if ( key -> entryRes [j ] )
882
923
continue ;
883
924
925
+ /*
926
+ * Interested tuples are from pos->firstOffset to pos->lastOffset
927
+ * and they are ordered by (attnum, Datum) as it's done in entry tree
928
+ * So we could use binary search to prevent linear scanning
929
+ */
884
930
while (StopLow < StopHigh )
885
931
{
886
932
StopMiddle = StopLow + ((StopHigh - StopLow ) >> 1 );
@@ -908,6 +954,11 @@ collectDatumForItem(IndexScanDesc scan, pendingPosition *pos)
908
954
909
955
if ( res == 0 )
910
956
{
957
+ /*
958
+ * The exact match causes, so we just scan from
959
+ * current position to find a partial match.
960
+ * See comment above about tuple's ordering.
961
+ */
911
962
if ( entry -> isPartialMatch )
912
963
key -> entryRes [j ] =
913
964
matchPartialInPendingList (& so -> ginstate ,
@@ -931,6 +982,12 @@ collectDatumForItem(IndexScanDesc scan, pendingPosition *pos)
931
982
}
932
983
933
984
if ( StopLow >=StopHigh && entry -> isPartialMatch )
985
+ {
986
+ /*
987
+ * The exact match wasn't found, so we need to start
988
+ * scan from first tuple greater then current entry
989
+ * See comment above about tuple's ordering.
990
+ */
934
991
key -> entryRes [j ] =
935
992
matchPartialInPendingList (& so -> ginstate ,
936
993
page , StopHigh ,
@@ -941,6 +998,7 @@ collectDatumForItem(IndexScanDesc scan, pendingPosition *pos)
941
998
datumExtracted ,
942
999
entry -> strategy ,
943
1000
entry -> extra_data );
1001
+ }
944
1002
945
1003
hasMatch |= key -> entryRes [j ];
946
1004
}
@@ -960,6 +1018,11 @@ collectDatumForItem(IndexScanDesc scan, pendingPosition *pos)
960
1018
{
961
1019
ItemPointerData item = pos -> item ;
962
1020
1021
+ /*
1022
+ * need to get next portion of tuples of row containing
1023
+ * on several pages
1024
+ */
1025
+
963
1026
if ( scanGetCandidate (scan , pos ) == false || !ItemPointerEquals (& pos -> item , & item ) )
964
1027
elog (ERROR ,"Could not process tuple" ); /* XXX should not be here ! */
965
1028
}
@@ -1004,19 +1067,23 @@ scanPendingInsert(IndexScanDesc scan, TIDBitmap *tbm, int64 *ntids)
1004
1067
UnlockReleaseBuffer ( metabuffer );
1005
1068
1006
1069
/*
1007
- * loop for each heap row
1070
+ * loop for each heap row. scanGetCandidate returns full row
1071
+ * or row's tuples from first page.
1008
1072
*/
1009
1073
while ( scanGetCandidate (scan , & pos ) )
1010
1074
{
1011
1075
1012
1076
/*
1013
- * Check entries in rows and setup entryRes array
1077
+ * Check entries in tuple and setup entryRes array
1078
+ * If tuples of heap's row are placed on several pages
1079
+ * collectDatumForItem will read all of that pages.
1014
1080
*/
1015
1081
if (!collectDatumForItem (scan , & pos ))
1016
1082
continue ;
1017
1083
1018
1084
/*
1019
- * check for consistent
1085
+ * Matching of entries of one row is finished,
1086
+ * so check row by consistent function.
1020
1087
*/
1021
1088
oldCtx = MemoryContextSwitchTo (so -> tempCtx );
1022
1089
recheck = false;
0 commit comments