-
Notifications
You must be signed in to change notification settings - Fork 3.6k
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
HHH-18359 Fixes to Informix functions errors #8652
base: 6.6
Are you sure you want to change the base?
Conversation
Thanks for your pull request! This pull request appears to follow the contribution rules. › This message was automatically generated. |
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.
Other than what I commented, this looks good.
@@ -269,19 +276,41 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio | |||
functionFactory.initcap(); | |||
functionFactory.yearMonthDay(); | |||
functionFactory.ceiling_ceil(); | |||
functionFactory.concat_pipeOperator(); | |||
functionFactory.concat_pipeOperator( SqlAstNodeRenderingMode.INLINE_ALL_PARAMETERS ); |
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.
Are you sure NO_PLAIN_PARAMETER
won't work? Inlining parameters really is the last resort and shouldn't be done lightly.
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.
After extensive testing, I discovered that the concat() function does not behave identically to concat_operator()
. Using concat_operator()
with Informix 11 results in an error in the test org.hibernate.orm.test.hql.ASTParserLoadingTest.testExpressionWithParamInFunction
.
Here's the failing HQL query:
s.createQuery( "from Animal where lower(upper('foo') || upper(:bar)) like 'f%'" ).setParameter( "bar", "xyz" ).list();
This translates to the following incorrect SQL:
select ... where lower((upper('foo')||upper(?))) like 'f%'
The error message is:
org.hibernate.exception.SQLGrammarException: could not prepare statement [A syntax error has occurred.] [select a1_0.id,case when a1_5.reptile is not null then 2 when a1_1.mammal is not null then 5 when a1_2.mammal is not null then 6 when a1_3.mammal is not null then 4 when a1_4.mammal is not null then 7 when a1_7.animal is not null then 1 when a1_6.animal is not null then 3 when a1_0.id is not null then 0 end,a1_0.body_weight,a1_0.description,a1_0.father_id,a1_0.mother_id,a1_0.serialNumber,a1_0.zoo_id,a1_3.owner,a1_4.bigDecimalValue,a1_4.bigIntegerValue,a1_4.floatValue,a1_4.height_centimeters / 2.54E0,a1_4.intValue,a1_4.name_first,a1_4.name_initial,a1_4.name_last,a1_4.nickName,a1_6.birthdate,a1_6.pregnant,a1_7.bodyTemperature from Animal a1_0 left join Cat a1_1 on a1_0.id=a1_1.mammal left join Dog a1_2 on a1_0.id=a1_2.mammal left join DomesticAnimal a1_3 on a1_0.id=a1_3.mammal left join Human a1_4 on a1_0.id=a1.mammal left join Lizard a1_5 on a1_0.id=a1_5.reptile left join Mammal a1_6 on a1_0.id=a1_6.animal left join Reptile a1_7 on a1_0.id=a1_7.animal where lower((upper('foo')||upper(?))) like 'f%']
The previously proposed solution using concat_operator( SqlAstNodeRenderingMode.INLINE_ALL_PARAMETERS )
can therefore be replaced with the default concat()
function.
As mentioned in issue HHH-18366, the problem also affects CaseSearchedExpression
. I attempted to address it using a similar approach as in other dialects.
Overriding visitAnsiCaseSearchedExpression()
as done in DB2 and others is not effective.
Overriding visitCaseSearchedExpression()
with a call to visitDecodeCaseSearchedExpression()
doesn't help either.
Overriding visitCaseSearchedExpression()
with a call to renderSelectExpressionWithCastedOrInlinedPlainParameters()
doesn't resolve this issue because the parameter is nested within the concat()
function. However, this approach can eliminate other errors, such as the one in the unit test org.hibernate.orm.test.hql.BulkManipulationTest.testSimpleInsertWithNamedParam()
.
org.hibernate.exception.SQLGrammarException: could not prepare statement [A syntax error has occurred.] [insert into Pickup(id,owner,vin) select c1_0.id,?,c1_0.vin from Car c1_0]
In my opinion, these tests should be marked with:
@RequiresDialectFeature(
value = DialectChecks.SupportsParametersInInsertSelectCheck.class,
comment = "dialect does not support parameter in INSERT ... SELECT"
)
Therefore, the solution I propose is to use:
withParameterRenderingMode(
SqlAstNodeRenderingMode.INLINE_ALL_PARAMETERS,
() -> super.visitCaseSearchedExpression( caseSearchedExpression, inSelect )
);
hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixDialect.java
Outdated
Show resolved
Hide resolved
); | ||
} | ||
else { | ||
functionFactory.coalesce( SqlAstNodeRenderingMode.INLINE_ALL_PARAMETERS ); |
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.
Are you sure NO_PLAIN_PARAMETER
won't work? Inlining parameters really is the last resort and shouldn't be done lightly.
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.
Using functionFactory.coalesce( SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER )
generates a SQL select statement that casts the parameter. However, this still results in the same error:
org.hibernate.exception.GenericJDBCException: could not prepare statement [Not implemented yet.] [select p1_0.id,p1_0.name,p1_0.surname from Person p1_0 where p1_0.name=coalesce(cast(? as varchar(255)),p1_0.name)]
According to the documentation COALESCE, "arguments cannot be host variables" for the coalesce function.
Can you please try to rebase on top of #8675 and make use of the |
Can you help me with this rebase as you suggested? I'm not sure how to rebase on top of pull request #8675. In my local clone of the repository, I added your remote fork https://github.com/hibernate/hibernate-orm. Then I fetched from it and finally rebases onto the remotes/beikov/wrap-parameter-rendering-mode branch. After my code changes, should I just push to my remote origin branch from which my pull request is created to get the expected result? |
After changing to
|
After making small changes to avoid cycling, I tested using rendering mode
Which ends with the error:
Informix 14 did not have this problem. For the
There is no syntax problem, but again it is the metadata. The changes are taken into account according to the cast type, but it is still not good. The latest Informix 14 also has a problem with this. Therefore, I stick to my proposal. After all, I assume that there may be problems with this metadata in other SQL selects as well, as contained in the tests. |
Hi Vlado, sorry for not responding in a while. I was working hard on some performance improvements and had to focus a while.
I just tested this myself on Informix 14 and it seems to work fine. What am I missing?
|
Hi Chris, I just got back from vacation on Tuesday evening, so the longer silence didn't bother me. Thanks for your support. I tried the rebase as you recommended. You solved the looping issue, but now in the resulting
Try using my exact scenario. Run the test
|
Please rebase your PR to resolve the conflicts. Also, please change the code to use |
I've done a rebase, but I can't directly use just |
As I predicted, problems with parameters are common in SqlSelections. Another example is from the test
Therefore, I propose a different, more radical solution: in Informix, for SqlSelections, set the default parameter rendering mode to |
4fd67bb
to
cd02eb3
Compare
I omitted the fixes for subtasks HHH-18366 Informix concat pipe operator error and HHH-18368 Informix function coalesce() error due to an ambiguous problematic solution. |
hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixDialect.java
Outdated
Show resolved
Hide resolved
hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixDialect.java
Show resolved
Hide resolved
assertEquals( 2, count.intValue() ); | ||
count = (Number) s.createQuery( "select count(distinct case when bodyWeight > 100 then nickName else null end) from Human" ).uniqueResult(); | ||
assertEquals( 2, count.intValue() ); | ||
if ( !( getDialect() instanceof InformixDialect && getDialect().getVersion().isBefore( 11, 70 ) ) ) { |
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.
Please use the @SkipForDialect
annotation for this instead.
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.
I will have to rework this test into JUnit 5 because the current deprecated annotation @SkipForDialect
does not have the attributes majorVersion
, minorVersion
.
hibernate-core/src/test/java/org/hibernate/orm/test/hql/ASTParserLoadingTest.java
Outdated
Show resolved
Hide resolved
I also found this documentation saying:
How about connecting it with an empty string in case the parameter is a string and +0 if it's a number? Maybe you can add 0 seconds to timestamps parameters as well? |
14d4232
to
f6f72bb
Compare
Cumulative PR for all subtasks [HHH-18360, HHH-18361, HHH-18362, HHH-18363, HHH-18364, HHH-18365, HHH-18168, HHH-18366, HHH-18367, HHH-18368, HHH-18369]
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license
and can be relicensed under the terms of the LGPL v2.1 license in the future at the maintainers' discretion.
For more information on licensing, please check here.