1313
1414#include "postgres.h"
1515#include "rumsort.h"
16+ #include "rumtidbitmap.h"
1617
1718#include "access/relscan.h"
1819#include "storage/predicate.h"
@@ -759,6 +760,53 @@ scan_entry_cmp(const void *p1, const void *p2, void *arg)
759760 return - cmpEntries (arg , e1 , e2 );
760761}
761762
763+ /*
764+ * The entryGetItem() function from rumget.c write the results to curItem
765+ * in a specific order. The functions below allow you to understand the order
766+ * in which the results will be returned. This is important in a multi-column
767+ * RUM index, when the results will be returned in different order for
768+ * different subquery conditions.
769+ */
770+ static bool
771+ isEntryOrderedByAddInfo (RumState * rumstate , RumScanEntry entry )
772+ {
773+ if (rumstate -> useAlternativeOrder )
774+ return (rumstate -> attrnAddToColumn == entry -> attnumOrig );
775+ else
776+ return false;
777+ }
778+ 779+ static bool
780+ isKeyOrderedByAddInfo (RumState * rumstate , RumScanKey key )
781+ {
782+ if (rumstate -> useAlternativeOrder )
783+ return (rumstate -> attrnAddToColumn == key -> attnumOrig );
784+ else
785+ return false;
786+ }
787+ 788+ static bool
789+ isScanWithAltOrderKeys (RumScanOpaque so )
790+ {
791+ RumState * rumstate = & so -> rumstate ;
792+ 793+ bool withAltKeys = false;
794+ bool withUsualKeys = false;
795+ 796+ if (so -> nkeys == 1 )
797+ return false;
798+ 799+ for (int i = 0 ; i < so -> nkeys ; i ++ )
800+ {
801+ if (isKeyOrderedByAddInfo (rumstate , so -> keys [i ]))
802+ withAltKeys = true;
803+ else
804+ withUsualKeys = true;
805+ }
806+ 807+ return (withUsualKeys && withAltKeys );
808+ }
809+ 762810static void
763811startScan (IndexScanDesc scan )
764812{
@@ -806,6 +854,17 @@ startScan(IndexScanDesc scan)
806854 for (i = 0 ; i < so -> nkeys ; i ++ )
807855 startScanKey (rumstate , so -> keys [i ]);
808856
857+ /*
858+ * If there are several keys in the scan and its are ordered differently,
859+ * need to set the scanWithAltOrderKeys flag and create a bitmap for
860+ * TIDs that are suitable for regular keys (which are ordered by tid).
861+ */
862+ if (isScanWithAltOrderKeys (so ))
863+ {
864+ so -> scanWithAltOrderKeys = true;
865+ so -> tbm = rum_tbm_create (work_mem * 1024L , NULL );
866+ }
867+ 809868 /*
810869 * Check if we can use a fast scan.
811870 * Use fast scan iff all keys have preConsistent method. But we can stop
@@ -1361,6 +1420,16 @@ compareCurRumItemScanDirection(RumState *rumstate, RumScanEntry entry,
13611420 & entry -> curItem , minItem );
13621421}
13631422
1423+ static int
1424+ rumCompareItemPointersScanDirection (ScanDirection scanDirection ,
1425+ const ItemPointerData * a ,
1426+ const ItemPointerData * b )
1427+ {
1428+ int res = rumCompareItemPointers (a , b );
1429+ 1430+ return (ScanDirectionIsForward (scanDirection )) ? res : - res ;
1431+ }
1432+ 13641433static void
13651434keyGetItem (RumState * rumstate , MemoryContext tempCtx , RumScanKey key )
13661435{
@@ -1445,6 +1514,63 @@ keyGetItem(RumState * rumstate, MemoryContext tempCtx, RumScanKey key)
14451514 MemoryContextReset (tempCtx );
14461515}
14471516
1517+ /*
1518+ * The function puts all the suitable tids for
1519+ * the passed RumScanKey into the RumTIDBitmap.
1520+ */
1521+ static void
1522+ collectAllCurItemsToBitmap (RumScanKey key , RumTIDBitmap * tbm ,
1523+ IndexScanDesc scan )
1524+ {
1525+ RumScanOpaque so = (RumScanOpaque ) scan -> opaque ;
1526+ RumState * rumstate = & so -> rumstate ;
1527+ ItemPointerData advancePast ;
1528+ 1529+ ItemPointerSetInvalid (& advancePast );
1530+ 1531+ for (;;)
1532+ {
1533+ /*
1534+ * Set the curItem for all the RumScanEntry
1535+ * of our RumScanKey after advancePast.
1536+ */
1537+ for (int i = 0 ; i < key -> nentries ; i ++ )
1538+ {
1539+ RumScanEntry entry = key -> scanEntry [i ];
1540+ 1541+ while (entry -> isFinished == false &&
1542+ (!ItemPointerIsValid (& advancePast ) ||
1543+ rumCompareItemPointersScanDirection (entry -> scanDirection ,
1544+ & entry -> curItem .iptr , & advancePast ) <= 0 ))
1545+ {
1546+ entryGetItem (rumstate , entry , NULL , scan -> xs_snapshot );
1547+ 1548+ /*
1549+ * On the first iteration of the loop,
1550+ * RumScanEntry->curItem is the first available.
1551+ */
1552+ if (!ItemPointerIsValid (& advancePast ))
1553+ break ;
1554+ }
1555+ }
1556+ 1557+ /*
1558+ * For RumScanKey, we set the minimum
1559+ * curItem from its RumScanEntry.
1560+ */
1561+ keyGetItem (rumstate , so -> tempCtx , key );
1562+ 1563+ if (key -> isFinished )
1564+ return ;
1565+ 1566+ /* If curItem is suitable, put it in the RumTIDBitmap */
1567+ if (key -> curItemMatches )
1568+ rum_tbm_add_tuples (tbm , & key -> curItem .iptr , 1 , false);
1569+ 1570+ advancePast = key -> curItem .iptr ;
1571+ }
1572+ }
1573+ 14481574/*
14491575 * Get next heap item pointer (after advancePast) from scan.
14501576 * Returns true if anything found.
@@ -1453,6 +1579,11 @@ keyGetItem(RumState * rumstate, MemoryContext tempCtx, RumScanKey key)
14531579 * Note: this is very nearly the same logic as in keyGetItem(), except
14541580 * that we know the keys are to be combined with AND logic, whereas in
14551581 * keyGetItem() the combination logic is known only to the consistentFn.
1582+ *
1583+ * Note: In the case of a scan that contains several keys ordered in different
1584+ * ways, you need to prepare. To do this, for all keys ordered by tid,
1585+ * the appropriate TIDs are placed in the RumTIDBitmap. After that, all
1586+ * these bitmaps intersect (because the RumScanKeys are connected via AND).
14561587 */
14571588static bool
14581589scanGetItemRegular (IndexScanDesc scan , RumItem * advancePast ,
@@ -1465,6 +1596,43 @@ scanGetItemRegular(IndexScanDesc scan, RumItem *advancePast,
14651596 bool allFinished ;
14661597 bool match , itemSet ;
14671598
1599+ RumTIDBitmap * cur_key_tbm = NULL ;
1600+ bool soBitmapSet = false;
1601+ bool bitmapRecheck = false;
1602+ 1603+ /*
1604+ * Preparation to scan with altOrderKeys. This preparation
1605+ * needs to be done only in the first call to scanGetItemRegular().
1606+ */
1607+ if (so -> scanWithAltOrderKeys &&
1608+ ItemPointerIsValid (& advancePast -> iptr ) == false)
1609+ {
1610+ /* For each key, put all the appropriate tids into the bitmap */
1611+ for (int i = 0 ; i < so -> nkeys ; i ++ )
1612+ {
1613+ if (so -> keys [i ]-> orderBy ||
1614+ isKeyOrderedByAddInfo (rumstate , so -> keys [i ]))
1615+ continue ;
1616+ 1617+ cur_key_tbm = rum_tbm_create (work_mem * 1024L , NULL );
1618+ collectAllCurItemsToBitmap (so -> keys [i ], cur_key_tbm , scan );
1619+ 1620+ /*
1621+ * so->tbm contains matching tids for
1622+ * all keys that are ordered by tid.
1623+ */
1624+ if (soBitmapSet == false)
1625+ {
1626+ soBitmapSet = true;
1627+ rum_tbm_union (so -> tbm , cur_key_tbm );
1628+ }
1629+ else
1630+ rum_tbm_intersect (so -> tbm , cur_key_tbm );
1631+ 1632+ rum_tbm_free (cur_key_tbm );
1633+ }
1634+ }
1635+ 14681636 for (;;)
14691637 {
14701638 /*
@@ -1478,6 +1646,11 @@ scanGetItemRegular(IndexScanDesc scan, RumItem *advancePast,
14781646 {
14791647 RumScanEntry entry = so -> entries [i ];
14801648
1649+ /* In the case of scanning with altOrderKeys, skip the usual keys */
1650+ if (so -> scanWithAltOrderKeys &&
1651+ isEntryOrderedByAddInfo (rumstate , entry ) == false)
1652+ continue ;
1653+ 14811654 while (entry -> isFinished == false &&
14821655 (!ItemPointerIsValid (& myAdvancePast .iptr ) ||
14831656 compareCurRumItemScanDirection (rumstate , entry ,
@@ -1512,7 +1685,9 @@ scanGetItemRegular(IndexScanDesc scan, RumItem *advancePast,
15121685 RumScanKey key = so -> keys [i ];
15131686 int cmp ;
15141687
1515- if (key -> orderBy )
1688+ /* In the case of scanning with altOrderKeys, skip the usual keys */
1689+ if (key -> orderBy || (so -> scanWithAltOrderKeys &&
1690+ isKeyOrderedByAddInfo (rumstate , key ) == false))
15161691 continue ;
15171692
15181693 keyGetItem (& so -> rumstate , so -> tempCtx , key );
@@ -1541,7 +1716,9 @@ scanGetItemRegular(IndexScanDesc scan, RumItem *advancePast,
15411716 {
15421717 RumScanKey key = so -> keys [i ];
15431718
1544- if (key -> orderBy )
1719+ /* In the case of scanning with altOrderKeys, skip the usual keys */
1720+ if (key -> orderBy || (so -> scanWithAltOrderKeys &&
1721+ isKeyOrderedByAddInfo (rumstate , key ) == false))
15451722 continue ;
15461723
15471724 if (key -> curItemMatches )
@@ -1553,6 +1730,17 @@ scanGetItemRegular(IndexScanDesc scan, RumItem *advancePast,
15531730 break ;
15541731 }
15551732
1733+ /*
1734+ * Now (if scan with altOrderKeys), if an *item is suitable for all
1735+ * altOrderKeys, you need to find it in the bitmap. If it's there,
1736+ * then it fits.
1737+ *
1738+ * Due to the fact that there may be lossy pages in the bitmap,
1739+ * you may need to recheck the *item.
1740+ */
1741+ if (so -> scanWithAltOrderKeys && match )
1742+ match = rum_tbm_contains_tid (so -> tbm , & item -> iptr , & bitmapRecheck );
1743+ 15561744 if (match )
15571745 break ;
15581746
@@ -1595,6 +1783,10 @@ scanGetItemRegular(IndexScanDesc scan, RumItem *advancePast,
15951783 }
15961784 }
15971785
1786+ /* If there was a lossy page in the bitmap, need to recheck */
1787+ if (so -> scanWithAltOrderKeys && bitmapRecheck )
1788+ * recheck = true;
1789+ 15981790 return true;
15991791}
16001792
0 commit comments