Skip to content

Commit 485709b

Browse files
authored
Merge pull request #10 from gizmodata/main
Added catalog support. Closes #9
2 parents 73ee3ae + b70fbab commit 485709b

File tree

3 files changed

+64
-20
lines changed

3 files changed

+64
-20
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ When setting up the connection in Metabase, the driver registers under the name
5757
- User: (Optional) – Username for authentication.
5858
- Password: (Optional) – Password for authentication (supports secret merging).
5959
- Token: (Optional) – A secure token for connection.
60+
- Catalog: (Optional) - The name of the catalog to use. If not specified, the default catalog will be used.
6061
- Use Encryption: (Default: true) – Enable or disable connection encryption. We don´t use this in our tests.
6162

6263
Advanced options can be set via the additional-options field.

resources/metabase-plugin.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ driver:
4141
type: secret
4242
required: false
4343

44+
- name: catalog
45+
display-name: Catalog (optional)
46+
type: string
47+
required: false
48+
4449
- name: useEncryption
4550
display-name: Use Encryption
4651
type: boolean

src/metabase/driver/arrow_flight_sql.clj

Lines changed: 58 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
;; ----------------------------------------------------------------
6565
(defmethod sql-jdbc.conn/connection-details->spec :arrow-flight-sql
6666
[_ details]
67-
(let [{:keys [host port token username user password useEncryption disableCertificateVerification]
67+
(let [{:keys [host port token username user password catalog useEncryption disableCertificateVerification]
6868
:or {useEncryption true
6969
disableCertificateVerification false}} details
7070
;; prefer :username (manifest) but fall back to :user
@@ -84,17 +84,21 @@
8484
:else [])
8585

8686
;; Build query params
87-
params (-> []
88-
(into auth-qps)
89-
(conj (str "useEncryption=" (boolean useEncryption)))
90-
(conj (str "disableCertificateVerification=" (boolean disableCertificateVerification))))
87+
params (cond-> []
88+
true (into auth-qps)
89+
true (conj (str "useEncryption=" (boolean useEncryption)))
90+
true (conj (str "disableCertificateVerification=" (boolean disableCertificateVerification)))
91+
;; Add catalog if specified
92+
(and (string? catalog) (not (str/blank? catalog)))
93+
(conj (str "catalog=" (codec/url-encode catalog))))
9194
qp (str/join "&" params)
9295

9396
;; Full JDBC URL
9497
full-url (str "jdbc:arrow-flight-sql://"
9598
(or host "localhost") ":"
9699
(or port 443)
97100
(when-not (str/blank? qp) (str "?" qp)))]
101+
(log/debug "Arrow Flight SQL connection URL:" full-url)
98102
(let [scheme "jdbc:arrow-flight-sql:"
99103
subname (subs full-url (count scheme))]
100104
{:classname "org.apache.arrow.driver.jdbc.ArrowFlightJdbcDriver"
@@ -115,13 +119,29 @@
115119
;; Executes a simple "SELECT 1" query to verify connectivity.
116120
(defmethod driver/can-connect? :arrow-flight-sql
117121
[driver details]
118-
(try
119-
(sql-jdbc.conn/with-connection-spec-for-testing-connection [spec [driver details]]
120-
(jdbc/query spec "SELECT 1"))
121-
true
122-
(catch Exception e
123-
(log/error e "Flight SQL connection test failed.")
124-
false)))
122+
(let [query-succeeded? (atom false)]
123+
(try
124+
(let [spec (sql-jdbc.conn/connection-details->spec driver details)]
125+
(log/info "Testing connection with spec, attempting to get connection...")
126+
(try
127+
(with-open [conn (jdbc/get-connection spec)]
128+
(log/info "Connection obtained, executing test query...")
129+
(let [result (jdbc/query {:connection conn} ["SELECT 1"])]
130+
(log/info "Test query successful:" result)
131+
(reset! query-succeeded? true)
132+
true))
133+
(catch java.sql.SQLException e
134+
;; If the query succeeded but closing failed (known issue with Flight SQL + catalog param),
135+
;; treat as successful connection
136+
(if @query-succeeded?
137+
(do
138+
(log/warn "Connection close failed but query succeeded, treating as success:" (.getMessage e))
139+
true)
140+
(throw e)))))
141+
(catch Exception e
142+
(log/error e "Flight SQL connection test failed.")
143+
false))))
144+
125145

126146
;; ----------------------------------------------------------------
127147
;; Map raw database types to Metabase base types.
@@ -183,27 +203,42 @@
183203
;; Custom Schema Sync Implementations
184204
;; ----------------------------------------------------------------
185205

206+
;; Helper function to safely close connections when catalog parameter is used
207+
(defn- safely-close-connection [conn]
208+
(try
209+
(.close conn)
210+
(catch java.sql.SQLException e
211+
(when-not (re-find #"Channel shutdown" (.getMessage e))
212+
(throw e))
213+
;; Log but ignore "Channel shutdown" errors during close
214+
(log/debug "Ignoring connection close error (known Flight SQL issue with catalog param):" (.getMessage e)))))
215+
216+
186217
;; List tables by querying information_schema.tables.
187218
(defmethod driver/describe-database :arrow-flight-sql
188219
[driver database]
189-
(let [spec (sql-jdbc.conn/connection-details->spec :arrow-flight-sql (:details database))]
190-
(with-open [conn (jdbc/get-connection spec)]
220+
(let [spec (sql-jdbc.conn/connection-details->spec :arrow-flight-sql (:details database))
221+
conn (jdbc/get-connection spec)]
222+
(try
191223
(let [rows (jdbc/query {:connection conn}
192-
["SELECT table_name, table_schema FROM information_schema.tables"]
224+
["SELECT table_name, table_schema FROM information_schema.tables WHERE table_catalog = CURRENT_CATALOG()"]
193225
{:identifiers str/lower-case})
194226
formatted (->> rows
195227
(filter #(not= (str/lower-case (:table_schema %)) "information_schema"))
196228
(map (fn [row]
197229
{:name (:table_name row)
198230
:schema (:table_schema row)})))]
199-
{:tables (into #{} formatted)})))) ;; Return a set of formatted table information
231+
{:tables (into #{} formatted)})
232+
(finally
233+
(safely-close-connection conn)))))
200234

201235
;; ----------------------------------------------------------------
202236
;; Describe a specific table by executing a DESCRIBE query.
203237
(defmethod driver/describe-table :arrow-flight-sql
204238
[_ driver database {:keys [name schema]}]
205-
(let [spec (sql-jdbc.conn/connection-details->spec :arrow-flight-sql (:details database))]
206-
(with-open [conn (jdbc/get-connection spec)]
239+
(let [spec (sql-jdbc.conn/connection-details->spec :arrow-flight-sql (:details database))
240+
conn (jdbc/get-connection spec)]
241+
(try
207242
(let [query (format "DESCRIBE \"%s\".\"%s\"" schema name) ;; Build the DESCRIBE query using schema and table name
208243
results (jdbc/query {:connection conn} [query] {:identifiers str/lower-case})
209244
fields (mapv (fn [{:keys [column_name data_type is_nullable]}]
@@ -221,7 +256,9 @@
221256
(log/info "Parsed fields:" fields)
222257
{:name name
223258
:schema schema
224-
:fields fields}))))
259+
:fields fields})
260+
(finally
261+
(safely-close-connection conn)))))
225262

226263
;; ----------------------------------------------------------------
227264
;; Define a method to describe table foreign keys.
@@ -237,13 +274,14 @@
237274
(defmethod sql-jdbc.sync/describe-fields-sql :arrow-flight-sql
238275
[driver & {:keys [schema-names table-names details]}]
239276
(let [base-condition [:>= [:inline 1] [:inline 1]]
277+
catalog-condition [:= :table_catalog [:raw "CURRENT_CATALOG()"]]
240278
schema-condition (when (seq schema-names)
241279
[:in [:lower :table_schema]
242280
(mapv (fn [s] [:inline (str/lower-case s)]) schema-names)])
243281
table-condition (when (seq table-names)
244282
[:in [:lower :table_name]
245283
(mapv (fn [t] [:inline (str/lower-case t)]) table-names)])
246-
where-clause (cond-> [base-condition]
284+
where-clause (cond-> [base-condition catalog-condition]
247285
schema-condition (conj schema-condition)
248286
table-condition (conj table-condition))]
249287
(sql/format

0 commit comments

Comments
 (0)