13
13
// limitations under the License.
14
14
15
15
use std:: borrow:: BorrowMut ;
16
+ use std:: collections:: HashSet ;
16
17
use std:: fmt:: Debug ;
17
18
use std:: sync:: Arc ;
18
19
use std:: sync:: Mutex ;
19
20
21
+ use common_arrow:: arrow:: bitmap:: Bitmap ;
20
22
use common_arrow:: arrow:: bitmap:: MutableBitmap ;
21
23
use common_base:: base:: tokio:: sync:: Notify ;
22
24
use common_datablocks:: DataBlock ;
@@ -35,7 +37,9 @@ use common_datavalues::DataField;
35
37
use common_datavalues:: DataSchema ;
36
38
use common_datavalues:: DataSchemaRef ;
37
39
use common_datavalues:: DataSchemaRefExt ;
40
+ use common_datavalues:: DataType ;
38
41
use common_datavalues:: DataTypeImpl ;
42
+ use common_datavalues:: DataValue ;
39
43
use common_datavalues:: NullableType ;
40
44
use common_exception:: ErrorCode ;
41
45
use common_exception:: Result ;
@@ -108,7 +112,7 @@ pub enum HashTable {
108
112
KeyU512HashTable ( KeyU512HashTable ) ,
109
113
}
110
114
111
- #[ derive( Clone , Copy , Eq , PartialEq , Debug ) ]
115
+ #[ derive( Clone , Copy , Eq , PartialEq , Debug , Hash ) ]
112
116
pub enum MarkerKind {
113
117
True ,
114
118
False ,
@@ -130,6 +134,7 @@ pub struct JoinHashTable {
130
134
pub ( crate ) row_space : RowSpace ,
131
135
pub ( crate ) hash_join_desc : HashJoinDesc ,
132
136
pub ( crate ) row_ptrs : RwLock < Vec < RowPtr > > ,
137
+ pub ( crate ) probe_schema : DataSchemaRef ,
133
138
finished_notify : Arc < Notify > ,
134
139
}
135
140
@@ -138,6 +143,7 @@ impl JoinHashTable {
138
143
ctx : Arc < QueryContext > ,
139
144
build_keys : & [ PhysicalScalar ] ,
140
145
build_schema : DataSchemaRef ,
146
+ probe_schema : DataSchemaRef ,
141
147
hash_join_desc : HashJoinDesc ,
142
148
) -> Result < Arc < JoinHashTable > > {
143
149
let hash_key_types: Vec < DataTypeImpl > =
@@ -151,6 +157,7 @@ impl JoinHashTable {
151
157
hash_method : HashMethodSerializer :: default ( ) ,
152
158
} ) ,
153
159
build_schema,
160
+ probe_schema,
154
161
hash_join_desc,
155
162
) ?) ,
156
163
HashMethodKind :: KeysU8 ( hash_method) => Arc :: new ( JoinHashTable :: try_create (
@@ -160,6 +167,7 @@ impl JoinHashTable {
160
167
hash_method,
161
168
} ) ,
162
169
build_schema,
170
+ probe_schema,
163
171
hash_join_desc,
164
172
) ?) ,
165
173
HashMethodKind :: KeysU16 ( hash_method) => Arc :: new ( JoinHashTable :: try_create (
@@ -169,6 +177,7 @@ impl JoinHashTable {
169
177
hash_method,
170
178
} ) ,
171
179
build_schema,
180
+ probe_schema,
172
181
hash_join_desc,
173
182
) ?) ,
174
183
HashMethodKind :: KeysU32 ( hash_method) => Arc :: new ( JoinHashTable :: try_create (
@@ -178,6 +187,7 @@ impl JoinHashTable {
178
187
hash_method,
179
188
} ) ,
180
189
build_schema,
190
+ probe_schema,
181
191
hash_join_desc,
182
192
) ?) ,
183
193
HashMethodKind :: KeysU64 ( hash_method) => Arc :: new ( JoinHashTable :: try_create (
@@ -187,6 +197,7 @@ impl JoinHashTable {
187
197
hash_method,
188
198
} ) ,
189
199
build_schema,
200
+ probe_schema,
190
201
hash_join_desc,
191
202
) ?) ,
192
203
HashMethodKind :: KeysU128 ( hash_method) => Arc :: new ( JoinHashTable :: try_create (
@@ -196,6 +207,7 @@ impl JoinHashTable {
196
207
hash_method,
197
208
} ) ,
198
209
build_schema,
210
+ probe_schema,
199
211
hash_join_desc,
200
212
) ?) ,
201
213
HashMethodKind :: KeysU256 ( hash_method) => Arc :: new ( JoinHashTable :: try_create (
@@ -205,6 +217,7 @@ impl JoinHashTable {
205
217
hash_method,
206
218
} ) ,
207
219
build_schema,
220
+ probe_schema,
208
221
hash_join_desc,
209
222
) ?) ,
210
223
HashMethodKind :: KeysU512 ( hash_method) => Arc :: new ( JoinHashTable :: try_create (
@@ -214,6 +227,7 @@ impl JoinHashTable {
214
227
hash_method,
215
228
} ) ,
216
229
build_schema,
230
+ probe_schema,
217
231
hash_join_desc,
218
232
) ?) ,
219
233
} )
@@ -223,6 +237,7 @@ impl JoinHashTable {
223
237
ctx : Arc < QueryContext > ,
224
238
hash_table : HashTable ,
225
239
mut build_data_schema : DataSchemaRef ,
240
+ mut probe_data_schema : DataSchemaRef ,
226
241
hash_join_desc : HashJoinDesc ,
227
242
) -> Result < Self > {
228
243
if hash_join_desc. join_type == JoinType :: Left
@@ -237,6 +252,16 @@ impl JoinHashTable {
237
252
}
238
253
build_data_schema = DataSchemaRefExt :: create ( nullable_field) ;
239
254
} ;
255
+ if hash_join_desc. join_type == JoinType :: Right {
256
+ let mut nullable_field = Vec :: with_capacity ( probe_data_schema. fields ( ) . len ( ) ) ;
257
+ for field in probe_data_schema. fields ( ) . iter ( ) {
258
+ nullable_field. push ( DataField :: new_nullable (
259
+ field. name ( ) ,
260
+ field. data_type ( ) . clone ( ) ,
261
+ ) ) ;
262
+ }
263
+ probe_data_schema = DataSchemaRefExt :: create ( nullable_field) ;
264
+ }
240
265
Ok ( Self {
241
266
row_space : RowSpace :: new ( build_data_schema) ,
242
267
ref_count : Mutex :: new ( 0 ) ,
@@ -245,6 +270,7 @@ impl JoinHashTable {
245
270
ctx,
246
271
hash_table : RwLock :: new ( hash_table) ,
247
272
row_ptrs : RwLock :: new ( vec ! [ ] ) ,
273
+ probe_schema : probe_data_schema,
248
274
finished_notify : Arc :: new ( Notify :: new ( ) ) ,
249
275
} )
250
276
}
@@ -407,6 +433,31 @@ impl JoinHashTable {
407
433
}
408
434
}
409
435
}
436
+
437
+ fn find_unmatched_build_indexes ( & self ) -> Result < Vec < RowPtr > > {
438
+ // For right join, build side will appear at least once in the joined table
439
+ // Find the unmatched rows in build side
440
+ let mut unmatched_build_indexes = vec ! [ ] ;
441
+ let build_indexes = self . hash_join_desc . right_join_desc . build_indexes . read ( ) ;
442
+ let build_indexes_set: HashSet < & RowPtr > = build_indexes. iter ( ) . collect ( ) ;
443
+ // TODO(xudong): remove the line of code below after https://github.com/rust-lang/rust-clippy/issues/8987
444
+ #[ allow( clippy:: significant_drop_in_scrutinee) ]
445
+ for ( chunk_index, chunk) in self . row_space . chunks . read ( ) . unwrap ( ) . iter ( ) . enumerate ( ) {
446
+ for row_index in 0 ..chunk. num_rows ( ) {
447
+ let row_ptr = RowPtr {
448
+ chunk_index : chunk_index as u32 ,
449
+ row_index : row_index as u32 ,
450
+ marker : None ,
451
+ } ;
452
+ if !build_indexes_set. contains ( & row_ptr) {
453
+ let mut row_state = self . hash_join_desc . right_join_desc . row_state . write ( ) ;
454
+ row_state. entry ( row_ptr) . or_insert ( 0_usize ) ;
455
+ unmatched_build_indexes. push ( row_ptr) ;
456
+ }
457
+ }
458
+ }
459
+ Ok ( unmatched_build_indexes)
460
+ }
410
461
}
411
462
412
463
#[ async_trait:: async_trait]
@@ -429,7 +480,8 @@ impl HashJoinState for JoinHashTable {
429
480
| JoinType :: Anti
430
481
| JoinType :: Left
431
482
| Mark
432
- | JoinType :: Single => self . probe_join ( input, probe_state) ,
483
+ | JoinType :: Single
484
+ | JoinType :: Right => self . probe_join ( input, probe_state) ,
433
485
JoinType :: Cross => self . probe_cross_join ( input, probe_state) ,
434
486
_ => unimplemented ! ( "{} is unimplemented" , self . hash_join_desc. join_type) ,
435
487
}
@@ -661,4 +713,73 @@ impl HashJoinState for JoinHashTable {
661
713
let build_block = self . row_space . gather ( & row_ptrs) ?;
662
714
Ok ( vec ! [ self . merge_eq_block( & marker_block, & build_block) ?] )
663
715
}
716
+
717
+ fn right_join_blocks ( & self , blocks : & [ DataBlock ] ) -> Result < Vec < DataBlock > > {
718
+ let unmatched_build_indexes = self . find_unmatched_build_indexes ( ) ?;
719
+ if unmatched_build_indexes. is_empty ( ) && self . hash_join_desc . other_predicate . is_none ( ) {
720
+ return Ok ( blocks. to_vec ( ) ) ;
721
+ }
722
+
723
+ let unmatched_build_block = self . row_space . gather ( & unmatched_build_indexes) ?;
724
+ // Create null block for unmatched rows in probe side
725
+ let null_probe_block = DataBlock :: create (
726
+ self . probe_schema . clone ( ) ,
727
+ self . probe_schema
728
+ . fields ( )
729
+ . iter ( )
730
+ . map ( |df| {
731
+ df. data_type ( )
732
+ . clone ( )
733
+ . create_constant_column ( & DataValue :: Null , unmatched_build_indexes. len ( ) )
734
+ } )
735
+ . collect :: < Result < Vec < _ > > > ( ) ?,
736
+ ) ;
737
+ let mut merged_block = self . merge_eq_block ( & unmatched_build_block, & null_probe_block) ?;
738
+ merged_block = DataBlock :: concat_blocks ( & [ blocks, & [ merged_block] ] . concat ( ) ) ?;
739
+
740
+ if self . hash_join_desc . other_predicate . is_none ( ) {
741
+ return Ok ( vec ! [ merged_block] ) ;
742
+ }
743
+
744
+ let ( bm, all_true, all_false) = self . get_other_filters (
745
+ & merged_block,
746
+ self . hash_join_desc . other_predicate . as_ref ( ) . unwrap ( ) ,
747
+ ) ?;
748
+
749
+ if all_true {
750
+ return Ok ( vec ! [ merged_block] ) ;
751
+ }
752
+
753
+ let validity = match ( bm, all_false) {
754
+ ( Some ( b) , _) => b,
755
+ ( None , true ) => Bitmap :: new_zeroed ( merged_block. num_rows ( ) ) ,
756
+ // must be one of above
757
+ _ => unreachable ! ( ) ,
758
+ } ;
759
+ let probe_column_len = self . probe_schema . fields ( ) . len ( ) ;
760
+ let probe_columns = merged_block. columns ( ) [ 0 ..probe_column_len]
761
+ . iter ( )
762
+ . map ( |c| Self :: set_validity ( c, & validity) )
763
+ . collect :: < Result < Vec < _ > > > ( ) ?;
764
+ let probe_block = DataBlock :: create ( self . probe_schema . clone ( ) , probe_columns) ;
765
+ let build_block = DataBlock :: create (
766
+ self . row_space . data_schema . clone ( ) ,
767
+ merged_block. columns ( ) [ probe_column_len..] . to_vec ( ) ,
768
+ ) ;
769
+ merged_block = self . merge_eq_block ( & build_block, & probe_block) ?;
770
+
771
+ // If build_indexes size will greater build table size, we need filter the redundant rows for build side.
772
+ let mut build_indexes = self . hash_join_desc . right_join_desc . build_indexes . write ( ) ;
773
+ let mut row_state = self . hash_join_desc . right_join_desc . row_state . write ( ) ;
774
+ build_indexes. extend ( & unmatched_build_indexes) ;
775
+ if build_indexes. len ( ) > self . row_space . rows_number ( ) {
776
+ let mut bm = validity. into_mut ( ) . right ( ) . unwrap ( ) ;
777
+ Self :: filter_rows_for_right_join ( & mut bm, & build_indexes, & mut row_state) ;
778
+ let predicate = BooleanColumn :: from_arrow_data ( bm. into ( ) ) . arc ( ) ;
779
+ let filtered_block = DataBlock :: filter_block ( merged_block, & predicate) ?;
780
+ return Ok ( vec ! [ filtered_block] ) ;
781
+ }
782
+
783
+ Ok ( vec ! [ merged_block] )
784
+ }
664
785
}
0 commit comments