From a0cc592256a5b85f75e4f0ae5c7f0121bcc310a9 Mon Sep 17 00:00:00 2001 From: Mike Blume Date: Thu, 22 Jan 2015 18:23:46 -0800 Subject: [PATCH] extend ToSql to cover Object This commit avoids extraneous calls to satisfies?. Satisfies? is very slow compared to protocol method dispatch, because method dispatch is cached and satisfies? is not. Instead of using satisfies? to check for cases where we need to fall back to a default behavior, we extend ToSql to java.lang.Object, providing a default behavior directly. This commit boosts honeysql's speed substantially. In my benchmarks, 80-90% of the time spent calling sql/format was spent in satisfies?. --- src/honeysql/format.clj | 55 +++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/src/honeysql/format.clj b/src/honeysql/format.clj index 004a640..2c40bc8 100644 --- a/src/honeysql/format.clj +++ b/src/honeysql/format.clj @@ -76,7 +76,10 @@ "not-like" "not like" "regex" "regexp"}) -(declare to-sql format-predicate*) +(declare format-predicate*) + +(defprotocol ToSql + (to-sql [x])) (defmulti fn-handler (fn [op & args] op)) @@ -206,27 +209,24 @@ (into [sql-str] @*params*) [sql-str])))) -(defprotocol ToSql - (-to-sql [x])) - (declare -format-clause) (extend-protocol ToSql clojure.lang.Keyword - (-to-sql [x] (let [s ^String (name x)] + (to-sql [x] (let [s ^String (name x)] (condp = (.charAt s 0) \% (let [call-args (string/split (subs s 1) #"\." 2)] (to-sql (apply call (map keyword call-args)))) \? (to-sql (param (keyword (subs s 1)))) (quote-identifier x)))) clojure.lang.Symbol - (-to-sql [x] (quote-identifier x)) + (to-sql [x] (quote-identifier x)) java.lang.Number - (-to-sql [x] (str x)) + (to-sql [x] (str x)) java.lang.Boolean - (-to-sql [x] (if x "TRUE" "FALSE")) + (to-sql [x] (if x "TRUE" "FALSE")) clojure.lang.Sequential - (-to-sql [x] (if *fn-context?* + (to-sql [x] (if *fn-context?* ;; list argument in fn call (paren-wrap (comma-join (map to-sql x))) ;; alias @@ -239,14 +239,14 @@ (quote-identifier (second x)) (to-sql (second x)))))) SqlCall - (-to-sql [x] (binding [*fn-context?* true] + (to-sql [x] (binding [*fn-context?* true] (let [fn-name (name (.name x)) fn-name (fn-aliases fn-name fn-name)] (apply fn-handler fn-name (.args x))))) SqlRaw - (-to-sql [x] (.s x)) + (to-sql [x] (.s x)) clojure.lang.IPersistentMap - (-to-sql [x] (let [clause-ops (concat + (to-sql [x] (let [clause-ops (concat (filter #(contains? x %) clause-order) (remove known-clauses (keys x))) sql-str (binding [*subquery?* true @@ -258,27 +258,24 @@ (paren-wrap sql-str) sql-str))) nil - (-to-sql [x] "NULL")) + (to-sql [x] "NULL") + Object + (to-sql [x] (let [[x pname] (if (instance? SqlParam x) + (let [pname (param-name x)] + (if (map? @*input-params*) + [(get @*input-params* pname) pname] + (let [x (first @*input-params*)] + (swap! *input-params* rest) + [x pname]))) + ;; Anonymous param name -- :_1, :_2, etc. + [x (keyword (str "_" (swap! *param-counter* inc)))])] + (swap! *param-names* conj pname) + (swap! *params* conj x) + "?"))) (defn sqlable? [x] (satisfies? ToSql x)) -(defn to-sql [x] - (if (satisfies? ToSql x) - (-to-sql x) - (let [[x pname] (if (instance? SqlParam x) - (let [pname (param-name x)] - (if (map? @*input-params*) - [(get @*input-params* pname) pname] - (let [x (first @*input-params*)] - (swap! *input-params* rest) - [x pname]))) - ;; Anonymous param name -- :_1, :_2, etc. - [x (keyword (str "_" (swap! *param-counter* inc)))])] - (swap! *param-names* conj pname) - (swap! *params* conj x) - "?"))) - ;;;; (defn format-predicate* [pred]