Skip to content

Commit

Permalink
fix: Pass file_format values as-is in external table configuration
Browse files Browse the repository at this point in the history
Common use of FILE_FORMAT under CREATE EXTERNAL TABLE includes specifying
a previously created format name (FORMAT_NAME = 'NAME') or the various
type options (TYPE=CSV FIELD_DELIMITER='|').

Both of these usage require defining string literals with the single quote
character (') that should not be escaped.

This change removes the escaping of single quotes performed for the
file_format values.

Some examples have also been added to the field documentation
to make it easier to understand how values need to be passed to
external tables.

Testing:

  - Modified unit tests to exercise passing of typical file format values
  - Ran 'make test' to confirm existing tests continue to pass
  - Attempted an external table creation on a personal account with the
    changes included and observed it to execute a successful SQL

Fixes Snowflake-Labs#1046
  • Loading branch information
sfc-gh-hachouraria committed Aug 22, 2022
1 parent fc3a8c2 commit b34105b
Show file tree
Hide file tree
Showing 5 changed files with 12 additions and 11 deletions.
9 changes: 5 additions & 4 deletions examples/resources/snowflake_external_table/resource.tf
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
resource snowflake_external_table external_table {
database = "db"
schema = "schema"
name = "external_table"
comment = "External table"
database = "db"
schema = "schema"
name = "external_table"
comment = "External table"
file_format = "TYPE = CSV FIELD_DELIMITER = '|'"

column {
name = "id"
Expand Down
2 changes: 1 addition & 1 deletion pkg/resources/external_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ var externalTableSchema = map[string]*schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "Specifies the file format for the external table.",
Description: "Specifies the file format options for the external table.",
},
"pattern": {
Type: schema.TypeString,
Expand Down
4 changes: 2 additions & 2 deletions pkg/resources/external_table_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ func TestExternalTableCreate(t *testing.T) {
"comment": "great comment",
"column": []interface{}{map[string]interface{}{"name": "column1", "type": "OBJECT", "as": "a"}, map[string]interface{}{"name": "column2", "type": "VARCHAR", "as": "b"}},
"location": "location",
"file_format": "format",
"file_format": "FORMAT_NAME = 'format'",
"pattern": "pattern",
}
d := externalTable(t, "database_name|schema_name|good_name", in)

WithMockDb(t, func(db *sql.DB, mock sqlmock.Sqlmock) {
mock.ExpectExec(`CREATE EXTERNAL TABLE "database_name"."schema_name"."good_name" \("column1" OBJECT AS a, "column2" VARCHAR AS b\) WITH LOCATION = location REFRESH_ON_CREATE = true AUTO_REFRESH = true PATTERN = 'pattern' FILE_FORMAT = \( format \) COMMENT = 'great comment'`).WillReturnResult(sqlmock.NewResult(1, 1))
mock.ExpectExec(`CREATE EXTERNAL TABLE "database_name"."schema_name"."good_name" \("column1" OBJECT AS a, "column2" VARCHAR AS b\) WITH LOCATION = location REFRESH_ON_CREATE = true AUTO_REFRESH = true PATTERN = 'pattern' FILE_FORMAT = \( FORMAT_NAME = 'format' \) COMMENT = 'great comment'`).WillReturnResult(sqlmock.NewResult(1, 1))

expectExternalTableRead(mock)
err := resources.CreateExternalTable(d, db)
Expand Down
2 changes: 1 addition & 1 deletion pkg/snowflake/external_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ func (tb *ExternalTableBuilder) Create() string {
q.WriteString(fmt.Sprintf(` PATTERN = '%v'`, EscapeString(tb.pattern)))
}

q.WriteString(fmt.Sprintf(` FILE_FORMAT = ( %v )`, EscapeString(tb.fileFormat)))
q.WriteString(fmt.Sprintf(` FILE_FORMAT = ( %v )`, tb.fileFormat))

if tb.awsSNSTopic != "" {
q.WriteString(fmt.Sprintf(` AWS_SNS_TOPIC = '%v'`, EscapeString(tb.awsSNSTopic)))
Expand Down
6 changes: 3 additions & 3 deletions pkg/snowflake/external_table_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ func TestExternalTableCreate(t *testing.T) {
s.WithColumns([]map[string]string{{"name": "column1", "type": "OBJECT", "as": "expression1"}, {"name": "column2", "type": "VARCHAR", "as": "expression2"}})
s.WithLocation("location")
s.WithPattern("pattern")
s.WithFileFormat("file format")
s.WithFileFormat("TYPE = CSV FIELD_DELIMITER = '|'")
r.Equal(s.QualifiedName(), `"test_db"."test_schema"."test_table"`)

r.Equal(s.Create(), `CREATE EXTERNAL TABLE "test_db"."test_schema"."test_table" ("column1" OBJECT AS expression1, "column2" VARCHAR AS expression2) WITH LOCATION = location REFRESH_ON_CREATE = false AUTO_REFRESH = false PATTERN = 'pattern' FILE_FORMAT = ( file format )`)
r.Equal(s.Create(), `CREATE EXTERNAL TABLE "test_db"."test_schema"."test_table" ("column1" OBJECT AS expression1, "column2" VARCHAR AS expression2) WITH LOCATION = location REFRESH_ON_CREATE = false AUTO_REFRESH = false PATTERN = 'pattern' FILE_FORMAT = ( TYPE = CSV FIELD_DELIMITER = '|' )`)

s.WithComment("Test Comment")
r.Equal(s.Create(), `CREATE EXTERNAL TABLE "test_db"."test_schema"."test_table" ("column1" OBJECT AS expression1, "column2" VARCHAR AS expression2) WITH LOCATION = location REFRESH_ON_CREATE = false AUTO_REFRESH = false PATTERN = 'pattern' FILE_FORMAT = ( file format ) COMMENT = 'Test Comment'`)
r.Equal(s.Create(), `CREATE EXTERNAL TABLE "test_db"."test_schema"."test_table" ("column1" OBJECT AS expression1, "column2" VARCHAR AS expression2) WITH LOCATION = location REFRESH_ON_CREATE = false AUTO_REFRESH = false PATTERN = 'pattern' FILE_FORMAT = ( TYPE = CSV FIELD_DELIMITER = '|' ) COMMENT = 'Test Comment'`)
}

func TestExternalTableUpdate(t *testing.T) {
Expand Down

0 comments on commit b34105b

Please sign in to comment.