http://git-wip-us.apache.org/repos/asf/calcite/blob/5cee486f/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java ---------------------------------------------------------------------- diff --git a/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java b/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java deleted file mode 100644 index ff95a45..0000000 --- a/avatica-server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java +++ /dev/null @@ -1,626 +0,0 @@ -/* - * 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.calcite.avatica.remote; - -import org.apache.calcite.avatica.AvaticaConnection; -import org.apache.calcite.avatica.AvaticaSqlException; -import org.apache.calcite.avatica.AvaticaStatement; -import org.apache.calcite.avatica.AvaticaUtils; -import org.apache.calcite.avatica.ConnectionPropertiesImpl; -import org.apache.calcite.avatica.ConnectionSpec; -import org.apache.calcite.avatica.Meta; -import org.apache.calcite.avatica.jdbc.JdbcMeta; -import org.apache.calcite.avatica.remote.Service.ErrorResponse; -import org.apache.calcite.avatica.remote.Service.Response; -import org.apache.calcite.avatica.server.AvaticaJsonHandler; -import org.apache.calcite.avatica.server.AvaticaProtobufHandler; -import org.apache.calcite.avatica.server.HttpServer; -import org.apache.calcite.avatica.server.Main; -import org.apache.calcite.avatica.server.Main.HandlerFactory; -import org.apache.calcite.avatica.util.ArrayImpl; - -import com.google.common.base.Throwables; -import com.google.common.cache.Cache; - -import org.junit.AfterClass; -import org.junit.Ignore; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.net.InetAddress; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.sql.Array; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.UUID; - -import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -/** Tests covering {@link RemoteMeta}. */ -@RunWith(Parameterized.class) -public class RemoteMetaTest { - private static final Random RANDOM = new Random(); - private static final ConnectionSpec CONNECTION_SPEC = ConnectionSpec.HSQLDB; - - // Keep a reference to the servers we start to clean them up after - private static final List<HttpServer> ACTIVE_SERVERS = new ArrayList<>(); - - private final HttpServer server; - private final String url; - private final int port; - private final Driver.Serialization serialization; - - @Parameters - public static List<Object[]> parameters() throws Exception { - List<Object[]> params = new ArrayList<>(); - - final String[] mainArgs = { FullyRemoteJdbcMetaFactory.class.getName() }; - - // Bind to '0' to pluck an ephemeral port instead of expecting a certain one to be free - - final HttpServer jsonServer = Main.start(mainArgs, 0, new HandlerFactory() { - @Override public AvaticaJsonHandler createHandler(Service service) { - return new AvaticaJsonHandler(service); - } - }); - params.add(new Object[] {jsonServer, Driver.Serialization.JSON}); - ACTIVE_SERVERS.add(jsonServer); - - final HttpServer protobufServer = Main.start(mainArgs, 0, new HandlerFactory() { - @Override public AvaticaProtobufHandler createHandler(Service service) { - return new AvaticaProtobufHandler(service); - } - }); - params.add(new Object[] {protobufServer, Driver.Serialization.PROTOBUF}); - - ACTIVE_SERVERS.add(protobufServer); - - return params; - } - - public RemoteMetaTest(HttpServer server, Driver.Serialization serialization) { - this.server = server; - this.port = this.server.getPort(); - this.serialization = serialization; - url = "jdbc:avatica:remote:url=http://localhost:" + port + ";serialization=" - + serialization.name(); - } - - @AfterClass public static void afterClass() throws Exception { - for (HttpServer server : ACTIVE_SERVERS) { - if (server != null) { - server.stop(); - } - } - } - - private static Meta getMeta(AvaticaConnection conn) throws Exception { - Field f = AvaticaConnection.class.getDeclaredField("meta"); - f.setAccessible(true); - return (Meta) f.get(conn); - } - - private static Meta.ExecuteResult prepareAndExecuteInternal(AvaticaConnection conn, - final AvaticaStatement statement, String sql, int maxRowCount) throws Exception { - Method m = - AvaticaConnection.class.getDeclaredMethod("prepareAndExecuteInternal", - AvaticaStatement.class, String.class, long.class); - m.setAccessible(true); - return (Meta.ExecuteResult) m.invoke(conn, statement, sql, maxRowCount); - } - - private static Connection getConnection(JdbcMeta m, String id) throws Exception { - Field f = JdbcMeta.class.getDeclaredField("connectionCache"); - f.setAccessible(true); - //noinspection unchecked - Cache<String, Connection> connectionCache = (Cache<String, Connection>) f.get(m); - return connectionCache.getIfPresent(id); - } - - @Test public void testRemoteExecuteMaxRowCount() throws Exception { - ConnectionSpec.getDatabaseLock().lock(); - try (AvaticaConnection conn = (AvaticaConnection) DriverManager.getConnection(url)) { - final AvaticaStatement statement = conn.createStatement(); - prepareAndExecuteInternal(conn, statement, - "select * from (values ('a', 1), ('b', 2))", 0); - ResultSet rs = statement.getResultSet(); - int count = 0; - while (rs.next()) { - count++; - } - assertEquals("Check maxRowCount=0 and ResultSets is 0 row", count, 0); - assertEquals("Check result set meta is still there", - rs.getMetaData().getColumnCount(), 2); - rs.close(); - statement.close(); - conn.close(); - } finally { - ConnectionSpec.getDatabaseLock().unlock(); - } - } - - /** Test case for - * <a href="https://issues.apache.org/jira/browse/CALCITE-780">[CALCITE-780] - * HTTP error 413 when sending a long string to the Avatica server</a>. */ - @Test public void testRemoteExecuteVeryLargeQuery() throws Exception { - ConnectionSpec.getDatabaseLock().lock(); - try { - // Before the bug was fixed, a value over 7998 caused an HTTP 413. - // 16K bytes, I guess. - checkLargeQuery(8); - checkLargeQuery(240); - checkLargeQuery(8000); - checkLargeQuery(240000); - } finally { - ConnectionSpec.getDatabaseLock().unlock(); - } - } - - private void checkLargeQuery(int n) throws Exception { - try (AvaticaConnection conn = (AvaticaConnection) DriverManager.getConnection(url)) { - final AvaticaStatement statement = conn.createStatement(); - final String frenchDisko = "It said human existence is pointless\n" - + "As acts of rebellious solidarity\n" - + "Can bring sense in this world\n" - + "La resistance!\n"; - final String sql = "select '" - + longString(frenchDisko, n) - + "' as s from (values 'x')"; - prepareAndExecuteInternal(conn, statement, sql, -1); - ResultSet rs = statement.getResultSet(); - int count = 0; - while (rs.next()) { - count++; - } - assertThat(count, is(1)); - rs.close(); - statement.close(); - conn.close(); - } - } - - /** Creates a string of exactly {@code length} characters by concatenating - * {@code fragment}. */ - private static String longString(String fragment, int length) { - assert fragment.length() > 0; - final StringBuilder buf = new StringBuilder(); - while (buf.length() < length) { - buf.append(fragment); - } - buf.setLength(length); - return buf.toString(); - } - - @Test public void testRemoteConnectionProperties() throws Exception { - ConnectionSpec.getDatabaseLock().lock(); - try (AvaticaConnection conn = (AvaticaConnection) DriverManager.getConnection(url)) { - String id = conn.id; - final Map<String, ConnectionPropertiesImpl> m = ((RemoteMeta) getMeta(conn)).propsMap; - assertFalse("remote connection map should start ignorant", m.containsKey(id)); - // force creating a connection object on the remote side. - try (final Statement stmt = conn.createStatement()) { - assertTrue("creating a statement starts a local object.", m.containsKey(id)); - assertTrue(stmt.execute("select count(1) from EMP")); - } - Connection remoteConn = getConnection(FullyRemoteJdbcMetaFactory.getInstance(), id); - final boolean defaultRO = remoteConn.isReadOnly(); - final boolean defaultAutoCommit = remoteConn.getAutoCommit(); - final String defaultCatalog = remoteConn.getCatalog(); - final String defaultSchema = remoteConn.getSchema(); - conn.setReadOnly(!defaultRO); - assertTrue("local changes dirty local state", m.get(id).isDirty()); - assertEquals("remote connection has not been touched", defaultRO, remoteConn.isReadOnly()); - conn.setAutoCommit(!defaultAutoCommit); - assertEquals("remote connection has not been touched", - defaultAutoCommit, remoteConn.getAutoCommit()); - - // further interaction with the connection will force a sync - try (final Statement stmt = conn.createStatement()) { - assertEquals(!defaultAutoCommit, remoteConn.getAutoCommit()); - assertFalse("local values should be clean", m.get(id).isDirty()); - } - } finally { - ConnectionSpec.getDatabaseLock().unlock(); - } - } - - @Test public void testRemoteStatementInsert() throws Exception { - final String t = AvaticaUtils.unique("TEST_TABLE2"); - AvaticaConnection conn = (AvaticaConnection) DriverManager.getConnection(url); - Statement statement = conn.createStatement(); - final String create = - String.format("create table if not exists %s (" - + " id int not null, msg varchar(255) not null)", t); - int status = statement.executeUpdate(create); - assertEquals(status, 0); - - statement = conn.createStatement(); - final String update = String.format("insert into %s values ('%d', '%s')", - t, RANDOM.nextInt(Integer.MAX_VALUE), UUID.randomUUID()); - status = statement.executeUpdate(update); - assertEquals(status, 1); - } - - @Test public void testBigints() throws Exception { - final String table = "TESTBIGINTS"; - ConnectionSpec.getDatabaseLock().lock(); - try (AvaticaConnection conn = (AvaticaConnection) DriverManager.getConnection(url); - Statement stmt = conn.createStatement()) { - assertFalse(stmt.execute("DROP TABLE IF EXISTS " + table)); - assertFalse(stmt.execute("CREATE TABLE " + table + " (id BIGINT)")); - assertFalse(stmt.execute("INSERT INTO " + table + " values(10)")); - ResultSet results = conn.getMetaData().getColumns(null, null, table, null); - assertTrue(results.next()); - assertEquals(table, results.getString(3)); - // ordinal position - assertEquals(1L, results.getLong(17)); - } finally { - ConnectionSpec.getDatabaseLock().unlock(); - } - } - - @Test public void testOpenConnectionWithProperties() throws Exception { - // This tests that username and password are used for creating a connection on the - // server. If this was not the case, it would succeed. - try { - DriverManager.getConnection(url, "john", "doe"); - fail("expected exception"); - } catch (RuntimeException e) { - assertEquals("Remote driver error: RuntimeException: " - + "java.sql.SQLInvalidAuthorizationSpecException: invalid authorization specification" - + " - not found: john" - + " -> SQLInvalidAuthorizationSpecException: invalid authorization specification - " - + "not found: john" - + " -> HsqlException: invalid authorization specification - not found: john", - e.getMessage()); - } - } - - @Test public void testRemoteConnectionsAreDifferent() throws SQLException { - Connection conn1 = DriverManager.getConnection(url); - Statement stmt = conn1.createStatement(); - stmt.execute("DECLARE LOCAL TEMPORARY TABLE" - + " buffer (id INTEGER PRIMARY KEY, textdata VARCHAR(100))"); - stmt.execute("insert into buffer(id, textdata) values(1, 'abc')"); - stmt.executeQuery("select * from buffer"); - - // The local temporary table is local to the connection above, and should - // not be visible on another connection - Connection conn2 = DriverManager.getConnection(url); - Statement stmt2 = conn2.createStatement(); - try { - stmt2.executeQuery("select * from buffer"); - fail("expected exception"); - } catch (Exception e) { - assertEquals("Error -1 (00000) : Error while executing SQL \"select * from buffer\": " - + "Remote driver error: RuntimeException: java.sql.SQLSyntaxErrorException: " - + "user lacks privilege or object not found: BUFFER -> " - + "SQLSyntaxErrorException: user lacks privilege or object not found: BUFFER -> " - + "HsqlException: user lacks privilege or object not found: BUFFER", - e.getMessage()); - } - } - - @Ignore("[CALCITE-942] AvaticaConnection should fail-fast when closed.") - @Test public void testRemoteConnectionClosing() throws Exception { - AvaticaConnection conn = (AvaticaConnection) DriverManager.getConnection(url); - // Verify connection is usable - conn.createStatement(); - conn.close(); - - // After closing the connection, it should not be usable anymore - try { - conn.createStatement(); - fail("expected exception"); - } catch (SQLException e) { - assertThat(e.getMessage(), - containsString("Connection is closed")); - } - } - - @Test public void testExceptionPropagation() throws Exception { - final String sql = "SELECT * from EMP LIMIT FOOBARBAZ"; - ConnectionSpec.getDatabaseLock().lock(); - try (final AvaticaConnection conn = (AvaticaConnection) DriverManager.getConnection(url); - final Statement stmt = conn.createStatement()) { - try { - // invalid SQL - stmt.execute(sql); - fail("Expected an AvaticaSqlException"); - } catch (AvaticaSqlException e) { - assertEquals(ErrorResponse.UNKNOWN_ERROR_CODE, e.getErrorCode()); - assertEquals(ErrorResponse.UNKNOWN_SQL_STATE, e.getSQLState()); - assertTrue("Message should contain original SQL, was '" + e.getMessage() + "'", - e.getMessage().contains(sql)); - assertEquals(1, e.getStackTraces().size()); - final String stacktrace = e.getStackTraces().get(0); - final String substring = "unexpected token: FOOBARBAZ"; - assertTrue("Message should contain '" + substring + "', was '" + e.getMessage() + ",", - stacktrace.contains(substring)); - } - } finally { - ConnectionSpec.getDatabaseLock().unlock(); - } - } - - @Test public void testRemoteColumnsMeta() throws Exception { - // Verify all columns are retrieved, thus that frame-based fetching works correctly for columns - int rowCount = 0; - try (AvaticaConnection conn = (AvaticaConnection) DriverManager.getConnection(url)) { - ResultSet rs = conn.getMetaData().getColumns(null, null, null, null); - while (rs.next()) { - rowCount++; - } - rs.close(); - - // The implicitly created statement should have been closed - assertTrue(rs.getStatement().isClosed()); - } - // default fetch size is 100, we are well beyond it - assertTrue(rowCount > 900); - } - - @Test public void testArrays() throws SQLException { - ConnectionSpec.getDatabaseLock().lock(); - try (AvaticaConnection conn = (AvaticaConnection) DriverManager.getConnection(url); - Statement stmt = conn.createStatement()) { - ResultSet resultSet = - stmt.executeQuery("select * from (values ('a', array['b', 'c']));"); - - assertTrue(resultSet.next()); - assertEquals("a", resultSet.getString(1)); - Array arr = resultSet.getArray(2); - assertTrue(arr instanceof ArrayImpl); - Object[] values = (Object[]) ((ArrayImpl) arr).getArray(); - assertArrayEquals(new String[]{"b", "c"}, values); - } finally { - ConnectionSpec.getDatabaseLock().unlock(); - } - } - - @Test public void testBinaryAndStrings() throws Exception { - final String tableName = "testbinaryandstrs"; - final byte[] data = "asdf".getBytes(StandardCharsets.UTF_8); - ConnectionSpec.getDatabaseLock().lock(); - try (final Connection conn = DriverManager.getConnection(url); - final Statement stmt = conn.createStatement()) { - assertFalse(stmt.execute("DROP TABLE IF EXISTS " + tableName)); - assertFalse(stmt.execute("CREATE TABLE " + tableName + "(id int, bin BINARY(4))")); - try (final PreparedStatement prepStmt = conn.prepareStatement( - "INSERT INTO " + tableName + " values(1, ?)")) { - prepStmt.setBytes(1, data); - assertFalse(prepStmt.execute()); - } - try (ResultSet results = stmt.executeQuery("SELECT id, bin from " + tableName)) { - assertTrue(results.next()); - assertEquals(1, results.getInt(1)); - // byte comparison should work - assertArrayEquals("Bytes were " + Arrays.toString(results.getBytes(2)), - data, results.getBytes(2)); - // as should string - assertEquals(new String(data, StandardCharsets.UTF_8), results.getString(2)); - assertFalse(results.next()); - } - } finally { - ConnectionSpec.getDatabaseLock().unlock(); - } - } - - @Test public void testLocalStackTraceHasServerStackTrace() { - ConnectionSpec.getDatabaseLock().lock(); - try { - Statement statement = DriverManager.getConnection(url).createStatement(); - statement.executeQuery("SELECT * FROM BOGUS_TABLE_DEF_DOESNT_EXIST"); - } catch (SQLException e) { - // Verify that we got the expected exception - assertThat(e, instanceOf(AvaticaSqlException.class)); - - // Attempt to verify that we got a "server-side" class in the stack. - assertThat(Throwables.getStackTraceAsString(e), - containsString(JdbcMeta.class.getName())); - } finally { - ConnectionSpec.getDatabaseLock().unlock(); - } - } - - @Test public void testServerAddressInResponse() throws Exception { - ConnectionSpec.getDatabaseLock().lock(); - try { - URL url = new URL("http://localhost:" + this.port); - AvaticaHttpClient httpClient = new AvaticaHttpClientImpl(url); - byte[] request; - - Service.OpenConnectionRequest jsonReq = new Service.OpenConnectionRequest( - UUID.randomUUID().toString(), Collections.<String, String>emptyMap()); - switch (this.serialization) { - case JSON: - request = JsonService.MAPPER.writeValueAsBytes(jsonReq); - break; - case PROTOBUF: - ProtobufTranslation pbTranslation = new ProtobufTranslationImpl(); - request = pbTranslation.serializeRequest(jsonReq); - break; - default: - throw new IllegalStateException("Should not reach here"); - } - - byte[] response = httpClient.send(request); - Service.OpenConnectionResponse openCnxnResp; - switch (this.serialization) { - case JSON: - openCnxnResp = JsonService.MAPPER.readValue(response, - Service.OpenConnectionResponse.class); - break; - case PROTOBUF: - ProtobufTranslation pbTranslation = new ProtobufTranslationImpl(); - Response genericResp = pbTranslation.parseResponse(response); - assertTrue("Expected an OpenConnnectionResponse, but got " + genericResp.getClass(), - genericResp instanceof Service.OpenConnectionResponse); - openCnxnResp = (Service.OpenConnectionResponse) genericResp; - break; - default: - throw new IllegalStateException("Should not reach here"); - } - - String hostname = InetAddress.getLocalHost().getHostName(); - - assertNotNull(openCnxnResp.rpcMetadata); - assertEquals(hostname + ":" + this.port, openCnxnResp.rpcMetadata.serverAddress); - } finally { - ConnectionSpec.getDatabaseLock().unlock(); - } - } - - @Test public void testCommitRollback() throws Exception { - final String productTable = "commitrollback_products"; - final String salesTable = "commitrollback_sales"; - ConnectionSpec.getDatabaseLock().lock(); - try (final Connection conn = DriverManager.getConnection(url); - final Statement stmt = conn.createStatement()) { - assertFalse(stmt.execute("DROP TABLE IF EXISTS " + productTable)); - assertFalse( - stmt.execute( - String.format("CREATE TABLE %s(id integer, stock integer)", productTable))); - assertFalse(stmt.execute("DROP TABLE IF EXISTS " + salesTable)); - assertFalse( - stmt.execute( - String.format("CREATE TABLE %s(id integer, units_sold integer)", salesTable))); - - final int productId = 1; - // No products and no sales - assertFalse( - stmt.execute( - String.format("INSERT INTO %s VALUES(%d, 0)", productTable, productId))); - assertFalse( - stmt.execute( - String.format("INSERT INTO %s VALUES(%d, 0)", salesTable, productId))); - - conn.setAutoCommit(false); - PreparedStatement productStmt = conn.prepareStatement( - String.format("UPDATE %s SET stock = stock + ? WHERE id = ?", productTable)); - PreparedStatement salesStmt = conn.prepareStatement( - String.format("UPDATE %s SET units_sold = units_sold + ? WHERE id = ?", salesTable)); - - // No stock - assertEquals(0, getInventory(conn, productTable, productId)); - - // Set a stock of 10 for product 1 - productStmt.setInt(1, 10); - productStmt.setInt(2, productId); - productStmt.executeUpdate(); - - conn.commit(); - assertEquals(10, getInventory(conn, productTable, productId)); - - // Sold 5 items (5 in stock, 5 sold) - productStmt.setInt(1, -5); - productStmt.setInt(2, productId); - productStmt.executeUpdate(); - salesStmt.setInt(1, 5); - salesStmt.setInt(2, productId); - salesStmt.executeUpdate(); - - conn.commit(); - // We will definitely see the updated values - assertEquals(5, getInventory(conn, productTable, productId)); - assertEquals(5, getSales(conn, salesTable, productId)); - - // Update some "bad" values - productStmt.setInt(1, -10); - productStmt.setInt(2, productId); - productStmt.executeUpdate(); - salesStmt.setInt(1, 10); - salesStmt.setInt(2, productId); - salesStmt.executeUpdate(); - - // We just went negative, nonsense. Better rollback. - conn.rollback(); - - // Should still have 5 and 5 - assertEquals(5, getInventory(conn, productTable, productId)); - assertEquals(5, getSales(conn, salesTable, productId)); - } finally { - ConnectionSpec.getDatabaseLock().unlock(); - } - } - - private int getInventory(Connection conn, String productTable, int productId) throws Exception { - try (Statement stmt = conn.createStatement()) { - ResultSet results = stmt.executeQuery( - String.format("SELECT stock FROM %s WHERE id = %d", productTable, productId)); - assertTrue(results.next()); - return results.getInt(1); - } - } - - private int getSales(Connection conn, String salesTable, int productId) throws Exception { - try (Statement stmt = conn.createStatement()) { - ResultSet results = stmt.executeQuery( - String.format("SELECT units_sold FROM %s WHERE id = %d", salesTable, productId)); - assertTrue(results.next()); - return results.getInt(1); - } - } - - /** Factory that provides a {@link JdbcMeta}. */ - public static class FullyRemoteJdbcMetaFactory implements Meta.Factory { - - private static JdbcMeta instance = null; - - private static JdbcMeta getInstance() { - if (instance == null) { - try { - instance = new JdbcMeta(CONNECTION_SPEC.url, CONNECTION_SPEC.username, - CONNECTION_SPEC.password); - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - return instance; - } - - @Override public Meta create(List<String> args) { - return getInstance(); - } - } -} - -// End RemoteMetaTest.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/5cee486f/avatica-server/src/test/java/org/apache/calcite/avatica/server/HandlerFactoryTest.java ---------------------------------------------------------------------- diff --git a/avatica-server/src/test/java/org/apache/calcite/avatica/server/HandlerFactoryTest.java b/avatica-server/src/test/java/org/apache/calcite/avatica/server/HandlerFactoryTest.java deleted file mode 100644 index 3504e02..0000000 --- a/avatica-server/src/test/java/org/apache/calcite/avatica/server/HandlerFactoryTest.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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.calcite.avatica.server; - -import org.apache.calcite.avatica.remote.Driver.Serialization; -import org.apache.calcite.avatica.remote.Service; - -import org.eclipse.jetty.server.Handler; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mockito; - -import static org.junit.Assert.assertTrue; - -/** - * Tests the {@link HandlerFactory} implementation. - */ -public class HandlerFactoryTest { - - private HandlerFactory factory; - private Service service; - - @Before - public void setup() { - this.factory = new HandlerFactory(); - this.service = Mockito.mock(Service.class); - } - - @Test - public void testJson() { - Handler handler = factory.getHandler(service, Serialization.JSON); - assertTrue("Expected an implementation of the AvaticaHandler, " - + "but got " + handler.getClass(), handler instanceof AvaticaJsonHandler); - } - - @Test - public void testProtobuf() { - Handler handler = factory.getHandler(service, Serialization.PROTOBUF); - assertTrue("Expected an implementation of the AvaticaProtobufHandler, " - + "but got " + handler.getClass(), handler instanceof AvaticaProtobufHandler); - } -} - -// End HandlerFactoryTest.java http://git-wip-us.apache.org/repos/asf/calcite/blob/5cee486f/avatica-server/src/test/java/org/apache/calcite/avatica/test/AvaticaSuite.java ---------------------------------------------------------------------- diff --git a/avatica-server/src/test/java/org/apache/calcite/avatica/test/AvaticaSuite.java b/avatica-server/src/test/java/org/apache/calcite/avatica/test/AvaticaSuite.java deleted file mode 100644 index 4a0c26c..0000000 --- a/avatica-server/src/test/java/org/apache/calcite/avatica/test/AvaticaSuite.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * 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.calcite.avatica.test; - -import org.apache.calcite.avatica.RemoteDriverTest; - -import org.junit.runner.RunWith; - -import org.junit.runners.Suite; - -/** - * Avatica test suite. - */ -@RunWith(Suite.class) [email protected]({ - AvaticaUtilsTest.class, - ConnectStringParserTest.class, - RemoteDriverTest.class -}) -public class AvaticaSuite { -} - -// End AvaticaSuite.java http://git-wip-us.apache.org/repos/asf/calcite/blob/5cee486f/avatica-server/src/test/resources/log4j.properties ---------------------------------------------------------------------- diff --git a/avatica-server/src/test/resources/log4j.properties b/avatica-server/src/test/resources/log4j.properties deleted file mode 100644 index 834e2db..0000000 --- a/avatica-server/src/test/resources/log4j.properties +++ /dev/null @@ -1,24 +0,0 @@ -# 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. - -# Root logger is configured at INFO and is sent to A1 -log4j.rootLogger=INFO, A1 - -# A1 goes to the console -log4j.appender.A1=org.apache.log4j.ConsoleAppender - -# Set the pattern for each log message -log4j.appender.A1.layout=org.apache.log4j.PatternLayout -log4j.appender.A1.layout.ConversionPattern=%d [%t] %-5p - %m%n http://git-wip-us.apache.org/repos/asf/calcite/blob/5cee486f/avatica/LICENSE ---------------------------------------------------------------------- diff --git a/avatica/LICENSE b/avatica/LICENSE new file mode 100644 index 0000000..f7b9863 --- /dev/null +++ b/avatica/LICENSE @@ -0,0 +1,268 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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. + + + + + +----------------------------------------------------------------------- + +APACHE CALCITE SUBCOMPONENTS: + +The Apache Calcite project contains subcomponents with separate copyright +notices and license terms. Your use of the source code for the these +subcomponents is subject to the terms and conditions of the following +licenses. + +----------------------------------------------------------------------- + The MIT License +----------------------------------------------------------------------- + +The Apache Calcite project bundles the following files under the MIT License: + +- site + Parts of the web site generated by Jekyll (http://jekyllrb.com/) + Copyright (c) 2008-2015 Tom Preston-Werner +- site/_sass/_font-awesome.scss + Font-awesome css files v4.1.0 (http://fortawesome.github.io/Font-Awesome/) + Copyright (c) 2013 Dave Gandy +- site/_sass/_normalize.scss + normalize.css v3.0.2 | git.io/normalize + Copyright (c) Nicolas Gallagher and Jonathan Neal +- site/_sass/_gridism.scss + Gridism: A simple, responsive, and handy CSS grid by @cobyism + https://github.com/cobyism/gridism + Copyright (c) 2013 Coby Chapple +- site/js/html5shiv.min.js + HTML5 Shiv 3.7.2 | @afarkas @jdalton @jon_neal @rem +- site/js/respond.min.js + Respond.js v1.4.2: min/max-width media query polyfill + Copyright 2013 Scott Jehl + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +----------------------------------------------------------------------- + The Open Font License +----------------------------------------------------------------------- + +The Apache Calcite project bundles the following fonts under the +SIL Open Font License (OFL) - http://scripts.sil.org/OFL/ + +- site/fonts/fontawesome-webfont.* + Font-awesome font files v4.0.3 (http://fortawesome.github.io/Font-Awesome/) http://git-wip-us.apache.org/repos/asf/calcite/blob/5cee486f/avatica/NOTICE ---------------------------------------------------------------------- diff --git a/avatica/NOTICE b/avatica/NOTICE new file mode 100644 index 0000000..989c480 --- /dev/null +++ b/avatica/NOTICE @@ -0,0 +1,10 @@ +Apache Calcite +Copyright 2012-2016 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). + +This product is based on source code originally developed +by DynamoBI Corporation, LucidEra Inc., SQLstream Inc. and others +under the auspices of the Eigenbase Foundation +and released as the LucidDB project. http://git-wip-us.apache.org/repos/asf/calcite/blob/5cee486f/avatica/core/pom.xml ---------------------------------------------------------------------- diff --git a/avatica/core/pom.xml b/avatica/core/pom.xml new file mode 100644 index 0000000..192d2dd --- /dev/null +++ b/avatica/core/pom.xml @@ -0,0 +1,224 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- +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. +--> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.apache.calcite.avatica</groupId> + <artifactId>calcite-avatica-parent</artifactId> + <version>1.7.0-SNAPSHOT</version> + </parent> + + <artifactId>calcite-avatica</artifactId> + <packaging>jar</packaging> + <name>Calcite Avatica</name> + <description>JDBC driver framework.</description> + + <properties> + <top.dir>${project.basedir}/..</top.dir> + </properties> + + <dependencies> + <!-- Make sure that there are no dependencies on other calcite modules, + or on libraries other than Jackson. --> + <dependency> + <groupId>org.apache.calcite</groupId> + <artifactId>calcite-avatica-metrics</artifactId> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-core</artifactId> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-annotations</artifactId> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-databind</artifactId> + </dependency> + <dependency> + <groupId>com.google.protobuf</groupId> + <artifactId>protobuf-java</artifactId> + </dependency> + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpclient</artifactId> + </dependency> + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpcore</artifactId> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>hamcrest-core</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-all</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-log4j12</artifactId> + <scope>test</scope> + </dependency> + </dependencies> + + <build> + <pluginManagement> + <plugins> + <plugin> + <groupId>org.eclipse.m2e</groupId> + <artifactId>lifecycle-mapping</artifactId> + <version>1.0.0</version> + <configuration> + <lifecycleMappingMetadata> + <pluginExecutions> + <pluginExecution> + <pluginExecutionFilter> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-checkstyle-plugin</artifactId> + <versionRange>[2.12.1,)</versionRange> + <goals> + <goal>check</goal> + </goals> + </pluginExecutionFilter> + <action> + <ignore /> + </action> + </pluginExecution> + </pluginExecutions> + </lifecycleMappingMetadata> + </configuration> + </plugin> + </plugins> + </pluginManagement> + <plugins> + <plugin> + <artifactId>maven-dependency-plugin</artifactId> + <executions> + <execution> + <id>analyze</id> + <goals> + <goal>analyze-only</goal> + </goals> + <configuration> + <failOnWarning>true</failOnWarning> + <!-- ignore "unused but declared" warnings --> + <ignoredUnusedDeclaredDependencies> + <ignoredUnusedDeclaredDependency>org.slf4j:slf4j-log4j12</ignoredUnusedDeclaredDependency> + </ignoredUnusedDeclaredDependencies> + </configuration> + </execution> + </executions> + </plugin> + <!-- Parent module has the same plugin and does the work of + generating -sources.jar for each project. But without the + plugin declared here, IDEs don't know the sources are + available. --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-source-plugin</artifactId> + <executions> + <execution> + <id>attach-sources</id> + <phase>verify</phase> + <goals> + <goal>jar-no-fork</goal> + <goal>test-jar-no-fork</goal> + </goals> + </execution> + </executions> + </plugin> + + <!-- Produce a tests jar so that avatica-server/pom.xml can reference for suite. + TODO: remove after moving over to annotation-based TestSuite definitions. --> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <executions> + <execution> + <goals> + <goal>test-jar</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <artifactId>maven-remote-resources-plugin</artifactId> + <executions> + <execution> + <id>non-root-resources</id> + <goals> + <goal>process</goal> + </goals> + </execution> + </executions> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-shade-plugin</artifactId> + <executions> + <execution> + <phase>package</phase> + <goals> + <goal>shade</goal> + </goals> + <configuration> + <relocations> + <relocation> + <pattern>com.google.protobuf</pattern> + <shadedPattern>org.apache.calcite.avatica.com.google.protobuf</shadedPattern> + </relocation> + <relocation> + <pattern>org.apache.http</pattern> + <shadedPattern>org.apache.calcite.avatica.org.apache.http</shadedPattern> + </relocation> + <relocation> + <pattern>org.apache.commons</pattern> + <shadedPattern>org.apache.calcite.avatica.org.apache.commons</shadedPattern> + </relocation> + </relocations> + <createDependencyReducedPom>false</createDependencyReducedPom> + <transformers> + <transformer implementation="org.apache.maven.plugins.shade.resource.ApacheNoticeResourceTransformer"> + <addHeader>false</addHeader> + </transformer> + <transformer implementation="org.apache.maven.plugins.shade.resource.DontIncludeResourceTransformer"> + <resources> + <resource>LICENSE.txt</resource> + </resources> + </transformer> + </transformers> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> http://git-wip-us.apache.org/repos/asf/calcite/blob/5cee486f/avatica/core/src/main/java/com/google/protobuf/HBaseZeroCopyByteString.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/com/google/protobuf/HBaseZeroCopyByteString.java b/avatica/core/src/main/java/com/google/protobuf/HBaseZeroCopyByteString.java new file mode 100644 index 0000000..62c4dd2 --- /dev/null +++ b/avatica/core/src/main/java/com/google/protobuf/HBaseZeroCopyByteString.java @@ -0,0 +1,77 @@ +/* + * 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 com.google.protobuf; + +/** + * Helper class to extract byte arrays from {@link ByteString} without copy. + * + * Without this protobufs would force us to copy every single byte array out + * of the objects de-serialized from the wire (which already do one copy, on + * top of the copies the JVM does to go from kernel buffer to C buffer and + * from C buffer to JVM buffer). + * + * Graciously copied from Apache HBase. + */ +public final class HBaseZeroCopyByteString extends LiteralByteString { + // Gotten from AsyncHBase code base with permission. + /** Private constructor so this class cannot be instantiated. */ + private HBaseZeroCopyByteString() { + super(null); + throw new UnsupportedOperationException("Should never be here."); + } + + /** + * Wraps a byte array in a {@link ByteString} without copying it. + * + * @param array The byte array to wrap + * @return a ByteString wrapping the <code>array</code> + */ + public static ByteString wrap(final byte[] array) { + return new LiteralByteString(array); + } + + /** + * Wraps a subset of a byte array in a {@link ByteString} without copying it. + * + * @param array The byte array to wrap + * @param offset the start of data in the array + * @param length The number of bytes of data at <code>offset</code> + * @return a ByteString wrapping the <code>array</code> + */ + public static ByteString wrap(final byte[] array, int offset, int length) { + return new BoundedByteString(array, offset, length); + } + + + /** + * Extracts the byte array from the given {@link ByteString} without copy. + * @param buf A buffer from which to extract the array. This buffer must be + * actually an instance of a {@code LiteralByteString}. + * + * @param buf <code>ByteString</code> to access + * @return The underlying byte array of the ByteString + */ + public static byte[] zeroCopyGetBytes(final ByteString buf) { + if (buf instanceof LiteralByteString) { + return ((LiteralByteString) buf).bytes; + } + throw new UnsupportedOperationException("Need a LiteralByteString, got a " + + buf.getClass().getName()); + } +} + +// End HBaseZeroCopyByteString.java http://git-wip-us.apache.org/repos/asf/calcite/blob/5cee486f/avatica/core/src/main/java/com/google/protobuf/package-info.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/com/google/protobuf/package-info.java b/avatica/core/src/main/java/com/google/protobuf/package-info.java new file mode 100644 index 0000000..92f110e --- /dev/null +++ b/avatica/core/src/main/java/com/google/protobuf/package-info.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +/** + * Avatica-custom classes to access protected classes in Google Protobuf. + */ +@PackageMarker +package com.google.protobuf; + +import org.apache.calcite.avatica.util.PackageMarker; + +// End package-info.java http://git-wip-us.apache.org/repos/asf/calcite/blob/5cee486f/avatica/core/src/main/java/org/apache/calcite/avatica/AvaticaClientRuntimeException.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/AvaticaClientRuntimeException.java b/avatica/core/src/main/java/org/apache/calcite/avatica/AvaticaClientRuntimeException.java new file mode 100644 index 0000000..df03b03 --- /dev/null +++ b/avatica/core/src/main/java/org/apache/calcite/avatica/AvaticaClientRuntimeException.java @@ -0,0 +1,94 @@ +/* + * 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.calcite.avatica; + +import org.apache.calcite.avatica.remote.AvaticaRuntimeException; +import org.apache.calcite.avatica.remote.Service.ErrorResponse; +import org.apache.calcite.avatica.remote.Service.RpcMetadataResponse; + +import java.util.Collections; +import java.util.List; + +/** + * The client-side representation of {@link AvaticaRuntimeException}. This exception is not intended + * for consumption by clients, {@link AvaticaSqlException} serves that purpose. This exception only + * exists to pass the original error attributes to a higher level of execution without modifying + * existing exception-handling logic. + */ +public class AvaticaClientRuntimeException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + private final int errorCode; + private final String sqlState; + private final AvaticaSeverity severity; + private final List<String> serverExceptions; + private final RpcMetadataResponse metadata; + + public AvaticaClientRuntimeException(String errorMessage, int errorCode, String sqlState, + AvaticaSeverity severity, List<String> serverExceptions, RpcMetadataResponse metadata) { + super(errorMessage); + this.errorCode = errorCode; + this.sqlState = sqlState; + this.severity = severity; + this.serverExceptions = serverExceptions; + this.metadata = metadata; + } + + public AvaticaClientRuntimeException(String message, Throwable cause) { + super(message, cause); + errorCode = ErrorResponse.UNKNOWN_ERROR_CODE; + sqlState = ErrorResponse.UNKNOWN_SQL_STATE; + severity = AvaticaSeverity.UNKNOWN; + serverExceptions = Collections.singletonList(""); + metadata = null; + } + + public int getErrorCode() { + return errorCode; + } + + public String getSqlState() { + return sqlState; + } + + public AvaticaSeverity getSeverity() { + return severity; + } + + public List<String> getServerExceptions() { + return serverExceptions; + } + + public RpcMetadataResponse getRpcMetadata() { + return metadata; + } + + @Override public String toString() { + StringBuilder sb = new StringBuilder(64); + sb.append(getClass().getSimpleName()).append(": ") + .append(getMessage()).append(". Error ").append(getErrorCode()) + .append(" (").append(sqlState).append(") ").append(getSeverity()).append("\n\n"); + for (String serverException : getServerExceptions()) { + sb.append(serverException).append("\n"); + } + return sb.toString(); + } + +} + +// End AvaticaClientRuntimeException.java http://git-wip-us.apache.org/repos/asf/calcite/blob/5cee486f/avatica/core/src/main/java/org/apache/calcite/avatica/AvaticaConnection.java ---------------------------------------------------------------------- diff --git a/avatica/core/src/main/java/org/apache/calcite/avatica/AvaticaConnection.java b/avatica/core/src/main/java/org/apache/calcite/avatica/AvaticaConnection.java new file mode 100644 index 0000000..2d89f45 --- /dev/null +++ b/avatica/core/src/main/java/org/apache/calcite/avatica/AvaticaConnection.java @@ -0,0 +1,696 @@ +/* + * 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.calcite.avatica; + +import org.apache.calcite.avatica.Meta.MetaResultSet; +import org.apache.calcite.avatica.remote.Service.ErrorResponse; +import org.apache.calcite.avatica.remote.Service.OpenConnectionRequest; +import org.apache.calcite.avatica.remote.TypedValue; + +import java.sql.Array; +import java.sql.Blob; +import java.sql.CallableStatement; +import java.sql.Clob; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.NClob; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLClientInfoException; +import java.sql.SQLException; +import java.sql.SQLWarning; +import java.sql.SQLXML; +import java.sql.Savepoint; +import java.sql.Statement; +import java.sql.Struct; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Properties; +import java.util.TimeZone; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; + +/** + * Implementation of JDBC connection + * for the Avatica framework. + * + * <p>Abstract to allow newer versions of JDBC to add methods. + */ +public abstract class AvaticaConnection implements Connection { + + /** The name of the sole column returned by DML statements, containing + * the number of rows modified. */ + public static final String ROWCOUNT_COLUMN_NAME = "ROWCOUNT"; + + public static final String NUM_EXECUTE_RETRIES_KEY = "avatica.statement.retries"; + public static final String NUM_EXECUTE_RETRIES_DEFAULT = "5"; + + /** The name of the sole column returned by an EXPLAIN statement. + * + * <p>Actually Avatica does not care what this column is called, but here is + * a useful place to define a suggested value. */ + public static final String PLAN_COLUMN_NAME = "PLAN"; + + protected int statementCount; + private boolean closed; + private int holdability; + private int networkTimeout; + + public final String id; + public final Meta.ConnectionHandle handle; + protected final UnregisteredDriver driver; + protected final AvaticaFactory factory; + final String url; + protected final Properties info; + protected final Meta meta; + protected final AvaticaDatabaseMetaData metaData; + public final Helper helper = Helper.INSTANCE; + public final Map<InternalProperty, Object> properties = new HashMap<>(); + public final Map<Integer, AvaticaStatement> statementMap = + new ConcurrentHashMap<>(); + protected final long maxRetriesPerExecute; + + /** + * Creates an AvaticaConnection. + * + * <p>Not public; method is called only from the driver or a derived + * class.</p> + * + * @param driver Driver + * @param factory Factory for JDBC objects + * @param url Server URL + * @param info Other connection properties + */ + protected AvaticaConnection(UnregisteredDriver driver, + AvaticaFactory factory, + String url, + Properties info) { + this.id = UUID.randomUUID().toString(); + this.handle = new Meta.ConnectionHandle(this.id); + this.driver = driver; + this.factory = factory; + this.url = url; + this.info = info; + this.meta = driver.createMeta(this); + this.metaData = factory.newDatabaseMetaData(this); + this.holdability = metaData.getResultSetHoldability(); + this.maxRetriesPerExecute = getNumStatementRetries(info); + } + + /** Computes the number of retries + * {@link AvaticaStatement#executeInternal(Meta.Signature, boolean)} + * should retry before failing. */ + long getNumStatementRetries(Properties props) { + return Long.valueOf(Objects.requireNonNull(props) + .getProperty(NUM_EXECUTE_RETRIES_KEY, NUM_EXECUTE_RETRIES_DEFAULT)); + } + + /** Returns a view onto this connection's configuration properties. Code + * in Avatica and derived projects should use this view rather than calling + * {@link java.util.Properties#getProperty(String)}. Derived projects will + * almost certainly subclass {@link ConnectionConfig} with their own + * properties. */ + public ConnectionConfig config() { + return new ConnectionConfigImpl(info); + } + + /** + * Opens the connection on the server. + */ + public void openConnection() { + // Open the connection on the server + this.meta.openConnection(handle, OpenConnectionRequest.serializeProperties(info)); + } + + // Connection methods + + public AvaticaStatement createStatement() throws SQLException { + //noinspection MagicConstant + return createStatement(ResultSet.TYPE_FORWARD_ONLY, + ResultSet.CONCUR_READ_ONLY, + holdability); + } + + public PreparedStatement prepareStatement(String sql) throws SQLException { + //noinspection MagicConstant + return prepareStatement( + sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, + holdability); + } + + public CallableStatement prepareCall(String sql) throws SQLException { + throw helper.unsupported(); + } + + public String nativeSQL(String sql) throws SQLException { + throw helper.unsupported(); + } + + public void setAutoCommit(boolean autoCommit) throws SQLException { + meta.connectionSync(handle, new ConnectionPropertiesImpl().setAutoCommit(autoCommit)); + } + + public boolean getAutoCommit() throws SQLException { + return unbox(sync().isAutoCommit(), true); + } + + public void commit() throws SQLException { + meta.commit(handle); + } + + public void rollback() throws SQLException { + meta.rollback(handle); + } + + public void close() throws SQLException { + if (!closed) { + closed = true; + + // Per specification, if onConnectionClose throws, this method will throw + // a SQLException, but statement will still be closed. + try { + meta.closeConnection(handle); + driver.handler.onConnectionClose(this); + } catch (RuntimeException e) { + throw helper.createException("While closing connection", e); + } + } + } + + public boolean isClosed() throws SQLException { + return closed; + } + + public DatabaseMetaData getMetaData() throws SQLException { + return metaData; + } + + public void setReadOnly(boolean readOnly) throws SQLException { + meta.connectionSync(handle, new ConnectionPropertiesImpl().setReadOnly(readOnly)); + } + + public boolean isReadOnly() throws SQLException { + return unbox(sync().isReadOnly(), true); + } + + public void setCatalog(String catalog) throws SQLException { + meta.connectionSync(handle, new ConnectionPropertiesImpl().setCatalog(catalog)); + } + + public String getCatalog() { + return sync().getCatalog(); + } + + public void setTransactionIsolation(int level) throws SQLException { + meta.connectionSync(handle, new ConnectionPropertiesImpl().setTransactionIsolation(level)); + } + + public int getTransactionIsolation() throws SQLException { + //noinspection MagicConstant + return unbox(sync().getTransactionIsolation(), TRANSACTION_NONE); + } + + public SQLWarning getWarnings() throws SQLException { + return null; + } + + public void clearWarnings() throws SQLException { + // no-op since connection pooling often calls this. + } + + public Statement createStatement( + int resultSetType, int resultSetConcurrency) throws SQLException { + //noinspection MagicConstant + return createStatement(resultSetType, resultSetConcurrency, holdability); + } + + public PreparedStatement prepareStatement( + String sql, + int resultSetType, + int resultSetConcurrency) throws SQLException { + //noinspection MagicConstant + return prepareStatement( + sql, resultSetType, resultSetConcurrency, holdability); + } + + public CallableStatement prepareCall( + String sql, + int resultSetType, + int resultSetConcurrency) throws SQLException { + throw helper.unsupported(); + } + + public Map<String, Class<?>> getTypeMap() throws SQLException { + throw helper.unsupported(); + } + + public void setTypeMap(Map<String, Class<?>> map) throws SQLException { + throw helper.unsupported(); + } + + public void setHoldability(int holdability) throws SQLException { + if (!(holdability == ResultSet.CLOSE_CURSORS_AT_COMMIT + || holdability == ResultSet.HOLD_CURSORS_OVER_COMMIT)) { + throw new SQLException("invalid value"); + } + this.holdability = holdability; + } + + public int getHoldability() throws SQLException { + return holdability; + } + + public Savepoint setSavepoint() throws SQLException { + throw helper.unsupported(); + } + + public Savepoint setSavepoint(String name) throws SQLException { + throw helper.unsupported(); + } + + public void rollback(Savepoint savepoint) throws SQLException { + throw helper.unsupported(); + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + throw helper.unsupported(); + } + + public AvaticaStatement createStatement( + int resultSetType, + int resultSetConcurrency, + int resultSetHoldability) throws SQLException { + return factory.newStatement(this, null, resultSetType, resultSetConcurrency, + resultSetHoldability); + } + + public PreparedStatement prepareStatement( + String sql, + int resultSetType, + int resultSetConcurrency, + int resultSetHoldability) throws SQLException { + try { + final Meta.StatementHandle h = meta.prepare(handle, sql, -1); + return factory.newPreparedStatement(this, h, h.signature, resultSetType, + resultSetConcurrency, resultSetHoldability); + } catch (RuntimeException e) { + throw helper.createException("while preparing SQL: " + sql, e); + } + } + + public CallableStatement prepareCall( + String sql, + int resultSetType, + int resultSetConcurrency, + int resultSetHoldability) throws SQLException { + throw helper.unsupported(); + } + + public PreparedStatement prepareStatement( + String sql, int autoGeneratedKeys) throws SQLException { + throw helper.unsupported(); + } + + public PreparedStatement prepareStatement( + String sql, int[] columnIndexes) throws SQLException { + throw helper.unsupported(); + } + + public PreparedStatement prepareStatement( + String sql, String[] columnNames) throws SQLException { + throw helper.unsupported(); + } + + public Clob createClob() throws SQLException { + throw helper.unsupported(); + } + + public Blob createBlob() throws SQLException { + throw helper.unsupported(); + } + + public NClob createNClob() throws SQLException { + throw helper.unsupported(); + } + + public SQLXML createSQLXML() throws SQLException { + throw helper.unsupported(); + } + + public boolean isValid(int timeout) throws SQLException { + throw helper.unsupported(); + } + + public void setClientInfo(String name, String value) + throws SQLClientInfoException { + throw helper.clientInfo(); + } + + public void setClientInfo(Properties properties) + throws SQLClientInfoException { + throw helper.clientInfo(); + } + + public String getClientInfo(String name) throws SQLException { + throw helper.unsupported(); + } + + public Properties getClientInfo() throws SQLException { + throw helper.unsupported(); + } + + public Array createArrayOf(String typeName, Object[] elements) + throws SQLException { + throw helper.unsupported(); + } + + public Struct createStruct(String typeName, Object[] attributes) + throws SQLException { + throw helper.unsupported(); + } + + public void setSchema(String schema) throws SQLException { + meta.connectionSync(handle, new ConnectionPropertiesImpl().setSchema(schema)); + } + + public String getSchema() { + return sync().getSchema(); + } + + public void abort(Executor executor) throws SQLException { + throw helper.unsupported(); + } + + public void setNetworkTimeout( + Executor executor, int milliseconds) throws SQLException { + this.networkTimeout = milliseconds; + } + + public int getNetworkTimeout() throws SQLException { + return networkTimeout; + } + + public <T> T unwrap(Class<T> iface) throws SQLException { + if (iface.isInstance(this)) { + return iface.cast(this); + } + throw helper.createException( + "does not implement '" + iface + "'"); + } + + public boolean isWrapperFor(Class<?> iface) throws SQLException { + return iface.isInstance(this); + } + + /** Returns the time zone of this connection. Determines the offset applied + * when converting datetime values from the database into + * {@link java.sql.Timestamp} values. */ + public TimeZone getTimeZone() { + final String timeZoneName = config().timeZone(); + return timeZoneName == null + ? TimeZone.getDefault() + : TimeZone.getTimeZone(timeZoneName); + } + + /** + * Executes a prepared query, closing any previously open result set. + * + * @param statement Statement + * @param signature Prepared query + * @param firstFrame First frame of rows, or null if we need to execute + * @param state The state used to create the given result + * @param isUpdate Was the caller context via {@link PreparedStatement#executeUpdate()}. + * @return Result set + * @throws java.sql.SQLException if a database error occurs + */ + protected ResultSet executeQueryInternal(AvaticaStatement statement, + Meta.Signature signature, Meta.Frame firstFrame, QueryState state, boolean isUpdate) + throws SQLException { + // Close the previous open result set, if there is one. + Meta.Frame frame = firstFrame; + Meta.Signature signature2 = signature; + + synchronized (statement) { + if (statement.openResultSet != null) { + final AvaticaResultSet rs = statement.openResultSet; + statement.openResultSet = null; + try { + rs.close(); + } catch (Exception e) { + throw helper.createException( + "Error while closing previous result set", e); + } + } + + try { + if (statement.isWrapperFor(AvaticaPreparedStatement.class)) { + final AvaticaPreparedStatement pstmt = (AvaticaPreparedStatement) statement; + Meta.StatementHandle handle = pstmt.handle; + if (isUpdate) { + // Make a copy of the StatementHandle, nulling out the Signature. + // CALCITE-1086 we don't need to send the Signature to the server + // when we're only performing an update. Saves on serialization. + handle = new Meta.StatementHandle(handle.connectionId, handle.id, null); + } + final Meta.ExecuteResult executeResult = + meta.execute(handle, pstmt.getParameterValues(), + statement.getFetchSize()); + final MetaResultSet metaResultSet = executeResult.resultSets.get(0); + frame = metaResultSet.firstFrame; + statement.updateCount = metaResultSet.updateCount; + signature2 = executeResult.resultSets.get(0).signature; + } + } catch (Exception e) { + e.printStackTrace(); + throw helper.createException(e.getMessage(), e); + } + + final TimeZone timeZone = getTimeZone(); + if (frame == null && signature2 == null && statement.updateCount != -1) { + statement.openResultSet = null; + } else { + // Duplicative SQL, for support non-prepared statements + statement.openResultSet = + factory.newResultSet(statement, state, signature2, timeZone, frame); + } + } + // Release the monitor before executing, to give another thread the + // opportunity to call cancel. + try { + if (statement.openResultSet != null) { + statement.openResultSet.execute(); + isUpdateCapable(statement); + } + } catch (Exception e) { + throw helper.createException( + "exception while executing query: " + e.getMessage(), e); + } + return statement.openResultSet; + } + + /** Returns whether a a statement is capable of updates and if so, + * and the statement's {@code updateCount} is still -1, proceeds to + * get updateCount value from statement's resultSet. + * + * <p>Handles "ROWCOUNT" object as Number or List + * + * @param statement Statement + * @throws SQLException on error + */ + private void isUpdateCapable(final AvaticaStatement statement) + throws SQLException { + Meta.Signature signature = statement.getSignature(); + if (signature == null || signature.statementType == null) { + return; + } + if (signature.statementType.canUpdate() && statement.updateCount == -1) { + statement.openResultSet.next(); + Object obj = statement.openResultSet.getObject(ROWCOUNT_COLUMN_NAME); + if (obj instanceof Number) { + statement.updateCount = ((Number) obj).intValue(); + } else if (obj instanceof List) { + @SuppressWarnings("unchecked") + final List<Number> numbers = (List<Number>) obj; + statement.updateCount = numbers.get(0).intValue(); + } else { + throw helper.createException("Not a valid return result."); + } + statement.openResultSet = null; + } + } + + protected Meta.ExecuteResult prepareAndExecuteInternal( + final AvaticaStatement statement, final String sql, long maxRowCount) + throws SQLException, NoSuchStatementException { + final Meta.PrepareCallback callback = + new Meta.PrepareCallback() { + public Object getMonitor() { + return statement; + } + + public void clear() throws SQLException { + if (statement.openResultSet != null) { + final AvaticaResultSet rs = statement.openResultSet; + statement.openResultSet = null; + try { + rs.close(); + } catch (Exception e) { + throw helper.createException( + "Error while closing previous result set", e); + } + } + } + + public void assign(Meta.Signature signature, Meta.Frame firstFrame, + long updateCount) throws SQLException { + statement.setSignature(signature); + + if (updateCount != -1) { + statement.updateCount = updateCount; + } else { + final TimeZone timeZone = getTimeZone(); + statement.openResultSet = factory.newResultSet(statement, new QueryState(sql), + signature, timeZone, firstFrame); + } + } + + public void execute() throws SQLException { + if (statement.openResultSet != null) { + statement.openResultSet.execute(); + isUpdateCapable(statement); + } + } + }; + return meta.prepareAndExecute(statement.handle, sql, maxRowCount, callback); + } + + protected ResultSet createResultSet(Meta.MetaResultSet metaResultSet, QueryState state) + throws SQLException { + final Meta.StatementHandle h = new Meta.StatementHandle( + metaResultSet.connectionId, metaResultSet.statementId, null); + final AvaticaStatement statement = lookupStatement(h); + // These are all the metadata operations, no updates + ResultSet resultSet = executeQueryInternal(statement, metaResultSet.signature.sanitize(), + metaResultSet.firstFrame, state, false); + if (metaResultSet.ownStatement) { + resultSet.getStatement().closeOnCompletion(); + } + return resultSet; + } + + /** Creates a statement wrapper around an existing handle. */ + protected AvaticaStatement lookupStatement(Meta.StatementHandle h) + throws SQLException { + final AvaticaStatement statement = statementMap.get(h.id); + if (statement != null) { + return statement; + } + //noinspection MagicConstant + return factory.newStatement(this, Objects.requireNonNull(h), + ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, holdability); + } + + // do not make public + protected static Trojan createTrojan() { + return new Trojan(); + } + + /** Converts a {@link Boolean} to a {@code boolean}, with a default value. */ + private boolean unbox(Boolean b, boolean defaultValue) { + return b == null ? defaultValue : b; + } + + /** Converts an {@link Integer} to an {@code int}, with a default value. */ + private int unbox(Integer i, int defaultValue) { + return i == null ? defaultValue : i; + } + + private Meta.ConnectionProperties sync() { + return meta.connectionSync(handle, new ConnectionPropertiesImpl()); + } + + /** A way to call package-protected methods. But only a sub-class of + * connection can create one. */ + public static class Trojan { + // must be private + private Trojan() { + } + + /** A means for anyone who has a trojan to call the protected method + * {@link org.apache.calcite.avatica.AvaticaResultSet#execute()}. + * @throws SQLException if execute fails for some reason. */ + public ResultSet execute(AvaticaResultSet resultSet) throws SQLException { + return resultSet.execute(); + } + + /** A means for anyone who has a trojan to call the protected method + * {@link org.apache.calcite.avatica.AvaticaStatement#getParameterValues()}. + */ + public List<TypedValue> getParameterValues(AvaticaStatement statement) { + return statement.getParameterValues(); + } + + /** A means for anyone who has a trojan to get the protected field + * {@link org.apache.calcite.avatica.AvaticaConnection#meta}. */ + public Meta getMeta(AvaticaConnection connection) { + return connection.meta; + } + } + + /** + * A Callable-like interface but without a "throws Exception". + * + * @param <T> The return type from {@code call}. + */ + public interface CallableWithoutException<T> { + T call(); + } + + /** + * Invokes the given "callable", retrying the call when the server responds with an error + * denoting that the connection is missing on the server. + * + * @param callable The function to invoke. + * @return The value from the result of the callable. + */ + public <T> T invokeWithRetries(CallableWithoutException<T> callable) { + RuntimeException lastException = null; + for (int i = 0; i < maxRetriesPerExecute; i++) { + try { + return callable.call(); + } catch (AvaticaClientRuntimeException e) { + lastException = e; + if (ErrorResponse.MISSING_CONNECTION_ERROR_CODE == e.getErrorCode()) { + this.openConnection(); + continue; + } + throw e; + } + } + if (null != lastException) { + throw lastException; + } else { + // Shouldn't ever happen. + throw new IllegalStateException(); + } + } +} + +// End AvaticaConnection.java
