diff --git a/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java b/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java index 93d91a94c..369be3917 100644 --- a/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/DatabasePlatform.java @@ -148,8 +148,6 @@ public class DatabasePlatform { protected String columnAliasPrefix = "c"; - protected String tableAliasPlaceHolder = "${ta}"; - /** * Use a BackTick ` at the beginning and end of table or column names that you * want to use quoted identifiers for. The backticks get converted to the @@ -183,6 +181,7 @@ public class DatabasePlatform { protected boolean idInExpandedForm; protected boolean selectCountWithAlias; + protected boolean selectCountWithColumnAlias; /** * If set then use the FORWARD ONLY hint when creating ResultSets for @@ -478,20 +477,6 @@ public class DatabasePlatform { this.columnAliasPrefix = columnAliasPrefix; } - /** - * Return the table alias placeholder. - */ - public String getTableAliasPlaceHolder() { - return tableAliasPlaceHolder; - } - - /** - * Set the table alias placeholder. - */ - public void setTableAliasPlaceHolder(String tableAliasPlaceHolder) { - this.tableAliasPlaceHolder = tableAliasPlaceHolder; - } - /** * Return the close quote for quoted identifiers. */ @@ -684,6 +669,14 @@ public class DatabasePlatform { return selectCountWithAlias; } + /** + * Return true if select count with subquery needs column alias (SQL Server). + */ + public boolean isSelectCountWithColumnAlias() { + return selectCountWithColumnAlias; + } + + public String completeSql(String sql, Query query) { if (query.isForUpdate()) { sql = withForUpdate(sql, query.getForUpdateMode()); diff --git a/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerBasePlatform.java b/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerBasePlatform.java index 960309bbc..b79c69413 100644 --- a/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerBasePlatform.java +++ b/src/main/java/io/ebean/config/dbplatform/sqlserver/SqlServerBasePlatform.java @@ -28,6 +28,7 @@ abstract class SqlServerBasePlatform extends DatabasePlatform { this.persistBatchOnCascade = PersistBatch.NONE; this.idInExpandedForm = true; this.selectCountWithAlias = true; + this.selectCountWithColumnAlias = true; this.sqlLimiter = new SqlServerSqlLimiter(); this.basicSqlLimiter = new SqlServerBasicSqlLimiter(); this.historySupport = new SqlServerHistorySupport(); diff --git a/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java b/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java index 552d3d03c..38b2e1f8c 100644 --- a/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java +++ b/src/main/java/io/ebeaninternal/server/query/CQueryBuilder.java @@ -43,9 +43,7 @@ import java.util.List; */ class CQueryBuilder { - final String tableAliasPlaceHolder; - final String columnAliasPrefix; - + private final String columnAliasPrefix; private final SqlLimiter sqlLimiter; private final CQueryBuilderRawSql rawSqlHandler; private final Binder binder; @@ -55,6 +53,7 @@ class CQueryBuilder { private final CQueryHistorySupport historySupport; private final CQueryDraftSupport draftSupport; private final DatabasePlatform dbPlatform; + private final boolean selectCountWithColumnAlias; /** * Create the SqlGenSelect. @@ -64,11 +63,11 @@ class CQueryBuilder { this.binder = binder; this.draftSupport = draftSupport; this.historySupport = historySupport; - this.tableAliasPlaceHolder = dbPlatform.getTableAliasPlaceHolder(); this.columnAliasPrefix = dbPlatform.getColumnAliasPrefix(); this.sqlLimiter = dbPlatform.getSqlLimiter(); this.rawSqlHandler = new CQueryBuilderRawSql(sqlLimiter, dbPlatform); this.selectCountWithAlias = dbPlatform.isSelectCountWithAlias(); + this.selectCountWithColumnAlias = dbPlatform.isSelectCountWithColumnAlias(); } /** @@ -86,7 +85,6 @@ class CQueryBuilder { sb.append("."); sb.append(token.trim()); } - return sb.toString(); } @@ -273,7 +271,7 @@ class CQueryBuilder { predicates.prepare(true); - SqlTree sqlTree = createSqlTree(request, predicates); + SqlTree sqlTree = createSqlTree(request, predicates, selectCountWithColumnAlias && withAgg); if (SpiQuery.TemporalMode.CURRENT == query.getTemporalMode()) { sqlTree.addSoftDeletePredicate(query); } @@ -399,6 +397,10 @@ class CQueryBuilder { *

*/ 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); @@ -406,7 +408,8 @@ class CQueryBuilder { if (request.isRawSql()) { return createRawSqlSqlTree(request, predicates); } - return new SqlTreeBuilder(this, request, predicates).build(); + String colAliasPrefix = forceColumnAlias ? "c" : columnAliasPrefix; + return new SqlTreeBuilder(colAliasPrefix, this, request, predicates).build(); } private String nativeQueryPaging(SpiQuery query, String sql) { diff --git a/src/main/java/io/ebeaninternal/server/query/DefaultDbSqlContext.java b/src/main/java/io/ebeaninternal/server/query/DefaultDbSqlContext.java index 0af0c3f24..c596a2b36 100644 --- a/src/main/java/io/ebeaninternal/server/query/DefaultDbSqlContext.java +++ b/src/main/java/io/ebeaninternal/server/query/DefaultDbSqlContext.java @@ -16,7 +16,7 @@ class DefaultDbSqlContext implements DbSqlContext { private static final String PERIOD = "."; private static final int STRING_BUILDER_INITIAL_CAPACITY = 140; - private final String tableAliasPlaceHolder; + private static final String tableAliasPlaceHolder = "${ta}"; private final String columnAliasPrefix; @@ -56,14 +56,11 @@ class DefaultDbSqlContext implements DbSqlContext { /** * Construct for SELECT clause (with column alias settings). */ - DefaultDbSqlContext(SqlTreeAlias alias, CQueryBuilder builder, - boolean alwaysUseColumnAlias, CQueryHistorySupport historySupport, + DefaultDbSqlContext(SqlTreeAlias alias, String columnAliasPrefix, CQueryHistorySupport historySupport, CQueryDraftSupport draftSupport, String fromForUpdate) { - this.alias = alias; - this.tableAliasPlaceHolder = builder.tableAliasPlaceHolder; - this.columnAliasPrefix = builder.columnAliasPrefix; - this.useColumnAlias = columnAliasPrefix != null && alwaysUseColumnAlias; + this.columnAliasPrefix = columnAliasPrefix; + this.useColumnAlias = columnAliasPrefix != null; this.draftSupport = draftSupport; this.historySupport = historySupport; this.historyQuery = (historySupport != null); diff --git a/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java b/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java index a8ec12191..3ce94118a 100644 --- a/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java +++ b/src/main/java/io/ebeaninternal/server/query/SqlTreeBuilder.java @@ -96,7 +96,7 @@ public final class SqlTreeBuilder { * support the where and/or order by clause. If so these extra joins are added * to the root node. */ - SqlTreeBuilder(CQueryBuilder builder, OrmQueryRequest request, CQueryPredicates predicates) { + SqlTreeBuilder(String columnAliasPrefix, CQueryBuilder builder, OrmQueryRequest request, CQueryPredicates predicates) { this.rawSql = false; this.rawNoId = false; @@ -116,7 +116,8 @@ public final class SqlTreeBuilder { String fromForUpdate = builder.fromForUpdate(query); CQueryHistorySupport historySupport = builder.getHistorySupport(query); CQueryDraftSupport draftSupport = builder.getDraftSupport(query); - this.ctx = new DefaultDbSqlContext(alias, builder, !subQuery, historySupport, draftSupport, fromForUpdate); + String colAlias = subQuery ? null : columnAliasPrefix; + this.ctx = new DefaultDbSqlContext(alias, colAlias, historySupport, draftSupport, fromForUpdate); } /** diff --git a/src/test/java/org/tests/model/aggregation/TestAggregationTopLevel.java b/src/test/java/org/tests/model/aggregation/TestAggregationTopLevel.java index 2039caa15..bb43e192c 100644 --- a/src/test/java/org/tests/model/aggregation/TestAggregationTopLevel.java +++ b/src/test/java/org/tests/model/aggregation/TestAggregationTopLevel.java @@ -52,6 +52,8 @@ public class TestAggregationTopLevel extends BaseTestCase { if (isH2() || isPostgres()) { assertThat(sql.get(0)).contains("select count(*) from ( select t0.date, sum(t0.total_kms) from d_machine_stats t0 group by t0.date having sum(t0.total_kms) > ?)"); assertThat(sql.get(1)).contains("select t0.date, sum(t0.total_kms) from d_machine_stats t0 group by t0.date having sum(t0.total_kms) > ? limit 10"); + } else if (isSqlServer()) { + assertThat(sql.get(0)).contains("select count(*) from ( select t0.date c1, sum(t0.total_kms) c2 from d_machine_stats t0 group by t0.date having sum(t0.total_kms) > ?)"); } }