Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding support for equi-join on struct #7720

Merged
merged 196 commits into from
Apr 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
196 commits
Select commit Hold shift + click to select a range
4a4b4af
Merge branch 'branch-0.17' into branch-0.18
shwina Dec 11, 2020
223f2b5
Merge branch 'branch-0.18' of https://github.com/rapidsai/cudf into b…
shwina Dec 15, 2020
abd6ad2
Merge branch 'branch-0.18' of https://github.com/rapidsai/cudf into b…
shwina Dec 17, 2020
18863b5
Merge branch 'branch-0.18' of https://github.com/rapidsai/cudf into b…
shwina Jan 4, 2021
0fbdd31
Merge branch 'branch-0.18' of https://github.com/rapidsai/cudf into b…
shwina Jan 5, 2021
dc9b943
Merge branch 'branch-0.18' of https://github.com/rapidsai/cudf into b…
shwina Jan 5, 2021
d586aa7
Merge branch 'branch-0.18' of https://github.com/rapidsai/cudf into b…
shwina Jan 7, 2021
996fda8
Merge branch 'branch-0.18' of https://github.com/rapidsai/cudf into b…
shwina Jan 8, 2021
2808a5c
Add a compute_hash_join_indices that returns just the join indices
shwina Jan 11, 2021
ef0baee
Don't need common_columns stuff for join that returns a gathermap
shwina Jan 11, 2021
18f3074
Add hash_join_impl methods that return gathermaps
shwina Jan 11, 2021
70abf48
Add overloads to public hash_join class
shwina Jan 11, 2021
13dff67
Add top-level join APIs that return gathermaps
shwina Jan 11, 2021
3300fe1
Merge branch 'branch-0.18' of https://github.com/rapidsai/cudf into g…
shwina Jan 12, 2021
7ed694c
Use device_uvector instead of device_vector in join
shwina Jan 12, 2021
636c2ea
Undo some API changes
shwina Jan 12, 2021
b79da68
Add join_result
shwina Jan 13, 2021
380aa59
Add APIs that return join_result
shwina Jan 13, 2021
3cbb2b4
Remove column_in_common
shwina Jan 13, 2021
53ae7c9
Add an inner join API that returns gathermaps
shwina Jan 14, 2021
fde172b
Add remaining APIs to return gathermaps
shwina Jan 14, 2021
4a286dd
Add gathermap join test
shwina Jan 18, 2021
c756db9
Replace -1 with INT_MIN
shwina Jan 18, 2021
6a3d23e
Make join_result columns instead of column_views
shwina Jan 20, 2021
5dfc2a0
Replace join_result with a pair of columns
shwina Jan 20, 2021
362829b
Add gathermap test for outer join
shwina Jan 20, 2021
4e4380c
Add and pass full join gathermap test
shwina Jan 20, 2021
339a13d
Begin Python-side refactor
shwina Jan 21, 2021
2b07802
Merge branch 'branch-0.18' of https://github.com/rapidsai/cudf into g…
shwina Jan 25, 2021
0d5a19c
Merge branch 'branch-0.18' of https://github.com/rapidsai/cudf into g…
shwina Jan 28, 2021
fdbdc12
Merge branch 'branch-0.18' of https://github.com/rapidsai/cudf into g…
shwina Feb 1, 2021
5dd5d29
Merge branch 'branch-0.18' of https://github.com/rapidsai/cudf into g…
shwina Feb 5, 2021
6b20429
Merge branch 'branch-0.19' into gathermap-based-join-apis
shwina Feb 8, 2021
044eac1
Add left_semi and left_anti join APIs that return gathermaps
shwina Feb 8, 2021
555d5ec
Add Cython bindings
shwina Feb 8, 2021
56ae616
full -> outer
shwina Feb 9, 2021
dd05121
Merge branch 'branch-0.19' of https://github.com/rapidsai/cudf into g…
shwina Feb 9, 2021
d447924
Progress
shwina Feb 9, 2021
484512e
More progress on py refactor
shwina Feb 9, 2021
5227582
Remove breakpoint
shwina Feb 10, 2021
9cd870e
Fix neg index handling
shwina Feb 10, 2021
8e4f193
Use nullify gather in join
shwina Feb 10, 2021
29fe140
Handle outer joins better
shwina Feb 10, 2021
b634055
Fix index construction
shwina Feb 10, 2021
cd53d6c
Fix sorting behaviour
shwina Feb 10, 2021
75f1efd
Fix Index.join
shwina Feb 10, 2021
1f5d6ad
Progress on semi/anti joins
shwina Feb 10, 2021
de30520
Add simple join test
shwina Feb 10, 2021
66a0de5
Semi-join fix
shwina Feb 11, 2021
ca72295
Only combine key columns in outer join if they have the same name
shwina Feb 11, 2021
ee2242d
Handle when both _on and _index are provided
shwina Feb 11, 2021
e531725
Fix sorting join result
shwina Feb 11, 2021
c8b4948
Merge branch 'branch-0.19' of https://github.com/rapidsai/cudf into g…
shwina Feb 11, 2021
674095c
whitespace
shwina Feb 12, 2021
cbd9dc3
Make construct_join_output_df work with column views
shwina Feb 12, 2021
3f3c3cb
Get rid of hash_join::left_join
shwina Feb 12, 2021
01415fc
More join C++ cleanup
shwina Feb 12, 2021
6185492
Even more cleaning
shwina Feb 17, 2021
d736d1c
More join tests
shwina Feb 18, 2021
b58591d
Fix all join tests
shwina Feb 18, 2021
be560bb
Python regressions
shwina Feb 18, 2021
efb60d6
Revert
shwina Feb 18, 2021
fe6d0b8
Invalid -> Unkown
shwina Feb 18, 2021
547027c
Don't mutate lhs/rhs
shwina Feb 18, 2021
5f93d23
Fix join tests
shwina Feb 19, 2021
b7bf821
Fix semi/anti join trivial cases
shwina Feb 19, 2021
50a2fb2
When testing join results, use a helper that sorts values
shwina Feb 19, 2021
ff0ae79
Totally broken commit
shwina Feb 19, 2021
07cd052
Cleanup
shwina Feb 20, 2021
bd6bf77
Warnings
shwina Feb 20, 2021
a40063e
Cleanup
shwina Feb 22, 2021
ccef9d0
Cleanup
shwina Feb 22, 2021
210244b
Cleanup
shwina Feb 22, 2021
b57348c
Add typing for join helpers
shwina Feb 22, 2021
e19c30c
add struct_compare at row_lexicographic_comparator
karthikeyann Feb 22, 2021
19310e5
add unit test to sort with struct column
karthikeyann Feb 22, 2021
5c2c9b3
Typing for Join class
shwina Feb 22, 2021
558aa15
Simplify joiner API
shwina Feb 22, 2021
3184896
Example doc
shwina Feb 22, 2021
d3535dc
Refactor join APIs to return a device_uvector
shwina Feb 25, 2021
f2e55a7
remove nullable in is_null condition
karthikeyann Feb 26, 2021
0d30d8a
Add null_compare (DRY)
karthikeyann Feb 26, 2021
3b0a2a5
Merge tag 'branch-0.19-latest' of https://github.com/rapidsai/cudf in…
shwina Mar 1, 2021
b82181d
docs
shwina Mar 3, 2021
77d2bfd
Finish up docs?
shwina Mar 3, 2021
bb64b06
remove stale comment
karthikeyann Mar 4, 2021
a79a92a
Merge branch 'branch-0.19' of https://github.com/rapidsai/cudf into f…
karthikeyann Mar 4, 2021
0bf34e8
Merge branch 'branch-0.19' of https://github.com/rapidsai/cudf into g…
shwina Mar 4, 2021
26a3fb0
Fix join tests
shwina Mar 4, 2021
8a60d62
Refactor join APIs to work with unique_ptr<rmm::device_uvector>>
shwina Mar 5, 2021
387a953
Update join Cython
shwina Mar 5, 2021
6cd6433
Need to resize the gathermap
shwina Mar 5, 2021
c67dcce
Doc
shwina Mar 5, 2021
30c22ed
Changelog
shwina Mar 5, 2021
2723ffb
bypass single nested type column to normal sort
karthikeyann Mar 8, 2021
69f37d0
add support for nested struct columns with depth>1
karthikeyann Mar 8, 2021
a8ad736
Merge branch 'branch-0.19' of https://github.com/rapidsai/cudf into f…
karthikeyann Mar 9, 2021
245116b
add struct sort tests
karthikeyann Mar 9, 2021
f73199d
Add helper to convert gather_map_type->Column
shwina Mar 9, 2021
393c06a
Update python/cudf/cudf/core/frame.py
shwina Mar 9, 2021
e91f554
Cannot specify both column and index
shwina Mar 9, 2021
0185896
Vaildate how
shwina Mar 9, 2021
b232f85
Merge branch 'gathermap-based-join-apis' of github.com:shwina/cudf in…
shwina Mar 9, 2021
1eb495d
Can't use a set
shwina Mar 9, 2021
4f1f072
Avoid function local import
shwina Mar 10, 2021
4aa8fec
False -> NotImplementedError
shwina Mar 10, 2021
ae0e5f9
Update cpp/include/cudf/join.hpp
shwina Mar 10, 2021
f47cf7e
Reuse some join logic
shwina Mar 10, 2021
2a201c3
Merge branch 'gathermap-based-join-apis' of github.com:shwina/cudf in…
shwina Mar 10, 2021
230ca08
Formatting
shwina Mar 10, 2021
498a621
Update cpp/include/cudf/join.hpp
shwina Mar 11, 2021
2de26f3
Docs?
shwina Mar 11, 2021
d6f128c
Merge branch 'gathermap-based-join-apis' of github.com:shwina/cudf in…
shwina Mar 11, 2021
b7d8d8a
Use mr
shwina Mar 11, 2021
9efc761
Docs
shwina Mar 15, 2021
bc598a1
remove struct comparator support, add flatten_table
karthikeyann Mar 16, 2021
b1add6a
review comments update
karthikeyann Mar 16, 2021
8779bc7
Simplify suffix handling
shwina Mar 16, 2021
8116c49
fix sliced struct column sort, add unit tests
karthikeyann Mar 16, 2021
496c9ca
move flatten_talbe to structs/utilities.hpp
karthikeyann Mar 16, 2021
aebf4ec
style fixes
karthikeyann Mar 16, 2021
4c651ac
Simplify joiner requirements
shwina Mar 17, 2021
b4f4d7c
Do less work in SemiJoin._merge_results
shwina Mar 17, 2021
d353c92
Doc
shwina Mar 17, 2021
580a346
Doc
shwina Mar 17, 2021
328dafd
Return None from semi_join
shwina Mar 17, 2021
297d20a
Init common_type
shwina Mar 17, 2021
7621d5e
add is_sorted struct support, reorder tuple returned
karthikeyann Mar 19, 2021
320c94b
add is_sorted struct unit tests
karthikeyann Mar 19, 2021
50b862f
add logic_error in row_lexicographic_comparator constructor if columns
karthikeyann Mar 22, 2021
4ce4bae
update copyright year
karthikeyann Mar 23, 2021
76894e1
Partial clean up of ORC writer (#7324)
vuule Mar 4, 2021
cc73af6
Java cleaner synchronization (#7474)
abellina Mar 4, 2021
213f1ad
Change jit launch to safe_launch (#7510)
devavret Mar 4, 2021
d77a393
Add cython for converting strings/fixed-point functions (#7429)
davidwendt Mar 4, 2021
94dd756
JNI: Support skipping nulls for collect aggregation (#7457)
firestarman Mar 5, 2021
520d92c
Rename ARROW_STATIC_LIB because it conflicts with one in FindArrow.cm…
trxcllnt Mar 6, 2021
6f6b5ab
Statistics cleanup (#7439)
kaatish Mar 6, 2021
b7d9d7d
Update JNI build to use CUDF_USE_ARROW_STATIC (#7526)
jlowe Mar 6, 2021
ec90eff
FIX Remove random build directory generation for ccache (#7508)
dillon-cullinan Mar 8, 2021
7b02cb1
Java support for casting of nested child columns (#7417)
razajafri Mar 8, 2021
e6659ca
bitmask_or implementation with bitmask refactor (#7406)
rwlee Mar 8, 2021
6b5b477
Resolving unlinked type shorthands in cudf doc (#7416)
isVoid Mar 8, 2021
c8a8669
Change dask and distributed branch to main (#7532)
dantegd Mar 8, 2021
4f702a0
Add gbenchmarks for strings extract function (#7522)
davidwendt Mar 9, 2021
2d5d5d5
Reduce compile time/size for scan.cu (#7516)
davidwendt Mar 9, 2021
8e76075
fix missing renames of dask git branches from master to main (#7535)
Mar 9, 2021
0784a31
Remove detail from device_span (#7533)
rwlee Mar 9, 2021
75f4db8
Make sure rmm::rmm CMake target is visibile to cudf users (#7524)
robertmaynard Mar 9, 2021
1f89144
FIX Retry conda output location (#7540)
dillon-cullinan Mar 9, 2021
b301977
Decimal32 Build Fix (#7544)
razajafri Mar 9, 2021
22604d7
Update missing docstring examples in python public APIs (#7546)
galipremsagar Mar 10, 2021
af91aca
Enable type conversion from float to decimal type (#7450)
ChrisJar Mar 10, 2021
2f6e019
Update Changelog Link (#7550)
ajschmidt8 Mar 10, 2021
34f6de8
Fix contiguous_split not properly handling output partitions > 2 GB. …
nvdbaranec Mar 10, 2021
4a0be16
FIX Revert gpuci_conda_retry on conda file output locations (#7552)
dillon-cullinan Mar 10, 2021
2818928
Add `Series.drop` api (#7304)
isVoid Mar 10, 2021
0e2736a
Support `Series.__setitem__` with key to a new row (#7443)
isVoid Mar 10, 2021
4d1812f
Fix offset_end iterator for lists_column_view, which was not correctl…
ttnghia Mar 10, 2021
e10fc49
Fix no such file dlpack.h error when build libcudf (#7549)
chenrui17 Mar 10, 2021
8ea0a7f
Fix index mismatch issue in equality related APIs (#7555)
galipremsagar Mar 10, 2021
0d8db61
FIX Fix Anaconda upload args (#7558)
dillon-cullinan Mar 11, 2021
fa66823
Change device_vector to device_uvector in nvtext source files (#7512)
davidwendt Mar 11, 2021
d0f6c3c
Removed unneeded includes from traits.hpp (#7509)
davidwendt Mar 11, 2021
b7dd2cd
Fix cudf::lists::sort_lists failing for sliced column (#7564)
ttnghia Mar 11, 2021
5752ad3
Remove unneeded step parameter from strings::detail::copy_slice (#7525)
davidwendt Mar 11, 2021
e9e70c1
Another fix for offsets_end() iterator in lists_column_view (#7575)
ttnghia Mar 12, 2021
e373a68
Implement drop_list_duplicates (#7528)
ttnghia Mar 12, 2021
5c5beb1
Fix ORC writer output corruption with string columns (#7565)
vuule Mar 12, 2021
66beb63
Fix missing Dask imports (#7580)
Mar 12, 2021
7d3420a
Add `__repr__` for Column and ColumnAccessor (#7531)
shwina Mar 12, 2021
9db65f8
`fixed_point` + `cudf::binary_operation` API Changes (#7435)
codereport Mar 12, 2021
29f7092
CMAKE_CUDA_ARCHITECTURES doesn't change when build-system invokes cma…
robertmaynard Mar 13, 2021
89377dc
ENH Fix stale GHA and prevent duplicates (#7594)
mike-wendt Mar 14, 2021
cebc67e
Revert "ENH Fix stale GHA and prevent duplicates (#7594)" (#7595)
mike-wendt Mar 14, 2021
a7ff744
Use device_uvector, device_span in sort groupby (#7523)
karthikeyann Mar 15, 2021
6564581
Fix ORC issue with incorrect timestamp nanosecond values (#7581)
vuule Mar 15, 2021
234c562
review comments (code_report)
karthikeyann Mar 23, 2021
106f13b
style fix
karthikeyann Mar 23, 2021
f7ab0d2
name with non-ASCII UTF-8 char
karthikeyann Mar 23, 2021
a83c5d5
Merge branch 'branch-0.19' of https://github.com/rapidsai/cudf into f…
karthikeyann Mar 23, 2021
fcac9ef
merged in join rework
hyperbolic2346 Mar 23, 2021
11b4e8d
add is_relationally_comparable(table_view), review comments
karthikeyann Mar 24, 2021
e76a338
copyright year update
karthikeyann Mar 24, 2021
728ea01
Merge remote-tracking branch 'karthik/fea-sort_struct' into mwilson/s…
hyperbolic2346 Mar 25, 2021
541c38c
Adding support for equijoin on structs
hyperbolic2346 Mar 25, 2021
8f0f2c2
Updating test
hyperbolic2346 Mar 25, 2021
afc4925
Merge branch 'branch-0.19' into mwilson/struct_join
hyperbolic2346 Mar 26, 2021
5154d4e
adding some more struct join tests
hyperbolic2346 Mar 29, 2021
65fcc0e
Merge remote-tracking branch 'upstream/branch-0.19' into mwilson/stru…
hyperbolic2346 Mar 29, 2021
b6fe885
Merge remote-tracking branch 'upstream/branch-0.19' into mwilson/stru…
hyperbolic2346 Mar 30, 2021
2dae5a4
reverting files from branch merging
hyperbolic2346 Mar 30, 2021
3fe20de
fixing merge issue with tests
hyperbolic2346 Mar 30, 2021
681b7af
moving flatten into the hash_join object
hyperbolic2346 Mar 31, 2021
d9a7f52
Merge remote-tracking branch 'upstream/branch-0.19' into mwilson/stru…
hyperbolic2346 Mar 31, 2021
b946217
removing semi_join special code
hyperbolic2346 Mar 31, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 14 additions & 8 deletions cpp/src/join/hash_join.cu
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
#include <thrust/uninitialized_fill.h>
#include <join/hash_join.cuh>
#include <structs/utilities.hpp>

#include <cudf/detail/concatenate.cuh>
#include <cudf/detail/gather.cuh>
Expand Down Expand Up @@ -299,13 +300,15 @@ hash_join::hash_join_impl::~hash_join_impl() = default;
hash_join::hash_join_impl::hash_join_impl(cudf::table_view const &build,
null_equality compare_nulls,
rmm::cuda_stream_view stream)
: _build(build), _hash_table(nullptr)
: _hash_table(nullptr)
{
CUDF_FUNC_RANGE();
CUDF_EXPECTS(0 != _build.num_columns(), "Hash join build table is empty");
CUDF_EXPECTS(_build.num_rows() < cudf::detail::MAX_JOIN_SIZE,
CUDF_EXPECTS(0 != build.num_columns(), "Hash join build table is empty");
CUDF_EXPECTS(build.num_rows() < cudf::detail::MAX_JOIN_SIZE,
"Build column size is too big for hash join");

_build = std::get<0>(structs::detail::flatten_nested_columns(build, {}, {}));

if (0 == build.num_rows()) { return; }

_hash_table = build_join_hash_table(_build, compare_nulls, stream);
Expand Down Expand Up @@ -355,22 +358,25 @@ hash_join::hash_join_impl::compute_hash_join(cudf::table_view const &probe,
CUDF_EXPECTS(0 != probe.num_columns(), "Hash join probe table is empty");
CUDF_EXPECTS(probe.num_rows() < cudf::detail::MAX_JOIN_SIZE,
"Probe column size is too big for hash join");
CUDF_EXPECTS(_build.num_columns() == probe.num_columns(),

auto const _probe = std::get<0>(structs::detail::flatten_nested_columns(probe, {}, {}));

CUDF_EXPECTS(_build.num_columns() == _probe.num_columns(),
"Mismatch in number of columns to be joined on");

if (is_trivial_join(probe, _build, JoinKind)) {
if (is_trivial_join(_probe, _build, JoinKind)) {
return std::make_pair(std::make_unique<rmm::device_uvector<size_type>>(0, stream, mr),
std::make_unique<rmm::device_uvector<size_type>>(0, stream, mr));
}

CUDF_EXPECTS(std::equal(std::cbegin(_build),
std::cend(_build),
std::cbegin(probe),
std::cend(probe),
std::cbegin(_probe),
std::cend(_probe),
[](const auto &b, const auto &p) { return b.type() == p.type(); }),
"Mismatch in joining column data types");

return probe_join_indices<JoinKind>(probe, compare_nulls, stream, mr);
return probe_join_indices<JoinKind>(_probe, compare_nulls, stream, mr);
}

template <cudf::detail::join_kind JoinKind>
Expand Down
300 changes: 300 additions & 0 deletions cpp/tests/join/join_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,97 @@ TEST_F(JoinTest, LeftJoinWithNulls)
CUDF_TEST_EXPECT_TABLES_EQUIVALENT(*sorted_gold, *sorted_result);
}

TEST_F(JoinTest, LeftJoinWithStructsAndNulls)
{
column_wrapper<int32_t> col0_0{{3, 1, 2, 0, 2}};
strcol_wrapper col0_1({"s1", "s1", "", "s4", "s0"}, {1, 1, 0, 1, 1});
column_wrapper<int32_t> col0_2{{0, 1, 2, 4, 1}};
auto col0_names_col = strcol_wrapper{
"Samuel Vimes", "Carrot Ironfoundersson", "Detritus", "Samuel Vimes", "Angua von Überwald"};
auto col0_ages_col = column_wrapper<int32_t>{{48, 27, 351, 31, 25}};

auto col0_is_human_col = column_wrapper<bool>{{true, true, false, false, false}, {1, 1, 0, 1, 0}};

auto col0_3 =
cudf::test::structs_column_wrapper{{col0_names_col, col0_ages_col, col0_is_human_col}};

column_wrapper<int32_t> col1_0{{2, 2, 0, 4, 3}};
strcol_wrapper col1_1({"s1", "s0", "s1", "s2", "s1"});
column_wrapper<int32_t> col1_2{{1, 0, 1, 2, 1}, {1, 0, 1, 1, 1}};
auto col1_names_col = strcol_wrapper{
"Samuel Vimes", "Detritus", "Detritus", "Carrot Ironfoundersson", "Angua von Überwald"};
auto col1_ages_col = column_wrapper<int32_t>{{48, 35, 351, 22, 25}};

auto col1_is_human_col = column_wrapper<bool>{{true, true, false, false, true}, {1, 1, 0, 1, 1}};

auto col1_3 =
cudf::test::structs_column_wrapper{{col1_names_col, col1_ages_col, col1_is_human_col}};

CVector cols0, cols1;
cols0.push_back(col0_0.release());
cols0.push_back(col0_1.release());
cols0.push_back(col0_2.release());
cols0.push_back(col0_3.release());
cols1.push_back(col1_0.release());
cols1.push_back(col1_1.release());
cols1.push_back(col1_2.release());
cols1.push_back(col1_3.release());

Table t0(std::move(cols0));
Table t1(std::move(cols1));

auto result = cudf::left_join(t0, t1, {3}, {3});
auto result_sort_order = cudf::sorted_order(result->view());
auto sorted_result = cudf::gather(result->view(), *result_sort_order);

column_wrapper<int32_t> col_gold_0{{3, 2, 1, 0, 2}, {1, 1, 1, 1, 1}};
strcol_wrapper col_gold_1({"s1", "", "s1", "s4", "s0"}, {1, 0, 1, 1, 1});
column_wrapper<int32_t> col_gold_2{{0, 2, 1, 4, 1}, {1, 1, 1, 1, 1}};
auto col0_gold_names_col = strcol_wrapper{
"Samuel Vimes", "Detritus", "Carrot Ironfoundersson", "Samuel Vimes", "Angua von Überwald"};
auto col0_gold_ages_col = column_wrapper<int32_t>{{48, 351, 27, 31, 25}};

auto col0_gold_is_human_col =
column_wrapper<bool>{{true, false, true, false, false}, {1, 0, 1, 1, 0}};

auto col_gold_3 = cudf::test::structs_column_wrapper{
{col0_gold_names_col, col0_gold_ages_col, col0_gold_is_human_col}};

column_wrapper<int32_t> col_gold_4{{2, 0, -1, -1, -1}, {1, 1, 0, 0, 0}};
strcol_wrapper col_gold_5{{"s1", "s1", "", "", ""}, {1, 1, 0, 0, 0}};
column_wrapper<int32_t> col_gold_6{{1, 1, -1, -1, -1}, {1, 1, 0, 0, 0}};
auto col1_gold_names_col = strcol_wrapper{{
"Samuel Vimes",
"Detritus",
"",
"",
"",
},
{1, 1, 0, 0, 0}};
auto col1_gold_ages_col = column_wrapper<int32_t>{{48, 351, -1, -1, -1}, {1, 1, 0, 0, 0}};

auto col1_gold_is_human_col =
column_wrapper<bool>{{true, false, false, false, false}, {1, 0, 0, 0, 0}};

auto col_gold_7 = cudf::test::structs_column_wrapper{
{col1_gold_names_col, col1_gold_ages_col, col1_gold_is_human_col}, {1, 1, 0, 0, 0}};

CVector cols_gold;
cols_gold.push_back(col_gold_0.release());
cols_gold.push_back(col_gold_1.release());
cols_gold.push_back(col_gold_2.release());
cols_gold.push_back(col_gold_3.release());
cols_gold.push_back(col_gold_4.release());
cols_gold.push_back(col_gold_5.release());
cols_gold.push_back(col_gold_6.release());
cols_gold.push_back(col_gold_7.release());
Table gold(std::move(cols_gold));

auto gold_sort_order = cudf::sorted_order(gold.view());
auto sorted_gold = cudf::gather(gold.view(), *gold_sort_order);
CUDF_TEST_EXPECT_TABLES_EQUIVALENT(*sorted_gold, *sorted_result);
}

TEST_F(JoinTest, LeftJoinOnNulls)
{
// clang-format off
Expand Down Expand Up @@ -629,6 +720,91 @@ TEST_F(JoinTest, InnerJoinWithNulls)
CUDF_TEST_EXPECT_TABLES_EQUIVALENT(*sorted_gold, *sorted_result);
}

TEST_F(JoinTest, InnerJoinWithStructsAndNulls)
{
column_wrapper<int32_t> col0_0{{3, 1, 2, 0, 2}};
strcol_wrapper col0_1({"s1", "s1", "s0", "s4", "s0"}, {1, 1, 0, 1, 1});
column_wrapper<int32_t> col0_2{{0, 1, 2, 4, 1}};
std::initializer_list<std::string> col0_names = {
"Samuel Vimes", "Carrot Ironfoundersson", "Detritus", "Samuel Vimes", "Angua von Überwald"};
auto col0_names_col = strcol_wrapper{col0_names.begin(), col0_names.end()};
auto col0_ages_col = column_wrapper<int32_t>{{48, 27, 351, 31, 25}};

auto col0_is_human_col = column_wrapper<bool>{{true, true, false, false, false}, {1, 1, 0, 1, 0}};

auto col0_3 =
cudf::test::structs_column_wrapper{{col0_names_col, col0_ages_col, col0_is_human_col}};

column_wrapper<int32_t> col1_0{{2, 2, 0, 4, 3}};
strcol_wrapper col1_1({"s1", "s0", "s1", "s2", "s1"});
column_wrapper<int32_t> col1_2{{1, 0, 1, 2, 1}, {1, 0, 1, 1, 1}};
std::initializer_list<std::string> col1_names = {"Carrot Ironfoundersson",
"Angua von Überwald",
"Detritus",
"Carrot Ironfoundersson",
"Samuel Vimes"};
auto col1_names_col = strcol_wrapper{col1_names.begin(), col1_names.end()};
auto col1_ages_col = column_wrapper<int32_t>{{351, 25, 27, 31, 48}};

auto col1_is_human_col = column_wrapper<bool>{{true, false, false, false, true}, {1, 0, 0, 1, 1}};

auto col1_3 =
cudf::test::structs_column_wrapper{{col1_names_col, col1_ages_col, col1_is_human_col}};

CVector cols0, cols1;
cols0.push_back(col0_0.release());
cols0.push_back(col0_1.release());
cols0.push_back(col0_2.release());
cols0.push_back(col0_3.release());
cols1.push_back(col1_0.release());
cols1.push_back(col1_1.release());
cols1.push_back(col1_2.release());
cols1.push_back(col1_3.release());

Table t0(std::move(cols0));
Table t1(std::move(cols1));

auto result = cudf::inner_join(t0, t1, {0, 1, 3}, {0, 1, 3});
auto result_sort_order = cudf::sorted_order(result->view());
auto sorted_result = cudf::gather(result->view(), *result_sort_order);

column_wrapper<int32_t> col_gold_0{{3, 2}};
strcol_wrapper col_gold_1({"s1", "s0"}, {1, 1});
column_wrapper<int32_t> col_gold_2{{0, 1}};
auto col_gold_3_names_col = strcol_wrapper{"Samuel Vimes", "Angua von Überwald"};
auto col_gold_3_ages_col = column_wrapper<int32_t>{{48, 25}};

auto col_gold_3_is_human_col = column_wrapper<bool>{{true, false}, {1, 0}};

auto col_gold_3 = cudf::test::structs_column_wrapper{
{col_gold_3_names_col, col_gold_3_ages_col, col_gold_3_is_human_col}};

column_wrapper<int32_t> col_gold_4{{3, 2}};
strcol_wrapper col_gold_5({"s1", "s0"}, {1, 1});
column_wrapper<int32_t> col_gold_6{{1, -1}, {1, 0}};
auto col_gold_7_names_col = strcol_wrapper{"Samuel Vimes", "Angua von Überwald"};
auto col_gold_7_ages_col = column_wrapper<int32_t>{{48, 25}};

auto col_gold_7_is_human_col = column_wrapper<bool>{{true, false}, {1, 0}};

auto col_gold_7 = cudf::test::structs_column_wrapper{
{col_gold_7_names_col, col_gold_7_ages_col, col_gold_7_is_human_col}};
CVector cols_gold;
cols_gold.push_back(col_gold_0.release());
cols_gold.push_back(col_gold_1.release());
cols_gold.push_back(col_gold_2.release());
cols_gold.push_back(col_gold_3.release());
cols_gold.push_back(col_gold_4.release());
cols_gold.push_back(col_gold_5.release());
cols_gold.push_back(col_gold_6.release());
cols_gold.push_back(col_gold_7.release());
Table gold(std::move(cols_gold));

auto gold_sort_order = cudf::sorted_order(gold.view());
auto sorted_gold = cudf::gather(gold.view(), *gold_sort_order);
CUDF_TEST_EXPECT_TABLES_EQUIVALENT(*sorted_gold, *sorted_result);
}

// // Test to check join behaviour when join keys are null.
TEST_F(JoinTest, InnerJoinOnNulls)
{
Expand Down Expand Up @@ -1359,4 +1535,128 @@ TEST_F(JoinDictionaryTest, FullJoinWithNulls)
CUDF_TEST_EXPECT_TABLES_EQUIVALENT(*gold, cudf::table_view(result_decoded));
}

TEST_F(JoinTest, FullJoinWithStructsAndNulls)
{
column_wrapper<int32_t> col0_0{{3, 1, 2, 0, 3}};
strcol_wrapper col0_1({"s0", "s1", "s2", "s4", "s1"});
column_wrapper<int32_t> col0_2{{0, 1, 2, 4, 1}};

std::initializer_list<std::string> col0_names = {"Samuel Vimes",
"Carrot Ironfoundersson",
"Angua von Überwald",
"Detritus",
"Carrot Ironfoundersson"};
auto col0_names_col = strcol_wrapper{col0_names.begin(), col0_names.end()};
auto col0_ages_col = column_wrapper<int32_t>{{48, 27, 25, 31, 351}};

auto col0_is_human_col = column_wrapper<bool>{{true, true, false, false, false}, {1, 1, 0, 1, 1}};

auto col0_3 =
cudf::test::structs_column_wrapper{{col0_names_col, col0_ages_col, col0_is_human_col}};

column_wrapper<int32_t> col1_0{{2, 2, 0, 4, 3}, {1, 1, 1, 0, 1}};
strcol_wrapper col1_1{{"s1", "s0", "s1", "s2", "s1"}};
column_wrapper<int32_t> col1_2{{1, 0, 1, 2, 1}};

std::initializer_list<std::string> col1_names = {"Carrot Ironfoundersson",
"Samuel Vimes",
"Carrot Ironfoundersson",
"Angua von Überwald",
"Carrot Ironfoundersson"};
auto col1_names_col = strcol_wrapper{col1_names.begin(), col1_names.end()};
auto col1_ages_col = column_wrapper<int32_t>{{27, 48, 27, 25, 27}};

auto col1_is_human_col = column_wrapper<bool>{{true, true, true, false, true}, {1, 1, 1, 0, 1}};

auto col1_3 =
cudf::test::structs_column_wrapper{{col1_names_col, col1_ages_col, col1_is_human_col}};

CVector cols0, cols1;
cols0.push_back(col0_0.release());
cols0.push_back(col0_1.release());
cols0.push_back(col0_2.release());
cols0.push_back(col0_3.release());
cols1.push_back(col1_0.release());
cols1.push_back(col1_1.release());
cols1.push_back(col1_2.release());
cols1.push_back(col1_3.release());

Table t0(std::move(cols0));
Table t1(std::move(cols1));

auto result = cudf::full_join(t0, t1, {0, 1, 3}, {0, 1, 3});
auto result_sort_order = cudf::sorted_order(result->view());
auto sorted_result = cudf::gather(result->view(), *result_sort_order);

column_wrapper<int32_t> col_gold_0{{3, 1, 2, 0, 3, -1, -1, -1, -1, -1},
{1, 1, 1, 1, 1, 0, 0, 0, 0, 0}};
strcol_wrapper col_gold_1({"s0", "s1", "s2", "s4", "s1", "", "", "", "", ""},
{1, 1, 1, 1, 1, 0, 0, 0, 0, 0});
column_wrapper<int32_t> col_gold_2{{0, 1, 2, 4, 1, -1, -1, -1, -1, -1},
{1, 1, 1, 1, 1, 0, 0, 0, 0, 0}};
auto gold_names0_col = strcol_wrapper{{"Samuel Vimes",
"Carrot Ironfoundersson",
"Angua von Überwald",
"Detritus",
"Carrot Ironfoundersson",
"",
"",
"",
"",
""},
{1, 1, 1, 1, 1, 0, 0, 0, 0, 0}};
auto gold_ages0_col = column_wrapper<int32_t>{{48, 27, 25, 31, 351, -1, -1, -1, -1, -1},
{1, 1, 1, 1, 1, 0, 0, 0, 0, 0}};

auto gold_is_human0_col =
column_wrapper<bool>{{true, true, false, false, false, false, false, false, false, false},
{1, 1, 0, 1, 1, 0, 0, 0, 0, 0}};

auto col_gold_3 = cudf::test::structs_column_wrapper{
{gold_names0_col, gold_ages0_col, gold_is_human0_col}, {1, 1, 1, 1, 1, 0, 0, 0, 0, 0}};

column_wrapper<int32_t> col_gold_4{{-1, -1, -1, -1, -1, 3, 2, 2, 0, 4},
{0, 0, 0, 0, 0, 1, 1, 1, 1, 0}};
strcol_wrapper col_gold_5({"", "", "", "", "", "s1", "s1", "s0", "s1", "s2"},
{0, 0, 0, 0, 0, 1, 1, 1, 1, 1});
column_wrapper<int32_t> col_gold_6{{-1, -1, -1, -1, -1, 1, 1, 0, 1, 2},
{0, 0, 0, 0, 0, 1, 1, 1, 1, 1}};
auto gold_names1_col = strcol_wrapper{{"",
"",
"",
"",
"",
"Carrot Ironfoundersson",
"Carrot Ironfoundersson",
"Samuel Vimes",
"Carrot Ironfoundersson",
"Angua von Überwald"},
{0, 0, 0, 0, 0, 1, 1, 1, 1, 1}};
auto gold_ages1_col = column_wrapper<int32_t>{{-1, -1, -1, -1, -1, 27, 27, 48, 27, 25},
{0, 0, 0, 0, 0, 1, 1, 1, 1, 1}};

auto gold_is_human1_col =
column_wrapper<bool>{{false, false, false, false, false, true, true, true, true, false},
{0, 0, 0, 0, 0, 1, 1, 1, 1, 0}};

auto col_gold_7 = cudf::test::structs_column_wrapper{
{gold_names1_col, gold_ages1_col, gold_is_human1_col}, {0, 0, 0, 0, 0, 1, 1, 1, 1, 1}};

CVector cols_gold;
cols_gold.push_back(col_gold_0.release());
cols_gold.push_back(col_gold_1.release());
cols_gold.push_back(col_gold_2.release());
cols_gold.push_back(col_gold_3.release());
cols_gold.push_back(col_gold_4.release());
cols_gold.push_back(col_gold_5.release());
cols_gold.push_back(col_gold_6.release());
cols_gold.push_back(col_gold_7.release());

Table gold(std::move(cols_gold));

auto gold_sort_order = cudf::sorted_order(gold.view());
auto sorted_gold = cudf::gather(gold.view(), *gold_sort_order);
CUDF_TEST_EXPECT_TABLES_EQUIVALENT(*sorted_gold, *sorted_result);
}

CUDF_TEST_PROGRAM_MAIN()