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

Add COALESCE and NULLIF to the logical plan #1404

Merged
merged 3 commits into from
Mar 29, 2024

Conversation

alancai98
Copy link
Member

@alancai98 alancai98 commented Mar 28, 2024

Relevant Issues

Related to partiql/partiql-scribe#26.

Description

Previous rewrite according to SQL-99 spec was creating large logical plans with nested COALESCE and NULLIF expressions. This change makes dedicated COALESCE and NULLIF nodes within the logical plan.

Other than that,

Other Information

  • Updated Unreleased Section in CHANGELOG: [YES]

  • Any backward-incompatible changes? [YES]

Adding new nodes to the plan is technically a breaking change for the PlanVisitor interface. Tracking the sprout generation to add a warning on the interface as a separate issue -- #1405.

License Information

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@alancai98 alancai98 self-assigned this Mar 28, 2024
Copy link

github-actions bot commented Mar 28, 2024

Conformance comparison report

Base (6fbfa78) 6646bd2 +/-
% Passing 92.54% 92.54% 0.00%
✅ Passing 5384 5384 0
❌ Failing 434 434 0
🔶 Ignored 0 0 0
Total Tests 5818 5818 0

Number passing in both: 5384

Number failing in both: 434

Number passing in Base (6fbfa78) but now fail: 0

Number failing in Base (6fbfa78) but now pass: 0

@codecov-commenter
Copy link

codecov-commenter commented Mar 28, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 73.14%. Comparing base (5bcde13) to head (b178180).
Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff            @@
##               main    #1404   +/-   ##
=========================================
  Coverage     73.14%   73.14%           
  Complexity     2393     2393           
=========================================
  Files           247      247           
  Lines         17623    17623           
  Branches       3176     3176           
=========================================
  Hits          12890    12890           
  Misses         3856     3856           
  Partials        877      877           
Flag Coverage Δ
CLI 11.82% <ø> (ø)
EXAMPLES 80.07% <ø> (ø)
LANG 81.04% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

val v2 = visitRex(node.v2, node.v2.type)
val typer = DynamicTyper()
typer.accumulate(NULL)
typer.accumulate(v1.type)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only add v1's type here. I found that posgresql actually does something different here. Per their docs:

The result has the same type as the first argument — but there is a subtlety. What is actually returned is the first argument of the implied = operator, and in some cases that will have been promoted to match the second argument's type. For example, NULLIF(1, 2.2) yields numeric, because there is no integer = numeric operator, only numeric = numeric.

Per my read of SQL-99, I can't find any mention of this promotion behavior, so leaving the result type as just the minimal common supertype of (<type v1>, null). Postgresql would do something like the minimal common supertype of (<type v1>, <type v2>, null).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we can skip the dynamic typer here. It's just type of union(v1, null).flatten() or something as simple as that

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I'll simplify it. I initially included the dynamic typer in case we wanted to follow what postgresql did, which is easy to do w/ the dynamic typer.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Followup from offline discussion, will keep the dynamic typer here to ensure consistency with the typing of CASE WHEN and COALESCE.

Copy link
Member

@RCHowell RCHowell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall looks good and is very straightforward. Only suggestion is to update the nullif names and simplify the typing logic.

val v2 = visitRex(node.v2, node.v2.type)
val typer = DynamicTyper()
typer.accumulate(NULL)
typer.accumulate(v1.type)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we can skip the dynamic typer here. It's just type of union(v1, null).flatten() or something as simple as that

@alancai98 alancai98 requested a review from RCHowell March 29, 2024 20:42
@alancai98 alancai98 merged commit 92cc57a into main Mar 29, 2024
10 checks passed
@alancai98 alancai98 deleted the add-coalesce-nullif-to-plan branch March 29, 2024 22:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants