diff --git a/framework/db/src/com/cloud/utils/db/GenericDao.java b/framework/db/src/com/cloud/utils/db/GenericDao.java index 121d65d6501..63047e7c699 100644 --- a/framework/db/src/com/cloud/utils/db/GenericDao.java +++ b/framework/db/src/com/cloud/utils/db/GenericDao.java @@ -276,4 +276,6 @@ public interface GenericDao { Pair, Integer> searchAndDistinctCount(final SearchCriteria sc, final Filter filter); Map getAllAttributes(); + + Pair, Integer> searchAndDistinctCount(final SearchCriteria sc, final Filter filter, final String[] distinctColumns); } diff --git a/framework/db/src/com/cloud/utils/db/GenericDaoBase.java b/framework/db/src/com/cloud/utils/db/GenericDaoBase.java index c5a4cd85dd8..304a122a0b7 100644 --- a/framework/db/src/com/cloud/utils/db/GenericDaoBase.java +++ b/framework/db/src/com/cloud/utils/db/GenericDaoBase.java @@ -44,7 +44,7 @@ import java.util.Map; import java.util.TimeZone; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; - +import com.google.common.base.Strings; import javax.naming.ConfigurationException; import javax.persistence.AttributeOverride; import javax.persistence.Column; @@ -1326,6 +1326,14 @@ public abstract class GenericDaoBase extends Compone return new Pair, Integer>(objects, count); } + @Override + @DB() + public Pair, Integer> searchAndDistinctCount(final SearchCriteria sc, final Filter filter, final String[] distinctColumns) { + List objects = search(sc, filter, null, false); + Integer count = getDistinctCount(sc, distinctColumns); + return new Pair, Integer>(objects, count); + } + @Override @DB() public List search(final SearchCriteria sc, final Filter filter, final boolean enableQueryCache) { @@ -1927,6 +1935,52 @@ public abstract class GenericDaoBase extends Compone } } + public Integer getDistinctCount(SearchCriteria sc, String[] distinctColumns) { + String clause = sc != null ? sc.getWhereClause() : null; + if (Strings.isNullOrEmpty(clause)) { + clause = null; + } + + final StringBuilder str = createDistinctSelect(sc, clause != null, distinctColumns); + if (clause != null) { + str.append(clause); + } + + Collection>> joins = null; + if (sc != null) { + joins = sc.getJoins(); + if (joins != null) { + addJoins(str, joins); + } + } + + final TransactionLegacy txn = TransactionLegacy.currentTxn(); + final String sql = "SELECT COUNT(*) FROM (" + str.toString() + ") AS tmp"; + + try (PreparedStatement pstmt = txn.prepareAutoCloseStatement(sql)) { + int i = 1; + if (clause != null) { + for (final Pair value : sc.getValues()) { + prepareAttribute(i++, pstmt, value.first(), value.second()); + } + } + + if (joins != null) { + i = addJoinAttributes(i, pstmt, joins); + } + + final ResultSet rs = pstmt.executeQuery(); + while (rs.next()) { + return rs.getInt(1); + } + return 0; + } catch (final SQLException e) { + throw new CloudRuntimeException("DB Exception in executing: " + sql, e); + } catch (final Throwable e) { + throw new CloudRuntimeException("Caught exception in : " + sql, e); + } + } + public Integer getCount(SearchCriteria sc) { String clause = sc != null ? sc.getWhereClause() : null; if (clause != null && clause.length() == 0) { @@ -2013,4 +2067,18 @@ public abstract class GenericDaoBase extends Compone Integer count = getCount(sc); return new Pair, Integer>(objects, count); } + + @DB() + protected StringBuilder createDistinctSelect(SearchCriteria sc, final boolean whereClause, String[] distinctColumns) { + final SqlGenerator generator = new SqlGenerator(_entityBeanType); + String distinctSql = generator.buildDistinctSql(distinctColumns); + + StringBuilder sql = new StringBuilder(distinctSql); + + if (!whereClause) { + sql.delete(sql.length() - (_discriminatorClause == null ? 6 : 4), sql.length()); + } + + return sql; + } } diff --git a/framework/db/src/com/cloud/utils/db/SqlGenerator.java b/framework/db/src/com/cloud/utils/db/SqlGenerator.java index e6cb9cb8897..516849650f1 100644 --- a/framework/db/src/com/cloud/utils/db/SqlGenerator.java +++ b/framework/db/src/com/cloud/utils/db/SqlGenerator.java @@ -680,4 +680,20 @@ public class SqlGenerator { return sql.append("SELECT DISTINCT id FROM ").append(buildTableReferences()).append(" WHERE ").append(buildDiscriminatorClause().first()).toString(); } + + public String buildDistinctSql(String[] distinctColumnNames) { + StringBuilder sbColumn = new StringBuilder(); + + if (distinctColumnNames != null && distinctColumnNames.length > 0) { + for (String columnName : distinctColumnNames) { + sbColumn.append(columnName).append(", "); + } + sbColumn.delete(sbColumn.length() - 2, sbColumn.length()); + } else { + sbColumn.append("*"); + } + + StringBuilder sql = new StringBuilder(); + return sql.append("SELECT DISTINCT " + sbColumn.toString() + " FROM ").append(buildTableReferences()).append(" WHERE ").append(buildDiscriminatorClause().first()).toString(); + } } diff --git a/server/src/com/cloud/api/query/QueryManagerImpl.java b/server/src/com/cloud/api/query/QueryManagerImpl.java index 2d6fabcaaa6..efe31cbd895 100644 --- a/server/src/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/com/cloud/api/query/QueryManagerImpl.java @@ -3383,7 +3383,8 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q uniqueTmplPair = _templateJoinDao.searchIncludingRemovedAndCount(sc, searchFilter); } else { sc.addAnd("templateState", SearchCriteria.Op.IN, new State[]{State.Active, State.UploadAbandoned, State.UploadError, State.NotUploaded, State.UploadInProgress}); - uniqueTmplPair = _templateJoinDao.searchAndCount(sc, searchFilter); + final String[] distinctColumns = {"temp_zone_pair"}; + uniqueTmplPair = _templateJoinDao.searchAndDistinctCount(sc, searchFilter, distinctColumns); } Integer count = uniqueTmplPair.second(); diff --git a/server/test/com/cloud/user/MockUsageEventDao.java b/server/test/com/cloud/user/MockUsageEventDao.java index 4959b83a452..5d8ed6c4555 100644 --- a/server/test/com/cloud/user/MockUsageEventDao.java +++ b/server/test/com/cloud/user/MockUsageEventDao.java @@ -278,6 +278,11 @@ public class MockUsageEventDao implements UsageEventDao{ return null; } + @Override + public Pair, Integer> searchAndDistinctCount(SearchCriteria sc, Filter filter, String[] distinctColumns) { + return null; + } + @Override public List listLatestEvents(Date endDate) { return null; @@ -303,5 +308,4 @@ public class MockUsageEventDao implements UsageEventDao{ public void saveDetails(long eventId, Map details) { } - }