Query.setparameter using TemporalTipe.Time - java

I wanna do SELECT e FROM Pedidos e WHERE e.diaPedido = :diaPedido AND e.horaPedido = :horaPedido.
When I write parameters use query.setParameter("diaPedido", fechaEscogida, TemporalTipe.DATE) and query.setParameter("horaPedido", horaEscogida, TemporalTipe.TIME) but i don´t know why second filter Temporal.TIME doesn´t work because still compare like TIMESTAMP.
I use eclipseLink 2.3.0 and javax.persistence 2.0.1.
diaPedido and horaPedido are both Date in oracle database.

If you want to just compare the time portion of a TIMESTAMP column, you need to use a database function.
In EclipseLink (>=2.4) you can use EXTRACT or CAST, or the FUNCTION/FUNC operator to call a database function.
See,
http://java-persistence-performance.blogspot.com/2012/05/jpql-vs-sql-have-both-with-eclipselink.html

Related

Criteria JPA - Call Postgres CAST function

I'm trying to call a Postgres function with Criteria but it's not working. I need to use the LIKE clause in a UUID field, so I need to convert into VARCHAR first.
The result I need:
SELECT * FROM my_table WHERE cast(uuid as varchar(36)) like '%1234%';
What I'm doing in Criteria:
final Path<UUID> uuidField = from.get("uuid");
var cast = cb.function("cast", String.class, uuidField, cb.literal("as varchar(36)"));
cb.like(cast, String.format("%%%s%%", stringValue));
The query which is being generated:
HQL: select generatedAlias0 from com.MyTable as generatedAlias0 where function('cast', generatedAlias0.uuid, 'as varchar(36)') like '%1234%' order by generatedAlias0.name asc
Error:
2022-08-08 18:38:48,549 WARN [io.ver.cor.imp.BlockedThreadChecker] (vertx-blocked-thread-checker) Thread Thread[vert.x-eventloop-thread-9,5,main] has been blocked for 2393 ms, time limit is 2000 ms: io.vertx.core.VertxException: Thread blocked
at antlr.ASTFactory.make(ASTFactory.java:342)
at antlr.ASTFactory.make(ASTFactory.java:352)
at org.hibernate.hql.internal.antlr.HqlBaseParser.jpaFunctionSyntax(HqlBaseParser.java:4633)
at org.hibernate.hql.internal.antlr.HqlBaseParser.primaryExpression(HqlBaseParser.java:1075)
The log is not so clear (I'm using Quarkus + Hibernate Reactive), but I suspect it crashed in database because the function('cast', generatedAlias0.uuid, 'as varchar(36)').
I think it should be something like: function('cast', generatedAlias0.uuid, as varchar(36)) (without quotes). But I don't know how to achieve this result to test my theory.
How can I call this CAST function?
After investigating some possible solutions (I'm avoiding to create custom database routines) I found something interesting in a answer from another question:
Currently JPA does not have APIs for replace() and cast(string as numeric). But you can use CriteriaBuilder.function(...) to create database native functions if database portability is not critical.
Source: JPA criteria builder: how to replace and cast a string to numeric in order-by?
I don't know if this is documented is some place, but assuming that there is no way to call CAST(x AS y) using Criteria, I tried a workaround to force the UUID to VARCHAR cast without using the probably unsupported CAST function.
I tested this direct SQL query to database:
SELECT * FROM my_table WHERE concat(uuid, '') like '%123%';
And it works. This CONCAT forces the cast to VARCHAR and the LIKE function does his job. Knowing this, I did:
final Path<UUID> uuidField = from.get("uuid");
var cast = cb.function("concat", String.class, uuidField, cb.literal(""));
cb.like(cast, String.format("%%%s%%", stringValue));
Worked perfectly. I hope this help someone else.
As #HaroldH said, it's a weird requirement, but happened in my project.

Set the database current timestamp while inserting using JOOQ

I am using the following code segment to do the insertion using JOOQ's UpdatableRecord.
public void acknowledgeDisclaimer(AcknowledgeDisclaimerReq acknowledgeDisclaimerReq) {
DisclaimerRecord disclaimerRecord = dslContext.newRecord(Disclaimer.DISCLAIMER);
disclaimerRecord.setDisclaimerForId(acknowledgeDisclaimerReq.getDealListingId());
disclaimerRecord.setDisclaimerForType("DEAL");
disclaimerRecord.setAcceptedAt(LocalDateTime.now());
disclaimerRecord.setAcceptedByOwnerId(acknowledgeDisclaimerReq.getLoggedInOwnerId());
int count = disclaimerRecord.store();
log.info("Inserted entry for disclaimer for deal: {}, owner: {}, id {}, insertCount: {}", disclaimerRecord.getDisclaimerForId(), disclaimerRecord.getAcceptedByOwnerId(), disclaimerRecord.getId(), count);
}
When setting the AcceptedAt data, I want to use the database's current timestamp instead of passing the JVM timestamp. Is there any way to do that in JOOQ?
UpdatableRecord.store() can only set Field<T> => T key/values, not Field<T> => Field<T>, so you cannot set an expression in your record. You can obviously run an explicit INSERT / UPDATE / MERGE statement instead.
Using triggers
The best way to ensure such a timestamp is set to the database timestamp whenever you run some specific DML on the table is to use a database trigger (you could make the trigger watch for changes in the ACCEPTED_BY_OWNER_ID value)
If you can't do this on the server side (which is the most reliable, because it will behave correctly for all database clients, not just the JDBC/jOOQ based ones), you might have a few client side options in jOOQ:
Using jOOQ 3.17 client side computed columns
jOOQ 3.17 has added support for stored (or virtual) client side computed columns, a special case of which are audit columns (which is almost what you're doing).
Using this, you can specify, for example:
<forcedType>
<generator><![CDATA[
ctx -> org.jooq.impl.DSL.currentTimestamp()
]]></generator>
<includeExpression>(?i:ACCEPTED_AT)</includeExpression>
</forcedType>
The above acts like a trigger that sets the ACCEPTED_AT date to the current timestamp every time you write to the table. In your case, it'll be more like:
<forcedType>
<generator><![CDATA[
ctx -> org.jooq.impl.DSL
.when(ACCEPTED_BY_OWNER_ID.isNotNull(), org.jooq.impl.DSL.currentTimestamp())
.else_(ctx.table().ACCEPTED_AT)
]]></generator>
<includeExpression>(?i:ACCEPTED_AT)</includeExpression>
</forcedType>
See a current limitation of the above here:
https://github.com/jOOQ/jOOQ/issues/13809
See the relevant manual sections here:
Client side computed columns
Audit columns
Should be something like disclaimerRecord.setAcceptedAt(DSL.now());

Jooq update return value

I try to update rows in table and get results after.
If I do
dsl.update(TABLE)
.set(TABLE.ROW, newRow)
.where(TABLE.ROW_2.eq(
dsl.select(ANOTHER_TABLE.ID)
.from(ANOTHER_TABLE)
.where(ANOTHER_TABLE.GUID.eq(guid))
)).execute()
it returns 1. But if I do
dsl.update(TABLE)
.set(TABLE.ROW, newRow)
.where(TABLE.ROW_2.eq(
dsl.select(ANOTHER_TABLE.ID)
.from(ANOTHER_TABLE)
.where(ANOTHER_TABLE.GUID.eq(guid))
)).returningResult(TABLE.ROW_3).fetchOne()
it returns empty result. But I want to get TABLE.ROW_3 after update. Whats the problem?
Vertica doesn't support UPDATE .. RETURNING like PostgreSQL, as can be seen in the Vertica docs:
https://www.vertica.com/docs/9.2.x/HTML/Content/Authoring/SQLReferenceManual/Statements/UPDATE.htm
The jOOQ documentation of UpdateReturningStep::returningResult reflects this by not listing SQLDialect.VERTICA in its #Support annotation:
#Support({AURORA_POSTGRES,COCKROACHDB,DB2,FIREBIRD,ORACLE,POSTGRES,SQLSERVER})
There's currently no workaround for this. If you want to avoid using such API, you could use the jOOQ-checker module in your build to produce compilation errors whenever you use API that is not supported by VERTICA

Problems with queryBuilder greenDAO

I am using latest version of GreenDAO... I am missing something on using the data from the DB.
I need to prevent the creation of records that have the same PROFILE_NUMBER. Currently during testing I have inserted 1 record with the PROFILE_NUMBER of 1.
I need someone to show me an example of how to obtain the actual value of the field from the db.
I am using this
SvecPoleDao svecPoleDao = daoSession.getSvecPoleDao();
List poles = svecPoleDao.queryBuilder().where(SvecPoleDao.Properties.Profile_number.eq(1)).list();
and it obtains something... this.
[com.example.bobby.poleattachmenttest2_workingdatabase.db.SvecPole#bfe830c3.2]
Is this serialized? The actual value I am looking for here is 1.
Here is the solution.You'll need to use listlazy() instead of list().
List<SvecPole> poles = svecPoleDao.queryBuilder().where(SvecPoleDao.Properties.Profile_number.eq(1)).listLazy();

DB2 sql error code -245 for a date

I am reading several sql queries from database inside a loop as below:
{ // start of loop
Map<String, Object> queryRS = this.jdbcTemplate.queryForMap(this.querySql,queryParam);
String query = (String) queryRS.get("QUERY");
// code here as explained below
} // end of loop
The query returned could have any number of parameters. However, in all of them I have to set same date as the parameter.
For this I am counting the number of occurrence of character ? in the query and creating an Object array with same date repeated as below.
String date = '2010-12-31';
int numArgs = StringUtils.countMatches(query, "?");
String[] paramArgs = new String[numArgs];
for (int i = 0; i < numArgs; i++) {
paramArgs[i] = date;
}
After which I am executing the query as below:
SqlRowSet myRowSet = this.jdbcTemplate.queryForRowSet(query,(Object[]) paramArgs);
However, this is giving error when the query has a Date(?) function.
com.ibm.db2.jcc.am.SqlSyntaxErrorException: DB2 SQL Error: SQLCODE=-245, SQLSTATE=428F5, SQLERRMC=DATE;1, DRIVER=3.64.96
The description of above error is:
An untyped parameter marker is passed to a function and there are two or more possible candidate functions to resolve to during function resolution.
What is the solution to this?
Thanks for reading!
I suppose you are using String jdbcTemplate.
I had not the same but a similar problem: the function was char(?) and I was
passing an integer argument to it.
I was using a Old framework Ibatis 2.x (now I use MyBatis 3.x).
The framework was not the error cause.
On Ibatis I pass the argument so: char(#value:INTEGER#)
On my develop server all was work well but on remote production server I get your same error.
The problem was caused by the JDBC driver version 4.x on develop end 1.x on production.
To solve my problem I have two ways:
change the production driver (but I cannot)
use a different call: char('$value:INTEGER$') (I do this)
In IBATIS/MYBATIS framework, if value is 123, char('$value:INTEGER$') is translate to sql char('123') so solve my problem and when production change driver I can put back to char(#value:INTEGER#).
You have a similar problem. Try to:
look at the driver version
use type like in spring reference, sql type, spring manual
I do not use direct access to jdbcTemplate but I think that you have not to put args in string, you have to create a Date variable end put it in an Object array.
I hope that this can help you.

Categories

Resources