diff --git a/engine/schema/src/main/java/com/cloud/upgrade/dao/DatabaseAccessObject.java b/engine/schema/src/main/java/com/cloud/upgrade/dao/DatabaseAccessObject.java index 21d5a205a09..0b38acb5c21 100644 --- a/engine/schema/src/main/java/com/cloud/upgrade/dao/DatabaseAccessObject.java +++ b/engine/schema/src/main/java/com/cloud/upgrade/dao/DatabaseAccessObject.java @@ -18,6 +18,7 @@ package com.cloud.upgrade.dao; import java.sql.Connection; import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.sql.SQLException; import org.apache.log4j.Logger; @@ -84,6 +85,33 @@ public class DatabaseAccessObject { return columnExists; } + public String generateIndexName(String tableName, String columnName) { + return String.format("i_%s__%s", tableName, columnName); + } + + public boolean indexExists(Connection conn, String tableName, String indexName) { + try (PreparedStatement pstmt = conn.prepareStatement(String.format("SHOW INDEXES FROM %s where Key_name = \"%s\"", tableName, indexName))) { + ResultSet result = pstmt.executeQuery(); + if (result.next()) { + return true; + } + } catch (SQLException e) { + s_logger.debug(String.format("Index %s doesn't exist, ignoring exception:", indexName, e.getMessage())); + } + return false; + } + + public void createIndex(Connection conn, String tableName, String columnName, String indexName) { + String stmt = String.format("CREATE INDEX %s on %s (%s)", indexName, tableName, columnName); + s_logger.debug("Statement: " + stmt); + try (PreparedStatement pstmt = conn.prepareStatement(stmt)) { + pstmt.execute(); + s_logger.debug(String.format("Created index %s", indexName)); + } catch (SQLException e) { + s_logger.warn(String.format("Unable to create index %s", indexName), e); + } + } + protected static void closePreparedStatement(PreparedStatement pstmt, String errorMessage) { try { if (pstmt != null) { @@ -93,5 +121,4 @@ public class DatabaseAccessObject { s_logger.warn(errorMessage, e); } } - } diff --git a/engine/schema/src/main/java/com/cloud/upgrade/dao/DbUpgradeUtils.java b/engine/schema/src/main/java/com/cloud/upgrade/dao/DbUpgradeUtils.java index 02dad6250dc..6b4e1814de0 100644 --- a/engine/schema/src/main/java/com/cloud/upgrade/dao/DbUpgradeUtils.java +++ b/engine/schema/src/main/java/com/cloud/upgrade/dao/DbUpgradeUtils.java @@ -23,6 +23,14 @@ public class DbUpgradeUtils { private static DatabaseAccessObject dao = new DatabaseAccessObject(); + public static void addIndexIfNeeded(Connection conn, String tableName, String columnName) { + String indexName = dao.generateIndexName(tableName, columnName); + + if (!dao.indexExists(conn, tableName, indexName)) { + dao.createIndex(conn, tableName, columnName, indexName); + } + } + public static void addForeignKey(Connection conn, String tableName, String tableColumn, String foreignTableName, String foreignColumnName) { dao.addForeignKey(conn, tableName, tableColumn, foreignTableName, foreignColumnName); } diff --git a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade41800to41810.java b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade41800to41810.java index 8eb50666ec8..a58d9965259 100644 --- a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade41800to41810.java +++ b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade41800to41810.java @@ -69,6 +69,7 @@ public class Upgrade41800to41810 implements DbUpgrade, DbUpgradeSystemVmTemplate copyGuestOsMappingsToVMware80u1(); addForeignKeyToAutoscaleVmprofiles(conn); mergeDuplicateGuestOSes(); + addIndexes(conn); } private void mergeDuplicateGuestOSes() { @@ -242,4 +243,8 @@ public class Upgrade41800to41810 implements DbUpgrade, DbUpgradeSystemVmTemplate private void addForeignKeyToAutoscaleVmprofiles(Connection conn) { DbUpgradeUtils.addForeignKey(conn, "autoscale_vmprofiles", "user_data_id", "user_data", "id"); } + + private void addIndexes(Connection conn) { + DbUpgradeUtils.addIndexIfNeeded(conn, "cluster_details", "name"); + } } diff --git a/engine/schema/src/test/java/com/cloud/upgrade/dao/DatabaseAccessObjectTest.java b/engine/schema/src/test/java/com/cloud/upgrade/dao/DatabaseAccessObjectTest.java index 2b8b2bd8f1c..7e78c3ec3e9 100644 --- a/engine/schema/src/test/java/com/cloud/upgrade/dao/DatabaseAccessObjectTest.java +++ b/engine/schema/src/test/java/com/cloud/upgrade/dao/DatabaseAccessObjectTest.java @@ -16,6 +16,7 @@ // under the License. package com.cloud.upgrade.dao; +import static org.mockito.Matchers.startsWith; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.contains; @@ -27,9 +28,11 @@ import static org.mockito.Mockito.when; import java.sql.Connection; import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.sql.SQLException; import org.apache.log4j.Logger; +import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -49,6 +52,9 @@ public class DatabaseAccessObjectTest { @Mock private Logger loggerMock; + @Mock + private ResultSet resultSetMock; + private final DatabaseAccessObject dao = new DatabaseAccessObject(); @Before @@ -83,6 +89,61 @@ public class DatabaseAccessObjectTest { dao.dropKey(conn, tableName, key, isForeignKey); } + @Test + public void generateIndexNameTest() { + String indexName = dao.generateIndexName("mytable","mycolumn"); + Assert.assertEquals( "i_mytable__mycolumn", indexName); + } + + @Test + public void indexExistsFalseTest() throws Exception { + when(resultSetMock.next()).thenReturn(false); + when(connectionMock.prepareStatement(startsWith("SHOW INDEXES FROM"))).thenReturn(preparedStatementMock); + when(preparedStatementMock.executeQuery()).thenReturn(resultSetMock); + + Connection conn = connectionMock; + String tableName = "mytable"; + String indexName = "myindex"; + + Assert.assertFalse(dao.indexExists(conn, tableName, indexName)); + verify(connectionMock, times(1)).prepareStatement(anyString()); + verify(preparedStatementMock, times(1)).executeQuery(); + verify(preparedStatementMock, times(1)).close(); + } + + @Test + public void indexExistsTrueTest() throws Exception { + when(resultSetMock.next()).thenReturn(true); + when(connectionMock.prepareStatement(startsWith("SHOW INDEXES FROM"))).thenReturn(preparedStatementMock); + when(preparedStatementMock.executeQuery()).thenReturn(resultSetMock); + + Connection conn = connectionMock; + String tableName = "mytable"; + String indexName = "myindex"; + + Assert.assertTrue(dao.indexExists(conn, tableName, indexName)); + verify(connectionMock, times(1)).prepareStatement(anyString()); + verify(preparedStatementMock, times(1)).executeQuery(); + verify(preparedStatementMock, times(1)).close(); + } + + @Test + public void createIndexTest() throws Exception { + when(connectionMock.prepareStatement(startsWith("CREATE INDEX"))).thenReturn(preparedStatementMock); + when(preparedStatementMock.execute()).thenReturn(true); + + Connection conn = connectionMock; + String tableName = "mytable"; + String columnName = "mycolumn"; + String indexName = "myindex"; + + dao.createIndex(conn, tableName, columnName, indexName); + verify(connectionMock, times(1)).prepareStatement(anyString()); + verify(preparedStatementMock, times(1)).execute(); + verify(preparedStatementMock, times(1)).close(); + verify(loggerMock, times(1)).debug("Created index myindex"); + } + @Test public void testDropKeyWhenTableNameIsNull() throws Exception { SQLException sqlException = new SQLException();