diff --git a/codestyle/spotbugs-exclude.xml b/codestyle/spotbugs-exclude.xml
index 2092f31db3a4..cb6cb9c34fee 100644
--- a/codestyle/spotbugs-exclude.xml
+++ b/codestyle/spotbugs-exclude.xml
@@ -38,6 +38,12 @@
+
+
+
+
+
+
diff --git a/docs/querying/sql.md b/docs/querying/sql.md
index 38625cb190a8..c5ba6ac24614 100644
--- a/docs/querying/sql.md
+++ b/docs/querying/sql.md
@@ -954,6 +954,14 @@ try (Connection connection = DriverManager.getConnection(url, connectionProperti
}
```
+It is also possible to use a protocol buffers JDBC connection with Druid, this offer reduced bloat and potential performance
+improvements for larger result sets. To use it apply the following connection url instead, everything else remains the same
+```
+String url = "jdbc:avatica:remote:url=http://localhost:8082/druid/v2/sql/avatica-protobuf/;serialization=protobuf";
+```
+
+> The protobuf endpoint is also known to work with the official [Golang Avatica driver](https://github.com/apache/calcite-avatica-go)
+
Table metadata is available over JDBC using `connection.getMetaData()` or by querying the
["INFORMATION_SCHEMA" tables](#metadata-tables).
diff --git a/integration-tests/src/test/java/org/apache/druid/tests/security/AbstractAuthConfigurationTest.java b/integration-tests/src/test/java/org/apache/druid/tests/security/AbstractAuthConfigurationTest.java
index 65e8005989a4..ddbb2ef84443 100644
--- a/integration-tests/src/test/java/org/apache/druid/tests/security/AbstractAuthConfigurationTest.java
+++ b/integration-tests/src/test/java/org/apache/druid/tests/security/AbstractAuthConfigurationTest.java
@@ -34,7 +34,7 @@
import org.apache.druid.java.util.http.client.HttpClient;
import org.apache.druid.java.util.http.client.auth.BasicCredentials;
import org.apache.druid.java.util.http.client.response.StatusResponseHolder;
-import org.apache.druid.sql.avatica.DruidAvaticaHandler;
+import org.apache.druid.sql.avatica.DruidAvaticaJsonHandler;
import org.apache.druid.testing.IntegrationTestingConfig;
import org.apache.druid.testing.clients.CoordinatorResourceTestClient;
import org.apache.druid.testing.utils.HttpUtil;
@@ -285,12 +285,12 @@ void verifySystemSchemaQueryFailure(
String getBrokerAvacticaUrl()
{
- return "jdbc:avatica:remote:url=" + config.getBrokerUrl() + DruidAvaticaHandler.AVATICA_PATH;
+ return "jdbc:avatica:remote:url=" + config.getBrokerUrl() + DruidAvaticaJsonHandler.AVATICA_PATH;
}
String getRouterAvacticaUrl()
{
- return "jdbc:avatica:remote:url=" + config.getRouterUrl() + DruidAvaticaHandler.AVATICA_PATH;
+ return "jdbc:avatica:remote:url=" + config.getRouterUrl() + DruidAvaticaJsonHandler.AVATICA_PATH;
}
void verifyAdminOptionsRequest()
diff --git a/server/pom.xml b/server/pom.xml
index 5e7ac5eb0a4b..2c5ad5b16161 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -319,6 +319,10 @@
com.fasterxml.jackson.module
jackson-module-guice
+
+ org.apache.calcite.avatica
+ avatica-core
+
@@ -450,11 +454,6 @@
1.3
test
-
- org.apache.calcite.avatica
- avatica-core
- test
-
diff --git a/server/src/main/java/org/apache/druid/server/AsyncQueryForwardingServlet.java b/server/src/main/java/org/apache/druid/server/AsyncQueryForwardingServlet.java
index 24e29e4fb557..253fe1da4a30 100644
--- a/server/src/main/java/org/apache/druid/server/AsyncQueryForwardingServlet.java
+++ b/server/src/main/java/org/apache/druid/server/AsyncQueryForwardingServlet.java
@@ -26,6 +26,10 @@
import com.google.common.collect.ImmutableMap;
import com.google.inject.Inject;
import com.google.inject.Provider;
+import org.apache.calcite.avatica.remote.ProtobufTranslation;
+import org.apache.calcite.avatica.remote.ProtobufTranslationImpl;
+import org.apache.calcite.avatica.remote.Service;
+import org.apache.commons.io.IOUtils;
import org.apache.druid.client.selector.Server;
import org.apache.druid.guice.annotations.Json;
import org.apache.druid.guice.annotations.Smile;
@@ -118,6 +122,7 @@ private static void handleException(HttpServletResponse response, ObjectMapper o
private final RequestLogger requestLogger;
private final GenericQueryMetricsFactory queryMetricsFactory;
private final AuthenticatorMapper authenticatorMapper;
+ private final ProtobufTranslation protobufTranslation;
private HttpClient broadcastClient;
@@ -145,6 +150,7 @@ public AsyncQueryForwardingServlet(
this.requestLogger = requestLogger;
this.queryMetricsFactory = queryMetricsFactory;
this.authenticatorMapper = authenticatorMapper;
+ this.protobufTranslation = new ProtobufTranslationImpl();
}
@Override
@@ -191,9 +197,16 @@ protected void service(HttpServletRequest request, HttpServletResponse response)
// them as a generic request.
final boolean isQueryEndpoint = requestURI.startsWith("/druid/v2") && !requestURI.startsWith("/druid/v2/sql");
- final boolean isAvatica = requestURI.startsWith("/druid/v2/sql/avatica");
+ final boolean isAvaticaJson = requestURI.startsWith("/druid/v2/sql/avatica");
+ final boolean isAvaticaPb = requestURI.startsWith("/druid/v2/sql/avatica-protobuf");
- if (isAvatica) {
+ if (isAvaticaPb) {
+ byte[] requestBytes = IOUtils.toByteArray(request.getInputStream());
+ Service.Request protobufRequest = this.protobufTranslation.parseRequest(requestBytes);
+ String connectionId = getAvaticaProtobufConnectionId(protobufRequest);
+ targetServer = hostFinder.findServerAvatica(connectionId);
+ request.setAttribute(AVATICA_QUERY_ATTRIBUTE, requestBytes);
+ } else if (isAvaticaJson) {
Map requestMap = objectMapper.readValue(
request.getInputStream(),
JacksonUtils.TYPE_REFERENCE_MAP_STRING_OBJECT
@@ -456,6 +469,95 @@ static String getAvaticaConnectionId(Map requestMap)
return (String) connectionIdObj;
}
+ static String getAvaticaProtobufConnectionId(Service.Request request)
+ {
+ if (request instanceof Service.CatalogsRequest) {
+ return ((Service.CatalogsRequest) request).connectionId;
+ }
+
+ if (request instanceof Service.SchemasRequest) {
+ return ((Service.SchemasRequest) request).connectionId;
+ }
+
+ if (request instanceof Service.TablesRequest) {
+ return ((Service.TablesRequest) request).connectionId;
+ }
+
+ if (request instanceof Service.TypeInfoRequest) {
+ return ((Service.TypeInfoRequest) request).connectionId;
+ }
+
+ if (request instanceof Service.ColumnsRequest) {
+ return ((Service.ColumnsRequest) request).connectionId;
+ }
+
+ if (request instanceof Service.ExecuteRequest) {
+ return ((Service.ExecuteRequest) request).statementHandle.connectionId;
+ }
+
+ if (request instanceof Service.TableTypesRequest) {
+ return ((Service.TableTypesRequest) request).connectionId;
+ }
+
+ if (request instanceof Service.PrepareRequest) {
+ return ((Service.PrepareRequest) request).connectionId;
+ }
+
+ if (request instanceof Service.PrepareAndExecuteRequest) {
+ return ((Service.PrepareAndExecuteRequest) request).connectionId;
+ }
+
+ if (request instanceof Service.FetchRequest) {
+ return ((Service.FetchRequest) request).connectionId;
+ }
+
+ if (request instanceof Service.CreateStatementRequest) {
+ return ((Service.CreateStatementRequest) request).connectionId;
+ }
+
+ if (request instanceof Service.CloseStatementRequest) {
+ return ((Service.CloseStatementRequest) request).connectionId;
+ }
+
+ if (request instanceof Service.OpenConnectionRequest) {
+ return ((Service.OpenConnectionRequest) request).connectionId;
+ }
+
+ if (request instanceof Service.CloseConnectionRequest) {
+ return ((Service.CloseConnectionRequest) request).connectionId;
+ }
+
+ if (request instanceof Service.ConnectionSyncRequest) {
+ return ((Service.ConnectionSyncRequest) request).connectionId;
+ }
+
+ if (request instanceof Service.DatabasePropertyRequest) {
+ return ((Service.DatabasePropertyRequest) request).connectionId;
+ }
+
+ if (request instanceof Service.SyncResultsRequest) {
+ return ((Service.SyncResultsRequest) request).connectionId;
+ }
+
+ if (request instanceof Service.CommitRequest) {
+ return ((Service.CommitRequest) request).connectionId;
+ }
+
+ if (request instanceof Service.RollbackRequest) {
+ return ((Service.RollbackRequest) request).connectionId;
+ }
+
+ if (request instanceof Service.PrepareAndExecuteBatchRequest) {
+ return ((Service.PrepareAndExecuteBatchRequest) request).connectionId;
+ }
+
+ if (request instanceof Service.ExecuteBatchRequest) {
+ return ((Service.ExecuteBatchRequest) request).connectionId;
+ }
+
+ throw new IAE("Received an unknown Avatica protobuf request");
+ }
+
private class MetricsEmittingProxyResponseListener extends ProxyResponseListener
{
private final HttpServletRequest req;
diff --git a/server/src/test/java/org/apache/druid/server/AsyncQueryForwardingServletTest.java b/server/src/test/java/org/apache/druid/server/AsyncQueryForwardingServletTest.java
index 066088c0eac4..b7767be043b7 100644
--- a/server/src/test/java/org/apache/druid/server/AsyncQueryForwardingServletTest.java
+++ b/server/src/test/java/org/apache/druid/server/AsyncQueryForwardingServletTest.java
@@ -468,6 +468,45 @@ public void testGetAvaticaConnectionId() throws JsonProcessingException
}
}
+ @Test
+ public void testGetAvaticaProtobufConnectionId()
+ {
+ final String query = "SELECT someColumn FROM druid.someTable WHERE someColumn IS NOT NULL";
+ final String connectionId = "000000-0000-0000-00000000";
+ final int statementId = 1337;
+ final int maxNumRows = 1000;
+
+ final List extends Service.Request> avaticaRequests = ImmutableList.of(
+ new Service.CatalogsRequest(connectionId),
+ new Service.SchemasRequest(connectionId, "druid", null),
+ new Service.TablesRequest(connectionId, "druid", "druid", null, null),
+ new Service.ColumnsRequest(connectionId, "druid", "druid", "someTable", null),
+ new Service.PrepareAndExecuteRequest(
+ connectionId,
+ statementId,
+ query,
+ maxNumRows
+ ),
+ new Service.PrepareRequest(connectionId, query, maxNumRows),
+ new Service.ExecuteRequest(
+ new Meta.StatementHandle(connectionId, statementId, null),
+ ImmutableList.of(),
+ maxNumRows
+ ),
+ new Service.CloseStatementRequest(connectionId, statementId),
+ new Service.CloseConnectionRequest(connectionId)
+ );
+
+
+ for (Service.Request request : avaticaRequests) {
+ Assert.assertEquals(
+ "failed",
+ connectionId,
+ AsyncQueryForwardingServlet.getAvaticaProtobufConnectionId(request)
+ );
+ }
+ }
+
private static Map asMap(String json, ObjectMapper mapper) throws JsonProcessingException
{
return mapper.readValue(json, JacksonUtils.TYPE_REFERENCE_MAP_STRING_OBJECT);
diff --git a/services/src/main/java/org/apache/druid/cli/RouterJettyServerInitializer.java b/services/src/main/java/org/apache/druid/cli/RouterJettyServerInitializer.java
index 40f3f0c08853..1850de588a51 100644
--- a/services/src/main/java/org/apache/druid/cli/RouterJettyServerInitializer.java
+++ b/services/src/main/java/org/apache/druid/cli/RouterJettyServerInitializer.java
@@ -39,7 +39,8 @@
import org.apache.druid.server.security.AuthenticationUtils;
import org.apache.druid.server.security.Authenticator;
import org.apache.druid.server.security.AuthenticatorMapper;
-import org.apache.druid.sql.avatica.DruidAvaticaHandler;
+import org.apache.druid.sql.avatica.DruidAvaticaJsonHandler;
+import org.apache.druid.sql.avatica.DruidAvaticaProtobufHandler;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.HandlerList;
@@ -57,7 +58,8 @@ public class RouterJettyServerInitializer implements JettyServerInitializer
// JDBC authentication uses the JDBC connection context instead of HTTP headers, skip the normal auth checks.
// The router will keep the connection context in the forwarded message, and the broker is responsible for
// performing the auth checks.
- DruidAvaticaHandler.AVATICA_PATH
+ DruidAvaticaJsonHandler.AVATICA_PATH,
+ DruidAvaticaProtobufHandler.AVATICA_PATH
);
private final DruidHttpClientConfig routerHttpClientConfig;
diff --git a/sql/src/main/java/org/apache/druid/sql/avatica/AvaticaModule.java b/sql/src/main/java/org/apache/druid/sql/avatica/AvaticaModule.java
index 8e795cebf352..0f052326e571 100644
--- a/sql/src/main/java/org/apache/druid/sql/avatica/AvaticaModule.java
+++ b/sql/src/main/java/org/apache/druid/sql/avatica/AvaticaModule.java
@@ -36,7 +36,8 @@ public void configure(Binder binder)
{
JsonConfigProvider.bind(binder, "druid.sql.avatica", AvaticaServerConfig.class);
binder.bind(AvaticaMonitor.class).in(LazySingleton.class);
- JettyBindings.addHandler(binder, DruidAvaticaHandler.class);
+ JettyBindings.addHandler(binder, DruidAvaticaJsonHandler.class);
+ JettyBindings.addHandler(binder, DruidAvaticaProtobufHandler.class);
MetricsModule.register(binder, AvaticaMonitor.class);
}
}
diff --git a/sql/src/main/java/org/apache/druid/sql/avatica/DruidAvaticaHandler.java b/sql/src/main/java/org/apache/druid/sql/avatica/DruidAvaticaJsonHandler.java
similarity index 95%
rename from sql/src/main/java/org/apache/druid/sql/avatica/DruidAvaticaHandler.java
rename to sql/src/main/java/org/apache/druid/sql/avatica/DruidAvaticaJsonHandler.java
index 1a7877fcaadd..ffb1107bacfb 100644
--- a/sql/src/main/java/org/apache/druid/sql/avatica/DruidAvaticaHandler.java
+++ b/sql/src/main/java/org/apache/druid/sql/avatica/DruidAvaticaJsonHandler.java
@@ -32,12 +32,12 @@
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
-public class DruidAvaticaHandler extends AvaticaJsonHandler
+public class DruidAvaticaJsonHandler extends AvaticaJsonHandler
{
public static final String AVATICA_PATH = "/druid/v2/sql/avatica/";
@Inject
- public DruidAvaticaHandler(
+ public DruidAvaticaJsonHandler(
final DruidMeta druidMeta,
@Self final DruidNode druidNode,
final AvaticaMonitor avaticaMonitor
diff --git a/sql/src/main/java/org/apache/druid/sql/avatica/DruidAvaticaProtobufHandler.java b/sql/src/main/java/org/apache/druid/sql/avatica/DruidAvaticaProtobufHandler.java
new file mode 100644
index 000000000000..8bc9f33d9f9f
--- /dev/null
+++ b/sql/src/main/java/org/apache/druid/sql/avatica/DruidAvaticaProtobufHandler.java
@@ -0,0 +1,62 @@
+/*
+ * 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.druid.sql.avatica;
+
+import com.google.inject.Inject;
+import org.apache.calcite.avatica.remote.LocalService;
+import org.apache.calcite.avatica.remote.Service;
+import org.apache.calcite.avatica.server.AvaticaProtobufHandler;
+import org.apache.druid.guice.annotations.Self;
+import org.apache.druid.server.DruidNode;
+import org.eclipse.jetty.server.Request;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+public class DruidAvaticaProtobufHandler extends AvaticaProtobufHandler
+{
+ public static final String AVATICA_PATH = "/druid/v2/sql/avatica-protobuf/";
+
+ @Inject
+ public DruidAvaticaProtobufHandler(
+ final DruidMeta druidMeta,
+ @Self final DruidNode druidNode,
+ final AvaticaMonitor avaticaMonitor
+ )
+ {
+ super(new LocalService(druidMeta), avaticaMonitor);
+ setServerRpcMetadata(new Service.RpcMetadataResponse(druidNode.getHostAndPortToUse()));
+ }
+
+ @Override
+ public void handle(
+ final String target,
+ final Request baseRequest,
+ final HttpServletRequest request,
+ final HttpServletResponse response
+ ) throws IOException, ServletException
+ {
+ if (request.getRequestURI().equals(AVATICA_PATH)) {
+ super.handle(target, baseRequest, request, response);
+ }
+ }
+}
diff --git a/sql/src/main/java/org/apache/druid/sql/avatica/DruidMeta.java b/sql/src/main/java/org/apache/druid/sql/avatica/DruidMeta.java
index 5cfea96cfbd7..145790f6f1bd 100644
--- a/sql/src/main/java/org/apache/druid/sql/avatica/DruidMeta.java
+++ b/sql/src/main/java/org/apache/druid/sql/avatica/DruidMeta.java
@@ -104,8 +104,10 @@ public void openConnection(final ConnectionHandle ch, final Map
{
// Build connection context.
final ImmutableMap.Builder context = ImmutableMap.builder();
- for (Map.Entry entry : info.entrySet()) {
- context.put(entry);
+ if (info != null) {
+ for (Map.Entry entry : info.entrySet()) {
+ context.put(entry);
+ }
}
openDruidConnection(ch.id, context.build());
}
diff --git a/sql/src/test/java/org/apache/druid/sql/avatica/AvaticaModuleTest.java b/sql/src/test/java/org/apache/druid/sql/avatica/AvaticaModuleTest.java
index adf084d7c503..69153c8a740b 100644
--- a/sql/src/test/java/org/apache/druid/sql/avatica/AvaticaModuleTest.java
+++ b/sql/src/test/java/org/apache/druid/sql/avatica/AvaticaModuleTest.java
@@ -176,19 +176,36 @@ public void testAvaticaServerConfigPropertiesBadMinRowsPerFrame()
}
@Test
- public void testDruidAvaticaHandlerIsInjected()
+ public void testDruidAvaticaJsonHandlerIsInjected()
{
- DruidAvaticaHandler handler = injector.getInstance(DruidAvaticaHandler.class);
+ DruidAvaticaJsonHandler handler = injector.getInstance(DruidAvaticaJsonHandler.class);
Assert.assertNotNull(handler);
- DruidAvaticaHandler other = injector.getInstance(DruidAvaticaHandler.class);
+ DruidAvaticaJsonHandler other = injector.getInstance(DruidAvaticaJsonHandler.class);
Assert.assertNotSame(handler, other);
}
@Test
- public void testDruidAvaticaHandlerIsRegisterdWithJerseyModule()
+ public void testDruidAvaticaProtobufHandlerIsInjected()
+ {
+ DruidAvaticaProtobufHandler handler = injector.getInstance(DruidAvaticaProtobufHandler.class);
+ Assert.assertNotNull(handler);
+ DruidAvaticaProtobufHandler other = injector.getInstance(DruidAvaticaProtobufHandler.class);
+ Assert.assertNotSame(handler, other);
+ }
+
+ @Test
+ public void testDruidAvaticaJsonHandlerIsRegisterdWithJerseyModule()
{
Set handlers =
injector.getInstance(Key.get(new TypeLiteral>(){}));
- Assert.assertTrue(handlers.stream().anyMatch(h -> DruidAvaticaHandler.class.equals(h.getClass())));
+ Assert.assertTrue(handlers.stream().anyMatch(h -> DruidAvaticaJsonHandler.class.equals(h.getClass())));
+ }
+
+ @Test
+ public void testDruidAvaticaProtobufHandlerIsRegisterdWithJerseyModule()
+ {
+ Set handlers =
+ injector.getInstance(Key.get(new TypeLiteral>(){}));
+ Assert.assertTrue(handlers.stream().anyMatch(h -> DruidAvaticaProtobufHandler.class.equals(h.getClass())));
}
}
diff --git a/sql/src/test/java/org/apache/druid/sql/avatica/DruidAvaticaHandlerTest.java b/sql/src/test/java/org/apache/druid/sql/avatica/DruidAvaticaHandlerTest.java
index 3587aa25d319..b39c35173adc 100644
--- a/sql/src/test/java/org/apache/druid/sql/avatica/DruidAvaticaHandlerTest.java
+++ b/sql/src/test/java/org/apache/druid/sql/avatica/DruidAvaticaHandlerTest.java
@@ -35,6 +35,7 @@
import org.apache.calcite.avatica.Meta;
import org.apache.calcite.avatica.MissingResultsException;
import org.apache.calcite.avatica.NoSuchStatementException;
+import org.apache.calcite.avatica.server.AbstractAvaticaHandler;
import org.apache.calcite.schema.SchemaPlus;
import org.apache.druid.common.config.NullHandling;
import org.apache.druid.guice.GuiceInjectors;
@@ -46,7 +47,6 @@
import org.apache.druid.java.util.emitter.service.ServiceEmitter;
import org.apache.druid.math.expr.ExprMacroTable;
import org.apache.druid.query.QueryRunnerFactoryConglomerate;
-import org.apache.druid.server.DruidNode;
import org.apache.druid.server.QueryLifecycleFactory;
import org.apache.druid.server.QueryStackTests;
import org.apache.druid.server.RequestLogLine;
@@ -101,7 +101,7 @@
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadLocalRandom;
-public class DruidAvaticaHandlerTest extends CalciteTestBase
+public abstract class DruidAvaticaHandlerTest extends CalciteTestBase
{
private static final AvaticaServerConfig AVATICA_CONFIG = new AvaticaServerConfig()
{
@@ -200,20 +200,12 @@ public void configure(Binder binder)
);
druidMeta = injector.getInstance(DruidMeta.class);
- final DruidAvaticaHandler handler = new DruidAvaticaHandler(
- druidMeta,
- new DruidNode("dummy", "dummy", false, 1, null, true, false),
- new AvaticaMonitor()
- );
+ final AbstractAvaticaHandler handler = this.getAvaticaHandler(druidMeta);
final int port = ThreadLocalRandom.current().nextInt(9999) + 10000;
server = new Server(new InetSocketAddress("127.0.0.1", port));
server.setHandler(handler);
server.start();
- url = StringUtils.format(
- "jdbc:avatica:remote:url=http://127.0.0.1:%d%s",
- port,
- DruidAvaticaHandler.AVATICA_PATH
- );
+ url = this.getJdbcConnectionString(port);
client = DriverManager.getConnection(url, "regularUser", "druid");
superuserClient = DriverManager.getConnection(url, CalciteTests.TEST_SUPERUSER_NAME, "druid");
@@ -886,20 +878,12 @@ public Frame fetch(
}
};
- final DruidAvaticaHandler handler = new DruidAvaticaHandler(
- smallFrameDruidMeta,
- new DruidNode("dummy", "dummy", false, 1, null, true, false),
- new AvaticaMonitor()
- );
+ final AbstractAvaticaHandler handler = this.getAvaticaHandler(smallFrameDruidMeta);
final int port = ThreadLocalRandom.current().nextInt(9999) + 20000;
Server smallFrameServer = new Server(new InetSocketAddress("127.0.0.1", port));
smallFrameServer.setHandler(handler);
smallFrameServer.start();
- String smallFrameUrl = StringUtils.format(
- "jdbc:avatica:remote:url=http://127.0.0.1:%d%s",
- port,
- DruidAvaticaHandler.AVATICA_PATH
- );
+ String smallFrameUrl = this.getJdbcConnectionString(port);
Connection smallFrameClient = DriverManager.getConnection(smallFrameUrl, "regularUser", "druid");
final ResultSet resultSet = smallFrameClient.createStatement().executeQuery(
@@ -984,20 +968,12 @@ public Frame fetch(
}
};
- final DruidAvaticaHandler handler = new DruidAvaticaHandler(
- smallFrameDruidMeta,
- new DruidNode("dummy", "dummy", false, 1, null, true, false),
- new AvaticaMonitor()
- );
+ final AbstractAvaticaHandler handler = this.getAvaticaHandler(smallFrameDruidMeta);
final int port = ThreadLocalRandom.current().nextInt(9999) + 20000;
Server smallFrameServer = new Server(new InetSocketAddress("127.0.0.1", port));
smallFrameServer.setHandler(handler);
smallFrameServer.start();
- String smallFrameUrl = StringUtils.format(
- "jdbc:avatica:remote:url=http://127.0.0.1:%d%s",
- port,
- DruidAvaticaHandler.AVATICA_PATH
- );
+ String smallFrameUrl = this.getJdbcConnectionString(port);
Connection smallFrameClient = DriverManager.getConnection(smallFrameUrl, "regularUser", "druid");
// use a prepared statement because avatica currently ignores fetchSize on the initial fetch of a Statement
@@ -1328,6 +1304,10 @@ public void testEscapingForGetTables() throws Exception
);
}
+ protected abstract String getJdbcConnectionString(int port);
+
+ protected abstract AbstractAvaticaHandler getAvaticaHandler(DruidMeta druidMeta);
+
private static List