fix #229
This commit is contained in:
parent
a0be7d162d
commit
dd040150fc
3 changed files with 89 additions and 15 deletions
|
|
@ -3,6 +3,7 @@
|
||||||
Only accretive/fixative changes will be made from now on.
|
Only accretive/fixative changes will be made from now on.
|
||||||
|
|
||||||
* 1.3.next in progress
|
* 1.3.next in progress
|
||||||
|
* Fix [#229](https://github.com/seancorfield/next-jdbc/issues/229) by adding `next.jdbc.connect/uri->db-spec` which converts a URI string to a db-spec hash map; in addition, if `DriverManager/getConnection` fails, it assumes it was passed a URI instead of a JDBC URL, and retries after calling that function and then recreating the JDBC URL (which should have the effect of moving the embedded user/password credentials into the properties structure instead of the URL).
|
||||||
* Address [#228](https://github.com/seancorfield/next-jdbc/issues/228) by adding `PreparedStatement` caveat to the Oracle **Tips & Tricks** section.
|
* Address [#228](https://github.com/seancorfield/next-jdbc/issues/228) by adding `PreparedStatement` caveat to the Oracle **Tips & Tricks** section.
|
||||||
|
|
||||||
* 1.3.834 -- 2022-09-23
|
* 1.3.834 -- 2022-09-23
|
||||||
|
|
|
||||||
|
|
@ -132,21 +132,6 @@
|
||||||
:dbname-separator ":dsn="
|
:dbname-separator ":dsn="
|
||||||
:host :none}})
|
:host :none}})
|
||||||
|
|
||||||
(defn- ^Properties as-properties
|
|
||||||
"Convert any seq of pairs to a `java.util.Properties` instance."
|
|
||||||
[m]
|
|
||||||
(let [p (Properties.)]
|
|
||||||
(doseq [[k v] m]
|
|
||||||
(.setProperty p (name k) (str v)))
|
|
||||||
p))
|
|
||||||
|
|
||||||
(defn- get-driver-connection
|
|
||||||
"Common logic for loading the designated JDBC driver class and
|
|
||||||
obtaining the appropriate `Connection` object."
|
|
||||||
[url timeout etc]
|
|
||||||
(when timeout (DriverManager/setLoginTimeout timeout))
|
|
||||||
(DriverManager/getConnection url (as-properties etc)))
|
|
||||||
|
|
||||||
(def ^:private driver-cache
|
(def ^:private driver-cache
|
||||||
"An optimization for repeated calls to get-datasource, or for get-connection
|
"An optimization for repeated calls to get-datasource, or for get-connection
|
||||||
called on a db-spec hash map, so that we only try to load the classes once."
|
called on a db-spec hash map, so that we only try to load the classes once."
|
||||||
|
|
@ -359,6 +344,53 @@
|
||||||
[s]
|
[s]
|
||||||
[s {}])
|
[s {}])
|
||||||
|
|
||||||
|
(defn- ^Properties as-properties
|
||||||
|
"Convert any seq of pairs to a `java.util.Properties` instance."
|
||||||
|
[m]
|
||||||
|
(let [p (Properties.)]
|
||||||
|
(doseq [[k v] m]
|
||||||
|
(.setProperty p (name k) (str v)))
|
||||||
|
p))
|
||||||
|
|
||||||
|
(defn uri->db-spec
|
||||||
|
"clojure.java.jdbc (and some users out there) considered the URI format
|
||||||
|
to be an acceptable JDBC URL, i.e., with credentials embdedded in the string,
|
||||||
|
rather than as query parameters.
|
||||||
|
|
||||||
|
This function accepts a URI string, optionally prefixed with `jdbc:` and
|
||||||
|
returns a db-spec hash map."
|
||||||
|
[uri]
|
||||||
|
(let [{:keys [scheme userInfo host port path query]}
|
||||||
|
(j/from-java (java.net.URI. (str/replace uri #"^jdbc:" "")))
|
||||||
|
[user password] (when (seq userInfo) (str/split userInfo #":"))
|
||||||
|
properties (when (seq query)
|
||||||
|
(into {}
|
||||||
|
(map #(str/split % #"="))
|
||||||
|
(str/split query #"\&")))]
|
||||||
|
(cond-> (assoc properties
|
||||||
|
:dbtype scheme
|
||||||
|
:host host
|
||||||
|
:port port)
|
||||||
|
(seq path) (assoc :dbname (subs path 1))
|
||||||
|
user (assoc :user user)
|
||||||
|
password (assoc :password password))))
|
||||||
|
|
||||||
|
(defn- get-driver-connection
|
||||||
|
"Common logic for loading the designated JDBC driver class and
|
||||||
|
obtaining the appropriate `Connection` object."
|
||||||
|
[url timeout etc]
|
||||||
|
(when timeout (DriverManager/setLoginTimeout timeout))
|
||||||
|
(try
|
||||||
|
(DriverManager/getConnection url (as-properties etc))
|
||||||
|
(catch Exception e
|
||||||
|
(try
|
||||||
|
(let [db-spec (uri->db-spec url)
|
||||||
|
[url' etc'] (spec->url+etc db-spec)]
|
||||||
|
(DriverManager/getConnection url' (as-properties (merge etc' etc))))
|
||||||
|
(catch Exception _
|
||||||
|
;; if the fallback fails too, throw the original exception
|
||||||
|
(throw e))))))
|
||||||
|
|
||||||
(defn- url+etc->datasource
|
(defn- url+etc->datasource
|
||||||
"Given a JDBC URL and a map of options, return a `DataSource` that can be
|
"Given a JDBC URL and a map of options, return a `DataSource` that can be
|
||||||
used to obtain a new database connection."
|
used to obtain a new database connection."
|
||||||
|
|
|
||||||
41
test/next/jdbc/connection_string_test.clj
Normal file
41
test/next/jdbc/connection_string_test.clj
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
;; copyright (c) 2019-2021 Sean Corfield, all rights reserved
|
||||||
|
|
||||||
|
(ns next.jdbc.connection-string-test
|
||||||
|
"Tests for the main hash map spec to JDBC URL logic and the get-datasource
|
||||||
|
and get-connection protocol implementations.
|
||||||
|
|
||||||
|
At some point, the datasource/connection tests should probably be extended
|
||||||
|
to accept EDN specs from an external source (environment variables?)."
|
||||||
|
(:require [clojure.string :as str]
|
||||||
|
[clojure.test :refer [deftest is testing use-fixtures]]
|
||||||
|
[next.jdbc.connection :as c]
|
||||||
|
[next.jdbc.protocols :as p]
|
||||||
|
[next.jdbc.specs :as specs]
|
||||||
|
[next.jdbc.test-fixtures :refer [with-test-db db]]))
|
||||||
|
|
||||||
|
(set! *warn-on-reflection* true)
|
||||||
|
|
||||||
|
(use-fixtures :once with-test-db)
|
||||||
|
|
||||||
|
(specs/instrument)
|
||||||
|
|
||||||
|
(deftest test-uri-strings
|
||||||
|
(testing "datasource via String"
|
||||||
|
(let [db-spec (db)
|
||||||
|
db-spec (if (= "embedded-postgres" (:dbtype db-spec))
|
||||||
|
(assoc db-spec :dbtype "postgresql")
|
||||||
|
db-spec)
|
||||||
|
[url etc] (#'c/spec->url+etc db-spec)
|
||||||
|
{:keys [user password]} etc
|
||||||
|
etc (dissoc etc :user :password)
|
||||||
|
uri (-> url
|
||||||
|
;; strip jdbc: prefix for fun
|
||||||
|
(str/replace #"^jdbc:" "")
|
||||||
|
(str/replace #";" "?") ; for SQL Server tests
|
||||||
|
(str/replace #":sqlserver" "") ; for SQL Server tests
|
||||||
|
(cond-> (and user password)
|
||||||
|
(str/replace #"://" (str "://" user ":" password "@"))))
|
||||||
|
ds (p/get-datasource (assoc etc :jdbcUrl uri))]
|
||||||
|
(when (and user password)
|
||||||
|
(with-open [con (p/get-connection ds {})]
|
||||||
|
(is (instance? java.sql.Connection con)))))))
|
||||||
Loading…
Reference in a new issue