You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

DatabaseUtilsIT.java 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2023 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. package org.sonar.db;
  21. import java.sql.Connection;
  22. import java.sql.DatabaseMetaData;
  23. import java.sql.PreparedStatement;
  24. import java.sql.ResultSet;
  25. import java.sql.SQLException;
  26. import java.sql.Statement;
  27. import java.util.ArrayList;
  28. import java.util.Collections;
  29. import java.util.List;
  30. import java.util.Locale;
  31. import java.util.Objects;
  32. import java.util.Optional;
  33. import java.util.Set;
  34. import java.util.function.Function;
  35. import javax.annotation.Nullable;
  36. import org.junit.Rule;
  37. import org.junit.Test;
  38. import org.slf4j.LoggerFactory;
  39. import org.slf4j.event.Level;
  40. import org.sonar.api.testfixtures.log.LogTester;
  41. import org.sonar.db.dialect.Oracle;
  42. import static org.assertj.core.api.Assertions.assertThat;
  43. import static org.assertj.core.api.Assertions.assertThatCode;
  44. import static org.assertj.core.api.Assertions.assertThatThrownBy;
  45. import static org.assertj.core.api.Assertions.fail;
  46. import static org.mockito.ArgumentMatchers.any;
  47. import static org.mockito.ArgumentMatchers.anyBoolean;
  48. import static org.mockito.ArgumentMatchers.anyString;
  49. import static org.mockito.ArgumentMatchers.eq;
  50. import static org.mockito.Mockito.doReturn;
  51. import static org.mockito.Mockito.doThrow;
  52. import static org.mockito.Mockito.mock;
  53. import static org.mockito.Mockito.spy;
  54. import static org.mockito.Mockito.verify;
  55. import static org.mockito.Mockito.when;
  56. import static org.sonar.db.DatabaseUtils.ORACLE_DRIVER_NAME;
  57. import static org.sonar.db.DatabaseUtils.checkThatNotTooManyConditions;
  58. import static org.sonar.db.DatabaseUtils.closeQuietly;
  59. import static org.sonar.db.DatabaseUtils.getColumnMetadata;
  60. import static org.sonar.db.DatabaseUtils.getDriver;
  61. import static org.sonar.db.DatabaseUtils.log;
  62. import static org.sonar.db.DatabaseUtils.tableColumnExists;
  63. import static org.sonar.db.DatabaseUtils.tableExists;
  64. import static org.sonar.db.DatabaseUtils.toUniqueAndSortedList;
  65. public class DatabaseUtilsIT {
  66. private static final String DEFAULT_SCHEMA = "public";
  67. private static final String SCHEMA_MIGRATIONS_TABLE = "SCHEMA_MIGRATIONS";
  68. @Rule
  69. public CoreDbTester dbTester = CoreDbTester.createForSchema(DatabaseUtilsIT.class, "sql.sql", false);
  70. @Rule
  71. public LogTester logTester = new LogTester();
  72. @Test
  73. public void findExistingIndex_whenTableBothInLowerAndUpperCase_shouldFindIndex() throws SQLException {
  74. String indexName = "lower_case_name";
  75. try (Connection connection = dbTester.openConnection()) {
  76. assertThat(DatabaseUtils.findExistingIndex(connection, SCHEMA_MIGRATIONS_TABLE, indexName)).contains(indexName);
  77. assertThat(DatabaseUtils.findExistingIndex(connection, SCHEMA_MIGRATIONS_TABLE.toLowerCase(Locale.US), indexName)).contains(indexName);
  78. }
  79. }
  80. @Test
  81. public void findExistingIndex_whenMixedCasesInTableAndIndexName_shouldFindIndex() throws SQLException {
  82. String indexName = "UPPER_CASE_NAME";
  83. try (Connection connection = dbTester.openConnection()) {
  84. assertThat(DatabaseUtils.findExistingIndex(connection, SCHEMA_MIGRATIONS_TABLE, indexName)).contains(indexName);
  85. assertThat(DatabaseUtils.findExistingIndex(connection, SCHEMA_MIGRATIONS_TABLE, indexName.toLowerCase(Locale.US))).contains(indexName);
  86. assertThat(DatabaseUtils.findExistingIndex(connection, SCHEMA_MIGRATIONS_TABLE.toLowerCase(Locale.US), indexName.toLowerCase(Locale.US))).contains(indexName);
  87. }
  88. }
  89. @Test
  90. public void findExistingIndex_whenPassingOnlyPartOfIndexName_shouldFindIndexAndReturnFullName() throws SQLException {
  91. String indexName = "INDEX_NAME";
  92. try (Connection connection = dbTester.openConnection()) {
  93. assertThat(DatabaseUtils.findExistingIndex(connection, SCHEMA_MIGRATIONS_TABLE, indexName)).contains("idx_1234_index_name");
  94. assertThat(DatabaseUtils.findExistingIndex(connection, SCHEMA_MIGRATIONS_TABLE.toLowerCase(Locale.US), indexName)).contains("idx_1234_index_name");
  95. assertThat(DatabaseUtils.findExistingIndex(connection, SCHEMA_MIGRATIONS_TABLE.toLowerCase(Locale.US), indexName.toLowerCase(Locale.US))).contains("idx_1234_index_name");
  96. assertThat(DatabaseUtils.findExistingIndex(connection, SCHEMA_MIGRATIONS_TABLE, "index")).isEmpty();
  97. assertThat(DatabaseUtils.findExistingIndex(connection, SCHEMA_MIGRATIONS_TABLE, "index_name_2")).isEmpty();
  98. assertThat(DatabaseUtils.findExistingIndex(connection, SCHEMA_MIGRATIONS_TABLE, "index_name_")).isEmpty();
  99. }
  100. }
  101. @Test
  102. public void tableColumnExists_whenTableNameLowerCaseColumnUpperCase_shouldFindColumn() throws SQLException {
  103. String tableName = "tablea";
  104. String columnName = "COLUMNA";
  105. try (Connection connection = dbTester.openConnection()) {
  106. assertThat(tableColumnExists(connection, tableName, columnName)).isTrue();
  107. }
  108. }
  109. @Test
  110. public void tableColumnExists_whenArgumentInUpperCase_shouldFindColumn() throws SQLException {
  111. String tableName = "TABLEA";
  112. String columnName = "COLUMNA";
  113. try (Connection connection = dbTester.openConnection()) {
  114. assertThat(tableColumnExists(connection, tableName, columnName)).isTrue();
  115. }
  116. }
  117. @Test
  118. public void tableColumnExists_whenArgumentsInLowerCase_shouldFindColumn() throws SQLException {
  119. String tableName = "tablea";
  120. String columnName = "columna";
  121. try (Connection connection = dbTester.openConnection()) {
  122. assertThat(tableColumnExists(connection, tableName, columnName)).isTrue();
  123. }
  124. }
  125. @Test
  126. public void tableColumnExists_whenTableNameInUpperCaseAndColumnInLowerCase_shouldFindColumn() throws SQLException {
  127. String tableName = "TABLEA";
  128. String columnName = "columna";
  129. try (Connection connection = dbTester.openConnection()) {
  130. assertThat(tableColumnExists(connection, tableName, columnName)).isTrue();
  131. }
  132. }
  133. @Test
  134. public void getColumnMetadata_whenTableNameLowerCaseColumnUpperCase_shouldFindColumn() throws SQLException {
  135. String tableName = "tablea";
  136. String columnName = "COLUMNA";
  137. try (Connection connection = dbTester.openConnection()) {
  138. assertThat(getColumnMetadata(connection, tableName, columnName)).isNotNull();
  139. }
  140. }
  141. @Test
  142. public void getColumnMetadata_whenArgumentInUpperCase_shouldFindColumn() throws SQLException {
  143. String tableName = "TABLEA";
  144. String columnName = "COLUMNA";
  145. try (Connection connection = dbTester.openConnection()) {
  146. assertThat(getColumnMetadata(connection, tableName, columnName)).isNotNull();
  147. }
  148. }
  149. @Test
  150. public void closeQuietly_shouldCloseConnection() throws SQLException {
  151. try (Connection connection = dbTester.openConnection()) {
  152. assertThat(isClosed(connection)).isFalse();
  153. closeQuietly(connection);
  154. assertThat(isClosed(connection)).isTrue();
  155. }
  156. }
  157. @Test
  158. public void closeQuietly_shouldNotFailOnNullArgument() {
  159. assertThatCode(() -> closeQuietly((Connection) null)).doesNotThrowAnyException();
  160. }
  161. @Test
  162. public void closeQuietly_whenStatementAndResultSetOpen_shouldCloseBoth() throws SQLException {
  163. try (Connection connection = dbTester.openConnection(); PreparedStatement statement = connection.prepareStatement(selectDual())) {
  164. ResultSet rs = statement.executeQuery();
  165. closeQuietly(rs);
  166. closeQuietly(statement);
  167. assertThat(isClosed(statement)).isTrue();
  168. assertThat(isClosed(rs)).isTrue();
  169. }
  170. }
  171. @Test
  172. public void closeQuietly_whenConnectionThrowsException_shouldNotThrowException() throws SQLException {
  173. Connection connection = mock(Connection.class);
  174. doThrow(new SQLException()).when(connection).close();
  175. closeQuietly(connection);
  176. // no failure
  177. verify(connection).close(); // just to be sure
  178. }
  179. @Test
  180. public void closeQuietly_whenStatementThrowsException_shouldNotThrowException() throws SQLException {
  181. Statement statement = mock(Statement.class);
  182. doThrow(new SQLException()).when(statement).close();
  183. closeQuietly(statement);
  184. // no failure
  185. verify(statement).close(); // just to be sure
  186. }
  187. @Test
  188. public void closeQuietly_whenResultSetThrowsException_shouldNotThrowException() throws SQLException {
  189. ResultSet rs = mock(ResultSet.class);
  190. doThrow(new SQLException()).when(rs).close();
  191. closeQuietly(rs);
  192. // no failure
  193. verify(rs).close(); // just to be sure
  194. }
  195. @Test
  196. public void toUniqueAndSortedList_whenNullPassed_shouldThrowNullPointerException() {
  197. assertThatThrownBy(() -> toUniqueAndSortedList(null))
  198. .isInstanceOf(NullPointerException.class);
  199. }
  200. @Test
  201. public void toUniqueAndSortedList_whenNullPassedInsideTheList_shouldThrowNullPointerException() {
  202. assertThatThrownBy(() -> toUniqueAndSortedList(List.of("A", null, "C")))
  203. .isInstanceOf(NullPointerException.class);
  204. }
  205. @Test
  206. public void toUniqueAndSortedList_whenNullPassedInsideTheSet_shouldThrowNullPointerException() {
  207. assertThatThrownBy(() -> toUniqueAndSortedList(Set.of("A", null, "C")))
  208. .isInstanceOf(NullPointerException.class);
  209. }
  210. @Test
  211. public void toUniqueAndSortedList_shouldEnforceNaturalOrder() {
  212. assertThat(toUniqueAndSortedList(List.of("A", "B", "C"))).containsExactly("A", "B", "C");
  213. assertThat(toUniqueAndSortedList(List.of("B", "A", "C"))).containsExactly("A", "B", "C");
  214. assertThat(toUniqueAndSortedList(List.of("B", "C", "A"))).containsExactly("A", "B", "C");
  215. }
  216. @Test
  217. public void toUniqueAndSortedList_shouldRemoveDuplicates() {
  218. assertThat(toUniqueAndSortedList(List.of("A", "A", "A"))).containsExactly("A");
  219. assertThat(toUniqueAndSortedList(List.of("A", "C", "A"))).containsExactly("A", "C");
  220. assertThat(toUniqueAndSortedList(List.of("C", "C", "B", "B", "A", "N", "C", "A"))).containsExactly("A", "B", "C", "N");
  221. }
  222. @Test
  223. public void toUniqueAndSortedList_shouldRemoveDuplicatesAndEnforceNaturalOrder() {
  224. assertThat(
  225. toUniqueAndSortedList(List.of(myComparable(2), myComparable(5), myComparable(2), myComparable(4), myComparable(-1), myComparable(10))))
  226. .containsExactly(
  227. myComparable(-1), myComparable(2), myComparable(4), myComparable(5), myComparable(10));
  228. }
  229. @Test
  230. public void getDriver_whenIssuesWithDriver_shouldLeaveAMessageInTheLogs() throws SQLException {
  231. Connection connection = mock(Connection.class);
  232. DatabaseMetaData metaData = mock(DatabaseMetaData.class);
  233. when(connection.getMetaData()).thenReturn(metaData);
  234. when(metaData.getDriverName()).thenThrow(new SQLException());
  235. getDriver(connection);
  236. assertThat(logTester.logs(Level.WARN)).contains("Fail to determine database driver.");
  237. }
  238. @Test
  239. public void findExistingIndex_whenResultSetThrowsException_shouldThrowExceptionToo() throws SQLException {
  240. String indexName = "idx";
  241. String schema = "TEST-SONAR";
  242. ResultSet resultSet = mock(ResultSet.class);
  243. when(resultSet.next()).thenThrow(new SQLException());
  244. assertThatThrownBy(() -> findExistingIndex(indexName, schema, resultSet, true))
  245. .isInstanceOf(IllegalStateException.class)
  246. .hasMessage("Can not check that table test_table exists");
  247. }
  248. @Test
  249. public void findExistingIndex_whenExistingIndexOnOracleDoubleQuotedSchema_shouldReturnIndex() throws SQLException {
  250. String indexName = "idx";
  251. String schema = "TEST-SONAR";
  252. ResultSet resultSet = newResultSet(true, indexName, schema);
  253. Optional<String> foundIndex = findExistingIndex(indexName, schema, resultSet, true);
  254. assertThat(foundIndex).hasValue(indexName);
  255. }
  256. @Test
  257. public void findExistingIndex_whenExistingIndexOnDefaultSchema_shouldReturnIndex() throws SQLException {
  258. String indexName = "idx";
  259. String schema = DEFAULT_SCHEMA;
  260. ResultSet resultSet = newResultSet(true, indexName, schema);
  261. Optional<String> foundIndex = findExistingIndex(indexName, schema, resultSet, true);
  262. assertThat(foundIndex).hasValue(indexName);
  263. }
  264. @Test
  265. public void findExistingIndex_whenNoExistingIndexOnOracleDoubleQuotedSchema_shouldNotReturnIndex() throws SQLException {
  266. String indexName = "idx";
  267. String schema = "TEST-SONAR";
  268. ResultSet resultSet = newResultSet(false, null, null);
  269. Optional<String> foundIndex = findExistingIndex(indexName, schema, resultSet, true);
  270. assertThat(foundIndex).isEmpty();
  271. }
  272. @Test
  273. public void findExistingIndex_whenNoMatchingIndexOnOracleDoubleQuotedSchema_shouldNotReturnIndex() throws SQLException {
  274. String indexName = "idx";
  275. String schema = "TEST-SONAR";
  276. ResultSet resultSet = newResultSet(true, "different", "different");
  277. Optional<String> foundIndex = findExistingIndex(indexName, schema, resultSet, true);
  278. assertThat(foundIndex).isEmpty();
  279. }
  280. @Test
  281. public void findExistingIndex_whenExistingIndexAndSchemaPassed_shouldFindIndex() throws SQLException {
  282. String indexName = "idx";
  283. String schema = DEFAULT_SCHEMA;
  284. ResultSet resultSet = newResultSet(true, indexName, schema);
  285. Optional<String> foundIndex = findExistingIndex(indexName, schema, resultSet, false);
  286. assertThat(foundIndex).hasValue(indexName);
  287. }
  288. @Test
  289. public void executeLargeInputs_whenALotOfElementsPassed_shouldProcessAllItems() {
  290. List<Integer> inputs = new ArrayList<>();
  291. List<String> expectedOutputs = new ArrayList<>();
  292. for (int i = 0; i < 2010; i++) {
  293. inputs.add(i);
  294. expectedOutputs.add(Integer.toString(i));
  295. }
  296. List<String> outputs = DatabaseUtils.executeLargeInputs(inputs, input -> {
  297. // Check that each partition is only done on 1000 elements max
  298. assertThat(input).hasSizeLessThanOrEqualTo(1000);
  299. return input.stream().map(String::valueOf).toList();
  300. });
  301. assertThat(outputs).isEqualTo(expectedOutputs);
  302. }
  303. @Test
  304. public void executeLargeInputsWithFunctionAsInput_whenEmptyList_shouldReturnEmpty() {
  305. List<String> outputs = DatabaseUtils.executeLargeInputs(Collections.emptyList(), (Function<List<Integer>, List<String>>) input -> {
  306. fail("No partition should be made on empty list");
  307. return Collections.emptyList();
  308. });
  309. assertThat(outputs).isEmpty();
  310. }
  311. @Test
  312. public void executeLargeUpdates_whenEmptyList_shouldFail() {
  313. DatabaseUtils.executeLargeUpdates(Collections.<Integer>emptyList(), input -> fail("No partition should be made on empty list"));
  314. }
  315. @Test
  316. public void executeLargeInputs_whenPartitionSizeIsCustom_shouldParitionAccordingly() {
  317. List<List<Integer>> partitions = new ArrayList<>();
  318. List<Integer> outputs = DatabaseUtils.executeLargeInputs(
  319. List.of(1, 2, 3),
  320. partition -> {
  321. partitions.add(partition);
  322. return partition;
  323. },
  324. i -> i / 500);
  325. assertThat(outputs).containsExactly(1, 2, 3);
  326. assertThat(partitions).containsExactly(List.of(1, 2), List.of(3));
  327. }
  328. @Test
  329. public void executeLargeUpdates_whenALotOfElementsPassed_shouldProcessAllItems() {
  330. List<Integer> inputs = new ArrayList<>();
  331. for (int i = 0; i < 2010; i++) {
  332. inputs.add(i);
  333. }
  334. List<Integer> processed = new ArrayList<>();
  335. DatabaseUtils.executeLargeUpdates(inputs, input -> {
  336. assertThat(input).hasSizeLessThanOrEqualTo(1000);
  337. processed.addAll(input);
  338. });
  339. assertThat(processed).containsExactlyElementsOf(inputs);
  340. }
  341. @Test
  342. public void logging_whenSomeExceptionThrown_shouldContainThemInTheLog() {
  343. SQLException root = new SQLException("this is root", "123");
  344. SQLException next = new SQLException("this is next", "456");
  345. root.setNextException(next);
  346. log(LoggerFactory.getLogger(getClass()), root);
  347. assertThat(logTester.logs(Level.ERROR)).contains("SQL error: 456. Message: this is next");
  348. }
  349. @Test
  350. public void tableExists_whenTableInTheMetadata_shouldReturnTrue() throws Exception {
  351. try (Connection connection = dbTester.openConnection()) {
  352. assertThat(tableExists("SCHEMA_MIGRATIONS", connection)).isTrue();
  353. assertThat(tableExists("schema_migrations", connection)).isTrue();
  354. assertThat(tableExists("schema_MIGRATIONS", connection)).isTrue();
  355. assertThat(tableExists("foo", connection)).isFalse();
  356. }
  357. }
  358. @Test
  359. public void tableExists_whenGetSchemaThrowException_shouldNotFail() throws Exception {
  360. try (Connection connection = spy(dbTester.openConnection())) {
  361. doThrow(AbstractMethodError.class).when(connection).getSchema();
  362. assertThat(tableExists("SCHEMA_MIGRATIONS", connection)).isTrue();
  363. assertThat(tableExists("schema_migrations", connection)).isTrue();
  364. assertThat(tableExists("schema_MIGRATIONS", connection)).isTrue();
  365. assertThat(tableExists("foo", connection)).isFalse();
  366. }
  367. }
  368. @Test//is_using_getSchema_when_not_using_h2
  369. public void tableExists_whenNotUsingH2_shouldReturnTrue() throws Exception {
  370. try (Connection connection = spy(dbTester.openConnection())) {
  371. // DatabaseMetaData mock
  372. DatabaseMetaData metaData = mock(DatabaseMetaData.class);
  373. doReturn("xxx").when(metaData).getDriverName();
  374. // ResultSet mock
  375. ResultSet resultSet = mock(ResultSet.class);
  376. doReturn(true, false).when(resultSet).next();
  377. doReturn(SCHEMA_MIGRATIONS_TABLE).when(resultSet).getString("TABLE_NAME");
  378. doReturn(resultSet).when(metaData).getTables(any(), eq("yyyy"), any(), any());
  379. // Connection mock
  380. doReturn("yyyy").when(connection).getSchema();
  381. doReturn(metaData).when(connection).getMetaData();
  382. assertThat(tableExists(SCHEMA_MIGRATIONS_TABLE, connection)).isTrue();
  383. }
  384. }
  385. @Test
  386. public void checkThatNotTooManyConditions_whenLessThan1000Items_shouldNotThrowException() {
  387. checkThatNotTooManyConditions(null, "unused");
  388. checkThatNotTooManyConditions(Collections.emptySet(), "unused");
  389. checkThatNotTooManyConditions(Collections.nCopies(10, "foo"), "unused");
  390. checkThatNotTooManyConditions(Collections.nCopies(1_000, "foo"), "unused");
  391. }
  392. @Test
  393. public void checkThatNotTooManyConditions_whenMoreThan1000ItemsInTheList_shouldNotThrowException() {
  394. List<String> list = Collections.nCopies(1_001, "foo");
  395. assertThatThrownBy(() -> checkThatNotTooManyConditions(list, "the message"))
  396. .isInstanceOf(IllegalArgumentException.class)
  397. .hasMessage("the message");
  398. }
  399. private Optional<String> findExistingIndex(String indexName, String schema, ResultSet resultSet, boolean isOracle) throws SQLException {
  400. Connection connection = mock(Connection.class);
  401. DatabaseMetaData metaData = mock(DatabaseMetaData.class);
  402. if (isOracle) {
  403. when(metaData.getDriverName()).thenReturn(ORACLE_DRIVER_NAME);
  404. }
  405. when(metaData.getIndexInfo(anyString(), eq(DEFAULT_SCHEMA.equals(schema) ? schema : null), anyString(), anyBoolean(), anyBoolean())).thenReturn(resultSet);
  406. when(connection.getMetaData()).thenReturn(metaData);
  407. when(connection.getSchema()).thenReturn(schema);
  408. when(connection.getCatalog()).thenReturn("catalog");
  409. return DatabaseUtils.findExistingIndex(connection, "test_table", indexName);
  410. }
  411. private ResultSet newResultSet(boolean hasNext, String indexName, String schema) throws SQLException {
  412. ResultSet resultSet = mock(ResultSet.class);
  413. when(resultSet.next()).thenReturn(hasNext).thenReturn(false);
  414. when(resultSet.getString("INDEX_NAME")).thenReturn(indexName);
  415. when(resultSet.getString("TABLE_SCHEM")).thenReturn(schema);
  416. return resultSet;
  417. }
  418. private static DatabaseUtilsIT.MyComparable myComparable(int ordinal) {
  419. return new DatabaseUtilsIT.MyComparable(ordinal);
  420. }
  421. private static final class MyComparable implements Comparable<MyComparable> {
  422. private final int ordinal;
  423. private MyComparable(int ordinal) {
  424. this.ordinal = ordinal;
  425. }
  426. @Override
  427. public int compareTo(MyComparable o) {
  428. return ordinal - o.ordinal;
  429. }
  430. @Override
  431. public boolean equals(@Nullable Object o) {
  432. if (this == o) {
  433. return true;
  434. }
  435. if (o == null || getClass() != o.getClass()) {
  436. return false;
  437. }
  438. MyComparable that = (MyComparable) o;
  439. return ordinal == that.ordinal;
  440. }
  441. @Override
  442. public int hashCode() {
  443. return Objects.hash(ordinal);
  444. }
  445. }
  446. /**
  447. * Connection.isClosed() has been introduced in java 1.6
  448. */
  449. private boolean isClosed(Connection c) {
  450. try {
  451. c.createStatement().execute(selectDual());
  452. return false;
  453. } catch (Exception e) {
  454. return true;
  455. }
  456. }
  457. /**
  458. * Statement.isClosed() has been introduced in java 1.6
  459. */
  460. private boolean isClosed(Statement s) {
  461. try {
  462. s.execute("SELECT 1");
  463. return false;
  464. } catch (Exception e) {
  465. return true;
  466. }
  467. }
  468. /**
  469. * ResultSet.isClosed() has been introduced in java 1.6
  470. */
  471. private boolean isClosed(ResultSet rs) {
  472. try {
  473. rs.next();
  474. return false;
  475. } catch (Exception e) {
  476. return true;
  477. }
  478. }
  479. private String selectDual() {
  480. String sql = "SELECT 1";
  481. if (Oracle.ID.equals(dbTester.database().getDialect().getId())) {
  482. sql = "SELECT 1 FROM DUAL";
  483. }
  484. return sql;
  485. }
  486. }