Bug #2347
hql to SQL name mapping issue
100%
History
#1 Updated by Ovidiu Maxiniuc almost 10 years ago
- Priority changed from Normal to High
- Start date deleted (
07/28/2014)
Consider the following Progress code sample:
define temp-table tt9 field ci as character field cs as character case-sensitive. create tt9. ci = " Abc ". cs = " Abc ". validate tt9. create tt9. ci = "Abc". cs = "Abc". validate tt9. find first tt9 where ci = trim(ci) and length(trim(cs)) = 3. display "found it!".
This is a correct Progress procedure and when executed should print evidently (the 2 nd record satisfies the where clause from find)
┌─────────┐ │found it!│ └─────────┘
The procedure is correctly converted into java as:
RecordBuffer.openScope(tt9); tt9.create(); tt9.setCi(new character(" Abc ")); tt9.setCs(new character(" Abc ")); tt9.validate(); tt9.create(); tt9.setCi(new character("Abc")); tt9.setCs(new character("Abc")); tt9.validate(); new FindQuery(tt9, "upper(tt9.ci) = trimws(upper(tt9.ci)) and lengthOf(trimws(upper(tt9.cs))) = 3", null, "tt9.id asc").first(); FrameElement[] elementList0 = new FrameElement[] { new Element("found it!", frame0.widgetExpr1()) }; frame0.display(elementList0);
When executed, the following messages are printed:
[07/28/2014 20:46:23 EEST] (org.hibernate.engine.jdbc.spi.SqlExceptionHelper:WARN) SQL Error: 90022, SQLState: 90022 [07/28/2014 20:46:23 EEST] (org.hibernate.engine.jdbc.spi.SqlExceptionHelper:ERROR) Function "TRIMWS" not found; SQL statement: select temprecord0_.id as col_0_0_ from tt1 temprecord0_ where temprecord0_._multiplex=? and temprecord0_.__ici=trimws(temprecord0_.__ici) and lengthOf(trimws(upper(temprecord0_.__scs)))=3 order by temprecord0_.__ici asc, temprecord0_.__scs desc, temprecord0_._multiplex asc, temprecord0_.id desc limit ? [90022-169] [07/28/2014 20:46:23 EEST] (com.goldencode.p2j.persist.Persistence:WARNING) [00000001:00000007:bogus-->local/_temp/primary] error loading record select tt9.id from TempRecord1Impl as tt9 where (tt9._multiplex = ?0) and (tt9.__ici = trimws(tt9.__ici) and lengthOf(trimws(upper(tt9.__scs))) = 3) order by tt9.__ici asc, tt9.__scs desc, tt9._multiplex asc, tt9.id desc [07/28/2014 20:46:23 EEST] (ErrorManager:SEVERE) {00000001:00000007:bogus} stack trace follows com.goldencode.p2j.persist.PersistenceException: [00000001:00000007:bogus-->local/_temp/primary] error loading record at com.goldencode.p2j.persist.Persistence.load(Persistence.java:1879) at com.goldencode.p2j.persist.RandomAccessQuery.executeImpl(RandomAccessQuery.java:3187) at com.goldencode.p2j.persist.RandomAccessQuery.execute(RandomAccessQuery.java:2493) at com.goldencode.p2j.persist.RandomAccessQuery.first(RandomAccessQuery.java:1161) at com.goldencode.p2j.persist.RandomAccessQuery.first(RandomAccessQuery.java:1067) at com.goldencode.testcases.<customer>_schema.TestRoot$1.body(TestRoot.java:42) at com.goldencode.p2j.util.BlockManager.processBody(BlockManager.java:7048) at com.goldencode.p2j.util.BlockManager.topLevelBlock(BlockManager.java:6881) at com.goldencode.p2j.util.BlockManager.externalProcedure(BlockManager.java:221) at com.goldencode.p2j.util.BlockManager.externalProcedure(BlockManager.java:203) at com.goldencode.testcases.<customer>_schema.TestRoot.execute(TestRoot.java:28) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at com.goldencode.p2j.util.Utils.invoke(Utils.java:1234) at com.goldencode.p2j.main.StandardServer$MainInvoker.execute(StandardServer.java:1701) at com.goldencode.p2j.main.StandardServer.invoke(StandardServer.java:1201) at com.goldencode.p2j.main.StandardServer.standardEntry(StandardServer.java:364) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at com.goldencode.p2j.util.MethodInvoker.invoke(MethodInvoker.java:76) at com.goldencode.p2j.net.Dispatcher.processInbound(Dispatcher.java:694) at com.goldencode.p2j.net.Conversation.block(Conversation.java:319) at com.goldencode.p2j.net.Conversation.run(Conversation.java:163) at java.lang.Thread.run(Thread.java:745) Caused by: org.hibernate.exception.GenericJDBCException: Function "TRIMWS" not found; SQL statement: select temprecord0_.id as col_0_0_ from tt1 temprecord0_ where temprecord0_._multiplex=? and temprecord0_.__ici=trimws(temprecord0_.__ici) and lengthOf(trimws(upper(temprecord0_.__scs)))=3 order by temprecord0_.__ici asc, temprecord0_.__scs desc, temprecord0_._multiplex asc, temprecord0_.id desc limit ? [90022-169] at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:54) at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:125) at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:110) at org.hibernate.engine.jdbc.internal.proxy.ConnectionProxyHandler.continueInvocation(ConnectionProxyHandler.java:146) at org.hibernate.engine.jdbc.internal.proxy.AbstractProxyHandler.invoke(AbstractProxyHandler.java:81) at com.sun.proxy.$Proxy4.prepareStatement(Unknown Source) at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$5.doPrepare(StatementPreparerImpl.java:147) at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:166) at org.hibernate.engine.jdbc.internal.StatementPreparerImpl.prepareQueryStatement(StatementPreparerImpl.java:145) at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1749) at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1726) at org.hibernate.loader.Loader.doQuery(Loader.java:852) at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:293) at org.hibernate.loader.Loader.doList(Loader.java:2411) at org.hibernate.loader.Loader.doList(Loader.java:2397) at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2227) at org.hibernate.loader.Loader.list(Loader.java:2222) at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:470) at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:355) at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:195) at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1247) at org.hibernate.internal.QueryImpl.list(QueryImpl.java:101) at org.hibernate.internal.AbstractQueryImpl.uniqueResult(AbstractQueryImpl.java:905) at com.goldencode.p2j.persist.Persistence.load(Persistence.java:1723) at com.goldencode.p2j.persist.RandomAccessQuery.executeImpl(RandomAccessQuery.java:3187) at com.goldencode.p2j.persist.RandomAccessQuery.execute(RandomAccessQuery.java:2493) at com.goldencode.p2j.persist.RandomAccessQuery.first(RandomAccessQuery.java:1161) at com.goldencode.p2j.persist.RandomAccessQuery.first(RandomAccessQuery.java:1067) at com.goldencode.testcases.<customer>_schema.TestRoot$1.body(TestRoot.java:42) at com.goldencode.p2j.util.BlockManager.processBody(BlockManager.java:7048) at com.goldencode.p2j.util.BlockManager.topLevelBlock(BlockManager.java:6881) at com.goldencode.p2j.util.BlockManager.externalProcedure(BlockManager.java:221) at com.goldencode.p2j.util.BlockManager.externalProcedure(BlockManager.java:203) at com.goldencode.testcases.<customer>_schema.TestRoot.execute(TestRoot.java:28) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at com.goldencode.p2j.util.Utils.invoke(Utils.java:1234) at com.goldencode.p2j.main.StandardServer$MainInvoker.execute(StandardServer.java:1701) at com.goldencode.p2j.main.StandardServer.invoke(StandardServer.java:1201) at com.goldencode.p2j.main.StandardServer.standardEntry(StandardServer.java:364) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at com.goldencode.p2j.util.MethodInvoker.invoke(MethodInvoker.java:76) at com.goldencode.p2j.net.Dispatcher.processInbound(Dispatcher.java:694) at com.goldencode.p2j.net.Conversation.block(Conversation.java:319) at com.goldencode.p2j.net.Conversation.run(Conversation.java:163) at java.lang.Thread.run(Thread.java:745) Caused by: org.h2.jdbc.JdbcSQLException: Function "TRIMWS" not found; SQL statement: select temprecord0_.id as col_0_0_ from tt1 temprecord0_ where temprecord0_._multiplex=? and temprecord0_.__ici=trimws(temprecord0_.__ici) and lengthOf(trimws(upper(temprecord0_.__scs)))=3 order by temprecord0_.__ici asc, temprecord0_.__scs desc, temprecord0_._multiplex asc, temprecord0_.id desc limit ? [90022-169] at org.h2.message.DbException.getJdbcSQLException(DbException.java:329) at org.h2.message.DbException.get(DbException.java:169) at org.h2.message.DbException.get(DbException.java:146) at org.h2.command.Parser.readJavaFunction(Parser.java:2122) at org.h2.command.Parser.readFunction(Parser.java:2174) at org.h2.command.Parser.readTerm(Parser.java:2476) at org.h2.command.Parser.readFactor(Parser.java:2046) at org.h2.command.Parser.readSum(Parser.java:2033) at org.h2.command.Parser.readConcat(Parser.java:2006) at org.h2.command.Parser.readCondition(Parser.java:1964) at org.h2.command.Parser.readAnd(Parser.java:1854) at org.h2.command.Parser.readExpression(Parser.java:1844) at org.h2.command.Parser.parseSelectSimple(Parser.java:1801) at org.h2.command.Parser.parseSelectSub(Parser.java:1684) at org.h2.command.Parser.parseSelectUnion(Parser.java:1527) at org.h2.command.Parser.parseSelect(Parser.java:1515) at org.h2.command.Parser.parsePrepared(Parser.java:405) at org.h2.command.Parser.parse(Parser.java:279) at org.h2.command.Parser.parse(Parser.java:251) at org.h2.command.Parser.prepareCommand(Parser.java:217) at org.h2.engine.Session.prepareLocal(Session.java:415) at org.h2.engine.Session.prepareCommand(Session.java:364) at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1114) at org.h2.jdbc.JdbcPreparedStatement.<init>(JdbcPreparedStatement.java:74) at org.h2.jdbc.JdbcConnection.prepareStatement(JdbcConnection.java:265) at sun.reflect.GeneratedMethodAccessor318.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.hibernate.engine.jdbc.internal.proxy.ConnectionProxyHandler.continueInvocation(ConnectionProxyHandler.java:138) at org.hibernate.engine.jdbc.internal.proxy.AbstractProxyHandler.invoke(AbstractProxyHandler.java:81) at com.sun.proxy.$Proxy4.prepareStatement(Unknown Source) at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$5.doPrepare(StatementPreparerImpl.java:147) at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:166) at org.hibernate.engine.jdbc.internal.StatementPreparerImpl.prepareQueryStatement(StatementPreparerImpl.java:145) at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1749) at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1726) at org.hibernate.loader.Loader.doQuery(Loader.java:852) at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:293) at org.hibernate.loader.Loader.doList(Loader.java:2411) at org.hibernate.loader.Loader.doList(Loader.java:2397) at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2227) at org.hibernate.loader.Loader.list(Loader.java:2222) at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:470) at org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:355) at org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:195) at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1247) at org.hibernate.internal.QueryImpl.list(QueryImpl.java:101) at org.hibernate.internal.AbstractQueryImpl.uniqueResult(AbstractQueryImpl.java:905) at com.goldencode.p2j.persist.Persistence.load(Persistence.java:1723) at com.goldencode.p2j.persist.RandomAccessQuery.executeImpl(RandomAccessQuery.java:3187) at com.goldencode.p2j.persist.RandomAccessQuery.execute(RandomAccessQuery.java:2493) at com.goldencode.p2j.persist.RandomAccessQuery.first(RandomAccessQuery.java:1161) at com.goldencode.p2j.persist.RandomAccessQuery.first(RandomAccessQuery.java:1067) at com.goldencode.testcases.<customer>_schema.TestRoot$1.body(TestRoot.java:42) at com.goldencode.p2j.util.BlockManager.processBody(BlockManager.java:7048) at com.goldencode.p2j.util.BlockManager.topLevelBlock(BlockManager.java:6881) at com.goldencode.p2j.util.BlockManager.externalProcedure(BlockManager.java:221) at com.goldencode.p2j.util.BlockManager.externalProcedure(BlockManager.java:203) at com.goldencode.testcases.<customer>_schema.TestRoot.execute(TestRoot.java:28) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at com.goldencode.p2j.util.Utils.invoke(Utils.java:1234) at com.goldencode.p2j.main.StandardServer$MainInvoker.execute(StandardServer.java:1701) at com.goldencode.p2j.main.StandardServer.invoke(StandardServer.java:1201) at com.goldencode.p2j.main.StandardServer.standardEntry(StandardServer.java:364) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at com.goldencode.p2j.util.MethodInvoker.invoke(MethodInvoker.java:76) at com.goldencode.p2j.net.Dispatcher.processInbound(Dispatcher.java:694) at com.goldencode.p2j.net.Conversation.block(Conversation.java:319) at com.goldencode.p2j.net.Conversation.run(Conversation.java:163) at java.lang.Thread.run(Thread.java:745)
First I thought this is a MSSQL issue, but after this test-case it's clear that it's also a H2 issue. PostgreSQL is not affected because the ddr declares the correct functions names (and they are resolved directly by SQL rather than looked up when preparing the HQL/SQL).
In details:
When initializing the database, the com.goldencode.p2j.persist.pl.Functions.trimWS()
is registered to HQLPreprocessor
with its unique name (in this case trimWS
, same as method as it is not overloaded).
). Such mapping is not found so the error state is printed to console and the query is aborted with error. In order to find the right SQL function, the name of the function from generated hql / java code MUST match the name of the method implementation from
At runtime, when looked up, the name of the function from generated hql is used (@trimwsOperators
/ Functions
classes because this is how the lookup is performed (the mapping key).
Adding some annotation to declared functions is not useful at runtime lookup, but can be used for automation for extracting pl ddr file and similar solution for MSSQL. I investigated both pl java files and I found only a few methods affected: chr
/ toChr
, ltrimws
/ ltrimWS
, trimws
/ trimWS
, replace
/ replaceText
. A solution would be to rename these methods or hql intermediary function name to match each-other.
Alternatively, we can use the annotation, but when registering the functions/operators with HQLPreprocessor
to add another parameter, the name of the HQL function. The name of the Method
registered is not important, only its signature.
LE: GES replaced customer's name with <customer>
for this entry.
#2 Updated by Ovidiu Maxiniuc almost 10 years ago
- % Done changed from 0 to 70
- File om_upd20140729a.zip added
- Status changed from New to WIP
The provided solution uses HQLFunction
annotation to make available at runtime the name of the function used in generated HQL that a specified method must be called. It will be registered at database initialization and when a function name is encountered in HQLPreprocessor
it is looked-up in the internal overload mapping and the correct SQL alias is retrieved.
The HQLFunction
is tested when a method is registered. Because it supports immutable
/volatile
attribute, it also allows p2j.ddr
to be automatically generated at conversion time. For simplicity, the name of HQL function obtained used in HQL code is optional, if not specified then it matches the name of the method.
Example:
find first t1 where trim(c1) = "v1".
Will be converted as
new FindQuery(t1, "trimws(t1.f1) = 'v1'", null, "t1.id asc").first();
The Functions.trimWS
is annotated with HQLFunction(name="trimws")
. So at database initialization H2 will register "db:trimws:TEXT" to "trimWS_1" and create the trimWS_1
as alias to Functions.trimWS
.
When HQLPreprocessor
parses the hql and encounters the trimws
function it is looked-up (in manuallyOverload
) and will replace rewrite the hql as "trimWS_1(t1.f1) = 'v1'". This will be recognized as alias for our method successfully executes the query.
#3 Updated by Eric Faulhaber over 9 years ago
Ovidiu, were the changes in this update rolled up into om_upd20140811a.zip (#2332)?
#4 Updated by Ovidiu Maxiniuc over 9 years ago
Yes, they are part of om_upd20140811a.zip (#2332).
It's hard for me to maintain them in separate updates, at some point multiple changes occur on the same file.
#5 Updated by Eric Faulhaber over 9 years ago
Makes sense. So no need for a separate code review here. Once that update (0811a) is finished/tested, we can close out this issue.
#6 Updated by Ovidiu Maxiniuc over 8 years ago
- % Done changed from 70 to 100
- Assignee set to Ovidiu Maxiniuc
The proposed update was merged to 2332a task branch from #2332 and committed to trunk. This can be closed now.
#7 Updated by Eric Faulhaber about 8 years ago
- Status changed from WIP to Closed