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

Implement sqlexp Messages for Query/QueryContext #690

Merged
merged 15 commits into from Jan 20, 2022
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions appveyor.yml
Expand Up @@ -49,6 +49,7 @@ install:
- go version
- go env
- go get -u github.com/golang-sql/civil
- go get -u github.com/golang-sql/sqlexp
shueybubbles marked this conversation as resolved.
Show resolved Hide resolved

build_script:
- go build
Expand Down
1 change: 1 addition & 0 deletions go.mod
Expand Up @@ -4,5 +4,6 @@ go 1.11

require (
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe
github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c
)
2 changes: 2 additions & 0 deletions go.sum
@@ -1,5 +1,7 @@
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188 h1:+eHOFJl1BaXrQxKX+T06f78590z4qA2ZzBTqahsKSE4=
github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188/go.mod h1:vXjM/+wXQnTPR4KqTKDgJukSZ6amVRtWMPEjE6sQoK8=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
63 changes: 63 additions & 0 deletions messages_benchmark_test.go
@@ -0,0 +1,63 @@
// +build go1.14

package mssql

import (
"testing"
)

func BenchmarkMessageQueue(b *testing.B) {
conn, logger := open(b)
defer conn.Close()
defer logger.StopLogging()

b.Run("BlockingQuery", func(b *testing.B) {
var errs, results float64
for i := 0; i < b.N; i++ {
r, err := conn.Query(mixedQuery)
if err != nil {
b.Fatal(err.Error())
}
defer r.Close()
active := true
first := true
for active {
active = r.Next()
if active && first {
results++
}
first = false
if !active {
if r.Err() != nil {
b.Logf("r.Err:%v", r.Err())
errs++
}
active = r.NextResultSet()
if active {
first = true
}
}
}
}
b.ReportMetric(float64(0), "msgs/op")
b.ReportMetric(errs/float64(b.N), "errors/op")
b.ReportMetric(results/float64(b.N), "results/op")
})
b.Run("NonblockingQuery", func(b *testing.B) {
var msgs, errs, results, rowcounts float64
for i := 0; i < b.N; i++ {
m, e, r, rc := testMixedQuery(conn, b)
msgs += float64(m)
errs += float64(e)
results += float64(r)
rowcounts += float64(rc)
if r != 4 {
b.Fatalf("Got wrong results count: %d, expected 4", r)
}
}
b.ReportMetric(msgs/float64(b.N), "msgs/op")
b.ReportMetric(errs/float64(b.N), "errors/op")
b.ReportMetric(results/float64(b.N), "results/op")
b.ReportMetric(rowcounts/float64(b.N), "rowcounts/op")
})
}
89 changes: 89 additions & 0 deletions messages_example_test.go
@@ -0,0 +1,89 @@
// +build go1.10

package mssql_test

import (
"context"
"database/sql"
"flag"
"fmt"
"log"
"os"

mssql "github.com/denisenkom/go-mssqldb"
"github.com/golang-sql/sqlexp"
)

const (
msgQuery = `select name from sys.tables
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be better to select something that won't vary from system to system (and potentially even run to run). That would make the test more repeatable.

PRINT N'This is a message'
select 199
RAISERROR (N'Testing!' , 11, 1)
select 300
`
)

// This example shows the usage of sqlexp/Messages
func ExampleRows_usingmessages() {
shueybubbles marked this conversation as resolved.
Show resolved Hide resolved
flag.Parse()
shueybubbles marked this conversation as resolved.
Show resolved Hide resolved

if *debug {
fmt.Printf(" password:%s\n", *password)
fmt.Printf(" port:%d\n", *port)
fmt.Printf(" server:%s\n", *server)
fmt.Printf(" user:%s\n", *user)
}

connString := makeConnURL().String()
if *debug {
fmt.Printf(" connString:%s\n", connString)
}

// Create a new connector object by calling NewConnector
connector, err := mssql.NewConnector(connString)
if err != nil {
log.Println(err)
return
}

// Pass connector to sql.OpenDB to get a sql.DB object
db := sql.OpenDB(connector)
defer db.Close()
retmsg := &sqlexp.ReturnMessage{}
ctx := context.Background()
rows, err := db.QueryContext(ctx, msgQuery, retmsg)
if err != nil {
log.Fatalf("QueryContext failed: %v", err)
}
active := true
for active {
msg := retmsg.Message(ctx)
switch m := msg.(type) {
case sqlexp.MsgNotice:
fmt.Println(m.Message)
case sqlexp.MsgNext:
inresult := true
for inresult {
inresult = rows.Next()
cols, err := rows.Columns()
if err != nil {
log.Fatalf("Columns failed: %v", err)
}
fmt.Println(cols)
if inresult {
var d interface{}
if err = rows.Scan(&d); err != nil {
shueybubbles marked this conversation as resolved.
Show resolved Hide resolved
fmt.Println(d)
}
}
}
case sqlexp.MsgNextResultSet:
active = rows.NextResultSet()
case sqlexp.MsgError:
fmt.Fprintln(os.Stderr, m.Error)
case sqlexp.MsgRowsAffected:
fmt.Println("Rows affected:", m.Count)
}
}

shueybubbles marked this conversation as resolved.
Show resolved Hide resolved
}