Skip to content
Snippets Groups Projects
Unverified Commit 76ea4e50 authored by Ryan Senior's avatar Ryan Senior Committed by GitHub
Browse files

Merge pull request #8632 from metabase/turkish-h2-locale-fix

 Specify English locale when formatting H2 SQL identifiers 
parents c59e476d c942a4b5
No related branches found
No related tags found
No related merge requests found
(ns metabase.util.honeysql-extensions
(:refer-clojure :exclude [+ - / * mod inc dec cast concat format])
(:require [clojure.string :as s]
(honeysql [core :as hsql]
[format :as hformat]
helpers))
(:import honeysql.format.ToSql))
[honeysql
[core :as hsql]
[format :as hformat]])
(:import honeysql.format.ToSql
java.util.Locale))
(alter-meta! #'honeysql.core/format assoc :style/indent 1)
(alter-meta! #'honeysql.core/call assoc :style/indent 1)
;; for some reason the metadata on these helper functions is wrong which causes Eastwood to fail, see
;; https://github.com/jkk/honeysql/issues/123
(alter-meta! #'honeysql.helpers/merge-left-join assoc
:arglists '([m & clauses])
:style/indent 1)
(defn- english-upper-case
"Use this function when you need to upper-case an identifier or table name. Similar to `clojure.string/upper-case`
but always converts the string to upper-case characters in the English locale. Using `clojure.string/upper-case` for
table names, like we are using below in the `:h2` `honeysql.format` function can cause issues when the user has
changed the locale to a language that has different upper-case characters. Turkish is one example, where `i` gets
converted to `İ`. This causes the `SETTING` table to become the `SETTİNG` table, which doesn't exist."
[^CharSequence s]
(-> s str (.toUpperCase Locale/ENGLISH)))
;; Add an `:h2` quote style that uppercases the identifier
(let [quote-fns @(resolve 'honeysql.format/quote-fns)
ansi-quote-fn (:ansi quote-fns)]
(intern 'honeysql.format 'quote-fns
(assoc quote-fns :h2 (comp s/upper-case ansi-quote-fn))))
(assoc quote-fns :h2 (comp english-upper-case ansi-quote-fn))))
;; `:crate` quote style that correctly quotes nested column identifiers
......
(ns metabase.util.honeysql-extensions-test
(:require [expectations :refer :all]
[honeysql.format :as hformat]
[metabase.util.honeysql-extensions :as hsql-ext])
(:import java.util.Locale))
;; Basic format test not including a specific quoting option
(expect
["setting"]
(hformat/format :setting))
;; `:h2` quoting will uppercase and quote the identifier
(expect
["\"SETTING\""]
(hformat/format :setting :quoting :h2))
(defn- call-with-locale
"Sets the default locale temporarily to `locale-tag`, then invokes `f` and reverts the locale change"
[locale-tag f]
(let [current-locale (Locale/getDefault)]
(try
(Locale/setDefault (Locale/forLanguageTag locale-tag))
(f)
(finally
(Locale/setDefault current-locale)))))
(defmacro ^:private with-locale [locale-tag & body]
`(call-with-locale ~locale-tag (fn [] ~@body)))
;; We provide our own quoting function for `:h2` databases. We quote and uppercase the identifier. Using Java's
;; toUpperCase method is surprisingly locale dependent. When uppercasing a string in a language like Turkish, it can
;; turn an i into an İ. This test converts a keyword with an `i` in it to verify that we convert the identifier
;; correctly using the english locale even when the user has changed the locale to Turkish
(expect
["\"SETTING\""]
(with-locale "tr"
(hformat/format :setting :quoting :h2)))
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment