io.hypersistence.utils.hibernate.query.SQLExtractor Maven / Gradle / Ivy
Show all versions of hypersistence-utils-hibernate-63 Show documentation
package io.hypersistence.utils.hibernate.query;
import io.hypersistence.utils.common.ReflectionUtils;
import jakarta.persistence.Query;
import org.hibernate.query.spi.DomainQueryExecutionContext;
import org.hibernate.query.spi.QueryImplementor;
import org.hibernate.query.spi.QueryInterpretationCache;
import org.hibernate.query.spi.SelectQueryPlan;
import org.hibernate.query.sqm.internal.ConcreteSqmSelectQueryPlan;
import org.hibernate.query.sqm.internal.DomainParameterXref;
import org.hibernate.query.sqm.internal.QuerySqmImpl;
import org.hibernate.query.sqm.internal.SqmInterpretationsKey;
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
import org.hibernate.sql.exec.spi.JdbcOperationQuerySelect;
import java.util.function.Supplier;
/**
* The {@link SQLExtractor} allows you to extract the
* underlying SQL query generated by a JPQL or JPA Criteria API query.
*
* For more details about how to use it, check out this article on vladmihalcea.com.
*
* @author Vlad Mihalcea
* @since 2.9.11
*/
public class SQLExtractor {
protected SQLExtractor() {
}
/**
* Get the underlying SQL generated by the provided JPA query.
*
* @param query JPA query
* @return the underlying SQL generated by the provided JPA query
*/
public static String from(Query query) {
if(query instanceof SqmInterpretationsKey.InterpretationsKeySource &&
query instanceof QueryImplementor &&
query instanceof QuerySqmImpl) {
QueryInterpretationCache.Key cacheKey = SqmInterpretationsKey.createInterpretationsKey((SqmInterpretationsKey.InterpretationsKeySource) query);
QuerySqmImpl querySqm = (QuerySqmImpl) query;
Supplier buildSelectQueryPlan = () -> ReflectionUtils.invokeMethod(querySqm, "buildSelectQueryPlan");
SelectQueryPlan plan = cacheKey != null ? ((QueryImplementor) query).getSession().getFactory().getQueryEngine()
.getInterpretationCache()
.resolveSelectQueryPlan(cacheKey, buildSelectQueryPlan) :
(SelectQueryPlan) buildSelectQueryPlan.get();
if(plan instanceof ConcreteSqmSelectQueryPlan) {
ConcreteSqmSelectQueryPlan selectQueryPlan = (ConcreteSqmSelectQueryPlan) plan;
Object cacheableSqmInterpretation = ReflectionUtils.getFieldValueOrNull(selectQueryPlan, "cacheableSqmInterpretation");
if(cacheableSqmInterpretation == null) {
DomainQueryExecutionContext domainQueryExecutionContext = DomainQueryExecutionContext.class.cast(querySqm);
cacheableSqmInterpretation = ReflectionUtils.invokeStaticMethod(
ReflectionUtils.getMethod(
ConcreteSqmSelectQueryPlan.class,
"buildCacheableSqmInterpretation",
SqmSelectStatement.class,
DomainParameterXref.class,
DomainQueryExecutionContext.class
),
ReflectionUtils.getFieldValueOrNull(selectQueryPlan, "sqm"),
ReflectionUtils.getFieldValueOrNull(selectQueryPlan, "domainParameterXref"),
domainQueryExecutionContext
);
}
if (cacheableSqmInterpretation != null) {
JdbcOperationQuerySelect jdbcSelect = ReflectionUtils.getFieldValueOrNull(cacheableSqmInterpretation, "jdbcSelect");
if (jdbcSelect != null) {
return jdbcSelect.getSqlString();
}
}
}
}
return ReflectionUtils.invokeMethod(query, "getQueryString");
}
}