Repository: snowflakedb/gosnowflake
Pull request #1200 (2024-08-20 18:44:51)

SNOW-1633839: Fix error in arrayToString calls
### Description

SNOW-1633839

Fix the following panic. It is illegal to call `IsNil()` on arrays, it's only legal on slices, but we were hitting this code path for both arrays and slices.

```
panic: reflect: call of reflect.Value.IsNil on array Value

goroutine 101 [running]:
reflect.Value.IsNil(...)
	/usr/local/go/src/reflect/value.go:1574
github.com/snowflakedb/gosnowflake.arrayToString({0x36b3920, 0xc00413d790}, 0x6, 0xc0014ab7d0)
	/go/pkg/mod/github.com/snowflakedb/gosnowflake@v1.11.0/converter.go:276 +0x14d7
github.com/snowflakedb/gosnowflake.valueToString({0x36b3920, 0xc00413d790}, 0x6, 0xc0014ab7d0)
	/go/pkg/mod/github.com/snowflakedb/gosnowflake@v1.11.0/converter.go:264 +0x425
github.com/snowflakedb/gosnowflake.getBindValues({0xc004188000, 0x4a6, 0x10?}, 0xc0014ab7d0)
	/go/pkg/mod/github.com/snowflakedb/gosnowflake@v1.11.0/bind_uploader.go:251 +0x26d
github.com/snowflakedb/gosnowflake.(*snowflakeConn).processBindings(0xc0001db9e0, {0x42770b0, 0xc00415a2d0}, {0xc004188000, 0x4a6, 0x4a6}, 0x0, {0x5f, 0x2e, 0x45, ...}, ...)
	/go/pkg/mod/github.com/snowflakedb/gosnowflake@v1.11.0/bind_uploader.go:219 +0x248
github.com/snowflakedb/gosnowflake.(*snowflakeConn).exec(0xc0001db9e0, {0x42770b0, 0xc00415a2d0}, {0xc004186000, 0xe57}, 0x0, 0x0, 0x0, {0xc004188000, 0x4a6, ...})
	/go/pkg/mod/github.com/snowflakedb/gosnowflake@v1.11.0/connection.go:119 +0x438
github.com/snowflakedb/gosnowflake.(*snowflakeConn).ExecContext(0xc0001db9e0, {0x42770e8, 0xc0014dc050}, {0xc004186000, 0xe57}, {0xc004188000, 0x4a6, 0x4a6})
	/go/pkg/mod/github.com/snowflakedb/gosnowflake@v1.11.0/connection.go:305 +0x225
database/sql.ctxDriverExec({0x42770e8?, 0xc0014dc050?}, {0x7f1415cd72f8?, 0xc0001db9e0?}, {0x0?, 0x0?}, {0xc004186000?, 0x0?}, {0xc004188000, 0x4a6, ...})
	/usr/local/go/src/database/sql/ctxutil.go:31 +0xd7
database/sql.(*DB).execDC.func2()
	/usr/local/go/src/database/sql/sql.go:1703 +0x159
database/sql.withLock({0x42516a8, 0xc000b58480}, 0xc001604c60)
	/usr/local/go/src/database/sql/sql.go:3530 +0x82
database/sql.(*DB).execDC(0xc001604d01?, {0x42770e8, 0xc0014dc050}, 0xc000b58480, 0xc001604d78?, {0xc004186000, 0xe57}, {0xc004180008, 0x4a6, 0x5ff})
	/usr/local/go/src/database/sql/sql.go:1698 +0x229
database/sql.(*DB).exec(0xc000bcad00, {0x42770e8, 0xc0014dc050}, {0xc004186000, 0xe57}, {0xc004180008, 0x4a6, 0x5ff}, 0xf0?)
	/usr/local/go/src/database/sql/sql.go:1683 +0xd5
database/sql.(*DB).ExecContext.func1(0x4?)
	/usr/local/go/src/database/sql/sql.go:1662 +0x4f
database/sql.(*DB).retry(0xc004186e56?, 0xc001604e50)
	/usr/local/go/src/database/sql/sql.go:1566 +0x42
database/sql.(*DB).ExecContext(0xc00413d780?, {0x42770e8?, 0xc0014dc050?}, {0xc004186000?, 0x329fde0?}, {0xc004180008?, 0x15555555?, 0x3837880?})
	/usr/local/go/src/database/sql/sql.go:1661 +0xc8
neeva.co/snowscope/eval.(*snowflakeEvalWriter).WriteAll(0xc001aee140, {0xc001068a08, 0x46, 0x1?})
```

### Checklist
- [X] Created tests which fail without the change (if possible)
- [X] Extended the README / documentation, if necessary


github-actions[bot]: <br/>Thank you for your submission, we really appreciate it. Like many open-source projects, we ask that you sign our [Contributor License Agreement](https://github.com/snowflakedb/CLA/blob/main/README.md) before we can accept your contribution. You can sign the CLA by just posting a Pull Request Comment same as the below format.<br/>
   - - -
   I have read the CLA Document and I hereby sign the CLA
   - - -
   <sub>You can retrigger this bot by commenting **recheck** in this Pull Request. Posted by the **CLA Assistant Lite bot**.</sub>
sfc-gh-vvenugopal: I have read the CLA Document and I hereby sign the CLA
sfc-gh-vvenugopal: recheck

Patch:
diff --git a/converter.go b/converter.go
index 363d93f..3478523 100644
--- a/converter.go
+++ b/converter.go
@@ -273,7 +273,7 @@ func valueToString(v driver.Value, tsmode snowflakeType, params map[string]*stri
 
 func arrayToString(v driver.Value, tsmode snowflakeType, params map[string]*string) (bindingValue, error) {
 	v1 := reflect.Indirect(reflect.ValueOf(v))
-	if v1.IsNil() {
+	if v1.Kind() == reflect.Slice && v1.IsNil() {
 		return bindingValue{nil, "json", nil}, nil
 	}
 	if bd, ok := v.([][]byte); ok && tsmode == binaryType {


Test patch:
diff --git a/converter_test.go b/converter_test.go
index b0030e2..102660d 100644
--- a/converter_test.go
+++ b/converter_test.go
@@ -269,6 +269,19 @@ func TestValueToString(t *testing.T) {
 	assertNilE(t, bv.schema)
 	assertEqualE(t, *bv.value, expectedString)
 
+	t.Run("arrays", func(t *testing.T) {
+		bv, err := valueToString([2]int{1, 2}, objectType, nil)
+		assertNilF(t, err)
+		assertEqualE(t, bv.format, "json")
+		assertEqualE(t, *bv.value, "[1,2]")
+	})
+	t.Run("slices", func(t *testing.T) {
+		bv, err := valueToString([]int{1, 2}, objectType, nil)
+		assertNilF(t, err)
+		assertEqualE(t, bv.format, "json")
+		assertEqualE(t, *bv.value, "[1,2]")
+	})
+
 	bv, err = valueToString(&testValueToStringStructuredObject{s: "some string", i: 123, date: time.Date(2024, time.May, 24, 0, 0, 0, 0, time.UTC)}, timestampLtzType, params)
 	assertNilF(t, err)
 	assertEqualE(t, bv.format, "json")