@@ -8529,6 +8529,104 @@ TEST_P(HashJoinTest, arrayBasedLookupCustomComparisonType) {
85298529 EXPECT_EQ (result->size (), 1'024 );
85308530}
85318531
8532+ DEBUG_ONLY_TEST_P (HashJoinTest, reuseHashTable) {
8533+ // Create build and probe vectors.
8534+ std::vector<RowVectorPtr> buildVectors = makeBatches (1 , [&](int32_t ) {
8535+ return makeRowVector (
8536+ {" u_0" },
8537+ {
8538+ makeFlatVector<int64_t >(100 , [](auto row) { return row % 23 ; }),
8539+ });
8540+ });
8541+
8542+ std::vector<RowVectorPtr> probeVectors = makeBatches (5 , [&](int32_t ) {
8543+ return makeRowVector (
8544+ {" t_0" },
8545+ {
8546+ makeFlatVector<int64_t >(100 , [](auto row) { return row % 23 ; }),
8547+ });
8548+ });
8549+
8550+ createDuckDbTable (" t" , probeVectors);
8551+ createDuckDbTable (" u" , buildVectors);
8552+
8553+ auto planNodeIdGenerator = std::make_shared<core::PlanNodeIdGenerator>();
8554+ auto buildPlanNode =
8555+ PlanBuilder (planNodeIdGenerator).values (buildVectors).planNode ();
8556+ auto probePlanNode =
8557+ PlanBuilder (planNodeIdGenerator).values (probeVectors).planNode ();
8558+
8559+ auto outputType = ROW ({" t_0" , " u_0" }, {BIGINT (), BIGINT ()});
8560+
8561+ // Build the HashTable for build side data
8562+ std::vector<std::unique_ptr<VectorHasher>> hashers;
8563+ hashers.push_back (std::make_unique<VectorHasher>(BIGINT (), 0 ));
8564+
8565+ std::shared_ptr<facebook::velox::exec::BaseHashTable> table =
8566+ HashTable<false >::createForJoin (
8567+ std::move (hashers),
8568+ {}, /* dependentTypes*/
8569+ true /* allowDuplicates*/ ,
8570+ true /* hasProbedFlag*/ ,
8571+ 1 /* minTableSizeForParallelJoinBuild*/ ,
8572+ pool ());
8573+
8574+ auto rowContainer = table->rows ();
8575+ uint32_t numColumns = buildVectors[0 ]->childrenSize ();
8576+ std::vector<DecodedVector> decodedVectors;
8577+ decodedVectors.reserve (numColumns);
8578+ for (const auto & rowVector : buildVectors) {
8579+ if (!rowVector || rowVector->size () == 0 )
8580+ continue ;
8581+
8582+ decodedVectors.clear ();
8583+ SelectivityVector rows (rowVector->size ());
8584+ for (auto & child : rowVector->children ()) {
8585+ decodedVectors.emplace_back (*child, rows);
8586+ }
8587+
8588+ for (auto i = 0 ; i < rowVector->size (); ++i) {
8589+ auto * row = rowContainer->newRow ();
8590+ for (auto j = 0 ; j < numColumns; ++j) {
8591+ rowContainer->store (decodedVectors[j], i, row, j);
8592+ }
8593+ }
8594+ }
8595+
8596+ table->prepareJoinTable (
8597+ {}, BaseHashTable::kNoSpillInputStartPartitionBit , 1'000'000 );
8598+
8599+ auto opaqueSharedHashTable = std::shared_ptr<core::OpaqueHashTable>(
8600+ table, reinterpret_cast <core::OpaqueHashTable*>(table.get ()));
8601+
8602+ auto joinNode =
8603+ core::HashJoinNode::Builder ()
8604+ .id (planNodeIdGenerator->next ())
8605+ .joinType (core::JoinType::kInner )
8606+ .nullAware (false )
8607+ .leftKeys (
8608+ {std::make_shared<core::FieldAccessTypedExpr>(INTEGER (), " t_0" )})
8609+ .rightKeys (
8610+ {std::make_shared<core::FieldAccessTypedExpr>(INTEGER (), " u_0" )})
8611+ .left (probePlanNode)
8612+ .right (buildPlanNode)
8613+ .outputType (outputType)
8614+ .reusableHashTable (opaqueSharedHashTable)
8615+ .build ();
8616+
8617+ std::atomic_bool reusedHashTable{false };
8618+ SCOPED_TESTVALUE_SET (
8619+ " facebook::velox::exec::HashBuild::HashBuild" ,
8620+ std::function<void (HashBuild*)>(
8621+ [&](HashBuild* windowBuild) { reusedHashTable.store (true ); }));
8622+
8623+ auto task =
8624+ AssertQueryBuilder (joinNode, duckDbQueryRunner_)
8625+ .maxDrivers (1 )
8626+ .assertResults (" SELECT t.t_0, u.u_0 FROM t, u WHERE t.t_0 = u.u_0" );
8627+ ASSERT_TRUE (reusedHashTable.load ());
8628+ }
8629+
85328630DEBUG_ONLY_TEST_P (
85338631 HashJoinTest,
85348632 hashProbeShouldYieldWhenFilterConsistentlyRejectAll) {
0 commit comments