| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * 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.drill.jdbc; |
| |
| import static org.hamcrest.CoreMatchers.anyOf; |
| import static org.hamcrest.CoreMatchers.containsString; |
| import static org.hamcrest.CoreMatchers.equalTo; |
| import static org.junit.Assert.assertFalse; |
| import static org.hamcrest.MatcherAssert.assertThat; |
| import static org.junit.Assert.assertTrue; |
| |
| import org.apache.drill.categories.JdbcTest; |
| import org.apache.drill.exec.ExecConstants; |
| import org.junit.AfterClass; |
| import org.junit.BeforeClass; |
| import org.junit.Ignore; |
| import org.junit.Test; |
| import org.junit.experimental.categories.Category; |
| |
| import java.sql.Connection; |
| import java.sql.DriverManager; |
| import java.sql.PreparedStatement; |
| import java.sql.ResultSet; |
| import java.sql.SQLFeatureNotSupportedException; |
| import java.sql.SQLException; |
| import java.sql.Statement; |
| import java.util.Properties; |
| import java.util.concurrent.ExecutorService; |
| import java.util.concurrent.Executors; |
| |
| /** |
| * Test for Drill's implementation of Connection's methods (other than |
| * main transaction-related methods in {@link ConnectionTransactionMethodsTest}). |
| * TODO: When here will be more tests, they should be sorted according to the {@link Connection} methods order |
| */ |
| @Category(JdbcTest.class) |
| public class ConnectionTest extends JdbcTestBase { |
| |
| private static Connection connection; |
| |
| private static ExecutorService executor; |
| |
| |
| @BeforeClass |
| public static void setUpConnection() throws SQLException { |
| // (Note: Can't use JdbcTest's connect(...) because JdbcTest closes |
| // Connection--and other JDBC objects--on test method failure, but this test |
| // class uses some objects across methods.) |
| Driver.load(); |
| Properties properties = new Properties(); |
| properties.setProperty(ExecConstants.bootDefaultFor(ExecConstants.CREATE_PREPARE_STATEMENT_TIMEOUT_MILLIS), "30000"); |
| connection = DriverManager.getConnection( "jdbc:drill:zk=local", properties); |
| executor = Executors.newSingleThreadExecutor(); |
| } |
| |
| @AfterClass |
| public static void tearDownConnection() throws SQLException { |
| connection.close(); |
| executor.shutdown(); |
| } |
| |
| private static void emitSupportExceptionWarning() { |
| System.err.println( |
| "Note: Still throwing older-Avatica UnsupportedOperationException" |
| + " instead of less-noncompliant SQLFeatureNotSupportedException" ); |
| } |
| |
| |
| //////////////////////////////////////// |
| // Basic tests of statement creation methods (not necessarily executing |
| // statements): |
| |
| ////////// |
| // Simplest cases of createStatement, prepareStatement, prepareCall: |
| |
| @Test |
| public void testCreateStatementBasicCaseWorks() throws SQLException { |
| Statement stmt = connection.createStatement(); |
| ResultSet rs = stmt.executeQuery( "VALUES 1" ); |
| assertTrue( rs.next() ); |
| } |
| |
| @Test |
| public void testPrepareStatementBasicCaseWorks() throws SQLException { |
| PreparedStatement stmt = connection.prepareStatement( "VALUES 1" ); |
| ResultSet rs = stmt.executeQuery(); |
| assertTrue( rs.next() ); |
| } |
| |
| @Test( expected = SQLFeatureNotSupportedException.class ) |
| public void testPrepareCallThrows() throws SQLException { |
| try { |
| connection.prepareCall( "VALUES 1" ); |
| } |
| catch ( UnsupportedOperationException e) { |
| // TODO(DRILL-2769): Purge this mapping when right exception is thrown. |
| emitSupportExceptionWarning(); |
| throw new SQLFeatureNotSupportedException( |
| "Note: Still throwing UnsupportedOperationException ", e ); |
| } |
| } |
| |
| ////////// |
| // createStatement(int, int): |
| |
| @Test |
| public void testCreateStatement_overload2_supportedCase_returns() throws SQLException { |
| connection.createStatement( ResultSet.TYPE_FORWARD_ONLY, |
| ResultSet.CONCUR_READ_ONLY ); |
| } |
| |
| @Test( expected = SQLFeatureNotSupportedException.class ) |
| @Ignore( "until unsupported characteristics are rejected" ) |
| public void testCreateStatement_overload2_unsupportedType1_throws() throws SQLException { |
| connection.createStatement( ResultSet.TYPE_SCROLL_INSENSITIVE, |
| ResultSet.CONCUR_READ_ONLY ); |
| } |
| |
| @Test( expected = SQLFeatureNotSupportedException.class ) |
| @Ignore( "until unsupported characteristics are rejected" ) |
| public void testCreateStatement_overload2_unsupportedType2_throws() throws SQLException { |
| connection.createStatement( ResultSet.TYPE_SCROLL_SENSITIVE, |
| ResultSet.CONCUR_READ_ONLY); |
| } |
| |
| @Test( expected = SQLFeatureNotSupportedException.class ) |
| @Ignore( "until unsupported characteristics are rejected" ) |
| public void testCreateStatement_overload2_unsupportedConcurrency_throws() throws SQLException { |
| connection.createStatement( ResultSet.TYPE_FORWARD_ONLY, |
| ResultSet.CONCUR_UPDATABLE ); |
| } |
| |
| |
| ////////// |
| // prepareStatement(String, int, int, int): |
| |
| @Test |
| public void testPrepareStatement_overload2_supportedCase_returns() throws SQLException { |
| connection.prepareStatement( "VALUES 1", |
| ResultSet.TYPE_FORWARD_ONLY, |
| ResultSet.CONCUR_READ_ONLY ); |
| } |
| |
| @Test( expected = SQLFeatureNotSupportedException.class ) |
| @Ignore( "until unsupported characteristics are rejected" ) |
| public void testPrepareStatement_overload2_unsupportedType1_throws() throws SQLException { |
| connection.prepareStatement( "VALUES 1", |
| ResultSet.TYPE_SCROLL_INSENSITIVE, |
| ResultSet.CONCUR_READ_ONLY ); |
| } |
| |
| @Test( expected = SQLFeatureNotSupportedException.class ) |
| @Ignore( "until unsupported characteristics are rejected" ) |
| public void testPrepareStatement_overload2_unsupportedType2_throws() throws SQLException { |
| connection.prepareStatement( "VALUES 1", |
| ResultSet.TYPE_SCROLL_SENSITIVE, |
| ResultSet.CONCUR_READ_ONLY ); |
| } |
| |
| @Test( expected = SQLFeatureNotSupportedException.class ) |
| @Ignore( "until unsupported characteristics are rejected" ) |
| public void testPrepareStatement_overload2_unsupportedConcurrency_throws() throws SQLException { |
| connection.prepareStatement( "VALUES 1", |
| ResultSet.TYPE_FORWARD_ONLY, |
| ResultSet.CONCUR_UPDATABLE ); |
| } |
| |
| |
| ////////// |
| // createStatement(int, int, int) (case not covered with |
| // createStatement(int, int)): |
| |
| |
| @Test( expected = SQLFeatureNotSupportedException.class ) |
| @Ignore( "until unsupported characteristics are rejected" ) |
| public void testCreateStatement_overload3_unsupportedHoldability_throws() throws SQLException { |
| connection.createStatement( ResultSet.TYPE_FORWARD_ONLY, |
| ResultSet.CONCUR_READ_ONLY, |
| ResultSet.CLOSE_CURSORS_AT_COMMIT); |
| } |
| |
| |
| ////////// |
| // prepareStatement(int, int, int) (case not covered with |
| // prepareStatement(int, int)): |
| |
| @Test( expected = SQLFeatureNotSupportedException.class ) |
| @Ignore( "until unsupported characteristics are rejected" ) |
| public void testPrepareStatement_overload3_unsupportedHoldability_throws() throws SQLException { |
| connection.prepareStatement( "VALUES 1", |
| ResultSet.TYPE_FORWARD_ONLY, |
| ResultSet.CONCUR_READ_ONLY, |
| ResultSet.CLOSE_CURSORS_AT_COMMIT ); |
| } |
| |
| ////////// |
| // prepareCall(String, int, int, int): |
| |
| @Test( expected = SQLFeatureNotSupportedException.class ) |
| public void testCreateCall_overload3_throws() throws SQLException { |
| try { |
| connection.prepareCall( "VALUES 1", |
| ResultSet.TYPE_FORWARD_ONLY, |
| ResultSet.CONCUR_READ_ONLY, |
| ResultSet.HOLD_CURSORS_OVER_COMMIT ); |
| } |
| catch ( UnsupportedOperationException e) { |
| // TODO(DRILL-2769): Purge this mapping when right exception is thrown. |
| emitSupportExceptionWarning(); |
| throw new SQLFeatureNotSupportedException( |
| "Note: Still throwing UnsupportedOperationException ", e ); |
| } |
| } |
| |
| ////////// |
| // remaining prepareStatement(...): |
| |
| @Test( expected = SQLFeatureNotSupportedException.class ) |
| public void testPrepareStatement_overload4_throws() throws SQLException { |
| try { |
| connection.prepareStatement( "VALUES 1", Statement.RETURN_GENERATED_KEYS ); |
| } |
| catch ( UnsupportedOperationException e) { |
| // TODO(DRILL-2769): Purge this mapping when right exception is thrown. |
| emitSupportExceptionWarning(); |
| throw new SQLFeatureNotSupportedException( |
| "Note: Still throwing UnsupportedOperationException ", e ); |
| } |
| } |
| |
| @Test( expected = SQLFeatureNotSupportedException.class ) |
| public void testPrepareStatement_overload5_throws() throws SQLException { |
| try { |
| connection.prepareStatement( "VALUES 1", new int[] { 1 } ); |
| } |
| catch ( UnsupportedOperationException e) { |
| // TODO(DRILL-2769): Purge this mapping when right exception is thrown. |
| emitSupportExceptionWarning(); |
| throw new SQLFeatureNotSupportedException( |
| "Note: Still throwing UnsupportedOperationException ", e ); |
| } |
| } |
| |
| @Test( expected = SQLFeatureNotSupportedException.class ) |
| public void testPrepareStatement_overload6_throws() throws SQLException { |
| try { |
| connection.prepareStatement( "VALUES 1 AS colA", new String[] { "colA" } ); |
| } |
| catch ( UnsupportedOperationException e) { |
| // TODO(DRILL-2769): Purge this mapping when right exception is thrown. |
| emitSupportExceptionWarning(); |
| throw new SQLFeatureNotSupportedException( |
| "Note: Still throwing UnsupportedOperationException ", e ); |
| } |
| } |
| |
| |
| //////////////////////////////////////// |
| // Network timeout methods: |
| |
| ////////// |
| // getNetworkTimeout(): |
| |
| /** Tests that getNetworkTimeout() indicates no timeout set. */ |
| @Test |
| public void testGetNetworkTimeoutSaysNoTimeout() throws SQLException { |
| assertThat( connection.getNetworkTimeout(), equalTo( 0 ) ); |
| } |
| |
| ////////// |
| // setNetworkTimeout(...): |
| |
| /** Tests that setNetworkTimeout(...) accepts (redundantly) setting to |
| * no-timeout mode. */ |
| @Test |
| public void testSetNetworkTimeoutAcceptsNotimeoutRequest() throws SQLException { |
| connection.setNetworkTimeout( executor, 0 ); |
| } |
| |
| /** Tests that setNetworkTimeout(...) rejects setting a timeout. */ |
| @Test( expected = SQLFeatureNotSupportedException.class ) |
| public void testSetNetworkTimeoutRejectsTimeoutRequest() throws SQLException { |
| try { |
| connection.setNetworkTimeout( executor, 1_000 ); |
| } |
| catch ( SQLFeatureNotSupportedException e ) { |
| // Check exception for some mention of network timeout: |
| assertThat( e.getMessage(), anyOf( containsString( "Timeout" ), |
| containsString( "timeout" ) ) ); |
| throw e; |
| } |
| } |
| |
| /** Tests that setNetworkTimeout(...) rejects setting a timeout (different |
| * value). */ |
| @Test( expected = SQLFeatureNotSupportedException.class ) |
| public void testSetNetworkTimeoutRejectsTimeoutRequest2() throws SQLException { |
| connection.setNetworkTimeout( executor, Integer.MAX_VALUE ); |
| } |
| |
| @Test( expected = InvalidParameterSqlException.class ) |
| public void testSetNetworkTimeoutRejectsBadTimeoutValue() throws SQLException { |
| try { |
| connection.setNetworkTimeout( executor, -1 ); |
| } |
| catch ( InvalidParameterSqlException e ) { |
| // Check exception for some mention of parameter name or semantics: |
| assertThat( e.getMessage(), anyOf( containsString( "milliseconds" ), |
| containsString( "timeout" ), |
| containsString( "Timeout" ) ) ); |
| throw e; |
| } |
| } |
| |
| @Test( expected = InvalidParameterSqlException.class ) |
| public void testSetNetworkTimeoutRejectsBadExecutorValue() throws SQLException { |
| try { |
| connection.setNetworkTimeout( null, 1 ); |
| } |
| catch ( InvalidParameterSqlException e ) { |
| // Check exception for some mention of parameter name or semantics: |
| assertThat( e.getMessage(), anyOf( containsString( "executor" ), |
| containsString( "Executor" ) ) ); |
| throw e; |
| } |
| } |
| |
| @Test |
| public void testIsReadOnly() throws Exception { |
| assertFalse(connection.isReadOnly()); |
| } |
| |
| } |