Distinguish between exists and in subquery

This commit is contained in:
Roland Praml committed 2021-08-11 08:54:40 +02:00
1 parent 12b8b4b955
commit 1a2aba3f56
11 files changed
+37 -18

No files matched your search

@@ -8,6 +8,7 @@ import io.ebean.config.dbplatform.DatabasePlatform;
import io.ebean.event.readaudit.ReadAuditLogger;
import io.ebean.event.readaudit.ReadAuditPrepare;
import io.ebean.meta.MetricVisitor;
import io.ebeaninternal.api.SpiQuery.Type;
import io.ebeaninternal.server.core.SpiResultSet;
import io.ebeaninternal.server.core.timezone.DataTimeZone;
import io.ebeaninternal.server.deploy.BeanDescriptor;
@@ -149,7 +150,7 @@ public interface SpiEbeanServer extends ExtendedServer, EbeanServer, BeanCollect
/**
* Compile a query.
*/
<T> CQuery<T> compileQuery(Query<T> query, Transaction t);
<T> CQuery<T> compileQuery(Type type, Query<T> query, Transaction t);
/**
* Execute the findId's query but without copying the query.
@@ -92,9 +92,14 @@ public interface SpiQuery<T> extends Query<T>, SpiQueryFetch, TxnProfileEventCod
COUNT(FIND_COUNT, "findCount"),
/**
* A subquery used as part of a where clause.
* A subquery used as part of an exists where clause.
*/
SUBQUERY(FIND_SUBQUERY, "subquery"),
SQ_EXISTS(FIND_SUBQUERY, "sqExists"),
/**
* A subquery used as part of an in where clause.
*/
SQ_IN(FIND_SUBQUERY, "sqIn"),
/**
* Delete query.
@@ -526,8 +526,8 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
* Compile a query. Only valid for ORM queries.
*/
@Override
public <T> CQuery<T> compileQuery(Query<T> query, Transaction t) {
SpiOrmQueryRequest<T> qr = createQueryRequest(Type.SUBQUERY, query, t);
public <T> CQuery<T> compileQuery(Type type, Query<T> query, Transaction t) {
SpiOrmQueryRequest<T> qr = createQueryRequest(type, query, t);
OrmQueryRequest<T> orm = (OrmQueryRequest<T>) qr;
return cqueryEngine.buildQuery(orm);
}
@@ -9,6 +9,7 @@ import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.api.SpiExpressionValidation;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.api.SpiQuery.Type;
import io.ebeaninternal.server.deploy.BeanDescriptor;
import io.ebeaninternal.server.query.CQuery;
@@ -82,7 +83,7 @@ class ExistsQueryExpression implements SpiExpression, UnsupportedDocStoreExpress
*/
protected CQuery<?> compileSubQuery(BeanQueryRequest<?> queryRequest) {
SpiEbeanServer ebeanServer = (SpiEbeanServer) queryRequest.getEbeanServer();
return ebeanServer.compileQuery(subQuery, queryRequest.getTransaction());
return ebeanServer.compileQuery(Type.SQ_EXISTS, subQuery, queryRequest.getTransaction());
}
@Override
@@ -6,6 +6,7 @@ import io.ebeaninternal.api.SpiEbeanServer;
import io.ebeaninternal.api.SpiExpression;
import io.ebeaninternal.api.SpiExpressionRequest;
import io.ebeaninternal.api.SpiQuery;
import io.ebeaninternal.api.SpiQuery.Type;
import io.ebeaninternal.server.query.CQuery;
import java.io.IOException;
@@ -69,7 +70,7 @@ class InQueryExpression extends AbstractExpression implements UnsupportedDocStor
private CQuery<?> compileSubQuery(BeanQueryRequest<?> queryRequest) {
SpiEbeanServer ebeanServer = (SpiEbeanServer) queryRequest.getEbeanServer();
return ebeanServer.compileQuery(subQuery, queryRequest.getTransaction());
return ebeanServer.compileQuery(Type.SQ_IN, subQuery, queryRequest.getTransaction());
}
@Override
@@ -101,6 +101,7 @@ class SqlTree {
* Return the String for the actual SQL.
*/
String getSelectSql() {
assert selectSql != null : "selectSql was null";
return selectSql;
}
@@ -102,7 +102,11 @@ public final class SqlTreeBuilder {
this.query = request.getQuery();
this.temporalMode = SpiQuery.TemporalMode.of(query);
this.disableLazyLoad = query.isDisableLazyLoading();
this.subQuery = Type.SUBQUERY == query.getType() || Type.ID_LIST == query.getType() || Type.DELETE == query.getType() || query.isCountDistinct();
this.subQuery = Type.SQ_EXISTS == query.getType()
|| Type.SQ_IN == query.getType()
|| Type.ID_LIST == query.getType()
|| Type.DELETE == query.getType()
|| query.isCountDistinct();
this.includeJoin = query.getM2mIncludeJoin();
this.manyWhereJoins = query.getManyWhereJoins();
this.queryDetail = query.getDetail();
@@ -146,6 +150,10 @@ public final class SqlTreeBuilder {
if (rawSql) {
return "Not Used";
}
if (query.getType() ==Type.SQ_EXISTS) {
// effective query is "where exists (select 1 from ...)"
return "1";
}
rootNode.appendSelect(ctx, subQuery);
return trimComma(ctx.getContent());
}
@@ -565,7 +565,8 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
* Limit the number of fetch joins to Many properties, mark as query joins as needed.
*/
private void markQueryJoins() {
detail.markQueryJoins(beanDescriptor, lazyLoadManyPath, isAllowOneManyFetch(), type != Type.ATTRIBUTE && type != Type.SUBQUERY);
detail.markQueryJoins(beanDescriptor, lazyLoadManyPath, isAllowOneManyFetch(),
type != Type.ATTRIBUTE && type != Type.SQ_EXISTS && type != Type.SQ_IN);
}
private boolean isAllowOneManyFetch() {
@@ -578,7 +579,7 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
@Override
public void setDefaultSelectClause() {
if (type != Type.ATTRIBUTE && type != Type.SUBQUERY) {
if (type != Type.ATTRIBUTE && type != Type.SQ_EXISTS && type != Type.SQ_IN) {
detail.setDefaultSelectClause(beanDescriptor);
} else if (!detail.hasSelectClause()) {
// explicit empty select when single attribute query on non-root fetch path