Migration to SpringBoot 3: trunc a date with oracle driver no longer works (hibernate) - spring

I am currently migrating a SpringBoot 2.7 application to SpringBoot 3. The following query is used within a SpringData repository:
#Query("select b from #{#entityName} b where (trunc(b.date) <= trunc(:date))")
List<T> findByDate(LocalDateTime date);
While this works great in SpringBoot 2.7, with SpringBoot 3 the following message is thrown:
org.hibernate.QueryException: Parameter 1 of function trunc() has type NUMERIC, but argument is of type java.time.LocalDateTime
Unfortunately, a simple migration to datetrunc was unsuccessful:
Error Msg = ORA-00904: "DATETRUNC": ungültige ID
Does anyone have a solution for this?
Best regards

So, as I noted in my previous answer, there's no standard HQL function for date truncation. That's because it would be quite difficult to implement in most SQL dialects (I have not really investigated to see quite how difficult, but it's at least nontrivial.)
However, just especially for you, in Hibernate 6.2, which should go into CR today, what I have done is added undocumented (but tested) support for the date_trunc() function under Postgres, DB2, Oracle, and H2. On Oracle, this translates to trunc(), of course.
For example, you could write:
date_trunc(year,current_timestamp)
When I say it's "undocumented" I mean you use it at your own risk. (The documented way to do this remains to use a FunctionContributor.)
I hope that helps.
UPDATE:
Oh and by the way, I just noticed that you're not actually using the full form of the trunc() function in your query. You're actually just stripping off the time part of a timestamp.
There's actually multiple ways to do that in HQL without needing to use the Oracle-specific trunc() function. (But of course trunc()/date_trunc() can do more things that you're not using here.)
JPA-standard way
One of the improvements I added to the new JPA 3.1 specification was to let you write:
extract(date from current_timestamp)
To strip off the time part of the timestamp.
HQL alternative
But you can also do it using the HQL cast() function if you prefer:
cast(current_timestamp as Date)
These two options translate to the same SQL on Oracle.

In Hibernate 6 we started checking the argument types of HQL functions.
Since trunc(numeric,places) is a very common function across many dialects of SQL, we register it as one of the known functions, though we have not yet promoted it to a “standard” HQL function (perhaps we should).
On the other hand, Oracle’s trunc(date) is extremely specific to Oracle and is more like the date_trunc() function on DB2 and Postgres. We have not (so far) attempted to standardize on any sort of function for timestamp truncation, and I don’t consider it a high priority. This function is not registered by OracleDialect.
So, therefore, if you try to call trunc() on a Date, you will get a typing error.
Now, in general, in Hibernate 6.x:
We do not guarantee that Hibernate Dialects know about every single SQL function in your database, and you can't depend on that.
Instead we have a rather long list of documented HQL functions that we promise work portably across every database we support. (Right now trunc() is not on that list, but it almost made it onto the list.)
And that's perfectly fine, because we also provide APIs that make it very easy to register new SQL functions, either platform-specific functions like this one, or functions you've written yourself, either by:
writing a custom Dialect, or
providing a FunctionContributor.
https://docs.jboss.org/hibernate/orm/6.1/userguide/html_single/Hibernate_User_Guide.html#hql-user-defined-functions
Alternatively, if that's too much work, you can just use the JPA-standard syntax for calling native SQL functions, which is function('trunc', date, 'YEAR'), but I consider this a bit unlovely.

I'm using Oracle database and after migration to new hibernate I had the same issue.
I solved it by overriding org.hibernate.dialect.OracleDialect and adding ORACLE_TRUNC function to a functionRegistry. I've used the same definition trunc function definition as in Hibernate < 6 Oracle8iDialect.
public class CustomOracleDialect extends OracleDialect {
public CustomOracleDialect() {
super();
}
#Override
public void initializeFunctionRegistry(FunctionContributions functionContributions) {
super.initializeFunctionRegistry(functionContributions);
functionContributions.getFunctionRegistry().register("ORACLE_TRUNC", new StandardSQLFunction("trunc"));
}
}
Configure hibernate to use this dialect inapplication.properties / application.yml file:
spring:
jpa:
database-platform: com.example.CustomOracleDialect
In your queries use ORACLE_TRUNC() instead of TRUNC().
I tried using DATE_TRUNC(date, my_date) function from hibernate 6.2 RC2 as Gavin King said - but it transformed my query to CAST(my_date AS DATE) instead of TRUNC(my_date) causing date comparison issues.

Related

User-Defined Function Nested in Macro - Framework Manager

We are trying to create a dynamic query subject filter. To do this, we are trying to nest an Oracle user-defined function inside of a macro.
Example query subject filter:
#strip(ORACLE_USER_DEFINED_FUNCTION())#
We have imported the oracle function ORACLE_USER_DEFINED_FUNCTION into Framework Manager. The function returns a VARCHAR2 of the desired expression. For testing purposes, this function is simply returning VARCHAR2 value of '1=1' (the single quotes are not part of the VARCHAR2 return value).
The idea being that we want the query subject filter expression to be dynamically generated at run-time so the resulting query contains '...WHERE 1=1'. The strip macro is the mechanism to pre-process and invoke the user-defined function before the query is sent to the database.
However, when attempting to verify/check the query subject filter we receive the following error.
XQE-GEN-0018 Query Service internal error has occurred, please see the log for details.
I'm trying to get a hold of the query service log, but don't yet have it.
Perhaps there is some casting needed to convert the oracle VARCHAR2 output from the function to an IBM/Cognos string that is acceptable input for the IBM/Cognos macro.
Your assistance is appreciated. Thanks in advance.
Using Oracle 12c and Cognos 11.1.
With the exception of the queryValue macro function, macros are evaluated prior to accessing the database. This means the macro does not know what the Oracle UDF is or what its supposed to do. If you are able to call the UDF via a FM query subject you maybe able to get away with something similar to the queryValue answer found here:
Cognos 11.1.7 Framework manager change the table for the query subject, type data

How to use Dapper LINQ with TableDirect (without embedded SQL) with ORACLE?

I tried DapperExtensions, Dapper.Extensions.Linq and linq2dapper to no avail. I will try Dapper.SimpleCRUD-with-Oracle. I will probably settle with a Stored Procedure instead. I want to use TableDirect with no embedded SQL statement. How can I use Dapper and Linq with a TableDirect? Or, how can I use TableDirect without embedded SQL, and filter a table?
Following are my problems:
I could not create Predicate without run time error.
I need missing configuration
I got ORA error about table saying "column not correct, runtime error".
How to use Dapper LINQ with TableDirect (without embedded SQL) with ORACLE?
You can achieve this with simple Dapper. For example, look at the following code from Dapper:
public static IEnumerable<T> Query<T>(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = default(int?), CommandType? commandType = default(CommandType?));
Look at the last commandType parameter. It supports the TableDirect value that you are looking for.
As far as other extensions of Dapper you mentioned in question, I do not think they will support it. I know for sure Dapper Extensions do not support it; not sure about others.
This is because, those extensions are basic query generators written over Dapper. So, you are using them for generating the query and in that case, that parameter value will/should be Text. If you want to use other values, bypass the extension and use simple Dapper.
If you want to simply provide a table name or stored procedure name, why use query generator? Just use Dapper.
I used //https://github.com/jmo21/Dapper.SimpleCRUD-with-Oracle-/blob/master/Dapper.SimpleCRUD/SimpleCRUD.cs . No nuget package for this ORACLE dialect. It just obfuscates the WHERE clause, and it is an answer, when I the organization probably will not like SELECT.. FROM ... WHERE...
We don't have SQL injection possible in any case.

Is there a way to get FIND_IN_SET functionality in MonetDB

I am migrating some of my workflows from MySQL to MonetDB.
One thing that has hampered my progress so far is the lack of FIND_IN_SET functionality in MonetDB:
> SELECT FIND_IN_SET('b', 'a,b,c,d');
2
I was relying on this functionality for converting domain definitions between two alignments.
Any idea how I could get this function in MonetDB with reasonable performance?
You could try using a regular expression. I recommended this to someone using MySQL who wanted to find more than one needle in a comma-delimited haystack, perhaps it could be adapted to MonetDB?
SELECT name FROM table WHERE CONCAT(',', DataID, ',') REGEXP ',(222|777|400),'

Can I define the target table for int-jdbc:outbound-channel-adapter based on the received message?

I´m using Spring Integration JDBC support to persist a message in one of several tables (>20) depending on a certain condition (stored in the message headers as "table"):
<int:channel id="cmTablesJdbcChannel"></int:channel>
<int-jdbc:outbound-channel-adapter channel="cmTablesJdbcChannel"
id="cmTableJdbcOutputAdaptor" data-source="datasource"
query="insert into TABLE_NAME values (int_id, parent_int_id, name) values (:headers[int_id],:headers[parent_int_id],:headers[name])">
</int-jdbc:outbound-channel-adapter>
I have tried to replace TABLE_NAME by several expressions but none worked:
${headers['table']}
#{headers['table']}
:[headers['table]}
I´m trying to avoid the usage of 20 different outbound channel adaptors and reuse a single one but dynamically setting the name of the table to be used. Do you know if it is possible?
There were similar questions but related to the parameters to be used: How can I create a dynamic query for Spring Integration JDBC outbound-channel-adapter?
No, it doesn't work now and TABLE_NAME can't be as a parameter.
Feel free to raise JIRA issue to consider something like query-expression to build the INSERT/UPDATE SQL at runtime against request message.
In meantime you should use NamedParameterJdbcTemplate from the some custom POJO to be used from the <outbound-channel-adapter> or like a complex expression:
<service-activator input-channel="cmTablesJdbcChannel" output-channel="nullChannel"
expression="#jdbcTemplate.update('insert into ' + headers.table + ' (int_id, parent_int_id, name) values (:int_id,:parent_int_id,:name)', headers)"/>
Note, don't use direct SQL expression building with the parameter values. The parametrized variant with : is preferable way for any RDBMS. It will be compiled on the server side (indexes, query plan etc.) and reused for all other upcoming executions.

Nhibernate Update timestamp

Is there a way to do
"UPDATE Item SET start_date = CURRENT_TIMESTAMP" ?
in Nhibernate without using hql/sql.
I am trying to avoid hql/sql because the rest of my code is in criteria. I want to do something like :
var item = session.get<Item>(id)
item.start_date = current_timestamp
There are two ways and sql is correct one.
Either you will
load all entities, change, update and commit, or
write sql query and let dbms handle most of the work
I am trying to avoid hql/sql because the rest of my code is in criteria
That is not a valid argument. Criteria is an API intended for relational search, and it does not support mass updates.
Different tasks, different APIs.
In this case, you can use either HQL or SQL, as the syntax is the same. I recommend the former, because you'll be using your entity/property names instead of table/column ones.

Resources