Repository navigation
fix: IS NULL panic with invalid function without input arguments - #20306
Conversation
neilconway
left a comment
There was a problem hiding this comment.
Thanks for taking a look at this!
| }); | ||
| Ok(Transformed::yes(new_expr)) | ||
| } | ||
| // IS NULL / IS NOT NULL / SIMILAR TO / CAST / TRY_CAST validate |
There was a problem hiding this comment.
I don't think comments should reference "previously" (previously to what?); they should just talk about the current state of the code.
I'd rephrase this comment to something like:
// IS NULL, IS NOT NULL, SIMILAR TO, CAST, and TRY CAST don't require
// type coercion, but we need to handle them here to ensure that their
// arguments have type coercion and type checking applied (see #20201
// for context).
| Expr::ScalarFunction(ScalarFunction::new_udf(Arc::new(fun), vec![])) | ||
| } | ||
|
|
||
| #[test] |
There was a problem hiding this comment.
These tests feel redundant to the SLT tests, no? In my opinion we should be fine with just adding the SLT tests only (which arguably is closer to testing the user-visible behavior anyway).
There was a problem hiding this comment.
I don't see it as overlapping. slt ensures the whole path works, and unit tests are there to help us isolate the root cause when something goes wrong.
There was a problem hiding this comment.
I agree with @neilconway here -- I do think the tests are redundant and I think we can just use the slt tests
|
|
||
| ############################################################################### | ||
| ## Test that IS NULL / IS NOT NULL / SIMILAR TO / CAST / TRY_CAST validate ## | ||
| ## their inner expressions during type coercion (previously they were in ## |
There was a problem hiding this comment.
I'm omit discussion of the previous incorrect behavior, I'd just talk about the current/correct behavior under test.
| let _check_type = inner_expr.get_type(self.schema)?; | ||
| Ok(Transformed::no(expr)) | ||
| } | ||
| Expr::SimilarTo(Like { |
There was a problem hiding this comment.
I wonder whether the handling of SIMILAR TO should be more similar to how we handle LIKE?
There was a problem hiding this comment.
I suspect this is because the current implementation has focused more on optimizing LIKE. Many of these optimizations could likely be applied to SIMILAR TO as well, but they are probably just yet to be implemented.
For this issue, let's maintain consistency with the existing implementation. Maybe we should create separate issues to refine how SIMILAR TO is handled.
There was a problem hiding this comment.
I wasn't thinking about optimizations; my concern was more whether the type coercion that is done for LIKE should also be done for IS SIMILAR TO for correctness reasons. Some digging suggests this might be the case:
-- works
SELECT CAST('hello' AS BYTEA) LIKE 'hello%';
-- fails ("Cannot infer common argument type for regex operation Binary ~ Utf8")
SELECT CAST('hello' AS BYTEA) SIMILAR TO 'hello%';
-- works
SELECT arrow_cast('hello', 'Dictionary(Int32, Utf8)') LIKE 'hello%';
-- fails ("Data type Dictionary(Int32, Utf8) not supported for regex_match_dyn")
SELECT arrow_cast('hello', 'Dictionary(Int32, Utf8)') SIMILAR TO 'hello%';
There was a problem hiding this comment.
I filed #20342, I'll take a look at fixing shortly.
|
Digging into this a bit further, this fix seems cleaner to me: i.e., |
alamb
left a comment
There was a problem hiding this comment.
Thanks @Acfboy and @neilconway
I think this looks good to me
| Expr::ScalarFunction(ScalarFunction::new_udf(Arc::new(fun), vec![])) | ||
| } | ||
|
|
||
| #[test] |
There was a problem hiding this comment.
I agree with @neilconway here -- I do think the tests are redundant and I think we can just use the slt tests
|
|
||
| # https://github.com/apache/datafusion/issues/20201 | ||
|
|
||
| # IS NULL should reject invalid inner expression |
There was a problem hiding this comment.
I ran these tests without the code changes to verify they cover the issue and they fail like
Completed 403 test files in 8 seconds failure in type_coercion.slt for sql SELECT * FROM (SELECT 1) WHERE (STARTS_WITH() IS NULL);
caused by
External error: task 22188 panicked with message "index out of bounds: the len is 0 but the index is 1"
Error: Execution("1 failures")
error: test failed, to rerun pass `-p datafusion-sqllogictest --test sqllogictests`
There was a problem hiding this comment.
Thanks for the review, @alamb and @neilconway. I have removed the redundant unit tests in type_coercion.rs and will rely on the .slt tests for coverage as suggested.
Thanks @alamb ! I'm curious what you think of the alternative approach I suggested #20306 (comment) |
I think that sounds like a great change to me |
It seems this only works for cases where UDFs are called without arguments. However, there are other cases failing due to a lack of type-checking in IS NULL. For example, |
Good point! Can you add one or more example queries like this to the SLT tests? |
137947b to
2c04325
Compare
|
@neilconway Thanks! While trying to add some tests, another bug occurs: #20355 . So I can't add something like Also, my apologies for the oversight. Binary operators are indeed type-checked. The bitwise operation issue was a bug that's already been fixed in a merged PR. I've checked the other branches, and it appears that only unary negation and function calls still have this problem. |
|
Proposal:
My understanding is that if we do the above, we don't need the changes to |
2c04325 to
9f54b51
Compare
|
Thanks @neilconway ! You are right. I have changed the pr and re-request reivews. |
neilconway
left a comment
There was a problem hiding this comment.
🎉🎉🎉
Can you update the PR description to match the current approach?
alamb
left a comment
There was a problem hiding this comment.
makes sense to me -- thank you @Acfboy and @neilconway
…che#20306) ## Which issue does this PR close? <!-- We generally require a GitHub issue to be filed for all bug fixes and enhancements and this helps us generate change logs for our releases. You can link an issue to this PR using the GitHub syntax. For example `Closes apache#123` indicates that this PR will close issue apache#123. --> - Closes apache#20201 . ## Rationale for this change Unlike `Projection`, expressions within a `Filter` node do not always have their types resolved during the initial LogicalPlan generation. Validation is often deferred until the type_coercion phase. When invoking f_up on the expression tree to perform type coercion, the check is bypassed for function nodes with empty arguments, leading to a panic during subsequent execution. For example, all statements below cause a panic: ``` SELECT * FROM (SELECT 1) WHERE (STARTS_WITH() IS NULL); SELECT * FROM (SELECT 1) WHERE (STARTS_WITH() IS NOT NULL); SELECT * FROM (SELECT 'a') WHERE (STARTS_WITH() SIMILAR TO 'abc%'); SELECT * FROM (SELECT 1) WHERE CAST(STARTS_WITH() AS STRING) = 'x'; SELECT * FROM (SELECT 1) WHERE TRY_CAST(STARTS_WITH() AS INT) IS NULL; ``` This pr aims to stop panic. It would be better if reject these invalid cases at planning. ## What changes are included in this PR? <!-- There is no need to duplicate the description in the issue here but it is sometimes worth providing a summary of the individual changes in this PR. --> ```diff fn coerce_arguments_for_signature<F: UDFCoercionExt>( schema: &DFSchema, func: &F, ) -> Result<Vec<Expr>> { - if expressions.is_empty() { - return Ok(expressions); - } ``` Deleted the early return. Thanks to @neilconway . ## Are these changes tested? All original tests passed. Added some unit tests and sqllogictests. ## Are there any user-facing changes? <!-- If there are user-facing changes then we may require documentation to be updated before approving the PR. --> <!-- If there are any breaking changes to public APIs, please add the `api change` label. --> No. --------- Co-authored-by: Andrew Lamb <andrew@nerdnetworks.org>
Which issue does this PR close?
Rationale for this change
Unlike
Projection, expressions within aFilternode do not always have their types resolved during the initial LogicalPlan generation. Validation is often deferred until the type_coercion phase. When invoking f_up on the expression tree to perform type coercion, the check is bypassed for function nodes with empty arguments, leading to a panic during subsequent execution.For example, all statements below cause a panic:
This pr aims to stop panic. It would be better if reject these invalid cases at planning.
What changes are included in this PR?
fn coerce_arguments_for_signature<F: UDFCoercionExt>( schema: &DFSchema, func: &F, ) -> Result<Vec<Expr>> { - if expressions.is_empty() { - return Ok(expressions); - }Deleted the early return. Thanks to @neilconway .
Are these changes tested?
All original tests passed. Added some unit tests and sqllogictests.
Are there any user-facing changes?
No.