@@ -81,6 +81,41 @@ impl ScanState {
8181 }
8282}
8383
84+ fn tid_cmp ( a : & pg_sys:: ItemPointerData , b : & pg_sys:: ItemPointerData ) -> Ordering {
85+ let a_blk = ( a. ip_blkid . bi_hi as u32 ) << 16 | a. ip_blkid . bi_lo as u32 ;
86+ let b_blk = ( b. ip_blkid . bi_hi as u32 ) << 16 | b. ip_blkid . bi_lo as u32 ;
87+ match a_blk. cmp ( & b_blk) {
88+ Ordering :: Equal => a. ip_posid . cmp ( & b. ip_posid ) ,
89+ other => other,
90+ }
91+ }
92+
93+ fn intersect_scan_states ( mut left : ScanState , right : ScanState ) -> ScanState {
94+ let mut matches = Vec :: with_capacity ( left. matches . len ( ) . min ( right. matches . len ( ) ) ) ;
95+ let mut lidx = 0usize ;
96+ let mut ridx = 0usize ;
97+
98+ while lidx < left. matches . len ( ) && ridx < right. matches . len ( ) {
99+ match tid_cmp ( & left. matches [ lidx] . tid , & right. matches [ ridx] . tid ) {
100+ Ordering :: Less => lidx += 1 ,
101+ Ordering :: Greater => ridx += 1 ,
102+ Ordering :: Equal => {
103+ matches. push ( MatchEntry {
104+ tid : left. matches [ lidx] . tid ,
105+ // Every clause must hold, so any lossy clause forces a heap recheck.
106+ recheck : left. matches [ lidx] . recheck || right. matches [ ridx] . recheck ,
107+ } ) ;
108+ lidx += 1 ;
109+ ridx += 1 ;
110+ }
111+ }
112+ }
113+
114+ left. matches = matches;
115+ left. cursor = 0 ;
116+ left
117+ }
118+
84119fn scan_keys_to_pattern ( keys : pg_sys:: ScanKey , nkeys : i32 ) -> Option < String > {
85120 if keys. is_null ( ) || nkeys <= 0 {
86121 return None ;
@@ -1527,12 +1562,11 @@ fn add_matches_from_regex_branches(
15271562 Ok ( ( ) )
15281563}
15291564
1530- unsafe fn build_scan_state (
1565+ unsafe fn build_scan_state_for_key (
15311566 index_relation : pg_sys:: Relation ,
15321567 keys : pg_sys:: ScanKey ,
1533- nkeys : std:: os:: raw:: c_int ,
15341568) -> ScanState {
1535- let pattern = scan_keys_to_pattern ( keys, nkeys ) ;
1569+ let pattern = scan_keys_to_pattern ( keys, 1 ) ;
15361570 let pattern_str = if let Some ( p) = pattern {
15371571 p
15381572 } else {
@@ -1688,6 +1722,34 @@ unsafe fn build_scan_state(
16881722 }
16891723}
16901724
1725+ unsafe fn build_scan_state (
1726+ index_relation : pg_sys:: Relation ,
1727+ keys : pg_sys:: ScanKey ,
1728+ nkeys : std:: os:: raw:: c_int ,
1729+ ) -> ScanState {
1730+ if keys. is_null ( ) || nkeys <= 0 {
1731+ return ScanState :: default ( ) ;
1732+ }
1733+
1734+ let mut combined: Option < ScanState > = None ;
1735+ for idx in 0 ..( nkeys as usize ) {
1736+ let key = unsafe { keys. add ( idx) } ;
1737+ let state = unsafe { build_scan_state_for_key ( index_relation, key) } ;
1738+ combined = Some ( match combined. take ( ) {
1739+ Some ( existing) => intersect_scan_states ( existing, state) ,
1740+ None => state,
1741+ } ) ;
1742+ if combined
1743+ . as_ref ( )
1744+ . is_some_and ( |state| state. matches . is_empty ( ) )
1745+ {
1746+ break ;
1747+ }
1748+ }
1749+
1750+ combined. unwrap_or_default ( )
1751+ }
1752+
16911753fn build_full_regex_scan_state ( index_relation : pg_sys:: Relation ) -> ScanState {
16921754 let mut state = ScanState :: default ( ) ;
16931755 state. tombstones =
0 commit comments