hibernate query doesn't get translated on saas sql properly - sql

I'm using below query in a Spring Boot app repository. Although it runs fine locally, and the queries return expected values both on h2 console and SaaS SQL SSMS, but I get the error below when I call the API that uses this repository.
org.hibernate.exception.SQLGrammerException: Couldn't extract
ResultSet
here is the hibernate query:
#Query("FROM xyzTable t1 where (t1.field1, t1.field2) in (SELECT Max(t2.field1), t2.field2 FROM xyzTable t2 GROUP BY t2.field2) ORDER BY t1.field2")
I think it has something to do with "(t1.field1, t1.field2)" part of the query. If I use one field in the WHERE clause, it won't object.
any ideas?

Related

Access pass-through query to Oracle using WITH

I tried to run this in TOAD and sqldeveloper is ok, but when I run in Access with passthrough query I got an error:
"pass-through query with returnsRecords property"
hereby the code
With T1 as (select * from baasa),
T2 as (select * from lalala),
T4 as (select * from babab)
select distinct T1.C11 as something, T4.C5 as somewhere, T2.C2 as what
from T1,T2,T4
Where T1.C11=T4.C5 and T1.C10=T2.C2
or in fiddle: http://sqlfiddle.com/#!4/84c06/2
can anyone help me?
Your (amended) query works fine in SQL Server 2008 R2, and it also works fine as an Access pass-through query to same. Verify that the Returns Records property of the query is set to Yes (as seen below) and try running the pass-through query again. As I said in my initial comment to your question, if it works for SQL Server then I see no reason why it shouldn't work for Oracle.
I'm pretty sure your query has a syntax error: there's no SELECT nor FROM clause before the WHERE clause...

Can I get the SQL string from a JPA Query object?

May I know how can I get the sql from a JPA query? or let's say, convert the JPA query to a SQL string? Thank you very much!
For Eclipselink: you can extract the SQL the following way:
query.unwrap(EJBQueryImpl.class).getDatabaseQuery().getSQLString()
It works only after the query has been executed.
If you only want to know how your JPQL or Criteria Query gets translated to the SQL dialect of your database you can enable fine grained logging in the persistence xml and then look into your log files.
The property name and value depends on your JPA implementation. Here is an example of the relevant part of persistence.xml for EclipseLink:
<properties>
<property name="eclipselink.logging.level" value="FINEST"/>
</properties>
JPA Specification
While there is not standard JPA functionality to achieve this goal, you can still extract the SQL query from a JPQL or Criteria API Query using the JPA provider-specific API.
Hibernate Types
Starting with the 2.9.11 version, the Hibernate Types open-source project offers the SQLExtractor utility that allows you to get the SQL query from any JPQL or Criteria API query, no matter you are using Hibernate 5.4, 5.3, 5.2, 5.1, 5.0, 4.3, 4.2, or 4.1.
Get the SQL statement from a JPQL Query
Let's assume we have the following JPQL query:
Query jpql = entityManager.createQuery("""
select
YEAR(p.createdOn) as year,
count(p) as postCount
from
Post p
group by
YEAR(p.createdOn)
""", Tuple.class
);
With Hibernate Types, extracting the Hibernate-generated SQL query is as simple as that:
String sql = SQLExtractor.from(jpql);
And, if we log the extracted SQL query:
LOGGER.info("""
The JPQL query: [
{}
]
generates the following SQL query: [
{}
]
""",
jpql.unwrap(org.hibernate.query.Query.class).getQueryString(),
sql
);
We get the following output:
- The JPQL query: [
select
YEAR(p.createdOn) as year,
count(p) as postCount
from
Post p
group by
YEAR(p.createdOn)
]
generates the following SQL query: [
SELECT
extract(YEAR FROM sqlextract0_.created_on) AS col_0_0_,
count(sqlextract0_.id) AS col_1_0_
FROM
post p
GROUP BY
extract(YEAR FROM p.created_on)
]
Notice that we unwrapped the JPA Query to the Hibernate org.hibernate.query.Query interface which provided the getQueryString method we can use to log the associated JPQL query string.
Get the SQL statement from a JPA Criteria API Query
The SQLExtractor is not limited to JPQL queries. You can use it with Criteria API queries as well, as illustrated by the following example:
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<PostComment> criteria = builder.createQuery(PostComment.class);
Root<PostComment> postComment = criteria.from(PostComment.class);
Join<PostComment, Post> post = postComment.join("post");
criteria.where(
builder.like(post.get("title"), "%Java%")
);
criteria.orderBy(
builder.asc(postComment.get("id"))
);
Query criteriaQuery = entityManager.createQuery(criteria);
String sql = SQLExtractor.from(criteriaQuery);
assertNotNull(sql);
LOGGER.info("""
The Criteria API, compiled to this JPQL query: [
{}
]
generates the following SQL query: [
{}
]
""",
jpql.unwrap(org.hibernate.query.Query.class).getQueryString(),
sql
);
When running the above test case, we get the following SQL query:
- The Criteria API, compiled to this JPQL query: [
select
pc
from
PostComment as pc
inner join
pc.post as p
where
p.title like :param0
order by
pc.id asc
]
generates the following SQL query: [
SELECT
pc.id AS id1_1_,
pc.post_id AS post_id3_1_,
pc.review AS review2_1_
FROM
post_comment pc
INNER JOIN
post p ON pc.post_id=p.id
WHERE
p.title LIKE ?
ORDER BY
pc.id ASC
]
The Criteria API is first compiled to a JPQL query, as illustrated by the getQueryString() method call.
The intermediary JPQL query is further translated to an SQL query, which is properly resolved by the SQLExtractor utility.
Following Karol's answer - It is possible to retrieve the SQL before executing the statement in EclipseLink :
Session session = em.unwrap(JpaEntityManager.class).getActiveSession();
DatabaseQuery databaseQuery = query.unwrap(EJBQueryImpl.class).getDatabaseQuery();
databaseQuery.prepareCall(session, new DatabaseRecord());
Record r = databaseQuery.getTranslationRow();
String bound = databaseQuery.getTranslatedSQLString(session, r);
String sqlString = databaseQuery.getSQLString();
To retrieve the SQL String During/After execution it is probably best to do so using persistence properties rather than in-code :
<property name="eclipselink.logging.parameters" value="true"/>
<property name="eclipselink.logging.level" value="FINE"/>
Beside enabling the logging like #Matt Handy mentioned it is also possible to get the SQL String for a specific query with eclipselink at runtime as described here.
Using Hibernate as a provider you can enable the following properties:
hibernate.show_sql
Write all SQL statements to console. This is an alternative to setting the log category org.hibernate.SQL to debug. (e.g. true | false)
hibernate.format_sql
Pretty print the SQL in the log and console. (e.g. true | false)
Or, as stated above you can enable logging to the debug level for the logger
org.hibernate.SQL
Log all SQL DML statements as they are executed
You are probably interested if there's a way to 'extract' JPQL string (either with placeholders for params, or final JPQL after params are filled-in) out of javax.persistence.Query (one of it's possible subclasses to be more precise),- in this case it's not possible according to JPA specification contract. However, this hypothetically might be possible by JPA implementation (e.g., NamedQueryImpl could have #toJPQLString(), which you could access via casting), but I doubt about that.
And even if it's possible I don't think it's a good code performing such manipulations. I would suggest finding another design solutions (and for that you could specify what kind of actual problem do you have). E.g., if you are building your queries dynamically, JPA Criteria API could be used for that, and along with 'building' JPA query, you could maintain your internal data structure reflecting the logic of your query.
This blog contains instructions: http://narcanti.keyboardsamurais.de/hibernate-hql-to-sql-translation.html
You could use p6spy. At the following link there are instructions for its operation:
https://p6spy.readthedocs.io/en/latest/install.html

SQL Query in Hibernate

I'm carrying out a SQL query which looks like:
SELECT thi.*
FROM track_history_items thi
JOIN artists art
ON thi.artist_id = art.id
WHERE thi.type = TrackBroadcast
Group By art.name
ORDER thi.created_at DESC
This works fine when I run it directly on my database from MySql Workbench, but when I run in through Hibernate, I get a No Dialect mapping for JDBC type: -1 error.
Anyone have any ideas what could be causing it?
Probably one or more of the columns in the query is not supported by the mysql dialect... try expanding the * and add one column at a time until you find the offending one.
Then it is just a matter of deciding whether you need that column or not.

How do I construct a cross database query in MySQL?

I've got two databases on the same server. The Google gave me some hints but there wasn't anything "official" that I could find. Could someone point me to the documentation that explains how to do this? An explanation using PHP would be useful as well. Thanks!
I've got two databases on the same server. ...How do I construct a cross database query in MySQL?
You access other databases on the same MySQL instance by prefixing the table with the appropriate database name. IE:
SELECT *
FROM this_database.table_1 t1
JOIN that_database.table_2 t2 ON t2.column = t1.column
Keep in mind
A query executes with the credentials of the authentication used to set up the
connection. If you want to query two tables simultaneously across two (or more)
databases, the user used to run the query will need SELECT access to all
databases involved.
Reference:
Identity Qualifiers
SELECT * FROM DB1.myTable1 AS db1, DB2.myTable2 AS db2
http://www.dottedidesign.com/node/14 provides the following example:
SELECT
arbogast.node.nid as anid,
mcguffin.node.nid as mnid,
arbogast.node.title as atitle,
mcguffin.node.title as mtitle
FROM arbogast.node, mcguffin.node
WHERE arbogast.node.nid = 1
AND mcguffin.node.nid = arbogast.node.nid;
Where arbogast and mcguffin are different databases.

Glassfish Eclipselink join-fetch hint not working

I'm having real difficulty getting the eclipselink.join-fetch hint to work in glassfish.
I have a Client object that contains a collection of Task objects and the Task object has a collection of WorkPeriod objects.
My code looks like this:
Query query = entityManager.createQuery("select client from Client client left join fetch client.tasks");
//Set hint to allow nested fetch joins
query.setHint("eclipselink.join-fetch","client.tasks.workPeriods");
List<Client> clients = query.getResultList();
But no matter what I do when I set the TOPLINK debug level to fine it always shows that the SQL which is actually run is:
SELECT t0.ID, t0.NAME, t1.ID, t1.DESCRIPTION FROM CLIENT t0 LEFT OUTER JOIN (CLIENT_TASK t2 JOIN TASK t1 ON (t1.ID = t2.tasks_ID)) ON (t2.Client_ID = t0.ID)
Clearly not doing the third tier of the join fetch.
Has anyone else had problems with this... or is it just me :-(
Any help or hints (no pun intended) would be much appreciated.
OK, after 8 hours of frustration I've got to the bottom of it.
Glassfish V2 doesn't use EclipseLink as it's persistence provider, it uses Toplink Essentitals. Unfortunately Toplink essentials doesn't provide a join-fetch hint (I was very confused by the following link which made me think it did: https://glassfish.dev.java.net/issues/show_bug.cgi?id=1200 although this is obviously a feature request NOT a feature).
So it would appear that what I'm attempting to do is not possible and if I want to do multi-level eager fetch in glassfish I'm going to have to get the EntityManagers delegate and use the toplink essentials Expressions directly.