@@ -415,8 +415,7 @@ PageRestoreTempPage(Page tempPage, Page oldPage)
415
415
}
416
416
417
417
/*
418
- * sorting support for PageRepairFragmentation, PageIndexMultiDelete,
419
- * PageIndexDeleteNoCompact
418
+ * sorting support for PageRepairFragmentation and PageIndexMultiDelete
420
419
*/
421
420
typedef struct itemIdSortData
422
421
{
@@ -762,15 +761,14 @@ PageIndexTupleDelete(Page page, OffsetNumber offnum)
762
761
* Now move everything between the old upper bound (beginning of tuple
763
762
* space) and the beginning of the deleted tuple forward, so that space in
764
763
* the middle of the page is left free. If we've just deleted the tuple
765
- * at the beginning of tuple space, then there's no need to do the copy
766
- * (and bcopy on some architectures SEGV's if asked to move zero bytes).
764
+ * at the beginning of tuple space, then there's no need to do the copy.
767
765
*/
768
766
769
767
/* beginning of tuple space */
770
768
addr = (char * ) page + phdr -> pd_upper ;
771
769
772
770
if (offset > phdr -> pd_upper )
773
- memmove (addr + size , addr , ( int ) ( offset - phdr -> pd_upper ) );
771
+ memmove (addr + size , addr , offset - phdr -> pd_upper );
774
772
775
773
/* adjust free space boundary pointers */
776
774
phdr -> pd_upper += size ;
@@ -918,155 +916,105 @@ PageIndexMultiDelete(Page page, OffsetNumber *itemnos, int nitems)
918
916
compactify_tuples (itemidbase , nused , page );
919
917
}
920
918
919
+
921
920
/*
922
- * PageIndexDeleteNoCompact
923
- * Delete the given items for an index page, and defragment the resulting
924
- * free space, but do not compact the item pointers array.
925
- *
926
- * itemnos is the array of tuples to delete; nitems is its size. maxIdxTuples
927
- * is the maximum number of tuples that can exist in a page.
921
+ * PageIndexTupleDeleteNoCompact
928
922
*
929
- * Unused items at the end of the array are removed.
923
+ * Remove the specified tuple from an index page, but set its line pointer
924
+ * to "unused" instead of compacting it out, except that it can be removed
925
+ * if it's the last line pointer on the page.
930
926
*
931
927
* This is used for index AMs that require that existing TIDs of live tuples
932
- * remain unchanged.
928
+ * remain unchanged, and are willing to allow unused line pointers instead .
933
929
*/
934
930
void
935
- PageIndexDeleteNoCompact (Page page , OffsetNumber * itemnos , int nitems )
931
+ PageIndexTupleDeleteNoCompact (Page page , OffsetNumber offnum )
936
932
{
937
933
PageHeader phdr = (PageHeader ) page ;
938
- LocationIndex pd_lower = phdr -> pd_lower ;
939
- LocationIndex pd_upper = phdr -> pd_upper ;
940
- LocationIndex pd_special = phdr -> pd_special ;
934
+ char * addr ;
935
+ ItemId tup ;
936
+ Size size ;
937
+ unsigned offset ;
941
938
int nline ;
942
- bool empty ;
943
- OffsetNumber offnum ;
944
- int nextitm ;
945
939
946
940
/*
947
941
* As with PageRepairFragmentation, paranoia seems justified.
948
942
*/
949
- if (pd_lower < SizeOfPageHeaderData ||
950
- pd_lower > pd_upper ||
951
- pd_upper > pd_special ||
952
- pd_special > BLCKSZ ||
953
- pd_special != MAXALIGN (pd_special ))
943
+ if (phdr -> pd_lower < SizeOfPageHeaderData ||
944
+ phdr -> pd_lower > phdr -> pd_upper ||
945
+ phdr -> pd_upper > phdr -> pd_special ||
946
+ phdr -> pd_special > BLCKSZ ||
947
+ phdr -> pd_special != MAXALIGN (phdr -> pd_special ))
954
948
ereport (ERROR ,
955
949
(errcode (ERRCODE_DATA_CORRUPTED ),
956
950
errmsg ("corrupted page pointers: lower = %u, upper = %u, special = %u" ,
957
- pd_lower , pd_upper , pd_special )));
951
+ phdr -> pd_lower , phdr -> pd_upper , phdr -> pd_special )));
952
+
953
+ nline = PageGetMaxOffsetNumber (page );
954
+ if ((int ) offnum <= 0 || (int ) offnum > nline )
955
+ elog (ERROR , "invalid index offnum: %u" , offnum );
956
+
957
+ tup = PageGetItemId (page , offnum );
958
+ Assert (ItemIdHasStorage (tup ));
959
+ size = ItemIdGetLength (tup );
960
+ offset = ItemIdGetOffset (tup );
961
+
962
+ if (offset < phdr -> pd_upper || (offset + size ) > phdr -> pd_special ||
963
+ offset != MAXALIGN (offset ))
964
+ ereport (ERROR ,
965
+ (errcode (ERRCODE_DATA_CORRUPTED ),
966
+ errmsg ("corrupted item pointer: offset = %u, size = %u" ,
967
+ offset , (unsigned int ) size )));
968
+
969
+ /* Amount of space to actually be deleted */
970
+ size = MAXALIGN (size );
958
971
959
972
/*
960
- * Scan the existing item pointer array and mark as unused those that are
961
- * in our kill-list; make sure any non-interesting ones are marked unused
962
- * as well.
973
+ * Either set the item pointer to "unused", or zap it if it's the last
974
+ * one. (Note: it's possible that the next-to-last one(s) are already
975
+ * unused, but we do not trouble to try to compact them out if so.)
963
976
*/
964
- nline = PageGetMaxOffsetNumber (page );
965
- empty = true;
966
- nextitm = 0 ;
967
- for (offnum = FirstOffsetNumber ; offnum <= nline ; offnum = OffsetNumberNext (offnum ))
977
+ if ((int ) offnum < nline )
978
+ ItemIdSetUnused (tup );
979
+ else
968
980
{
969
- ItemId lp ;
970
- ItemLength itemlen ;
971
- ItemOffset offset ;
981
+ phdr -> pd_lower -= sizeof ( ItemIdData ) ;
982
+ nline -- ; /* there's one less than when we started */
983
+ }
972
984
973
- lp = PageGetItemId (page , offnum );
985
+ /*
986
+ * Now move everything between the old upper bound (beginning of tuple
987
+ * space) and the beginning of the deleted tuple forward, so that space in
988
+ * the middle of the page is left free. If we've just deleted the tuple
989
+ * at the beginning of tuple space, then there's no need to do the copy.
990
+ */
974
991
975
- itemlen = ItemIdGetLength ( lp );
976
- offset = ItemIdGetOffset ( lp ) ;
992
+ /* beginning of tuple space */
993
+ addr = ( char * ) page + phdr -> pd_upper ;
977
994
978
- if (ItemIdIsUsed (lp ))
979
- {
980
- if (offset < pd_upper ||
981
- (offset + itemlen ) > pd_special ||
982
- offset != MAXALIGN (offset ))
983
- ereport (ERROR ,
984
- (errcode (ERRCODE_DATA_CORRUPTED ),
985
- errmsg ("corrupted item pointer: offset = %u, length = %u" ,
986
- offset , (unsigned int ) itemlen )));
987
-
988
- if (nextitm < nitems && offnum == itemnos [nextitm ])
989
- {
990
- /* this one is on our list to delete, so mark it unused */
991
- ItemIdSetUnused (lp );
992
- nextitm ++ ;
993
- }
994
- else if (ItemIdHasStorage (lp ))
995
- {
996
- /* This one's live -- must do the compaction dance */
997
- empty = false;
998
- }
999
- else
1000
- {
1001
- /* get rid of this one too */
1002
- ItemIdSetUnused (lp );
1003
- }
1004
- }
1005
- }
995
+ if (offset > phdr -> pd_upper )
996
+ memmove (addr + size , addr , offset - phdr -> pd_upper );
1006
997
1007
- /* this will catch invalid or out-of-order itemnos[] */
1008
- if (nextitm != nitems )
1009
- elog (ERROR , "incorrect index offsets supplied" );
998
+ /* adjust free space boundary pointer */
999
+ phdr -> pd_upper += size ;
1010
1000
1011
- if ( empty )
1012
- {
1013
- /* Page is completely empty, so just reset it quickly */
1014
- phdr -> pd_lower = SizeOfPageHeaderData ;
1015
- phdr -> pd_upper = pd_special ;
1016
- }
1017
- else
1001
+ /*
1002
+ * Finally, we need to adjust the linp entries that remain.
1003
+ *
1004
+ * Anything that used to be before the deleted tuple's data was moved
1005
+ * forward by the size of the deleted tuple.
1006
+ */
1007
+ if (! PageIsEmpty ( page ))
1018
1008
{
1019
- /* There are live items: need to compact the page the hard way */
1020
- itemIdSortData itemidbase [MaxOffsetNumber ];
1021
- itemIdSort itemidptr ;
1022
1009
int i ;
1023
- Size totallen ;
1024
1010
1025
- /*
1026
- * Scan the page taking note of each item that we need to preserve.
1027
- * This includes both live items (those that contain data) and
1028
- * interspersed unused ones. It's critical to preserve these unused
1029
- * items, because otherwise the offset numbers for later live items
1030
- * would change, which is not acceptable. Unused items might get used
1031
- * again later; that is fine.
1032
- */
1033
- itemidptr = itemidbase ;
1034
- totallen = 0 ;
1035
- PageClearHasFreeLinePointers (page );
1036
- for (i = 0 ; i < nline ; i ++ )
1011
+ for (i = 1 ; i <= nline ; i ++ )
1037
1012
{
1038
- ItemId lp ;
1039
-
1040
- itemidptr -> offsetindex = i ;
1013
+ ItemId ii = PageGetItemId (phdr , i );
1041
1014
1042
- lp = PageGetItemId (page , i + 1 );
1043
- if (ItemIdHasStorage (lp ))
1044
- {
1045
- itemidptr -> itemoff = ItemIdGetOffset (lp );
1046
- itemidptr -> alignedlen = MAXALIGN (ItemIdGetLength (lp ));
1047
- totallen += itemidptr -> alignedlen ;
1048
- itemidptr ++ ;
1049
- }
1050
- else
1051
- {
1052
- PageSetHasFreeLinePointers (page );
1053
- ItemIdSetUnused (lp );
1054
- }
1015
+ if (ItemIdHasStorage (ii ) && ItemIdGetOffset (ii ) <= offset )
1016
+ ii -> lp_off += size ;
1055
1017
}
1056
- nline = itemidptr - itemidbase ;
1057
- /* By here, there are exactly nline elements in itemidbase array */
1058
-
1059
- if (totallen > (Size ) (pd_special - pd_lower ))
1060
- ereport (ERROR ,
1061
- (errcode (ERRCODE_DATA_CORRUPTED ),
1062
- errmsg ("corrupted item lengths: total %u, available space %u" ,
1063
- (unsigned int ) totallen , pd_special - pd_lower )));
1064
-
1065
- /*
1066
- * Defragment the data areas of each tuple, being careful to preserve
1067
- * each item's position in the linp array.
1068
- */
1069
- compactify_tuples (itemidbase , nline , page );
1070
1018
}
1071
1019
}
1072
1020
0 commit comments