forked from apache/ignite
-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
IGNITE-5438: JDBC Thin Driver: support Statement.setQueryTimeout. This …
…closes apache#5772. This closes apache#5813. (cherry picked from commit 8734adf)
- Loading branch information
1 parent
40f5554
commit 0e94605
Showing
5 changed files
with
446 additions
and
65 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
311 changes: 311 additions & 0 deletions
311
...s/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStatementTimeoutSelfTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,311 @@ | ||
/* | ||
* Copyright 2019 GridGain Systems, Inc. and Contributors. | ||
* | ||
* Licensed under the GridGain Community Edition License (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.gridgain.com/products/software/community-edition/gridgain-community-edition-license | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package org.apache.ignite.jdbc.thin; | ||
|
||
import java.io.File; | ||
import java.io.FileWriter; | ||
import java.sql.Connection; | ||
import java.sql.DriverManager; | ||
import java.sql.SQLException; | ||
import java.sql.SQLTimeoutException; | ||
import java.sql.Statement; | ||
import org.apache.ignite.cache.query.annotations.QuerySqlFunction; | ||
import org.apache.ignite.configuration.CacheConfiguration; | ||
import org.apache.ignite.configuration.ClientConnectorConfiguration; | ||
import org.apache.ignite.configuration.IgniteConfiguration; | ||
import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi; | ||
import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder; | ||
import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder; | ||
import org.apache.ignite.testframework.GridTestUtils; | ||
import org.junit.After; | ||
import org.junit.Before; | ||
import org.junit.Test; | ||
import org.junit.runner.RunWith; | ||
import org.junit.runners.JUnit4; | ||
|
||
import static org.apache.ignite.cache.CacheMode.PARTITIONED; | ||
import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC; | ||
|
||
/** | ||
* Statement timeout test. | ||
*/ | ||
@SuppressWarnings("ThrowableNotThrown") | ||
@RunWith(JUnit4.class) | ||
public class JdbcThinStatementTimeoutSelfTest extends JdbcThinAbstractSelfTest { | ||
/** IP finder. */ | ||
private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true); | ||
|
||
/** URL. */ | ||
private static final String URL = "jdbc:ignite:thin://127.0.0.1/"; | ||
|
||
/** Server thread pull size. */ | ||
private static final int SERVER_THREAD_POOL_SIZE = 4; | ||
|
||
/** Connection. */ | ||
private Connection conn; | ||
|
||
/** Statement. */ | ||
private Statement stmt; | ||
|
||
/** {@inheritDoc} */ | ||
@Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { | ||
IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); | ||
|
||
CacheConfiguration<?,?> cache = defaultCacheConfiguration(); | ||
|
||
cache.setCacheMode(PARTITIONED); | ||
cache.setBackups(1); | ||
cache.setWriteSynchronizationMode(FULL_SYNC); | ||
cache.setSqlFunctionClasses(TestSQLFunctions.class); | ||
cache.setIndexedTypes(Integer.class, Integer.class, Long.class, Long.class, String.class, | ||
JdbcThinAbstractDmlStatementSelfTest.Person.class); | ||
|
||
cfg.setCacheConfiguration(cache); | ||
|
||
TcpDiscoverySpi disco = new TcpDiscoverySpi(); | ||
|
||
disco.setIpFinder(IP_FINDER); | ||
|
||
cfg.setDiscoverySpi(disco); | ||
|
||
cfg.setClientConnectorConfiguration(new ClientConnectorConfiguration().setThreadPoolSize(SERVER_THREAD_POOL_SIZE)); | ||
|
||
return cfg; | ||
} | ||
|
||
/** {@inheritDoc} */ | ||
@Override protected void beforeTestsStarted() throws Exception { | ||
super.beforeTestsStarted(); | ||
|
||
startGridsMultiThreaded(3); | ||
|
||
for (int i = 0; i < 10000; ++i) | ||
grid(0).cache(DEFAULT_CACHE_NAME).put(i, i); | ||
|
||
for (int i = 0; i < 10000; ++i) | ||
grid(0).cache(DEFAULT_CACHE_NAME).put((long)i, (long)i); | ||
} | ||
|
||
/** | ||
* Called before execution of every test method in class. | ||
* | ||
* @throws Exception If failed. | ||
*/ | ||
@Before | ||
public void before() throws Exception { | ||
conn = DriverManager.getConnection(URL); | ||
|
||
conn.setSchema('"' + DEFAULT_CACHE_NAME + '"'); | ||
|
||
stmt = conn.createStatement(); | ||
|
||
assert stmt != null; | ||
assert !stmt.isClosed(); | ||
} | ||
|
||
/** | ||
* Called after execution of every test method in class. | ||
* | ||
* @throws Exception If failed. | ||
*/ | ||
@After | ||
public void after() throws Exception { | ||
if (stmt != null && !stmt.isClosed()) { | ||
stmt.close(); | ||
|
||
assert stmt.isClosed(); | ||
} | ||
|
||
conn.close(); | ||
|
||
assert stmt.isClosed(); | ||
assert conn.isClosed(); | ||
} | ||
|
||
/** | ||
* Trying to set negative timeout. <code>SQLException</> with message "Invalid timeout value." is expected. | ||
*/ | ||
@Test | ||
public void testSettingNegativeQueryTimeout() { | ||
GridTestUtils.assertThrows(log, () -> { | ||
stmt.setQueryTimeout(-1); | ||
|
||
return null; | ||
}, SQLException.class, "Invalid timeout value."); | ||
} | ||
|
||
/** | ||
* Trying to set zero timeout. Zero timeout means no timeout, so no exception is expected. | ||
* | ||
* @throws Exception If failed. | ||
*/ | ||
@Test | ||
public void testSettingZeroQueryTimeout() throws Exception { | ||
stmt.setQueryTimeout(0); | ||
|
||
stmt.executeQuery("select sleep_func(1000);"); | ||
} | ||
|
||
/** | ||
* Setting timeout that is greater than query execution time. <code>SQLTimeoutException</code> is expected. | ||
* | ||
* @throws Exception If failed. | ||
*/ | ||
@Test | ||
public void testQueryTimeout() throws Exception { | ||
stmt.setQueryTimeout(2); | ||
|
||
GridTestUtils.assertThrows(log, () -> { | ||
stmt.executeQuery("select sleep_func(10) from Integer;"); | ||
|
||
return null; | ||
}, SQLTimeoutException.class, "The query was cancelled while executing."); | ||
} | ||
|
||
/** | ||
* Setting timeout that is greater than query execution time. Running same query multiple times. | ||
* <code>SQLTimeoutException</code> is expected in all cases. | ||
* | ||
* @throws Exception If failed. | ||
*/ | ||
@SuppressWarnings("unchecked") | ||
@Test | ||
public void testQueryTimeoutRepeatable() throws Exception { | ||
stmt.setQueryTimeout(2); | ||
|
||
GridTestUtils.assertThrows(log, () -> { | ||
stmt.executeQuery("select sleep_func(10) from Integer;"); | ||
|
||
return null; | ||
}, SQLTimeoutException.class, "The query was cancelled while executing."); | ||
|
||
GridTestUtils.assertThrows(log, () -> { | ||
stmt.executeQuery("select sleep_func(10) from Integer;"); | ||
|
||
return null; | ||
}, SQLTimeoutException.class, "The query was cancelled while executing."); | ||
} | ||
|
||
/** | ||
* Setting timeout that is greater than file uploading execution time. | ||
* <code>SQLTimeoutException</code> is expected. | ||
* | ||
* @throws Exception If failed. | ||
*/ | ||
@SuppressWarnings("unchecked") | ||
@Test | ||
public void testFileUploadingTimeout() throws Exception { | ||
|
||
File file = File.createTempFile("bulkload", "csv"); | ||
|
||
FileWriter writer = new FileWriter(file); | ||
|
||
for (int i = 1; i <= 1_000_000; i++) | ||
writer.write(String.format("%d,%d,\"FirstName%d MiddleName%d\",LastName%d", i, i, i, i, i)); | ||
|
||
writer.close(); | ||
|
||
stmt.setQueryTimeout(1); | ||
|
||
GridTestUtils.assertThrows(log, () -> { | ||
stmt.executeUpdate( | ||
"copy from '" + file.getAbsolutePath() + "' into Person" + | ||
" (_key, age, firstName, lastName)" + | ||
" format csv"); | ||
|
||
return null; | ||
}, SQLTimeoutException.class, "The query was cancelled while executing."); | ||
} | ||
|
||
/** | ||
* Setting timeout that is greater than batch query execution time. | ||
* <code>SQLTimeoutException</code> is expected. | ||
* | ||
* @throws Exception If failed. | ||
*/ | ||
@Test | ||
public void testBatchQuery() throws Exception { | ||
stmt.setQueryTimeout(1); | ||
|
||
GridTestUtils.assertThrows(log, () -> { | ||
stmt.addBatch("update Long set _val = _val + 1 where _key < sleep_func (30)"); | ||
stmt.addBatch("update Long set _val = _val + 1 where _key > sleep_func (10)"); | ||
|
||
stmt.executeBatch(); | ||
|
||
return null; | ||
}, SQLTimeoutException.class, "The query was cancelled while executing."); | ||
} | ||
|
||
/** | ||
* Setting timeout that is greater than multiple statements query execution time. | ||
* <code>SQLTimeoutException</code> is expected. | ||
* | ||
* @throws Exception If failed. | ||
*/ | ||
@Test | ||
public void testMultipleStatementsQuery() throws Exception { | ||
stmt.setQueryTimeout(1); | ||
|
||
GridTestUtils.assertThrows(log, () -> { | ||
stmt.execute( | ||
"update Long set _val = _val + 1 where _key > sleep_func (10);" | ||
+ "update Long set _val = _val + 1 where _key > sleep_func (10);" | ||
+ "update Long set _val = _val + 1 where _key > sleep_func (10);" | ||
+ "update Long set _val = _val + 1 where _key > sleep_func (10);" | ||
+ "select _val, sleep_func(10) as s from Integer limit 10"); | ||
|
||
return null; | ||
}, SQLTimeoutException.class, "The query was cancelled while executing."); | ||
} | ||
|
||
/** | ||
* Setting timeout that is greater than update query execution time. | ||
* <code>SQLTimeoutException</code> is expected. | ||
* | ||
* @throws Exception If failed. | ||
*/ | ||
@Test | ||
public void testExecuteUpdateTimeout() throws Exception { | ||
stmt.setQueryTimeout(1); | ||
|
||
GridTestUtils.assertThrows(log, () -> | ||
stmt.executeUpdate("update Integer set _val=1 where _key > sleep_func(10)"), | ||
SQLTimeoutException.class, "The query was cancelled while executing."); | ||
} | ||
|
||
/** | ||
* Utility class with custom SQL functions. | ||
*/ | ||
public static class TestSQLFunctions { | ||
/** | ||
* @param v amount of milliseconds to sleep | ||
* @return amount of milliseconds to sleep | ||
*/ | ||
@SuppressWarnings("unused") | ||
@QuerySqlFunction | ||
public static int sleep_func(int v) { | ||
try { | ||
Thread.sleep(v); | ||
} | ||
catch (InterruptedException ignored) { | ||
// No-op | ||
} | ||
return v; | ||
} | ||
} | ||
} |
Oops, something went wrong.