diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md index ba822828e4..1973ca9ac3 100644 --- a/MIGRATION_GUIDE.md +++ b/MIGRATION_GUIDE.md @@ -102,6 +102,40 @@ Additionally, `JWT` value is no longer available for `authenticator` field in th ## 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 20133cacc2..fad1f2be7d 100644 --- a/docs/index.md +++ b/docs/index.md @@ -351,6 +351,8 @@ provider "snowflake" { ## Currently deprecated resources +- [snowflake_function](./docs/resources/function) +- [snowflake_procedure](./docs/resources/procedure) - [snowflake_unsafe_execute](./docs/resources/unsafe_execute) - use [snowflake_execute](./docs/resources/execute) instead diff --git a/docs/resources/function.md b/docs/resources/function.md index aa4785268c..9511de1dce 100644 --- a/docs/resources/function.md +++ b/docs/resources/function.md @@ -9,7 +9,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 64f598ce3a..5570e2575e 100644 --- a/docs/resources/function_java.md +++ b/docs/resources/function_java.md @@ -7,11 +7,44 @@ description: |- !> **Caution: Preview Feature** This feature is considered a preview feature in the provider, regardless of the state of the resource in Snowflake. We do not guarantee its stability. It will be reworked and marked as a stable feature in future releases. Breaking changes are expected, even without bumping the major version. To use this feature, add the relevant feature name to `preview_features_enabled field` in the [provider configuration](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs#schema). Please always refer to the [Getting Help](https://github.com/Snowflake-Labs/terraform-provider-snowflake?tab=readme-ov-file#getting-help) section in our Github repo to best determine how to get help for your questions. +-> **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 @@ -175,3 +208,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 950f13042f..9333693081 100644 --- a/docs/resources/function_javascript.md +++ b/docs/resources/function_javascript.md @@ -7,11 +7,46 @@ description: |- !> **Caution: Preview Feature** This feature is considered a preview feature in the provider, regardless of the state of the resource in Snowflake. We do not guarantee its stability. It will be reworked and marked as a stable feature in future releases. Breaking changes are expected, even without bumping the major version. To use this feature, add the relevant feature name to `preview_features_enabled field` in the [provider configuration](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs#schema). Please always refer to the [Getting Help](https://github.com/Snowflake-Labs/terraform-provider-snowflake?tab=readme-ov-file#getting-help) section in our Github repo to best determine how to get help for your questions. +-> **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 @@ -141,3 +176,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 4a47c89ea8..a2cf487db5 100644 --- a/docs/resources/function_python.md +++ b/docs/resources/function_python.md @@ -7,11 +7,51 @@ description: |- !> **Caution: Preview Feature** This feature is considered a preview feature in the provider, regardless of the state of the resource in Snowflake. We do not guarantee its stability. It will be reworked and marked as a stable feature in future releases. Breaking changes are expected, even without bumping the major version. To use this feature, add the relevant feature name to `preview_features_enabled field` in the [provider configuration](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs#schema). Please always refer to the [Getting Help](https://github.com/Snowflake-Labs/terraform-provider-snowflake?tab=readme-ov-file#getting-help) section in our Github repo to best determine how to get help for your questions. +-> **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 @@ -166,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_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 2c8bf718a6..9a03c90548 100644 --- a/docs/resources/function_scala.md +++ b/docs/resources/function_scala.md @@ -7,11 +7,97 @@ description: |- !> **Caution: Preview Feature** This feature is considered a preview feature in the provider, regardless of the state of the resource in Snowflake. We do not guarantee its stability. It will be reworked and marked as a stable feature in future releases. Breaking changes are expected, even without bumping the major version. To use this feature, add the relevant feature name to `preview_features_enabled field` in the [provider configuration](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs#schema). Please always refer to the [Getting Help](https://github.com/Snowflake-Labs/terraform-provider-snowflake?tab=readme-ov-file#getting-help) section in our Github repo to best determine how to get help for your questions. +-> **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 @@ -175,3 +261,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 79c94ee6c7..66124dc89f 100644 --- a/docs/resources/function_sql.md +++ b/docs/resources/function_sql.md @@ -7,11 +7,64 @@ description: |- !> **Caution: Preview Feature** This feature is considered a preview feature in the provider, regardless of the state of the resource in Snowflake. We do not guarantee its stability. It will be reworked and marked as a stable feature in future releases. Breaking changes are expected, even without bumping the major version. To use this feature, add the relevant feature name to `preview_features_enabled field` in the [provider configuration](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs#schema). Please always refer to the [Getting Help](https://github.com/Snowflake-Labs/terraform-provider-snowflake?tab=readme-ov-file#getting-help) section in our Github repo to best determine how to get help for your questions. +-> **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 @@ -140,3 +193,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 48987004a9..3f85c71c33 100644 --- a/docs/resources/procedure.md +++ b/docs/resources/procedure.md @@ -9,7 +9,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 9edc8ae6f1..3dd3858f89 100644 --- a/docs/resources/procedure_java.md +++ b/docs/resources/procedure_java.md @@ -7,11 +7,92 @@ description: |- !> **Caution: Preview Feature** This feature is considered a preview feature in the provider, regardless of the state of the resource in Snowflake. We do not guarantee its stability. It will be reworked and marked as a stable feature in future releases. Breaking changes are expected, even without bumping the major version. To use this feature, add the relevant feature name to `preview_features_enabled field` in the [provider configuration](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs#schema). Please always refer to the [Getting Help](https://github.com/Snowflake-Labs/terraform-provider-snowflake?tab=readme-ov-file#getting-help) section in our Github repo to best determine how to get help for your questions. +-> **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 @@ -31,7 +112,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. @@ -172,3 +253,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 9f28b9187a..fd50fab116 100644 --- a/docs/resources/procedure_javascript.md +++ b/docs/resources/procedure_javascript.md @@ -7,11 +7,44 @@ description: |- !> **Caution: Preview Feature** This feature is considered a preview feature in the provider, regardless of the state of the resource in Snowflake. We do not guarantee its stability. It will be reworked and marked as a stable feature in future releases. Breaking changes are expected, even without bumping the major version. To use this feature, add the relevant feature name to `preview_features_enabled field` in the [provider configuration](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs#schema). Please always refer to the [Getting Help](https://github.com/Snowflake-Labs/terraform-provider-snowflake?tab=readme-ov-file#getting-help) section in our Github repo to best determine how to get help for your questions. +-> **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 @@ -29,7 +62,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). @@ -137,3 +170,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 82d2f18b7e..76d9495fd4 100644 --- a/docs/resources/procedure_python.md +++ b/docs/resources/procedure_python.md @@ -7,11 +7,48 @@ description: |- !> **Caution: Preview Feature** This feature is considered a preview feature in the provider, regardless of the state of the resource in Snowflake. We do not guarantee its stability. It will be reworked and marked as a stable feature in future releases. Breaking changes are expected, even without bumping the major version. To use this feature, add the relevant feature name to `preview_features_enabled field` in the [provider configuration](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs#schema). Please always refer to the [Getting Help](https://github.com/Snowflake-Labs/terraform-provider-snowflake?tab=readme-ov-file#getting-help) section in our Github repo to best determine how to get help for your questions. +-> **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 @@ -31,7 +68,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. @@ -162,3 +199,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 d41a65a9c2..0b6cf82659 100644 --- a/docs/resources/procedure_scala.md +++ b/docs/resources/procedure_scala.md @@ -7,11 +7,44 @@ description: |- !> **Caution: Preview Feature** This feature is considered a preview feature in the provider, regardless of the state of the resource in Snowflake. We do not guarantee its stability. It will be reworked and marked as a stable feature in future releases. Breaking changes are expected, even without bumping the major version. To use this feature, add the relevant feature name to `preview_features_enabled field` in the [provider configuration](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs#schema). Please always refer to the [Getting Help](https://github.com/Snowflake-Labs/terraform-provider-snowflake?tab=readme-ov-file#getting-help) section in our Github repo to best determine how to get help for your questions. +-> **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 @@ -31,7 +64,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. @@ -172,3 +205,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 8bf74ae5d3..6aefb8e115 100644 --- a/docs/resources/procedure_sql.md +++ b/docs/resources/procedure_sql.md @@ -7,11 +7,41 @@ description: |- !> **Caution: Preview Feature** This feature is considered a preview feature in the provider, regardless of the state of the resource in Snowflake. We do not guarantee its stability. It will be reworked and marked as a stable feature in future releases. Breaking changes are expected, even without bumping the major version. To use this feature, add the relevant feature name to `preview_features_enabled field` in the [provider configuration](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs#schema). Please always refer to the [Getting Help](https://github.com/Snowflake-Labs/terraform-provider-snowflake?tab=readme-ov-file#getting-help) section in our Github repo to best determine how to get help for your questions. +-> **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 @@ -29,7 +59,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). @@ -137,3 +167,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 81a1a1f339..78735c7f69 100644 --- a/examples/additional/deprecated_resources.MD +++ b/examples/additional/deprecated_resources.MD @@ -1,4 +1,6 @@ ## Currently deprecated resources +- [snowflake_function](./docs/resources/function) +- [snowflake_procedure](./docs/resources/procedure) - [snowflake_unsafe_execute](./docs/resources/unsafe_execute) - use [snowflake_execute](./docs/resources/execute) instead 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/function_javascript_resource_gen.go b/pkg/acceptance/bettertestspoc/assert/resourceassert/function_javascript_resource_gen.go index e633c26e0c..86fa5f5a52 100644 --- a/pkg/acceptance/bettertestspoc/assert/resourceassert/function_javascript_resource_gen.go +++ b/pkg/acceptance/bettertestspoc/assert/resourceassert/function_javascript_resource_gen.go @@ -93,7 +93,7 @@ func (f *FunctionJavascriptResourceAssert) HasNullInputBehaviorString(expected s } func (f *FunctionJavascriptResourceAssert) HasReturnBehaviorString(expected string) *FunctionJavascriptResourceAssert { - f.AddAssertion(assert.ValueSet("return_behavior", expected)) + f.AddAssertion(assert.ValueSet("return_results_behavior", expected)) return f } diff --git a/pkg/acceptance/bettertestspoc/assert/resourceassert/function_sql_resource_gen.go b/pkg/acceptance/bettertestspoc/assert/resourceassert/function_sql_resource_gen.go index 142de640a5..7a4188adeb 100644 --- a/pkg/acceptance/bettertestspoc/assert/resourceassert/function_sql_resource_gen.go +++ b/pkg/acceptance/bettertestspoc/assert/resourceassert/function_sql_resource_gen.go @@ -93,7 +93,7 @@ func (f *FunctionSqlResourceAssert) HasNullInputBehaviorString(expected string) } func (f *FunctionSqlResourceAssert) HasReturnBehaviorString(expected string) *FunctionSqlResourceAssert { - f.AddAssertion(assert.ValueSet("return_behavior", expected)) + f.AddAssertion(assert.ValueSet("return_results_behavior", expected)) return f } 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/function_javascript_model_ext.go b/pkg/acceptance/bettertestspoc/config/model/function_javascript_model_ext.go index 3fa63b5701..c1429191a6 100644 --- a/pkg/acceptance/bettertestspoc/config/model/function_javascript_model_ext.go +++ b/pkg/acceptance/bettertestspoc/config/model/function_javascript_model_ext.go @@ -2,6 +2,12 @@ package model import ( "encoding/json" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/config" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider/resources" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk/datatypes" + tfconfig "github.com/hashicorp/terraform-plugin-testing/config" ) func (f *FunctionJavascriptModel) MarshalJSON() ([]byte, error) { @@ -14,3 +20,24 @@ func (f *FunctionJavascriptModel) MarshalJSON() ([]byte, error) { DependsOn: f.DependsOn(), }) } + +func FunctionJavascriptInline(resourceName string, id sdk.SchemaObjectIdentifierWithArguments, functionDefinition string, returnType string) *FunctionJavascriptModel { + f := &FunctionJavascriptModel{ResourceModelMeta: config.Meta(resourceName, resources.FunctionJavascript)} + f.WithDatabase(id.DatabaseName()) + f.WithFunctionDefinition(functionDefinition) + f.WithName(id.Name()) + f.WithReturnType(returnType) + f.WithSchema(id.SchemaName()) + return f +} + +func (f *FunctionJavascriptModel) WithArgument(argName string, argDataType datatypes.DataType) *FunctionJavascriptModel { + 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/function_python_model_ext.go b/pkg/acceptance/bettertestspoc/config/model/function_python_model_ext.go index 8d7475e389..f68dec8871 100644 --- a/pkg/acceptance/bettertestspoc/config/model/function_python_model_ext.go +++ b/pkg/acceptance/bettertestspoc/config/model/function_python_model_ext.go @@ -2,6 +2,11 @@ package model import ( "encoding/json" + + "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" + tfconfig "github.com/hashicorp/terraform-plugin-testing/config" ) func (f *FunctionPythonModel) MarshalJSON() ([]byte, error) { @@ -14,3 +19,67 @@ func (f *FunctionPythonModel) MarshalJSON() ([]byte, error) { DependsOn: f.DependsOn(), }) } + +func FunctionPythonBasicInline(resourceName string, id sdk.SchemaObjectIdentifierWithArguments, runtimeVersion string, returnType datatypes.DataType, handler string, functionDefinition string) *FunctionPythonModel { + return FunctionPython(resourceName, id.DatabaseName(), handler, id.Name(), returnType.ToSql(), runtimeVersion, id.SchemaName()).WithFunctionDefinition(functionDefinition) +} + +func (f *FunctionPythonModel) WithArgument(argName string, argDataType datatypes.DataType) *FunctionPythonModel { + return f.WithArgumentsValue( + tfconfig.ObjectVariable( + map[string]tfconfig.Variable{ + "arg_name": tfconfig.StringVariable(argName), + "arg_data_type": tfconfig.StringVariable(argDataType.ToSql()), + }, + ), + ) +} + +func (f *FunctionPythonModel) WithImports(imports ...sdk.NormalizedPath) *FunctionPythonModel { + 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 *FunctionPythonModel) WithExternalAccessIntegrations(ids ...sdk.AccountObjectIdentifier) *FunctionPythonModel { + return f.WithExternalAccessIntegrationsValue( + tfconfig.SetVariable( + collections.Map(ids, func(id sdk.AccountObjectIdentifier) tfconfig.Variable { return tfconfig.StringVariable(id.Name()) })..., + ), + ) +} + +func (f *FunctionPythonModel) WithSecrets(secrets map[string]sdk.SchemaObjectIdentifier) *FunctionPythonModel { + 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 *FunctionPythonModel) WithPackages(pkgs ...string) *FunctionPythonModel { + return f.WithPackagesValue( + tfconfig.SetVariable( + collections.Map(pkgs, func(pkg string) tfconfig.Variable { return tfconfig.StringVariable(pkg) })..., + ), + ) +} diff --git a/pkg/acceptance/bettertestspoc/config/model/function_scala_model_ext.go b/pkg/acceptance/bettertestspoc/config/model/function_scala_model_ext.go index a5e43e53ca..bb7fcf2847 100644 --- a/pkg/acceptance/bettertestspoc/config/model/function_scala_model_ext.go +++ b/pkg/acceptance/bettertestspoc/config/model/function_scala_model_ext.go @@ -2,6 +2,12 @@ package model import ( "encoding/json" + "strings" + + "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" + tfconfig "github.com/hashicorp/terraform-plugin-testing/config" ) func (f *FunctionScalaModel) MarshalJSON() ([]byte, error) { @@ -14,3 +20,96 @@ func (f *FunctionScalaModel) MarshalJSON() ([]byte, error) { DependsOn: f.DependsOn(), }) } + +func FunctionScalaBasicInline( + resourceName string, + id sdk.SchemaObjectIdentifierWithArguments, + runtimeVersion string, + returnType datatypes.DataType, + handler string, + functionDefinition string, +) *FunctionScalaModel { + return FunctionScala(resourceName, id.DatabaseName(), handler, id.Name(), returnType.ToSql(), runtimeVersion, id.SchemaName()).WithFunctionDefinition(functionDefinition) +} + +func (f *FunctionScalaModel) WithArgument(argName string, argDataType datatypes.DataType) *FunctionScalaModel { + return f.WithArgumentsValue( + tfconfig.ObjectVariable( + map[string]tfconfig.Variable{ + "arg_name": tfconfig.StringVariable(argName), + "arg_data_type": tfconfig.StringVariable(argDataType.ToSql()), + }, + ), + ) +} + +func (f *FunctionScalaModel) WithImport(stageLocation string, pathOnStage string) *FunctionScalaModel { + return f.WithImportsValue( + tfconfig.ObjectVariable( + map[string]tfconfig.Variable{ + "stage_location": tfconfig.StringVariable(strings.TrimPrefix(stageLocation, "@")), + "path_on_stage": tfconfig.StringVariable(pathOnStage), + }, + ), + ) +} + +func (f *FunctionScalaModel) WithImports(imports ...sdk.NormalizedPath) *FunctionScalaModel { + 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 *FunctionScalaModel) WithPackages(pkgs ...string) *FunctionScalaModel { + return f.WithPackagesValue( + tfconfig.SetVariable( + collections.Map(pkgs, func(pkg string) tfconfig.Variable { return tfconfig.StringVariable(pkg) })..., + ), + ) +} + +func (f *FunctionScalaModel) WithExternalAccessIntegrations(ids ...sdk.AccountObjectIdentifier) *FunctionScalaModel { + return f.WithExternalAccessIntegrationsValue( + tfconfig.SetVariable( + collections.Map(ids, func(id sdk.AccountObjectIdentifier) tfconfig.Variable { return tfconfig.StringVariable(id.Name()) })..., + ), + ) +} + +func (f *FunctionScalaModel) WithSecrets(secrets map[string]sdk.SchemaObjectIdentifier) *FunctionScalaModel { + 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 *FunctionScalaModel) WithTargetPathParts(stageLocation string, pathOnStage string) *FunctionScalaModel { + 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/function_sql_model_ext.go b/pkg/acceptance/bettertestspoc/config/model/function_sql_model_ext.go index d4f775628d..f01b2e8ffe 100644 --- a/pkg/acceptance/bettertestspoc/config/model/function_sql_model_ext.go +++ b/pkg/acceptance/bettertestspoc/config/model/function_sql_model_ext.go @@ -2,6 +2,12 @@ package model import ( "encoding/json" + + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/bettertestspoc/config" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/provider/resources" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk/datatypes" + tfconfig "github.com/hashicorp/terraform-plugin-testing/config" ) func (f *FunctionSqlModel) MarshalJSON() ([]byte, error) { @@ -14,3 +20,24 @@ func (f *FunctionSqlModel) MarshalJSON() ([]byte, error) { DependsOn: f.DependsOn(), }) } + +func FunctionSqlBasicInline(resourceName string, id sdk.SchemaObjectIdentifierWithArguments, functionDefinition string, returnType string) *FunctionSqlModel { + f := &FunctionSqlModel{ResourceModelMeta: config.Meta(resourceName, resources.FunctionSql)} + f.WithDatabase(id.DatabaseName()) + f.WithFunctionDefinition(functionDefinition) + f.WithName(id.Name()) + f.WithReturnType(returnType) + f.WithSchema(id.SchemaName()) + return f +} + +func (f *FunctionSqlModel) WithArgument(argName string, argDataType datatypes.DataType) *FunctionSqlModel { + 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_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/function_client.go b/pkg/acceptance/helpers/function_client.go index 36c5ffcfb4..600027fe2c 100644 --- a/pkg/acceptance/helpers/function_client.go +++ b/pkg/acceptance/helpers/function_client.go @@ -240,6 +240,11 @@ func (c *FunctionClient) SampleJavascriptDefinition(t *testing.T, argName string `, argName) } +func (c *FunctionClient) SampleJavascriptDefinitionNoArgs(t *testing.T) string { + t.Helper() + return `return 1;` +} + func (c *FunctionClient) SamplePythonDefinition(t *testing.T, funcName string, argName string) string { t.Helper() @@ -271,6 +276,14 @@ func (c *FunctionClient) SampleSqlDefinition(t *testing.T) string { return "3.141592654::FLOAT" } +func (c *FunctionClient) SampleSqlDefinitionWithArgument(t *testing.T, argName string) string { + t.Helper() + + return fmt.Sprintf(` +%s +`, argName) +} + func (c *FunctionClient) PythonIdentityDefinition(t *testing.T, funcName string, argName string) string { t.Helper() 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/function_java_acceptance_test.go b/pkg/resources/function_java_acceptance_test.go index 8e30bf28e4..e210974888 100644 --- a/pkg/resources/function_java_acceptance_test.go +++ b/pkg/resources/function_java_acceptance_test.go @@ -234,7 +234,7 @@ func TestAcc_FunctionJava_InlineFull(t *testing.T) { }). WithTargetPathParts(stage.ID().FullyQualifiedName(), jarName). WithRuntimeVersion("11"). - WithIsSecure("false"). + WithIsSecure(r.BooleanFalse). WithNullInputBehavior(string(sdk.NullInputBehaviorCalledOnNullInput)). WithReturnResultsBehavior(string(sdk.ReturnResultsBehaviorVolatile)). WithComment("some comment") diff --git a/pkg/resources/function_javascript_acceptance_test.go b/pkg/resources/function_javascript_acceptance_test.go new file mode 100644 index 0000000000..2ef1c7d7f7 --- /dev/null +++ b/pkg/resources/function_javascript_acceptance_test.go @@ -0,0 +1,194 @@ +package resources_test + +import ( + "testing" + + acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/importchecks" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers" + r "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/resources" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk/datatypes" + + "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/testdatatypes" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/testenvs" + "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_FunctionJavascript_InlineBasic(t *testing.T) { + argName := "x" + dataType := testdatatypes.DataTypeVariant + + id := acc.TestClient().Ids.RandomSchemaObjectIdentifierWithArgumentsNewDataTypes(dataType) + idWithChangedNameButTheSameDataType := acc.TestClient().Ids.RandomSchemaObjectIdentifierWithArgumentsNewDataTypes(dataType) + + definition := acc.TestClient().Function.SampleJavascriptDefinition(t, argName) + + functionModel := model.FunctionJavascriptInline("test", id, definition, datatypes.VariantLegacyDataType). + WithArgument(argName, dataType) + functionModelRenamed := model.FunctionJavascriptInline("test", idWithChangedNameButTheSameDataType, definition, datatypes.VariantLegacyDataType). + 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.FunctionJavascript), + Steps: []resource.TestStep{ + // CREATE BASIC + { + Config: config.FromModels(t, functionModel), + Check: assert.AssertThat(t, + resourceassert.FunctionJavascriptResource(t, functionModel.ResourceReference()). + HasNameString(id.Name()). + HasReturnTypeString(datatypes.VariantLegacyDataType). + HasIsSecureString(r.BooleanDefault). + HasCommentString(sdk.DefaultFunctionComment). + HasFunctionDefinitionString(definition). + HasFunctionLanguageString("JAVASCRIPT"). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + resourceshowoutputassert.FunctionShowOutput(t, functionModel.ResourceReference()). + HasIsSecure(false), + assert.Check(resource.TestCheckResourceAttr(functionModel.ResourceReference(), "arguments.0.arg_name", argName)), + assert.Check(resource.TestCheckResourceAttr(functionModel.ResourceReference(), "arguments.0.arg_data_type", dataType.ToSql())), + assert.Check(resource.TestCheckResourceAttr(functionModel.ResourceReference(), "arguments.0.arg_default_value", "")), + ), + }, + // RENAME + { + Config: config.FromModels(t, functionModelRenamed), + Check: assert.AssertThat(t, + resourceassert.FunctionJavaResource(t, functionModelRenamed.ResourceReference()). + HasNameString(idWithChangedNameButTheSameDataType.Name()). + HasFullyQualifiedNameString(idWithChangedNameButTheSameDataType.FullyQualifiedName()), + ), + }, + }, + }) +} + +func TestAcc_FunctionJavascript_InlineEmptyArgs(t *testing.T) { + id := acc.TestClient().Ids.RandomSchemaObjectIdentifierWithArgumentsNewDataTypes() + definition := acc.TestClient().Function.SampleJavascriptDefinitionNoArgs(t) + functionModel := model.FunctionJavascriptInline("test", id, definition, datatypes.VariantLegacyDataType) + + 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.FunctionJavascript), + Steps: []resource.TestStep{ + // CREATE BASIC + { + Config: config.FromModels(t, functionModel), + Check: assert.AssertThat(t, + resourceassert.FunctionJavaResource(t, functionModel.ResourceReference()). + HasNameString(id.Name()). + HasFunctionDefinitionString(definition). + HasFunctionLanguageString("JAVASCRIPT"). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + ), + }, + }, + }) +} + +func TestAcc_FunctionJavascript_InlineFull(t *testing.T) { + _ = testenvs.GetOrSkipTest(t, testenvs.EnableAcceptance) + acc.TestAccPreCheck(t) + + argName := "x" + dataType := testdatatypes.DataTypeVariant + + id := acc.TestClient().Ids.RandomSchemaObjectIdentifierWithArgumentsNewDataTypes(dataType) + definition := acc.TestClient().Function.SampleJavascriptDefinition(t, argName) + functionModel := model.FunctionJavascriptInline("test", id, definition, datatypes.VariantLegacyDataType). + WithIsSecure(r.BooleanFalse). + WithArgument(argName, dataType). + WithNullInputBehavior(string(sdk.NullInputBehaviorReturnsNullInput)). + WithReturnResultsBehavior(string(sdk.ReturnResultsBehaviorVolatile)). + WithComment("some comment") + + functionModelUpdateWithoutRecreation := model.FunctionJavascriptInline("test", id, definition, datatypes.VariantLegacyDataType). + WithArgument(argName, dataType). + WithIsSecure(r.BooleanFalse). + WithNullInputBehavior(string(sdk.NullInputBehaviorReturnsNullInput)). + WithReturnResultsBehavior(string(sdk.ReturnResultsBehaviorVolatile)). + 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.FunctionJavascript), + Steps: []resource.TestStep{ + // CREATE WITH ALL + { + Config: config.FromModels(t, functionModel), + Check: assert.AssertThat(t, + resourceassert.FunctionJavascriptResource(t, functionModel.ResourceReference()). + HasNameString(id.Name()). + HasIsSecureString(r.BooleanFalse). + HasFunctionDefinitionString(definition). + HasCommentString("some comment"). + HasFunctionLanguageString("JAVASCRIPT"). + HasNullInputBehaviorString(string(sdk.NullInputBehaviorReturnsNullInput)). + HasReturnBehaviorString(string(sdk.ReturnResultsBehaviorVolatile)). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + resourceshowoutputassert.FunctionShowOutput(t, functionModel.ResourceReference()). + HasIsSecure(false), + ), + }, + // IMPORT + { + ResourceName: functionModel.ResourceReference(), + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"arguments.0.arg_data_type"}, + ImportStateCheck: assert.AssertThatImport(t, + resourceassert.ImportedFunctionJavaResource(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", "VARIANT")), + assert.CheckImport(importchecks.TestCheckResourceAttrInstanceState(helpers.EncodeResourceIdentifier(id), "arguments.0.arg_default_value", "")), + ), + }, + // UPDATE WITHOUT RECREATION + { + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(functionModelUpdateWithoutRecreation.ResourceReference(), plancheck.ResourceActionUpdate), + }, + }, + Config: config.FromModels(t, functionModelUpdateWithoutRecreation), + Check: assert.AssertThat(t, + resourceassert.FunctionJavascriptResource(t, functionModelUpdateWithoutRecreation.ResourceReference()). + HasNameString(id.Name()). + HasIsSecureString(r.BooleanFalse). + HasFunctionDefinitionString(definition). + HasCommentString("some other comment"). + HasFunctionLanguageString("JAVASCRIPT"). + HasNullInputBehaviorString(string(sdk.NullInputBehaviorReturnsNullInput)). + HasReturnBehaviorString(string(sdk.ReturnResultsBehaviorVolatile)). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + resourceshowoutputassert.FunctionShowOutput(t, functionModelUpdateWithoutRecreation.ResourceReference()). + HasIsSecure(false), + ), + }, + }, + }) +} diff --git a/pkg/resources/function_python_acceptance_test.go b/pkg/resources/function_python_acceptance_test.go new file mode 100644 index 0000000000..04c82d91e5 --- /dev/null +++ b/pkg/resources/function_python_acceptance_test.go @@ -0,0 +1,229 @@ +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/hashicorp/terraform-plugin-testing/plancheck" + + "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/tfversion" +) + +func TestAcc_FunctionPython_InlineBasic(t *testing.T) { + funcName := "some_function" + argName := "x" + dataType := testdatatypes.DataTypeNumber_36_2 + + id := acc.TestClient().Ids.RandomSchemaObjectIdentifierWithArgumentsNewDataTypes(dataType) + idWithChangedNameButTheSameDataType := acc.TestClient().Ids.RandomSchemaObjectIdentifierWithArgumentsNewDataTypes(dataType) + + definition := acc.TestClient().Function.SamplePythonDefinition(t, funcName, argName) + + functionModel := model.FunctionPythonBasicInline("test", id, "3.8", dataType, funcName, definition). + WithArgument(argName, dataType) + functionModelRenamed := model.FunctionPythonBasicInline("test", idWithChangedNameButTheSameDataType, "3.8", 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.FunctionPython), + Steps: []resource.TestStep{ + // CREATE BASIC + { + Config: config.FromModels(t, functionModel), + Check: assert.AssertThat(t, + resourceassert.FunctionPythonResource(t, functionModel.ResourceReference()). + HasNameString(id.Name()). + HasIsSecureString(r.BooleanDefault). + HasCommentString(sdk.DefaultFunctionComment). + HasRuntimeVersionString("3.8"). + HasFunctionDefinitionString(definition). + HasFunctionLanguageString("PYTHON"). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + resourceshowoutputassert.FunctionShowOutput(t, functionModel.ResourceReference()). + HasIsSecure(false), + assert.Check(resource.TestCheckResourceAttr(functionModel.ResourceReference(), "arguments.0.arg_name", argName)), + assert.Check(resource.TestCheckResourceAttr(functionModel.ResourceReference(), "arguments.0.arg_data_type", dataType.ToSql())), + assert.Check(resource.TestCheckResourceAttr(functionModel.ResourceReference(), "arguments.0.arg_default_value", "")), + ), + }, + // IMPORT + { + ResourceName: functionModel.ResourceReference(), + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"arguments.0.arg_data_type", "is_aggregate", "is_secure", "null_input_behavior", "return_results_behavior"}, + ImportStateCheck: assert.AssertThatImport(t, + resourceassert.ImportedFunctionPythonResource(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", "NUMBER(38, 0)")), + assert.CheckImport(importchecks.TestCheckResourceAttrInstanceState(helpers.EncodeResourceIdentifier(id), "arguments.0.arg_default_value", "")), + ), + }, + // RENAME + { + Config: config.FromModels(t, functionModelRenamed), + Check: assert.AssertThat(t, + resourceassert.FunctionPythonResource(t, functionModelRenamed.ResourceReference()). + HasNameString(idWithChangedNameButTheSameDataType.Name()). + HasFullyQualifiedNameString(idWithChangedNameButTheSameDataType.FullyQualifiedName()), + ), + }, + }, + }) +} + +func TestAcc_FunctionPython_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 := "some_function" + argName := "x" + dataType := testdatatypes.DataTypeNumber_36_2 + + id := acc.TestClient().Ids.RandomSchemaObjectIdentifierWithArgumentsNewDataTypes(dataType) + definition := acc.TestClient().Function.SamplePythonDefinition(t, funcName, argName) + + functionModel := model.FunctionPythonBasicInline("test", id, "3.8", dataType, funcName, definition). + WithIsSecure(r.BooleanFalse). + WithArgument(argName, dataType). + WithNullInputBehavior(string(sdk.NullInputBehaviorCalledOnNullInput)). + WithReturnResultsBehavior(string(sdk.ReturnResultsBehaviorVolatile)). + WithComment("some comment"). + WithImports( + sdk.NormalizedPath{StageLocation: "~", PathOnStage: tmpPythonFunction.ModuleName + ".py"}, + sdk.NormalizedPath{StageLocation: "~", PathOnStage: tmpPythonFunction2.ModuleName + ".py"}, + ). + WithPackages("numpy", "pandas"). + WithExternalAccessIntegrations(externalAccessIntegration, externalAccessIntegration2). + WithSecrets(map[string]sdk.SchemaObjectIdentifier{ + "abc": secretId, + "def": secretId2, + }) + + functionModelUpdateWithoutRecreation := model.FunctionPythonBasicInline("test", id, "3.8", dataType, funcName, definition). + WithIsSecure(r.BooleanFalse). + WithArgument(argName, dataType). + WithNullInputBehavior(string(sdk.NullInputBehaviorCalledOnNullInput)). + WithReturnResultsBehavior(string(sdk.ReturnResultsBehaviorVolatile)). + WithComment("some other comment"). + WithImports( + sdk.NormalizedPath{StageLocation: "~", PathOnStage: tmpPythonFunction.ModuleName + ".py"}, + sdk.NormalizedPath{StageLocation: "~", PathOnStage: tmpPythonFunction2.ModuleName + ".py"}, + ). + WithPackages("numpy", "pandas"). + WithExternalAccessIntegrations(externalAccessIntegration). + WithSecrets(map[string]sdk.SchemaObjectIdentifier{ + "def": secretId2, + }) + + 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.FunctionPython), + Steps: []resource.TestStep{ + // CREATE WITH ALL + { + Config: config.FromModels(t, functionModel), + Check: assert.AssertThat(t, + resourceassert.FunctionPythonResource(t, functionModel.ResourceReference()). + HasNameString(id.Name()). + HasIsSecureString(r.BooleanFalse). + HasRuntimeVersionString("3.8"). + HasFunctionDefinitionString(definition). + HasCommentString("some comment"). + HasFunctionLanguageString("PYTHON"). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + assert.Check(resource.TestCheckResourceAttr(functionModel.ResourceReference(), "secrets.#", "2")), + assert.Check(resource.TestCheckResourceAttr(functionModel.ResourceReference(), "external_access_integrations.#", "2")), + assert.Check(resource.TestCheckResourceAttr(functionModel.ResourceReference(), "packages.#", "2")), + resourceshowoutputassert.FunctionShowOutput(t, functionModel.ResourceReference()). + HasIsSecure(false), + ), + }, + // IMPORT + { + ResourceName: functionModel.ResourceReference(), + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"is_aggregate", "arguments.0.arg_data_type"}, + ImportStateCheck: assert.AssertThatImport(t, + resourceassert.ImportedFunctionPythonResource(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", "NUMBER(38, 0)")), + assert.CheckImport(importchecks.TestCheckResourceAttrInstanceState(helpers.EncodeResourceIdentifier(id), "arguments.0.arg_default_value", "")), + ), + }, + // UPDATE WITHOUT RECREATION + { + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(functionModelUpdateWithoutRecreation.ResourceReference(), plancheck.ResourceActionUpdate), + }, + }, + Config: config.FromModels(t, functionModelUpdateWithoutRecreation), + Check: assert.AssertThat(t, + resourceassert.FunctionPythonResource(t, functionModelUpdateWithoutRecreation.ResourceReference()). + HasNameString(id.Name()). + HasIsSecureString(r.BooleanFalse). + HasRuntimeVersionString("3.8"). + HasFunctionDefinitionString(definition). + HasCommentString("some other comment"). + HasFunctionLanguageString("PYTHON"). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + assert.Check(resource.TestCheckResourceAttr(functionModelUpdateWithoutRecreation.ResourceReference(), "secrets.#", "1")), + assert.Check(resource.TestCheckResourceAttr(functionModelUpdateWithoutRecreation.ResourceReference(), "secrets.0.secret_variable_name", "def")), + assert.Check(resource.TestCheckResourceAttr(functionModelUpdateWithoutRecreation.ResourceReference(), "secrets.0.secret_id", secretId2.FullyQualifiedName())), + assert.Check(resource.TestCheckResourceAttr(functionModelUpdateWithoutRecreation.ResourceReference(), "external_access_integrations.#", "1")), + assert.Check(resource.TestCheckResourceAttr(functionModelUpdateWithoutRecreation.ResourceReference(), "external_access_integrations.0", externalAccessIntegration.Name())), + assert.Check(resource.TestCheckResourceAttr(functionModelUpdateWithoutRecreation.ResourceReference(), "packages.#", "2")), + resourceshowoutputassert.FunctionShowOutput(t, functionModelUpdateWithoutRecreation.ResourceReference()). + HasIsSecure(false), + ), + }, + }, + }) +} diff --git a/pkg/resources/function_scala.go b/pkg/resources/function_scala.go index 44208a46d9..558e84107c 100644 --- a/pkg/resources/function_scala.go +++ b/pkg/resources/function_scala.go @@ -66,7 +66,7 @@ func CreateContextFunctionScala(ctx context.Context, d *schema.ResourceData, met argumentDataTypes := collections.Map(argumentRequests, func(r sdk.FunctionArgumentRequest) datatypes.DataType { return r.ArgDataType }) id := sdk.NewSchemaObjectIdentifierWithArgumentsNormalized(database, sc, name, argumentDataTypes...) - request := sdk.NewCreateForScalaFunctionRequest(id.SchemaObjectId(), returnDataType, runtimeVersion, handler). + request := sdk.NewCreateForScalaFunctionRequest(id.SchemaObjectId(), returnDataType, handler, runtimeVersion). WithArguments(argumentRequests) errs := errors.Join( diff --git a/pkg/resources/function_scala_acceptance_test.go b/pkg/resources/function_scala_acceptance_test.go new file mode 100644 index 0000000000..2dbc466a4a --- /dev/null +++ b/pkg/resources/function_scala_acceptance_test.go @@ -0,0 +1,248 @@ +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" +) + +func TestAcc_FunctionScala_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().Function.SampleScalaDefinition(t, className, funcName, argName) + + functionModel := model.FunctionScalaBasicInline("test", id, "2.12", dataType, handler, definition). + WithArgument(argName, dataType) + functionModelRenamed := model.FunctionScalaBasicInline("test", idWithChangedNameButTheSameDataType, "2.12", 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.FunctionScala), + Steps: []resource.TestStep{ + // CREATE BASIC + { + Config: config.FromModels(t, functionModel), + Check: assert.AssertThat(t, + resourceassert.FunctionScalaResource(t, functionModel.ResourceReference()). + HasNameString(id.Name()). + HasIsSecureString(r.BooleanDefault). + HasCommentString(sdk.DefaultFunctionComment). + HasRuntimeVersionString("2.12"). + HasFunctionDefinitionString(definition). + HasFunctionLanguageString("SCALA"). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + resourceshowoutputassert.FunctionShowOutput(t, functionModel.ResourceReference()). + HasIsSecure(false), + assert.Check(resource.TestCheckResourceAttr(functionModel.ResourceReference(), "arguments.0.arg_name", argName)), + assert.Check(resource.TestCheckResourceAttr(functionModel.ResourceReference(), "arguments.0.arg_data_type", dataType.ToSql())), + assert.Check(resource.TestCheckResourceAttr(functionModel.ResourceReference(), "arguments.0.arg_default_value", "")), + ), + }, + // IMPORT + { + ResourceName: functionModel.ResourceReference(), + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"arguments.0.arg_data_type", "is_secure", "null_input_behavior", "return_results_behavior"}, + ImportStateCheck: assert.AssertThatImport(t, + resourceassert.ImportedFunctionScalaResource(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, functionModelRenamed), + Check: assert.AssertThat(t, + resourceassert.FunctionJavaResource(t, functionModelRenamed.ResourceReference()). + HasNameString(idWithChangedNameButTheSameDataType.Name()). + HasFullyQualifiedNameString(idWithChangedNameButTheSameDataType.FullyQualifiedName()), + ), + }, + }, + }) +} + +func TestAcc_FunctionScala_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) + + tmpJavaFunction := acc.TestClient().CreateSampleJavaFunctionAndJarOnUserStage(t) + tmpJavaFunction2 := acc.TestClient().CreateSampleJavaFunctionAndJarOnUserStage(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().Function.SampleScalaDefinition(t, className, funcName, argName) + // TODO [SNOW-1850370]: extract to helper + jarName := fmt.Sprintf("tf-%d-%s.jar", time.Now().Unix(), random.AlphaN(5)) + + functionModel := model.FunctionScalaBasicInline("test", id, "2.12", dataType, handler, definition). + WithArgument(argName, dataType). + WithImports( + sdk.NormalizedPath{StageLocation: "~", PathOnStage: tmpJavaFunction.JarName}, + sdk.NormalizedPath{StageLocation: "~", PathOnStage: tmpJavaFunction2.JarName}, + ). + WithPackages("com.snowflake:snowpark:1.14.0", "com.snowflake:telemetry:0.1.0"). + WithExternalAccessIntegrations(externalAccessIntegration, externalAccessIntegration2). + WithSecrets(map[string]sdk.SchemaObjectIdentifier{ + "abc": secretId, + "def": secretId2, + }). + WithTargetPathParts(stage.ID().FullyQualifiedName(), jarName). + WithIsSecure(r.BooleanFalse). + WithNullInputBehavior(string(sdk.NullInputBehaviorCalledOnNullInput)). + WithReturnResultsBehavior(string(sdk.ReturnResultsBehaviorVolatile)). + WithComment("some comment") + + functionModelUpdateWithoutRecreation := model.FunctionScalaBasicInline("test", id, "2.12", dataType, handler, definition). + WithArgument(argName, dataType). + WithImports( + sdk.NormalizedPath{StageLocation: "~", PathOnStage: tmpJavaFunction.JarName}, + sdk.NormalizedPath{StageLocation: "~", PathOnStage: tmpJavaFunction2.JarName}, + ). + WithPackages("com.snowflake:snowpark:1.14.0", "com.snowflake:telemetry:0.1.0"). + WithExternalAccessIntegrations(externalAccessIntegration). + WithSecrets(map[string]sdk.SchemaObjectIdentifier{ + "def": secretId2, + }). + WithTargetPathParts(stage.ID().FullyQualifiedName(), jarName). + WithIsSecure(r.BooleanFalse). + WithNullInputBehavior(string(sdk.NullInputBehaviorCalledOnNullInput)). + WithReturnResultsBehavior(string(sdk.ReturnResultsBehaviorVolatile)). + 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.FunctionScala), + Steps: []resource.TestStep{ + // CREATE WITH ALL + { + Config: config.FromModels(t, functionModel), + Check: assert.AssertThat(t, + resourceassert.FunctionScalaResource(t, functionModel.ResourceReference()). + HasNameString(id.Name()). + HasIsSecureString(r.BooleanFalse). + HasRuntimeVersionString("2.12"). + HasFunctionDefinitionString(definition). + HasCommentString("some comment"). + HasFunctionLanguageString("SCALA"). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + assert.Check(resource.TestCheckResourceAttr(functionModel.ResourceReference(), "target_path.0.stage_location", stage.ID().FullyQualifiedName())), + assert.Check(resource.TestCheckResourceAttr(functionModel.ResourceReference(), "target_path.0.path_on_stage", jarName)), + assert.Check(resource.TestCheckResourceAttr(functionModel.ResourceReference(), "secrets.#", "2")), + assert.Check(resource.TestCheckResourceAttr(functionModel.ResourceReference(), "external_access_integrations.#", "2")), + assert.Check(resource.TestCheckResourceAttr(functionModel.ResourceReference(), "packages.#", "2")), + resourceshowoutputassert.FunctionShowOutput(t, functionModel.ResourceReference()). + HasIsSecure(false), + ), + }, + // IMPORT + { + ResourceName: functionModel.ResourceReference(), + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"arguments.0.arg_data_type"}, + ImportStateCheck: assert.AssertThatImport(t, + resourceassert.ImportedFunctionScalaResource(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(functionModelUpdateWithoutRecreation.ResourceReference(), plancheck.ResourceActionUpdate), + }, + }, + Config: config.FromModels(t, functionModelUpdateWithoutRecreation), + Check: assert.AssertThat(t, + resourceassert.FunctionScalaResource(t, functionModelUpdateWithoutRecreation.ResourceReference()). + HasNameString(id.Name()). + HasIsSecureString(r.BooleanFalse). + HasRuntimeVersionString("2.12"). + HasFunctionDefinitionString(definition). + HasCommentString("some other comment"). + HasFunctionLanguageString("SCALA"). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + assert.Check(resource.TestCheckResourceAttr(functionModelUpdateWithoutRecreation.ResourceReference(), "target_path.0.stage_location", stage.ID().FullyQualifiedName())), + assert.Check(resource.TestCheckResourceAttr(functionModelUpdateWithoutRecreation.ResourceReference(), "target_path.0.path_on_stage", jarName)), + assert.Check(resource.TestCheckResourceAttr(functionModelUpdateWithoutRecreation.ResourceReference(), "secrets.#", "1")), + assert.Check(resource.TestCheckResourceAttr(functionModelUpdateWithoutRecreation.ResourceReference(), "secrets.0.secret_variable_name", "def")), + assert.Check(resource.TestCheckResourceAttr(functionModelUpdateWithoutRecreation.ResourceReference(), "secrets.0.secret_id", secretId2.FullyQualifiedName())), + assert.Check(resource.TestCheckResourceAttr(functionModelUpdateWithoutRecreation.ResourceReference(), "external_access_integrations.#", "1")), + assert.Check(resource.TestCheckResourceAttr(functionModelUpdateWithoutRecreation.ResourceReference(), "external_access_integrations.0", externalAccessIntegration.Name())), + assert.Check(resource.TestCheckResourceAttr(functionModelUpdateWithoutRecreation.ResourceReference(), "packages.#", "2")), + resourceshowoutputassert.FunctionShowOutput(t, functionModelUpdateWithoutRecreation.ResourceReference()). + HasIsSecure(false), + ), + }, + }, + }) +} diff --git a/pkg/resources/function_sql_acceptance_test.go b/pkg/resources/function_sql_acceptance_test.go new file mode 100644 index 0000000000..c8df1348ed --- /dev/null +++ b/pkg/resources/function_sql_acceptance_test.go @@ -0,0 +1,164 @@ +package resources_test + +import ( + "testing" + + acc "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance" + "github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/acceptance/helpers/random" + 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/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/tfversion" +) + +func TestAcc_FunctionSql_InlineBasic(t *testing.T) { + argName := "abc" + dataType := testdatatypes.DataTypeFloat + id := acc.TestClient().Ids.RandomSchemaObjectIdentifierWithArgumentsNewDataTypes(dataType) + idWithChangedNameButTheSameDataType := acc.TestClient().Ids.RandomSchemaObjectIdentifierWithArgumentsNewDataTypes() + + definition := acc.TestClient().Function.SampleSqlDefinitionWithArgument(t, argName) + + functionModel := model.FunctionSqlBasicInline("test", id, definition, dataType.ToLegacyDataTypeSql()). + WithArgument(argName, dataType) + functionModelRenamed := model.FunctionSqlBasicInline("test", idWithChangedNameButTheSameDataType, definition, dataType.ToLegacyDataTypeSql()). + 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.FunctionSql), + Steps: []resource.TestStep{ + // CREATE BASIC + { + Config: config.FromModels(t, functionModel), + Check: assert.AssertThat(t, + resourceassert.FunctionSqlResource(t, functionModel.ResourceReference()). + HasNameString(id.Name()). + HasIsSecureString(r.BooleanDefault). + HasCommentString(sdk.DefaultFunctionComment). + HasFunctionDefinitionString(definition). + HasFunctionLanguageString("SQL"). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + resourceshowoutputassert.FunctionShowOutput(t, functionModel.ResourceReference()). + HasIsSecure(false), + assert.Check(resource.TestCheckResourceAttr(functionModel.ResourceReference(), "arguments.0.arg_name", argName)), + assert.Check(resource.TestCheckResourceAttr(functionModel.ResourceReference(), "arguments.0.arg_data_type", dataType.ToSql())), + assert.Check(resource.TestCheckResourceAttr(functionModel.ResourceReference(), "arguments.0.arg_default_value", "")), + ), + }, + // IMPORT + { + ResourceName: functionModel.ResourceReference(), + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{}, + ImportStateCheck: assert.AssertThatImport(t, + resourceassert.ImportedFunctionSqlResource(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", "FLOAT")), + assert.CheckImport(importchecks.TestCheckResourceAttrInstanceState(helpers.EncodeResourceIdentifier(id), "arguments.0.arg_default_value", "")), + ), + }, + // RENAME + { + Config: config.FromModels(t, functionModelRenamed), + Check: assert.AssertThat(t, + resourceassert.FunctionSqlResource(t, functionModelRenamed.ResourceReference()). + HasNameString(idWithChangedNameButTheSameDataType.Name()). + HasFullyQualifiedNameString(idWithChangedNameButTheSameDataType.FullyQualifiedName()), + ), + }, + }, + }) +} + +func TestAcc_FunctionSql_InlineFull(t *testing.T) { + argName := "abc" + comment := random.Comment() + otherComment := random.Comment() + dataType := testdatatypes.DataTypeFloat + id := acc.TestClient().Ids.RandomSchemaObjectIdentifierWithArgumentsNewDataTypes(dataType) + idWithChangedNameButTheSameDataType := acc.TestClient().Ids.RandomSchemaObjectIdentifierWithArgumentsNewDataTypes(dataType) + + definition := acc.TestClient().Function.SampleSqlDefinitionWithArgument(t, argName) + + functionModel := model.FunctionSqlBasicInline("test", id, definition, dataType.ToLegacyDataTypeSql()). + WithIsSecure(r.BooleanFalse). + WithArgument(argName, dataType). + WithReturnResultsBehavior(string(sdk.ReturnResultsBehaviorVolatile)). + WithComment(comment) + functionModelRenamed := model.FunctionSqlBasicInline("test", idWithChangedNameButTheSameDataType, definition, dataType.ToLegacyDataTypeSql()). + WithIsSecure(r.BooleanFalse). + WithArgument(argName, dataType). + WithReturnResultsBehavior(string(sdk.ReturnResultsBehaviorVolatile)). + WithComment(otherComment) + + 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.FunctionSql), + Steps: []resource.TestStep{ + // CREATE BASIC + { + Config: config.FromModels(t, functionModel), + Check: assert.AssertThat(t, + resourceassert.FunctionSqlResource(t, functionModel.ResourceReference()). + HasNameString(id.Name()). + HasIsSecureString(r.BooleanFalse). + HasCommentString(comment). + HasReturnBehaviorString(string(sdk.ReturnResultsBehaviorVolatile)). + HasFunctionDefinitionString(definition). + HasFunctionLanguageString("SQL"). + HasFullyQualifiedNameString(id.FullyQualifiedName()), + resourceshowoutputassert.FunctionShowOutput(t, functionModel.ResourceReference()). + HasIsSecure(false), + assert.Check(resource.TestCheckResourceAttr(functionModel.ResourceReference(), "arguments.0.arg_name", argName)), + assert.Check(resource.TestCheckResourceAttr(functionModel.ResourceReference(), "arguments.0.arg_data_type", dataType.ToSql())), + assert.Check(resource.TestCheckResourceAttr(functionModel.ResourceReference(), "arguments.0.arg_default_value", "")), + ), + }, + // IMPORT + { + ResourceName: functionModel.ResourceReference(), + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"return_results_behavior"}, + ImportStateCheck: assert.AssertThatImport(t, + resourceassert.ImportedFunctionSqlResource(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", "FLOAT")), + assert.CheckImport(importchecks.TestCheckResourceAttrInstanceState(helpers.EncodeResourceIdentifier(id), "arguments.0.arg_default_value", "")), + ), + }, + // RENAME + { + Config: config.FromModels(t, functionModelRenamed), + Check: assert.AssertThat(t, + resourceassert.FunctionSqlResource(t, functionModelRenamed.ResourceReference()). + HasNameString(idWithChangedNameButTheSameDataType.Name()). + HasFullyQualifiedNameString(idWithChangedNameButTheSameDataType.FullyQualifiedName()). + HasCommentString(otherComment), + ), + }, + }, + }) +} 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 8a9811e08d..11e500063f 100644 --- a/pkg/resources/procedure_java.go +++ b/pkg/resources/procedure_java.go @@ -78,6 +78,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), @@ -129,6 +130,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 38c1830552..1f5a7eee8d 100644 --- a/pkg/resources/procedure_javascript.go +++ b/pkg/resources/procedure_javascript.go @@ -71,6 +71,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 { @@ -117,6 +118,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 6dc866a476..756e65dc7e 100644 --- a/pkg/resources/procedure_python.go +++ b/pkg/resources/procedure_python.go @@ -78,6 +78,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), @@ -128,6 +129,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 72461cd782..46651737ac 100644 --- a/pkg/resources/procedure_scala.go +++ b/pkg/resources/procedure_scala.go @@ -24,7 +24,7 @@ func ProcedureScala() *schema.Resource { return &schema.Resource{ CreateContext: PreviewFeatureCreateContextWrapper(string(previewfeatures.ProcedureScalaResource), TrackingCreateWrapper(resources.ProcedureScala, CreateContextProcedureScala)), ReadContext: PreviewFeatureReadContextWrapper(string(previewfeatures.ProcedureScalaResource), TrackingReadWrapper(resources.ProcedureScala, ReadContextProcedureScala)), - UpdateContext: PreviewFeatureUpdateContextWrapper(string(previewfeatures.ProcedureScalaResource), TrackingUpdateWrapper(resources.ProcedureScala, UpdateProcedure("SQL", ReadContextProcedureScala))), + UpdateContext: PreviewFeatureUpdateContextWrapper(string(previewfeatures.ProcedureScalaResource), TrackingUpdateWrapper(resources.ProcedureScala, UpdateProcedure("SCALA", ReadContextProcedureScala))), DeleteContext: PreviewFeatureDeleteContextWrapper(string(previewfeatures.ProcedureScalaResource), 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).", @@ -78,6 +78,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), @@ -129,6 +130,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 3a7424b4de..496ff81071 100644 --- a/pkg/resources/procedure_sql.go +++ b/pkg/resources/procedure_sql.go @@ -70,6 +70,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 { @@ -116,6 +117,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 b5e9a35fb6..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() @@ -2053,12 +2053,13 @@ func TestInt_Functions(t *testing.T) { t.Run("create function for SQL - return table data type", func(t *testing.T) { argName := "x" - returnDataType, err := datatypes.ParseDataType(fmt.Sprintf("TABLE(ID %s, PRICE %s, THIRD %s)", datatypes.NumberLegacyDataType, datatypes.FloatLegacyDataType, datatypes.VarcharLegacyDataType)) + returnDataType, err := datatypes.ParseDataType(fmt.Sprintf("TABLE(PRICE %s, THIRD %s)", datatypes.FloatLegacyDataType, datatypes.VarcharLegacyDataType)) require.NoError(t, err) id := testClientHelper().Ids.RandomSchemaObjectIdentifierWithArguments(datatypes.VarcharLegacyDataType) - definition := ` SELECT 1, 2.2::float, 'abc';` + definition := ` +SELECT 2.2::float, 'abc');` // the ending parenthesis has to be there (otherwise SQL compilation error is thrown) dt := sdk.NewFunctionReturnsResultDataTypeRequest(returnDataType) returns := sdk.NewFunctionReturnsRequest().WithResultDataType(*dt) argument := sdk.NewFunctionArgumentRequest(argName, nil).WithArgDataTypeOld(datatypes.VarcharLegacyDataType) @@ -2076,7 +2077,7 @@ func TestInt_Functions(t *testing.T) { HasCreatedOnNotEmpty(). HasName(id.Name()). HasSchemaName(id.SchemaName()). - HasArgumentsRawContains(returnDataType.ToLegacyDataTypeSql()), + HasArgumentsRawContains(strings.ReplaceAll(returnDataType.ToLegacyDataTypeSql(), "TABLE(", "TABLE (")), ) assertions.AssertThatObject(t, objectassert.FunctionDetails(t, id). 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..70d8c90119 --- /dev/null +++ b/templates/resources/function_java.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 }} +--- + +!> **Caution: Preview Feature** This feature is considered a preview feature in the provider, regardless of the state of the resource in Snowflake. We do not guarantee its stability. It will be reworked and marked as a stable feature in future releases. Breaking changes are expected, even without bumping the major version. To use this feature, add the relevant feature name to `preview_features_enabled field` in the [provider configuration](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs#schema). Please always refer to the [Getting Help](https://github.com/Snowflake-Labs/terraform-provider-snowflake?tab=readme-ov-file#getting-help) section in our Github repo to best determine how to get help for your questions. + +-> **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..70d8c90119 --- /dev/null +++ b/templates/resources/function_javascript.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 }} +--- + +!> **Caution: Preview Feature** This feature is considered a preview feature in the provider, regardless of the state of the resource in Snowflake. We do not guarantee its stability. It will be reworked and marked as a stable feature in future releases. Breaking changes are expected, even without bumping the major version. To use this feature, add the relevant feature name to `preview_features_enabled field` in the [provider configuration](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs#schema). Please always refer to the [Getting Help](https://github.com/Snowflake-Labs/terraform-provider-snowflake?tab=readme-ov-file#getting-help) section in our Github repo to best determine how to get help for your questions. + +-> **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..8739210377 --- /dev/null +++ b/templates/resources/function_python.md.tmpl @@ -0,0 +1,56 @@ +--- +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 }} +--- + +!> **Caution: Preview Feature** This feature is considered a preview feature in the provider, regardless of the state of the resource in Snowflake. We do not guarantee its stability. It will be reworked and marked as a stable feature in future releases. Breaking changes are expected, even without bumping the major version. To use this feature, add the relevant feature name to `preview_features_enabled field` in the [provider configuration](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs#schema). Please always refer to the [Getting Help](https://github.com/Snowflake-Labs/terraform-provider-snowflake?tab=readme-ov-file#getting-help) section in our Github repo to best determine how to get help for your questions. + +-> **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..ff73515a0c --- /dev/null +++ b/templates/resources/function_scala.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 }} +--- + +!> **Caution: Preview Feature** This feature is considered a preview feature in the provider, regardless of the state of the resource in Snowflake. We do not guarantee its stability. It will be reworked and marked as a stable feature in future releases. Breaking changes are expected, even without bumping the major version. To use this feature, add the relevant feature name to `preview_features_enabled field` in the [provider configuration](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs#schema). Please always refer to the [Getting Help](https://github.com/Snowflake-Labs/terraform-provider-snowflake?tab=readme-ov-file#getting-help) section in our Github repo to best determine how to get help for your questions. + +-> **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..7a34e9af24 --- /dev/null +++ b/templates/resources/function_sql.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 }} +--- + +!> **Caution: Preview Feature** This feature is considered a preview feature in the provider, regardless of the state of the resource in Snowflake. We do not guarantee its stability. It will be reworked and marked as a stable feature in future releases. Breaking changes are expected, even without bumping the major version. To use this feature, add the relevant feature name to `preview_features_enabled field` in the [provider configuration](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs#schema). Please always refer to the [Getting Help](https://github.com/Snowflake-Labs/terraform-provider-snowflake?tab=readme-ov-file#getting-help) section in our Github repo to best determine how to get help for your questions. + +-> **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..61ec281fff --- /dev/null +++ b/templates/resources/procedure_java.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 }} +--- + +!> **Caution: Preview Feature** This feature is considered a preview feature in the provider, regardless of the state of the resource in Snowflake. We do not guarantee its stability. It will be reworked and marked as a stable feature in future releases. Breaking changes are expected, even without bumping the major version. To use this feature, add the relevant feature name to `preview_features_enabled field` in the [provider configuration](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs#schema). Please always refer to the [Getting Help](https://github.com/Snowflake-Labs/terraform-provider-snowflake?tab=readme-ov-file#getting-help) section in our Github repo to best determine how to get help for your questions. + +-> **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..61ec281fff --- /dev/null +++ b/templates/resources/procedure_javascript.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 }} +--- + +!> **Caution: Preview Feature** This feature is considered a preview feature in the provider, regardless of the state of the resource in Snowflake. We do not guarantee its stability. It will be reworked and marked as a stable feature in future releases. Breaking changes are expected, even without bumping the major version. To use this feature, add the relevant feature name to `preview_features_enabled field` in the [provider configuration](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs#schema). Please always refer to the [Getting Help](https://github.com/Snowflake-Labs/terraform-provider-snowflake?tab=readme-ov-file#getting-help) section in our Github repo to best determine how to get help for your questions. + +-> **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..2636c371fa --- /dev/null +++ b/templates/resources/procedure_python.md.tmpl @@ -0,0 +1,56 @@ +--- +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 }} +--- + +!> **Caution: Preview Feature** This feature is considered a preview feature in the provider, regardless of the state of the resource in Snowflake. We do not guarantee its stability. It will be reworked and marked as a stable feature in future releases. Breaking changes are expected, even without bumping the major version. To use this feature, add the relevant feature name to `preview_features_enabled field` in the [provider configuration](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs#schema). Please always refer to the [Getting Help](https://github.com/Snowflake-Labs/terraform-provider-snowflake?tab=readme-ov-file#getting-help) section in our Github repo to best determine how to get help for your questions. + +-> **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..e8ea3af6eb --- /dev/null +++ b/templates/resources/procedure_scala.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 }} +--- + +!> **Caution: Preview Feature** This feature is considered a preview feature in the provider, regardless of the state of the resource in Snowflake. We do not guarantee its stability. It will be reworked and marked as a stable feature in future releases. Breaking changes are expected, even without bumping the major version. To use this feature, add the relevant feature name to `preview_features_enabled field` in the [provider configuration](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs#schema). Please always refer to the [Getting Help](https://github.com/Snowflake-Labs/terraform-provider-snowflake?tab=readme-ov-file#getting-help) section in our Github repo to best determine how to get help for your questions. + +-> **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..70ea3952a5 --- /dev/null +++ b/templates/resources/procedure_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 }} +--- + +!> **Caution: Preview Feature** This feature is considered a preview feature in the provider, regardless of the state of the resource in Snowflake. We do not guarantee its stability. It will be reworked and marked as a stable feature in future releases. Breaking changes are expected, even without bumping the major version. To use this feature, add the relevant feature name to `preview_features_enabled field` in the [provider configuration](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs#schema). Please always refer to the [Getting Help](https://github.com/Snowflake-Labs/terraform-provider-snowflake?tab=readme-ov-file#getting-help) section in our Github repo to best determine how to get help for your questions. + +-> **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.