From 10517f337c6b22d5f7f2a4f6c747b6fd2d2f47e9 Mon Sep 17 00:00:00 2001 From: Artur Sawicki Date: Thu, 12 Dec 2024 20:32:49 +0100 Subject: [PATCH] feat: Docs, test, and missing parameter (#3280) - Update docs - Update migration guide - Add execute as - change execute as SDK - Add tests to procedures - Add examples and import instructions - Describe limitations - Deprecate old function and procedure --- MIGRATION_GUIDE.md | 34 +++ docs/index.md | 2 + docs/resources/function.md | 2 +- docs/resources/function_java.md | 46 ++- docs/resources/function_javascript.md | 48 +++- docs/resources/function_python.md | 53 +++- docs/resources/function_scala.md | 99 ++++++- docs/resources/function_sql.md | 66 ++++- docs/resources/procedure.md | 2 +- docs/resources/procedure_java.md | 96 ++++++- docs/resources/procedure_javascript.md | 48 +++- docs/resources/procedure_python.md | 52 +++- docs/resources/procedure_scala.md | 48 +++- docs/resources/procedure_sql.md | 45 ++- examples/additional/deprecated_resources.MD | 2 + .../snowflake_function_java/import.sh | 1 + .../snowflake_function_java/resource.tf | 12 + .../snowflake_function_javascript/import.sh | 1 + .../snowflake_function_javascript/resource.tf | 14 + .../snowflake_function_python/import.sh | 2 + .../snowflake_function_python/resource.tf | 17 ++ .../snowflake_function_scala/import.sh | 1 + .../snowflake_function_scala/resource.tf | 67 +++++ .../snowflake_function_sql/import.sh | 1 + .../snowflake_function_sql/resource.tf | 32 +++ .../snowflake_procedure_java/import.sh | 1 + .../snowflake_procedure_java/resource.tf | 60 ++++ .../snowflake_procedure_javascript/import.sh | 1 + .../resource.tf | 12 + .../snowflake_procedure_python/import.sh | 1 + .../snowflake_procedure_python/resource.tf | 14 + .../snowflake_procedure_scala/import.sh | 1 + .../snowflake_procedure_scala/resource.tf | 14 + .../snowflake_procedure_sql/import.sh | 1 + .../snowflake_procedure_sql/resource.tf | 11 + .../procedure_python_resource_ext.go | 12 + .../procedure_scala_resource_ext.go | 17 ++ .../model/procedure_javascript_model_ext.go | 25 ++ .../model/procedure_python_model_ext.go | 77 +++++ .../config/model/procedure_scala_model_ext.go | 123 ++++++++ .../config/model/procedure_sql_model_ext.go | 25 ++ pkg/acceptance/helpers/procedure_client.go | 10 + pkg/resources/function.go | 2 + pkg/resources/procedure.go | 2 + pkg/resources/procedure_commons.go | 22 ++ pkg/resources/procedure_java.go | 2 + .../procedure_java_acceptance_test.go | 6 +- pkg/resources/procedure_javascript.go | 2 + .../procedure_javascript_acceptance_test.go | 178 ++++++++++++ pkg/resources/procedure_python.go | 2 + .../procedure_python_acceptance_test.go | 240 ++++++++++++++++ pkg/resources/procedure_scala.go | 4 +- .../procedure_scala_acceptance_test.go | 262 ++++++++++++++++++ pkg/resources/procedure_sql.go | 2 + .../procedure_sql_acceptance_test.go | 178 ++++++++++++ pkg/sdk/common_types.go | 4 +- pkg/sdk/common_types_test.go | 2 +- pkg/sdk/functions_and_procedures_commons.go | 2 +- pkg/sdk/procedures_gen.go | 12 +- pkg/sdk/testint/functions_integration_test.go | 2 +- .../testint/procedures_integration_test.go | 2 +- templates/resources/function_java.md.tmpl | 52 ++++ .../resources/function_javascript.md.tmpl | 52 ++++ templates/resources/function_python.md.tmpl | 54 ++++ templates/resources/function_scala.md.tmpl | 50 ++++ templates/resources/function_sql.md.tmpl | 52 ++++ templates/resources/procedure_java.md.tmpl | 52 ++++ .../resources/procedure_javascript.md.tmpl | 52 ++++ templates/resources/procedure_python.md.tmpl | 54 ++++ templates/resources/procedure_scala.md.tmpl | 50 ++++ templates/resources/procedure_sql.md.tmpl | 50 ++++ 71 files changed, 2609 insertions(+), 31 deletions(-) create mode 100644 examples/resources/snowflake_function_java/import.sh create mode 100644 examples/resources/snowflake_function_java/resource.tf create mode 100644 examples/resources/snowflake_function_javascript/import.sh create mode 100644 examples/resources/snowflake_function_javascript/resource.tf create mode 100644 examples/resources/snowflake_function_python/import.sh create mode 100644 examples/resources/snowflake_function_python/resource.tf create mode 100644 examples/resources/snowflake_function_scala/import.sh create mode 100644 examples/resources/snowflake_function_scala/resource.tf create mode 100644 examples/resources/snowflake_function_sql/import.sh create mode 100644 examples/resources/snowflake_function_sql/resource.tf create mode 100644 examples/resources/snowflake_procedure_java/import.sh create mode 100644 examples/resources/snowflake_procedure_java/resource.tf create mode 100644 examples/resources/snowflake_procedure_javascript/import.sh create mode 100644 examples/resources/snowflake_procedure_javascript/resource.tf create mode 100644 examples/resources/snowflake_procedure_python/import.sh create mode 100644 examples/resources/snowflake_procedure_python/resource.tf create mode 100644 examples/resources/snowflake_procedure_scala/import.sh create mode 100644 examples/resources/snowflake_procedure_scala/resource.tf create mode 100644 examples/resources/snowflake_procedure_sql/import.sh create mode 100644 examples/resources/snowflake_procedure_sql/resource.tf create mode 100644 pkg/acceptance/bettertestspoc/assert/resourceassert/procedure_python_resource_ext.go create mode 100644 pkg/acceptance/bettertestspoc/assert/resourceassert/procedure_scala_resource_ext.go create mode 100644 pkg/resources/procedure_javascript_acceptance_test.go create mode 100644 pkg/resources/procedure_python_acceptance_test.go create mode 100644 pkg/resources/procedure_scala_acceptance_test.go create mode 100644 pkg/resources/procedure_sql_acceptance_test.go create mode 100644 templates/resources/function_java.md.tmpl create mode 100644 templates/resources/function_javascript.md.tmpl create mode 100644 templates/resources/function_python.md.tmpl create mode 100644 templates/resources/function_scala.md.tmpl create mode 100644 templates/resources/function_sql.md.tmpl create mode 100644 templates/resources/procedure_java.md.tmpl create mode 100644 templates/resources/procedure_javascript.md.tmpl create mode 100644 templates/resources/procedure_python.md.tmpl create mode 100644 templates/resources/procedure_scala.md.tmpl create mode 100644 templates/resources/procedure_sql.md.tmpl diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md index 8bd54b0a87..7dea8fd480 100644 --- a/MIGRATION_GUIDE.md +++ b/MIGRATION_GUIDE.md @@ -9,6 +9,40 @@ across different versions. ## v0.99.0 ➞ v0.100.0 +### *(preview feature/deprecation)* Function and procedure resources + +`snowflake_function` is now deprecated in favor of 5 new preview resources: + +- `snowflake_function_java` +- `snowflake_function_javascript` +- `snowflake_function_python` +- `snowflake_function_scala` +- `snowflake_function_sql` + +It will be removed with the v1 release. Please check the docs for the new resources and adjust your configuration files. +For no downtime migration, follow our [guide](https://github.com/Snowflake-Labs/terraform-provider-snowflake/blob/main/docs/technical-documentation/resource_migration.md). + +The new resources are more aligned with current features like: +- external access integrations support +- secrets support +- argument default values + +`snowflake_procedure` is now deprecated in favor of 5 new preview resources: + +- `snowflake_procedure_java` +- `snowflake_procedure_javascript` +- `snowflake_procedure_python` +- `snowflake_procedure_scala` +- `snowflake_procedure_sql` + +It will be removed with the v1 release. Please check the docs for the new resources and adjust your configuration files. +For no downtime migration, follow our [guide](https://github.com/Snowflake-Labs/terraform-provider-snowflake/blob/main/docs/technical-documentation/resource_migration.md). + +The new resources are more aligned with current features like: +- external access integrations support +- secrets support +- argument default values + ### *(new feature)* Account role data source Added a new `snowflake_account_roles` data source for account roles. Now it reflects It's based on `snowflake_roles` data source. `account_roles` field now organizes output of show under `show_output` field. diff --git a/docs/index.md b/docs/index.md index c36999718b..9055832dba 100644 --- a/docs/index.md +++ b/docs/index.md @@ -362,7 +362,9 @@ provider "snowflake" { ## Currently deprecated resources - [snowflake_database_old](./docs/resources/database_old) +- [snowflake_function](./docs/resources/function) - [snowflake_oauth_integration](./docs/resources/oauth_integration) +- [snowflake_procedure](./docs/resources/procedure) - [snowflake_role](./docs/resources/role) - use [snowflake_account_role](./docs/resources/account_role) instead - [snowflake_saml_integration](./docs/resources/saml_integration) - use [snowflake_saml2_integration](./docs/resources/saml2_integration) instead - [snowflake_stream](./docs/resources/stream) diff --git a/docs/resources/function.md b/docs/resources/function.md index f3a3290542..43b28436fc 100644 --- a/docs/resources/function.md +++ b/docs/resources/function.md @@ -7,7 +7,7 @@ description: |- # snowflake_function (Resource) - +~> **Deprecation** This resource is deprecated and will be removed in a future major version release. Please use snowflake_function_java, snowflake_function_javascript, snowflake_function_python, snowflake_function_scala, and snowflake_function_sql instead. ## Example Usage diff --git a/docs/resources/function_java.md b/docs/resources/function_java.md index 820bb4e63d..e1c86fdda8 100644 --- a/docs/resources/function_java.md +++ b/docs/resources/function_java.md @@ -5,11 +5,44 @@ description: |- Resource used to manage java function objects. For more information, check function documentation https://docs.snowflake.com/en/sql-reference/sql/create-function. --- +-> **Note** External changes to `is_secure`, `return_results_behavior`, and `null_input_behavior` are not currently supported. They will be handled in the following versions of the provider which may still affect this resource. + +-> **Note** `COPY GRANTS` and `OR REPLACE` are not currently supported. + +-> **Note** `RETURN... [[ NOT ] NULL]` is not currently supported. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Use of return type `TABLE` is currently limited. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Snowflake is not returning full data type information for arguments which may lead to unexpected plan outputs. Diff suppression for such cases will be improved. + +-> **Note** Snowflake is not returning the default values for arguments so argument's `arg_default_value` external changes cannot be tracked. + +-> **Note** Limit the use of special characters (`.`, `'`, `/`, `"`, `(`, `)`, `[`, `]`, `{`, `}`, ` `) in argument names, stage ids, and secret ids. It's best to limit to only alphanumeric and underscores. There is a lot of parsing of SHOW/DESCRIBE outputs involved and using special characters may limit the possibility to achieve the correct results. + +~> **Required warehouse** This resource may require active warehouse. Please, make sure you have either set a DEFAULT_WAREHOUSE for the user, or specified a warehouse in the provider configuration. + # snowflake_function_java (Resource) Resource used to manage java function objects. For more information, check [function documentation](https://docs.snowflake.com/en/sql-reference/sql/create-function). - +## Example Usage + +```terraform +resource "snowflake_function_java" "w" { + database = "Database" + schema = "Schema" + name = "Name" + arguments { + arg_data_type = "VARCHAR(100)" + arg_name = "x" + } + return_type = "VARCHAR(100)" + handler = "TestFunc.echoVarchar" + function_definition = "\n\tclass TestFunc {\n\t\tpublic static String echoVarchar(String x) {\n\t\t\treturn x;\n\t\t}\n\t}\n" +} +``` +-> **Note** Instead of using fully_qualified_name, you can reference objects managed outside Terraform by constructing a correct ID, consult [identifiers guide](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/guides/identifiers#new-computed-fully-qualified-name-field-in-resources). + ## Schema @@ -173,3 +206,14 @@ Read-Only: - `schema_name` (String) - `secrets` (String) - `valid_for_clustering` (Boolean) + +## Import + +Import is supported using the following syntax: + +```shell +terraform import snowflake_function_java.example '""."".""(varchar, varchar, varchar)' +``` + +Note: Snowflake is not returning all information needed to populate the state correctly after import (e.g. data types with attributes like NUMBER(32, 10) are returned as NUMBER, default values for arguments are not returned at all). +Also, `ALTER` for functions is very limited so most of the attributes on this resource are marked as force new. Because of that, in multiple situations plan won't be empty after importing and manual state operations may be required. diff --git a/docs/resources/function_javascript.md b/docs/resources/function_javascript.md index 1619ab3a06..c81f21a080 100644 --- a/docs/resources/function_javascript.md +++ b/docs/resources/function_javascript.md @@ -5,11 +5,46 @@ description: |- Resource used to manage javascript function objects. For more information, check function documentation https://docs.snowflake.com/en/sql-reference/sql/create-function. --- +-> **Note** External changes to `is_secure`, `return_results_behavior`, and `null_input_behavior` are not currently supported. They will be handled in the following versions of the provider which may still affect this resource. + +-> **Note** `COPY GRANTS` and `OR REPLACE` are not currently supported. + +-> **Note** `RETURN... [[ NOT ] NULL]` is not currently supported. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Use of return type `TABLE` is currently limited. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Snowflake is not returning full data type information for arguments which may lead to unexpected plan outputs. Diff suppression for such cases will be improved. + +-> **Note** Snowflake is not returning the default values for arguments so argument's `arg_default_value` external changes cannot be tracked. + +-> **Note** Limit the use of special characters (`.`, `'`, `/`, `"`, `(`, `)`, `[`, `]`, `{`, `}`, ` `) in argument names, stage ids, and secret ids. It's best to limit to only alphanumeric and underscores. There is a lot of parsing of SHOW/DESCRIBE outputs involved and using special characters may limit the possibility to achieve the correct results. + +~> **Required warehouse** This resource may require active warehouse. Please, make sure you have either set a DEFAULT_WAREHOUSE for the user, or specified a warehouse in the provider configuration. + # snowflake_function_javascript (Resource) Resource used to manage javascript function objects. For more information, check [function documentation](https://docs.snowflake.com/en/sql-reference/sql/create-function). - +## Example Usage + +```terraform +# Minimal +resource "snowflake_function_javascript" "minimal" { + database = snowflake_database.test.name + schema = snowflake_schema.test.name + name = "my_javascript_function" + arguments { + arg_data_type = "VARIANT" + arg_name = "x" + } + function_definition = < **Note** Instead of using fully_qualified_name, you can reference objects managed outside Terraform by constructing a correct ID, consult [identifiers guide](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/guides/identifiers#new-computed-fully-qualified-name-field-in-resources). + ## Schema @@ -139,3 +174,14 @@ Read-Only: - `schema_name` (String) - `secrets` (String) - `valid_for_clustering` (Boolean) + +## Import + +Import is supported using the following syntax: + +```shell +terraform import snowflake_function_javascript.example '""."".""(varchar, varchar, varchar)' +``` + +Note: Snowflake is not returning all information needed to populate the state correctly after import (e.g. data types with attributes like NUMBER(32, 10) are returned as NUMBER, default values for arguments are not returned at all). +Also, `ALTER` for functions is very limited so most of the attributes on this resource are marked as force new. Because of that, in multiple situations plan won't be empty after importing and manual state operations may be required. diff --git a/docs/resources/function_python.md b/docs/resources/function_python.md index 21e4244789..66fee1c02f 100644 --- a/docs/resources/function_python.md +++ b/docs/resources/function_python.md @@ -5,11 +5,51 @@ description: |- Resource used to manage python function objects. For more information, check function documentation https://docs.snowflake.com/en/sql-reference/sql/create-function. --- +-> **Note** External changes to `is_secure`, `return_results_behavior`, and `null_input_behavior` are not currently supported. They will be handled in the following versions of the provider which may still affect this resource. + +-> **Note** `COPY GRANTS` and `OR REPLACE` are not currently supported. + +-> **Note** `RETURN... [[ NOT ] NULL]` is not currently supported. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** `is_aggregate` is not currently supported. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Use of return type `TABLE` is currently limited. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Snowflake is not returning full data type information for arguments which may lead to unexpected plan outputs. Diff suppression for such cases will be improved. + +-> **Note** Snowflake is not returning the default values for arguments so argument's `arg_default_value` external changes cannot be tracked. + +-> **Note** Limit the use of special characters (`.`, `'`, `/`, `"`, `(`, `)`, `[`, `]`, `{`, `}`, ` `) in argument names, stage ids, and secret ids. It's best to limit to only alphanumeric and underscores. There is a lot of parsing of SHOW/DESCRIBE outputs involved and using special characters may limit the possibility to achieve the correct results. + +~> **Required warehouse** This resource may require active warehouse. Please, make sure you have either set a DEFAULT_WAREHOUSE for the user, or specified a warehouse in the provider configuration. + # snowflake_function_python (Resource) Resource used to manage python function objects. For more information, check [function documentation](https://docs.snowflake.com/en/sql-reference/sql/create-function). - +## Example Usage + +```terraform +# Minimal +resource "snowflake_function_python" "minimal" { + database = snowflake_database.test.name + schema = snowflake_schema.test.name + name = "my_function_function" + runtime_version = "3.8" + arguments { + arg_data_type = "NUMBER(36, 2)" + arg_name = "x" + } + function_definition = < **Note** Instead of using fully_qualified_name, you can reference objects managed outside Terraform by constructing a correct ID, consult [identifiers guide](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/guides/identifiers#new-computed-fully-qualified-name-field-in-resources). + ## Schema @@ -164,3 +204,14 @@ Read-Only: - `schema_name` (String) - `secrets` (String) - `valid_for_clustering` (Boolean) + +## Import + +Import is supported using the following syntax: + +```shell +terraform import snowflake_function_python.example '""."".""(varchar, varchar, varchar)' +``` + +Note: Snowflake is not returning all information needed to populate the state correctly after import (e.g. data types with attributes like NUMBER(32, 10) are returned as NUMBER, default values for arguments are not returned at all). +Also, `ALTER` for functions is very limited so most of the attributes on this resource are marked as force new. Because of that, in multiple situations plan won't be empty after importing and manual state operations may be required. diff --git a/docs/resources/function_scala.md b/docs/resources/function_scala.md index 01226e5512..b9da549e0f 100644 --- a/docs/resources/function_scala.md +++ b/docs/resources/function_scala.md @@ -5,11 +5,97 @@ description: |- Resource used to manage scala function objects. For more information, check function documentation https://docs.snowflake.com/en/sql-reference/sql/create-function. --- +-> **Note** External changes to `is_secure`, `return_results_behavior`, and `null_input_behavior` are not currently supported. They will be handled in the following versions of the provider which may still affect this resource. + +-> **Note** `COPY GRANTS` and `OR REPLACE` are not currently supported. + +-> **Note** `RETURN... [[ NOT ] NULL]` is not currently supported. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Snowflake is not returning full data type information for arguments which may lead to unexpected plan outputs. Diff suppression for such cases will be improved. + +-> **Note** Snowflake is not returning the default values for arguments so argument's `arg_default_value` external changes cannot be tracked. + +-> **Note** Limit the use of special characters (`.`, `'`, `/`, `"`, `(`, `)`, `[`, `]`, `{`, `}`, ` `) in argument names, stage ids, and secret ids. It's best to limit to only alphanumeric and underscores. There is a lot of parsing of SHOW/DESCRIBE outputs involved and using special characters may limit the possibility to achieve the correct results. + +~> **Required warehouse** This resource may require active warehouse. Please, make sure you have either set a DEFAULT_WAREHOUSE for the user, or specified a warehouse in the provider configuration. + # snowflake_function_scala (Resource) Resource used to manage scala function objects. For more information, check [function documentation](https://docs.snowflake.com/en/sql-reference/sql/create-function). - +## Example Usage + +```terraform +# Minimal +resource "snowflake_function_scala" "minimal" { + database = snowflake_database.test.name + schema = snowflake_schema.test.name + name = "my_scala_function" + arguments { + arg_data_type = "VARCHAR(100)" + arg_name = "x" + } + function_definition = < **Note** Instead of using fully_qualified_name, you can reference objects managed outside Terraform by constructing a correct ID, consult [identifiers guide](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/guides/identifiers#new-computed-fully-qualified-name-field-in-resources). + ## Schema @@ -173,3 +259,14 @@ Read-Only: - `schema_name` (String) - `secrets` (String) - `valid_for_clustering` (Boolean) + +## Import + +Import is supported using the following syntax: + +```shell +terraform import snowflake_function_scala.example '""."".""(varchar, varchar, varchar)' +``` + +Note: Snowflake is not returning all information needed to populate the state correctly after import (e.g. data types with attributes like NUMBER(32, 10) are returned as NUMBER, default values for arguments are not returned at all). +Also, `ALTER` for functions is very limited so most of the attributes on this resource are marked as force new. Because of that, in multiple situations plan won't be empty after importing and manual state operations may be required. diff --git a/docs/resources/function_sql.md b/docs/resources/function_sql.md index bb4e772742..82efdc328a 100644 --- a/docs/resources/function_sql.md +++ b/docs/resources/function_sql.md @@ -5,11 +5,64 @@ description: |- Resource used to manage sql function objects. For more information, check function documentation https://docs.snowflake.com/en/sql-reference/sql/create-function. --- +-> **Note** External changes to `is_secure` and `return_results_behavior` are not currently supported. They will be handled in the following versions of the provider which may still affect this resource. + +-> **Note** `COPY GRANTS` and `OR REPLACE` are not currently supported. + +-> **Note** `MEMOIZABLE` is not currently supported. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Use of return type `TABLE` is currently limited. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Snowflake is not returning full data type information for arguments which may lead to unexpected plan outputs. Diff suppression for such cases will be improved. + +-> **Note** Snowflake is not returning the default values for arguments so argument's `arg_default_value` external changes cannot be tracked. + +-> **Note** Limit the use of special characters (`.`, `'`, `/`, `"`, `(`, `)`, `[`, `]`, `{`, `}`, ` `) in argument names, stage ids, and secret ids. It's best to limit to only alphanumeric and underscores. There is a lot of parsing of SHOW/DESCRIBE outputs involved and using special characters may limit the possibility to achieve the correct results. + +~> **Required warehouse** This resource may require active warehouse. Please, make sure you have either set a DEFAULT_WAREHOUSE for the user, or specified a warehouse in the provider configuration. + # snowflake_function_sql (Resource) Resource used to manage sql function objects. For more information, check [function documentation](https://docs.snowflake.com/en/sql-reference/sql/create-function). - +## Example Usage + +```terraform +# Minimal +resource "snowflake_function_sql" "minimal" { + database = snowflake_database.test.name + schema = snowflake_schema.test.name + name = "my_sql_function" + arguments { + arg_data_type = "FLOAT" + arg_name = "arg_name" + } + function_definition = < **Note** Instead of using fully_qualified_name, you can reference objects managed outside Terraform by constructing a correct ID, consult [identifiers guide](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/guides/identifiers#new-computed-fully-qualified-name-field-in-resources). + ## Schema @@ -138,3 +191,14 @@ Read-Only: - `schema_name` (String) - `secrets` (String) - `valid_for_clustering` (Boolean) + +## Import + +Import is supported using the following syntax: + +```shell +terraform import snowflake_function_sql.example '""."".""(varchar, varchar, varchar)' +``` + +Note: Snowflake is not returning all information needed to populate the state correctly after import (e.g. data types with attributes like NUMBER(32, 10) are returned as NUMBER, default values for arguments are not returned at all). +Also, `ALTER` for functions is very limited so most of the attributes on this resource are marked as force new. Because of that, in multiple situations plan won't be empty after importing and manual state operations may be required. diff --git a/docs/resources/procedure.md b/docs/resources/procedure.md index d8135b31b0..5985cb4dab 100644 --- a/docs/resources/procedure.md +++ b/docs/resources/procedure.md @@ -7,7 +7,7 @@ description: |- # snowflake_procedure (Resource) - +~> **Deprecation** This resource is deprecated and will be removed in a future major version release. Please use snowflake_procedure_java, snowflake_procedure_javascript, snowflake_procedure_python, snowflake_procedure_scala, and snowflake_procedure_sql instead. ## Example Usage diff --git a/docs/resources/procedure_java.md b/docs/resources/procedure_java.md index edc8047672..b7fae95a96 100644 --- a/docs/resources/procedure_java.md +++ b/docs/resources/procedure_java.md @@ -5,11 +5,92 @@ description: |- Resource used to manage java procedure objects. For more information, check procedure documentation https://docs.snowflake.com/en/sql-reference/sql/create-procedure. --- +-> **Note** External changes to `is_secure` and `null_input_behavior` are not currently supported. They will be handled in the following versions of the provider which may still affect this resource. + +-> **Note** `COPY GRANTS` and `OR REPLACE` are not currently supported. + +-> **Note** `RETURN... [[ NOT ] NULL]` is not currently supported. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Use of return type `TABLE` is currently limited. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Snowflake is not returning full data type information for arguments which may lead to unexpected plan outputs. Diff suppression for such cases will be improved. + +-> **Note** Snowflake is not returning the default values for arguments so argument's `arg_default_value` external changes cannot be tracked. + +-> **Note** Limit the use of special characters (`.`, `'`, `/`, `"`, `(`, `)`, `[`, `]`, `{`, `}`, ` `) in argument names, stage ids, and secret ids. It's best to limit to only alphanumeric and underscores. There is a lot of parsing of SHOW/DESCRIBE outputs involved and using special characters may limit the possibility to achieve the correct results. + +~> **Required warehouse** This resource may require active warehouse. Please, make sure you have either set a DEFAULT_WAREHOUSE for the user, or specified a warehouse in the provider configuration. + # snowflake_procedure_java (Resource) Resource used to manage java procedure objects. For more information, check [procedure documentation](https://docs.snowflake.com/en/sql-reference/sql/create-procedure). - +## Example Usage + +```terraform +# basic example +resource "snowflake_procedure_java" "basic" { + database = "Database" + schema = "Schema" + name = "ProcedureName" + arguments { + arg_data_type = "VARCHAR(100)" + arg_name = "x" + } + return_type = "VARCHAR(100)" + handler = "TestFunc.echoVarchar" + procedure_definition = "\n\timport com.snowflake.snowpark_java.*;\n\tclass TestFunc {\n\t\tpublic static String echoVarchar(Session session, String x) {\n\t\t\treturn x;\n\t\t}\n\t}\n" + runtime_version = "11" + snowpark_package = "1.14.0" +} + +# full example +resource "snowflake_procedure_java" "full" { + database = "Database" + schema = "Schema" + name = "ProcedureName" + arguments { + arg_data_type = "VARCHAR(100)" + arg_name = "x" + } + return_type = "VARCHAR(100)" + handler = "TestFunc.echoVarchar" + procedure_definition = "\n\timport com.snowflake.snowpark_java.*;\n\tclass TestFunc {\n\t\tpublic static String echoVarchar(Session session, String x) {\n\t\t\treturn x;\n\t\t}\n\t}\n" + runtime_version = "11" + snowpark_package = "1.14.0" + + comment = "some comment" + execute_as = "CALLER" + target_path { + path_on_stage = "tf-1734028493-OkoTf.jar" + stage_location = snowflake_stage.example.fully_qualified_name + } + packages = ["com.snowflake:telemetry:0.1.0"] + imports { + path_on_stage = "tf-1734028486-OLJpF.jar" + stage_location = "~" + } + imports { + path_on_stage = "tf-1734028491-EMoDC.jar" + stage_location = "~" + } + is_secure = "false" + null_input_behavior = "CALLED ON NULL INPUT" + external_access_integrations = [ + "INTEGRATION_1", "INTEGRATION_2" + ] + secrets { + secret_id = snowflake_secret_with_generic_string.example1.fully_qualified_name + secret_variable_name = "abc" + } + secrets { + secret_id = snowflake_secret_with_generic_string.example2.fully_qualified_name + secret_variable_name = "def" + } +} +``` +-> **Note** Instead of using fully_qualified_name, you can reference objects managed outside Terraform by constructing a correct ID, consult [identifiers guide](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/guides/identifiers#new-computed-fully-qualified-name-field-in-resources). + ## Schema @@ -29,7 +110,7 @@ Resource used to manage java procedure objects. For more information, check [pro - `arguments` (Block List) List of the arguments for the procedure. Consult the [docs](https://docs.snowflake.com/en/sql-reference/sql/create-procedure#all-languages) for more details. (see [below for nested schema](#nestedblock--arguments)) - `comment` (String) Specifies a comment for the procedure. - `enable_console_output` (Boolean) Enable stdout/stderr fast path logging for anonyous stored procs. This is a public parameter (similar to LOG_LEVEL). For more information, check [ENABLE_CONSOLE_OUTPUT docs](https://docs.snowflake.com/en/sql-reference/parameters#enable-console-output). -- `execute_as` (String) Specifies whether the stored procedure executes with the privileges of the owner (an “owner’s rights” stored procedure) or with the privileges of the caller (a “caller’s rights” stored procedure). If you execute the statement CREATE PROCEDURE … EXECUTE AS CALLER, then in the future the procedure will execute as a caller’s rights procedure. If you execute CREATE PROCEDURE … EXECUTE AS OWNER, then the procedure will execute as an owner’s rights procedure. For more information, see [Understanding caller’s rights and owner’s rights stored procedures](https://docs.snowflake.com/en/developer-guide/stored-procedure/stored-procedures-rights). Valid values are (case-insensitive): `EXECUTE AS CALLER` | `EXECUTE AS OWNER`. +- `execute_as` (String) Specifies whether the stored procedure executes with the privileges of the owner (an “owner’s rights” stored procedure) or with the privileges of the caller (a “caller’s rights” stored procedure). If you execute the statement CREATE PROCEDURE … EXECUTE AS CALLER, then in the future the procedure will execute as a caller’s rights procedure. If you execute CREATE PROCEDURE … EXECUTE AS OWNER, then the procedure will execute as an owner’s rights procedure. For more information, see [Understanding caller’s rights and owner’s rights stored procedures](https://docs.snowflake.com/en/developer-guide/stored-procedure/stored-procedures-rights). Valid values are (case-insensitive): `CALLER` | `OWNER`. - `external_access_integrations` (Set of String) The names of [external access integrations](https://docs.snowflake.com/en/sql-reference/sql/create-external-access-integration) needed in order for this procedure’s handler code to access external networks. An external access integration specifies [network rules](https://docs.snowflake.com/en/sql-reference/sql/create-network-rule) and [secrets](https://docs.snowflake.com/en/sql-reference/sql/create-secret) that specify external locations and credentials (if any) allowed for use by handler code when making requests of an external network, such as an external REST API. - `imports` (Block Set) The location (stage), path, and name of the file(s) to import. You must set the IMPORTS clause to include any files that your stored procedure depends on. If you are writing an in-line stored procedure, you can omit this clause, unless your code depends on classes defined outside the stored procedure or resource files. If you are writing a stored procedure with a staged handler, you must also include a path to the JAR file containing the stored procedure’s handler code. The IMPORTS definition cannot reference variables from arguments that are passed into the stored procedure. Each file in the IMPORTS clause must have a unique name, even if the files are in different subdirectories or different stages. (see [below for nested schema](#nestedblock--imports)) - `is_secure` (String) Specifies that the procedure is secure. For more information about secure procedures, see [Protecting Sensitive Information with Secure UDFs and Stored Procedures](https://docs.snowflake.com/en/developer-guide/secure-udf-procedure). Available options are: "true" or "false". When the value is not set in the configuration the provider will put "default" there which means to use the Snowflake default for this value. @@ -170,3 +251,14 @@ Read-Only: - `schema_name` (String) - `secrets` (String) - `valid_for_clustering` (Boolean) + +## Import + +Import is supported using the following syntax: + +```shell +terraform import snowflake_procedure_java.example '""."".""(varchar, varchar, varchar)' +``` + +Note: Snowflake is not returning all information needed to populate the state correctly after import (e.g. data types with attributes like NUMBER(32, 10) are returned as NUMBER, default values for arguments are not returned at all). +Also, `ALTER` for functions is very limited so most of the attributes on this resource are marked as force new. Because of that, in multiple situations plan won't be empty after importing and manual state operations may be required. diff --git a/docs/resources/procedure_javascript.md b/docs/resources/procedure_javascript.md index a8d0ee9db2..cecdf0a6f2 100644 --- a/docs/resources/procedure_javascript.md +++ b/docs/resources/procedure_javascript.md @@ -5,11 +5,44 @@ description: |- Resource used to manage javascript procedure objects. For more information, check procedure documentation https://docs.snowflake.com/en/sql-reference/sql/create-procedure. --- +-> **Note** External changes to `is_secure` and `null_input_behavior` are not currently supported. They will be handled in the following versions of the provider which may still affect this resource. + +-> **Note** `COPY GRANTS` and `OR REPLACE` are not currently supported. + +-> **Note** `RETURN... [[ NOT ] NULL]` is not currently supported. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Use of return type `TABLE` is currently limited. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Snowflake is not returning full data type information for arguments which may lead to unexpected plan outputs. Diff suppression for such cases will be improved. + +-> **Note** Snowflake is not returning the default values for arguments so argument's `arg_default_value` external changes cannot be tracked. + +-> **Note** Limit the use of special characters (`.`, `'`, `/`, `"`, `(`, `)`, `[`, `]`, `{`, `}`, ` `) in argument names, stage ids, and secret ids. It's best to limit to only alphanumeric and underscores. There is a lot of parsing of SHOW/DESCRIBE outputs involved and using special characters may limit the possibility to achieve the correct results. + +~> **Required warehouse** This resource may require active warehouse. Please, make sure you have either set a DEFAULT_WAREHOUSE for the user, or specified a warehouse in the provider configuration. + # snowflake_procedure_javascript (Resource) Resource used to manage javascript procedure objects. For more information, check [procedure documentation](https://docs.snowflake.com/en/sql-reference/sql/create-procedure). - +## Example Usage + +```terraform +# basic +resource "snowflake_procedure_javascript" "basic" { + database = "Database" + schema = "Schema" + name = "Name" + arguments { + arg_data_type = "VARCHAR(100)" + arg_name = "x" + } + return_type = "VARCHAR(100)" + procedure_definition = "\n\tif (x \u003c= 0) {\n\t\treturn 1;\n\t} else {\n\t\tvar result = 1;\n\t\tfor (var i = 2; i \u003c= x; i++) {\n\t\t\tresult = result * i;\n\t\t}\n\t\treturn result;\n\t}\n" +} +``` +-> **Note** Instead of using fully_qualified_name, you can reference objects managed outside Terraform by constructing a correct ID, consult [identifiers guide](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/guides/identifiers#new-computed-fully-qualified-name-field-in-resources). + ## Schema @@ -27,7 +60,7 @@ Resource used to manage javascript procedure objects. For more information, chec - `arguments` (Block List) List of the arguments for the procedure. Consult the [docs](https://docs.snowflake.com/en/sql-reference/sql/create-procedure#all-languages) for more details. (see [below for nested schema](#nestedblock--arguments)) - `comment` (String) Specifies a comment for the procedure. - `enable_console_output` (Boolean) Enable stdout/stderr fast path logging for anonyous stored procs. This is a public parameter (similar to LOG_LEVEL). For more information, check [ENABLE_CONSOLE_OUTPUT docs](https://docs.snowflake.com/en/sql-reference/parameters#enable-console-output). -- `execute_as` (String) Specifies whether the stored procedure executes with the privileges of the owner (an “owner’s rights” stored procedure) or with the privileges of the caller (a “caller’s rights” stored procedure). If you execute the statement CREATE PROCEDURE … EXECUTE AS CALLER, then in the future the procedure will execute as a caller’s rights procedure. If you execute CREATE PROCEDURE … EXECUTE AS OWNER, then the procedure will execute as an owner’s rights procedure. For more information, see [Understanding caller’s rights and owner’s rights stored procedures](https://docs.snowflake.com/en/developer-guide/stored-procedure/stored-procedures-rights). Valid values are (case-insensitive): `EXECUTE AS CALLER` | `EXECUTE AS OWNER`. +- `execute_as` (String) Specifies whether the stored procedure executes with the privileges of the owner (an “owner’s rights” stored procedure) or with the privileges of the caller (a “caller’s rights” stored procedure). If you execute the statement CREATE PROCEDURE … EXECUTE AS CALLER, then in the future the procedure will execute as a caller’s rights procedure. If you execute CREATE PROCEDURE … EXECUTE AS OWNER, then the procedure will execute as an owner’s rights procedure. For more information, see [Understanding caller’s rights and owner’s rights stored procedures](https://docs.snowflake.com/en/developer-guide/stored-procedure/stored-procedures-rights). Valid values are (case-insensitive): `CALLER` | `OWNER`. - `is_secure` (String) Specifies that the procedure is secure. For more information about secure procedures, see [Protecting Sensitive Information with Secure UDFs and Stored Procedures](https://docs.snowflake.com/en/developer-guide/secure-udf-procedure). Available options are: "true" or "false". When the value is not set in the configuration the provider will put "default" there which means to use the Snowflake default for this value. - `log_level` (String) LOG_LEVEL to use when filtering events For more information, check [LOG_LEVEL docs](https://docs.snowflake.com/en/sql-reference/parameters#log-level). - `metric_level` (String) METRIC_LEVEL value to control whether to emit metrics to Event Table For more information, check [METRIC_LEVEL docs](https://docs.snowflake.com/en/sql-reference/parameters#metric-level). @@ -135,3 +168,14 @@ Read-Only: - `schema_name` (String) - `secrets` (String) - `valid_for_clustering` (Boolean) + +## Import + +Import is supported using the following syntax: + +```shell +terraform import snowflake_procedure_javascript.example '""."".""(varchar, varchar, varchar)' +``` + +Note: Snowflake is not returning all information needed to populate the state correctly after import (e.g. data types with attributes like NUMBER(32, 10) are returned as NUMBER, default values for arguments are not returned at all). +Also, `ALTER` for functions is very limited so most of the attributes on this resource are marked as force new. Because of that, in multiple situations plan won't be empty after importing and manual state operations may be required. diff --git a/docs/resources/procedure_python.md b/docs/resources/procedure_python.md index 8761764754..9a857e15be 100644 --- a/docs/resources/procedure_python.md +++ b/docs/resources/procedure_python.md @@ -5,11 +5,48 @@ description: |- Resource used to manage python procedure objects. For more information, check procedure documentation https://docs.snowflake.com/en/sql-reference/sql/create-procedure. --- +-> **Note** External changes to `is_secure` and `null_input_behavior` are not currently supported. They will be handled in the following versions of the provider which may still affect this resource. + +-> **Note** `COPY GRANTS` and `OR REPLACE` are not currently supported. + +-> **Note** `RETURN... [[ NOT ] NULL]` is not currently supported. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** `is_aggregate` is not currently supported. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Use of return type `TABLE` is currently limited. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Snowflake is not returning full data type information for arguments which may lead to unexpected plan outputs. Diff suppression for such cases will be improved. + +-> **Note** Snowflake is not returning the default values for arguments so argument's `arg_default_value` external changes cannot be tracked. + +-> **Note** Limit the use of special characters (`.`, `'`, `/`, `"`, `(`, `)`, `[`, `]`, `{`, `}`, ` `) in argument names, stage ids, and secret ids. It's best to limit to only alphanumeric and underscores. There is a lot of parsing of SHOW/DESCRIBE outputs involved and using special characters may limit the possibility to achieve the correct results. + +~> **Required warehouse** This resource may require active warehouse. Please, make sure you have either set a DEFAULT_WAREHOUSE for the user, or specified a warehouse in the provider configuration. + # snowflake_procedure_python (Resource) Resource used to manage python procedure objects. For more information, check [procedure documentation](https://docs.snowflake.com/en/sql-reference/sql/create-procedure). - +## Example Usage + +```terraform +resource "snowflake_procedure_python" "w" { + database = "Database" + schema = "Schema" + name = "Name" + arguments { + arg_data_type = "VARCHAR(100)" + arg_name = "x" + } + return_type = "VARCHAR(100)" + handler = "echoVarchar" + procedure_definition = "\ndef echoVarchar(x):\n\tresult = \"\"\n\tfor a in range(5):\n\t\tresult += x\n\treturn result\n" + runtime_version = "3.8" + snowpark_package = "1.14.0" +} +``` +-> **Note** Instead of using fully_qualified_name, you can reference objects managed outside Terraform by constructing a correct ID, consult [identifiers guide](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/guides/identifiers#new-computed-fully-qualified-name-field-in-resources). + ## Schema @@ -29,7 +66,7 @@ Resource used to manage python procedure objects. For more information, check [p - `arguments` (Block List) List of the arguments for the procedure. Consult the [docs](https://docs.snowflake.com/en/sql-reference/sql/create-procedure#all-languages) for more details. (see [below for nested schema](#nestedblock--arguments)) - `comment` (String) Specifies a comment for the procedure. - `enable_console_output` (Boolean) Enable stdout/stderr fast path logging for anonyous stored procs. This is a public parameter (similar to LOG_LEVEL). For more information, check [ENABLE_CONSOLE_OUTPUT docs](https://docs.snowflake.com/en/sql-reference/parameters#enable-console-output). -- `execute_as` (String) Specifies whether the stored procedure executes with the privileges of the owner (an “owner’s rights” stored procedure) or with the privileges of the caller (a “caller’s rights” stored procedure). If you execute the statement CREATE PROCEDURE … EXECUTE AS CALLER, then in the future the procedure will execute as a caller’s rights procedure. If you execute CREATE PROCEDURE … EXECUTE AS OWNER, then the procedure will execute as an owner’s rights procedure. For more information, see [Understanding caller’s rights and owner’s rights stored procedures](https://docs.snowflake.com/en/developer-guide/stored-procedure/stored-procedures-rights). Valid values are (case-insensitive): `EXECUTE AS CALLER` | `EXECUTE AS OWNER`. +- `execute_as` (String) Specifies whether the stored procedure executes with the privileges of the owner (an “owner’s rights” stored procedure) or with the privileges of the caller (a “caller’s rights” stored procedure). If you execute the statement CREATE PROCEDURE … EXECUTE AS CALLER, then in the future the procedure will execute as a caller’s rights procedure. If you execute CREATE PROCEDURE … EXECUTE AS OWNER, then the procedure will execute as an owner’s rights procedure. For more information, see [Understanding caller’s rights and owner’s rights stored procedures](https://docs.snowflake.com/en/developer-guide/stored-procedure/stored-procedures-rights). Valid values are (case-insensitive): `CALLER` | `OWNER`. - `external_access_integrations` (Set of String) The names of [external access integrations](https://docs.snowflake.com/en/sql-reference/sql/create-external-access-integration) needed in order for this procedure’s handler code to access external networks. An external access integration specifies [network rules](https://docs.snowflake.com/en/sql-reference/sql/create-network-rule) and [secrets](https://docs.snowflake.com/en/sql-reference/sql/create-secret) that specify external locations and credentials (if any) allowed for use by handler code when making requests of an external network, such as an external REST API. - `imports` (Block Set) The location (stage), path, and name of the file(s) to import. You must set the IMPORTS clause to include any files that your stored procedure depends on. If you are writing an in-line stored procedure, you can omit this clause, unless your code depends on classes defined outside the stored procedure or resource files. If your stored procedure’s code will be on a stage, you must also include a path to the module file your code is in. The IMPORTS definition cannot reference variables from arguments that are passed into the stored procedure. Each file in the IMPORTS clause must have a unique name, even if the files are in different subdirectories or different stages. (see [below for nested schema](#nestedblock--imports)) - `is_secure` (String) Specifies that the procedure is secure. For more information about secure procedures, see [Protecting Sensitive Information with Secure UDFs and Stored Procedures](https://docs.snowflake.com/en/developer-guide/secure-udf-procedure). Available options are: "true" or "false". When the value is not set in the configuration the provider will put "default" there which means to use the Snowflake default for this value. @@ -160,3 +197,14 @@ Read-Only: - `schema_name` (String) - `secrets` (String) - `valid_for_clustering` (Boolean) + +## Import + +Import is supported using the following syntax: + +```shell +terraform import snowflake_procedure_python.example '""."".""(varchar, varchar, varchar)' +``` + +Note: Snowflake is not returning all information needed to populate the state correctly after import (e.g. data types with attributes like NUMBER(32, 10) are returned as NUMBER, default values for arguments are not returned at all). +Also, `ALTER` for functions is very limited so most of the attributes on this resource are marked as force new. Because of that, in multiple situations plan won't be empty after importing and manual state operations may be required. diff --git a/docs/resources/procedure_scala.md b/docs/resources/procedure_scala.md index ef76be8b1d..51d0382cbf 100644 --- a/docs/resources/procedure_scala.md +++ b/docs/resources/procedure_scala.md @@ -5,11 +5,44 @@ description: |- Resource used to manage scala procedure objects. For more information, check procedure documentation https://docs.snowflake.com/en/sql-reference/sql/create-procedure. --- +-> **Note** External changes to `is_secure` and `null_input_behavior` are not currently supported. They will be handled in the following versions of the provider which may still affect this resource. + +-> **Note** `COPY GRANTS` and `OR REPLACE` are not currently supported. + +-> **Note** `RETURN... [[ NOT ] NULL]` is not currently supported. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Snowflake is not returning full data type information for arguments which may lead to unexpected plan outputs. Diff suppression for such cases will be improved. + +-> **Note** Snowflake is not returning the default values for arguments so argument's `arg_default_value` external changes cannot be tracked. + +-> **Note** Limit the use of special characters (`.`, `'`, `/`, `"`, `(`, `)`, `[`, `]`, `{`, `}`, ` `) in argument names, stage ids, and secret ids. It's best to limit to only alphanumeric and underscores. There is a lot of parsing of SHOW/DESCRIBE outputs involved and using special characters may limit the possibility to achieve the correct results. + +~> **Required warehouse** This resource may require active warehouse. Please, make sure you have either set a DEFAULT_WAREHOUSE for the user, or specified a warehouse in the provider configuration. + # snowflake_procedure_scala (Resource) Resource used to manage scala procedure objects. For more information, check [procedure documentation](https://docs.snowflake.com/en/sql-reference/sql/create-procedure). - +## Example Usage + +```terraform +resource "snowflake_procedure_scala" "w" { + database = "Database" + schema = "Schema" + name = "Name" + arguments { + arg_data_type = "VARCHAR(100)" + arg_name = "x" + } + return_type = "VARCHAR(100)" + handler = "TestFunc.echoVarchar" + procedure_definition = "\n\timport com.snowflake.snowpark_java.Session\n\n\tclass TestFunc {\n\t\tdef echoVarchar(session : Session, x : String): String = {\n\t\t\treturn x\n\t\t}\n\t}\n" + runtime_version = "2.12" + snowpark_package = "1.14.0" +} +``` +-> **Note** Instead of using fully_qualified_name, you can reference objects managed outside Terraform by constructing a correct ID, consult [identifiers guide](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/guides/identifiers#new-computed-fully-qualified-name-field-in-resources). + ## Schema @@ -29,7 +62,7 @@ Resource used to manage scala procedure objects. For more information, check [pr - `arguments` (Block List) List of the arguments for the procedure. Consult the [docs](https://docs.snowflake.com/en/sql-reference/sql/create-procedure#all-languages) for more details. (see [below for nested schema](#nestedblock--arguments)) - `comment` (String) Specifies a comment for the procedure. - `enable_console_output` (Boolean) Enable stdout/stderr fast path logging for anonyous stored procs. This is a public parameter (similar to LOG_LEVEL). For more information, check [ENABLE_CONSOLE_OUTPUT docs](https://docs.snowflake.com/en/sql-reference/parameters#enable-console-output). -- `execute_as` (String) Specifies whether the stored procedure executes with the privileges of the owner (an “owner’s rights” stored procedure) or with the privileges of the caller (a “caller’s rights” stored procedure). If you execute the statement CREATE PROCEDURE … EXECUTE AS CALLER, then in the future the procedure will execute as a caller’s rights procedure. If you execute CREATE PROCEDURE … EXECUTE AS OWNER, then the procedure will execute as an owner’s rights procedure. For more information, see [Understanding caller’s rights and owner’s rights stored procedures](https://docs.snowflake.com/en/developer-guide/stored-procedure/stored-procedures-rights). Valid values are (case-insensitive): `EXECUTE AS CALLER` | `EXECUTE AS OWNER`. +- `execute_as` (String) Specifies whether the stored procedure executes with the privileges of the owner (an “owner’s rights” stored procedure) or with the privileges of the caller (a “caller’s rights” stored procedure). If you execute the statement CREATE PROCEDURE … EXECUTE AS CALLER, then in the future the procedure will execute as a caller’s rights procedure. If you execute CREATE PROCEDURE … EXECUTE AS OWNER, then the procedure will execute as an owner’s rights procedure. For more information, see [Understanding caller’s rights and owner’s rights stored procedures](https://docs.snowflake.com/en/developer-guide/stored-procedure/stored-procedures-rights). Valid values are (case-insensitive): `CALLER` | `OWNER`. - `external_access_integrations` (Set of String) The names of [external access integrations](https://docs.snowflake.com/en/sql-reference/sql/create-external-access-integration) needed in order for this procedure’s handler code to access external networks. An external access integration specifies [network rules](https://docs.snowflake.com/en/sql-reference/sql/create-network-rule) and [secrets](https://docs.snowflake.com/en/sql-reference/sql/create-secret) that specify external locations and credentials (if any) allowed for use by handler code when making requests of an external network, such as an external REST API. - `imports` (Block Set) The location (stage), path, and name of the file(s) to import. You must set the IMPORTS clause to include any files that your stored procedure depends on. If you are writing an in-line stored procedure, you can omit this clause, unless your code depends on classes defined outside the stored procedure or resource files. If you are writing a stored procedure with a staged handler, you must also include a path to the JAR file containing the stored procedure’s handler code. The IMPORTS definition cannot reference variables from arguments that are passed into the stored procedure. Each file in the IMPORTS clause must have a unique name, even if the files are in different subdirectories or different stages. (see [below for nested schema](#nestedblock--imports)) - `is_secure` (String) Specifies that the procedure is secure. For more information about secure procedures, see [Protecting Sensitive Information with Secure UDFs and Stored Procedures](https://docs.snowflake.com/en/developer-guide/secure-udf-procedure). Available options are: "true" or "false". When the value is not set in the configuration the provider will put "default" there which means to use the Snowflake default for this value. @@ -170,3 +203,14 @@ Read-Only: - `schema_name` (String) - `secrets` (String) - `valid_for_clustering` (Boolean) + +## Import + +Import is supported using the following syntax: + +```shell +terraform import snowflake_procedure_scala.example '""."".""(varchar, varchar, varchar)' +``` + +Note: Snowflake is not returning all information needed to populate the state correctly after import (e.g. data types with attributes like NUMBER(32, 10) are returned as NUMBER, default values for arguments are not returned at all). +Also, `ALTER` for functions is very limited so most of the attributes on this resource are marked as force new. Because of that, in multiple situations plan won't be empty after importing and manual state operations may be required. diff --git a/docs/resources/procedure_sql.md b/docs/resources/procedure_sql.md index 3dcc0fefb7..3814df934f 100644 --- a/docs/resources/procedure_sql.md +++ b/docs/resources/procedure_sql.md @@ -5,11 +5,41 @@ description: |- Resource used to manage sql procedure objects. For more information, check procedure documentation https://docs.snowflake.com/en/sql-reference/sql/create-procedure. --- +-> **Note** External changes to `is_secure` are not currently supported. They will be handled in the following versions of the provider which may still affect this resource. + +-> **Note** `COPY GRANTS` and `OR REPLACE` are not currently supported. + +-> **Note** Use of return type `TABLE` is currently limited. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Snowflake is not returning full data type information for arguments which may lead to unexpected plan outputs. Diff suppression for such cases will be improved. + +-> **Note** Snowflake is not returning the default values for arguments so argument's `arg_default_value` external changes cannot be tracked. + +-> **Note** Limit the use of special characters (`.`, `'`, `/`, `"`, `(`, `)`, `[`, `]`, `{`, `}`, ` `) in argument names, stage ids, and secret ids. It's best to limit to only alphanumeric and underscores. There is a lot of parsing of SHOW/DESCRIBE outputs involved and using special characters may limit the possibility to achieve the correct results. + +~> **Required warehouse** This resource may require active warehouse. Please, make sure you have either set a DEFAULT_WAREHOUSE for the user, or specified a warehouse in the provider configuration. + # snowflake_procedure_sql (Resource) Resource used to manage sql procedure objects. For more information, check [procedure documentation](https://docs.snowflake.com/en/sql-reference/sql/create-procedure). - +## Example Usage + +```terraform +resource "snowflake_procedure_sql" "w" { + database = "Database" + schema = "Schema" + name = "Name" + arguments { + arg_data_type = "VARCHAR(100)" + arg_name = "x" + } + return_type = "VARCHAR(100)" + procedure_definition = "\nBEGIN\n RETURN message;\nEND;\n" +} +``` +-> **Note** Instead of using fully_qualified_name, you can reference objects managed outside Terraform by constructing a correct ID, consult [identifiers guide](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/guides/identifiers#new-computed-fully-qualified-name-field-in-resources). + ## Schema @@ -27,7 +57,7 @@ Resource used to manage sql procedure objects. For more information, check [proc - `arguments` (Block List) List of the arguments for the procedure. Consult the [docs](https://docs.snowflake.com/en/sql-reference/sql/create-procedure#all-languages) for more details. (see [below for nested schema](#nestedblock--arguments)) - `comment` (String) Specifies a comment for the procedure. - `enable_console_output` (Boolean) Enable stdout/stderr fast path logging for anonyous stored procs. This is a public parameter (similar to LOG_LEVEL). For more information, check [ENABLE_CONSOLE_OUTPUT docs](https://docs.snowflake.com/en/sql-reference/parameters#enable-console-output). -- `execute_as` (String) Specifies whether the stored procedure executes with the privileges of the owner (an “owner’s rights” stored procedure) or with the privileges of the caller (a “caller’s rights” stored procedure). If you execute the statement CREATE PROCEDURE … EXECUTE AS CALLER, then in the future the procedure will execute as a caller’s rights procedure. If you execute CREATE PROCEDURE … EXECUTE AS OWNER, then the procedure will execute as an owner’s rights procedure. For more information, see [Understanding caller’s rights and owner’s rights stored procedures](https://docs.snowflake.com/en/developer-guide/stored-procedure/stored-procedures-rights). Valid values are (case-insensitive): `EXECUTE AS CALLER` | `EXECUTE AS OWNER`. +- `execute_as` (String) Specifies whether the stored procedure executes with the privileges of the owner (an “owner’s rights” stored procedure) or with the privileges of the caller (a “caller’s rights” stored procedure). If you execute the statement CREATE PROCEDURE … EXECUTE AS CALLER, then in the future the procedure will execute as a caller’s rights procedure. If you execute CREATE PROCEDURE … EXECUTE AS OWNER, then the procedure will execute as an owner’s rights procedure. For more information, see [Understanding caller’s rights and owner’s rights stored procedures](https://docs.snowflake.com/en/developer-guide/stored-procedure/stored-procedures-rights). Valid values are (case-insensitive): `CALLER` | `OWNER`. - `is_secure` (String) Specifies that the procedure is secure. For more information about secure procedures, see [Protecting Sensitive Information with Secure UDFs and Stored Procedures](https://docs.snowflake.com/en/developer-guide/secure-udf-procedure). Available options are: "true" or "false". When the value is not set in the configuration the provider will put "default" there which means to use the Snowflake default for this value. - `log_level` (String) LOG_LEVEL to use when filtering events For more information, check [LOG_LEVEL docs](https://docs.snowflake.com/en/sql-reference/parameters#log-level). - `metric_level` (String) METRIC_LEVEL value to control whether to emit metrics to Event Table For more information, check [METRIC_LEVEL docs](https://docs.snowflake.com/en/sql-reference/parameters#metric-level). @@ -135,3 +165,14 @@ Read-Only: - `schema_name` (String) - `secrets` (String) - `valid_for_clustering` (Boolean) + +## Import + +Import is supported using the following syntax: + +```shell +terraform import snowflake_procedure_sql.example '""."".""(varchar, varchar, varchar)' +``` + +Note: Snowflake is not returning all information needed to populate the state correctly after import (e.g. data types with attributes like NUMBER(32, 10) are returned as NUMBER, default values for arguments are not returned at all). +Also, `ALTER` for functions is very limited so most of the attributes on this resource are marked as force new. Because of that, in multiple situations plan won't be empty after importing and manual state operations may be required. diff --git a/examples/additional/deprecated_resources.MD b/examples/additional/deprecated_resources.MD index b0a8941854..0f6a49a421 100644 --- a/examples/additional/deprecated_resources.MD +++ b/examples/additional/deprecated_resources.MD @@ -1,7 +1,9 @@ ## Currently deprecated resources - [snowflake_database_old](./docs/resources/database_old) +- [snowflake_function](./docs/resources/function) - [snowflake_oauth_integration](./docs/resources/oauth_integration) +- [snowflake_procedure](./docs/resources/procedure) - [snowflake_role](./docs/resources/role) - use [snowflake_account_role](./docs/resources/account_role) instead - [snowflake_saml_integration](./docs/resources/saml_integration) - use [snowflake_saml2_integration](./docs/resources/saml2_integration) instead - [snowflake_stream](./docs/resources/stream) diff --git a/examples/resources/snowflake_function_java/import.sh b/examples/resources/snowflake_function_java/import.sh new file mode 100644 index 0000000000..0b92dc8ebb --- /dev/null +++ b/examples/resources/snowflake_function_java/import.sh @@ -0,0 +1 @@ +terraform import snowflake_function_java.example '""."".""(varchar, varchar, varchar)' diff --git a/examples/resources/snowflake_function_java/resource.tf b/examples/resources/snowflake_function_java/resource.tf new file mode 100644 index 0000000000..a34d6af477 --- /dev/null +++ b/examples/resources/snowflake_function_java/resource.tf @@ -0,0 +1,12 @@ +resource "snowflake_function_java" "w" { + database = "Database" + schema = "Schema" + name = "Name" + arguments { + arg_data_type = "VARCHAR(100)" + arg_name = "x" + } + return_type = "VARCHAR(100)" + handler = "TestFunc.echoVarchar" + function_definition = "\n\tclass TestFunc {\n\t\tpublic static String echoVarchar(String x) {\n\t\t\treturn x;\n\t\t}\n\t}\n" +} diff --git a/examples/resources/snowflake_function_javascript/import.sh b/examples/resources/snowflake_function_javascript/import.sh new file mode 100644 index 0000000000..12b84c4fe0 --- /dev/null +++ b/examples/resources/snowflake_function_javascript/import.sh @@ -0,0 +1 @@ +terraform import snowflake_function_javascript.example '""."".""(varchar, varchar, varchar)' diff --git a/examples/resources/snowflake_function_javascript/resource.tf b/examples/resources/snowflake_function_javascript/resource.tf new file mode 100644 index 0000000000..9cff28c6e0 --- /dev/null +++ b/examples/resources/snowflake_function_javascript/resource.tf @@ -0,0 +1,14 @@ +# Minimal +resource "snowflake_function_javascript" "minimal" { + database = snowflake_database.test.name + schema = snowflake_schema.test.name + name = "my_javascript_function" + arguments { + arg_data_type = "VARIANT" + arg_name = "x" + } + function_definition = <"."".""(varchar, varchar, varchar)' + diff --git a/examples/resources/snowflake_function_python/resource.tf b/examples/resources/snowflake_function_python/resource.tf new file mode 100644 index 0000000000..50a450a239 --- /dev/null +++ b/examples/resources/snowflake_function_python/resource.tf @@ -0,0 +1,17 @@ +# Minimal +resource "snowflake_function_python" "minimal" { + database = snowflake_database.test.name + schema = snowflake_schema.test.name + name = "my_function_function" + runtime_version = "3.8" + arguments { + arg_data_type = "NUMBER(36, 2)" + arg_name = "x" + } + function_definition = <"."".""(varchar, varchar, varchar)' diff --git a/examples/resources/snowflake_function_scala/resource.tf b/examples/resources/snowflake_function_scala/resource.tf new file mode 100644 index 0000000000..0fa07b79ff --- /dev/null +++ b/examples/resources/snowflake_function_scala/resource.tf @@ -0,0 +1,67 @@ +# Minimal +resource "snowflake_function_scala" "minimal" { + database = snowflake_database.test.name + schema = snowflake_schema.test.name + name = "my_scala_function" + arguments { + arg_data_type = "VARCHAR(100)" + arg_name = "x" + } + function_definition = <"."".""(varchar, varchar, varchar)' diff --git a/examples/resources/snowflake_function_sql/resource.tf b/examples/resources/snowflake_function_sql/resource.tf new file mode 100644 index 0000000000..16a91889dd --- /dev/null +++ b/examples/resources/snowflake_function_sql/resource.tf @@ -0,0 +1,32 @@ +# Minimal +resource "snowflake_function_sql" "minimal" { + database = snowflake_database.test.name + schema = snowflake_schema.test.name + name = "my_sql_function" + arguments { + arg_data_type = "FLOAT" + arg_name = "arg_name" + } + function_definition = <"."".""(varchar, varchar, varchar)' diff --git a/examples/resources/snowflake_procedure_java/resource.tf b/examples/resources/snowflake_procedure_java/resource.tf new file mode 100644 index 0000000000..6f3bc051b9 --- /dev/null +++ b/examples/resources/snowflake_procedure_java/resource.tf @@ -0,0 +1,60 @@ +# basic example +resource "snowflake_procedure_java" "basic" { + database = "Database" + schema = "Schema" + name = "ProcedureName" + arguments { + arg_data_type = "VARCHAR(100)" + arg_name = "x" + } + return_type = "VARCHAR(100)" + handler = "TestFunc.echoVarchar" + procedure_definition = "\n\timport com.snowflake.snowpark_java.*;\n\tclass TestFunc {\n\t\tpublic static String echoVarchar(Session session, String x) {\n\t\t\treturn x;\n\t\t}\n\t}\n" + runtime_version = "11" + snowpark_package = "1.14.0" +} + +# full example +resource "snowflake_procedure_java" "full" { + database = "Database" + schema = "Schema" + name = "ProcedureName" + arguments { + arg_data_type = "VARCHAR(100)" + arg_name = "x" + } + return_type = "VARCHAR(100)" + handler = "TestFunc.echoVarchar" + procedure_definition = "\n\timport com.snowflake.snowpark_java.*;\n\tclass TestFunc {\n\t\tpublic static String echoVarchar(Session session, String x) {\n\t\t\treturn x;\n\t\t}\n\t}\n" + runtime_version = "11" + snowpark_package = "1.14.0" + + comment = "some comment" + execute_as = "CALLER" + target_path { + path_on_stage = "tf-1734028493-OkoTf.jar" + stage_location = snowflake_stage.example.fully_qualified_name + } + packages = ["com.snowflake:telemetry:0.1.0"] + imports { + path_on_stage = "tf-1734028486-OLJpF.jar" + stage_location = "~" + } + imports { + path_on_stage = "tf-1734028491-EMoDC.jar" + stage_location = "~" + } + is_secure = "false" + null_input_behavior = "CALLED ON NULL INPUT" + external_access_integrations = [ + "INTEGRATION_1", "INTEGRATION_2" + ] + secrets { + secret_id = snowflake_secret_with_generic_string.example1.fully_qualified_name + secret_variable_name = "abc" + } + secrets { + secret_id = snowflake_secret_with_generic_string.example2.fully_qualified_name + secret_variable_name = "def" + } +} diff --git a/examples/resources/snowflake_procedure_javascript/import.sh b/examples/resources/snowflake_procedure_javascript/import.sh new file mode 100644 index 0000000000..15833413b7 --- /dev/null +++ b/examples/resources/snowflake_procedure_javascript/import.sh @@ -0,0 +1 @@ +terraform import snowflake_procedure_javascript.example '""."".""(varchar, varchar, varchar)' diff --git a/examples/resources/snowflake_procedure_javascript/resource.tf b/examples/resources/snowflake_procedure_javascript/resource.tf new file mode 100644 index 0000000000..5ad3f42b62 --- /dev/null +++ b/examples/resources/snowflake_procedure_javascript/resource.tf @@ -0,0 +1,12 @@ +# basic +resource "snowflake_procedure_javascript" "basic" { + database = "Database" + schema = "Schema" + name = "Name" + arguments { + arg_data_type = "VARCHAR(100)" + arg_name = "x" + } + return_type = "VARCHAR(100)" + procedure_definition = "\n\tif (x \u003c= 0) {\n\t\treturn 1;\n\t} else {\n\t\tvar result = 1;\n\t\tfor (var i = 2; i \u003c= x; i++) {\n\t\t\tresult = result * i;\n\t\t}\n\t\treturn result;\n\t}\n" +} diff --git a/examples/resources/snowflake_procedure_python/import.sh b/examples/resources/snowflake_procedure_python/import.sh new file mode 100644 index 0000000000..ccc897486f --- /dev/null +++ b/examples/resources/snowflake_procedure_python/import.sh @@ -0,0 +1 @@ +terraform import snowflake_procedure_python.example '""."".""(varchar, varchar, varchar)' diff --git a/examples/resources/snowflake_procedure_python/resource.tf b/examples/resources/snowflake_procedure_python/resource.tf new file mode 100644 index 0000000000..3f4987d36b --- /dev/null +++ b/examples/resources/snowflake_procedure_python/resource.tf @@ -0,0 +1,14 @@ +resource "snowflake_procedure_python" "w" { + database = "Database" + schema = "Schema" + name = "Name" + arguments { + arg_data_type = "VARCHAR(100)" + arg_name = "x" + } + return_type = "VARCHAR(100)" + handler = "echoVarchar" + procedure_definition = "\ndef echoVarchar(x):\n\tresult = \"\"\n\tfor a in range(5):\n\t\tresult += x\n\treturn result\n" + runtime_version = "3.8" + snowpark_package = "1.14.0" +} diff --git a/examples/resources/snowflake_procedure_scala/import.sh b/examples/resources/snowflake_procedure_scala/import.sh new file mode 100644 index 0000000000..6efc556919 --- /dev/null +++ b/examples/resources/snowflake_procedure_scala/import.sh @@ -0,0 +1 @@ +terraform import snowflake_procedure_scala.example '""."".""(varchar, varchar, varchar)' diff --git a/examples/resources/snowflake_procedure_scala/resource.tf b/examples/resources/snowflake_procedure_scala/resource.tf new file mode 100644 index 0000000000..889473e122 --- /dev/null +++ b/examples/resources/snowflake_procedure_scala/resource.tf @@ -0,0 +1,14 @@ +resource "snowflake_procedure_scala" "w" { + database = "Database" + schema = "Schema" + name = "Name" + arguments { + arg_data_type = "VARCHAR(100)" + arg_name = "x" + } + return_type = "VARCHAR(100)" + handler = "TestFunc.echoVarchar" + procedure_definition = "\n\timport com.snowflake.snowpark_java.Session\n\n\tclass TestFunc {\n\t\tdef echoVarchar(session : Session, x : String): String = {\n\t\t\treturn x\n\t\t}\n\t}\n" + runtime_version = "2.12" + snowpark_package = "1.14.0" +} diff --git a/examples/resources/snowflake_procedure_sql/import.sh b/examples/resources/snowflake_procedure_sql/import.sh new file mode 100644 index 0000000000..f976bd6fed --- /dev/null +++ b/examples/resources/snowflake_procedure_sql/import.sh @@ -0,0 +1 @@ +terraform import snowflake_procedure_sql.example '""."".""(varchar, varchar, varchar)' diff --git a/examples/resources/snowflake_procedure_sql/resource.tf b/examples/resources/snowflake_procedure_sql/resource.tf new file mode 100644 index 0000000000..77258c73d9 --- /dev/null +++ b/examples/resources/snowflake_procedure_sql/resource.tf @@ -0,0 +1,11 @@ +resource "snowflake_procedure_sql" "w" { + database = "Database" + schema = "Schema" + name = "Name" + arguments { + arg_data_type = "VARCHAR(100)" + arg_name = "x" + } + return_type = "VARCHAR(100)" + procedure_definition = "\nBEGIN\n RETURN message;\nEND;\n" +} diff --git a/pkg/acceptance/bettertestspoc/assert/resourceassert/procedure_python_resource_ext.go b/pkg/acceptance/bettertestspoc/assert/resourceassert/procedure_python_resource_ext.go new file mode 100644 index 0000000000..5890820342 --- /dev/null +++ b/pkg/acceptance/bettertestspoc/assert/resourceassert/procedure_python_resource_ext.go @@ -0,0 +1,12 @@ +package resourceassert + +import ( + "strconv" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert" +) + +func (f *ProcedurePythonResourceAssert) HasImportsLength(len int) *ProcedurePythonResourceAssert { + f.AddAssertion(assert.ValueSet("imports.#", strconv.FormatInt(int64(len), 10))) + return f +} diff --git a/pkg/acceptance/bettertestspoc/assert/resourceassert/procedure_scala_resource_ext.go b/pkg/acceptance/bettertestspoc/assert/resourceassert/procedure_scala_resource_ext.go new file mode 100644 index 0000000000..86473eaad2 --- /dev/null +++ b/pkg/acceptance/bettertestspoc/assert/resourceassert/procedure_scala_resource_ext.go @@ -0,0 +1,17 @@ +package resourceassert + +import ( + "strconv" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert" +) + +func (f *ProcedureScalaResourceAssert) HasImportsLength(len int) *ProcedureScalaResourceAssert { + f.AddAssertion(assert.ValueSet("imports.#", strconv.FormatInt(int64(len), 10))) + return f +} + +func (f *ProcedureScalaResourceAssert) HasTargetPathEmpty() *ProcedureScalaResourceAssert { + f.AddAssertion(assert.ValueSet("target_path.#", "0")) + return f +} diff --git a/pkg/acceptance/bettertestspoc/config/model/procedure_javascript_model_ext.go b/pkg/acceptance/bettertestspoc/config/model/procedure_javascript_model_ext.go index 548259aa97..4952c06d38 100644 --- a/pkg/acceptance/bettertestspoc/config/model/procedure_javascript_model_ext.go +++ b/pkg/acceptance/bettertestspoc/config/model/procedure_javascript_model_ext.go @@ -2,6 +2,11 @@ package model import ( "encoding/json" + + tfconfig "github.com/hashicorp/terraform-plugin-testing/config" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk/datatypes" ) func (f *ProcedureJavascriptModel) MarshalJSON() ([]byte, error) { @@ -14,3 +19,23 @@ func (f *ProcedureJavascriptModel) MarshalJSON() ([]byte, error) { DependsOn: f.DependsOn(), }) } + +func ProcedureJavascriptBasicInline( + resourceName string, + id sdk.SchemaObjectIdentifierWithArguments, + returnType datatypes.DataType, + procedureDefinition string, +) *ProcedureJavascriptModel { + return ProcedureJavascript(resourceName, id.DatabaseName(), id.Name(), procedureDefinition, returnType.ToSql(), id.SchemaName()) +} + +func (f *ProcedureJavascriptModel) WithArgument(argName string, argDataType datatypes.DataType) *ProcedureJavascriptModel { + return f.WithArgumentsValue( + tfconfig.ObjectVariable( + map[string]tfconfig.Variable{ + "arg_name": tfconfig.StringVariable(argName), + "arg_data_type": tfconfig.StringVariable(argDataType.ToSql()), + }, + ), + ) +} diff --git a/pkg/acceptance/bettertestspoc/config/model/procedure_python_model_ext.go b/pkg/acceptance/bettertestspoc/config/model/procedure_python_model_ext.go index 1bff75bcc2..3ebd87eca7 100644 --- a/pkg/acceptance/bettertestspoc/config/model/procedure_python_model_ext.go +++ b/pkg/acceptance/bettertestspoc/config/model/procedure_python_model_ext.go @@ -2,6 +2,12 @@ package model import ( "encoding/json" + + tfconfig "github.com/hashicorp/terraform-plugin-testing/config" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/collections" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk/datatypes" ) func (f *ProcedurePythonModel) MarshalJSON() ([]byte, error) { @@ -14,3 +20,74 @@ func (f *ProcedurePythonModel) MarshalJSON() ([]byte, error) { DependsOn: f.DependsOn(), }) } + +func ProcedurePythonBasicInline( + resourceName string, + id sdk.SchemaObjectIdentifierWithArguments, + returnType datatypes.DataType, + handler string, + procedureDefinition string, +) *ProcedurePythonModel { + return ProcedurePython(resourceName, id.DatabaseName(), handler, id.Name(), returnType.ToSql(), "3.8", id.SchemaName(), "1.14.0"). + WithProcedureDefinition(procedureDefinition) +} + +func (f *ProcedurePythonModel) WithArgument(argName string, argDataType datatypes.DataType) *ProcedurePythonModel { + return f.WithArgumentsValue( + tfconfig.ObjectVariable( + map[string]tfconfig.Variable{ + "arg_name": tfconfig.StringVariable(argName), + "arg_data_type": tfconfig.StringVariable(argDataType.ToSql()), + }, + ), + ) +} + +func (f *ProcedurePythonModel) WithImports(imports ...sdk.NormalizedPath) *ProcedurePythonModel { + return f.WithImportsValue( + tfconfig.SetVariable( + collections.Map(imports, func(imp sdk.NormalizedPath) tfconfig.Variable { + return tfconfig.ObjectVariable( + map[string]tfconfig.Variable{ + "stage_location": tfconfig.StringVariable(imp.StageLocation), + "path_on_stage": tfconfig.StringVariable(imp.PathOnStage), + }, + ) + })..., + ), + ) +} + +func (f *ProcedurePythonModel) WithPackages(pkgs ...string) *ProcedurePythonModel { + return f.WithPackagesValue( + tfconfig.SetVariable( + collections.Map(pkgs, func(pkg string) tfconfig.Variable { return tfconfig.StringVariable(pkg) })..., + ), + ) +} + +func (f *ProcedurePythonModel) WithExternalAccessIntegrations(ids ...sdk.AccountObjectIdentifier) *ProcedurePythonModel { + return f.WithExternalAccessIntegrationsValue( + tfconfig.SetVariable( + collections.Map(ids, func(id sdk.AccountObjectIdentifier) tfconfig.Variable { return tfconfig.StringVariable(id.Name()) })..., + ), + ) +} + +func (f *ProcedurePythonModel) WithSecrets(secrets map[string]sdk.SchemaObjectIdentifier) *ProcedurePythonModel { + objects := make([]tfconfig.Variable, 0) + for k, v := range secrets { + objects = append(objects, tfconfig.ObjectVariable( + map[string]tfconfig.Variable{ + "secret_variable_name": tfconfig.StringVariable(k), + "secret_id": tfconfig.StringVariable(v.FullyQualifiedName()), + }, + )) + } + + return f.WithSecretsValue( + tfconfig.SetVariable( + objects..., + ), + ) +} diff --git a/pkg/acceptance/bettertestspoc/config/model/procedure_scala_model_ext.go b/pkg/acceptance/bettertestspoc/config/model/procedure_scala_model_ext.go index b7434a4250..c78de9dbcc 100644 --- a/pkg/acceptance/bettertestspoc/config/model/procedure_scala_model_ext.go +++ b/pkg/acceptance/bettertestspoc/config/model/procedure_scala_model_ext.go @@ -2,6 +2,12 @@ package model import ( "encoding/json" + + tfconfig "github.com/hashicorp/terraform-plugin-testing/config" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/collections" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk/datatypes" ) func (f *ProcedureScalaModel) MarshalJSON() ([]byte, error) { @@ -14,3 +20,120 @@ func (f *ProcedureScalaModel) MarshalJSON() ([]byte, error) { DependsOn: f.DependsOn(), }) } + +func ProcedureScalaBasicInline( + resourceName string, + id sdk.SchemaObjectIdentifierWithArguments, + returnType datatypes.DataType, + handler string, + procedureDefinition string, +) *ProcedureScalaModel { + return ProcedureScala(resourceName, id.DatabaseName(), handler, id.Name(), returnType.ToSql(), "2.12", id.SchemaName(), "1.14.0"). + WithProcedureDefinition(procedureDefinition) +} + +func ProcedureScalaBasicStaged( + resourceName string, + id sdk.SchemaObjectIdentifierWithArguments, + returnType datatypes.DataType, + handler string, + stageLocation string, + pathOnStage string, +) *ProcedureScalaModel { + return ProcedureScala(resourceName, id.DatabaseName(), handler, id.Name(), returnType.ToSql(), "2.12", id.SchemaName(), "1.14.0"). + WithImport(stageLocation, pathOnStage) +} + +func (f *ProcedureScalaModel) WithArgument(argName string, argDataType datatypes.DataType) *ProcedureScalaModel { + return f.WithArgumentsValue( + tfconfig.ObjectVariable( + map[string]tfconfig.Variable{ + "arg_name": tfconfig.StringVariable(argName), + "arg_data_type": tfconfig.StringVariable(argDataType.ToSql()), + }, + ), + ) +} + +func (f *ProcedureScalaModel) WithArgumentWithDefaultValue(argName string, argDataType datatypes.DataType, value string) *ProcedureScalaModel { + return f.WithArgumentsValue( + tfconfig.ObjectVariable( + map[string]tfconfig.Variable{ + "arg_name": tfconfig.StringVariable(argName), + "arg_data_type": tfconfig.StringVariable(argDataType.ToSql()), + "arg_default_value": tfconfig.StringVariable(value), + }, + ), + ) +} + +func (f *ProcedureScalaModel) WithImport(stageLocation string, pathOnStage string) *ProcedureScalaModel { + return f.WithImportsValue( + tfconfig.ObjectVariable( + map[string]tfconfig.Variable{ + "stage_location": tfconfig.StringVariable(stageLocation), + "path_on_stage": tfconfig.StringVariable(pathOnStage), + }, + ), + ) +} + +func (f *ProcedureScalaModel) WithImports(imports ...sdk.NormalizedPath) *ProcedureScalaModel { + return f.WithImportsValue( + tfconfig.SetVariable( + collections.Map(imports, func(imp sdk.NormalizedPath) tfconfig.Variable { + return tfconfig.ObjectVariable( + map[string]tfconfig.Variable{ + "stage_location": tfconfig.StringVariable(imp.StageLocation), + "path_on_stage": tfconfig.StringVariable(imp.PathOnStage), + }, + ) + })..., + ), + ) +} + +func (f *ProcedureScalaModel) WithPackages(pkgs ...string) *ProcedureScalaModel { + return f.WithPackagesValue( + tfconfig.SetVariable( + collections.Map(pkgs, func(pkg string) tfconfig.Variable { return tfconfig.StringVariable(pkg) })..., + ), + ) +} + +func (f *ProcedureScalaModel) WithExternalAccessIntegrations(ids ...sdk.AccountObjectIdentifier) *ProcedureScalaModel { + return f.WithExternalAccessIntegrationsValue( + tfconfig.SetVariable( + collections.Map(ids, func(id sdk.AccountObjectIdentifier) tfconfig.Variable { return tfconfig.StringVariable(id.Name()) })..., + ), + ) +} + +func (f *ProcedureScalaModel) WithSecrets(secrets map[string]sdk.SchemaObjectIdentifier) *ProcedureScalaModel { + objects := make([]tfconfig.Variable, 0) + for k, v := range secrets { + objects = append(objects, tfconfig.ObjectVariable( + map[string]tfconfig.Variable{ + "secret_variable_name": tfconfig.StringVariable(k), + "secret_id": tfconfig.StringVariable(v.FullyQualifiedName()), + }, + )) + } + + return f.WithSecretsValue( + tfconfig.SetVariable( + objects..., + ), + ) +} + +func (f *ProcedureScalaModel) WithTargetPathParts(stageLocation string, pathOnStage string) *ProcedureScalaModel { + return f.WithTargetPathValue( + tfconfig.ObjectVariable( + map[string]tfconfig.Variable{ + "stage_location": tfconfig.StringVariable(stageLocation), + "path_on_stage": tfconfig.StringVariable(pathOnStage), + }, + ), + ) +} diff --git a/pkg/acceptance/bettertestspoc/config/model/procedure_sql_model_ext.go b/pkg/acceptance/bettertestspoc/config/model/procedure_sql_model_ext.go index 8b5dc3afbf..0cb2a2bf8c 100644 --- a/pkg/acceptance/bettertestspoc/config/model/procedure_sql_model_ext.go +++ b/pkg/acceptance/bettertestspoc/config/model/procedure_sql_model_ext.go @@ -2,6 +2,11 @@ package model import ( "encoding/json" + + tfconfig "github.com/hashicorp/terraform-plugin-testing/config" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk/datatypes" ) func (f *ProcedureSqlModel) MarshalJSON() ([]byte, error) { @@ -14,3 +19,23 @@ func (f *ProcedureSqlModel) MarshalJSON() ([]byte, error) { DependsOn: f.DependsOn(), }) } + +func ProcedureSqlBasicInline( + resourceName string, + id sdk.SchemaObjectIdentifierWithArguments, + returnType datatypes.DataType, + procedureDefinition string, +) *ProcedureSqlModel { + return ProcedureSql(resourceName, id.DatabaseName(), id.Name(), procedureDefinition, returnType.ToSql(), id.SchemaName()) +} + +func (f *ProcedureSqlModel) WithArgument(argName string, argDataType datatypes.DataType) *ProcedureSqlModel { + return f.WithArgumentsValue( + tfconfig.ObjectVariable( + map[string]tfconfig.Variable{ + "arg_name": tfconfig.StringVariable(argName), + "arg_data_type": tfconfig.StringVariable(argDataType.ToSql()), + }, + ), + ) +} diff --git a/pkg/acceptance/helpers/procedure_client.go b/pkg/acceptance/helpers/procedure_client.go index 7e77e37782..b35f9239df 100644 --- a/pkg/acceptance/helpers/procedure_client.go +++ b/pkg/acceptance/helpers/procedure_client.go @@ -245,3 +245,13 @@ BEGIN END; ` } + +func (c *ProcedureClient) SampleSqlDefinitionWithArgument(t *testing.T) string { + t.Helper() + + return ` +BEGIN + RETURN message; +END; +` +} diff --git a/pkg/resources/function.go b/pkg/resources/function.go index 69e972f7d5..663dcf5693 100644 --- a/pkg/resources/function.go +++ b/pkg/resources/function.go @@ -173,6 +173,8 @@ func Function() *schema.Resource { UpdateContext: TrackingUpdateWrapper(resources.Function, UpdateContextFunction), DeleteContext: TrackingDeleteWrapper(resources.Function, DeleteFunction), + DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_function_java, snowflake_function_javascript, snowflake_function_python, snowflake_function_scala, and snowflake_function_sql instead.", + CustomizeDiff: TrackingCustomDiffWrapper(resources.Function, customdiff.All( // TODO(SNOW-1348103): add `arguments` to ComputedIfAnyAttributeChanged. This can't be done now because this function compares values without diff suppress. ComputedIfAnyAttributeChanged(functionSchema, FullyQualifiedNameAttributeName, "name"), diff --git a/pkg/resources/procedure.go b/pkg/resources/procedure.go index fa986ae8f5..2c567902f8 100644 --- a/pkg/resources/procedure.go +++ b/pkg/resources/procedure.go @@ -188,6 +188,8 @@ func Procedure() *schema.Resource { UpdateContext: TrackingUpdateWrapper(resources.Procedure, UpdateContextProcedure), DeleteContext: TrackingDeleteWrapper(resources.Procedure, DeleteProcedure), + DeprecationMessage: "This resource is deprecated and will be removed in a future major version release. Please use snowflake_procedure_java, snowflake_procedure_javascript, snowflake_procedure_python, snowflake_procedure_scala, and snowflake_procedure_sql instead.", + // TODO(SNOW-1348106): add `arguments` to ComputedIfAnyAttributeChanged for FullyQualifiedNameAttributeName. // This can't be done now because this function compares values without diff suppress. CustomizeDiff: TrackingCustomDiffWrapper(resources.Procedure, customdiff.All( diff --git a/pkg/resources/procedure_commons.go b/pkg/resources/procedure_commons.go index 83d79963a5..1cd819647b 100644 --- a/pkg/resources/procedure_commons.go +++ b/pkg/resources/procedure_commons.go @@ -467,12 +467,33 @@ func UpdateProcedure(language string, readFunc func(ctx context.Context, d *sche if !reflect.DeepEqual(*setRequest, *sdk.NewProcedureSetRequest()) { err := client.Procedures.Alter(ctx, sdk.NewAlterProcedureRequest(id).WithSet(*setRequest)) if err != nil { + d.Partial(true) return diag.FromErr(err) } } if !reflect.DeepEqual(*unsetRequest, *sdk.NewProcedureUnsetRequest()) { err := client.Procedures.Alter(ctx, sdk.NewAlterProcedureRequest(id).WithUnset(*unsetRequest)) if err != nil { + d.Partial(true) + return diag.FromErr(err) + } + } + + // has to be handled separately + if d.HasChange("execute_as") { + var value sdk.ExecuteAs + if v, ok := d.GetOk("execute_as"); ok { + value, err = sdk.ToExecuteAs(v.(string)) + if err != nil { + return diag.FromErr(err) + } + } else { + // there is no UNSET, so we need to set it manually + value = sdk.ExecuteAsOwner + } + err = client.Procedures.Alter(ctx, sdk.NewAlterProcedureRequest(id).WithExecuteAs(value)) + if err != nil { + d.Partial(true) return diag.FromErr(err) } } @@ -505,6 +526,7 @@ func ImportProcedure(ctx context.Context, d *schema.ResourceData, meta any) ([]* d.Set("name", id.Name()), d.Set("is_secure", booleanStringFromBool(procedure.IsSecure)), setOptionalFromStringPtr(d, "null_input_behavior", procedureDetails.NullHandling), + d.Set("execute_as", procedureDetails.ExecuteAs), importFunctionOrProcedureArguments(d, procedureDetails.NormalizedArguments), // all others are set in read ) diff --git a/pkg/resources/procedure_java.go b/pkg/resources/procedure_java.go index 584c4da787..b9901eb77e 100644 --- a/pkg/resources/procedure_java.go +++ b/pkg/resources/procedure_java.go @@ -77,6 +77,7 @@ func CreateContextProcedureJava(ctx context.Context, d *schema.ResourceData, met errs := errors.Join( booleanStringAttributeCreateBuilder(d, "is_secure", request.WithSecure), attributeMappedValueCreateBuilder[string](d, "null_input_behavior", request.WithNullInputBehavior, sdk.ToNullInputBehavior), + attributeMappedValueCreateBuilder[string](d, "execute_as", request.WithExecuteAs, sdk.ToExecuteAs), stringAttributeCreateBuilder(d, "comment", request.WithComment), setProcedureImportsInBuilder(d, request.WithImports), setExternalAccessIntegrationsInBuilder(d, request.WithExternalAccessIntegrations), @@ -128,6 +129,7 @@ func ReadContextProcedureJava(ctx context.Context, d *schema.ResourceData, meta readFunctionOrProcedureArguments(d, allProcedureDetails.procedureDetails.NormalizedArguments), d.Set("return_type", allProcedureDetails.procedureDetails.ReturnDataType.ToSql()), // not reading null_input_behavior on purpose (handled as external change to show output) + // not reading execute_as on purpose (handled as external change to show output) setRequiredFromStringPtr(d, "runtime_version", allProcedureDetails.procedureDetails.RuntimeVersion), d.Set("comment", allProcedureDetails.procedure.Description), readFunctionOrProcedureImports(d, allProcedureDetails.procedureDetails.NormalizedImports), diff --git a/pkg/resources/procedure_java_acceptance_test.go b/pkg/resources/procedure_java_acceptance_test.go index b7a81a0b40..651e1e35c5 100644 --- a/pkg/resources/procedure_java_acceptance_test.go +++ b/pkg/resources/procedure_java_acceptance_test.go @@ -81,7 +81,7 @@ func TestAcc_ProcedureJava_InlineBasic(t *testing.T) { ResourceName: procedureModel.ResourceReference(), ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"is_secure", "arguments.0.arg_data_type", "null_input_behavior"}, + ImportStateVerifyIgnore: []string{"is_secure", "arguments.0.arg_data_type", "null_input_behavior", "execute_as"}, ImportStateCheck: assert.AssertThatImport(t, resourceassert.ImportedProcedureJavaResource(t, id.FullyQualifiedName()). HasFullyQualifiedNameString(id.FullyQualifiedName()), @@ -236,6 +236,7 @@ func TestAcc_ProcedureJava_InlineFull(t *testing.T) { WithRuntimeVersion("11"). WithIsSecure("false"). WithNullInputBehavior(string(sdk.NullInputBehaviorCalledOnNullInput)). + WithExecuteAs(string(sdk.ExecuteAsCaller)). WithComment("some comment") procedureModelUpdateWithoutRecreation := model.ProcedureJavaBasicInline("w", id, dataType, handler, definition). @@ -254,6 +255,7 @@ func TestAcc_ProcedureJava_InlineFull(t *testing.T) { WithRuntimeVersion("11"). WithIsSecure("false"). WithNullInputBehavior(string(sdk.NullInputBehaviorCalledOnNullInput)). + WithExecuteAs(string(sdk.ExecuteAsOwner)). WithComment("some other comment") resource.Test(t, resource.TestCase{ @@ -276,6 +278,7 @@ func TestAcc_ProcedureJava_InlineFull(t *testing.T) { HasProcedureDefinitionString(definition). HasCommentString("some comment"). HasProcedureLanguageString("JAVA"). + HasExecuteAsString(string(sdk.ExecuteAsCaller)). HasFullyQualifiedNameString(id.FullyQualifiedName()), assert.Check(resource.TestCheckResourceAttr(procedureModel.ResourceReference(), "target_path.0.stage_location", stage.ID().FullyQualifiedName())), assert.Check(resource.TestCheckResourceAttr(procedureModel.ResourceReference(), "target_path.0.path_on_stage", jarName)), @@ -318,6 +321,7 @@ func TestAcc_ProcedureJava_InlineFull(t *testing.T) { HasProcedureDefinitionString(definition). HasCommentString("some other comment"). HasProcedureLanguageString("JAVA"). + HasExecuteAsString(string(sdk.ExecuteAsOwner)). HasFullyQualifiedNameString(id.FullyQualifiedName()), assert.Check(resource.TestCheckResourceAttr(procedureModelUpdateWithoutRecreation.ResourceReference(), "target_path.0.stage_location", stage.ID().FullyQualifiedName())), assert.Check(resource.TestCheckResourceAttr(procedureModelUpdateWithoutRecreation.ResourceReference(), "target_path.0.path_on_stage", jarName)), diff --git a/pkg/resources/procedure_javascript.go b/pkg/resources/procedure_javascript.go index 97336f2839..d2b8fa9392 100644 --- a/pkg/resources/procedure_javascript.go +++ b/pkg/resources/procedure_javascript.go @@ -70,6 +70,7 @@ func CreateContextProcedureJavascript(ctx context.Context, d *schema.ResourceDat errs := errors.Join( booleanStringAttributeCreateBuilder(d, "is_secure", request.WithSecure), attributeMappedValueCreateBuilder[string](d, "null_input_behavior", request.WithNullInputBehavior, sdk.ToNullInputBehavior), + attributeMappedValueCreateBuilder[string](d, "execute_as", request.WithExecuteAs, sdk.ToExecuteAs), stringAttributeCreateBuilder(d, "comment", request.WithComment), ) if errs != nil { @@ -116,6 +117,7 @@ func ReadContextProcedureJavascript(ctx context.Context, d *schema.ResourceData, readFunctionOrProcedureArguments(d, allProcedureDetails.procedureDetails.NormalizedArguments), d.Set("return_type", allProcedureDetails.procedureDetails.ReturnDataType.ToSql()), // not reading null_input_behavior on purpose (handled as external change to show output) + // not reading execute_as on purpose (handled as external change to show output) d.Set("comment", allProcedureDetails.procedure.Description), setOptionalFromStringPtr(d, "procedure_definition", allProcedureDetails.procedureDetails.Body), d.Set("procedure_language", allProcedureDetails.procedureDetails.Language), diff --git a/pkg/resources/procedure_javascript_acceptance_test.go b/pkg/resources/procedure_javascript_acceptance_test.go new file mode 100644 index 0000000000..3a6bf5efd8 --- /dev/null +++ b/pkg/resources/procedure_javascript_acceptance_test.go @@ -0,0 +1,178 @@ +package resources_test + +import ( + "testing" + + acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" + r "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert/resourceassert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert/resourceshowoutputassert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/config" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/config/model" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/importchecks" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/testdatatypes" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/testenvs" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider/resources" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/tfversion" +) + +func TestAcc_ProcedureJavascript_InlineBasic(t *testing.T) { + argName := "x" + dataType := testdatatypes.DataTypeVarchar_100 + + id := acc.TestClient().Ids.RandomSchemaObjectIdentifierWithArgumentsNewDataTypes(dataType) + idWithChangedNameButTheSameDataType := acc.TestClient().Ids.RandomSchemaObjectIdentifierWithArgumentsNewDataTypes(dataType) + + definition := acc.TestClient().Procedure.SampleJavascriptDefinition(t, argName) + + procedureModel := model.ProcedureJavascriptBasicInline("w", id, dataType, definition). + WithArgument(argName, dataType) + procedureModelRenamed := model.ProcedureJavascriptBasicInline("w", idWithChangedNameButTheSameDataType, dataType, definition). + WithArgument(argName, dataType) + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + PreCheck: func() { acc.TestAccPreCheck(t) }, + CheckDestroy: acc.CheckDestroy(t, resources.ProcedureJavascript), + Steps: []resource.TestStep{ + // CREATE BASIC + { + Config: config.FromModels(t, procedureModel), + Check: assert.AssertThat(t, + resourceassert.ProcedureJavascriptResource(t, procedureModel.ResourceReference()). + HasNameString(id.Name()). + HasIsSecureString(r.BooleanDefault). + HasCommentString(sdk.DefaultProcedureComment). + HasProcedureDefinitionString(definition). + HasProcedureLanguageString("JAVASCRIPT"). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + resourceshowoutputassert.ProcedureShowOutput(t, procedureModel.ResourceReference()). + HasIsSecure(false), + assert.Check(resource.TestCheckResourceAttr(procedureModel.ResourceReference(), "arguments.0.arg_name", argName)), + assert.Check(resource.TestCheckResourceAttr(procedureModel.ResourceReference(), "arguments.0.arg_data_type", dataType.ToSql())), + assert.Check(resource.TestCheckResourceAttr(procedureModel.ResourceReference(), "arguments.0.arg_default_value", "")), + ), + }, + // IMPORT + { + ResourceName: procedureModel.ResourceReference(), + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"is_secure", "arguments.0.arg_data_type", "null_input_behavior", "execute_as"}, + ImportStateCheck: assert.AssertThatImport(t, + resourceassert.ImportedProcedureJavascriptResource(t, id.FullyQualifiedName()). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + assert.CheckImport(importchecks.TestCheckResourceAttrInstanceState(helpers.EncodeResourceIdentifier(id), "arguments.0.arg_name", argName)), + assert.CheckImport(importchecks.TestCheckResourceAttrInstanceState(helpers.EncodeResourceIdentifier(id), "arguments.0.arg_data_type", "VARCHAR(16777216)")), + assert.CheckImport(importchecks.TestCheckResourceAttrInstanceState(helpers.EncodeResourceIdentifier(id), "arguments.0.arg_default_value", "")), + ), + }, + // RENAME + { + Config: config.FromModels(t, procedureModelRenamed), + Check: assert.AssertThat(t, + resourceassert.ProcedureJavascriptResource(t, procedureModelRenamed.ResourceReference()). + HasNameString(idWithChangedNameButTheSameDataType.Name()). + HasFullyQualifiedNameString(idWithChangedNameButTheSameDataType.FullyQualifiedName()), + ), + }, + }, + }) +} + +func TestAcc_ProcedureJavascript_InlineFull(t *testing.T) { + _ = testenvs.GetOrSkipTest(t, testenvs.EnableAcceptance) + acc.TestAccPreCheck(t) + + argName := "x" + dataType := testdatatypes.DataTypeVarchar_100 + + id := acc.TestClient().Ids.RandomSchemaObjectIdentifierWithArgumentsNewDataTypes(dataType) + + definition := acc.TestClient().Procedure.SampleJavascriptDefinition(t, argName) + + procedureModel := model.ProcedureJavascriptBasicInline("w", id, dataType, definition). + WithArgument(argName, dataType). + WithIsSecure("false"). + WithNullInputBehavior(string(sdk.NullInputBehaviorCalledOnNullInput)). + WithExecuteAs(string(sdk.ExecuteAsCaller)). + WithComment("some comment") + + procedureModelUpdateWithoutRecreation := model.ProcedureJavascriptBasicInline("w", id, dataType, definition). + WithArgument(argName, dataType). + WithIsSecure("false"). + WithNullInputBehavior(string(sdk.NullInputBehaviorCalledOnNullInput)). + WithExecuteAs(string(sdk.ExecuteAsOwner)). + WithComment("some other comment") + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + PreCheck: func() { acc.TestAccPreCheck(t) }, + CheckDestroy: acc.CheckDestroy(t, resources.ProcedureJavascript), + Steps: []resource.TestStep{ + // CREATE BASIC + { + Config: config.FromModels(t, procedureModel), + Check: assert.AssertThat(t, + resourceassert.ProcedureJavascriptResource(t, procedureModel.ResourceReference()). + HasNameString(id.Name()). + HasIsSecureString(r.BooleanFalse). + HasProcedureDefinitionString(definition). + HasCommentString("some comment"). + HasProcedureLanguageString("JAVASCRIPT"). + HasExecuteAsString(string(sdk.ExecuteAsCaller)). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + resourceshowoutputassert.ProcedureShowOutput(t, procedureModel.ResourceReference()). + HasIsSecure(false), + ), + }, + // IMPORT + { + ResourceName: procedureModel.ResourceReference(), + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"arguments.0.arg_data_type"}, + ImportStateCheck: assert.AssertThatImport(t, + resourceassert.ImportedProcedureJavascriptResource(t, id.FullyQualifiedName()). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + assert.CheckImport(importchecks.TestCheckResourceAttrInstanceState(helpers.EncodeResourceIdentifier(id), "arguments.0.arg_name", argName)), + assert.CheckImport(importchecks.TestCheckResourceAttrInstanceState(helpers.EncodeResourceIdentifier(id), "arguments.0.arg_data_type", "VARCHAR(16777216)")), + assert.CheckImport(importchecks.TestCheckResourceAttrInstanceState(helpers.EncodeResourceIdentifier(id), "arguments.0.arg_default_value", "")), + ), + }, + // UPDATE WITHOUT RECREATION + { + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(procedureModelUpdateWithoutRecreation.ResourceReference(), plancheck.ResourceActionUpdate), + }, + }, + Config: config.FromModels(t, procedureModelUpdateWithoutRecreation), + Check: assert.AssertThat(t, + resourceassert.ProcedureJavascriptResource(t, procedureModelUpdateWithoutRecreation.ResourceReference()). + HasNameString(id.Name()). + HasIsSecureString(r.BooleanFalse). + HasProcedureDefinitionString(definition). + HasCommentString("some other comment"). + HasProcedureLanguageString("JAVASCRIPT"). + HasExecuteAsString(string(sdk.ExecuteAsOwner)). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + resourceshowoutputassert.ProcedureShowOutput(t, procedureModelUpdateWithoutRecreation.ResourceReference()). + HasIsSecure(false), + ), + }, + }, + }) +} diff --git a/pkg/resources/procedure_python.go b/pkg/resources/procedure_python.go index deb95c9871..eb62cdac7b 100644 --- a/pkg/resources/procedure_python.go +++ b/pkg/resources/procedure_python.go @@ -77,6 +77,7 @@ func CreateContextProcedurePython(ctx context.Context, d *schema.ResourceData, m errs := errors.Join( booleanStringAttributeCreateBuilder(d, "is_secure", request.WithSecure), attributeMappedValueCreateBuilder[string](d, "null_input_behavior", request.WithNullInputBehavior, sdk.ToNullInputBehavior), + attributeMappedValueCreateBuilder[string](d, "execute_as", request.WithExecuteAs, sdk.ToExecuteAs), stringAttributeCreateBuilder(d, "comment", request.WithComment), setProcedureImportsInBuilder(d, request.WithImports), setExternalAccessIntegrationsInBuilder(d, request.WithExternalAccessIntegrations), @@ -127,6 +128,7 @@ func ReadContextProcedurePython(ctx context.Context, d *schema.ResourceData, met readFunctionOrProcedureArguments(d, allProcedureDetails.procedureDetails.NormalizedArguments), d.Set("return_type", allProcedureDetails.procedureDetails.ReturnDataType.ToSql()), // not reading null_input_behavior on purpose (handled as external change to show output) + // not reading execute_as on purpose (handled as external change to show output) setRequiredFromStringPtr(d, "runtime_version", allProcedureDetails.procedureDetails.RuntimeVersion), d.Set("comment", allProcedureDetails.procedure.Description), readFunctionOrProcedureImports(d, allProcedureDetails.procedureDetails.NormalizedImports), diff --git a/pkg/resources/procedure_python_acceptance_test.go b/pkg/resources/procedure_python_acceptance_test.go new file mode 100644 index 0000000000..7932a83381 --- /dev/null +++ b/pkg/resources/procedure_python_acceptance_test.go @@ -0,0 +1,240 @@ +package resources_test + +import ( + "testing" + + acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" + r "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert/resourceassert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert/resourceshowoutputassert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/config" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/config/model" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/importchecks" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/testdatatypes" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/testenvs" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider/resources" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/tfversion" +) + +func TestAcc_ProcedurePython_InlineBasic(t *testing.T) { + funcName := "echoVarchar" + argName := "x" + dataType := testdatatypes.DataTypeVarchar_100 + + id := acc.TestClient().Ids.RandomSchemaObjectIdentifierWithArgumentsNewDataTypes(dataType) + idWithChangedNameButTheSameDataType := acc.TestClient().Ids.RandomSchemaObjectIdentifierWithArgumentsNewDataTypes(dataType) + + definition := acc.TestClient().Procedure.SamplePythonDefinition(t, funcName, argName) + + procedureModel := model.ProcedurePythonBasicInline("w", id, dataType, funcName, definition). + WithArgument(argName, dataType) + procedureModelRenamed := model.ProcedurePythonBasicInline("w", idWithChangedNameButTheSameDataType, dataType, funcName, definition). + WithArgument(argName, dataType) + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + PreCheck: func() { acc.TestAccPreCheck(t) }, + CheckDestroy: acc.CheckDestroy(t, resources.ProcedurePython), + Steps: []resource.TestStep{ + // CREATE BASIC + { + Config: config.FromModels(t, procedureModel), + Check: assert.AssertThat(t, + resourceassert.ProcedurePythonResource(t, procedureModel.ResourceReference()). + HasNameString(id.Name()). + HasIsSecureString(r.BooleanDefault). + HasCommentString(sdk.DefaultProcedureComment). + HasImportsLength(0). + HasRuntimeVersionString("3.8"). + HasProcedureDefinitionString(definition). + HasProcedureLanguageString("PYTHON"). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + resourceshowoutputassert.ProcedureShowOutput(t, procedureModel.ResourceReference()). + HasIsSecure(false), + assert.Check(resource.TestCheckResourceAttr(procedureModel.ResourceReference(), "arguments.0.arg_name", argName)), + assert.Check(resource.TestCheckResourceAttr(procedureModel.ResourceReference(), "arguments.0.arg_data_type", dataType.ToSql())), + assert.Check(resource.TestCheckResourceAttr(procedureModel.ResourceReference(), "arguments.0.arg_default_value", "")), + ), + }, + // IMPORT + { + ResourceName: procedureModel.ResourceReference(), + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"is_secure", "arguments.0.arg_data_type", "null_input_behavior", "execute_as"}, + ImportStateCheck: assert.AssertThatImport(t, + resourceassert.ImportedProcedurePythonResource(t, id.FullyQualifiedName()). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + assert.CheckImport(importchecks.TestCheckResourceAttrInstanceState(helpers.EncodeResourceIdentifier(id), "arguments.0.arg_name", argName)), + assert.CheckImport(importchecks.TestCheckResourceAttrInstanceState(helpers.EncodeResourceIdentifier(id), "arguments.0.arg_data_type", "VARCHAR(16777216)")), + assert.CheckImport(importchecks.TestCheckResourceAttrInstanceState(helpers.EncodeResourceIdentifier(id), "arguments.0.arg_default_value", "")), + ), + }, + // RENAME + { + Config: config.FromModels(t, procedureModelRenamed), + Check: assert.AssertThat(t, + resourceassert.ProcedurePythonResource(t, procedureModelRenamed.ResourceReference()). + HasNameString(idWithChangedNameButTheSameDataType.Name()). + HasFullyQualifiedNameString(idWithChangedNameButTheSameDataType.FullyQualifiedName()), + ), + }, + }, + }) +} + +func TestAcc_ProcedurePython_InlineFull(t *testing.T) { + _ = testenvs.GetOrSkipTest(t, testenvs.EnableAcceptance) + acc.TestAccPreCheck(t) + + secretId := acc.TestClient().Ids.RandomSchemaObjectIdentifier() + secretId2 := acc.TestClient().Ids.RandomSchemaObjectIdentifier() + + networkRule, networkRuleCleanup := acc.TestClient().NetworkRule.Create(t) + t.Cleanup(networkRuleCleanup) + + secret, secretCleanup := acc.TestClient().Secret.CreateWithGenericString(t, secretId, "test_secret_string") + t.Cleanup(secretCleanup) + + secret2, secret2Cleanup := acc.TestClient().Secret.CreateWithGenericString(t, secretId2, "test_secret_string_2") + t.Cleanup(secret2Cleanup) + + externalAccessIntegration, externalAccessIntegrationCleanup := acc.TestClient().ExternalAccessIntegration.CreateExternalAccessIntegrationWithNetworkRuleAndSecret(t, networkRule.ID(), secret.ID()) + t.Cleanup(externalAccessIntegrationCleanup) + + externalAccessIntegration2, externalAccessIntegration2Cleanup := acc.TestClient().ExternalAccessIntegration.CreateExternalAccessIntegrationWithNetworkRuleAndSecret(t, networkRule.ID(), secret2.ID()) + t.Cleanup(externalAccessIntegration2Cleanup) + + tmpPythonFunction := acc.TestClient().CreateSamplePythonFunctionAndModule(t) + tmpPythonFunction2 := acc.TestClient().CreateSamplePythonFunctionAndModule(t) + + funcName := "echoVarchar" + argName := "x" + dataType := testdatatypes.DataTypeVarchar_100 + + id := acc.TestClient().Ids.RandomSchemaObjectIdentifierWithArgumentsNewDataTypes(dataType) + + definition := acc.TestClient().Procedure.SamplePythonDefinition(t, funcName, argName) + + procedureModel := model.ProcedurePythonBasicInline("w", id, dataType, funcName, definition). + WithArgument(argName, dataType). + WithImports( + sdk.NormalizedPath{StageLocation: "~", PathOnStage: tmpPythonFunction.PythonFileName()}, + sdk.NormalizedPath{StageLocation: "~", PathOnStage: tmpPythonFunction2.PythonFileName()}, + ). + WithSnowparkPackage("1.14.0"). + WithPackages("absl-py==0.10.0"). + WithExternalAccessIntegrations(externalAccessIntegration, externalAccessIntegration2). + WithSecrets(map[string]sdk.SchemaObjectIdentifier{ + "abc": secretId, + "def": secretId2, + }). + WithRuntimeVersion("3.8"). + WithIsSecure("false"). + WithNullInputBehavior(string(sdk.NullInputBehaviorCalledOnNullInput)). + WithExecuteAs(string(sdk.ExecuteAsCaller)). + WithComment("some comment") + + procedureModelUpdateWithoutRecreation := model.ProcedurePythonBasicInline("w", id, dataType, funcName, definition). + WithArgument(argName, dataType). + WithImports( + sdk.NormalizedPath{StageLocation: "~", PathOnStage: tmpPythonFunction.PythonFileName()}, + sdk.NormalizedPath{StageLocation: "~", PathOnStage: tmpPythonFunction2.PythonFileName()}, + ). + WithSnowparkPackage("1.14.0"). + WithPackages("absl-py==0.10.0"). + WithExternalAccessIntegrations(externalAccessIntegration). + WithSecrets(map[string]sdk.SchemaObjectIdentifier{ + "def": secretId2, + }). + WithRuntimeVersion("3.8"). + WithIsSecure("false"). + WithNullInputBehavior(string(sdk.NullInputBehaviorCalledOnNullInput)). + WithExecuteAs(string(sdk.ExecuteAsOwner)). + WithComment("some other comment") + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + PreCheck: func() { acc.TestAccPreCheck(t) }, + CheckDestroy: acc.CheckDestroy(t, resources.ProcedurePython), + Steps: []resource.TestStep{ + // CREATE BASIC + { + Config: config.FromModels(t, procedureModel), + Check: assert.AssertThat(t, + resourceassert.ProcedurePythonResource(t, procedureModel.ResourceReference()). + HasNameString(id.Name()). + HasIsSecureString(r.BooleanFalse). + HasImportsLength(2). + HasRuntimeVersionString("3.8"). + HasProcedureDefinitionString(definition). + HasCommentString("some comment"). + HasProcedureLanguageString("PYTHON"). + HasExecuteAsString(string(sdk.ExecuteAsCaller)). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + assert.Check(resource.TestCheckResourceAttr(procedureModel.ResourceReference(), "secrets.#", "2")), + assert.Check(resource.TestCheckResourceAttr(procedureModel.ResourceReference(), "external_access_integrations.#", "2")), + assert.Check(resource.TestCheckResourceAttr(procedureModel.ResourceReference(), "packages.#", "1")), + assert.Check(resource.TestCheckResourceAttr(procedureModel.ResourceReference(), "packages.0", "absl-py==0.10.0")), + resourceshowoutputassert.ProcedureShowOutput(t, procedureModel.ResourceReference()). + HasIsSecure(false), + ), + }, + // IMPORT + { + ResourceName: procedureModel.ResourceReference(), + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"arguments.0.arg_data_type"}, + ImportStateCheck: assert.AssertThatImport(t, + resourceassert.ImportedProcedurePythonResource(t, id.FullyQualifiedName()). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + assert.CheckImport(importchecks.TestCheckResourceAttrInstanceState(helpers.EncodeResourceIdentifier(id), "arguments.0.arg_name", argName)), + assert.CheckImport(importchecks.TestCheckResourceAttrInstanceState(helpers.EncodeResourceIdentifier(id), "arguments.0.arg_data_type", "VARCHAR(16777216)")), + assert.CheckImport(importchecks.TestCheckResourceAttrInstanceState(helpers.EncodeResourceIdentifier(id), "arguments.0.arg_default_value", "")), + ), + }, + // UPDATE WITHOUT RECREATION + { + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(procedureModelUpdateWithoutRecreation.ResourceReference(), plancheck.ResourceActionUpdate), + }, + }, + Config: config.FromModels(t, procedureModelUpdateWithoutRecreation), + Check: assert.AssertThat(t, + resourceassert.ProcedurePythonResource(t, procedureModelUpdateWithoutRecreation.ResourceReference()). + HasNameString(id.Name()). + HasIsSecureString(r.BooleanFalse). + HasImportsLength(2). + HasRuntimeVersionString("3.8"). + HasProcedureDefinitionString(definition). + HasCommentString("some other comment"). + HasProcedureLanguageString("PYTHON"). + HasExecuteAsString(string(sdk.ExecuteAsOwner)). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + assert.Check(resource.TestCheckResourceAttr(procedureModelUpdateWithoutRecreation.ResourceReference(), "secrets.#", "1")), + assert.Check(resource.TestCheckResourceAttr(procedureModelUpdateWithoutRecreation.ResourceReference(), "secrets.0.secret_variable_name", "def")), + assert.Check(resource.TestCheckResourceAttr(procedureModelUpdateWithoutRecreation.ResourceReference(), "secrets.0.secret_id", secretId2.FullyQualifiedName())), + assert.Check(resource.TestCheckResourceAttr(procedureModelUpdateWithoutRecreation.ResourceReference(), "external_access_integrations.#", "1")), + assert.Check(resource.TestCheckResourceAttr(procedureModelUpdateWithoutRecreation.ResourceReference(), "external_access_integrations.0", externalAccessIntegration.Name())), + assert.Check(resource.TestCheckResourceAttr(procedureModelUpdateWithoutRecreation.ResourceReference(), "packages.#", "1")), + resourceshowoutputassert.ProcedureShowOutput(t, procedureModelUpdateWithoutRecreation.ResourceReference()). + HasIsSecure(false), + ), + }, + }, + }) +} diff --git a/pkg/resources/procedure_scala.go b/pkg/resources/procedure_scala.go index c860c6282d..5b21c728ae 100644 --- a/pkg/resources/procedure_scala.go +++ b/pkg/resources/procedure_scala.go @@ -23,7 +23,7 @@ func ProcedureScala() *schema.Resource { return &schema.Resource{ CreateContext: TrackingCreateWrapper(resources.ProcedureScala, CreateContextProcedureScala), ReadContext: TrackingReadWrapper(resources.ProcedureScala, ReadContextProcedureScala), - UpdateContext: TrackingUpdateWrapper(resources.ProcedureScala, UpdateProcedure("SQL", ReadContextProcedureScala)), + UpdateContext: TrackingUpdateWrapper(resources.ProcedureScala, UpdateProcedure("SCALA", ReadContextProcedureScala)), DeleteContext: TrackingDeleteWrapper(resources.ProcedureScala, DeleteProcedure), Description: "Resource used to manage scala procedure objects. For more information, check [procedure documentation](https://docs.snowflake.com/en/sql-reference/sql/create-procedure).", @@ -77,6 +77,7 @@ func CreateContextProcedureScala(ctx context.Context, d *schema.ResourceData, me errs := errors.Join( booleanStringAttributeCreateBuilder(d, "is_secure", request.WithSecure), attributeMappedValueCreateBuilder[string](d, "null_input_behavior", request.WithNullInputBehavior, sdk.ToNullInputBehavior), + attributeMappedValueCreateBuilder[string](d, "execute_as", request.WithExecuteAs, sdk.ToExecuteAs), stringAttributeCreateBuilder(d, "comment", request.WithComment), setProcedureImportsInBuilder(d, request.WithImports), setExternalAccessIntegrationsInBuilder(d, request.WithExternalAccessIntegrations), @@ -128,6 +129,7 @@ func ReadContextProcedureScala(ctx context.Context, d *schema.ResourceData, meta readFunctionOrProcedureArguments(d, allProcedureDetails.procedureDetails.NormalizedArguments), d.Set("return_type", allProcedureDetails.procedureDetails.ReturnDataType.ToSql()), // not reading null_input_behavior on purpose (handled as external change to show output) + // not reading execute_as on purpose (handled as external change to show output) setRequiredFromStringPtr(d, "runtime_version", allProcedureDetails.procedureDetails.RuntimeVersion), d.Set("comment", allProcedureDetails.procedure.Description), readFunctionOrProcedureImports(d, allProcedureDetails.procedureDetails.NormalizedImports), diff --git a/pkg/resources/procedure_scala_acceptance_test.go b/pkg/resources/procedure_scala_acceptance_test.go new file mode 100644 index 0000000000..a45a717b63 --- /dev/null +++ b/pkg/resources/procedure_scala_acceptance_test.go @@ -0,0 +1,262 @@ +package resources_test + +import ( + "fmt" + "testing" + "time" + + acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" + r "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert/resourceassert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert/resourceshowoutputassert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/config" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/config/model" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/helpers/random" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/importchecks" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/testdatatypes" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/testenvs" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider/resources" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/tfversion" +) + +// TODO [SNOW-1348103]: test external changes +// TODO [SNOW-1348103]: test changes of attributes separately + +func TestAcc_ProcedureScala_InlineBasic(t *testing.T) { + className := "TestFunc" + funcName := "echoVarchar" + argName := "x" + dataType := testdatatypes.DataTypeVarchar_100 + + id := acc.TestClient().Ids.RandomSchemaObjectIdentifierWithArgumentsNewDataTypes(dataType) + idWithChangedNameButTheSameDataType := acc.TestClient().Ids.RandomSchemaObjectIdentifierWithArgumentsNewDataTypes(dataType) + + handler := fmt.Sprintf("%s.%s", className, funcName) + definition := acc.TestClient().Procedure.SampleScalaDefinition(t, className, funcName, argName) + + procedureModel := model.ProcedureScalaBasicInline("w", id, dataType, handler, definition). + WithArgument(argName, dataType) + procedureModelRenamed := model.ProcedureScalaBasicInline("w", idWithChangedNameButTheSameDataType, dataType, handler, definition). + WithArgument(argName, dataType) + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + PreCheck: func() { acc.TestAccPreCheck(t) }, + CheckDestroy: acc.CheckDestroy(t, resources.ProcedureScala), + Steps: []resource.TestStep{ + // CREATE BASIC + { + Config: config.FromModels(t, procedureModel), + Check: assert.AssertThat(t, + resourceassert.ProcedureScalaResource(t, procedureModel.ResourceReference()). + HasNameString(id.Name()). + HasIsSecureString(r.BooleanDefault). + HasCommentString(sdk.DefaultProcedureComment). + HasImportsLength(0). + HasTargetPathEmpty(). + HasRuntimeVersionString("2.12"). + HasProcedureDefinitionString(definition). + HasProcedureLanguageString("SCALA"). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + resourceshowoutputassert.ProcedureShowOutput(t, procedureModel.ResourceReference()). + HasIsSecure(false), + assert.Check(resource.TestCheckResourceAttr(procedureModel.ResourceReference(), "arguments.0.arg_name", argName)), + assert.Check(resource.TestCheckResourceAttr(procedureModel.ResourceReference(), "arguments.0.arg_data_type", dataType.ToSql())), + assert.Check(resource.TestCheckResourceAttr(procedureModel.ResourceReference(), "arguments.0.arg_default_value", "")), + ), + }, + // IMPORT + { + ResourceName: procedureModel.ResourceReference(), + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"is_secure", "arguments.0.arg_data_type", "null_input_behavior", "execute_as"}, + ImportStateCheck: assert.AssertThatImport(t, + resourceassert.ImportedProcedureScalaResource(t, id.FullyQualifiedName()). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + assert.CheckImport(importchecks.TestCheckResourceAttrInstanceState(helpers.EncodeResourceIdentifier(id), "arguments.0.arg_name", argName)), + assert.CheckImport(importchecks.TestCheckResourceAttrInstanceState(helpers.EncodeResourceIdentifier(id), "arguments.0.arg_data_type", "VARCHAR(16777216)")), + assert.CheckImport(importchecks.TestCheckResourceAttrInstanceState(helpers.EncodeResourceIdentifier(id), "arguments.0.arg_default_value", "")), + ), + }, + // RENAME + { + Config: config.FromModels(t, procedureModelRenamed), + Check: assert.AssertThat(t, + resourceassert.ProcedureScalaResource(t, procedureModelRenamed.ResourceReference()). + HasNameString(idWithChangedNameButTheSameDataType.Name()). + HasFullyQualifiedNameString(idWithChangedNameButTheSameDataType.FullyQualifiedName()), + ), + }, + }, + }) +} + +func TestAcc_ProcedureScala_InlineFull(t *testing.T) { + _ = testenvs.GetOrSkipTest(t, testenvs.EnableAcceptance) + acc.TestAccPreCheck(t) + + stage, stageCleanup := acc.TestClient().Stage.CreateStage(t) + t.Cleanup(stageCleanup) + + secretId := acc.TestClient().Ids.RandomSchemaObjectIdentifier() + secretId2 := acc.TestClient().Ids.RandomSchemaObjectIdentifier() + + networkRule, networkRuleCleanup := acc.TestClient().NetworkRule.Create(t) + t.Cleanup(networkRuleCleanup) + + secret, secretCleanup := acc.TestClient().Secret.CreateWithGenericString(t, secretId, "test_secret_string") + t.Cleanup(secretCleanup) + + secret2, secret2Cleanup := acc.TestClient().Secret.CreateWithGenericString(t, secretId2, "test_secret_string_2") + t.Cleanup(secret2Cleanup) + + externalAccessIntegration, externalAccessIntegrationCleanup := acc.TestClient().ExternalAccessIntegration.CreateExternalAccessIntegrationWithNetworkRuleAndSecret(t, networkRule.ID(), secret.ID()) + t.Cleanup(externalAccessIntegrationCleanup) + + externalAccessIntegration2, externalAccessIntegration2Cleanup := acc.TestClient().ExternalAccessIntegration.CreateExternalAccessIntegrationWithNetworkRuleAndSecret(t, networkRule.ID(), secret2.ID()) + t.Cleanup(externalAccessIntegration2Cleanup) + + tmpJavaProcedure := acc.TestClient().CreateSampleJavaProcedureAndJarOnUserStage(t) + tmpJavaProcedure2 := acc.TestClient().CreateSampleJavaProcedureAndJarOnUserStage(t) + + className := "TestFunc" + funcName := "echoVarchar" + argName := "x" + dataType := testdatatypes.DataTypeVarchar_100 + + id := acc.TestClient().Ids.RandomSchemaObjectIdentifierWithArgumentsNewDataTypes(dataType) + + handler := fmt.Sprintf("%s.%s", className, funcName) + definition := acc.TestClient().Procedure.SampleScalaDefinition(t, className, funcName, argName) + // TODO [SNOW-1850370]: extract to helper + jarName := fmt.Sprintf("tf-%d-%s.jar", time.Now().Unix(), random.AlphaN(5)) + + procedureModel := model.ProcedureScalaBasicInline("w", id, dataType, handler, definition). + WithArgument(argName, dataType). + WithImports( + sdk.NormalizedPath{StageLocation: "~", PathOnStage: tmpJavaProcedure.JarName}, + sdk.NormalizedPath{StageLocation: "~", PathOnStage: tmpJavaProcedure2.JarName}, + ). + WithSnowparkPackage("1.14.0"). + WithPackages("com.snowflake:telemetry:0.1.0"). + WithExternalAccessIntegrations(externalAccessIntegration, externalAccessIntegration2). + WithSecrets(map[string]sdk.SchemaObjectIdentifier{ + "abc": secretId, + "def": secretId2, + }). + WithTargetPathParts(stage.ID().FullyQualifiedName(), jarName). + WithRuntimeVersion("2.12"). + WithIsSecure("false"). + WithNullInputBehavior(string(sdk.NullInputBehaviorCalledOnNullInput)). + WithExecuteAs(string(sdk.ExecuteAsCaller)). + WithComment("some comment") + + procedureModelUpdateWithoutRecreation := model.ProcedureScalaBasicInline("w", id, dataType, handler, definition). + WithArgument(argName, dataType). + WithImports( + sdk.NormalizedPath{StageLocation: "~", PathOnStage: tmpJavaProcedure.JarName}, + sdk.NormalizedPath{StageLocation: "~", PathOnStage: tmpJavaProcedure2.JarName}, + ). + WithSnowparkPackage("1.14.0"). + WithPackages("com.snowflake:telemetry:0.1.0"). + WithExternalAccessIntegrations(externalAccessIntegration). + WithSecrets(map[string]sdk.SchemaObjectIdentifier{ + "def": secretId2, + }). + WithTargetPathParts(stage.ID().FullyQualifiedName(), jarName). + WithRuntimeVersion("2.12"). + WithIsSecure("false"). + WithNullInputBehavior(string(sdk.NullInputBehaviorCalledOnNullInput)). + WithExecuteAs(string(sdk.ExecuteAsOwner)). + WithComment("some other comment") + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + PreCheck: func() { acc.TestAccPreCheck(t) }, + CheckDestroy: acc.CheckDestroy(t, resources.ProcedureScala), + Steps: []resource.TestStep{ + // CREATE BASIC + { + Config: config.FromModels(t, procedureModel), + Check: assert.AssertThat(t, + resourceassert.ProcedureScalaResource(t, procedureModel.ResourceReference()). + HasNameString(id.Name()). + HasIsSecureString(r.BooleanFalse). + HasImportsLength(2). + HasRuntimeVersionString("2.12"). + HasProcedureDefinitionString(definition). + HasCommentString("some comment"). + HasProcedureLanguageString("SCALA"). + HasExecuteAsString(string(sdk.ExecuteAsCaller)). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + assert.Check(resource.TestCheckResourceAttr(procedureModel.ResourceReference(), "target_path.0.stage_location", stage.ID().FullyQualifiedName())), + assert.Check(resource.TestCheckResourceAttr(procedureModel.ResourceReference(), "target_path.0.path_on_stage", jarName)), + assert.Check(resource.TestCheckResourceAttr(procedureModel.ResourceReference(), "secrets.#", "2")), + assert.Check(resource.TestCheckResourceAttr(procedureModel.ResourceReference(), "external_access_integrations.#", "2")), + assert.Check(resource.TestCheckResourceAttr(procedureModel.ResourceReference(), "packages.#", "1")), + assert.Check(resource.TestCheckResourceAttr(procedureModel.ResourceReference(), "packages.0", "com.snowflake:telemetry:0.1.0")), + resourceshowoutputassert.ProcedureShowOutput(t, procedureModel.ResourceReference()). + HasIsSecure(false), + ), + }, + // IMPORT + { + ResourceName: procedureModel.ResourceReference(), + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"arguments.0.arg_data_type"}, + ImportStateCheck: assert.AssertThatImport(t, + resourceassert.ImportedProcedureScalaResource(t, id.FullyQualifiedName()). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + assert.CheckImport(importchecks.TestCheckResourceAttrInstanceState(helpers.EncodeResourceIdentifier(id), "arguments.0.arg_name", argName)), + assert.CheckImport(importchecks.TestCheckResourceAttrInstanceState(helpers.EncodeResourceIdentifier(id), "arguments.0.arg_data_type", "VARCHAR(16777216)")), + assert.CheckImport(importchecks.TestCheckResourceAttrInstanceState(helpers.EncodeResourceIdentifier(id), "arguments.0.arg_default_value", "")), + ), + }, + // UPDATE WITHOUT RECREATION + { + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(procedureModelUpdateWithoutRecreation.ResourceReference(), plancheck.ResourceActionUpdate), + }, + }, + Config: config.FromModels(t, procedureModelUpdateWithoutRecreation), + Check: assert.AssertThat(t, + resourceassert.ProcedureScalaResource(t, procedureModelUpdateWithoutRecreation.ResourceReference()). + HasNameString(id.Name()). + HasIsSecureString(r.BooleanFalse). + HasImportsLength(2). + HasRuntimeVersionString("2.12"). + HasProcedureDefinitionString(definition). + HasCommentString("some other comment"). + HasProcedureLanguageString("SCALA"). + HasExecuteAsString(string(sdk.ExecuteAsOwner)). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + assert.Check(resource.TestCheckResourceAttr(procedureModelUpdateWithoutRecreation.ResourceReference(), "target_path.0.stage_location", stage.ID().FullyQualifiedName())), + assert.Check(resource.TestCheckResourceAttr(procedureModelUpdateWithoutRecreation.ResourceReference(), "target_path.0.path_on_stage", jarName)), + assert.Check(resource.TestCheckResourceAttr(procedureModelUpdateWithoutRecreation.ResourceReference(), "secrets.#", "1")), + assert.Check(resource.TestCheckResourceAttr(procedureModelUpdateWithoutRecreation.ResourceReference(), "secrets.0.secret_variable_name", "def")), + assert.Check(resource.TestCheckResourceAttr(procedureModelUpdateWithoutRecreation.ResourceReference(), "secrets.0.secret_id", secretId2.FullyQualifiedName())), + assert.Check(resource.TestCheckResourceAttr(procedureModelUpdateWithoutRecreation.ResourceReference(), "external_access_integrations.#", "1")), + assert.Check(resource.TestCheckResourceAttr(procedureModelUpdateWithoutRecreation.ResourceReference(), "external_access_integrations.0", externalAccessIntegration.Name())), + assert.Check(resource.TestCheckResourceAttr(procedureModelUpdateWithoutRecreation.ResourceReference(), "packages.#", "1")), + resourceshowoutputassert.ProcedureShowOutput(t, procedureModelUpdateWithoutRecreation.ResourceReference()). + HasIsSecure(false), + ), + }, + }, + }) +} diff --git a/pkg/resources/procedure_sql.go b/pkg/resources/procedure_sql.go index d38717904a..290d20f279 100644 --- a/pkg/resources/procedure_sql.go +++ b/pkg/resources/procedure_sql.go @@ -69,6 +69,7 @@ func CreateContextProcedureSql(ctx context.Context, d *schema.ResourceData, meta errs := errors.Join( booleanStringAttributeCreateBuilder(d, "is_secure", request.WithSecure), attributeMappedValueCreateBuilder[string](d, "null_input_behavior", request.WithNullInputBehavior, sdk.ToNullInputBehavior), + attributeMappedValueCreateBuilder[string](d, "execute_as", request.WithExecuteAs, sdk.ToExecuteAs), stringAttributeCreateBuilder(d, "comment", request.WithComment), ) if errs != nil { @@ -115,6 +116,7 @@ func ReadContextProcedureSql(ctx context.Context, d *schema.ResourceData, meta a readFunctionOrProcedureArguments(d, allProcedureDetails.procedureDetails.NormalizedArguments), d.Set("return_type", allProcedureDetails.procedureDetails.ReturnDataType.ToSql()), // not reading null_input_behavior on purpose (handled as external change to show output) + // not reading execute_as on purpose (handled as external change to show output) d.Set("comment", allProcedureDetails.procedure.Description), setOptionalFromStringPtr(d, "procedure_definition", allProcedureDetails.procedureDetails.Body), d.Set("procedure_language", allProcedureDetails.procedureDetails.Language), diff --git a/pkg/resources/procedure_sql_acceptance_test.go b/pkg/resources/procedure_sql_acceptance_test.go new file mode 100644 index 0000000000..f00eb1003f --- /dev/null +++ b/pkg/resources/procedure_sql_acceptance_test.go @@ -0,0 +1,178 @@ +package resources_test + +import ( + "testing" + + acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" + r "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert/resourceassert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/assert/resourceshowoutputassert" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/config" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/config/model" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/importchecks" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/testdatatypes" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/testenvs" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider/resources" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/tfversion" +) + +func TestAcc_ProcedureSql_InlineBasic(t *testing.T) { + argName := "x" + dataType := testdatatypes.DataTypeVarchar_100 + + id := acc.TestClient().Ids.RandomSchemaObjectIdentifierWithArgumentsNewDataTypes(dataType) + idWithChangedNameButTheSameDataType := acc.TestClient().Ids.RandomSchemaObjectIdentifierWithArgumentsNewDataTypes(dataType) + + definition := acc.TestClient().Procedure.SampleSqlDefinitionWithArgument(t) + + procedureModel := model.ProcedureSqlBasicInline("w", id, dataType, definition). + WithArgument(argName, dataType) + procedureModelRenamed := model.ProcedureSqlBasicInline("w", idWithChangedNameButTheSameDataType, dataType, definition). + WithArgument(argName, dataType) + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + PreCheck: func() { acc.TestAccPreCheck(t) }, + CheckDestroy: acc.CheckDestroy(t, resources.ProcedureSql), + Steps: []resource.TestStep{ + // CREATE BASIC + { + Config: config.FromModels(t, procedureModel), + Check: assert.AssertThat(t, + resourceassert.ProcedureSqlResource(t, procedureModel.ResourceReference()). + HasNameString(id.Name()). + HasIsSecureString(r.BooleanDefault). + HasCommentString(sdk.DefaultProcedureComment). + HasProcedureDefinitionString(definition). + HasProcedureLanguageString("SQL"). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + resourceshowoutputassert.ProcedureShowOutput(t, procedureModel.ResourceReference()). + HasIsSecure(false), + assert.Check(resource.TestCheckResourceAttr(procedureModel.ResourceReference(), "arguments.0.arg_name", argName)), + assert.Check(resource.TestCheckResourceAttr(procedureModel.ResourceReference(), "arguments.0.arg_data_type", dataType.ToSql())), + assert.Check(resource.TestCheckResourceAttr(procedureModel.ResourceReference(), "arguments.0.arg_default_value", "")), + ), + }, + // IMPORT + { + ResourceName: procedureModel.ResourceReference(), + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"is_secure", "arguments.0.arg_data_type", "null_input_behavior", "execute_as"}, + ImportStateCheck: assert.AssertThatImport(t, + resourceassert.ImportedProcedureSqlResource(t, id.FullyQualifiedName()). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + assert.CheckImport(importchecks.TestCheckResourceAttrInstanceState(helpers.EncodeResourceIdentifier(id), "arguments.0.arg_name", argName)), + assert.CheckImport(importchecks.TestCheckResourceAttrInstanceState(helpers.EncodeResourceIdentifier(id), "arguments.0.arg_data_type", "VARCHAR(16777216)")), + assert.CheckImport(importchecks.TestCheckResourceAttrInstanceState(helpers.EncodeResourceIdentifier(id), "arguments.0.arg_default_value", "")), + ), + }, + // RENAME + { + Config: config.FromModels(t, procedureModelRenamed), + Check: assert.AssertThat(t, + resourceassert.ProcedureSqlResource(t, procedureModelRenamed.ResourceReference()). + HasNameString(idWithChangedNameButTheSameDataType.Name()). + HasFullyQualifiedNameString(idWithChangedNameButTheSameDataType.FullyQualifiedName()), + ), + }, + }, + }) +} + +func TestAcc_ProcedureSql_InlineFull(t *testing.T) { + _ = testenvs.GetOrSkipTest(t, testenvs.EnableAcceptance) + acc.TestAccPreCheck(t) + + argName := "x" + dataType := testdatatypes.DataTypeVarchar_100 + + id := acc.TestClient().Ids.RandomSchemaObjectIdentifierWithArgumentsNewDataTypes(dataType) + + definition := acc.TestClient().Procedure.SampleSqlDefinitionWithArgument(t) + + procedureModel := model.ProcedureSqlBasicInline("w", id, dataType, definition). + WithArgument(argName, dataType). + WithIsSecure("false"). + WithNullInputBehavior(string(sdk.NullInputBehaviorCalledOnNullInput)). + WithExecuteAs(string(sdk.ExecuteAsCaller)). + WithComment("some comment") + + procedureModelUpdateWithoutRecreation := model.ProcedureSqlBasicInline("w", id, dataType, definition). + WithArgument(argName, dataType). + WithIsSecure("false"). + WithNullInputBehavior(string(sdk.NullInputBehaviorCalledOnNullInput)). + WithExecuteAs(string(sdk.ExecuteAsOwner)). + WithComment("some other comment") + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: acc.TestAccProtoV6ProviderFactories, + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.RequireAbove(tfversion.Version1_5_0), + }, + PreCheck: func() { acc.TestAccPreCheck(t) }, + CheckDestroy: acc.CheckDestroy(t, resources.ProcedureSql), + Steps: []resource.TestStep{ + // CREATE BASIC + { + Config: config.FromModels(t, procedureModel), + Check: assert.AssertThat(t, + resourceassert.ProcedureSqlResource(t, procedureModel.ResourceReference()). + HasNameString(id.Name()). + HasIsSecureString(r.BooleanFalse). + HasProcedureDefinitionString(definition). + HasCommentString("some comment"). + HasProcedureLanguageString("SQL"). + HasExecuteAsString(string(sdk.ExecuteAsCaller)). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + resourceshowoutputassert.ProcedureShowOutput(t, procedureModel.ResourceReference()). + HasIsSecure(false), + ), + }, + // IMPORT + { + ResourceName: procedureModel.ResourceReference(), + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"arguments.0.arg_data_type", "null_input_behavior"}, + ImportStateCheck: assert.AssertThatImport(t, + resourceassert.ImportedProcedureSqlResource(t, id.FullyQualifiedName()). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + assert.CheckImport(importchecks.TestCheckResourceAttrInstanceState(helpers.EncodeResourceIdentifier(id), "arguments.0.arg_name", argName)), + assert.CheckImport(importchecks.TestCheckResourceAttrInstanceState(helpers.EncodeResourceIdentifier(id), "arguments.0.arg_data_type", "VARCHAR(16777216)")), + assert.CheckImport(importchecks.TestCheckResourceAttrInstanceState(helpers.EncodeResourceIdentifier(id), "arguments.0.arg_default_value", "")), + ), + }, + // UPDATE WITHOUT RECREATION + { + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(procedureModelUpdateWithoutRecreation.ResourceReference(), plancheck.ResourceActionUpdate), + }, + }, + Config: config.FromModels(t, procedureModelUpdateWithoutRecreation), + Check: assert.AssertThat(t, + resourceassert.ProcedureSqlResource(t, procedureModelUpdateWithoutRecreation.ResourceReference()). + HasNameString(id.Name()). + HasIsSecureString(r.BooleanFalse). + HasProcedureDefinitionString(definition). + HasCommentString("some other comment"). + HasProcedureLanguageString("SQL"). + HasExecuteAsString(string(sdk.ExecuteAsOwner)). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + resourceshowoutputassert.ProcedureShowOutput(t, procedureModelUpdateWithoutRecreation.ResourceReference()). + HasIsSecure(false), + ), + }, + }, + }) +} diff --git a/pkg/sdk/common_types.go b/pkg/sdk/common_types.go index 0621d9d995..57215541ef 100644 --- a/pkg/sdk/common_types.go +++ b/pkg/sdk/common_types.go @@ -222,8 +222,8 @@ func ExecuteAsPointer(v ExecuteAs) *ExecuteAs { // TODO [SNOW-1348103]: fix SDK - constants should have only CALLER and OWNER (not the EXECUTE AS part) const ( - ExecuteAsCaller ExecuteAs = "EXECUTE AS CALLER" - ExecuteAsOwner ExecuteAs = "EXECUTE AS OWNER" + ExecuteAsCaller ExecuteAs = "CALLER" + ExecuteAsOwner ExecuteAs = "OWNER" ) func ToExecuteAs(value string) (ExecuteAs, error) { diff --git a/pkg/sdk/common_types_test.go b/pkg/sdk/common_types_test.go index 7df8be779e..ac935b09e1 100644 --- a/pkg/sdk/common_types_test.go +++ b/pkg/sdk/common_types_test.go @@ -273,7 +273,7 @@ func Test_ToExecuteAs(t *testing.T) { {Input: string(ExecuteAsOwner), Expected: ExecuteAsOwner}, {Name: "validation: incorrect execute as", Input: "incorrect", Error: "unknown execute as: incorrect"}, {Name: "validation: empty input", Input: "", Error: "unknown execute as: "}, - {Name: "validation: lower case input", Input: "execute as caller", Expected: ExecuteAsCaller}, + {Name: "validation: lower case input", Input: "caller", Expected: ExecuteAsCaller}, } for _, testCase := range testCases { diff --git a/pkg/sdk/functions_and_procedures_commons.go b/pkg/sdk/functions_and_procedures_commons.go index 35f4ab3dbb..574166dab5 100644 --- a/pkg/sdk/functions_and_procedures_commons.go +++ b/pkg/sdk/functions_and_procedures_commons.go @@ -127,7 +127,7 @@ func parseFunctionOrProcedureExternalAccessIntegrations(raw string) ([]AccountOb // TODO [before V1]: test func parseFunctionOrProcedurePackages(raw string) ([]string, error) { - log.Printf("[DEBUG] external access integrations: %s", raw) + log.Printf("[DEBUG] packages: %s", raw) return collections.Map(ParseCommaSeparatedStringArray(raw, true), strings.TrimSpace), nil } diff --git a/pkg/sdk/procedures_gen.go b/pkg/sdk/procedures_gen.go index 0dbbf8f5a1..88777d0e8f 100644 --- a/pkg/sdk/procedures_gen.go +++ b/pkg/sdk/procedures_gen.go @@ -52,7 +52,7 @@ type CreateForJavaProcedureOptions struct { Secrets []SecretReference `ddl:"parameter,parentheses" sql:"SECRETS"` TargetPath *string `ddl:"parameter,single_quotes" sql:"TARGET_PATH"` Comment *string `ddl:"parameter,single_quotes" sql:"COMMENT"` - ExecuteAs *ExecuteAs `ddl:"keyword"` + ExecuteAs *ExecuteAs `ddl:"parameter,no_quotes,no_equals" sql:"EXECUTE AS"` ProcedureDefinition *string `ddl:"parameter,no_equals" sql:"AS"` } @@ -110,7 +110,7 @@ type CreateForJavaScriptProcedureOptions struct { NullInputBehavior *NullInputBehavior `ddl:"keyword"` ReturnResultsBehavior *ReturnResultsBehavior `ddl:"keyword"` Comment *string `ddl:"parameter,single_quotes" sql:"COMMENT"` - ExecuteAs *ExecuteAs `ddl:"keyword"` + ExecuteAs *ExecuteAs `ddl:"parameter,no_quotes,no_equals" sql:"EXECUTE AS"` ProcedureDefinition string `ddl:"parameter,no_equals" sql:"AS"` } @@ -134,7 +134,7 @@ type CreateForPythonProcedureOptions struct { ExternalAccessIntegrations []AccountObjectIdentifier `ddl:"parameter,parentheses" sql:"EXTERNAL_ACCESS_INTEGRATIONS"` Secrets []SecretReference `ddl:"parameter,parentheses" sql:"SECRETS"` Comment *string `ddl:"parameter,single_quotes" sql:"COMMENT"` - ExecuteAs *ExecuteAs `ddl:"keyword"` + ExecuteAs *ExecuteAs `ddl:"parameter,no_quotes,no_equals" sql:"EXECUTE AS"` ProcedureDefinition *string `ddl:"parameter,no_equals" sql:"AS"` } @@ -159,7 +159,7 @@ type CreateForScalaProcedureOptions struct { Secrets []SecretReference `ddl:"parameter,parentheses" sql:"SECRETS"` TargetPath *string `ddl:"parameter,single_quotes" sql:"TARGET_PATH"` Comment *string `ddl:"parameter,single_quotes" sql:"COMMENT"` - ExecuteAs *ExecuteAs `ddl:"keyword"` + ExecuteAs *ExecuteAs `ddl:"parameter,no_quotes,no_equals" sql:"EXECUTE AS"` ProcedureDefinition *string `ddl:"parameter,no_equals" sql:"AS"` } @@ -177,7 +177,7 @@ type CreateForSQLProcedureOptions struct { NullInputBehavior *NullInputBehavior `ddl:"keyword"` ReturnResultsBehavior *ReturnResultsBehavior `ddl:"keyword"` Comment *string `ddl:"parameter,single_quotes" sql:"COMMENT"` - ExecuteAs *ExecuteAs `ddl:"keyword"` + ExecuteAs *ExecuteAs `ddl:"parameter,no_quotes,no_equals" sql:"EXECUTE AS"` ProcedureDefinition string `ddl:"parameter,no_equals" sql:"AS"` } @@ -198,7 +198,7 @@ type AlterProcedureOptions struct { Unset *ProcedureUnset `ddl:"list" sql:"UNSET"` SetTags []TagAssociation `ddl:"keyword" sql:"SET TAG"` UnsetTags []ObjectIdentifier `ddl:"keyword" sql:"UNSET TAG"` - ExecuteAs *ExecuteAs `ddl:"keyword"` + ExecuteAs *ExecuteAs `ddl:"parameter,no_quotes,no_equals" sql:"EXECUTE AS"` } type ProcedureSet struct { diff --git a/pkg/sdk/testint/functions_integration_test.go b/pkg/sdk/testint/functions_integration_test.go index 1036429d78..b28d3ef9e2 100644 --- a/pkg/sdk/testint/functions_integration_test.go +++ b/pkg/sdk/testint/functions_integration_test.go @@ -34,7 +34,7 @@ import ( // TODO [SNOW-1348103]: test secure // TODO [SNOW-1348103]: python aggregate func (100357 (P0000): Could not find accumulate method in function CVVEMHIT_06547800_08D6_DBCA_1AC7_5E422AFF8B39 with handler dump) // TODO [SNOW-1348103]: add test with multiple imports -// TODO [this PR]: test with multiple external access integrations and secrets +// TODO [SNOW-1348103]: test with multiple external access integrations and secrets func TestInt_Functions(t *testing.T) { client := testClient(t) ctx := context.Background() diff --git a/pkg/sdk/testint/procedures_integration_test.go b/pkg/sdk/testint/procedures_integration_test.go index 56f1a20248..b0a935f070 100644 --- a/pkg/sdk/testint/procedures_integration_test.go +++ b/pkg/sdk/testint/procedures_integration_test.go @@ -1811,7 +1811,7 @@ def filter_by_role(session, table_name, role): HasCreatedOnNotEmpty(). HasName(id.Name()). HasSchemaName(id.SchemaName()). - HasArgumentsRawContains(expectedReturnDataType.ToLegacyDataTypeSql()), + HasArgumentsRawContains(strings.ReplaceAll(expectedReturnDataType.ToLegacyDataTypeSql(), "TABLE(", "TABLE (")), ) assertions.AssertThatObject(t, objectassert.ProcedureDetails(t, id). diff --git a/templates/resources/function_java.md.tmpl b/templates/resources/function_java.md.tmpl new file mode 100644 index 0000000000..4092173dd0 --- /dev/null +++ b/templates/resources/function_java.md.tmpl @@ -0,0 +1,52 @@ +--- +page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}" +subcategory: "" +description: |- +{{ if gt (len (split .Description "")) 1 -}} +{{ index (split .Description "") 1 | plainmarkdown | trimspace | prefixlines " " }} +{{- else -}} +{{ .Description | plainmarkdown | trimspace | prefixlines " " }} +{{- end }} +--- + +-> **Note** External changes to `is_secure`, `return_results_behavior`, and `null_input_behavior` are not currently supported. They will be handled in the following versions of the provider which may still affect this resource. + +-> **Note** `COPY GRANTS` and `OR REPLACE` are not currently supported. + +-> **Note** `RETURN... [[ NOT ] NULL]` is not currently supported. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Use of return type `TABLE` is currently limited. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Snowflake is not returning full data type information for arguments which may lead to unexpected plan outputs. Diff suppression for such cases will be improved. + +-> **Note** Snowflake is not returning the default values for arguments so argument's `arg_default_value` external changes cannot be tracked. + +-> **Note** Limit the use of special characters (`.`, `'`, `/`, `"`, `(`, `)`, `[`, `]`, `{`, `}`, ` `) in argument names, stage ids, and secret ids. It's best to limit to only alphanumeric and underscores. There is a lot of parsing of SHOW/DESCRIBE outputs involved and using special characters may limit the possibility to achieve the correct results. + +~> **Required warehouse** This resource may require active warehouse. Please, make sure you have either set a DEFAULT_WAREHOUSE for the user, or specified a warehouse in the provider configuration. + +# {{.Name}} ({{.Type}}) + +{{ .Description | trimspace }} + +{{ if .HasExample -}} +## Example Usage + +{{ tffile (printf "examples/resources/%s/resource.tf" .Name)}} +-> **Note** Instead of using fully_qualified_name, you can reference objects managed outside Terraform by constructing a correct ID, consult [identifiers guide](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/guides/identifiers#new-computed-fully-qualified-name-field-in-resources). + + +{{- end }} + +{{ .SchemaMarkdown | trimspace }} +{{- if .HasImport }} + +## Import + +Import is supported using the following syntax: + +{{ codefile "shell" (printf "examples/resources/%s/import.sh" .Name)}} +{{- end }} + +Note: Snowflake is not returning all information needed to populate the state correctly after import (e.g. data types with attributes like NUMBER(32, 10) are returned as NUMBER, default values for arguments are not returned at all). +Also, `ALTER` for functions is very limited so most of the attributes on this resource are marked as force new. Because of that, in multiple situations plan won't be empty after importing and manual state operations may be required. diff --git a/templates/resources/function_javascript.md.tmpl b/templates/resources/function_javascript.md.tmpl new file mode 100644 index 0000000000..4092173dd0 --- /dev/null +++ b/templates/resources/function_javascript.md.tmpl @@ -0,0 +1,52 @@ +--- +page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}" +subcategory: "" +description: |- +{{ if gt (len (split .Description "")) 1 -}} +{{ index (split .Description "") 1 | plainmarkdown | trimspace | prefixlines " " }} +{{- else -}} +{{ .Description | plainmarkdown | trimspace | prefixlines " " }} +{{- end }} +--- + +-> **Note** External changes to `is_secure`, `return_results_behavior`, and `null_input_behavior` are not currently supported. They will be handled in the following versions of the provider which may still affect this resource. + +-> **Note** `COPY GRANTS` and `OR REPLACE` are not currently supported. + +-> **Note** `RETURN... [[ NOT ] NULL]` is not currently supported. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Use of return type `TABLE` is currently limited. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Snowflake is not returning full data type information for arguments which may lead to unexpected plan outputs. Diff suppression for such cases will be improved. + +-> **Note** Snowflake is not returning the default values for arguments so argument's `arg_default_value` external changes cannot be tracked. + +-> **Note** Limit the use of special characters (`.`, `'`, `/`, `"`, `(`, `)`, `[`, `]`, `{`, `}`, ` `) in argument names, stage ids, and secret ids. It's best to limit to only alphanumeric and underscores. There is a lot of parsing of SHOW/DESCRIBE outputs involved and using special characters may limit the possibility to achieve the correct results. + +~> **Required warehouse** This resource may require active warehouse. Please, make sure you have either set a DEFAULT_WAREHOUSE for the user, or specified a warehouse in the provider configuration. + +# {{.Name}} ({{.Type}}) + +{{ .Description | trimspace }} + +{{ if .HasExample -}} +## Example Usage + +{{ tffile (printf "examples/resources/%s/resource.tf" .Name)}} +-> **Note** Instead of using fully_qualified_name, you can reference objects managed outside Terraform by constructing a correct ID, consult [identifiers guide](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/guides/identifiers#new-computed-fully-qualified-name-field-in-resources). + + +{{- end }} + +{{ .SchemaMarkdown | trimspace }} +{{- if .HasImport }} + +## Import + +Import is supported using the following syntax: + +{{ codefile "shell" (printf "examples/resources/%s/import.sh" .Name)}} +{{- end }} + +Note: Snowflake is not returning all information needed to populate the state correctly after import (e.g. data types with attributes like NUMBER(32, 10) are returned as NUMBER, default values for arguments are not returned at all). +Also, `ALTER` for functions is very limited so most of the attributes on this resource are marked as force new. Because of that, in multiple situations plan won't be empty after importing and manual state operations may be required. diff --git a/templates/resources/function_python.md.tmpl b/templates/resources/function_python.md.tmpl new file mode 100644 index 0000000000..32911bea98 --- /dev/null +++ b/templates/resources/function_python.md.tmpl @@ -0,0 +1,54 @@ +--- +page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}" +subcategory: "" +description: |- +{{ if gt (len (split .Description "")) 1 -}} +{{ index (split .Description "") 1 | plainmarkdown | trimspace | prefixlines " " }} +{{- else -}} +{{ .Description | plainmarkdown | trimspace | prefixlines " " }} +{{- end }} +--- + +-> **Note** External changes to `is_secure`, `return_results_behavior`, and `null_input_behavior` are not currently supported. They will be handled in the following versions of the provider which may still affect this resource. + +-> **Note** `COPY GRANTS` and `OR REPLACE` are not currently supported. + +-> **Note** `RETURN... [[ NOT ] NULL]` is not currently supported. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** `is_aggregate` is not currently supported. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Use of return type `TABLE` is currently limited. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Snowflake is not returning full data type information for arguments which may lead to unexpected plan outputs. Diff suppression for such cases will be improved. + +-> **Note** Snowflake is not returning the default values for arguments so argument's `arg_default_value` external changes cannot be tracked. + +-> **Note** Limit the use of special characters (`.`, `'`, `/`, `"`, `(`, `)`, `[`, `]`, `{`, `}`, ` `) in argument names, stage ids, and secret ids. It's best to limit to only alphanumeric and underscores. There is a lot of parsing of SHOW/DESCRIBE outputs involved and using special characters may limit the possibility to achieve the correct results. + +~> **Required warehouse** This resource may require active warehouse. Please, make sure you have either set a DEFAULT_WAREHOUSE for the user, or specified a warehouse in the provider configuration. + +# {{.Name}} ({{.Type}}) + +{{ .Description | trimspace }} + +{{ if .HasExample -}} +## Example Usage + +{{ tffile (printf "examples/resources/%s/resource.tf" .Name)}} +-> **Note** Instead of using fully_qualified_name, you can reference objects managed outside Terraform by constructing a correct ID, consult [identifiers guide](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/guides/identifiers#new-computed-fully-qualified-name-field-in-resources). + + +{{- end }} + +{{ .SchemaMarkdown | trimspace }} +{{- if .HasImport }} + +## Import + +Import is supported using the following syntax: + +{{ codefile "shell" (printf "examples/resources/%s/import.sh" .Name)}} +{{- end }} + +Note: Snowflake is not returning all information needed to populate the state correctly after import (e.g. data types with attributes like NUMBER(32, 10) are returned as NUMBER, default values for arguments are not returned at all). +Also, `ALTER` for functions is very limited so most of the attributes on this resource are marked as force new. Because of that, in multiple situations plan won't be empty after importing and manual state operations may be required. diff --git a/templates/resources/function_scala.md.tmpl b/templates/resources/function_scala.md.tmpl new file mode 100644 index 0000000000..f452e9136e --- /dev/null +++ b/templates/resources/function_scala.md.tmpl @@ -0,0 +1,50 @@ +--- +page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}" +subcategory: "" +description: |- +{{ if gt (len (split .Description "")) 1 -}} +{{ index (split .Description "") 1 | plainmarkdown | trimspace | prefixlines " " }} +{{- else -}} +{{ .Description | plainmarkdown | trimspace | prefixlines " " }} +{{- end }} +--- + +-> **Note** External changes to `is_secure`, `return_results_behavior`, and `null_input_behavior` are not currently supported. They will be handled in the following versions of the provider which may still affect this resource. + +-> **Note** `COPY GRANTS` and `OR REPLACE` are not currently supported. + +-> **Note** `RETURN... [[ NOT ] NULL]` is not currently supported. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Snowflake is not returning full data type information for arguments which may lead to unexpected plan outputs. Diff suppression for such cases will be improved. + +-> **Note** Snowflake is not returning the default values for arguments so argument's `arg_default_value` external changes cannot be tracked. + +-> **Note** Limit the use of special characters (`.`, `'`, `/`, `"`, `(`, `)`, `[`, `]`, `{`, `}`, ` `) in argument names, stage ids, and secret ids. It's best to limit to only alphanumeric and underscores. There is a lot of parsing of SHOW/DESCRIBE outputs involved and using special characters may limit the possibility to achieve the correct results. + +~> **Required warehouse** This resource may require active warehouse. Please, make sure you have either set a DEFAULT_WAREHOUSE for the user, or specified a warehouse in the provider configuration. + +# {{.Name}} ({{.Type}}) + +{{ .Description | trimspace }} + +{{ if .HasExample -}} +## Example Usage + +{{ tffile (printf "examples/resources/%s/resource.tf" .Name)}} +-> **Note** Instead of using fully_qualified_name, you can reference objects managed outside Terraform by constructing a correct ID, consult [identifiers guide](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/guides/identifiers#new-computed-fully-qualified-name-field-in-resources). + + +{{- end }} + +{{ .SchemaMarkdown | trimspace }} +{{- if .HasImport }} + +## Import + +Import is supported using the following syntax: + +{{ codefile "shell" (printf "examples/resources/%s/import.sh" .Name)}} +{{- end }} + +Note: Snowflake is not returning all information needed to populate the state correctly after import (e.g. data types with attributes like NUMBER(32, 10) are returned as NUMBER, default values for arguments are not returned at all). +Also, `ALTER` for functions is very limited so most of the attributes on this resource are marked as force new. Because of that, in multiple situations plan won't be empty after importing and manual state operations may be required. diff --git a/templates/resources/function_sql.md.tmpl b/templates/resources/function_sql.md.tmpl new file mode 100644 index 0000000000..63cede4080 --- /dev/null +++ b/templates/resources/function_sql.md.tmpl @@ -0,0 +1,52 @@ +--- +page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}" +subcategory: "" +description: |- +{{ if gt (len (split .Description "")) 1 -}} +{{ index (split .Description "") 1 | plainmarkdown | trimspace | prefixlines " " }} +{{- else -}} +{{ .Description | plainmarkdown | trimspace | prefixlines " " }} +{{- end }} +--- + +-> **Note** External changes to `is_secure` and `return_results_behavior` are not currently supported. They will be handled in the following versions of the provider which may still affect this resource. + +-> **Note** `COPY GRANTS` and `OR REPLACE` are not currently supported. + +-> **Note** `MEMOIZABLE` is not currently supported. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Use of return type `TABLE` is currently limited. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Snowflake is not returning full data type information for arguments which may lead to unexpected plan outputs. Diff suppression for such cases will be improved. + +-> **Note** Snowflake is not returning the default values for arguments so argument's `arg_default_value` external changes cannot be tracked. + +-> **Note** Limit the use of special characters (`.`, `'`, `/`, `"`, `(`, `)`, `[`, `]`, `{`, `}`, ` `) in argument names, stage ids, and secret ids. It's best to limit to only alphanumeric and underscores. There is a lot of parsing of SHOW/DESCRIBE outputs involved and using special characters may limit the possibility to achieve the correct results. + +~> **Required warehouse** This resource may require active warehouse. Please, make sure you have either set a DEFAULT_WAREHOUSE for the user, or specified a warehouse in the provider configuration. + +# {{.Name}} ({{.Type}}) + +{{ .Description | trimspace }} + +{{ if .HasExample -}} +## Example Usage + +{{ tffile (printf "examples/resources/%s/resource.tf" .Name)}} +-> **Note** Instead of using fully_qualified_name, you can reference objects managed outside Terraform by constructing a correct ID, consult [identifiers guide](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/guides/identifiers#new-computed-fully-qualified-name-field-in-resources). + + +{{- end }} + +{{ .SchemaMarkdown | trimspace }} +{{- if .HasImport }} + +## Import + +Import is supported using the following syntax: + +{{ codefile "shell" (printf "examples/resources/%s/import.sh" .Name)}} +{{- end }} + +Note: Snowflake is not returning all information needed to populate the state correctly after import (e.g. data types with attributes like NUMBER(32, 10) are returned as NUMBER, default values for arguments are not returned at all). +Also, `ALTER` for functions is very limited so most of the attributes on this resource are marked as force new. Because of that, in multiple situations plan won't be empty after importing and manual state operations may be required. diff --git a/templates/resources/procedure_java.md.tmpl b/templates/resources/procedure_java.md.tmpl new file mode 100644 index 0000000000..e67c6205b5 --- /dev/null +++ b/templates/resources/procedure_java.md.tmpl @@ -0,0 +1,52 @@ +--- +page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}" +subcategory: "" +description: |- +{{ if gt (len (split .Description "")) 1 -}} +{{ index (split .Description "") 1 | plainmarkdown | trimspace | prefixlines " " }} +{{- else -}} +{{ .Description | plainmarkdown | trimspace | prefixlines " " }} +{{- end }} +--- + +-> **Note** External changes to `is_secure` and `null_input_behavior` are not currently supported. They will be handled in the following versions of the provider which may still affect this resource. + +-> **Note** `COPY GRANTS` and `OR REPLACE` are not currently supported. + +-> **Note** `RETURN... [[ NOT ] NULL]` is not currently supported. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Use of return type `TABLE` is currently limited. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Snowflake is not returning full data type information for arguments which may lead to unexpected plan outputs. Diff suppression for such cases will be improved. + +-> **Note** Snowflake is not returning the default values for arguments so argument's `arg_default_value` external changes cannot be tracked. + +-> **Note** Limit the use of special characters (`.`, `'`, `/`, `"`, `(`, `)`, `[`, `]`, `{`, `}`, ` `) in argument names, stage ids, and secret ids. It's best to limit to only alphanumeric and underscores. There is a lot of parsing of SHOW/DESCRIBE outputs involved and using special characters may limit the possibility to achieve the correct results. + +~> **Required warehouse** This resource may require active warehouse. Please, make sure you have either set a DEFAULT_WAREHOUSE for the user, or specified a warehouse in the provider configuration. + +# {{.Name}} ({{.Type}}) + +{{ .Description | trimspace }} + +{{ if .HasExample -}} +## Example Usage + +{{ tffile (printf "examples/resources/%s/resource.tf" .Name)}} +-> **Note** Instead of using fully_qualified_name, you can reference objects managed outside Terraform by constructing a correct ID, consult [identifiers guide](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/guides/identifiers#new-computed-fully-qualified-name-field-in-resources). + + +{{- end }} + +{{ .SchemaMarkdown | trimspace }} +{{- if .HasImport }} + +## Import + +Import is supported using the following syntax: + +{{ codefile "shell" (printf "examples/resources/%s/import.sh" .Name)}} +{{- end }} + +Note: Snowflake is not returning all information needed to populate the state correctly after import (e.g. data types with attributes like NUMBER(32, 10) are returned as NUMBER, default values for arguments are not returned at all). +Also, `ALTER` for functions is very limited so most of the attributes on this resource are marked as force new. Because of that, in multiple situations plan won't be empty after importing and manual state operations may be required. diff --git a/templates/resources/procedure_javascript.md.tmpl b/templates/resources/procedure_javascript.md.tmpl new file mode 100644 index 0000000000..e67c6205b5 --- /dev/null +++ b/templates/resources/procedure_javascript.md.tmpl @@ -0,0 +1,52 @@ +--- +page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}" +subcategory: "" +description: |- +{{ if gt (len (split .Description "")) 1 -}} +{{ index (split .Description "") 1 | plainmarkdown | trimspace | prefixlines " " }} +{{- else -}} +{{ .Description | plainmarkdown | trimspace | prefixlines " " }} +{{- end }} +--- + +-> **Note** External changes to `is_secure` and `null_input_behavior` are not currently supported. They will be handled in the following versions of the provider which may still affect this resource. + +-> **Note** `COPY GRANTS` and `OR REPLACE` are not currently supported. + +-> **Note** `RETURN... [[ NOT ] NULL]` is not currently supported. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Use of return type `TABLE` is currently limited. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Snowflake is not returning full data type information for arguments which may lead to unexpected plan outputs. Diff suppression for such cases will be improved. + +-> **Note** Snowflake is not returning the default values for arguments so argument's `arg_default_value` external changes cannot be tracked. + +-> **Note** Limit the use of special characters (`.`, `'`, `/`, `"`, `(`, `)`, `[`, `]`, `{`, `}`, ` `) in argument names, stage ids, and secret ids. It's best to limit to only alphanumeric and underscores. There is a lot of parsing of SHOW/DESCRIBE outputs involved and using special characters may limit the possibility to achieve the correct results. + +~> **Required warehouse** This resource may require active warehouse. Please, make sure you have either set a DEFAULT_WAREHOUSE for the user, or specified a warehouse in the provider configuration. + +# {{.Name}} ({{.Type}}) + +{{ .Description | trimspace }} + +{{ if .HasExample -}} +## Example Usage + +{{ tffile (printf "examples/resources/%s/resource.tf" .Name)}} +-> **Note** Instead of using fully_qualified_name, you can reference objects managed outside Terraform by constructing a correct ID, consult [identifiers guide](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/guides/identifiers#new-computed-fully-qualified-name-field-in-resources). + + +{{- end }} + +{{ .SchemaMarkdown | trimspace }} +{{- if .HasImport }} + +## Import + +Import is supported using the following syntax: + +{{ codefile "shell" (printf "examples/resources/%s/import.sh" .Name)}} +{{- end }} + +Note: Snowflake is not returning all information needed to populate the state correctly after import (e.g. data types with attributes like NUMBER(32, 10) are returned as NUMBER, default values for arguments are not returned at all). +Also, `ALTER` for functions is very limited so most of the attributes on this resource are marked as force new. Because of that, in multiple situations plan won't be empty after importing and manual state operations may be required. diff --git a/templates/resources/procedure_python.md.tmpl b/templates/resources/procedure_python.md.tmpl new file mode 100644 index 0000000000..c0d68e135d --- /dev/null +++ b/templates/resources/procedure_python.md.tmpl @@ -0,0 +1,54 @@ +--- +page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}" +subcategory: "" +description: |- +{{ if gt (len (split .Description "")) 1 -}} +{{ index (split .Description "") 1 | plainmarkdown | trimspace | prefixlines " " }} +{{- else -}} +{{ .Description | plainmarkdown | trimspace | prefixlines " " }} +{{- end }} +--- + +-> **Note** External changes to `is_secure` and `null_input_behavior` are not currently supported. They will be handled in the following versions of the provider which may still affect this resource. + +-> **Note** `COPY GRANTS` and `OR REPLACE` are not currently supported. + +-> **Note** `RETURN... [[ NOT ] NULL]` is not currently supported. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** `is_aggregate` is not currently supported. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Use of return type `TABLE` is currently limited. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Snowflake is not returning full data type information for arguments which may lead to unexpected plan outputs. Diff suppression for such cases will be improved. + +-> **Note** Snowflake is not returning the default values for arguments so argument's `arg_default_value` external changes cannot be tracked. + +-> **Note** Limit the use of special characters (`.`, `'`, `/`, `"`, `(`, `)`, `[`, `]`, `{`, `}`, ` `) in argument names, stage ids, and secret ids. It's best to limit to only alphanumeric and underscores. There is a lot of parsing of SHOW/DESCRIBE outputs involved and using special characters may limit the possibility to achieve the correct results. + +~> **Required warehouse** This resource may require active warehouse. Please, make sure you have either set a DEFAULT_WAREHOUSE for the user, or specified a warehouse in the provider configuration. + +# {{.Name}} ({{.Type}}) + +{{ .Description | trimspace }} + +{{ if .HasExample -}} +## Example Usage + +{{ tffile (printf "examples/resources/%s/resource.tf" .Name)}} +-> **Note** Instead of using fully_qualified_name, you can reference objects managed outside Terraform by constructing a correct ID, consult [identifiers guide](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/guides/identifiers#new-computed-fully-qualified-name-field-in-resources). + + +{{- end }} + +{{ .SchemaMarkdown | trimspace }} +{{- if .HasImport }} + +## Import + +Import is supported using the following syntax: + +{{ codefile "shell" (printf "examples/resources/%s/import.sh" .Name)}} +{{- end }} + +Note: Snowflake is not returning all information needed to populate the state correctly after import (e.g. data types with attributes like NUMBER(32, 10) are returned as NUMBER, default values for arguments are not returned at all). +Also, `ALTER` for functions is very limited so most of the attributes on this resource are marked as force new. Because of that, in multiple situations plan won't be empty after importing and manual state operations may be required. diff --git a/templates/resources/procedure_scala.md.tmpl b/templates/resources/procedure_scala.md.tmpl new file mode 100644 index 0000000000..cc0445d06e --- /dev/null +++ b/templates/resources/procedure_scala.md.tmpl @@ -0,0 +1,50 @@ +--- +page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}" +subcategory: "" +description: |- +{{ if gt (len (split .Description "")) 1 -}} +{{ index (split .Description "") 1 | plainmarkdown | trimspace | prefixlines " " }} +{{- else -}} +{{ .Description | plainmarkdown | trimspace | prefixlines " " }} +{{- end }} +--- + +-> **Note** External changes to `is_secure` and `null_input_behavior` are not currently supported. They will be handled in the following versions of the provider which may still affect this resource. + +-> **Note** `COPY GRANTS` and `OR REPLACE` are not currently supported. + +-> **Note** `RETURN... [[ NOT ] NULL]` is not currently supported. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Snowflake is not returning full data type information for arguments which may lead to unexpected plan outputs. Diff suppression for such cases will be improved. + +-> **Note** Snowflake is not returning the default values for arguments so argument's `arg_default_value` external changes cannot be tracked. + +-> **Note** Limit the use of special characters (`.`, `'`, `/`, `"`, `(`, `)`, `[`, `]`, `{`, `}`, ` `) in argument names, stage ids, and secret ids. It's best to limit to only alphanumeric and underscores. There is a lot of parsing of SHOW/DESCRIBE outputs involved and using special characters may limit the possibility to achieve the correct results. + +~> **Required warehouse** This resource may require active warehouse. Please, make sure you have either set a DEFAULT_WAREHOUSE for the user, or specified a warehouse in the provider configuration. + +# {{.Name}} ({{.Type}}) + +{{ .Description | trimspace }} + +{{ if .HasExample -}} +## Example Usage + +{{ tffile (printf "examples/resources/%s/resource.tf" .Name)}} +-> **Note** Instead of using fully_qualified_name, you can reference objects managed outside Terraform by constructing a correct ID, consult [identifiers guide](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/guides/identifiers#new-computed-fully-qualified-name-field-in-resources). + + +{{- end }} + +{{ .SchemaMarkdown | trimspace }} +{{- if .HasImport }} + +## Import + +Import is supported using the following syntax: + +{{ codefile "shell" (printf "examples/resources/%s/import.sh" .Name)}} +{{- end }} + +Note: Snowflake is not returning all information needed to populate the state correctly after import (e.g. data types with attributes like NUMBER(32, 10) are returned as NUMBER, default values for arguments are not returned at all). +Also, `ALTER` for functions is very limited so most of the attributes on this resource are marked as force new. Because of that, in multiple situations plan won't be empty after importing and manual state operations may be required. diff --git a/templates/resources/procedure_sql.md.tmpl b/templates/resources/procedure_sql.md.tmpl new file mode 100644 index 0000000000..a72c04a1c2 --- /dev/null +++ b/templates/resources/procedure_sql.md.tmpl @@ -0,0 +1,50 @@ +--- +page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}" +subcategory: "" +description: |- +{{ if gt (len (split .Description "")) 1 -}} +{{ index (split .Description "") 1 | plainmarkdown | trimspace | prefixlines " " }} +{{- else -}} +{{ .Description | plainmarkdown | trimspace | prefixlines " " }} +{{- end }} +--- + +-> **Note** External changes to `is_secure` are not currently supported. They will be handled in the following versions of the provider which may still affect this resource. + +-> **Note** `COPY GRANTS` and `OR REPLACE` are not currently supported. + +-> **Note** Use of return type `TABLE` is currently limited. It will be improved in the following versions of the provider which may still affect this resource. + +-> **Note** Snowflake is not returning full data type information for arguments which may lead to unexpected plan outputs. Diff suppression for such cases will be improved. + +-> **Note** Snowflake is not returning the default values for arguments so argument's `arg_default_value` external changes cannot be tracked. + +-> **Note** Limit the use of special characters (`.`, `'`, `/`, `"`, `(`, `)`, `[`, `]`, `{`, `}`, ` `) in argument names, stage ids, and secret ids. It's best to limit to only alphanumeric and underscores. There is a lot of parsing of SHOW/DESCRIBE outputs involved and using special characters may limit the possibility to achieve the correct results. + +~> **Required warehouse** This resource may require active warehouse. Please, make sure you have either set a DEFAULT_WAREHOUSE for the user, or specified a warehouse in the provider configuration. + +# {{.Name}} ({{.Type}}) + +{{ .Description | trimspace }} + +{{ if .HasExample -}} +## Example Usage + +{{ tffile (printf "examples/resources/%s/resource.tf" .Name)}} +-> **Note** Instead of using fully_qualified_name, you can reference objects managed outside Terraform by constructing a correct ID, consult [identifiers guide](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/guides/identifiers#new-computed-fully-qualified-name-field-in-resources). + + +{{- end }} + +{{ .SchemaMarkdown | trimspace }} +{{- if .HasImport }} + +## Import + +Import is supported using the following syntax: + +{{ codefile "shell" (printf "examples/resources/%s/import.sh" .Name)}} +{{- end }} + +Note: Snowflake is not returning all information needed to populate the state correctly after import (e.g. data types with attributes like NUMBER(32, 10) are returned as NUMBER, default values for arguments are not returned at all). +Also, `ALTER` for functions is very limited so most of the attributes on this resource are marked as force new. Because of that, in multiple situations plan won't be empty after importing and manual state operations may be required.