parent
737699c11a
commit
3073d28525
3 changed files with 84 additions and 49 deletions
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
* 2.3.next in progress
|
* 2.3.next in progress
|
||||||
* Address [#425](https://github.com/seancorfield/honeysql/issues/425) by clarifying that `INTERVAL` as special syntax may be MySQL-specific and PostgreSQL uses difference syntax (because `INTERVAL` is a data type there).
|
* Address [#425](https://github.com/seancorfield/honeysql/issues/425) by clarifying that `INTERVAL` as special syntax may be MySQL-specific and PostgreSQL uses difference syntax (because `INTERVAL` is a data type there).
|
||||||
|
* Address [#423](https://github.com/seancorfield/honeysql/issues/423) by supporting `DEFAULT` values and `DEFAULT` rows in `VALUES` clause -- NEEDS DOCUMENTATION!
|
||||||
* **WIP** Address [#422](https://github.com/seancorfield/honeysql/issues/422) by auto-quoting unusual entity names when `:quoted` (and `:dialect`) are not specified, making HoneySQL more secure by default.
|
* **WIP** Address [#422](https://github.com/seancorfield/honeysql/issues/422) by auto-quoting unusual entity names when `:quoted` (and `:dialect`) are not specified, making HoneySQL more secure by default.
|
||||||
* Address [#419](https://github.com/seancorfield/honeysql/issues/419) by adding `honey.sql.protocols` and `InlineValue` with a `sqlize` function.
|
* Address [#419](https://github.com/seancorfield/honeysql/issues/419) by adding `honey.sql.protocols` and `InlineValue` with a `sqlize` function.
|
||||||
* Address [#413](https://github.com/seancorfield/honeysql/issues/413) by flagging a lack of `WHERE` clause for `DELETE`, `DELETE FROM`, and `UPDATE` when `:checking :basic` (or `:checking :strict`).
|
* Address [#413](https://github.com/seancorfield/honeysql/issues/413) by flagging a lack of `WHERE` clause for `DELETE`, `DELETE FROM`, and `UPDATE` when `:checking :basic` (or `:checking :strict`).
|
||||||
|
|
|
||||||
|
|
@ -699,59 +699,74 @@
|
||||||
(str " " (sql-kw nowait))))))]))
|
(str " " (sql-kw nowait))))))]))
|
||||||
|
|
||||||
(defn- format-values [k xs]
|
(defn- format-values [k xs]
|
||||||
(cond (sequential? (first xs))
|
(let [first-xs (when (sequential? xs) (first (drop-while ident? xs)))]
|
||||||
;; [[1 2 3] [4 5 6]]
|
(cond (contains? #{:default 'default} xs)
|
||||||
(let [n-1 (map count xs)
|
[(str (sql-kw xs) " " (sql-kw k))]
|
||||||
;; issue #291: ensure all value sequences are the same length
|
(empty? xs)
|
||||||
xs' (if (apply = n-1)
|
[(str (sql-kw k) " ()")]
|
||||||
xs
|
(sequential? first-xs)
|
||||||
(let [n-n (apply max n-1)]
|
;; [[1 2 3] [4 5 6]]
|
||||||
(map (fn [x] (take n-n (concat x (repeat nil)))) xs)))
|
(let [n-1 (map count (filter sequential? xs))
|
||||||
[sqls params]
|
;; issue #291: ensure all value sequences are the same length
|
||||||
(reduce (fn [[sql params] [sqls' params']]
|
xs' (if (apply = n-1)
|
||||||
[(conj sql (str "(" (str/join ", " sqls') ")"))
|
xs
|
||||||
(into params params')])
|
(let [n-n (when (seq n-1) (apply max n-1))]
|
||||||
[[] []]
|
(map (fn [x]
|
||||||
(map #'format-expr-list xs'))]
|
(if (sequential? x)
|
||||||
(into [(str (sql-kw k) " " (str/join ", " sqls))] params))
|
(take n-n (concat x (repeat nil)))
|
||||||
|
x))
|
||||||
|
xs)))
|
||||||
|
[sqls params]
|
||||||
|
(reduce (fn [[sql params] [sqls' params']]
|
||||||
|
[(conj sql
|
||||||
|
(if (sequential? sqls')
|
||||||
|
(str "(" (str/join ", " sqls') ")")
|
||||||
|
sqls'))
|
||||||
|
(into params params')])
|
||||||
|
[[] []]
|
||||||
|
(map #(if (sequential? %)
|
||||||
|
(format-expr-list %)
|
||||||
|
[(sql-kw %)])
|
||||||
|
xs'))]
|
||||||
|
(into [(str (sql-kw k) " " (str/join ", " sqls))] params))
|
||||||
|
|
||||||
(map? (first xs))
|
(map? first-xs)
|
||||||
;; [{:a 1 :b 2 :c 3}]
|
;; [{:a 1 :b 2 :c 3}]
|
||||||
(let [cols-1 (keys (first xs))
|
(let [cols-1 (keys (first xs))
|
||||||
;; issue #291: check for all keys in all maps but still
|
;; issue #291: check for all keys in all maps but still
|
||||||
;; use the keys from the first map if they match so that
|
;; use the keys from the first map if they match so that
|
||||||
;; users can rely on the key ordering if they want to,
|
;; users can rely on the key ordering if they want to,
|
||||||
;; e.g., see test that uses array-map for the first row
|
;; e.g., see test that uses array-map for the first row
|
||||||
cols-n (into #{} (mapcat keys) xs)
|
cols-n (into #{} (mapcat keys) xs)
|
||||||
cols (if (= (set cols-1) cols-n) cols-1 cols-n)
|
cols (if (= (set cols-1) cols-n) cols-1 cols-n)
|
||||||
[sqls params]
|
[sqls params]
|
||||||
(reduce (fn [[sql params] [sqls' params']]
|
(reduce (fn [[sql params] [sqls' params']]
|
||||||
[(conj sql (str "(" (str/join ", " sqls') ")"))
|
[(conj sql (str "(" (str/join ", " sqls') ")"))
|
||||||
(if params' (into params params') params')])
|
(if params' (into params params') params')])
|
||||||
[[] []]
|
[[] []]
|
||||||
(map (fn [m]
|
(map (fn [m]
|
||||||
(format-expr-list
|
(format-expr-list
|
||||||
(map #(get m
|
(map #(get m
|
||||||
%
|
%
|
||||||
;; issue #366: use NULL or DEFAULT
|
;; issue #366: use NULL or DEFAULT
|
||||||
;; for missing column values:
|
;; for missing column values:
|
||||||
(if (contains? *values-default-columns* %)
|
(if (contains? *values-default-columns* %)
|
||||||
[:default]
|
[:default]
|
||||||
nil))
|
nil))
|
||||||
cols)))
|
cols)))
|
||||||
xs))]
|
xs))]
|
||||||
(into [(str "("
|
(into [(str "("
|
||||||
(str/join ", "
|
(str/join ", "
|
||||||
(map #(format-entity % {:drop-ns true}) cols))
|
(map #(format-entity % {:drop-ns true}) cols))
|
||||||
") "
|
") "
|
||||||
(sql-kw k)
|
(sql-kw k)
|
||||||
" "
|
" "
|
||||||
(str/join ", " sqls))]
|
(str/join ", " sqls))]
|
||||||
params))
|
params))
|
||||||
|
|
||||||
:else
|
:else
|
||||||
(throw (ex-info ":values expects sequences or maps"
|
(throw (ex-info ":values expects sequences or maps"
|
||||||
{:first (first xs)}))))
|
{:first (first xs)})))))
|
||||||
|
|
||||||
(comment
|
(comment
|
||||||
(into #{} (mapcat keys) [{:a 1 :b 2} {:b 3 :c 4}])
|
(into #{} (mapcat keys) [{:a 1 :b 2} {:b 3 :c 4}])
|
||||||
|
|
|
||||||
|
|
@ -737,6 +737,25 @@ ORDER BY id = ? DESC
|
||||||
:values [{:name name
|
:values [{:name name
|
||||||
:enabled enabled}]})))))
|
:enabled enabled}]})))))
|
||||||
|
|
||||||
|
(deftest issue-425-default-values-test
|
||||||
|
(testing "default values"
|
||||||
|
(is (= ["INSERT INTO table (a, b, c) DEFAULT VALUES"]
|
||||||
|
(format {:insert-into [:table [:a :b :c]] :values :default}))))
|
||||||
|
(testing "values with default row"
|
||||||
|
(is (= ["INSERT INTO table (a, b, c) VALUES (1, 2, 3), DEFAULT, (4, 5, 6)"]
|
||||||
|
(format {:insert-into [:table [:a :b :c]]
|
||||||
|
:values [[1 2 3] :default [4 5 6]]}
|
||||||
|
{:inline true}))))
|
||||||
|
(testing "values with default column"
|
||||||
|
(is (= ["INSERT INTO table (a, b, c) VALUES (1, DEFAULT, 3), DEFAULT"]
|
||||||
|
(format {:insert-into [:table [:a :b :c]]
|
||||||
|
:values [[1 [:default] 3] :default]}
|
||||||
|
{:inline true}))))
|
||||||
|
(testing "empty values"
|
||||||
|
(is (= ["INSERT INTO table (a, b, c) VALUES ()"]
|
||||||
|
(format {:insert-into [:table [:a :b :c]]
|
||||||
|
:values []})))))
|
||||||
|
|
||||||
(deftest issue-316-test
|
(deftest issue-316-test
|
||||||
;; this is a pretty naive test -- there are other tricks to perform injection
|
;; this is a pretty naive test -- there are other tricks to perform injection
|
||||||
;; that are not detected by HoneySQL and you should generally use :quoted true
|
;; that are not detected by HoneySQL and you should generally use :quoted true
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue