@@ -153,6 +153,62 @@ bool HashJoinIterator::InitProbeIterator() {
153
153
return false ;
154
154
}
155
155
156
+ bool HashJoinIterator::ReadFirstProbeRow () {
157
+ assert (m_first_input == HashJoinInput::kProbe );
158
+ m_state = State::READING_ROW_FROM_PROBE_ITERATOR;
159
+
160
+ if (InitProbeIterator ()) {
161
+ return true ;
162
+ }
163
+
164
+ const int result = m_probe_input->Read ();
165
+ if (result == 1 ) {
166
+ return true ;
167
+
168
+ } else if (result == -1 ) {
169
+ m_state = State::END_OF_ROWS;
170
+ return false ;
171
+
172
+ } else {
173
+ assert (result == 0 );
174
+ m_probe_row_read = true ;
175
+ // Prepare to read the build input into the hash map.
176
+ PrepareForRequestRowId (m_build_input_tables.tables (),
177
+ m_tables_to_get_rowid_for);
178
+
179
+ return false ;
180
+ }
181
+ }
182
+
183
+ bool HashJoinIterator::InitHashTable () {
184
+ if (BuildHashTable ()) {
185
+ return true ;
186
+ }
187
+
188
+ if (m_hash_table_generation != nullptr ) {
189
+ m_last_hash_table_generation = *m_hash_table_generation;
190
+ }
191
+
192
+ if (m_state == State::END_OF_ROWS) {
193
+ // BuildHashTable() decided that the join is done (the build input is
194
+ // empty, and we are in an inner-/semijoin. Anti-/outer join must output
195
+ // NULL-complemented rows from the probe input).
196
+ return false ;
197
+ }
198
+
199
+ if (m_join_type == JoinType::ANTI && m_join_conditions.empty () &&
200
+ m_extra_condition == nullptr && !m_row_buffer.empty ()) {
201
+ // For degenerate antijoins, we know we will never output anything
202
+ // if there's anything in the hash table, so we can end right away.
203
+ // (We also don't need to read more than one row, but
204
+ // CreateHashJoinAccessPath() has already added a LIMIT 1 for us
205
+ // in this case.)
206
+ m_state = State::END_OF_ROWS;
207
+ }
208
+
209
+ return false ;
210
+ }
211
+
156
212
bool HashJoinIterator::Init () {
157
213
// If we are entirely in-memory and the JOIN we are part of hasn't been
158
214
// asked to clear its hash tables since last time, we can reuse the table
@@ -243,73 +299,35 @@ bool HashJoinIterator::Init() {
243
299
m_tables_to_get_rowid_for);
244
300
245
301
if (m_first_input == HashJoinInput::kProbe ) {
246
- m_state = State::READING_ROW_FROM_PROBE_ITERATOR;
247
-
248
- if (InitProbeIterator ()) {
249
- return true ;
250
- }
251
-
252
- const int result = m_probe_input->Read ();
253
- if (result == 1 ) {
254
- assert (thd ()->is_error () ||
255
- thd ()->killed ); // my_error should have been called.
256
- return true ;
257
- } else if (result == -1 ) {
258
- m_probe_input->EndPSIBatchModeIfStarted ();
259
- m_state = State::END_OF_ROWS;
260
- return false ;
261
- } else {
262
- assert (result == 0 );
263
- m_probe_row_read = true ;
264
- // Prepare to read the build input into the hash map.
265
- PrepareForRequestRowId (m_build_input_tables.tables (),
266
- m_tables_to_get_rowid_for);
267
- if (m_build_input->Init ()) {
268
- assert (thd ()->is_error () ||
269
- thd ()->killed ); // my_error should have been called.
302
+ const bool error = [&]() {
303
+ if (ReadFirstProbeRow ()) {
270
304
return true ;
305
+ } else if (m_state == State::END_OF_ROWS) {
306
+ return false ;
307
+ } else {
308
+ return m_build_input->Init () || InitHashTable ();
271
309
}
272
- }
273
- }
310
+ }();
274
311
275
- // Build the hash table
276
- if (BuildHashTable ()) {
277
- assert (thd ()->is_error () ||
312
+ assert (!error || thd ()->is_error () ||
278
313
thd ()->killed ); // my_error should have been called.
279
- if (m_first_input == HashJoinInput::kProbe ) {
280
- m_probe_input->EndPSIBatchModeIfStarted ();
281
- }
282
- return true ;
283
- }
284
- if (m_hash_table_generation != nullptr ) {
285
- m_last_hash_table_generation = *m_hash_table_generation;
286
- }
287
314
288
- if (m_state == State::END_OF_ROWS) {
289
- // BuildHashTable() decided that the join is done (the build input is
290
- // empty, and we are in an inner-/semijoin. Anti-/outer join must output
291
- // NULL-complemented rows from the probe input).
292
- if (m_first_input == HashJoinInput::kProbe ) {
315
+ if (m_state == State::END_OF_ROWS || error) {
293
316
m_probe_input->EndPSIBatchModeIfStarted ();
294
317
}
295
- return false ;
296
- }
297
318
298
- if (m_join_type == JoinType::ANTI && m_join_conditions.empty () &&
299
- m_extra_condition == nullptr && !m_row_buffer.empty ()) {
300
- // For degenerate antijoins, we know we will never output anything
301
- // if there's anything in the hash table, so we can end right away.
302
- // (We also don't need to read more than one row, but
303
- // CreateHashJoinAccessPath() has already added a LIMIT 1 for us
304
- // in this case.)
305
- if (m_first_input == HashJoinInput::kProbe ) {
306
- m_probe_input->EndPSIBatchModeIfStarted ();
319
+ return error;
320
+
321
+ } else { // Start with 'build' input.
322
+ if (InitHashTable ()) {
323
+ assert (thd ()->is_error () ||
324
+ thd ()->killed ); // my_error should have been called.
325
+
326
+ return true ;
307
327
}
308
- m_state = State::END_OF_ROWS;
309
- return false ;
310
- }
311
328
312
- return m_first_input == HashJoinInput::kProbe ? false : InitProbeIterator ();
329
+ return m_state == State::END_OF_ROWS ? false : InitProbeIterator ();
330
+ }
313
331
}
314
332
315
333
// Construct a join key from a list of join conditions, where the join key from
0 commit comments