Skip to content

Commit

Permalink
Make SQLServer join work (#11511)
Browse files Browse the repository at this point in the history
* Make join work

* Code Review Changes
  • Loading branch information
AdRiley authored Nov 8, 2024
1 parent a6460c1 commit 29faf20
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,7 @@ type SQLServer_Dialect
Feature.Select_Columns -> True
Feature.Sort -> True
Feature.Filter -> True
Feature.Join -> True
_ -> False

## PRIVATE
Expand Down Expand Up @@ -357,16 +358,17 @@ private _generate_expression dialect base_gen expr expression_kind:Expression_Ki
SQL_Expression.Operation op_kind arguments metadata ->
op = dialect.dialect_operations.operations_dict.get op_kind (Error.throw <| Unsupported_Database_Operation.Error op_kind)
expected_kind = _op_expected_kind op_kind
parsed_args_and_null_checks = arguments.map (c -> _generate_expression dialect base_gen c expected_kind)
materialize_child_null_check = _op_needs_to_materialize_null_checks op_kind
parsed_args_and_null_checks = arguments.map (c -> _generate_expression dialect base_gen c expected_kind materialize_child_null_check)
parsed_args = parsed_args_and_null_checks.map .first
null_checks = parsed_args_and_null_checks.map .second . flatten

## In the case that we actually want to check for null then we need to generate the null
check sql for all the columns that have been used up to this point and that
becomes the expression.
check sql for all the columns that have been used up to this point and that
becomes the expression.
expr_result = if op_kind == "IS_NULL" then _generate_is_null_expr null_checks else
base_gen.apply_op_generator_with_metadata op parsed_args metadata
null_checks_result = if op_kind == "IS_NULL" then [] else null_checks
null_checks_result = if op_kind == "IS_NULL" || materialize_child_null_check then [] else null_checks
has_kind = _op_return_kind op_kind
converted_expr = _align_type expr_result has_kind expression_kind
final_expr = if materialize_null_check then _generate_null_check_sql_builder null_checks_result converted_expr else
Expand Down Expand Up @@ -406,6 +408,9 @@ private _op_return_kind op -> Expression_Kind =
return_bool_ops = ["NOT", "BETWEEN", ">=", ">", "<=", "<", "!=", "==", "IN", "IS_NULL", "LIKE", "STARTS_WITH", "ENDS_WITH", "CONTAINS", "EQUALS_IGNORE_CASE", "IS_EMPTY"]
if return_bool_ops.contains op then Expression_Kind.Boolean_Condition else Expression_Kind.Value

private _op_needs_to_materialize_null_checks op -> Boolean =
["FILL_NULL", "COALESCE"].contains op

## PRIVATE
make_dialect_operations =
cases = [["LOWER", Base_Generator.make_function "LOWER"], ["UPPER", Base_Generator.make_function "UPPER"]]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import project.Common_Table_Operations.Util
main filter=Nothing = run_default_backend add_specs filter

add_specs suite_builder setup =
if setup.is_feature_supported ..Column_Operations then (add_coalesce_specs suite_builder setup)
if setup.is_operation_supported "COALESCE" then (add_coalesce_specs suite_builder setup)

add_coalesce_specs suite_builder setup =
prefix = setup.prefix
Expand Down
56 changes: 39 additions & 17 deletions test/Table_Tests/src/Common_Table_Operations/Join/Join_Spec.enso
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ add_join_specs suite_builder setup =
group_builder.specify "should correctly handle duplicated rows in Equals" <|
t1 = table_builder [["X", [1, 2, 2, 3]]]
t2 = table_builder [["X", [1, 2, 2, 4]]]
r1 = t1.join t2 join_kind=Join_Kind.Full on="X" . sort "X"
r1 = t1.join t2 join_kind=Join_Kind.Full on="X" |> materialize |> _.sort "X"
within_table r1 <|
# Both 2's from t1 match with _both_ ones from t2 _each_, so in total we get 4 `2` pairs:
r1.at "X" . to_vector . should_equal [Nothing, 1, 2, 2, 2, 2, 3]
Expand All @@ -144,11 +144,17 @@ add_join_specs suite_builder setup =
t1 = table_builder [["X", ["a", "B"]], ["Y", [1, 2]]]
t2 = table_builder [["X", ["A", "a", "b"]], ["Z", [1, 2, 3]]]

r1 = t1.join t2 join_kind=Join_Kind.Inner
r1 = t1.join t2 join_kind=Join_Kind.Inner |> materialize |> _.sort "Z"
expect_column_names ["X", "Y", "Z"] r1
r1 . at "X" . to_vector . should_equal ["a"]
r1 . at "Y" . to_vector . should_equal [1]
r1 . at "Z" . to_vector . should_equal [2]
case setup.flagged ..Case_Sensitive_Text_Comparison of
True ->
r1 . at "X" . to_vector . should_equal ["a"]
r1 . at "Y" . to_vector . should_equal [1]
r1 . at "Z" . to_vector . should_equal [2]
False ->
r1 . at "X" . to_vector . should_equal ["a", "a", "B"]
r1 . at "Y" . to_vector . should_equal [1, 1, 2]
r1 . at "Z" . to_vector . should_equal [1, 2, 3]

r2 = t1.join t2 join_kind=Join_Kind.Inner on=(Join_Condition.Equals_Ignore_Case "X") |> materialize |> _.sort ["Z"]
expect_column_names ["X", "Y", "Right X", "Z"] r2
Expand All @@ -162,7 +168,7 @@ add_join_specs suite_builder setup =
t1 = table_builder [["X", ['s\u0301', 'S\u0301']], ["Y", [1, 2]]]
t2 = table_builder [["X", ['s', 'S', 'ś']], ["Z", [1, 2, 3]]]

r1 = t1.join t2 join_kind=Join_Kind.Inner
r1 = t1.join t2 join_kind=Join_Kind.Inner |> materialize |> _.sort "Z"
expect_column_names ["X", "Y", "Z"] r1
r1 . at "X" . to_vector . should_equal ['ś']
r1 . at "Y" . to_vector . should_equal [1]
Expand All @@ -180,7 +186,7 @@ add_join_specs suite_builder setup =
t1 = table_builder [["X", [1, 2]], ["Y", [10, 20]]]
t2 = table_builder [["X", [2.0, 2.1, 0.0]], ["Z", [1, 2, 3]]]

r1 = t1.join t2 join_kind=Join_Kind.Inner
r1 = t1.join t2 join_kind=Join_Kind.Inner |> materialize |> _.sort "Z"
expect_column_names ["X", "Y", "Z"] r1
r1 . at "X" . to_vector . should_equal [2]
r1 . at "Y" . to_vector . should_equal [20]
Expand Down Expand Up @@ -272,7 +278,7 @@ add_join_specs suite_builder setup =
# 7. duplicated rows on both sides
t1 = table_builder [["X", [10, 20, 20]]]
t2 = table_builder [["low", [15, 15]], ["high", [30, 30]]]
r1 = t1.join t2 join_kind=Join_Kind.Right_Outer on=(Join_Condition.Between "X" "low" "high")
r1 = t1.join t2 join_kind=Join_Kind.Right_Outer on=(Join_Condition.Between "X" "low" "high") |> materialize
within_table r1 <|
r1.at "X" . to_vector . should_equal [20, 20, 20, 20]
r1.at "low" . to_vector . should_equal [15, 15, 15, 15]
Expand Down Expand Up @@ -497,9 +503,15 @@ add_join_specs suite_builder setup =

r1 = t1.join t2 join_kind=Join_Kind.Inner |> materialize |> _.sort ["Y"]
expect_column_names ["X", "Y", "Z"] r1
r1.at "X" . to_vector . should_equal ["a", "b"]
r1.at "Y" . to_vector . should_equal [2, 5]
r1.at "Z" . to_vector . should_equal [10, 50]
case setup.flagged ..Case_Sensitive_Text_Comparison of
True ->
r1.at "X" . to_vector . should_equal ["a", "b"]
r1.at "Y" . to_vector . should_equal [2, 5]
r1.at "Z" . to_vector . should_equal [10, 50]
False ->
r1.at "X" . to_vector . should_equal ["A", "a", "b"]
r1.at "Y" . to_vector . should_equal [0, 2, 5]
r1.at "Z" . to_vector . should_equal [10, 10, 50]

group_builder.specify "should correctly handle nulls in equality conditions in outer joins" <|
t1 = table_builder [["X", ["A", Nothing, "a", Nothing, "ą", "b"]], ["Y", [0, 1, 2, 3, 4, 5]]]
Expand All @@ -509,7 +521,9 @@ add_join_specs suite_builder setup =
expect_column_names ["X", "Y", "Right X", "Z"] r2
vs2 = r2 . rows . map .to_vector
within_table r2 <|
vs2.at 0 . to_vector . should_equal ["A", 0, Nothing, Nothing]
case setup.flagged ..Case_Sensitive_Text_Comparison of
True -> vs2.at 0 . to_vector . should_equal ["A", 0, Nothing, Nothing]
False -> vs2.at 0 . to_vector . should_equal ["A", 0, 'a', 10]
vs2.at 1 . to_vector . should_equal [Nothing, 1, Nothing, Nothing]
vs2.at 2 . to_vector . should_equal ["a", 2, "a", 10]
vs2.at 3 . to_vector . should_equal [Nothing, 3, Nothing, Nothing]
Expand All @@ -520,11 +534,19 @@ add_join_specs suite_builder setup =
expect_column_names ["X", "Y", "Right X", "Z"] r3
vs3 = r3 . rows . map .to_vector
within_table r3 <|
vs3.at 0 . to_vector . should_equal ["a", 2, "a", 10]
vs3.at 1 . to_vector . should_equal [Nothing, Nothing, Nothing, 20]
vs3.at 2 . to_vector . should_equal [Nothing, Nothing, Nothing, 30]
vs3.at 3 . to_vector . should_equal ["b", 5, "b", 50]

case setup.flagged ..Case_Sensitive_Text_Comparison of
True ->
vs3.at 0 . to_vector . should_equal ["a", 2, "a", 10]
vs3.at 1 . to_vector . should_equal [Nothing, Nothing, Nothing, 20]
vs3.at 2 . to_vector . should_equal [Nothing, Nothing, Nothing, 30]
vs3.at 3 . to_vector . should_equal ["b", 5, "b", 50]
False ->
vs3.at 0 . to_vector . should_equal ["A", 0, "a", 10]
vs3.at 1 . to_vector . should_equal ["a", 2, "a", 10]
vs3.at 2 . to_vector . should_equal [Nothing, Nothing, Nothing, 20]
vs3.at 3 . to_vector . should_equal [Nothing, Nothing, Nothing, 30]
vs3.at 4 . to_vector . should_equal ["b", 5, "b", 50]

group_builder.specify "should correctly handle nulls in case-insensitive equality conditions" <|
t1 = table_builder [["X", ["A", Nothing, "a", Nothing, "ą", "b"]], ["Y", [0, 1, 2, 3, 4, 5]]]
t2 = table_builder [["X", ["a", Nothing, Nothing, "b"]], ["Z", [10, 20, 30, 50]]]
Expand Down

0 comments on commit 29faf20

Please sign in to comment.