-
Notifications
You must be signed in to change notification settings - Fork 569
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
v2.25.0 breaks sql.Scanner implementation #1359
Comments
Hi @IlyushaZ At the moment, I haven't come up with any solution that will enable us to pass a pointer to I was looking into other Indeed, your code can work, but if we don't expect a pointer, but value: package issues
import (
"database/sql/driver"
"encoding/json"
"fmt"
"testing"
clickhouse_tests "github.com/ClickHouse/clickhouse-go/v2/tests"
"github.com/stretchr/testify/require"
)
type SomeStruct struct {
SomeField string `json:"some_field"`
}
// SomeStructs implements sql.Scanner and driver.Valuer interfaces.
// We want to save slice as a JSON object to clickhouse. We're using Nullable(String) for this purpose.
type SomeStructs []SomeStruct
func (ss *SomeStructs) Scan(src any) error {
if src == nil {
*ss = nil
return nil
}
sp, ok := src.(string)
if !ok {
return fmt.Errorf("expected *string, got %T", src)
}
return json.Unmarshal([]byte(sp), ss)
}
func (ss SomeStructs) Value() (driver.Value, error) {
if ss == nil {
return nil, nil
}
marshalled, err := json.Marshal(ss)
if err != nil {
return nil, err
}
return string(marshalled), nil
}
func Test1359(t *testing.T) {
testEnv, err := clickhouse_tests.GetTestEnvironment("issues")
require.NoError(t, err)
conn, err := clickhouse_tests.TestDatabaseSQLClientWithDefaultSettings(testEnv)
require.NoError(t, err)
_, err = conn.Exec(`CREATE TABLE test_1359 (
NStr Nullable(String)
) Engine MergeTree() ORDER BY tuple()`)
require.NoError(t, err)
t.Cleanup(func() {
_, _ = conn.Exec("DROP TABLE test_1359")
})
toInsert := SomeStructs{
{SomeField: "value1"},
{SomeField: "value2"},
}
_, err = conn.Exec("insert into test_1359 (NStr) values (?)", toInsert)
require.NoError(t, err)
var fromDB SomeStructs
row := conn.QueryRow("select NStr from test_1359 limit 1")
require.NoError(t, row.Scan(&fromDB))
} Happy to hear proposals thought. I will update changelog with a breaking change note. |
Feel free to continue the discussion on this issue. I will close it for now. |
Observed
I am using stdlib interface to interact with Clickhouse. I have a table with
Nullable(String)
column which stores JSON objects. To unmarshal JSON when retrieving data from table I am using custom type that implementssql.Scanner
interface. After upgrading fromv2.23.0
tov2.26.0
I noticed that my program started failing because of incorrect data type passed toScan
method.I assume that is because
*stdRows
now populatesdest
withstring
instead of*string
in case when column with typeNullable(String)
has a non-null value in it. That behavior was changed in v2.25.0 (in this PR in particular) so that the driver could work with standard library.However this update has broken the code that had already been written assuming that
*string
is passed as an argument tosql.Scanner
’sScan
method. It’s a common practice to use pointers to deal with nullable columns.There's example of code that reproduces the issue below. It will work as I am expecting only using version older than
v2.25.0
.Expected behaviour
JSON object will be unmarshalled successfully.
Code example
Error log
Environment
clickhouse-go
version:v2.26.0
database/sql
compatible driver23.8.12.13
CREATE TABLE
statements for tables involved: presented in the example aboveThe text was updated successfully, but these errors were encountered: