-
Notifications
You must be signed in to change notification settings - Fork 28.9k
[SPARK-12054] [SQL] Consider nullability of expression in codegen #10333
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
Changes from all commits
8956204
ddca7e2
8304251
7e1b5e0
e3cccda
2cca3a1
7e300b7
8aa8bb5
f160069
fd4c945
88b2107
e418358
765f735
9adad17
7e5381b
55bb6a9
9f7d763
3b1e42f
3cc4cdf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -340,14 +340,21 @@ abstract class UnaryExpression extends Expression { | |
| ev: GeneratedExpressionCode, | ||
| f: String => String): String = { | ||
| val eval = child.gen(ctx) | ||
| val resultCode = f(eval.value) | ||
| eval.code + s""" | ||
| boolean ${ev.isNull} = ${eval.isNull}; | ||
| ${ctx.javaType(dataType)} ${ev.value} = ${ctx.defaultValue(dataType)}; | ||
| if (!${ev.isNull}) { | ||
| $resultCode | ||
| } | ||
| """ | ||
| if (nullable) { | ||
| eval.code + s""" | ||
| boolean ${ev.isNull} = ${eval.isNull}; | ||
| ${ctx.javaType(dataType)} ${ev.value} = ${ctx.defaultValue(dataType)}; | ||
| if (!${eval.isNull}) { | ||
| ${f(eval.value)} | ||
| } | ||
| """ | ||
| } else { | ||
| ev.isNull = "false" | ||
| eval.code + s""" | ||
| ${ctx.javaType(dataType)} ${ev.value} = ${ctx.defaultValue(dataType)}; | ||
| ${f(eval.value)} | ||
| """ | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -424,19 +431,30 @@ abstract class BinaryExpression extends Expression { | |
| val eval1 = left.gen(ctx) | ||
| val eval2 = right.gen(ctx) | ||
| val resultCode = f(eval1.value, eval2.value) | ||
| s""" | ||
| ${eval1.code} | ||
| boolean ${ev.isNull} = ${eval1.isNull}; | ||
| ${ctx.javaType(dataType)} ${ev.value} = ${ctx.defaultValue(dataType)}; | ||
| if (!${ev.isNull}) { | ||
| ${eval2.code} | ||
| if (!${eval2.isNull}) { | ||
| $resultCode | ||
| } else { | ||
| ${ev.isNull} = true; | ||
| if (nullable) { | ||
| s""" | ||
| ${eval1.code} | ||
| boolean ${ev.isNull} = ${eval1.isNull}; | ||
| ${ctx.javaType(dataType)} ${ev.value} = ${ctx.defaultValue(dataType)}; | ||
| if (!${ev.isNull}) { | ||
| ${eval2.code} | ||
| if (!${eval2.isNull}) { | ||
| $resultCode | ||
| } else { | ||
| ${ev.isNull} = true; | ||
| } | ||
| } | ||
| } | ||
| """ | ||
| """ | ||
|
|
||
| } else { | ||
| ev.isNull = "false" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this branch necessary? (not suggesting you change it) but does the nullable path collapse correctly if left and right are non nullable? What I mean is: if eval1.isNull and eval2.isNull is always just false, do we get the same behavior as this special casing from the compiler optimizations?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's not necessary (in terms of performance). Compiler can do all these, but not sure how far Janino had achieved on constant folding. We don't need to do this for every expression, but since UnaryExpression/BinaryExpression/TernaryExpression are used by many, this changes may worth it.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In addition to Janino the JIT might also do more constant folding etc, which makes it hard to tell unfortunately. |
||
| s""" | ||
| ${eval1.code} | ||
| ${eval2.code} | ||
| ${ctx.javaType(dataType)} ${ev.value} = ${ctx.defaultValue(dataType)}; | ||
| $resultCode | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. are we assuming if a
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should forbid non-nullable
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe we can add an assert:
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Even |
||
| """ | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -548,20 +566,31 @@ abstract class TernaryExpression extends Expression { | |
| f: (String, String, String) => String): String = { | ||
| val evals = children.map(_.gen(ctx)) | ||
| val resultCode = f(evals(0).value, evals(1).value, evals(2).value) | ||
| s""" | ||
| ${evals(0).code} | ||
| boolean ${ev.isNull} = true; | ||
| ${ctx.javaType(dataType)} ${ev.value} = ${ctx.defaultValue(dataType)}; | ||
| if (!${evals(0).isNull}) { | ||
| ${evals(1).code} | ||
| if (!${evals(1).isNull}) { | ||
| ${evals(2).code} | ||
| if (!${evals(2).isNull}) { | ||
| ${ev.isNull} = false; // resultCode could change nullability | ||
| $resultCode | ||
| if (nullable) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if a
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could, but it have too much combinations. |
||
| s""" | ||
| ${evals(0).code} | ||
| boolean ${ev.isNull} = true; | ||
| ${ctx.javaType(dataType)} ${ev.value} = ${ctx.defaultValue(dataType)}; | ||
| if (!${evals(0).isNull}) { | ||
| ${evals(1).code} | ||
| if (!${evals(1).isNull}) { | ||
| ${evals(2).code} | ||
| if (!${evals(2).isNull}) { | ||
| ${ev.isNull} = false; // resultCode could change nullability | ||
| $resultCode | ||
| } | ||
| } | ||
| } | ||
| } | ||
| """ | ||
| """ | ||
| } else { | ||
| ev.isNull = "false" | ||
| s""" | ||
| ${evals(0).code} | ||
| ${evals(1).code} | ||
| ${evals(2).code} | ||
| ${ctx.javaType(dataType)} ${ev.value} = ${ctx.defaultValue(dataType)}; | ||
| $resultCode | ||
| """ | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should
DateTypetoStringTypebefalse?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, will fix it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the current ccde, there is no case for (DateType, StringType).
I can send a PR if this is to be added
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's covered by (_, StringType)