Add SpiQuery.Type.defaultSelect() for ATTRIBUTE and sub-query type queries

This commit is contained in:
rbygrave
2021-08-11 20:51:46 +12:00
parent 709f8ed05f
commit b676476cd2
3 changed files with 18 additions and 38 deletions
@@ -84,7 +84,7 @@ public interface SpiQuery<T> extends Query<T>, SpiQueryFetch, TxnProfileEventCod
/**
* Find single attribute.
*/
ATTRIBUTE(FIND_ATTRIBUTE, "findAttribute"),
ATTRIBUTE(FIND_ATTRIBUTE, "findAttribute", false, false),
/**
* Find rowCount.
@@ -94,12 +94,12 @@ public interface SpiQuery<T> extends Query<T>, SpiQueryFetch, TxnProfileEventCod
/**
* A subquery used as part of an exists where clause.
*/
SQ_EXISTS(FIND_SUBQUERY, "sqExists"),
SQ_EXISTS(FIND_SUBQUERY, "sqExists", false, false),
/**
* A subquery used as part of an in where clause.
*/
SQ_IN(FIND_SUBQUERY, "sqIn"),
SQ_IN(FIND_SUBQUERY, "sqIn", false, false),
/**
* Delete query.
@@ -112,17 +112,21 @@ public interface SpiQuery<T> extends Query<T>, SpiQueryFetch, TxnProfileEventCod
UPDATE(FIND_UPDATE, "update", true);
private final boolean update;
private final boolean defaultSelect;
private final String profileEventId;
private final String label;
Type(String profileEventId, String label) {
this(profileEventId, label, false);
this(profileEventId, label, false, true);
}
Type(String profileEventId, String label, boolean update) {
this(profileEventId, label, update, true);
}
Type(String profileEventId, String label, boolean update, boolean defaultSelect) {
this.profileEventId = profileEventId;
this.label = label;
this.update = update;
this.defaultSelect = defaultSelect;
}
/**
@@ -132,6 +136,13 @@ public interface SpiQuery<T> extends Query<T>, SpiQueryFetch, TxnProfileEventCod
return update;
}
/**
* Return true if this allows default select clause.
*/
public boolean defaultSelect() {
return defaultSelect;
}
public String profileEventId() {
return profileEventId;
}
@@ -46,9 +46,7 @@ class CQueryBuilder {
private final SqlLimiter sqlLimiter;
private final CQueryBuilderRawSql rawSqlHandler;
private final Binder binder;
private final boolean selectCountWithAlias;
private final CQueryHistorySupport historySupport;
private final CQueryDraftSupport draftSupport;
private final DatabasePlatform dbPlatform;
@@ -79,7 +77,6 @@ class CQueryBuilder {
if (sb.length() > 0) {
sb.append(", ");
}
sb.append(name);
sb.append(".");
sb.append(token.trim());
@@ -91,7 +88,6 @@ class CQueryBuilder {
* Build the delete query.
*/
<T> CQueryUpdate buildUpdateQuery(boolean deleteRequest, OrmQueryRequest<T> request) {
SpiQuery<T> query = request.getQuery();
String rootTableAlias = query.getAlias();
query.setupForDeleteOrUpdate();
@@ -105,7 +101,6 @@ class CQueryBuilder {
}
predicates.prepare(true);
SqlTree sqlTree = createSqlTree(request, predicates);
String sql;
@@ -114,7 +109,6 @@ class CQueryBuilder {
} else {
sql = buildUpdateSql(request, rootTableAlias, predicates, sqlTree);
}
// cache the query plan
queryPlan = new CQueryPlan(request, sql, sqlTree, predicates.getLogWhereSql());
request.putQueryPlan(queryPlan);
@@ -122,7 +116,6 @@ class CQueryBuilder {
}
private <T> String buildDeleteSql(OrmQueryRequest<T> request, String rootTableAlias, CQueryPredicates predicates, SqlTree sqlTree) {
String alias = alias(rootTableAlias);
if (sqlTree.noJoins() && !request.getQuery().hasMaxRowsOrFirstRow()) {
if (dbPlatform.isSupportsDeleteTableAlias()) {
@@ -151,7 +144,6 @@ class CQueryBuilder {
}
private <T> String buildUpdateSql(OrmQueryRequest<T> request, String rootTableAlias, CQueryPredicates predicates, SqlTree sqlTree) {
StringBuilder sb = new StringBuilder(200);
sb.append("update ").append(request.getBeanDescriptor().getBaseTable());
if (rootTableAlias != null) {
@@ -159,7 +151,6 @@ class CQueryBuilder {
}
sb.append(" set ").append(predicates.getDbUpdateClause());
String updateClause = sb.toString();
if (sqlTree.noJoins() && request.isInlineSqlUpdateLimit()) {
// simple - update table set ... where ...
return aliasStrip(buildSqlUpdate(updateClause, request, predicates, sqlTree).getSql());
@@ -186,7 +177,6 @@ class CQueryBuilder {
}
CQueryFetchSingleAttribute buildFetchAttributeQuery(OrmQueryRequest<?> request) {
SpiQuery<?> query = request.getQuery();
query.setSingleAttribute();
if (!query.isIncludeSoftDeletes()) {
@@ -218,7 +208,6 @@ class CQueryBuilder {
* Build the find ids query.
*/
<T> CQueryFetchSingleAttribute buildFetchIdsQuery(OrmQueryRequest<T> request) {
SpiQuery<T> query = request.getQuery();
query.setSelectId();
BeanDescriptor<T> desc = request.getBeanDescriptor();
@@ -246,9 +235,7 @@ class CQueryBuilder {
* Build the row count query.
*/
<T> CQueryRowCount buildRowCountQuery(OrmQueryRequest<T> request) {
SpiQuery<T> query = request.getQuery();
// always set the order by to null for row count query
query.setOrder(null);
query.setFirstRow(0);
@@ -310,7 +297,6 @@ class CQueryBuilder {
// cache the query plan
queryPlan = new CQueryPlan(request, sql, sqlTree, predicates.getLogWhereSql());
request.putQueryPlan(queryPlan);
return new CQueryRowCount(queryPlan, request, predicates);
}
@@ -334,9 +320,7 @@ class CQueryBuilder {
* names to physical deployment column names.
*/
<T> CQuery<T> buildQuery(OrmQueryRequest<T> request) {
CQueryPredicates predicates = new CQueryPredicates(binder, request);
CQueryPlan queryPlan = request.getQueryPlan();
if (queryPlan != null) {
// Reuse the query plan so skip generating SqlTree and SQL.
@@ -370,7 +354,6 @@ class CQueryBuilder {
boolean rawSql = request.isRawSql();
if (rawSql) {
queryPlan = new CQueryPlanRawSql(request, res, sqlTree, predicates.getLogWhereSql());
} else {
queryPlan = new CQueryPlan(request, res, sqlTree, false, predicates.getLogWhereSql());
}
@@ -380,11 +363,9 @@ class CQueryBuilder {
// log the query plan based bean type (i.e. ignoring query disabling for logging the sql/plan)
desc.getReadAuditLogger().queryPlan(new ReadAuditQueryPlan(desc.getFullName(), queryPlan.getAuditQueryKey(), queryPlan.getSql()));
}
// cache the query plan because we can reuse it and also
// gather query performance statistics based on it.
request.putQueryPlan(queryPlan);
return new CQuery<>(request, predicates, queryPlan);
}
@@ -393,18 +374,15 @@ class CQueryBuilder {
* <p>
* The SqlTree is immutable after construction and so is safe to use by
* concurrent threads.
* </p>
* <p>
* The predicates is used to add additional joins that come from the where or
* order by clauses that are not already included for the select clause.
* </p>
*/
private SqlTree createSqlTree(OrmQueryRequest<?> request, CQueryPredicates predicates) {
return createSqlTree(request, predicates, false);
}
private SqlTree createSqlTree(OrmQueryRequest<?> request, CQueryPredicates predicates, boolean forceColumnAlias) {
if (request.isNativeSql()) {
return createNativeSqlTree(request, predicates);
}
@@ -423,9 +401,7 @@ class CQueryBuilder {
* Create the SqlTree by reading the ResultSetMetaData and mapping table/columns to bean property paths.
*/
private SqlTree createNativeSqlTree(OrmQueryRequest<?> request, CQueryPredicates predicates) {
SpiQuery<?> query = request.getQuery();
// parse named parameters returning the final sql to execute
String sql = predicates.parseBindParams(query.getNativeSql());
if (query.hasMaxRowsOrFirstRow()) {
@@ -469,10 +445,8 @@ class CQueryBuilder {
}
private SqlTree createRawSqlSqlTree(OrmQueryRequest<?> request, CQueryPredicates predicates) {
BeanDescriptor<?> descriptor = request.getBeanDescriptor();
ColumnMapping columnMapping = request.getQuery().getRawSql().getColumnMapping();
PathProperties pathProps = new PathProperties();
// convert list of columns into (tree like) PathProperties
@@ -498,12 +472,10 @@ class CQueryBuilder {
}
OrmQueryDetail detail = new OrmQueryDetail();
// transfer PathProperties into OrmQueryDetail
for (PathProperties.Props props : pathProps.getPathProps()) {
detail.fetch(props.getPath(), props.getProperties());
}
// check if @Id property included in RawSql
boolean rawNoId = true;
BeanProperty idProperty = descriptor.getIdProperty();
@@ -511,7 +483,6 @@ class CQueryBuilder {
// contains the @Id property for the root level bean
rawNoId = false;
}
// build SqlTree based on OrmQueryDetail of the RawSql
return new SqlTreeBuilder(request, predicates, detail, rawNoId).build();
}
@@ -603,7 +574,6 @@ class CQueryBuilder {
private void appendSelect() {
if (selectClause != null) {
sb.append(selectClause);
} else {
useSqlLimiter = (query.hasMaxRowsOrFirstRow() && select.getManyProperty() == null);
if (!useSqlLimiter) {
@@ -565,8 +565,7 @@ 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.SQ_EXISTS && type != Type.SQ_IN);
detail.markQueryJoins(beanDescriptor, lazyLoadManyPath, isAllowOneManyFetch(), type.defaultSelect());
}
private boolean isAllowOneManyFetch() {
@@ -579,7 +578,7 @@ public class DefaultOrmQuery<T> extends AbstractQuery implements SpiQuery<T> {
@Override
public void setDefaultSelectClause() {
if (type != Type.ATTRIBUTE && type != Type.SQ_EXISTS && type != Type.SQ_IN) {
if (type.defaultSelect()) {
detail.setDefaultSelectClause(beanDescriptor);
} else if (!detail.hasSelectClause()) {
// explicit empty select when single attribute query on non-root fetch path