sql

emccue 2024-02-21T17:41:41.469819Z

deep(?) JDBC question - is there any reason that you would have to use setInt, setLong, setString, etc? As opposed to always using setObject

rpatrelle 2024-02-21T18:36:43.494819Z

I am working on the deployment of a mysql generic Polylith component on some Polylith project. The polylith component is a stuart Sierra component, using next.jdbc and Hikary pool. Problem I am facing is when I launch my test on the CI , I am facing this error:

lojure.lang.ExceptionInfo: Error while evaluating form (do (clojure.core/use (quote clojure.test)) (clojure.core/require (quote beop.export-api.modules.schedule-test)) (clojure.test/run-tests (quote beop.export-api.modules.schedule-test))) in class-loader. Cause: java.lang.reflect.InvocationTargetException; java.lang.RuntimeException: Failed to get driver instance for jdbcUrl=jdbc:; java.sql.SQLException: No suitable driver {:form (do (clojure.core/use (quote clojure.test)) (clojure.core/require (quote beop.export-api.modules.schedule-test)) (clojure.test/run-tests (quote beop.export-api.modules.schedule-test)))}
I don't face this issue when I launch the same test locally. This test is a test of the base project I am trying to update with this new component. The component is used in the CI before for another project but mixed with hugsql. So I have the feeling there is a jdbc driver conflict but I not able solve the issue. When I list deps for the first project (the one working, with hugsql), I find following jdbc deps:
mysql/mysql-connector-java 5.1.49
com.layerware/hugsql 0.5.1
  . com.layerware/hugsql-core 0.5.1
    X org.clojure/tools.reader 1.3.2 :superseded
    . com.layerware/hugsql-adapter 0.5.1
  . com.layerware/hugsql-adapter-clojure-java-jdbc 0.5.1
    . org.clojure/java.jdbc 0.7.10 :newer-version
    . com.layerware/hugsql-adapter 0.5.1
For the second project, the one not working on CI , there is no jdbc driver directly in the project because the driver is supposed to be called by the Polylith mysql component , with such deps.edn dependencies:
com.layerware/hugsql {:mvn/version "0.5.1"
                                 :exclusions [com.layerware/hugsql-adapter]}
com.layerware/hugsql-adapter-next-jdbc {:mvn/version "0.5.1"
                                                   :exclusions [seancorfield/next.jdbc]}
com.github.seancorfield/next.jdbc {:mvn/version "1.3.894"}
mysql/mysql-connector-java {:mvn/version "5.1.49"}
com.zaxxer/HikariCP {:mvn/version "5.0.1"}
Does anybody have an idea how to solve my problem?

seancorfield 2024-02-21T18:57:05.999709Z

How exactly are you running the Polylith tests in CI? (and I suspect this belongs in #polylith but I'll try to answer it here)

rpatrelle 2024-02-21T19:23:26.288099Z

We run test on github action with following command:

AWS_REGION=eu-west-1 AWS_CBOR_DISABLE=true clojure -M:poly test :project since:release

seancorfield 2024-02-21T19:38:43.338709Z

And how are you running the tests locally?

rpatrelle 2024-02-21T19:39:48.872629Z

I run test in the repl.

seancorfield 2024-02-21T19:40:06.407699Z

Well, that's not the same environment...

seancorfield 2024-02-21T19:40:26.670149Z

Does clojure -M:poly test since:release fail locally from a terminal?

seancorfield 2024-02-21T19:40:53.888769Z

(not sure why you have :project in there if you're not specifying a particular project to use?)

rpatrelle 2024-02-21T19:42:24.865659Z

I will launch test locally when I will be in front of my laptop (evening here in France)

seancorfield 2024-02-21T19:47:01.707289Z

Follow-up in #polylith since this is a classpath dependency issue due to something in your Polylith structure, not a SQL issue, as far as I can tell. In your REPL, you'd be in the :dev project with all bricks on the classpath and all of their dependencies. When you run clojure -M:poly test it is running in the project context, with the classpath constructed from each individual project.

rpatrelle 2024-02-21T19:53:54.509059Z

Ok, i will ask there.

rpatrelle 2024-02-21T19:54:13.848479Z

Thanks for you help

rpatrelle 2024-02-21T21:55:27.746279Z

A last question @seancorfield: What do you mean by :dev project? In Polylith projects folder, we have all our business project but no dev project. When we launch test in repl, we use the same test-system as the one used in CI test environnement. This test-system is still for the moment the test-system of one of the bases , not move yet to a specific component (legacy from before Polylith).

rpatrelle 2024-02-21T21:56:36.136229Z

I moved my question to #polylith in the mean time.

seancorfield 2024-02-21T23:58:31.230609Z

The :dev alias represents the development project, intended for use with the REPL. Maybe you need to have another read of the Polylith docs? It sounds like you don't have a grasp on some of the basics yet...?

seancorfield 2024-02-22T00:00:06.860049Z

(and there's also a :dev command-line argument for some poly commands that adds the development project into the scope of the command -- e.g., you normally test via projects but that doesn't include development, unless you add the :dev command-line argument... not to be confused with using :dev as an alias with the Clojure CLI when you are starting a REPL)

rpatrelle 2024-02-27T16:33:27.610619Z

Hello @seancorfield, sorry for late reply, we were focused on this issue. True, I am quite new to polylith. As I work on an already setup project, I used usual command like create a new component and so on. Now, I read the documentation and understand better how it works. Anyway, sound our issue is not a polylith one. In order to validate that the driver is well in the classpath, I have add this line in a test namespace: (prn (Class/forName "com.mysql.jdbc.Driver")) With this line, there is no more exception.

rpatrelle 2024-02-27T16:35:10.876009Z

So we have the feeling that the jdbc driver loading is lazy and not realized without the prn . Just a feeling. Do you have an idea?

seancorfield 2024-02-27T18:58:11.883549Z

Can you share the code of how you set up the HikariCP connection pool?

J 2024-02-27T19:43:15.876069Z

Hi Sean! (I work with rpatrelle) Basically this is how our component looks like https://github.com/patinside/sql_classpath_issue/blob/main/components/sql/src/beop/sql/core.clj

seancorfield 2024-02-27T19:46:30.375199Z

OK, so that would attempt to load com.mysql.cj.jdbc.Driver first and if that failed it would attempt to load com.mysql.jdbc.Driver -- because MySQL's driver has changed the class name.

seancorfield 2024-02-27T19:47:00.526719Z

You're using a pretty old driver mysql/mysql-connector-java {:mvn/version "5.1.49"}

seancorfield 2024-02-27T19:47:51.725849Z

Is it possible you have both the old and the new driver on your classpath?

J 2024-02-27T20:47:08.785789Z

How did you know that com.mysql.cj.jdbc.Driver is loaded first? It's Hikari which import this?

seancorfield 2024-02-27T20:50:59.595179Z

connection/jdbc-url will construct the :jdbcUrl from a db-spec and as part of that it will try to load (and cache) driver classes that correspond to the :dbtype.

seancorfield 2024-02-27T20:51:50.545789Z

For MySQL -- and MySQL alone -- two possible driver classes exist: the new one (with .cj) and the old one, and next.jdbc tries them in a specific order (new, then old).

J 2024-02-27T20:53:25.264589Z

Thanks for the clarification! When I run -Stree I see only the old driver.

seancorfield 2024-02-27T20:53:59.470309Z

How are you running -Stree -- Polylith uses different classpaths for dev (REPL) and for tests (projects)

J 2024-02-27T20:54:30.559049Z

like this: clojure -Stree -M:dev

seancorfield 2024-02-27T20:54:31.817459Z

You really need to run clojure -Stree inside each of the projects folders

seancorfield 2024-02-27T20:55:22.625029Z

The :dev alias is for the REPL, not the tests (although you can ask poly test to also include development when running tests -- but the default is per-project)

J 2024-02-27T20:59:54.799309Z

Each projects only have the old mysql version

seancorfield 2024-02-27T21:04:24.017059Z

Is that github repo an actual repo of the problem? Should I expect to see the driver not found error if I clone and run it?

J 2024-02-27T21:05:51.663759Z

Unfortunately we don't reproduce the behaviour in the public repo.

seancorfield 2024-02-27T21:06:36.014819Z

That is why I still think this is a Polylith-related problem in your actual repo 😕

seancorfield 2024-02-27T21:08:50.420879Z

If you can repro it in a public repo, I can try to help.

seancorfield 2024-02-27T21:10:31.592999Z

That public repo "works" (modulo failing to find the expected rows in the database) and uses the old driver -- so that shows there isn't a problem with next.jdbc -- and at work we use it with the new driver and Polylith and that also works.

seancorfield 2024-02-27T21:11:45.882719Z

When it fails with No suitable driver do you get a full stack trace?

J 2024-02-27T21:11:51.816569Z

Is not next related indeed. In fact, the error occurs when other projects are tested. If the ci test the project alone, no error.

seancorfield 2024-02-27T21:12:30.881979Z

Not sure what you mean by "If the ci test the project alone" -- how exactly are you running those tests?

J 2024-02-27T21:15:37.501569Z

We launch the poly command: clojure -M:poly test :project since:release we get the projects to test. If the culprit project is the only to test, no problem. The full exception thrown:

clojure.lang.ExceptionInfo: Error while evaluating form (do (clojure.core/use (quote clojure.test)) (clojure.core/require (quote beop.export-api.modules.schedule-test)) (clojure.test/run-tests (quote beop.export-api.modules.schedule-test))) in class-loader. Cause: java.lang.reflect.InvocationTargetException; java.lang.RuntimeException: Failed to get driver instance for jdbcUrl=jdbc:; java.sql.SQLException: No suitable driver {:form (do (clojure.core/use (quote clojure.test)) (clojure.core/require (quote beop.export-api.modules.schedule-test)) (clojure.test/run-tests (quote beop.export-api.modules.schedule-test)))}
	at polylith.clj.core.test_runner_orchestrator.core$__GT_eval_in_project$fn__27578.invoke(core.clj:110)
	at polylith.clj.core.clojure_test_test_runner.core$run_test_statements$fn__41996.invoke(core.clj:59)
	at polylith.clj.core.clojure_test_test_runner.core$run_test_statements.invokeStatic(core.clj:58)
	at polylith.clj.core.clojure_test_test_runner.core$run_test_statements.invoke(core.clj:52)
	at polylith.clj.core.clojure_test_test_runner.core$create$reify__42023.run_tests(core.clj:98)
	at polylith.clj.core.test_runner_orchestrator.core$run_tests_for_project_with_test_runner.invokeStatic(core.clj:88)
	at polylith.clj.core.test_runner_orchestrator.core$run_tests_for_project_with_test_runner.invoke(core.clj:77)
	at polylith.clj.core.test_runner_orchestrator.core$run_tests_for_project.invokeStatic(core.clj:159)
	at polylith.clj.core.test_runner_orchestrator.core$run_tests_for_project.invoke(core.clj:129)
	at polylith.clj.core.test_runner_orchestrator.core$run.invokeStatic(core.clj:214)
	at polylith.clj.core.test_runner_orchestrator.core$run.invoke(core.clj:197)
	at polylith.clj.core.test_runner_orchestrator.interface$run.invokeStatic(interface.clj:5)
	at polylith.clj.core.test_runner_orchestrator.interface$run.invoke(interface.clj:4)
	at polylith.clj.core.command.test$run.invokeStatic(test.clj:11)
	at polylith.clj.core.command.test$run.invoke(test.clj:5)
	at polylith.clj.core.command.core$execute.invokeStatic(core.clj:118)
	at polylith.clj.core.command.core$execute.invoke(core.clj:89)
	at polylith.clj.core.command.interface$execute_command.invokeStatic(interface.clj:5)
	at polylith.clj.core.command.interface$execute_command.invoke(interface.clj:4)
	at polylith.clj.core.poly_cli.core$_main.invokeStatic(core.clj:33)
	at polylith.clj.core.poly_cli.core$_main.doInvoke(core.clj:7)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.lang.Var.applyTo(Var.java:705)
	at clojure.core$apply.invokeStatic(core.clj:667)
	at clojure.main$main_opt.invokeStatic(main.clj:514)
	at clojure.main$main_opt.invoke(main.clj:510)
	at clojure.main$main.invokeStatic(main.clj:664)
	at clojure.main$main.doInvoke(main.clj:616)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.lang.Var.applyTo(Var.java:705)
	at clojure.main.main(main.java:40)
Caused by: java.lang.reflect.InvocationTargetException
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at polylith.clj.core.common.class_loader$invoke_in_STAR_.invokeStatic(class_loader.clj:31)
	at polylith.clj.core.common.class_loader$invoke_in_STAR_.doInvoke(class_loader.clj:27)
	at clojure.lang.RestFn.invoke(RestFn.java:494)
	at polylith.clj.core.common.class_loader$eval_in_STAR_$print_read_eval__3887.invoke(class_loader.clj:49)
	at polylith.clj.core.common.class_loader$eval_in_STAR_.invokeStatic(class_loader.clj:51)
	at polylith.clj.core.common.class_loader$eval_in_STAR_.invoke(class_loader.clj:45)
	at polylith.clj.core.common.class_loader$eval_in.invokeStatic(class_loader.clj:61)
	at polylith.clj.core.common.class_loader$eval_in.invoke(class_loader.clj:60)
	at polylith.clj.core.common.interface$eval_in.invokeStatic(interface.clj:30)
	at polylith.clj.core.common.interface$eval_in.invoke(interface.clj:29)
	at polylith.clj.core.test_runner_orchestrator.core$__GT_eval_in_project$fn__27578.invoke(core.clj:108)
	... 30 more
Caused by: java.lang.RuntimeException: Failed to get driver instance for jdbcUrl=jdbc:
	at com.zaxxer.hikari.util.DriverDataSource.<init>(DriverDataSource.java:114)
	at com.zaxxer.hikari.pool.PoolBase.initializeDataSource(PoolBase.java:326)
	at com.zaxxer.hikari.pool.PoolBase.<init>(PoolBase.java:112)
	at com.zaxxer.hikari.pool.HikariPool.<init>(HikariPool.java:93)
	at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:112)
	at next.jdbc.connection$make_connection.invokeStatic(connection.clj:452)
	at next.jdbc.connection$make_connection.invoke(connection.clj:436)
	at next.jdbc.connection$eval30353$fn__30354.invoke(connection.clj:481)
	at next.jdbc.protocols$eval30083$fn__30084$G__30074__30091.invoke(protocols.clj:25)
	at next.jdbc.result_set$eval31056$fn__31064.invoke(result_set.clj:934)
	at next.jdbc.protocols$eval30115$fn__30116$G__30106__30125.invoke(protocols.clj:34)
	at next.jdbc.result_set$eval31095$fn__31100.invoke(result_set.clj:1023)
	at next.jdbc.protocols$eval30115$fn__30116$G__30106__30125.invoke(protocols.clj:34)
	at next.jdbc$execute_BANG_.invokeStatic(jdbc.clj:251)
	at next.jdbc$execute_BANG_.invoke(jdbc.clj:238)
	at beop.export_api.test_utils$with_test_system.invokeStatic(test_utils.clj:43)
	at beop.export_api.test_utils$with_test_system.invoke(test_utils.clj:35)
	at clojure.test$compose_fixtures$fn__9850$fn__9851.invoke(test.clj:694)
	at clojure.test$default_fixture.invokeStatic(test.clj:687)
	at clojure.test$default_fixture.invoke(test.clj:683)
	at clojure.test$compose_fixtures$fn__9850.invoke(test.clj:694)
	at clojure.test$compose_fixtures$fn__9850.invoke(test.clj:694)
	at clojure.test$test_vars.invokeStatic(test.clj:731)
	at clojure.test$test_all_vars.invokeStatic(test.clj:737)
	at clojure.test$test_ns.invokeStatic(test.clj:758)
	at clojure.test$test_ns.invoke(test.clj:743)
	at clojure.core$map$fn__5935.invoke(core.clj:2772)
	at clojure.lang.LazySeq.sval(LazySeq.java:42)
	at clojure.lang.LazySeq.seq(LazySeq.java:51)
	at clojure.lang.Cons.next(Cons.java:39)
	at clojure.lang.RT.boundedLength(RT.java:1790)
	at clojure.lang.RestFn.applyTo(RestFn.java:130)
	at clojure.core$apply.invokeStatic(core.clj:669)
	at clojure.test$run_tests.invokeStatic(test.clj:768)
	at clojure.test$run_tests.doInvoke(test.clj:768)
	at clojure.lang.RestFn.invoke(RestFn.java:408)
	at clojure.core$eval73541.invokeStatic(NO_SOURCE_FILE:0)
	at clojure.core$eval73541.invoke(NO_SOURCE_FILE)
	at clojure.lang.Compiler.eval(Compiler.java:7194)
	at clojure.lang.Compiler.eval(Compiler.java:7184)
	at clojure.lang.Compiler.eval(Compiler.java:7149)
	at clojure.core$eval.invokeStatic(core.clj:3215)
	at clojure.core$eval.invoke(core.clj:3211)
	at clojure.core$eval73461.invokeStatic(NO_SOURCE_FILE:0)
	at clojure.core$eval73461.invoke(NO_SOURCE_FILE)
	at clojure.lang.Compiler.eval(Compiler.java:7194)
	at clojure.lang.Compiler.eval(Compiler.java:7149)
	... 45 more
Caused by: java.sql.SQLException: No suitable driver
	at java.sql/java.sql.DriverManager.getDriver(DriverManager.java:298)
	at com.zaxxer.hikari.util.DriverDataSource.<init>(DriverDataSource.java:106)
	... 91 more

seancorfield 2024-02-27T21:18:43.109169Z

Without access to your source code, I really can't help.

seancorfield 2024-02-27T21:20:01.511099Z

What is the code around these lines:

at beop.export_api.test_utils$with_test_system.invokeStatic(test_utils.clj:43)
	at beop.export_api.test_utils$with_test_system.invoke(test_utils.clj:35)

seancorfield 2024-02-27T21:20:26.926899Z

(but I'll probably need to keep asking to see more code and more deps.edn files)

J 2024-02-27T21:25:22.286089Z

Just a function and a call to jdbc/execute! to create test table. I will continue the debug tomorrow, I will reach you if I find something interesting. Huge thanks for your support and help!

seancorfield 2024-02-27T21:32:41.052349Z

> Just a function and a call to jdbc/execute! to create test table. This is not a useful answer. I would need to know exactly what the arguments were and how they were constructed.