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

[CALCITE-1703] Functions on TIMESTAMP column throws ClassCastException #971

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

ijokarumawak
Copy link
Member

Currently, TIMESTAMP or TIME column is used at any function, ClassCastException is thrown. For example, if a TIMESTAMP column date_added is used like this, select name, EXTRACT(YEAR FROM date_added) as year_added from FLOWFILE, Calcite generates the following code. And a ClassCastException is thrown at (Long) current[1]:

            public Object current() {
              final Object[] current = (Object[]) inputEnumerator.current();
              return new Object[] {
                  current[0],
                  (java.sql.Timestamp) current[1] == null ? (Long) null : Long.valueOf(org.apache.calcite.avatica.util.DateTimeUtils.unixDateExtract(org.apache.calcite.avatica.util.TimeUnitRange.YEAR, (Long) current[1] / 86400000L))};
            }

That happens because of the wrong if condition at PhysTypeImple.fieldReference method where it ignores the fieldType that is used as a fromType to convert the value to Long. Since fromType is null, the generated code casts current[1] to Long blindly.

The condition should accept not only java.sql.Date but also java.sql.Time and java.sql.Timestamp. Since these classes are all sub-class of java.util.Date, using isAssignableFrom method will address the issue.

Current if statement only supports java.sql.Date:
image

DISCLAIMER: This is my first PR to Apache Calcite project. Kindly give me some advice on unit testing.

I wanted to add an unit test to reproduce the issue and prove this fix it. But I couldn't figure out where is the right place for such test.

There is an existing case testExtractYearFromTimestamp but this test doesn't call PhysTypeImple.fieldReference. Some other test cases in the same JdbcTest such as testSumOverUnboundedPreceding does call PhysTypeImple.fieldReference. I don't know where this difference comes from..

@ijokarumawak
Copy link
Member Author

I found that the particular code branch that can throw ClassCastException is generated when a timestamp column in an Object array row type is referenced. Referencing timestamp field at a Java class (POJO) doesn't seem having this issue.

@ijokarumawak
Copy link
Member Author

Fixed check-style errors.

@ijokarumawak
Copy link
Member Author

@vlsi Thanks for reviewing! I've added more commits to address your comments. As I was working on that, I've found few more issues to fix. The added test cases illustrate what had not been working as expected.

@F21
Copy link
Member

F21 commented Jan 3, 2019

@ijokarumawak Does this supersede #405? If so, I will close that PR.

@vlsi vlsi added the returned-with-feedback There are review comments (in JIRA and/or in GitHub) to be implemented before merging the PR label Jan 4, 2019
@ijokarumawak
Copy link
Member Author

@F21 Yes, I believe this PR covers what #405 tries to fix.

@F21
Copy link
Member

F21 commented Jan 7, 2019

@ijokarumawak Thanks for taking this on! I'll close #405

…astException

Incorporated review comments

- Added the new test to CalciteSuite
- Added test case message to clarify assertion objectives

Adding more fixes

- java.sql.Time is not converted to int correctly
- java.sql.Timestamp fraction can not be used with some conditions such as '='

Fixed checkstyle errors.

Better assertion messages.
@ijokarumawak
Copy link
Member Author

Rebased with the latest master as the PR had a conflict on CalciteSuite. Also squashed commits.

@vlsi vlsi added LGTM-will-merge-soon Overall PR looks OK. Only minor things left. and removed returned-with-feedback There are review comments (in JIRA and/or in GitHub) to be implemented before merging the PR labels Jan 8, 2019
@ijokarumawak
Copy link
Member Author

@vlsi I've implemented timestamp cast and added unit test for that. The issue was the existing code has had the conversion but used scale instead of precision. Please see the added commit for what I changed. Hopefully this PR is now ready to be merged. Thanks!

@risdenk
Copy link
Contributor

risdenk commented Feb 27, 2019

@vlsi - planning to merge still?

format(Locale.ROOT, sql, expected, actual));
resultSet.next();
assertEquals(format(Locale.ROOT, "cast(java.sql.Timestamp as %s)", castTo),
resultSet.getTimestamp(1), resultSet.getTimestamp(2));
Copy link
Contributor

Choose a reason for hiding this comment

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

@ijokarumawak , this is wrong. "EXPECTED" value must not come from a system under test.
You should either hard-code the expected value (which is preferred) or compute it with a "simple to understand" approach.

Copy link
Member Author

Choose a reason for hiding this comment

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

Changed to use hard-coded expected values.

final ResultSet resultSet = statement.executeQuery(
format(Locale.ROOT, sql, expected, actual));
resultSet.next();
assertEquals(format(Locale.ROOT, "cast(java.sql.Timestamp as %s)", castTo),
Copy link
Contributor

Choose a reason for hiding this comment

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

It is great you add castTo to the message, however it would be really good if you add source value as well.

Copy link
Member Author

Choose a reason for hiding this comment

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

Added source value.

final String sql = "select %s as EXPECTED, %s as ACTUAL from \"java_sql_date_types\"";

for (int i = 3; i >= 0; i--) {
final String castTo = format(Locale.ROOT, "TIMESTAMP(%d)", i);
Copy link
Contributor

Choose a reason for hiding this comment

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

You seem to use format(Locale.ROOT extensively. It makes the code extremely obscure. Could you just use + operator?

Alternative option is to use Kotlin's string interpolation

Copy link
Member Author

Choose a reason for hiding this comment

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

Changed to simple string concatenation using +.

@Test public void testCastTimestampToTimestamp() throws SQLException {

withJavaSqlDateTypes(connection -> {

Copy link
Contributor

Choose a reason for hiding this comment

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

Please avoid having to many blank lines

Copy link
Member Author

Choose a reason for hiding this comment

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

Removed blank lines.

@vlsi vlsi added returned-with-feedback There are review comments (in JIRA and/or in GitHub) to be implemented before merging the PR and removed LGTM-will-merge-soon Overall PR looks OK. Only minor things left. labels Feb 27, 2019
@ijokarumawak
Copy link
Member Author

Hi @vlsi, sorry for the delay. I've added another commit to address review feedback. Please let me know if there's anything more. Thanks for reviewing!

@ijokarumawak
Copy link
Member Author

Hi @vlsi I just noticed that CI tests failed at DateRangeRulesTest. But the only thing I changed at the last commit is ObjectArrayTableTest test class. Do you know why DateRangeRulesTest failed on travis and appveyor?? The test had been successful before, and is successful if I run it locally..

@michaelmior
Copy link
Member

@vlsi Could you take another look?

@vlsi
Copy link
Contributor

vlsi commented Jun 5, 2019

@michaelmior , the review comments are resolved.

However it looks like the change fails the build, and I have not analyzed the reason.

@michaelmior
Copy link
Member

Thanks!

@michaelmior
Copy link
Member

@ijokarumawak What JDK version are you using? It passes on CI with JDK 10.

@vlsi
Copy link
Contributor

vlsi commented Jun 5, 2019

@michaelmior , it does not.
I think the reason one of Travis job passes is it runs with SLOW_TESTS=Y, so only a subset of tests is executed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
returned-with-feedback There are review comments (in JIRA and/or in GitHub) to be implemented before merging the PR
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants