Skip to content
Snippets Groups Projects
Commit 85b6b546 authored by Cam Saül's avatar Cam Saül
Browse files

Merge pull request #344 from metabase/native_timezones

thou can setteth thy timezones
parents 889b2912 662c88ad
No related branches found
No related tags found
No related merge requests found
......@@ -66,7 +66,8 @@
[lein-bikeshed "0.2.0"] ; Linting
[lein-expectations "0.0.8"] ; run unit tests with 'lein expectations'
[lein-instant-cheatsheet "2.1.1"] ; use awesome instant cheatsheet created by yours truly w/ 'lein instant-cheatsheet'
[lein-marginalia "0.8.0"]] ; generate documentation with 'lein marg'
[lein-marginalia "0.8.0"] ; generate documentation with 'lein marg'
[refactor-nrepl "1.0.1"]] ; support for advanced refactoring in Emacs/LightTable
:jvm-opts ["-Dlogfile.path=target/log"
"-Xms1024m" ; give JVM a decent heap size to start with
"-Xmx2048m" ; hard limit of 2GB so we stop hitting the 4GB container limit on CircleCI
......
......@@ -3,13 +3,13 @@
(:import com.metabase.corvus.api.ApiException)
(:require [clojure.java.jdbc :as jdbc]
[clojure.tools.logging :as log]
[korma.core :as korma]
korma.db
(korma [core :as korma]
db)
[metabase.db :refer [sel]]
[metabase.driver.generic-sql.util :refer :all]
[metabase.models.database :refer [Database]]))
(def class->base-type
(def ^:const class->base-type
"Map of classes returned from DB call to metabase.models.field/base-types"
{java.lang.Boolean :BooleanField
java.lang.Double :FloatField
......@@ -22,6 +22,18 @@
java.sql.Date :DateField
java.sql.Timestamp :DateTimeField})
(def ^:dynamic *timezone->set-timezone-sql*
" This function is called whenever `timezone` is specified in a native query, at the beginning of
the DB transaction.
If implemented, it should take a timestamp like `\"US/Pacific\"` and return a SQL
string that can be executed to set the timezone within the context of a transaction,
e.g. `\"SET LOCAL timezone to 'US/Pacific'\"`.
Because not all DB engines support timestamps (e.g., H2), the default implementation is a no-op.
Engines that *do* support timestamps (e.g., Postgres) should override this function."
(fn [_]))
(defn- value->base-type
"Attempt to match a value we get back from the DB with the corresponding base-type`."
[v]
......@@ -29,6 +41,7 @@
(or (class->base-type (type v))
(throw (ApiException. (int 500) (format "Missing base type mapping for %s in metabase.driver.generic-sql.native/class->base-type. Please add an entry."
(str (type v))))))))
(defn process-and-run
"Process and run a native (raw SQL) QUERY."
{:arglists '([query])}
......@@ -36,11 +49,18 @@
database-id :database :as query}]
{:pre [(string? sql)
(integer? database-id)]}
(log/debug "QUERY: " query)
(log/debug "QUERY: \n"
(with-out-str (clojure.pprint/pprint query)))
(try (let [db (-> (sel :one Database :id database-id)
korma-db
korma.db/get-connection)
[columns & [first-row :as rows]] (jdbc/query db sql :as-arrays? true)]
[columns & [first-row :as rows]] (jdbc/with-db-transaction [conn db :read-only? true]
;; If timezone is specified in the Query and the driver supports setting the timezone then execute SQL to set it
(when-let [timezone (-> query :native :timezone)]
(when-let [set-timezone-sql (*timezone->set-timezone-sql* timezone)]
(log/debug "Setting timezone to:" timezone)
(jdbc/db-do-prepared conn set-timezone-sql)))
(jdbc/query conn sql :as-arrays? true))]
{:status :completed
:row_count (count rows)
:data {:rows rows
......@@ -55,3 +75,7 @@
(re-find #"^(.*);") ; the user already knows the SQL, and error code is meaningless
second) ; so just return the part of the exception that is relevant
(.getMessage e))})))
(def db (delay (-> (sel :one Database :id 1)
korma-db
korma.db/get-connection)))
......@@ -19,7 +19,7 @@
query-is-cumulative-sum?
apply-cumulative-sum)
(def ^{:dynamic true, :private true} *query*
(def ^:dynamic ^:private *query*
"Query dictionary that we're currently processing"
nil)
......
(ns metabase.driver.postgres.query-processor
(:require [metabase.driver.generic-sql.query-processor :as generic]
(:require (metabase.driver.generic-sql [native :as native]
[query-processor :as generic])
[metabase.driver :refer [process-and-run]]))
(defmethod process-and-run :postgres [query]
(generic/process-and-run query))
(binding [native/*timezone->set-timezone-sql* (fn [timezone]
(format "SET LOCAL timezone TO '%s';" timezone))]
(generic/process-and-run query)))
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment