44 (:require [clojure.java.jdbc :as jdbc]
55 [clojure.string :as str]
66 [clojure.tools.logging :as log]
7- [honeysql [core :as hsql] [format :as hformat] ]
7+ [honey.sql :as sql ]
88 [java-time :as t]
99 [medley.core :as m]
1010 [metabase [config :as config] [driver :as driver] [util :as u]]
1111 [metabase.driver.ddl.interface :as ddl.i]
12+ [metabase.driver.sql :as driver.sql]
1213 [metabase.driver.sql.util :as sql.u]
1314 [metabase.driver.sql-jdbc [common :as sql-jdbc.common]
1415 [connection :as sql-jdbc.conn] [execute :as sql-jdbc.execute]
1819 [metabase.driver.sql-jdbc.sync.common :as common]
1920 [metabase.driver.sql-jdbc.execute.legacy-impl :as legacy]
2021 [metabase.driver.sql-jdbc.sync.interface :as i]
21- [metabase.mbql.schema :as mbql.s]
22- [metabase.mbql.util :as mbql.u]
22+ [metabase.util.honey-sql-2 :as h2x]
2323 [metabase.util.date-2 :as u.date]
24- [metabase.util.honeysql-extensions :as hx]
2524 [metabase.util.ssh :as ssh]
2625 [schema.core :as s])
2726
7877
7978(def ^:private default-connection-details
8079 {:classname " com.databend.jdbc.DatabendDriver" , :subprotocol " databend" , :user " root" , :password " root" , :dbname " default" ,:host " localhost" , :port " 8000" , :ssl false })
81- (def ^:private product-name " metabase/1.4.0" )
82-
83- (defmethod sql-jdbc.conn /connection-details->spec :databend
84- [_ details]
80+ (def ^:private product-name " metabase/1.4.1" )
81+ (defn- connection-details->spec* [details]
8582 ; ; ensure defaults merge on top of nils
8683 (let [details (reduce-kv (fn [m k v] (assoc m k (or v (k default-connection-details ))))
8784 default-connection-details
9996 (sql-jdbc.common/handle-additional-options details :separator-style :url ))
10097 ))
10198
99+ (defmethod sql-jdbc.conn /connection-details->spec :databend
100+ [_ details]
101+ (connection-details->spec* details))
102102
103103; Testing the databend database connection
104- (defmethod driver /can-connect? :databend [driver details]
105- (let [connection (sql-jdbc.conn/connection-details->spec driver (ssh/include-ssh-tunnel! details))]
106- (= 1 (first (vals (first (jdbc/query connection [" SELECT 1" ])))))))
104+ (defmethod driver /can-connect? :databend
105+ [driver details]
106+ (if config/is-test?
107+ (try
108+ ; ; Default SELECT 1 is not enough for Metabase test suite,
109+ ; ; as it works slightly differently than expected there
110+ (let [spec (sql-jdbc.conn/connection-details->spec driver details)
111+ db (or (:dbname details) (:db details) " default" )]
112+ (sql-jdbc.execute/do-with-connection-with-options
113+ driver spec nil
114+ (fn [^java.sql.Connection conn]
115+ (let [stmt (.prepareStatement conn " SELECT count(*) > 0 FROM system.databases WHERE name = ?" )
116+ _ (.setString stmt 1 db)
117+ rset (.executeQuery stmt)]
118+ (when (.next rset)
119+ (.getBoolean rset 1 ))))))
120+ (catch Throwable e
121+ (log/error e " An exception during Databend connectivity check" )
122+ false ))
123+ ; ; During normal usage, fall back to the default implementation
124+ (sql-jdbc.conn/can-connect? driver details)))
107125
108126
109127(def ^:private allowed-table-types
184202
185203(defn- to-start-of-year
186204 [expr]
187- ( hsql/call : to_start_of_year ( hsql/call :TO_DATETIME expr)) )
205+ [:' to_start_of_year expr] )
188206
189207(defn- to-day-of-year
190208 [expr]
191- ( hsql/call : to_day_of_year ( hsql/call :TO_DATETIME expr)) )
209+ [:' to_day_of_year expr] )
192210
193211
194212(defn- to-start-of-week
195213 [expr]
196214 ; ; The first day of a week can be Sunday or Monday, which is specified by the argument mode.
197215 ; ; Here we use Sunday as default
198- ( hsql/call : to_start_of_week expr) )
216+ [:' to_start_of_week expr] )
199217
200218(defn- to-start-of-minute
201219 [expr]
202- ( hsql/call : to_start_of_minute ( hsql/call :TO_DATETIME expr)) )
220+ [:' to_start_of_minute expr] )
203221
204222(defn- to-start-of-hour
205223 [expr]
206- ( hsql/call : to_start_of_hour ( hsql/call :TO_DATETIME expr)) )
224+ [:' to_start_of_hour expr] )
207225
208- (defn- to-hour [expr] ( hsql/call : to_hour ( hsql/call :TO_DATETIME expr)) )
226+ (defn- to-hour [expr] [:' to_hour expr] )
209227
210- (defn- to-minute [expr] ( hsql/call : to_minute ( hsql/call :TO_DATETIME expr)) )
228+ (defn- to-minute [expr] [:' to_minute expr] )
211229
212- (defn- to-day [expr] (hsql/call :to_date expr))
213230
214231(defmethod sql.qp /date [:databend :day-of-week ]
215232 [_ _ expr]
216- (sql.qp/adjust-day-of-week :databend ( hsql/call : to_day_of_week expr) ))
233+ (sql.qp/adjust-day-of-week :databend [:' to_day_of_week expr] ))
217234
218235(defn- to-day-of-month
219236 [expr]
220- ( hsql/call : to_day_of_month ( hsql/call :TO_DATETIME expr)) )
237+ [:' to_day_of_month expr] )
221238
222239(defn- to-start-of-month
223240 [expr]
224- ( hsql/call : to_start_of_month ( hsql/call :TO_DATETIME expr)) )
241+ [:' to_start_of_month expr] )
225242
226243(defn- to-start-of-quarter
227244 [expr]
228- ( hsql/call : to_start_of_quarter ( hsql/call :TO_DATETIME expr)) )
245+ [:' to_start_of_quarter expr] )
229246
230247(defmethod sql.qp /date [:databend :default ] [_ _ expr] expr )
231248(defmethod sql.qp /date [:databend :minute ]
232249 [_ _ expr]
233250 (to-start-of-minute expr))
234251
235- ; Return an appropriate HoneySQL form for converting a Unix timestamp integer field or value to a proper SQL Timestamp.
236- ; (defmethod sql.qp/unix-timestamp->honeysql [:databend :seconds] [_ _ expr] (hsql/call :to_timestamp expr))
237-
238252(defmethod sql.qp /date [:databend :minute-of-hour ]
239253 [_ _ expr]
240254 (to-minute expr))
249263(defmethod sql.qp /date [:databend :month ] [_ _ expr] (to-start-of-month expr))
250264(defmethod sql.qp /date [:databend :year ] [_ _ expr] (to-start-of-year expr))
251265
252- (defmethod sql.qp /date [:databend :day ] [_ _ expr] (to-day expr))
253266(defmethod sql.qp /date [:databend :week ]
254267 [driver _ expr]
255268 (sql.qp/adjust-start-of-week driver to-start-of-week expr))
256269(defmethod sql.qp /date [:databend :quarter ]
257270 [_ _ expr]
258271 (to-start-of-quarter expr))
259272
260- ; (defmethod sql.qp/unix-timestamp->honeysql [:databend :seconds]
261- ; [_ _ expr]
262- ; (hsql/call :TO_DATETIME expr))
273+ (defmethod sql.qp /unix-timestamp->honeysql [:databend :seconds ]
274+ [_ _ expr]
275+ (h2x/->datetime expr))
263276
264277(defmethod unprepare /unprepare-value [:databend LocalDate]
265278 [_ t]
288301
289302(defmethod sql.qp /->honeysql [:databend :log ]
290303 [driver [_ field]]
291- (hsql/call :log10 (sql.qp/->honeysql driver field)))
292-
293- (defmethod hformat /fn-handler " quantile"
294- [_ field p]
295- (str " quantile(" (hformat/to-sql p) " )(" (hformat/to-sql field) " )" ))
304+ [:'log10 (sql.qp/->honeysql driver field)])
296305
297306; call REGEXP_SUBSTR function when regex-match-first is called
298307(defmethod sql.qp /->honeysql [:databend :regex-match-first ]
299308 [driver [_ arg pattern]]
300- (let [arg-sql (hformat/to-sql (sql.qp/->honeysql driver arg))
301- pattern-sql (sql.u/escape-sql (sql.qp/->honeysql driver pattern) :ansi )
302- sql-string (str " REGEXP_SUBSTR(" arg-sql " , '" pattern-sql " ')" )]
303- (hsql/raw sql-string)))
309+ [:'extract (sql.qp/->honeysql driver arg) pattern])
310+
311+ (defmethod sql.qp /->honeysql [:databend :stddev ]
312+ [driver [_ field]]
313+ [:'stddevPop (sql.qp/->honeysql driver field)])
304314
315+ (defmethod sql.qp /->honeysql [:databend :median ]
316+ [driver [_ field]]
317+ [:'median (sql.qp/->honeysql driver field)])
318+
319+ (defn- args->float64
320+ [args]
321+ (map (fn [arg] [:'to_float64 (sql.qp/->honeysql :databend arg)]) args))
322+
323+ (defmethod sql.qp /->float :databend
324+ [_ value]
325+ [:'to_float64 value])
326+ (defmethod sql.qp /->honeysql [:databend :substring ]
327+ [driver [_ arg start length]]
328+ (let [str [:'toString (sql.qp/->honeysql driver arg)]]
329+ (if length
330+ [:'substr str
331+ (sql.qp/->honeysql driver start)
332+ (sql.qp/->honeysql driver length)]
333+ [:'substr str
334+ (sql.qp/->honeysql driver start)])))
305335
306336; ; metabase.query-processor-test.count-where-test
307337; ; metabase.query-processor-test.share-test
308338(defmethod sql.qp /->honeysql [:databend :count-where ]
309339 [driver [_ pred]]
310- (hsql/call :case
311- (hsql/call :>
312- (hsql/call :count ) 0 )
313- (hsql/call :sum
314- (hsql/call :case (sql.qp/->honeysql driver pred) 1.0 :else 0.0 ))
315- :else nil ))
340+ [:case
341+ [:> [:'count] 0 ]
342+ [:sum [:case (sql.qp/->honeysql driver pred) 1 :else 0 ]]
343+ :else nil ])
344+
316345
317346(defmethod sql.qp /quote-style :databend [_] :mysql )
318347
319348(defmethod sql.qp /add-interval-honeysql-form :databend
320349 [_ dt amount unit]
321- (hx/+ (hx/->timestamp dt)
322- (hsql/raw (format " INTERVAL %d %s" (int amount) (name unit)))))
323-
324- ; ; The following lines make sure we call lowerUTF8 instead of lower
325- (defn- databend-like-clause
326- [driver field value options]
327- (if (get options :case-sensitive true )
328- [:like field (sql.qp/->honeysql driver value)]
329- [:like (hsql/call :lowerUTF8 field)
330- (sql.qp/->honeysql driver (update value 1 str/lower-case))]))
331-
332- (s/defn ^:private update-string-value :- mbql.s /value
333- [value :- (s/constrained mbql.s/value #(string? (second %)) " string value" ) f]
334- (update value 1 f))
335-
336- (defmethod sql.qp /->honeysql [:databendd :starts-with ]
337- [driver [_ field value options]]
338- (databend-like-clause driver
339- (sql.qp/->honeysql driver field)
340- (update-string-value value #(str % \%))
341- options))
342-
343- (defmethod sql.qp /->honeysql [:databend :contains ]
344- [driver [_ field value options]]
345- (databend-like-clause driver
346- (sql.qp/->honeysql driver field)
347- (update-string-value value #(str \% % \%))
348- options))
349-
350- (defmethod sql.qp /->honeysql [:databend :ends-with ]
351- [driver [_ field value options]]
352- (databend-like-clause driver
353- (sql.qp/->honeysql driver field)
354- (update-string-value value #(str \% %))
355- options))
350+ (h2x/+ dt [:raw (format " INTERVAL %d %s" (int amount) (name unit))]))
356351
357352
358353(defmethod sql.qp /cast-temporal-byte [:databend :Coercion/ISO8601->Time ]
359354 [_driver _special_type expr]
360- (hx /->timestamp expr))
355+ (h2x /->timestamp expr))
361356
362- ; (defmethod sql-jdbc.execute/read-column-thunk [:databend Types/TIMESTAMP]
363- ; [_ ^ResultSet rs ^ResultSetMetaData _ ^Integer i]
364- ; (fn []
365- ; (let [r (.getObject rs i LocalDateTime)]
366- ; (cond (nil? r) nil
367- ; (= (.toLocalDate r) (t/local-date 1970 1 1)) (.toLocalTime r)
368- ; :else r))))
369357
370358(defmethod sql-jdbc.execute /read-column-thunk [:databend Types/TIMESTAMP_WITH_TIMEZONE]
371359 [_ ^ResultSet rs ^ResultSetMetaData _ ^Integer i]
405393
406394(defmethod driver /display-name :databend [_] " Databend" )
407395
408- (defmethod driver /supports? [:databend :standard-deviation-aggregations ] [_ _] true )
409- (defmethod driver /supports? [:databend :set-timezone ] [_ _] true )
410- (defmethod driver /supports? [:databend :foreign-keys ] [_ _] false )
411- (defmethod driver /supports? [:databend :test/jvm-timezone-setting ] [_ _] false )
396+ (doseq [[feature supported?] {:standard-deviation-aggregations true
397+ :foreign-keys false
398+ :set-timezone false
399+ :convert-timezone false
400+ :test/jvm-timezone-setting false
401+ :connection-impersonation false
402+ :schemas true
403+ :datetime-diff true
404+ :upload-with-auto-pk false }]
405+
406+ (defmethod driver /database-supports? [:databend feature] [_driver _feature _db] supported? ))
412407
413408(defmethod sql-jdbc.sync /db-default-timezone :databend
414409 [_ spec]
420415
421416(defmethod ddl.i /format-name :databend [_ table-or-field-name]
422417 (str/replace table-or-field-name #"-" " _" ))
418+
419+ (defmethod driver.sql /set-role-statement :databend
420+ [_ role]
421+ (format " SET ROLE %s;" role))
0 commit comments