Skip to content

Commit

Permalink
Implement sqlexp Messages for Query/QueryContext (#690)
Browse files Browse the repository at this point in the history
* Ask for usedb and set language messages

* add functional test for message queue

* first basic version of msg queue

* complete messages implementation

* fix lint and build issues

* fix test to avoid 0 rows in a query

* add sqlexp to appveyor yml

* fix build

* fix the merge

* move messageq tests to go1.9

* fix example function and support env vars

* implement data type discovery

* fix pipeline variables for tests
  • Loading branch information
shueybubbles committed Jan 20, 2022
1 parent b979f7a commit e538731
Show file tree
Hide file tree
Showing 20 changed files with 762 additions and 85 deletions.
4 changes: 2 additions & 2 deletions .pipelines/TestSql2017.yml
Expand Up @@ -58,9 +58,9 @@ steps:
workingDirectory: '$(Build.SourcesDirectory)'
displayName: 'run tests'
env:
SQLSERVER_DSN: 'server=.;user id=sa;password=$(TESTPASSWORD)'
SQLPASSWORD: $(SQLPASSWORD)
AZURESERVER_DSN: $(AZURESERVER_DSN)

SQLSERVER_DSN: $(SQLSERVER_DSN)
continueOnError: true
- task: PublishTestResults@2
displayName: "Publish junit-style results"
Expand Down
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

build_script:
- go build
Expand Down
14 changes: 1 addition & 13 deletions bulkimport_example_test.go
@@ -1,11 +1,10 @@
//go:build go1.10
// +build go1.10

package mssql_test

import (
"database/sql"
"flag"
"fmt"
"log"
"strings"
"unicode/utf8"
Expand All @@ -32,19 +31,8 @@ const (

// This example shows how to perform bulk imports
func ExampleCopyIn() {
flag.Parse()

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)
}

db, err := sql.Open("sqlserver", connString)
if err != nil {
Expand Down
13 changes: 1 addition & 12 deletions datetimeoffset_example_test.go
@@ -1,10 +1,10 @@
//go:build go1.10
// +build go1.10

package mssql_test

import (
"database/sql"
"flag"
"fmt"
"log"
"time"
Expand All @@ -15,19 +15,8 @@ import (

// This example shows how to insert and retrieve date and time types data
func ExampleDateTimeOffset() {
flag.Parse()

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)
}

db, err := sql.Open("sqlserver", connString)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions go.mod
Expand Up @@ -6,5 +6,6 @@ require (
github.com/Azure/azure-sdk-for-go/sdk/azcore v0.19.0
github.com/Azure/azure-sdk-for-go/sdk/azidentity v0.11.0
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-20201016220609-9e8e0b390897
)
2 changes: 2 additions & 0 deletions go.sum
Expand Up @@ -10,6 +10,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
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=
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4 h1:49lOXmGaUpV9Fz3gd7TFZY106KVlPVa5jcYD1gaQf98=
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
Expand Down
14 changes: 1 addition & 13 deletions lastinsertid_example_test.go
@@ -1,29 +1,17 @@
//go:build go1.10
// +build go1.10

package mssql_test

import (
"database/sql"
"flag"
"fmt"
"log"
)

// This example shows the usage of Connector type
func ExampleLastInsertId() {
flag.Parse()

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)
}

db, err := sql.Open("sqlserver", connString)
if err != nil {
Expand Down
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")
})
}
76 changes: 76 additions & 0 deletions messages_example_test.go
@@ -0,0 +1,76 @@
//go:build go1.10
// +build go1.10

package mssql_test

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

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

const (
msgQuery = `select 'name' as Name
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() {

connString := makeConnURL().String()

// 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()
if inresult {
cols, err := rows.Columns()
if err != nil {
log.Fatalf("Columns failed: %v", err)
}
fmt.Println(cols)
var d interface{}
if err = rows.Scan(&d); err == nil {
fmt.Println(d)
}
}
}
case sqlexp.MsgNextResultSet:
active = rows.NextResultSet()
case sqlexp.MsgError:
fmt.Println("Error:", m.Error)
case sqlexp.MsgRowsAffected:
fmt.Println("Rows affected:", m.Count)
}
}
}

0 comments on commit e538731

Please sign in to comment.