You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by el...@apache.org on 2016/03/07 19:28:24 UTC
[46/59] [partial] calcite git commit: [CALCITE-1078] Detach avatica
from the core calcite Maven project
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)
-@Suite.SuiteClasses({
- 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