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

SNOW-726742: Implement GetQueryId for statements #899

Merged
merged 1 commit into from
Aug 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,36 @@
ctxWithID := WithRequestID(ctx, requestID)
rows, err := db.QueryContext(ctxWithID, query)

# Last query ID

If you need query ID for your query you have to use raw connection.

For queries:
```

err := conn.Raw(func(x any) error {
stmt, err := x.(driver.ConnPrepareContext).PrepareContext(ctx, "SELECT 1")
rows, err := stmt.(driver.StmtQueryContext).QueryContext(ctx, nil)
rows.(SnowflakeRows).GetQueryID()
stmt.(SnowflakeStmt).GetQueryID()
return nil
}

```

For execs:
```

err := conn.Raw(func(x any) error {
stmt, err := x.(driver.ConnPrepareContext).PrepareContext(ctx, "INSERT INTO TestStatementQueryIdForExecs VALUES (1)")
result, err := stmt.(driver.StmtExecContext).ExecContext(ctx, nil)
result.(SnowflakeResult).GetQueryID()
stmt.(SnowflakeStmt).GetQueryID()
return nil
}

```

# Canceling Query by CtrlC

From 0.5.0, a signal handling responsibility has moved to the applications. If you want to cancel a
Expand Down Expand Up @@ -902,7 +932,7 @@
tableName)
dbt.mustExecContext(WithFileStream(context.Background(), fileStream),
sqlText)

Check failure on line 935 in doc.go

View workflow job for this annotation

GitHub Actions / AWS Go 1.20 on Windows

package comment is detached; there should be no blank lines between it and the package statement

Check failure on line 935 in doc.go

View workflow job for this annotation

GitHub Actions / AWS Go 1.19 on Windows

package comment is detached; there should be no blank lines between it and the package statement

Check failure on line 935 in doc.go

View workflow job for this annotation

GitHub Actions / AZURE Go 1.20 on Windows

package comment is detached; there should be no blank lines between it and the package statement

Check failure on line 935 in doc.go

View workflow job for this annotation

GitHub Actions / AZURE Go 1.19 on Windows

package comment is detached; there should be no blank lines between it and the package statement

Check failure on line 935 in doc.go

View workflow job for this annotation

GitHub Actions / GCP Go 1.20 on Windows

package comment is detached; there should be no blank lines between it and the package statement

Check failure on line 935 in doc.go

View workflow job for this annotation

GitHub Actions / GCP Go 1.19 on Windows

package comment is detached; there should be no blank lines between it and the package statement
Note: PUT statements are not supported for multi-statement queries.

## Using GET
Expand Down
30 changes: 24 additions & 6 deletions statement.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,15 @@ import (
"database/sql/driver"
)

// SnowflakeStmt represents the prepared statement in driver.
sfc-gh-dprzybysz marked this conversation as resolved.
Show resolved Hide resolved
type SnowflakeStmt interface {
GetQueryID() string
}

type snowflakeStmt struct {
sc *snowflakeConn
query string
sc *snowflakeConn
query string
lastQueryID string
}

func (stmt *snowflakeStmt) Close() error {
Expand All @@ -26,20 +32,32 @@ func (stmt *snowflakeStmt) NumInput() int {

func (stmt *snowflakeStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
logger.WithContext(stmt.sc.ctx).Infoln("Stmt.ExecContext")
return stmt.sc.ExecContext(ctx, stmt.query, args)
result, err := stmt.sc.ExecContext(ctx, stmt.query, args)
stmt.lastQueryID = result.(SnowflakeResult).GetQueryID()
return result, err
}

func (stmt *snowflakeStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
logger.WithContext(stmt.sc.ctx).Infoln("Stmt.QueryContext")
return stmt.sc.QueryContext(ctx, stmt.query, args)
rows, err := stmt.sc.QueryContext(ctx, stmt.query, args)
stmt.lastQueryID = rows.(SnowflakeRows).GetQueryID()
return rows, err
}

func (stmt *snowflakeStmt) Exec(args []driver.Value) (driver.Result, error) {
logger.WithContext(stmt.sc.ctx).Infoln("Stmt.Exec")
return stmt.sc.Exec(stmt.query, args)
result, err := stmt.sc.Exec(stmt.query, args)
stmt.lastQueryID = result.(SnowflakeResult).GetQueryID()
return result, err
}

func (stmt *snowflakeStmt) Query(args []driver.Value) (driver.Rows, error) {
logger.WithContext(stmt.sc.ctx).Infoln("Stmt.Query")
return stmt.sc.Query(stmt.query, args)
rows, err := stmt.sc.Query(stmt.query, args)
stmt.lastQueryID = rows.(SnowflakeRows).GetQueryID()
return rows, err
}

func (stmt *snowflakeStmt) GetQueryID() string {
return stmt.lastQueryID
}
127 changes: 127 additions & 0 deletions statement_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Copyright (c) 2020-2022 Snowflake Computing Inc. All rights reserved.
//lint:file-ignore SA1019 Ignore deprecated methods. We should leave them as-is to keep backward compatibility.

package gosnowflake

Expand Down Expand Up @@ -287,3 +288,129 @@ func TestUnitCheckQueryStatus(t *testing.T) {
t.Fatalf("unexpected error code. expected: %v, got: %v", ErrQueryStatus, driverErr.Number)
}
}

func TestStatementQueryIdForQueries(t *testing.T) {
ctx := context.Background()
conn := openConn(t)
defer conn.Close()

testcases := []struct {
name string
f func(stmt driver.Stmt) (driver.Rows, error)
}{
{
"query",
func(stmt driver.Stmt) (driver.Rows, error) {
return stmt.Query(nil)
},
},
{
"queryContext",
func(stmt driver.Stmt) (driver.Rows, error) {
return stmt.(driver.StmtQueryContext).QueryContext(ctx, nil)
},
},
}

for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
err := conn.Raw(func(x any) error {
stmt, err := x.(driver.ConnPrepareContext).PrepareContext(ctx, "SELECT 1")
if err != nil {
t.Fatal(err)
}
if stmt.(SnowflakeStmt).GetQueryID() != "" {
t.Error("queryId should be empty before executing any query")
}
firstQuery, err := tc.f(stmt)
if err != nil {
t.Fatal(err)
}
if stmt.(SnowflakeStmt).GetQueryID() == "" {
t.Error("queryId should not be empty after executing query")
}
if stmt.(SnowflakeStmt).GetQueryID() != firstQuery.(SnowflakeRows).GetQueryID() {
sfc-gh-pfus marked this conversation as resolved.
Show resolved Hide resolved
t.Error("queryId should be equal among query result and prepared statement")
}
secondQuery, err := tc.f(stmt)
if err != nil {
t.Fatal(err)
}
if stmt.(SnowflakeStmt).GetQueryID() == "" {
t.Error("queryId should not be empty after executing query")
}
if stmt.(SnowflakeStmt).GetQueryID() != secondQuery.(SnowflakeRows).GetQueryID() {
t.Error("queryId should be equal among query result and prepared statement")
}
return nil
})
if err != nil {
t.Fatal(err)
}
})
}
}

func TestStatementQueryIdForExecs(t *testing.T) {
ctx := context.Background()
runDBTest(t, func(dbt *DBTest) {
dbt.mustExec("CREATE TABLE TestStatementQueryIdForExecs (v INTEGER)")
defer dbt.mustExec("DROP TABLE IF EXISTS TestStatementQueryIdForExecs")

testcases := []struct {
name string
f func(stmt driver.Stmt) (driver.Result, error)
}{
{
"exec",
func(stmt driver.Stmt) (driver.Result, error) {
return stmt.Exec(nil)
},
},
{
"execContext",
func(stmt driver.Stmt) (driver.Result, error) {
return stmt.(driver.StmtExecContext).ExecContext(ctx, nil)
},
},
}

for _, tc := range testcases {
t.Run(tc.name, func(t *testing.T) {
err := dbt.conn.Raw(func(x any) error {
stmt, err := x.(driver.ConnPrepareContext).PrepareContext(ctx, "INSERT INTO TestStatementQueryIdForExecs VALUES (1)")
if err != nil {
t.Fatal(err)
}
if stmt.(SnowflakeStmt).GetQueryID() != "" {
t.Error("queryId should be empty before executing any query")
}
firstExec, err := tc.f(stmt)
if err != nil {
t.Fatal(err)
}
if stmt.(SnowflakeStmt).GetQueryID() == "" {
t.Error("queryId should not be empty after executing query")
}
if stmt.(SnowflakeStmt).GetQueryID() != firstExec.(SnowflakeResult).GetQueryID() {
t.Error("queryId should be equal among query result and prepared statement")
}
secondExec, err := tc.f(stmt)
if err != nil {
t.Fatal(err)
}
if stmt.(SnowflakeStmt).GetQueryID() == "" {
t.Error("queryId should not be empty after executing query")
}
if stmt.(SnowflakeStmt).GetQueryID() != secondExec.(SnowflakeResult).GetQueryID() {
t.Error("queryId should be equal among query result and prepared statement")
}
return nil
})
if err != nil {
t.Fatal(err)
}
})
}
})
}
Loading