|
4 | 4 | [string :as str]] |
5 | 5 | [clojure.java.jdbc :as jdbc] |
6 | 6 | [honeysql.core :as hsql] |
| 7 | + [honeysql.format :as hformat] |
7 | 8 | [java-time :as t] |
8 | 9 | [metabase.driver :as driver] |
9 | 10 | [metabase.driver.common :as driver.common] |
| 11 | + ;; [metabase.driver.sql-jdbc.sync.describe-database :as sql-jdbc.sync.describe-database] |
10 | 12 | [metabase.driver.sql-jdbc |
11 | 13 | [common :as sql-jdbc.common] |
12 | 14 | [connection :as sql-jdbc.conn] |
13 | 15 | [sync :as sql-jdbc.sync]] |
| 16 | + [metabase.driver.sql-jdbc.sync.common :as sql-jdbc.sync.common] |
14 | 17 | [metabase.driver.sql.query-processor :as sql.qp] |
15 | 18 | [metabase.util |
16 | | - [honeysql-extensions :as hx] |
17 | | - [ssh :as ssh]]) |
| 19 | + [honeysql-extensions :as hx]] |
| 20 | + [metabase.util.ssh :as ssh]) |
18 | 21 | (:import [java.sql DatabaseMetaData Time] |
19 | | - [java.time LocalDate LocalDateTime LocalTime OffsetDateTime OffsetTime ZonedDateTime])) |
| 22 | + [java.time LocalDate LocalDateTime LocalTime OffsetDateTime OffsetTime ZonedDateTime] |
| 23 | + [java.sql Connection DatabaseMetaData ResultSet])) |
| 24 | + |
20 | 25 |
|
21 | 26 | (driver/register! :firebird, :parent :sql-jdbc) |
22 | 27 |
|
|
42 | 47 | (sql-jdbc.common/handle-additional-options details))) |
43 | 48 |
|
44 | 49 | (defmethod driver/can-connect? :firebird [driver details] |
45 | | - (let [connection (sql-jdbc.conn/connection-details->spec driver (ssh/include-ssh-tunnel details))] |
| 50 | + (let [connection (sql-jdbc.conn/connection-details->spec driver (ssh/include-ssh-tunnel! details))] |
46 | 51 | (= 1 (first (vals (first (jdbc/query connection ["SELECT 1 FROM RDB$DATABASE"]))))))) |
47 | 52 |
|
48 | 53 | ;; Use pattern matching because some parameters can have a length parameter, e.g. VARCHAR(255) |
|
80 | 85 | items |
81 | 86 | (* items (dec page)))])) |
82 | 87 |
|
| 88 | + |
| 89 | +;; When selecting constants Firebird doesn't check privileges, we have to select all fields |
| 90 | +(defn simple-select-probe-query |
| 91 | + [driver schema table] |
| 92 | + {:pre [(string? table)]} |
| 93 | + (let [honeysql {:select [:*] |
| 94 | + :from [(sql.qp/->honeysql driver (hx/identifier :table schema table))] |
| 95 | + :where [:not= 1 1]} |
| 96 | + honeysql (sql.qp/apply-top-level-clause driver :limit honeysql {:limit 0})] |
| 97 | + (sql.qp/format-honeysql driver honeysql))) |
| 98 | + |
| 99 | +(defn- execute-select-probe-query |
| 100 | + [driver ^Connection conn [sql & params]] |
| 101 | + {:pre [(string? sql)]} |
| 102 | + (with-open [stmt (sql-jdbc.sync.common/prepare-statement driver conn sql params)] |
| 103 | + ;; attempting to execute the SQL statement will throw an Exception if we don't have permissions; otherwise it will |
| 104 | + ;; truthy wheter or not it returns a ResultSet, but we can ignore that since we have enough info to proceed at |
| 105 | + ;; this point. |
| 106 | + (.execute stmt))) |
| 107 | + |
| 108 | +(defmethod sql-jdbc.sync/have-select-privilege? :sql-jdbc |
| 109 | + [driver conn table-schema table-name] |
| 110 | + ;; Query completes = we have SELECT privileges |
| 111 | + ;; Query throws some sort of no permissions exception = no SELECT privileges |
| 112 | + (let [sql-args (simple-select-probe-query driver table-schema table-name)] |
| 113 | + (try |
| 114 | + (execute-select-probe-query driver conn sql-args) |
| 115 | + true |
| 116 | + (catch Throwable _ |
| 117 | + false)))) |
| 118 | + |
83 | 119 | (defmethod sql-jdbc.sync/active-tables :firebird [& args] |
84 | 120 | (apply sql-jdbc.sync/post-filtered-active-tables args)) |
85 | 121 |
|
|
153 | 189 | (defmethod sql.qp/date [:firebird :quarter-of-year] [_ _ expr] (hx/+ (hx// (hx/- (hsql/call :extract :MONTH expr) 1) 3) 1)) |
154 | 190 | (defmethod sql.qp/date [:firebird :year] [_ _ expr] (hsql/call :extract :YEAR expr)) |
155 | 191 |
|
| 192 | +;; Firebird 2.x doesn't support TRUE/FALSE, replacing them with 1 and 0 |
| 193 | +(defmethod sql.qp/->honeysql [:firebird Boolean] [_ bool] (if bool 1 0)) |
| 194 | + |
| 195 | +;; Firebird 2.x doesn't support SUBSTRING arugments seperated by commas, but uses FROM and FOR keywords |
| 196 | +(defmethod sql.qp/->honeysql [:firebird :substring] |
| 197 | + [driver [_ arg start length]] |
| 198 | + (let [col-name (hformat/to-sql (sql.qp/->honeysql driver arg))] |
| 199 | + (if length |
| 200 | + (reify |
| 201 | + hformat/ToSql |
| 202 | + (to-sql [_] |
| 203 | + (str "substring(" col-name " FROM " start " FOR " length ")"))) |
| 204 | + (reify |
| 205 | + hformat/ToSql |
| 206 | + (to-sql [_] |
| 207 | + (str "substring(" col-name " FROM " start ")")))))) |
| 208 | + |
156 | 209 | (defmethod sql.qp/add-interval-honeysql-form :firebird [driver hsql-form amount unit] |
157 | 210 | (if (= unit :quarter) |
158 | 211 | (recur driver hsql-form (hx/* amount 3) :month) |
|
0 commit comments