From 33b2aca0b76f81e81e653c3bad1f02d020c91248 Mon Sep 17 00:00:00 2001 From: Tim Hable Date: Wed, 28 Jan 2026 09:16:44 +0100 Subject: [PATCH 1/3] Redshift support --- CONTRIBUTING.md | 1 + README.md | 1 + integration_test_project/example-env.sh | 5 +++++ integration_test_project/profiles.yml | 12 ++++++++++ .../database_specific_helpers/parse_json.sql | 8 +++++++ .../type_helpers.sql | 22 ++++++++++++++++++- macros/integration_tests/safe_cast.sql | 12 ++++++---- 7 files changed, 56 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index eb364e05..7df48ba2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -93,6 +93,7 @@ Tox will take care of installing the dependencies for each environment, so you d tox -e integration_snowflake # For the Snowflake tests tox -e integration_databricks # For the Databricks tests tox -e integration_bigquery # For the BigQuery tests + tox -e integration_redshift # For the Redshift tests ``` The Spark tests require installing the [ODBC driver](https://www.databricks.com/spark/odbc-drivers-download). On a Mac, diff --git a/README.md b/README.md index 905924ab..4c5d4df3 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ The package currently supports - Postgres :white_check_mark: - SQL Server :white_check_mark: - Trino :white_check_mark: +- Redshift :white_check_mark: Models included: diff --git a/integration_test_project/example-env.sh b/integration_test_project/example-env.sh index 47cb0d67..3fa2ff68 100755 --- a/integration_test_project/example-env.sh +++ b/integration_test_project/example-env.sh @@ -16,6 +16,11 @@ export DBT_ENV_SECRET_DATABRICKS_TOKEN= export DBT_ENV_SECRET_GCP_PROJECT= export DBT_ENV_SPARK_DRIVER_PATH= # /Library/simba/spark/lib/libsparkodbc_sbu.dylib on a Mac export DBT_ENV_SPARK_ENDPOINT= # The endpoint ID from the Databricks HTTP path +export DBT_ENV__REDSHIFT__HOST= +export DBT_ENV__REDSHIFT__DBNAME= +export DBT_ENV__REDSHIFT__SCHEMA= +export DBT_ENV__REDSHIFT__USER= +export DBT_ENV__REDSHIFT__PASSWORD= # dbt environment variables, change these export DBT_VERSION="1_5_0" diff --git a/integration_test_project/profiles.yml b/integration_test_project/profiles.yml index 84d85ddc..455e3904 100644 --- a/integration_test_project/profiles.yml +++ b/integration_test_project/profiles.yml @@ -74,3 +74,15 @@ dbt_artifacts: schema: default port: 8080 threads: 8 + redshift: + type: redshift + host: "{{ env_var('DBT_ENV__REDSHIFT__HOST') }}" + port: "{{ env_var('DBT_ENV__REDSHIFT__PORT', 5439) | int }}" + dbname: "{{ env_var('DBT_ENV__REDSHIFT__DBNAME', 'main') }}" + schema: "{{ env_var('DBT_ENV__REDSHIFT__SCHEMA', 'public') }}" + connect_timeout: "{{ env_var('DBT_ENV__REDSHIFT__CONNECT_TIMEOUT', 3600) | int }}" + ssl_mode: "{{ env_var('DBT_ENV__REDSHIFT__SSL_MODE', 'prefer') }}" + ra3_node: "{{ env_var('DBT_ENV__REDSHIFT__RA3_NODE', True) | as_bool }}" + threads: "{{ env_var('DBT_ENV__REDSHIFT__THREADS', 8) | int }}" + user: "{{ env_var('DBT_ENV__REDSHIFT__USER') }}" + password: "{{ env_var('DBT_ENV__REDSHIFT__PASSWORD') }}" diff --git a/macros/database_specific_helpers/parse_json.sql b/macros/database_specific_helpers/parse_json.sql index 5dde5f9c..a960d36d 100644 --- a/macros/database_specific_helpers/parse_json.sql +++ b/macros/database_specific_helpers/parse_json.sql @@ -14,3 +14,11 @@ safe.parse_json("""{{ field }}""", wide_number_mode=>'round') {%- endmacro %} +{% macro redshift__parse_json(field) %} + case + when can_json_parse({{ field }}) + then json_parse({{ field }}) + else + {{ field }} + end +{%- endmacro %} diff --git a/macros/database_specific_helpers/type_helpers.sql b/macros/database_specific_helpers/type_helpers.sql index cbc19e5f..51529036 100644 --- a/macros/database_specific_helpers/type_helpers.sql +++ b/macros/database_specific_helpers/type_helpers.sql @@ -26,6 +26,10 @@ json {% endmacro %} +{% macro redshift__type_json() %} + varchar(max) +{% endmacro %} + {#- ARRAY -#} {% macro type_array() %} @@ -48,7 +52,11 @@ array(varchar) {% endmacro %} -{#- NUMERIC -#}%} +{% macro redshift__type_array() %} + varchar(max) +{% endmacro %} + +{#- NUMERIC -#} {% macro type_numeric() %} {{ return(adapter.dispatch('type_numeric', 'dbt_artifacts')()) }} @@ -61,3 +69,15 @@ {% macro trino__type_numeric() %} double {% endmacro %} + +{% macro type_string() %} + {{ return(adapter.dispatch('type_string', 'dbt_artifacts')()) }} +{% endmacro %} + +{% macro default__type_string() %} + {{ return(api.Column.translate_type("string")) }} +{% endmacro %} + +{% macro redshift__type_string() %} + varchar(max) +{% endmacro %} diff --git a/macros/integration_tests/safe_cast.sql b/macros/integration_tests/safe_cast.sql index 92a7e717..faa1ba12 100644 --- a/macros/integration_tests/safe_cast.sql +++ b/macros/integration_tests/safe_cast.sql @@ -8,7 +8,8 @@ 'bigquery': 'STRING', 'snowflake': 'VARCHAR', 'databricks': 'STRING', - 'trino': 'VARCHAR' + 'trino': 'VARCHAR', + 'redshift': 'TEXT' }, 'integer': { 'postgres': 'NUMERIC', @@ -16,7 +17,8 @@ 'bigquery': 'FLOAT64', 'snowflake': 'FLOAT', 'databricks': 'DOUBLE', - 'trino': 'DOUBLE' + 'trino': 'DOUBLE', + 'redshift': 'NUMERIC' }, 'date': { 'postgres': 'DATE', @@ -24,7 +26,8 @@ 'bigquery': 'DATE', 'snowflake': 'DATE', 'databricks': 'DATE', - 'trino': 'DATE' + 'trino': 'DATE', + 'redshift': 'DATE' }, 'timestamp': { 'postgres': 'TIMESTAMP', @@ -32,7 +35,8 @@ 'bigquery': 'TIMESTAMP', 'snowflake': 'TIMESTAMP', 'databricks': 'TIMESTAMP', - 'trino': 'TIMESTAMP' + 'trino': 'TIMESTAMP', + 'redshift': 'TIMESTAMPTZ' } } %} From 733191f1eca0d06380b7b502dc82fd8794172586 Mon Sep 17 00:00:00 2001 From: Tim Hable Date: Wed, 28 Jan 2026 09:36:05 +0100 Subject: [PATCH 2/3] Fix typo and lower default connect timeout --- integration_test_project/profiles.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integration_test_project/profiles.yml b/integration_test_project/profiles.yml index 455e3904..5c326a4e 100644 --- a/integration_test_project/profiles.yml +++ b/integration_test_project/profiles.yml @@ -80,8 +80,8 @@ dbt_artifacts: port: "{{ env_var('DBT_ENV__REDSHIFT__PORT', 5439) | int }}" dbname: "{{ env_var('DBT_ENV__REDSHIFT__DBNAME', 'main') }}" schema: "{{ env_var('DBT_ENV__REDSHIFT__SCHEMA', 'public') }}" - connect_timeout: "{{ env_var('DBT_ENV__REDSHIFT__CONNECT_TIMEOUT', 3600) | int }}" - ssl_mode: "{{ env_var('DBT_ENV__REDSHIFT__SSL_MODE', 'prefer') }}" + connect_timeout: "{{ env_var('DBT_ENV__REDSHIFT__CONNECT_TIMEOUT', 100) | int }}" + sslmode: "{{ env_var('DBT_ENV__REDSHIFT__SSL_MODE', 'prefer') }}" ra3_node: "{{ env_var('DBT_ENV__REDSHIFT__RA3_NODE', True) | as_bool }}" threads: "{{ env_var('DBT_ENV__REDSHIFT__THREADS', 8) | int }}" user: "{{ env_var('DBT_ENV__REDSHIFT__USER') }}" From cda6f2599b65010c645c63bd671727f6cd4ff2f6 Mon Sep 17 00:00:00 2001 From: Tim Hable Date: Wed, 28 Jan 2026 09:37:03 +0100 Subject: [PATCH 3/3] Set ra3_node default to dbts default --- integration_test_project/profiles.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration_test_project/profiles.yml b/integration_test_project/profiles.yml index 5c326a4e..cd52bfa3 100644 --- a/integration_test_project/profiles.yml +++ b/integration_test_project/profiles.yml @@ -82,7 +82,7 @@ dbt_artifacts: schema: "{{ env_var('DBT_ENV__REDSHIFT__SCHEMA', 'public') }}" connect_timeout: "{{ env_var('DBT_ENV__REDSHIFT__CONNECT_TIMEOUT', 100) | int }}" sslmode: "{{ env_var('DBT_ENV__REDSHIFT__SSL_MODE', 'prefer') }}" - ra3_node: "{{ env_var('DBT_ENV__REDSHIFT__RA3_NODE', True) | as_bool }}" + ra3_node: "{{ env_var('DBT_ENV__REDSHIFT__RA3_NODE', False) | as_bool }}" threads: "{{ env_var('DBT_ENV__REDSHIFT__THREADS', 8) | int }}" user: "{{ env_var('DBT_ENV__REDSHIFT__USER') }}" password: "{{ env_var('DBT_ENV__REDSHIFT__PASSWORD') }}"