Skip to content

[CALCITE-2417] Fix ClassCastException in RelToSqlConverter with structs#761

Closed
BenoitHanotte wants to merge 1 commit intoapache:masterfrom
BenoitHanotte:CALCITE-2417
Closed

[CALCITE-2417] Fix ClassCastException in RelToSqlConverter with structs#761
BenoitHanotte wants to merge 1 commit intoapache:masterfrom
BenoitHanotte:CALCITE-2417

Conversation

@BenoitHanotte
Copy link
Copy Markdown

@BenoitHanotte BenoitHanotte commented Jul 17, 2018

Trying to convert the pysical plan of a select * query on a table with a nested struct throws ClassCastException as RexInputRef cannot be cast to RexCorrelVariable.
This is due to the cast to RexCorrelVariable not being done on the referenced expression of RexInputRef accessible through RexFieldAccess.getReferenceExpr()

I am not sure how you would advise testing such a case? In order to isolate the issue I had to recreate a custom schema with a nested struct, however this is adds a lot of boiler plate.

@michaelmior
Copy link
Copy Markdown
Member

Overall LGTM. Can you rename RelToSqlNestedStruct to RelToSqlNestedStructTest? It would also probably be a good idea to validate the result of RelToSqlConverter.

@BenoitHanotte BenoitHanotte force-pushed the CALCITE-2417 branch 2 times, most recently from f3dee40 to ff2aaf8 Compare July 18, 2018 06:57
@BenoitHanotte
Copy link
Copy Markdown
Author

Hello @michaelmior, thanks for the feedback :)
I renamed the test class and updated the test case to assert the validity of the sql string.

@zabetak
Copy link
Copy Markdown
Member

zabetak commented Jul 18, 2018

Hi @BenoitHanotte, for creating appropriate tests I believe you can add a few test methods in RelToSqlConverterTest. A schema with some minimal nesting that may be sufficient for your case exists in CalciteAssert.SchemaSpec.HR.

If you need a Schema with more nesting in order to test your feature wait for PR762.

@BenoitHanotte
Copy link
Copy Markdown
Author

BenoitHanotte commented Jul 18, 2018

Thanks @zabetak , indeed the depts table has a nested struct that allows testing this fix with a much reduced boiler plate.
I updated my PR to add a test case to RelToSqlConverterTest and remove the RelToSqlConverterNestedStructsTest file, it is much cleaner this way :)

@BenoitHanotte
Copy link
Copy Markdown
Author

BenoitHanotte commented Jul 18, 2018

Unfortunately I discovered that this fix is not giving correct names for the nested fields:

SELECT * FROM depts

gives the following query:

SELECT deptno, name, employees, location, location AS location FROM hr.depts

I'll have alook at it this afternoon but from my limited understanding of the code, we'll have to make sure that RexFieldAccess is actually going through the correlation path to keep track of the reference

@BenoitHanotte
Copy link
Copy Markdown
Author

@zabetak @michaelmior I updated my PR, it seems that in addition to the cast issue we were not correctly mapping the field index to the RelDataTypeField of the row when the row type is nested.

For instance, for a RecordType(INT a, RecordType(INT b), we need to build an ordered list such as

0: RelDataTypeField of a
1: RelDataTypeField of a.b

This way we can get the RelDataTypeField for given field index in an AliasContext

I added a few test cases to ensure that names were correctly retrieved for nested fields.

for (Function<RelNode, RelNode> transform : transforms) {
rel = transform.apply(rel);
}
System.out.println(RelOptUtil.toString(rel));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Minor, but looks like this was for debugging and should be removed.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Sorry, I forgot to remove it

final RexCorrelVariable variable = (RexCorrelVariable) access.getReferenceExpr();
final Context aliasContext = correlTableMap.get(variable.id);
return aliasContext.field(access.getField().getIndex());
default:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The code assumes that FIELD_ACCESS wraps always a CORREL_VARIABLE or INPUT_REF. I have the impression that this code will lead again to a ClassCastException just a bit later (e.g., for a doubly nested struct where there is a RexFieldAccess(RexFieldAccess(RexInputRef)).

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

You're right, I thought that it could only go down one level but after adding tests for multiple nested levels I see that it can happen, I am updating the PR to support this and add tests for this case

@BenoitHanotte BenoitHanotte force-pushed the CALCITE-2417 branch 2 times, most recently from 8e82059 to f9d609c Compare July 19, 2018 10:27
@BenoitHanotte
Copy link
Copy Markdown
Author

BenoitHanotte commented Jul 19, 2018

I updated the PR to do the following:

  1. Support more than one level of RexFieldAccess (use a stack called accesses to store the RexFieldAccess levels, get the referenced SqlNodeand then poll from the stack to add the name components)
  2. Add tests on a schema containing more than one level of nesting and more than one nested column

I haven't been able to find a more elegant solution to the correlation variable case as I don't seem to be able to get the field index without having access to the last level of RexFieldAccess, hence the inner switch case to handle this particular case.

I tested this patch on our production schema and it seems to have solved the issue.

Trying to convert the pysical plan of a select * query on a table with a
nested struct throws ClassCastException as RexInputRef cannot be cast to
RexCorrelVariable.
This is due to the cast to RexCorrelVariable not being done on the
referenced expression of RexInputRef accessible through
RexFieldAccess.getReferenceExpr()
@BenoitHanotte
Copy link
Copy Markdown
Author

BenoitHanotte commented Jul 25, 2018

Hello @michaelmior @zabetak would you have time for a review of this PR so that we can see whether this is the right approach or not? Thanks!

@asfgit asfgit closed this in 3c40d86 Jul 25, 2018
@michaelmior
Copy link
Copy Markdown
Member

LGTM, merged! Sorry for the delay. I was waiting for the latest release to go through and this slipped off my radar. Thanks for the contribution :)

snuyanzin pushed a commit to snuyanzin/calcite that referenced this pull request Jul 27, 2018
…ts (Benoit Hanotte)

Trying to convert the pysical plan of a select * query on a table with a
nested struct throws ClassCastException as RexInputRef cannot be cast to
RexCorrelVariable.
This is due to the cast to RexCorrelVariable not being done on the
referenced expression of RexInputRef accessible through
RexFieldAccess.getReferenceExpr()

Close apache#761
snuyanzin pushed a commit to snuyanzin/calcite that referenced this pull request Jul 27, 2018
…ts (Benoit Hanotte)

Trying to convert the pysical plan of a select * query on a table with a
nested struct throws ClassCastException as RexInputRef cannot be cast to
RexCorrelVariable.
This is due to the cast to RexCorrelVariable not being done on the
referenced expression of RexInputRef accessible through
RexFieldAccess.getReferenceExpr()

Close apache#761
snuyanzin pushed a commit to snuyanzin/calcite that referenced this pull request Jul 27, 2018
…ts (Benoit Hanotte)

Trying to convert the pysical plan of a select * query on a table with a
nested struct throws ClassCastException as RexInputRef cannot be cast to
RexCorrelVariable.
This is due to the cast to RexCorrelVariable not being done on the
referenced expression of RexInputRef accessible through
RexFieldAccess.getReferenceExpr()

Close apache#761
snuyanzin pushed a commit to snuyanzin/calcite that referenced this pull request Jul 27, 2018
…ts (Benoit Hanotte)

Trying to convert the pysical plan of a select * query on a table with a
nested struct throws ClassCastException as RexInputRef cannot be cast to
RexCorrelVariable.
This is due to the cast to RexCorrelVariable not being done on the
referenced expression of RexInputRef accessible through
RexFieldAccess.getReferenceExpr()

Close apache#761
snuyanzin pushed a commit to snuyanzin/calcite that referenced this pull request Jul 27, 2018
…ts (Benoit Hanotte)

Trying to convert the pysical plan of a select * query on a table with a
nested struct throws ClassCastException as RexInputRef cannot be cast to
RexCorrelVariable.
This is due to the cast to RexCorrelVariable not being done on the
referenced expression of RexInputRef accessible through
RexFieldAccess.getReferenceExpr()

Close apache#761
sergeyT2 pushed a commit to sergeyT2/calcite that referenced this pull request Aug 29, 2018
…ts (Benoit Hanotte)

Trying to convert the pysical plan of a select * query on a table with a
nested struct throws ClassCastException as RexInputRef cannot be cast to
RexCorrelVariable.
This is due to the cast to RexCorrelVariable not being done on the
referenced expression of RexInputRef accessible through
RexFieldAccess.getReferenceExpr()

Close apache#761
sergeyT2 pushed a commit to sergeyT2/calcite that referenced this pull request Aug 29, 2018
…ts (Benoit Hanotte)

Trying to convert the pysical plan of a select * query on a table with a
nested struct throws ClassCastException as RexInputRef cannot be cast to
RexCorrelVariable.
This is due to the cast to RexCorrelVariable not being done on the
referenced expression of RexInputRef accessible through
RexFieldAccess.getReferenceExpr()

Close apache#761
wangxlong pushed a commit to wangxlong/calcite that referenced this pull request Feb 13, 2020
…ts (Benoit Hanotte)

Trying to convert the pysical plan of a select * query on a table with a
nested struct throws ClassCastException as RexInputRef cannot be cast to
RexCorrelVariable.
This is due to the cast to RexCorrelVariable not being done on the
referenced expression of RexInputRef accessible through
RexFieldAccess.getReferenceExpr()

Close apache#761
jamesstarr pushed a commit to jamesstarr/calcite that referenced this pull request Aug 28, 2025
…ts (Benoit Hanotte)

- This patch changes RelToSqlConvertedTest framework which is needed by the calcite-3138

Trying to convert the pysical plan of a select * query on a table with a
nested struct throws ClassCastException as RexInputRef cannot be cast to
RexCorrelVariable.
This is due to the cast to RexCorrelVariable not being done on the
referenced expression of RexInputRef accessible through
RexFieldAccess.getReferenceExpr()

Close apache#761

Change-Id: I43416d770e757deb521e4a1cebe003fcc73df7ee
jamesstarr pushed a commit to jamesstarr/calcite that referenced this pull request Mar 16, 2026
…ts (Benoit Hanotte)

- This patch changes RelToSqlConvertedTest framework which is needed by the calcite-3138

Trying to convert the pysical plan of a select * query on a table with a
nested struct throws ClassCastException as RexInputRef cannot be cast to
RexCorrelVariable.
This is due to the cast to RexCorrelVariable not being done on the
referenced expression of RexInputRef accessible through
RexFieldAccess.getReferenceExpr()

Close apache#761

Change-Id: I43416d770e757deb521e4a1cebe003fcc73df7ee
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