Hello team,
I have recently started writing an implementation of Avatica server.
I am trying to use a commercial ODBC connector for Windows to integrate
tools like Excel and Tableau via avatica server.

Here is the driver:

https://www.cloudera.com/downloads/connectors/phoenix/odbc/1-0-8-1011.html

The driver seems to be dated from June 23, 2016 (before the Hortonworks
acquisition):

https://hortonworks.com/wp-content/uploads/2016/08/phoenix-ODBC-guide.pdf

I have installed the driver for Windows and launched the Windows ODBC
configuration tool:
%windir%\system32\odbcad32.exe
And set a configuration as follows:

----------
- Configuration
----------
host: localhost
port: 8080
path: test
Mechanism: no authentication
----------

On the avatica side, I have implemented some sample code to place avatica
in front of H2 with northwind database:

Older style implementation (18 Mar 2016, Release 1.7.1)

```gradle
dependencies {
    implementation 'org.apache.calcite.avatica:avatica-core:1.7.1'
    implementation 'org.apache.calcite.avatica:avatica-server:1.7.1'
}
```

```java
Server h2server = Server.createTcpServer("-tcp", "-tcpAllowOthers",
"-tcpPort", "9092").start();
Server h2serverWeb = Server.createWebServer("-webAllowOthers", "-webPort",
"8082").start();
Connection h2connection =
DriverManager.getConnection("jdbc:h2:./test;MODE=PostgreSQL;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;INIT=RUNSCRIPT
FROM 'src/test/resources/northwind.sql'", "sa", "");
ConfigurableJdbcMeta meta = new
ConfigurableJdbcMeta("jdbc:h2:tcp://localhost:9092/./test", "sa", "");
LocalService service = new LocalService(meta);
HughProtobufHandler pHandler = new HughProtobufHandler(service);
HughJsonHandler jHandler = new HughJsonHandler(service);
server.start();
server.join();
```

And newer style implementation (05 Apr 2024, Release 1.25.0)

```gradle
dependencies {
    implementation 'org.apache.calcite.avatica:avatica-core:1.25.0'
    implementation 'org.apache.calcite.avatica:avatica-core:1.25.0'
}
```

```java
        Server h2server = Server.createTcpServer("-tcp", "-tcpAllowOthers",
"-tcpPort", "9092").start();
        Server h2serverWeb = Server.createWebServer("-webAllowOthers",
"-webPort", "8082").start();
        Connection h2connection =
DriverManager.getConnection("jdbc:h2:./test;MODE=PostgreSQL;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;INIT=RUNSCRIPT
FROM 'src/test/resources/northwind.sql'", "sa", "");
        ConfigurableJdbcMeta meta = new
ConfigurableJdbcMeta("jdbc:h2:tcp://localhost:9092/./test", "sa", "");
        LocalService service = new LocalService(meta);
        HughJsonHandler handler = new HughJsonHandler(service);
        HttpServer.Builder<Server> builder = new
HttpServer.Builder<Server>()
                .withHandler(handler)
                .withPort(8080);
        HttpServer avaticaserver = builder.build();
        avaticaserver.start();
        avaticaserver.join();
```

Both of these return "500 internal server error".

Here is the trace in Wireshark of Phoenix ODBC Connector 1.0.8.1011 for CDP
to Avatica (18 Mar 2016, Release 1.7.1).

==========
= START Wireshark trace
==========
POST /test/ HTTP/1.1
Host: localhost:8080
Content-Type: application/octet-stream
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
User-Agent: Phoenix ODBC
Connection: keep-alive
Content-Length: 105
?org.apache.calcite.avatica.proto.Requests$OpenConnectionRequest&
$ae2df14d-913f-1870-03ef-a2d458f6f7cd

`
HTTP/1.1 500 Server Error
Date: Mon, 19 Aug 2024 13:43:56 GMT
Content-Type: application/json;charset=utf-8
Content-Length: 2773
Server: Jetty(9.2.15.v20160210)
{"response":"error","exceptions":["com.fasterxml.jackson.core.JsonParseException:
Unexpected character ('?' (code 63)): expected a valid value (number,
String, array, object, 'true', 'false' or 'null')\n at [Source:
\n?org.apache.calcite.avatica.proto.Requests$OpenConnectionRequest\u0012&\n$ae2df14d-913f-1870-03ef-a2d458f6f7cd;
line: 2, column: 2]\r\n\tat
com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:1581)\r\n\tat
com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:533)\r\n\tat
com.fasterxml.jackson.core.base.ParserMinimalBase._reportUnexpectedChar(ParserMinimalBase.java:462)\r\n\tat
com.fasterxml.jackson.core.json.ReaderBasedJsonParser._handleOddValue(ReaderBasedJsonParser.java:1624)\r\n\tat
com.fasterxml.jackson.core.json.ReaderBasedJsonParser.nextToken(ReaderBasedJsonParser.java:689)\r\n\tat
com.fasterxml.jackson.databind.ObjectMapper._initForReading(ObjectMapper.java:3776)\r\n\tat
com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3721)\r\n\tat
com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2726)\r\n\tat
org.apache.calcite.avatica.remote.JsonHandler.decode(JsonHandler.java:57)\r\n\tat
org.apache.calcite.avatica.remote.JsonHandler.decode(JsonHandler.java:37)\r\n\tat
org.apache.calcite.avatica.remote.AbstractHandler.apply(AbstractHandler.java:93)\r\n\tat
org.apache.calcite.avatica.remote.JsonHandler.apply(JsonHandler.java:52)\r\n\tat
org.apache.calcite.avatica.server.AvaticaJsonHandler.handle(AvaticaJsonHandler.java:105)\r\n\tat
hugh.HughJsonHandler.handle(HughJsonHandler.java:31)\r\n\tat
org.eclipse.jetty.server.handler.HandlerList.handle(HandlerList.java:52)\r\n\tat
org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)\r\n\tat
org.eclipse.jetty.server.Server.handle(Server.java:499)\r\n\tat
org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:311)\r\n\tat
org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257)\r\n\tat
org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:544)\r\n\tat
org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)\r\n\tat
org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)\r\n\tat
java.base/java.lang.Thread.run(Thread.java:833)\r\n"],"errorMessage":"JsonParseException:
Unexpected character ('?' (code 63)): expected a valid value (number,
String, array, object, 'true', 'false' or 'null')\n at [Source:
\n?org.apache.calcite.avatica.proto.Requests$OpenConnectionRequest\u0012&\n$ae2df14d-913f-1870-03ef-a2d458f6f7cd;
line: 2, column:
2]","errorCode":-1,"sqlState":"00000","severity":"UNKNOWN","rpcMetadata":{"response":"rpcMetadata","serverAddress":"AP-LMcALY5bFLMz:8080"}}

POST /test/ HTTP/1.1
Host: localhost:8080
Content-Type: application/octet-stream
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
User-Agent: Phoenix ODBC
Connection: keep-alive
Content-Length: 92
{"request":"openConnection","connectionId":"0b4c6fba-0b81-49f5-bdd9-7092754aee69","info":{}}

HTTP/1.1 200 OK
Date: Mon, 19 Aug 2024 13:43:56 GMT
Content-Type: application/json;charset=utf-8
Content-Length: 111
Server: Jetty(9.2.15.v20160210)
{"response":"openConnection","rpcMetadata":{"response":"rpcMetadata","serverAddress":"AP-LMcALY5bFLMz:8080"}}

POST /test/ HTTP/1.1
Host: localhost:8080
Content-Type: application/octet-stream
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
User-Agent: Phoenix ODBC
Connection: keep-alive
Content-Length: 229
{"request":"connectionSync","connectionId":"0b4c6fba-0b81-49f5-bdd9-7092754aee69","connProps":{"connProps":"connPropsImpl","autoCommit":true,"readOnly":false,"transactionIsolation":null,"catalog":null,"schema":null,"dirty":true}}

HTTP/1.1 200 OK
Date: Mon, 19 Aug 2024 13:43:56 GMT
Content-Type: application/json;charset=utf-8
Content-Length: 262
Server: Jetty(9.2.15.v20160210)
{"response":"connectionSync","connProps":{"connProps":"connPropsImpl","autoCommit":true,"readOnly":false,"transactionIsolation":2,"catalog":"TEST","schema":"PUBLIC","dirty":false},"rpcMetadata":{"response":"rpcMetadata","serverAddress":"AP-LMcALY5bFLMz:8080"}}

POST /test/ HTTP/1.1
Host: localhost:8080
Content-Type: application/octet-stream
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
User-Agent: Phoenix ODBC
Connection: keep-alive
Content-Length: 81
{"request":"getTableTypes","connectionId":"0b4c6fba-0b81-49f5-bdd9-7092754aee69"}

HTTP/1.1 500 Server Error
Date: Mon, 19 Aug 2024 13:43:56 GMT
Content-Type: application/json;charset=utf-8
Content-Length: 1980
Server: Jetty(9.2.15.v20160210)
{"response":"error","exceptions":["java.lang.NullPointerException\r\n\tat
java.base/java.util.Objects.requireNonNull(Objects.java:208)\r\n\tat
org.apache.calcite.avatica.jdbc.StatementInfo.<init>(StatementInfo.java:40)\r\n\tat
org.apache.calcite.avatica.jdbc.JdbcMeta.registerMetaStatement(JdbcMeta.java:318)\r\n\tat
org.apache.calcite.avatica.jdbc.JdbcMeta.getTableTypes(JdbcMeta.java:361)\r\n\tat
hugh.ConfigurableJdbcMeta.getTableTypes(ConfigurableJdbcMeta.java:46)\r\n\tat
org.apache.calcite.avatica.remote.LocalService.apply(LocalService.java:173)\r\n\tat
org.apache.calcite.avatica.remote.Service$TableTypesRequest.accept(Service.java:541)\r\n\tat
org.apache.calcite.avatica.remote.Service$TableTypesRequest.accept(Service.java:526)\r\n\tat
org.apache.calcite.avatica.remote.AbstractHandler.apply(AbstractHandler.java:94)\r\n\tat
org.apache.calcite.avatica.remote.JsonHandler.apply(JsonHandler.java:52)\r\n\tat
org.apache.calcite.avatica.server.AvaticaJsonHandler.handle(AvaticaJsonHandler.java:105)\r\n\tat
hugh.HughJsonHandler.handle(HughJsonHandler.java:31)\r\n\tat
org.eclipse.jetty.server.handler.HandlerList.handle(HandlerList.java:52)\r\n\tat
org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)\r\n\tat
org.eclipse.jetty.server.Server.handle(Server.java:499)\r\n\tat
org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:311)\r\n\tat
org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257)\r\n\tat
org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:544)\r\n\tat
org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)\r\n\tat
org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)\r\n\tat
java.base/java.lang.Thread.run(Thread.java:833)\r\n"],"errorMessage":"NullPointerException:
(null exception
message)","errorCode":-1,"sqlState":"00000","severity":"UNKNOWN","rpcMetadata":{"response":"rpcMetadata","serverAddress":"AP-LMcALY5bFLMz:8080"}}

POST /test/ HTTP/1.1
Host: localhost:8080
Content-Type: application/octet-stream
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
User-Agent: Phoenix ODBC
Connection: keep-alive
request:
{"request":"connectionSync","connectionId":"ec77d999-6e4a-1468-06c4-11aec6dac3c4","connProps":{"connProps":"connPropsImpl","autoCommit":true,"readOnly":false,"transactionIsolation":null,"catalog":null,"schema":null,"dirty":true}}
Content-Length: 0

HTTP/1.1 500 Server Error
Date: Mon, 19 Aug 2024 13:43:57 GMT
Content-Type: application/json;charset=utf-8
Content-Length: 1806
Server: Jetty(9.2.15.v20160210)
{"response":"error","exceptions":["org.apache.calcite.avatica.NoSuchConnectionException\r\n\tat
org.apache.calcite.avatica.jdbc.JdbcMeta.getConnection(JdbcMeta.java:542)\r\n\tat
org.apache.calcite.avatica.jdbc.JdbcMeta.connectionSync(JdbcMeta.java:642)\r\n\tat
hugh.ConfigurableJdbcMeta.connectionSync(ConfigurableJdbcMeta.java:40)\r\n\tat
org.apache.calcite.avatica.remote.LocalService.apply(LocalService.java:307)\r\n\tat
org.apache.calcite.avatica.remote.Service$ConnectionSyncRequest.accept(Service.java:2048)\r\n\tat
org.apache.calcite.avatica.remote.Service$ConnectionSyncRequest.accept(Service.java:2024)\r\n\tat
org.apache.calcite.avatica.remote.AbstractHandler.apply(AbstractHandler.java:94)\r\n\tat
org.apache.calcite.avatica.remote.JsonHandler.apply(JsonHandler.java:52)\r\n\tat
org.apache.calcite.avatica.server.AvaticaJsonHandler.handle(AvaticaJsonHandler.java:105)\r\n\tat
hugh.HughJsonHandler.handle(HughJsonHandler.java:31)\r\n\tat
org.eclipse.jetty.server.handler.HandlerList.handle(HandlerList.java:52)\r\n\tat
org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)\r\n\tat
org.eclipse.jetty.server.Server.handle(Server.java:499)\r\n\tat
org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:311)\r\n\tat
org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:257)\r\n\tat
org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:544)\r\n\tat
org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:635)\r\n\tat
org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:555)\r\n\tat
java.base/java.lang.Thread.run(Thread.java:833)\r\n"],"errorMessage":null,"errorCode":1,"sqlState":"00000","severity":"ERROR","rpcMetadata":{"response":"rpcMetadata","serverAddress":"AP-LMcALY5bFLMz:8080"}}

==========
= END Wireshark trace
==========

Questions:
1. Does anyone know if this commercial driver was working with Avatica at
any point?
2. Could it still be working, and I am just missing some custom
configuration in Avatica?

Reference:
1. phoenix-queryserver code -
https://github.com/apache/phoenix-queryserver/blob/3360154858e27cabe258dfb33b37ec31ed3bd210/phoenix-queryserver/src/main/java/org/apache/phoenix/queryserver/server/QueryServer.java#L379


From,
Hugh Pearse

Reply via email to