diff --git a/CHANGELOG.md b/CHANGELOG.md index 6859b67..7422775 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * 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`. * 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. + * Fix [#421](https://github.com/seancorfield/honeysql/issues/421) by adding `:replace-into` for `:mysql` dialect. * 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`). * Fix [#392](https://github.com/seancorfield/honeysql/issues/392) by adding support for `WITH` / (`NOT`) `MATERIALIZED` -- via PR [#420](https://github.com/seancorfield/honeysql/issues/420) [@robhanlon22](https://github.com/robhanlon22). diff --git a/doc/clause-reference.md b/doc/clause-reference.md index e2b789c..5e74b9a 100644 --- a/doc/clause-reference.md +++ b/doc/clause-reference.md @@ -439,7 +439,7 @@ user=> (sql/format '{select * bulk-collect-into [arrv 100] from mytable}) ["SELECT * BULK COLLECT INTO arrv LIMIT ? FROM mytable" 100] ``` -## insert-into +## insert-into, replace-into There are three use cases with `:insert-into`. @@ -457,6 +457,9 @@ or a table/column specifier and a SQL query. For the first and second cases, you'll use the `:values` clause to specify rows of values to insert. +`:replace-into` is part of the `:mysql` dialect that produces a `REPLACE INTO` +statement but otherwise has identical syntax to `:insert-into`. + ```clojure ;; first case -- table specifier: user=> (sql/format {:insert-into :transport diff --git a/src/honey/sql.cljc b/src/honey/sql.cljc index b1843f9..52a8bdb 100644 --- a/src/honey/sql.cljc +++ b/src/honey/sql.cljc @@ -94,6 +94,8 @@ [s x e] (str s (str/replace x (str e) (str e e)) e)) +(declare register-clause!) + (def ^:private dialects (atom (reduce-kv (fn [m k v] @@ -102,7 +104,10 @@ {:ansi {:quote #(strop \" % \")} :sqlserver {:quote #(strop \[ % \])} :mysql {:quote #(strop \` % \`) - :clause-order-fn #(add-clause-before % :set :where)} + :clause-order-fn + #(do + (register-clause! :replace-into :insert-into :insert-into) + (add-clause-before % :set :where))} :oracle {:quote #(strop \" % \") :as false}}))) ; should become defonce diff --git a/test/honey/sql_test.cljc b/test/honey/sql_test.cljc index 9c0c171..686e713 100644 --- a/test/honey/sql_test.cljc +++ b/test/honey/sql_test.cljc @@ -968,6 +968,16 @@ ORDER BY id = ? DESC (is (= ["SELECT `A``B`"] (sut/format {:select (keyword "A`B")} {:dialect :mysql}))) (is (= ["SELECT \"A\"\"B\""] (sut/format {:select (keyword "A\"B")} {:dialect :oracle})))) +(deftest issue-421-mysql-replace-into + ;; because the :mysql dialect registers a new clause, and we've probably already run + ;; tests with that dialect, we can't test that :replace-into throws an exception when + ;; no :dialect is specified because the clause might already be in place: + (is (= ["INSERT INTO table VALUES (?, ?, ?)" 1 2 3] + (sut/format {:insert-into :table :values [[1 2 3]]}))) + (is (= ["REPLACE INTO table VALUES (?, ?, ?)" 1 2 3] + (sut/format {:replace-into :table :values [[1 2 3]]} + {:dialect :mysql :quoted false})))) + (deftest issue-422-quoting ;; default quote if strange entity: (is (= ["SELECT A, \"B C\""] (sut/format {:select [:A (keyword "B C")]})))