Skip to content

Commit 922e228

Browse files
authored
Merge pull request #3 from BLACKBUCK-LABS/set_limit_native_query
[Metabase v0.36.7] Blackbuck metabase changes
2 parents d7d3248 + 750e6f2 commit 922e228

File tree

3 files changed

+73
-21
lines changed

3 files changed

+73
-21
lines changed

frontend/src/metabase/query_builder/components/QueryDownloadWidget.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import * as Urls from "metabase/lib/urls";
1616
import _ from "underscore";
1717
import cx from "classnames";
1818

19-
const EXPORT_FORMATS = ["csv", "xlsx", "json"];
19+
const EXPORT_FORMATS = ["csv", "json"];
2020

2121
const QueryDownloadWidget = ({
2222
className,

src/metabase/query_processor/interface.clj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
1010
This is coming directly from the max rows allowed by Excel for now ...
1111
https://support.office.com/en-nz/article/Excel-specifications-and-limits-1672b34d-7043-467e-8e27-269d656771c3"
12-
1048576)
12+
100000)
1313

1414
;; TODO - maybe we should do this more generally with the help of a macro like `do-with-suppressed-output` from the
1515
;; test utils, perhaps implemented as separate middleware (and using a `:middleware` option). Or perhaps even make QP

src/metabase/query_processor/middleware/process_userland_query.clj

Lines changed: 71 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
(:require [clojure.tools.logging :as log]
66
[java-time :as t]
77
[metabase.models
8+
[database :refer [Database]]
89
[query :as query]
910
[query-execution :as query-execution :refer [QueryExecution]]]
1011
[metabase.query-processor.util :as qputil]
@@ -32,7 +33,7 @@
3233
(query/save-query-and-update-average-execution-time! query query-hash running-time)
3334
(if-not context
3435
(log/warn (trs "Cannot save QueryExecution, missing :context"))
35-
(db/insert! QueryExecution (dissoc query-execution :json_query))))
36+
(db/insert! QueryExecution (dissoc query-execution :json_query :original_query_stmt))))
3637

3738
(defn- save-query-execution!
3839
"Save a `QueryExecution` row containing `execution-info`. Done asynchronously when a query is finished."
@@ -63,12 +64,25 @@
6364
;;; | Middleware |
6465
;;; +----------------------------------------------------------------------------------------------------------------+
6566

67+
(defn result-with-original-query
68+
"Modify result with original query (ie. query without modification(done by add-limit-query).
69+
This is done as this raw query is used for json and csv download"
70+
[result, query-execution-info]
71+
(if (and (get-in query-execution-info[:native]) (some? (get-in query-execution-info[:original_query_stmt])))
72+
(-> result
73+
(assoc-in [:data :native_form :query] (get-in query-execution-info [:original_query_stmt]))
74+
(assoc-in [:json_query :native :query] (get-in query-execution-info [:original_query_stmt]))
75+
)
76+
result
77+
)
78+
)
79+
6680
(defn- success-response [{query-hash :hash, :as query-execution} {cached? :cached, :as result}]
6781
(merge
82+
(result-with-original-query result query-execution)
6883
(-> query-execution
6984
add-running-time
70-
(dissoc :error :hash :executor_id :card_id :dashboard_id :pulse_id :result_rows :native))
71-
result
85+
(dissoc :error :hash :executor_id :card_id :dashboard_id :pulse_id :result_rows :native :original_query_stmt))
7286
{:status :completed
7387
:average_execution_time (when cached?
7488
(query/average-execution-time-ms query-hash))}))
@@ -95,35 +109,73 @@
95109
(rf result row))))))
96110

97111
(defn- query-execution-info
98-
"Return the info for the QueryExecution entry for this `query`."
112+
"Return the info for the QueryExecution entry for this `query`.
113+
setting original_query in query-execution-info for the context of query passed by client for other middleware's
114+
"
99115
{:arglists '([query])}
100116
[{{:keys [executed-by query-hash context card-id dashboard-id pulse-id]} :info
101117
database-id :database
102118
query-type :type
103119
:as query}]
104120
{:pre [(instance? (Class/forName "[B") query-hash)]}
105-
{:database_id database-id
106-
:executor_id executed-by
107-
:card_id card-id
108-
:dashboard_id dashboard-id
109-
:pulse_id pulse-id
110-
:context context
111-
:hash query-hash
112-
:native (= (keyword query-type) :native)
113-
:json_query (cond-> (dissoc query :info)
114-
(empty? (:parameters query)) (dissoc :parameters))
115-
:started_at (t/zoned-date-time)
116-
:running_time 0
117-
:result_rows 0
118-
:start_time_millis (System/currentTimeMillis)})
121+
{:database_id database-id
122+
:executor_id executed-by
123+
:card_id card-id
124+
:dashboard_id dashboard-id
125+
:pulse_id pulse-id
126+
:context context
127+
:hash query-hash
128+
:native (= (keyword query-type) :native)
129+
:original_query_stmt (get-in query[:native :original_query])
130+
:json_query (cond-> (dissoc query :info)
131+
(empty? (:parameters query)) (dissoc :parameters))
132+
:started_at (t/zoned-date-time)
133+
:running_time 0
134+
:result_rows 0
135+
:start_time_millis (System/currentTimeMillis)})
136+
137+
(defn adhoc-or-question?
138+
"Check if adhoc or question query"
139+
[context]
140+
(if (or (clojure.string/includes? context "question") (clojure.string/includes? context "ad-hoc"))
141+
true false
142+
)
143+
)
144+
145+
(defn limit-native-query?
146+
[database]
147+
(let[engine (:engine (db/select-one (into [Database] [:id :engine]) :id database))]
148+
(if (some (partial = (name engine)) ["presto" "mysql" "postgres" "redshift" "athena"]) true false)
149+
))
150+
151+
(defn add-limit-query
152+
"Add limit to query. If is native query(adhoc or question limit is set to 10000 else json or csv then limit set to 100000.
153+
Works only for native queries"
154+
155+
[{:keys [database], :as query}]
156+
(if (and (contains? query :native) (limit-native-query? database) (clojure.string/includes? (clojure.string/lower-case (get-in query[:native :query])) "select"))
157+
(let [context (get-in query [:info :context])
158+
query (update-in query[:native] assoc :original_query (get-in query[:native :query]))
159+
raw_query (clojure.string/replace (get-in query[:native :query]) #"[ ;]*$" "" )
160+
limit (if(adhoc-or-question? context) (atom 10000) (atom 100000))]
161+
(if-not (re-find #"(?i)limit " raw_query)
162+
(update-in query[:native] assoc :query (str raw_query " limit " @limit ))
163+
query
164+
)
165+
)
166+
query
167+
)
168+
)
119169

120170
(defn process-userland-query
121171
"Do extra handling 'userland' queries (i.e. ones ran as a result of a user action, e.g. an API call, scheduled Pulse,
122172
etc.). This includes recording QueryExecution entries and returning the results in an FE-client-friendly format."
123173
[qp]
124174
(fn [query rff {:keys [raisef], :as context}]
125-
(let [query (assoc-in query [:info :query-hash] (qputil/query-hash query))
175+
(let [query (add-limit-query query)
176+
query (assoc-in query [:info :query-hash] (qputil/query-hash query))
126177
execution-info (query-execution-info query)]
178+
(log/debug "Original query:\n %s -> Limit query:\n %s " (get-in query[:native :original_query]) (get-in query[:native :query]))
127179
(letfn [(rff* [metadata]
128180
(add-and-save-execution-info-xform! metadata execution-info (rff metadata)))
129181
(raisef* [^Throwable e context]

0 commit comments

Comments
 (0)