No method in multimethod 'connection-details->spec' for dispatch value

I am trying to build a new database driver to be shipped as a 3rd-party plugin ( i.e. in a separate repo rather than the modules/drivers/ directory).
To begin, I am doing a spike where I clone the Sql Server driver plugin into a new driver named, say, ss2.
I copied the project.clj file and the resources and src folders into a new Clojure project, and I renamed the project file from sqlserver.clj to ss2.clj.
I also renamed the namespace (from metabase.driver.sqlserver to metabase.driver.ss2) and the project name (metabase/sqlserver-driver to metabase/ss2-driver) and the display name (Sql Server to SS2).
And I replaced every occurrence of the keyword :sqlserver with the keyword :ss2.
The rest of the code remained the same as for Sql Server.
Therefore, in my thinking, the driver should work the same as for Sql Server.

I installed metabase-core locally, then I built the new SS2 driver using the leinengen command:
     lein uberjar
This produced the ss2.metabase-driver.jar file in the target directory of my SS2 project.
I launched Metabase as a Docker container with Bind Mounting to the Plugins directory using the Docker command below:
     docker run -d -p 3000:3000 --mount type=bind,source=/Users/myuser/Documents/Metabase/plugins,destination=/plugins --name metabase metabase/metabase

During initialization, Metabase built and produced the database drivers in the local host directory that I set a bind mount to:
     /Users/myuser/Documents/Metabase/plugins
I copied my ss2.metabase-driver.jar file into that /Users/myuser/Documents/Metabase/plugins directory and stopped and reran the Metabase container.
In my browser, when I navigated to http://localhost:3000 I get the Metabase Setup page.
In step 2, in the Add Your Data section, I can select “Sql Server” from the dropdown and complete the connection configuration. When I hit “Next”, my connection succeeds.
However, when I select “SS2” from the dropdown and complete the same connection configuration and hit “Next”, I get the error:
     No method in multimethod ‘connection-details->spec’ for dispatch value: SS2

Why is my SS2 (a clone of Sql Server) failing with this message while Sql Server does not?

Hi @reydavid
I’m not sure why it’s failing like that.
Could it be that you are trying to build from an outdated repo?
Or perhaps using the same namespace as already used by sqlserver.metabase-driver.jar?

Are there other warnings/errors in the log (check from startup to failure)?

You might want to have a look at the structure of these drivers as a template:
https://github.com/dludwig-jrt/metabase-db2-driver
https://github.com/enqueue/metabase-clickhouse-driver
https://github.com/dacort/metabase-athena-driver
https://github.com/fhsgoncalves/metabase-sparksql-databricks-driver
There’s a lot of information in this issue too:
https://github.com/metabase/metabase/issues/9348

Thanks for your prompt reply, @flamber
I followed your suggestion and took a closer look at the other warnings/errors in the log.
I have found that the underlying error may be that I don’t have some java classes in my classpath.

     Caused by: java.io.FileNotFoundException: Could not locate java_time__init.class, java_time.clj or java_time.cljc on classpath. Please check that namespaces with dashes use underscores in the Clojure file name.

How do I resolve this underlying issue?
Thanks.

@reydavid
Please post the following:

java -version
nodejs --version
lein --version
yarn --version
lsb_release -d
git log -1 --format="commit %H"
git status | head -1

Hi @flamber
I’m not using Git. I am developing locally. Here are my versions:

java -version
1.8.0_121
node --version
v12.13.0
lein --version
Leiningen 2.9.1 on Java 1.8.0_121 Java HotSpot™ 64-Bit Server VM
yarn --version
1.13.0
lsb_release -d
lsb_release: command not found (I am not using lsb)
git log -1 --format=“commit %H”
fatal: not a git repository (or any of the parent directories)

@reydavid
Upgrade Java - latest is 8u231
Upgrade Yarn - latest is 1.19.1
Which OS are you using?
If you’re not using Git, then how did you get the source code?

@flamber
I figured it out.
When building Metabase drivers shipped as 3rd party plugins, it is not enough to write my project files with the same assumptions as drivers shipped as part of the core Metabase repo.
I had to explicitly declare other dependencies in my project.clj file.
In the case of the Sql Server driver, the project.clj code starts out with:

(defproject metabase/sqlserver-driver “1.0.0-SNAPSHOT”
:min-lein-version “2.5.0”
:dependencies
[[com.microsoft.sqlserver/mssql-jdbc “7.4.1.jre8”]]

In my case, I had to explicitly add the clojure.java-time dependency:

(defproject metabase/ss2-driver “1.0.0-SNAPSHOT”
:min-lein-version “2.5.0”
:dependencies
[[com.microsoft.sqlserver/mssql-jdbc “7.4.1.jre8”]
[clojure.java-time “0.3.2”]
]

I can add the remaining dependencies from here.
Thanks for the attention you gave to this, @flamber .

1 Like

@reydavid
Looking at one of the other drivers, it looks like you can just add metabase-core as a profile dependency, which should then add whatever is needed.
https://github.com/fhsgoncalves/metabase-sparksql-databricks-driver/blob/master/project.clj
I would recommend that you look at the other third-party drivers - I’m sure there’s other things you can learn from them.

Hi @flamber
I am well on my way into writing a Metabase driver plugin for Dremio.
I have already installed the Dremio JDBC driver with the Clojure project.
Now I am trying to implement the multifunction for sql-jdbc.conn/connection-details->spec
My code looks like this:

(defmethod sql-jdbc.conn/connection-details->spec :dremio
[_ {:keys [user password db host port instance ssl]
:or {user “dbuser”, password “dbpassword”, db “”, host “localhost”}
:as details}]
(-> {:applicationName config/mb-app-id-string
:url host
:subprotocol “dremio”
:dbname db
:database db
:password password
:classname “com.dremio.jdbc.Driver”
:connection-uri “jdbc:dremio:direct=127.0.0.1:31010”
:user user
:instanceName instance
:encrypt (boolean ssl)
(sql-jdbc.common/handle-additional-options details, :seperator-style :semicolon)))

The connection-url property should override some of the database connection attributes.
I am running Dremio locally on a Docker container, with the Dremio services at port 31010.
However, when I do the Metabase setup, entering connection attributes in the “Add your data” section, and hit the “Next” button, I would get the following “Connection Refused” error message from the Metabase logs:

ERROR rpc.BasicClient :: Failed to establish connection
java.util.concurrent.ExecutionException: cdjd.io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: localhost/127.0.0.1:31010
at cdjd.io.netty.util.concurrent.AbstractFuture.get(AbstractFuture.java:54)
at cdjd.com.dremio.exec.rpc.BasicClient$ConnectionMultiListener$ConnectionEstablishmentListener.operationComplete(BasicClient.java:284)
at cdjd.com.dremio.exec.rpc.BasicClient$ConnectionMultiListener$ConnectionEstablishmentListener.operationComplete(BasicClient.java:272)
at cdjd.io.netty.util.concurrent.DefaultPromise.notifyListener0(DefaultPromise.java:500)
at cdjd.io.netty.util.concurrent.DefaultPromise.notifyListeners0(DefaultPromise.java:493)
at cdjd.io.netty.util.concurrent.DefaultPromise.notifyListenersNow(DefaultPromise.java:472)
at cdjd.io.netty.util.concurrent.DefaultPromise.notifyListeners(DefaultPromise.java:413)
at cdjd.io.netty.util.concurrent.DefaultPromise.setValue0(DefaultPromise.java:538)
at cdjd.io.netty.util.concurrent.DefaultPromise.setFailure0(DefaultPromise.java:531)
at cdjd.io.netty.util.concurrent.DefaultPromise.tryFailure(DefaultPromise.java:111)
at cdjd.io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.fulfillConnectPromise(AbstractNioChannel.java:323)
at cdjd.io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.finishConnect(AbstractNioChannel.java:339)
at cdjd.io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:685)
at cdjd.io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:632)
at cdjd.io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:549)
at cdjd.io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:511)
at cdjd.io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:918)
at cdjd.io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at java.base/java.lang.Thread.run(Unknown Source)
Caused by: cdjd.io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: localhost/127.0.0.1:31010
Caused by: java.net.ConnectException: Connection refused

I have tried countless permutations of the connection attributes.
Only this permutation, with this connection-url, produces the “Connection refused” error.
Most of the others would produce a TimeoutException, suggesting that the service does not exist.
So I suspect that my connection string is correct, but its request is just not reaching the Dremio service.
What could be going on? Please help!

@reydavid Since you created another post, let’s continue there: Connection Refused to Dremio
Ignore anything in my comment about checking other drivers, I didn’t see this topic before answering the other.