-
Notifications
You must be signed in to change notification settings - Fork 125
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
SNOW-1669514: uuid.UUID Valuer Interface No Longer Honored #1209
Comments
It treats a UUID as an array, which makes sense. It is an alias for an array of bytes that can be written as a string: |
hi - thanks for filing this issue with us. do i gather correctly this issue doesn't happen when you use v1.10.1 of the driver, only after upgrading to v1.11.1 ? thank you in advance if that's possible |
in the meantime, i found your account and query details, and i indeed see that with v1.10.1 of the driver, the binding was sent like i tried to guess how exactly you're approaching the generation of the bind data and passing it to Snowflake, and using this simplistic attempt to repro: # cat main.go
package main
import (
//uuid "github.com/google/uuid"
"context"
"database/sql"
"fmt"
"log"
sf "github.com/snowflakedb/gosnowflake"
)
type myUuid struct {
uuid string
}
func newUuid(inUuid string) *myUuid {
n := myUuid{uuid: inUuid}
return &n
}
func main() {
u := "cc95f80a-cf6a-45c2-91ea-a053aa29592f"
res := newUuid(u)
cfg, err := sf.GetConfigFromEnv([]*sf.ConfigParam{
{Name: "Account", EnvName: "SNOWFLAKE_TEST_ACCOUNT", FailOnMissing: true},
{Name: "User", EnvName: "SNOWFLAKE_TEST_USER", FailOnMissing: true},
{Name: "Password", EnvName: "SNOWFLAKE_TEST_PASSWORD", FailOnMissing: true},
})
cfg.Tracing = "TRACE"
cfg.InsecureMode = true
if err != nil {
log.Fatalf("failed to create Config, err: %v", err)
}
dsn, err := sf.DSN(cfg)
if err != nil {
log.Fatalf("failed to create DSN from Config: %v, err: %v", cfg, err)
}
db, err := sql.Open("snowflake", dsn)
if err != nil {
log.Fatalf("failed to connect. %v, err: %v", dsn, err)
}
defer db.Close()
ctx := context.Background()
conn, err := db.Conn(ctx)
if err != nil {
log.Fatalf("Failed to acquire connection. err: %v", err)
}
defer conn.Close()
query := "update test_db.go.issue1209 set is_read = ? where id in (?); "
_, err = conn.ExecContext(ctx, query, false, sf.Array(res))
if err != nil {
log.Fatalf("failed to run a query. %v, err: %v", query, err)
}
fmt.Printf("Congrats! You have successfully run %v with Snowflake DB!\n", query)
} but since it ends up with
i'm obviously missing at least one, possibly more steps. So it would be highly helpful if you could share how you're generating and passing the input data into the bindings and how you use the struct here. Thank you in advance ! |
@sfc-gh-dszmolka It is more like below where the google uuid.UUID is the struct type, and the column is declared as a varchar in Snowflake. When binding, the raw uuid.UUID values were passed in. Previously those uuid.UUIDs had been converted to strings, but with the recent changes they are treated like arrays. There is this line in the logs that is comming from arrayToString:
Output:
|
You'll also see that if you change the UUID to a string, it will update the row:
|
Updating this: https://go.dev/play/p/iLBnvDe-3ES My colleague also just pointed out that uuid.UUID implements Valuer that returns the db.Value back; that isn't being honored anymore. https://pkg.go.dev/database/sql/driver#Valuer |
Opened PR to try and solve this. It should work for both your UUID package and the google's uuid.UUID package. |
@sfc-gh-dszmolka I pinged Mike Wies as he is our enterprise support technical person. Hoping to get some eyes on PR #1211 |
great, thank you @AdamDrewsTR for the details and @ChronosMasterOfAllTime for the contribution here ! |
@sfc-gh-dszmolka Anytime; how do you run the tests locally without setting |
Tests do not run automatically when submitted from external contributors. We'll take a look once we get there and take care of the PR and fix. Again, thank you for your contribution! |
With @sfc-gh-pfus 's help we have the PR in the place that's ready for kicking off the GHA's @sfc-gh-dszmolka |
apparently PR is merged :) but reopening this issue to be able to properly keep track of the release |
I saw that! Thanks for the collab @sfc-gh-pfus. Enjoyed working on the driver as it gave me a much better understanding of how it works. |
Thanks @ChronosMasterOfAllTime for aligning with all our requirements :) It was a pleasure working with you! |
Please answer these questions before submitting your issue.
In order to accurately debug the issue this information is required. Thanks!
What version of GO driver are you using?
1.11.1
What operating system and processor architecture are you using?
Mac, Linux x64 amd and m1
What version of GO are you using?
1.22.7
4.Server version:* E.g. 1.90.1
8.34.0
What did you do?
Updated from 10.1 to 11.1.
What did you expect to see?
Values updated when using an in clause containing a struct that IS a string. We also had to implement a custom serializer to convert UUIDs to strings prior to making their way to sql. It seems like String() isn't honored anymore on struct?
Binding array of structs in a query's IN clause should return results. It seems like something is getting double escaped somewhere. We are using google's UUIDs which would resolve as an driver.Value of array b/c it's driver value is a string. This results in it flowing throug converter.arrayToString:
[SAM CLI:59345] time="2024-09-17T21:03:11Z" level=debug msg="TYPE: uuid.UUID, 51d3526b-bf57-46bb-8258-1344e6e8d910" func="gosnowflake.(*defaultLogger).Debugf" file="log.go:176"
When I run the UUID through arrayToString I get a bingingValue of json, and the value is a quoted string:
{0x1400022b640 json }
"49dbf3b3-7a72-42f2-9183-d6e24d00f292"
Is this then getting double escaped somewhere because it thinks the string is json?
What should have happened and what happened instead?
Queries find the value by string.
Can you set logging to DEBUG and collect the logs?
[SAM CLI:59345] time="2024-09-17T21:03:11Z" level=info msg="Exec: "UPDATE \"some_table\" SET \"is_read\"=? WHERE \"id\" IN (?) AND \"some_table\".\"deleted_at\" IS NULL AND \"user_id\" = ?", [{ 1 true} { 2 51d3526b-bf57-46bb-8258-1344e6e8d910} { 3 _USERID}]" func="gosnowflake.(*snowflakeConn).ExecContext" file="connection.go:312"
What is your Snowflake account identifier, if any? (Optional)
The text was updated successfully, but these errors were encountered: