diff --git a/CHANGELOG.md b/CHANGELOG.md index 9018a8e..61a0cc1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changes * 2.3.next in progress + * **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 [#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/src/honey/sql.cljc b/src/honey/sql.cljc index 4b003de..baf818c 100644 --- a/src/honey/sql.cljc +++ b/src/honey/sql.cljc @@ -210,13 +210,25 @@ (let [col-fn (if (or *quoted* (string? e)) (if *quoted-snake* name-_ name) name-_) - quote-fn (if (or *quoted* (string? e)) (:quote *dialect*) identity) + col-e (col-fn e) + dialect-q (:quote *dialect* identity) + quote-fn (cond (or *quoted* (string? e)) + dialect-q + ;; #422: if default quoting and "unusual" + ;; characters in entity, then quote it: + (nil? *quoted*) + (fn opt-quote [part] + (if (re-find #"^[A-Za-z0-9_]+$" part) + part + (dialect-q part))) + :else + identity) parts (if-let [n (when-not (or drop-ns (string? e)) (namespace-_ e))] - [n (col-fn e)] + [n col-e] (if aliased - [(col-fn e)] - (str/split (col-fn e) #"\."))) + [col-e] + (str/split col-e #"\."))) entity (str/join "." (map #(cond-> % (not= "*" %) (quote-fn)) parts)) suspicious #";"] (when-not *allow-suspicious-entities* diff --git a/test/honey/sql_test.cljc b/test/honey/sql_test.cljc index 3ae8b8f..2270428 100644 --- a/test/honey/sql_test.cljc +++ b/test/honey/sql_test.cljc @@ -936,3 +936,15 @@ 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 :mysql}))) (is (= ["SELECT \"A\"\"B\""] (sut/format {:select (keyword "A\"B")} {:dialect :oracle})))) + +(deftest issue-422-quoting + ;; default quote if strange entity: + (is (= ["SELECT A, \"B C\""] (sut/format {:select [:A (keyword "B C")]}))) + ;; default don't quote normal entity: + (is (= ["SELECT A, B_C"] (sut/format {:select [:A (keyword "B_C")]}))) + ;; quote all entities when quoting enabled: + (is (= ["SELECT \"A\", \"B C\""] (sut/format {:select [:A (keyword "B C")]} + {:quoted true}))) + ;; don't quote if quoting disabled (illegal SQL): + (is (= ["SELECT A, B C"] (sut/format {:select [:A (keyword "B C")]} + {:quoted false}))))