diff --git a/frontend/src/metabase/databases/components/DatabaseHostnameSectionField/DatabaseHostameSectionField.styled.tsx b/frontend/src/metabase/databases/components/DatabaseHostnameSectionField/DatabaseHostameSectionField.styled.tsx
new file mode 100644
index 0000000000000..671c58493d174
--- /dev/null
+++ b/frontend/src/metabase/databases/components/DatabaseHostnameSectionField/DatabaseHostameSectionField.styled.tsx
@@ -0,0 +1,15 @@
+import styled from "@emotion/styled";
+
+import Button from "metabase/core/components/Button";
+import { color } from "metabase/lib/colors";
+
+export const SectionButton = styled(Button)`
+ color: ${color("brand")};
+ padding: 0;
+ border: none;
+ border-radius: 0;
+
+ &:hover {
+ background-color: transparent;
+ }
+`;
diff --git a/frontend/src/metabase/databases/components/DatabaseHostnameSectionField/DatabaseHostameSectionField.tsx b/frontend/src/metabase/databases/components/DatabaseHostnameSectionField/DatabaseHostameSectionField.tsx
new file mode 100644
index 0000000000000..9b5a1b131541d
--- /dev/null
+++ b/frontend/src/metabase/databases/components/DatabaseHostnameSectionField/DatabaseHostameSectionField.tsx
@@ -0,0 +1,32 @@
+import { useField } from "formik";
+import { useCallback } from "react";
+import { t } from "ttag";
+
+import FormField from "metabase/core/components/FormField";
+
+import { SectionButton } from "./DatabaseHostameSectionField.styled";
+
+export interface DatabaseHostnameSectionFieldProps {
+ name: string;
+}
+
+const DatabaseHostnameSectionField = ({
+ name,
+}: DatabaseHostnameSectionFieldProps): JSX.Element => {
+ const [{ value }, , { setValue }] = useField(name);
+
+ const handleClick = useCallback(() => {
+ setValue(!value);
+ }, [value, setValue]);
+
+ return (
+
+
+ {value ? t`Use hostname` : t`Use account name`}
+
+
+ );
+};
+
+// eslint-disable-next-line import/no-default-export -- deprecated usage
+export default DatabaseHostnameSectionField;
diff --git a/frontend/src/metabase/databases/components/DatabaseHostnameSectionField/index.ts b/frontend/src/metabase/databases/components/DatabaseHostnameSectionField/index.ts
new file mode 100644
index 0000000000000..d926659b9e2aa
--- /dev/null
+++ b/frontend/src/metabase/databases/components/DatabaseHostnameSectionField/index.ts
@@ -0,0 +1,2 @@
+// eslint-disable-next-line import/no-default-export -- deprecated usage
+export { default } from "./DatabaseHostameSectionField";
diff --git a/frontend/src/metabase/databases/constants.tsx b/frontend/src/metabase/databases/constants.tsx
index cae32e030d7ad..8082e466b07a5 100644
--- a/frontend/src/metabase/databases/constants.tsx
+++ b/frontend/src/metabase/databases/constants.tsx
@@ -6,6 +6,7 @@ import DatabaseAuthCodeDescription from "./components/DatabaseAuthCodeDescriptio
import DatabaseCacheScheduleField from "./components/DatabaseCacheScheduleField";
import DatabaseClientIdDescription from "./components/DatabaseClientIdDescription";
import DatabaseConnectionSectionField from "./components/DatabaseConnectionSectionField";
+import DatabaseHostnameSectionField from "./components/DatabaseHostnameSectionField";
import DatabaseScheduleToggleField from "./components/DatabaseScheduleToggleField";
import DatabaseSshDescription from "./components/DatabaseSshDescription";
import DatabaseSslKeyDescription from "./components/DatabaseSslKeyDescription";
@@ -104,6 +105,9 @@ export const FIELD_OVERRIDES: Record = {
"use-conn-uri": {
type: DatabaseConnectionSectionField,
},
+ "use-hostname": {
+ type: DatabaseHostnameSectionField,
+ },
"let-user-control-scheduling": {
type: DatabaseScheduleToggleField,
},
diff --git a/modules/drivers/snowflake/resources/metabase-plugin.yaml b/modules/drivers/snowflake/resources/metabase-plugin.yaml
index 9d2397c25d16f..02daf68d2bdb4 100644
--- a/modules/drivers/snowflake/resources/metabase-plugin.yaml
+++ b/modules/drivers/snowflake/resources/metabase-plugin.yaml
@@ -8,11 +8,20 @@ driver:
lazy-load: true
parent: sql-jdbc
connection-properties:
+ - name: use-hostname
+ type: section
+ default: false
+ - merge:
+ - host
+ - visible-if:
+ use-hostname: true
- name: account
display-name: Account name
helper-text: Enter your Account ID with the region that your Snowflake cluster is running on e.g. "xxxxxxxx.us-east-2.aws". Some regions don't have this suffix.
placeholder: xxxxxxxx.us-east-2.aws
required: true
+ visible-if:
+ use-hostname: false
- user
- password
- name: private-key
diff --git a/modules/drivers/snowflake/src/metabase/driver/snowflake.clj b/modules/drivers/snowflake/src/metabase/driver/snowflake.clj
index c4ae98690e89c..6bd20e190ff13 100644
--- a/modules/drivers/snowflake/src/metabase/driver/snowflake.clj
+++ b/modules/drivers/snowflake/src/metabase/driver/snowflake.clj
@@ -123,7 +123,7 @@
(str "\"" (str/replace raw-name "\"" "\"\"") "\"")))
(defmethod sql-jdbc.conn/connection-details->spec :snowflake
- [_ {:keys [account additional-options], :as details}]
+ [_ {:keys [account additional-options host use-hostname], :as details}]
(when (get "week_start" (sql-jdbc.common/additional-options->map additional-options :url))
(log/warn (trs "You should not set WEEK_START in Snowflake connection options; this might lead to incorrect results. Set the Start of Week Setting instead.")))
(let [upcase-not-nil (fn [s] (when s (u/upper-case-en s)))]
@@ -131,7 +131,12 @@
;; https://support.snowflake.net/s/question/0D50Z00008WTOMCSA5/
(-> (merge {:classname "net.snowflake.client.jdbc.SnowflakeDriver"
:subprotocol "snowflake"
- :subname (str "//" account ".snowflakecomputing.com/")
+ ;; see https://github.com/metabase/metabase/issues/22133
+ :subname (let [base-url (if (and use-hostname (string? host) (not (str/blank? host)))
+ (cond-> host
+ (not= (last host) \/) (str "/"))
+ (str account ".snowflakecomputing.com/"))]
+ (str "//" base-url ))
:client_metadata_request_use_connection_ctx true
:ssl true
;; keep open connections open indefinitely instead of closing them. See #9674 and
diff --git a/modules/drivers/snowflake/test/metabase/driver/snowflake_test.clj b/modules/drivers/snowflake/test/metabase/driver/snowflake_test.clj
index da1fb5eced74f..ad1fe53acc535 100644
--- a/modules/drivers/snowflake/test/metabase/driver/snowflake_test.clj
+++ b/modules/drivers/snowflake/test/metabase/driver/snowflake_test.clj
@@ -87,13 +87,29 @@
:engine :snowflake
:private-key-creator-id 3
:user "SNOWFLAKE_DEVELOPER"
- :private-key-created-at "2024-01-05T19:10:30.861839Z"}]
- (testing "Database name is quoted iff quoting is requested (#27856)"
+ :private-key-created-at "2024-01-05T19:10:30.861839Z"
+ :host ""}]
+ (testing "Database name is quoted if quoting is requested (#27856)"
(are [quote? result] (=? {:db result}
(let [details (assoc details :quote-db-name quote?)]
(sql-jdbc.conn/connection-details->spec :snowflake details)))
true "\"v3_sample-dataset\""
- false "v3_sample-dataset"))))
+ false "v3_sample-dataset"))
+ (testing "Subname is replaced if hostname is provided (#22133)"
+ (are [use-hostname alternative-host expected-subname] (=? expected-subname
+ (:subname (let [details (-> details
+ (assoc :host alternative-host)
+ (assoc :use-hostname use-hostname))]
+ (sql-jdbc.conn/connection-details->spec :snowflake details))))
+ true nil "//ls10467.us-east-2.aws.snowflakecomputing.com/"
+ true "" "//ls10467.us-east-2.aws.snowflakecomputing.com/"
+ true " " "//ls10467.us-east-2.aws.snowflakecomputing.com/"
+ true "snowflake.example.com/" "//snowflake.example.com/"
+ true "snowflake.example.com" "//snowflake.example.com/"
+ false nil "//ls10467.us-east-2.aws.snowflakecomputing.com/"
+ false "" "//ls10467.us-east-2.aws.snowflakecomputing.com/"
+ false "snowflake.example.com/" "//ls10467.us-east-2.aws.snowflakecomputing.com/"
+ false "snowflake.example.com" "//ls10467.us-east-2.aws.snowflakecomputing.com/"))))
(deftest ^:parallel ddl-statements-test
(testing "make sure we didn't break the code that is used to generate DDL statements when we add new test datasets"