|
5 | 5 | [medley.core :as m] |
6 | 6 | [clojure.tools.logging :as log] |
7 | 7 | [clojure.java.jdbc :as jdbc] |
8 | | - [honeysql.core :as hsql] |
9 | 8 | [java-time :as t] |
10 | 9 | [metabase |
11 | 10 | [driver :as driver] |
|
20 | 19 | [metabase.driver.sql-jdbc.sync.describe-table :as sql-jdbc.describe-table] |
21 | 20 | [metabase.driver.sql.query-processor :as sql.qp] |
22 | 21 | [metabase.driver.sql.util.deduplicate :as deduplicateutil] |
23 | | - [metabase.query-processor.util :as qputil] |
24 | | - [metabase.util |
25 | | - [honeysql-extensions :as hx] |
26 | | - [i18n :refer [trs]]]) |
| 22 | + [metabase.util.i18n :refer [trs]] |
| 23 | + [metabase.util.honey-sql-2 :as h2x]) |
27 | 24 | (:import [java.sql Connection DatabaseMetaData ResultSet Types PreparedStatement] |
28 | 25 | [java.time OffsetDateTime OffsetTime] |
29 | 26 | [java.util Calendar TimeZone])) |
|
86 | 83 | (keyword "timestamp with timezone") :type/DateTime |
87 | 84 | (keyword "timestamp without timezone") :type/DateTime}, column-type)) |
88 | 85 |
|
| 86 | +(defmethod sql.qp/honey-sql-version :teradata |
| 87 | + [_driver] |
| 88 | + 2) |
| 89 | + |
89 | 90 | (defn- dbnames-set |
90 | 91 | "Transform the string of databases to a set of strings." |
91 | 92 | [dbnames] |
|
212 | 213 | teradata-spec |
213 | 214 | (sql-jdbc.common/handle-additional-options details-map, :seperator-style :comma))) |
214 | 215 |
|
215 | | -;; trunc always returns a date in Teradata |
216 | | -(defn- date-trunc [unit expr] (hsql/call :trunc expr (hx/literal unit))) |
217 | | - |
218 | | -(defn- timestamp-trunc [unit expr] (hsql/call :to_timestamp |
219 | | - (hsql/call :to_char |
220 | | - expr |
221 | | - unit) unit)) |
222 | | - |
223 | | -(defn- extract [unit expr] (hsql/call :extract unit expr)) |
224 | | - |
225 | | -(def ^:private extract-integer (comp hx/->integer extract)) |
226 | | - |
227 | | -(def ^:private ^:const one-day (hsql/raw "INTERVAL '1' DAY")) |
228 | | - |
229 | | -(def ^:private ^:const now (hsql/raw "CURRENT_TIMESTAMP")) |
230 | | - |
231 | | -(defmethod sql.qp/date [:teradata :default] [_ _ expr] expr) |
232 | | -(defmethod sql.qp/date [:teradata :minute] [_ _ expr] (timestamp-trunc (hsql/raw "'yyyy-mm-dd hh24:mi'") expr)) |
233 | | -(defmethod sql.qp/date [:teradata :minute-of-hour] [_ _ expr] (extract-integer :minute expr)) |
234 | | -(defmethod sql.qp/date [:teradata :hour] [_ _ expr] (timestamp-trunc (hsql/raw "'yyyy-mm-dd hh24'") expr)) |
235 | | -(defmethod sql.qp/date [:teradata :hour-of-day] [_ _ expr] (extract-integer :hour expr)) |
236 | | -(defmethod sql.qp/date [:teradata :day] [_ _ expr] (hx/->date expr)) |
237 | | -(defmethod sql.qp/date [:teradata :day-of-week] [driver _ expr] (hx/inc (hx/- (sql.qp/date driver :day expr) |
238 | | - (sql.qp/date driver :week expr)))) |
239 | | -(defmethod sql.qp/date [:teradata :day-of-month] [_ _ expr] (extract-integer :day expr)) |
240 | | -(defmethod sql.qp/date [:teradata :day-of-year] [driver _ expr] (hx/inc (hx/- (sql.qp/date driver :day expr) (date-trunc :year expr)))) |
241 | | -(defmethod sql.qp/date [:teradata :week] [_ _ expr] (date-trunc :day expr)) ; Same behaviour as with Oracle. |
242 | | -(defmethod sql.qp/date [:teradata :week-of-year] [_ _ expr] (hx/inc (hx// (hx/- (date-trunc :iw expr) |
243 | | - (date-trunc :iy expr)) |
244 | | - 7))) |
245 | | -(defmethod sql.qp/date [:teradata :month] [_ _ expr] (date-trunc :mm expr)) |
246 | | -(defmethod sql.qp/date [:teradata :month-of-year] [_ _ expr] (extract-integer :month expr)) |
247 | | -(defmethod sql.qp/date [:teradata :quarter] [_ _ expr] (date-trunc :q expr)) |
248 | | -(defmethod sql.qp/date [:teradata :quarter-of-year] [driver _ expr] (hx// (hx/+ (sql.qp/date driver :month-of-year (sql.qp/date driver :quarter expr)) 2) 3)) |
249 | | -(defmethod sql.qp/date [:teradata :year] [_ _ expr] (date-trunc :year expr)) |
| 216 | +(defn- trunc [format-template v] |
| 217 | + [:trunc v (h2x/literal format-template)]) |
| 218 | + |
| 219 | +(def ^:private ^:const one-day [:raw "INTERVAL '1' DAY"]) |
| 220 | + |
| 221 | +(def ^:private ^:const now [:raw "CURRENT_TIMESTAMP"]) |
| 222 | + |
| 223 | +(defmethod sql.qp/date [:teradata :default] [_ _ expr] expr) |
| 224 | +(defmethod sql.qp/date [:teradata :minute] [_ _ expr] (:to_timestamp (:raw "'yyyy-mm-dd hh24:mi'") expr)) |
| 225 | +(defmethod sql.qp/date [:teradata :minute-of-hour] [_ _ expr] [::h2x/extract :minute expr]) |
| 226 | +(defmethod sql.qp/date [:teradata :hour] [_ _ expr] (:to_timestamp (:raw "'yyyy-mm-dd hh24'") expr)) |
| 227 | +(defmethod sql.qp/date [:teradata :hour-of-day] [_ _ expr] [::h2x/extract :hour expr]) |
| 228 | +(defmethod sql.qp/date [:teradata :day] [_ _ expr] (h2x/->date expr)) |
| 229 | +(defmethod sql.qp/date [:teradata :day-of-week] [driver _ expr] (h2x/inc (h2x/- (sql.qp/date driver :day expr) |
| 230 | + (sql.qp/date driver :week expr)))) |
| 231 | +(defmethod sql.qp/date [:teradata :day-of-month] [_ _ expr] [::h2x/extract :day expr]) |
| 232 | +(defmethod sql.qp/date [:teradata :day-of-year] [driver _ expr] (h2x/inc (h2x/- (sql.qp/date driver :day expr) (trunc :year expr)))) |
| 233 | +(defmethod sql.qp/date [:teradata :week] [_ _ expr] (trunc :day expr)) ; Same behaviour as with Oracle. |
| 234 | +(defmethod sql.qp/date [:teradata :week-of-year] [_ _ expr] (h2x/inc (h2x// (h2x/- (trunc :iw expr) |
| 235 | + (trunc :iy expr)) |
| 236 | + 7))) |
| 237 | +(defmethod sql.qp/date [:teradata :month] [_ _ expr] (trunc :month expr)) |
| 238 | +(defmethod sql.qp/date [:teradata :month-of-year] [_ _ expr] [::h2x/extract :month expr]) |
| 239 | +(defmethod sql.qp/date [:teradata :quarter] [_ _ expr] (trunc :q expr)) |
| 240 | +(defmethod sql.qp/date [:teradata :quarter-of-year] [driver _ expr] (h2x// (h2x/+ (sql.qp/date driver :month-of-year (sql.qp/date driver :quarter expr)) 2) 3)) |
| 241 | +(defmethod sql.qp/date [:teradata :year] [_ _ expr] (trunc :year expr)) |
250 | 242 |
|
251 | 243 | (defn- num-to-interval [unit amount] |
252 | | - (hsql/raw (format "INTERVAL '%d' %s" (int (Math/abs amount)) (name unit)))) |
| 244 | + [:raw (format "INTERVAL '%d' %s" (int (Math/abs amount)) (name unit))]) |
253 | 245 |
|
254 | 246 | (defmethod sql.qp/add-interval-honeysql-form :teradata [_ hsql-form amount unit] |
255 | | - (let [op (if (>= amount 0) hx/+ hx/-)] |
256 | | - (op (if |
257 | | - (= unit :month) |
258 | | - (date-trunc :month hsql-form) |
259 | | - (hx/->timestamp hsql-form)) |
260 | | - (case unit |
261 | | - :second (num-to-interval :second amount) |
262 | | - :minute (num-to-interval :minute amount) |
263 | | - :hour (num-to-interval :hour amount) |
264 | | - :day (num-to-interval :day amount) |
265 | | - :week (num-to-interval :day (* amount 7)) |
266 | | - :month (num-to-interval :month amount) |
267 | | - :quarter (num-to-interval :month (* amount 3)) |
268 | | - :year (num-to-interval :year amount))))) |
| 247 | + (let [op (if (>= amount 0) h2x/+ h2x/-)] |
| 248 | + (op (if (= unit :month) |
| 249 | + (trunc :month hsql-form) |
| 250 | + (h2x/->timestamp hsql-form)) |
| 251 | + (case unit |
| 252 | + :second (num-to-interval :second amount) |
| 253 | + :minute (num-to-interval :minute amount) |
| 254 | + :hour (num-to-interval :hour amount) |
| 255 | + :day (num-to-interval :day amount) |
| 256 | + :week (num-to-interval :day (* amount 7)) |
| 257 | + :month (num-to-interval :month amount) |
| 258 | + :quarter (num-to-interval :month (* amount 3)) |
| 259 | + :year (num-to-interval :year amount))))) |
| 260 | + |
| 261 | +(def ^:private timestamp-types |
| 262 | + #{"timestamp" "timestamp with time zone" "timestamp with local time zone"}) |
269 | 263 |
|
270 | 264 | (defmethod sql.qp/unix-timestamp->honeysql [:teradata :seconds] [_ _ field-or-value] |
271 | | - (hsql/call :to_timestamp field-or-value)) |
| 265 | + (:to_timestamp field-or-value)) |
272 | 266 |
|
273 | 267 | (defmethod sql.qp/unix-timestamp->honeysql [:teradata :milliseconds] [_ _ field-or-value] |
274 | | - (sql.qp/unix-timestamp->honeysql (hx// field-or-value 1000) :seconds)) |
| 268 | + (sql.qp/unix-timestamp->honeysql (h2x// field-or-value 1000) :seconds)) |
275 | 269 |
|
276 | | -(defmethod sql.qp/apply-top-level-clause [:teradata :limit] [_ _ honeysql-form {value :limit}] |
277 | | - (update (assoc honeysql-form :modifiers [(format "TOP %d" value)]) :select deduplicateutil/deduplicate-identifiers)) |
| 270 | +(defmethod sql.qp/apply-top-level-clause [:teradata :limit] |
| 271 | + [_ _ honeysql-form {value :limit}] |
| 272 | + (update honeysql-form :select deduplicateutil/deduplicate-identifiers) |
| 273 | + ) |
278 | 274 |
|
279 | 275 | (defmethod sql.qp/apply-top-level-clause [:teradata :page] [_ _ honeysql-form {{:keys [items page]} :page}] |
280 | | - (assoc honeysql-form :offset (hsql/raw (format "QUALIFY ROW_NUMBER() OVER (%s) BETWEEN %d AND %d" |
281 | | - (first (hsql/format (select-keys honeysql-form [:order-by]) |
| 276 | + (assoc honeysql-form :offset (:raw (format "QUALIFY ROW_NUMBER() OVER (%s) BETWEEN %d AND %d" |
| 277 | + (first (format (select-keys honeysql-form [:order-by]) |
282 | 278 | :allow-dashed-names? true |
283 | 279 | :quoting :ansi)) |
284 | 280 | (inc (* items (dec page))) |
|
386 | 382 |
|
387 | 383 | (defmethod driver/execute-reducible-query :teradata |
388 | 384 | [driver query context respond] |
389 | | - ((get-method driver/execute-reducible-query :sql-jdbc) driver (cleanup-query query) context respond)) |
| 385 | + ( |
| 386 | + (get-method driver/execute-reducible-query :sql-jdbc) driver (cleanup-query query) context respond) |
| 387 | + ) |
390 | 388 |
|
391 | 389 | (defmethod sql.qp/current-datetime-honeysql-form :teradata [_] now) |
392 | 390 |
|
|
0 commit comments