Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Support for selecting language in snowflake_procedure #1010

Merged
merged 10 commits into from
May 26, 2022
18 changes: 8 additions & 10 deletions docs/resources/function_grant.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,14 @@ resource snowflake_function_grant grant {
schema_name = "schema"
function_name = "function"

arguments = [
{
"name": "a",
"type": "array"
},
{
"name": "b",
"type": "string"
}
]
arguments {
name = "a"
type = "array"
}
arguments {
name = "b"
type = "string"
}
return_type = "string"

privilege = "USAGE"
Expand Down
2 changes: 2 additions & 0 deletions docs/resources/procedure.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ resource "snowflake_procedure" "proc" {
name = "SAMPLEPROC"
database = snowflake_database.db.name
schema = snowflake_schema.schema.name
language = "JAVASCRIPT"
arguments {
name = "arg1"
type = "varchar"
Expand Down Expand Up @@ -64,6 +65,7 @@ EOT
- `arguments` (Block List) List of the arguments for the procedure (see [below for nested schema](#nestedblock--arguments))
- `comment` (String) Specifies a comment for the procedure.
- `execute_as` (String) Sets execute context - see caller's rights and owner's rights
- `language` (String) Specifies the language of the stored procedure code.
- `null_input_behavior` (String) Specifies the behavior of the procedure when called with null inputs.
- `return_behavior` (String) Specifies the behavior of the function when returning results

Expand Down
18 changes: 8 additions & 10 deletions docs/resources/procedure_grant.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,14 @@ resource snowflake_procedure_grant grant {
schema_name = "schema"
procedure_name = "procedure"

arguments = [
{
"name": "a",
"type": "array"
},
{
"name": "b",
"type": "string"
}
]
arguments {
name = "a"
type = "array"
}
arguments {
name = "b"
type = "string"
}
return_type = "string"

privilege = "select"
Expand Down
18 changes: 8 additions & 10 deletions examples/resources/snowflake_function_grant/resource.tf
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,14 @@ resource snowflake_function_grant grant {
schema_name = "schema"
function_name = "function"

arguments = [
{
"name": "a",
"type": "array"
},
{
"name": "b",
"type": "string"
}
]
arguments {
name = "a"
type = "array"
}
arguments {
name = "b"
type = "string"
}
return_type = "string"

privilege = "USAGE"
Expand Down
1 change: 1 addition & 0 deletions examples/resources/snowflake_procedure/resource.tf
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ resource "snowflake_procedure" "proc" {
name = "SAMPLEPROC"
database = snowflake_database.db.name
schema = snowflake_schema.schema.name
language = "JAVASCRIPT"
arguments {
name = "arg1"
type = "varchar"
Expand Down
18 changes: 8 additions & 10 deletions examples/resources/snowflake_procedure_grant/resource.tf
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,14 @@ resource snowflake_procedure_grant grant {
schema_name = "schema"
procedure_name = "procedure"

arguments = [
{
"name": "a",
"type": "array"
},
{
"name": "b",
"type": "string"
}
]
arguments {
name = "a"
type = "array"
}
arguments {
name = "b"
type = "string"
}
return_type = "string"

privilege = "select"
Expand Down
20 changes: 19 additions & 1 deletion pkg/resources/procedure.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (
"github.com/pkg/errors"
)

var procedureLanguages = []string{"JAVASCRIPT", "JAVA", "SCALA", "SQL"}

var procedureSchema = map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Expand Down Expand Up @@ -70,6 +72,13 @@ var procedureSchema = map[string]*schema.Schema{
ForceNew: true,
DiffSuppressFunc: DiffSuppressStatement,
},
"language": {
Type: schema.TypeString,
Optional: true,
Default: "SQL",
ValidateFunc: validation.StringInSlice(procedureLanguages, false),
Description: "Specifies the language of the stored procedure code.",
},
"execute_as": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -159,6 +168,11 @@ func CreateProcedure(d *schema.ResourceData, meta interface{}) error {
builder.WithExecuteAs(v.(string))
}

// Set optionals, default is SQL
if v, ok := d.GetOk("language"); ok {
builder.WithLanguage(v.(string))
}

if v, ok := d.GetOk("comment"); ok {
builder.WithComment(v.(string))
}
Expand Down Expand Up @@ -259,7 +273,11 @@ func ReadProcedure(d *schema.ResourceData, meta interface{}) error {
return err
}
case "language":
// To ignore
if snowflake.Contains(languages, desc.Value.String) {
if err = d.Set("language", desc.Value.String); err != nil {
return err
}
}
default:
log.Printf("[WARN] unexpected procedure property %v returned from Snowflake", desc.Property.String)
}
Expand Down
6 changes: 4 additions & 2 deletions pkg/resources/procedure_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ func prepDummyProcedureResource(t *testing.T) *schema.ResourceData {
"schema": "my_schema",
"arguments": []interface{}{argument1, argument2},
"return_type": "varchar",
"language": "SCALA",
"comment": "mock comment",
"return_behavior": "IMMUTABLE",
"statement": procedureBody, //var message = DATA + DATA;return message
Expand All @@ -43,7 +44,7 @@ func TestProcedureCreate(t *testing.T) {
d := prepDummyProcedureResource(t)

WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) {
mock.ExpectExec(`CREATE OR REPLACE PROCEDURE "my_db"."my_schema"."my_proc"\(data VARCHAR, event_dt DATE\) RETURNS VARCHAR LANGUAGE javascript CALLED ON NULL INPUT IMMUTABLE COMMENT = 'mock comment' EXECUTE AS OWNER AS \$\$hi\$\$`).WillReturnResult(sqlmock.NewResult(1, 1))
mock.ExpectExec(`CREATE OR REPLACE PROCEDURE "my_db"."my_schema"."my_proc"\(data VARCHAR, event_dt DATE\) RETURNS VARCHAR LANGUAGE SCALA CALLED ON NULL INPUT IMMUTABLE COMMENT = 'mock comment' EXECUTE AS OWNER AS \$\$hi\$\$`).WillReturnResult(sqlmock.NewResult(1, 1))
expectProcedureRead(mock)
err := resources.CreateProcedure(d, db)
r.NoError(err)
Expand All @@ -61,7 +62,7 @@ func expectProcedureRead(mock sqlmock.Sqlmock) {
describeRows := sqlmock.NewRows([]string{"property", "value"}).
AddRow("signature", "(data VARCHAR, event_dt DATE)").
AddRow("returns", "VARCHAR(123456789)"). // This is how return type is stored in Snowflake DB
AddRow("language", "JAVASCRIPT").
AddRow("language", "SQL").
AddRow("null handling", "CALLED ON NULL INPUT").
AddRow("volatility", "IMMUTABLE").
AddRow("execute as", "CALLER").
Expand All @@ -85,6 +86,7 @@ func TestProcedureRead(t *testing.T) {
r.Equal("MY_SCHEMA", d.Get("schema").(string))
r.Equal("mock comment", d.Get("comment").(string))
r.Equal("VARCHAR", d.Get("return_type").(string))
r.Equal("SQL", d.Get("language").(string))
r.Equal("IMMUTABLE", d.Get("return_behavior").(string))
r.Equal(procedureBody, d.Get("statement").(string))

Expand Down
11 changes: 10 additions & 1 deletion pkg/snowflake/procedure.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type ProcedureBuilder struct {
args []map[string]string
returnBehavior string // VOLATILE, IMMUTABLE
nullInputBehavior string // "CALLED ON NULL INPUT" or "RETURNS NULL ON NULL INPUT"
language string // SQL, JAVASCRIPT, JAVA, SCALA
returnType string
executeAs string
comment string
Expand Down Expand Up @@ -83,6 +84,12 @@ func (pb *ProcedureBuilder) WithExecuteAs(s string) *ProcedureBuilder {
return pb
}

// WithLanguage sets the language to SQL, JAVA, SCALA or JAVASCRIPT
func (pb *ProcedureBuilder) WithLanguage(s string) *ProcedureBuilder {
pb.language = s
return pb
}

// WithComment adds a comment to the ProcedureBuilder
func (pb *ProcedureBuilder) WithComment(c string) *ProcedureBuilder {
pb.comment = c
Expand Down Expand Up @@ -141,7 +148,9 @@ func (pb *ProcedureBuilder) Create() (string, error) {
q.WriteString(`)`)

q.WriteString(fmt.Sprintf(" RETURNS %v", pb.returnType))
q.WriteString(" LANGUAGE javascript")
if pb.language != "" {
q.WriteString(fmt.Sprintf(" LANGUAGE %v", EscapeString(pb.language)))
}
if pb.nullInputBehavior != "" {
q.WriteString(fmt.Sprintf(` %v`, EscapeString(pb.nullInputBehavior)))
}
Expand Down
5 changes: 3 additions & 2 deletions pkg/snowflake/procedure_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func TestProcedureCreate(t *testing.T) {
r.Equal([]string{"VARCHAR", "DATE"}, s.ArgTypes())
createStmnt, _ := s.Create()
expected := `CREATE OR REPLACE PROCEDURE "test_db"."test_schema"."test_proc"` +
`(user VARCHAR, eventdt DATE) RETURNS VARCHAR LANGUAGE javascript EXECUTE AS CALLER AS $$` +
`(user VARCHAR, eventdt DATE) RETURNS VARCHAR EXECUTE AS CALLER AS $$` +
`var message = "Hi"` + "\nreturn message$$"
r.Equal(expected, createStmnt)
}
Expand All @@ -45,10 +45,11 @@ func TestProcedureCreateWithOptionalParams(t *testing.T) {
s := getProcedure(true)
s.WithNullInputBehavior("RETURNS NULL ON NULL INPUT")
s.WithReturnBehavior("IMMUTABLE")
s.WithLanguage("JAVASCRIPT")
s.WithComment("this is cool proc!")
createStmnt, _ := s.Create()
expected := `CREATE OR REPLACE PROCEDURE "test_db"."test_schema"."test_proc"` +
`(user VARCHAR, eventdt DATE) RETURNS VARCHAR LANGUAGE javascript RETURNS NULL ON NULL INPUT` +
`(user VARCHAR, eventdt DATE) RETURNS VARCHAR LANGUAGE JAVASCRIPT RETURNS NULL ON NULL INPUT` +
` IMMUTABLE COMMENT = 'this is cool proc!' EXECUTE AS CALLER AS $$` +
`var message = "Hi"` + "\nreturn message$$"
r.Equal(expected, createStmnt)
Expand Down